clawborrator-mcp 0.0.2 → 0.0.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.js CHANGED
@@ -24,6 +24,8 @@ import { runHook } from './hook.js';
24
24
  import { writeSidecar, deleteSidecar } from './sidecar.js';
25
25
  import { TOOL_DEFINITIONS, callTool } from './tools/index.js';
26
26
  import { enqueueRoutedPrompt } from './inbox.js';
27
+ import { installHooks } from './install-hooks.js';
28
+ import { loadPersistedSessionId, savePersistedSession } from './persisted-session.js';
27
29
  const __dirname = dirname(fileURLToPath(import.meta.url));
28
30
  // Dispatch on top-level flags BEFORE booting the long-lived MCP.
29
31
  // --hook=<HookName> short-lived hook spawn (fast path)
@@ -69,6 +71,46 @@ async function main() {
69
71
  log.info('clawborrator-mcp starting', { hubUrl: config.hubUrl });
70
72
  const cwd = process.cwd();
71
73
  const host = hostname();
74
+ // Self-install / refresh project hooks in .claude/. Idempotent —
75
+ // touches files only when the desired state diverges from disk, so
76
+ // re-runs of `claude` cost nothing. Operators no longer need to
77
+ // run a separate `init` command — dropping a .mcp.json with a
78
+ // valid channel token is the only setup step.
79
+ try {
80
+ const r = installHooks(cwd);
81
+ if (r.hookFileWritten || r.settingsWritten) {
82
+ log.info('hooks installed', {
83
+ hookFile: r.hookFileWritten,
84
+ settings: r.settingsWritten,
85
+ added: r.added,
86
+ refreshed: r.refreshed,
87
+ alreadyOk: r.alreadyOk,
88
+ path: r.hookFilePath,
89
+ });
90
+ }
91
+ else {
92
+ log.debug('hooks already up-to-date', { added: r.added, refreshed: r.refreshed, alreadyOk: r.alreadyOk });
93
+ }
94
+ }
95
+ catch (e) {
96
+ // Don't fail boot — operator can still drive Claude; just log so
97
+ // they see hooks aren't capturing.
98
+ log.warn('install-hooks failed', { error: e?.message ?? String(e) });
99
+ }
100
+ // Layer the session-id source: explicit env var > on-disk persisted
101
+ // file > null (fresh). Persisting across restarts is what stops a
102
+ // cold `claude` boot in the same project from minting a duplicate
103
+ // session row with a sibling UUID under the same routing name.
104
+ if (!config.reuseSessionId) {
105
+ const persisted = loadPersistedSessionId(cwd);
106
+ if (persisted) {
107
+ log.info('reusing persisted session id', { sessionId: persisted });
108
+ config = { ...config, reuseSessionId: persisted };
109
+ }
110
+ }
111
+ else {
112
+ log.info('reusing session id from env override', { sessionId: config.reuseSessionId });
113
+ }
72
114
  // Open the channel-side WS to hub.
73
115
  const client = new ChannelClient(config, {
74
116
  onWelcome: (m) => {
@@ -77,6 +119,15 @@ async function main() {
77
119
  routingName: m.routingName,
78
120
  channelToken: m.channelTokenName,
79
121
  });
122
+ // Persist the hub-issued session id so the NEXT cold boot of
123
+ // this MCP rebinds the same row instead of minting a sibling
124
+ // (same routing name, different UUID — class of bug we hit
125
+ // before this was wired up).
126
+ savePersistedSession(cwd, {
127
+ sessionId: m.sessionId,
128
+ routingName: m.routingName,
129
+ hubUrl: config.hubUrl,
130
+ });
80
131
  // Sidecar — Phase B hooks read this. The hub URL on the sidecar
81
132
  // is the HTTP form (hooks POST over HTTPS, not WS).
82
133
  const httpHubUrl = config.hubUrl.replace(/^ws/i, 'http');
package/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * Install/maintain .claude/settings.json + .claude/hooks/clawborrator-
3
+ * tail.mjs for the project at `cwd`. Returns a summary describing what
4
+ * changed; useful for boot-time logging.
5
+ */
6
+ export declare function installHooks(cwd: string): {
7
+ hookFileWritten: boolean;
8
+ settingsWritten: boolean;
9
+ added: number;
10
+ refreshed: number;
11
+ alreadyOk: number;
12
+ hookFilePath: string;
13
+ };
@@ -0,0 +1,139 @@
1
+ // Self-installer for Claude Code hook config + the bundled hook
2
+ // entry. Called once per long-lived MCP startup. Idempotent —
3
+ // touches files only when the desired state differs from what's on
4
+ // disk, so re-launches don't churn mtimes or git diffs.
5
+ //
6
+ // Two artifacts maintained:
7
+ // 1. <cwd>/.claude/hooks/clawborrator-tail.mjs — bytewise copy of
8
+ // this package's bundled dist-hook/clawborrator-tail.mjs. Hooks
9
+ // run `node` against this path so per-hook latency is just
10
+ // Node startup, not an npx + registry round-trip.
11
+ // 2. <cwd>/.claude/settings.json — 12 hook entries (one per
12
+ // Claude-Code hook name), each invoking the local .mjs above.
13
+ // We tag every entry with a #clawborrator-hook sentinel so we
14
+ // can detect + refresh our own entries without disturbing
15
+ // anything else the operator added.
16
+ import { readFileSync, writeFileSync, existsSync, mkdirSync, chmodSync } from 'node:fs';
17
+ import { resolve, dirname } from 'node:path';
18
+ import { fileURLToPath } from 'node:url';
19
+ import { log } from './log.js';
20
+ const __dirname = dirname(fileURLToPath(import.meta.url));
21
+ const HOOK_NAMES = [
22
+ 'SessionStart',
23
+ 'SessionEnd',
24
+ 'UserPromptSubmit',
25
+ 'PreToolUse',
26
+ 'PostToolUse',
27
+ 'PostToolUseFailure',
28
+ 'TaskCreated',
29
+ 'SubagentStart',
30
+ 'SubagentStop',
31
+ 'TaskCompleted',
32
+ 'Stop',
33
+ 'Notification',
34
+ ];
35
+ const TAG = 'clawborrator-hook';
36
+ function isOurHook(h) {
37
+ return h.type === 'command' && h.command.includes(`#${TAG}`);
38
+ }
39
+ function hookCommand(name) {
40
+ // Hooks run with cwd = project root. Quoting the path keeps Windows
41
+ // paths with spaces working.
42
+ return `node ".claude/hooks/clawborrator-tail.mjs" ${name} #${TAG}`;
43
+ }
44
+ // Find the bundled dist-hook/clawborrator-tail.mjs that ships next
45
+ // to this compiled module. Compiled __dirname is .../dist or
46
+ // .../dist-bundled depending on the build flavor; the bundle lives
47
+ // alongside at .../dist-hook/.
48
+ function findBundledHookFile() {
49
+ const candidates = [
50
+ resolve(__dirname, '..', 'dist-hook', 'clawborrator-tail.mjs'),
51
+ ];
52
+ for (const c of candidates) {
53
+ if (existsSync(c))
54
+ return c;
55
+ }
56
+ return null;
57
+ }
58
+ /**
59
+ * Install/maintain .claude/settings.json + .claude/hooks/clawborrator-
60
+ * tail.mjs for the project at `cwd`. Returns a summary describing what
61
+ * changed; useful for boot-time logging.
62
+ */
63
+ export function installHooks(cwd) {
64
+ const claudeDir = resolve(cwd, '.claude');
65
+ const hooksDir = resolve(claudeDir, 'hooks');
66
+ const hookFile = resolve(hooksDir, 'clawborrator-tail.mjs');
67
+ const settings = resolve(claudeDir, 'settings.json');
68
+ const bundleSource = findBundledHookFile();
69
+ if (!bundleSource) {
70
+ log.warn('install-hooks: bundled hook file not found in this package; skipping');
71
+ return { hookFileWritten: false, settingsWritten: false, added: 0, refreshed: 0, alreadyOk: 0, hookFilePath: hookFile };
72
+ }
73
+ if (!existsSync(claudeDir))
74
+ mkdirSync(claudeDir, { recursive: true });
75
+ if (!existsSync(hooksDir))
76
+ mkdirSync(hooksDir, { recursive: true });
77
+ // 1) Copy the bundled .mjs only if its bytes differ from what's
78
+ // already on disk. Compare exact bytes — cheaper than hashing
79
+ // and good enough for files this small.
80
+ const bundleBytes = readFileSync(bundleSource);
81
+ let hookFileWritten = false;
82
+ if (!existsSync(hookFile) || !readFileSync(hookFile).equals(bundleBytes)) {
83
+ writeFileSync(hookFile, bundleBytes);
84
+ try {
85
+ chmodSync(hookFile, 0o755);
86
+ }
87
+ catch { /* Windows */ }
88
+ hookFileWritten = true;
89
+ }
90
+ // 2) Read existing settings.json (tolerate missing/empty).
91
+ let s = {};
92
+ let originalText = '';
93
+ if (existsSync(settings)) {
94
+ try {
95
+ originalText = readFileSync(settings, 'utf8');
96
+ if (originalText.trim())
97
+ s = JSON.parse(originalText);
98
+ }
99
+ catch (e) {
100
+ log.warn('install-hooks: settings.json unparseable, leaving alone', { error: e?.message ?? String(e) });
101
+ return { hookFileWritten, settingsWritten: false, added: 0, refreshed: 0, alreadyOk: 0, hookFilePath: hookFile };
102
+ }
103
+ }
104
+ if (!s.hooks)
105
+ s.hooks = {};
106
+ let added = 0, refreshed = 0, alreadyOk = 0;
107
+ for (const name of HOOK_NAMES) {
108
+ const arr = (s.hooks[name] ??= []);
109
+ let entry = arr.find((e) => (e.matcher ?? '.*') === '.*');
110
+ if (!entry) {
111
+ entry = { matcher: '.*', hooks: [] };
112
+ arr.push(entry);
113
+ }
114
+ const desiredCmd = hookCommand(name);
115
+ const existingIdx = entry.hooks.findIndex(isOurHook);
116
+ if (existingIdx >= 0) {
117
+ if (entry.hooks[existingIdx].command !== desiredCmd) {
118
+ entry.hooks[existingIdx] = { type: 'command', command: desiredCmd };
119
+ refreshed++;
120
+ }
121
+ else {
122
+ alreadyOk++;
123
+ }
124
+ }
125
+ else {
126
+ entry.hooks.push({ type: 'command', command: desiredCmd });
127
+ added++;
128
+ }
129
+ }
130
+ // 3) Write only if the serialized form changed.
131
+ const newText = JSON.stringify(s, null, 2) + '\n';
132
+ let settingsWritten = false;
133
+ if (newText !== originalText) {
134
+ writeFileSync(settings, newText);
135
+ settingsWritten = true;
136
+ }
137
+ return { hookFileWritten, settingsWritten, added, refreshed, alreadyOk, hookFilePath: hookFile };
138
+ }
139
+ //# sourceMappingURL=install-hooks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"install-hooks.js","sourceRoot":"","sources":["../src/install-hooks.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ /**
2
+ * Read the persisted session UUID for `cwd`. Returns null if the file
3
+ * is missing, unreadable, malformed, or contains a non-UUID — i.e.
4
+ * any failure mode we'd rather treat as "no persisted session" than
5
+ * as a fatal error. Worst case we mint a fresh session id; the new
6
+ * session.json on welcome supersedes the bad one.
7
+ */
8
+ export declare function loadPersistedSessionId(cwd: string): string | null;
9
+ /**
10
+ * Write the session.json after a successful welcome. Also drops a
11
+ * sibling .gitignore on first creation so the dir as a whole stays
12
+ * out of source control.
13
+ */
14
+ export declare function savePersistedSession(cwd: string, info: {
15
+ sessionId: string;
16
+ routingName?: string;
17
+ hubUrl?: string;
18
+ }): void;
19
+ /**
20
+ * Delete the persisted session.json. Currently unused — kept for
21
+ * symmetry / future operator-driven `claw session reset` flows.
22
+ */
23
+ export declare function deletePersistedSession(cwd: string): void;
@@ -0,0 +1,91 @@
1
+ // Persist the hub-issued session UUID across MCP process restarts so a
2
+ // fresh `claude` boot in the same project rebinds to the existing
3
+ // session row instead of minting a sibling row with the same routing
4
+ // name. This is what eliminates the "@driver appears 5 times in
5
+ // list_peers / session ls" duplicate-row class of bug.
6
+ //
7
+ // Storage shape:
8
+ // <cwd>/.claude/clawborrator/session.json
9
+ // {
10
+ // "sessionId": "<uuid>",
11
+ // "routingName": "@<slug>",
12
+ // "hubUrl": "wss://...",
13
+ // "writtenAt": "ISO-8601"
14
+ // }
15
+ //
16
+ // Plus a sibling `.gitignore` ("*\n") inside the same directory so the
17
+ // session file (which contains nothing secret, but is per-machine
18
+ // runtime state) never leaks into commits.
19
+ import { readFileSync, writeFileSync, existsSync, mkdirSync, unlinkSync } from 'node:fs';
20
+ import { resolve } from 'node:path';
21
+ import { log } from './log.js';
22
+ const REL_DIR = '.claude/clawborrator';
23
+ const REL_FILE = '.claude/clawborrator/session.json';
24
+ const REL_GI = '.claude/clawborrator/.gitignore';
25
+ const UUID_RE = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
26
+ /**
27
+ * Read the persisted session UUID for `cwd`. Returns null if the file
28
+ * is missing, unreadable, malformed, or contains a non-UUID — i.e.
29
+ * any failure mode we'd rather treat as "no persisted session" than
30
+ * as a fatal error. Worst case we mint a fresh session id; the new
31
+ * session.json on welcome supersedes the bad one.
32
+ */
33
+ export function loadPersistedSessionId(cwd) {
34
+ const path = resolve(cwd, REL_FILE);
35
+ if (!existsSync(path))
36
+ return null;
37
+ try {
38
+ const raw = readFileSync(path, 'utf8');
39
+ const parsed = JSON.parse(raw);
40
+ if (typeof parsed.sessionId === 'string' && UUID_RE.test(parsed.sessionId)) {
41
+ return parsed.sessionId;
42
+ }
43
+ log.warn('persisted-session: invalid sessionId, ignoring', { path });
44
+ return null;
45
+ }
46
+ catch (e) {
47
+ log.warn('persisted-session: read failed', { path, error: e?.message ?? String(e) });
48
+ return null;
49
+ }
50
+ }
51
+ /**
52
+ * Write the session.json after a successful welcome. Also drops a
53
+ * sibling .gitignore on first creation so the dir as a whole stays
54
+ * out of source control.
55
+ */
56
+ export function savePersistedSession(cwd, info) {
57
+ const dir = resolve(cwd, REL_DIR);
58
+ const path = resolve(cwd, REL_FILE);
59
+ const gitignore = resolve(cwd, REL_GI);
60
+ try {
61
+ if (!existsSync(dir))
62
+ mkdirSync(dir, { recursive: true });
63
+ if (!existsSync(gitignore))
64
+ writeFileSync(gitignore, '*\n', 'utf8');
65
+ const body = {
66
+ sessionId: info.sessionId,
67
+ routingName: info.routingName,
68
+ hubUrl: info.hubUrl,
69
+ writtenAt: new Date().toISOString(),
70
+ };
71
+ writeFileSync(path, JSON.stringify(body, null, 2) + '\n', 'utf8');
72
+ }
73
+ catch (e) {
74
+ log.warn('persisted-session: write failed', { path, error: e?.message ?? String(e) });
75
+ }
76
+ }
77
+ /**
78
+ * Delete the persisted session.json. Currently unused — kept for
79
+ * symmetry / future operator-driven `claw session reset` flows.
80
+ */
81
+ export function deletePersistedSession(cwd) {
82
+ const path = resolve(cwd, REL_FILE);
83
+ try {
84
+ if (existsSync(path))
85
+ unlinkSync(path);
86
+ }
87
+ catch (e) {
88
+ log.warn('persisted-session: delete failed', { path, error: e?.message ?? String(e) });
89
+ }
90
+ }
91
+ //# sourceMappingURL=persisted-session.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"persisted-session.js","sourceRoot":"","sources":["../src/persisted-session.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "clawborrator-mcp",
3
- "version": "0.0.2",
3
+ "version": "0.0.4",
4
4
  "type": "module",
5
5
  "description": "clawborrator channel for hub_v1 — MCP server that connects Claude Code to a hub over WebSocket, with hooks for activity capture and tools for cross-session routing.",
6
6
  "license": "MIT",