agentic-engineering-harness 0.6.4 → 0.6.6

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 (50) hide show
  1. package/README.md +119 -17
  2. package/dist/audit/run.d.ts +2 -0
  3. package/dist/audit/run.js +28 -15
  4. package/dist/audit/run.js.map +1 -1
  5. package/dist/core/init.js +9 -2
  6. package/dist/core/init.js.map +1 -1
  7. package/dist/core/types.d.ts +9 -0
  8. package/dist/main.d.ts +2 -0
  9. package/dist/main.js +266 -0
  10. package/dist/main.js.map +1 -0
  11. package/dist/operations/controller.d.ts +17 -0
  12. package/dist/operations/controller.js +198 -0
  13. package/dist/operations/controller.js.map +1 -0
  14. package/dist/operations/interactive.d.ts +5 -0
  15. package/dist/operations/interactive.js +45 -0
  16. package/dist/operations/interactive.js.map +1 -0
  17. package/dist/operations/mcp.d.ts +1 -0
  18. package/dist/operations/mcp.js +129 -0
  19. package/dist/operations/mcp.js.map +1 -0
  20. package/dist/operations/state.d.ts +43 -0
  21. package/dist/operations/state.js +127 -0
  22. package/dist/operations/state.js.map +1 -0
  23. package/dist/paseo/launchSpec.d.ts +25 -0
  24. package/dist/paseo/launchSpec.js +69 -0
  25. package/dist/paseo/launchSpec.js.map +1 -0
  26. package/dist/paseo/runtime.d.ts +8 -1
  27. package/dist/paseo/runtime.js +66 -21
  28. package/dist/paseo/runtime.js.map +1 -1
  29. package/dist/paseo/sdk.d.ts +33 -12
  30. package/dist/paseo/sdk.js +122 -55
  31. package/dist/paseo/sdk.js.map +1 -1
  32. package/dist/paseo/start.d.ts +9 -2
  33. package/dist/paseo/start.js +63 -13
  34. package/dist/paseo/start.js.map +1 -1
  35. package/dist/runtime/invocation.d.ts +10 -0
  36. package/dist/runtime/invocation.js +51 -0
  37. package/dist/runtime/invocation.js.map +1 -0
  38. package/dist/telemetry/events.js +19 -0
  39. package/dist/telemetry/events.js.map +1 -1
  40. package/dist/workers/agentPrompt.d.ts +4 -0
  41. package/dist/workers/agentPrompt.js +110 -32
  42. package/dist/workers/agentPrompt.js.map +1 -1
  43. package/dist/workers/paseo.js +23 -26
  44. package/dist/workers/paseo.js.map +1 -1
  45. package/docs/PASEO.md +162 -27
  46. package/package.json +10 -6
  47. package/scripts/link-self-bin.mjs +36 -0
  48. package/skills/engineering-workflow/SKILL.md +40 -16
  49. package/skills/paseo-orchestration/SKILL.md +18 -3
  50. package/templates/AGENTS.md +8 -6
