feat(plugin): package as a Claude Code marketplace plugin
- .claude-plugin/plugin.json v0.1.0 (auto_discover, MIT) - SessionStart hook: thin zero-dep .mjs wrapper (marketplace convention) around scripts/coord-inbox.sh, emitting the additionalContext envelope; always exits 0. Smoke-tested: empty mailbox -> bare continue, pending message -> injected with UNTRUSTED framing. - coord-send skill bundled; examples and description use generic repo names only (coordination metadata never reaches a public surface). - README (English; documents the deliver-until-done lifecycle correctly, review §7), CHANGELOG, LICENSE (MIT), CLAUDE.md, package.json + node --test wrapper around the bash selftest. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HBbjgS5A55RVavoyjJC4FX
This commit is contained in:
parent
77664e9e51
commit
0e6014fe98
10 changed files with 472 additions and 0 deletions
42
hooks/scripts/session-start.mjs
Normal file
42
hooks/scripts/session-start.mjs
Normal file
|
|
@ -0,0 +1,42 @@
|
|||
#!/usr/bin/env node
|
||||
// coord - SessionStart hook: inject this repo's pending coordination inbox
|
||||
// (directed messages + unseen broadcasts) as additionalContext.
|
||||
//
|
||||
// Thin Node wrapper (marketplace convention: hooks are .mjs) around the bash
|
||||
// engine scripts/coord-inbox.sh, which owns the mailbox semantics and is
|
||||
// covered by scripts/coord-selftest.sh. Zero dependencies. Always exits 0 -
|
||||
// a broken mailbox must never block a session.
|
||||
|
||||
import { execFileSync } from 'node:child_process';
|
||||
import { basename, dirname, join } from 'node:path';
|
||||
import { fileURLToPath } from 'node:url';
|
||||
|
||||
function emit(context) {
|
||||
const out = { continue: true };
|
||||
if (context) {
|
||||
out.hookSpecificOutput = { hookEventName: 'SessionStart', additionalContext: context };
|
||||
}
|
||||
process.stdout.write(JSON.stringify(out) + '\n');
|
||||
}
|
||||
|
||||
try {
|
||||
const pluginRoot = process.env.CLAUDE_PLUGIN_ROOT
|
||||
|| join(dirname(fileURLToPath(import.meta.url)), '..', '..');
|
||||
|
||||
let repoRoot = '';
|
||||
try {
|
||||
repoRoot = execFileSync('git', ['rev-parse', '--show-toplevel'],
|
||||
{ stdio: ['ignore', 'pipe', 'ignore'], encoding: 'utf8' }).trim();
|
||||
} catch {
|
||||
// not a git repo: fall back to the working directory below
|
||||
}
|
||||
if (!repoRoot) repoRoot = process.cwd();
|
||||
|
||||
const inbox = execFileSync('bash',
|
||||
[join(pluginRoot, 'scripts', 'coord-inbox.sh'), '--repo', basename(repoRoot)],
|
||||
{ stdio: ['ignore', 'pipe', 'ignore'], encoding: 'utf8' });
|
||||
|
||||
emit(inbox.trim() ? '== Repo coordination (unread messages) ==\n' + inbox : '');
|
||||
} catch {
|
||||
emit('');
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue