@cydm/magic-shell-agent-node 0.1.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.
Files changed (58) hide show
  1. package/dist/adapters/pty-adapter.d.ts +18 -0
  2. package/dist/adapters/pty-adapter.js +99 -0
  3. package/dist/adapters/registry.d.ts +28 -0
  4. package/dist/adapters/registry.js +64 -0
  5. package/dist/adapters/rpc-adapter.d.ts +19 -0
  6. package/dist/adapters/rpc-adapter.js +182 -0
  7. package/dist/adapters/stdio-adapter.d.ts +17 -0
  8. package/dist/adapters/stdio-adapter.js +107 -0
  9. package/dist/adapters/types.d.ts +17 -0
  10. package/dist/adapters/types.js +2 -0
  11. package/dist/claude-exec.d.ts +11 -0
  12. package/dist/claude-exec.js +54 -0
  13. package/dist/claude-worker.d.ts +12 -0
  14. package/dist/claude-worker.js +163 -0
  15. package/dist/codex-exec.d.ts +12 -0
  16. package/dist/codex-exec.js +84 -0
  17. package/dist/codex-worker.d.ts +12 -0
  18. package/dist/codex-worker.js +179 -0
  19. package/dist/directory-browser.d.ts +3 -0
  20. package/dist/directory-browser.js +48 -0
  21. package/dist/index.d.ts +2 -0
  22. package/dist/index.js +2 -0
  23. package/dist/local-direct-server.d.ts +38 -0
  24. package/dist/local-direct-server.js +266 -0
  25. package/dist/node-conversation.d.ts +21 -0
  26. package/dist/node-conversation.js +28 -0
  27. package/dist/node-intent.d.ts +2 -0
  28. package/dist/node-intent.js +40 -0
  29. package/dist/node-reply.d.ts +30 -0
  30. package/dist/node-reply.js +77 -0
  31. package/dist/node.d.ts +132 -0
  32. package/dist/node.js +1954 -0
  33. package/dist/pie-session-control.d.ts +21 -0
  34. package/dist/pie-session-control.js +28 -0
  35. package/dist/plugin-loader.d.ts +19 -0
  36. package/dist/plugin-loader.js +144 -0
  37. package/dist/plugins/pie.json +7 -0
  38. package/dist/primary-agent-bridge.d.ts +69 -0
  39. package/dist/primary-agent-bridge.js +282 -0
  40. package/dist/session-manager.d.ts +66 -0
  41. package/dist/session-manager.js +197 -0
  42. package/dist/terminal-metadata.d.ts +7 -0
  43. package/dist/terminal-metadata.js +52 -0
  44. package/dist/types.d.ts +1 -0
  45. package/dist/types.js +1 -0
  46. package/dist/worker-control.d.ts +15 -0
  47. package/dist/worker-control.js +89 -0
  48. package/dist/worker-narration.d.ts +25 -0
  49. package/dist/worker-narration.js +90 -0
  50. package/dist/worker-output.d.ts +6 -0
  51. package/dist/worker-output.js +72 -0
  52. package/dist/worker-registry.d.ts +45 -0
  53. package/dist/worker-registry.js +501 -0
  54. package/dist/worker-runtime.d.ts +18 -0
  55. package/dist/worker-runtime.js +69 -0
  56. package/dist/ws-client.d.ts +68 -0
  57. package/dist/ws-client.js +193 -0
  58. package/package.json +38 -0
