@openclaw-cloud/agent-controller 1.0.0-beta.12 → 1.0.0-beta.14

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.
Files changed (38) hide show
  1. package/bin/agent-controller.js +3 -0
  2. package/dist/commands/channel-server.d.ts +17 -0
  3. package/dist/commands/channel-server.js +71 -0
  4. package/dist/commands/channel-server.js.map +1 -0
  5. package/dist/config-file.js +5 -0
  6. package/dist/config-file.js.map +1 -1
  7. package/dist/config.d.ts +10 -0
  8. package/dist/config.js +20 -0
  9. package/dist/config.js.map +1 -1
  10. package/dist/handlers/board-handler.js +32 -19
  11. package/dist/handlers/board-handler.js.map +1 -1
  12. package/dist/handlers/chat.d.ts +15 -0
  13. package/dist/handlers/chat.js +42 -0
  14. package/dist/handlers/chat.js.map +1 -1
  15. package/dist/index.js +24 -0
  16. package/dist/index.js.map +1 -1
  17. package/dist/providers/claude-code/channel-server.d.ts +60 -0
  18. package/dist/providers/claude-code/channel-server.js +155 -0
  19. package/dist/providers/claude-code/channel-server.js.map +1 -0
  20. package/dist/providers/claude-code/index.d.ts +68 -0
  21. package/dist/providers/claude-code/index.js +276 -0
  22. package/dist/providers/claude-code/index.js.map +1 -0
  23. package/dist/providers/claude-code/login-flow.d.ts +26 -0
  24. package/dist/providers/claude-code/login-flow.js +129 -0
  25. package/dist/providers/claude-code/login-flow.js.map +1 -0
  26. package/dist/providers/claude-code/settings-writer.d.ts +29 -0
  27. package/dist/providers/claude-code/settings-writer.js +79 -0
  28. package/dist/providers/claude-code/settings-writer.js.map +1 -0
  29. package/dist/providers/claude-code/socket-bridge.d.ts +88 -0
  30. package/dist/providers/claude-code/socket-bridge.js +288 -0
  31. package/dist/providers/claude-code/socket-bridge.js.map +1 -0
  32. package/dist/providers/claude-code/spawn-claude.d.ts +44 -0
  33. package/dist/providers/claude-code/spawn-claude.js +105 -0
  34. package/dist/providers/claude-code/spawn-claude.js.map +1 -0
  35. package/dist/providers/index.d.ts +3 -1
  36. package/dist/providers/index.js +12 -0
  37. package/dist/providers/index.js.map +1 -1
  38. package/package.json +1 -1
