@the-open-engine/zeroshot 6.39.2 → 6.41.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 (73) hide show
  1. package/README.md +18 -0
  2. package/cli/agent-provider-boundary.js +19 -0
  3. package/cli/agent-provider-boundary.ts +79 -0
  4. package/cli/export-stream.js +94 -0
  5. package/cli/export-stream.ts +118 -0
  6. package/cli/index.js +102 -54
  7. package/cli/json-export.js +2 -38
  8. package/cli/json-export.ts +2 -56
  9. package/cli/semantic-canonical.js +60 -0
  10. package/cli/semantic-canonical.ts +59 -0
  11. package/cli/semantic-contract.js +97 -0
  12. package/cli/semantic-contract.ts +153 -0
  13. package/cli/semantic-events.js +53 -0
  14. package/cli/semantic-events.ts +65 -0
  15. package/cli/semantic-evidence.js +63 -0
  16. package/cli/semantic-evidence.ts +65 -0
  17. package/cli/semantic-export.js +186 -0
  18. package/cli/semantic-export.ts +245 -0
  19. package/cli/semantic-json.js +69 -0
  20. package/cli/semantic-json.ts +69 -0
  21. package/cli/semantic-line-scanner.js +56 -0
  22. package/cli/semantic-line-scanner.ts +54 -0
  23. package/cli/semantic-parser.js +78 -0
  24. package/cli/semantic-parser.ts +95 -0
  25. package/cli/semantic-provider-line.js +91 -0
  26. package/cli/semantic-provider-line.ts +106 -0
  27. package/cli/trace-evidence.js +86 -0
  28. package/cli/trace-evidence.ts +115 -0
  29. package/cli/trace-export.js +120 -0
  30. package/cli/trace-export.ts +164 -0
  31. package/cli/trace-output-record.js +15 -0
  32. package/cli/trace-output-record.ts +18 -0
  33. package/cli/trace-output.js +98 -0
  34. package/cli/trace-output.ts +119 -0
  35. package/lib/agent-cli-provider/log-prefix.d.ts.map +1 -1
  36. package/lib/agent-cli-provider/log-prefix.js +8 -6
  37. package/lib/agent-cli-provider/log-prefix.js.map +1 -1
  38. package/lib/cluster/connection-types.d.cts +2 -2
  39. package/lib/cluster/connection-types.d.mts +2 -2
  40. package/lib/cluster/connection-types.d.ts +2 -2
  41. package/lib/cluster/generated/protocol-schema.cjs +1 -1
  42. package/lib/cluster/generated/protocol-schema.mjs +1 -1
  43. package/lib/cluster/generated/protocol.cjs +4 -4
  44. package/lib/cluster/generated/protocol.d.cts +271 -9
  45. package/lib/cluster/generated/protocol.d.mts +271 -9
  46. package/lib/cluster/generated/protocol.d.ts +271 -9
  47. package/lib/cluster/generated/protocol.mjs +4 -4
  48. package/lib/stream-json-parser.js +6 -5
  49. package/npm-shrinkwrap.json +2 -2
  50. package/package.json +9 -18
  51. package/scripts/generate-cluster-types.js +16 -1
  52. package/scripts/node-release-analyzer.js +17 -0
  53. package/scripts/node-release-commits.js +82 -0
  54. package/scripts/release-dry-run.js +1 -1
  55. package/scripts/release-preflight.js +3 -3
  56. package/scripts/semantic-release-notes.js +8 -2
  57. package/src/agent/agent-task-executor.js +36 -40
  58. package/src/agent/output-extraction-json.js +5 -6
  59. package/src/agent/output-extraction-json.ts +4 -7
  60. package/src/agent-cli-provider/log-prefix.ts +12 -7
  61. package/src/claude-task-runner.js +9 -9
  62. package/src/cluster/connection-types.ts +2 -2
  63. package/src/cluster/generated/protocol-schema.ts +1 -1
  64. package/src/cluster/generated/protocol.ts +67 -5
  65. package/src/legacy-lib/stream-json-parser.ts +10 -5
  66. package/src/providers/index.js +1 -19
  67. package/src/task-log-line.d.ts +20 -0
  68. package/src/task-log-line.js +80 -0
  69. package/task-lib/commands/logs.js +5 -8
  70. package/task-lib/sdk-watcher-output.js +31 -0
  71. package/task-lib/sdk-watcher.js +4 -11
  72. package/task-lib/watcher-output-runtime.js +30 -16
  73. package/scripts/rust-distribution.js +0 -924
@@ -5,14 +5,14 @@ export const JSON_RPC_VERSION = "2.0" as const;
5
5
  export const PROTOCOL_VERSION = "openengine.cluster/v1" as const;
6
6
  export const SUBSCRIPTION_QUEUE_CAPACITY = 1024 as const;
7
7
  export const MAX_FRAME_BYTES = 1048576 as const;
8
- export const CLUSTER_METHODS = ["initialize","plan","apply","update","stop","retry","resubmit","delete","get","watch","logs","agent/attach"] as const;
8
+ export const CLUSTER_METHODS = ["initialize","plan","apply","update","stop","retry","resubmit","delete","get","watch","logs","agent/attach","run/submit","run/list","run/status","run/watch","run/logs","run/attach","run/force"] as const;
9
9
  export type ClusterMethod = (typeof CLUSTER_METHODS)[number];
10
10
 
11
- export const UNARY_METHODS = ["initialize","plan","apply","update","stop","retry","resubmit","delete","get"] as const;
11
+ export const UNARY_METHODS = ["initialize","plan","apply","update","stop","retry","resubmit","delete","get","run/submit","run/list","run/status","run/force"] as const;
12
12
  export type UnaryClusterMethod = (typeof UNARY_METHODS)[number];
13
- export const SUBSCRIPTION_METHODS = ["watch","logs","agent/attach"] as const;
13
+ export const SUBSCRIPTION_METHODS = ["watch","logs","agent/attach","run/watch","run/logs","run/attach"] as const;
14
14
  export type SubscriptionMethod = (typeof SUBSCRIPTION_METHODS)[number];
15
- export const METHOD_RESULT_DEFINITIONS = {"initialize":"InitializeResult","plan":"PlanResult","apply":"ApplyResult","update":"UpdateResult","stop":"StopResult","retry":"RetryResult","resubmit":"ResubmitResult","delete":"DeleteResult","get":"GetResult","watch":"WatchResult","logs":"LogsResult","agent/attach":"AgentAttachResult"} as const;
15
+ export const METHOD_RESULT_DEFINITIONS = {"initialize":"InitializeResult","plan":"PlanResult","apply":"ApplyResult","update":"UpdateResult","stop":"StopResult","retry":"RetryResult","resubmit":"ResubmitResult","delete":"DeleteResult","get":"GetResult","watch":"WatchResult","logs":"LogsResult","agent/attach":"AgentAttachResult","run/submit":"RunSubmitResult","run/list":"RunListResult","run/status":"RunStatusResult","run/watch":"RunWatchResult","run/logs":"RunLogsResult","run/attach":"RunAttachResult","run/force":"RunForceResult"} as const;
16
16
 
