@gajae-code/coding-agent 0.18.11 → 0.18.12
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 +293 -0
- package/dist/types/async/job-manager.d.ts +7 -3
- package/dist/types/async/result-formatting.d.ts +2 -0
- package/dist/types/autoresearch/git.d.ts +1 -1
- package/dist/types/capability/fs.d.ts +2 -2
- package/dist/types/cli/accounts-cli.d.ts +2 -2
- package/dist/types/cli/doctor/install-repairs.d.ts +4 -1
- package/dist/types/cli/install-activation.d.ts +10 -4
- package/dist/types/cli/public-command-errors.d.ts +1 -0
- package/dist/types/cli/update-cli.d.ts +14 -1
- package/dist/types/cli-ordinary.d.ts +2 -2
- package/dist/types/commands/accounts.d.ts +2 -1
- package/dist/types/commands/migrate.d.ts +1 -1
- package/dist/types/commands/sdk.d.ts +5 -0
- package/dist/types/commit/changelog/index.d.ts +1 -0
- package/dist/types/config/autorouting-tier-map.d.ts +30 -0
- package/dist/types/config/config-hot-reload-trust.d.ts +12 -0
- package/dist/types/config/config-hot-reload.d.ts +39 -0
- package/dist/types/config/file-lock.d.ts +8 -1
- package/dist/types/config/model-discovery-manager.d.ts +2 -0
- package/dist/types/config/model-profile-activation.d.ts +62 -6
- package/dist/types/config/model-registry.d.ts +56 -5
- package/dist/types/config/model-resolver.d.ts +2 -0
- package/dist/types/config/models-config-schema.d.ts +10 -0
- package/dist/types/config/settings-schema.d.ts +46 -3
- package/dist/types/config/settings.d.ts +33 -1
- package/dist/types/dap/config.d.ts +8 -4
- package/dist/types/debug/system-info.d.ts +6 -1
- package/dist/types/discovery/mcp-compat.d.ts +3 -1
- package/dist/types/edit/modes/patch.d.ts +5 -0
- package/dist/types/edit/modes/replace.d.ts +3 -0
- package/dist/types/exec/bash-executor.d.ts +12 -0
- package/dist/types/gjc-runtime/managed-owner-admission.d.ts +3 -0
- package/dist/types/gjc-runtime/session-state-lock.d.ts +2 -0
- package/dist/types/gjc-runtime/state-runtime.d.ts +0 -2
- package/dist/types/migrate/adapters/codex.d.ts +2 -1
- package/dist/types/migrate/adapters/index.d.ts +10 -1
- package/dist/types/migrate/executor.d.ts +3 -1
- package/dist/types/migrate/types.d.ts +15 -3
- package/dist/types/modes/components/settings-selector.d.ts +6 -0
- package/dist/types/modes/controllers/selector-controller.d.ts +2 -0
- package/dist/types/modes/theme/theme.d.ts +1 -0
- package/dist/types/runtime-mcp/content-limits.d.ts +4 -0
- package/dist/types/runtime-mcp/manager.d.ts +7 -0
- package/dist/types/runtime-mcp/plugin-mcp-name-filter.d.ts +22 -0
- package/dist/types/runtime-mcp/tool-bridge.d.ts +4 -0
- package/dist/types/sdk/broker/broker-exit.d.ts +2 -2
- package/dist/types/sdk/broker/broker.d.ts +7 -1
- package/dist/types/sdk/broker/daemon-entry.d.ts +11 -1
- package/dist/types/sdk/broker/doctor-restart.d.ts +1 -1
- package/dist/types/sdk/broker/ensure.d.ts +136 -7
- package/dist/types/sdk/broker/hop.d.ts +36 -0
- package/dist/types/sdk/broker/lifecycle-ledger.d.ts +18 -10
- package/dist/types/sdk/broker/lock-host-identity.d.ts +5 -0
- package/dist/types/sdk/broker/session-index.d.ts +4 -1
- package/dist/types/sdk/bus/chat-command-policy.d.ts +2 -1
- package/dist/types/sdk/bus/index.d.ts +23 -0
- package/dist/types/sdk/bus/reconciliation-store.d.ts +10 -0
- package/dist/types/sdk/bus/telegram-daemon-contract.d.ts +3 -1
- package/dist/types/sdk/cli/session-cli.d.ts +0 -1
- package/dist/types/sdk/host/session-runtime.d.ts +32 -0
- package/dist/types/sdk/prompt-deadline-flush.d.ts +42 -4
- package/dist/types/sdk/prompt-deadline-manager.d.ts +2 -0
- package/dist/types/sdk/protocol/adapter-validation.d.ts +10 -4
- package/dist/types/sdk/reconciliation-extensions.d.ts +1 -1
- package/dist/types/sdk/session-list.d.ts +1 -1
- package/dist/types/session/agent-session.d.ts +58 -2
- package/dist/types/session/internal/managed-session-scope.d.ts +2 -2
- package/dist/types/session/internal/managed-session-storage.d.ts +1 -1
- package/dist/types/session/internal/native-publish-outcome.d.ts +1 -1
- package/dist/types/session/messages.d.ts +5 -1
- package/dist/types/session/session-manager.d.ts +13 -3
- package/dist/types/session/startup-auth-config.d.ts +24 -2
- package/dist/types/session/streaming-output.d.ts +11 -0
- package/dist/types/session/terminal-abort.d.ts +3 -1
- package/dist/types/session-import/service.d.ts +1 -1
- package/dist/types/skill-state/workflow-mutation-guard.d.ts +7 -3
- package/dist/types/slash-commands/helpers/provider-auth-status.d.ts +8 -0
- package/dist/types/task/executor.d.ts +19 -2
- package/dist/types/tools/ast-edit-write-path.d.ts +10 -0
- package/dist/types/tools/atomic-file-write.d.ts +9 -7
- package/dist/types/tools/bash-allowed-prefixes.d.ts +11 -0
- package/dist/types/tools/descriptors.d.ts +2 -0
- package/dist/types/tools/fetch.d.ts +1 -1
- package/dist/types/tools/index.d.ts +2 -0
- package/dist/types/tools/python.d.ts +1 -1
- package/dist/types/tools/report-issue.d.ts +41 -0
- package/dist/types/tools/subagent.d.ts +23 -0
- package/dist/types/web/scrapers/types.d.ts +8 -1
- package/dist/types/web/search/providers/insane.d.ts +7 -1
- package/dist/types/web/search/providers/searxng.d.ts +5 -0
- package/package.json +8 -8
- package/scripts/build-binary.ts +2 -1
- package/scripts/capture-subagent-compact-panel-showcase.ts +105 -0
- package/scripts/generate-docs-index.ts +8 -1
- package/scripts/generate-sdk-operation-inventory.ts +22 -4
- package/src/async/job-manager.ts +356 -56
- package/src/async/result-formatting.ts +40 -0
- package/src/autoresearch/git.ts +9 -2
- package/src/autoresearch/prompts/prompt-setup.md +1 -1
- package/src/capability/fs.ts +27 -19
- package/src/capability/index.ts +2 -2
- package/src/cli/accounts-cli.ts +176 -8
- package/src/cli/auth-broker-cli.ts +21 -11
- package/src/cli/doctor/install-repairs.ts +35 -5
- package/src/cli/fast-help.ts +1 -1
- package/src/cli/install-activation.ts +47 -4
- package/src/cli/migrate-cli.ts +7 -5
- package/src/cli/public-command-errors.ts +4 -0
- package/src/cli/root-flags.ts +2 -2
- package/src/cli/stats-cli.ts +9 -5
- package/src/cli/update-cli.ts +224 -7
- package/src/cli-ordinary.ts +7 -2
- package/src/commands/accounts.ts +10 -5
- package/src/commands/migrate.ts +3 -3
- package/src/commands/sdk.ts +199 -42
- package/src/commands/ultragoal.ts +16 -8
- package/src/commit/changelog/index.ts +39 -1
- package/src/commit/message.ts +10 -3
- package/src/config/autorouting-tier-map.ts +30 -0
- package/src/config/config-hot-reload-trust.ts +148 -0
- package/src/config/config-hot-reload.ts +734 -0
- package/src/config/file-lock.ts +216 -56
- package/src/config/model-bindings-applier.ts +85 -47
- package/src/config/model-discovery-manager.ts +10 -0
- package/src/config/model-profile-activation.ts +716 -113
- package/src/config/model-registry.ts +1334 -158
- package/src/config/model-resolver.ts +3 -1
- package/src/config/models-config-schema.ts +6 -0
- package/src/config/settings-schema.ts +60 -3
- package/src/config/settings.ts +458 -24
- package/src/coordinator-mcp/policy.ts +26 -1
- package/src/crash/sanitize.ts +4 -0
- package/src/customization/import.ts +3 -1
- package/src/dap/config.ts +31 -11
- package/src/dap/defaults.json +1 -1
- package/src/debug/crash-diagnostics.ts +2 -1
- package/src/debug/report-bundle.ts +19 -0
- package/src/debug/system-info.ts +8 -3
- package/src/defaults/gjc/extensions/grok-cli-vendor/src/shared/base-url.ts +21 -7
- package/src/discovery/agents-md.ts +1 -1
- package/src/discovery/helpers.ts +1 -2
- package/src/discovery/mcp-compat.ts +120 -17
- package/src/edit/apply-patch/index.ts +12 -1
- package/src/edit/index.ts +13 -17
- package/src/edit/modes/patch.ts +187 -8
- package/src/edit/modes/replace.ts +136 -0
- package/src/eval/js/context-manager.ts +29 -3
- package/src/eval/js/worker-entry.ts +51 -18
- package/src/eval/py/executor.ts +14 -4
- package/src/eval/py/runner.py +144 -5
- package/src/exec/bash-executor.ts +81 -4
- package/src/exec/bash-shell-guardian.ts +4 -1
- package/src/exec/bash-shell-supervisor.ts +8 -4
- package/src/exec/isolated-shell.ts +5 -1
- package/src/export/html/index.ts +46 -6
- package/src/extensibility/custom-tools/wrapper.ts +3 -1
- package/src/extensibility/extensions/loader.ts +8 -1
- package/src/extensibility/plugins/marketplace/fetcher.ts +2 -2
- package/src/gjc-runtime/gc-runtime.ts +33 -6
- package/src/gjc-runtime/launch-tmux.ts +7 -2
- package/src/gjc-runtime/launch-worktree.test.ts +148 -0
- package/src/gjc-runtime/launch-worktree.ts +101 -14
- package/src/gjc-runtime/managed-owner-admission.ts +46 -2
- package/src/gjc-runtime/session-resolution.ts +38 -6
- package/src/gjc-runtime/session-state-lock.ts +59 -14
- package/src/gjc-runtime/state-runtime.ts +23 -19
- package/src/hooks/native-skill-hook.ts +14 -11
- package/src/internal-urls/docs-index.generated.ts +14 -13
- package/src/internal-urls/local-protocol.ts +142 -8
- package/src/lsp/index.ts +29 -0
- package/src/lsp/workspace-path.ts +23 -0
- package/src/migrate/action-planner.ts +57 -0
- package/src/migrate/adapters/claude-code.ts +23 -4
- package/src/migrate/adapters/codex.ts +22 -4
- package/src/migrate/adapters/index.ts +22 -4
- package/src/migrate/adapters/opencode.ts +6 -1
- package/src/migrate/executor.ts +84 -7
- package/src/migrate/report.ts +19 -2
- package/src/migrate/types.ts +14 -4
- package/src/modes/DESIGN.md +51 -0
- package/src/modes/acp/permission-mode.ts +18 -1
- package/src/modes/components/assistant-message.ts +55 -1
- package/src/modes/components/settings-selector.ts +103 -37
- package/src/modes/controllers/command-controller.ts +38 -2
- package/src/modes/controllers/plan-mode-controller.ts +17 -7
- package/src/modes/controllers/selector-controller.ts +62 -6
- package/src/modes/interactive-mode.ts +68 -0
- package/src/modes/theme/theme.ts +15 -0
- package/src/prompts/tools/debug.md +1 -1
- package/src/prompts/tools/read.md +1 -1
- package/src/prompts/tools/report-issue.md +13 -0
- package/src/prompts/tools/task.md +1 -1
- package/src/runtime-credential-selector.ts +2 -2
- package/src/runtime-mcp/content-limits.ts +7 -0
- package/src/runtime-mcp/manager-pool.test.ts +5 -4
- package/src/runtime-mcp/manager.ts +32 -0
- package/src/runtime-mcp/oauth-flow.ts +32 -6
- package/src/runtime-mcp/plugin-mcp-name-filter.ts +62 -0
- package/src/runtime-mcp/render.ts +16 -1
- package/src/runtime-mcp/tool-bridge.ts +126 -17
- package/src/sdk/broker/broker-exit.ts +8 -5
- package/src/sdk/broker/broker.ts +342 -82
- package/src/sdk/broker/daemon-entry.ts +338 -116
- package/src/sdk/broker/doctor-restart.ts +2 -1
- package/src/sdk/broker/ensure.ts +1143 -265
- package/src/sdk/broker/hop.ts +274 -0
- package/src/sdk/broker/lifecycle-ledger.ts +35 -11
- package/src/sdk/broker/lock-host-identity.ts +29 -0
- package/src/sdk/broker/session-index.ts +62 -12
- package/src/sdk/bus/chat-command-policy.ts +16 -3
- package/src/sdk/bus/index.ts +52 -21
- package/src/sdk/bus/reconciliation-store.ts +201 -8
- package/src/sdk/bus/telegram-daemon-contract.ts +3 -1
- package/src/sdk/cli/session-cli.ts +21 -6
- package/src/sdk/host/session-runtime.test.ts +118 -23
- package/src/sdk/host/session-runtime.ts +352 -47
- package/src/sdk/lifecycle/service.ts +1 -0
- package/src/sdk/prompt-deadline-flush.ts +78 -5
- package/src/sdk/prompt-deadline-manager.ts +68 -14
- package/src/sdk/protocol/adapter-validation.ts +53 -11
- package/src/sdk/protocol/operation-inventory.generated.json +101 -2
- package/src/sdk/reconciliation-extensions.ts +1 -0
- package/src/sdk/session-list.ts +1 -0
- package/src/sdk/session.ts +114 -61
- package/src/session/agent-session.ts +1043 -81
- package/src/session/internal/managed-session-scope.ts +126 -39
- package/src/session/internal/managed-session-storage.ts +14 -11
- package/src/session/internal/native-publish-outcome.ts +5 -1
- package/src/session/messages.ts +47 -6
- package/src/session/session-manager.ts +236 -14
- package/src/session/startup-auth-config.ts +116 -8
- package/src/session/streaming-output.ts +262 -4
- package/src/session/terminal-abort.ts +14 -2
- package/src/session-import/service.ts +1 -0
- package/src/skill-state/workflow-mutation-guard.ts +491 -32
- package/src/slash-commands/builtin-registry.ts +15 -3
- package/src/slash-commands/helpers/credential-switch.ts +10 -5
- package/src/slash-commands/helpers/provider-auth-status.ts +456 -0
- package/src/task/executor.ts +103 -12
- package/src/task/index.ts +389 -175
- package/src/tools/ast-edit-write-path.ts +64 -0
- package/src/tools/ast-edit.ts +18 -1
- package/src/tools/atomic-file-write.ts +46 -15
- package/src/tools/auto-generated-guard.ts +3 -0
- package/src/tools/bash-allowed-prefixes.ts +153 -5
- package/src/tools/bash-interactive.ts +14 -2
- package/src/tools/bash.ts +14 -0
- package/src/tools/debug.ts +7 -6
- package/src/tools/descriptors.test.ts +44 -0
- package/src/tools/descriptors.ts +34 -2
- package/src/tools/fetch.ts +3 -2
- package/src/tools/index.ts +2 -0
- package/src/tools/output-meta.ts +23 -2
- package/src/tools/python.ts +1 -1
- package/src/tools/read.ts +17 -35
- package/src/tools/report-issue.ts +184 -0
- package/src/tools/subagent-render.ts +114 -12
- package/src/tools/subagent.ts +108 -1
- package/src/tools/todo-write.ts +41 -3
- package/src/tools/tool-catalog.generated.ts +31 -3
- package/src/tools/write.ts +35 -3
- package/src/utils/commit-message-generator.ts +9 -2
- package/src/utils/file-mentions.ts +29 -1
- package/src/utils/title-generator.ts +7 -2
- package/src/web/scrapers/index.ts +3 -1
- package/src/web/scrapers/types.ts +8 -0
- package/src/web/scrapers/youtube.ts +3 -2
- package/src/web/search/providers/insane.ts +91 -28
- package/src/web/search/providers/searxng.ts +62 -10
|
@@ -73,7 +73,7 @@ import {
|
|
|
73
73
|
syntheticNamespaceCollision,
|
|
74
74
|
} from "../model-profile-model";
|
|
75
75
|
import { projectQ10Models } from "../models.js";
|
|
76
|
-
import {
|
|
76
|
+
import { autosaveWorktreeOnPromptDeadline } from "../prompt-deadline-flush";
|
|
77
77
|
import {
|
|
78
78
|
PromptDeadlineManager,
|
|
79
79
|
type PromptDeadlinePublicationResult,
|
|
@@ -103,6 +103,7 @@ import {
|
|
|
103
103
|
createKindAwareReconciliation,
|
|
104
104
|
createReconciliationStore,
|
|
105
105
|
type KindAwareReconciliation,
|
|
106
|
+
type ReconciliationStoreInstrumentationEvent,
|
|
106
107
|
resolveReconciliationSessionFile,
|
|
107
108
|
} from "../reconciliation-extensions";
|
|
108
109
|
import {
|
|
@@ -445,6 +446,8 @@ export interface SdkOnlyTerminalAbortSeams {
|
|
|
445
446
|
getReconciliationStore?: () => SdkOnlyReconciliationStore | undefined;
|
|
446
447
|
getTerminalTurnEpoch: () => number | undefined;
|
|
447
448
|
getActivePromptHandle: () => string | undefined;
|
|
449
|
+
onDeadlineRecoveryCheckpointForTests?: (checkpoint: SdkOnlyDeadlineRecoveryCheckpoint) => void;
|
|
450
|
+
onPersistenceInstrumentationForTests?: (event: PersistenceInstrumentationEvent) => void;
|
|
448
451
|
/** Re-read the active prompt's owning SDK connection for the owner-mismatch
|
|
449
452
|
* recheck; falls back to the runtime-tracked owner when absent (review
|
|
450
453
|
* thread P1). */
|
|
@@ -481,6 +484,35 @@ export interface SdkOnlyTerminalAbortSeams {
|
|
|
481
484
|
maxDurableTerminalReservationsForTests?: number;
|
|
482
485
|
}
|
|
483
486
|
|
|
487
|
+
export interface SdkOnlyDeadlineRecoveryCheckpoint {
|
|
488
|
+
at: number;
|
|
489
|
+
stage:
|
|
490
|
+
| "terminalization-start"
|
|
491
|
+
| "terminalization-result"
|
|
492
|
+
| "publication-start"
|
|
493
|
+
| "publication-result"
|
|
494
|
+
| "note-transition-start"
|
|
495
|
+
| "note-transition-awaiting-finalization"
|
|
496
|
+
| "note-transition-finalization-ready"
|
|
497
|
+
| "note-transition-before-persist"
|
|
498
|
+
| "note-transition-persisted"
|
|
499
|
+
| "note-transition-persist-failed"
|
|
500
|
+
| "deadline-recovery-retired";
|
|
501
|
+
correlation: InvocationCorrelation;
|
|
502
|
+
result?: "settled" | "uncertain" | "published" | "not-published" | "rejected";
|
|
503
|
+
reason?: string;
|
|
504
|
+
recordStatus?: string;
|
|
505
|
+
recordRevision?: number;
|
|
506
|
+
recordTerminalAt?: number;
|
|
507
|
+
pendingFinalization?: boolean;
|
|
508
|
+
eventCaptured?: boolean;
|
|
509
|
+
eventPrepared?: boolean;
|
|
510
|
+
terminalCommitted?: boolean;
|
|
511
|
+
leaseCurrent?: boolean;
|
|
512
|
+
pendingToolCount?: number;
|
|
513
|
+
errorCode?: string;
|
|
514
|
+
}
|
|
515
|
+
|
|
484
516
|
/**
|
|
485
517
|
* The transport-neutral SDK session runtime.
|
|
486
518
|
*
|
|
@@ -1024,8 +1056,26 @@ function canonicalizeHydratedDiagnostics(record: InvocationRecord): InvocationRe
|
|
|
1024
1056
|
return canonical;
|
|
1025
1057
|
}
|
|
1026
1058
|
|
|
1059
|
+
export interface PersistenceInstrumentationEvent {
|
|
1060
|
+
at: number;
|
|
1061
|
+
phase: "enqueued" | "started" | "completed" | "failed";
|
|
1062
|
+
operation?: string;
|
|
1063
|
+
substep?: string;
|
|
1064
|
+
error?: string;
|
|
1065
|
+
/** Detailed information about lock acquisition, promise identity, db state, etc. */
|
|
1066
|
+
detail?: string;
|
|
1067
|
+
/** Time spent waiting (ms) before the operation started. */
|
|
1068
|
+
waitMs?: number;
|
|
1069
|
+
}
|
|
1070
|
+
|
|
1027
1071
|
export function createInvocationReconciliation(
|
|
1028
|
-
options: {
|
|
1072
|
+
options: {
|
|
1073
|
+
stateRoot?: string;
|
|
1074
|
+
sessionId?: string;
|
|
1075
|
+
store?: SdkOnlyReconciliationStore;
|
|
1076
|
+
onDeadlineRecoveryCheckpointForTests?: (checkpoint: SdkOnlyDeadlineRecoveryCheckpoint) => void;
|
|
1077
|
+
onPersistenceInstrumentationForTests?: (event: PersistenceInstrumentationEvent) => void;
|
|
1078
|
+
} = {},
|
|
1029
1079
|
): InvocationReconciliation {
|
|
1030
1080
|
const ACTIVE_CAPACITY = 256;
|
|
1031
1081
|
const TERMINAL_CAPACITY = 512;
|
|
@@ -1063,6 +1113,17 @@ export function createInvocationReconciliation(
|
|
|
1063
1113
|
}
|
|
1064
1114
|
>();
|
|
1065
1115
|
const pendingTerminalVisibility = new Map<string, { visibleRecord: InvocationRecord; writes: number }>();
|
|
1116
|
+
const recordDeadlineRecoveryCheckpoint = (
|
|
1117
|
+
stage: SdkOnlyDeadlineRecoveryCheckpoint["stage"],
|
|
1118
|
+
correlation: InvocationCorrelation,
|
|
1119
|
+
details: Omit<SdkOnlyDeadlineRecoveryCheckpoint, "at" | "correlation" | "stage"> = {},
|
|
1120
|
+
): void => {
|
|
1121
|
+
try {
|
|
1122
|
+
options.onDeadlineRecoveryCheckpointForTests?.({ at: Date.now(), stage, correlation, ...details });
|
|
1123
|
+
} catch {
|
|
1124
|
+
// A test observer must never participate in durable reconciliation.
|
|
1125
|
+
}
|
|
1126
|
+
};
|
|
1066
1127
|
const retainPendingTerminalVisibility = (recordKey: string, visibleRecord: InvocationRecord): (() => void) => {
|
|
1067
1128
|
const existing = pendingTerminalVisibility.get(recordKey);
|
|
1068
1129
|
if (existing) existing.writes += 1;
|
|
@@ -1079,36 +1140,120 @@ export function createInvocationReconciliation(
|
|
|
1079
1140
|
};
|
|
1080
1141
|
const persist = async (): Promise<void> => {
|
|
1081
1142
|
const run = async (): Promise<void> => {
|
|
1143
|
+
try {
|
|
1144
|
+
options.onPersistenceInstrumentationForTests?.({ at: Date.now(), phase: "enqueued" });
|
|
1145
|
+
} catch {
|
|
1146
|
+
// A test observer must never participate in durable reconciliation.
|
|
1147
|
+
}
|
|
1148
|
+
try {
|
|
1149
|
+
options.onPersistenceInstrumentationForTests?.({ at: Date.now(), phase: "started" });
|
|
1150
|
+
} catch {
|
|
1151
|
+
// Ignore observer errors.
|
|
1152
|
+
}
|
|
1082
1153
|
// Construct the candidate only when this serialized write starts. A
|
|
1083
1154
|
// pre-await full snapshot lets a later agent_start/agent_end transition
|
|
1084
1155
|
// be overwritten on disk by an older queued write even though the live
|
|
1085
1156
|
// map has already converged.
|
|
1086
1157
|
const snapshot = [...records.values()].map(record => ({ ...record }));
|
|
1087
1158
|
if (store) {
|
|
1088
|
-
|
|
1089
|
-
|
|
1090
|
-
|
|
1091
|
-
|
|
1159
|
+
const promiseId = `transact-${crypto.randomUUID().slice(0, 8)}`;
|
|
1160
|
+
const lockWaitStart = Date.now();
|
|
1161
|
+
try {
|
|
1162
|
+
options.onPersistenceInstrumentationForTests?.({
|
|
1163
|
+
at: lockWaitStart,
|
|
1164
|
+
phase: "started",
|
|
1165
|
+
operation: "store.transact",
|
|
1166
|
+
detail: `promise=${promiseId} awaiting-lock`,
|
|
1167
|
+
});
|
|
1168
|
+
} catch {}
|
|
1169
|
+
const lockAcquiredTime = Date.now();
|
|
1170
|
+
try {
|
|
1171
|
+
await store.transact(current => [
|
|
1172
|
+
...current.filter(record => record.kind !== "prompt" && record.kind !== "skill"),
|
|
1173
|
+
...snapshot.map(record => ({ ...record })),
|
|
1174
|
+
]);
|
|
1175
|
+
} catch (error) {
|
|
1176
|
+
try {
|
|
1177
|
+
options.onPersistenceInstrumentationForTests?.({
|
|
1178
|
+
at: Date.now(),
|
|
1179
|
+
phase: "failed",
|
|
1180
|
+
operation: "store.transact",
|
|
1181
|
+
detail: `promise=${promiseId} lock-wait=${Date.now() - lockWaitStart}ms`,
|
|
1182
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1183
|
+
});
|
|
1184
|
+
} catch {}
|
|
1185
|
+
throw error;
|
|
1186
|
+
}
|
|
1187
|
+
try {
|
|
1188
|
+
options.onPersistenceInstrumentationForTests?.({
|
|
1189
|
+
at: Date.now(),
|
|
1190
|
+
phase: "completed",
|
|
1191
|
+
operation: "store.transact",
|
|
1192
|
+
detail: `promise=${promiseId} lock-acquire=${lockAcquiredTime - lockWaitStart}ms`,
|
|
1193
|
+
});
|
|
1194
|
+
} catch {}
|
|
1092
1195
|
return;
|
|
1093
1196
|
}
|
|
1094
1197
|
if (!reconciliationFile) return;
|
|
1095
1198
|
const directory = path.dirname(reconciliationFile);
|
|
1096
1199
|
const temporary = `${reconciliationFile}.${process.pid}.${crypto.randomUUID()}.tmp`;
|
|
1200
|
+
try {
|
|
1201
|
+
options.onPersistenceInstrumentationForTests?.({ at: Date.now(), phase: "started", substep: "mkdir" });
|
|
1202
|
+
} catch {}
|
|
1097
1203
|
await fs.mkdir(directory, { recursive: true, mode: 0o700 });
|
|
1204
|
+
try {
|
|
1205
|
+
options.onPersistenceInstrumentationForTests?.({ at: Date.now(), phase: "completed", substep: "mkdir" });
|
|
1206
|
+
} catch {}
|
|
1207
|
+
try {
|
|
1208
|
+
options.onPersistenceInstrumentationForTests?.({ at: Date.now(), phase: "started", substep: "writeFile" });
|
|
1209
|
+
} catch {}
|
|
1098
1210
|
await fs.writeFile(
|
|
1099
1211
|
temporary,
|
|
1100
1212
|
JSON.stringify({ version: 1, sessionId: options.sessionId, records: [...snapshot] }),
|
|
1101
1213
|
{ encoding: "utf8", mode: 0o600 },
|
|
1102
1214
|
);
|
|
1215
|
+
try {
|
|
1216
|
+
options.onPersistenceInstrumentationForTests?.({
|
|
1217
|
+
at: Date.now(),
|
|
1218
|
+
phase: "completed",
|
|
1219
|
+
substep: "writeFile",
|
|
1220
|
+
});
|
|
1221
|
+
} catch {}
|
|
1222
|
+
try {
|
|
1223
|
+
options.onPersistenceInstrumentationForTests?.({ at: Date.now(), phase: "started", substep: "chmod" });
|
|
1224
|
+
} catch {}
|
|
1103
1225
|
await fs.chmod(temporary, 0o600);
|
|
1226
|
+
try {
|
|
1227
|
+
options.onPersistenceInstrumentationForTests?.({ at: Date.now(), phase: "completed", substep: "chmod" });
|
|
1228
|
+
} catch {}
|
|
1229
|
+
try {
|
|
1230
|
+
options.onPersistenceInstrumentationForTests?.({ at: Date.now(), phase: "started", substep: "rename" });
|
|
1231
|
+
} catch {}
|
|
1104
1232
|
await fs.rename(temporary, reconciliationFile);
|
|
1233
|
+
try {
|
|
1234
|
+
options.onPersistenceInstrumentationForTests?.({ at: Date.now(), phase: "completed", substep: "rename" });
|
|
1235
|
+
} catch {}
|
|
1105
1236
|
};
|
|
1106
1237
|
const pending = persistenceChain.then(run, run);
|
|
1107
1238
|
persistenceChain = pending.then(
|
|
1108
1239
|
() => undefined,
|
|
1109
1240
|
() => undefined,
|
|
1110
1241
|
);
|
|
1111
|
-
|
|
1242
|
+
try {
|
|
1243
|
+
await pending;
|
|
1244
|
+
try {
|
|
1245
|
+
options.onPersistenceInstrumentationForTests?.({ at: Date.now(), phase: "completed" });
|
|
1246
|
+
} catch {}
|
|
1247
|
+
} catch (error) {
|
|
1248
|
+
try {
|
|
1249
|
+
options.onPersistenceInstrumentationForTests?.({
|
|
1250
|
+
at: Date.now(),
|
|
1251
|
+
phase: "failed",
|
|
1252
|
+
error: error instanceof Error ? error.message : String(error),
|
|
1253
|
+
});
|
|
1254
|
+
} catch {}
|
|
1255
|
+
throw error;
|
|
1256
|
+
}
|
|
1112
1257
|
};
|
|
1113
1258
|
// Retention contract (#4547): terminal records are never age-evicted; only
|
|
1114
1259
|
// the per-kind oldest-terminal-first capacity trim removes them, so a
|
|
@@ -1257,7 +1402,22 @@ export function createInvocationReconciliation(
|
|
|
1257
1402
|
let record = records.get(recordKey);
|
|
1258
1403
|
if (!record) return;
|
|
1259
1404
|
const pending = pendingFinalizations.get(recordKey);
|
|
1405
|
+
const isPromptEnd = kind === "prompt" && frame.type === "agent_end";
|
|
1406
|
+
if (isPromptEnd)
|
|
1407
|
+
recordDeadlineRecoveryCheckpoint("note-transition-start", correlation, {
|
|
1408
|
+
recordStatus: record.status,
|
|
1409
|
+
recordRevision: record.revision,
|
|
1410
|
+
recordTerminalAt: record.terminalAt,
|
|
1411
|
+
pendingFinalization: pending?.finalizedRecord === record,
|
|
1412
|
+
});
|
|
1260
1413
|
if (pending?.finalizedRecord === record) {
|
|
1414
|
+
if (isPromptEnd)
|
|
1415
|
+
recordDeadlineRecoveryCheckpoint("note-transition-awaiting-finalization", correlation, {
|
|
1416
|
+
recordStatus: record.status,
|
|
1417
|
+
recordRevision: record.revision,
|
|
1418
|
+
recordTerminalAt: record.terminalAt,
|
|
1419
|
+
pendingFinalization: true,
|
|
1420
|
+
});
|
|
1261
1421
|
const upgrade = Promise.withResolvers<void>();
|
|
1262
1422
|
pending.upgrades.add(upgrade);
|
|
1263
1423
|
let upgradeError: unknown;
|
|
@@ -1269,6 +1429,13 @@ export function createInvocationReconciliation(
|
|
|
1269
1429
|
// so a real lifecycle event is never swallowed.
|
|
1270
1430
|
}
|
|
1271
1431
|
const current = records.get(recordKey);
|
|
1432
|
+
if (isPromptEnd)
|
|
1433
|
+
recordDeadlineRecoveryCheckpoint("note-transition-finalization-ready", correlation, {
|
|
1434
|
+
recordStatus: current?.status,
|
|
1435
|
+
recordRevision: current?.revision,
|
|
1436
|
+
recordTerminalAt: current?.terminalAt,
|
|
1437
|
+
pendingFinalization: pendingFinalizations.get(recordKey) === pending,
|
|
1438
|
+
});
|
|
1272
1439
|
const incomingOutcome = frame.type === "agent_end" ? canonicalTerminalOutcome(frame.outcome) : undefined;
|
|
1273
1440
|
const providerFailure =
|
|
1274
1441
|
current?.error !== undefined && current.error.code !== "prompt_deadline_exceeded";
|
|
@@ -1650,10 +1817,31 @@ export function createInvocationReconciliation(
|
|
|
1650
1817
|
record.terminalAt === undefined && next.terminalAt !== undefined
|
|
1651
1818
|
? retainPendingTerminalVisibility(recordKey, record)
|
|
1652
1819
|
: undefined;
|
|
1820
|
+
if (isPromptEnd)
|
|
1821
|
+
recordDeadlineRecoveryCheckpoint("note-transition-before-persist", correlation, {
|
|
1822
|
+
recordStatus: next.status,
|
|
1823
|
+
recordRevision: next.revision,
|
|
1824
|
+
recordTerminalAt: next.terminalAt,
|
|
1825
|
+
pendingFinalization: pendingFinalizations.has(recordKey),
|
|
1826
|
+
});
|
|
1653
1827
|
records.set(recordKey, next);
|
|
1654
1828
|
try {
|
|
1655
1829
|
await persist();
|
|
1830
|
+
if (isPromptEnd)
|
|
1831
|
+
recordDeadlineRecoveryCheckpoint("note-transition-persisted", correlation, {
|
|
1832
|
+
recordStatus: next.status,
|
|
1833
|
+
recordRevision: next.revision,
|
|
1834
|
+
recordTerminalAt: next.terminalAt,
|
|
1835
|
+
pendingFinalization: pendingFinalizations.has(recordKey),
|
|
1836
|
+
});
|
|
1656
1837
|
} catch (error) {
|
|
1838
|
+
if (isPromptEnd)
|
|
1839
|
+
recordDeadlineRecoveryCheckpoint("note-transition-persist-failed", correlation, {
|
|
1840
|
+
recordStatus: next.status,
|
|
1841
|
+
recordRevision: next.revision,
|
|
1842
|
+
recordTerminalAt: next.terminalAt,
|
|
1843
|
+
pendingFinalization: pendingFinalizations.has(recordKey),
|
|
1844
|
+
});
|
|
1657
1845
|
if (records.get(recordKey) === next) records.set(recordKey, record);
|
|
1658
1846
|
throw error;
|
|
1659
1847
|
} finally {
|
|
@@ -6419,16 +6607,38 @@ export function createSdkSessionRuntimeExtension(api: ExtensionAPI, options: Cre
|
|
|
6419
6607
|
(typeof ctx.sessionManager.getSessionFile === "function" ? ctx.sessionManager.getSessionFile() : undefined) ??
|
|
6420
6608
|
resolveReconciliationSessionFile(undefined, stateRoot, sessionId);
|
|
6421
6609
|
const sessionIdentity = `${sessionId}\u0000${sessionFile}`;
|
|
6610
|
+
const reconciliationInstrumentation = options.terminalAbortSeams?.onPersistenceInstrumentationForTests
|
|
6611
|
+
? (event: ReconciliationStoreInstrumentationEvent) => {
|
|
6612
|
+
try {
|
|
6613
|
+
options.terminalAbortSeams?.onPersistenceInstrumentationForTests?.(event as never);
|
|
6614
|
+
} catch {}
|
|
6615
|
+
}
|
|
6616
|
+
: undefined;
|
|
6422
6617
|
const reconciliationStore =
|
|
6423
6618
|
options.terminalAbortSeams?.getReconciliationStore?.() ??
|
|
6424
|
-
createReconciliationStore({
|
|
6425
|
-
|
|
6619
|
+
createReconciliationStore({
|
|
6620
|
+
sessionFile,
|
|
6621
|
+
sessionId,
|
|
6622
|
+
onInstrumentationForTests: reconciliationInstrumentation,
|
|
6623
|
+
});
|
|
6624
|
+
const reconciliation = createInvocationReconciliation({
|
|
6625
|
+
store: reconciliationStore,
|
|
6626
|
+
onDeadlineRecoveryCheckpointForTests: options.terminalAbortSeams?.onDeadlineRecoveryCheckpointForTests,
|
|
6627
|
+
onPersistenceInstrumentationForTests: options.terminalAbortSeams?.onPersistenceInstrumentationForTests,
|
|
6628
|
+
});
|
|
6426
6629
|
await reconciliation.hydrate();
|
|
6427
6630
|
const steerReconciliation = createKindAwareReconciliation({
|
|
6428
6631
|
store: reconciliationStore as never,
|
|
6429
6632
|
ownedKinds: ["steer"],
|
|
6430
6633
|
});
|
|
6431
6634
|
await steerReconciliation.hydrateFromStore();
|
|
6635
|
+
const recordDeadlineRecoveryCheckpoint = (checkpoint: Omit<SdkOnlyDeadlineRecoveryCheckpoint, "at">): void => {
|
|
6636
|
+
try {
|
|
6637
|
+
options.terminalAbortSeams?.onDeadlineRecoveryCheckpointForTests?.({ ...checkpoint, at: Date.now() });
|
|
6638
|
+
} catch {
|
|
6639
|
+
// A test observer must never participate in deadline correctness.
|
|
6640
|
+
}
|
|
6641
|
+
};
|
|
6432
6642
|
const deadlineManager = new PromptDeadlineManager({
|
|
6433
6643
|
reconciliation,
|
|
6434
6644
|
getLeaseMs: () => resolveSdkPromptDeadlineMs(options.settings?.get("sdk.promptDeadlineMs" as never)),
|
|
@@ -6448,6 +6658,9 @@ export function createSdkSessionRuntimeExtension(api: ExtensionAPI, options: Cre
|
|
|
6448
6658
|
const seams = options.terminalAbortSeams;
|
|
6449
6659
|
const handle = seams?.getActivePromptHandle();
|
|
6450
6660
|
const epoch = seams?.getTerminalTurnEpoch();
|
|
6661
|
+
// Capture lifecycle ownership independently of settlement proof. Without
|
|
6662
|
+
// a tool-set observer the later terminalization hook still fails closed,
|
|
6663
|
+
// but a matching real end must remain private and recoverable meanwhile.
|
|
6451
6664
|
if (!seams || !handle || epoch === undefined) return;
|
|
6452
6665
|
const existing = deadlineTerminalizationObservations.get(key);
|
|
6453
6666
|
if (existing) return () => cleanupDeadlineTerminalizationObservation(key, existing);
|
|
@@ -6495,8 +6708,36 @@ export function createSdkSessionRuntimeExtension(api: ExtensionAPI, options: Cre
|
|
|
6495
6708
|
const observation = deadlineTerminalizationObservations.get(target);
|
|
6496
6709
|
const seams = options.terminalAbortSeams;
|
|
6497
6710
|
const pendingToolExecutions = seams?.pendingToolExecutions;
|
|
6498
|
-
|
|
6499
|
-
|
|
6711
|
+
recordDeadlineRecoveryCheckpoint({
|
|
6712
|
+
stage: "terminalization-start",
|
|
6713
|
+
correlation,
|
|
6714
|
+
eventCaptured: observation?.eventCaptured,
|
|
6715
|
+
eventPrepared: observation?.eventPrepared,
|
|
6716
|
+
terminalCommitted: observation?.terminalCommitted,
|
|
6717
|
+
});
|
|
6718
|
+
let pendingToolCount: number | undefined;
|
|
6719
|
+
const finish = (result: PromptDeadlineTerminalization, reason: string): PromptDeadlineTerminalization => {
|
|
6720
|
+
recordDeadlineRecoveryCheckpoint({
|
|
6721
|
+
stage: "terminalization-result",
|
|
6722
|
+
correlation,
|
|
6723
|
+
result,
|
|
6724
|
+
reason,
|
|
6725
|
+
eventCaptured: observation?.eventCaptured,
|
|
6726
|
+
eventPrepared: observation?.eventPrepared,
|
|
6727
|
+
terminalCommitted: observation?.terminalCommitted,
|
|
6728
|
+
pendingToolCount,
|
|
6729
|
+
});
|
|
6730
|
+
// Notify deadline manager about termination result to adjust retry strategy
|
|
6731
|
+
deadlineManager.notifyTerminationResult(correlation, result, reason);
|
|
6732
|
+
return result;
|
|
6733
|
+
};
|
|
6734
|
+
if (!observation || !seams || !pendingToolExecutions)
|
|
6735
|
+
return finish("uncertain", "missing-observation-or-tool-observer");
|
|
6736
|
+
const pendingTools = () => {
|
|
6737
|
+
const pending = pendingToolExecutions(observation.handle);
|
|
6738
|
+
pendingToolCount = pending.length;
|
|
6739
|
+
return pending;
|
|
6740
|
+
};
|
|
6500
6741
|
const awaitEventPreparation = async (): Promise<boolean> => {
|
|
6501
6742
|
if (observation.eventPrepared) return true;
|
|
6502
6743
|
const captured = await Promise.race([
|
|
@@ -6507,7 +6748,15 @@ export function createSdkSessionRuntimeExtension(api: ExtensionAPI, options: Cre
|
|
|
6507
6748
|
};
|
|
6508
6749
|
if (observation.eventCaptured) {
|
|
6509
6750
|
const prepared = await awaitEventPreparation();
|
|
6510
|
-
|
|
6751
|
+
pendingToolCount = pendingTools().length;
|
|
6752
|
+
return finish(
|
|
6753
|
+
prepared && pendingToolCount === 0 ? "settled" : "uncertain",
|
|
6754
|
+
!prepared
|
|
6755
|
+
? "captured-event-not-prepared"
|
|
6756
|
+
: pendingToolCount > 0
|
|
6757
|
+
? "tools-still-pending"
|
|
6758
|
+
: "captured-event-and-tools-settled",
|
|
6759
|
+
);
|
|
6511
6760
|
}
|
|
6512
6761
|
|
|
6513
6762
|
if (!observation.eventCaptured) {
|
|
@@ -6521,13 +6770,13 @@ export function createSdkSessionRuntimeExtension(api: ExtensionAPI, options: Cre
|
|
|
6521
6770
|
entry => lifecycleCorrelationKey(entry.correlation) === target,
|
|
6522
6771
|
)
|
|
6523
6772
|
)
|
|
6524
|
-
return "uncertain";
|
|
6773
|
+
return finish("uncertain", "lifecycle-batch-no-longer-owns-correlation");
|
|
6525
6774
|
if (
|
|
6526
6775
|
!isCurrent() ||
|
|
6527
6776
|
seams.getActivePromptHandle() !== observation.handle ||
|
|
6528
6777
|
seams.getTerminalTurnEpoch() !== observation.epoch
|
|
6529
6778
|
)
|
|
6530
|
-
return "uncertain";
|
|
6779
|
+
return finish("uncertain", "lease-or-active-run-mismatch");
|
|
6531
6780
|
}
|
|
6532
6781
|
await waitForToolCallBoundary({
|
|
6533
6782
|
pending: pendingTools,
|
|
@@ -6536,14 +6785,22 @@ export function createSdkSessionRuntimeExtension(api: ExtensionAPI, options: Cre
|
|
|
6536
6785
|
});
|
|
6537
6786
|
if (observation.eventCaptured) {
|
|
6538
6787
|
const prepared = await awaitEventPreparation();
|
|
6539
|
-
|
|
6788
|
+
pendingToolCount = pendingTools().length;
|
|
6789
|
+
return finish(
|
|
6790
|
+
prepared && pendingToolCount === 0 ? "settled" : "uncertain",
|
|
6791
|
+
!prepared
|
|
6792
|
+
? "captured-event-not-prepared"
|
|
6793
|
+
: pendingToolCount > 0
|
|
6794
|
+
? "tools-still-pending"
|
|
6795
|
+
: "captured-event-and-tools-settled",
|
|
6796
|
+
);
|
|
6540
6797
|
}
|
|
6541
6798
|
if (
|
|
6542
6799
|
!isCurrent() ||
|
|
6543
6800
|
seams.getActivePromptHandle() !== observation.handle ||
|
|
6544
6801
|
seams.getTerminalTurnEpoch() !== observation.epoch
|
|
6545
6802
|
)
|
|
6546
|
-
return "uncertain";
|
|
6803
|
+
return finish("uncertain", "lease-or-active-run-mismatch-after-tool-boundary");
|
|
6547
6804
|
|
|
6548
6805
|
let steeringSnapshotToken: number | undefined;
|
|
6549
6806
|
let proof: { status: string; terminalScope?: unknown } | undefined;
|
|
@@ -6560,7 +6817,15 @@ export function createSdkSessionRuntimeExtension(api: ExtensionAPI, options: Cre
|
|
|
6560
6817
|
});
|
|
6561
6818
|
if (proof.status !== "settled") {
|
|
6562
6819
|
const prepared = await awaitEventPreparation();
|
|
6563
|
-
|
|
6820
|
+
pendingToolCount = pendingTools().length;
|
|
6821
|
+
return finish(
|
|
6822
|
+
prepared && pendingToolCount === 0 ? "settled" : "uncertain",
|
|
6823
|
+
!prepared
|
|
6824
|
+
? "abort-proof-not-settled-and-event-not-prepared"
|
|
6825
|
+
: pendingToolCount > 0
|
|
6826
|
+
? "tools-still-pending"
|
|
6827
|
+
: "captured-event-and-tools-settled",
|
|
6828
|
+
);
|
|
6564
6829
|
}
|
|
6565
6830
|
const terminalScope = proof.terminalScope as
|
|
6566
6831
|
| { abortedAttemptEpoch?: unknown; lineageIdHash?: unknown }
|
|
@@ -6570,17 +6835,26 @@ export function createSdkSessionRuntimeExtension(api: ExtensionAPI, options: Cre
|
|
|
6570
6835
|
typeof terminalScope.lineageIdHash !== "string" ||
|
|
6571
6836
|
isOwnedAttemptRegistrationIncomplete(terminalScope.lineageIdHash, observation.epoch)
|
|
6572
6837
|
)
|
|
6573
|
-
return "uncertain";
|
|
6838
|
+
return finish("uncertain", "terminal-scope-mismatch");
|
|
6574
6839
|
const exactJobs = findOwnedRegistrationsForTurn(terminalScope.lineageIdHash, observation.epoch);
|
|
6575
6840
|
if (exactJobs.length > 0) {
|
|
6576
6841
|
const endpointId = exactJobs[0]?.endpointId;
|
|
6577
6842
|
const manager = AsyncJobManager.forEndpoint(endpointId) ?? AsyncJobManager.instance();
|
|
6578
|
-
if (!manager || (await settleOwnedWork(manager, exactJobs, 500)) !== "stopped")
|
|
6843
|
+
if (!manager || (await settleOwnedWork(manager, exactJobs, 500)) !== "stopped")
|
|
6844
|
+
return finish("uncertain", "owned-work-not-stopped");
|
|
6579
6845
|
}
|
|
6580
6846
|
const prepared = await awaitEventPreparation();
|
|
6581
|
-
|
|
6847
|
+
pendingToolCount = pendingTools().length;
|
|
6848
|
+
return finish(
|
|
6849
|
+
prepared && pendingToolCount === 0 ? "settled" : "uncertain",
|
|
6850
|
+
!prepared
|
|
6851
|
+
? "captured-event-not-prepared"
|
|
6852
|
+
: pendingToolCount > 0
|
|
6853
|
+
? "tools-still-pending"
|
|
6854
|
+
: "captured-event-and-tools-settled",
|
|
6855
|
+
);
|
|
6582
6856
|
} catch {
|
|
6583
|
-
return "uncertain";
|
|
6857
|
+
return finish("uncertain", "terminal-abort-error");
|
|
6584
6858
|
} finally {
|
|
6585
6859
|
if (steeringSnapshotToken !== undefined && proof?.status !== "settled")
|
|
6586
6860
|
seams.discardTerminalAbortSteeringSnapshot?.(steeringSnapshotToken);
|
|
@@ -6592,21 +6866,57 @@ export function createSdkSessionRuntimeExtension(api: ExtensionAPI, options: Cre
|
|
|
6592
6866
|
const terminalOutcome = observation
|
|
6593
6867
|
? deadlineOutcomeAfterAbort(correlation, observation.terminalOutcome, observation.terminalHasActivity)
|
|
6594
6868
|
: undefined;
|
|
6595
|
-
|
|
6869
|
+
let terminalIsCurrent: boolean | undefined;
|
|
6870
|
+
let pendingToolCount = -1;
|
|
6871
|
+
const recordPublicationResult = (
|
|
6872
|
+
result: SdkOnlyDeadlineRecoveryCheckpoint["result"],
|
|
6873
|
+
reason: string,
|
|
6874
|
+
errorCodeValue?: string,
|
|
6875
|
+
): void => {
|
|
6876
|
+
recordDeadlineRecoveryCheckpoint({
|
|
6877
|
+
stage: "publication-result",
|
|
6878
|
+
correlation,
|
|
6879
|
+
result,
|
|
6880
|
+
reason,
|
|
6881
|
+
eventCaptured: observation?.eventCaptured,
|
|
6882
|
+
eventPrepared: observation?.eventPrepared,
|
|
6883
|
+
terminalCommitted: observation?.terminalCommitted,
|
|
6884
|
+
leaseCurrent: terminalIsCurrent,
|
|
6885
|
+
pendingToolCount,
|
|
6886
|
+
errorCode: errorCodeValue,
|
|
6887
|
+
});
|
|
6888
|
+
};
|
|
6889
|
+
recordDeadlineRecoveryCheckpoint({
|
|
6890
|
+
stage: "publication-start",
|
|
6891
|
+
correlation,
|
|
6892
|
+
eventCaptured: observation?.eventCaptured,
|
|
6893
|
+
eventPrepared: observation?.eventPrepared,
|
|
6894
|
+
terminalCommitted: observation?.terminalCommitted,
|
|
6895
|
+
});
|
|
6896
|
+
if (!observation?.eventCaptured || !observation.eventPrepared || terminalOutcome === undefined) {
|
|
6897
|
+
recordPublicationResult("rejected", "missing-captured-terminal-outcome");
|
|
6596
6898
|
return false;
|
|
6899
|
+
}
|
|
6597
6900
|
if (!observation.terminalCommitted) {
|
|
6598
6901
|
const pendingTools = options.terminalAbortSeams?.pendingToolExecutions;
|
|
6599
|
-
let terminalIsCurrent = false;
|
|
6600
|
-
let pendingToolCount = -1;
|
|
6601
6902
|
try {
|
|
6602
6903
|
terminalIsCurrent = isCurrent();
|
|
6603
6904
|
if (pendingTools) pendingToolCount = pendingTools(observation.handle).length;
|
|
6604
|
-
} catch {
|
|
6905
|
+
} catch (error) {
|
|
6906
|
+
recordPublicationResult("rejected", "publication-precheck-threw", errorCode(error));
|
|
6907
|
+
return false;
|
|
6908
|
+
}
|
|
6909
|
+
if (!terminalIsCurrent || !pendingTools || pendingToolCount > 0) {
|
|
6910
|
+
recordPublicationResult("rejected", "publication-precheck-rejected");
|
|
6605
6911
|
return false;
|
|
6606
6912
|
}
|
|
6607
|
-
if (!terminalIsCurrent || !pendingTools || pendingToolCount > 0) return false;
|
|
6608
6913
|
try {
|
|
6609
|
-
|
|
6914
|
+
terminalIsCurrent = isCurrent();
|
|
6915
|
+
pendingToolCount = pendingTools(observation.handle).length;
|
|
6916
|
+
if (!terminalIsCurrent || pendingToolCount > 0) {
|
|
6917
|
+
recordPublicationResult("rejected", "publication-recheck-rejected");
|
|
6918
|
+
return false;
|
|
6919
|
+
}
|
|
6610
6920
|
// Commit the authoritative Q26 result before exposing its terminal
|
|
6611
6921
|
// boundary; a crash between publication and this write would strand
|
|
6612
6922
|
// restart recovery with only a hidden pending claim.
|
|
@@ -6619,40 +6929,35 @@ export function createSdkSessionRuntimeExtension(api: ExtensionAPI, options: Cre
|
|
|
6619
6929
|
observation.terminalOutcome = terminalOutcome;
|
|
6620
6930
|
observation.terminalCommitted = true;
|
|
6621
6931
|
observation.clearUnrecordedFailure?.();
|
|
6622
|
-
} catch {
|
|
6932
|
+
} catch (error) {
|
|
6933
|
+
recordPublicationResult("rejected", "terminal-transition-persist-failed", errorCode(error));
|
|
6623
6934
|
return false;
|
|
6624
6935
|
}
|
|
6625
6936
|
}
|
|
6626
6937
|
const published = publishDeadlineTerminalBoundary(observation, correlation, terminalOutcome);
|
|
6938
|
+
recordPublicationResult(published ? "published" : "not-published", "terminal-boundary-result");
|
|
6627
6939
|
return { outcome: terminalOutcome, published } satisfies PromptDeadlinePublicationResult;
|
|
6628
6940
|
},
|
|
6629
6941
|
// Persist the agent's uncommitted work before the retirement below tears
|
|
6630
6942
|
// the session down (#5583). Best effort by contract: failures are logged
|
|
6631
6943
|
// inside the flush and the deadline outcome is unaffected.
|
|
6632
6944
|
onDeadlineExceeded: async (_correlation, signal, isCurrent) => {
|
|
6633
|
-
|
|
6634
|
-
//
|
|
6635
|
-
|
|
6636
|
-
// honours the default inside a linked worktree the session owns.
|
|
6637
|
-
const configured = options.settings?.get("sdk.flushWorktreeOnDeadline" as never);
|
|
6638
|
-
const hasExplicitSetting =
|
|
6639
|
-
typeof options.settings?.has === "function"
|
|
6640
|
-
? options.settings.has("sdk.flushWorktreeOnDeadline" as never)
|
|
6641
|
-
: configured === true;
|
|
6642
|
-
const explicitOptIn = hasExplicitSetting === true && configured === true;
|
|
6643
|
-
await flushWorktreeOnPromptDeadline(ctx.cwd, {
|
|
6644
|
-
agentDir: options.settings?.getAgentDir(),
|
|
6645
|
-
explicitOptIn,
|
|
6646
|
-
isCurrent,
|
|
6647
|
-
signal,
|
|
6648
|
-
});
|
|
6945
|
+
// Project `.gjc` files are not an opt-in. The shared helper reads the
|
|
6946
|
+
// user/global layer and runtime overrides only (#5583).
|
|
6947
|
+
await autosaveWorktreeOnPromptDeadline(ctx.cwd, options.settings, { isCurrent, signal });
|
|
6649
6948
|
},
|
|
6650
6949
|
onExpired: correlation => {
|
|
6651
6950
|
retireAcceptedQueueCancellation(acceptedQueueCancellations, correlation, true);
|
|
6652
6951
|
const owner = lifecycleOwnerHolder.state;
|
|
6653
|
-
if (
|
|
6654
|
-
|
|
6655
|
-
|
|
6952
|
+
if (owner) {
|
|
6953
|
+
removeLifecycleReferences(owner, correlation);
|
|
6954
|
+
maybeRetireLifecycleOwner(owner);
|
|
6955
|
+
}
|
|
6956
|
+
recordDeadlineRecoveryCheckpoint({
|
|
6957
|
+
stage: "deadline-recovery-retired",
|
|
6958
|
+
correlation,
|
|
6959
|
+
terminalCommitted: true,
|
|
6960
|
+
});
|
|
6656
6961
|
},
|
|
6657
6962
|
});
|
|
6658
6963
|
const pending: Array<{
|