@@ -0,0 +1,129 @@
1
+ import { spawn } from 'node:child_process';
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import os from 'node:os';
5
+ import { logCollector } from '../../connection.js';
6
+ import { toErrorMessage } from '../../utils/response.js';
7
+ const AUTH_URL_RE = /https:\/\/claude\.ai\/oauth\/authorize\?\S+/;
8
+ const DEFAULT_TIMEOUT_MS = 10 * 60 * 1000; // 10 min
9
+ /**
10
+ * Drive the `claude setup-token` subscription login flow.
11
+ *
12
+ * Flow:
13
+ * 1. Spawn `claude setup-token` and watch stdout for the `claude.ai/oauth/authorize?...` URL.
14
+ * 2. Push the URL to chat via `deps.publishLoginUrl`.
15
+ * 3. Await `deps.waitForCode()` — resolves with the code the user submitted.
16
+ * 4. Write `code + "\n"` to subprocess stdin, wait for exit.
17
+ * 5. Verify `~/.claude/.credentials.json` was created/updated → success.
18
+ *
19
+ * Emits structured logCollector events at each milestone.
20
+ */
21
+ export async function runSetupTokenFlow(deps) {
22
+ const spawnFn = deps.spawnFn ?? spawn;
23
+ const credPath = deps.credentialsPath ?? path.join(os.homedir(), '.claude', '.credentials.json');
24
+ const timeoutMs = deps.timeoutMs ?? DEFAULT_TIMEOUT_MS;
25
+ const startedAt = Date.now();
26
+ logCollector?.push('claude_login_start', 'info', 'Starting claude setup-token flow');
27
+ const credMtimeBefore = safeMtime(credPath);
28
+ const child = spawnFn('claude', ['setup-token'], {
29
+ stdio: ['pipe', 'pipe', 'pipe'],
30
+ });
31
+ let stdoutBuf = '';
32
+ let stderrBuf = '';
33
+ let urlPublished = false;
34
+ let codeWritten = false;
35
+ return new Promise((resolve, reject) => {
36
+ const timeoutHandle = setTimeout(() => {
37
+ cleanup();
38
+ logCollector?.push('claude_login_failed', 'error', 'Claude login timed out before completion', { durationMs: Date.now() - startedAt });
39
+ try {
40
+ child.kill('SIGKILL');
41
+ }
42
+ catch {
43
+ /* ignore */
44
+ }
45
+ reject(new Error('claude setup-token timed out'));
46
+ }, timeoutMs);
47
+ const onStdout = (chunk) => {
48
+ const text = chunk.toString();
49
+ stdoutBuf += text;
50
+ if (!urlPublished) {
51
+ const match = stdoutBuf.match(AUTH_URL_RE);
52
+ if (match) {
53
+ urlPublished = true;
54
+ const url = match[0];
55
+ logCollector?.push('claude_login_url_published', 'info', 'Captured OAuth URL', { url });
56
+ Promise.resolve(deps.publishLoginUrl(url))
57
+ .then(() => deps.waitForCode())
58
+ .then((code) => {
59
+ if (!code || typeof code !== 'string') {
60
+ throw new Error('waitForCode returned empty value');
61
+ }
62
+ codeWritten = true;
63
+ logCollector?.push('claude_login_code_received', 'info', 'User submitted code');
64
+ child.stdin.write(code.trim() + '\n');
65
+ child.stdin.end();
66
+ })
67
+ .catch((err) => {
68
+ cleanup();
69
+ logCollector?.push('claude_login_failed', 'error', `Login pre-exit step failed: ${toErrorMessage(err)}`);
70
+ try {
71
+ child.kill('SIGKILL');
72
+ }
73
+ catch {
74
+ /* ignore */
75
+ }
76
+ reject(err instanceof Error ? err : new Error(String(err)));
77
+ });
78
+ }
79
+ }
80
+ };
81
+ const onStderr = (chunk) => {
82
+ stderrBuf += chunk.toString();
83
+ };
84
+ const onError = (err) => {
85
+ cleanup();
86
+ logCollector?.push('claude_login_failed', 'error', `spawn error: ${err.message}`);
87
+ reject(err);
88
+ };
89
+ const onExit = (code) => {
90
+ cleanup();
91
+ if (code === 0 && codeWritten) {
92
+ const credMtimeAfter = safeMtime(credPath);
93
+ const credChanged = credMtimeAfter !== null && credMtimeAfter !== credMtimeBefore;
94
+ if (credChanged) {
95
+ logCollector?.push('claude_login_completed', 'info', 'Claude login succeeded', {
96
+ durationMs: Date.now() - startedAt,
97
+ });
98
+ resolve();
99
+ return;
100
+ }
101
+ logCollector?.push('claude_login_failed', 'error', 'Login exited 0 but credentials file was not updated', { credPath });
102
+ reject(new Error('credentials file not updated after setup-token'));
103
+ return;
104
+ }
105
+ logCollector?.push('claude_login_failed', 'error', `claude setup-token exited with code ${code ?? 'null'}`, { stderrTail: stderrBuf.slice(-500) });
106
+ reject(new Error(`claude setup-token exited with code ${code ?? 'null'}`));
107
+ };
108
+ function cleanup() {
109
+ clearTimeout(timeoutHandle);
110
+ child.stdout.off('data', onStdout);
111
+ child.stderr.off('data', onStderr);
112
+ child.off('error', onError);
113
+ child.off('exit', onExit);
114
+ }
115
+ child.stdout.on('data', onStdout);
116
+ child.stderr.on('data', onStderr);
117
+ child.on('error', onError);
118
+ child.on('exit', onExit);
119
+ });
120
+ }
121
+ function safeMtime(p) {
122
+ try {
123
+ return fs.statSync(p).mtimeMs;
124
+ }
125
+ catch {
126
+ return null;
127
+ }
128
+ }
129
+ //# sourceMappingURL=login-flow.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"login-flow.js","sourceRoot":"","sources":["../../../src/providers/claude-code/login-flow.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,29 @@
1
+ export interface ClaudeCodeSettingsContext {
2
+ /** Absolute path to the Claude workspace (cwd of `claude` process) */
3
+ workspaceDir: string;
4
+ /** Anthropic API key. If prefixed with `sk-ant-oat` → treated as OAuth token. */
5
+ anthropicApiKey?: string;
6
+ /** Alternative: explicit auth token (takes precedence over anthropicApiKey) */
7
+ anthropicAuthToken?: string;
8
+ /** Backend URL for the openclaw-backend MCP server entry */
9
+ backendUrl?: string;
10
+ /** Bearer token for the openclaw-backend MCP server */
11
+ agentToken?: string;
12
+ /** Content of CLAUDE.md to write into the workspace (persona / bootstrap) */
13
+ claudeMdContent?: string;
14
+ /** Port of the local agent-memory MCP server (defaults to 3457). */
15
+ memoryMcpPort?: number;
16
+ /** Absolute path to the `agent-controller` bin. Defaults to `agent-controller` on PATH. */
17
+ agentControllerBin?: string;
18
+ /** Override the socket path (tests). */
19
+ channelSocketPath?: string;
20
+ }
21
+ /**
22
+ * Write `.claude/settings.json`, `.mcp.json`, and `CLAUDE.md` into the workspace.
23
+ *
24
+ * Idempotent — overwrites each call. Mirrors the logic in
25
+ * `src/utils/claude-env.ts` for OAuth vs API-key auth.
26
+ */
27
+ export declare function writeClaudeCodeSettings(ctx: ClaudeCodeSettingsContext): Promise<void>;
28
+ export declare function buildSettings(ctx: ClaudeCodeSettingsContext): Record<string, unknown>;
29
+ export declare function buildMcpJson(ctx: ClaudeCodeSettingsContext): Record<string, unknown>;
@@ -0,0 +1,79 @@
1
+ import fs from 'node:fs/promises';
2
+ import path from 'node:path';
3
+ import { config } from '../../config.js';
4
+ /**
5
+ * Write `.claude/settings.json`, `.mcp.json`, and `CLAUDE.md` into the workspace.
6
+ *
7
+ * Idempotent — overwrites each call. Mirrors the logic in
8
+ * `src/utils/claude-env.ts` for OAuth vs API-key auth.
9
+ */
10
+ export async function writeClaudeCodeSettings(ctx) {
11
+ const { workspaceDir } = ctx;
12
+ const dotClaude = path.join(workspaceDir, '.claude');
13
+ await fs.mkdir(dotClaude, { recursive: true });
14
+ await fs.writeFile(path.join(dotClaude, 'settings.json'), JSON.stringify(buildSettings(ctx), null, 2) + '\n');
15
+ await fs.writeFile(path.join(workspaceDir, '.mcp.json'), JSON.stringify(buildMcpJson(ctx), null, 2) + '\n');
16
+ if (ctx.claudeMdContent !== undefined) {
17
+ await fs.writeFile(path.join(workspaceDir, 'CLAUDE.md'), ctx.claudeMdContent);
18
+ }
19
+ }
20
+ // ---------------------------------------------------------------------------
21
+ // Builders (exported for unit tests)
22
+ // ---------------------------------------------------------------------------
23
+ export function buildSettings(ctx) {
24
+ const permissions = { allow: ['Bash(*)', 'Read(*)', 'Write(*)', 'Edit(*)', 'mcp__*'] };
25
+ // Token precedence: explicit auth token > API key that looks like OAuth > API key
26
+ const authToken = ctx.anthropicAuthToken?.trim();
27
+ const apiKey = ctx.anthropicApiKey?.trim();
28
+ if (authToken) {
29
+ return { permissions, env: { ANTHROPIC_AUTH_TOKEN: authToken } };
30
+ }
31
+ if (apiKey?.startsWith('sk-ant-oat')) {
32
+ return { permissions, env: { ANTHROPIC_AUTH_TOKEN: apiKey } };
33
+ }
34
+ if (apiKey) {
35
+ return {
36
+ permissions,
37
+ env: { ANTHROPIC_API_KEY: apiKey },
38
+ };
39
+ }
40
+ // No static credentials: rely on ~/.claude/.credentials.json (subscription login)
41
+ return { permissions };
42
+ }
43
+ export function buildMcpJson(ctx) {
44
+ const memoryPort = ctx.memoryMcpPort ?? 3457;
45
+ const servers = {
46
+ 'agent-memory': {
47
+ type: 'http',
48
+ url: `http://127.0.0.1:${memoryPort}/mcp`,
49
+ },
50
+ };
51
+ const backendUrl = ctx.backendUrl ?? config.backendUrl;
52
+ const token = ctx.agentToken ?? config.agentToken;
53
+ if (backendUrl && token) {
54
+ servers['openclaw-backend'] = {
55
+ type: 'http',
56
+ url: `${backendUrl.replace(/\/+$/, '')}/mcp`,
57
+ headers: { Authorization: `Bearer ${token}` },
58
+ };
59
+ }
60
+ // Channel server — spawned by Claude Code as a stdio MCP plugin. Declares
61
+ // the `experimental.claude/channel` capability, so Claude routes inbound
62
+ // chat traffic through it (and invokes the `reply`/`edit_message` tools
63
+ // when it wants to reply to the user).
64
+ //
65
+ // We use a plain stdio MCP entry (Option B) rather than Claude's `--channels
66
+ // plugin:` install mechanism — it avoids any out-of-band plugin install
67
+ // step and works with stock Claude Code.
68
+ const binary = ctx.agentControllerBin?.trim() || 'agent-controller';
69
+ const channelArgs = ['channel-server'];
70
+ if (ctx.channelSocketPath) {
71
+ channelArgs.push('--socket-path', ctx.channelSocketPath);
72
+ }
73
+ servers['agent-controller-channel'] = {
74
+ command: binary,
75
+ args: channelArgs,
76
+ };
77
+ return { mcpServers: servers };
78
+ }
79
+ //# sourceMappingURL=settings-writer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"settings-writer.js","sourceRoot":"","sources":["../../../src/providers/claude-code/settings-writer.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,88 @@
1
+ import { EventEmitter } from 'node:events';
2
+ import type { ChannelReply, ChannelMessageMeta, ChannelReplyMeta } from './channel-server.js';
3
+ /**
4
+ * Unix-domain-socket bridge between the main agent-controller process and the
5
+ * channel-server worker that holds Claude Code's stdio MCP channel.
6
+ *
7
+ * Protocol: newline-delimited JSON. Ops:
8
+ * { op: "hello", pid } — worker → main
9
+ * { op: "reply", content, meta } — worker → main (Claude reply tool)
10
+ * { op: "edit", content, meta } — worker → main (Claude edit_message tool)
11
+ * { op: "push", content, meta } — main → worker (inbound chat msg)
12
+ *
13
+ * Liberal parsing: malformed lines are logged + dropped (never crash the link).
14
+ */
15
+ export declare const DEFAULT_SOCKET_PATH: string;
16
+ export type SocketOp = {
17
+ op: 'hello';
18
+ pid: number;
19
+ } | {
20
+ op: 'reply';
21
+ content: string;
22
+ meta: ChannelReplyMeta;
23
+ } | {
24
+ op: 'edit';
25
+ content: string;
26
+ meta: ChannelReplyMeta;
27
+ } | {
28
+ op: 'push';
29
+ content: string;
30
+ meta: ChannelMessageMeta;
31
+ };
32
+ export interface ChannelBridgeServerEvents {
33
+ connect: [pid: number | null];
34
+ reply: [content: string, meta: ChannelReplyMeta, tool: 'reply' | 'edit_message'];
35
+ close: [];
36
+ error: [err: Error];
37
+ }
38
+ /**
39
+ * Server side — lives in the main agent-controller process.
40
+ *
41
+ * Accepts exactly one worker connection (extras are rejected + closed). Emits
42
+ * reply/edit ops; callers invoke `push(content, meta)` to emit an inbound
43
+ * chat message to the worker.
44
+ */
45
+ export declare class ChannelBridgeServer extends EventEmitter {
46
+ private readonly opts;
47
+ private server;
48
+ private active;
49
+ private buf;
50
+ constructor(opts?: {
51
+ socketPath?: string;
52
+ });
53
+ get socketPath(): string;
54
+ listen(): Promise<void>;
55
+ private handleConnection;
56
+ private ingest;
57
+ private dispatch;
58
+ /** Push an inbound chat message to the worker (→ Claude MCP notification). */
59
+ push(content: string, meta: ChannelMessageMeta): void;
60
+ private write;
61
+ close(): Promise<void>;
62
+ isConnected(): boolean;
63
+ }
64
+ /**
65
+ * Client side — lives in the channel-server worker subprocess.
66
+ *
67
+ * Connects to the bridge socket with retry/backoff (up to 30s). Parses
68
+ * incoming `push` ops and forwards outgoing `reply`/`edit` ops.
69
+ */
70
+ export declare class ChannelBridgeClient extends EventEmitter {
71
+ private readonly opts;
72
+ private sock;
73
+ private buf;
74
+ private closed;
75
+ constructor(opts?: {
76
+ socketPath?: string;
77
+ maxWaitMs?: number;
78
+ });
79
+ get socketPath(): string;
80
+ connect(): Promise<void>;
81
+ private connectOnce;
82
+ sendHello(pid: number): void;
83
+ sendReply(content: string, meta: ChannelReplyMeta, tool: 'reply' | 'edit_message'): void;
84
+ private ingest;
85
+ private write;
86
+ close(): void;
87
+ }
88
+ export type { ChannelReply, ChannelMessageMeta, ChannelReplyMeta };
@@ -0,0 +1,288 @@
1
+ import net from 'node:net';
2
+ import fs from 'node:fs';
3
+ import path from 'node:path';
4
+ import os from 'node:os';
5
+ import { EventEmitter } from 'node:events';
6
+ import { logCollector } from '../../connection.js';
7
+ import { toErrorMessage } from '../../utils/response.js';
8
+ /**
9
+ * Unix-domain-socket bridge between the main agent-controller process and the
10
+ * channel-server worker that holds Claude Code's stdio MCP channel.
11
+ *
12
+ * Protocol: newline-delimited JSON. Ops:
13
+ * { op: "hello", pid } — worker → main
14
+ * { op: "reply", content, meta } — worker → main (Claude reply tool)
15
+ * { op: "edit", content, meta } — worker → main (Claude edit_message tool)
16
+ * { op: "push", content, meta } — main → worker (inbound chat msg)
17
+ *
18
+ * Liberal parsing: malformed lines are logged + dropped (never crash the link).
19
+ */
20
+ export const DEFAULT_SOCKET_PATH = path.join(os.homedir(), '.openclaw', 'claude-channel.sock');
21
+ /**
22
+ * Server side — lives in the main agent-controller process.
23
+ *
24
+ * Accepts exactly one worker connection (extras are rejected + closed). Emits
25
+ * reply/edit ops; callers invoke `push(content, meta)` to emit an inbound
26
+ * chat message to the worker.
27
+ */
28
+ export class ChannelBridgeServer extends EventEmitter {
29
+ opts;
30
+ server = null;
31
+ active = null;
32
+ buf = '';
33
+ constructor(opts = {}) {
34
+ super();
35
+ this.opts = opts;
36
+ }
37
+ get socketPath() {
38
+ return this.opts.socketPath ?? DEFAULT_SOCKET_PATH;
39
+ }
40
+ async listen() {
41
+ const p = this.socketPath;
42
+ await fs.promises.mkdir(path.dirname(p), { recursive: true });
43
+ // Best-effort: remove stale socket file from a previous crash.
44
+ try {
45
+ await fs.promises.unlink(p);
46
+ }
47
+ catch {
48
+ /* not present */
49
+ }
50
+ return new Promise((resolve, reject) => {
51
+ const srv = net.createServer((sock) => this.handleConnection(sock));
52
+ srv.on('error', (err) => {
53
+ logCollector?.push('channel_bridge_error', 'error', `bridge server error: ${err.message}`);
54
+ this.emit('error', err);
55
+ });
56
+ srv.listen(p, () => {
57
+ this.server = srv;
58
+ logCollector?.push('channel_bridge_listening', 'info', `channel bridge on ${p}`);
59
+ resolve();
60
+ });
61
+ srv.once('error', (err) => reject(err));
62
+ });
63
+ }
64
+ handleConnection(sock) {
65
+ if (this.active) {
66
+ // Reject extras — we expect exactly one worker.
67
+ logCollector?.push('channel_bridge_reject_extra', 'warn', 'extra worker connection rejected — one worker already active');
68
+ try {
69
+ sock.end();
70
+ }
71
+ catch {
72
+ /* ignore */
73
+ }
74
+ return;
75
+ }
76
+ this.active = sock;
77
+ sock.setEncoding('utf8');
78
+ sock.on('data', (chunk) => this.ingest(String(chunk)));
79
+ sock.on('close', () => {
80
+ this.active = null;
81
+ this.buf = '';
82
+ logCollector?.push('channel_bridge_closed', 'info', 'worker connection closed');
83
+ this.emit('close');
84
+ });
85
+ sock.on('error', (err) => {
86
+ logCollector?.push('channel_bridge_sock_error', 'warn', `worker socket error: ${err.message}`);
87
+ });
88
+ }
89
+ ingest(chunk) {
90
+ this.buf += chunk;
91
+ let idx;
92
+ while ((idx = this.buf.indexOf('\n')) >= 0) {
93
+ const line = this.buf.slice(0, idx).trim();
94
+ this.buf = this.buf.slice(idx + 1);
95
+ if (!line)
96
+ continue;
97
+ let msg = null;
98
+ try {
99
+ msg = JSON.parse(line);
100
+ }
101
+ catch {
102
+ logCollector?.push('channel_bridge_bad_line', 'warn', 'dropped malformed bridge line');
103
+ continue;
104
+ }
105
+ this.dispatch(msg);
106
+ }
107
+ }
108
+ dispatch(msg) {
109
+ if (!msg || typeof msg !== 'object' || !msg.op)
110
+ return;
111
+ switch (msg.op) {
112
+ case 'hello': {
113
+ const pid = typeof msg.pid === 'number' ? msg.pid : null;
114
+ logCollector?.push('channel_bridge_hello', 'info', `worker hello pid=${pid ?? 'unknown'}`);
115
+ this.emit('connect', pid);
116
+ break;
117
+ }
118
+ case 'reply': {
119
+ const m = msg;
120
+ const content = typeof m.content === 'string' ? m.content : '';
121
+ const meta = (m.meta ?? {});
122
+ this.emit('reply', content, meta, 'reply');
123
+ break;
124
+ }
125
+ case 'edit': {
126
+ const m = msg;
127
+ const content = typeof m.content === 'string' ? m.content : '';
128
+ const meta = (m.meta ?? {});
129
+ this.emit('reply', content, meta, 'edit_message');
130
+ break;
131
+ }
132
+ default:
133
+ logCollector?.push('channel_bridge_unknown_op', 'warn', `unknown op: ${String(msg.op)}`);
134
+ }
135
+ }
136
+ /** Push an inbound chat message to the worker (→ Claude MCP notification). */
137
+ push(content, meta) {
138
+ this.write({ op: 'push', content, meta });
139
+ }
140
+ write(op) {
141
+ if (!this.active) {
142
+ logCollector?.push('channel_bridge_no_worker', 'warn', `dropped op ${op.op} — no worker`);
143
+ return;
144
+ }
145
+ try {
146
+ this.active.write(JSON.stringify(op) + '\n');
147
+ }
148
+ catch (err) {
149
+ logCollector?.push('channel_bridge_write_error', 'warn', `write ${op.op} failed: ${toErrorMessage(err)}`);
150
+ }
151
+ }
152
+ async close() {
153
+ try {
154
+ this.active?.end();
155
+ }
156
+ catch {
157
+ /* ignore */
158
+ }
159
+ this.active = null;
160
+ if (!this.server)
161
+ return;
162
+ const srv = this.server;
163
+ this.server = null;
164
+ await new Promise((resolve) => srv.close(() => resolve()));
165
+ try {
166
+ await fs.promises.unlink(this.socketPath);
167
+ }
168
+ catch {
169
+ /* ignore */
170
+ }
171
+ }
172
+ isConnected() {
173
+ return !!this.active;
174
+ }
175
+ }
176
+ /**
177
+ * Client side — lives in the channel-server worker subprocess.
178
+ *
179
+ * Connects to the bridge socket with retry/backoff (up to 30s). Parses
180
+ * incoming `push` ops and forwards outgoing `reply`/`edit` ops.
181
+ */
182
+ export class ChannelBridgeClient extends EventEmitter {
183
+ opts;
184
+ sock = null;
185
+ buf = '';
186
+ closed = false;
187
+ constructor(opts = {}) {
188
+ super();
189
+ this.opts = opts;
190
+ }
191
+ get socketPath() {
192
+ return this.opts.socketPath ?? DEFAULT_SOCKET_PATH;
193
+ }
194
+ async connect() {
195
+ const maxWait = this.opts.maxWaitMs ?? 30_000;
196
+ const started = Date.now();
197
+ let attempt = 0;
198
+ // Retry with capped exponential backoff while the main process comes up.
199
+ while (true) {
200
+ try {
201
+ await this.connectOnce();
202
+ return;
203
+ }
204
+ catch (err) {
205
+ if (Date.now() - started > maxWait) {
206
+ throw err instanceof Error ? err : new Error(String(err));
207
+ }
208
+ attempt += 1;
209
+ const delay = Math.min(2000, 100 * 2 ** Math.min(attempt, 6));
210
+ await new Promise((r) => setTimeout(r, delay));
211
+ }
212
+ }
213
+ }
214
+ connectOnce() {
215
+ return new Promise((resolve, reject) => {
216
+ const s = net.createConnection({ path: this.socketPath });
217
+ const onError = (err) => {
218
+ s.removeAllListeners();
219
+ reject(err);
220
+ };
221
+ s.once('error', onError);
222
+ s.once('connect', () => {
223
+ s.removeListener('error', onError);
224
+ s.setEncoding('utf8');
225
+ this.sock = s;
226
+ s.on('data', (chunk) => this.ingest(String(chunk)));
227
+ s.on('close', () => {
228
+ this.sock = null;
229
+ this.buf = '';
230
+ if (!this.closed)
231
+ this.emit('close');
232
+ });
233
+ s.on('error', (err) => this.emit('error', err));
234
+ resolve();
235
+ });
236
+ });
237
+ }
238
+ sendHello(pid) {
239
+ this.write({ op: 'hello', pid });
240
+ }
241
+ sendReply(content, meta, tool) {
242
+ this.write({ op: tool === 'edit_message' ? 'edit' : 'reply', content, meta });
243
+ }
244
+ ingest(chunk) {
245
+ this.buf += chunk;
246
+ let idx;
247
+ while ((idx = this.buf.indexOf('\n')) >= 0) {
248
+ const line = this.buf.slice(0, idx).trim();
249
+ this.buf = this.buf.slice(idx + 1);
250
+ if (!line)
251
+ continue;
252
+ let msg = null;
253
+ try {
254
+ msg = JSON.parse(line);
255
+ }
256
+ catch {
257
+ continue;
258
+ }
259
+ if (msg && msg.op === 'push') {
260
+ const m = msg;
261
+ const content = typeof m.content === 'string' ? m.content : '';
262
+ const meta = (m.meta ?? {});
263
+ this.emit('push', content, meta);
264
+ }
265
+ }
266
+ }
267
+ write(op) {
268
+ if (!this.sock)
269
+ return;
270
+ try {
271
+ this.sock.write(JSON.stringify(op) + '\n');
272
+ }
273
+ catch {
274
+ /* ignore — socket will emit close/error */
275
+ }
276
+ }
277
+ close() {
278
+ this.closed = true;
279
+ try {
280
+ this.sock?.end();
281
+ }
282
+ catch {
283
+ /* ignore */
284
+ }
285
+ this.sock = null;
286
+ }
287
+ }
288
+ //# sourceMappingURL=socket-bridge.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"socket-bridge.js","sourceRoot":"","sources":["../../../src/providers/claude-code/socket-bridge.ts"],"names":[],"mappings":"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"}