@astrosheep/keiyaku 2.9.3 → 2.9.5
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/build/.tsbuildinfo +1 -1
- package/build/agents/call-terms.js +14 -94
- package/build/agents/harness/activity-values.js +16 -0
- package/build/agents/harness/event-persistence.js +218 -0
- package/build/agents/harness/execution-handle.js +26 -222
- package/build/agents/harness/index.js +3 -1
- package/build/agents/harness/outcome.js +68 -5
- package/build/agents/harness/projection.js +179 -124
- package/build/agents/harness/provider-adapter.js +58 -0
- package/build/agents/harness/router.js +11 -187
- package/build/agents/harness/runtime.js +17 -4
- package/build/agents/harness/session.js +15 -0
- package/build/agents/launch-snapshot/model.js +15 -236
- package/build/agents/launch-snapshot/parse-helpers.js +114 -0
- package/build/agents/launch-snapshot/resolve.js +17 -43
- package/build/agents/opencode-sdk.js +45 -12
- package/build/agents/providers/claude-agent-sdk/adapter.js +6 -17
- package/build/agents/providers/claude-agent-sdk/registration.js +214 -0
- package/build/agents/providers/claude-agent-sdk/session-schema.js +2 -0
- package/build/agents/providers/codex-app-server/adapter.js +82 -53
- package/build/agents/providers/codex-app-server/events.js +90 -11
- package/build/agents/providers/codex-app-server/identity.js +1 -0
- package/build/agents/providers/codex-app-server/policy.js +29 -0
- package/build/agents/providers/codex-app-server/registration.js +248 -0
- package/build/agents/providers/codex-app-server/session-schema.js +6 -0
- package/build/agents/providers/codex-app-server/session.js +23 -17
- package/build/agents/providers/codex-app-server/terms.js +1 -0
- package/build/agents/providers/opencode-sdk/adapter.js +94 -50
- package/build/agents/providers/opencode-sdk/events.js +8 -4
- package/build/agents/providers/opencode-sdk/registration.js +135 -0
- package/build/agents/providers/opencode-sdk/session-schema.js +2 -0
- package/build/agents/providers/opencode-sdk/session.js +21 -14
- package/build/agents/providers/opencode-sdk/terms.js +1 -0
- package/build/agents/providers/pi/adapter.js +36 -30
- package/build/agents/providers/pi/events.js +4 -3
- package/build/agents/providers/pi/registration.js +145 -0
- package/build/agents/providers/pi/session-schema.js +6 -0
- package/build/agents/providers/pi/terms.js +1 -0
- package/build/agents/providers/registration.js +7 -0
- package/build/agents/providers/registry.js +76 -0
- package/build/agents/selector.js +2 -29
- package/build/agents/types.js +10 -0
- package/build/artifact-directories.js +22 -0
- package/build/cli/commands/akuma/akuma/handler.js +1 -1
- package/build/cli/commands/akuma/akuma/meta.js +1 -1
- package/build/cli/commands/akuma/list/meta-ls.js +1 -1
- package/build/cli/commands/akuma/view/handler.js +5 -4
- package/build/cli/commands/akuma/view/meta.js +1 -1
- package/build/cli/commands/akuma.js +6 -0
- package/build/cli/commands/contract/amend/handler.js +8 -2
- package/build/cli/commands/contract/amend/meta.js +4 -4
- package/build/cli/commands/contract/arc/handler.js +8 -2
- package/build/cli/commands/contract/arc/meta.js +4 -4
- package/build/cli/commands/contract/audit/handler.js +16 -0
- package/build/cli/commands/contract/audit/meta.js +16 -0
- package/build/cli/commands/contract/bind/handler.js +4 -3
- package/build/cli/commands/contract/bind/meta.js +44 -8
- package/build/cli/commands/contract/catalog.js +2 -0
- package/build/cli/commands/contract/forfeit/handler.js +4 -4
- package/build/cli/commands/contract/forfeit/meta.js +1 -1
- package/build/cli/commands/contract/log/handler.js +3 -3
- package/build/cli/commands/contract/log/meta.js +1 -1
- package/build/cli/commands/contract/petition/handler.js +5 -8
- package/build/cli/commands/contract/petition/meta.js +6 -6
- package/build/cli/commands/contract/renew/handler.js +20 -6
- package/build/cli/commands/contract/renew/meta.js +6 -5
- package/build/cli/commands/metadata.js +59 -0
- package/build/cli/commands/projection/call/handler.js +6 -5
- package/build/cli/commands/projection/call/meta.js +4 -1
- package/build/cli/commands/projection/kill/handler.js +16 -32
- package/build/cli/commands/projection/kill/meta.js +1 -1
- package/build/cli/commands/projection/revive/meta.js +4 -1
- package/build/cli/commands/projection/shared.js +28 -0
- package/build/cli/commands/projection/status/handler.js +1 -1
- package/build/cli/commands/projection/status/meta.js +1 -1
- package/build/cli/commands/projection/tell/handler.js +14 -30
- package/build/cli/commands/projection/tell/meta.js +4 -1
- package/build/cli/commands/projection/wait/handler.js +45 -22
- package/build/cli/commands/projection/wait/meta.js +8 -3
- package/build/cli/commands/registry.js +2 -54
- package/build/cli/commands/shared.js +10 -7
- package/build/cli/commands/skills/install/handler.js +2 -5
- package/build/cli/commands/skills/install/meta.js +1 -1
- package/build/cli/commands/skills/skills/handler.js +1 -1
- package/build/cli/commands/skills/skills/meta.js +1 -1
- package/build/cli/commands/system/completion/meta.js +1 -1
- package/build/cli/commands/system/dump-env/meta.js +1 -1
- package/build/cli/commands/system/guide/meta.js +1 -1
- package/build/cli/commands/task/add/handler.js +7 -15
- package/build/cli/commands/task/add/meta.js +4 -1
- package/build/cli/commands/task/catalog.js +2 -2
- package/build/cli/commands/task/doctor/meta.js +1 -1
- package/build/cli/commands/task/done/handler.js +4 -8
- package/build/cli/commands/task/done/meta.js +1 -1
- package/build/cli/commands/task/drop/handler.js +3 -6
- package/build/cli/commands/task/drop/meta.js +1 -1
- package/build/cli/commands/task/ls/handler.js +12 -8
- package/build/cli/commands/task/ls/meta.js +3 -3
- package/build/cli/commands/task/shared.js +14 -4
- package/build/cli/commands/task/{view → show}/handler.js +7 -8
- package/build/cli/commands/task/show/meta.js +8 -0
- package/build/cli/commands/task/start/handler.js +3 -6
- package/build/cli/commands/task/start/meta.js +1 -1
- package/build/cli/commands/task/stop/handler.js +4 -8
- package/build/cli/commands/task/stop/meta.js +1 -1
- package/build/cli/commands/task/task/handler.js +1 -1
- package/build/cli/commands/task/task/meta.js +1 -1
- package/build/cli/commands/task/update/handler.js +6 -11
- package/build/cli/commands/task/update/meta.js +4 -1
- package/build/cli/completion.js +1 -1
- package/build/cli/flags.js +37 -6
- package/build/cli/help.js +7 -14
- package/build/cli/index.js +112 -154
- package/build/cli/missing-subcommand.js +7 -0
- package/build/cli/output-stream-error-policy.js +19 -5
- package/build/cli/parse-flags.js +33 -7
- package/build/cli/parse-metadata.js +3 -9
- package/build/cli/parse-selectors.js +2 -1
- package/build/cli/parse.js +35 -5
- package/build/cli/projection-address.js +12 -12
- package/build/cli/render/address.js +41 -37
- package/build/cli/render/arc.js +24 -12
- package/build/cli/render/audit.js +121 -0
- package/build/cli/render/call.js +11 -5
- package/build/cli/render/errors.js +36 -1
- package/build/cli/render/format.js +4 -0
- package/build/cli/render/kanshi.js +6 -12
- package/build/cli/render/kill.js +9 -0
- package/build/cli/render/misc.js +58 -13
- package/build/cli/render/petition.js +20 -15
- package/build/cli/render/projection-activity.js +15 -6
- package/build/cli/render/shared.js +60 -21
- package/build/cli/render/skills.js +10 -0
- package/build/cli/render/status.js +56 -23
- package/build/cli/render/success-response.js +78 -0
- package/build/cli/render/task.js +66 -57
- package/build/cli/render/tell.js +5 -0
- package/build/cli/render/terminal-failure.js +63 -0
- package/build/cli/render/types.js +1 -0
- package/build/cli/render/wait.js +68 -38
- package/build/cli/types.js +1 -1
- package/build/config/akuma-loader.js +0 -5
- package/build/config/env-keys.js +3 -1
- package/build/config/env.js +3 -0
- package/build/config/provider-policy-ownership.js +3 -32
- package/build/config/settings/disease.js +8 -1
- package/build/config/settings/loader.js +11 -3
- package/build/config/settings/provider-instance-fields.js +51 -0
- package/build/config/settings/schema.js +6 -176
- package/build/core/addressing.js +66 -16
- package/build/core/amend.js +61 -18
- package/build/core/arc.js +33 -73
- package/build/core/audit.js +650 -0
- package/build/core/bind.js +82 -35
- package/build/core/call/call.js +15 -9
- package/build/core/call/context.js +6 -51
- package/build/core/call/execution.js +22 -22
- package/build/core/call/prompt.js +14 -1
- package/build/core/command-markdown.js +45 -0
- package/build/core/context.js +13 -7
- package/build/core/contract-view.js +22 -6
- package/build/core/draft.js +139 -19
- package/build/core/entry.js +3 -4
- package/build/core/forfeit.js +5 -2
- package/build/core/hints.js +1 -75
- package/build/core/identifier-slug.js +66 -0
- package/build/core/ids.js +25 -11
- package/build/core/ledger.js +20 -68
- package/build/core/markdown/lex.js +2 -1
- package/build/core/markdown/parser.js +0 -68
- package/build/core/markdown/render.js +68 -0
- package/build/core/markdown/sections.js +2 -1
- package/build/core/outcome-base.js +4 -0
- package/build/core/projection/generation/database.js +41 -52
- package/build/core/projection/generation/model.js +63 -2
- package/build/core/{projection-generation-continuation.js → projection/generation/projection-generation-continuation.js} +3 -3
- package/build/core/{projection-generation-execution.js → projection/generation/projection-generation-execution.js} +36 -53
- package/build/core/{projection-generation-identity.js → projection/generation/projection-generation-identity.js} +2 -2
- package/build/core/{projection-generation-launcher.js → projection/generation/projection-generation-launcher.js} +9 -7
- package/build/core/{projection-generation-process.js → projection/generation/projection-generation-process.js} +2 -1
- package/build/core/{projection-generation-runner.js → projection/generation/projection-generation-runner.js} +19 -3
- package/build/core/projection/generation/store.js +3 -3
- package/build/core/projection/generation/transitions.js +19 -3
- package/build/core/projection/index.js +27 -0
- package/build/core/{projection-activity.js → projection/projection-activity.js} +12 -0
- package/build/core/{projection-alias.js → projection/projection-alias.js} +13 -13
- package/build/core/projection/projection-coordinate.js +61 -0
- package/build/core/{projection-core.js → projection/projection-core.js} +9 -9
- package/build/core/{projection-execution-observer.js → projection/projection-execution-observer.js} +37 -78
- package/build/core/{projection-identity.js → projection/projection-identity.js} +1 -1
- package/build/core/{projection-kill.js → projection/projection-kill.js} +1 -1
- package/build/core/{projection-life-observer.js → projection/projection-life-observer.js} +16 -2
- package/build/core/{projection-mint.js → projection/projection-mint.js} +10 -10
- package/build/core/{projection-status.js → projection/projection-status.js} +163 -45
- package/build/core/projection/projection-terminal-failure.js +106 -0
- package/build/core/projection/projection-wait.js +275 -0
- package/build/core/projection/projection-wake.js +227 -0
- package/build/core/provider-loader-ports.js +4 -0
- package/build/core/ref-log.js +65 -40
- package/build/core/registry.js +63 -10
- package/build/core/renew-session.js +128 -0
- package/build/core/renew.js +448 -102
- package/build/core/scope.js +272 -68
- package/build/core/seal.js +165 -40
- package/build/core/{claim-delivery.js → settlement/claim-delivery.js} +8 -8
- package/build/core/{claim.js → settlement/claim.js} +32 -8
- package/build/core/settlement/index.js +19 -0
- package/build/core/{petition-claim-gates.js → settlement/petition-claim-gates.js} +24 -49
- package/build/core/{petition-forfeit.js → settlement/petition-forfeit.js} +2 -2
- package/build/core/{petition-head-guard.js → settlement/petition-head-guard.js} +2 -2
- package/build/core/settlement/petition-io.js +1 -0
- package/build/core/{petition-preview.js → settlement/petition-preview.js} +2 -2
- package/build/core/{petition.js → settlement/petition.js} +21 -12
- package/build/core/settlement/queue-read-model.js +143 -0
- package/build/core/settlement/queue-seat-allocation.js +156 -0
- package/build/core/settlement/queue.js +6 -0
- package/build/core/settlement/settlement.js +288 -0
- package/build/core/{verdict.js → settlement/verdict.js} +9 -37
- package/build/core/settlement/verification.js +59 -0
- package/build/core/status/board.js +62 -41
- package/build/core/status/ledger-batch.js +158 -0
- package/build/core/status/reconciliation.js +10 -4
- package/build/core/stored-agent-event.js +6 -2
- package/build/core/task/board.js +41 -4
- package/build/core/task/commands.js +45 -28
- package/build/core/task/document.js +5 -0
- package/build/core/task/index.js +12 -0
- package/build/core/task/model.js +8 -1
- package/build/core/task/query.js +172 -0
- package/build/core/task/settlement-git.js +265 -74
- package/build/core/task/settlement-policy.js +67 -29
- package/build/core/task/source-board.js +1 -0
- package/build/core/task/task-contract.js +444 -0
- package/build/core/{task-doctor.js → task/task-doctor.js} +1 -1
- package/build/core/{task-git-actor.js → task/task-git-actor.js} +5 -10
- package/build/core/{task-git-runtime.js → task/task-git-runtime.js} +3 -3
- package/build/core/{task-git-store.js → task/task-git-store.js} +90 -19
- package/build/core/task/task-repository.js +1 -0
- package/build/core/{task-store-repository.js → task/task-store-repository.js} +6 -4
- package/build/core/task/task-store.js +1 -0
- package/build/core/{task-worktree.js → task/task-worktree.js} +2 -1
- package/build/core/task/task.js +7 -0
- package/build/core/task/tree.js +37 -0
- package/build/core/task/validation.js +5 -2
- package/build/core/transcripts.js +15 -3
- package/build/core/worktree-path.js +43 -28
- package/build/flow-error.js +83 -39
- package/build/fs/path-coordinate.js +16 -0
- package/build/generated/version.js +3 -2
- package/build/git/branches.js +2 -1
- package/build/git/core.js +106 -2
- package/build/git/diff/parsers.js +23 -13
- package/build/git/diff/structured.js +127 -0
- package/build/git/path-coordinate.js +17 -0
- package/build/git/refs.js +57 -0
- package/build/git/streaming-batch.js +301 -0
- package/build/git/worktree.js +65 -0
- package/build/index.js +9 -9
- package/build/keiyaku.js +2 -36
- package/build/telemetry/logger.js +4 -2
- package/package.json +4 -10
- package/skills/keiyaku/SKILL.md +5 -4
- package/skills/keiyaku-akuma/SKILL.md +25 -11
- package/skills/keiyaku-task/SKILL.md +17 -8
- package/skills/keiyaku-workflow/SKILL.md +58 -9
- package/build/agents/providers/codex-sdk.js +0 -329
- package/build/cli/commands/task/view/meta.js +0 -8
- package/build/core/command-io.js +0 -174
- package/build/core/path-coordinate.js +0 -27
- package/build/core/petition-claim.js +0 -117
- package/build/core/petition-run.js +0 -83
- package/build/core/projection-coordinate.js +0 -63
- package/build/core/projection-wait.js +0 -165
- package/build/core/projection-wake.js +0 -136
- package/build/core/queue.js +0 -343
- package/build/core/task-contract.js +0 -237
- package/build/core/task.js +0 -4
- /package/build/{core/task-repository.js → agents/launch-snapshot/types.js} +0 -0
- /package/build/{core/task-store.js → agents/providers/claude-agent-sdk/terms.js} +0 -0
- /package/build/core/{projection-generation-runtime.js → projection/generation/projection-generation-runtime.js} +0 -0
- /package/build/core/{projection-life-protocol.js → projection/projection-life-protocol.js} +0 -0
- /package/build/core/{projection-runner-lock.js → projection/projection-runner-lock.js} +0 -0
|
@@ -0,0 +1,68 @@
|
|
|
1
|
+
function renderListItemFirstLine(item) {
|
|
2
|
+
const content = renderNodeContent(item);
|
|
3
|
+
if (!content) {
|
|
4
|
+
return `${" ".repeat(item.indent)}${item.marker}`;
|
|
5
|
+
}
|
|
6
|
+
const [firstLine, ...rest] = content.split("\n");
|
|
7
|
+
const prefix = `${" ".repeat(item.indent)}${item.marker}${firstLine.length > 0 ? " " : ""}${firstLine}`;
|
|
8
|
+
if (rest.length === 0) {
|
|
9
|
+
return prefix;
|
|
10
|
+
}
|
|
11
|
+
return [prefix, ...rest].join("\n");
|
|
12
|
+
}
|
|
13
|
+
export function renderBlock(node) {
|
|
14
|
+
switch (node.type) {
|
|
15
|
+
case "section": {
|
|
16
|
+
const header = `${"#".repeat(node.level)} ${node.title}`;
|
|
17
|
+
const body = renderNodeContent(node);
|
|
18
|
+
return body ? `${header}\n${body}` : header;
|
|
19
|
+
}
|
|
20
|
+
case "list":
|
|
21
|
+
return node.items.map((item) => renderListItemFirstLine(item)).join("\n");
|
|
22
|
+
case "code_block":
|
|
23
|
+
return node.lines.join("\n");
|
|
24
|
+
case "blockquote":
|
|
25
|
+
return node.lines.map((line) => `${node.marker}${line}`).join("\n");
|
|
26
|
+
case "text":
|
|
27
|
+
return node.value;
|
|
28
|
+
case "heading":
|
|
29
|
+
return `${"#".repeat(node.level)} ${node.text}`;
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
export function renderNodeContent(node) {
|
|
33
|
+
switch (node.type) {
|
|
34
|
+
case "document":
|
|
35
|
+
return node.children.map((child) => renderBlock(child)).join("\n");
|
|
36
|
+
case "section":
|
|
37
|
+
return node.children.map((child) => renderBlock(child)).join("\n");
|
|
38
|
+
case "list":
|
|
39
|
+
return renderBlock(node);
|
|
40
|
+
case "list_item":
|
|
41
|
+
return node.children.map((child) => renderBlock(child)).join("\n");
|
|
42
|
+
case "code_block":
|
|
43
|
+
return node.lines.join("\n");
|
|
44
|
+
case "blockquote":
|
|
45
|
+
return node.lines.map((line) => `${node.marker}${line}`).join("\n");
|
|
46
|
+
case "text":
|
|
47
|
+
return node.value;
|
|
48
|
+
case "heading":
|
|
49
|
+
return `${"#".repeat(node.level)} ${node.text}`;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
export function renderSectionContent(sectionNode) {
|
|
53
|
+
return sectionNode.children.map((child) => renderBlock(child)).join("\n");
|
|
54
|
+
}
|
|
55
|
+
export function extractListItems(sectionNode) {
|
|
56
|
+
const items = [];
|
|
57
|
+
for (const child of sectionNode.children) {
|
|
58
|
+
if (child.type !== "list")
|
|
59
|
+
continue;
|
|
60
|
+
for (const item of child.items) {
|
|
61
|
+
const rendered = renderNodeContent(item).trimEnd();
|
|
62
|
+
if (rendered.trim().length > 0) {
|
|
63
|
+
items.push(rendered);
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return items;
|
|
68
|
+
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { parseToAST } from "./parser.js";
|
|
2
|
+
import { extractListItems, renderBlock, renderSectionContent } from "./render.js";
|
|
2
3
|
import { KeiyakuParseError } from "./types.js";
|
|
3
4
|
import { normalizeSectionTitle } from "./titles.js";
|
|
4
5
|
function splitByHeadingBlocks(sectionNode) {
|
|
@@ -57,11 +57,40 @@ const TELL_TABLE_SQL = `
|
|
|
57
57
|
) STRICT
|
|
58
58
|
`;
|
|
59
59
|
const closedDatabases = new WeakSet();
|
|
60
|
+
/** Classify only proved missing schema evidence as historical incompatibility. */
|
|
61
|
+
export function projectionGenerationStoreInspectionError(databasePath, error) {
|
|
62
|
+
if (error instanceof ProjectionGenerationStoreError)
|
|
63
|
+
return error;
|
|
64
|
+
const code = error && typeof error === "object" && "code" in error
|
|
65
|
+
? error.code
|
|
66
|
+
: undefined;
|
|
67
|
+
if (code === "ENOENT") {
|
|
68
|
+
return new ProjectionGenerationStoreError(`projection generation store does not exist at ${databasePath}`, {
|
|
69
|
+
cause: error,
|
|
70
|
+
observation: "incompatible",
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
return new ProjectionGenerationStoreError(`projection generation store could not be inspected at ${databasePath}`, {
|
|
74
|
+
cause: error,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
function projectionGenerationStoreReadError(databasePath, error) {
|
|
78
|
+
if (error instanceof ProjectionGenerationStoreError)
|
|
79
|
+
return error;
|
|
80
|
+
const sqliteCode = error && typeof error === "object" && "errcode" in error
|
|
81
|
+
? error.errcode
|
|
82
|
+
: undefined;
|
|
83
|
+
const incompatible = sqliteCode === 11 || sqliteCode === 26;
|
|
84
|
+
return new ProjectionGenerationStoreError(`cannot read projection generation store at ${databasePath}`, {
|
|
85
|
+
cause: error,
|
|
86
|
+
...(incompatible ? { observation: "incompatible" } : {}),
|
|
87
|
+
});
|
|
88
|
+
}
|
|
60
89
|
function pragmaNumber(database, pragma) {
|
|
61
90
|
const row = database.prepare(`PRAGMA ${pragma}`).get();
|
|
62
91
|
const value = row ? Object.values(row)[0] : undefined;
|
|
63
92
|
if (typeof value !== "number" && typeof value !== "bigint") {
|
|
64
|
-
throw new ProjectionGenerationStoreError(`PRAGMA ${pragma} returned an invalid value
|
|
93
|
+
throw new ProjectionGenerationStoreError(`PRAGMA ${pragma} returned an invalid value`, { observation: "incompatible" });
|
|
65
94
|
}
|
|
66
95
|
return Number(value);
|
|
67
96
|
}
|
|
@@ -76,7 +105,7 @@ export function rollbackQuietly(database) {
|
|
|
76
105
|
function validateSchemaShape(database) {
|
|
77
106
|
const version = pragmaNumber(database, "user_version");
|
|
78
107
|
if (version !== PROJECTION_GENERATION_SCHEMA_VERSION) {
|
|
79
|
-
throw new ProjectionGenerationStoreError(`projection generation schema version ${version}
|
|
108
|
+
throw new ProjectionGenerationStoreError(`incompatible projection generation schema version ${version}; expected ${PROJECTION_GENERATION_SCHEMA_VERSION}`, { observation: "incompatible" });
|
|
80
109
|
}
|
|
81
110
|
const objects = database.prepare(`
|
|
82
111
|
SELECT name, type
|
|
@@ -86,36 +115,36 @@ function validateSchemaShape(database) {
|
|
|
86
115
|
`).all();
|
|
87
116
|
const signature = objects.map((object) => `${object.type}:${object.name}`).join(",");
|
|
88
117
|
if (signature !== "table:generation_records,table:generation_schema,table:projection_identity,table:projection_tells") {
|
|
89
|
-
throw new ProjectionGenerationStoreError(`projection generation schema contains unexpected objects: ${signature || "none"}
|
|
118
|
+
throw new ProjectionGenerationStoreError(`projection generation schema contains unexpected objects: ${signature || "none"}`, { observation: "incompatible" });
|
|
90
119
|
}
|
|
91
120
|
const metadata = database.prepare("SELECT singleton, version FROM generation_schema").all();
|
|
92
121
|
if (metadata.length !== 1 || Number(metadata[0].singleton) !== 1 || Number(metadata[0].version) !== PROJECTION_GENERATION_SCHEMA_VERSION) {
|
|
93
|
-
throw new ProjectionGenerationStoreError("projection generation schema metadata is malformed");
|
|
122
|
+
throw new ProjectionGenerationStoreError("projection generation schema metadata is malformed", { observation: "incompatible" });
|
|
94
123
|
}
|
|
95
124
|
const recordColumns = database.prepare("PRAGMA table_info(generation_records)").all();
|
|
96
125
|
const columnSignature = recordColumns
|
|
97
126
|
.map((column) => `${column.name}:${column.type}:${Number(column.notnull)}:${Number(column.pk)}`)
|
|
98
127
|
.join(",");
|
|
99
128
|
if (columnSignature !== "seq:INTEGER:0:1,kind:TEXT:1:0,execution_id:TEXT:1:0,facts_json:TEXT:1:0") {
|
|
100
|
-
throw new ProjectionGenerationStoreError("projection generation record schema is malformed");
|
|
129
|
+
throw new ProjectionGenerationStoreError("projection generation record schema is malformed", { observation: "incompatible" });
|
|
101
130
|
}
|
|
102
131
|
const identityColumns = database.prepare("PRAGMA table_info(projection_identity)").all();
|
|
103
132
|
const identitySignature = identityColumns
|
|
104
133
|
.map((column) => `${column.name}:${column.type}:${Number(column.notnull)}:${Number(column.pk)}`)
|
|
105
134
|
.join(",");
|
|
106
135
|
if (identitySignature !== "singleton:INTEGER:0:1,version:INTEGER:1:0,pid:INTEGER:1:0,akuma:TEXT:1:0,provider:TEXT:1:0,authority_json:TEXT:1:0,binding_json:TEXT:1:0,minted_at:TEXT:1:0,workspace_root:TEXT:1:0,effective_policy_json:TEXT:0:0") {
|
|
107
|
-
throw new ProjectionGenerationStoreError("projection identity schema is malformed");
|
|
136
|
+
throw new ProjectionGenerationStoreError("projection identity schema is malformed", { observation: "incompatible" });
|
|
108
137
|
}
|
|
109
138
|
const tellColumns = database.prepare("PRAGMA table_info(projection_tells)").all();
|
|
110
139
|
const tellSignature = tellColumns
|
|
111
140
|
.map((column) => `${column.name}:${column.type}:${Number(column.notnull)}:${Number(column.pk)}`)
|
|
112
141
|
.join(",");
|
|
113
142
|
if (tellSignature !== "tell_id:TEXT:1:1,text:TEXT:1:0,created_at:TEXT:1:0,effort:TEXT:0:0,state:TEXT:1:0,execution_id:TEXT:0:0,fence_json:TEXT:0:0,replayed_from_json:TEXT:0:0,delivered_at:TEXT:0:0") {
|
|
114
|
-
throw new ProjectionGenerationStoreError("projection tell schema is malformed");
|
|
143
|
+
throw new ProjectionGenerationStoreError("projection tell schema is malformed", { observation: "incompatible" });
|
|
115
144
|
}
|
|
116
145
|
const quickCheck = database.prepare("PRAGMA quick_check").get();
|
|
117
146
|
if (!quickCheck || Object.values(quickCheck)[0] !== "ok") {
|
|
118
|
-
throw new ProjectionGenerationStoreError("projection generation database failed quick_check");
|
|
147
|
+
throw new ProjectionGenerationStoreError("projection generation database failed quick_check", { observation: "incompatible" });
|
|
119
148
|
}
|
|
120
149
|
}
|
|
121
150
|
function initializeOrValidateSchema(database) {
|
|
@@ -138,7 +167,7 @@ function initializeOrValidateSchema(database) {
|
|
|
138
167
|
database.exec(`PRAGMA user_version = ${PROJECTION_GENERATION_SCHEMA_VERSION}`);
|
|
139
168
|
}
|
|
140
169
|
else if (version !== PROJECTION_GENERATION_SCHEMA_VERSION) {
|
|
141
|
-
throw new ProjectionGenerationStoreError(`projection generation schema version ${version}
|
|
170
|
+
throw new ProjectionGenerationStoreError(`incompatible projection generation schema version ${version}; expected ${PROJECTION_GENERATION_SCHEMA_VERSION}`, { observation: "incompatible" });
|
|
142
171
|
}
|
|
143
172
|
validateSchemaShape(database);
|
|
144
173
|
database.exec("COMMIT");
|
|
@@ -195,13 +224,11 @@ export function openReadOnlyDatabase(projectionDirectory) {
|
|
|
195
224
|
const databasePath = path.join(projectionDirectory, PROJECTION_GENERATION_STORE_FILE);
|
|
196
225
|
try {
|
|
197
226
|
if (!fs.lstatSync(databasePath).isFile()) {
|
|
198
|
-
throw new ProjectionGenerationStoreError("projection generation store must be a regular file");
|
|
227
|
+
throw new ProjectionGenerationStoreError("projection generation store must be a regular file", { observation: "incompatible" });
|
|
199
228
|
}
|
|
200
229
|
}
|
|
201
230
|
catch (error) {
|
|
202
|
-
|
|
203
|
-
throw error;
|
|
204
|
-
throw new ProjectionGenerationStoreError(`projection generation store does not exist at ${databasePath}`, { cause: error });
|
|
231
|
+
throw projectionGenerationStoreInspectionError(databasePath, error);
|
|
205
232
|
}
|
|
206
233
|
let database;
|
|
207
234
|
try {
|
|
@@ -220,9 +247,7 @@ export function openReadOnlyDatabase(projectionDirectory) {
|
|
|
220
247
|
database?.close();
|
|
221
248
|
}
|
|
222
249
|
catch { /* preserve the read/open failure */ }
|
|
223
|
-
|
|
224
|
-
throw error;
|
|
225
|
-
throw new ProjectionGenerationStoreError(`cannot read projection generation store at ${databasePath}`, { cause: error });
|
|
250
|
+
throw projectionGenerationStoreReadError(databasePath, error);
|
|
226
251
|
}
|
|
227
252
|
}
|
|
228
253
|
export function assertDatabaseOpen(database) {
|
|
@@ -268,39 +293,3 @@ export function closeDatabase(database) {
|
|
|
268
293
|
closedDatabases.add(database);
|
|
269
294
|
database.close();
|
|
270
295
|
}
|
|
271
|
-
/**
|
|
272
|
-
* Discovery-only predicate: a readable regular heart whose PRAGMA user_version
|
|
273
|
-
* is exactly 1 is recognized historical residue. Never opens through the store
|
|
274
|
-
* class, never mutates, and any observation failure returns false so callers
|
|
275
|
-
* proceed into the strict current-schema reader.
|
|
276
|
-
*/
|
|
277
|
-
export function isProjectionGenerationSchemaV1Residue(projectionDirectory) {
|
|
278
|
-
const databasePath = path.join(projectionDirectory, PROJECTION_GENERATION_STORE_FILE);
|
|
279
|
-
let database;
|
|
280
|
-
let residue = false;
|
|
281
|
-
try {
|
|
282
|
-
if (!fs.lstatSync(databasePath).isFile())
|
|
283
|
-
return false;
|
|
284
|
-
database = new DatabaseSync(databasePath, {
|
|
285
|
-
readOnly: true,
|
|
286
|
-
enableDoubleQuotedStringLiterals: false,
|
|
287
|
-
allowExtension: false,
|
|
288
|
-
});
|
|
289
|
-
configureHeartBusyTimeout(database);
|
|
290
|
-
residue = pragmaNumber(database, "user_version") === 1;
|
|
291
|
-
}
|
|
292
|
-
catch {
|
|
293
|
-
return false;
|
|
294
|
-
}
|
|
295
|
-
finally {
|
|
296
|
-
if (database) {
|
|
297
|
-
try {
|
|
298
|
-
database.close();
|
|
299
|
-
}
|
|
300
|
-
catch {
|
|
301
|
-
residue = false;
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
}
|
|
305
|
-
return residue;
|
|
306
|
-
}
|
|
@@ -1,13 +1,30 @@
|
|
|
1
|
-
import { GENERATION_VERDICT_STATES, } from "
|
|
1
|
+
import { GENERATION_VERDICT_STATES, } from "../projection-life-protocol.js";
|
|
2
|
+
import { OUTCOME_ERROR_VERSION, SUBAGENT_FAILURE_CODES } from "../../../agents/types.js";
|
|
2
3
|
export { GENERATION_VERDICT_STATES };
|
|
3
4
|
export const VERDICTS = new Set(GENERATION_VERDICT_STATES);
|
|
5
|
+
const OUTCOME_ERROR_CODES = new Set(SUBAGENT_FAILURE_CODES);
|
|
6
|
+
const OUTCOME_ERROR_KEYS = new Set([
|
|
7
|
+
"version",
|
|
8
|
+
"code",
|
|
9
|
+
"message",
|
|
10
|
+
"timeoutMs",
|
|
11
|
+
"exitCode",
|
|
12
|
+
"publicCause",
|
|
13
|
+
]);
|
|
4
14
|
export class ProjectionGenerationStoreError extends Error {
|
|
5
15
|
code = "PROJECTION_GENERATION_STORE_ERROR";
|
|
16
|
+
/** Historical schemas/outcomes are not a current lifecycle observation. */
|
|
17
|
+
observation;
|
|
6
18
|
constructor(message, options) {
|
|
7
19
|
super(message, options);
|
|
8
20
|
this.name = "ProjectionGenerationStoreError";
|
|
21
|
+
this.observation = options?.observation ?? "unknown";
|
|
9
22
|
}
|
|
10
23
|
}
|
|
24
|
+
export function isIncompatibleProjectionGenerationStoreError(error) {
|
|
25
|
+
return error instanceof ProjectionGenerationStoreError
|
|
26
|
+
&& error.observation === "incompatible";
|
|
27
|
+
}
|
|
11
28
|
export function isPlainObject(value) {
|
|
12
29
|
if (value === null || typeof value !== "object" || Array.isArray(value))
|
|
13
30
|
return false;
|
|
@@ -121,6 +138,40 @@ export function validateVerdictFacts(value, location) {
|
|
|
121
138
|
if (typeof facts.state !== "string" || !VERDICTS.has(facts.state)) {
|
|
122
139
|
throw new ProjectionGenerationStoreError(`${location}.state is not in the closed verdict vocabulary`);
|
|
123
140
|
}
|
|
141
|
+
if (facts.terminalAt !== undefined) {
|
|
142
|
+
facts.terminalAt = assertIsoTimestamp(facts.terminalAt, `${location}.terminalAt`);
|
|
143
|
+
}
|
|
144
|
+
if (facts.state === "failed") {
|
|
145
|
+
const error = isPlainObject(facts.error) ? facts.error : undefined;
|
|
146
|
+
const version = error?.version;
|
|
147
|
+
if (!error || version !== OUTCOME_ERROR_VERSION) {
|
|
148
|
+
throw new ProjectionGenerationStoreError(`${location}.error has incompatible version ${version === undefined ? "missing" : String(version)}; expected ${OUTCOME_ERROR_VERSION}`, { observation: "incompatible" });
|
|
149
|
+
}
|
|
150
|
+
if (Object.keys(error).some((key) => !OUTCOME_ERROR_KEYS.has(key))) {
|
|
151
|
+
throw new ProjectionGenerationStoreError(`${location}.error is not the current closed OutcomeError shape`);
|
|
152
|
+
}
|
|
153
|
+
if (typeof error.code !== "string" || !OUTCOME_ERROR_CODES.has(error.code)) {
|
|
154
|
+
throw new ProjectionGenerationStoreError(`${location}.error.code is not a recognized subagent failure code`);
|
|
155
|
+
}
|
|
156
|
+
if (typeof error.message !== "string") {
|
|
157
|
+
throw new ProjectionGenerationStoreError(`${location}.error.message must be a string`);
|
|
158
|
+
}
|
|
159
|
+
if (error.timeoutMs !== null && (typeof error.timeoutMs !== "number"
|
|
160
|
+
|| !Number.isSafeInteger(error.timeoutMs)
|
|
161
|
+
|| error.timeoutMs < 0)) {
|
|
162
|
+
throw new ProjectionGenerationStoreError(`${location}.error.timeoutMs must be null or a non-negative safe integer`);
|
|
163
|
+
}
|
|
164
|
+
if (error.exitCode !== null && (typeof error.exitCode !== "number"
|
|
165
|
+
|| !Number.isSafeInteger(error.exitCode))) {
|
|
166
|
+
throw new ProjectionGenerationStoreError(`${location}.error.exitCode must be null or a safe integer`);
|
|
167
|
+
}
|
|
168
|
+
if (error.publicCause !== undefined) {
|
|
169
|
+
const cause = isPlainObject(error.publicCause) ? error.publicCause : undefined;
|
|
170
|
+
if (!cause || cause.kind !== "rate_limit_exhausted" || Object.keys(cause).length !== 1) {
|
|
171
|
+
throw new ProjectionGenerationStoreError(`${location}.error.publicCause is not a current closed cause`);
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
}
|
|
124
175
|
return facts;
|
|
125
176
|
}
|
|
126
177
|
export function parseStoredRow(row) {
|
|
@@ -140,7 +191,7 @@ export function parseStoredRow(row) {
|
|
|
140
191
|
decoded = JSON.parse(row.facts_json);
|
|
141
192
|
}
|
|
142
193
|
catch (error) {
|
|
143
|
-
throw new ProjectionGenerationStoreError(`generation row ${seq} contains malformed facts JSON`, { cause: error });
|
|
194
|
+
throw new ProjectionGenerationStoreError(`generation row ${seq} contains malformed facts JSON`, { cause: error, observation: "incompatible" });
|
|
144
195
|
}
|
|
145
196
|
const location = `generation row ${seq} facts`;
|
|
146
197
|
const facts = row.kind === "launch"
|
|
@@ -199,3 +250,13 @@ export function validateHistory(records) {
|
|
|
199
250
|
}
|
|
200
251
|
return current;
|
|
201
252
|
}
|
|
253
|
+
export function extractTerminalTimestamp(facts) {
|
|
254
|
+
if (!facts)
|
|
255
|
+
return undefined;
|
|
256
|
+
for (const key of ["completedAt", "failedAt", "dismissedAt", "killedAt", "terminalAt"]) {
|
|
257
|
+
const value = facts[key];
|
|
258
|
+
if (typeof value === "string" && Number.isFinite(Date.parse(value)))
|
|
259
|
+
return value;
|
|
260
|
+
}
|
|
261
|
+
return undefined;
|
|
262
|
+
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { ProjectionStateError } from "
|
|
2
|
-
import { applySnapshotEffort, parseResolvedAkumaLaunchSnapshot, } from "
|
|
3
|
-
import { listTellIds, readTellOriginal, readTellSubmitted, } from "
|
|
1
|
+
import { ProjectionStateError } from "../../atomic-publish.js";
|
|
2
|
+
import { applySnapshotEffort, parseResolvedAkumaLaunchSnapshot, } from "../../../agents/launch-snapshot/model.js";
|
|
3
|
+
import { listTellIds, readTellOriginal, readTellSubmitted, } from "../projection-core.js";
|
|
4
4
|
export function snapshotPendingTells(projectionDirectory) {
|
|
5
5
|
const pending = ["inbox", "inflight", "submitted"]
|
|
6
6
|
.flatMap((layer) => listTellIds(projectionDirectory, layer)
|
|
@@ -1,12 +1,13 @@
|
|
|
1
|
-
import { initializeConfig } from "
|
|
2
|
-
import { buildCallTerms } from "
|
|
3
|
-
import { parseResolvedAkumaLaunchSnapshot
|
|
4
|
-
import { revive, call, } from "
|
|
5
|
-
import { demoteSubmittedTellsForReplay, readProjectionEvents, } from "
|
|
6
|
-
import { createProjectionExecutionObserver,
|
|
7
|
-
import { readProjectionIdentity } from "
|
|
8
|
-
import { selectValidStoredAgentEvents } from "
|
|
9
|
-
import { persistResponseHistory } from "
|
|
1
|
+
import { initializeConfig } from "../../../config/env.js";
|
|
2
|
+
import { buildCallTerms } from "../../../agents/call-terms.js";
|
|
3
|
+
import { parseResolvedAkumaLaunchSnapshot } from "../../../agents/launch-snapshot/model.js";
|
|
4
|
+
import { revive, call, } from "../../../agents/harness/index.js";
|
|
5
|
+
import { claimFencedTells, demoteSubmittedTellsForReplay, readTellOriginal, readProjectionEvents, } from "../projection-core.js";
|
|
6
|
+
import { createProjectionExecutionObserver, renderProjectionTellFrame, } from "../projection-execution-observer.js";
|
|
7
|
+
import { readProjectionIdentity } from "../projection-identity.js";
|
|
8
|
+
import { selectValidStoredAgentEvents } from "../../stored-agent-event.js";
|
|
9
|
+
import { persistResponseHistory } from "../../transcripts.js";
|
|
10
|
+
import { attachProviderLoaderPorts, } from "../../provider-loader-ports.js";
|
|
10
11
|
function isObject(value) {
|
|
11
12
|
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
12
13
|
}
|
|
@@ -57,6 +58,7 @@ function parseLaunchInputs(launch) {
|
|
|
57
58
|
...(context ? { context } : {}),
|
|
58
59
|
launchSnapshot,
|
|
59
60
|
idleTimeoutMs: requirePositiveSafeInteger(raw.idleTimeoutMs, "idleTimeoutMs"),
|
|
61
|
+
executionTimeoutMs: requirePositiveSafeInteger(raw.executionTimeoutMs, "executionTimeoutMs"),
|
|
60
62
|
persistProjectionResponse: raw.persistProjectionResponse,
|
|
61
63
|
...(raw.session ? { session: raw.session } : {}),
|
|
62
64
|
...(resumePath ? { resumePath } : {}),
|
|
@@ -134,66 +136,47 @@ async function completionFacts(projectionDirectory, executionId, inputs, outcome
|
|
|
134
136
|
* Construct the public Projection once and expose a provider-neutral execution
|
|
135
137
|
* handle. Provider adapters and harness public types are unchanged.
|
|
136
138
|
*/
|
|
137
|
-
export function executeProjectionGeneration(projectionDirectory, launch) {
|
|
139
|
+
export function executeProjectionGeneration(projectionDirectory, launch, providerLoaderPorts = {}) {
|
|
138
140
|
const inputs = parseLaunchInputs(launch);
|
|
139
141
|
initializeConfig(process.env, inputs.cwd);
|
|
140
142
|
const executionId = launch.executionId;
|
|
141
|
-
const tellFence = launch.facts.tellFence ?? [];
|
|
142
143
|
demoteSubmittedTellsForReplay(projectionDirectory, executionId);
|
|
143
|
-
const
|
|
144
|
+
const initialTellIds = claimFencedTells(projectionDirectory, launch.facts.tellFence ?? [], executionId);
|
|
145
|
+
const tellPrompt = initialTellIds.map((tellId) => {
|
|
146
|
+
const tell = readTellOriginal(projectionDirectory, "inflight", tellId);
|
|
147
|
+
return renderProjectionTellFrame(tellId, tell.text);
|
|
148
|
+
}).join("\n\n");
|
|
149
|
+
const prompt = tellPrompt === ""
|
|
150
|
+
? inputs.prompt
|
|
151
|
+
: inputs.session
|
|
152
|
+
? tellPrompt
|
|
153
|
+
: `${inputs.prompt}\n\n${tellPrompt}`;
|
|
154
|
+
const terms = attachProviderLoaderPorts(buildCallTerms(inputs.launchSnapshot, prompt, inputs.cwd, {
|
|
144
155
|
idleTimeoutMs: inputs.idleTimeoutMs,
|
|
156
|
+
executionTimeoutMs: inputs.executionTimeoutMs,
|
|
145
157
|
initialTurn: maximumValidEnvelopeTurn(projectionDirectory),
|
|
146
|
-
});
|
|
147
|
-
const launchSnapshot = baseTerms.provider === "codex-sdk"
|
|
148
|
-
? snapshotReplayPrompt(projectionDirectory, baseTerms.prompt, tellFence, executionId, {
|
|
149
|
-
sessionContinuationPromptPrefix: inputs.session && inputs.resumePath
|
|
150
|
-
? baseTerms.sessionContinuationPromptPrefix
|
|
151
|
-
: undefined,
|
|
152
|
-
})
|
|
153
|
-
: undefined;
|
|
154
|
-
const terms = launchSnapshot
|
|
155
|
-
? baseTerms.provider === "codex-sdk" && launchSnapshot.effort
|
|
156
|
-
? {
|
|
157
|
-
...baseTerms,
|
|
158
|
-
prompt: launchSnapshot.prompt,
|
|
159
|
-
threadOptions: {
|
|
160
|
-
...baseTerms.threadOptions,
|
|
161
|
-
modelReasoningEffort: launchSnapshot.effort,
|
|
162
|
-
},
|
|
163
|
-
}
|
|
164
|
-
: { ...baseTerms, prompt: launchSnapshot.prompt }
|
|
165
|
-
: baseTerms;
|
|
166
|
-
// A constructed driver is not an SDK run acknowledgement. Tier-2 has no
|
|
167
|
-
// live steer surface, so the first provider event is the earliest harness
|
|
168
|
-
// observable start; a successful no-event completion is the only fallback.
|
|
169
|
-
const replayStartGate = launchSnapshot
|
|
170
|
-
? createReplayRunStartGate(projectionDirectory, executionId, launchSnapshot.tellIds)
|
|
171
|
-
: undefined;
|
|
158
|
+
}), providerLoaderPorts);
|
|
172
159
|
const observerController = createProjectionExecutionObserver({
|
|
173
160
|
projectionDirectory,
|
|
174
161
|
executionId,
|
|
175
|
-
|
|
162
|
+
initialTellIds,
|
|
176
163
|
});
|
|
177
164
|
let projection;
|
|
178
165
|
try {
|
|
179
|
-
projection = inputs.session
|
|
180
|
-
? revive({
|
|
166
|
+
projection = inputs.session
|
|
167
|
+
? revive({
|
|
168
|
+
...terms,
|
|
169
|
+
session: inputs.session,
|
|
170
|
+
resumePath: inputs.resumePath ?? projectionDirectory,
|
|
171
|
+
}, { observer: observerController.observer })
|
|
181
172
|
: call(terms, { observer: observerController.observer });
|
|
182
173
|
}
|
|
183
174
|
catch (error) {
|
|
184
|
-
observerController.close();
|
|
175
|
+
void observerController.close();
|
|
185
176
|
throw error;
|
|
186
177
|
}
|
|
187
178
|
const outcome = projection.outcome.then(async (result) => {
|
|
188
179
|
try {
|
|
189
|
-
if (result.status === "completed") {
|
|
190
|
-
// A provider may complete successfully without emitting any observable
|
|
191
|
-
// events. Its successful completion is still a real run start.
|
|
192
|
-
replayStartGate?.observeSuccessfulCompletion();
|
|
193
|
-
if (launchSnapshot) {
|
|
194
|
-
markReplayCompleted(projectionDirectory, executionId);
|
|
195
|
-
}
|
|
196
|
-
}
|
|
197
180
|
return {
|
|
198
181
|
verdict: result.status === "completed"
|
|
199
182
|
? "completed"
|
|
@@ -204,10 +187,10 @@ export function executeProjectionGeneration(projectionDirectory, launch) {
|
|
|
204
187
|
};
|
|
205
188
|
}
|
|
206
189
|
finally {
|
|
207
|
-
observerController.close();
|
|
190
|
+
await observerController.close();
|
|
208
191
|
}
|
|
209
|
-
}, (error) => {
|
|
210
|
-
observerController.close();
|
|
192
|
+
}, async (error) => {
|
|
193
|
+
await observerController.close();
|
|
211
194
|
throw error;
|
|
212
195
|
});
|
|
213
196
|
return {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { randomBytes } from "node:crypto";
|
|
2
2
|
import * as path from "node:path";
|
|
3
|
-
import { ProjectionStateError } from "
|
|
4
|
-
import { createUlid } from "
|
|
3
|
+
import { ProjectionStateError } from "../../atomic-publish.js";
|
|
4
|
+
import { createUlid } from "../../ids.js";
|
|
5
5
|
const EXECUTION_ID_PATTERN = /^[0-9A-HJKMNP-TV-Z]{26}$/;
|
|
6
6
|
export function createProjectionExecutionId(nowMs = Date.now()) {
|
|
7
7
|
return createUlid(nowMs, [...randomBytes(10)]);
|
|
@@ -1,18 +1,18 @@
|
|
|
1
1
|
import { setTimeout as delay } from "node:timers/promises";
|
|
2
|
-
import { openProjectionGenerationStore } from "./
|
|
2
|
+
import { openProjectionGenerationStore } from "./store.js";
|
|
3
3
|
import { spawnProjectionGenerationRunner, } from "./projection-generation-process.js";
|
|
4
4
|
export const PROJECTION_ADOPTION_TIMEOUT_MS = 4_000;
|
|
5
5
|
export const PROJECTION_ADOPTION_POLL_MS = 20;
|
|
6
6
|
function errorDetail(error) {
|
|
7
7
|
return error instanceof Error ? error.message : String(error);
|
|
8
8
|
}
|
|
9
|
-
function recordLaunchFailure(projectionDirectory, executionId, detail, stage) {
|
|
9
|
+
function recordLaunchFailure(projectionDirectory, executionId, detail, stage, terminalAt) {
|
|
10
10
|
const store = openProjectionGenerationStore(projectionDirectory);
|
|
11
11
|
try {
|
|
12
12
|
return store.verdictIfOpen({
|
|
13
13
|
executionId,
|
|
14
14
|
verdict: "launch-failed",
|
|
15
|
-
facts: { stage, detail },
|
|
15
|
+
facts: { stage, detail, ...(terminalAt ? { terminalAt } : {}) },
|
|
16
16
|
}).status === "committed";
|
|
17
17
|
}
|
|
18
18
|
finally {
|
|
@@ -29,8 +29,8 @@ export async function startProjectionGeneration(projectionDirectory, executionId
|
|
|
29
29
|
}
|
|
30
30
|
catch (error) {
|
|
31
31
|
const detail = `runner spawn failed: ${errorDetail(error)}`;
|
|
32
|
-
recordLaunchFailure(projectionDirectory, executionId, detail, "spawn");
|
|
33
|
-
return { status: "failed", detail };
|
|
32
|
+
recordLaunchFailure(projectionDirectory, executionId, detail, "spawn", new Date(now()).toISOString());
|
|
33
|
+
return { status: "failed", cause: "spawn", detail };
|
|
34
34
|
}
|
|
35
35
|
const deadline = now() + PROJECTION_ADOPTION_TIMEOUT_MS;
|
|
36
36
|
for (;;) {
|
|
@@ -41,6 +41,7 @@ export async function startProjectionGeneration(projectionDirectory, executionId
|
|
|
41
41
|
if (current?.launch.executionId !== executionId) {
|
|
42
42
|
return {
|
|
43
43
|
status: "failed",
|
|
44
|
+
cause: "adoption",
|
|
44
45
|
detail: "launch stopped being current before adoption",
|
|
45
46
|
};
|
|
46
47
|
}
|
|
@@ -49,6 +50,7 @@ export async function startProjectionGeneration(projectionDirectory, executionId
|
|
|
49
50
|
if (current.verdict) {
|
|
50
51
|
return {
|
|
51
52
|
status: "failed",
|
|
53
|
+
cause: "adoption",
|
|
52
54
|
detail: typeof current.verdict.facts.detail === "string"
|
|
53
55
|
? current.verdict.facts.detail
|
|
54
56
|
: `launch ended as ${String(current.verdict.facts.state)}`,
|
|
@@ -73,7 +75,7 @@ export async function startProjectionGeneration(projectionDirectory, executionId
|
|
|
73
75
|
store.close();
|
|
74
76
|
}
|
|
75
77
|
const detail = "runner did not commit adoption before startup timeout";
|
|
76
|
-
if (!recordLaunchFailure(projectionDirectory, executionId, detail, "adoption")) {
|
|
78
|
+
if (!recordLaunchFailure(projectionDirectory, executionId, detail, "adoption", new Date(now()).toISOString())) {
|
|
77
79
|
const raced = openProjectionGenerationStore(projectionDirectory);
|
|
78
80
|
try {
|
|
79
81
|
const current = raced.readCurrentGeneration();
|
|
@@ -86,5 +88,5 @@ export async function startProjectionGeneration(projectionDirectory, executionId
|
|
|
86
88
|
}
|
|
87
89
|
}
|
|
88
90
|
child.kill("SIGTERM");
|
|
89
|
-
return { status: "failed", detail };
|
|
91
|
+
return { status: "failed", cause: "adoption", detail };
|
|
90
92
|
}
|
|
@@ -4,7 +4,8 @@ import { spawn as nodeSpawn } from "node:child_process";
|
|
|
4
4
|
import { fileURLToPath } from "node:url";
|
|
5
5
|
import { executionStdioLogPath } from "./projection-generation-identity.js";
|
|
6
6
|
const MODULE_FILE = fileURLToPath(import.meta.url);
|
|
7
|
-
|
|
7
|
+
// Lives at src/core/projection/generation/ — four levels up is the package root.
|
|
8
|
+
const PACKAGE_ROOT = path.resolve(path.dirname(MODULE_FILE), "..", "..", "..", "..");
|
|
8
9
|
const RUNNER_ENTRY = MODULE_FILE.endsWith(".ts")
|
|
9
10
|
? [process.execPath, "--import", "tsx", path.join(PACKAGE_ROOT, "src", "index.ts")]
|
|
10
11
|
: [process.execPath, path.join(PACKAGE_ROOT, "build", "index.js")];
|
|
@@ -1,8 +1,9 @@
|
|
|
1
|
-
import { openProjectionGenerationStore, } from "./
|
|
2
|
-
import { acquireProjectionRunnerLock, observeProjectionRunnerLock, } from "
|
|
1
|
+
import { openProjectionGenerationStore, } from "./store.js";
|
|
2
|
+
import { acquireProjectionRunnerLock, observeProjectionRunnerLock, } from "../projection-runner-lock.js";
|
|
3
3
|
import { createProjectionExecutionId } from "./projection-generation-identity.js";
|
|
4
4
|
import { applyContinuationEffort, } from "./projection-generation-continuation.js";
|
|
5
|
-
import { openProjectionTellObserver } from "
|
|
5
|
+
import { openProjectionTellObserver } from "../tell/database.js";
|
|
6
|
+
import { OUTCOME_ERROR_VERSION } from "../../../agents/types.js";
|
|
6
7
|
/** Private runner-side kill grace. Not a setting, env, parameter, or export. */
|
|
7
8
|
const KILL_GRACE_MS = 5000;
|
|
8
9
|
function successorLaunchFacts(launch, completionFacts, effort, now) {
|
|
@@ -228,6 +229,13 @@ export async function runProjectionGeneration(input) {
|
|
|
228
229
|
diagnostic: "escalation-failed",
|
|
229
230
|
detail: errorDetail(error),
|
|
230
231
|
failedAt: new Date(now()).toISOString(),
|
|
232
|
+
error: {
|
|
233
|
+
version: OUTCOME_ERROR_VERSION,
|
|
234
|
+
code: "SUBAGENT_EXEC_ERROR",
|
|
235
|
+
message: errorDetail(error),
|
|
236
|
+
timeoutMs: null,
|
|
237
|
+
exitCode: null,
|
|
238
|
+
},
|
|
231
239
|
},
|
|
232
240
|
});
|
|
233
241
|
// Durably completed after the failed verdict; outer catch must not overwrite.
|
|
@@ -278,6 +286,7 @@ export async function runProjectionGeneration(input) {
|
|
|
278
286
|
facts: {
|
|
279
287
|
stage: "spawn",
|
|
280
288
|
detail: `successor runner spawn failed: ${errorDetail(error)}`,
|
|
289
|
+
terminalAt: new Date(now()).toISOString(),
|
|
281
290
|
},
|
|
282
291
|
});
|
|
283
292
|
}
|
|
@@ -315,6 +324,13 @@ export async function runProjectionGeneration(input) {
|
|
|
315
324
|
facts: {
|
|
316
325
|
failedAt: new Date(now()).toISOString(),
|
|
317
326
|
detail: error instanceof Error ? error.message : String(error),
|
|
327
|
+
error: {
|
|
328
|
+
version: OUTCOME_ERROR_VERSION,
|
|
329
|
+
code: "SUBAGENT_EXEC_ERROR",
|
|
330
|
+
message: error instanceof Error ? error.message : String(error),
|
|
331
|
+
timeoutMs: null,
|
|
332
|
+
exitCode: null,
|
|
333
|
+
},
|
|
318
334
|
},
|
|
319
335
|
});
|
|
320
336
|
}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { PROJECTION_GENERATION_SCHEMA_VERSION, PROJECTION_GENERATION_STORE_FILE, assertDatabaseOpen, closeDatabase,
|
|
1
|
+
import { PROJECTION_GENERATION_SCHEMA_VERSION, PROJECTION_GENERATION_STORE_FILE, assertDatabaseOpen, closeDatabase, openMutableDatabase, openReadOnlyDatabase, readValidatedHistory, } from "./database.js";
|
|
2
2
|
import { initializeIdentity as initializeProjectionIdentity, readIdentity as readProjectionIdentity, } from "./identity.js";
|
|
3
3
|
import * as transitions from "./transitions.js";
|
|
4
|
-
export { PROJECTION_GENERATION_SCHEMA_VERSION, PROJECTION_GENERATION_STORE_FILE,
|
|
5
|
-
export { GENERATION_VERDICT_STATES, ProjectionGenerationStoreError, } from "./model.js";
|
|
4
|
+
export { PROJECTION_GENERATION_SCHEMA_VERSION, PROJECTION_GENERATION_STORE_FILE, };
|
|
5
|
+
export { GENERATION_VERDICT_STATES, isIncompatibleProjectionGenerationStoreError, ProjectionGenerationStoreError, } from "./model.js";
|
|
6
6
|
export class ProjectionGenerationStore {
|
|
7
7
|
databasePath;
|
|
8
8
|
readOnly;
|