17
17
  export const JSON_RPC_ERROR_CODES = {
18
18
  PARSE_ERROR: -32700,
@@ -25,6 +25,7 @@ export const JSON_RPC_ERROR_CODES = {
25
25
 
26
26
  export const DOMAIN_ERROR_CODES = ["NOT_FOUND","GONE","SLOW_CONSUMER","UNSUPPORTED_PROTOCOL_VERSION","INTERNAL_ERROR"] as const;
27
27
 
28
+ export type ActiveExecution = { readonly "execution": string; readonly "node": string; };
28
29
  export type AdmissionTransition = { readonly "runId": string; readonly "seedInput": unknown; readonly "spec": GraphSpec; };
29
30
  export type AgentAttachClosedNotification = { readonly "reason": SubscriptionCloseReason; readonly "subscriptionId": string; };
30
31
  export type AgentAttachEvent = { readonly "type": "working"; } | { readonly "text": string; readonly "type": "output"; } | { readonly "type": "settled"; };
@@ -41,10 +42,13 @@ export type BackendFault = BackendFaultWire;
41
42
  export type BackendFaultWire = { readonly "action": FaultAction; readonly "code": FaultCode; readonly "consequence": FaultConsequence; readonly "eventId": string; readonly "executionRef"?: string | null; readonly "retry": FaultRetryDisposition; readonly "severity": FaultSeverity; readonly "source": ReadonlyArray<FaultSourceFrame>; readonly "summary": string; };
42
43
  export type CancelRequestParams = { readonly "id": RequestId; };
43
44
  export type ChoiceBranch = { readonly "node": GraphNode; readonly "when": Guard; };
45
+ export type ClaudeProvider = "anthropic" | "openrouter";
44
46
  export type ClusterStatus = { readonly "atCursor"?: string | null; readonly "currentRunId"?: string | null; readonly "observedGeneration"?: number | null; readonly "operational"?: OperationalStatus | null; readonly "phase": Phase; };
47
+ export type CodexProvider = "openai" | "openrouter";
45
48
  export type ControlSelector = { readonly "field"?: string | null; readonly "name": string; readonly "source": ControlSource; };
46
49
  export type ControlSource = "signal" | "error" | "group";
47
50
  export type DataSelector = { readonly "path": ReadonlyArray<string>; readonly "source": "state"; } | { readonly "path": ReadonlyArray<string>; readonly "source": "item"; };
51
+ export type DeclaredEnvironment = ReadonlyArray<string>;
48
52
  export type DeleteParams = { readonly "idempotencyKey": string; readonly "ifGeneration": number; readonly "ifRunId"?: string | null; };
49
53
  export type DeleteResult = { readonly "atCursor"?: string | null; readonly "deduped": boolean; readonly "deleted": boolean; readonly "generation"?: number | null; readonly "phase": Phase; readonly "runId"?: string | null; };
50
54
  export type DiagnosticPathSegment = { readonly "kind": "field"; readonly "name": string; } | { readonly "index": number; readonly "kind": "index"; } | { readonly "kind": "node"; readonly "name": string; };
@@ -63,7 +67,7 @@ export type GetResult = { readonly "atCursor"?: string | null; readonly "spec"?:
63
67
  export type GraphDiagnostic = { readonly "code": GraphDiagnosticCode; readonly "message": string; readonly "path": ReadonlyArray<DiagnosticPathSegment>; readonly "relatedNodes": ReadonlyArray<string>; readonly "severity": DiagnosticSeverity; };
64
68
  export type GraphDiagnosticCode = "schema_safety" | "reachability" | "choice_exhaustiveness" | "loop_exit_satisfiability" | "missing_bound" | "write_conflict" | "ceiling_exceeded" | "cyclic_reference" | "undefined_read" | "invalid_graph_shape";
65
69
  export type GraphDiff = { readonly "added": ReadonlyArray<string>; readonly "changed": ReadonlyArray<string>; readonly "removed": ReadonlyArray<string>; };
66
- export type GraphNode = { readonly "attempts": number; readonly "input": PayloadType; readonly "inputBindings": ReadonlyArray<InputBinding>; readonly "kind": "step"; readonly "name": string; readonly "output": PayloadType; readonly "timeoutMs": number; readonly "worker": string; readonly "writeBindings": ReadonlyArray<WriteBinding>; } | { readonly "attempts": number; readonly "diagnostic": PayloadType; readonly "input": PayloadType; readonly "inputBindings": ReadonlyArray<InputBinding>; readonly "kind": "verifier"; readonly "name": string; readonly "output": PayloadType; readonly "signals": { readonly [key: string]: ReadonlyArray<string> }; readonly "timeoutMs": number; readonly "worker": string; readonly "writeBindings": ReadonlyArray<WriteBinding>; } | { readonly "children": NonEmptyVec_of_GraphNode; readonly "kind": "seq"; readonly "name": string; readonly "promotedStatePaths": ReadonlyArray<ReadonlyArray<string>>; readonly "state": PayloadType; } | ({ readonly "branches": NonEmptyVec_of_ChoiceBranch; readonly "kind": "choice"; readonly "name": string; readonly "otherwise"?: GraphNode | null; readonly "promotedStatePaths": ReadonlyArray<ReadonlyArray<string>>; readonly "state": PayloadType; }) | { readonly "branches": NonEmptyVec_of_GraphNode; readonly "join": Join; readonly "kind": "par"; readonly "name": string; readonly "promotedStatePaths": ReadonlyArray<ReadonlyArray<string>>; readonly "state": PayloadType; } | { readonly "body": GraphNode; readonly "kind": "loop"; readonly "maxIterations": number; readonly "name": string; readonly "promotedStatePaths": ReadonlyArray<ReadonlyArray<string>>; readonly "state": PayloadType; readonly "until": Guard; } | { readonly "body": GraphNode; readonly "kind": "map"; readonly "maxItems": number; readonly "name": string; readonly "over": DataSelector; readonly "promotedStatePaths": ReadonlyArray<ReadonlyArray<string>>; readonly "state": PayloadType; } | { readonly "bindings": ReadonlyArray<InputBinding>; readonly "kind": "succeed"; readonly "name": string; readonly "output": PayloadType; } | { readonly "kind": "fail"; readonly "name": string; readonly "reason": string; };
70
+ export type GraphNode = ({ readonly "attempts": number; readonly "input": PayloadType; readonly "inputBindings": ReadonlyArray<InputBinding>; readonly "instructions"?: NodeInstructions | null; readonly "kind": "step"; readonly "name": string; readonly "output": PayloadType; readonly "timeoutMs": number; readonly "worker": string; readonly "writeBindings": ReadonlyArray<WriteBinding>; }) | ({ readonly "attempts": number; readonly "diagnostic": PayloadType; readonly "input": PayloadType; readonly "inputBindings": ReadonlyArray<InputBinding>; readonly "instructions"?: NodeInstructions | null; readonly "kind": "verifier"; readonly "name": string; readonly "output": PayloadType; readonly "signals": { readonly [key: string]: ReadonlyArray<string> }; readonly "timeoutMs": number; readonly "worker": string; readonly "writeBindings": ReadonlyArray<WriteBinding>; }) | { readonly "children": NonEmptyVec_of_GraphNode; readonly "kind": "seq"; readonly "name": string; readonly "promotedStatePaths": ReadonlyArray<ReadonlyArray<string>>; readonly "state": PayloadType; } | ({ readonly "branches": NonEmptyVec_of_ChoiceBranch; readonly "kind": "choice"; readonly "name": string; readonly "otherwise"?: GraphNode | null; readonly "promotedStatePaths": ReadonlyArray<ReadonlyArray<string>>; readonly "state": PayloadType; }) | { readonly "branches": NonEmptyVec_of_GraphNode; readonly "join": Join; readonly "kind": "par"; readonly "name": string; readonly "promotedStatePaths": ReadonlyArray<ReadonlyArray<string>>; readonly "state": PayloadType; } | ({ readonly "body": GraphNode; readonly "kind": "loop"; readonly "maxIterations": number; readonly "name": string; readonly "promotedStatePaths": ReadonlyArray<ReadonlyArray<string>>; readonly "state": PayloadType; readonly "until"?: Guard | null; }) | { readonly "body": GraphNode; readonly "kind": "map"; readonly "maxItems": number; readonly "name": string; readonly "over": DataSelector; readonly "promotedStatePaths": ReadonlyArray<ReadonlyArray<string>>; readonly "state": PayloadType; } | { readonly "bindings": ReadonlyArray<InputBinding>; readonly "kind": "succeed"; readonly "name": string; readonly "output": PayloadType; } | { readonly "kind": "fail"; readonly "name": string; readonly "reason": string; };
67
71
  export type GraphProfile = "openengine.graph.full/v1" | "openengine.graph.single-worker/v1";
68
72
  export type GraphSpec = { readonly "initialInput": PayloadType; readonly "policy": PolicyBinding; readonly "profile": GraphProfile; readonly "root": GraphNode; };
69
73
  export type Guard = { readonly "kind": "in"; readonly "labels": ReadonlyArray<string>; readonly "value": ControlSelector; } | { readonly "guards": NonEmptyVec_of_Guard; readonly "kind": "all"; } | { readonly "guards": NonEmptyVec_of_Guard; readonly "kind": "any"; } | { readonly "guard": Guard; readonly "kind": "not"; } | { readonly "count": number; readonly "kind": "k_of_n"; readonly "labels": ReadonlyArray<string>; readonly "values": NonEmptyVec_of_ControlSelector; } | { readonly "count": number; readonly "kind": "k_of_map"; readonly "labels": ReadonlyArray<string>; readonly "value": ControlSelector; };
@@ -74,6 +78,8 @@ export type Join = { readonly "kind": "all"; } | { readonly "kind": "any"; } | {
74
78
  export type JsonRpcError = { readonly "code": number; readonly "data"?: DomainErrorData | null; readonly "message": string; };
75
79
  export type JsonRpcErrorResponse = { readonly "error": JsonRpcError; readonly "id"?: RequestId | null; readonly "jsonrpc": string; };
76
80
  export type JsonRpcNotification = { readonly "jsonrpc": string; readonly "method": string; readonly "params": EventNotification; };
81
+ export type JsonRpcNotification10 = { readonly "jsonrpc": string; readonly "method": string; readonly "params": RunLogEventNotification; };
82
+ export type JsonRpcNotification11 = { readonly "jsonrpc": string; readonly "method": string; readonly "params": RunAttachEventNotification; };
77
83
  export type JsonRpcNotification2 = { readonly "jsonrpc": string; readonly "method": string; readonly "params": SubscriptionCancelParams; };
78
84
  export type JsonRpcNotification3 = { readonly "jsonrpc": string; readonly "method": string; readonly "params": SubscriptionClosedNotification; };
79
85
  export type JsonRpcNotification4 = { readonly "jsonrpc": string; readonly "method": string; readonly "params": CancelRequestParams; };
@@ -81,10 +87,18 @@ export type JsonRpcNotification5 = { readonly "jsonrpc": string; readonly "metho
81
87
  export type JsonRpcNotification6 = { readonly "jsonrpc": string; readonly "method": string; readonly "params": LogsClosedNotification; };
82
88
  export type JsonRpcNotification7 = { readonly "jsonrpc": string; readonly "method": string; readonly "params": AgentAttachEventNotification; };
83
89
  export type JsonRpcNotification8 = { readonly "jsonrpc": string; readonly "method": string; readonly "params": AgentAttachClosedNotification; };
90
+ export type JsonRpcNotification9 = { readonly "jsonrpc": string; readonly "method": string; readonly "params": RunWatchEventNotification; };
84
91
  export type JsonRpcRequest = { readonly "id": RequestId; readonly "jsonrpc": string; readonly "method": string; readonly "params": InitializeParams; };
85
92
  export type JsonRpcRequest10 = { readonly "id": RequestId; readonly "jsonrpc": string; readonly "method": string; readonly "params": WatchParams; };
86
93
  export type JsonRpcRequest11 = { readonly "id": RequestId; readonly "jsonrpc": string; readonly "method": string; readonly "params": LogsParams; };
87
94
  export type JsonRpcRequest12 = { readonly "id": RequestId; readonly "jsonrpc": string; readonly "method": string; readonly "params": AgentAttachParams; };
95
+ export type JsonRpcRequest13 = { readonly "id": RequestId; readonly "jsonrpc": string; readonly "method": string; readonly "params": RunSubmitParams; };
96
+ export type JsonRpcRequest14 = { readonly "id": RequestId; readonly "jsonrpc": string; readonly "method": string; readonly "params": RunListParams; };
97
+ export type JsonRpcRequest15 = { readonly "id": RequestId; readonly "jsonrpc": string; readonly "method": string; readonly "params": RunStatusParams; };
98
+ export type JsonRpcRequest16 = { readonly "id": RequestId; readonly "jsonrpc": string; readonly "method": string; readonly "params": RunWatchParams; };
99
+ export type JsonRpcRequest17 = { readonly "id": RequestId; readonly "jsonrpc": string; readonly "method": string; readonly "params": RunLogsParams; };
100
+ export type JsonRpcRequest18 = { readonly "id": RequestId; readonly "jsonrpc": string; readonly "method": string; readonly "params": RunAttachParams; };
101
+ export type JsonRpcRequest19 = { readonly "id": RequestId; readonly "jsonrpc": string; readonly "method": string; readonly "params": RunForceParams; };
88
102
  export type JsonRpcRequest2 = { readonly "id": RequestId; readonly "jsonrpc": string; readonly "method": string; readonly "params": PlanParams; };
89
103
  export type JsonRpcRequest3 = { readonly "id": RequestId; readonly "jsonrpc": string; readonly "method": string; readonly "params": ApplyParams; };
90
104
  export type JsonRpcRequest4 = { readonly "id": RequestId; readonly "jsonrpc": string; readonly "method": string; readonly "params": GetParams; };
@@ -97,6 +111,13 @@ export type JsonRpcResponse = JsonRpcSuccess | JsonRpcErrorResponse;
97
111
  export type JsonRpcResponse10 = JsonRpcSuccess10 | JsonRpcErrorResponse;
98
112
  export type JsonRpcResponse11 = JsonRpcSuccess11 | JsonRpcErrorResponse;
99
113
  export type JsonRpcResponse12 = JsonRpcSuccess12 | JsonRpcErrorResponse;
114
+ export type JsonRpcResponse13 = JsonRpcSuccess13 | JsonRpcErrorResponse;
115
+ export type JsonRpcResponse14 = JsonRpcSuccess14 | JsonRpcErrorResponse;
116
+ export type JsonRpcResponse15 = JsonRpcSuccess15 | JsonRpcErrorResponse;
117
+ export type JsonRpcResponse16 = JsonRpcSuccess16 | JsonRpcErrorResponse;
118
+ export type JsonRpcResponse17 = JsonRpcSuccess17 | JsonRpcErrorResponse;
119
+ export type JsonRpcResponse18 = JsonRpcSuccess18 | JsonRpcErrorResponse;
120
+ export type JsonRpcResponse19 = JsonRpcSuccess19 | JsonRpcErrorResponse;
100
121
  export type JsonRpcResponse2 = JsonRpcSuccess2 | JsonRpcErrorResponse;
101
122
  export type JsonRpcResponse3 = JsonRpcSuccess3 | JsonRpcErrorResponse;
102
123
  export type JsonRpcResponse4 = JsonRpcSuccess4 | JsonRpcErrorResponse;
@@ -109,6 +130,13 @@ export type JsonRpcSuccess = { readonly "id": RequestId; readonly "jsonrpc": str
109
130
  export type JsonRpcSuccess10 = { readonly "id": RequestId; readonly "jsonrpc": string; readonly "result": WatchResult; };
110
131
  export type JsonRpcSuccess11 = { readonly "id": RequestId; readonly "jsonrpc": string; readonly "result": LogsResult; };
111
132
  export type JsonRpcSuccess12 = { readonly "id": RequestId; readonly "jsonrpc": string; readonly "result": AgentAttachResult; };
133
+ export type JsonRpcSuccess13 = { readonly "id": RequestId; readonly "jsonrpc": string; readonly "result": RunSubmitResult; };
134
+ export type JsonRpcSuccess14 = { readonly "id": RequestId; readonly "jsonrpc": string; readonly "result": RunListResult; };
135
+ export type JsonRpcSuccess15 = { readonly "id": RequestId; readonly "jsonrpc": string; readonly "result": RunStatusResult; };
136
+ export type JsonRpcSuccess16 = { readonly "id": RequestId; readonly "jsonrpc": string; readonly "result": RunWatchResult; };
137
+ export type JsonRpcSuccess17 = { readonly "id": RequestId; readonly "jsonrpc": string; readonly "result": RunLogsResult; };
138
+ export type JsonRpcSuccess18 = { readonly "id": RequestId; readonly "jsonrpc": string; readonly "result": RunAttachResult; };
139
+ export type JsonRpcSuccess19 = { readonly "id": RequestId; readonly "jsonrpc": string; readonly "result": RunForceResult; };
112
140
  export type JsonRpcSuccess2 = { readonly "id": RequestId; readonly "jsonrpc": string; readonly "result": PlanResult; };
113
141
  export type JsonRpcSuccess3 = { readonly "id": RequestId; readonly "jsonrpc": string; readonly "result": ApplyResult; };
114
142
  export type JsonRpcSuccess4 = { readonly "id": RequestId; readonly "jsonrpc": string; readonly "result": GetResult; };
@@ -126,8 +154,10 @@ export type LogsClosedNotification = { readonly "reason": SubscriptionCloseReaso
126
154
  export type LogsParams = Record<string, never>;
127
155
  export type LogsResult = { readonly "subscriptionId": string; };
128
156
  export type NodeAddress = { readonly "attempt": number; readonly "node": string; };
157
+ export type NodeInstructions = string;
129
158
  export type NodeOutputChannel = "out" | "signal" | "diagnostic";
130
159
  export type NodeOutputSelector = { readonly "channel": NodeOutputChannel; readonly "node": string; readonly "path": ReadonlyArray<string>; };
160
+ export type NodeRuntimeBinding = ({ readonly "effort"?: ReasoningEffort | null; readonly "env"?: DeclaredEnvironment; readonly "kind": "agent"; readonly "model": string; readonly "sessionScope"?: SessionScope; }) | { readonly "env"?: DeclaredEnvironment; readonly "kind": "git_delivery"; };
131
161
  export type NonEmptyVec_of_ChoiceBranch = ReadonlyArray<ChoiceBranch>;
132
162
  export type NonEmptyVec_of_ControlSelector = ReadonlyArray<ControlSelector>;
133
163
  export type NonEmptyVec_of_FieldPath = ReadonlyArray<ReadonlyArray<string>>;
@@ -141,14 +171,38 @@ export type PlanParams = { readonly "graph": GraphSpec; };
141
171
  export type PlanResult = { readonly "bounds"?: StructuralBounds | null; readonly "diagnostics": ReadonlyArray<GraphDiagnostic>; readonly "ok": boolean; };
142
172
  export type PolicyBinding = { readonly "default": PolicyDefault; readonly "policy": string; };
143
173
  export type PolicyDefault = "deny";
174
+ export type ReasoningEffort = "low" | "medium" | "high" | "xhigh" | "max";
144
175
  export type RecordField = { readonly "required": boolean; readonly "type": PayloadType; };
145
176
  export type RedactionClass = "public" | "internal" | "confidential" | "restricted";
146
177
  export type RequestId = string | number;
178
+ export type ResolvedSource = { readonly "branch": string; readonly "repository": string; readonly "revision": string; };
147
179
  export type ResubmitParams = { readonly "idempotencyKey": string; readonly "ifGeneration": number; readonly "ifRunId": string; readonly "replacementInput"?: unknown; };
148
180
  export type ResubmitResult = { readonly "atCursor": string; readonly "deduped": boolean; readonly "generation": number; readonly "operational": OperationalStatus; readonly "phase": Phase; readonly "priorRunId": string; readonly "runId": string; };
149
181
  export type RetryParams = { readonly "idempotencyKey": string; readonly "ifGeneration": number; };
150
182
  export type RetryResult = { readonly "atCursor": string; readonly "deduped": boolean; readonly "generation": number; readonly "operational": OperationalStatus; readonly "phase": Phase; readonly "retriedTurnId": string; readonly "retryTurnId": string; readonly "runId": string; };
183
+ export type RunAttachEventNotification = { readonly "event": AgentAttachEvent; readonly "execution": string; readonly "runId": string; readonly "subscriptionId": string; };
184
+ export type RunAttachParams = { readonly "execution": string; readonly "runId": string; };
185
+ export type RunAttachResult = { readonly "execution": string; readonly "runId": string; readonly "subscriptionId": string; };
186
+ export type RunForceParams = { readonly "runId": string; };
187
+ export type RunForceResult = { readonly "atCursor": string; readonly "runId": string; readonly "size": RunSize; readonly "source": ResolvedSource; readonly "status": RunStatus; readonly "title": string; };
188
+ export type RunListParams = Record<string, never>;
189
+ export type RunListResult = { readonly "runs": ReadonlyArray<RunStatusResult>; };
190
+ export type RunLogEventNotification = { readonly "cursor": string; readonly "execution"?: string | null; readonly "record": LogRecord; readonly "runId": string; readonly "subscriptionId": string; };
191
+ export type RunLogsParams = { readonly "execution"?: string | null; readonly "fromCursor"?: string | null; readonly "runId": string; };
192
+ export type RunLogsResult = { readonly "atCursor": string; readonly "runId": string; readonly "subscriptionId": string; };
193
+ export type RunSize = "tiny" | "small" | "standard" | "large";
194
+ export type RunStatus = { readonly "phase": "admitted"; } | { readonly "activeExecutions": ReadonlyArray<ActiveExecution>; readonly "phase": "running"; } | { readonly "activeExecutions": ReadonlyArray<ActiveExecution>; readonly "phase": "stopping"; } | { readonly "phase": "finished"; readonly "terminalResult": TerminalResult; };
195
+ export type RunStatusParams = { readonly "runId": string; };
196
+ export type RunStatusResult = { readonly "atCursor": string; readonly "runId": string; readonly "size": RunSize; readonly "source": ResolvedSource; readonly "status": RunStatus; readonly "title": string; };
197
+ export type RunSubmission = { readonly "graph": GraphSpec; readonly "initialInput": unknown; readonly "runtime": RuntimePlan; readonly "source": ResolvedSource; readonly "submissionKey": string; readonly "title": string; };
198
+ export type RunSubmitParams = { readonly "runId": string; readonly "submission": RunSubmission; };
199
+ export type RunSubmitResult = { readonly "runId": string; };
200
+ export type RunWatchEventNotification = { readonly "cursor": string; readonly "runId": string; readonly "size": RunSize; readonly "source": ResolvedSource; readonly "status": RunStatus; readonly "subscriptionId": string; readonly "title": string; };
201
+ export type RunWatchParams = { readonly "fromCursor"?: string | null; readonly "runId": string; };
202
+ export type RunWatchResult = { readonly "atCursor": string; readonly "runId": string; readonly "subscriptionId": string; };
203
+ export type RuntimePlan = { readonly "harness": "codex"; readonly "nodes": Record<string, never>; readonly "provider": CodexProvider; readonly "size": RunSize; } | { readonly "harness": "claude"; readonly "nodes": Record<string, never>; readonly "provider": ClaudeProvider; readonly "size": RunSize; };
151
204
  export type ServerCapabilities = { readonly "agentAttach"?: boolean; readonly "graphProfiles"?: ReadonlyArray<GraphProfile>; readonly "logs"?: boolean; };
205
+ export type SessionScope = "execution" | "node_instance";
152
206
  export type StopMode = "drain" | "force";
153
207
  export type StopParams = { readonly "idempotencyKey": string; readonly "ifGeneration": number; readonly "mode": StopMode; };
154
208
  export type StopResult = { readonly "acceptedMode": StopMode; readonly "atCursor": string; readonly "deduped": boolean; readonly "effectiveMode": StopMode; readonly "generation": number; readonly "operational": OperationalStatus; readonly "phase": Phase; readonly "runId": string; };
@@ -174,6 +228,10 @@ export interface ClusterMethodParams {
174
228
  readonly update: UpdateParams; readonly stop: StopParams; readonly retry: RetryParams;
175
229
  readonly resubmit: ResubmitParams; readonly delete: DeleteParams; readonly get: GetParams;
176
230
  readonly watch: WatchParams; readonly logs: LogsParams; readonly 'agent/attach': AgentAttachParams;
231
+ readonly 'run/submit': RunSubmitParams; readonly 'run/list': RunListParams;
232
+ readonly 'run/status': RunStatusParams; readonly 'run/watch': RunWatchParams;
233
+ readonly 'run/logs': RunLogsParams; readonly 'run/attach': RunAttachParams;
234
+ readonly 'run/force': RunForceParams;
177
235
  }
178
236
 
179
237
  export interface ClusterMethodResults {
@@ -181,4 +239,8 @@ export interface ClusterMethodResults {
181
239
  readonly update: UpdateResult; readonly stop: StopResult; readonly retry: RetryResult;
182
240
  readonly resubmit: ResubmitResult; readonly delete: DeleteResult; readonly get: GetResult;
183
241
  readonly watch: WatchResult; readonly logs: LogsResult; readonly 'agent/attach': AgentAttachResult;
242
+ readonly 'run/submit': RunSubmitResult; readonly 'run/list': RunListResult;
243
+ readonly 'run/status': RunStatusResult; readonly 'run/watch': RunWatchResult;
244
+ readonly 'run/logs': RunLogsResult; readonly 'run/attach': RunAttachResult;
245
+ readonly 'run/force': RunForceResult;
184
246
  }
@@ -16,9 +16,16 @@ interface ProviderFacade {
16
16
  listProviders(): string[];
17
17
  }
18
18
 
19
+ interface TaskLogDecoder {
20
+ decodeTaskLogLine(line: string): { content: string; providerOutput: boolean };
21
+ }
22
+
19
23
  // The runtime facade is maintained JavaScript; keep its original emitted require path.
20
24
  // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
21
25
  const { getProvider, listProviders }: ProviderFacade = require('../src/providers');
26
+ // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment
27
+ const taskLogDecoder: TaskLogDecoder = require('../src/task-log-line');
28
+ const { decodeTaskLogLine } = taskLogDecoder;
22
29
 
23
30
  function createProviderParsers(): ProviderParser[] {
24
31
  return listProviders().map((name) => getProvider(name));
@@ -26,11 +33,9 @@ function createProviderParsers(): ProviderParser[] {
26
33
 
27
34
  function stripTimestampPrefix(line: unknown): string {
28
35
  if (!line || typeof line !== 'string') return '';
29
- let trimmed = line.trim().replace(/\r$/, '');
30
- if (!trimmed) return '';
31
-
32
- const tsMatch = /^\[(\d{13})\](.*)$/.exec(trimmed);
33
- if (tsMatch) trimmed = (tsMatch[2] || '').trimStart();
36
+ const decoded = decodeTaskLogLine(line.trim());
37
+ if (!decoded.providerOutput) return '';
38
+ const trimmed = decoded.content;
34
39
 
35
40
  if (!trimmed.startsWith('{') && !trimmed.startsWith('[')) {
36
41
  const pipeMatch = /^[^|]{1,40}\|\s*(.*)$/.exec(trimmed);
@@ -6,6 +6,7 @@ const {
6
6
  } = require('../../lib/provider-names');
7
7
  const { commandExists, getCommandPath } = require('../../lib/provider-detection');
8
8
  const helper = require('../../lib/agent-cli-provider');
9
+ const { stripTimestampPrefix } = require('../../lib/agent-cli-provider/log-prefix');
9
10
 
10
11
  const warned = new Set();
11
12
 
@@ -218,25 +219,6 @@ function listProviders() {
218
219
  return helper.listProviderAdapters();
219
220
  }
220
221
 
221
- function stripTimestampPrefix(line) {
222
- if (!line || typeof line !== 'string') return '';
223
- let trimmed = line.trim().replace(/\r$/, '');
224
- if (!trimmed) return '';
225
-
226
- const tsMatch = trimmed.match(/^\[(\d{13})\](.*)$/);
227
- if (tsMatch) trimmed = (tsMatch[2] || '').trimStart();
228
-
229
- if (!trimmed.startsWith('{') && !trimmed.startsWith('[')) {
230
- const pipeMatch = trimmed.match(/^[^|]{1,40}\|\s*(.*)$/);
231
- if (pipeMatch) {
232
- const afterPipe = (pipeMatch[1] || '').trimStart();
233
- if (afterPipe.startsWith('{') || afterPipe.startsWith('[')) return afterPipe;
234
- }
235
- }
236
-
237
- return trimmed;
238
- }
239
-
240
222
  function collectEvents(events, event) {
241
223
  if (!event) return;
242
224
  if (Array.isArray(event)) {
@@ -0,0 +1,20 @@
1
+ export const TASK_LOG_V2_MARKER: '[ZEROSHOT][LOG_FORMAT] channel-framed-v2';
2
+ export const TASK_LOG_STDOUT_PREFIX: '[ZEROSHOT][PROVIDER_STDOUT] ';
3
+ export const TASK_LOG_STDERR_PREFIX: '[ZEROSHOT][PROVIDER_STDERR] ';
4
+
5
+ export type TaskLogChannel = 'provider_stdout' | 'provider_stderr' | 'control' | 'legacy';
6
+ export type TaskLogFormat = 'stderr-tagged-v1' | 'channel-framed-v2' | null;
7
+
8
+ export interface DecodedTaskLogLine {
9
+ readonly channel: TaskLogChannel;
10
+ readonly content: string;
11
+ readonly format: TaskLogFormat;
12
+ readonly providerOutput: boolean;
13
+ readonly timestamp: number | null;
14
+ readonly timestamped: boolean;
15
+ }
16
+
17
+ export function decodeTaskLogLine(line: string): DecodedTaskLogLine;
18
+ export function formatTaskLogMarker(timestamp: number): string;
19
+ export function formatTaskLogStderr(timestamp: number, content: string): string;
20
+ export function formatTaskLogStdout(timestamp: number, content: string): string;
@@ -0,0 +1,80 @@
1
+ 'use strict';
2
+
3
+ const TASK_LOG_V2_MARKER = '[ZEROSHOT][LOG_FORMAT] channel-framed-v2';
4
+ const TASK_LOG_STDOUT_PREFIX = '[ZEROSHOT][PROVIDER_STDOUT] ';
5
+ const TASK_LOG_STDERR_PREFIX = '[ZEROSHOT][PROVIDER_STDERR] ';
6
+ const TASK_LOG_V1_MARKER = '[ZEROSHOT][LOG_FORMAT] stderr-tagged-v1';
7
+ const CONTROL_LINE =
8
+ /^\[(?:ATTACH|CLEANUP|CRASH|DETACH|ERROR|OMP-OWNERSHIP|SDK-DIAGNOSTIC|SYSTEM)\](?:\s|$)/;
9
+
10
+ function timestampParts(line) {
11
+ const normalized = line.replace(/\r$/, '');
12
+ const match = /^\[(\d{13}|\d{4}-\d{2}-\d{2}T[^\]]+)\](.*)$/.exec(normalized);
13
+ if (!match) return { content: normalized, timestamp: null };
14
+ const rawTimestamp = match[1];
15
+ const epochTimestamp = /^\d{13}$/.test(rawTimestamp);
16
+ const timestamp = epochTimestamp
17
+ ? Number.parseInt(rawTimestamp, 10)
18
+ : new Date(rawTimestamp).getTime();
19
+ return {
20
+ content: match[2].trimStart(),
21
+ timestamp: Number.isFinite(timestamp) ? timestamp : null,
22
+ };
23
+ }
24
+
25
+ function decodeTaskLogLine(line) {
26
+ const { content, timestamp } = timestampParts(line);
27
+ const common = { timestamp, timestamped: timestamp !== null };
28
+ if (content.startsWith(TASK_LOG_STDOUT_PREFIX)) {
29
+ return {
30
+ ...common,
31
+ channel: 'provider_stdout',
32
+ content: content.slice(TASK_LOG_STDOUT_PREFIX.length),
33
+ format: null,
34
+ providerOutput: true,
35
+ };
36
+ }
37
+ if (content.startsWith(TASK_LOG_STDERR_PREFIX)) {
38
+ return {
39
+ ...common,
40
+ channel: 'provider_stderr',
41
+ content: content.slice(TASK_LOG_STDERR_PREFIX.length),
42
+ format: null,
43
+ providerOutput: false,
44
+ };
45
+ }
46
+ let format = null;
47
+ if (content === TASK_LOG_V2_MARKER) format = 'channel-framed-v2';
48
+ else if (content === TASK_LOG_V1_MARKER) format = 'stderr-tagged-v1';
49
+ const control =
50
+ format !== null || content.startsWith('[ZEROSHOT][FATAL] ') || CONTROL_LINE.test(content);
51
+ return {
52
+ ...common,
53
+ channel: control ? 'control' : 'legacy',
54
+ content,
55
+ format,
56
+ providerOutput: !control,
57
+ };
58
+ }
59
+
60
+ function formatTaskLogMarker(timestamp) {
61
+ return `[${timestamp}]${TASK_LOG_V2_MARKER}\n`;
62
+ }
63
+
64
+ function formatTaskLogStdout(timestamp, content) {
65
+ return `[${timestamp}]${TASK_LOG_STDOUT_PREFIX}${content}\n`;
66
+ }
67
+
68
+ function formatTaskLogStderr(timestamp, content) {
69
+ return `[${timestamp}]${TASK_LOG_STDERR_PREFIX}${content}\n`;
70
+ }
71
+
72
+ module.exports = {
73
+ TASK_LOG_STDERR_PREFIX,
74
+ TASK_LOG_STDOUT_PREFIX,
75
+ TASK_LOG_V2_MARKER,
76
+ decodeTaskLogLine,
77
+ formatTaskLogMarker,
78
+ formatTaskLogStderr,
79
+ formatTaskLogStdout,
80
+ };
@@ -7,6 +7,7 @@ import { createRequire } from 'module';
7
7
  // Import cluster's stream parser (shared between task and cluster)
8
8
  const require = createRequire(import.meta.url);
9
9
  const { parseChunk } = require('../../lib/stream-json-parser');
10
+ const { decodeTaskLogLine } = require('../../src/task-log-line');
10
11
 
11
12
  // Tool icons for different tool types
12
13
  const TOOL_ICONS = {
@@ -271,16 +272,12 @@ function handleMulti(event) {
271
272
  }
272
273
 
273
274
  // Parse a raw log line (may have timestamp prefix)
274
- function parseLogLine(line) {
275
- let trimmed = line.trim();
275
+ export function parseLogLine(line) {
276
+ const decoded = decodeTaskLogLine(line);
277
+ if (!decoded.providerOutput) return [];
278
+ const trimmed = decoded.content.trim();
276
279
  if (!trimmed) return [];
277
280
 
278
- // Strip timestamp prefix if present: [1234567890]{...} -> {...}
279
- const timestampMatch = trimmed.match(/^\[\d+\](.*)$/);
280
- if (timestampMatch) {
281
- trimmed = timestampMatch[1];
282
- }
283
-
284
281
  // Non-JSON lines output as-is
285
282
  if (!trimmed.startsWith('{')) {
286
283
  return [{ type: 'text', text: trimmed + '\n' }];
@@ -0,0 +1,31 @@
1
+ import { createRequire } from 'module';
2
+
3
+ const require = createRequire(import.meta.url);
4
+ const {
5
+ formatTaskLogMarker,
6
+ formatTaskLogStderr,
7
+ formatTaskLogStdout,
8
+ } = require('../src/task-log-line.js');
9
+
10
+ export function markSdkTaskLog(log, timestamp = Date.now()) {
11
+ log(formatTaskLogMarker(timestamp));
12
+ }
13
+
14
+ function normalizedTerminalEvent(terminal) {
15
+ if (terminal.type === 'result') return terminal.event;
16
+ return {
17
+ type: 'result',
18
+ success: false,
19
+ error: { ...terminal.frame.error },
20
+ };
21
+ }
22
+
23
+ export function logSdkTerminal(log, result, now = Date.now) {
24
+ for (const frame of result.progress) {
25
+ log(formatTaskLogStdout(now(), JSON.stringify(frame)));
26
+ }
27
+ log(formatTaskLogStdout(now(), JSON.stringify(normalizedTerminalEvent(result.terminal))));
28
+ for (const line of (result.diagnosticStderr || '').replace(/\r/g, '').split('\n')) {
29
+ if (line) log(formatTaskLogStderr(now(), line));
30
+ }
31
+ }
@@ -7,6 +7,7 @@
7
7
  import { appendFileSync } from 'fs';
8
8
  import { getTask, updateTask } from './store.js';
9
9
  import { createCommandSpecCleanup } from './command-spec-cleanup.js';
10
+ import { logSdkTerminal, markSdkTaskLog } from './sdk-watcher-output.js';
10
11
  import {
11
12
  completePendingWatcherCancellation,
12
13
  completeWatcherFailure,
@@ -72,16 +73,6 @@ function completionFor(result) {
72
73
  };
73
74
  }
74
75
 
75
- function logTerminal(result) {
76
- for (const frame of result.progress) log(`[${Date.now()}]${JSON.stringify(frame)}\n`);
77
- const terminal =
78
- result.terminal.type === 'result' ? result.terminal.event : result.terminal.frame;
79
- log(`[${Date.now()}]${JSON.stringify(terminal)}\n`);
80
- if (result.diagnosticStderr) {
81
- log(`[${Date.now()}][SDK-DIAGNOSTIC] ${result.diagnosticStderr}\n`);
82
- }
83
- }
84
-
85
76
  async function terminateOwnedProviderBoundary() {
86
77
  if (terminalResult) return terminalResult.cleanupAttestation.clean === true;
87
78
  if (!running) return true;
@@ -116,6 +107,8 @@ process.on('unhandledRejection', (reason) => {
116
107
  void crashWithError(reason, 'unhandledRejection');
117
108
  });
118
109
 
110
+ markSdkTaskLog(log);
111
+
119
112
  if (
120
113
  await completePendingWatcherCancellation({
121
114
  taskId,
@@ -139,7 +132,7 @@ try {
139
132
  if (getTask(taskId)?.cancelRequested) running.cancel();
140
133
 
141
134
  terminalResult = await running.result;
142
- logTerminal(terminalResult);
135
+ logSdkTerminal(log, terminalResult);
143
136
  await completeWatcherTask({
144
137
  taskId,
145
138
  completion: completionFor(terminalResult),
@@ -8,6 +8,14 @@ import {
8
8
  supportsProviderStructuredOutputRecovery,
9
9
  } from './provider-helper-runtime.js';
10
10
  import { terminateProcess } from './process-termination.js';
11
+ import { createRequire } from 'module';
12
+
13
+ const require = createRequire(import.meta.url);
14
+ const {
15
+ TASK_LOG_STDOUT_PREFIX,
16
+ formatTaskLogMarker,
17
+ formatTaskLogStdout,
18
+ } = require('../src/task-log-line.js');
11
19
 
12
20
  export const COMMAND_CLEANUP_UNINITIALIZED = Symbol('command-cleanup-uninitialized');
13
21
 
@@ -69,7 +77,7 @@ function createCodexOutputPassthrough({ log, captureProviderSession }) {
69
77
  let offset = 0;
70
78
  while (offset < text.length) {
71
79
  if (atLineStart) {
72
- logged.push(`[${timestamp}]`);
80
+ logged.push(`[${timestamp}]${TASK_LOG_STDOUT_PREFIX}`);
73
81
  atLineStart = false;
74
82
  }
75
83
  const newline = text.indexOf('\n', offset);
@@ -128,7 +136,7 @@ function createBoundedLinePassthrough({
128
136
  }
129
137
  if (byteLength > MAX_WATCHER_CONTROL_RECORD_BYTES) {
130
138
  if (deferRawUntilOverflow && log) {
131
- log(`[${lineTimestamp}]${inspectionParts.join('')}${part}`);
139
+ log(`[${lineTimestamp}]${linePrefix}${inspectionParts.join('')}${part}`);
132
140
  rawOverflowStreaming = true;
133
141
  }
134
142
  inspectable = false;
@@ -310,8 +318,10 @@ export function completeWatcherFailure({ error, source, ...completionOptions })
310
318
  * frames, prompt text, or control payloads.
311
319
  */
312
320
  export function createRpcWatcherOutputRuntime({ log }) {
321
+ log(formatTaskLogMarker(Date.now()));
322
+
313
323
  function logEvent(event) {
314
- log(`[${Date.now()}]${JSON.stringify(event)}\n`);
324
+ log(formatTaskLogStdout(Date.now(), JSON.stringify(event)));
315
325
  }
316
326
 
317
327
  function complete(result) {
@@ -350,6 +360,7 @@ export function createWatcherOutputRuntime({
350
360
  let finalResultJson = null;
351
361
  let streamingModeError = null;
352
362
  let fatalError = null;
363
+ log(formatTaskLogMarker(Date.now()));
353
364
  const captureProviderSession = providerSessionCapture?.captureLine || (() => {});
354
365
  const codexOutputPassthrough =
355
366
  providerName === 'codex' ? createCodexOutputPassthrough({ log, captureProviderSession }) : null;
@@ -358,6 +369,7 @@ export function createWatcherOutputRuntime({
358
369
  : createBoundedLinePassthrough({
359
370
  log,
360
371
  deferRawUntilOverflow: silentJsonMode,
372
+ linePrefix: TASK_LOG_STDOUT_PREFIX,
361
373
  handleLine: (line, timestamp, { oversized }) =>
362
374
  handleOutputLine(line, timestamp, {
363
375
  alreadyLogged: !silentJsonMode,
@@ -366,19 +378,20 @@ export function createWatcherOutputRuntime({
366
378
  });
367
379
  const stderrPassthrough = createBoundedLinePassthrough({
368
380
  log,
369
- // Pi reserves stdout for its JSON protocol and deliberately routes ordinary writes to
370
- // stderr. Keep those diagnostics in the task log with explicit provenance so followers can
371
- // exclude them from strict JSON validation.
372
- linePrefix: providerName === 'pi' ? '[ZEROSHOT][PROVIDER_STDERR] ' : '',
373
- handleLine: (line, timestamp) => maybeHandleFatalError(line, timestamp),
381
+ // Stderr must never be mistaken for provider protocol output. Fatal detection still receives
382
+ // the raw line through handleLine; only the persisted task-log representation is tagged.
383
+ linePrefix: '[ZEROSHOT][PROVIDER_STDERR] ',
384
+ handleLine: (line, timestamp) => maybeHandleFatalError(line, timestamp, true),
374
385
  });
375
386
 
376
- function maybeHandleFatalError(line, timestamp) {
387
+ function maybeHandleFatalError(line, timestamp, rawPersisted = false) {
377
388
  if (fatalError) return false;
378
389
  const detected = detectProviderFatalError(providerName, line);
379
390
  if (!detected) return false;
380
391
  fatalError = detected;
381
- if (silentJsonMode) log(`[${timestamp}]${line}\n`);
392
+ if (silentJsonMode && !rawPersisted) {
393
+ log(formatTaskLogStdout(timestamp, line));
394
+ }
382
395
  log(`[${timestamp}][ZEROSHOT][FATAL] ${detected}\n`);
383
396
  stopProvider(timestamp);
384
397
  return true;
@@ -413,12 +426,12 @@ export function createWatcherOutputRuntime({
413
426
  if (silentJsonMode && !line.trim()) return;
414
427
  // Pi reserves stdout for JSON lifecycle events. Error text inside an assistant message may be
415
428
  // followed by an automatic retry, so only Pi stderr can prove a pre-agent startup failure.
416
- if (providerName !== 'pi') maybeHandleFatalError(line, timestamp);
429
+ if (providerName !== 'pi') maybeHandleFatalError(line, timestamp, alreadyLogged);
417
430
  if (captureStreamingError(line, timestamp)) return;
418
431
  if (silentJsonMode) {
419
432
  maybeCaptureStructuredOutput(line);
420
433
  } else if (!alreadyLogged) {
421
- log(`[${timestamp}]${line}\n`);
434
+ log(formatTaskLogStdout(timestamp, line));
422
435
  }
423
436
  }
424
437
 
@@ -444,11 +457,10 @@ export function createWatcherOutputRuntime({
444
457
  if (silentJsonMode) {
445
458
  finalResultJson = recoveredLine;
446
459
  } else {
447
- log(`[${timestamp}]${recoveredLine}\n`);
460
+ log(formatTaskLogStdout(timestamp, recoveredLine));
448
461
  }
449
462
  } else if (streamingModeError.line) {
450
- const prefix = silentJsonMode ? '' : `[${streamingModeError.timestamp}]`;
451
- log(`${prefix}${streamingModeError.line}\n`);
463
+ log(formatTaskLogStdout(streamingModeError.timestamp, streamingModeError.line));
452
464
  }
453
465
  return recovered;
454
466
  }
@@ -463,7 +475,9 @@ export function createWatcherOutputRuntime({
463
475
  if (stderrBuffer !== null) stderrPassthrough.flush();
464
476
  const recovered = attemptRecovery(code, timestamp);
465
477
  const sessionIdentityError = providerSessionCapture?.getCompletionError() || null;
466
- if (silentJsonMode && finalResultJson) log(`${finalResultJson}\n`);
478
+ if (silentJsonMode && finalResultJson) {
479
+ log(formatTaskLogStdout(timestamp, finalResultJson));
480
+ }
467
481
  if (config.outputFormat !== 'json') {
468
482
  log(`\n${'='.repeat(50)}\n`);
469
483
  log(`Finished: ${new Date().toISOString()}\n`);