@@ -0,0 +1,129 @@
1
+ import readline from "node:readline";
2
+ import path from "node:path";
3
+ import process from "node:process";
4
+ import { cancelOperation, startDetachedOperation } from "./controller.js";
5
+ import { loadOperation } from "./state.js";
6
+ const tools = [
7
+ {
8
+ name: "aeh_operation_start_audit",
9
+ description: "Start a detached Harness AUDIT for this lead's fixed project root and return its durable operation record immediately.",
10
+ inputSchema: {
11
+ type: "object",
12
+ properties: {
13
+ request: { type: "string" },
14
+ files: { type: "array", items: { type: "string" } },
15
+ domains: { type: "array", items: { type: "string" } },
16
+ risk: { type: "string", enum: ["low", "medium", "high"] },
17
+ reviewers: { type: "array", items: { type: "string" } }
18
+ },
19
+ required: ["request"],
20
+ additionalProperties: false
21
+ }
22
+ },
23
+ {
24
+ name: "aeh_operation_start_run",
25
+ description: "Start detached execution of an already prepared/sealed AEH task in this lead's fixed project root and return its operation record immediately.",
26
+ inputSchema: {
27
+ type: "object",
28
+ properties: { taskId: { type: "string" }, profile: { type: "string" } },
29
+ required: ["taskId"],
30
+ additionalProperties: false
31
+ }
32
+ },
33
+ {
34
+ name: "aeh_operation_status",
35
+ description: "Read durable status/phase/result for an AEH operation in this lead's fixed project root without blocking the caller.",
36
+ inputSchema: {
37
+ type: "object",
38
+ properties: { operationId: { type: "string" } },
39
+ required: ["operationId"],
40
+ additionalProperties: false
41
+ }
42
+ },
43
+ {
44
+ name: "aeh_operation_cancel",
45
+ description: "Cancel a running AEH operation in this lead's fixed project root and persist CANCELLED state.",
46
+ inputSchema: {
47
+ type: "object",
48
+ properties: { operationId: { type: "string" } },
49
+ required: ["operationId"],
50
+ additionalProperties: false
51
+ }
52
+ }
53
+ ];
54
+ export async function serveOperationMcp() {
55
+ const rl = readline.createInterface({ input: process.stdin, crlfDelay: Infinity });
56
+ for await (const line of rl) {
57
+ if (!line.trim())
58
+ continue;
59
+ let request;
60
+ try {
61
+ request = JSON.parse(line);
62
+ }
63
+ catch {
64
+ continue;
65
+ }
66
+ if (request.id === undefined || request.id === null)
67
+ continue;
68
+ try {
69
+ write({ jsonrpc: "2.0", id: request.id, result: await handle(request) });
70
+ }
71
+ catch (error) {
72
+ write({ jsonrpc: "2.0", id: request.id, error: { code: -32603, message: error instanceof Error ? error.message : String(error) } });
73
+ }
74
+ }
75
+ }
76
+ async function handle(request) {
77
+ if (request.method === "initialize") {
78
+ return {
79
+ protocolVersion: typeof request.params?.protocolVersion === "string" ? request.params.protocolVersion : "2025-06-18",
80
+ capabilities: { tools: {} },
81
+ serverInfo: { name: "aeh-operation-controller", version: "1" }
82
+ };
83
+ }
84
+ if (request.method === "ping")
85
+ return {};
86
+ if (request.method === "tools/list")
87
+ return { tools };
88
+ if (request.method === "tools/call")
89
+ return callTool(request.params ?? {});
90
+ throw new Error(`Unsupported MCP method: ${request.method ?? "<missing>"}`);
91
+ }
92
+ async function callTool(params) {
93
+ const name = string(params.name, "tool name");
94
+ const args = object(params.arguments);
95
+ const root = controlRoot();
96
+ if (name === "aeh_operation_start_audit") {
97
+ const payload = {
98
+ request: string(args.request, "request"),
99
+ files: stringArray(args.files),
100
+ domains: stringArray(args.domains),
101
+ risk: risk(args.risk),
102
+ reviewers: stringArray(args.reviewers)
103
+ };
104
+ return toolResult(await startDetachedOperation(root, "audit", payload, { nodeExecutable: process.execPath, entryFile: path.resolve(process.argv[1]) }));
105
+ }
106
+ if (name === "aeh_operation_start_run") {
107
+ const payload = { taskId: string(args.taskId, "taskId"), profile: optionalString(args.profile) };
108
+ return toolResult(await startDetachedOperation(root, "run", payload, { nodeExecutable: process.execPath, entryFile: path.resolve(process.argv[1]) }));
109
+ }
110
+ if (name === "aeh_operation_status")
111
+ return toolResult(await loadOperation(root, string(args.operationId, "operationId")));
112
+ if (name === "aeh_operation_cancel")
113
+ return toolResult(await cancelOperation(root, string(args.operationId, "operationId")));
114
+ throw new Error(`Unknown AEH operation tool '${name}'.`);
115
+ }
116
+ function controlRoot() { return path.resolve(process.env.AEH_CONTROL_ROOT?.trim() || process.cwd()); }
117
+ function toolResult(value) { return { content: [{ type: "text", text: JSON.stringify(value, null, 2) }], structuredContent: value }; }
118
+ function write(value) { process.stdout.write(`${JSON.stringify(value)}\n`); }
119
+ function object(value) { return value && typeof value === "object" && !Array.isArray(value) ? value : {}; }
120
+ function string(value, name) { if (typeof value !== "string" || !value.trim())
121
+ throw new Error(`${name} is required.`); return value.trim(); }
122
+ function optionalString(value) { return typeof value === "string" && value.trim() ? value.trim() : undefined; }
123
+ function stringArray(value) { if (value === undefined)
124
+ return undefined; if (!Array.isArray(value) || value.some((item) => typeof item !== "string"))
125
+ throw new Error("Expected an array of strings."); return value; }
126
+ function risk(value) { if (value === undefined)
127
+ return undefined; if (value === "low" || value === "medium" || value === "high")
128
+ return value; throw new Error("risk must be low, medium or high."); }
129
+ //# sourceMappingURL=mcp.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../src/operations/mcp.ts"],"names":[],"mappings":"AAAA,OAAO,QAAQ,MAAM,eAAe,CAAC;AACrC,OAAO,IAAI,MAAM,WAAW,CAAC;AAC7B,OAAO,OAAO,MAAM,cAAc,CAAC;AACnC,OAAO,EAAE,eAAe,EAAE,sBAAsB,EAAE,MAAM,iBAAiB,CAAC;AAC1E,OAAO,EAAE,aAAa,EAAwD,MAAM,YAAY,CAAC;AAIjG,MAAM,KAAK,GAAG;IACZ;QACE,IAAI,EAAE,2BAA2B;QACjC,WAAW,EAAE,wHAAwH;QACrI,WAAW,EAAE;YACX,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE;gBACV,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE;gBAC3B,KAAK,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;gBACnD,OAAO,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;gBACrD,IAAI,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,QAAQ,EAAE,MAAM,CAAC,EAAE;gBACzD,SAAS,EAAE,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;aACxD;YACD,QAAQ,EAAE,CAAC,SAAS,CAAC;YACrB,oBAAoB,EAAE,KAAK;SAC5B;KACF;IACD;QACE,IAAI,EAAE,yBAAyB;QAC/B,WAAW,EAAE,gJAAgJ;QAC7J,WAAW,EAAE;YACX,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE,EAAE,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;YACvE,QAAQ,EAAE,CAAC,QAAQ,CAAC;YACpB,oBAAoB,EAAE,KAAK;SAC5B;KACF;IACD;QACE,IAAI,EAAE,sBAAsB;QAC5B,WAAW,EAAE,sHAAsH;QACnI,WAAW,EAAE;YACX,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE,EAAE,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;YAC/C,QAAQ,EAAE,CAAC,aAAa,CAAC;YACzB,oBAAoB,EAAE,KAAK;SAC5B;KACF;IACD;QACE,IAAI,EAAE,sBAAsB;QAC5B,WAAW,EAAE,+FAA+F;QAC5G,WAAW,EAAE;YACX,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE,EAAE,WAAW,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,EAAE;YAC/C,QAAQ,EAAE,CAAC,aAAa,CAAC;YACzB,oBAAoB,EAAE,KAAK;SAC5B;KACF;CACO,CAAC;AAEX,MAAM,CAAC,KAAK,UAAU,iBAAiB;IACrC,MAAM,EAAE,GAAG,QAAQ,CAAC,eAAe,CAAC,EAAE,KAAK,EAAE,OAAO,CAAC,KAAK,EAAE,SAAS,EAAE,QAAQ,EAAE,CAAC,CAAC;IACnF,IAAI,KAAK,EAAE,MAAM,IAAI,IAAI,EAAE,EAAE,CAAC;QAC5B,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;YAAE,SAAS;QAC3B,IAAI,OAAuB,CAAC;QAC5B,IAAI,CAAC;YAAC,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,IAAI,CAAmB,CAAC;QAAC,CAAC;QACrD,MAAM,CAAC;YAAC,SAAS;QAAC,CAAC;QACnB,IAAI,OAAO,CAAC,EAAE,KAAK,SAAS,IAAI,OAAO,CAAC,EAAE,KAAK,IAAI;YAAE,SAAS;QAC9D,IAAI,CAAC;YAAC,KAAK,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,MAAM,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC;QAAC,CAAC;QACjF,OAAO,KAAK,EAAE,CAAC;YAAC,KAAK,CAAC,EAAE,OAAO,EAAE,KAAK,EAAE,EAAE,EAAE,OAAO,CAAC,EAAE,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,KAAK,YAAY,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,EAAE,CAAC,CAAC;QAAC,CAAC;IACxJ,CAAC;AACH,CAAC;AAED,KAAK,UAAU,MAAM,CAAC,OAAuB;IAC3C,IAAI,OAAO,CAAC,MAAM,KAAK,YAAY,EAAE,CAAC;QACpC,OAAO;YACL,eAAe,EAAE,OAAO,OAAO,CAAC,MAAM,EAAE,eAAe,KAAK,QAAQ,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC,eAAe,CAAC,CAAC,CAAC,YAAY;YACpH,YAAY,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE;YAC3B,UAAU,EAAE,EAAE,IAAI,EAAE,0BAA0B,EAAE,OAAO,EAAE,GAAG,EAAE;SAC/D,CAAC;IACJ,CAAC;IACD,IAAI,OAAO,CAAC,MAAM,KAAK,MAAM;QAAE,OAAO,EAAE,CAAC;IACzC,IAAI,OAAO,CAAC,MAAM,KAAK,YAAY;QAAE,OAAO,EAAE,KAAK,EAAE,CAAC;IACtD,IAAI,OAAO,CAAC,MAAM,KAAK,YAAY;QAAE,OAAO,QAAQ,CAAC,OAAO,CAAC,MAAM,IAAI,EAAE,CAAC,CAAC;IAC3E,MAAM,IAAI,KAAK,CAAC,2BAA2B,OAAO,CAAC,MAAM,IAAI,WAAW,EAAE,CAAC,CAAC;AAC9E,CAAC;AAED,KAAK,UAAU,QAAQ,CAAC,MAA+B;IACrD,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,IAAI,EAAE,WAAW,CAAC,CAAC;IAC9C,MAAM,IAAI,GAAG,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,CAAC;IACtC,MAAM,IAAI,GAAG,WAAW,EAAE,CAAC;IAC3B,IAAI,IAAI,KAAK,2BAA2B,EAAE,CAAC;QACzC,MAAM,OAAO,GAA0B;YACrC,OAAO,EAAE,MAAM,CAAC,IAAI,CAAC,OAAO,EAAE,SAAS,CAAC;YACxC,KAAK,EAAE,WAAW,CAAC,IAAI,CAAC,KAAK,CAAC;YAC9B,OAAO,EAAE,WAAW,CAAC,IAAI,CAAC,OAAO,CAAC;YAClC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC;YACrB,SAAS,EAAE,WAAW,CAAC,IAAI,CAAC,SAAS,CAAC;SACvC,CAAC;QACF,OAAO,UAAU,CAAC,MAAM,sBAAsB,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,EAAE,cAAc,EAAE,OAAO,CAAC,QAAQ,EAAE,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IAC1J,CAAC;IACD,IAAI,IAAI,KAAK,yBAAyB,EAAE,CAAC;QACvC,MAAM,OAAO,GAAwB,EAAE,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,OAAO,EAAE,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,EAAE,CAAC;QACtH,OAAO,UAAU,CAAC,MAAM,sBAAsB,CAAC,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,cAAc,EAAE,OAAO,CAAC,QAAQ,EAAE,SAAS,EAAE,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;IACxJ,CAAC;IACD,IAAI,IAAI,KAAK,sBAAsB;QAAE,OAAO,UAAU,CAAC,MAAM,aAAa,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC;IAC3H,IAAI,IAAI,KAAK,sBAAsB;QAAE,OAAO,UAAU,CAAC,MAAM,eAAe,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,WAAW,EAAE,aAAa,CAAC,CAAC,CAAC,CAAC;IAC7H,MAAM,IAAI,KAAK,CAAC,+BAA+B,IAAI,IAAI,CAAC,CAAC;AAC3D,CAAC;AAED,SAAS,WAAW,KAAa,OAAO,IAAI,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,EAAE,IAAI,EAAE,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC;AAC9G,SAAS,UAAU,CAAC,KAAc,IAA6B,OAAO,EAAE,OAAO,EAAE,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC,EAAE,CAAC,EAAE,iBAAiB,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC;AACxK,SAAS,KAAK,CAAC,KAAc,IAAU,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;AAC5F,SAAS,MAAM,CAAC,KAAc,IAA6B,OAAO,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAgC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC;AACxK,SAAS,MAAM,CAAC,KAAc,EAAE,IAAY,IAAY,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE;IAAE,MAAM,IAAI,KAAK,CAAC,GAAG,IAAI,eAAe,CAAC,CAAC,CAAC,OAAO,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC;AACvK,SAAS,cAAc,CAAC,KAAc,IAAwB,OAAO,OAAO,KAAK,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,KAAK,CAAC,IAAI,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC;AAC5I,SAAS,WAAW,CAAC,KAAc,IAA0B,IAAI,KAAK,KAAK,SAAS;IAAE,OAAO,SAAS,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,OAAO,IAAI,KAAK,QAAQ,CAAC;IAAE,MAAM,IAAI,KAAK,CAAC,+BAA+B,CAAC,CAAC,CAAC,OAAO,KAAiB,CAAC,CAAC,CAAC;AAClQ,SAAS,IAAI,CAAC,KAAc,IAA2C,IAAI,KAAK,KAAK,SAAS;IAAE,OAAO,SAAS,CAAC,CAAC,IAAI,KAAK,KAAK,KAAK,IAAI,KAAK,KAAK,QAAQ,IAAI,KAAK,KAAK,MAAM;IAAE,OAAO,KAAK,CAAC,CAAC,MAAM,IAAI,KAAK,CAAC,mCAAmC,CAAC,CAAC,CAAC,CAAC"}
@@ -0,0 +1,43 @@
1
+ export type OperationKind = "audit" | "run";
2
+ export type OperationStatus = "QUEUED" | "RUNNING" | "SUCCEEDED" | "FAILED" | "CANCELLED";
3
+ export interface AuditOperationPayload {
4
+ request: string;
5
+ files?: string[];
6
+ domains?: string[];
7
+ risk?: "low" | "medium" | "high";
8
+ reviewers?: string[];
9
+ }
10
+ export interface RunOperationPayload {
11
+ taskId: string;
12
+ profile?: string;
13
+ }
14
+ export type OperationPayload = AuditOperationPayload | RunOperationPayload;
15
+ export interface OperationRecord {
16
+ version: 1;
17
+ id: string;
18
+ kind: OperationKind;
19
+ status: OperationStatus;
20
+ phase: string;
21
+ root: string;
22
+ payload: OperationPayload;
23
+ createdAt: string;
24
+ updatedAt: string;
25
+ startedAt?: string;
26
+ finishedAt?: string;
27
+ pid?: number;
28
+ workspaceId?: string;
29
+ workspaceWarning?: string;
30
+ cleanupWarnings?: string[];
31
+ result?: Record<string, unknown>;
32
+ error?: string;
33
+ }
34
+ export declare function operationFile(root: string, operationId: string): string;
35
+ export declare function loadOperation(root: string, operationId: string): Promise<OperationRecord>;
36
+ export declare function saveOperation(root: string, record: OperationRecord): Promise<void>;
37
+ export declare function patchOperation(root: string, operationId: string, patch: Partial<OperationRecord>): Promise<OperationRecord>;
38
+ export declare function currentOperationContext(): {
39
+ id?: string;
40
+ kind?: string;
41
+ workspaceId?: string;
42
+ };
43
+ export declare function updateCurrentOperationPhase(root: string, phase: string): Promise<void>;
@@ -0,0 +1,127 @@
1
+ import crypto from "node:crypto";
2
+ import fs from "node:fs/promises";
3
+ import path from "node:path";
4
+ const OPERATIONS_DIR = ".harness/operations";
5
+ const LOCK_RETRY_MS = 20;
6
+ const LOCK_TIMEOUT_MS = 10_000;
7
+ const STALE_LOCK_MS = 30_000;
8
+ export function operationFile(root, operationId) {
9
+ return path.resolve(root, OPERATIONS_DIR, `${safeId(operationId)}.json`);
10
+ }
11
+ export async function loadOperation(root, operationId) {
12
+ return JSON.parse(await fs.readFile(operationFile(root, operationId), "utf8"));
13
+ }
14
+ export async function saveOperation(root, record) {
15
+ const file = operationFile(root, record.id);
16
+ await fs.mkdir(path.dirname(file), { recursive: true });
17
+ await withOperationLock(file, async () => writeRecord(file, record));
18
+ }
19
+ export async function patchOperation(root, operationId, patch) {
20
+ const file = operationFile(root, operationId);
21
+ await fs.mkdir(path.dirname(file), { recursive: true });
22
+ return withOperationLock(file, async () => {
23
+ const current = JSON.parse(await fs.readFile(file, "utf8"));
24
+ const guardedPatch = guardTerminalTransition(current, patch);
25
+ const next = { ...current, ...guardedPatch, id: current.id, kind: current.kind, version: 1, updatedAt: new Date().toISOString() };
26
+ await writeRecord(file, next);
27
+ return next;
28
+ });
29
+ }
30
+ export function currentOperationContext() {
31
+ return {
32
+ id: process.env.AEH_OPERATION_ID?.trim() || undefined,
33
+ kind: process.env.AEH_OPERATION_KIND?.trim() || undefined,
34
+ workspaceId: process.env.AEH_OPERATION_WORKSPACE_ID?.trim() || undefined
35
+ };
36
+ }
37
+ export async function updateCurrentOperationPhase(root, phase) {
38
+ const operationId = currentOperationContext().id;
39
+ if (!operationId)
40
+ return;
41
+ try {
42
+ await patchOperation(root, operationId, { phase });
43
+ }
44
+ catch { /* direct/non-controller execution has no operation state to update */ }
45
+ }
46
+ async function writeRecord(file, record) {
47
+ const temp = `${file}.${process.pid}.${crypto.randomUUID()}.tmp`;
48
+ await fs.writeFile(temp, `${JSON.stringify(record, null, 2)}\n`);
49
+ try {
50
+ await fs.rename(temp, file);
51
+ }
52
+ finally {
53
+ await fs.rm(temp, { force: true }).catch(() => undefined);
54
+ }
55
+ }
56
+ async function withOperationLock(file, action) {
57
+ const lock = `${file}.lock`;
58
+ const deadline = Date.now() + LOCK_TIMEOUT_MS;
59
+ for (;;) {
60
+ let handle;
61
+ try {
62
+ handle = await fs.open(lock, "wx");
63
+ try {
64
+ await handle.writeFile(`${process.pid}\n`);
65
+ return await action();
66
+ }
67
+ finally {
68
+ await handle.close().catch(() => undefined);
69
+ await fs.rm(lock, { force: true }).catch(() => undefined);
70
+ }
71
+ }
72
+ catch (error) {
73
+ if (handle) {
74
+ await handle.close().catch(() => undefined);
75
+ await fs.rm(lock, { force: true }).catch(() => undefined);
76
+ throw error;
77
+ }
78
+ if (!isAlreadyExists(error))
79
+ throw error;
80
+ if (await canRecoverLock(lock)) {
81
+ await fs.rm(lock, { force: true }).catch(() => undefined);
82
+ continue;
83
+ }
84
+ if (Date.now() >= deadline)
85
+ throw new Error(`Timed out acquiring operation state lock for ${path.basename(file)}.`);
86
+ await delay(LOCK_RETRY_MS);
87
+ }
88
+ }
89
+ }
90
+ async function canRecoverLock(lock) {
91
+ try {
92
+ const [rawPid, stat] = await Promise.all([fs.readFile(lock, "utf8").catch(() => ""), fs.stat(lock)]);
93
+ const ownerPid = Number.parseInt(rawPid.trim(), 10);
94
+ if (Number.isInteger(ownerPid) && ownerPid > 0 && !processAlive(ownerPid))
95
+ return true;
96
+ return Date.now() - stat.mtimeMs > STALE_LOCK_MS;
97
+ }
98
+ catch {
99
+ return true;
100
+ }
101
+ }
102
+ function processAlive(pid) {
103
+ try {
104
+ process.kill(pid, 0);
105
+ return true;
106
+ }
107
+ catch (error) {
108
+ return !/ESRCH/.test(String(error));
109
+ }
110
+ }
111
+ function guardTerminalTransition(current, patch) {
112
+ if (!isTerminal(current.status))
113
+ return patch;
114
+ const guarded = {};
115
+ if (patch.cleanupWarnings)
116
+ guarded.cleanupWarnings = patch.cleanupWarnings;
117
+ return guarded;
118
+ }
119
+ function isTerminal(status) { return status === "SUCCEEDED" || status === "FAILED" || status === "CANCELLED"; }
120
+ function isAlreadyExists(error) { return Boolean(error && typeof error === "object" && "code" in error && error.code === "EEXIST"); }
121
+ function delay(ms) { return new Promise((resolve) => setTimeout(resolve, ms)); }
122
+ function safeId(value) {
123
+ if (!/^[A-Za-z0-9._-]+$/.test(value))
124
+ throw new Error(`Invalid operation id '${value}'.`);
125
+ return value;
126
+ }
127
+ //# sourceMappingURL=state.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"state.js","sourceRoot":"","sources":["../../src/operations/state.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,25 @@
1
+ import type { AgentExecutionSelection } from "../agents/types.js";
2
+ import type { HarnessProjectConfig, TaskContract } from "../core/types.js";
3
+ export interface PaseoLaunchSpecOptions {
4
+ selection?: AgentExecutionSelection;
5
+ logicalAgent?: string;
6
+ provider?: string;
7
+ model?: string;
8
+ titlePrefix?: string;
9
+ phase?: string;
10
+ kind?: string;
11
+ }
12
+ export interface PaseoAgentLaunchSpec {
13
+ cwd: string;
14
+ title: string;
15
+ provider: string;
16
+ model?: string;
17
+ workspaceId?: string;
18
+ labels: Record<string, string>;
19
+ timeoutSeconds: number;
20
+ operationId: string;
21
+ operationKind: string;
22
+ phase: string;
23
+ }
24
+ export declare function compilePaseoAgentLaunchSpec(root: string, config: HarnessProjectConfig, contract: TaskContract, options?: PaseoLaunchSpecOptions): Promise<PaseoAgentLaunchSpec>;
25
+ export declare function inferAgentPhase(selection: AgentExecutionSelection | undefined, logicalAgent: string): string;
@@ -0,0 +1,69 @@
1
+ import { deliveryWorkspaceId } from "../delivery/handoff.js";
2
+ import { currentOperationContext } from "../operations/state.js";
3
+ export async function compilePaseoAgentLaunchSpec(root, config, contract, options = {}) {
4
+ const selection = options.selection;
5
+ const worker = config.orchestration?.worker;
6
+ const logicalAgent = options.logicalAgent ?? selection?.logicalAgent ?? "worker";
7
+ const provider = options.provider ?? selection?.paseoProvider ?? worker?.provider ?? "opencode";
8
+ const model = options.model ?? (selection ? (selection.runtimeAdapter === "codex" ? selection.modelName : selection.modelId) : worker?.model);
9
+ const operation = currentOperationContext();
10
+ const operationId = operation.id ?? contract.task.id;
11
+ const operationKind = operation.kind ?? options.kind ?? inferOperationKind(contract);
12
+ const phase = options.phase ?? inferAgentPhase(selection, logicalAgent);
13
+ const deliveryId = await deliveryWorkspaceId(root, config, contract.task.id);
14
+ const workspaceId = deliveryId ?? operation.workspaceId;
15
+ const title = `${options.titlePrefix ?? worker?.titlePrefix ?? "aeh"}-${contract.task.id}-${logicalAgent}`;
16
+ const labels = {
17
+ "aeh.project": config.project.name,
18
+ "aeh.kind": "worker",
19
+ "aeh.task": contract.task.id,
20
+ "aeh.role": logicalAgent,
21
+ "aeh.operation": operationId,
22
+ "aeh.operation.kind": operationKind,
23
+ "aeh.operation.phase": phase
24
+ };
25
+ if (selection?.profile)
26
+ labels["aeh.profile"] = selection.profile;
27
+ if (workspaceId && workspaceId === operation.workspaceId && !deliveryId)
28
+ labels["aeh.workspace.kind"] = "orchestration";
29
+ if (workspaceId && deliveryId)
30
+ labels["aeh.workspace.kind"] = "delivery";
31
+ return {
32
+ cwd: root,
33
+ title,
34
+ provider,
35
+ model,
36
+ workspaceId,
37
+ labels,
38
+ timeoutSeconds: worker?.timeoutSeconds ?? 1800,
39
+ operationId,
40
+ operationKind,
41
+ phase
42
+ };
43
+ }
44
+ export function inferAgentPhase(selection, logicalAgent) {
45
+ const role = selection?.role?.toLowerCase() ?? "";
46
+ const name = logicalAgent.toLowerCase();
47
+ if (role === "planner" || name.includes("planner"))
48
+ return "planning";
49
+ if (role === "reviewer" || name.includes("reviewer"))
50
+ return "review";
51
+ if (role === "escalation" || name.includes("oracle"))
52
+ return "diagnosis";
53
+ if (name.includes("spec-manager"))
54
+ return "spec-authoring";
55
+ if (name.includes("environment-manager"))
56
+ return "environment-recovery";
57
+ if (role === "implementer" || name.includes("implementer") || name.includes("worker"))
58
+ return "implementation";
59
+ return "work";
60
+ }
61
+ function inferOperationKind(contract) {
62
+ const intent = contract.routing?.intent?.trim();
63
+ if (intent === "audit")
64
+ return "audit";
65
+ if (intent)
66
+ return intent;
67
+ return contract.mode === "quick" ? "quick" : "run";
68
+ }
69
+ //# sourceMappingURL=launchSpec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"launchSpec.js","sourceRoot":"","sources":["../../src/paseo/launchSpec.ts"],"names":[],"mappings":"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"}
@@ -1,5 +1,5 @@
1
1
  import { detectPaseoCapabilities } from "./capabilities.js";
