@gajae-code/coding-agent 0.12.0 → 0.12.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +111 -0
- package/dist/types/async/job-manager.d.ts +17 -3
- package/dist/types/config/settings-schema.d.ts +56 -2
- package/dist/types/exa/mcp-client.d.ts +10 -1
- package/dist/types/exec/bash-executor.d.ts +45 -12
- package/dist/types/extensibility/extensions/types.d.ts +16 -2
- package/dist/types/extensibility/gjc-plugins/index.d.ts +12 -2
- package/dist/types/extensibility/gjc-plugins/installer.d.ts +63 -7
- package/dist/types/extensibility/gjc-plugins/lifecycle-reconciliation.d.ts +55 -0
- package/dist/types/extensibility/gjc-plugins/lifecycle.d.ts +64 -0
- package/dist/types/extensibility/gjc-plugins/runtime-quarantine.d.ts +67 -0
- package/dist/types/extensibility/gjc-plugins/session-validation.d.ts +3 -1
- package/dist/types/extensibility/gjc-plugins/types.d.ts +124 -0
- package/dist/types/gjc-runtime/launch-tmux.d.ts +1 -0
- package/dist/types/gjc-runtime/ralplan-review-conflicts.d.ts +114 -0
- package/dist/types/gjc-runtime/ralplan-runtime.d.ts +23 -3
- package/dist/types/gjc-runtime/team-launch.d.ts +1 -1
- package/dist/types/gjc-runtime/team-runtime.d.ts +25 -0
- package/dist/types/gjc-runtime/team-worker-heartbeat.d.ts +43 -0
- package/dist/types/gjc-runtime/tmux-owner-isolation.d.ts +10 -0
- package/dist/types/gjc-runtime/ultragoal-runtime.d.ts +37 -80
- package/dist/types/modes/acp/acp-agent.d.ts +2 -19
- package/dist/types/modes/components/gjc-bundle-settings.d.ts +34 -0
- package/dist/types/modes/components/irc-sidebar.d.ts +16 -0
- package/dist/types/modes/components/notifications-settings-editor.d.ts +1 -0
- package/dist/types/modes/components/session-observer-overlay.d.ts +18 -0
- package/dist/types/modes/components/settings-selector.d.ts +9 -0
- package/dist/types/modes/components/status-line/gh.d.ts +5 -0
- package/dist/types/modes/components/transcript-viewer-overlay.d.ts +18 -1
- package/dist/types/modes/controllers/command-controller.d.ts +1 -1
- package/dist/types/modes/controllers/event-controller.d.ts +1 -1
- package/dist/types/modes/controllers/extension-ui-controller.d.ts +2 -1
- package/dist/types/modes/controllers/selector-controller.d.ts +1 -1
- package/dist/types/modes/interactive-mode.d.ts +9 -0
- package/dist/types/modes/theme/theme.d.ts +3 -1
- package/dist/types/modes/types.d.ts +32 -0
- package/dist/types/reminders/star-reminder.d.ts +3 -13
- package/dist/types/runtime-mcp/manager.d.ts +1 -0
- package/dist/types/sdk/acp/adapter.d.ts +3 -1
- package/dist/types/sdk/broker/transport.d.ts +2 -0
- package/dist/types/sdk/bus/attachment-registry.d.ts +1 -0
- package/dist/types/sdk/bus/chat-daemon-control.d.ts +5 -1
- package/dist/types/sdk/bus/config.d.ts +6 -2
- package/dist/types/sdk/bus/index.d.ts +29 -0
- package/dist/types/sdk/bus/kind-aware-reconciliation.d.ts +8 -1
- package/dist/types/sdk/bus/lifecycle-control-runtime.d.ts +4 -0
- package/dist/types/sdk/bus/reconciliation-store.d.ts +7 -3
- package/dist/types/sdk/bus/rich-draft.d.ts +1 -0
- package/dist/types/sdk/bus/rich-render.d.ts +2 -0
- package/dist/types/sdk/bus/telegram-adoption-intent.d.ts +165 -0
- package/dist/types/sdk/bus/telegram-cli.d.ts +12 -0
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +12 -4
- package/dist/types/sdk/bus/telegram-daemon.d.ts +25 -1
- package/dist/types/sdk/bus/telegram-reference.d.ts +11 -1
- package/dist/types/sdk/bus/threaded-render.d.ts +3 -2
- package/dist/types/sdk/bus/topic-registry.d.ts +11 -1
- package/dist/types/sdk/host/query/revision-store.d.ts +2 -0
- package/dist/types/sdk/host/reverse-leases.d.ts +1 -1
- package/dist/types/sdk/prompt-status.d.ts +23 -3
- package/dist/types/sdk/session.d.ts +6 -0
- package/dist/types/session/agent-session.d.ts +40 -2
- package/dist/types/session/artifacts.d.ts +8 -0
- package/dist/types/session/blob-store.d.ts +57 -4
- package/dist/types/session/internal/managed-session-storage.d.ts +30 -4
- package/dist/types/session/session-manager.d.ts +23 -6
- package/dist/types/session/session-storage.d.ts +4 -0
- package/dist/types/session/streaming-output.d.ts +36 -7
- package/dist/types/setup/credential-import.d.ts +12 -0
- package/dist/types/skill-state/active-state.d.ts +12 -0
- package/dist/types/skill-state/workflow-hud.d.ts +6 -0
- package/dist/types/task/executor.d.ts +3 -2
- package/dist/types/task/index.d.ts +7 -1
- package/dist/types/task/output-manager.d.ts +1 -0
- package/dist/types/task/provider-retry-status.d.ts +8 -0
- package/dist/types/task/receipt.d.ts +9 -1
- package/dist/types/task/types.d.ts +23 -0
- package/dist/types/tools/ask-answer-registry.d.ts +2 -2
- package/dist/types/tools/bash-interactive.d.ts +4 -1
- package/dist/types/tools/bash.d.ts +3 -1
- package/dist/types/tools/image-gen.d.ts +4 -0
- package/dist/types/tools/index.d.ts +6 -0
- package/dist/types/tools/output-meta.d.ts +23 -2
- package/dist/types/tools/path-utils.d.ts +1 -0
- package/dist/types/tools/read.d.ts +0 -6
- package/dist/types/tools/review.d.ts +5 -7
- package/dist/types/tools/subagent.d.ts +2 -0
- package/dist/types/utils/gh.d.ts +13 -0
- package/dist/types/utils/image-resize.d.ts +1 -0
- package/dist/types/web/search/providers/kimi.d.ts +2 -0
- package/dist/types/web/search/providers/searxng.d.ts +7 -0
- package/dist/types/web/search/providers/xai.d.ts +2 -0
- package/package.json +10 -8
- package/scripts/acp-conformance-agent.ts +218 -0
- package/scripts/capture-gjc-bundle-settings.ts +306 -0
- package/scripts/dogfood-ralplan-review-conflicts.ts +272 -0
- package/scripts/generate-sdk-operation-inventory.ts +5 -0
- package/scripts/resident-memory-bench.ts +1341 -0
- package/scripts/run-acp-conformance.ts +290 -0
- package/src/async/job-manager.ts +99 -39
- package/src/cli/fast-help.ts +1 -1
- package/src/cli/plugin-cli.ts +176 -18
- package/src/commands/team.ts +19 -1
- package/src/config/file-lock.ts +11 -2
- package/src/config/settings-schema.ts +53 -2
- package/src/coordinator-mcp/question-gate-codec.ts +1 -1
- package/src/coordinator-mcp/server.ts +5 -12
- package/src/debug/index.ts +42 -17
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +1 -0
- package/src/defaults/gjc/skills/ralplan/SKILL.md +25 -20
- package/src/defaults/gjc/skills/team/SKILL.md +2 -0
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +39 -26
- package/src/defaults/gjc/skills/ultragoal/validation-batch-contracts.md +12 -0
- package/src/defaults/gjc-defaults.ts +4 -4
- package/src/exa/mcp-client.ts +12 -3
- package/src/exec/bash-executor.ts +144 -27
- package/src/extensibility/extensions/runner.ts +15 -0
- package/src/extensibility/extensions/types.ts +18 -1
- package/src/extensibility/gjc-plugins/constrained-hooks.ts +8 -2
- package/src/extensibility/gjc-plugins/index.ts +19 -2
- package/src/extensibility/gjc-plugins/installer.ts +189 -50
- package/src/extensibility/gjc-plugins/lifecycle-reconciliation.ts +199 -0
- package/src/extensibility/gjc-plugins/lifecycle.ts +626 -0
- package/src/extensibility/gjc-plugins/observability.ts +3 -3
- package/src/extensibility/gjc-plugins/prompt-appendix.ts +5 -1
- package/src/extensibility/gjc-plugins/runtime-adapters.ts +12 -2
- package/src/extensibility/gjc-plugins/runtime-quarantine.ts +121 -0
- package/src/extensibility/gjc-plugins/schema.ts +84 -12
- package/src/extensibility/gjc-plugins/session-validation.ts +9 -3
- package/src/extensibility/gjc-plugins/types.ts +141 -0
- package/src/extensibility/gjc-plugins/validation.ts +9 -0
- package/src/gjc-runtime/launch-tmux.ts +25 -6
- package/src/gjc-runtime/launch-worktree.ts +103 -1
- package/src/gjc-runtime/ledger-event-renderer.ts +1 -0
- package/src/gjc-runtime/managed-owner-admission.ts +1 -1
- package/src/gjc-runtime/ralplan-review-conflicts.ts +472 -0
- package/src/gjc-runtime/ralplan-runtime.ts +491 -27
- package/src/gjc-runtime/team-launch.ts +8 -0
- package/src/gjc-runtime/team-runtime.ts +140 -32
- package/src/gjc-runtime/team-worker-heartbeat.ts +149 -0
- package/src/gjc-runtime/tmux-owner-isolation.ts +10 -0
- package/src/gjc-runtime/tmux-sessions.ts +58 -13
- package/src/gjc-runtime/ultragoal-evidence.ts +6 -74
- package/src/gjc-runtime/ultragoal-runtime.ts +635 -612
- package/src/gjc-runtime/workflow-manifest.generated.json +37 -99
- package/src/gjc-runtime/workflow-manifest.ts +21 -70
- package/src/internal-urls/docs-index.generated.ts +16 -16
- package/src/modes/DESIGN.md +104 -0
- package/src/modes/acp/acp-agent.ts +298 -186
- package/src/modes/components/gjc-bundle-settings.ts +508 -0
- package/src/modes/components/irc-sidebar.ts +30 -1
- package/src/modes/components/notifications-settings-editor.ts +12 -1
- package/src/modes/components/oauth-selector.ts +68 -30
- package/src/modes/components/session-observer-overlay.ts +305 -86
- package/src/modes/components/settings-selector.ts +56 -5
- package/src/modes/components/status-line/gh.ts +16 -0
- package/src/modes/components/tool-status-header.ts +3 -15
- package/src/modes/components/transcript-viewer-overlay.ts +99 -24
- package/src/modes/controllers/command-controller.ts +42 -34
- package/src/modes/controllers/event-controller.ts +27 -16
- package/src/modes/controllers/extension-ui-controller.ts +193 -34
- package/src/modes/controllers/selector-controller.ts +160 -22
- package/src/modes/interactive-mode.ts +189 -62
- package/src/modes/jobs-observer.ts +1 -1
- package/src/modes/runtime-init.ts +3 -0
- package/src/modes/theme/theme.ts +11 -9
- package/src/modes/types.ts +88 -0
- package/src/prompts/agent-fragments/ralplan-persistence.md +4 -3
- package/src/prompts/system/eager-todo.md +8 -4
- package/src/prompts/system/system-prompt.md +11 -4
- package/src/prompts/tools/bash.md +5 -5
- package/src/prompts/tools/search-tool-bm25.md +5 -0
- package/src/prompts/tools/task.md +1 -1
- package/src/reminders/star-reminder.ts +4 -42
- package/src/runtime-mcp/manager.ts +19 -4
- package/src/sdk/acp/adapter.ts +22 -6
- package/src/sdk/broker/lifecycle.ts +18 -13
- package/src/sdk/broker/transport.ts +35 -3
- package/src/sdk/bus/attachment-registry.ts +5 -1
- package/src/sdk/bus/chat-daemon-cli.ts +4 -39
- package/src/sdk/bus/chat-daemon-control.ts +7 -3
- package/src/sdk/bus/config.ts +18 -2
- package/src/sdk/bus/index.ts +661 -126
- package/src/sdk/bus/kind-aware-reconciliation.ts +148 -73
- package/src/sdk/bus/lifecycle-commands.ts +4 -1
- package/src/sdk/bus/lifecycle-control-runtime.ts +403 -88
- package/src/sdk/bus/reconciliation-store.ts +95 -16
- package/src/sdk/bus/rich-draft.ts +1 -1
- package/src/sdk/bus/rich-render.ts +2 -2
- package/src/sdk/bus/telegram-adoption-intent.ts +574 -0
- package/src/sdk/bus/telegram-cli.ts +33 -8
- package/src/sdk/bus/telegram-daemon-cli.ts +1 -0
- package/src/sdk/bus/telegram-daemon-contract.ts +12 -4
- package/src/sdk/bus/telegram-daemon.ts +916 -23
- package/src/sdk/bus/telegram-reference.ts +40 -3
- package/src/sdk/bus/threaded-render.ts +48 -3
- package/src/sdk/bus/topic-registry.ts +20 -0
- package/src/sdk/host/query/revision-store.ts +36 -2
- package/src/sdk/host/reverse-leases.ts +44 -7
- package/src/sdk/prompt-status.ts +16 -3
- package/src/sdk/protocol/operation-inventory.generated.json +33 -0
- package/src/sdk/session.ts +89 -9
- package/src/session/agent-session.ts +844 -173
- package/src/session/artifacts.ts +22 -0
- package/src/session/auth-broker-config.ts +10 -3
- package/src/session/blob-store.ts +915 -24
- package/src/session/internal/managed-session-scope.ts +200 -111
- package/src/session/internal/managed-session-storage.ts +492 -62
- package/src/session/session-manager.ts +1614 -435
- package/src/session/session-storage.ts +38 -45
- package/src/session/streaming-output.ts +238 -68
- package/src/setup/credential-import.ts +75 -13
- package/src/skill-state/active-state.ts +32 -0
- package/src/skill-state/workflow-hud.ts +17 -0
- package/src/skill-state/workflow-mutation-guard.ts +496 -2
- package/src/task/executor.ts +122 -39
- package/src/task/index.ts +280 -45
- package/src/task/output-manager.ts +24 -14
- package/src/task/provider-retry-status.ts +16 -0
- package/src/task/receipt.ts +34 -8
- package/src/task/render.ts +6 -2
- package/src/task/types.ts +108 -0
- package/src/tools/ask-answer-registry.ts +12 -6
- package/src/tools/ask.ts +86 -55
- package/src/tools/ast-edit.ts +1 -0
- package/src/tools/ast-grep.ts +1 -0
- package/src/tools/bash-interactive.ts +8 -3
- package/src/tools/bash.ts +503 -60
- package/src/tools/find.ts +1 -0
- package/src/tools/image-gen.ts +29 -5
- package/src/tools/index.ts +6 -0
- package/src/tools/output-meta.ts +108 -14
- package/src/tools/path-utils.ts +3 -2
- package/src/tools/read.ts +18 -0
- package/src/tools/review.ts +5 -7
- package/src/tools/search.ts +1 -0
- package/src/tools/subagent-render.ts +6 -2
- package/src/tools/subagent.ts +6 -0
- package/src/tools/telegram-send.ts +6 -3
- package/src/utils/gh.ts +39 -0
- package/src/utils/image-resize.ts +3 -0
- package/src/web/search/providers/anthropic.ts +4 -4
- package/src/web/search/providers/kimi.ts +15 -5
- package/src/web/search/providers/searxng.ts +47 -4
- package/src/web/search/providers/xai.ts +7 -2
- package/dist/types/gjc-runtime/ultragoal-pipeline.d.ts +0 -23
- package/src/defaults/gjc/skills/ultragoal/pipeline-validation-contracts.md +0 -30
- package/src/gjc-runtime/ultragoal-pipeline.ts +0 -306
package/src/task/receipt.ts
CHANGED
|
@@ -1,4 +1,9 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
hasCompleteUsageCostBreakdown,
|
|
3
|
+
type ReviewFindingsArtifactRef,
|
|
4
|
+
type SingleResult,
|
|
5
|
+
type TaskToolDetails,
|
|
6
|
+
} from "./types";
|
|
2
7
|
export interface TaskRoi {
|
|
3
8
|
tokens: number;
|
|
4
9
|
contextTokens?: number;
|
|
@@ -29,21 +34,32 @@ export interface TaskResultReceipt {
|
|
|
29
34
|
contextWindow?: number;
|
|
30
35
|
modelOverride?: string | string[];
|
|
31
36
|
modelSubstitutionWarning?: SingleResult["modelSubstitutionWarning"];
|
|
37
|
+
fastMode?: boolean;
|
|
32
38
|
usage?: SingleResult["usage"];
|
|
33
39
|
cost?: number;
|
|
34
40
|
usageCostBreakdownComplete?: true;
|
|
35
41
|
branchName?: string;
|
|
36
42
|
retryFailure?: { attempt: number; errorSummary: string };
|
|
43
|
+
setupFailure?: { summary: string };
|
|
37
44
|
errorSummary?: string;
|
|
38
45
|
abortSummary?: string;
|
|
39
46
|
preview: string;
|
|
40
47
|
previewTruncated: boolean;
|
|
41
|
-
outputRef?: {
|
|
48
|
+
outputRef?: {
|
|
49
|
+
uri: string;
|
|
50
|
+
sizeBytes: number;
|
|
51
|
+
lineCount: number;
|
|
52
|
+
sha256?: string;
|
|
53
|
+
/** Output remains readable for the parent session lifetime (and same-session descendants). */
|
|
54
|
+
durability?: "session";
|
|
55
|
+
};
|
|
42
56
|
outputUnavailable?: boolean;
|
|
43
57
|
review?: {
|
|
44
58
|
overallCorrectness?: string;
|
|
45
59
|
findingCount: number;
|
|
46
60
|
findings?: Array<{ severity?: string; summary: string }>;
|
|
61
|
+
/** Canonical full-fidelity findings; inline summaries are display-only. */
|
|
62
|
+
findingsRef?: ReviewFindingsArtifactRef;
|
|
47
63
|
};
|
|
48
64
|
extractedToolCounts?: Record<string, number>;
|
|
49
65
|
forkContext?: SingleResult["forkContext"];
|
|
@@ -103,6 +119,9 @@ function normalizeReviewFindingSeverity(severity: unknown, priority: unknown): s
|
|
|
103
119
|
|
|
104
120
|
function buildSafeSynopsis(raw: SingleResult, outputRef: TaskResultReceipt["outputRef"]): string {
|
|
105
121
|
const status = getStatus(raw);
|
|
122
|
+
if (raw.setupFailure) {
|
|
123
|
+
return `Task ${status} during setup: ${raw.setupFailure.summary}`;
|
|
124
|
+
}
|
|
106
125
|
if (raw.modelSubstitutionWarning) {
|
|
107
126
|
return `Task ${status}; requested model substituted from ${raw.modelSubstitutionWarning.requested} to ${raw.modelSubstitutionWarning.effective}.`;
|
|
108
127
|
}
|
|
@@ -131,32 +150,34 @@ function getStatus(raw: SingleResult): TaskResultReceipt["status"] {
|
|
|
131
150
|
|
|
132
151
|
function buildReview(raw: SingleResult): TaskResultReceipt["review"] | undefined {
|
|
133
152
|
const data = raw.extractedToolData;
|
|
134
|
-
|
|
135
|
-
const yields = Array.isArray(data
|
|
153
|
+
const findingsRef = raw.reviewFindingsRef;
|
|
154
|
+
const yields = Array.isArray(data?.yield) ? data.yield : [];
|
|
136
155
|
const reviewYield = yields
|
|
137
156
|
.map(item => (item && typeof item === "object" ? (item as { data?: unknown }).data : undefined))
|
|
138
157
|
.findLast(item => item && typeof item === "object" && "overall_correctness" in item) as
|
|
139
158
|
| { overall_correctness?: unknown }
|
|
140
159
|
| undefined;
|
|
141
|
-
const rawFindings = Array.isArray(data
|
|
160
|
+
const rawFindings = Array.isArray(data?.report_finding) ? data.report_finding : [];
|
|
142
161
|
const findings = rawFindings.slice(0, 20).map(item => {
|
|
143
162
|
const value = item && typeof item === "object" ? (item as Record<string, unknown>) : {};
|
|
144
163
|
const severity = normalizeReviewFindingSeverity(value.severity, value.priority);
|
|
145
164
|
const summaryValue = value.summary ?? value.title ?? value.message ?? value.body ?? "finding";
|
|
146
165
|
return { severity, summary: truncateText(String(summaryValue), 200) ?? "finding" };
|
|
147
166
|
});
|
|
148
|
-
if (!reviewYield && findings.length === 0) return undefined;
|
|
167
|
+
if (!reviewYield && findings.length === 0 && !findingsRef) return undefined;
|
|
149
168
|
return {
|
|
150
169
|
overallCorrectness: truncateText(
|
|
151
170
|
typeof reviewYield?.overall_correctness === "string" ? reviewYield.overall_correctness : undefined,
|
|
152
171
|
200,
|
|
153
172
|
),
|
|
154
|
-
findingCount: rawFindings.length,
|
|
173
|
+
findingCount: findingsRef?.findingCount ?? rawFindings.length,
|
|
155
174
|
findings: findings.length > 0 ? findings : undefined,
|
|
175
|
+
findingsRef,
|
|
156
176
|
};
|
|
157
177
|
}
|
|
158
178
|
|
|
159
179
|
function hasReviewFindings(raw: SingleResult): boolean {
|
|
180
|
+
if (raw.reviewFindingsRef) return true;
|
|
160
181
|
const findings = raw.extractedToolData?.report_finding;
|
|
161
182
|
return Array.isArray(findings) && findings.length > 0;
|
|
162
183
|
}
|
|
@@ -210,12 +231,15 @@ export function buildTaskRoiSummary(receipts: readonly TaskResultReceipt[]): Tas
|
|
|
210
231
|
}
|
|
211
232
|
|
|
212
233
|
export function buildTaskReceipt(raw: SingleResult): TaskResultReceipt {
|
|
234
|
+
// Receipts only include outputRef when production code kept outputMeta after a
|
|
235
|
+
// durable write (file-backed session dir or session-lifetime durable root).
|
|
213
236
|
const outputRef = raw.outputMeta
|
|
214
237
|
? {
|
|
215
238
|
uri: `agent://${raw.id}`,
|
|
216
239
|
sizeBytes: raw.outputMeta.byteSize ?? Buffer.byteLength(raw.output, "utf8"),
|
|
217
240
|
lineCount: raw.outputMeta.lineCount,
|
|
218
241
|
sha256: raw.outputMeta.sha256,
|
|
242
|
+
durability: "session" as const,
|
|
219
243
|
}
|
|
220
244
|
: undefined;
|
|
221
245
|
const preview = buildSafeSynopsis(raw, outputRef);
|
|
@@ -251,10 +275,12 @@ export function buildTaskReceipt(raw: SingleResult): TaskResultReceipt {
|
|
|
251
275
|
usageCostBreakdownComplete:
|
|
252
276
|
raw.usageCostBreakdownComplete === true && hasCompleteUsageCostBreakdown(raw.usage) ? true : undefined,
|
|
253
277
|
branchName: raw.branchName,
|
|
278
|
+
fastMode: raw.fastMode,
|
|
254
279
|
retryFailure: raw.retryFailure
|
|
255
280
|
? { attempt: raw.retryFailure.attempt, errorSummary: "Retry failure recorded." }
|
|
256
281
|
: undefined,
|
|
257
|
-
errorSummary: raw.error ? "Error recorded." : undefined,
|
|
282
|
+
errorSummary: raw.setupFailure?.summary ?? (raw.error ? "Error recorded." : undefined),
|
|
283
|
+
setupFailure: raw.setupFailure ? { summary: raw.setupFailure.summary } : undefined,
|
|
258
284
|
abortSummary: raw.abortReason ? "Abort reason recorded." : undefined,
|
|
259
285
|
preview,
|
|
260
286
|
previewTruncated: false,
|
package/src/task/render.ts
CHANGED
|
@@ -561,7 +561,7 @@ function renderAgentProgress(
|
|
|
561
561
|
const description = progress.description?.trim();
|
|
562
562
|
const displayId = formatTaskId(progress.id);
|
|
563
563
|
const titlePart = description ? `${theme.bold(displayId)}: ${description}` : displayId;
|
|
564
|
-
let statusLine = `${prefix} ${theme.fg(iconColor, icon)} ${theme.fg("accent", titlePart)}`;
|
|
564
|
+
let statusLine = `${prefix} ${theme.fg(iconColor, icon)} ${theme.fg("accent", titlePart)}${progress.fastMode && theme.icon.fast ? ` ${theme.icon.fast}` : ""}`;
|
|
565
565
|
|
|
566
566
|
// A provider recovery loop is operationally distinct from normal agent work.
|
|
567
567
|
if (progress.retryState && progress.status === "running") {
|
|
@@ -594,6 +594,10 @@ function renderAgentProgress(
|
|
|
594
594
|
)}`,
|
|
595
595
|
);
|
|
596
596
|
}
|
|
597
|
+
if (progress.setupFailure && progress.status !== "running") {
|
|
598
|
+
const summary = `Setup failure: ${truncateToWidth(replaceTabs(progress.setupFailure.summary), 80)}`;
|
|
599
|
+
lines.push(`${continuePrefix}${theme.tree.hook} ${theme.fg("error", summary)}`);
|
|
600
|
+
}
|
|
597
601
|
|
|
598
602
|
// Current tool (if running) or most recent completed tool
|
|
599
603
|
if (progress.status === "running") {
|
|
@@ -862,7 +866,7 @@ function renderAgentResult(result: TaskResultReceipt, isLast: boolean, expanded:
|
|
|
862
866
|
const description = result.description?.trim();
|
|
863
867
|
const displayId = formatTaskId(result.id);
|
|
864
868
|
const titlePart = description ? `${theme.bold(displayId)}: ${description}` : displayId;
|
|
865
|
-
let statusLine = `${prefix} ${theme.fg(iconColor, icon)} ${theme.fg("accent", titlePart)} ${formatBadge(
|
|
869
|
+
let statusLine = `${prefix} ${theme.fg(iconColor, icon)} ${theme.fg("accent", titlePart)}${result.fastMode && theme.icon.fast ? ` ${theme.icon.fast}` : ""} ${formatBadge(
|
|
866
870
|
statusText,
|
|
867
871
|
iconColor,
|
|
868
872
|
theme,
|
package/src/task/types.ts
CHANGED
|
@@ -212,6 +212,14 @@ export interface ReviewFinding {
|
|
|
212
212
|
line_end: number;
|
|
213
213
|
}
|
|
214
214
|
|
|
215
|
+
/** Durable full-fidelity review findings artifact associated with a task result. */
|
|
216
|
+
export interface ReviewFindingsArtifactRef {
|
|
217
|
+
uri: `artifact://${string}`;
|
|
218
|
+
sizeBytes: number;
|
|
219
|
+
sha256: string;
|
|
220
|
+
findingCount: number;
|
|
221
|
+
}
|
|
222
|
+
|
|
215
223
|
/** Review summary submitted by the reviewer agent */
|
|
216
224
|
export interface ReviewSummary {
|
|
217
225
|
overall_correctness: "correct" | "incorrect";
|
|
@@ -283,6 +291,8 @@ export interface AgentProgress {
|
|
|
283
291
|
durationMs: number;
|
|
284
292
|
modelOverride?: string | string[];
|
|
285
293
|
modelSubstitutionWarning?: ModelSubstitutionWarning;
|
|
294
|
+
/** Whether the resolved subagent model runs under the effective fast service tier. */
|
|
295
|
+
fastMode?: boolean;
|
|
286
296
|
/** Data extracted by registered subprocess tool handlers (keyed by tool name) */
|
|
287
297
|
extractedToolData?: Record<string, unknown[]>;
|
|
288
298
|
/**
|
|
@@ -313,6 +323,8 @@ export interface AgentProgress {
|
|
|
313
323
|
attempt: number;
|
|
314
324
|
errorMessage: string;
|
|
315
325
|
};
|
|
326
|
+
/** Safe diagnostic retained in terminal progress when setup fails before the first LLM request. */
|
|
327
|
+
setupFailure?: SetupFailureSummary;
|
|
316
328
|
/**
|
|
317
329
|
* Snapshot of the most recent `task` tool call's in-flight `TaskToolDetails`,
|
|
318
330
|
* captured from `tool_execution_update`. Lets the parent UI surface live
|
|
@@ -323,6 +335,96 @@ export interface AgentProgress {
|
|
|
323
335
|
inflightTaskDetails?: TaskToolDetails;
|
|
324
336
|
}
|
|
325
337
|
|
|
338
|
+
/** Bounded diagnostic retained when subagent setup fails before an LLM request starts. */
|
|
339
|
+
export interface SetupFailureSummary {
|
|
340
|
+
summary: string;
|
|
341
|
+
}
|
|
342
|
+
|
|
343
|
+
const SETUP_FAILURE_SUMMARY_MAX_CHARS = 280;
|
|
344
|
+
const SETUP_FAILURE_SUMMARY_MAX_BYTES = 1_024;
|
|
345
|
+
const AUTHORIZATION_HEADER_VALUE_PATTERN = /(["']?(?:Proxy-)?Authorization\b["']?\s*:\s*)[^\r\n]*/gi;
|
|
346
|
+
const COOKIE_HEADER_VALUE_PATTERN = /(["']?(?:Set-)?Cookie\b["']?\s*:\s*)[^\r\n]*/gi;
|
|
347
|
+
const URL_CREDENTIAL_PATTERN = /([a-z][a-z0-9+.-]*:\/\/)[^/?#\s:@]+:[^@/?#\s]+@/gi;
|
|
348
|
+
const API_KEY_LABEL_VALUE_PATTERN = /(["']?api\s+key["']?\s*:\s*)(?:"[^"]*"|'[^']*'|[^\s&]+)/gi;
|
|
349
|
+
const SENSITIVE_SETUP_FAILURE_VALUE_PATTERN =
|
|
350
|
+
/(["']?(?:(?:[A-Za-z][A-Za-z0-9]*[_.-])*?)(?:access[_-]?token|refresh[_-]?token|session[_-]?token|id[_-]?token|api[_-]?key|client[_-]?secret|private[_-]?key|signing[_-]?key|secret|password|passwd|pwd|authorization|credential|token)(?:[_.-][A-Za-z0-9]+)*["']?)(\s*[=:]\s*)(?:"[^"]*"|'[^']*'|[^\s&]+)/gi;
|
|
351
|
+
const BARE_PROVIDER_TOKEN_PATTERN =
|
|
352
|
+
/\b(?:gh[pousr]_[A-Za-z0-9_]{20,}|github_pat_[A-Za-z0-9_]{20,}|xox[baprs]-[A-Za-z0-9-]{20,}|sk-(?:proj-)?[A-Za-z0-9_-]{20,}|sk-ant-[A-Za-z0-9_-]{20,}|AIza[A-Za-z0-9_-]{35}|AKIA[A-Z0-9]{16})\b/g;
|
|
353
|
+
const LOCAL_ABSOLUTE_PATH_PATTERN = /(^|[\s("'`=])((?:\/(?!\/)[^\s/:?"'`()[\]{},;<>]+){2,})/g;
|
|
354
|
+
const WINDOWS_ABSOLUTE_PATH_PATTERN =
|
|
355
|
+
/(^|[\s("'`=])([A-Za-z]:\\(?:[^\\/:?"'`()[\]{},;<>\s]+\\)+[^\\/:?"'`()[\]{},;<>\s]+)/g;
|
|
356
|
+
const LOCAL_FILE_URI_PATTERN = /\bfile:\/\/(?:localhost)?(?:\/[^\s/:?"'`()[\]{},;<>]+)+/gi;
|
|
357
|
+
const SENSITIVE_PATH_BASENAME_PATTERN =
|
|
358
|
+
/(?:^|[_.-])(?:access[_-]?token|refresh[_-]?token|session[_-]?token|id[_-]?token|api[_-]?key|client[_-]?secret|private[_-]?key|signing[_-]?key|secrets?|password|passwd|pwd|authorization|credential|token)(?:[_.-]|$)|^(?:\.env(?:\..*)?|credentials?(?:\.[A-Za-z0-9_-]+)?|id_(?:rsa|ed25519)|.+\.(?:pem|p12|pfx|key))$|^(?:sk|pk|rk|gh[opsur]|github_pat|xox[baprs])[_-][A-Za-z0-9_-]+$/i;
|
|
359
|
+
|
|
360
|
+
function redactPathBasename(path: string): string {
|
|
361
|
+
const basename = path.slice(Math.max(path.lastIndexOf("/"), path.lastIndexOf("\\")) + 1);
|
|
362
|
+
return SENSITIVE_PATH_BASENAME_PATTERN.test(basename) ? "[redacted]" : basename;
|
|
363
|
+
}
|
|
364
|
+
|
|
365
|
+
function redactLocalAbsolutePath(_match: string, prefix: string, absolutePath: string): string {
|
|
366
|
+
return `${prefix}<path>/${redactPathBasename(absolutePath)}`;
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
function redactLocalFileUri(uri: string): string {
|
|
370
|
+
return `file://<path>/${redactPathBasename(uri)}`;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
function normalizeSetupFailureText(value: string): string {
|
|
374
|
+
return value
|
|
375
|
+
.normalize("NFKC")
|
|
376
|
+
.replace(/\u001B(?:\[[0-?]*[ -/]*[@-~]|\][^\u0007\u001B]*(?:\u0007|\u001B\\))/g, "")
|
|
377
|
+
.replace(/[\u200B-\u200D\u2060\uFEFF]/g, "")
|
|
378
|
+
.replace(/[\u0000-\u0008\u000B\u000C\u000E-\u001F\u007F-\u009F]/g, "")
|
|
379
|
+
.replace(/\t/g, " ");
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
function capSetupFailureSummary(value: string): string {
|
|
383
|
+
const ellipsis = "…";
|
|
384
|
+
const ellipsisBytes = Buffer.byteLength(ellipsis, "utf8");
|
|
385
|
+
const chunks: string[] = [];
|
|
386
|
+
let chars = 0;
|
|
387
|
+
let bytes = 0;
|
|
388
|
+
for (const codePoint of value) {
|
|
389
|
+
const codePointBytes = Buffer.byteLength(codePoint, "utf8");
|
|
390
|
+
if (chars + 1 > SETUP_FAILURE_SUMMARY_MAX_CHARS || bytes + codePointBytes > SETUP_FAILURE_SUMMARY_MAX_BYTES) {
|
|
391
|
+
while (
|
|
392
|
+
chunks.length > 0 &&
|
|
393
|
+
(chars + 1 > SETUP_FAILURE_SUMMARY_MAX_CHARS || bytes + ellipsisBytes > SETUP_FAILURE_SUMMARY_MAX_BYTES)
|
|
394
|
+
) {
|
|
395
|
+
const removed = chunks.pop()!;
|
|
396
|
+
chars -= 1;
|
|
397
|
+
bytes -= Buffer.byteLength(removed, "utf8");
|
|
398
|
+
}
|
|
399
|
+
return `${chunks.join("")}${ellipsis}`;
|
|
400
|
+
}
|
|
401
|
+
chunks.push(codePoint);
|
|
402
|
+
chars += 1;
|
|
403
|
+
bytes += codePointBytes;
|
|
404
|
+
}
|
|
405
|
+
return chunks.join("");
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
/** Create a bounded diagnostic that preserves a setup failure's cause without exposing credentials or local paths. */
|
|
409
|
+
export function createSetupFailureSummary(error: unknown): SetupFailureSummary {
|
|
410
|
+
const message = normalizeSetupFailureText(error instanceof Error ? error.message : String(error));
|
|
411
|
+
const summary = message
|
|
412
|
+
.replace(AUTHORIZATION_HEADER_VALUE_PATTERN, "$1[redacted]")
|
|
413
|
+
.replace(COOKIE_HEADER_VALUE_PATTERN, "$1[redacted]")
|
|
414
|
+
.replace(URL_CREDENTIAL_PATTERN, "$1[redacted]@")
|
|
415
|
+
.replace(API_KEY_LABEL_VALUE_PATTERN, "$1[redacted]")
|
|
416
|
+
.replace(LOCAL_FILE_URI_PATTERN, redactLocalFileUri)
|
|
417
|
+
.replace(LOCAL_ABSOLUTE_PATH_PATTERN, redactLocalAbsolutePath)
|
|
418
|
+
.replace(WINDOWS_ABSOLUTE_PATH_PATTERN, redactLocalAbsolutePath)
|
|
419
|
+
.replace(SENSITIVE_SETUP_FAILURE_VALUE_PATTERN, "$1$2[redacted]")
|
|
420
|
+
.replace(BARE_PROVIDER_TOKEN_PATTERN, "[redacted]")
|
|
421
|
+
.replace(/\s+/g, " ")
|
|
422
|
+
.trim();
|
|
423
|
+
return {
|
|
424
|
+
summary: capSetupFailureSummary(summary) || "Subagent setup failed.",
|
|
425
|
+
};
|
|
426
|
+
}
|
|
427
|
+
|
|
326
428
|
/** Result from a single agent execution */
|
|
327
429
|
export interface SingleResult {
|
|
328
430
|
index: number;
|
|
@@ -346,7 +448,11 @@ export interface SingleResult {
|
|
|
346
448
|
contextWindow?: number;
|
|
347
449
|
modelOverride?: string | string[];
|
|
348
450
|
modelSubstitutionWarning?: ModelSubstitutionWarning;
|
|
451
|
+
/** Whether the resolved subagent model ran under the effective fast service tier. */
|
|
452
|
+
fastMode?: boolean;
|
|
349
453
|
error?: string;
|
|
454
|
+
/** Safe diagnostic for a failure before the subagent sent its first LLM request. */
|
|
455
|
+
setupFailure?: SetupFailureSummary;
|
|
350
456
|
aborted?: boolean;
|
|
351
457
|
abortReason?: string;
|
|
352
458
|
paused?: boolean;
|
|
@@ -366,6 +472,8 @@ export interface SingleResult {
|
|
|
366
472
|
producedChanges?: boolean;
|
|
367
473
|
/** Data extracted by registered subprocess tool handlers (keyed by tool name) */
|
|
368
474
|
extractedToolData?: Record<string, unknown[]>;
|
|
475
|
+
/** Full wrapper-owned review evidence, kept separate from caller completion data. */
|
|
476
|
+
reviewFindingsRef?: ReviewFindingsArtifactRef;
|
|
369
477
|
/**
|
|
370
478
|
* Terminal retry failure, when the subagent exited because the auto-retry
|
|
371
479
|
* loop gave up (retry-after exceeded the cap, or all attempts exhausted).
|
|
@@ -11,21 +11,27 @@ import { logger } from "@gajae-code/utils";
|
|
|
11
11
|
import type { WorkflowGateEmitter } from "../modes/shared/agent-wire/workflow-gate-broker";
|
|
12
12
|
import type { AskAnswerSource } from "./index";
|
|
13
13
|
|
|
14
|
-
const sources = new Map<string, AskAnswerSource>();
|
|
14
|
+
const sources = new Map<string, AskAnswerSource[]>();
|
|
15
15
|
const workflowGateEmitters = new Map<string, WorkflowGateEmitter>();
|
|
16
16
|
const workflowGateListeners = new Map<string, Set<(emitter: WorkflowGateEmitter | undefined) => void>>();
|
|
17
17
|
|
|
18
|
-
/** Register `source` for `sessionId`. Returns a disposer that
|
|
18
|
+
/** Register `source` for `sessionId`. Returns a disposer that restores the prior source. */
|
|
19
19
|
export function registerAskAnswerSource(sessionId: string, source: AskAnswerSource): () => void {
|
|
20
|
-
sources.
|
|
20
|
+
const stack = sources.get(sessionId) ?? [];
|
|
21
|
+
stack.push(source);
|
|
22
|
+
sources.set(sessionId, stack);
|
|
21
23
|
return () => {
|
|
22
|
-
|
|
24
|
+
const current = sources.get(sessionId);
|
|
25
|
+
if (!current) return;
|
|
26
|
+
const index = current.lastIndexOf(source);
|
|
27
|
+
if (index >= 0) current.splice(index, 1);
|
|
28
|
+
if (current.length === 0) sources.delete(sessionId);
|
|
23
29
|
};
|
|
24
30
|
}
|
|
25
31
|
|
|
26
|
-
/** The answer source for `sessionId`, if one is registered. */
|
|
32
|
+
/** The highest-priority answer source for `sessionId`, if one is registered. */
|
|
27
33
|
export function getAskAnswerSource(sessionId: string): AskAnswerSource | undefined {
|
|
28
|
-
return sources.get(sessionId);
|
|
34
|
+
return sources.get(sessionId)?.at(-1);
|
|
29
35
|
}
|
|
30
36
|
|
|
31
37
|
/** Publish a session's current workflow-gate emitter after mode initialization. */
|
package/src/tools/ask.ts
CHANGED
|
@@ -1281,9 +1281,11 @@ export class AskTool implements AgentTool<AskParametersSchema, AskToolDetails> {
|
|
|
1281
1281
|
// attended TUI asks would route to emitGate() and hang forever waiting on
|
|
1282
1282
|
// a remote responder.
|
|
1283
1283
|
const hasInteractiveUi = context?.hasUI === true && !!context.ui;
|
|
1284
|
-
const
|
|
1285
|
-
|
|
1286
|
-
|
|
1284
|
+
const initialAnswerSource = this.session.getAskAnswerSource?.();
|
|
1285
|
+
const canUseWorkflowGate =
|
|
1286
|
+
!hasInteractiveUi && !initialAnswerSource && gateEmitter?.supportsRemoteGateAnswers() === true;
|
|
1287
|
+
// Headless fallback: an SDK answer source or workflow gate is the non-TUI answer path.
|
|
1288
|
+
if (!hasInteractiveUi && !initialAnswerSource && !canUseWorkflowGate) {
|
|
1287
1289
|
context?.abort();
|
|
1288
1290
|
throw new ToolAbortError("Ask tool requires interactive mode");
|
|
1289
1291
|
}
|
|
@@ -1291,9 +1293,11 @@ export class AskTool implements AgentTool<AskParametersSchema, AskToolDetails> {
|
|
|
1291
1293
|
const extensionUi = context?.ui;
|
|
1292
1294
|
const ui: UIContext = {
|
|
1293
1295
|
select: (prompt, options, dialogOptions) => {
|
|
1294
|
-
if (!extensionUi) throw new ToolAbortError("Ask tool requires interactive mode");
|
|
1295
1296
|
const source = this.session.getAskAnswerSource?.();
|
|
1296
|
-
if (!source)
|
|
1297
|
+
if (!source) {
|
|
1298
|
+
if (!extensionUi) throw new ToolAbortError("Ask tool requires interactive mode");
|
|
1299
|
+
return extensionUi.select(prompt, options, dialogOptions);
|
|
1300
|
+
}
|
|
1297
1301
|
// Race the local UI against a remote answer (e.g. an SDK reply) so asks
|
|
1298
1302
|
// can be answered without local UI interaction. The first valid answer
|
|
1299
1303
|
// wins; the loser is aborted so neither side is left hanging:
|
|
@@ -1322,7 +1326,10 @@ export class AskTool implements AgentTool<AskParametersSchema, AskToolDetails> {
|
|
|
1322
1326
|
: source.awaitAnswer(prompt, options, remoteController.signal)
|
|
1323
1327
|
)
|
|
1324
1328
|
.then((answer): RemoteRaceResult | Promise<RemoteRaceResult> => {
|
|
1325
|
-
if (answer === undefined)
|
|
1329
|
+
if (answer === undefined) {
|
|
1330
|
+
if (!extensionUi) throw new ToolAbortError("Ask was cancelled by the remote client");
|
|
1331
|
+
return new Promise<never>(() => {});
|
|
1332
|
+
}
|
|
1326
1333
|
const receipt = typeof answer === "string" ? legacyAskReceipt(answer) : answer;
|
|
1327
1334
|
if (generation !== remoteGeneration) {
|
|
1328
1335
|
return receipt
|
|
@@ -1375,40 +1382,49 @@ export class AskTool implements AgentTool<AskParametersSchema, AskToolDetails> {
|
|
|
1375
1382
|
}
|
|
1376
1383
|
return { winner: "remote" as const, value: selectedValue, receipt };
|
|
1377
1384
|
})
|
|
1378
|
-
.catch(ignoreRemoteAnswerFailure);
|
|
1379
|
-
|
|
1380
|
-
const local = extensionUi
|
|
1381
|
-
.select(prompt, options, { ...dialogOptions, signal: localController.signal })
|
|
1382
|
-
.then(answer => {
|
|
1383
|
-
if (generation === remoteGeneration) remoteGeneration++;
|
|
1384
|
-
remoteController.abort();
|
|
1385
|
-
return { winner: "local" as const, value: answer };
|
|
1386
|
-
})
|
|
1387
1385
|
.catch(error => {
|
|
1388
|
-
if (
|
|
1389
|
-
|
|
1390
|
-
throw error;
|
|
1386
|
+
if (!extensionUi) throw error;
|
|
1387
|
+
return ignoreRemoteAnswerFailure(error);
|
|
1391
1388
|
});
|
|
1389
|
+
|
|
1390
|
+
const local = extensionUi
|
|
1391
|
+
? extensionUi
|
|
1392
|
+
.select(prompt, options, { ...dialogOptions, signal: localController.signal })
|
|
1393
|
+
.then(answer => {
|
|
1394
|
+
if (generation === remoteGeneration) remoteGeneration++;
|
|
1395
|
+
remoteController.abort();
|
|
1396
|
+
return { winner: "local" as const, value: answer };
|
|
1397
|
+
})
|
|
1398
|
+
.catch(error => {
|
|
1399
|
+
if (generation === remoteGeneration) remoteGeneration++;
|
|
1400
|
+
remoteController.abort();
|
|
1401
|
+
throw error;
|
|
1402
|
+
})
|
|
1403
|
+
: new Promise<never>(() => {});
|
|
1392
1404
|
// The losing selector may reject when aborted after the race already settled;
|
|
1393
1405
|
// swallow that so it is not an unhandled rejection (the race result is unaffected).
|
|
1394
1406
|
void local.catch(() => undefined);
|
|
1395
|
-
return Promise.race([local, remote])
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
|
|
1399
|
-
|
|
1400
|
-
|
|
1401
|
-
|
|
1402
|
-
|
|
1403
|
-
|
|
1404
|
-
|
|
1405
|
-
|
|
1406
|
-
|
|
1407
|
+
return Promise.race([local, remote])
|
|
1408
|
+
.then(async result => {
|
|
1409
|
+
if (result.winner === "remote") {
|
|
1410
|
+
localController.abort();
|
|
1411
|
+
if (result.settlement) await result.receipt.settle(result.settlement);
|
|
1412
|
+
else activeRemoteReceipt = result.receipt;
|
|
1413
|
+
} else {
|
|
1414
|
+
void remote.then(remoteResult =>
|
|
1415
|
+
remoteResult.receipt.settle({ kind: "resolve_without_commit", reason: "aborted" }),
|
|
1416
|
+
);
|
|
1417
|
+
}
|
|
1418
|
+
return result.value;
|
|
1419
|
+
})
|
|
1420
|
+
.finally(() => toolSignal?.removeEventListener("abort", abortRace));
|
|
1407
1421
|
},
|
|
1408
1422
|
editor: (title, prefill, dialogOptions, editorOptions) => {
|
|
1409
|
-
if (!extensionUi) throw new ToolAbortError("Ask tool requires interactive mode");
|
|
1410
1423
|
const source = this.session.getAskAnswerSource?.();
|
|
1411
|
-
if (!source)
|
|
1424
|
+
if (!source) {
|
|
1425
|
+
if (!extensionUi) throw new ToolAbortError("Ask tool requires interactive mode");
|
|
1426
|
+
return extensionUi.editor(title, prefill, dialogOptions, editorOptions);
|
|
1427
|
+
}
|
|
1412
1428
|
// Race the local editor against a remote free-text answer so "Other / type
|
|
1413
1429
|
// your own" custom input can be provided remotely (e.g. a typed Telegram
|
|
1414
1430
|
// reply) instead of blocking on the local-only editor. Mirrors `select`.
|
|
@@ -1439,7 +1455,10 @@ export class AskTool implements AgentTool<AskParametersSchema, AskToolDetails> {
|
|
|
1439
1455
|
: source.awaitAnswer(title, [], remoteController.signal)
|
|
1440
1456
|
)
|
|
1441
1457
|
.then((answer): RemoteRaceResult | Promise<RemoteRaceResult> => {
|
|
1442
|
-
if (answer === undefined)
|
|
1458
|
+
if (answer === undefined) {
|
|
1459
|
+
if (!extensionUi) throw new ToolAbortError("Ask was cancelled by the remote client");
|
|
1460
|
+
return new Promise<never>(() => {});
|
|
1461
|
+
}
|
|
1443
1462
|
const receipt = typeof answer === "string" ? legacyAskReceipt(answer) : answer;
|
|
1444
1463
|
if (generation !== remoteGeneration) {
|
|
1445
1464
|
return receipt
|
|
@@ -1450,31 +1469,43 @@ export class AskTool implements AgentTool<AskParametersSchema, AskToolDetails> {
|
|
|
1450
1469
|
receipt.interaction.kind === "control" ? REMOTE_NAVIGATION_FORWARD : receipt.interaction.value;
|
|
1451
1470
|
return { winner: "remote" as const, value, receipt };
|
|
1452
1471
|
})
|
|
1453
|
-
.catch(ignoreRemoteAnswerFailure);
|
|
1454
|
-
const local = extensionUi
|
|
1455
|
-
.editor(title, prefill, { ...(dialogOptions ?? {}), signal: localController.signal }, editorOptions)
|
|
1456
|
-
.then(answer => {
|
|
1457
|
-
if (generation === remoteGeneration) remoteGeneration++;
|
|
1458
|
-
remoteController.abort();
|
|
1459
|
-
return { winner: "local" as const, value: answer };
|
|
1460
|
-
})
|
|
1461
1472
|
.catch(error => {
|
|
1462
|
-
if (
|
|
1463
|
-
|
|
1464
|
-
throw error;
|
|
1473
|
+
if (!extensionUi) throw error;
|
|
1474
|
+
return ignoreRemoteAnswerFailure(error);
|
|
1465
1475
|
});
|
|
1476
|
+
const local = extensionUi
|
|
1477
|
+
? extensionUi
|
|
1478
|
+
.editor(
|
|
1479
|
+
title,
|
|
1480
|
+
prefill,
|
|
1481
|
+
{ ...(dialogOptions ?? {}), signal: localController.signal },
|
|
1482
|
+
editorOptions,
|
|
1483
|
+
)
|
|
1484
|
+
.then(answer => {
|
|
1485
|
+
if (generation === remoteGeneration) remoteGeneration++;
|
|
1486
|
+
remoteController.abort();
|
|
1487
|
+
return { winner: "local" as const, value: answer };
|
|
1488
|
+
})
|
|
1489
|
+
.catch(error => {
|
|
1490
|
+
if (generation === remoteGeneration) remoteGeneration++;
|
|
1491
|
+
remoteController.abort();
|
|
1492
|
+
throw error;
|
|
1493
|
+
})
|
|
1494
|
+
: new Promise<never>(() => {});
|
|
1466
1495
|
void local.catch(() => undefined);
|
|
1467
|
-
return Promise.race([local, remote])
|
|
1468
|
-
|
|
1469
|
-
|
|
1470
|
-
|
|
1471
|
-
|
|
1472
|
-
|
|
1473
|
-
|
|
1474
|
-
|
|
1475
|
-
|
|
1476
|
-
|
|
1477
|
-
|
|
1496
|
+
return Promise.race([local, remote])
|
|
1497
|
+
.then(result => {
|
|
1498
|
+
if (result.winner === "remote") {
|
|
1499
|
+
activeRemoteReceipt = result.receipt;
|
|
1500
|
+
localController.abort();
|
|
1501
|
+
} else {
|
|
1502
|
+
void remote.then(remoteResult =>
|
|
1503
|
+
remoteResult.receipt.settle({ kind: "resolve_without_commit", reason: "aborted" }),
|
|
1504
|
+
);
|
|
1505
|
+
}
|
|
1506
|
+
return result.value;
|
|
1507
|
+
})
|
|
1508
|
+
.finally(() => toolSignal?.removeEventListener("abort", abortRace));
|
|
1478
1509
|
},
|
|
1479
1510
|
};
|
|
1480
1511
|
|
package/src/tools/ast-edit.ts
CHANGED
|
@@ -205,6 +205,7 @@ export class AstEditTool implements AgentTool<typeof astEditSchema, AstEditToolD
|
|
|
205
205
|
rawPaths: params.paths,
|
|
206
206
|
cwd: this.session.cwd,
|
|
207
207
|
getArtifactsDir: this.session.getArtifactsDir,
|
|
208
|
+
getAuthorizedArtifactsDirs: this.session.getAuthorizedArtifactsDirs,
|
|
208
209
|
internalUrlAction: "rewrite",
|
|
209
210
|
});
|
|
210
211
|
const { searchPath: resolvedSearchPath, scopePath, isDirectory, multiTargets, globFilter } = scope;
|
package/src/tools/ast-grep.ts
CHANGED
|
@@ -152,6 +152,7 @@ export class AstGrepTool implements AgentTool<typeof astGrepSchema, AstGrepToolD
|
|
|
152
152
|
rawPaths: params.paths,
|
|
153
153
|
cwd: this.session.cwd,
|
|
154
154
|
getArtifactsDir: this.session.getArtifactsDir,
|
|
155
|
+
getAuthorizedArtifactsDirs: this.session.getAuthorizedArtifactsDirs,
|
|
155
156
|
internalUrlAction: "search",
|
|
156
157
|
});
|
|
157
158
|
const { searchPath: resolvedSearchPath, scopePath, isDirectory, multiTargets, globFilter } = scope;
|
|
@@ -15,9 +15,9 @@ import type { Terminal as XtermTerminalType } from "@xterm/headless";
|
|
|
15
15
|
import { Settings } from "../config/settings";
|
|
16
16
|
import { NON_INTERACTIVE_ENV } from "../exec/non-interactive-env";
|
|
17
17
|
import type { Theme } from "../modes/theme/theme";
|
|
18
|
-
import { OutputSink, type OutputSummary } from "../session/streaming-output";
|
|
18
|
+
import { OutputSink, type OutputSummary, type TerminalArtifactPublisher } from "../session/streaming-output";
|
|
19
19
|
import { sanitizeWithOptionalSixelPassthrough } from "../utils/sixel";
|
|
20
|
-
import {
|
|
20
|
+
import { resolveBashOutputSinkHeadBytes, resolveBashOutputSinkTailBytes, resolveOutputMaxColumns } from "./output-meta";
|
|
21
21
|
import { formatStatusIcon, replaceTabs } from "./render-utils";
|
|
22
22
|
|
|
23
23
|
export interface BashInteractiveResult extends OutputSummary {
|
|
@@ -293,6 +293,9 @@ export async function runInteractiveBashPty(
|
|
|
293
293
|
env?: Record<string, string>;
|
|
294
294
|
artifactPath?: string;
|
|
295
295
|
artifactId?: string;
|
|
296
|
+
artifactPublisher?: TerminalArtifactPublisher;
|
|
297
|
+
spillThreshold?: number;
|
|
298
|
+
headBytes?: number;
|
|
296
299
|
},
|
|
297
300
|
): Promise<BashInteractiveResult> {
|
|
298
301
|
const settings = await Settings.init();
|
|
@@ -300,7 +303,9 @@ export async function runInteractiveBashPty(
|
|
|
300
303
|
const sink = new OutputSink({
|
|
301
304
|
artifactPath: options.artifactPath,
|
|
302
305
|
artifactId: options.artifactId,
|
|
303
|
-
|
|
306
|
+
artifactPublisher: options.artifactPublisher,
|
|
307
|
+
spillThreshold: options.spillThreshold ?? resolveBashOutputSinkTailBytes(settings),
|
|
308
|
+
headBytes: options.headBytes ?? resolveBashOutputSinkHeadBytes(settings),
|
|
304
309
|
maxColumns: resolveOutputMaxColumns(settings),
|
|
305
310
|
});
|
|
306
311
|
const { default: xterm } = await import("@xterm/headless");
|