@gajae-code/coding-agent 0.12.0 → 0.12.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 +82 -1
- package/dist/types/async/job-manager.d.ts +17 -3
- package/dist/types/config/settings-schema.d.ts +54 -0
- 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-runtime.d.ts +18 -0
- 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 +31 -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/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/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 +4 -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 +11 -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 +38 -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 +8 -1
- 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 +3 -1
- package/dist/types/task/provider-retry-status.d.ts +8 -0
- package/dist/types/task/receipt.d.ts +7 -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 +4 -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/generate-sdk-operation-inventory.ts +3 -0
- package/scripts/resident-memory-bench.ts +1341 -0
- package/scripts/run-acp-conformance.ts +285 -0
- package/src/async/job-manager.ts +78 -20
- 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 +51 -0
- package/src/coordinator-mcp/question-gate-codec.ts +1 -1
- package/src/coordinator-mcp/server.ts +5 -12
- package/src/defaults/gjc/skills/deep-interview/SKILL.md +1 -0
- package/src/defaults/gjc/skills/ralplan/SKILL.md +19 -16
- package/src/defaults/gjc/skills/team/SKILL.md +2 -0
- package/src/defaults/gjc/skills/ultragoal/SKILL.md +37 -24
- 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/managed-owner-admission.ts +1 -1
- package/src/gjc-runtime/ralplan-runtime.ts +411 -17
- 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-runtime.ts +401 -611
- package/src/gjc-runtime/workflow-manifest.generated.json +8 -99
- package/src/gjc-runtime/workflow-manifest.ts +4 -68
- package/src/internal-urls/docs-index.generated.ts +15 -15
- package/src/modes/DESIGN.md +51 -0
- package/src/modes/acp/acp-agent.ts +298 -186
- package/src/modes/components/gjc-bundle-settings.ts +508 -0
- 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 -14
- package/src/modes/components/transcript-viewer-overlay.ts +99 -24
- package/src/modes/controllers/command-controller.ts +4 -0
- package/src/modes/controllers/extension-ui-controller.ts +7 -0
- package/src/modes/controllers/selector-controller.ts +45 -0
- package/src/modes/runtime-init.ts +3 -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/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 +6 -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 +11 -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 +22 -0
- package/src/sdk/session.ts +88 -9
- package/src/session/agent-session.ts +822 -172
- 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 +44 -6
- package/src/session/internal/managed-session-storage.ts +48 -6
- package/src/session/session-manager.ts +1614 -435
- package/src/session/session-storage.ts +9 -1
- 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 +23 -14
- package/src/task/provider-retry-status.ts +16 -0
- package/src/task/receipt.ts +23 -7
- 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 +4 -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/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");
|