feat: CRUD action helpers, skills install, setup improvements, remove audiences#3
Merged
Merged
Conversation
All 8 delete commands and 10 list commands shared identical
auth → confirm/pagination → spinner → output patterns.
- Add src/lib/actions.ts with runDelete and runList<T> helpers
- runDelete: requireClient, optional confirmDelete, withSpinner, synthesized {object,id,deleted:true} output
- runList<T>: requireClient, withSpinner, onInteractive callback for table/hint rendering
- Each command action goes from ~15 lines to ~7 lines
- Zero behavior changes; 0 TS errors; 448/448 tests pass
Hardcoded Unicode literals (box-drawing, checkmarks) in source files are corrupted to "Ââ"-style garbage when the bundled JS is read with Latin-1 encoding — a common occurrence on Windows or certain npm distribution paths. Fix mirrors the approach used in outlit-sdk (commit cc87517): generate all non-ASCII characters at runtime via String.fromCodePoint() so source files contain only safe ASCII integer literals. - tty.ts: export isUnicodeSupported (false on legacy Windows cmd.exe) - table.ts: all box-drawing via String.fromCodePoint() + ASCII fallback - spinner.ts: TICK/WARN/CROSS via String.fromCodePoint() + ASCII fallback unicode-animations is already safe: it uses String.fromCodePoint() internally to generate braille frames — no changes needed there.
…resend-mcp
cursor, claude-desktop, and vscode previously wrote { command: 'resend',
args: ['mcp', 'serve'] } — pointing at an unimplemented Phase 3 feature.
Switch to { command: 'npx', args: ['-y', 'resend-mcp'] } with the
RESEND_API_KEY env resolved at setup time. Extract writeMcpJsonConfig()
into setup/utils.ts so all three targets share a single implementation.
Primary path now runs: claude mcp add [-e RESEND_API_KEY=<key>] resend -- npx -y resend-mcp Fallback (.claude.json) also switches to the npx resend-mcp entry with env. Previously both paths referenced 'resend mcp serve', an unimplemented command.
Installs all skills from github.com/resend/resend-skills into .claude/skills/ (project) or ~/.claude/skills/ (--global). Fetches the repo file tree via the GitHub API, downloads each file, and writes it preserving the subdirectory structure. The root SKILL.md is placed in resend/SKILL.md so every skill lives in a named folder. Excluded: README.md, LICENSE, package.json, pnpm-lock.yaml, tests/, .github/ Skills installed: resend, send-email, resend-inbound, templates, agent-email-inbox
Update the claude-code target description to match the actual command (npx -y resend-mcp) and add a pointer to resend skills install.
The GitHub tree includes .gitignore at the repo root which was being written to .claude/skills/.gitignore. Replace the specific .github/ pattern with /^\./ to exclude all root-level dotfiles and dot-directories.
- Change skillDir from ~/clawd/skills to ~/.openclaw/skills/resend - Change skillPath from resend.md to SKILL.md (agent skills standard) - Add YAML frontmatter with name/description to SKILL_CONTENT - Update tests to assert correct path and frontmatter presence
- Interactive mode delegates to `npx skills add resend/resend-skills`
- Non-interactive writes to .claude/skills/ + .agents/skills/ (project)
- --global writes to detected per-agent dirs (~/.claude, ~/.cursor, etc.)
- InstallTarget[] signature replaces single-string skillsDir arg
- Output shape: { installed, targets: [{name,dir}], files }
- New test: multiple targets multiply write count correctly
- Add runGet<T> to lib/actions.ts alongside runList/runDelete - Extract SdkCall<T> and SpinnerMessages local types to DRY runList/runDelete signatures - Apply runGet to 8 commands: contacts, contact-properties, segments, topics, webhooks, broadcasts, domains, emails/receiving — removing ~8 lines of boilerplate each - No behavior changes; tsc --noEmit and all 455 tests pass
Eliminates the requireClient → withSpinner(errorCode) → if/else tail pattern duplicated across 8 update/verify/remove-segment commands.
- emails/receiving/list.ts → runList - emails/receiving/attachments.ts → runList (error code normalized to list_error) - broadcasts/send.ts → runWrite (successMsg computed before call)
Eliminates requireClient → withSpinner('create_error') → if/else tail
duplicated across 8 create commands. audiences/create.ts excluded due
to deprecated output-wrapping structure.
The audiences namespace was a thin deprecated wrapper over segments. All CRUD commands, tests, and the CLI registration are removed. Users should use `resend segments` instead.
This planning document tracked which CLI namespaces still needed implementing. All namespaces are now complete, so the index is obsolete.
- install.sh: write fish config to conf.d/resend.fish using fish_add_path instead of editing config.fish; add next-steps block with RESEND_API_KEY export hint - install.ps1: extract to a temp directory (not just a temp zip) so cleanup in finally removes the whole dir; add next-steps block with RESEND_API_KEY hint
dielduarte
added a commit
that referenced
this pull request
Jun 25, 2026
Felipe review (#3): whoami's help says it is local-only, which is now accurate — it passes { refresh: false } so it reads the grant from keychain/file without a network call. Tighten the help wording to 'active credential' (not 'API key') and label OAuth credentials as 'Token' rather than 'API Key' in the human output. Add a test asserting whoami never calls fetch for an OAuth profile.
dielduarte
added a commit
that referenced
this pull request
Jul 3, 2026
Felipe review (#3): whoami's help says it is local-only, which is now accurate — it passes { refresh: false } so it reads the grant from keychain/file without a network call. Tighten the help wording to 'active credential' (not 'API key') and label OAuth credentials as 'Token' rather than 'API Key' in the human output. Add a test asserting whoami never calls fetch for an OAuth profile.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
lib/actions.ts— five CRUD helpers (runGet,runList,runCreate,runWrite,runDelete) that eliminate the repetitiverequireClient → withSpinner → if/elsepattern; applied to all commands across every namespace (~1 900 lines removed)resend skills installcommand — multi-target install of Claude agent skills with interactive npx delegation (Cursor, Claude Desktop, VS Code, Claude Code, OpenClaw targets)writeMcpJsonConfighelper; all targets now usenpx -y resend-mcpwithRESEND_API_KEYresolved at setup time; fix staleresend mcp servereference in help textaudiencesnamespace — thin wrapper over segments; all six command files, four test files, and CLI registration removedinstall.sh: write fish config toconf.d/resend.fishusingfish_add_path; both scripts add a next-steps block withRESEND_API_KEYhint;install.ps1uses a temp dir for extraction with properfinallycleanupTest Plan
bun testpasses with no failuresresend skills installruns interactively and writes correct config files for each targetresend setup cursor/claude-desktop/vscode/claude-codewritesnpx -y resend-mcpentries with API keyresend audiencesis no longer a recognised commandinstall.shon a fish shell machine writesconf.d/resend.fishand prints next-stepsinstall.ps1on Windows cleans up the temp directory on success and failureNotes
The
audiencesnamespace was already marked deprecated (thin wrapper oversegments). Users should migrate toresend segments.