@@ -0,0 +1,18 @@
1
+ import type { AgentAdapter, AdapterInput, AdapterOutput, PluginConfig } from "./types.js";
2
+ export declare class PtyAdapter implements AgentAdapter {
3
+ readonly name = "pty";
4
+ readonly description = "PTY native terminal adapter (supports vim, tmux)";
5
+ readonly capabilities: string[];
6
+ private agents;
7
+ private outputCallbacks;
8
+ private exitCallbacks;
9
+ canHandle(type: string): boolean;
10
+ start(config: PluginConfig): Promise<string>;
11
+ stop(agentId: string): Promise<void>;
12
+ sendInput(agentId: string, input: AdapterInput): void;
13
+ sendRawInput(agentId: string, data: string): void;
14
+ resize(agentId: string, cols: number, rows: number): void;
15
+ isRunning(agentId: string): boolean;
16
+ onOutput(callback: (agentId: string, output: AdapterOutput) => void): void;
17
+ onExit(callback: (agentId: string, code: number | null) => void): void;
18
+ }
@@ -0,0 +1,99 @@
1
+ import { spawn } from "node-pty";
2
+ import { dirname } from "path";
3
+ import { fileURLToPath } from "url";
4
+ const __filename = fileURLToPath(import.meta.url);
5
+ const __dirname = dirname(__filename);
6
+ export class PtyAdapter {
7
+ name = "pty";
8
+ description = "PTY native terminal adapter (supports vim, tmux)";
9
+ capabilities = ["pty", "terminal", "ansi256", "interactive"];
10
+ agents = new Map();
11
+ outputCallbacks = [];
12
+ exitCallbacks = [];
13
+ canHandle(type) {
14
+ // PTY 可以处理任何类型
15
+ return true;
16
+ }
17
+ async start(config) {
18
+ const agentId = `pty-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
19
+ const pty = spawn(config.command, config.args || [], {
20
+ name: "xterm-256color",
21
+ cols: 80,
22
+ rows: 24,
23
+ cwd: config.cwd || process.cwd(),
24
+ env: { ...process.env, ...config.env },
25
+ });
26
+ const agent = {
27
+ id: agentId,
28
+ pty,
29
+ config,
30
+ };
31
+ agent.outputCallback = (output) => {
32
+ for (const callback of this.outputCallbacks) {
33
+ callback(agentId, output);
34
+ }
35
+ };
36
+ agent.exitCallback = (code) => {
37
+ for (const callback of this.exitCallbacks) {
38
+ callback(agentId, code);
39
+ }
40
+ };
41
+ // 处理输出
42
+ pty.onData((data) => {
43
+ console.log(`[PtyAdapter ${agentId}] onData: ${data.length} chars, callback=${!!agent.outputCallback}`);
44
+ agent.outputCallback?.({
45
+ timestamp: Date.now(),
46
+ type: "output",
47
+ content: data,
48
+ });
49
+ });
50
+ // 处理退出
51
+ pty.onExit(({ exitCode, signal }) => {
52
+ console.log(`[PtyAdapter] Agent ${agentId} exited: code=${exitCode}, signal=${signal}`);
53
+ agent.exitCallback?.(exitCode);
54
+ this.agents.delete(agentId);
55
+ });
56
+ this.agents.set(agentId, agent);
57
+ console.log(`[PtyAdapter] Started ${agentId}: ${config.command}`);
58
+ return agentId;
59
+ }
60
+ async stop(agentId) {
61
+ const agent = this.agents.get(agentId);
62
+ if (!agent)
63
+ return;
64
+ agent.pty.kill();
65
+ this.agents.delete(agentId);
66
+ console.log(`[PtyAdapter] Stopped ${agentId}`);
67
+ }
68
+ sendInput(agentId, input) {
69
+ // 普通输入
70
+ this.sendRawInput(agentId, input.text);
71
+ }
72
+ sendRawInput(agentId, data) {
73
+ const agent = this.agents.get(agentId);
74
+ if (!agent) {
75
+ console.warn(`[PtyAdapter] Agent ${agentId} not found`);
76
+ return;
77
+ }
78
+ agent.pty.write(data);
79
+ }
80
+ resize(agentId, cols, rows) {
81
+ const agent = this.agents.get(agentId);
82
+ if (!agent)
83
+ return;
84
+ agent.pty.resize(cols, rows);
85
+ }
86
+ isRunning(agentId) {
87
+ const agent = this.agents.get(agentId);
88
+ if (!agent)
89
+ return false;
90
+ // node-pty 没有直接的 running 状态,检查是否还在 agents Map 中
91
+ return true;
92
+ }
93
+ onOutput(callback) {
94
+ this.outputCallbacks.push(callback);
95
+ }
96
+ onExit(callback) {
97
+ this.exitCallbacks.push(callback);
98
+ }
99
+ }
@@ -0,0 +1,28 @@
1
+ import type { AgentAdapter, PluginConfig } from "./types.js";
2
+ /**
3
+ * 适配器注册表
4
+ * 管理所有可用的 Agent 适配器,根据配置自动选择
5
+ */
6
+ export declare class AdapterRegistry {
7
+ private adapters;
8
+ private defaultAdapter?;
9
+ constructor();
10
+ /**
11
+ * 注册自定义适配器
12
+ */
13
+ register(adapter: AgentAdapter): void;
14
+ /**
15
+ * 根据插件配置查找适配器
16
+ * 优先匹配显式 type,其次匹配 canHandle,最后使用默认
17
+ */
18
+ findAdapter(config: PluginConfig): AgentAdapter;
19
+ /**
20
+ * 列出所有已注册的适配器
21
+ */
22
+ listAdapters(): Array<{
23
+ name: string;
24
+ description: string;
25
+ capabilities: string[];
26
+ }>;
27
+ }
28
+ export declare const adapterRegistry: AdapterRegistry;
@@ -0,0 +1,64 @@
1
+ import { PtyAdapter } from "./pty-adapter.js";
2
+ import { StdioAdapter } from "./stdio-adapter.js";
3
+ import { RpcAdapter } from "./rpc-adapter.js";
4
+ /**
5
+ * 适配器注册表
6
+ * 管理所有可用的 Agent 适配器,根据配置自动选择
7
+ */
8
+ export class AdapterRegistry {
9
+ adapters = [];
10
+ defaultAdapter;
11
+ constructor() {
12
+ // 注册内置适配器
13
+ this.register(new PtyAdapter());
14
+ this.register(new StdioAdapter());
15
+ this.register(new RpcAdapter());
16
+ // PTY 作为默认适配器(通用性最强)
17
+ this.defaultAdapter = this.adapters[0];
18
+ }
19
+ /**
20
+ * 注册自定义适配器
21
+ */
22
+ register(adapter) {
23
+ this.adapters.push(adapter);
24
+ console.log(`[AdapterRegistry] Registered: ${adapter.name} - ${adapter.description}`);
25
+ }
26
+ /**
27
+ * 根据插件配置查找适配器
28
+ * 优先匹配显式 type,其次匹配 canHandle,最后使用默认
29
+ */
30
+ findAdapter(config) {
31
+ // 1. 根据 type 精确匹配,确保插件声明的适配器类型真正生效
32
+ for (const adapter of this.adapters) {
33
+ if (adapter.name === config.type) {
34
+ console.log(`[AdapterRegistry] Found by type: ${adapter.name}`);
35
+ return adapter;
36
+ }
37
+ }
38
+ // 2. 回退到能力匹配,允许通用适配器兜底
39
+ for (const adapter of this.adapters) {
40
+ if (adapter.canHandle(config.type)) {
41
+ console.log(`[AdapterRegistry] Found by canHandle: ${adapter.name} for type=${config.type}`);
42
+ return adapter;
43
+ }
44
+ }
45
+ // 3. 返回默认适配器
46
+ if (this.defaultAdapter) {
47
+ console.log(`[AdapterRegistry] Using default: ${this.defaultAdapter.name}`);
48
+ return this.defaultAdapter;
49
+ }
50
+ throw new Error(`No adapter available for type: ${config.type}`);
51
+ }
52
+ /**
53
+ * 列出所有已注册的适配器
54
+ */
55
+ listAdapters() {
56
+ return this.adapters.map((a) => ({
57
+ name: a.name,
58
+ description: a.description,
59
+ capabilities: a.capabilities,
60
+ }));
61
+ }
62
+ }
63
+ // 全局单例
64
+ export const adapterRegistry = new AdapterRegistry();
@@ -0,0 +1,19 @@
1
+ import type { AgentAdapter, AdapterInput, AdapterOutput, PluginConfig } from "./types.js";
2
+ export declare class RpcAdapter implements AgentAdapter {
3
+ readonly name = "rpc";
4
+ readonly description = "JSON-RPC adapter for line-oriented RPC workers";
5
+ readonly capabilities: string[];
6
+ private agents;
7
+ private outputCallbacks;
8
+ private exitCallbacks;
9
+ canHandle(type: string): boolean;
10
+ start(config: PluginConfig): Promise<string>;
11
+ private handleLine;
12
+ private handleRpcEvent;
13
+ stop(agentId: string): Promise<void>;
14
+ sendInput(agentId: string, input: AdapterInput): void;
15
+ sendRawInput(agentId: string, data: string): void;
16
+ isRunning(agentId: string): boolean;
17
+ onOutput(callback: (agentId: string, output: AdapterOutput) => void): void;
18
+ onExit(callback: (agentId: string, code: number | null) => void): void;
19
+ }
@@ -0,0 +1,182 @@
1
+ import { spawn } from "child_process";
2
+ export class RpcAdapter {
3
+ name = "rpc";
4
+ description = "JSON-RPC adapter for line-oriented RPC workers";
5
+ capabilities = ["json-rpc", "tool-call", "streaming"];
6
+ agents = new Map();
7
+ outputCallbacks = [];
8
+ exitCallbacks = [];
9
+ canHandle(type) {
10
+ return type === "rpc";
11
+ }
12
+ async start(config) {
13
+ const agentId = `rpc-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
14
+ const proc = spawn(config.command, config.args || [], {
15
+ cwd: config.cwd || process.cwd(),
16
+ env: { ...process.env, ...config.env },
17
+ stdio: ["pipe", "pipe", "pipe"],
18
+ });
19
+ const agent = {
20
+ id: agentId,
21
+ process: proc,
22
+ config,
23
+ buffer: "",
24
+ };
25
+ agent.outputCallback = (output) => {
26
+ for (const callback of this.outputCallbacks) {
27
+ callback(agentId, output);
28
+ }
29
+ };
30
+ agent.exitCallback = (code) => {
31
+ for (const callback of this.exitCallbacks) {
32
+ callback(agentId, code);
33
+ }
34
+ };
35
+ // 处理 stdout(JSON 行协议)
36
+ proc.stdout?.on("data", (data) => {
37
+ const text = data.toString("utf-8");
38
+ agent.buffer += text;
39
+ // 按行分割处理
40
+ const lines = agent.buffer.split("\n");
41
+ agent.buffer = lines.pop() || ""; // 保留未完成的行
42
+ for (const line of lines) {
43
+ if (line.trim()) {
44
+ this.handleLine(agent, line);
45
+ }
46
+ }
47
+ });
48
+ // 处理 stderr
49
+ proc.stderr?.on("data", (data) => {
50
+ agent.outputCallback?.({
51
+ timestamp: Date.now(),
52
+ type: "error",
53
+ content: data.toString("utf-8"),
54
+ });
55
+ });
56
+ // 处理退出
57
+ proc.on("close", (code) => {
58
+ console.log(`[RpcAdapter] Agent ${agentId} exited: code=${code}`);
59
+ agent.exitCallback?.(code);
60
+ this.agents.delete(agentId);
61
+ });
62
+ this.agents.set(agentId, agent);
63
+ console.log(`[RpcAdapter] Started ${agentId}: ${config.command}`);
64
+ return agentId;
65
+ }
66
+ handleLine(agent, line) {
67
+ try {
68
+ const event = JSON.parse(line);
69
+ this.handleRpcEvent(agent, event);
70
+ }
71
+ catch {
72
+ // 非 JSON 行,当作普通输出
73
+ agent.outputCallback?.({
74
+ timestamp: Date.now(),
75
+ type: "output",
76
+ content: line,
77
+ });
78
+ }
79
+ }
80
+ handleRpcEvent(agent, event) {
81
+ switch (event.type) {
82
+ case "thinking_delta": {
83
+ const content = event.delta || event.partial?.thinking || "";
84
+ if (content) {
85
+ agent.outputCallback?.({
86
+ timestamp: Date.now(),
87
+ type: "output",
88
+ content,
89
+ });
90
+ }
91
+ break;
92
+ }
93
+ case "toolcall_start": {
94
+ const toolCall = event.toolCall || event.partial?.toolCall;
95
+ if (toolCall?.name) {
96
+ agent.outputCallback?.({
97
+ timestamp: Date.now(),
98
+ type: "system",
99
+ content: `🔧 Tool: ${toolCall.name} ${JSON.stringify(toolCall.arguments || {})}`,
100
+ });
101
+ }
102
+ break;
103
+ }
104
+ case "text_delta":
105
+ case "content_block_delta": {
106
+ const text = event.delta?.text || event.delta || "";
107
+ if (text) {
108
+ agent.outputCallback?.({
109
+ timestamp: Date.now(),
110
+ type: "output",
111
+ content: text,
112
+ });
113
+ }
114
+ break;
115
+ }
116
+ case "message":
117
+ case "message_end": {
118
+ if (event.message?.content) {
119
+ agent.outputCallback?.({
120
+ timestamp: Date.now(),
121
+ type: "output",
122
+ content: event.message.content,
123
+ });
124
+ }
125
+ break;
126
+ }
127
+ case "error": {
128
+ agent.outputCallback?.({
129
+ timestamp: Date.now(),
130
+ type: "error",
131
+ content: event.message || "Unknown error",
132
+ });
133
+ break;
134
+ }
135
+ default:
136
+ // 忽略其他事件类型
137
+ break;
138
+ }
139
+ }
140
+ async stop(agentId) {
141
+ const agent = this.agents.get(agentId);
142
+ if (!agent)
143
+ return;
144
+ agent.process.kill();
145
+ this.agents.delete(agentId);
146
+ console.log(`[RpcAdapter] Stopped ${agentId}`);
147
+ }
148
+ sendInput(agentId, input) {
149
+ const agent = this.agents.get(agentId);
150
+ if (!agent) {
151
+ console.warn(`[RpcAdapter] Agent ${agentId} not found`);
152
+ return;
153
+ }
154
+ if (!agent.process.stdin || agent.process.stdin.destroyed) {
155
+ console.warn(`[RpcAdapter] Agent ${agentId} stdin closed`);
156
+ return;
157
+ }
158
+ // RPC workers use a simple line-delimited JSON command envelope.
159
+ const command = {
160
+ id: `cmd-${Date.now()}`,
161
+ type: input.mode || "prompt",
162
+ message: input.text,
163
+ };
164
+ agent.process.stdin.write(`${JSON.stringify(command)}\n`);
165
+ }
166
+ sendRawInput(agentId, data) {
167
+ // RPC 模式不支持原始输入,转为普通输入
168
+ this.sendInput(agentId, { text: data });
169
+ }
170
+ isRunning(agentId) {
171
+ const agent = this.agents.get(agentId);
172
+ if (!agent)
173
+ return false;
174
+ return !agent.process.killed && agent.process.exitCode === null;
175
+ }
176
+ onOutput(callback) {
177
+ this.outputCallbacks.push(callback);
178
+ }
179
+ onExit(callback) {
180
+ this.exitCallbacks.push(callback);
181
+ }
182
+ }
@@ -0,0 +1,17 @@
1
+ import type { AgentAdapter, AdapterInput, AdapterOutput, PluginConfig } from "./types.js";
2
+ export declare class StdioAdapter implements AgentAdapter {
3
+ readonly name = "stdio";
4
+ readonly description = "Stdio pipe adapter for CLI agents";
5
+ readonly capabilities: string[];
6
+ private agents;
7
+ private outputCallbacks;
8
+ private exitCallbacks;
9
+ canHandle(type: string): boolean;
10
+ start(config: PluginConfig): Promise<string>;
11
+ stop(agentId: string): Promise<void>;
12
+ sendInput(agentId: string, input: AdapterInput): void;
13
+ sendRawInput(agentId: string, data: string): void;
14
+ isRunning(agentId: string): boolean;
15
+ onOutput(callback: (agentId: string, output: AdapterOutput) => void): void;
16
+ onExit(callback: (agentId: string, code: number | null) => void): void;
17
+ }
@@ -0,0 +1,107 @@
1
+ import { spawn } from "child_process";
2
+ export class StdioAdapter {
3
+ name = "stdio";
4
+ description = "Stdio pipe adapter for CLI agents";
5
+ capabilities = ["terminal", "stream", "interactive"];
6
+ agents = new Map();
7
+ outputCallbacks = [];
8
+ exitCallbacks = [];
9
+ canHandle(type) {
10
+ // stdio 模式处理 pie-unity、claude-code 等
11
+ return ["pie-unity", "claude-code", "aider", "stdio"].includes(type);
12
+ }
13
+ async start(config) {
14
+ const agentId = `stdio-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
15
+ const proc = spawn(config.command, config.args || [], {
16
+ cwd: config.cwd || process.cwd(),
17
+ env: { ...process.env, ...config.env },
18
+ stdio: ["pipe", "pipe", "pipe"],
19
+ });
20
+ const agent = {
21
+ id: agentId,
22
+ process: proc,
23
+ config,
24
+ };
25
+ agent.outputCallback = (output) => {
26
+ for (const callback of this.outputCallbacks) {
27
+ callback(agentId, output);
28
+ }
29
+ };
30
+ agent.exitCallback = (code) => {
31
+ for (const callback of this.exitCallbacks) {
32
+ callback(agentId, code);
33
+ }
34
+ };
35
+ // 处理 stdout
36
+ proc.stdout?.on("data", (data) => {
37
+ agent.outputCallback?.({
38
+ timestamp: Date.now(),
39
+ type: "output",
40
+ content: data.toString("utf-8"),
41
+ });
42
+ });
43
+ // 处理 stderr
44
+ proc.stderr?.on("data", (data) => {
45
+ agent.outputCallback?.({
46
+ timestamp: Date.now(),
47
+ type: "error",
48
+ content: data.toString("utf-8"),
49
+ });
50
+ });
51
+ // 处理退出
52
+ proc.on("close", (code) => {
53
+ console.log(`[StdioAdapter] Agent ${agentId} exited: code=${code}`);
54
+ agent.exitCallback?.(code);
55
+ this.agents.delete(agentId);
56
+ });
57
+ proc.on("error", (err) => {
58
+ console.error(`[StdioAdapter] Agent ${agentId} error:`, err.message);
59
+ agent.outputCallback?.({
60
+ timestamp: Date.now(),
61
+ type: "error",
62
+ content: `Process error: ${err.message}`,
63
+ });
64
+ agent.exitCallback?.(1);
65
+ this.agents.delete(agentId);
66
+ });
67
+ this.agents.set(agentId, agent);
68
+ console.log(`[StdioAdapter] Started ${agentId}: ${config.command}`);
69
+ return agentId;
70
+ }
71
+ async stop(agentId) {
72
+ const agent = this.agents.get(agentId);
73
+ if (!agent)
74
+ return;
75
+ agent.process.kill();
76
+ this.agents.delete(agentId);
77
+ console.log(`[StdioAdapter] Stopped ${agentId}`);
78
+ }
79
+ sendInput(agentId, input) {
80
+ const agent = this.agents.get(agentId);
81
+ if (!agent) {
82
+ console.warn(`[StdioAdapter] Agent ${agentId} not found`);
83
+ return;
84
+ }
85
+ if (!agent.process.stdin || agent.process.stdin.destroyed) {
86
+ console.warn(`[StdioAdapter] Agent ${agentId} stdin closed`);
87
+ return;
88
+ }
89
+ agent.process.stdin.write(input.text);
90
+ }
91
+ sendRawInput(agentId, data) {
92
+ // stdio 模式与普通输入相同
93
+ this.sendInput(agentId, { text: data });
94
+ }
95
+ isRunning(agentId) {
96
+ const agent = this.agents.get(agentId);
97
+ if (!agent)
98
+ return false;
99
+ return !agent.process.killed && agent.process.exitCode === null;
100
+ }
101
+ onOutput(callback) {
102
+ this.outputCallbacks.push(callback);
103
+ }
104
+ onExit(callback) {
105
+ this.exitCallbacks.push(callback);
106
+ }
107
+ }
@@ -0,0 +1,17 @@
1
+ import type { AgentAdapter, AdapterInput, AdapterOutput, PluginConfig } from "../types.js";
2
+ export type { AgentAdapter, AdapterInput, AdapterOutput, PluginConfig };
3
+ /** 运行中的 Agent 进程信息 */
4
+ export interface ManagedAgent {
5
+ id: string;
6
+ config: PluginConfig;
7
+ process?: any;
8
+ startedAt: number;
9
+ lastActivity: number;
10
+ outputCallback?: (output: AdapterOutput) => void;
11
+ exitCallback?: (code: number | null) => void;
12
+ }
13
+ /** 适配器构造函数的参数 */
14
+ export interface AdapterOptions {
15
+ pluginDir?: string;
16
+ logLevel?: "debug" | "info" | "warn" | "error";
17
+ }
@@ -0,0 +1,2 @@
1
+ // Adapter 类型定义
2
+ export {};
@@ -0,0 +1,11 @@
1
+ export interface ClaudeExecOptions {
2
+ cwd: string;
3
+ message: string;
4
+ timeoutMs: number;
5
+ }
6
+ export interface ClaudeExecResult {
7
+ message: string;
8
+ summary: string;
9
+ rawOutput: string;
10
+ }
11
+ export declare function runClaudeExec(options: ClaudeExecOptions): Promise<ClaudeExecResult>;
@@ -0,0 +1,54 @@
1
+ import { spawn } from "node:child_process";
2
+ export async function runClaudeExec(options) {
3
+ return new Promise((resolve, reject) => {
4
+ const child = spawn("claude", [
5
+ "-p",
6
+ "--dangerously-skip-permissions",
7
+ options.message,
8
+ ], {
9
+ cwd: options.cwd,
10
+ env: process.env,
11
+ stdio: ["ignore", "pipe", "pipe"],
12
+ });
13
+ let stdout = "";
14
+ let stderr = "";
15
+ let settled = false;
16
+ const finish = (handler) => {
17
+ if (settled)
18
+ return;
19
+ settled = true;
20
+ clearTimeout(timeoutHandle);
21
+ handler();
22
+ };
23
+ child.stdout.on("data", (chunk) => {
24
+ stdout += chunk.toString();
25
+ });
26
+ child.stderr.on("data", (chunk) => {
27
+ stderr += chunk.toString();
28
+ });
29
+ child.on("error", (error) => {
30
+ finish(() => reject(error));
31
+ });
32
+ child.on("close", (code) => {
33
+ finish(() => {
34
+ const message = stdout.trim();
35
+ const rawOutput = [stdout, stderr].filter(Boolean).join("");
36
+ if (code !== 0) {
37
+ reject(new Error(rawOutput.trim() || `claude -p exited with code ${code}`));
38
+ return;
39
+ }
40
+ resolve({
41
+ message,
42
+ summary: message,
43
+ rawOutput,
44
+ });
45
+ });
46
+ });
47
+ const timeoutHandle = setTimeout(() => {
48
+ child.kill("SIGTERM");
49
+ const error = new Error(`claude -p timed out after ${options.timeoutMs}ms`);
50
+ error.code = "CLAUDE_EXEC_TIMEOUT";
51
+ finish(() => reject(error));
52
+ }, Math.max(options.timeoutMs, 250));
53
+ });
54
+ }
@@ -0,0 +1,12 @@
1
+ export interface ClaudeTurnResult {
2
+ message: string;
3
+ summary: string;
4
+ changed: boolean;
5
+ }
6
+ export declare function isClaudeCodeWorker(agentType: string | undefined): boolean;
7
+ export declare function claudeNeedsTrustConfirmation(bufferedOutput: string): boolean;
8
+ export declare function formatClaudeTurnInput(message: string): string;
9
+ export declare function summarizeClaudeWorkerOutput(bufferedOutput: string, input?: string): string;
10
+ export declare function getLastClaudeWorkerMessage(bufferedOutput: string, input?: string): string;
11
+ export declare function getFreshClaudeTurnResult(beforeOutput: string, afterOutput: string, input: string): ClaudeTurnResult;
12
+ export declare function isClaudeReadyForTask(bufferedOutput: string): boolean;