2
- import { createPaseoSdkAgent, inspectPaseoSdkAgent, listPaseoSdkAgents, probePaseoSdkAgent, runPaseoSdkAgent, type PaseoSdkAgentOptions, type PaseoSdkAgentRecord } from "./sdk.js";
2
+ import { createPaseoSdkAgent, dispatchPaseoSdkAgent, inspectPaseoSdkAgent, listPaseoSdkAgents, materializePaseoSdkAgent, probePaseoSdkAgent, runPaseoSdkAgent, waitPaseoSdkAgent, type PaseoSdkAgentOptions, type PaseoSdkAgentRecord } from "./sdk.js";
3
3
  import { runProcess } from "../utils/process.js";
4
4
  export interface ManagedPaseoAgentOptions extends PaseoSdkAgentOptions {
5
5
  timeoutSeconds?: number;
@@ -10,6 +10,7 @@ export interface ManagedPaseoAgentResult {
10
10
  stdout: string;
11
11
  stderr: string;
12
12
  status?: string;
13
+ workspaceId?: string;
13
14
  transport: "sdk" | "cli";
14
15
  }
15
16
  interface PaseoRuntimeDeps {
@@ -17,6 +18,9 @@ interface PaseoRuntimeDeps {
17
18
  detectCapabilities: typeof detectPaseoCapabilities;
18
19
  sdk: {
19
20
  create: typeof createPaseoSdkAgent;
21
+ materialize: typeof materializePaseoSdkAgent;
22
+ dispatch: typeof dispatchPaseoSdkAgent;
23
+ wait: typeof waitPaseoSdkAgent;
20
24
  run: typeof runPaseoSdkAgent;
21
25
  probe: typeof probePaseoSdkAgent;
22
26
  inspect: typeof inspectPaseoSdkAgent;
@@ -24,6 +28,9 @@ interface PaseoRuntimeDeps {
24
28
  };
25
29
  }
26
30
  export declare function launchManagedPaseoAgent(root: string, options: ManagedPaseoAgentOptions, deps?: PaseoRuntimeDeps): Promise<ManagedPaseoAgentResult>;
31
+ export declare function materializeManagedPaseoAgent(root: string, options: ManagedPaseoAgentOptions, deps?: PaseoRuntimeDeps): Promise<ManagedPaseoAgentResult>;
32
+ export declare function dispatchManagedPaseoAgent(root: string, agentId: string, prompt: string, timeoutSeconds?: number, deps?: PaseoRuntimeDeps): Promise<ManagedPaseoAgentResult>;
33
+ export declare function waitManagedPaseoAgent(root: string, agentId: string, timeoutSeconds?: number, deps?: PaseoRuntimeDeps): Promise<ManagedPaseoAgentResult>;
27
34
  export declare function continueManagedPaseoAgent(root: string, agentId: string, prompt: string, timeoutSeconds?: number, deps?: PaseoRuntimeDeps): Promise<ManagedPaseoAgentResult>;
28
35
  export declare function probeManagedPaseoAgent(root: string, agentId: string, deps?: PaseoRuntimeDeps): Promise<boolean>;
29
36
  export declare function inspectManagedPaseoAgent(root: string, agentId: string, deps?: PaseoRuntimeDeps): Promise<PaseoSdkAgentRecord | undefined>;
@@ -1,17 +1,25 @@
1
1
  import process from "node:process";
2
2
  import { buildPaseoBackgroundRunCommand, detectPaseoCapabilities, extractPaseoAgentId } from "./capabilities.js";
3
- import { PaseoSdkUnavailableError, createPaseoSdkAgent, inspectPaseoSdkAgent, listPaseoSdkAgents, probePaseoSdkAgent, runPaseoSdkAgent } from "./sdk.js";
3
+ import { PaseoSdkUnavailableError, createPaseoSdkAgent, dispatchPaseoSdkAgent, inspectPaseoSdkAgent, listPaseoSdkAgents, materializePaseoSdkAgent, probePaseoSdkAgent, runPaseoSdkAgent, waitPaseoSdkAgent } from "./sdk.js";
4
4
  import { runProcess } from "../utils/process.js";
5
5
  const DEFAULT_DEPS = {
6
6
  run: runProcess,
7
7
  detectCapabilities: detectPaseoCapabilities,
8
- sdk: { create: createPaseoSdkAgent, run: runPaseoSdkAgent, probe: probePaseoSdkAgent, inspect: inspectPaseoSdkAgent, list: listPaseoSdkAgents }
8
+ sdk: {
9
+ create: createPaseoSdkAgent,
10
+ materialize: materializePaseoSdkAgent,
11
+ dispatch: dispatchPaseoSdkAgent,
12
+ wait: waitPaseoSdkAgent,
13
+ run: runPaseoSdkAgent,
14
+ probe: probePaseoSdkAgent,
15
+ inspect: inspectPaseoSdkAgent,
16
+ list: listPaseoSdkAgents
17
+ }
9
18
  };
10
19
  export async function launchManagedPaseoAgent(root, options, deps = DEFAULT_DEPS) {
11
- if (preferSdk(options)) {
20
+ if (!forceCli()) {
12
21
  try {
13
- const result = await deps.sdk.create(root, { ...options, timeoutMs: options.timeoutMs ?? timeoutMs(options.timeoutSeconds) });
14
- return fromSdk(result);
22
+ return fromSdk(await deps.sdk.create(root, { ...options, timeoutMs: options.timeoutMs ?? timeoutMs(options.timeoutSeconds) }));
15
23
  }
16
24
  catch (error) {
17
25
  if (!sdkCanFallback(error))
@@ -19,25 +27,62 @@ export async function launchManagedPaseoAgent(root, options, deps = DEFAULT_DEPS
19
27
  return launchCli(root, options, deps, `SDK unavailable: ${error instanceof Error ? error.message : String(error)}`);
20
28
  }
21
29
  }
22
- return launchCli(root, options, deps, "SDK skipped because no explicit provider/model was available or AEH_PASEO_FORCE_CLI=1.");
30
+ return launchCli(root, options, deps, "AEH_PASEO_FORCE_CLI=1 forced the compatibility lifecycle.");
23
31
  }
24
- export async function continueManagedPaseoAgent(root, agentId, prompt, timeoutSeconds, deps = DEFAULT_DEPS) {
32
+ export async function materializeManagedPaseoAgent(root, options, deps = DEFAULT_DEPS) {
33
+ if (forceCli())
34
+ throw new PaseoSdkUnavailableError("Idle agent materialization is SDK-only; AEH_PASEO_FORCE_CLI=1 is active.");
35
+ try {
36
+ return fromSdk(await deps.sdk.materialize(root, { ...options, prompt: undefined, waitForFinish: false }));
37
+ }
38
+ catch (error) {
39
+ if (sdkCanFallback(error))
40
+ throw new PaseoSdkUnavailableError(`Paseo SDK is required to materialize an idle visible agent. ${error instanceof Error ? error.message : String(error)}`, { cause: error });
41
+ throw error;
42
+ }
43
+ }
44
+ export async function dispatchManagedPaseoAgent(root, agentId, prompt, timeoutSeconds, deps = DEFAULT_DEPS) {
25
45
  if (!forceCli()) {
26
46
  try {
27
- return fromSdk(await deps.sdk.run(root, agentId, prompt, timeoutMs(timeoutSeconds)));
47
+ return fromSdk(await deps.sdk.dispatch(root, agentId, prompt, timeoutMs(timeoutSeconds)));
28
48
  }
29
49
  catch (error) {
30
50
  if (!sdkCanFallback(error))
31
51
  throw error;
32
52
  }
33
53
  }
34
- const timeout = timeoutSeconds ?? 1800;
35
54
  const send = await deps.run(`paseo send ${quote(agentId)} --no-wait ${quote(prompt)}`, { cwd: root, timeoutMs: 60_000 });
36
- if (send.exitCode !== 0)
37
- return { id: agentId, exitCode: send.exitCode, stdout: send.stdout, stderr: send.stderr, transport: "cli" };
55
+ return { id: agentId, exitCode: send.exitCode, stdout: send.stdout, stderr: send.stderr, status: send.exitCode === 0 ? "working" : "failed", transport: "cli" };
56
+ }
57
+ export async function waitManagedPaseoAgent(root, agentId, timeoutSeconds, deps = DEFAULT_DEPS) {
58
+ if (!forceCli()) {
59
+ try {
60
+ return fromSdk(await deps.sdk.wait(root, agentId, timeoutMs(timeoutSeconds)));
61
+ }
62
+ catch (error) {
63
+ if (!sdkCanFallback(error))
64
+ throw error;
65
+ }
66
+ }
67
+ const timeout = timeoutSeconds ?? 1800;
38
68
  const wait = await deps.run(`paseo wait ${quote(agentId)} --timeout ${timeout}`, { cwd: root, timeoutMs: (timeout + 30) * 1000 });
39
69
  const logs = await deps.run(`paseo logs ${quote(agentId)} --tail 200`, { cwd: root, timeoutMs: 60_000 });
40
- return { id: agentId, exitCode: wait.exitCode, stdout: logs.stdout || wait.stdout, stderr: [send.stderr, wait.stderr, logs.stderr].filter(Boolean).join("\n"), transport: "cli" };
70
+ return { id: agentId, exitCode: wait.exitCode, stdout: logs.stdout || wait.stdout, stderr: [wait.stderr, logs.stderr].filter(Boolean).join("\n"), status: wait.exitCode === 0 ? "idle" : "failed", transport: "cli" };
71
+ }
72
+ export async function continueManagedPaseoAgent(root, agentId, prompt, timeoutSeconds, deps = DEFAULT_DEPS) {
73
+ if (!forceCli()) {
74
+ try {
75
+ return fromSdk(await deps.sdk.run(root, agentId, prompt, timeoutMs(timeoutSeconds)));
76
+ }
77
+ catch (error) {
78
+ if (!sdkCanFallback(error))
79
+ throw error;
80
+ }
81
+ }
82
+ const sent = await dispatchManagedPaseoAgent(root, agentId, prompt, timeoutSeconds, deps);
83
+ if (sent.exitCode !== 0)
84
+ return sent;
85
+ return waitManagedPaseoAgent(root, agentId, timeoutSeconds, deps);
41
86
  }
42
87
  export async function probeManagedPaseoAgent(root, agentId, deps = DEFAULT_DEPS) {
43
88
  if (!forceCli()) {
@@ -95,18 +140,17 @@ async function launchCli(root, options, deps, fallbackReason) {
95
140
  parts.push(`--model ${quote(options.model)}`);
96
141
  parts.push(`--output-schema ${quote(JSON.stringify(options.outputSchema))}`, quote(prompt));
97
142
  const result = await deps.run(parts.join(" "), { cwd: root, timeoutMs: timeout * 1000 });
98
- return { exitCode: result.exitCode, stdout: result.stdout, stderr: [fallbackReason, result.stderr].filter(Boolean).join("\n"), transport: "cli" };
143
+ return { exitCode: result.exitCode, stdout: result.stdout, stderr: [fallbackReason, result.stderr].filter(Boolean).join("\n"), status: result.exitCode === 0 ? "idle" : "failed", transport: "cli" };
99
144
  }
100
145
  const command = buildPaseoBackgroundRunCommand({ title: options.title, provider: options.provider, model: options.model, workspaceId: options.workspaceId, prompt }, capabilities);
101
146
  const launch = await deps.run(command, { cwd: root, timeoutMs: 60_000 });
102
147
  if (launch.exitCode !== 0)
103
- return { exitCode: launch.exitCode, stdout: launch.stdout, stderr: [fallbackReason, launch.stderr].filter(Boolean).join("\n"), transport: "cli" };
148
+ return { exitCode: launch.exitCode, stdout: launch.stdout, stderr: [fallbackReason, launch.stderr].filter(Boolean).join("\n"), status: "failed", transport: "cli" };
104
149
  const id = extractPaseoAgentId(launch.stdout);
105
150
  if (!id)
106
- return { exitCode: 1, stdout: launch.stdout, stderr: [fallbackReason, "Paseo returned no parseable agent id."].join("\n"), transport: "cli" };
107
- const wait = await deps.run(`paseo wait ${quote(id)} --timeout ${timeout}`, { cwd: root, timeoutMs: (timeout + 30) * 1000 });
108
- const logs = await deps.run(`paseo logs ${quote(id)} --tail 200`, { cwd: root, timeoutMs: 60_000 });
109
- return { id, exitCode: wait.exitCode, stdout: logs.stdout || wait.stdout || launch.stdout, stderr: [fallbackReason, launch.stderr, wait.stderr, logs.stderr].filter(Boolean).join("\n"), transport: "cli" };
151
+ return { exitCode: 1, stdout: launch.stdout, stderr: [fallbackReason, "Paseo returned no parseable agent id."].join("\n"), status: "failed", transport: "cli" };
152
+ const waited = await waitManagedPaseoAgent(root, id, timeout, { ...deps, sdk: deps.sdk });
153
+ return { ...waited, stderr: [fallbackReason, launch.stderr, waited.stderr].filter(Boolean).join("\n") };
110
154
  }
111
155
  async function listCliAgents(root, deps) {
112
156
  const result = await deps.run("paseo ls -a -g --json", { cwd: root, timeoutMs: 30_000 });
@@ -137,13 +181,14 @@ function collectCliAgents(value, out) {
137
181
  for (const child of Object.values(record))
138
182
  collectCliAgents(child, out);
139
183
  }
140
- function preferSdk(options) { return !forceCli() && (Boolean(options.model) || options.provider.includes("/")); }
141
184
  function forceCli() { return process.env.AEH_PASEO_FORCE_CLI === "1"; }
142
185
  function sdkCanFallback(error) { return error instanceof PaseoSdkUnavailableError || (error instanceof Error && error.name === "PaseoSdkUnavailableError"); }
143
186
  function timeoutMs(seconds) { return (seconds ?? 1800) * 1000; }
144
- function fromSdk(result) { return { id: result.id, exitCode: sdkExitCode(result.status, result.error), stdout: result.lastMessage ?? "", stderr: result.error ?? "", status: result.status, transport: "sdk" }; }
187
+ function fromSdk(result) { return { id: result.id, exitCode: sdkExitCode(result.status, result.error), stdout: result.lastMessage ?? "", stderr: result.error ?? "", status: result.status, workspaceId: result.workspaceId, transport: "sdk" }; }
145
188
  function sdkExitCode(status, error) { if (error)
146
- return 1; return !status || status === "idle" ? 0 : status === "timeout" ? 124 : 1; }
189
+ return 1; if (status === "timeout")
190
+ return 124; if (status === "failed" || status === "error" || status === "cancelled")
191
+ return 1; return 0; }
147
192
  function firstString(record, keys) { for (const key of keys)
148
193
  if (typeof record[key] === "string" && record[key])
149
194
  return record[key]; return undefined; }