@shardworks/claude-code-apparatus 0.1.148 → 0.1.150
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 +159 -0
- package/dist/babysitter.d.ts +152 -0
- package/dist/babysitter.d.ts.map +1 -0
- package/dist/babysitter.js +471 -0
- package/dist/babysitter.js.map +1 -0
- package/dist/detached.d.ts +86 -0
- package/dist/detached.d.ts.map +1 -0
- package/dist/detached.js +257 -0
- package/dist/detached.js.map +1 -0
- package/dist/index.d.ts +14 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +97 -81
- package/dist/index.js.map +1 -1
- package/package.json +11 -4
package/README.md
ADDED
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
# `@shardworks/claude-code-apparatus`
|
|
2
|
+
|
|
3
|
+
Claude Code session provider apparatus for Nexus. Implements the `AnimatorSessionProvider` interface for the Claude Code CLI, enabling the Animator to launch and manage AI sessions. Also provides the **Session Babysitter** — a detached process that hosts sessions independently of the guild lifecycle.
|
|
4
|
+
|
|
5
|
+
Depends on `@shardworks/animator-apparatus` (types), `@shardworks/tools-apparatus` (tool definitions and routing), and `@shardworks/nexus-core`.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## Installation
|
|
10
|
+
|
|
11
|
+
```json
|
|
12
|
+
{
|
|
13
|
+
"dependencies": {
|
|
14
|
+
"@shardworks/claude-code-apparatus": "workspace:*"
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
## API
|
|
20
|
+
|
|
21
|
+
### Session Provider
|
|
22
|
+
|
|
23
|
+
The default export is a `Plugin` whose apparatus `provides` an `AnimatorSessionProvider`:
|
|
24
|
+
|
|
25
|
+
```typescript
|
|
26
|
+
import createClaudeCodeProvider from '@shardworks/claude-code-apparatus';
|
|
27
|
+
|
|
28
|
+
// In guild.json:
|
|
29
|
+
// { "animator": { "sessionProvider": "claude-code" } }
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
The provider implements `launch()` and `cancel()`:
|
|
33
|
+
|
|
34
|
+
- **`launch(config)`** — spawns a **detached babysitter process** that hosts the session independently of the guild. The babysitter spawns `claude` in autonomous mode, streams transcripts to SQLite, and reports lifecycle events via HTTP. Returns `{ chunks, result, processInfo }` where:
|
|
35
|
+
- `chunks` completes immediately (empty) — real-time output is available via the transcripts book
|
|
36
|
+
- `result` polls the sessions book for terminal status (resolves when the babysitter calls `session-record`)
|
|
37
|
+
- `processInfo` polls the SessionDoc for `cancelMetadata.pid` (set by the babysitter via `session-running`)
|
|
38
|
+
- **`cancel(cancelMetadata)`** — sends SIGTERM to the claude process using the PID from `cancelMetadata`. Works cross-process regardless of parent-child relationships.
|
|
39
|
+
|
|
40
|
+
An **attached mode** (`launchAttached()`) is preserved as an internal export for debugging — it spawns claude as a direct child process with in-process MCP server and streaming.
|
|
41
|
+
|
|
42
|
+
### MCP Server
|
|
43
|
+
|
|
44
|
+
The package exports functions for running MCP tool servers:
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
import { createMcpServer, startMcpHttpServer } from '@shardworks/claude-code-apparatus';
|
|
48
|
+
|
|
49
|
+
// Create an MCP server with resolved tool definitions
|
|
50
|
+
const mcpServer = await createMcpServer(toolDefinitions);
|
|
51
|
+
|
|
52
|
+
// Or start an HTTP server on an ephemeral port
|
|
53
|
+
const handle = await startMcpHttpServer(toolDefinitions);
|
|
54
|
+
console.log(handle.url); // "http://127.0.0.1:PORT/sse"
|
|
55
|
+
await handle.close(); // cleanup
|
|
56
|
+
```
|
|
57
|
+
|
|
58
|
+
### Stream Parsing
|
|
59
|
+
|
|
60
|
+
Exported utilities for parsing Claude's NDJSON output:
|
|
61
|
+
|
|
62
|
+
```typescript
|
|
63
|
+
import {
|
|
64
|
+
processNdjsonBuffer,
|
|
65
|
+
parseStreamJsonMessage,
|
|
66
|
+
extractFinalAssistantText,
|
|
67
|
+
} from '@shardworks/claude-code-apparatus';
|
|
68
|
+
```
|
|
69
|
+
|
|
70
|
+
- **`processNdjsonBuffer(buffer, handler)`** — splits NDJSON buffer on newlines, calls handler for each parsed JSON object, returns remaining incomplete buffer.
|
|
71
|
+
- **`parseStreamJsonMessage(msg, acc)`** — processes a single NDJSON message, accumulates transcript/metrics, returns `SessionChunk[]`.
|
|
72
|
+
- **`extractFinalAssistantText(transcript)`** — walks transcript backwards to find the last assistant message's text content.
|
|
73
|
+
|
|
74
|
+
## Session Babysitter
|
|
75
|
+
|
|
76
|
+
The babysitter is a standalone Node.js script that runs as a detached process, hosting a claude session independently of the guild. It survives guild restarts.
|
|
77
|
+
|
|
78
|
+
### Entry Point
|
|
79
|
+
|
|
80
|
+
```bash
|
|
81
|
+
node dist/babysitter.js # reads config from stdin
|
|
82
|
+
```
|
|
83
|
+
|
|
84
|
+
Or import the module for programmatic use:
|
|
85
|
+
|
|
86
|
+
```typescript
|
|
87
|
+
import { runBabysitter } from '@shardworks/claude-code-apparatus/babysitter';
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
### Config (via stdin)
|
|
91
|
+
|
|
92
|
+
The spawning process writes JSON config to the babysitter's stdin:
|
|
93
|
+
|
|
94
|
+
```typescript
|
|
95
|
+
interface BabysitterConfig {
|
|
96
|
+
sessionId: string; // Pre-generated session ID
|
|
97
|
+
guildToolUrl: string; // Guild's Tool HTTP API URL (e.g. "http://127.0.0.1:7471")
|
|
98
|
+
dbPath: string; // Path to guild's SQLite database
|
|
99
|
+
claudeArgs: string[]; // CLI args for claude (--model, --system-prompt-file, etc.)
|
|
100
|
+
cwd: string; // Working directory for the claude process
|
|
101
|
+
env: Record<string, string>; // Environment variables for the claude process
|
|
102
|
+
prompt: string; // Initial prompt piped to claude's stdin
|
|
103
|
+
tools: SerializedTool[]; // Tool definitions with JSON Schema params
|
|
104
|
+
startedAt: string; // ISO timestamp of session start
|
|
105
|
+
provider: string; // Provider name (e.g. "claude-code")
|
|
106
|
+
metadata?: Record<string, unknown>; // Optional session metadata
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
interface SerializedTool {
|
|
110
|
+
name: string;
|
|
111
|
+
description: string;
|
|
112
|
+
params: Record<string, unknown>; // JSON Schema
|
|
113
|
+
}
|
|
114
|
+
```
|
|
115
|
+
|
|
116
|
+
### Lifecycle
|
|
117
|
+
|
|
118
|
+
1. **Read config** from stdin, parse JSON, validate required fields
|
|
119
|
+
2. **Open SQLite** (WAL mode) for real-time transcript streaming
|
|
120
|
+
3. **Start MCP/SSE proxy server** — registers tools that forward calls to the guild's Tool HTTP API with retry and exponential backoff
|
|
121
|
+
4. **Prepare session files** — temp directory, mcp-config.json pointing to the proxy server
|
|
122
|
+
5. **Spawn claude** — pipes prompt to stdin, captures NDJSON stdout
|
|
123
|
+
6. **Report "running"** — calls `session-running` tool on guild via HTTP (DLQ fallback)
|
|
124
|
+
7. **Stream transcript** — parses NDJSON, writes to `books_animator_transcripts` table in SQLite after each message batch
|
|
125
|
+
8. **Report result** — calls `session-record` tool on guild via HTTP (DLQ fallback)
|
|
126
|
+
9. **Cleanup** — close MCP server, close SQLite, remove temp directory
|
|
127
|
+
|
|
128
|
+
### Error Handling
|
|
129
|
+
|
|
130
|
+
- **Tool call proxy errors**: retried with exponential backoff (1s initial, 8s max, 60s timeout). If retries exhaust, returns error to claude as MCP tool result — doesn't crash.
|
|
131
|
+
- **Lifecycle reporting errors**: if guild is unreachable, payload is written to `.nexus/dlq/{sessionId}[-running].json` for later drain.
|
|
132
|
+
- **Top-level errors**: attempts to report `status: 'failed'` to guild, falls back to DLQ, then exits non-zero.
|
|
133
|
+
|
|
134
|
+
## Exports
|
|
135
|
+
|
|
136
|
+
| Entry point | Description |
|
|
137
|
+
|---|---|
|
|
138
|
+
| `.` (`src/index.ts`) | Session provider plugin, MCP server, stream parsing utilities, `launchAttached()` |
|
|
139
|
+
| `./babysitter` (`src/babysitter.ts`) | Babysitter module — `runBabysitter()`, config parsing, proxy server, transcript DB |
|
|
140
|
+
|
|
141
|
+
### Internal Modules
|
|
142
|
+
|
|
143
|
+
| Module | Description |
|
|
144
|
+
|---|---|
|
|
145
|
+
| `src/detached.ts` | Detached launch — `launchDetached()`, tool serialization (`serializeTools()`), polling helpers |
|
|
146
|
+
|
|
147
|
+
## Configuration
|
|
148
|
+
|
|
149
|
+
Configured in `guild.json` under the `animator` key:
|
|
150
|
+
|
|
151
|
+
```json
|
|
152
|
+
{
|
|
153
|
+
"animator": {
|
|
154
|
+
"sessionProvider": "claude-code"
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
No additional configuration fields. The model is passed per-session via the Animator.
|
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session Babysitter — detached process that hosts a claude session.
|
|
3
|
+
*
|
|
4
|
+
* A standalone Node.js script that:
|
|
5
|
+
* 1. Reads config from stdin (spawned by the claude-code provider)
|
|
6
|
+
* 2. Opens the guild's SQLite database for transcript streaming
|
|
7
|
+
* 3. Starts an MCP/SSE server that proxies tool calls to the guild
|
|
8
|
+
* 4. Spawns claude with prepared session files
|
|
9
|
+
* 5. Reports session lifecycle events via the guild's HTTP API
|
|
10
|
+
* 6. Streams transcript data to SQLite in real-time
|
|
11
|
+
* 7. Reports the final result and cleans up
|
|
12
|
+
*
|
|
13
|
+
* The babysitter is a detached process: it survives guild restarts.
|
|
14
|
+
* All guild communication is via HTTP (tool server) and SQLite (transcripts).
|
|
15
|
+
*
|
|
16
|
+
* See: docs/architecture/detached-sessions.md
|
|
17
|
+
*/
|
|
18
|
+
import { spawn } from 'node:child_process';
|
|
19
|
+
import { type StreamJsonResult } from './index.ts';
|
|
20
|
+
/** A serialized tool definition as received in the babysitter config. */
|
|
21
|
+
export interface SerializedTool {
|
|
22
|
+
/** Tool name (e.g. 'writ-list'). */
|
|
23
|
+
name: string;
|
|
24
|
+
/** Tool description. */
|
|
25
|
+
description: string;
|
|
26
|
+
/** JSON Schema for the tool's input parameters. */
|
|
27
|
+
params: Record<string, unknown>;
|
|
28
|
+
}
|
|
29
|
+
/** Config written to the babysitter's stdin by the spawning process. */
|
|
30
|
+
export interface BabysitterConfig {
|
|
31
|
+
sessionId: string;
|
|
32
|
+
guildToolUrl: string;
|
|
33
|
+
dbPath: string;
|
|
34
|
+
claudeArgs: string[];
|
|
35
|
+
cwd: string;
|
|
36
|
+
env: Record<string, string>;
|
|
37
|
+
prompt: string;
|
|
38
|
+
tools: SerializedTool[];
|
|
39
|
+
startedAt: string;
|
|
40
|
+
provider: string;
|
|
41
|
+
metadata?: Record<string, unknown>;
|
|
42
|
+
}
|
|
43
|
+
export interface McpProxyHandle {
|
|
44
|
+
/** URL for --mcp-config (e.g. "http://127.0.0.1:PORT/sse"). */
|
|
45
|
+
url: string;
|
|
46
|
+
/** Shut down the HTTP server and MCP transport. */
|
|
47
|
+
close(): Promise<void>;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Read the babysitter config from stdin.
|
|
51
|
+
*
|
|
52
|
+
* Reads stdin to completion, parses the JSON, and validates required fields.
|
|
53
|
+
* The spawning process writes config and closes the write end.
|
|
54
|
+
*/
|
|
55
|
+
export declare function readConfigFromStdin(stream?: NodeJS.ReadableStream): Promise<BabysitterConfig>;
|
|
56
|
+
/**
|
|
57
|
+
* Call a guild HTTP API endpoint with exponential backoff retry.
|
|
58
|
+
*
|
|
59
|
+
* Retries on connection errors (ECONNREFUSED, ECONNRESET, ETIMEDOUT).
|
|
60
|
+
* Returns the parsed JSON response on success.
|
|
61
|
+
* Throws after RETRY_TIMEOUT_MS of retrying.
|
|
62
|
+
*/
|
|
63
|
+
export declare function callGuildHttpApi(url: string, sessionId: string, body: unknown, timeoutMs?: number): Promise<unknown>;
|
|
64
|
+
/**
|
|
65
|
+
* Write a payload to the Dead Letter Queue.
|
|
66
|
+
*
|
|
67
|
+
* Creates the DLQ directory if it doesn't exist. Writes the payload as
|
|
68
|
+
* pretty-printed JSON. Used as a fallback when the guild HTTP API is
|
|
69
|
+
* unreachable for lifecycle calls.
|
|
70
|
+
*/
|
|
71
|
+
export declare function writeToDlq(cwd: string, filename: string, payload: unknown): void;
|
|
72
|
+
/**
|
|
73
|
+
* Create an MCP/SSE HTTP server that proxies tool calls to the guild.
|
|
74
|
+
*
|
|
75
|
+
* For each tool in the config, registers an MCP tool whose handler
|
|
76
|
+
* forwards the call to the guild's Tool HTTP API via HTTP POST.
|
|
77
|
+
*
|
|
78
|
+
* Uses the low-level MCP Server class to register tools with raw
|
|
79
|
+
* JSON Schema (the serialized params from the config).
|
|
80
|
+
*/
|
|
81
|
+
export declare function createProxyMcpHttpServer(tools: SerializedTool[], guildToolUrl: string, sessionId: string): Promise<McpProxyHandle>;
|
|
82
|
+
/** Minimal interface for the SQLite database used by the babysitter. */
|
|
83
|
+
export interface TranscriptDb {
|
|
84
|
+
/** Write a transcript entry (id, content JSON). */
|
|
85
|
+
writeTranscript(sessionId: string, content: string): void;
|
|
86
|
+
/** Close the database connection. */
|
|
87
|
+
close(): void;
|
|
88
|
+
}
|
|
89
|
+
/**
|
|
90
|
+
* Open the guild's SQLite database for transcript streaming.
|
|
91
|
+
*
|
|
92
|
+
* Creates the database file and table if they don't exist.
|
|
93
|
+
* Enables WAL mode for concurrent read access by other processes
|
|
94
|
+
* (Oculus, CLI queries, other agents).
|
|
95
|
+
*
|
|
96
|
+
* Uses dynamic import() to load better-sqlite3 at runtime. This avoids
|
|
97
|
+
* requiring the native module at import time (beneficial for type-checking
|
|
98
|
+
* and testing).
|
|
99
|
+
*/
|
|
100
|
+
export declare function openTranscriptDb(dbPath: string): Promise<TranscriptDb>;
|
|
101
|
+
/**
|
|
102
|
+
* Initialize a TranscriptDb from a Database constructor.
|
|
103
|
+
*
|
|
104
|
+
* Shared logic between openTranscriptDb() and test injection.
|
|
105
|
+
* Exported for testing — allows injecting a mock Database constructor.
|
|
106
|
+
*/
|
|
107
|
+
export declare function initTranscriptDb(DatabaseConstructor: new (path: string) => {
|
|
108
|
+
pragma(stmt: string): unknown;
|
|
109
|
+
prepare(sql: string): {
|
|
110
|
+
run(...params: unknown[]): void;
|
|
111
|
+
};
|
|
112
|
+
exec(sql: string): void;
|
|
113
|
+
close(): void;
|
|
114
|
+
}, dbPath: string): TranscriptDb;
|
|
115
|
+
/**
|
|
116
|
+
* Write the current transcript to SQLite.
|
|
117
|
+
*/
|
|
118
|
+
export declare function writeTranscript(db: TranscriptDb, sessionId: string, messages: Record<string, unknown>[]): void;
|
|
119
|
+
/**
|
|
120
|
+
* Report "running" status to the guild via the session-running tool.
|
|
121
|
+
*
|
|
122
|
+
* If the guild is unreachable, writes the payload to the DLQ.
|
|
123
|
+
*/
|
|
124
|
+
export declare function reportRunning(config: BabysitterConfig, claudePid: number, timeoutMs?: number): Promise<void>;
|
|
125
|
+
/**
|
|
126
|
+
* Report the final session result to the guild via the session-record tool.
|
|
127
|
+
*
|
|
128
|
+
* If the guild is unreachable, writes the payload to the DLQ.
|
|
129
|
+
*/
|
|
130
|
+
export declare function reportResult(config: BabysitterConfig, result: StreamJsonResult, transcript: Record<string, unknown>[], timeoutMs?: number): Promise<void>;
|
|
131
|
+
/**
|
|
132
|
+
* Run the session babysitter.
|
|
133
|
+
*
|
|
134
|
+
* This is the main orchestration function. It:
|
|
135
|
+
* 1. Opens SQLite for transcript streaming
|
|
136
|
+
* 2. Starts the MCP proxy server
|
|
137
|
+
* 3. Prepares session files (tmpDir, system prompt, mcp-config)
|
|
138
|
+
* 4. Spawns claude
|
|
139
|
+
* 5. Reports "running" status
|
|
140
|
+
* 6. Streams transcript to SQLite
|
|
141
|
+
* 7. Reports result on exit
|
|
142
|
+
* 8. Cleans up
|
|
143
|
+
*/
|
|
144
|
+
export declare function runBabysitter(config: BabysitterConfig, deps?: {
|
|
145
|
+
/** Injected TranscriptDb for testing (avoids loading better-sqlite3). */
|
|
146
|
+
db?: TranscriptDb;
|
|
147
|
+
/** Override spawn for testing. */
|
|
148
|
+
spawnFn?: typeof spawn;
|
|
149
|
+
/** Override retry timeout for testing (default: 60_000ms). */
|
|
150
|
+
retryTimeoutMs?: number;
|
|
151
|
+
}): Promise<void>;
|
|
152
|
+
//# sourceMappingURL=babysitter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"babysitter.d.ts","sourceRoot":"","sources":["../src/babysitter.ts"],"names":[],"mappings":"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"}
|