@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
|
@@ -2,14 +2,13 @@
|
|
|
2
2
|
* Kind-aware invocation reconciliation (prompt | skill) with optional durable store.
|
|
3
3
|
* Preserves Q26 admit/first-terminal/capacity/TTL semantics; indexes and caps are per-kind.
|
|
4
4
|
*/
|
|
5
|
+
import type { PromptReconciliationStatus, SdkPromptTerminalOutcome, TurnPromptReconciliation } from "../prompt-status";
|
|
5
6
|
import {
|
|
6
7
|
PROMPT_RECONCILIATION_ACTIVE_CAPACITY,
|
|
7
8
|
PROMPT_RECONCILIATION_TERMINAL_CAPACITY,
|
|
8
9
|
PROMPT_RECONCILIATION_TERMINAL_TTL_MS,
|
|
9
10
|
type PromptCorrelation,
|
|
10
|
-
type PromptReconciliationStatus,
|
|
11
11
|
sanitizePromptFailure,
|
|
12
|
-
type TurnPromptReconciliation,
|
|
13
12
|
} from "./prompt-reconciliation";
|
|
14
13
|
import type { DurableReconciliationRecord, ReconciliationKind, ReconciliationStore } from "./reconciliation-store";
|
|
15
14
|
|
|
@@ -33,6 +32,16 @@ export interface KindAwareReconciliation {
|
|
|
33
32
|
correlation: PromptCorrelation | undefined,
|
|
34
33
|
frame: { type: "agent_start" | "agent_end" } | { type: "agent_failed"; error: unknown },
|
|
35
34
|
): Promise<void>;
|
|
35
|
+
claimPendingOutcome(
|
|
36
|
+
correlation: PromptCorrelation,
|
|
37
|
+
outcome: SdkPromptTerminalOutcome,
|
|
38
|
+
): Promise<SdkPromptTerminalOutcome>;
|
|
39
|
+
finalizePromptOutcome(
|
|
40
|
+
correlation: PromptCorrelation,
|
|
41
|
+
outcome?: SdkPromptTerminalOutcome,
|
|
42
|
+
recordError?: { code: string; message: string },
|
|
43
|
+
): Promise<void>;
|
|
44
|
+
peekPendingOutcome(correlation: PromptCorrelation): SdkPromptTerminalOutcome | undefined;
|
|
36
45
|
lookup(
|
|
37
46
|
kind: ReconciliationKind,
|
|
38
47
|
selector: { commandId?: string; turnId?: string; clientRef?: string },
|
|
@@ -48,48 +57,72 @@ export function createKindAwareReconciliation(
|
|
|
48
57
|
): KindAwareReconciliation {
|
|
49
58
|
const now = options.now ?? Date.now;
|
|
50
59
|
const store = options.store ?? null;
|
|
51
|
-
|
|
52
|
-
|
|
60
|
+
let records = new Map<string, DurableReconciliationRecord>();
|
|
61
|
+
let clientRefIndex = new Map<string, string>();
|
|
53
62
|
const reservedClientRefs = new Map<ReconciliationKind, Set<string>>();
|
|
54
63
|
const reservations: Array<{ kind: ReconciliationKind; clientRef?: string }> = [];
|
|
64
|
+
let mutationChain: Promise<void> = Promise.resolve();
|
|
55
65
|
|
|
56
66
|
const keyOf = (kind: ReconciliationKind, correlation: PromptCorrelation) =>
|
|
57
67
|
`${kind}:${correlation.commandId}:${correlation.turnId}`;
|
|
58
68
|
const refKey = (kind: ReconciliationKind, clientRef: string) => `${kind}\0${clientRef}`;
|
|
59
69
|
|
|
60
|
-
const
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
}
|
|
66
|
-
return set;
|
|
67
|
-
};
|
|
68
|
-
|
|
69
|
-
const remove = (key: string) => {
|
|
70
|
-
const record = records.get(key);
|
|
71
|
-
if (!record) return;
|
|
72
|
-
records.delete(key);
|
|
73
|
-
if (record.clientRef !== undefined) {
|
|
74
|
-
const rk = refKey(record.kind, record.clientRef);
|
|
75
|
-
if (clientRefIndex.get(rk) === key) clientRefIndex.delete(rk);
|
|
76
|
-
}
|
|
70
|
+
const indexRecords = (source: Map<string, DurableReconciliationRecord>) => {
|
|
71
|
+
const index = new Map<string, string>();
|
|
72
|
+
for (const [key, record] of source)
|
|
73
|
+
if (record.clientRef !== undefined) index.set(refKey(record.kind, record.clientRef), key);
|
|
74
|
+
return index;
|
|
77
75
|
};
|
|
78
76
|
|
|
79
|
-
const
|
|
77
|
+
const cleanupRecords = (source: Map<string, DurableReconciliationRecord>) => {
|
|
80
78
|
const at = now();
|
|
81
|
-
for (const [key, record] of
|
|
79
|
+
for (const [key, record] of source)
|
|
82
80
|
if (record.terminalAt !== undefined && record.terminalAt + PROMPT_RECONCILIATION_TERMINAL_TTL_MS <= at)
|
|
83
|
-
|
|
81
|
+
source.delete(key);
|
|
84
82
|
for (const kind of ["prompt", "skill"] as const) {
|
|
85
|
-
const terminalEntries = [...
|
|
83
|
+
const terminalEntries = [...source.entries()].filter(
|
|
86
84
|
([, record]) => record.kind === kind && record.terminalAt !== undefined,
|
|
87
85
|
);
|
|
88
86
|
if (terminalEntries.length <= PROMPT_RECONCILIATION_TERMINAL_CAPACITY) continue;
|
|
89
87
|
terminalEntries.sort((a, b) => (a[1].terminalAt as number) - (b[1].terminalAt as number));
|
|
90
88
|
for (const [key] of terminalEntries.slice(0, terminalEntries.length - PROMPT_RECONCILIATION_TERMINAL_CAPACITY))
|
|
91
|
-
|
|
89
|
+
source.delete(key);
|
|
90
|
+
}
|
|
91
|
+
};
|
|
92
|
+
|
|
93
|
+
const queueMutation = async <T>(
|
|
94
|
+
mutate: (candidate: Map<string, DurableReconciliationRecord>) => { value: T; changed: boolean },
|
|
95
|
+
): Promise<T> => {
|
|
96
|
+
const run = async () => {
|
|
97
|
+
const candidate = new Map([...records].map(([key, record]) => [key, { ...record }]));
|
|
98
|
+
const result = mutate(candidate);
|
|
99
|
+
if (!result.changed) return result.value;
|
|
100
|
+
const candidateIndex = indexRecords(candidate);
|
|
101
|
+
if (store) await store.transact(() => [...candidate.values()].map(record => ({ ...record })));
|
|
102
|
+
records = candidate;
|
|
103
|
+
clientRefIndex = candidateIndex;
|
|
104
|
+
return result.value;
|
|
105
|
+
};
|
|
106
|
+
const pending = mutationChain.then(run, run);
|
|
107
|
+
mutationChain = pending.then(
|
|
108
|
+
() => undefined,
|
|
109
|
+
() => undefined,
|
|
110
|
+
);
|
|
111
|
+
return await pending;
|
|
112
|
+
};
|
|
113
|
+
|
|
114
|
+
const reservedFor = (kind: ReconciliationKind) => {
|
|
115
|
+
let set = reservedClientRefs.get(kind);
|
|
116
|
+
if (!set) {
|
|
117
|
+
set = new Set();
|
|
118
|
+
reservedClientRefs.set(kind, set);
|
|
92
119
|
}
|
|
120
|
+
return set;
|
|
121
|
+
};
|
|
122
|
+
|
|
123
|
+
const cleanup = () => {
|
|
124
|
+
cleanupRecords(records);
|
|
125
|
+
clientRefIndex = indexRecords(records);
|
|
93
126
|
};
|
|
94
127
|
|
|
95
128
|
const activeCount = (kind: ReconciliationKind) => {
|
|
@@ -98,21 +131,19 @@ export function createKindAwareReconciliation(
|
|
|
98
131
|
return count;
|
|
99
132
|
};
|
|
100
133
|
|
|
101
|
-
const reservationCount = (kind: ReconciliationKind) => reservations.filter(
|
|
134
|
+
const reservationCount = (kind: ReconciliationKind) => reservations.filter(record => record.kind === kind).length;
|
|
102
135
|
|
|
103
136
|
const consumeReservation = (kind: ReconciliationKind, clientRef?: string) => {
|
|
104
|
-
const index = reservations.findIndex(
|
|
137
|
+
const index = reservations.findIndex(record => record.kind === kind && record.clientRef === clientRef);
|
|
105
138
|
if (index === -1) return;
|
|
106
139
|
reservations.splice(index, 1);
|
|
107
|
-
if (
|
|
140
|
+
if (
|
|
141
|
+
clientRef !== undefined &&
|
|
142
|
+
!reservations.some(record => record.kind === kind && record.clientRef === clientRef)
|
|
143
|
+
)
|
|
108
144
|
reservedFor(kind).delete(clientRef);
|
|
109
145
|
};
|
|
110
146
|
|
|
111
|
-
const persist = async () => {
|
|
112
|
-
if (!store) return;
|
|
113
|
-
await store.transact(() => [...records.values()].map(r => ({ ...r })));
|
|
114
|
-
};
|
|
115
|
-
|
|
116
147
|
const admit = (kind: ReconciliationKind, clientRef?: string) => {
|
|
117
148
|
cleanup();
|
|
118
149
|
const reserved = reservedFor(kind);
|
|
@@ -139,22 +170,20 @@ export function createKindAwareReconciliation(
|
|
|
139
170
|
clientRef?: string,
|
|
140
171
|
extra?: { skillName?: string },
|
|
141
172
|
) => {
|
|
142
|
-
|
|
173
|
+
await queueMutation(candidate => {
|
|
174
|
+
cleanupRecords(candidate);
|
|
175
|
+
candidate.set(keyOf(kind, correlation), {
|
|
176
|
+
kind,
|
|
177
|
+
commandId: correlation.commandId,
|
|
178
|
+
turnId: correlation.turnId,
|
|
179
|
+
...(clientRef !== undefined ? { clientRef } : {}),
|
|
180
|
+
status: "accepted",
|
|
181
|
+
acceptedAt: now(),
|
|
182
|
+
...(extra?.skillName ? { skillName: extra.skillName } : {}),
|
|
183
|
+
});
|
|
184
|
+
return { value: undefined, changed: true };
|
|
185
|
+
});
|
|
143
186
|
consumeReservation(kind, clientRef);
|
|
144
|
-
const at = now();
|
|
145
|
-
const key = keyOf(kind, correlation);
|
|
146
|
-
const record: DurableReconciliationRecord = {
|
|
147
|
-
kind,
|
|
148
|
-
commandId: correlation.commandId,
|
|
149
|
-
turnId: correlation.turnId,
|
|
150
|
-
...(clientRef !== undefined ? { clientRef } : {}),
|
|
151
|
-
status: "accepted",
|
|
152
|
-
acceptedAt: at,
|
|
153
|
-
...(extra?.skillName ? { skillName: extra.skillName } : {}),
|
|
154
|
-
};
|
|
155
|
-
records.set(key, record);
|
|
156
|
-
if (clientRef !== undefined) clientRefIndex.set(refKey(kind, clientRef), key);
|
|
157
|
-
await persist();
|
|
158
187
|
};
|
|
159
188
|
|
|
160
189
|
const noteTransition = async (
|
|
@@ -163,27 +192,63 @@ export function createKindAwareReconciliation(
|
|
|
163
192
|
frame: { type: "agent_start" | "agent_end" } | { type: "agent_failed"; error: unknown },
|
|
164
193
|
) => {
|
|
165
194
|
if (!correlation) return;
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
if (
|
|
195
|
+
await queueMutation(candidate => {
|
|
196
|
+
const record = candidate.get(keyOf(kind, correlation));
|
|
197
|
+
if (!record || record.terminalAt !== undefined) return { value: undefined, changed: false };
|
|
198
|
+
if (frame.type === "agent_start") {
|
|
199
|
+
if (record.status !== "accepted") return { value: undefined, changed: false };
|
|
170
200
|
record.status = "in_flight";
|
|
171
201
|
record.startedAt = now();
|
|
172
|
-
|
|
202
|
+
return { value: undefined, changed: true };
|
|
173
203
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
record.status = "
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
204
|
+
record.terminalAt = now();
|
|
205
|
+
if (frame.type === "agent_failed") {
|
|
206
|
+
record.status = "failed";
|
|
207
|
+
record.error = sanitizePromptFailure(frame.error);
|
|
208
|
+
} else record.status = "terminal_ok";
|
|
209
|
+
cleanupRecords(candidate);
|
|
210
|
+
return { value: undefined, changed: true };
|
|
211
|
+
});
|
|
212
|
+
};
|
|
213
|
+
|
|
214
|
+
const claimPendingOutcome = async (
|
|
215
|
+
correlation: PromptCorrelation,
|
|
216
|
+
outcome: SdkPromptTerminalOutcome,
|
|
217
|
+
): Promise<SdkPromptTerminalOutcome> =>
|
|
218
|
+
await queueMutation(candidate => {
|
|
219
|
+
const record = candidate.get(keyOf("prompt", correlation));
|
|
220
|
+
if (!record || record.terminalAt !== undefined || record.kind !== "prompt")
|
|
221
|
+
return { value: outcome, changed: false };
|
|
222
|
+
if (record.pendingOutcome !== undefined) return { value: record.pendingOutcome, changed: false };
|
|
223
|
+
record.pendingOutcome = outcome;
|
|
224
|
+
return { value: outcome, changed: true };
|
|
225
|
+
});
|
|
226
|
+
|
|
227
|
+
const finalizePromptOutcome = async (
|
|
228
|
+
correlation: PromptCorrelation,
|
|
229
|
+
outcome?: SdkPromptTerminalOutcome,
|
|
230
|
+
recordError?: { code: string; message: string },
|
|
231
|
+
) => {
|
|
232
|
+
await queueMutation(candidate => {
|
|
233
|
+
const record = candidate.get(keyOf("prompt", correlation));
|
|
234
|
+
if (!record || record.terminalAt !== undefined || record.kind !== "prompt")
|
|
235
|
+
return { value: undefined, changed: false };
|
|
236
|
+
const finalOutcome = outcome ?? record.pendingOutcome;
|
|
237
|
+
record.terminalAt = now();
|
|
238
|
+
if (finalOutcome?.kind === "failed") {
|
|
239
|
+
record.status = "failed";
|
|
240
|
+
record.error = recordError ?? { code: finalOutcome.code, message: finalOutcome.message };
|
|
241
|
+
} else record.status = "terminal_ok";
|
|
242
|
+
record.outcome = finalOutcome;
|
|
243
|
+
record.pendingOutcome = undefined;
|
|
244
|
+
cleanupRecords(candidate);
|
|
245
|
+
return { value: undefined, changed: true };
|
|
246
|
+
});
|
|
185
247
|
};
|
|
186
248
|
|
|
249
|
+
const peekPendingOutcome = (correlation: PromptCorrelation) =>
|
|
250
|
+
records.get(keyOf("prompt", correlation))?.pendingOutcome;
|
|
251
|
+
|
|
187
252
|
const lookup = (
|
|
188
253
|
kind: ReconciliationKind,
|
|
189
254
|
selector: { commandId?: string; turnId?: string; clientRef?: string },
|
|
@@ -210,6 +275,7 @@ export function createKindAwareReconciliation(
|
|
|
210
275
|
...identity,
|
|
211
276
|
...(record.startedAt !== undefined ? { startedAt: record.startedAt } : {}),
|
|
212
277
|
terminalAt: record.terminalAt as number,
|
|
278
|
+
...(record.outcome !== undefined ? { outcome: record.outcome } : {}),
|
|
213
279
|
};
|
|
214
280
|
if (record.status === "terminal_ok") return { status: "terminal_ok", ...terminal };
|
|
215
281
|
return { status: "failed", ...terminal, error: record.error ?? sanitizePromptFailure(undefined) };
|
|
@@ -217,14 +283,20 @@ export function createKindAwareReconciliation(
|
|
|
217
283
|
|
|
218
284
|
const hydrateFromStore = async () => {
|
|
219
285
|
if (!store) return;
|
|
220
|
-
const
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
records
|
|
226
|
-
|
|
227
|
-
}
|
|
286
|
+
const run = async () => {
|
|
287
|
+
const loaded = await store.load();
|
|
288
|
+
const candidate = new Map(loaded.map(record => [keyOf(record.kind, record), { ...record }] as const));
|
|
289
|
+
const candidateIndex = indexRecords(candidate);
|
|
290
|
+
await store.transact(() => [...candidate.values()].map(record => ({ ...record })));
|
|
291
|
+
records = candidate;
|
|
292
|
+
clientRefIndex = candidateIndex;
|
|
293
|
+
};
|
|
294
|
+
const pending = mutationChain.then(run, run);
|
|
295
|
+
mutationChain = pending.then(
|
|
296
|
+
() => undefined,
|
|
297
|
+
() => undefined,
|
|
298
|
+
);
|
|
299
|
+
await pending;
|
|
228
300
|
};
|
|
229
301
|
|
|
230
302
|
return {
|
|
@@ -232,6 +304,9 @@ export function createKindAwareReconciliation(
|
|
|
232
304
|
releaseAdmission,
|
|
233
305
|
noteAccepted,
|
|
234
306
|
noteTransition,
|
|
307
|
+
claimPendingOutcome,
|
|
308
|
+
finalizePromptOutcome,
|
|
309
|
+
peekPendingOutcome,
|
|
235
310
|
lookup,
|
|
236
311
|
cleanup,
|
|
237
312
|
activeCount,
|
|
@@ -270,7 +270,10 @@ function isSafePath(value: string): boolean {
|
|
|
270
270
|
// relative are both allowed (full-trust chat), but not injection shapes.
|
|
271
271
|
if (value.length === 0 || value.length > 4096) return false;
|
|
272
272
|
if (/[\n\r\0]/.test(value)) return false;
|
|
273
|
-
|
|
273
|
+
// Backslash is a shell escape on POSIX but the native path separator on
|
|
274
|
+
// Windows; allow it there so absolute Windows paths validate correctly.
|
|
275
|
+
const metachars = process.platform === "win32" ? /[;&|`$(){}<>*?!"']/ : /[;&|`$(){}<>*?!\\"']/;
|
|
276
|
+
return !metachars.test(value);
|
|
274
277
|
}
|
|
275
278
|
|
|
276
279
|
function isSafeBranch(value: string): boolean {
|