claws-code 0.8.0
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/.claude/commands/claws-auto.md +90 -0
- package/.claude/commands/claws-bin.md +28 -0
- package/.claude/commands/claws-cleanup.md +28 -0
- package/.claude/commands/claws-do.md +82 -0
- package/.claude/commands/claws-fix.md +40 -0
- package/.claude/commands/claws-goal.md +111 -0
- package/.claude/commands/claws-help.md +54 -0
- package/.claude/commands/claws-plan.md +103 -0
- package/.claude/commands/claws-report.md +29 -0
- package/.claude/commands/claws-status.md +37 -0
- package/.claude/commands/claws-update.md +32 -0
- package/.claude/commands/claws.md +64 -0
- package/.claude/rules/claws-default-behavior.md +76 -0
- package/.claude/settings.json +112 -0
- package/.claude/settings.local.json +19 -0
- package/.claude/skills/claws-auto-engine/SKILL.md +97 -0
- package/.claude/skills/claws-goal-tracker/SKILL.md +106 -0
- package/.claude/skills/claws-prompt-templates/SKILL.md +203 -0
- package/.claude/skills/claws-wave-lead/SKILL.md +126 -0
- package/.claude/skills/claws-wave-subworker/SKILL.md +60 -0
- package/CHANGELOG.md +1949 -0
- package/LICENSE +21 -0
- package/README.md +420 -0
- package/bin/cli.js +84 -0
- package/cli.js +223 -0
- package/docs/ARCHITECTURE.md +511 -0
- package/docs/event-protocol.md +588 -0
- package/docs/features.md +562 -0
- package/docs/guide.md +891 -0
- package/docs/index.html +716 -0
- package/docs/protocol.md +323 -0
- package/extension/.vscodeignore +15 -0
- package/extension/CHANGELOG.md +1906 -0
- package/extension/LICENSE +21 -0
- package/extension/README.md +137 -0
- package/extension/docs/features.md +424 -0
- package/extension/docs/protocol.md +197 -0
- package/extension/esbuild.mjs +25 -0
- package/extension/icon.png +0 -0
- package/extension/native/.metadata.json +10 -0
- package/extension/native/node-pty/LICENSE +69 -0
- package/extension/native/node-pty/README.md +165 -0
- package/extension/native/node-pty/lib/conpty_console_list_agent.js +16 -0
- package/extension/native/node-pty/lib/conpty_console_list_agent.js.map +1 -0
- package/extension/native/node-pty/lib/eventEmitter2.js +47 -0
- package/extension/native/node-pty/lib/eventEmitter2.js.map +1 -0
- package/extension/native/node-pty/lib/index.js +52 -0
- package/extension/native/node-pty/lib/index.js.map +1 -0
- package/extension/native/node-pty/lib/interfaces.js +7 -0
- package/extension/native/node-pty/lib/interfaces.js.map +1 -0
- package/extension/native/node-pty/lib/shared/conout.js +11 -0
- package/extension/native/node-pty/lib/shared/conout.js.map +1 -0
- package/extension/native/node-pty/lib/terminal.js +190 -0
- package/extension/native/node-pty/lib/terminal.js.map +1 -0
- package/extension/native/node-pty/lib/types.js +7 -0
- package/extension/native/node-pty/lib/types.js.map +1 -0
- package/extension/native/node-pty/lib/unixTerminal.js +346 -0
- package/extension/native/node-pty/lib/unixTerminal.js.map +1 -0
- package/extension/native/node-pty/lib/utils.js +39 -0
- package/extension/native/node-pty/lib/utils.js.map +1 -0
- package/extension/native/node-pty/lib/windowsConoutConnection.js +125 -0
- package/extension/native/node-pty/lib/windowsConoutConnection.js.map +1 -0
- package/extension/native/node-pty/lib/windowsPtyAgent.js +320 -0
- package/extension/native/node-pty/lib/windowsPtyAgent.js.map +1 -0
- package/extension/native/node-pty/lib/windowsTerminal.js +199 -0
- package/extension/native/node-pty/lib/windowsTerminal.js.map +1 -0
- package/extension/native/node-pty/lib/worker/conoutSocketWorker.js +22 -0
- package/extension/native/node-pty/lib/worker/conoutSocketWorker.js.map +1 -0
- package/extension/native/node-pty/package.json +64 -0
- package/extension/native/node-pty/prebuilds/darwin-arm64/pty.node +0 -0
- package/extension/native/node-pty/prebuilds/darwin-arm64/spawn-helper +0 -0
- package/extension/native/node-pty/prebuilds/darwin-x64/pty.node +0 -0
- package/extension/native/node-pty/prebuilds/darwin-x64/spawn-helper +0 -0
- package/extension/native/node-pty/prebuilds/win32-arm64/conpty/OpenConsole.exe +0 -0
- package/extension/native/node-pty/prebuilds/win32-arm64/conpty/conpty.dll +0 -0
- package/extension/native/node-pty/prebuilds/win32-arm64/conpty.node +0 -0
- package/extension/native/node-pty/prebuilds/win32-arm64/conpty_console_list.node +0 -0
- package/extension/native/node-pty/prebuilds/win32-arm64/pty.node +0 -0
- package/extension/native/node-pty/prebuilds/win32-arm64/winpty-agent.exe +0 -0
- package/extension/native/node-pty/prebuilds/win32-arm64/winpty.dll +0 -0
- package/extension/native/node-pty/prebuilds/win32-x64/conpty/OpenConsole.exe +0 -0
- package/extension/native/node-pty/prebuilds/win32-x64/conpty/conpty.dll +0 -0
- package/extension/native/node-pty/prebuilds/win32-x64/conpty.node +0 -0
- package/extension/native/node-pty/prebuilds/win32-x64/conpty_console_list.node +0 -0
- package/extension/native/node-pty/prebuilds/win32-x64/pty.node +0 -0
- package/extension/native/node-pty/prebuilds/win32-x64/winpty-agent.exe +0 -0
- package/extension/native/node-pty/prebuilds/win32-x64/winpty.dll +0 -0
- package/extension/package-lock.json +605 -0
- package/extension/package.json +343 -0
- package/extension/scripts/bundle-native.mjs +104 -0
- package/extension/scripts/deploy-dev.mjs +60 -0
- package/extension/src/ansi-strip.ts +52 -0
- package/extension/src/backends/vscode/claws-pty.ts +483 -0
- package/extension/src/backends/vscode/status-bar.ts +99 -0
- package/extension/src/backends/vscode/vscode-backend.ts +282 -0
- package/extension/src/capture-store.ts +125 -0
- package/extension/src/event-log.ts +629 -0
- package/extension/src/event-schemas.ts +478 -0
- package/extension/src/extension.js +492 -0
- package/extension/src/extension.ts +873 -0
- package/extension/src/lifecycle-engine.ts +60 -0
- package/extension/src/lifecycle-rules.ts +171 -0
- package/extension/src/lifecycle-store.ts +506 -0
- package/extension/src/peer-registry.ts +176 -0
- package/extension/src/pipeline-registry.ts +82 -0
- package/extension/src/platform.ts +64 -0
- package/extension/src/protocol.ts +532 -0
- package/extension/src/server-config.ts +98 -0
- package/extension/src/server.ts +2210 -0
- package/extension/src/task-registry.ts +51 -0
- package/extension/src/terminal-backend.ts +211 -0
- package/extension/src/terminal-manager.ts +395 -0
- package/extension/src/topic-registry.ts +70 -0
- package/extension/src/topic-utils.ts +46 -0
- package/extension/src/transport.ts +45 -0
- package/extension/src/uninstall-cleanup.ts +232 -0
- package/extension/src/wave-registry.ts +314 -0
- package/extension/src/websocket-transport.ts +153 -0
- package/extension/tsconfig.json +23 -0
- package/lib/capabilities.js +145 -0
- package/lib/dry-run.js +43 -0
- package/lib/install.js +1018 -0
- package/lib/mcp-setup.js +92 -0
- package/lib/platform.js +240 -0
- package/lib/preflight.js +152 -0
- package/lib/shell-hook.js +343 -0
- package/lib/uninstall.js +162 -0
- package/lib/verify.js +166 -0
- package/mcp_server.js +3529 -0
- package/package.json +48 -0
- package/rules/claws-default-behavior.md +72 -0
- package/scripts/_helpers/atomic-file.mjs +137 -0
- package/scripts/_helpers/fix-repair.js +64 -0
- package/scripts/_helpers/json-safe.mjs +218 -0
- package/scripts/bump-version.sh +84 -0
- package/scripts/codegen/gen-docs.mjs +61 -0
- package/scripts/codegen/gen-json-schema.mjs +62 -0
- package/scripts/codegen/gen-mcp-tools.mjs +358 -0
- package/scripts/codegen/gen-types.mjs +172 -0
- package/scripts/codegen/index.mjs +42 -0
- package/scripts/dev-hooks/check-extension-dirs.js +77 -0
- package/scripts/dev-hooks/check-open-claws-terminals.js +70 -0
- package/scripts/dev-hooks/check-stale-main.js +55 -0
- package/scripts/dev-hooks/check-tag-pushed.js +51 -0
- package/scripts/dev-hooks/check-tag-vs-main.js +56 -0
- package/scripts/dev-vsix-install.sh +60 -0
- package/scripts/fix.sh +702 -0
- package/scripts/gen-client-types.mjs +81 -0
- package/scripts/git-hooks/pre-commit +31 -0
- package/scripts/hooks/lifecycle-state.js +61 -0
- package/scripts/hooks/package.json +4 -0
- package/scripts/hooks/post-tool-use-claws.js +292 -0
- package/scripts/hooks/pre-bash-no-verify-block.js +72 -0
- package/scripts/hooks/pre-tool-use-claws.js +206 -0
- package/scripts/hooks/session-start-claws.js +97 -0
- package/scripts/hooks/stop-claws.js +88 -0
- package/scripts/inject-claude-md.js +205 -0
- package/scripts/inject-dev-hooks.js +96 -0
- package/scripts/inject-global-claude-md.js +140 -0
- package/scripts/inject-settings-hooks.js +370 -0
- package/scripts/install.ps1 +146 -0
- package/scripts/install.sh +1729 -0
- package/scripts/monitor-arm-watch.js +155 -0
- package/scripts/rebuild-node-pty.sh +245 -0
- package/scripts/report.sh +232 -0
- package/scripts/shell-hook.fish +164 -0
- package/scripts/shell-hook.ps1 +33 -0
- package/scripts/shell-hook.sh +232 -0
- package/scripts/stream-events.js +399 -0
- package/scripts/terminal-wrapper.sh +36 -0
- package/scripts/test-enforcement.sh +132 -0
- package/scripts/test-install.sh +174 -0
- package/scripts/test-installer-parity.sh +135 -0
- package/scripts/test-template-enforcement.sh +76 -0
- package/scripts/uninstall.sh +143 -0
- package/scripts/update.sh +337 -0
- package/scripts/verify-release.sh +323 -0
- package/scripts/verify-wrapped.sh +194 -0
- package/templates/CLAUDE.global.md +135 -0
- package/templates/CLAUDE.project.md +37 -0
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
export type PipelineStepRole = 'source' | 'sink';
|
|
2
|
+
export type PipelineStepState = 'active' | 'degraded' | 'closed';
|
|
3
|
+
export type PipelineState = 'active' | 'closed';
|
|
4
|
+
|
|
5
|
+
export interface PipelineStep {
|
|
6
|
+
stepId: string;
|
|
7
|
+
role: PipelineStepRole;
|
|
8
|
+
terminalId: string;
|
|
9
|
+
state: PipelineStepState;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface PipelineRecord {
|
|
13
|
+
pipelineId: string;
|
|
14
|
+
name: string;
|
|
15
|
+
steps: PipelineStep[];
|
|
16
|
+
state: PipelineState;
|
|
17
|
+
createdAt: string;
|
|
18
|
+
closedAt?: string;
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
export class PipelineRegistry {
|
|
22
|
+
private readonly pipelines = new Map<string, PipelineRecord>();
|
|
23
|
+
private pipelineSeq = 0;
|
|
24
|
+
|
|
25
|
+
create(
|
|
26
|
+
name: string,
|
|
27
|
+
steps: ReadonlyArray<{ role: PipelineStepRole; terminalId: string }>,
|
|
28
|
+
): PipelineRecord {
|
|
29
|
+
const pipelineId = `pipe_${String(++this.pipelineSeq).padStart(4, '0')}`;
|
|
30
|
+
const record: PipelineRecord = {
|
|
31
|
+
pipelineId,
|
|
32
|
+
name,
|
|
33
|
+
steps: steps.map((s, i) => ({
|
|
34
|
+
stepId: `${pipelineId}_step_${i}`,
|
|
35
|
+
role: s.role,
|
|
36
|
+
terminalId: s.terminalId,
|
|
37
|
+
state: 'active',
|
|
38
|
+
})),
|
|
39
|
+
state: 'active',
|
|
40
|
+
createdAt: new Date().toISOString(),
|
|
41
|
+
};
|
|
42
|
+
this.pipelines.set(pipelineId, { ...record, steps: record.steps.map((s) => ({ ...s })) });
|
|
43
|
+
return record;
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
get(pipelineId: string): PipelineRecord | undefined {
|
|
47
|
+
return this.pipelines.get(pipelineId);
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
list(): PipelineRecord[] {
|
|
51
|
+
return Array.from(this.pipelines.values());
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
close(pipelineId: string): PipelineRecord | null {
|
|
55
|
+
const p = this.pipelines.get(pipelineId);
|
|
56
|
+
if (!p) return null;
|
|
57
|
+
const closed: PipelineRecord = {
|
|
58
|
+
...p,
|
|
59
|
+
state: 'closed',
|
|
60
|
+
steps: p.steps.map((s) => ({ ...s, state: 'closed' as PipelineStepState })),
|
|
61
|
+
closedAt: new Date().toISOString(),
|
|
62
|
+
};
|
|
63
|
+
this.pipelines.set(pipelineId, closed);
|
|
64
|
+
return closed;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
/** Returns all active pipelines that have sourceTerminalId as their source step. */
|
|
68
|
+
findBySource(sourceTerminalId: string): PipelineRecord[] {
|
|
69
|
+
const result: PipelineRecord[] = [];
|
|
70
|
+
for (const p of this.pipelines.values()) {
|
|
71
|
+
if (p.state === 'active' && p.steps.some((s) => s.role === 'source' && s.terminalId === sourceTerminalId)) {
|
|
72
|
+
result.push(p);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
return result;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
clear(): void {
|
|
79
|
+
this.pipelines.clear();
|
|
80
|
+
this.pipelineSeq = 0;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
// extension/src/platform.ts
|
|
2
|
+
// Platform type alias and process helper factory for tri-platform discipline (v0.8+).
|
|
3
|
+
// win32 branches throw "not implemented" — that's P2 work.
|
|
4
|
+
|
|
5
|
+
import { spawnSync } from 'child_process';
|
|
6
|
+
|
|
7
|
+
export type NodePlatform = 'win32' | 'darwin' | 'linux';
|
|
8
|
+
|
|
9
|
+
export const currentPlatform: NodePlatform = process.platform as NodePlatform;
|
|
10
|
+
|
|
11
|
+
export const isWindows = currentPlatform === 'win32';
|
|
12
|
+
export const isMac = currentPlatform === 'darwin';
|
|
13
|
+
export const isLinux = currentPlatform === 'linux';
|
|
14
|
+
|
|
15
|
+
export interface ProcessHelpers {
|
|
16
|
+
/**
|
|
17
|
+
* Return the foreground process running under shellPid.
|
|
18
|
+
* Uses pgrep + ps on darwin/linux. Throws on win32 (P2).
|
|
19
|
+
*/
|
|
20
|
+
getForegroundProcess(shellPid: number): { pid: number | null; basename: string | null };
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* Return platform-appropriate process helpers.
|
|
25
|
+
* On win32, returns the shell PID and null basename (ConPTY does not expose
|
|
26
|
+
* the foreground process without Win32 API calls — v0.8 stub, improved in v0.8.1).
|
|
27
|
+
*/
|
|
28
|
+
export function getProcessHelpers(): ProcessHelpers {
|
|
29
|
+
if (currentPlatform === 'win32') {
|
|
30
|
+
return {
|
|
31
|
+
getForegroundProcess(shellPid: number): { pid: number | null; basename: string | null } {
|
|
32
|
+
// Win32 stub: ConPTY process tree requires NtQueryInformationProcess or
|
|
33
|
+
// toolhelp32 — neither is available in pure Node. Return the shell PID
|
|
34
|
+
// so the safety gate can still warn (basename=null → 'unknown' content type).
|
|
35
|
+
return { pid: shellPid, basename: null };
|
|
36
|
+
},
|
|
37
|
+
};
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
return {
|
|
41
|
+
getForegroundProcess(shellPid: number): { pid: number | null; basename: string | null } {
|
|
42
|
+
try {
|
|
43
|
+
const pgrepResult = spawnSync('pgrep', ['-P', String(shellPid)], { encoding: 'utf8', timeout: 500 });
|
|
44
|
+
const childOutput = (pgrepResult.stdout ?? '').trim();
|
|
45
|
+
let targetPid: number = shellPid;
|
|
46
|
+
if (childOutput) {
|
|
47
|
+
const childPids = childOutput.split('\n').filter(Boolean);
|
|
48
|
+
const candidatePid = parseInt(childPids[childPids.length - 1] ?? '', 10);
|
|
49
|
+
if (!isNaN(candidatePid)) targetPid = candidatePid;
|
|
50
|
+
}
|
|
51
|
+
const psResult = spawnSync('ps', ['-p', String(targetPid), '-o', 'comm='], { encoding: 'utf8', timeout: 500 });
|
|
52
|
+
let basename = (psResult.stdout ?? '').trim() || null;
|
|
53
|
+
if (!basename && targetPid !== shellPid) {
|
|
54
|
+
const fallback = spawnSync('ps', ['-p', String(shellPid), '-o', 'comm='], { encoding: 'utf8', timeout: 500 });
|
|
55
|
+
basename = (fallback.stdout ?? '').trim() || null;
|
|
56
|
+
targetPid = shellPid;
|
|
57
|
+
}
|
|
58
|
+
return { pid: targetPid, basename };
|
|
59
|
+
} catch {
|
|
60
|
+
return { pid: shellPid, basename: null };
|
|
61
|
+
}
|
|
62
|
+
},
|
|
63
|
+
};
|
|
64
|
+
}
|
|
@@ -0,0 +1,532 @@
|
|
|
1
|
+
// Claws wire protocol — v1.
|
|
2
|
+
//
|
|
3
|
+
// Requests and responses are newline-delimited JSON frames. Clients MAY
|
|
4
|
+
// include `protocol: "claws/1"` on any request; if the server sees a
|
|
5
|
+
// different protocol tag it will reject with `ok:false, error: "incompatible
|
|
6
|
+
// protocol version"`. Absent = treated as claws/1 (current).
|
|
7
|
+
//
|
|
8
|
+
// Every response includes `protocol: "claws/1"` and `rid` (request id) —
|
|
9
|
+
// `id` is preserved too for legacy clients, but `rid` is always the request
|
|
10
|
+
// id regardless of whether a response field shadows it (e.g. `create`
|
|
11
|
+
// returns a terminal `id`).
|
|
12
|
+
|
|
13
|
+
export const PROTOCOL_VERSION = 'claws/1';
|
|
14
|
+
export const PROTOCOL_VERSION_V2 = 'claws/2';
|
|
15
|
+
|
|
16
|
+
// ── Wave army protocol types ───────────────────────────────────────────────
|
|
17
|
+
|
|
18
|
+
/** Sub-worker roles in the wave army protocol. */
|
|
19
|
+
export type SubWorkerRole = 'lead' | 'tester' | 'reviewer' | 'auditor' | 'bench' | 'doc';
|
|
20
|
+
|
|
21
|
+
/** All contracted sub-worker roles with their discipline obligations. */
|
|
22
|
+
export const ContractedRoles: Record<SubWorkerRole, string> = {
|
|
23
|
+
lead: 'Implementer — owns the diff, commits, builds, PIAFEUR loop',
|
|
24
|
+
tester: 'TDD — writes red tests before impl, validates green after',
|
|
25
|
+
reviewer: 'Read-only code review — watches git diff, publishes findings',
|
|
26
|
+
auditor: 'Read-only — sweeps for race conditions, schema correctness, regression risks',
|
|
27
|
+
bench: 'Read-only — runs perf benchmarks after green, publishes metrics',
|
|
28
|
+
doc: 'Docs only — updates CHANGELOG, gap doc, templates',
|
|
29
|
+
};
|
|
30
|
+
|
|
31
|
+
export interface BaseRequest {
|
|
32
|
+
id?: number | string;
|
|
33
|
+
cmd: string;
|
|
34
|
+
/** Optional client-declared protocol tag. Must be 'claws/1' or absent. */
|
|
35
|
+
protocol?: string;
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
export interface ListRequest extends BaseRequest { cmd: 'list'; }
|
|
39
|
+
|
|
40
|
+
export interface CreateRequest extends BaseRequest {
|
|
41
|
+
cmd: 'create';
|
|
42
|
+
name?: string;
|
|
43
|
+
cwd?: string;
|
|
44
|
+
show?: boolean;
|
|
45
|
+
preserveFocus?: boolean;
|
|
46
|
+
wrapped?: boolean;
|
|
47
|
+
shellPath?: string;
|
|
48
|
+
env?: Record<string, string>;
|
|
49
|
+
/** AC-1: lifecycle correlation identifier; propagated as CLAWS_TERMINAL_CORR_ID env var to the spawned pty. */
|
|
50
|
+
correlation_id?: string;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface ShowRequest extends BaseRequest {
|
|
54
|
+
cmd: 'show';
|
|
55
|
+
id: string | number;
|
|
56
|
+
preserveFocus?: boolean;
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* `send` semantics differ slightly between wrapped and unwrapped terminals
|
|
61
|
+
* because VS Code exposes two distinct APIs:
|
|
62
|
+
*
|
|
63
|
+
* - UNWRAPPED → `Terminal.sendText(text, withNewline)`. VS Code owns the
|
|
64
|
+
* input decode path; `paste` bracketing is best-effort (sent as literal
|
|
65
|
+
* bytes) and newline is ALWAYS `\n` regardless of platform. Multi-line
|
|
66
|
+
* strings may be fragmented if the shell lacks bracketed-paste support.
|
|
67
|
+
*
|
|
68
|
+
* - WRAPPED → `Pseudoterminal.handleInput(data)` via ClawsPty.writeInjected.
|
|
69
|
+
* We fully control the byte stream: bracketed paste (`\x1b[200~…\x1b[201~`)
|
|
70
|
+
* is injected verbatim, and newline is sent as `\r` to match tty input
|
|
71
|
+
* conventions (terminals convert it to \n through icrnl). This path is
|
|
72
|
+
* what you want for sending prompts into TUI sessions like Claude Code.
|
|
73
|
+
*
|
|
74
|
+
* The server's `send` response includes `mode: 'wrapped' | 'unwrapped'` so
|
|
75
|
+
* clients can reason about which path they got.
|
|
76
|
+
*/
|
|
77
|
+
export interface SendRequest extends BaseRequest {
|
|
78
|
+
cmd: 'send';
|
|
79
|
+
id: string | number;
|
|
80
|
+
text: string;
|
|
81
|
+
newline?: boolean;
|
|
82
|
+
show?: boolean;
|
|
83
|
+
paste?: boolean;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
export interface ExecRequest extends BaseRequest {
|
|
87
|
+
cmd: 'exec';
|
|
88
|
+
id: string | number;
|
|
89
|
+
command: string;
|
|
90
|
+
timeoutMs?: number;
|
|
91
|
+
show?: boolean;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
export interface ReadRequest extends BaseRequest {
|
|
95
|
+
cmd: 'read';
|
|
96
|
+
id?: string | number;
|
|
97
|
+
since?: number;
|
|
98
|
+
limit?: number;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export interface PollRequest extends BaseRequest {
|
|
102
|
+
cmd: 'poll';
|
|
103
|
+
since?: number;
|
|
104
|
+
/** Optional client-requested cap. Server enforces its own cap via config. */
|
|
105
|
+
limit?: number;
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
export interface CloseRequest extends BaseRequest {
|
|
109
|
+
cmd: 'close';
|
|
110
|
+
id: string | number;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
export interface ReadLogRequest extends BaseRequest {
|
|
114
|
+
cmd: 'readLog';
|
|
115
|
+
id: string | number;
|
|
116
|
+
offset?: number;
|
|
117
|
+
limit?: number;
|
|
118
|
+
strip?: boolean;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/**
|
|
122
|
+
* Runtime introspection — returns extension + runtime metadata for
|
|
123
|
+
* health-checks and client-side version compatibility checks.
|
|
124
|
+
*/
|
|
125
|
+
export interface IntrospectRequest extends BaseRequest {
|
|
126
|
+
cmd: 'introspect';
|
|
127
|
+
/** Optional client-declared version string; server logs a warning on drift. */
|
|
128
|
+
clientVersion?: string;
|
|
129
|
+
/** Optional client name for the server log line. */
|
|
130
|
+
clientName?: string;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/**
|
|
134
|
+
* claws/2 handshake. Must be the first frame a peer sends on a new
|
|
135
|
+
* connection when speaking the v2 protocol. Server replies with the
|
|
136
|
+
* allocated peerId and its capability set. A second `hello` with
|
|
137
|
+
* `role: 'orchestrator'` and no `waveId` while a root orchestrator is
|
|
138
|
+
* already registered is rejected. Wave LEADs may register as orchestrator
|
|
139
|
+
* by including a `waveId` — the singleton guard is scoped to root peers only.
|
|
140
|
+
*/
|
|
141
|
+
export interface HelloRequest extends BaseRequest {
|
|
142
|
+
cmd: 'hello';
|
|
143
|
+
/** MUST be 'claws/2' — the server rejects any other value on hello. */
|
|
144
|
+
protocol: string;
|
|
145
|
+
role: 'orchestrator' | 'worker' | 'observer';
|
|
146
|
+
peerName: string;
|
|
147
|
+
terminalId?: string;
|
|
148
|
+
capabilities?: string[];
|
|
149
|
+
/**
|
|
150
|
+
* Optional stable identity nonce. When present, the server derives a
|
|
151
|
+
* fingerprint-based peerId (`fp_` + sha256(peerName+role+nonce)[:12]).
|
|
152
|
+
* Reconnecting with the same nonce restores subscriptions and re-binds
|
|
153
|
+
* any orphaned tasks assigned to the previous connection session.
|
|
154
|
+
*/
|
|
155
|
+
instanceNonce?: string;
|
|
156
|
+
/** Wave id this peer belongs to (wave army protocol). */
|
|
157
|
+
waveId?: string;
|
|
158
|
+
/** Sub-worker role within the wave (wave army protocol). */
|
|
159
|
+
subWorkerRole?: SubWorkerRole;
|
|
160
|
+
/**
|
|
161
|
+
* L18 AUTH — HMAC-SHA256 token. Required when server auth is enabled.
|
|
162
|
+
* Computed as: HMAC-SHA256(secret, `${peerName}:${role}:${nonce}:${timestamp}`).
|
|
163
|
+
*/
|
|
164
|
+
token?: string;
|
|
165
|
+
/** L18 AUTH — random hex nonce. Prevents replay attacks; single-use. */
|
|
166
|
+
nonce?: string;
|
|
167
|
+
/**
|
|
168
|
+
* L18 AUTH — Unix epoch milliseconds at token creation time. The server
|
|
169
|
+
* rejects tokens older than AUTH_MAX_TOKEN_AGE_MS (5 minutes).
|
|
170
|
+
*/
|
|
171
|
+
timestamp?: number;
|
|
172
|
+
/**
|
|
173
|
+
* Bug-6 Layer 2 — declares "I am the Monitor process armed for this
|
|
174
|
+
* correlation_id". When present, the server records an armedCorrelations
|
|
175
|
+
* claim linking this corrId to the registering peer. Spawn handlers verify
|
|
176
|
+
* this claim after a 30s grace window via the monitors.is-corr-armed RPC.
|
|
177
|
+
* Any role (observer/orchestrator/worker) may declare a claim.
|
|
178
|
+
*/
|
|
179
|
+
monitorCorrelationId?: string;
|
|
180
|
+
/** AC-1: worker's lifecycle correlation id, copied from CLAWS_TERMINAL_CORR_ID env var.
|
|
181
|
+
* When present, stored on the peer record and emitted in system.peer.connected. */
|
|
182
|
+
correlation_id?: string;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/** Create a new wave, registering expected sub-worker roles and heartbeat manifest. */
|
|
186
|
+
export interface WaveCreateRequest extends BaseRequest {
|
|
187
|
+
cmd: 'wave.create';
|
|
188
|
+
waveId: string;
|
|
189
|
+
/** Human-readable layers or goals this wave covers. */
|
|
190
|
+
layers: string[];
|
|
191
|
+
/** Expected sub-worker roles — server tracks heartbeats for each. */
|
|
192
|
+
manifest: SubWorkerRole[];
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
/** Mark a wave as complete. Only the LEAD should call this. */
|
|
196
|
+
export interface WaveCompleteRequest extends BaseRequest {
|
|
197
|
+
cmd: 'wave.complete';
|
|
198
|
+
waveId: string;
|
|
199
|
+
summary: string;
|
|
200
|
+
commits?: string[];
|
|
201
|
+
regressionClean?: boolean;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
/** Read-only status snapshot for a wave. */
|
|
205
|
+
export interface WaveStatusRequest extends BaseRequest {
|
|
206
|
+
cmd: 'wave.status';
|
|
207
|
+
waveId: string;
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Liveness probe. No state change, server responds with `serverTime`.
|
|
212
|
+
*/
|
|
213
|
+
export interface PingRequest extends BaseRequest {
|
|
214
|
+
cmd: 'ping';
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
/** Subscribe to a topic pattern. Returns a subscriptionId. */
|
|
218
|
+
export interface SubscribeRequest extends BaseRequest {
|
|
219
|
+
cmd: 'subscribe';
|
|
220
|
+
topic: string;
|
|
221
|
+
/**
|
|
222
|
+
* Optional cursor for catch-up replay. When present, the server will replay
|
|
223
|
+
* all matching events from this cursor before switching to live delivery.
|
|
224
|
+
* Format: "<4-digit-segment-id>:<decimal-byte-offset>" (same as publish response cursor).
|
|
225
|
+
* TODO(P1 v0.7.6): full replay not yet implemented — server accepts the field and logs a
|
|
226
|
+
* warning, then falls through to live delivery only.
|
|
227
|
+
*/
|
|
228
|
+
fromCursor?: string;
|
|
229
|
+
}
|
|
230
|
+
|
|
231
|
+
/** Response to a subscribe command. replayedCount is populated when fromCursor replay is used. */
|
|
232
|
+
export interface SubscribeResponse extends ClawsResponse {
|
|
233
|
+
ok: true;
|
|
234
|
+
subscriptionId: string;
|
|
235
|
+
replayedCount?: number;
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
/** Remove a subscription by id. */
|
|
239
|
+
export interface UnsubscribeRequest extends BaseRequest {
|
|
240
|
+
cmd: 'unsubscribe';
|
|
241
|
+
subscriptionId: string;
|
|
242
|
+
}
|
|
243
|
+
|
|
244
|
+
/** Publish a payload to a topic. Server fans out to all matching subscribers. */
|
|
245
|
+
export interface PublishRequest extends BaseRequest {
|
|
246
|
+
cmd: 'publish';
|
|
247
|
+
topic: string;
|
|
248
|
+
payload: unknown;
|
|
249
|
+
/** If true, also deliver to the sender. Default false. */
|
|
250
|
+
echo?: boolean;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
/** Orchestrator-only: fan out a message to all workers (or all peers). */
|
|
254
|
+
export interface BroadcastRequest extends BaseRequest {
|
|
255
|
+
cmd: 'broadcast';
|
|
256
|
+
text: string;
|
|
257
|
+
targetRole?: 'worker' | 'orchestrator' | 'observer' | 'all';
|
|
258
|
+
/** If true, also send the text into each target's associated terminalId via bracketed paste. */
|
|
259
|
+
inject?: boolean;
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/** Orchestrator: create a task and assign it to a worker peer. */
|
|
263
|
+
export interface TaskAssignRequest extends BaseRequest {
|
|
264
|
+
cmd: 'task.assign';
|
|
265
|
+
title: string;
|
|
266
|
+
assignee: string;
|
|
267
|
+
prompt: string;
|
|
268
|
+
timeoutMs?: number;
|
|
269
|
+
/** How to deliver the task to the worker. 'publish' sends a pub/sub message; 'inject' also sends the prompt into the terminal; 'both' does both. */
|
|
270
|
+
deliver?: 'publish' | 'inject' | 'both';
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
/** Worker: report progress on an assigned task (also acts as a heartbeat). */
|
|
274
|
+
export interface TaskUpdateRequest extends BaseRequest {
|
|
275
|
+
cmd: 'task.update';
|
|
276
|
+
taskId: string;
|
|
277
|
+
status: 'pending' | 'running' | 'blocked';
|
|
278
|
+
progressPct?: number;
|
|
279
|
+
note?: string;
|
|
280
|
+
}
|
|
281
|
+
|
|
282
|
+
/** Worker: mark a task as finished. Idempotent if already completed. */
|
|
283
|
+
export interface TaskCompleteRequest extends BaseRequest {
|
|
284
|
+
cmd: 'task.complete';
|
|
285
|
+
taskId: string;
|
|
286
|
+
status: 'succeeded' | 'failed' | 'skipped';
|
|
287
|
+
result?: unknown;
|
|
288
|
+
artifacts?: Array<{ type: string; path: string }>;
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
/** Orchestrator: request cancellation of a task. */
|
|
292
|
+
export interface TaskCancelRequest extends BaseRequest {
|
|
293
|
+
cmd: 'task.cancel';
|
|
294
|
+
taskId: string;
|
|
295
|
+
reason?: string;
|
|
296
|
+
}
|
|
297
|
+
|
|
298
|
+
/** Any role: list tasks with optional filters. */
|
|
299
|
+
export interface TaskListRequest extends BaseRequest {
|
|
300
|
+
cmd: 'task.list';
|
|
301
|
+
assignee?: string;
|
|
302
|
+
status?: string;
|
|
303
|
+
since?: number;
|
|
304
|
+
}
|
|
305
|
+
|
|
306
|
+
/** Lifecycle state shape — server-owned, never written by clients. */
|
|
307
|
+
export interface LifecycleState {
|
|
308
|
+
v: 1;
|
|
309
|
+
phase: string;
|
|
310
|
+
phases_completed: string[];
|
|
311
|
+
plan: string;
|
|
312
|
+
workers: Array<{ id: string; closed: boolean }>;
|
|
313
|
+
started_at: string;
|
|
314
|
+
reflect?: string;
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/**
|
|
318
|
+
* Start or reset the lifecycle. plan text must be non-empty.
|
|
319
|
+
* v0.7.10 (schema v3): workerMode + expectedWorkers REQUIRED — declares the
|
|
320
|
+
* mission shape upfront so OBSERVE→HARVEST routing and CLEANUP gate know
|
|
321
|
+
* what to expect. workerMode ∈ {single, fleet, army}.
|
|
322
|
+
*/
|
|
323
|
+
export interface LifecyclePlanRequest extends BaseRequest {
|
|
324
|
+
cmd: 'lifecycle.plan';
|
|
325
|
+
plan: string;
|
|
326
|
+
workerMode: 'single' | 'fleet' | 'army';
|
|
327
|
+
expectedWorkers: number;
|
|
328
|
+
}
|
|
329
|
+
|
|
330
|
+
/** Advance the phase state machine one step. */
|
|
331
|
+
export interface LifecycleAdvanceRequest extends BaseRequest {
|
|
332
|
+
cmd: 'lifecycle.advance';
|
|
333
|
+
to: string;
|
|
334
|
+
reason?: string;
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
/** Read-only snapshot of current lifecycle state. */
|
|
338
|
+
export interface LifecycleSnapshotRequest extends BaseRequest {
|
|
339
|
+
cmd: 'lifecycle.snapshot';
|
|
340
|
+
}
|
|
341
|
+
|
|
342
|
+
/** Terminal transition to REFLECT with persisted reflection text. */
|
|
343
|
+
export interface LifecycleReflectRequest extends BaseRequest {
|
|
344
|
+
cmd: 'lifecycle.reflect';
|
|
345
|
+
reflect: string;
|
|
346
|
+
}
|
|
347
|
+
|
|
348
|
+
/**
|
|
349
|
+
* D+F (v0.7.10): register a newly-spawned worker. Called by mcp_server's
|
|
350
|
+
* spawn-class tool handlers atomically with terminal creation. correlationId
|
|
351
|
+
* is the orchestrator-supplied UUID matching the pre-armed Bash watcher.
|
|
352
|
+
*/
|
|
353
|
+
export interface LifecycleRegisterSpawnRequest extends BaseRequest {
|
|
354
|
+
cmd: 'lifecycle.register-spawn';
|
|
355
|
+
terminalId: string;
|
|
356
|
+
correlationId: string;
|
|
357
|
+
name: string;
|
|
358
|
+
}
|
|
359
|
+
|
|
360
|
+
/**
|
|
361
|
+
* D+F: register a per-worker monitor. Called atomically with register-spawn
|
|
362
|
+
* by mcp_server. The "command" is the verbatim Bash(...) command the
|
|
363
|
+
* orchestrator was instructed to arm — recorded for audit/diagnostics.
|
|
364
|
+
*/
|
|
365
|
+
export interface LifecycleRegisterMonitorRequest extends BaseRequest {
|
|
366
|
+
cmd: 'lifecycle.register-monitor';
|
|
367
|
+
terminalId: string;
|
|
368
|
+
correlationId: string;
|
|
369
|
+
command: string;
|
|
370
|
+
}
|
|
371
|
+
|
|
372
|
+
/**
|
|
373
|
+
* D+F: update a worker's status. Called by detach watcher when worker reaches
|
|
374
|
+
* terminal state (completed/failed/timeout/closed).
|
|
375
|
+
*/
|
|
376
|
+
export interface LifecycleMarkWorkerStatusRequest extends BaseRequest {
|
|
377
|
+
cmd: 'lifecycle.mark-worker-status';
|
|
378
|
+
terminalId: string;
|
|
379
|
+
status: 'spawned' | 'completed' | 'failed' | 'timeout' | 'closed';
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
/** Deliver a typed command envelope to a specific worker peer (orchestrator-only). */
|
|
383
|
+
export interface DeliverCmdRequest extends BaseRequest {
|
|
384
|
+
cmd: 'deliver-cmd';
|
|
385
|
+
targetPeerId: string;
|
|
386
|
+
cmdTopic: string;
|
|
387
|
+
payload: unknown;
|
|
388
|
+
idempotencyKey: string;
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
/** Worker acknowledges receipt of a delivered command; fans out to orchestrator. */
|
|
392
|
+
export interface CmdAckRequest extends BaseRequest {
|
|
393
|
+
cmd: 'cmd.ack';
|
|
394
|
+
seq: number;
|
|
395
|
+
status: 'executed' | 'rejected' | 'duplicate';
|
|
396
|
+
correlation_id?: string;
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
/**
|
|
400
|
+
* L16 TYPED-RPC — issue a typed RPC call to a target peer. The server pushes
|
|
401
|
+
* the call to `rpc.<targetPeerId>.request` and holds this request open until
|
|
402
|
+
* the target publishes to `rpc.response.<callerPeerId>.<requestId>` or the
|
|
403
|
+
* timeout fires.
|
|
404
|
+
*/
|
|
405
|
+
export interface RpcCallRequest extends BaseRequest {
|
|
406
|
+
cmd: 'rpc.call';
|
|
407
|
+
targetPeerId: string;
|
|
408
|
+
method: string;
|
|
409
|
+
params?: Record<string, unknown>;
|
|
410
|
+
/** Milliseconds before the caller receives a timeout error. Default: 5000. */
|
|
411
|
+
timeoutMs?: number;
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
/** L7 Schema Registry — return sorted list of all registered schema names. */
|
|
415
|
+
export interface SchemaListRequest extends BaseRequest {
|
|
416
|
+
cmd: 'schema.list';
|
|
417
|
+
}
|
|
418
|
+
|
|
419
|
+
/** L7 Schema Registry — return a simplified JSON representation of one schema. */
|
|
420
|
+
export interface SchemaGetRequest extends BaseRequest {
|
|
421
|
+
cmd: 'schema.get';
|
|
422
|
+
name: string;
|
|
423
|
+
}
|
|
424
|
+
|
|
425
|
+
/** Create a named pipeline connecting source vehicle output to sink vehicle input. */
|
|
426
|
+
export interface PipelineCreateRequest extends BaseRequest {
|
|
427
|
+
cmd: 'pipeline.create';
|
|
428
|
+
name?: string;
|
|
429
|
+
steps: Array<{ role: 'source' | 'sink'; terminalId: string }>;
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
/** List all pipelines (active and closed). */
|
|
433
|
+
export interface PipelineListRequest extends BaseRequest {
|
|
434
|
+
cmd: 'pipeline.list';
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
/** Destroy a pipeline and emit pipeline.<id>.closed event. */
|
|
438
|
+
export interface PipelineCloseRequest extends BaseRequest {
|
|
439
|
+
cmd: 'pipeline.close';
|
|
440
|
+
pipelineId: string;
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
export type ClawsRequest =
|
|
444
|
+
| ListRequest
|
|
445
|
+
| CreateRequest
|
|
446
|
+
| ShowRequest
|
|
447
|
+
| SendRequest
|
|
448
|
+
| ExecRequest
|
|
449
|
+
| ReadRequest
|
|
450
|
+
| PollRequest
|
|
451
|
+
| CloseRequest
|
|
452
|
+
| ReadLogRequest
|
|
453
|
+
| IntrospectRequest
|
|
454
|
+
| HelloRequest
|
|
455
|
+
| PingRequest
|
|
456
|
+
| SubscribeRequest
|
|
457
|
+
| UnsubscribeRequest
|
|
458
|
+
| PublishRequest
|
|
459
|
+
| BroadcastRequest
|
|
460
|
+
| TaskAssignRequest
|
|
461
|
+
| TaskUpdateRequest
|
|
462
|
+
| TaskCompleteRequest
|
|
463
|
+
| TaskCancelRequest
|
|
464
|
+
| TaskListRequest
|
|
465
|
+
| LifecyclePlanRequest
|
|
466
|
+
| LifecycleAdvanceRequest
|
|
467
|
+
| LifecycleSnapshotRequest
|
|
468
|
+
| LifecycleReflectRequest
|
|
469
|
+
| LifecycleRegisterSpawnRequest
|
|
470
|
+
| LifecycleRegisterMonitorRequest
|
|
471
|
+
| LifecycleMarkWorkerStatusRequest
|
|
472
|
+
| WaveCreateRequest
|
|
473
|
+
| WaveCompleteRequest
|
|
474
|
+
| WaveStatusRequest
|
|
475
|
+
| DeliverCmdRequest
|
|
476
|
+
| CmdAckRequest
|
|
477
|
+
| PipelineCreateRequest
|
|
478
|
+
| PipelineListRequest
|
|
479
|
+
| PipelineCloseRequest
|
|
480
|
+
| RpcCallRequest
|
|
481
|
+
| SchemaListRequest
|
|
482
|
+
| SchemaGetRequest
|
|
483
|
+
| BaseRequest;
|
|
484
|
+
|
|
485
|
+
export interface TerminalDescriptor {
|
|
486
|
+
id: string;
|
|
487
|
+
name: string;
|
|
488
|
+
pid: number | null;
|
|
489
|
+
/**
|
|
490
|
+
* Real shell pid when the wrapped pty has spawned successfully. VS Code's
|
|
491
|
+
* `terminal.processId` returns null/-1 for Pseudoterminal-based terminals
|
|
492
|
+
* (because VS Code didn't spawn the process — we did), so we expose the
|
|
493
|
+
* underlying ptyProc/childProc pid here. Null when not wrapped or when
|
|
494
|
+
* pty.open() has not yet fired.
|
|
495
|
+
*/
|
|
496
|
+
ptyPid?: number | null;
|
|
497
|
+
/**
|
|
498
|
+
* 'pty' = real pseudoterminal via node-pty (TUIs work)
|
|
499
|
+
* 'pipe' = child_process fallback when node-pty unavailable (TUIs broken)
|
|
500
|
+
* 'none' = pty.open() has not been called yet by VS Code
|
|
501
|
+
* undefined = unwrapped terminal (no pty at all)
|
|
502
|
+
*/
|
|
503
|
+
ptyMode?: 'pty' | 'pipe' | 'none';
|
|
504
|
+
hasShellIntegration: boolean;
|
|
505
|
+
active: boolean;
|
|
506
|
+
logPath: string | null;
|
|
507
|
+
wrapped: boolean;
|
|
508
|
+
/** 'unknown' is emitted for terminals the manager has never adopted. */
|
|
509
|
+
status?: 'adopted' | 'unknown';
|
|
510
|
+
/** Current vehicle lifecycle state. Absent for unwrapped (non-pty) terminals. */
|
|
511
|
+
vehicleState?: 'PROVISIONING' | 'BOOTING' | 'READY' | 'BUSY' | 'IDLE' | 'CLOSING' | 'CLOSED';
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
export interface HistoryEvent {
|
|
515
|
+
seq: number;
|
|
516
|
+
terminalId: string;
|
|
517
|
+
terminalName: string;
|
|
518
|
+
commandLine: string;
|
|
519
|
+
output: string;
|
|
520
|
+
exitCode: number | null;
|
|
521
|
+
startedAt: number;
|
|
522
|
+
endedAt: number;
|
|
523
|
+
}
|
|
524
|
+
|
|
525
|
+
export interface ClawsResponse {
|
|
526
|
+
id?: number | string;
|
|
527
|
+
ok: boolean;
|
|
528
|
+
error?: string;
|
|
529
|
+
/** Always 'claws/1' on a successful server response. */
|
|
530
|
+
protocol?: string;
|
|
531
|
+
[key: string]: unknown;
|
|
532
|
+
}
|