@gajae-code/coding-agent 0.2.5 → 0.3.1
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/CHANGELOG.md +28 -0
- package/dist/types/async/job-manager.d.ts +91 -2
- package/dist/types/cli/args.d.ts +1 -1
- package/dist/types/commands/deep-interview.d.ts +3 -0
- package/dist/types/commands/harness.d.ts +37 -0
- package/dist/types/config/keybindings.d.ts +5 -0
- package/dist/types/config/settings-schema.d.ts +10 -4
- package/dist/types/config/settings.d.ts +2 -0
- package/dist/types/debug/crash-diagnostics.d.ts +45 -0
- package/dist/types/debug/runtime-gauges.d.ts +6 -0
- package/dist/types/deep-interview/render-middleware.d.ts +6 -0
- package/dist/types/eval/py/executor.d.ts +2 -0
- package/dist/types/eval/py/kernel.d.ts +2 -0
- package/dist/types/exec/bash-executor.d.ts +10 -0
- package/dist/types/extensibility/custom-tools/types.d.ts +1 -0
- package/dist/types/extensibility/extensions/types.d.ts +6 -0
- package/dist/types/extensibility/shared-events.d.ts +1 -0
- package/dist/types/gjc-runtime/cli-write-receipt.d.ts +24 -0
- package/dist/types/gjc-runtime/deep-interview-runtime.d.ts +1 -0
- package/dist/types/gjc-runtime/state-graph.d.ts +4 -0
- package/dist/types/gjc-runtime/state-migrations.d.ts +33 -0
- package/dist/types/gjc-runtime/state-renderer.d.ts +65 -0
- package/dist/types/gjc-runtime/state-runtime.d.ts +2 -0
- package/dist/types/gjc-runtime/state-schema.d.ts +317 -0
- package/dist/types/gjc-runtime/state-validation.d.ts +6 -0
- package/dist/types/gjc-runtime/state-writer.d.ts +147 -0
- package/dist/types/gjc-runtime/team-runtime.d.ts +81 -7
- package/dist/types/gjc-runtime/workflow-command-ref.d.ts +43 -0
- package/dist/types/gjc-runtime/workflow-manifest.d.ts +54 -0
- package/dist/types/harness-control-plane/classifier.d.ts +13 -0
- package/dist/types/harness-control-plane/control-endpoint.d.ts +31 -0
- package/dist/types/harness-control-plane/finalize.d.ts +47 -0
- package/dist/types/harness-control-plane/frame-mapper.d.ts +29 -0
- package/dist/types/harness-control-plane/operate.d.ts +35 -0
- package/dist/types/harness-control-plane/owner.d.ts +46 -0
- package/dist/types/harness-control-plane/preserve.d.ts +19 -0
- package/dist/types/harness-control-plane/receipts.d.ts +88 -0
- package/dist/types/harness-control-plane/rpc-adapter.d.ts +66 -0
- package/dist/types/harness-control-plane/seams.d.ts +21 -0
- package/dist/types/harness-control-plane/session-lease.d.ts +65 -0
- package/dist/types/harness-control-plane/state-machine.d.ts +19 -0
- package/dist/types/harness-control-plane/storage.d.ts +53 -0
- package/dist/types/harness-control-plane/types.d.ts +162 -0
- package/dist/types/hooks/skill-keywords.d.ts +2 -1
- package/dist/types/hooks/skill-state.d.ts +23 -29
- package/dist/types/internal-urls/agent-protocol.d.ts +2 -2
- package/dist/types/internal-urls/artifact-protocol.d.ts +2 -2
- package/dist/types/internal-urls/registry-helpers.d.ts +8 -7
- package/dist/types/internal-urls/types.d.ts +4 -0
- package/dist/types/lsp/index.d.ts +10 -10
- package/dist/types/modes/bridge/auth.d.ts +12 -0
- package/dist/types/modes/bridge/bridge-client-bridge.d.ts +9 -0
- package/dist/types/modes/bridge/bridge-mode.d.ts +44 -0
- package/dist/types/modes/bridge/bridge-ui-context.d.ts +88 -0
- package/dist/types/modes/bridge/event-stream.d.ts +8 -0
- package/dist/types/modes/components/custom-editor.d.ts +6 -0
- package/dist/types/modes/components/hook-selector.d.ts +1 -0
- package/dist/types/modes/components/jobs-overlay-model.d.ts +31 -0
- package/dist/types/modes/components/jobs-overlay.d.ts +30 -0
- package/dist/types/modes/components/status-line/types.d.ts +2 -0
- package/dist/types/modes/components/status-line.d.ts +2 -0
- package/dist/types/modes/controllers/input-controller.d.ts +1 -0
- package/dist/types/modes/controllers/selector-controller.d.ts +8 -0
- package/dist/types/modes/index.d.ts +1 -0
- package/dist/types/modes/interactive-mode.d.ts +2 -0
- package/dist/types/modes/jobs-observer.d.ts +57 -0
- package/dist/types/modes/rpc/host-tools.d.ts +1 -16
- package/dist/types/modes/rpc/host-uris.d.ts +1 -38
- package/dist/types/modes/shared/agent-wire/command-dispatch.d.ts +20 -0
- package/dist/types/modes/shared/agent-wire/command-validation.d.ts +2 -0
- package/dist/types/modes/shared/agent-wire/event-envelope.d.ts +24 -0
- package/dist/types/modes/shared/agent-wire/handshake.d.ts +46 -0
- package/dist/types/modes/shared/agent-wire/host-tool-bridge.d.ts +16 -0
- package/dist/types/modes/shared/agent-wire/host-uri-bridge.d.ts +17 -0
- package/dist/types/modes/shared/agent-wire/protocol.d.ts +44 -0
- package/dist/types/modes/shared/agent-wire/responses.d.ts +4 -0
- package/dist/types/modes/shared/agent-wire/scopes.d.ts +18 -0
- package/dist/types/modes/shared/agent-wire/ui-request-broker.d.ts +42 -0
- package/dist/types/modes/shared/agent-wire/ui-result.d.ts +27 -0
- package/dist/types/modes/types.d.ts +2 -0
- package/dist/types/sdk.d.ts +4 -0
- package/dist/types/session/agent-session.d.ts +19 -1
- package/dist/types/skill-state/active-state.d.ts +2 -0
- package/dist/types/skill-state/deep-interview-mutation-guard.d.ts +1 -1
- package/dist/types/skill-state/workflow-state-contract.d.ts +25 -2
- package/dist/types/skill-state/workflow-state-version.d.ts +3 -0
- package/dist/types/task/executor.d.ts +3 -0
- package/dist/types/task/id.d.ts +7 -0
- package/dist/types/task/index.d.ts +5 -0
- package/dist/types/task/receipt.d.ts +85 -0
- package/dist/types/task/spawn-gate.d.ts +38 -0
- package/dist/types/task/types.d.ts +198 -14
- package/dist/types/tools/cron.d.ts +6 -0
- package/dist/types/tools/index.d.ts +2 -0
- package/dist/types/tools/path-utils.d.ts +1 -0
- package/dist/types/tools/subagent.d.ts +26 -1
- package/package.json +7 -7
- package/scripts/build-binary.ts +7 -0
- package/src/async/job-manager.ts +334 -6
- package/src/cli/args.ts +9 -2
- package/src/cli/auth-broker-cli.ts +1 -0
- package/src/cli/config-cli.ts +10 -2
- package/src/cli.ts +2 -0
- package/src/commands/deep-interview.ts +1 -0
- package/src/commands/harness.ts +862 -0
- package/src/commands/launch.ts +2 -2
- package/src/commands/state.ts +2 -1
- package/src/commands/team.ts +54 -39
- package/src/config/keybindings.ts +6 -0
- package/src/config/settings-schema.ts +13 -3
- package/src/config/settings.ts +5 -0
- package/src/dap/client.ts +17 -3
- package/src/debug/crash-diagnostics.ts +223 -0
- package/src/debug/runtime-gauges.ts +20 -0
- package/src/deep-interview/render-middleware.ts +372 -0
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +1 -1
- package/src/defaults/gjc/skills/ralplan/SKILL.md +31 -2
- package/src/defaults/gjc/skills/team/SKILL.md +47 -21
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +106 -13
- package/src/eval/py/executor.ts +21 -1
- package/src/eval/py/kernel.ts +15 -0
- package/src/exec/bash-executor.ts +41 -0
- package/src/extensibility/custom-tools/types.ts +1 -0
- package/src/extensibility/extensions/types.ts +6 -0
- package/src/extensibility/shared-events.ts +1 -0
- package/src/gjc-runtime/cli-write-receipt.ts +31 -0
- package/src/gjc-runtime/deep-interview-runtime.ts +98 -42
- package/src/gjc-runtime/goal-mode-request.ts +11 -3
- package/src/gjc-runtime/ralplan-runtime.ts +235 -43
- package/src/gjc-runtime/state-graph.ts +86 -0
- package/src/gjc-runtime/state-migrations.ts +179 -0
- package/src/gjc-runtime/state-renderer.ts +345 -0
- package/src/gjc-runtime/state-runtime.ts +1155 -46
- package/src/gjc-runtime/state-schema.ts +192 -0
- package/src/gjc-runtime/state-validation.ts +49 -0
- package/src/gjc-runtime/state-writer.ts +749 -0
- package/src/gjc-runtime/team-runtime.ts +1255 -189
- package/src/gjc-runtime/ultragoal-runtime.ts +460 -43
- package/src/gjc-runtime/workflow-command-ref.ts +239 -0
- package/src/gjc-runtime/workflow-manifest.generated.json +1601 -0
- package/src/gjc-runtime/workflow-manifest.ts +427 -0
- package/src/harness-control-plane/classifier.ts +128 -0
- package/src/harness-control-plane/control-endpoint.ts +148 -0
- package/src/harness-control-plane/finalize.ts +222 -0
- package/src/harness-control-plane/frame-mapper.ts +286 -0
- package/src/harness-control-plane/operate.ts +225 -0
- package/src/harness-control-plane/owner.ts +600 -0
- package/src/harness-control-plane/preserve.ts +102 -0
- package/src/harness-control-plane/receipts.ts +216 -0
- package/src/harness-control-plane/rpc-adapter.ts +276 -0
- package/src/harness-control-plane/seams.ts +39 -0
- package/src/harness-control-plane/session-lease.ts +388 -0
- package/src/harness-control-plane/state-machine.ts +98 -0
- package/src/harness-control-plane/storage.ts +257 -0
- package/src/harness-control-plane/types.ts +214 -0
- package/src/hooks/skill-keywords.ts +4 -2
- package/src/hooks/skill-state.ts +197 -64
- package/src/internal-urls/agent-protocol.ts +68 -21
- package/src/internal-urls/artifact-protocol.ts +12 -17
- package/src/internal-urls/docs-index.generated.ts +3 -2
- package/src/internal-urls/registry-helpers.ts +19 -16
- package/src/internal-urls/types.ts +4 -0
- package/src/lsp/client.ts +18 -2
- package/src/main.ts +21 -5
- package/src/modes/bridge/auth.ts +41 -0
- package/src/modes/bridge/bridge-client-bridge.ts +47 -0
- package/src/modes/bridge/bridge-mode.ts +520 -0
- package/src/modes/bridge/bridge-ui-context.ts +200 -0
- package/src/modes/bridge/event-stream.ts +70 -0
- package/src/modes/components/assistant-message.ts +5 -1
- package/src/modes/components/custom-editor.ts +101 -0
- package/src/modes/components/hook-selector.ts +133 -20
- package/src/modes/components/jobs-overlay-model.ts +109 -0
- package/src/modes/components/jobs-overlay.ts +172 -0
- package/src/modes/components/status-line/presets.ts +7 -5
- package/src/modes/components/status-line/segments.ts +25 -0
- package/src/modes/components/status-line/types.ts +2 -0
- package/src/modes/components/status-line.ts +9 -1
- package/src/modes/controllers/event-controller.ts +71 -6
- package/src/modes/controllers/extension-ui-controller.ts +43 -1
- package/src/modes/controllers/input-controller.ts +105 -9
- package/src/modes/controllers/selector-controller.ts +31 -1
- package/src/modes/index.ts +1 -0
- package/src/modes/interactive-mode.ts +28 -0
- package/src/modes/jobs-observer.ts +204 -0
- package/src/modes/rpc/host-tools.ts +1 -186
- package/src/modes/rpc/host-uris.ts +1 -235
- package/src/modes/rpc/rpc-client.ts +25 -10
- package/src/modes/rpc/rpc-mode.ts +12 -381
- package/src/modes/shared/agent-wire/command-dispatch.ts +341 -0
- package/src/modes/shared/agent-wire/command-validation.ts +131 -0
- package/src/modes/shared/agent-wire/event-envelope.ts +108 -0
- package/src/modes/shared/agent-wire/handshake.ts +117 -0
- package/src/modes/shared/agent-wire/host-tool-bridge.ts +194 -0
- package/src/modes/shared/agent-wire/host-uri-bridge.ts +236 -0
- package/src/modes/shared/agent-wire/protocol.ts +96 -0
- package/src/modes/shared/agent-wire/responses.ts +17 -0
- package/src/modes/shared/agent-wire/scopes.ts +89 -0
- package/src/modes/shared/agent-wire/ui-request-broker.ts +150 -0
- package/src/modes/shared/agent-wire/ui-result.ts +48 -0
- package/src/modes/types.ts +2 -0
- package/src/prompts/agents/executor.md +13 -0
- package/src/prompts/tools/subagent.md +39 -4
- package/src/prompts/tools/task-summary.md +3 -9
- package/src/prompts/tools/task.md +5 -1
- package/src/sdk.ts +8 -0
- package/src/session/agent-session.ts +445 -71
- package/src/session/session-manager.ts +13 -1
- package/src/skill-state/active-state.ts +58 -65
- package/src/skill-state/deep-interview-mutation-guard.ts +114 -17
- package/src/skill-state/initial-phase.ts +2 -0
- package/src/skill-state/workflow-state-contract.ts +33 -4
- package/src/skill-state/workflow-state-version.ts +3 -0
- package/src/slash-commands/builtin-registry.ts +8 -0
- package/src/task/executor.ts +79 -13
- package/src/task/id.ts +33 -0
- package/src/task/index.ts +376 -74
- package/src/task/output-manager.ts +5 -4
- package/src/task/receipt.ts +297 -0
- package/src/task/render.ts +54 -134
- package/src/task/spawn-gate.ts +132 -0
- package/src/task/types.ts +104 -10
- package/src/tools/ask.ts +88 -27
- package/src/tools/ast-edit.ts +1 -0
- package/src/tools/ast-grep.ts +1 -0
- package/src/tools/bash.ts +1 -1
- package/src/tools/cron.ts +48 -0
- package/src/tools/find.ts +4 -1
- package/src/tools/index.ts +2 -0
- package/src/tools/path-utils.ts +3 -2
- package/src/tools/read.ts +1 -0
- package/src/tools/search.ts +1 -0
- package/src/tools/skill.ts +6 -1
- package/src/tools/subagent.ts +423 -79
|
@@ -8,6 +8,7 @@
|
|
|
8
8
|
* This enables reliable agent:// URL resolution and prevents artifact collisions.
|
|
9
9
|
*/
|
|
10
10
|
import * as fs from "node:fs/promises";
|
|
11
|
+
import { validateAllocatedTaskId, validateTaskId } from "./id";
|
|
11
12
|
|
|
12
13
|
function escapeRegExp(value: string): string {
|
|
13
14
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
@@ -73,8 +74,8 @@ export class AgentOutputManager {
|
|
|
73
74
|
*/
|
|
74
75
|
async allocate(id: string): Promise<string> {
|
|
75
76
|
await this.#ensureInitialized();
|
|
76
|
-
const prefix = this.#parentPrefix ? `${this.#parentPrefix}.` : "";
|
|
77
|
-
return `${prefix}${this.#nextId++}-${id}`;
|
|
77
|
+
const prefix = this.#parentPrefix ? `${validateAllocatedTaskId(this.#parentPrefix)}.` : "";
|
|
78
|
+
return `${prefix}${this.#nextId++}-${validateTaskId(id)}`;
|
|
78
79
|
}
|
|
79
80
|
|
|
80
81
|
/**
|
|
@@ -85,8 +86,8 @@ export class AgentOutputManager {
|
|
|
85
86
|
*/
|
|
86
87
|
async allocateBatch(ids: string[]): Promise<string[]> {
|
|
87
88
|
await this.#ensureInitialized();
|
|
88
|
-
const prefix = this.#parentPrefix ? `${this.#parentPrefix}.` : "";
|
|
89
|
-
return ids.map(id => `${prefix}${this.#nextId++}-${id}`);
|
|
89
|
+
const prefix = this.#parentPrefix ? `${validateAllocatedTaskId(this.#parentPrefix)}.` : "";
|
|
90
|
+
return ids.map(id => `${prefix}${this.#nextId++}-${validateTaskId(id)}`);
|
|
90
91
|
}
|
|
91
92
|
|
|
92
93
|
/**
|
|
@@ -0,0 +1,297 @@
|
|
|
1
|
+
import type { SingleResult, TaskToolDetails } from "./types";
|
|
2
|
+
|
|
3
|
+
export interface TaskRoi {
|
|
4
|
+
tokens: number;
|
|
5
|
+
contextTokens?: number;
|
|
6
|
+
clonedTokens?: number;
|
|
7
|
+
costTotal?: number;
|
|
8
|
+
outputBytes?: number;
|
|
9
|
+
outputLines?: number;
|
|
10
|
+
producedChanges: boolean;
|
|
11
|
+
materialContribution: boolean;
|
|
12
|
+
lowRoi: boolean;
|
|
13
|
+
}
|
|
14
|
+
export interface TaskResultReceipt {
|
|
15
|
+
index: number;
|
|
16
|
+
id: string;
|
|
17
|
+
agent: string;
|
|
18
|
+
agentSource: SingleResult["agentSource"];
|
|
19
|
+
task: string;
|
|
20
|
+
assignment?: string;
|
|
21
|
+
description?: string;
|
|
22
|
+
status: "completed" | "failed" | "aborted" | "merge_failed" | "paused";
|
|
23
|
+
exitCode: number;
|
|
24
|
+
aborted?: boolean;
|
|
25
|
+
paused?: boolean;
|
|
26
|
+
truncated: boolean;
|
|
27
|
+
durationMs: number;
|
|
28
|
+
tokens: number;
|
|
29
|
+
contextTokens?: number;
|
|
30
|
+
contextWindow?: number;
|
|
31
|
+
modelOverride?: string | string[];
|
|
32
|
+
usage?: SingleResult["usage"];
|
|
33
|
+
cost?: number;
|
|
34
|
+
branchName?: string;
|
|
35
|
+
retryFailure?: { attempt: number; errorSummary: string };
|
|
36
|
+
errorSummary?: string;
|
|
37
|
+
abortSummary?: string;
|
|
38
|
+
preview: string;
|
|
39
|
+
previewTruncated: boolean;
|
|
40
|
+
outputRef?: { uri: string; sizeBytes: number; lineCount: number; sha256?: string };
|
|
41
|
+
outputUnavailable?: boolean;
|
|
42
|
+
review?: {
|
|
43
|
+
overallCorrectness?: string;
|
|
44
|
+
findingCount: number;
|
|
45
|
+
findings?: Array<{ severity?: string; summary: string }>;
|
|
46
|
+
};
|
|
47
|
+
extractedToolCounts?: Record<string, number>;
|
|
48
|
+
forkContext?: SingleResult["forkContext"];
|
|
49
|
+
roi?: TaskRoi;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
const BANNED_RAW_TASK_KEYS = new Set([
|
|
53
|
+
"output",
|
|
54
|
+
"stderr",
|
|
55
|
+
"extractedToolData",
|
|
56
|
+
"resultText",
|
|
57
|
+
"errorText",
|
|
58
|
+
"artifactPayload",
|
|
59
|
+
"rawResult",
|
|
60
|
+
"rawResults",
|
|
61
|
+
"rawNestedResults",
|
|
62
|
+
"fullOutput",
|
|
63
|
+
"full_result",
|
|
64
|
+
"toolOutput",
|
|
65
|
+
"toolResultRaw",
|
|
66
|
+
"stdout",
|
|
67
|
+
"rawOutput",
|
|
68
|
+
"recentOutput",
|
|
69
|
+
"currentToolArgs",
|
|
70
|
+
"inflightTaskDetails",
|
|
71
|
+
]);
|
|
72
|
+
|
|
73
|
+
function truncateText(value: string | undefined, maxChars: number): string | undefined {
|
|
74
|
+
if (!value) return undefined;
|
|
75
|
+
return value.length > maxChars ? value.slice(0, maxChars) : value;
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function buildSafeSynopsis(raw: SingleResult, outputRef: TaskResultReceipt["outputRef"]): string {
|
|
79
|
+
const status = getStatus(raw);
|
|
80
|
+
if (raw.retryFailure) {
|
|
81
|
+
return `Task ${status}; retry stopped after attempt ${raw.retryFailure.attempt}.`;
|
|
82
|
+
}
|
|
83
|
+
if (raw.abortReason) {
|
|
84
|
+
return `Task ${status}; abort reason recorded.`;
|
|
85
|
+
}
|
|
86
|
+
if (raw.error) {
|
|
87
|
+
return `Task ${status}; error recorded.`;
|
|
88
|
+
}
|
|
89
|
+
if (outputRef) {
|
|
90
|
+
return `Task ${status}; output stored in ${outputRef.uri} (${outputRef.lineCount} lines, ${outputRef.sizeBytes} bytes).`;
|
|
91
|
+
}
|
|
92
|
+
return `Task ${status}; output artifact unavailable.`;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function getStatus(raw: SingleResult): TaskResultReceipt["status"] {
|
|
96
|
+
if (raw.paused) return "paused";
|
|
97
|
+
if (raw.aborted) return "aborted";
|
|
98
|
+
if (raw.exitCode === 0 && raw.error) return "merge_failed";
|
|
99
|
+
if (raw.exitCode !== 0 || raw.error) return "failed";
|
|
100
|
+
return "completed";
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
function buildReview(raw: SingleResult): TaskResultReceipt["review"] | undefined {
|
|
104
|
+
const data = raw.extractedToolData;
|
|
105
|
+
if (!data) return undefined;
|
|
106
|
+
const yields = Array.isArray(data.yield) ? data.yield : [];
|
|
107
|
+
const reviewYield = yields
|
|
108
|
+
.map(item => (item && typeof item === "object" ? (item as { data?: unknown }).data : undefined))
|
|
109
|
+
.findLast(item => item && typeof item === "object" && "overall_correctness" in item) as
|
|
110
|
+
| { overall_correctness?: unknown }
|
|
111
|
+
| undefined;
|
|
112
|
+
const rawFindings = Array.isArray(data.report_finding) ? data.report_finding : [];
|
|
113
|
+
const findings = rawFindings.slice(0, 20).map(item => {
|
|
114
|
+
const value = item && typeof item === "object" ? (item as Record<string, unknown>) : {};
|
|
115
|
+
const severity =
|
|
116
|
+
typeof value.severity === "string"
|
|
117
|
+
? value.severity
|
|
118
|
+
: typeof value.priority === "string"
|
|
119
|
+
? value.priority
|
|
120
|
+
: undefined;
|
|
121
|
+
const summaryValue = value.summary ?? value.title ?? value.message ?? value.body ?? "finding";
|
|
122
|
+
return { severity, summary: truncateText(String(summaryValue), 200) ?? "finding" };
|
|
123
|
+
});
|
|
124
|
+
if (!reviewYield && findings.length === 0) return undefined;
|
|
125
|
+
return {
|
|
126
|
+
overallCorrectness:
|
|
127
|
+
typeof reviewYield?.overall_correctness === "string" ? reviewYield.overall_correctness : undefined,
|
|
128
|
+
findingCount: rawFindings.length,
|
|
129
|
+
findings: findings.length > 0 ? findings : undefined,
|
|
130
|
+
};
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
function hasReviewFindings(raw: SingleResult): boolean {
|
|
134
|
+
const findings = raw.extractedToolData?.report_finding;
|
|
135
|
+
return Array.isArray(findings) && findings.length > 0;
|
|
136
|
+
}
|
|
137
|
+
|
|
138
|
+
function hasNonEmptyPreview(raw: SingleResult): boolean {
|
|
139
|
+
return Boolean((raw.output.trim() || raw.stderr.trim()).trim());
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/**
|
|
143
|
+
* Heuristic task ROI signal built only from receipt-safe accounting fields.
|
|
144
|
+
* Advisory only: these flags never change task success/failure semantics.
|
|
145
|
+
*/
|
|
146
|
+
export function buildTaskRoi(raw: SingleResult): TaskRoi {
|
|
147
|
+
const outputBytes = raw.outputMeta?.byteSize ?? (raw.outputMeta ? Buffer.byteLength(raw.output, "utf8") : undefined);
|
|
148
|
+
const outputLines = raw.outputMeta?.lineCount;
|
|
149
|
+
const producedChanges =
|
|
150
|
+
raw.producedChanges ??
|
|
151
|
+
Boolean(raw.branchName || (Array.isArray(raw.nestedPatches) && raw.nestedPatches.length > 0));
|
|
152
|
+
const status = getStatus(raw);
|
|
153
|
+
const terminal = status !== "paused" && !raw.aborted;
|
|
154
|
+
const materialContribution = Boolean(
|
|
155
|
+
producedChanges ||
|
|
156
|
+
(outputBytes !== undefined && outputBytes > 0) ||
|
|
157
|
+
hasReviewFindings(raw) ||
|
|
158
|
+
(status === "completed" && raw.tokens > 0 && hasNonEmptyPreview(raw)),
|
|
159
|
+
);
|
|
160
|
+
const lowRoi = terminal && raw.tokens > 0 && !materialContribution;
|
|
161
|
+
return {
|
|
162
|
+
tokens: raw.tokens,
|
|
163
|
+
contextTokens: raw.contextTokens,
|
|
164
|
+
clonedTokens: raw.forkContext?.clonedTokens,
|
|
165
|
+
costTotal: raw.usage?.cost.total,
|
|
166
|
+
outputBytes,
|
|
167
|
+
outputLines,
|
|
168
|
+
producedChanges,
|
|
169
|
+
materialContribution,
|
|
170
|
+
lowRoi,
|
|
171
|
+
};
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
export function buildTaskRoiSummary(receipts: readonly TaskResultReceipt[]): TaskToolDetails["roiSummary"] {
|
|
175
|
+
const totalCostTotal = receipts.reduce((total, receipt) => total + (receipt.roi?.costTotal ?? 0), 0);
|
|
176
|
+
const totalClonedTokens = receipts.reduce((total, receipt) => total + (receipt.roi?.clonedTokens ?? 0), 0);
|
|
177
|
+
return {
|
|
178
|
+
childCount: receipts.length,
|
|
179
|
+
totalTokens: receipts.reduce((total, receipt) => total + (receipt.roi?.tokens ?? receipt.tokens), 0),
|
|
180
|
+
totalCostTotal: totalCostTotal > 0 ? totalCostTotal : undefined,
|
|
181
|
+
totalClonedTokens: totalClonedTokens > 0 ? totalClonedTokens : undefined,
|
|
182
|
+
lowRoiChildIds: receipts.filter(receipt => receipt.roi?.lowRoi).map(receipt => receipt.id),
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
export function buildTaskReceipt(raw: SingleResult): TaskResultReceipt {
|
|
187
|
+
const outputRef = raw.outputMeta
|
|
188
|
+
? {
|
|
189
|
+
uri: `agent://${raw.id}`,
|
|
190
|
+
sizeBytes: raw.outputMeta.byteSize ?? Buffer.byteLength(raw.output, "utf8"),
|
|
191
|
+
lineCount: raw.outputMeta.lineCount,
|
|
192
|
+
sha256: raw.outputMeta.sha256,
|
|
193
|
+
}
|
|
194
|
+
: undefined;
|
|
195
|
+
const preview = buildSafeSynopsis(raw, outputRef);
|
|
196
|
+
const extractedToolCounts = raw.extractedToolData
|
|
197
|
+
? Object.fromEntries(
|
|
198
|
+
Object.entries(raw.extractedToolData).map(([tool, values]) => [
|
|
199
|
+
tool,
|
|
200
|
+
Array.isArray(values) ? values.length : 0,
|
|
201
|
+
]),
|
|
202
|
+
)
|
|
203
|
+
: undefined;
|
|
204
|
+
return {
|
|
205
|
+
index: raw.index,
|
|
206
|
+
id: raw.id,
|
|
207
|
+
agent: raw.agent,
|
|
208
|
+
agentSource: raw.agentSource,
|
|
209
|
+
task: raw.task,
|
|
210
|
+
assignment: raw.assignment,
|
|
211
|
+
description: raw.description,
|
|
212
|
+
status: getStatus(raw),
|
|
213
|
+
exitCode: raw.exitCode,
|
|
214
|
+
aborted: raw.aborted,
|
|
215
|
+
paused: raw.paused,
|
|
216
|
+
truncated: raw.truncated,
|
|
217
|
+
durationMs: raw.durationMs,
|
|
218
|
+
tokens: raw.tokens,
|
|
219
|
+
contextTokens: raw.contextTokens,
|
|
220
|
+
contextWindow: raw.contextWindow,
|
|
221
|
+
modelOverride: raw.modelOverride,
|
|
222
|
+
usage: raw.usage,
|
|
223
|
+
cost: raw.usage?.cost.total,
|
|
224
|
+
branchName: raw.branchName,
|
|
225
|
+
retryFailure: raw.retryFailure
|
|
226
|
+
? { attempt: raw.retryFailure.attempt, errorSummary: "Retry failure recorded." }
|
|
227
|
+
: undefined,
|
|
228
|
+
errorSummary: raw.error ? "Error recorded." : undefined,
|
|
229
|
+
abortSummary: raw.abortReason ? "Abort reason recorded." : undefined,
|
|
230
|
+
preview,
|
|
231
|
+
previewTruncated: false,
|
|
232
|
+
outputRef,
|
|
233
|
+
outputUnavailable: outputRef ? undefined : true,
|
|
234
|
+
review: buildReview(raw),
|
|
235
|
+
extractedToolCounts,
|
|
236
|
+
forkContext: raw.forkContext,
|
|
237
|
+
roi: buildTaskRoi(raw),
|
|
238
|
+
};
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
/**
|
|
242
|
+
* Raw, pre-sanitization task details: the internal shape produced during task
|
|
243
|
+
* execution, where `results` are full `SingleResult` objects. The public
|
|
244
|
+
* `TaskToolDetails` exposes only receipts.
|
|
245
|
+
*/
|
|
246
|
+
export interface RawTaskToolDetails {
|
|
247
|
+
projectAgentsDir: string | null;
|
|
248
|
+
results: SingleResult[];
|
|
249
|
+
totalDurationMs: number;
|
|
250
|
+
usage?: TaskToolDetails["usage"];
|
|
251
|
+
async?: TaskToolDetails["async"];
|
|
252
|
+
forkContextClonedTokens?: number;
|
|
253
|
+
roiSummary?: TaskToolDetails["roiSummary"];
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/** Central converter from raw task details to receipt-only public details. */
|
|
257
|
+
export function sanitizeTaskToolDetails(raw: RawTaskToolDetails): TaskToolDetails {
|
|
258
|
+
return {
|
|
259
|
+
projectAgentsDir: raw.projectAgentsDir,
|
|
260
|
+
results: raw.results.map(buildTaskReceipt),
|
|
261
|
+
totalDurationMs: raw.totalDurationMs,
|
|
262
|
+
usage: raw.usage,
|
|
263
|
+
forkContextClonedTokens: raw.forkContextClonedTokens,
|
|
264
|
+
roiSummary: raw.roiSummary ?? buildTaskRoiSummary(raw.results.map(buildTaskReceipt)),
|
|
265
|
+
async: raw.async,
|
|
266
|
+
};
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
export function findRawTaskLeakKeys(value: unknown): string[] {
|
|
270
|
+
const found = new Set<string>();
|
|
271
|
+
const seen = new WeakSet<object>();
|
|
272
|
+
const visit = (current: unknown) => {
|
|
273
|
+
if (!current || typeof current !== "object") return;
|
|
274
|
+
if (seen.has(current)) return;
|
|
275
|
+
seen.add(current);
|
|
276
|
+
if (Array.isArray(current)) {
|
|
277
|
+
for (const item of current) visit(item);
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
280
|
+
for (const [key, child] of Object.entries(current)) {
|
|
281
|
+
// Banned keys only leak when they carry text or structure. A numeric
|
|
282
|
+
// value (e.g. the `output` token count on a canonical `Usage` record,
|
|
283
|
+
// whose shape is `input/output/cacheRead/cacheWrite/totalTokens`) is safe.
|
|
284
|
+
if (BANNED_RAW_TASK_KEYS.has(key) && typeof child !== "number") found.add(key);
|
|
285
|
+
visit(child);
|
|
286
|
+
}
|
|
287
|
+
};
|
|
288
|
+
visit(value);
|
|
289
|
+
return [...found].sort();
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
export function assertNoRawTaskFields(value: unknown, surface: string): void {
|
|
293
|
+
const keys = findRawTaskLeakKeys(value);
|
|
294
|
+
if (keys.length > 0) {
|
|
295
|
+
throw new Error(`${surface} contains raw task fields: ${keys.join(", ")}`);
|
|
296
|
+
}
|
|
297
|
+
}
|
package/src/task/render.ts
CHANGED
|
@@ -6,12 +6,13 @@
|
|
|
6
6
|
*/
|
|
7
7
|
import path from "node:path";
|
|
8
8
|
import type { Component } from "@gajae-code/tui";
|
|
9
|
-
import {
|
|
9
|
+
import { Text } from "@gajae-code/tui";
|
|
10
10
|
import { formatNumber } from "@gajae-code/utils";
|
|
11
11
|
import type { RenderResultOptions } from "../extensibility/custom-tools/types";
|
|
12
12
|
import type { Theme } from "../modes/theme/theme";
|
|
13
13
|
import {
|
|
14
14
|
formatBadge,
|
|
15
|
+
formatBytes,
|
|
15
16
|
formatDuration,
|
|
16
17
|
formatMoreItems,
|
|
17
18
|
formatStatusIcon,
|
|
@@ -27,8 +28,9 @@ import {
|
|
|
27
28
|
type SubmitReviewDetails,
|
|
28
29
|
} from "../tools/review";
|
|
29
30
|
import { Ellipsis, Hasher, type RenderCache, renderStatusLine } from "../tui";
|
|
31
|
+
import type { TaskResultReceipt } from "./receipt";
|
|
30
32
|
import { subprocessToolRegistry } from "./subprocess-tool-registry";
|
|
31
|
-
import type { AgentProgress,
|
|
33
|
+
import type { AgentProgress, TaskParams, TaskToolDetails } from "./types";
|
|
32
34
|
|
|
33
35
|
/**
|
|
34
36
|
* Get status icon for agent state.
|
|
@@ -47,6 +49,8 @@ function getStatusIcon(status: AgentProgress["status"], theme: Theme, spinnerFra
|
|
|
47
49
|
return formatStatusIcon("error", theme);
|
|
48
50
|
case "aborted":
|
|
49
51
|
return formatStatusIcon("aborted", theme);
|
|
52
|
+
case "paused":
|
|
53
|
+
return formatStatusIcon("pending", theme);
|
|
50
54
|
}
|
|
51
55
|
}
|
|
52
56
|
|
|
@@ -137,21 +141,6 @@ function formatTaskId(id: string): string {
|
|
|
137
141
|
return `${indices} ${labels}`;
|
|
138
142
|
}
|
|
139
143
|
|
|
140
|
-
const MISSING_YIELD_WARNING_PREFIX = "SYSTEM WARNING: Subagent exited without calling yield tool";
|
|
141
|
-
|
|
142
|
-
function extractMissingYieldWarning(output: string): { warning?: string; rest: string } {
|
|
143
|
-
const lines = output.split("\n");
|
|
144
|
-
const firstLine = lines[0]?.trim() ?? "";
|
|
145
|
-
if (!firstLine.startsWith(MISSING_YIELD_WARNING_PREFIX)) {
|
|
146
|
-
return { rest: output };
|
|
147
|
-
}
|
|
148
|
-
const rest = lines
|
|
149
|
-
.slice(1)
|
|
150
|
-
.join("\n")
|
|
151
|
-
.replace(/^\s*\n+/, "");
|
|
152
|
-
return { warning: firstLine, rest };
|
|
153
|
-
}
|
|
154
|
-
|
|
155
144
|
function buildTreePrefix(ancestors: boolean[], theme: Theme): string {
|
|
156
145
|
return ancestors.map(hasNext => (hasNext ? `${theme.tree.vertical} ` : " ")).join("");
|
|
157
146
|
}
|
|
@@ -611,9 +600,10 @@ function renderAgentProgress(
|
|
|
611
600
|
if (progress.retryState && progress.status === "running") {
|
|
612
601
|
const remainingMs = Math.max(0, progress.retryState.startedAtMs + progress.retryState.delayMs - Date.now());
|
|
613
602
|
const waitLabel = remainingMs > 0 ? `in ${formatDuration(remainingMs)}` : "now";
|
|
614
|
-
const
|
|
615
|
-
`
|
|
616
|
-
|
|
603
|
+
const attemptLabel = progress.retryState.unbounded
|
|
604
|
+
? `attempt ${progress.retryState.attempt}`
|
|
605
|
+
: `${progress.retryState.attempt}/${progress.retryState.maxAttempts}`;
|
|
606
|
+
const summary = `retrying ${attemptLabel} ${waitLabel}: ${truncateToWidth(replaceTabs(progress.retryState.errorMessage), 60)}`;
|
|
617
607
|
lines.push(`${continuePrefix}${theme.tree.hook} ${theme.fg("warning", summary)}`);
|
|
618
608
|
} else if (progress.retryFailure && progress.status !== "running") {
|
|
619
609
|
const summary = `auto-retry gave up after ${progress.retryFailure.attempt} attempt${
|
|
@@ -801,35 +791,24 @@ function renderFindings(
|
|
|
801
791
|
/**
|
|
802
792
|
* Render final result for a single agent.
|
|
803
793
|
*/
|
|
804
|
-
function renderAgentResult(result:
|
|
794
|
+
function renderAgentResult(result: TaskResultReceipt, isLast: boolean, expanded: boolean, theme: Theme): string[] {
|
|
805
795
|
const lines: string[] = [];
|
|
806
796
|
const prefix = isLast ? theme.fg("dim", theme.tree.last) : theme.fg("dim", theme.tree.branch);
|
|
807
797
|
const continuePrefix = isLast ? " " : `${theme.fg("dim", theme.tree.vertical)} `;
|
|
808
798
|
|
|
809
|
-
const
|
|
810
|
-
const
|
|
811
|
-
const
|
|
812
|
-
const
|
|
813
|
-
|
|
814
|
-
|
|
815
|
-
|
|
816
|
-
|
|
817
|
-
|
|
818
|
-
: success
|
|
819
|
-
? theme.status.success
|
|
799
|
+
const success = result.status === "completed";
|
|
800
|
+
const mergeFailed = result.status === "merge_failed";
|
|
801
|
+
const aborted = result.status === "aborted";
|
|
802
|
+
const icon = success
|
|
803
|
+
? theme.status.success
|
|
804
|
+
: aborted
|
|
805
|
+
? theme.status.aborted
|
|
806
|
+
: mergeFailed
|
|
807
|
+
? theme.status.warning
|
|
820
808
|
: theme.status.error;
|
|
821
|
-
const iconColor =
|
|
822
|
-
const statusText =
|
|
823
|
-
? "aborted"
|
|
824
|
-
: needsWarning
|
|
825
|
-
? "warning"
|
|
826
|
-
: success
|
|
827
|
-
? "done"
|
|
828
|
-
: mergeFailed
|
|
829
|
-
? "merge failed"
|
|
830
|
-
: "failed";
|
|
809
|
+
const iconColor = success ? "success" : mergeFailed ? "warning" : "error";
|
|
810
|
+
const statusText = mergeFailed ? "merge failed" : success ? "done" : result.status;
|
|
831
811
|
|
|
832
|
-
// Main status line: id: description [status] · stats · ⟨agent⟩
|
|
833
812
|
const description = result.description?.trim();
|
|
834
813
|
const displayId = formatTaskId(result.id);
|
|
835
814
|
const titlePart = description ? `${theme.bold(displayId)}: ${description}` : displayId;
|
|
@@ -844,121 +823,62 @@ function renderAgentResult(result: SingleResult, isLast: boolean, expanded: bool
|
|
|
844
823
|
tokens: result.tokens,
|
|
845
824
|
contextTokens: result.contextTokens,
|
|
846
825
|
contextWindow: result.contextWindow,
|
|
847
|
-
cost: result.usage?.cost.total ?? 0,
|
|
826
|
+
cost: result.cost ?? result.usage?.cost.total ?? 0,
|
|
848
827
|
},
|
|
849
828
|
theme,
|
|
850
829
|
);
|
|
851
830
|
statusLine += `${theme.sep.dot}${theme.fg("dim", formatDuration(result.durationMs))}`;
|
|
852
|
-
|
|
853
|
-
if (result.truncated) {
|
|
831
|
+
if (result.truncated || result.previewTruncated) {
|
|
854
832
|
statusLine += ` ${theme.fg("warning", "[truncated]")}`;
|
|
855
833
|
}
|
|
856
|
-
|
|
857
834
|
lines.push(statusLine);
|
|
858
835
|
|
|
859
836
|
lines.push(...renderTaskSection(result.assignment ?? result.task, continuePrefix, expanded, theme));
|
|
860
837
|
|
|
861
|
-
if (
|
|
862
|
-
|
|
863
|
-
`${continuePrefix}${theme.fg("
|
|
864
|
-
|
|
865
|
-
|
|
866
|
-
|
|
867
|
-
|
|
868
|
-
|
|
869
|
-
|
|
870
|
-
|
|
871
|
-
const reviewData = completeData
|
|
872
|
-
?.map(c => c.data as SubmitReviewDetails)
|
|
873
|
-
.filter(d => d && typeof d === "object" && "overall_correctness" in d);
|
|
874
|
-
const submitReviewData = reviewData && reviewData.length > 0 ? reviewData : undefined;
|
|
875
|
-
|
|
876
|
-
if (submitReviewData && submitReviewData.length > 0) {
|
|
877
|
-
// Use combined review renderer
|
|
878
|
-
const summary = submitReviewData[submitReviewData.length - 1];
|
|
879
|
-
const findings = reportFindingData;
|
|
880
|
-
lines.push(...renderReviewResult(summary, findings, continuePrefix, expanded, theme));
|
|
881
|
-
return lines;
|
|
882
|
-
}
|
|
883
|
-
if (reportFindingData.length > 0) {
|
|
884
|
-
const hasCompleteData = completeData && completeData.length > 0;
|
|
885
|
-
const message = hasCompleteData
|
|
886
|
-
? "Review verdict missing expected fields"
|
|
887
|
-
: "Review incomplete (yield not called)";
|
|
888
|
-
lines.push(`${continuePrefix}${theme.fg("warning", theme.status.warning)} ${theme.fg("dim", message)}`);
|
|
889
|
-
lines.push(`${continuePrefix}${formatFindingSummary(reportFindingData, theme)}`);
|
|
890
|
-
lines.push(...renderFindings(reportFindingData, continuePrefix, expanded, theme));
|
|
891
|
-
return lines;
|
|
892
|
-
}
|
|
893
|
-
|
|
894
|
-
// Check for extracted tool data with custom renderers (skip review tools)
|
|
895
|
-
let hasCustomRendering = false;
|
|
896
|
-
const deferredToolLines: string[] = [];
|
|
897
|
-
if (result.extractedToolData) {
|
|
898
|
-
for (const [toolName, dataArray] of Object.entries(result.extractedToolData)) {
|
|
899
|
-
// Skip review tools - handled above
|
|
900
|
-
if (toolName === "yield" || toolName === "report_finding") continue;
|
|
901
|
-
|
|
902
|
-
const handler = subprocessToolRegistry.getHandler(toolName);
|
|
903
|
-
if (handler?.renderFinal && (dataArray as unknown[]).length > 0) {
|
|
904
|
-
const isTaskTool = toolName === "task";
|
|
905
|
-
const component = handler.renderFinal(dataArray as unknown[], theme, expanded);
|
|
906
|
-
const target = isTaskTool ? deferredToolLines : lines;
|
|
907
|
-
if (!isTaskTool) {
|
|
908
|
-
hasCustomRendering = true;
|
|
909
|
-
target.push(`${continuePrefix}${theme.fg("dim", `Tool: ${toolName}`)}`);
|
|
910
|
-
}
|
|
911
|
-
if (component instanceof Text) {
|
|
912
|
-
// Prefix each line with continuePrefix
|
|
913
|
-
const text = component.getText();
|
|
914
|
-
for (const line of text.split("\n")) {
|
|
915
|
-
target.push(`${continuePrefix}${line}`);
|
|
916
|
-
}
|
|
917
|
-
} else if (component instanceof Container) {
|
|
918
|
-
// For containers, render each child
|
|
919
|
-
for (const child of (component as Container).children) {
|
|
920
|
-
if (child instanceof Text) {
|
|
921
|
-
target.push(`${continuePrefix}${child.getText()}`);
|
|
922
|
-
}
|
|
923
|
-
}
|
|
838
|
+
if (result.review) {
|
|
839
|
+
if (result.review.overallCorrectness) {
|
|
840
|
+
lines.push(`${continuePrefix}${theme.fg("dim", `Review: ${result.review.overallCorrectness}`)}`);
|
|
841
|
+
}
|
|
842
|
+
if (result.review.findingCount > 0) {
|
|
843
|
+
lines.push(`${continuePrefix}${theme.fg("dim", `${result.review.findingCount} findings`)}`);
|
|
844
|
+
if (expanded && result.review.findings) {
|
|
845
|
+
for (const finding of result.review.findings) {
|
|
846
|
+
const severity = finding.severity ? `${finding.severity}: ` : "";
|
|
847
|
+
lines.push(`${continuePrefix}${theme.fg("dim", `- ${severity}${finding.summary}`)}`);
|
|
924
848
|
}
|
|
925
849
|
}
|
|
926
850
|
}
|
|
851
|
+
} else {
|
|
852
|
+
lines.push(...renderOutputSection(result.preview, continuePrefix, expanded, theme, 3, 12));
|
|
853
|
+
}
|
|
854
|
+
if (result.roi?.lowRoi) {
|
|
855
|
+
lines.push(`${continuePrefix}${theme.fg("warning", "low ROI: produced no material contribution")}`);
|
|
927
856
|
}
|
|
928
857
|
|
|
929
|
-
if (
|
|
858
|
+
if (result.outputRef) {
|
|
930
859
|
lines.push(
|
|
931
|
-
`${continuePrefix}${theme.fg(
|
|
860
|
+
`${continuePrefix}${theme.fg(
|
|
932
861
|
"dim",
|
|
933
|
-
|
|
862
|
+
`Output: ${result.outputRef.uri} (${formatBytes(result.outputRef.sizeBytes)}, ${result.outputRef.lineCount} lines)`,
|
|
934
863
|
)}`,
|
|
935
864
|
);
|
|
865
|
+
} else if (result.outputUnavailable) {
|
|
866
|
+
lines.push(`${continuePrefix}${theme.fg("dim", "Output artifact unavailable")}`);
|
|
936
867
|
}
|
|
937
868
|
|
|
938
|
-
|
|
939
|
-
|
|
869
|
+
if (result.branchName && success) {
|
|
870
|
+
lines.push(`${continuePrefix}${theme.fg("dim", `Branch: ${result.branchName}`)}`);
|
|
871
|
+
}
|
|
872
|
+
if (result.abortSummary) {
|
|
940
873
|
lines.push(
|
|
941
|
-
|
|
874
|
+
`${continuePrefix}${theme.fg("error", theme.status.aborted)} ${theme.fg("dim", truncateToWidth(replaceTabs(result.abortSummary), 80))}`,
|
|
942
875
|
);
|
|
943
876
|
}
|
|
944
|
-
|
|
945
|
-
if (deferredToolLines.length > 0) {
|
|
946
|
-
lines.push(...deferredToolLines);
|
|
947
|
-
}
|
|
948
|
-
|
|
949
|
-
if (result.patchPath && !aborted && result.exitCode === 0) {
|
|
950
|
-
lines.push(`${continuePrefix}${theme.fg("dim", `Patch: ${result.patchPath}`)}`);
|
|
951
|
-
} else if (result.branchName && !aborted && result.exitCode === 0) {
|
|
952
|
-
lines.push(`${continuePrefix}${theme.fg("dim", `Branch: ${result.branchName}`)}`);
|
|
953
|
-
}
|
|
954
|
-
|
|
955
|
-
// Error message
|
|
956
|
-
if (result.error && (!success || mergeFailed) && (!aborted || result.error !== result.abortReason)) {
|
|
877
|
+
if (result.errorSummary && (!success || mergeFailed)) {
|
|
957
878
|
lines.push(
|
|
958
|
-
`${continuePrefix}${theme.fg(mergeFailed ? "warning" : "error", truncateToWidth(replaceTabs(result.
|
|
879
|
+
`${continuePrefix}${theme.fg(mergeFailed ? "warning" : "error", truncateToWidth(replaceTabs(result.errorSummary), 70))}`,
|
|
959
880
|
);
|
|
960
881
|
}
|
|
961
|
-
|
|
962
882
|
return lines;
|
|
963
883
|
}
|
|
964
884
|
|
|
@@ -1006,9 +926,9 @@ export function renderResult(
|
|
|
1006
926
|
lines.push(...renderAgentResult(res, isLast, expanded, theme));
|
|
1007
927
|
});
|
|
1008
928
|
|
|
1009
|
-
const abortedCount = details.results.filter(r => r.aborted).length;
|
|
1010
|
-
const mergeFailedCount = details.results.filter(r =>
|
|
1011
|
-
const successCount = details.results.filter(r =>
|
|
929
|
+
const abortedCount = details.results.filter(r => r.status === "aborted").length;
|
|
930
|
+
const mergeFailedCount = details.results.filter(r => r.status === "merge_failed").length;
|
|
931
|
+
const successCount = details.results.filter(r => r.status === "completed").length;
|
|
1012
932
|
const failCount = details.results.length - successCount - mergeFailedCount - abortedCount;
|
|
1013
933
|
let summary = `${theme.fg("dim", "Total:")} `;
|
|
1014
934
|
if (abortedCount > 0) {
|