feat(plugin): ship Claude Code plugin + marketplace manifest
Adds a /plugin marketplace at the repo root and a `claude-mailbox` plugin under plugin/ that wires the UserPromptSubmit hook without needing the per-user `install-hook` step. The hook command (`claude-mailbox check --hook`) now reads the mailbox name from $CLAUDE_MAILBOX_NAME when --name is omitted and emits a one-line setup hint when the daemon is unreachable, so a missing daemon is loud instead of invisible. The plugin only contains the Claude Code glue — the daemon binary is still a separate prerequisite (`npm i -g @kuns/claude-mailbox` + install-autostart), and the plugin/README plus main README spell out the three-step setup.
This commit is contained in:
@@ -127,29 +127,45 @@ program
|
||||
|
||||
program
|
||||
.command("check")
|
||||
.description("Pull pending messages and mark delivered.")
|
||||
.requiredOption("--name <name>", "Mailbox name (also sent as X-Mailbox)")
|
||||
.description(
|
||||
"Pull pending messages and mark delivered. In --hook mode the name can come from CLAUDE_MAILBOX_NAME.",
|
||||
)
|
||||
.option("--name <name>", "Mailbox name (also sent as X-Mailbox). Falls back to $CLAUDE_MAILBOX_NAME.")
|
||||
.option("--url <url>", "Daemon base URL", DEFAULT_URL)
|
||||
.option(
|
||||
"--hook",
|
||||
"Hook mode: human-readable output, silent on empty inbox or unreachable daemon (exit 0)",
|
||||
"Hook mode: human-readable output, silent when no mailbox configured or daemon unreachable (exit 0). Emits a one-line setup hint when name is set but daemon is unreachable.",
|
||||
)
|
||||
.action(async (opts: { name: string; url: string; hook?: boolean }) => {
|
||||
.action(async (opts: { name?: string; url: string; hook?: boolean }) => {
|
||||
const name = (opts.name ?? process.env["CLAUDE_MAILBOX_NAME"] ?? "").trim();
|
||||
if (!name) {
|
||||
if (opts.hook) return;
|
||||
console.error("Missing --name (or set CLAUDE_MAILBOX_NAME).");
|
||||
process.exit(1);
|
||||
}
|
||||
try {
|
||||
const out = await callJson(
|
||||
"POST",
|
||||
`${opts.url}/v1/check-inbox?name=${encodeURIComponent(opts.name)}`,
|
||||
{ headers: { "X-Mailbox": opts.name } },
|
||||
`${opts.url}/v1/check-inbox?name=${encodeURIComponent(name)}`,
|
||||
{ headers: { "X-Mailbox": name } },
|
||||
);
|
||||
if (opts.hook) {
|
||||
const messages = (Array.isArray(out) ? out : []) as HookMessage[];
|
||||
const text = formatMessagesForHook(opts.name, messages);
|
||||
const text = formatMessagesForHook(name, messages);
|
||||
if (text) process.stdout.write(text);
|
||||
return;
|
||||
}
|
||||
console.log(JSON.stringify(out, null, 2));
|
||||
} catch (err) {
|
||||
if (opts.hook) return;
|
||||
if (opts.hook) {
|
||||
const msg = err instanceof Error ? err.message : String(err);
|
||||
if (/ECONNREFUSED|fetch failed|ENOTFOUND|connect/i.test(msg)) {
|
||||
process.stdout.write(
|
||||
`[Claude-Mailbox] Daemon not reachable at ${opts.url}. Run \`claude-mailbox install-autostart\` (one-time) or \`claude-mailbox start\`.\n`,
|
||||
);
|
||||
}
|
||||
return;
|
||||
}
|
||||
reportClientError(err, opts.url);
|
||||
}
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user