@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,266 @@
1
+ import { createServer } from "node:http";
2
+ import { existsSync, createReadStream } from "node:fs";
3
+ import path from "node:path";
4
+ import { fileURLToPath } from "node:url";
5
+ import { WebSocketServer, WebSocket } from "ws";
6
+ function createConnectionId() {
7
+ return `local-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
8
+ }
9
+ function guessContentType(filePath) {
10
+ if (filePath.endsWith(".html"))
11
+ return "text/html; charset=utf-8";
12
+ if (filePath.endsWith(".js"))
13
+ return "application/javascript; charset=utf-8";
14
+ if (filePath.endsWith(".css"))
15
+ return "text/css; charset=utf-8";
16
+ if (filePath.endsWith(".json"))
17
+ return "application/json; charset=utf-8";
18
+ if (filePath.endsWith(".svg"))
19
+ return "image/svg+xml";
20
+ if (filePath.endsWith(".png"))
21
+ return "image/png";
22
+ return "text/plain; charset=utf-8";
23
+ }
24
+ function findWorkbenchRoot() {
25
+ const currentDir = path.dirname(fileURLToPath(import.meta.url));
26
+ const candidates = [
27
+ path.resolve(currentDir, "../../../apps/web/src"),
28
+ path.resolve(currentDir, "../../../../apps/web/src"),
29
+ path.resolve(process.cwd(), "apps/web/src"),
30
+ ];
31
+ for (const candidate of candidates) {
32
+ if (existsSync(path.join(candidate, "index.html"))) {
33
+ return candidate;
34
+ }
35
+ }
36
+ return null;
37
+ }
38
+ export class LocalDirectServer {
39
+ options;
40
+ delegate;
41
+ httpServer = createServer((req, res) => this.handleHttpRequest(req, res));
42
+ wsServer = new WebSocketServer({ noServer: true });
43
+ connections = new Map();
44
+ sessionToConnections = new Map();
45
+ workbenchRoot = findWorkbenchRoot();
46
+ constructor(options, delegate) {
47
+ this.options = options;
48
+ this.delegate = delegate;
49
+ this.httpServer.on("upgrade", (req, socket, head) => {
50
+ const pathname = new URL(req.url || "/", "http://127.0.0.1").pathname;
51
+ if (pathname !== "/ws") {
52
+ socket.destroy();
53
+ return;
54
+ }
55
+ this.wsServer.handleUpgrade(req, socket, head, (ws) => {
56
+ this.wsServer.emit("connection", ws, req);
57
+ });
58
+ });
59
+ this.wsServer.on("connection", (ws) => {
60
+ this.handleSocketConnection(ws);
61
+ });
62
+ }
63
+ async start() {
64
+ await new Promise((resolve, reject) => {
65
+ this.httpServer.once("error", reject);
66
+ this.httpServer.listen(this.options.port, this.options.host, () => {
67
+ this.httpServer.off("error", reject);
68
+ resolve();
69
+ });
70
+ });
71
+ const address = this.httpServer.address();
72
+ const port = typeof address === "object" && address ? address.port : this.options.port;
73
+ return {
74
+ host: this.options.host,
75
+ port,
76
+ webUrl: `http://${this.options.host}:${port}/`,
77
+ wsUrl: `ws://${this.options.host}:${port}/ws`,
78
+ };
79
+ }
80
+ async stop() {
81
+ for (const conn of this.connections.values()) {
82
+ conn.ws.close();
83
+ }
84
+ this.connections.clear();
85
+ this.sessionToConnections.clear();
86
+ await new Promise((resolve) => this.wsServer.close(() => resolve()));
87
+ await new Promise((resolve) => this.httpServer.close(() => resolve()));
88
+ }
89
+ handleNodeMessage(message) {
90
+ switch (message.type) {
91
+ case "output":
92
+ case "session":
93
+ if (message.sessionId) {
94
+ this.sendToSession(message.sessionId, message);
95
+ }
96
+ return;
97
+ case "worker_list":
98
+ case "worker_detail":
99
+ case "dir_list":
100
+ case "node_reply":
101
+ case "attached":
102
+ case "auth_success":
103
+ case "pong":
104
+ case "error":
105
+ this.broadcast(message);
106
+ return;
107
+ case "control":
108
+ if (message.controlKind === "event" && String(message.controlName || "") === "session.subscription_changed") {
109
+ return;
110
+ }
111
+ this.broadcast(message);
112
+ return;
113
+ default:
114
+ this.broadcast(message);
115
+ }
116
+ }
117
+ handleHttpRequest(req, res) {
118
+ const url = new URL(req.url || "/", "http://127.0.0.1");
119
+ if (url.pathname === "/health") {
120
+ res.writeHead(200, { "content-type": "application/json; charset=utf-8" });
121
+ res.end(JSON.stringify({
122
+ ok: true,
123
+ nodeId: this.options.nodeId,
124
+ connections: this.connections.size,
125
+ }));
126
+ return;
127
+ }
128
+ if (!this.workbenchRoot) {
129
+ res.writeHead(404, { "content-type": "text/plain; charset=utf-8" });
130
+ res.end("Workbench files not found");
131
+ return;
132
+ }
133
+ const relativePath = url.pathname === "/" ? "/index.html" : url.pathname;
134
+ const normalizedPath = path.normalize(relativePath).replace(/^(\.\.[/\\])+/, "");
135
+ const targetPath = path.join(this.workbenchRoot, normalizedPath);
136
+ const safeRoot = path.resolve(this.workbenchRoot);
137
+ const safeTarget = path.resolve(targetPath);
138
+ if (!safeTarget.startsWith(safeRoot) || !existsSync(safeTarget)) {
139
+ res.writeHead(404, { "content-type": "text/plain; charset=utf-8" });
140
+ res.end("Not found");
141
+ return;
142
+ }
143
+ res.writeHead(200, { "content-type": guessContentType(safeTarget) });
144
+ createReadStream(safeTarget).pipe(res);
145
+ }
146
+ handleSocketConnection(ws) {
147
+ const connectionId = createConnectionId();
148
+ const connection = {
149
+ id: connectionId,
150
+ ws,
151
+ authenticated: false,
152
+ };
153
+ this.connections.set(connectionId, connection);
154
+ ws.on("message", async (buffer) => {
155
+ let message;
156
+ try {
157
+ message = JSON.parse(buffer.toString());
158
+ }
159
+ catch {
160
+ this.send(connection, { type: "error", error: "Invalid message format" });
161
+ return;
162
+ }
163
+ await this.handleBrowserMessage(connection, message);
164
+ });
165
+ ws.on("close", () => {
166
+ void this.cleanupConnection(connectionId);
167
+ });
168
+ }
169
+ async handleBrowserMessage(connection, message) {
170
+ if (message.type === "auth") {
171
+ if (message.clientType !== "browser" || message.nodeId !== this.options.nodeId || message.password !== this.options.password) {
172
+ this.send(connection, { type: "error", error: "Invalid credentials" });
173
+ return;
174
+ }
175
+ connection.authenticated = true;
176
+ if (message.sessionId) {
177
+ await this.attachConnectionToSession(connection, message.sessionId);
178
+ }
179
+ this.send(connection, {
180
+ type: "auth_success",
181
+ sessionId: message.sessionId || `local-${Date.now()}`,
182
+ });
183
+ return;
184
+ }
185
+ if (!connection.authenticated) {
186
+ this.send(connection, { type: "error", error: "Authenticate first" });
187
+ return;
188
+ }
189
+ if (message.type === "control" && message.controlKind === "command" && message.controlName === "attach_session") {
190
+ const sessionId = message.target?.sessionId
191
+ || (typeof message.payload === "object" && message.payload && "sessionId" in message.payload
192
+ ? String(message.payload.sessionId || "")
193
+ : "");
194
+ if (!sessionId) {
195
+ this.send(connection, { type: "error", error: "Missing sessionId" });
196
+ return;
197
+ }
198
+ await this.attachConnectionToSession(connection, sessionId);
199
+ this.send(connection, {
200
+ type: "attached",
201
+ sessionId,
202
+ });
203
+ }
204
+ if (message.type === "input" || message.type === "resize") {
205
+ message.sessionId = message.sessionId || connection.sessionId;
206
+ }
207
+ await this.delegate.handleIncomingMessage(message);
208
+ }
209
+ async attachConnectionToSession(connection, sessionId) {
210
+ const previousSessionId = connection.sessionId;
211
+ if (previousSessionId && previousSessionId !== sessionId) {
212
+ await this.detachConnectionFromSession(connection, previousSessionId);
213
+ }
214
+ connection.sessionId = sessionId;
215
+ let connections = this.sessionToConnections.get(sessionId);
216
+ if (!connections) {
217
+ connections = new Set();
218
+ this.sessionToConnections.set(sessionId, connections);
219
+ }
220
+ connections.add(connection.id);
221
+ await this.delegate.handleSubscriptionChange(sessionId, connections.size);
222
+ }
223
+ async detachConnectionFromSession(connection, sessionId) {
224
+ const connections = this.sessionToConnections.get(sessionId);
225
+ if (!connections)
226
+ return;
227
+ connections.delete(connection.id);
228
+ if (connections.size === 0) {
229
+ this.sessionToConnections.delete(sessionId);
230
+ }
231
+ connection.sessionId = connection.sessionId === sessionId ? undefined : connection.sessionId;
232
+ await this.delegate.handleSubscriptionChange(sessionId, connections.size);
233
+ }
234
+ async cleanupConnection(connectionId) {
235
+ const connection = this.connections.get(connectionId);
236
+ if (!connection)
237
+ return;
238
+ if (connection.sessionId) {
239
+ await this.detachConnectionFromSession(connection, connection.sessionId);
240
+ }
241
+ this.connections.delete(connectionId);
242
+ }
243
+ sendToSession(sessionId, message) {
244
+ const connectionIds = this.sessionToConnections.get(sessionId);
245
+ if (!connectionIds?.size)
246
+ return;
247
+ for (const connectionId of connectionIds) {
248
+ const connection = this.connections.get(connectionId);
249
+ if (connection) {
250
+ this.send(connection, message);
251
+ }
252
+ }
253
+ }
254
+ broadcast(message) {
255
+ for (const connection of this.connections.values()) {
256
+ if (connection.authenticated) {
257
+ this.send(connection, message);
258
+ }
259
+ }
260
+ }
261
+ send(connection, message) {
262
+ if (connection.ws.readyState === WebSocket.OPEN) {
263
+ connection.ws.send(JSON.stringify(message));
264
+ }
265
+ }
266
+ }
@@ -0,0 +1,21 @@
1
+ import type { NodeReply } from "./node-reply.js";
2
+ import type { AgentRecord } from "./types.js";
3
+ export interface NodeConversationTurn {
4
+ role: "user" | "assistant";
5
+ text: string;
6
+ timestamp: number;
7
+ actionType?: "spawn" | "attach";
8
+ actionLabel?: string;
9
+ actionTaskSummary?: string;
10
+ actionSessionId?: string;
11
+ }
12
+ export interface NodeConversationState {
13
+ lastTaskSummary?: string;
14
+ lastWorkerSessionId?: string;
15
+ lastWorkerAgentId?: string;
16
+ lastUserMessage?: string;
17
+ history: NodeConversationTurn[];
18
+ }
19
+ export declare function createNodeConversationState(): NodeConversationState;
20
+ export declare function recordConversationTurn(state: NodeConversationState, role: "user" | "assistant", text: string, extra?: Partial<NodeReply>): NodeConversationState;
21
+ export declare function rememberNodeSpawn(state: NodeConversationState, taskSummary: string | undefined, sessionId: string, worker?: AgentRecord): NodeConversationState;
@@ -0,0 +1,28 @@
1
+ export function createNodeConversationState() {
2
+ return { history: [] };
3
+ }
4
+ export function recordConversationTurn(state, role, text, extra = {}) {
5
+ return {
6
+ ...state,
7
+ history: [
8
+ ...state.history,
9
+ {
10
+ role,
11
+ text,
12
+ timestamp: Date.now(),
13
+ actionType: extra.actionType,
14
+ actionLabel: extra.actionLabel,
15
+ actionTaskSummary: extra.actionTaskSummary,
16
+ actionSessionId: extra.actionSessionId,
17
+ },
18
+ ].slice(-30),
19
+ };
20
+ }
21
+ export function rememberNodeSpawn(state, taskSummary, sessionId, worker) {
22
+ return {
23
+ ...state,
24
+ lastTaskSummary: taskSummary || state.lastTaskSummary,
25
+ lastWorkerSessionId: sessionId,
26
+ lastWorkerAgentId: worker?.agentId,
27
+ };
28
+ }
@@ -0,0 +1,2 @@
1
+ export type NodeIntent = "direct" | "follow_up" | "delegate";
2
+ export declare function classifyNodeIntent(text: string): NodeIntent;
@@ -0,0 +1,40 @@
1
+ export function classifyNodeIntent(text) {
2
+ const normalized = String(text || "").trim();
3
+ const lower = normalized.toLowerCase();
4
+ const isQuestionLike = normalized.endsWith("?")
5
+ || normalized.endsWith("?")
6
+ || lower === "status"
7
+ || lower === "state"
8
+ || lower === "workers";
9
+ const isCapabilityQuery = lower.includes("help")
10
+ || lower.includes("what can")
11
+ || lower.includes("how do")
12
+ || lower.includes("你能")
13
+ || lower.includes("能干什么")
14
+ || lower.includes("你会什么");
15
+ const isStatusQuery = lower.includes("现在什么情况")
16
+ || lower.includes("现在在忙什么")
17
+ || lower.includes("what's running")
18
+ || lower.includes("what is running")
19
+ || /^当前.*状态/.test(normalized)
20
+ || /^现在.*状态/.test(normalized)
21
+ || /^查看.*状态/.test(normalized);
22
+ const isPlanningQuery = lower.includes("怎么做")
23
+ || lower.includes("怎么安排")
24
+ || lower.includes("what should we do")
25
+ || lower.includes("how should")
26
+ || lower.includes("plan")
27
+ || lower.includes("安排一下")
28
+ || lower.includes("想想")
29
+ || lower.includes("讨论");
30
+ const isHelpQuery = isQuestionLike || isCapabilityQuery || isStatusQuery || isPlanningQuery;
31
+ const isFollowUp = /^(继续|开始吧|开工|推进|干活|你倒是让他干活啊\??|继续吧)$/u.test(normalized)
32
+ || lower.includes("keep going")
33
+ || lower.includes("continue")
34
+ || lower.includes("start working");
35
+ if (isHelpQuery)
36
+ return "direct";
37
+ if (isFollowUp)
38
+ return "follow_up";
39
+ return "delegate";
40
+ }
@@ -0,0 +1,30 @@
1
+ import type { AgentRecord } from "./types.js";
2
+ import type { NodeIntent } from "./node-intent.js";
3
+ export interface NodeReply {
4
+ text: string;
5
+ actionType?: "spawn" | "attach";
6
+ actionLabel?: string;
7
+ actionTaskSummary?: string;
8
+ actionSessionId?: string;
9
+ workerMessage?: string;
10
+ }
11
+ export interface PrimaryAgentReplyContext {
12
+ pluginName: string;
13
+ launchMode: "headless" | "session";
14
+ status: "starting" | "running" | "stopped" | "failed" | "disabled" | "missing";
15
+ lastError?: string;
16
+ }
17
+ export interface DirectNodeReplyContext {
18
+ text: string;
19
+ intent: NodeIntent;
20
+ primaryAgent: PrimaryAgentReplyContext;
21
+ liveWorkers: AgentRecord[];
22
+ waitingWorkers: number;
23
+ busyWorkers: number;
24
+ focusCount: number;
25
+ liveLastWorker?: AgentRecord;
26
+ currentTaskText: string;
27
+ }
28
+ export declare function buildWorkerFollowUpMessage(text: string): string;
29
+ export declare function describePrimaryAgent(primaryAgent: PrimaryAgentReplyContext): string;
30
+ export declare function buildDirectNodeReply(context: DirectNodeReplyContext): NodeReply;
@@ -0,0 +1,77 @@
1
+ export function buildWorkerFollowUpMessage(text) {
2
+ const normalized = String(text || "").trim();
3
+ const lower = normalized.toLowerCase();
4
+ if (/^(继续|继续吧|开始吧|开工|推进|干活|你倒是让他干活啊\??)$/u.test(normalized)
5
+ || lower === "continue"
6
+ || lower === "keep going"
7
+ || lower === "start working") {
8
+ return "Continue the current task now. Make visible progress, and briefly summarize what you are doing before you finish this turn.";
9
+ }
10
+ return normalized;
11
+ }
12
+ export function describePrimaryAgent(primaryAgent) {
13
+ switch (primaryAgent.status) {
14
+ case "running":
15
+ if (primaryAgent.lastError) {
16
+ return `Primary agent: ${primaryAgent.pluginName} is configured but currently unavailable (${primaryAgent.lastError}).`;
17
+ }
18
+ return primaryAgent.launchMode === "headless"
19
+ ? `Primary agent: ${primaryAgent.pluginName} bridge is ready.`
20
+ : `Primary agent: ${primaryAgent.pluginName} is online.`;
21
+ case "starting":
22
+ return `Primary agent: ${primaryAgent.pluginName} is starting.`;
23
+ case "missing":
24
+ return `Primary agent: ${primaryAgent.pluginName} plugin is not available on this node.`;
25
+ case "failed":
26
+ return `Primary agent: ${primaryAgent.pluginName} failed${primaryAgent.lastError ? ` (${primaryAgent.lastError})` : ""}.`;
27
+ case "disabled":
28
+ return "Primary agent is disabled for this node.";
29
+ default:
30
+ return `Primary agent: ${primaryAgent.pluginName} is idle.`;
31
+ }
32
+ }
33
+ export function buildDirectNodeReply(context) {
34
+ const normalized = String(context.text || "").trim();
35
+ const lower = normalized.toLowerCase();
36
+ const primaryText = describePrimaryAgent(context.primaryAgent);
37
+ const runtimeText = `Current node state: ${context.liveWorkers.length} live, ${context.waitingWorkers} waiting, ${context.busyWorkers} busy.`;
38
+ if (context.intent === "direct") {
39
+ const focusText = context.focusCount
40
+ ? `${context.focusCount} worker${context.focusCount > 1 ? "s" : ""} may need review.`
41
+ : "Nothing looks urgent right now.";
42
+ const intro = lower.includes("你能") || lower.includes("能干什么") || lower.includes("what can")
43
+ ? "AgentNode is running in deterministic control-plane mode. I can report runtime state and route you to explicit controls."
44
+ : "AgentNode is in deterministic mode. Use the web workbench, CLI, or a primary-agent skill for planning and orchestration.";
45
+ return {
46
+ text: [
47
+ intro,
48
+ primaryText,
49
+ runtimeText,
50
+ context.currentTaskText,
51
+ focusText,
52
+ ].join("\n"),
53
+ };
54
+ }
55
+ if (context.intent === "follow_up" && context.liveLastWorker) {
56
+ return {
57
+ text: [
58
+ "AgentNode will not reinterpret follow-up chat in deterministic mode.",
59
+ primaryText,
60
+ runtimeText,
61
+ `Attach to ${context.liveLastWorker.sessionId} or send explicit session input through the CLI/skill surface.`,
62
+ ].join("\n"),
63
+ actionType: "attach",
64
+ actionLabel: "ATTACH WORKER",
65
+ actionSessionId: context.liveLastWorker.sessionId,
66
+ };
67
+ }
68
+ return {
69
+ text: [
70
+ "AgentNode does not interpret free-form work requests in deterministic mode.",
71
+ primaryText,
72
+ runtimeText,
73
+ context.currentTaskText,
74
+ "Start or attach a worker explicitly from the workbench/CLI, or use a primary-agent skill to decide the next action.",
75
+ ].join("\n"),
76
+ };
77
+ }
package/dist/node.d.ts ADDED
@@ -0,0 +1,132 @@
1
+ import type { ClientMessage, ServerMessage } from "@cydm/magic-shell-protocol";
2
+ export interface NodeOptions {
3
+ relayUrl: string;
4
+ nodeId: string;
5
+ password: string;
6
+ pluginDir: string;
7
+ autoReconnect?: boolean;
8
+ primaryPluginName?: string;
9
+ primaryLaunchMode?: "headless" | "session";
10
+ enableLocalDirect?: boolean;
11
+ localControlHost?: string;
12
+ localControlPort?: number;
13
+ }
14
+ export interface SpawnWorkerOptions {
15
+ sessionId: string;
16
+ pluginName: string;
17
+ cwd?: string;
18
+ displayName?: string;
19
+ taskSummary?: string;
20
+ parentAgentId?: string;
21
+ }
22
+ export declare class AgentNode {
23
+ private options;
24
+ private wsClient;
25
+ private localDirectServer?;
26
+ private localDirectInfo?;
27
+ private sessionManager;
28
+ private workerRegistry;
29
+ private plugins;
30
+ private running;
31
+ private sessionTitleBuffers;
32
+ private primaryAgent;
33
+ private nodeConversation;
34
+ private lastFailedNamedWorker?;
35
+ private preferredWorkerPluginName;
36
+ private syntheticSessionResults;
37
+ private liveAttachedSessions;
38
+ private remoteAttachedSessions;
39
+ private localAttachedSessions;
40
+ private relayConnectedOnce;
41
+ constructor(options: NodeOptions);
42
+ getOptions(): Readonly<NodeOptions>;
43
+ getLocalDirectInfo(): {
44
+ host: string;
45
+ port: number;
46
+ webUrl: string;
47
+ wsUrl: string;
48
+ } | undefined;
49
+ /**
50
+ * 启动 AgentNode
51
+ */
52
+ start(): Promise<void>;
53
+ /**
54
+ * 停止 AgentNode
55
+ */
56
+ stop(): Promise<void>;
57
+ /**
58
+ * 设置消息处理器
59
+ */
60
+ private setupMessageHandlers;
61
+ handleIncomingMessage(message: ClientMessage | ServerMessage, source?: "relay" | "local"): Promise<void>;
62
+ /**
63
+ * 创建新会话
64
+ */
65
+ spawnWorker(options: SpawnWorkerOptions): Promise<void>;
66
+ /**
67
+ * Backward-compatible wrapper while the transport still speaks in session terms.
68
+ */
69
+ createSession(sessionId: string, pluginName: string): Promise<void>;
70
+ private waitForPrimaryAgentSessionId;
71
+ private sendPromptToPrimarySession;
72
+ private formatSessionControlInput;
73
+ private queryPrimarySessionText;
74
+ private dispatchInitialWorkerTask;
75
+ private seedWorkerTask;
76
+ private primeInteractiveWorkerSession;
77
+ private seedClaudeWorkerTask;
78
+ private seedCodexWorkerTask;
79
+ private ensurePrimaryAgent;
80
+ private handleControlEnvelope;
81
+ private handleControlMessage;
82
+ private handleControlCommand;
83
+ private handleControlQuery;
84
+ private sendControlResult;
85
+ private buildRuntimeSnapshot;
86
+ private buildPrimaryAgentStatus;
87
+ private isProtectedPrimarySession;
88
+ private runSessionTurn;
89
+ private runClaudeWorkerTurn;
90
+ private runCodexWorkerTurn;
91
+ private isLikelyEchoedSessionInput;
92
+ private isUsablePieSessionTurnResult;
93
+ private getWorkerOutputSummary;
94
+ private getWorkerOutputMessage;
95
+ private readString;
96
+ private readNumber;
97
+ private readPayloadObject;
98
+ private recordPrimaryOutput;
99
+ private captureWorkerTitleFromInput;
100
+ private broadcastWorkerList;
101
+ private rememberNodeSpawn;
102
+ private handlePrimaryMessage;
103
+ private tryHandlePrimaryOrchestration;
104
+ private parseSpawnWorkerIntent;
105
+ private parseWorkerName;
106
+ private extractPathFragment;
107
+ private resolveWorkerCwd;
108
+ private handleSpawnWorkerIntent;
109
+ private parseNamedWorkerAction;
110
+ private parseNamedWorkerTaskIntent;
111
+ private findWorkerByName;
112
+ private getOrderedLiveWorkers;
113
+ private handleStopWorkerIntent;
114
+ private handleRestartWorkerIntent;
115
+ private handleWorkerTaskIntent;
116
+ private handleOrdinalMultiWorkerIntent;
117
+ private handleNamedMultiWorkerCommitIntent;
118
+ private handleWorkerRosterIntent;
119
+ private ensureSessionForInteractiveMessage;
120
+ handleSessionOutput(sessionId: string, output: {
121
+ content: string;
122
+ }): void;
123
+ private sendServerMessage;
124
+ private sendToSource;
125
+ private startLocalDirectServer;
126
+ private updateSessionSubscription;
127
+ private onRelayConnected;
128
+ private maybeNarrateWorkerStateChange;
129
+ private recordConversationTurn;
130
+ }
131
+ declare function main(): Promise<void>;
132
+ export { main };