clawborrator-mcp 0.0.1
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/README.md +110 -0
- package/bin/clawborrator-mcp +5 -0
- package/dist/config.d.ts +6 -0
- package/dist/config.js +22 -0
- package/dist/config.js.map +1 -0
- package/dist/hook.d.ts +1 -0
- package/dist/hook.js +250 -0
- package/dist/hook.js.map +1 -0
- package/dist/inbox.d.ts +9 -0
- package/dist/inbox.js +55 -0
- package/dist/inbox.js.map +1 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +140 -0
- package/dist/index.js.map +1 -0
- package/dist/log.d.ts +6 -0
- package/dist/log.js +23 -0
- package/dist/log.js.map +1 -0
- package/dist/sidecar.d.ts +13 -0
- package/dist/sidecar.js +67 -0
- package/dist/sidecar.js.map +1 -0
- package/dist/tools/index.d.ts +98 -0
- package/dist/tools/index.js +163 -0
- package/dist/tools/index.js.map +1 -0
- package/dist/transcript.d.ts +21 -0
- package/dist/transcript.js +212 -0
- package/dist/transcript.js.map +1 -0
- package/dist/ws-client.d.ts +148 -0
- package/dist/ws-client.js +196 -0
- package/dist/ws-client.js.map +1 -0
- package/package.json +54 -0
package/README.md
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
# clawborrator-mcp (channel_v1)
|
|
2
|
+
|
|
3
|
+
MCP server that connects each running Claude Code instance to a
|
|
4
|
+
[`hub_v1`](https://github.com/clawborrator/hub_v1) over WebSocket.
|
|
5
|
+
Companion to the hub. Designed to be invoked by Claude Code via
|
|
6
|
+
`.mcp.json`; runs as both a long-lived stdio MCP server AND a
|
|
7
|
+
short-lived hook spawn (selected by the `--hook=<HookName>` CLI flag).
|
|
8
|
+
|
|
9
|
+
> **Status: dev-mode-only.** Connect to a local hub at `ws://localhost:8787`.
|
|
10
|
+
> Production deployment is a future concern.
|
|
11
|
+
>
|
|
12
|
+
> Design context: [`hub/design/IMPL-PLAN-1-CHANNEL-V1-FRESH-START.md`](https://github.com/clawborrator/hub/blob/main/design/IMPL-PLAN-1-CHANNEL-V1-FRESH-START.md).
|
|
13
|
+
|
|
14
|
+
---
|
|
15
|
+
|
|
16
|
+
## Configuration
|
|
17
|
+
|
|
18
|
+
Set in your project's `.mcp.json`:
|
|
19
|
+
|
|
20
|
+
```json
|
|
21
|
+
{
|
|
22
|
+
"mcpServers": {
|
|
23
|
+
"clawborrator": {
|
|
24
|
+
"command": "npx",
|
|
25
|
+
"args": ["-y", "clawborrator-mcp"],
|
|
26
|
+
"env": {
|
|
27
|
+
"CLAWBORRATOR_HUB_URL": "ws://localhost:8787",
|
|
28
|
+
"CLAWBORRATOR_TOKEN": "ck_live_…"
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
| Env var | Required | Notes |
|
|
36
|
+
|---|---|---|
|
|
37
|
+
| `CLAWBORRATOR_HUB_URL` | yes | `ws://…` or `wss://…`; no trailing slash |
|
|
38
|
+
| `CLAWBORRATOR_TOKEN` | yes | Channel token (`ck_live_…`) minted via `claw token mint --kind=channel` |
|
|
39
|
+
| `CLAWBORRATOR_REUSE_SESSION_ID` | no | Opt-in: reconnect rebinds to a known session id rather than creating a fresh one |
|
|
40
|
+
| `CLAWBORRATOR_LOG_LEVEL` | no | `debug`, `info`, `warn`, `error`; default `info` |
|
|
41
|
+
|
|
42
|
+
Get the snippet pre-filled with the right URL + token via:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
claw token mint --kind=channel --name=mbp --mcp-snippet
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
---
|
|
49
|
+
|
|
50
|
+
## What it does
|
|
51
|
+
|
|
52
|
+
**Long-lived MCP path** (default invocation):
|
|
53
|
+
1. Reads env config; loads channel token.
|
|
54
|
+
2. Opens WSS to `<HUB_URL>/channel` with `Authorization: Bearer <CHANNEL_TOKEN>`.
|
|
55
|
+
3. Sends `register` with host / cwd / pid / version; receives `welcome` with sessionId + routingName.
|
|
56
|
+
4. Writes `<cwd>/.claude/clawborrator.session.json` (mode 0600) so per-event hook spawns can find the active session.
|
|
57
|
+
5. Maintains the WS with heartbeat ping/pong; reconnects with exponential backoff (1s/2s/5s/15s/30s/60s).
|
|
58
|
+
6. Listens for hub-side messages: `prompt` (cross-session route), `permission_response`, `peers_update`, `bye`, `error`.
|
|
59
|
+
7. On clean shutdown (SIGINT/SIGTERM/exit), deletes the sidecar.
|
|
60
|
+
|
|
61
|
+
**Short-lived hook path** (`--hook=<HookName>` flag):
|
|
62
|
+
1. Reads JSON payload from stdin (Claude Code's hook protocol).
|
|
63
|
+
2. Locates the active sidecar (walks up from cwd looking for `.claude/clawborrator.session.json`).
|
|
64
|
+
3. Maps the hook name to a clawborrator event (e.g. `PreToolUse` → `tail/PreToolUse`, `UserPromptSubmit` → `chat/prompt`).
|
|
65
|
+
4. POSTs to `<HUB_URL>/api/channel/event` with the channel token from the sidecar.
|
|
66
|
+
5. Echoes stdin to stdout so Claude's hook chain stays intact.
|
|
67
|
+
6. Exits cleanly even if the hub is unreachable — never breaks the operator's actual Claude flow.
|
|
68
|
+
|
|
69
|
+
Hooks are installed with `claw session init` from inside a project — see hub_v1 README.
|
|
70
|
+
|
|
71
|
+
---
|
|
72
|
+
|
|
73
|
+
## Tools exposed to Claude
|
|
74
|
+
|
|
75
|
+
v1 ships an empty MCP tool list. The hooks-based event firehose
|
|
76
|
+
covers chat + tail event capture without any Claude-side tool calls.
|
|
77
|
+
|
|
78
|
+
Phase D adds these:
|
|
79
|
+
- `reply({ chat_id, text })` — Claude posts a tagged final reply
|
|
80
|
+
- `list_peers()` — Claude discovers other operator sessions
|
|
81
|
+
- `route_to_peer({ peer, prompt, mode })` — Claude routes a question
|
|
82
|
+
- `probe_peers({ prompt, peers? })` — Claude fan-out probes
|
|
83
|
+
|
|
84
|
+
For now, operators initiate routing via `claw route` / `claw probe`.
|
|
85
|
+
|
|
86
|
+
---
|
|
87
|
+
|
|
88
|
+
## Phases
|
|
89
|
+
|
|
90
|
+
- **Phase A** (✓): connect / register / heartbeat / reconnect
|
|
91
|
+
- **Phase B** (✓): hooks + event forwarding via sidecar
|
|
92
|
+
- **Phase C** (✓): bidirectional permission relay protocol (channel
|
|
93
|
+
→ hub → operator → back). Hook IPC for actually delivering decisions
|
|
94
|
+
into a blocked PreToolUse hook is upcoming.
|
|
95
|
+
- **Phase D**: MCP tools (above)
|
|
96
|
+
|
|
97
|
+
---
|
|
98
|
+
|
|
99
|
+
## Local dev (linked to a sibling hub_v1 checkout)
|
|
100
|
+
|
|
101
|
+
```bash
|
|
102
|
+
npm install
|
|
103
|
+
npm run build
|
|
104
|
+
npm link
|
|
105
|
+
|
|
106
|
+
# verify the binary is on PATH
|
|
107
|
+
clawborrator-mcp --hook=PreToolUse < /dev/null # exits cleanly with no sidecar
|
|
108
|
+
```
|
|
109
|
+
|
|
110
|
+
When `claude` runs in a folder whose `.mcp.json` references `clawborrator-mcp`, npm/npx resolves it to your linked build.
|
package/dist/config.d.ts
ADDED
package/dist/config.js
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// Read + validate the env-var configuration the MCP needs to connect.
|
|
2
|
+
// Mirrors the shape documented in the channel_v1 design doc §3.
|
|
3
|
+
export function loadConfig() {
|
|
4
|
+
const hubUrl = process.env.CLAWBORRATOR_HUB_URL?.trim();
|
|
5
|
+
const token = process.env.CLAWBORRATOR_TOKEN?.trim();
|
|
6
|
+
if (!hubUrl)
|
|
7
|
+
throw new Error('CLAWBORRATOR_HUB_URL is required');
|
|
8
|
+
if (!token)
|
|
9
|
+
throw new Error('CLAWBORRATOR_TOKEN is required');
|
|
10
|
+
if (!hubUrl.startsWith('ws://') && !hubUrl.startsWith('wss://')) {
|
|
11
|
+
throw new Error(`CLAWBORRATOR_HUB_URL must be ws:// or wss://, got: ${hubUrl}`);
|
|
12
|
+
}
|
|
13
|
+
if (!token.startsWith('ck_live_')) {
|
|
14
|
+
throw new Error(`CLAWBORRATOR_TOKEN must start with ck_live_`);
|
|
15
|
+
}
|
|
16
|
+
return {
|
|
17
|
+
hubUrl: hubUrl.replace(/\/$/, ''),
|
|
18
|
+
token,
|
|
19
|
+
reuseSessionId: process.env.CLAWBORRATOR_REUSE_SESSION_ID?.trim() || null,
|
|
20
|
+
};
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,sEAAsE;AACtE,gEAAgE;AAQhE,MAAM,UAAU,UAAU;IACxB,MAAM,MAAM,GAAG,OAAO,CAAC,GAAG,CAAC,oBAAoB,EAAE,IAAI,EAAE,CAAC;IACxD,MAAM,KAAK,GAAI,OAAO,CAAC,GAAG,CAAC,kBAAkB,EAAE,IAAI,EAAE,CAAC;IACtD,IAAI,CAAC,MAAM;QAAE,MAAM,IAAI,KAAK,CAAC,kCAAkC,CAAC,CAAC;IACjE,IAAI,CAAC,KAAK;QAAG,MAAM,IAAI,KAAK,CAAC,gCAAgC,CAAC,CAAC;IAC/D,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,QAAQ,CAAC,EAAE,CAAC;QAChE,MAAM,IAAI,KAAK,CAAC,sDAAsD,MAAM,EAAE,CAAC,CAAC;IAClF,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,UAAU,CAAC,UAAU,CAAC,EAAE,CAAC;QAClC,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAC;IACjE,CAAC;IACD,OAAO;QACL,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC;QACjC,KAAK;QACL,cAAc,EAAE,OAAO,CAAC,GAAG,CAAC,6BAA6B,EAAE,IAAI,EAAE,IAAI,IAAI;KAC1E,CAAC;AACJ,CAAC"}
|
package/dist/hook.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function runHook(hookName: string): Promise<void>;
|
package/dist/hook.js
ADDED
|
@@ -0,0 +1,250 @@
|
|
|
1
|
+
// Hook entry point. Spawned by Claude Code per `.claude/settings.json`
|
|
2
|
+
// like:
|
|
3
|
+
//
|
|
4
|
+
// { "type": "command", "command": "npx clawborrator-mcp --hook=PreToolUse" }
|
|
5
|
+
//
|
|
6
|
+
// The hook receives the JSON payload on stdin. We:
|
|
7
|
+
// 1. Read stdin to EOF
|
|
8
|
+
// 2. Locate the sidecar in the cwd (or walk up parents)
|
|
9
|
+
// 3. Map the hook name to a clawborrator event kind+type
|
|
10
|
+
// 4. Enrich Stop / SubagentStop with assistant_text (final answer)
|
|
11
|
+
// from the transcript JSONL
|
|
12
|
+
// 5. For PreToolUse, ship 0..N chat/assistant_text events for any
|
|
13
|
+
// "let me check X" running commentary Claude wrote in the same
|
|
14
|
+
// assistant message before this tool_use, plus a placeholder
|
|
15
|
+
// when extended thinking happened but the plaintext was stripped
|
|
16
|
+
// from disk
|
|
17
|
+
// 6. POST /api/channel/event with the channel token from the sidecar
|
|
18
|
+
// 7. Echo stdin to stdout so Claude's hook chain stays intact
|
|
19
|
+
import { findSidecar } from './sidecar.js';
|
|
20
|
+
import { log } from './log.js';
|
|
21
|
+
import { readTranscriptMessages, messageContainsToolUse, extractTextBlocksBeforeToolUse, hasThinkingBlocksBeforeToolUse, extractFromLastAssistantMessage, extractFinalAnswerFromTranscript, DEFAULT_TAIL_BYTES, } from './transcript.js';
|
|
22
|
+
// Mirrors the install-hooks set from the old clawborrator-channel
|
|
23
|
+
// package so the remote viewer has the same coverage of Claude Code's
|
|
24
|
+
// hook surface.
|
|
25
|
+
const HOOK_TO_EVENT = {
|
|
26
|
+
UserPromptSubmit: { kind: 'chat', type: 'prompt' },
|
|
27
|
+
PreToolUse: { kind: 'tail', type: 'PreToolUse' },
|
|
28
|
+
PostToolUse: { kind: 'tail', type: 'PostToolUse' },
|
|
29
|
+
PostToolUseFailure: { kind: 'tail', type: 'PostToolUseFailure' },
|
|
30
|
+
Stop: { kind: 'tail', type: 'Stop' },
|
|
31
|
+
Notification: { kind: 'tail', type: 'Notification' },
|
|
32
|
+
SessionStart: { kind: 'tail', type: 'SessionStart' },
|
|
33
|
+
SessionEnd: { kind: 'tail', type: 'SessionEnd' },
|
|
34
|
+
TaskCreated: { kind: 'tail', type: 'TaskCreated' },
|
|
35
|
+
SubagentStart: { kind: 'tail', type: 'SubagentStart' },
|
|
36
|
+
SubagentStop: { kind: 'tail', type: 'SubagentStop' },
|
|
37
|
+
TaskCompleted: { kind: 'tail', type: 'TaskCompleted' },
|
|
38
|
+
};
|
|
39
|
+
// Tools whose pre-text we DON'T ship as AssistantText. The clawborrator
|
|
40
|
+
// reply tool already routes the user-facing answer over the WS — pre-
|
|
41
|
+
// reply text from the model is nearly identical and would render as a
|
|
42
|
+
// duplicate row in chat.
|
|
43
|
+
const TOOLS_SKIPPED_FOR_PRE_TEXT = new Set([
|
|
44
|
+
'mcp__clawborrator__reply',
|
|
45
|
+
]);
|
|
46
|
+
async function readStdin() {
|
|
47
|
+
return new Promise((res) => {
|
|
48
|
+
let buf = '';
|
|
49
|
+
process.stdin.setEncoding('utf8');
|
|
50
|
+
process.stdin.on('data', (chunk) => { buf += chunk; });
|
|
51
|
+
process.stdin.on('end', () => res(buf));
|
|
52
|
+
process.stdin.on('close', () => res(buf));
|
|
53
|
+
});
|
|
54
|
+
}
|
|
55
|
+
async function postEvent(sidecar, body, timeoutMs) {
|
|
56
|
+
const ctl = new AbortController();
|
|
57
|
+
const timer = setTimeout(() => ctl.abort(), timeoutMs);
|
|
58
|
+
try {
|
|
59
|
+
const res = await fetch(`${sidecar.hubUrl}/api/channel/event`, {
|
|
60
|
+
method: 'POST',
|
|
61
|
+
headers: {
|
|
62
|
+
'Authorization': `Bearer ${sidecar.channelToken}`,
|
|
63
|
+
'Content-Type': 'application/json',
|
|
64
|
+
},
|
|
65
|
+
body: JSON.stringify(body),
|
|
66
|
+
signal: ctl.signal,
|
|
67
|
+
});
|
|
68
|
+
if (!res.ok) {
|
|
69
|
+
const text = await res.text().catch(() => '');
|
|
70
|
+
log.warn('hub rejected event', { kind: body.kind, type: body.type, status: res.status, body: text.slice(0, 240) });
|
|
71
|
+
return false;
|
|
72
|
+
}
|
|
73
|
+
return true;
|
|
74
|
+
}
|
|
75
|
+
catch (e) {
|
|
76
|
+
log.warn('event POST failed', { kind: body.kind, type: body.type, error: e?.message ?? String(e) });
|
|
77
|
+
return false;
|
|
78
|
+
}
|
|
79
|
+
finally {
|
|
80
|
+
clearTimeout(timer);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// Stop / SubagentStop: try to populate payload.assistant_text from
|
|
84
|
+
// (in order) last_assistant_message → existing payload fields →
|
|
85
|
+
// transcript tail. Mutates payload in place.
|
|
86
|
+
async function enrichStopAssistantText(payload, hookName) {
|
|
87
|
+
if (typeof payload.assistant_text === 'string' && payload.assistant_text.trim())
|
|
88
|
+
return;
|
|
89
|
+
const fromLAM = extractFromLastAssistantMessage(payload.last_assistant_message);
|
|
90
|
+
if (fromLAM) {
|
|
91
|
+
payload.assistant_text = fromLAM;
|
|
92
|
+
log.debug('stop: assistant_text from last_assistant_message', { chars: fromLAM.length });
|
|
93
|
+
return;
|
|
94
|
+
}
|
|
95
|
+
if (typeof payload.text === 'string' && payload.text.trim() ||
|
|
96
|
+
typeof payload.response === 'string' && payload.response.trim()) {
|
|
97
|
+
return; // a string-shaped variant is already there; let downstream use it
|
|
98
|
+
}
|
|
99
|
+
const transcriptPath = typeof payload.transcript_path === 'string' ? payload.transcript_path : '';
|
|
100
|
+
if (!transcriptPath) {
|
|
101
|
+
log.debug('stop: no transcript_path on payload, no assistant_text recoverable', { hookName });
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
// Sleep so CC has time to flush the just-finished assistant message
|
|
105
|
+
// to disk before we tail-read. Without this, on some CC versions the
|
|
106
|
+
// read returns the PRIOR turn's text, which would render the wrong
|
|
107
|
+
// reply on attached operators' TUI.
|
|
108
|
+
await new Promise((r) => setTimeout(r, 500));
|
|
109
|
+
const text = extractFinalAnswerFromTranscript(transcriptPath, DEFAULT_TAIL_BYTES);
|
|
110
|
+
if (text) {
|
|
111
|
+
payload.assistant_text = text;
|
|
112
|
+
log.info('stop: assistant_text extracted from transcript', { chars: text.length });
|
|
113
|
+
}
|
|
114
|
+
else {
|
|
115
|
+
log.debug('stop: transcript had no assistant-text block in tail window', { hookName, path: transcriptPath });
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
// PreToolUse: ship every text block Claude wrote in the same
|
|
119
|
+
// assistant message BEFORE this tool_use as its own chat/assistant_text
|
|
120
|
+
// event. If no text blocks but extended-thinking blocks were present
|
|
121
|
+
// (CC strips thinking plaintext on disk; only the signature survives),
|
|
122
|
+
// ship a single placeholder so the operator sees a "claude was
|
|
123
|
+
// thinking here" marker.
|
|
124
|
+
async function shipPreToolAssistantText(sidecar, payload) {
|
|
125
|
+
const transcriptPath = typeof payload.transcript_path === 'string' ? payload.transcript_path : '';
|
|
126
|
+
const toolUseId = String(payload.tool_use_id ?? payload.toolUseId ?? '');
|
|
127
|
+
const toolName = String(payload.tool_name ?? payload.toolName ?? '');
|
|
128
|
+
if (!transcriptPath || !toolUseId)
|
|
129
|
+
return;
|
|
130
|
+
if (TOOLS_SKIPPED_FOR_PRE_TEXT.has(toolName))
|
|
131
|
+
return;
|
|
132
|
+
// Race-retry: CC writes the assistant message that DECIDED the
|
|
133
|
+
// tool_use to the transcript ASYNC, so a fresh read right after the
|
|
134
|
+
// hook fires can miss it. Retry up to 4 times with 80ms delays.
|
|
135
|
+
let messages = readTranscriptMessages(transcriptPath, DEFAULT_TAIL_BYTES);
|
|
136
|
+
let foundTarget = messageContainsToolUse(messages, toolUseId);
|
|
137
|
+
let retries = 0;
|
|
138
|
+
while (!foundTarget && retries < 4) {
|
|
139
|
+
await new Promise((r) => setTimeout(r, 80));
|
|
140
|
+
messages = readTranscriptMessages(transcriptPath, DEFAULT_TAIL_BYTES);
|
|
141
|
+
foundTarget = messageContainsToolUse(messages, toolUseId);
|
|
142
|
+
retries++;
|
|
143
|
+
}
|
|
144
|
+
const blocks = extractTextBlocksBeforeToolUse(messages, toolUseId);
|
|
145
|
+
const hasThinking = blocks.length === 0 ? hasThinkingBlocksBeforeToolUse(messages, toolUseId) : false;
|
|
146
|
+
log.debug('PreToolUse extract', {
|
|
147
|
+
toolUseId: toolUseId.slice(0, 24),
|
|
148
|
+
messages: messages.length,
|
|
149
|
+
targetFound: foundTarget,
|
|
150
|
+
retries,
|
|
151
|
+
blocks: blocks.length,
|
|
152
|
+
placeholder: hasThinking,
|
|
153
|
+
});
|
|
154
|
+
// Monotonic timestamps so events sort chronologically on the hub
|
|
155
|
+
// (chat_events orders by ts; ties broken by id, but ts ordering is
|
|
156
|
+
// the human signal). We use ms epoch then convert to ISO.
|
|
157
|
+
const baseMs = Date.now();
|
|
158
|
+
const tsAt = (i) => new Date(baseMs + i).toISOString();
|
|
159
|
+
if (blocks.length > 0) {
|
|
160
|
+
// Fire all AssistantText POSTs in parallel — sequential with 600ms
|
|
161
|
+
// each could exceed CC's hook timeout on multi-block turns.
|
|
162
|
+
await Promise.all(blocks.map((text, i) => postEvent(sidecar, {
|
|
163
|
+
sessionId: sidecar.sessionId,
|
|
164
|
+
kind: 'chat',
|
|
165
|
+
type: 'assistant_text',
|
|
166
|
+
payload: { text, toolUseId },
|
|
167
|
+
ts: tsAt(i),
|
|
168
|
+
}, 800)));
|
|
169
|
+
}
|
|
170
|
+
else if (hasThinking) {
|
|
171
|
+
await postEvent(sidecar, {
|
|
172
|
+
sessionId: sidecar.sessionId,
|
|
173
|
+
kind: 'chat',
|
|
174
|
+
type: 'assistant_text',
|
|
175
|
+
payload: {
|
|
176
|
+
text: '(extended thinking — content not in transcript)',
|
|
177
|
+
toolUseId,
|
|
178
|
+
placeholder: true,
|
|
179
|
+
},
|
|
180
|
+
ts: tsAt(0),
|
|
181
|
+
}, 800);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
export async function runHook(hookName) {
|
|
185
|
+
const map = HOOK_TO_EVENT[hookName];
|
|
186
|
+
if (!map) {
|
|
187
|
+
log.warn('unknown hook name; skipping', { hookName });
|
|
188
|
+
process.exit(0);
|
|
189
|
+
}
|
|
190
|
+
const stdinRaw = await readStdin();
|
|
191
|
+
// Always echo stdin so Claude's hook chain sees the original payload.
|
|
192
|
+
if (stdinRaw)
|
|
193
|
+
process.stdout.write(stdinRaw);
|
|
194
|
+
let payload = {};
|
|
195
|
+
try {
|
|
196
|
+
if (stdinRaw.trim())
|
|
197
|
+
payload = JSON.parse(stdinRaw);
|
|
198
|
+
}
|
|
199
|
+
catch {
|
|
200
|
+
payload = { rawStdin: stdinRaw.slice(0, 2000) };
|
|
201
|
+
}
|
|
202
|
+
const sidecar = findSidecar(process.cwd());
|
|
203
|
+
if (!sidecar) {
|
|
204
|
+
log.warn('hook fired but no sidecar found — channel must not be running', { cwd: process.cwd() });
|
|
205
|
+
process.exit(0);
|
|
206
|
+
}
|
|
207
|
+
try {
|
|
208
|
+
if (hookName === 'Stop') {
|
|
209
|
+
// Real turn end — extract final answer + ship chat/reply so
|
|
210
|
+
// attached operators see Claude's response in the chat lane.
|
|
211
|
+
// The tail Stop event below marks the boundary.
|
|
212
|
+
await enrichStopAssistantText(payload, hookName);
|
|
213
|
+
const reply = typeof payload.assistant_text === 'string' ? payload.assistant_text.trim() : '';
|
|
214
|
+
if (reply) {
|
|
215
|
+
await postEvent(sidecar, {
|
|
216
|
+
sessionId: sidecar.sessionId,
|
|
217
|
+
kind: 'chat',
|
|
218
|
+
type: 'reply',
|
|
219
|
+
payload: { text: reply },
|
|
220
|
+
ts: new Date().toISOString(),
|
|
221
|
+
}, 2000);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
else if (hookName === 'SubagentStop') {
|
|
225
|
+
// A Task-tool subagent finished. NOT a final-answer event — the
|
|
226
|
+
// parent agent is still running and will fire its own Stop later.
|
|
227
|
+
// Some CC versions populate `last_assistant_message` with the
|
|
228
|
+
// subagent's INPUT prompt rather than its reply, which previously
|
|
229
|
+
// surfaced as a misleading chat/reply row. We still record the
|
|
230
|
+
// tail event below for activity-lane visibility, but skip the
|
|
231
|
+
// chat/reply ship entirely.
|
|
232
|
+
}
|
|
233
|
+
else if (hookName === 'PreToolUse') {
|
|
234
|
+
await shipPreToolAssistantText(sidecar, payload);
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
catch (e) {
|
|
238
|
+
log.warn('pre-event enrichment threw', { error: e?.message ?? String(e), hookName });
|
|
239
|
+
}
|
|
240
|
+
// Main hook event POST.
|
|
241
|
+
await postEvent(sidecar, {
|
|
242
|
+
sessionId: sidecar.sessionId,
|
|
243
|
+
kind: map.kind,
|
|
244
|
+
type: map.type,
|
|
245
|
+
payload,
|
|
246
|
+
ts: new Date().toISOString(),
|
|
247
|
+
}, 5000);
|
|
248
|
+
process.exit(0);
|
|
249
|
+
}
|
|
250
|
+
//# sourceMappingURL=hook.js.map
|
package/dist/hook.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"hook.js","sourceRoot":"","sources":["../src/hook.ts"],"names":[],"mappings":"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"}
|
package/dist/inbox.d.ts
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
interface InboxEntry {
|
|
2
|
+
chatId: string;
|
|
3
|
+
text: string;
|
|
4
|
+
}
|
|
5
|
+
export declare function enqueueRoutedPrompt(entry: InboxEntry): void;
|
|
6
|
+
export declare function tryDequeue(): InboxEntry | null;
|
|
7
|
+
export declare function awaitDequeue(maxWaitMs: number): Promise<InboxEntry | null>;
|
|
8
|
+
export declare function inboxSize(): number;
|
|
9
|
+
export {};
|
package/dist/inbox.js
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
// In-memory inbox for routed prompts arriving from the hub. The
|
|
2
|
+
// `await_routed_prompt` MCP tool reads from here.
|
|
3
|
+
//
|
|
4
|
+
// Why a queue rather than callback-driven: Claude Code can only see
|
|
5
|
+
// "messages" the operator types (or that the MCP returns from a tool
|
|
6
|
+
// call). To inject a routed prompt, the only mechanism we have today
|
|
7
|
+
// is for Claude to CALL a tool that returns the pending prompt as
|
|
8
|
+
// its result — Claude then treats the result as the next thing to
|
|
9
|
+
// answer.
|
|
10
|
+
//
|
|
11
|
+
// The convention in CLAUDE.md / the tool description is: at the
|
|
12
|
+
// start of each turn, Claude calls `await_routed_prompt({maxWaitMs:0})`.
|
|
13
|
+
// If the result has a non-null prompt, Claude answers by calling
|
|
14
|
+
// `reply({chat_id, text})` and skips its normal user-facing reply.
|
|
15
|
+
const queue = [];
|
|
16
|
+
let waiters = [];
|
|
17
|
+
export function enqueueRoutedPrompt(entry) {
|
|
18
|
+
// If a waiter is parked, hand off directly.
|
|
19
|
+
const w = waiters.shift();
|
|
20
|
+
if (w) {
|
|
21
|
+
w(entry);
|
|
22
|
+
return;
|
|
23
|
+
}
|
|
24
|
+
queue.push(entry);
|
|
25
|
+
}
|
|
26
|
+
export function tryDequeue() {
|
|
27
|
+
return queue.shift() ?? null;
|
|
28
|
+
}
|
|
29
|
+
export function awaitDequeue(maxWaitMs) {
|
|
30
|
+
const immediate = tryDequeue();
|
|
31
|
+
if (immediate || maxWaitMs <= 0) {
|
|
32
|
+
return Promise.resolve(immediate);
|
|
33
|
+
}
|
|
34
|
+
return new Promise((resolve) => {
|
|
35
|
+
let resolved = false;
|
|
36
|
+
let timer = null;
|
|
37
|
+
const settle = (entry) => {
|
|
38
|
+
if (resolved)
|
|
39
|
+
return;
|
|
40
|
+
resolved = true;
|
|
41
|
+
const i = waiters.indexOf(settle);
|
|
42
|
+
if (i >= 0)
|
|
43
|
+
waiters.splice(i, 1);
|
|
44
|
+
if (timer)
|
|
45
|
+
clearTimeout(timer);
|
|
46
|
+
resolve(entry);
|
|
47
|
+
};
|
|
48
|
+
waiters.push(settle);
|
|
49
|
+
timer = setTimeout(() => settle(null), maxWaitMs);
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
export function inboxSize() {
|
|
53
|
+
return queue.length;
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=inbox.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"inbox.js","sourceRoot":"","sources":["../src/inbox.ts"],"names":[],"mappings":"AAAA,gEAAgE;AAChE,kDAAkD;AAClD,EAAE;AACF,oEAAoE;AACpE,qEAAqE;AACrE,qEAAqE;AACrE,kEAAkE;AAClE,kEAAkE;AAClE,UAAU;AACV,EAAE;AACF,gEAAgE;AAChE,yEAAyE;AACzE,iEAAiE;AACjE,mEAAmE;AAOnE,MAAM,KAAK,GAAiB,EAAE,CAAC;AAC/B,IAAI,OAAO,GAA2C,EAAE,CAAC;AAEzD,MAAM,UAAU,mBAAmB,CAAC,KAAiB;IACnD,4CAA4C;IAC5C,MAAM,CAAC,GAAG,OAAO,CAAC,KAAK,EAAE,CAAC;IAC1B,IAAI,CAAC,EAAE,CAAC;QAAC,CAAC,CAAC,KAAK,CAAC,CAAC;QAAC,OAAO;IAAC,CAAC;IAC5B,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;AACpB,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,OAAO,KAAK,CAAC,KAAK,EAAE,IAAI,IAAI,CAAC;AAC/B,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,SAAiB;IAC5C,MAAM,SAAS,GAAG,UAAU,EAAE,CAAC;IAC/B,IAAI,SAAS,IAAI,SAAS,IAAI,CAAC,EAAE,CAAC;QAChC,OAAO,OAAO,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;IACpC,CAAC;IACD,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,IAAI,QAAQ,GAAG,KAAK,CAAC;QACrB,IAAI,KAAK,GAA0B,IAAI,CAAC;QACxC,MAAM,MAAM,GAAG,CAAC,KAAwB,EAAE,EAAE;YAC1C,IAAI,QAAQ;gBAAE,OAAO;YACrB,QAAQ,GAAG,IAAI,CAAC;YAChB,MAAM,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;YAClC,IAAI,CAAC,IAAI,CAAC;gBAAE,OAAO,CAAC,MAAM,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;YACjC,IAAI,KAAK;gBAAE,YAAY,CAAC,KAAK,CAAC,CAAC;YAC/B,OAAO,CAAC,KAAK,CAAC,CAAC;QACjB,CAAC,CAAC;QACF,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;QACrB,KAAK,GAAG,UAAU,CAAC,GAAG,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,EAAE,SAAS,CAAC,CAAC;IACpD,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,UAAU,SAAS;IACvB,OAAO,KAAK,CAAC,MAAM,CAAC;AACtB,CAAC"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
// MCP entrypoint. Phase A: open the WS to hub, register, log every
|
|
2
|
+
// inbound message to stderr. Subsequent phases will:
|
|
3
|
+
// - install hooks (Phase B) that turn into chat_event/tail_event sends
|
|
4
|
+
// - wire permission relay (Phase C)
|
|
5
|
+
// - register MCP tools (reply, list_peers, route_to_peer, probe_peers)
|
|
6
|
+
// for Claude to call (Phase D)
|
|
7
|
+
//
|
|
8
|
+
// In Phase A we still need the MCP transport open so Claude Code's
|
|
9
|
+
// MCP-discovery handshake succeeds; otherwise the user sees "MCP
|
|
10
|
+
// server failed to start." We register a no-op tool list — Claude
|
|
11
|
+
// gets an empty tools/list response and the WS work proceeds in the
|
|
12
|
+
// background.
|
|
13
|
+
import { hostname } from 'node:os';
|
|
14
|
+
import { Server } from '@modelcontextprotocol/sdk/server/index.js';
|
|
15
|
+
import { StdioServerTransport } from '@modelcontextprotocol/sdk/server/stdio.js';
|
|
16
|
+
import { ListToolsRequestSchema, CallToolRequestSchema } from '@modelcontextprotocol/sdk/types.js';
|
|
17
|
+
import { loadConfig } from './config.js';
|
|
18
|
+
import { ChannelClient } from './ws-client.js';
|
|
19
|
+
import { log } from './log.js';
|
|
20
|
+
import { runHook } from './hook.js';
|
|
21
|
+
import { writeSidecar, deleteSidecar } from './sidecar.js';
|
|
22
|
+
import { TOOL_DEFINITIONS, callTool } from './tools/index.js';
|
|
23
|
+
import { enqueueRoutedPrompt } from './inbox.js';
|
|
24
|
+
// Dispatch on --hook=<HookName> first; that's the short-lived spawn
|
|
25
|
+
// path Claude Code's hook system uses. Without it, fall through to
|
|
26
|
+
// the long-lived MCP stdio server.
|
|
27
|
+
const hookFlag = process.argv.find((a) => a.startsWith('--hook='));
|
|
28
|
+
if (hookFlag) {
|
|
29
|
+
const name = hookFlag.slice('--hook='.length);
|
|
30
|
+
runHook(name).catch((err) => {
|
|
31
|
+
log.error('hook fatal', { error: String(err) });
|
|
32
|
+
process.exit(0); // never fail the operator's actual Claude flow
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
else {
|
|
36
|
+
main().catch((err) => {
|
|
37
|
+
log.error('fatal', { error: String(err), stack: err?.stack });
|
|
38
|
+
process.exit(1);
|
|
39
|
+
});
|
|
40
|
+
}
|
|
41
|
+
async function main() {
|
|
42
|
+
let config;
|
|
43
|
+
try {
|
|
44
|
+
config = loadConfig();
|
|
45
|
+
}
|
|
46
|
+
catch (e) {
|
|
47
|
+
log.error('config invalid', { error: String(e) });
|
|
48
|
+
process.exit(2);
|
|
49
|
+
}
|
|
50
|
+
log.info('clawborrator-mcp starting', { hubUrl: config.hubUrl });
|
|
51
|
+
const cwd = process.cwd();
|
|
52
|
+
const host = hostname();
|
|
53
|
+
// Open the channel-side WS to hub.
|
|
54
|
+
const client = new ChannelClient(config, {
|
|
55
|
+
onWelcome: (m) => {
|
|
56
|
+
log.info('session ready', {
|
|
57
|
+
sessionId: m.sessionId,
|
|
58
|
+
routingName: m.routingName,
|
|
59
|
+
channelToken: m.channelTokenName,
|
|
60
|
+
});
|
|
61
|
+
// Sidecar — Phase B hooks read this. The hub URL on the sidecar
|
|
62
|
+
// is the HTTP form (hooks POST over HTTPS, not WS).
|
|
63
|
+
const httpHubUrl = config.hubUrl.replace(/^ws/i, 'http');
|
|
64
|
+
writeSidecar({
|
|
65
|
+
sessionId: m.sessionId,
|
|
66
|
+
routingName: m.routingName,
|
|
67
|
+
hubUrl: httpHubUrl,
|
|
68
|
+
channelToken: config.token,
|
|
69
|
+
host,
|
|
70
|
+
cwd,
|
|
71
|
+
writtenAt: new Date().toISOString(),
|
|
72
|
+
});
|
|
73
|
+
},
|
|
74
|
+
onPrompt: (m) => {
|
|
75
|
+
// A peer session routed a prompt to us. Push to the inbox so
|
|
76
|
+
// the next `await_routed_prompt` tool call can pick it up.
|
|
77
|
+
log.info('prompt received', { chatId: m.chatId, text: m.text });
|
|
78
|
+
enqueueRoutedPrompt({ chatId: m.chatId, text: m.text });
|
|
79
|
+
},
|
|
80
|
+
onPermissionResponse: (m) => {
|
|
81
|
+
// Phase C: the operator (or auto-expire) resolved a permission.
|
|
82
|
+
// We surface it in the log so operators running with
|
|
83
|
+
// CLAWBORRATOR_LOG_LEVEL=info can see decisions land. Real
|
|
84
|
+
// hook integration (where this decision routes back to a
|
|
85
|
+
// pending hook spawn) is a follow-on once we wire IPC between
|
|
86
|
+
// the long-lived MCP and the short-lived hook process.
|
|
87
|
+
log.info('permission resolved', {
|
|
88
|
+
requestId: m.requestId,
|
|
89
|
+
decision: m.decision,
|
|
90
|
+
message: m.message ?? null,
|
|
91
|
+
});
|
|
92
|
+
},
|
|
93
|
+
onError: (m) => {
|
|
94
|
+
log.error('hub rejected', { code: m.code, message: m.message });
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
client.connect();
|
|
98
|
+
// MCP stdio transport. Phase D ships the four routing tools.
|
|
99
|
+
const server = new Server({
|
|
100
|
+
name: 'clawborrator',
|
|
101
|
+
version: '0.0.1',
|
|
102
|
+
}, {
|
|
103
|
+
capabilities: {
|
|
104
|
+
tools: {},
|
|
105
|
+
},
|
|
106
|
+
});
|
|
107
|
+
// Track our session id so tools (and future use) can reference it.
|
|
108
|
+
// Set by the onWelcome handler above.
|
|
109
|
+
let toolCtxSessionId = null;
|
|
110
|
+
server.setRequestHandler(ListToolsRequestSchema, async () => ({
|
|
111
|
+
tools: TOOL_DEFINITIONS.map((t) => ({
|
|
112
|
+
name: t.name,
|
|
113
|
+
description: t.description,
|
|
114
|
+
inputSchema: t.inputSchema,
|
|
115
|
+
})),
|
|
116
|
+
}));
|
|
117
|
+
server.setRequestHandler(CallToolRequestSchema, async (req) => {
|
|
118
|
+
const args = (req.params.arguments ?? {});
|
|
119
|
+
return await callTool({ client, sessionId: toolCtxSessionId }, req.params.name, args);
|
|
120
|
+
});
|
|
121
|
+
void toolCtxSessionId;
|
|
122
|
+
const transport = new StdioServerTransport();
|
|
123
|
+
await server.connect(transport);
|
|
124
|
+
log.info('mcp transport connected');
|
|
125
|
+
// Clean shutdown on common signals so the WS goes away cleanly +
|
|
126
|
+
// sidecar gets removed so a stale file doesn't mislead future hooks.
|
|
127
|
+
for (const sig of ['SIGINT', 'SIGTERM']) {
|
|
128
|
+
process.on(sig, () => {
|
|
129
|
+
log.info('shutting down', { signal: sig });
|
|
130
|
+
client.stop();
|
|
131
|
+
deleteSidecar(cwd);
|
|
132
|
+
transport.close().catch(() => { });
|
|
133
|
+
setTimeout(() => process.exit(0), 200);
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
// Last-ditch sidecar cleanup. Even on uncaught exceptions, we'd
|
|
137
|
+
// rather not leave a stale file pointing at a dead WS.
|
|
138
|
+
process.on('exit', () => deleteSidecar(cwd));
|
|
139
|
+
}
|
|
140
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"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"}
|
package/dist/log.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
export declare const log: {
|
|
2
|
+
debug: (msg: string, fields?: Record<string, unknown>) => void;
|
|
3
|
+
info: (msg: string, fields?: Record<string, unknown>) => void;
|
|
4
|
+
warn: (msg: string, fields?: Record<string, unknown>) => void;
|
|
5
|
+
error: (msg: string, fields?: Record<string, unknown>) => void;
|
|
6
|
+
};
|