aws-runtime-bridge 1.9.0 → 1.9.2
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/dist/adapter/AcodeSdkAdapter.d.ts +2 -0
- package/dist/adapter/AcodeSdkAdapter.d.ts.map +1 -1
- package/dist/adapter/AcodeSdkAdapter.js +84 -18
- package/dist/adapter/AcodeSdkAdapter.test.js +275 -13
- package/dist/adapter/acode-tool-names.d.ts +16 -0
- package/dist/adapter/acode-tool-names.d.ts.map +1 -0
- package/dist/adapter/acode-tool-names.js +37 -0
- package/dist/adapter/acode-tool-names.test.d.ts +2 -0
- package/dist/adapter/acode-tool-names.test.d.ts.map +1 -0
- package/dist/adapter/acode-tool-names.test.js +28 -0
- package/dist/adapter/types.d.ts +22 -3
- package/dist/adapter/types.d.ts.map +1 -1
- package/dist/adapter/types.js +2 -1
- package/dist/config.d.ts +0 -4
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +0 -4
- package/dist/index.js +1 -1
- package/dist/routes/ai-sources.js +18 -14
- package/dist/routes/git.d.ts +10 -0
- package/dist/routes/git.d.ts.map +1 -1
- package/dist/routes/git.js +37 -3
- package/dist/routes/git.test.js +47 -1
- package/dist/routes/sessions.d.ts +1 -1
- package/dist/routes/sessions.d.ts.map +1 -1
- package/dist/routes/sessions.js +11 -4
- package/dist/routes/sessions.test.js +3 -0
- package/dist/routes/terminal.d.ts +28 -8
- package/dist/routes/terminal.d.ts.map +1 -1
- package/dist/routes/terminal.js +266 -44
- package/dist/routes/terminal.stop-options.test.d.ts +2 -0
- package/dist/routes/terminal.stop-options.test.d.ts.map +1 -0
- package/dist/routes/terminal.stop-options.test.js +39 -0
- package/dist/routes/terminal.test.js +87 -4
- package/dist/services/auto-register.d.ts.map +1 -1
- package/dist/services/auto-register.js +4 -5
- package/dist/services/mcp-launch-binding-queue.d.ts +5 -0
- package/dist/services/mcp-launch-binding-queue.d.ts.map +1 -1
- package/dist/services/mcp-launch-binding-queue.js +17 -0
- package/dist/services/mcp-launch-binding-queue.test.js +16 -1
- package/dist/services/session-output.d.ts +5 -0
- package/dist/services/session-output.d.ts.map +1 -1
- package/package/acode/dist/built-in-file-tools.d.ts +5 -1
- package/package/acode/dist/built-in-file-tools.d.ts.map +1 -1
- package/package/acode/dist/built-in-file-tools.js +14 -203
- package/package/acode/dist/builtins/commandArtifacts.d.ts +25 -0
- package/package/acode/dist/builtins/commandArtifacts.d.ts.map +1 -0
- package/package/acode/dist/builtins/commandArtifacts.js +77 -0
- package/package/acode/dist/builtins/commandOutputEvents.d.ts +21 -0
- package/package/acode/dist/builtins/commandOutputEvents.d.ts.map +1 -0
- package/package/acode/dist/builtins/commandOutputEvents.js +56 -0
- package/package/acode/dist/builtins/shellCommandPreparation.d.ts +15 -0
- package/package/acode/dist/builtins/shellCommandPreparation.d.ts.map +1 -0
- package/package/acode/dist/builtins/shellCommandPreparation.js +44 -0
- package/package/acode/dist/builtins/shellCommandResult.d.ts +30 -0
- package/package/acode/dist/builtins/shellCommandResult.d.ts.map +1 -0
- package/package/acode/dist/builtins/shellCommandResult.js +71 -0
- package/package/acode/dist/builtins/shellCommandRunner.d.ts +14 -0
- package/package/acode/dist/builtins/shellCommandRunner.d.ts.map +1 -0
- package/package/acode/dist/builtins/shellCommandRunner.js +114 -0
- package/package/acode/dist/builtins/shellOutputDecoder.d.ts +5 -0
- package/package/acode/dist/builtins/shellOutputDecoder.d.ts.map +1 -0
- package/package/acode/dist/builtins/shellOutputDecoder.js +30 -0
- package/package/acode/dist/mcpToolNames.d.ts +11 -0
- package/package/acode/dist/mcpToolNames.d.ts.map +1 -0
- package/package/acode/dist/mcpToolNames.js +17 -0
- package/package/acode/dist/runtime.d.ts +19 -0
- package/package/acode/dist/runtime.d.ts.map +1 -1
- package/package/acode/dist/runtime.js +233 -35
- package/package/acode/dist/types.d.ts +1 -1
- package/package/acode/dist/types.d.ts.map +1 -1
- package/package/acode/package.json +1 -1
- package/package/aws-client-agent-mcp/dist/agent-client.d.ts +20 -0
- package/package/aws-client-agent-mcp/dist/agent-client.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/agent-client.js +71 -2
- package/package/aws-client-agent-mcp/dist/agent-client.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/constants.d.ts +4 -1
- package/package/aws-client-agent-mcp/dist/constants.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/constants.js +5 -1
- package/package/aws-client-agent-mcp/dist/constants.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/http-client.d.ts +17 -1
- package/package/aws-client-agent-mcp/dist/http-client.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/http-client.js +124 -28
- package/package/aws-client-agent-mcp/dist/http-client.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/http-client.test.js +108 -2
- package/package/aws-client-agent-mcp/dist/http-client.test.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/mcp-server.d.ts +8 -3
- package/package/aws-client-agent-mcp/dist/mcp-server.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/mcp-server.js +63 -10
- package/package/aws-client-agent-mcp/dist/mcp-server.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/mcp-server.test.js +47 -0
- package/package/aws-client-agent-mcp/dist/mcp-server.test.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/mcp-tools.d.ts +1 -36
- package/package/aws-client-agent-mcp/dist/mcp-tools.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/mcp-tools.js +3 -169
- package/package/aws-client-agent-mcp/dist/mcp-tools.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/mcp-tools.test.d.ts +2 -0
- package/package/aws-client-agent-mcp/dist/mcp-tools.test.d.ts.map +1 -0
- package/package/aws-client-agent-mcp/dist/mcp-tools.test.js +45 -0
- package/package/aws-client-agent-mcp/dist/mcp-tools.test.js.map +1 -0
- package/package/aws-client-agent-mcp/dist/memory-tools.d.ts +11 -0
- package/package/aws-client-agent-mcp/dist/memory-tools.d.ts.map +1 -0
- package/package/aws-client-agent-mcp/dist/memory-tools.js +144 -0
- package/package/aws-client-agent-mcp/dist/memory-tools.js.map +1 -0
- package/package/aws-client-agent-mcp/dist/runtime-launch-binding.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/runtime-launch-binding.js +79 -28
- package/package/aws-client-agent-mcp/dist/runtime-launch-binding.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/runtime-launch-binding.test.js +35 -0
- package/package/aws-client-agent-mcp/dist/runtime-launch-binding.test.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/types.d.ts +9 -0
- package/package/aws-client-agent-mcp/dist/types.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/types.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/websocket-client.d.ts.map +1 -1
- package/package/aws-client-agent-mcp/dist/websocket-client.js +1 -0
- package/package/aws-client-agent-mcp/dist/websocket-client.js.map +1 -1
- package/package/aws-client-agent-mcp/dist/websocket-client.test.js +43 -3
- package/package/aws-client-agent-mcp/dist/websocket-client.test.js.map +1 -1
- package/package.json +1 -1
|
@@ -3,7 +3,7 @@ import os from "node:os";
|
|
|
3
3
|
import path from "node:path";
|
|
4
4
|
import { describe, expect, it } from "vitest";
|
|
5
5
|
import { SDK_PROVIDER_DEFINITIONS } from "../adapter/SdkProviderSpi.js";
|
|
6
|
-
import { buildAcodeCommandOutputPath, buildClaudeCodeLaunchConfig, buildRuntimeEnv, buildSdkOutputMetadata, buildToolResultTimelineActionInfo, countTerminalOutputLines, createTerminalOutputDecoder, decodeTerminalOutputChunk, evaluatePersistedSessionReuse, formatCommandInactivityTimeoutNotice, formatCommandOutputSpilloverNotice, formatTerminalPrompt, formatSdkOutputEvent, normalizeTerminalCommandInput, parseTerminalDirectoryChangeTarget, resolveSdkInputMessage, resolveTerminalOutputEncoding, resolveSdkProviderId, resolveSdkSessionDisplayStatus, resolveRuntimeStatusFromProviderEvent, resolveStatusChangeUsage, } from "./terminal.js";
|
|
6
|
+
import { buildAcodeCommandOutputPath, buildClaudeCodeLaunchConfig, buildRuntimeEnv, buildSdkOutputMetadata, buildToolResultTimelineActionInfo, countTerminalOutputLines, createTerminalOutputDecoder, decodeTerminalOutputChunk, evaluatePersistedSessionReuse, formatCommandInactivityTimeoutNotice, formatCommandOutputSpilloverNotice, formatTerminalPrompt, formatSdkOutputEvent, normalizeTerminalCommandInput, parseTerminalDirectoryChangeTarget, resolveSdkInputMessage, resolveTerminalOutputEncoding, resolveSdkProviderId, resolveSdkSessionDisplayStatus, resolveRuntimeStatusFromProviderEvent, resolveStatusChangeRuntimeState, resolveStatusChangeUsage, shouldProbeSdkProcessPid, } from "./terminal.js";
|
|
7
7
|
describe("terminal route validation", () => {
|
|
8
8
|
it("requires agentId and workspacePath for start", () => {
|
|
9
9
|
const validateStartRequest = (body) => {
|
|
@@ -90,6 +90,10 @@ describe("terminal route validation", () => {
|
|
|
90
90
|
});
|
|
91
91
|
});
|
|
92
92
|
describe("SDK startup idle command ordering", () => {
|
|
93
|
+
it("skips PID probing for in-process ACode sessions", () => {
|
|
94
|
+
expect(shouldProbeSdkProcessPid("acode")).toBe(false);
|
|
95
|
+
expect(shouldProbeSdkProcessPid("claude-code")).toBe(true);
|
|
96
|
+
});
|
|
93
97
|
it("sets idle commands immediately after adapter startup and before PID probing or persistence", async () => {
|
|
94
98
|
const calls = [];
|
|
95
99
|
const adapter = {
|
|
@@ -217,10 +221,19 @@ describe("SDK provider event runtime status mapping", () => {
|
|
|
217
221
|
expect(resolveRuntimeStatusFromProviderEvent(event("thinking"))?.status).toBe("thinking");
|
|
218
222
|
expect(resolveRuntimeStatusFromProviderEvent(event("text_delta"))?.status).toBe("thinking");
|
|
219
223
|
});
|
|
224
|
+
it("keeps command output chunks from changing the runtime status", () => {
|
|
225
|
+
expect(resolveRuntimeStatusFromProviderEvent(event("command_output", { text: "stdout chunk", stream: "stdout" }))).toBeUndefined();
|
|
226
|
+
});
|
|
220
227
|
it("maps AI request events to thinking status with request details", () => {
|
|
221
228
|
const state = resolveRuntimeStatusFromProviderEvent(event("ai_request", {
|
|
222
229
|
model: "test-model",
|
|
223
230
|
endpoint: "https://example.invalid/v1/chat/completions",
|
|
231
|
+
requestMethod: "POST",
|
|
232
|
+
requestUrl: "https://example.invalid/v1/chat/completions",
|
|
233
|
+
requestHeaders: {
|
|
234
|
+
"Content-Type": "application/json",
|
|
235
|
+
Authorization: "Bearer ***",
|
|
236
|
+
},
|
|
224
237
|
stream: true,
|
|
225
238
|
messageCount: 3,
|
|
226
239
|
toolCount: 2,
|
|
@@ -234,9 +247,25 @@ describe("SDK provider event runtime status mapping", () => {
|
|
|
234
247
|
});
|
|
235
248
|
expect(state?.actionInfo?.actionDetail).toContain("模型: test-model");
|
|
236
249
|
expect(state?.actionInfo?.actionDetail).toContain("接口: https://example.invalid/v1/chat/completions");
|
|
250
|
+
expect(state?.actionInfo?.actionDetail).toContain("方法: POST");
|
|
251
|
+
expect(state?.actionInfo?.actionDetail).toContain("请求头:\nContent-Type: application/json\nAuthorization: Bearer ***");
|
|
237
252
|
expect(state?.actionInfo?.actionDetail).toContain("最后请求: inspect status");
|
|
238
253
|
expect(state?.actionInfo?.actionDetail).toContain('请求体:\n{"model":"test-model"}');
|
|
239
254
|
});
|
|
255
|
+
it("does not let idle polling text chunks override waiting_input", () => {
|
|
256
|
+
expect(resolveRuntimeStatusFromProviderEvent(event("thinking"), "waiting_input")).toBeUndefined();
|
|
257
|
+
expect(resolveRuntimeStatusFromProviderEvent(event("text_delta"), "waiting_input")).toBeUndefined();
|
|
258
|
+
});
|
|
259
|
+
it("still reports AI request details when a request starts from waiting_input", () => {
|
|
260
|
+
expect(resolveRuntimeStatusFromProviderEvent(event("ai_request", {
|
|
261
|
+
model: "test-model",
|
|
262
|
+
requestBody: '{"model":"test-model"}',
|
|
263
|
+
}), "waiting_input")?.actionInfo).toMatchObject({
|
|
264
|
+
actionType: "ai_request",
|
|
265
|
+
actionLabel: "AI请求",
|
|
266
|
+
actionDetail: expect.stringContaining('请求体:\n{"model":"test-model"}'),
|
|
267
|
+
});
|
|
268
|
+
});
|
|
240
269
|
it("maps tool start events to tool_using with action info", () => {
|
|
241
270
|
const state = resolveRuntimeStatusFromProviderEvent(event("tool_use_start", {
|
|
242
271
|
toolName: "mcp__aws__my_task",
|
|
@@ -315,8 +344,8 @@ describe("terminal command helpers", () => {
|
|
|
315
344
|
expect(outputPath).toBe(path.join("D:", "code", "repo", ".agentswork", "acode", "cmd-dist", "2026-02-03", "04", "05", "20260203-040506-007-cmd.out"));
|
|
316
345
|
});
|
|
317
346
|
it("formats ACode long-output and inactivity notices for terminal users", () => {
|
|
318
|
-
expect(formatCommandOutputSpilloverNotice("/repo/out.txt",
|
|
319
|
-
expect(formatCommandOutputSpilloverNotice("/repo/out.txt",
|
|
347
|
+
expect(formatCommandOutputSpilloverNotice("/repo/out.txt", 300)).toContain("命令输出超过 300 行");
|
|
348
|
+
expect(formatCommandOutputSpilloverNotice("/repo/out.txt", 300)).toContain("/repo/out.txt");
|
|
320
349
|
expect(formatCommandInactivityTimeoutNotice(60_000)).toContain("超过 60 秒没有新的输出");
|
|
321
350
|
});
|
|
322
351
|
});
|
|
@@ -343,6 +372,20 @@ describe("resolveSdkProviderId", () => {
|
|
|
343
372
|
});
|
|
344
373
|
});
|
|
345
374
|
describe("SDK status usage forwarding", () => {
|
|
375
|
+
it("normalizes idle tool status changes to waiting_input", () => {
|
|
376
|
+
expect(resolveStatusChangeRuntimeState("tool_using", {
|
|
377
|
+
actionType: "idle",
|
|
378
|
+
actionLabel: "监听消息",
|
|
379
|
+
actionDetail: "aws-mcp/poll_message",
|
|
380
|
+
})).toEqual({
|
|
381
|
+
status: "waiting_input",
|
|
382
|
+
actionInfo: {
|
|
383
|
+
actionType: "idle",
|
|
384
|
+
actionLabel: "监听消息",
|
|
385
|
+
actionDetail: "aws-mcp/poll_message",
|
|
386
|
+
},
|
|
387
|
+
});
|
|
388
|
+
});
|
|
346
389
|
it("keeps accumulated usage from status-change action info", () => {
|
|
347
390
|
expect(resolveStatusChangeUsage({
|
|
348
391
|
usage: { inputTokens: 12000, outputTokens: 345 },
|
|
@@ -435,6 +478,20 @@ describe("SDK output forwarding", () => {
|
|
|
435
478
|
};
|
|
436
479
|
expect(formatSdkOutputEvent(thinkingEvent)).toBe("internal prompt or reasoning");
|
|
437
480
|
});
|
|
481
|
+
it("formats command output provider events as realtime output chunks", () => {
|
|
482
|
+
const commandOutputEvent = {
|
|
483
|
+
type: "command_output",
|
|
484
|
+
sessionId: "session-1",
|
|
485
|
+
timestamp: new Date(0).toISOString(),
|
|
486
|
+
data: {
|
|
487
|
+
text: "stdout chunk",
|
|
488
|
+
stream: "stdout",
|
|
489
|
+
sequence: 7,
|
|
490
|
+
cwd: "/repo",
|
|
491
|
+
},
|
|
492
|
+
};
|
|
493
|
+
expect(formatSdkOutputEvent(commandOutputEvent)).toBe("stdout chunk");
|
|
494
|
+
});
|
|
438
495
|
it("formats SDK errors as terminal output and ignores non-output events", () => {
|
|
439
496
|
const errorEvent = {
|
|
440
497
|
type: "error",
|
|
@@ -468,7 +525,11 @@ describe("SDK output forwarding", () => {
|
|
|
468
525
|
type: "ai_request",
|
|
469
526
|
sessionId: "session-1",
|
|
470
527
|
timestamp: new Date(0).toISOString(),
|
|
471
|
-
data: {
|
|
528
|
+
data: {
|
|
529
|
+
model: "test-model",
|
|
530
|
+
endpoint: "openai-compatible",
|
|
531
|
+
toolCount: 2,
|
|
532
|
+
},
|
|
472
533
|
};
|
|
473
534
|
const errorEvent = {
|
|
474
535
|
type: "error",
|
|
@@ -489,6 +550,28 @@ describe("SDK output forwarding", () => {
|
|
|
489
550
|
logMessage: "provider failed",
|
|
490
551
|
});
|
|
491
552
|
});
|
|
553
|
+
it("builds ordered ACode log metadata for command output callbacks", () => {
|
|
554
|
+
const commandOutputEvent = {
|
|
555
|
+
type: "command_output",
|
|
556
|
+
sessionId: "session-1",
|
|
557
|
+
timestamp: new Date(0).toISOString(),
|
|
558
|
+
data: {
|
|
559
|
+
text: "stdout chunk",
|
|
560
|
+
stream: "stdout",
|
|
561
|
+
sequence: 7,
|
|
562
|
+
cwd: "/repo",
|
|
563
|
+
},
|
|
564
|
+
};
|
|
565
|
+
expect(buildSdkOutputMetadata(commandOutputEvent)).toEqual({
|
|
566
|
+
sourceEventType: "command_output",
|
|
567
|
+
logCategory: "acode",
|
|
568
|
+
logLevel: "info",
|
|
569
|
+
logMessage: "命令输出(stdout #7): stdout chunk",
|
|
570
|
+
stream: "stdout",
|
|
571
|
+
sequence: 7,
|
|
572
|
+
cwd: "/repo",
|
|
573
|
+
});
|
|
574
|
+
});
|
|
492
575
|
it("does not mark streaming text chunks as standalone ACode log rows", () => {
|
|
493
576
|
const metadata = buildSdkOutputMetadata({
|
|
494
577
|
type: "text_delta",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auto-register.d.ts","sourceRoot":"","sources":["../../src/services/auto-register.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAmDH;;GAEG;AACH,UAAU,kBAAkB;IAC1B,eAAe;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,oBAAoB;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oCAAoC;IACpC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mCAAmC;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,0BAA0B;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,oBAAoB;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW;IACX,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW;IACX,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa;IACb,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,yCAAyC;IACzC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4BAA4B;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mCAAmC;IACnC,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,aAAa;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iBAAiB;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;
|
|
1
|
+
{"version":3,"file":"auto-register.d.ts","sourceRoot":"","sources":["../../src/services/auto-register.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAmDH;;GAEG;AACH,UAAU,kBAAkB;IAC1B,eAAe;IACf,OAAO,EAAE,OAAO,CAAC;IACjB,oBAAoB;IACpB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,oCAAoC;IACpC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mCAAmC;IACnC,OAAO,EAAE,MAAM,CAAC;IAChB,0BAA0B;IAC1B,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,oBAAoB;IACpB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,WAAW;IACX,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,WAAW;IACX,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,aAAa;IACb,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,yCAAyC;IACzC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,4BAA4B;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mCAAmC;IACnC,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,aAAa;IACb,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,iBAAiB;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAuBD,wBAAgB,2BAA2B,IAAI,MAAM,EAAE,CAEtD;AAiED;;GAEG;AACH,wBAAgB,6BAA6B,IAAI,MAAM,CAGtD;AAyJD;;;;;;GAMG;AACH,wBAAgB,UAAU,IAAI,kBAAkB,CA2C/C;AAED,wBAAgB,WAAW,IAAI,kBAAkB,EAAE,CA0ClD;AA2PD;;;;;;;;;;GAUG;AACH,wBAAsB,YAAY,CAChC,YAAY,CAAC,EAAE,OAAO,CAAC,kBAAkB,CAAC,GACzC,OAAO,CAAC,OAAO,CAAC,CAalB;AAyHD;;GAEG;AACH,wBAAsB,gCAAgC,IAAI,OAAO,CAAC;IAChE,OAAO,EAAE,OAAO,CAAC;IACjB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC,CAoED;AAED,wBAAsB,yCAAyC,CAC7D,aAAa,EAAE,MAAM,GACpB,OAAO,CAAC;IACT,OAAO,EAAE,OAAO,CAAC;IACjB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC,CA0ED;AAED,wBAAsB,UAAU,IAAI,OAAO,CAAC,OAAO,CAAC,CAgCnD;AAED;;GAEG;AACH,wBAAgB,oBAAoB;gBAh6BtB,OAAO;iBACN,MAAM;mBACJ,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC;kBACvB,IAAI;YACV,MAAM;EA85Bf;AAED;;GAEG;AACH,wBAAgB,YAAY,IAAI,OAAO,CAEtC;AAED;;GAEG;AACH,wBAAgB,aAAa,IAAI,MAAM,GAAG,SAAS,CAElD;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,oBAAoB,IAAI,OAAO,CAAC;IACpD,OAAO,EAAE,OAAO,CAAC;IACjB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB,CAAC,CA0ED"}
|
|
@@ -14,13 +14,12 @@ import fs from "node:fs";
|
|
|
14
14
|
import { logger } from "../utils/logger.js";
|
|
15
15
|
import { schedulerBaseUrl } from "../config.js";
|
|
16
16
|
import { clearRuntimeBinding, clearScopedRuntimeAccessToken, getRuntimeAccessToken, getRuntimeBindingPublicState, loadRuntimeBinding, normalizeSchedulerBaseUrl, saveRuntimeBinding, saveScopedRuntimeAccessToken, } from "./runtime-binding.js";
|
|
17
|
-
// 默认配置
|
|
18
17
|
const DEFAULT_CONFIG = {
|
|
19
18
|
enabled: false,
|
|
20
19
|
serverUrl: schedulerBaseUrl,
|
|
21
20
|
preferSameLanIp: true,
|
|
22
|
-
maxRetries:
|
|
23
|
-
retryInterval:
|
|
21
|
+
maxRetries: 3,
|
|
22
|
+
retryInterval: 2000,
|
|
24
23
|
};
|
|
25
24
|
let registrationState = {
|
|
26
25
|
registered: false,
|
|
@@ -533,8 +532,8 @@ async function autoRegisterSingle(config) {
|
|
|
533
532
|
return false;
|
|
534
533
|
}
|
|
535
534
|
// tenantId 现在是可选的,如果没有提供,后端会根据 userKey 自动推导
|
|
536
|
-
const maxRetries = config.maxRetries
|
|
537
|
-
const retryInterval = config.retryInterval
|
|
535
|
+
const maxRetries = config.maxRetries ?? 3;
|
|
536
|
+
const retryInterval = config.retryInterval ?? 2000;
|
|
538
537
|
// 重试循环
|
|
539
538
|
for (let attempt = 1; attempt <= maxRetries; attempt++) {
|
|
540
539
|
try {
|
|
@@ -31,6 +31,11 @@ export interface McpLaunchBindingClaimRequest {
|
|
|
31
31
|
export declare function enqueueMcpLaunchBinding(input: McpLaunchBindingInput): McpLaunchBinding | null;
|
|
32
32
|
export declare function claimMcpLaunchBinding(request: McpLaunchBindingClaimRequest): ClaimedMcpLaunchBinding | null;
|
|
33
33
|
export declare function getMcpLaunchQueueSize(workspacePath: unknown): number;
|
|
34
|
+
/**
|
|
35
|
+
* 主流程:按启动绑定 ID 移除尚未被 MCP node 认领的绑定。
|
|
36
|
+
* 具体逻辑:启动流程失败时调用;若绑定已被认领或 ID 不存在则返回 false,保持幂等。
|
|
37
|
+
*/
|
|
38
|
+
export declare function removeMcpLaunchBinding(bindingId: string): boolean;
|
|
34
39
|
export declare function clearMcpLaunchBindingQueues(): void;
|
|
35
40
|
/**
|
|
36
41
|
* 获取指定 agent 的最新 MCP session token。
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"mcp-launch-binding-queue.d.ts","sourceRoot":"","sources":["../../src/services/mcp-launch-binding-queue.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,uBAAwB,SAAQ,gBAAgB;IAC/D,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,4BAA4B;IAC3C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,aAAa,EAAE,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AA2DD,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,qBAAqB,GAAG,gBAAgB,GAAG,IAAI,CAyC7F;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,4BAA4B,GAAG,uBAAuB,GAAG,IAAI,CAkD3G;AAED,wBAAgB,qBAAqB,CAAC,aAAa,EAAE,OAAO,GAAG,MAAM,CAOpE;AAED,wBAAgB,2BAA2B,IAAI,IAAI,CAElD;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG;IAAE,kBAAkB,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAM1F"}
|
|
1
|
+
{"version":3,"file":"mcp-launch-binding-queue.d.ts","sourceRoot":"","sources":["../../src/services/mcp-launch-binding-queue.ts"],"names":[],"mappings":"AAaA,MAAM,WAAW,qBAAqB;IACpC,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,UAAU,EAAE,MAAM,CAAC;IACnB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,UAAU,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,uBAAwB,SAAQ,gBAAgB;IAC/D,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,4BAA4B;IAC3C,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,aAAa,EAAE,OAAO,CAAC;IACvB,SAAS,CAAC,EAAE,OAAO,CAAC;CACrB;AA2DD,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,qBAAqB,GAAG,gBAAgB,GAAG,IAAI,CAyC7F;AAED,wBAAgB,qBAAqB,CAAC,OAAO,EAAE,4BAA4B,GAAG,uBAAuB,GAAG,IAAI,CAkD3G;AAED,wBAAgB,qBAAqB,CAAC,aAAa,EAAE,OAAO,GAAG,MAAM,CAOpE;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAcjE;AAED,wBAAgB,2BAA2B,IAAI,IAAI,CAElD;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,GAAG;IAAE,kBAAkB,EAAE,MAAM,CAAA;CAAE,GAAG,IAAI,CAM1F"}
|
|
@@ -142,6 +142,23 @@ export function getMcpLaunchQueueSize(workspacePath) {
|
|
|
142
142
|
}
|
|
143
143
|
return launchBindings.filter((binding) => normalizeWorkspacePath(binding.workspacePath) === workspaceKey).length;
|
|
144
144
|
}
|
|
145
|
+
/**
|
|
146
|
+
* 主流程:按启动绑定 ID 移除尚未被 MCP node 认领的绑定。
|
|
147
|
+
* 具体逻辑:启动流程失败时调用;若绑定已被认领或 ID 不存在则返回 false,保持幂等。
|
|
148
|
+
*/
|
|
149
|
+
export function removeMcpLaunchBinding(bindingId) {
|
|
150
|
+
pruneExpiredBindings();
|
|
151
|
+
const normalizedId = String(bindingId || "").trim();
|
|
152
|
+
if (!normalizedId) {
|
|
153
|
+
return false;
|
|
154
|
+
}
|
|
155
|
+
const index = launchBindings.findIndex((binding) => binding.id === normalizedId);
|
|
156
|
+
if (index < 0) {
|
|
157
|
+
return false;
|
|
158
|
+
}
|
|
159
|
+
launchBindings.splice(index, 1);
|
|
160
|
+
return true;
|
|
161
|
+
}
|
|
145
162
|
export function clearMcpLaunchBindingQueues() {
|
|
146
163
|
launchBindings.splice(0, launchBindings.length);
|
|
147
164
|
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { afterEach, describe, expect, it } from 'vitest';
|
|
2
|
-
import { claimMcpLaunchBinding, clearMcpLaunchBindingQueues, enqueueMcpLaunchBinding, getMcpLaunchQueueSize, } from './mcp-launch-binding-queue.js';
|
|
2
|
+
import { claimMcpLaunchBinding, clearMcpLaunchBindingQueues, enqueueMcpLaunchBinding, getMcpLaunchQueueSize, removeMcpLaunchBinding, } from './mcp-launch-binding-queue.js';
|
|
3
3
|
describe('mcp launch binding queue', () => {
|
|
4
4
|
afterEach(() => {
|
|
5
5
|
clearMcpLaunchBindingQueues();
|
|
@@ -157,6 +157,21 @@ describe('mcp launch binding queue', () => {
|
|
|
157
157
|
expect(claimMcpLaunchBinding({ workspacePath: 'C:/repo/b', serverUrl: 'ws://server:7380/ws/agent' })?.agentId).toBe('agent-b');
|
|
158
158
|
expect(claimMcpLaunchBinding({ workspacePath: 'C:/repo/a', serverUrl: 'ws://server:7380/ws/agent' })?.agentId).toBe('agent-a');
|
|
159
159
|
});
|
|
160
|
+
it('removes a stale launch binding by id after a failed start', () => {
|
|
161
|
+
const binding = enqueueMcpLaunchBinding({
|
|
162
|
+
agentId: 'agent-a',
|
|
163
|
+
workspacePath: 'C:/repo/demo',
|
|
164
|
+
serverUrl: 'ws://server:7380/ws/agent',
|
|
165
|
+
});
|
|
166
|
+
expect(binding).not.toBeNull();
|
|
167
|
+
expect(removeMcpLaunchBinding(binding?.id || '')).toBe(true);
|
|
168
|
+
expect(claimMcpLaunchBinding({
|
|
169
|
+
agentId: 'agent-a',
|
|
170
|
+
workspacePath: 'C:/repo/demo',
|
|
171
|
+
serverUrl: 'ws://server:7380/ws/agent',
|
|
172
|
+
})).toBeNull();
|
|
173
|
+
expect(getMcpLaunchQueueSize('C:/repo/demo')).toBe(0);
|
|
174
|
+
});
|
|
160
175
|
it('returns null for missing or invalid workspaces', () => {
|
|
161
176
|
expect(enqueueMcpLaunchBinding({ agentId: '', workspacePath: 'C:/repo/demo' })).toBeNull();
|
|
162
177
|
expect(enqueueMcpLaunchBinding({ agentId: 'agent-a', workspacePath: '' })).toBeNull();
|
|
@@ -21,6 +21,11 @@ export interface RuntimeOutputMetadata {
|
|
|
21
21
|
logLevel?: "info" | "warn" | "error";
|
|
22
22
|
logMessage?: string;
|
|
23
23
|
logCategory?: string;
|
|
24
|
+
stream?: string;
|
|
25
|
+
sequence?: number;
|
|
26
|
+
cwd?: string;
|
|
27
|
+
commandFilePath?: string;
|
|
28
|
+
commandLineCount?: number;
|
|
24
29
|
}
|
|
25
30
|
/** 活跃会话存储 */
|
|
26
31
|
export declare const sessions: Map<string, Session>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"session-output.d.ts","sourceRoot":"","sources":["../../src/services/session-output.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAG3C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAI3C,UAAU,uBAAuB;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,0BAA0B;IACzC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,qBAAqB;IACpC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;IACrC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"session-output.d.ts","sourceRoot":"","sources":["../../src/services/session-output.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,OAAO,CAAC;AAG3C,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,aAAa,CAAC;AAI3C,UAAU,uBAAuB;IAC/B,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,0BAA0B;IACzC,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AAED,MAAM,WAAW,qBAAqB;IACpC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,EAAE,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;IACrC,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,GAAG,CAAC,EAAE,MAAM,CAAC;IACb,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,MAAM,CAAC;CAC3B;AA8BD,aAAa;AACb,eAAO,MAAM,QAAQ,EAAE,GAAG,CAAC,MAAM,EAAE,OAAO,CAAa,CAAC;AAExD;;;;;;;GAOG;AACH,wBAAsB,UAAU,CAC9B,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,GAAG,IAAI,EACxB,MAAM,EAAE,MAAM,EACd,UAAU,CAAC,EAAE,uBAAuB,EACpC,KAAK,CAAC,EAAE;IAAE,WAAW,EAAE,MAAM,CAAC;IAAC,YAAY,EAAE,MAAM,CAAA;CAAE,EACrD,WAAW,CAAC,EAAE,0BAA0B,GACvC,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,GAAG,SAAS,CAAC,CA4C7C;AAED;;;;;;;GAOG;AACH,wBAAsB,UAAU,CAC9B,OAAO,EAAE,MAAM,EACf,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,GAAG,EAAE,MAAM,EACX,QAAQ,CAAC,EAAE,qBAAqB,EAChC,WAAW,CAAC,EAAE,0BAA0B,GACvC,OAAO,CAAC,IAAI,CAAC,CA2Bf;AAED;;;;;;GAMG;AACH,wBAAsB,mBAAmB,CACvC,OAAO,EAAE,MAAM,EACf,SAAS,EAAE,MAAM,EACjB,SAAS,EAAE,OAAO,EAAE,EACpB,WAAW,CAAC,EAAE,0BAA0B,GACvC,OAAO,CAAC,IAAI,CAAC,CAef;AAED,MAAM,WAAW,yBAAyB;IACxC,aAAa,CAAC,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE,MAAM,CAAC;IACtB,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAED;;GAEG;AACH,wBAAsB,eAAe,CACnC,OAAO,EAAE,yBAAyB,GACjC,OAAO,CAAC,IAAI,CAAC,CAef;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,IAAI,CAgBzE;AAED;;;;GAIG;AACH,wBAAgB,mBAAmB,CAAC,SAAS,EAAE,MAAM,GAAG,IAAI,CAa3D;AAED;;;;GAIG;AACH,wBAAsB,kBAAkB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAqCzE"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { type CommandOutputSink } from "./builtins/shellCommandRunner.js";
|
|
1
2
|
export type JsonValue = string | number | boolean | null | JsonValue[] | {
|
|
2
3
|
[key: string]: JsonValue;
|
|
3
4
|
};
|
|
@@ -10,7 +11,10 @@ export interface ACodeBuiltInTool {
|
|
|
10
11
|
exposedName: string;
|
|
11
12
|
description: string;
|
|
12
13
|
inputSchema: JsonObject;
|
|
13
|
-
execute(args: JsonObject): Promise<unknown>;
|
|
14
|
+
execute(args: JsonObject, context?: ACodeBuiltInToolExecutionContext): Promise<unknown>;
|
|
15
|
+
}
|
|
16
|
+
export interface ACodeBuiltInToolExecutionContext {
|
|
17
|
+
readonly onOutput?: CommandOutputSink;
|
|
14
18
|
}
|
|
15
19
|
export declare function createBuiltInFileTools(workingDirectory: string): ACodeBuiltInTool[];
|
|
16
20
|
//# sourceMappingURL=built-in-file-tools.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"built-in-file-tools.d.ts","sourceRoot":"","sources":["../src/built-in-file-tools.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"built-in-file-tools.d.ts","sourceRoot":"","sources":["../src/built-in-file-tools.ts"],"names":[],"mappings":"AAIA,OAAO,EAEL,KAAK,iBAAiB,EACvB,MAAM,kCAAkC,CAAC;AAE1C,MAAM,MAAM,SAAS,GACjB,MAAM,GACN,MAAM,GACN,OAAO,GACP,IAAI,GACJ,SAAS,EAAE,GACX;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC;AACjC,MAAM,MAAM,UAAU,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,SAAS,CAAA;CAAE,CAAC;AAEtD,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,SAAS,CAAC;IAChB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,UAAU,CAAC;IACxB,OAAO,CACL,IAAI,EAAE,UAAU,EAChB,OAAO,CAAC,EAAE,gCAAgC,GACzC,OAAO,CAAC,OAAO,CAAC,CAAC;CACrB;AAED,MAAM,WAAW,gCAAgC;IAC/C,QAAQ,CAAC,QAAQ,CAAC,EAAE,iBAAiB,CAAC;CACvC;AAsfD,wBAAgB,sBAAsB,CACpC,gBAAgB,EAAE,MAAM,GACvB,gBAAgB,EAAE,CAOpB"}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { spawn } from "node:child_process";
|
|
2
1
|
import { randomUUID } from "node:crypto";
|
|
3
2
|
import { promises as fs } from "node:fs";
|
|
4
3
|
import path from "node:path";
|
|
4
|
+
import { runShellCommand, } from "./builtins/shellCommandRunner.js";
|
|
5
5
|
function toDisplayPath(targetPath) {
|
|
6
6
|
return targetPath.replace(/\\/g, "/");
|
|
7
7
|
}
|
|
@@ -178,208 +178,10 @@ async function readFileInsideWorkspace(workingDirectory, filePath) {
|
|
|
178
178
|
content: await fs.readFile(realTargetPath, "utf-8"),
|
|
179
179
|
};
|
|
180
180
|
}
|
|
181
|
-
const DEFAULT_COMMAND_TIMEOUT_MS = 30_000;
|
|
182
181
|
const MAX_COMMAND_TIMEOUT_MS = 10 * 60_000;
|
|
182
|
+
const DEFAULT_COMMAND_TIMEOUT_MS = MAX_COMMAND_TIMEOUT_MS;
|
|
183
183
|
const DEFAULT_COMMAND_INACTIVITY_TIMEOUT_MS = 60_000;
|
|
184
184
|
const MAX_COMMAND_INACTIVITY_TIMEOUT_MS = 10 * 60_000;
|
|
185
|
-
const MAX_COMMAND_OUTPUT_BYTES = 128 * 1024;
|
|
186
|
-
const COMMAND_OUTPUT_SPILLOVER_LINE_LIMIT = 100;
|
|
187
|
-
function padDatePart(value) {
|
|
188
|
-
return String(value).padStart(2, "0");
|
|
189
|
-
}
|
|
190
|
-
function countOutputLines(output) {
|
|
191
|
-
if (!output) {
|
|
192
|
-
return 0;
|
|
193
|
-
}
|
|
194
|
-
const normalized = output.replace(/\r\n/g, "\n").replace(/\r/g, "\n");
|
|
195
|
-
const withoutTrailingLineBreak = normalized.endsWith("\n")
|
|
196
|
-
? normalized.slice(0, -1)
|
|
197
|
-
: normalized;
|
|
198
|
-
return withoutTrailingLineBreak
|
|
199
|
-
? withoutTrailingLineBreak.split("\n").length
|
|
200
|
-
: 1;
|
|
201
|
-
}
|
|
202
|
-
function buildCommandOutputSpilloverPath(workspaceRoot, now = new Date()) {
|
|
203
|
-
const year = now.getFullYear();
|
|
204
|
-
const month = padDatePart(now.getMonth() + 1);
|
|
205
|
-
const day = padDatePart(now.getDate());
|
|
206
|
-
const hour = padDatePart(now.getHours());
|
|
207
|
-
const minute = padDatePart(now.getMinutes());
|
|
208
|
-
const timestamp = `${year}${month}${day}-${hour}${minute}${padDatePart(now.getSeconds())}-${String(now.getMilliseconds()).padStart(3, "0")}-${process.pid}-${randomUUID().slice(0, 8)}`;
|
|
209
|
-
return path.join(workspaceRoot, ".agentswork", "acode", "cmd-dist", `${year}-${month}-${day}`, hour, minute, `${timestamp}-cmd.out`);
|
|
210
|
-
}
|
|
211
|
-
async function writeCommandOutputSpilloverFile(workspaceRoot, content) {
|
|
212
|
-
const targetPath = buildCommandOutputSpilloverPath(workspaceRoot);
|
|
213
|
-
await fs.mkdir(path.dirname(targetPath), { recursive: true });
|
|
214
|
-
await fs.writeFile(targetPath, content, "utf-8");
|
|
215
|
-
return targetPath;
|
|
216
|
-
}
|
|
217
|
-
function buildCommandOutputSpilloverContent(input) {
|
|
218
|
-
return [
|
|
219
|
-
`Command: ${input.commandText}`,
|
|
220
|
-
`CWD: ${input.cwd}`,
|
|
221
|
-
`Started: ${input.startedAt.toISOString()}`,
|
|
222
|
-
`Ended: ${input.endedAt.toISOString()}`,
|
|
223
|
-
`Exit code: ${input.exitCode ?? "null"}`,
|
|
224
|
-
`Signal: ${input.signal ?? "null"}`,
|
|
225
|
-
`Timed out: ${input.timedOut}`,
|
|
226
|
-
`Timed out by inactivity: ${input.inactivityTimedOut}`,
|
|
227
|
-
"",
|
|
228
|
-
"--- stdout ---",
|
|
229
|
-
input.stdout,
|
|
230
|
-
"",
|
|
231
|
-
"--- stderr ---",
|
|
232
|
-
input.stderr,
|
|
233
|
-
].join("\n");
|
|
234
|
-
}
|
|
235
|
-
function formatCommandOutputSpilloverStdout(outputFilePath, outputLineCount) {
|
|
236
|
-
return [
|
|
237
|
-
`[ACode] 命令输出超过 ${COMMAND_OUTPUT_SPILLOVER_LINE_LIMIT} 行(共 ${outputLineCount} 行),完整输出已写入: ${toDisplayPath(outputFilePath)}`,
|
|
238
|
-
"[ACode] Agent 可自行读取该文件,或在该文件中搜索需要的内容。",
|
|
239
|
-
"",
|
|
240
|
-
].join("\n");
|
|
241
|
-
}
|
|
242
|
-
function truncateOutput(value) {
|
|
243
|
-
const bytes = Buffer.byteLength(value, "utf-8");
|
|
244
|
-
if (bytes <= MAX_COMMAND_OUTPUT_BYTES) {
|
|
245
|
-
return { text: value, truncated: false };
|
|
246
|
-
}
|
|
247
|
-
const buffer = Buffer.from(value, "utf-8");
|
|
248
|
-
return {
|
|
249
|
-
text: buffer.subarray(0, MAX_COMMAND_OUTPUT_BYTES).toString("utf-8") +
|
|
250
|
-
`\n...[truncated after ${MAX_COMMAND_OUTPUT_BYTES} bytes]`,
|
|
251
|
-
truncated: true,
|
|
252
|
-
};
|
|
253
|
-
}
|
|
254
|
-
function shellExecutable() {
|
|
255
|
-
if (process.platform === "win32") {
|
|
256
|
-
return {
|
|
257
|
-
command: process.env.ComSpec || "cmd.exe",
|
|
258
|
-
argsPrefix: ["/d", "/s", "/c"],
|
|
259
|
-
};
|
|
260
|
-
}
|
|
261
|
-
return { command: process.env.SHELL || "/bin/sh", argsPrefix: ["-lc"] };
|
|
262
|
-
}
|
|
263
|
-
function runShellCommand(commandText, workspaceRoot, cwd, timeoutMs, inactivityTimeoutMs) {
|
|
264
|
-
return new Promise((resolve, reject) => {
|
|
265
|
-
const shell = shellExecutable();
|
|
266
|
-
const startedAt = new Date();
|
|
267
|
-
const child = spawn(shell.command, [...shell.argsPrefix, commandText], {
|
|
268
|
-
cwd,
|
|
269
|
-
env: process.env,
|
|
270
|
-
windowsHide: true,
|
|
271
|
-
});
|
|
272
|
-
let stdout = "";
|
|
273
|
-
let stderr = "";
|
|
274
|
-
let timedOut = false;
|
|
275
|
-
let inactivityTimedOut = false;
|
|
276
|
-
let killEscalationTimer;
|
|
277
|
-
let inactivityTimer;
|
|
278
|
-
const escalateKill = () => {
|
|
279
|
-
killEscalationTimer = setTimeout(() => {
|
|
280
|
-
if (!child.killed) {
|
|
281
|
-
child.kill("SIGKILL");
|
|
282
|
-
}
|
|
283
|
-
}, 1000);
|
|
284
|
-
killEscalationTimer.unref?.();
|
|
285
|
-
};
|
|
286
|
-
const timer = setTimeout(() => {
|
|
287
|
-
timedOut = true;
|
|
288
|
-
child.kill("SIGTERM");
|
|
289
|
-
escalateKill();
|
|
290
|
-
}, timeoutMs);
|
|
291
|
-
timer.unref?.();
|
|
292
|
-
const resetInactivityTimer = () => {
|
|
293
|
-
if (inactivityTimer) {
|
|
294
|
-
clearTimeout(inactivityTimer);
|
|
295
|
-
}
|
|
296
|
-
inactivityTimer = setTimeout(() => {
|
|
297
|
-
inactivityTimedOut = true;
|
|
298
|
-
timedOut = true;
|
|
299
|
-
child.kill("SIGTERM");
|
|
300
|
-
escalateKill();
|
|
301
|
-
}, inactivityTimeoutMs);
|
|
302
|
-
inactivityTimer.unref?.();
|
|
303
|
-
};
|
|
304
|
-
resetInactivityTimer();
|
|
305
|
-
child.stdout?.setEncoding("utf-8");
|
|
306
|
-
child.stderr?.setEncoding("utf-8");
|
|
307
|
-
child.stdout?.on("data", (chunk) => {
|
|
308
|
-
stdout += chunk;
|
|
309
|
-
resetInactivityTimer();
|
|
310
|
-
});
|
|
311
|
-
child.stderr?.on("data", (chunk) => {
|
|
312
|
-
stderr += chunk;
|
|
313
|
-
resetInactivityTimer();
|
|
314
|
-
});
|
|
315
|
-
child.on("error", (error) => {
|
|
316
|
-
clearTimeout(timer);
|
|
317
|
-
if (inactivityTimer) {
|
|
318
|
-
clearTimeout(inactivityTimer);
|
|
319
|
-
}
|
|
320
|
-
if (killEscalationTimer) {
|
|
321
|
-
clearTimeout(killEscalationTimer);
|
|
322
|
-
}
|
|
323
|
-
reject(error);
|
|
324
|
-
});
|
|
325
|
-
child.on("close", async (exitCode, signal) => {
|
|
326
|
-
clearTimeout(timer);
|
|
327
|
-
if (inactivityTimer) {
|
|
328
|
-
clearTimeout(inactivityTimer);
|
|
329
|
-
}
|
|
330
|
-
if (killEscalationTimer) {
|
|
331
|
-
clearTimeout(killEscalationTimer);
|
|
332
|
-
}
|
|
333
|
-
const endedAt = new Date();
|
|
334
|
-
const outputLineCount = countOutputLines(`${stdout}${stderr}`);
|
|
335
|
-
try {
|
|
336
|
-
if (outputLineCount > COMMAND_OUTPUT_SPILLOVER_LINE_LIMIT) {
|
|
337
|
-
const outputFilePath = await writeCommandOutputSpilloverFile(workspaceRoot, buildCommandOutputSpilloverContent({
|
|
338
|
-
commandText,
|
|
339
|
-
cwd,
|
|
340
|
-
startedAt,
|
|
341
|
-
endedAt,
|
|
342
|
-
exitCode,
|
|
343
|
-
signal,
|
|
344
|
-
timedOut,
|
|
345
|
-
inactivityTimedOut,
|
|
346
|
-
stdout,
|
|
347
|
-
stderr,
|
|
348
|
-
}));
|
|
349
|
-
resolve({
|
|
350
|
-
exitCode,
|
|
351
|
-
signal,
|
|
352
|
-
stdout: formatCommandOutputSpilloverStdout(outputFilePath, outputLineCount),
|
|
353
|
-
stderr: "",
|
|
354
|
-
durationMs: endedAt.getTime() - startedAt.getTime(),
|
|
355
|
-
timedOut,
|
|
356
|
-
inactivityTimedOut,
|
|
357
|
-
outputSpilled: true,
|
|
358
|
-
outputFilePath: toDisplayPath(outputFilePath),
|
|
359
|
-
outputLineCount,
|
|
360
|
-
});
|
|
361
|
-
return;
|
|
362
|
-
}
|
|
363
|
-
const truncatedStdout = truncateOutput(stdout);
|
|
364
|
-
const truncatedStderr = truncateOutput(stderr);
|
|
365
|
-
resolve({
|
|
366
|
-
exitCode,
|
|
367
|
-
signal,
|
|
368
|
-
stdout: truncatedStdout.text,
|
|
369
|
-
stderr: truncatedStderr.text,
|
|
370
|
-
durationMs: endedAt.getTime() - startedAt.getTime(),
|
|
371
|
-
timedOut,
|
|
372
|
-
inactivityTimedOut,
|
|
373
|
-
outputSpilled: false,
|
|
374
|
-
outputLineCount,
|
|
375
|
-
});
|
|
376
|
-
}
|
|
377
|
-
catch (error) {
|
|
378
|
-
reject(error);
|
|
379
|
-
}
|
|
380
|
-
});
|
|
381
|
-
});
|
|
382
|
-
}
|
|
383
185
|
function writeFileTool(workingDirectory) {
|
|
384
186
|
return {
|
|
385
187
|
kind: "builtin",
|
|
@@ -512,7 +314,7 @@ function bashTool(workingDirectory) {
|
|
|
512
314
|
},
|
|
513
315
|
timeout_ms: {
|
|
514
316
|
type: "number",
|
|
515
|
-
description: "Optional timeout in milliseconds. Defaults to
|
|
317
|
+
description: "Optional timeout in milliseconds. Defaults to 600000 and is capped at 600000.",
|
|
516
318
|
},
|
|
517
319
|
inactivity_timeout_ms: {
|
|
518
320
|
type: "number",
|
|
@@ -526,7 +328,7 @@ function bashTool(workingDirectory) {
|
|
|
526
328
|
required: ["command"],
|
|
527
329
|
additionalProperties: false,
|
|
528
330
|
},
|
|
529
|
-
async execute(args) {
|
|
331
|
+
async execute(args, context) {
|
|
530
332
|
const command = readStringArg(args, ["command"], "command").trim();
|
|
531
333
|
if (!command) {
|
|
532
334
|
throw new Error("command must not be empty");
|
|
@@ -537,7 +339,14 @@ function bashTool(workingDirectory) {
|
|
|
537
339
|
const inactivityTimeoutMs = Math.min(requestedInactivityTimeoutMs, MAX_COMMAND_INACTIVITY_TIMEOUT_MS);
|
|
538
340
|
const cwdArg = readOptionalStringArg(args, ["cwd"]);
|
|
539
341
|
const resolved = await resolveWorkspaceDirectory(workingDirectory, cwdArg);
|
|
540
|
-
const result = await runShellCommand(
|
|
342
|
+
const result = await runShellCommand({
|
|
343
|
+
commandText: command,
|
|
344
|
+
workspaceRoot: resolved.workspaceRoot,
|
|
345
|
+
cwd: resolved.cwd,
|
|
346
|
+
timeoutMs,
|
|
347
|
+
inactivityTimeoutMs,
|
|
348
|
+
onOutput: context?.onOutput,
|
|
349
|
+
});
|
|
541
350
|
return {
|
|
542
351
|
ok: result.exitCode === 0 && !result.timedOut,
|
|
543
352
|
tool: "Bash",
|
|
@@ -553,6 +362,8 @@ function bashTool(workingDirectory) {
|
|
|
553
362
|
outputSpilled: result.outputSpilled,
|
|
554
363
|
outputFilePath: result.outputFilePath,
|
|
555
364
|
outputLineCount: result.outputLineCount,
|
|
365
|
+
commandFilePath: result.commandFilePath,
|
|
366
|
+
commandLineCount: result.commandLineCount,
|
|
556
367
|
stdout: result.stdout,
|
|
557
368
|
stderr: result.stderr,
|
|
558
369
|
};
|
|
@@ -0,0 +1,25 @@
|
|
|
1
|
+
export declare const COMMAND_OUTPUT_SPILLOVER_LINE_LIMIT = 300;
|
|
2
|
+
export declare const LONG_COMMAND_LINE_LIMIT = 300;
|
|
3
|
+
export declare const MAX_COMMAND_OUTPUT_BYTES: number;
|
|
4
|
+
export declare function toDisplayPath(targetPath: string): string;
|
|
5
|
+
export declare function countOutputLines(output: string): number;
|
|
6
|
+
export declare function writeCommandArtifactFile(workspaceRoot: string, suffix: string, extension: string, content: string, now?: Date): Promise<string>;
|
|
7
|
+
export declare function buildCommandOutputSpilloverContent(input: {
|
|
8
|
+
readonly commandText: string;
|
|
9
|
+
readonly commandFilePath?: string;
|
|
10
|
+
readonly commandLineCount: number;
|
|
11
|
+
readonly cwd: string;
|
|
12
|
+
readonly startedAt: Date;
|
|
13
|
+
readonly endedAt: Date;
|
|
14
|
+
readonly exitCode: number | null;
|
|
15
|
+
readonly signal: NodeJS.Signals | null;
|
|
16
|
+
readonly timedOut: boolean;
|
|
17
|
+
readonly inactivityTimedOut: boolean;
|
|
18
|
+
readonly stdout: string;
|
|
19
|
+
readonly stderr: string;
|
|
20
|
+
}): string;
|
|
21
|
+
export declare function formatCommandOutputSpilloverStdout(outputFilePath: string, outputLineCount: number): string;
|
|
22
|
+
export declare function truncateOutput(value: string): {
|
|
23
|
+
readonly text: string;
|
|
24
|
+
};
|
|
25
|
+
//# sourceMappingURL=commandArtifacts.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"commandArtifacts.d.ts","sourceRoot":"","sources":["../../src/builtins/commandArtifacts.ts"],"names":[],"mappings":"AAIA,eAAO,MAAM,mCAAmC,MAAM,CAAC;AACvD,eAAO,MAAM,uBAAuB,MAAM,CAAC;AAC3C,eAAO,MAAM,wBAAwB,QAAa,CAAC;AAEnD,wBAAgB,aAAa,CAAC,UAAU,EAAE,MAAM,GAAG,MAAM,CAExD;AAMD,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,MAAM,GAAG,MAAM,CAWvD;AA4BD,wBAAsB,wBAAwB,CAC5C,aAAa,EAAE,MAAM,EACrB,MAAM,EAAE,MAAM,EACd,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,MAAM,EACf,GAAG,OAAa,GACf,OAAO,CAAC,MAAM,CAAC,CAUjB;AAED,wBAAgB,kCAAkC,CAAC,KAAK,EAAE;IACxD,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC;IAC7B,QAAQ,CAAC,eAAe,CAAC,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,gBAAgB,EAAE,MAAM,CAAC;IAClC,QAAQ,CAAC,GAAG,EAAE,MAAM,CAAC;IACrB,QAAQ,CAAC,SAAS,EAAE,IAAI,CAAC;IACzB,QAAQ,CAAC,OAAO,EAAE,IAAI,CAAC;IACvB,QAAQ,CAAC,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACjC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,IAAI,CAAC;IACvC,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,kBAAkB,EAAE,OAAO,CAAC;IACrC,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IACxB,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;CACzB,GAAG,MAAM,CAmBT;AAED,wBAAgB,kCAAkC,CAChD,cAAc,EAAE,MAAM,EACtB,eAAe,EAAE,MAAM,GACtB,MAAM,CAMR;AAED,wBAAgB,cAAc,CAAC,KAAK,EAAE,MAAM,GAAG;IAAE,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;CAAE,CAWvE"}
|