@astrosheep/keiyaku 2.9.2 → 2.9.4

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.
Files changed (238) hide show
  1. package/build/.tsbuildinfo +1 -1
  2. package/build/agents/call-terms.js +13 -94
  3. package/build/agents/harness/activity-values.js +16 -0
  4. package/build/agents/harness/event-persistence.js +218 -0
  5. package/build/agents/harness/execution-handle.js +25 -222
  6. package/build/agents/harness/index.js +3 -1
  7. package/build/agents/harness/outcome.js +47 -4
  8. package/build/agents/harness/projection.js +42 -59
  9. package/build/agents/harness/provider-adapter.js +58 -0
  10. package/build/agents/harness/router.js +11 -187
  11. package/build/agents/harness/runtime.js +17 -4
  12. package/build/agents/harness/session.js +15 -0
  13. package/build/agents/launch-snapshot/model.js +15 -236
  14. package/build/agents/launch-snapshot/parse-helpers.js +114 -0
  15. package/build/agents/launch-snapshot/resolve.js +17 -43
  16. package/build/agents/opencode-sdk.js +45 -12
  17. package/build/agents/providers/claude-agent-sdk/adapter.js +6 -17
  18. package/build/agents/providers/claude-agent-sdk/registration.js +214 -0
  19. package/build/agents/providers/claude-agent-sdk/session-schema.js +2 -0
  20. package/build/agents/providers/codex-app-server/adapter.js +50 -53
  21. package/build/agents/providers/codex-app-server/events.js +67 -11
  22. package/build/agents/providers/codex-app-server/identity.js +1 -0
  23. package/build/agents/providers/codex-app-server/policy.js +29 -0
  24. package/build/agents/providers/codex-app-server/registration.js +248 -0
  25. package/build/agents/providers/codex-app-server/session-schema.js +6 -0
  26. package/build/agents/providers/codex-app-server/session.js +23 -17
  27. package/build/agents/providers/codex-app-server/terms.js +1 -0
  28. package/build/agents/providers/opencode-sdk/adapter.js +94 -50
  29. package/build/agents/providers/opencode-sdk/events.js +8 -4
  30. package/build/agents/providers/opencode-sdk/registration.js +135 -0
  31. package/build/agents/providers/opencode-sdk/session-schema.js +2 -0
  32. package/build/agents/providers/opencode-sdk/session.js +21 -14
  33. package/build/agents/providers/opencode-sdk/terms.js +1 -0
  34. package/build/agents/providers/pi/adapter.js +36 -30
  35. package/build/agents/providers/pi/registration.js +145 -0
  36. package/build/agents/providers/pi/session-schema.js +6 -0
  37. package/build/agents/providers/pi/terms.js +1 -0
  38. package/build/agents/providers/registration.js +7 -0
  39. package/build/agents/providers/registry.js +76 -0
  40. package/build/agents/selector.js +2 -29
  41. package/build/agents/types.js +8 -0
  42. package/build/artifact-directories.js +22 -0
  43. package/build/cli/commands/akuma/akuma/handler.js +1 -1
  44. package/build/cli/commands/akuma/view/handler.js +5 -4
  45. package/build/cli/commands/akuma.js +6 -0
  46. package/build/cli/commands/contract/amend/handler.js +8 -2
  47. package/build/cli/commands/contract/arc/handler.js +7 -1
  48. package/build/cli/commands/contract/bind/handler.js +4 -3
  49. package/build/cli/commands/contract/bind/meta.js +34 -7
  50. package/build/cli/commands/contract/forfeit/handler.js +4 -4
  51. package/build/cli/commands/contract/log/handler.js +3 -3
  52. package/build/cli/commands/contract/petition/handler.js +4 -6
  53. package/build/cli/commands/contract/renew/handler.js +20 -6
  54. package/build/cli/commands/contract/renew/meta.js +5 -4
  55. package/build/cli/commands/metadata.js +58 -0
  56. package/build/cli/commands/projection/call/handler.js +6 -5
  57. package/build/cli/commands/projection/kill/handler.js +16 -32
  58. package/build/cli/commands/projection/shared.js +28 -0
  59. package/build/cli/commands/projection/status/handler.js +1 -1
  60. package/build/cli/commands/projection/tell/handler.js +14 -30
  61. package/build/cli/commands/projection/wait/handler.js +45 -22
  62. package/build/cli/commands/projection/wait/meta.js +7 -2
  63. package/build/cli/commands/registry.js +2 -54
  64. package/build/cli/commands/shared.js +10 -7
  65. package/build/cli/commands/skills/install/handler.js +2 -5
  66. package/build/cli/commands/skills/skills/handler.js +1 -1
  67. package/build/cli/commands/task/add/handler.js +5 -13
  68. package/build/cli/commands/task/catalog.js +2 -2
  69. package/build/cli/commands/task/done/handler.js +4 -8
  70. package/build/cli/commands/task/drop/handler.js +3 -6
  71. package/build/cli/commands/task/ls/handler.js +3 -5
  72. package/build/cli/commands/task/shared.js +14 -4
  73. package/build/cli/commands/task/{view → show}/handler.js +7 -8
  74. package/build/cli/commands/task/show/meta.js +8 -0
  75. package/build/cli/commands/task/start/handler.js +3 -6
  76. package/build/cli/commands/task/stop/handler.js +4 -8
  77. package/build/cli/commands/task/task/handler.js +1 -1
  78. package/build/cli/commands/task/update/handler.js +4 -8
  79. package/build/cli/completion.js +1 -1
  80. package/build/cli/flags.js +19 -3
  81. package/build/cli/help.js +4 -11
  82. package/build/cli/index.js +57 -83
  83. package/build/cli/missing-subcommand.js +7 -0
  84. package/build/cli/parse-flags.js +14 -5
  85. package/build/cli/parse-metadata.js +3 -3
  86. package/build/cli/parse-selectors.js +1 -1
  87. package/build/cli/parse.js +21 -0
  88. package/build/cli/projection-address.js +7 -12
  89. package/build/cli/render/address.js +41 -37
  90. package/build/cli/render/arc.js +24 -12
  91. package/build/cli/render/call.js +11 -5
  92. package/build/cli/render/errors.js +36 -1
  93. package/build/cli/render/format.js +4 -0
  94. package/build/cli/render/kanshi.js +6 -12
  95. package/build/cli/render/kill.js +9 -0
  96. package/build/cli/render/misc.js +55 -12
  97. package/build/cli/render/petition.js +20 -15
  98. package/build/cli/render/projection-activity.js +3 -0
  99. package/build/cli/render/shared.js +60 -21
  100. package/build/cli/render/skills.js +10 -0
  101. package/build/cli/render/status.js +37 -14
  102. package/build/cli/render/success-response.js +77 -0
  103. package/build/cli/render/task.js +54 -14
  104. package/build/cli/render/tell.js +5 -0
  105. package/build/cli/render/terminal-failure.js +58 -0
  106. package/build/cli/render/types.js +1 -0
  107. package/build/cli/render/wait.js +38 -36
  108. package/build/cli/types.js +1 -1
  109. package/build/config/akuma-loader.js +0 -5
  110. package/build/config/env-keys.js +1 -1
  111. package/build/config/provider-policy-ownership.js +3 -32
  112. package/build/config/settings/disease.js +8 -1
  113. package/build/config/settings/loader.js +11 -3
  114. package/build/config/settings/provider-instance-fields.js +51 -0
  115. package/build/config/settings/schema.js +6 -176
  116. package/build/core/addressing.js +66 -16
  117. package/build/core/amend.js +135 -18
  118. package/build/core/arc.js +19 -67
  119. package/build/core/bind.js +82 -35
  120. package/build/core/call/call.js +15 -9
  121. package/build/core/call/context.js +6 -51
  122. package/build/core/call/execution.js +21 -22
  123. package/build/core/call/prompt.js +14 -1
  124. package/build/core/command-markdown.js +45 -0
  125. package/build/core/context.js +13 -7
  126. package/build/core/contract-view.js +20 -3
  127. package/build/core/draft.js +123 -16
  128. package/build/core/forfeit.js +5 -2
  129. package/build/core/hints.js +1 -75
  130. package/build/core/identifier-slug.js +66 -0
  131. package/build/core/ids.js +25 -11
  132. package/build/core/ledger.js +20 -68
  133. package/build/core/markdown/parser.js +0 -68
  134. package/build/core/markdown/render.js +68 -0
  135. package/build/core/markdown/sections.js +2 -1
  136. package/build/core/outcome-base.js +4 -0
  137. package/build/core/projection/generation/database.js +2 -38
  138. package/build/core/projection/generation/model.js +42 -1
  139. package/build/core/{projection-generation-continuation.js → projection/generation/projection-generation-continuation.js} +3 -3
  140. package/build/core/{projection-generation-execution.js → projection/generation/projection-generation-execution.js} +19 -49
  141. package/build/core/{projection-generation-identity.js → projection/generation/projection-generation-identity.js} +2 -2
  142. package/build/core/{projection-generation-launcher.js → projection/generation/projection-generation-launcher.js} +5 -3
  143. package/build/core/{projection-generation-process.js → projection/generation/projection-generation-process.js} +2 -1
  144. package/build/core/{projection-generation-runner.js → projection/generation/projection-generation-runner.js} +18 -3
  145. package/build/core/projection/generation/store.js +2 -2
  146. package/build/core/projection/generation/transitions.js +1 -1
  147. package/build/core/projection/index.js +27 -0
  148. package/build/core/{projection-activity.js → projection/projection-activity.js} +12 -0
  149. package/build/core/{projection-alias.js → projection/projection-alias.js} +14 -19
  150. package/build/core/projection/projection-coordinate.js +61 -0
  151. package/build/core/{projection-core.js → projection/projection-core.js} +9 -9
  152. package/build/core/{projection-execution-observer.js → projection/projection-execution-observer.js} +2 -57
  153. package/build/core/{projection-identity.js → projection/projection-identity.js} +1 -1
  154. package/build/core/{projection-kill.js → projection/projection-kill.js} +1 -1
  155. package/build/core/{projection-life-observer.js → projection/projection-life-observer.js} +1 -1
  156. package/build/core/{projection-mint.js → projection/projection-mint.js} +10 -10
  157. package/build/core/{projection-status.js → projection/projection-status.js} +98 -25
  158. package/build/core/projection/projection-terminal-failure.js +104 -0
  159. package/build/core/projection/projection-wait.js +278 -0
  160. package/build/core/projection/projection-wake.js +203 -0
  161. package/build/core/provider-loader-ports.js +4 -0
  162. package/build/core/ref-log.js +65 -40
  163. package/build/core/registry.js +63 -10
  164. package/build/core/renew-session.js +128 -0
  165. package/build/core/renew.js +426 -99
  166. package/build/core/scope.js +143 -66
  167. package/build/core/seal.js +139 -35
  168. package/build/core/{claim-delivery.js → settlement/claim-delivery.js} +9 -14
  169. package/build/core/{claim.js → settlement/claim.js} +32 -8
  170. package/build/core/settlement/index.js +19 -0
  171. package/build/core/{petition-claim-gates.js → settlement/petition-claim-gates.js} +22 -18
  172. package/build/core/{petition-forfeit.js → settlement/petition-forfeit.js} +2 -2
  173. package/build/core/{petition-head-guard.js → settlement/petition-head-guard.js} +2 -2
  174. package/build/core/settlement/petition-io.js +1 -0
  175. package/build/core/{petition-preview.js → settlement/petition-preview.js} +1 -1
  176. package/build/core/{petition.js → settlement/petition.js} +12 -10
  177. package/build/core/settlement/queue-read-model.js +143 -0
  178. package/build/core/settlement/queue-seat-allocation.js +156 -0
  179. package/build/core/settlement/queue.js +6 -0
  180. package/build/core/settlement/settlement.js +295 -0
  181. package/build/core/{verdict.js → settlement/verdict.js} +9 -37
  182. package/build/core/status/board.js +24 -23
  183. package/build/core/status/ledger-batch.js +158 -0
  184. package/build/core/status/reconciliation.js +10 -4
  185. package/build/core/stored-agent-event.js +3 -0
  186. package/build/core/task/board.js +40 -4
  187. package/build/core/task/commands.js +30 -21
  188. package/build/core/task/index.js +12 -0
  189. package/build/core/task/settlement-git.js +157 -65
  190. package/build/core/task/settlement-policy.js +54 -24
  191. package/build/core/task/task-contract.js +370 -0
  192. package/build/core/{task-doctor.js → task/task-doctor.js} +1 -1
  193. package/build/core/{task-git-actor.js → task/task-git-actor.js} +5 -10
  194. package/build/core/{task-git-runtime.js → task/task-git-runtime.js} +3 -3
  195. package/build/core/{task-git-store.js → task/task-git-store.js} +92 -29
  196. package/build/core/task/task-repository.js +1 -0
  197. package/build/core/{task-store-repository.js → task/task-store-repository.js} +5 -4
  198. package/build/core/task/task-store.js +1 -0
  199. package/build/core/{task-worktree.js → task/task-worktree.js} +2 -1
  200. package/build/core/task/task.js +5 -0
  201. package/build/core/task/tree.js +37 -0
  202. package/build/core/task/validation.js +5 -2
  203. package/build/core/transcripts.js +15 -3
  204. package/build/core/worktree-path.js +43 -28
  205. package/build/flow-error.js +85 -39
  206. package/build/fs/durability.js +27 -0
  207. package/build/fs/path-coordinate.js +16 -0
  208. package/build/generated/version.js +3 -2
  209. package/build/git/branches.js +2 -1
  210. package/build/git/core.js +106 -2
  211. package/build/git/path-coordinate.js +17 -0
  212. package/build/git/refs.js +57 -0
  213. package/build/git/streaming-batch.js +301 -0
  214. package/build/git/worktree.js +65 -0
  215. package/build/index.js +3 -3
  216. package/build/keiyaku.js +2 -36
  217. package/package.json +4 -10
  218. package/skills/keiyaku/SKILL.md +3 -2
  219. package/skills/keiyaku-akuma/SKILL.md +10 -6
  220. package/skills/keiyaku-task/SKILL.md +1 -1
  221. package/skills/keiyaku-workflow/SKILL.md +25 -4
  222. package/build/agents/providers/codex-sdk.js +0 -329
  223. package/build/cli/commands/task/view/meta.js +0 -8
  224. package/build/core/command-io.js +0 -174
  225. package/build/core/path-coordinate.js +0 -27
  226. package/build/core/petition-claim.js +0 -117
  227. package/build/core/petition-run.js +0 -83
  228. package/build/core/projection-coordinate.js +0 -63
  229. package/build/core/projection-wait.js +0 -165
  230. package/build/core/projection-wake.js +0 -136
  231. package/build/core/queue.js +0 -343
  232. package/build/core/task-contract.js +0 -237
  233. package/build/core/task.js +0 -4
  234. /package/build/{core/task-repository.js → agents/launch-snapshot/types.js} +0 -0
  235. /package/build/{core/task-store.js → agents/providers/claude-agent-sdk/terms.js} +0 -0
  236. /package/build/core/{projection-generation-runtime.js → projection/generation/projection-generation-runtime.js} +0 -0
  237. /package/build/core/{projection-life-protocol.js → projection/projection-life-protocol.js} +0 -0
  238. /package/build/core/{projection-runner-lock.js → projection/projection-runner-lock.js} +0 -0
@@ -1,117 +0,0 @@
1
- import { FlowError } from "../flow-error.js";
2
- import { readContractLog } from "./log.js";
3
- import { petitionContract } from "./petition.js";
4
- import { verdictContract } from "./verdict.js";
5
- import { nextReviewResponseNumber } from "./transcripts.js";
6
- import { buildClaimGatePipeline, } from "./petition-claim-gates.js";
7
- import { assertHeadUnchanged } from "./petition-head-guard.js";
8
- async function throwClaimGateFailure(failure, input, context, dependencies) {
9
- const { cwd, contractId } = context;
10
- void contractId;
11
- void dependencies;
12
- if (failure.reviewHeadBeforeWrite) {
13
- await assertHeadUnchanged(cwd, failure.reviewHeadBeforeWrite, "claim review");
14
- }
15
- throw new FlowError(failure.code, failure.message, {
16
- hints: failure.hints,
17
- review: failure.review,
18
- });
19
- }
20
- async function runClaimGatePipelineOrThrow(input, context, dependencies) {
21
- const { verificationCommands } = await dependencies.resolveClaimGateConfig(context.cwd);
22
- let review;
23
- let reviewHeadBeforeWrite;
24
- let reviewerActor;
25
- for (const gate of buildClaimGatePipeline()) {
26
- const result = await gate.evaluate({
27
- cwd: context.cwd,
28
- contractId: context.contractId,
29
- input,
30
- verificationCommands,
31
- baseBranch: dependencies.baseBranch,
32
- reviewNumber: dependencies.reviewNumber,
33
- });
34
- if (result.review) {
35
- review = result.review;
36
- reviewHeadBeforeWrite = result.reviewHeadBeforeWrite;
37
- }
38
- if (result.reviewerActor)
39
- reviewerActor = result.reviewerActor;
40
- if (!result.pass) {
41
- await throwClaimGateFailure(result, input, context, dependencies);
42
- }
43
- }
44
- return { review, reviewHeadBeforeWrite, reviewerActor };
45
- }
46
- function maxArc(entries) {
47
- return entries.filter((entry) => entry.kind === "arc").length;
48
- }
49
- function cleanupWarnings(cleanup) {
50
- return [
51
- ...(cleanup.worktreeRemoveFailure
52
- ? [`Could not remove contract worktree ${cleanup.worktreeRemoveFailure.path}: ${cleanup.worktreeRemoveFailure.reason}`]
53
- : []),
54
- ...(cleanup.branchDeleteFailure
55
- ? [`Could not delete contract branch ${cleanup.branchDeleteFailure.name}: ${cleanup.branchDeleteFailure.reason}`]
56
- : []),
57
- ];
58
- }
59
- export async function claimKeiyaku(input, context, dependencies) {
60
- const { cwd, baseBranch, contractId } = context;
61
- const claimResult = "dangerouslyBypassGates" in input && input.dangerouslyBypassGates
62
- ? { review: undefined, reviewHeadBeforeWrite: undefined, bypassedByArchitect: true }
63
- : {
64
- ...(await runClaimGatePipelineOrThrow(input, { cwd, contractId }, {
65
- ...dependencies,
66
- baseBranch,
67
- reviewNumber: await nextReviewResponseNumber(cwd),
68
- })),
69
- bypassedByArchitect: false,
70
- };
71
- if (claimResult.review && claimResult.reviewHeadBeforeWrite) {
72
- await assertHeadUnchanged(cwd, claimResult.reviewHeadBeforeWrite, "claim review");
73
- }
74
- const oath = String(input.oath ?? "").trim();
75
- if (!oath) {
76
- throw new FlowError("OATH_MISSING", "Oath missing.");
77
- }
78
- const petition = await petitionContract({
79
- cwd,
80
- contractId,
81
- actor: "keiyaku",
82
- nowMs: Date.now(),
83
- intent: "claim",
84
- oath,
85
- waivePaths: input.waivePaths,
86
- });
87
- const log = await readContractLog({ cwd, contractId });
88
- const verdict = await verdictContract({
89
- cwd,
90
- contractId,
91
- actor: claimResult.reviewerActor ?? "keiyaku",
92
- nowMs: Date.now(),
93
- result: "approved",
94
- summary: claimResult.review?.findings?.trim() || "礼成",
95
- });
96
- if (!verdict.claimed) {
97
- throw new FlowError("INTERNAL_STATE", `approved verdict for ${contractId} did not produce an engine claim`);
98
- }
99
- const cleanup = verdict.claimed.cleanup ?? { absent: ["worktree", "branch"] };
100
- const warnings = [...(verdict.claimed.warnings ?? []), ...cleanupWarnings(cleanup)];
101
- return {
102
- status: "success",
103
- result: "merged",
104
- arc: maxArc(log.entries),
105
- currentBranch: baseBranch,
106
- baseBranch,
107
- commit: verdict.claimed.mergeCommit,
108
- mergedInto: baseBranch,
109
- ...(cleanup.deletedBranch ? { deletedBranch: cleanup.deletedBranch } : {}),
110
- cleanup,
111
- diff: `Merged contract ${contractId} with merge-tree/commit-tree CAS.`,
112
- ...(petition.sealed ? { sealed: petition.sealed } : {}),
113
- ...(warnings.length > 0
114
- ? { meta: { warnings } }
115
- : {}),
116
- };
117
- }
@@ -1,83 +0,0 @@
1
- import { assertSettingsKnobUsable } from "../config/settings/disease.js";
2
- import { loadKeiyakuSettings } from "../config/settings/loader.js";
3
- import { FlowError } from "../flow-error.js";
4
- import { readCurrentContractContext } from "./context.js";
5
- import { readLedger } from "./ledger.js";
6
- import { commissionTarget } from "./status/drift.js";
7
- import { getCurrentBranch, requireGitRepository } from "../git/branches.js";
8
- import { claimKeiyaku } from "./petition-claim.js";
9
- import { forfeitKeiyaku } from "./petition-forfeit.js";
10
- const VERDICT_DENIED_CODE = "VERDICT_DENIED";
11
- async function resolveClaimGateConfig(cwd) {
12
- const merged = {
13
- verificationCommands: [],
14
- };
15
- try {
16
- const loaded = await loadKeiyakuSettings(cwd);
17
- assertSettingsKnobUsable(loaded, "gate");
18
- const gate = loaded.knobs?.gate;
19
- if (!gate) {
20
- return merged;
21
- }
22
- merged.verificationCommands = gate.commands ?? merged.verificationCommands;
23
- return merged;
24
- }
25
- catch (error) {
26
- if (error instanceof FlowError && error.code === "INVALID_SETTINGS") {
27
- throw new FlowError(VERDICT_DENIED_CODE, `Configuration Error: ${error.message}`, {
28
- cause: error,
29
- hints: error.hints,
30
- });
31
- }
32
- throw error;
33
- }
34
- }
35
- async function loadCloseContext(cwd, requestedContractId) {
36
- await requireGitRepository(cwd, "petition");
37
- if (requestedContractId) {
38
- const ledger = await readLedger(cwd, requestedContractId);
39
- if (!ledger) {
40
- throw new FlowError("INTERNAL_STATE", `contract ${requestedContractId} not found or not active`);
41
- }
42
- const target = commissionTarget(ledger.entries);
43
- if (!target) {
44
- throw new FlowError("INTERNAL_STATE", `contract ${requestedContractId} active ledger is missing commission target`);
45
- }
46
- return {
47
- cwd,
48
- keiyakuBranch: `keiyaku/${requestedContractId}`,
49
- baseBranch: target.branch,
50
- contractId: requestedContractId,
51
- };
52
- }
53
- let contractContext;
54
- try {
55
- contractContext = await readCurrentContractContext(cwd);
56
- }
57
- catch (error) {
58
- if (!(error instanceof FlowError) || error.code !== "EMPTY_PARAM") {
59
- throw error;
60
- }
61
- throw new FlowError("NOT_ACTIVE_KEIYAKU_BRANCH", "Current workspace is not addressing an active Keiyaku contract.", { hints: ["keiyaku bind — opens a new contract"] });
62
- }
63
- const keiyakuBranch = await getCurrentBranch(cwd);
64
- return {
65
- cwd,
66
- keiyakuBranch,
67
- baseBranch: contractContext.baseBranch,
68
- contractId: contractContext.contractId,
69
- };
70
- }
71
- export async function petitionKeiyaku(input) {
72
- const context = await loadCloseContext(input.cwd, input.contractId);
73
- const { intent } = input;
74
- if (intent === "FORFEIT") {
75
- return forfeitKeiyaku(context);
76
- }
77
- if (intent === "CLAIM") {
78
- return claimKeiyaku(input, context, {
79
- resolveClaimGateConfig,
80
- });
81
- }
82
- throw new FlowError("INVALID_CLOSE_INTENT", `unsupported close intent: ${intent}`);
83
- }
@@ -1,63 +0,0 @@
1
- import { spawnSync } from "node:child_process";
2
- import * as path from "node:path";
3
- import { ProjectionStateError } from "./atomic-publish.js";
4
- import { isGitExecutableUnavailable } from "../git/core.js";
5
- import { gitCommonRootPath, resolveGitCommonRootSync } from "./path-coordinate.js";
6
- /**
7
- * Resolve projection storage root and authority from one Git probe.
8
- *
9
- * A non-bare repository uses the parent of its absolute common Git directory,
10
- * so every linked worktree shares one coordinate. Repo-free callers retain the
11
- * existing cwd-local authority until its replacement is legislated.
12
- */
13
- export function resolveProjectionCoordinate(cwd) {
14
- const result = spawnSync("git", ["rev-parse", "--is-bare-repository", "--path-format=absolute", "--git-common-dir"], {
15
- cwd,
16
- encoding: "utf8",
17
- env: {
18
- ...process.env,
19
- GIT_TERMINAL_PROMPT: "0",
20
- LC_ALL: "C",
21
- },
22
- stdio: ["ignore", "pipe", "pipe"],
23
- });
24
- if (result.error && isGitExecutableUnavailable(result.error)) {
25
- return { physicalRoot: cwd, authority: { kind: "user" } };
26
- }
27
- if (result.error) {
28
- throw new ProjectionStateError(`cannot resolve projection repository coordinate: ${result.error.message}`);
29
- }
30
- if (result.status !== 0) {
31
- const detail = result.stderr.trim();
32
- if (detail.includes("not a git repository")) {
33
- return { physicalRoot: cwd, authority: { kind: "user" } };
34
- }
35
- throw new ProjectionStateError(`cannot resolve projection repository coordinate${detail ? `: ${detail}` : ` (git exited ${String(result.status)})`}`);
36
- }
37
- const [bare, commonDir] = result.stdout.trim().split(/\r?\n/);
38
- const stableRoot = commonDir === undefined ? undefined : gitCommonRootPath(commonDir);
39
- if (bare !== "false" || !commonDir || !stableRoot || !path.isAbsolute(stableRoot)) {
40
- return { physicalRoot: cwd, authority: { kind: "user" } };
41
- }
42
- let physicalRoot;
43
- try {
44
- physicalRoot = resolveGitCommonRootSync(commonDir);
45
- }
46
- catch (error) {
47
- throw new ProjectionStateError(`cannot resolve projection repository root ${stableRoot}`, { cause: error });
48
- }
49
- return {
50
- physicalRoot,
51
- authority: { kind: "repository", stableRoot: physicalRoot },
52
- };
53
- }
54
- /**
55
- * Select the filesystem authority for repository projection state.
56
- *
57
- * A non-bare repository uses the parent of its absolute common Git directory,
58
- * so every linked worktree shares one coordinate. Repo-free callers retain the
59
- * existing cwd-local authority until its replacement is legislated.
60
- */
61
- export function projectionCoordinateRoot(cwd) {
62
- return resolveProjectionCoordinate(cwd).physicalRoot;
63
- }
@@ -1,165 +0,0 @@
1
- import { foldAgentActivity } from "./projection-activity.js";
2
- import { readGenerationEvents, } from "./projection-core.js";
3
- import { readProjectionIdentity } from "./projection-identity.js";
4
- import { PROJECTION_ADOPTION_TIMEOUT_MS } from "./projection-generation-launcher.js";
5
- import { observeProjectionLifeSnapshot } from "./projection-life-observer.js";
6
- import { selectCurrentGeneration } from "./projection-life-protocol.js";
7
- import { readProjectionTellCounts } from "./projection/tell/store.js";
8
- import { invalidActivityEventDiagnostic, selectValidStoredAgentEvents, } from "./stored-agent-event.js";
9
- const WAIT_POLL_MS = 100;
10
- function sleep(ms) {
11
- return new Promise((resolve) => setTimeout(resolve, ms));
12
- }
13
- function waitingTellCount(projectionDirectory) {
14
- const counts = readProjectionTellCounts(projectionDirectory);
15
- return counts.inbox + counts.inflight + counts.submitted + counts.delivered;
16
- }
17
- function latestValidEventAgeMs(events, nowMs) {
18
- let latest;
19
- for (const event of events) {
20
- const atMs = Date.parse(event.at);
21
- if (!Number.isFinite(atMs))
22
- continue;
23
- if (latest === undefined || atMs > latest)
24
- latest = atMs;
25
- }
26
- return latest === undefined ? undefined : Math.max(0, nowMs - latest);
27
- }
28
- function adoptionAgeMs(current, nowMs) {
29
- const adoptedAt = current?.adoption?.facts.adoptedAt;
30
- if (typeof adoptedAt !== "string")
31
- return undefined;
32
- const adoptedAtMs = Date.parse(adoptedAt);
33
- return Number.isFinite(adoptedAtMs)
34
- ? Math.max(0, nowMs - adoptedAtMs)
35
- : undefined;
36
- }
37
- function relativeEventLedgerFile(executionId) {
38
- return `${executionId}.events.jsonl`;
39
- }
40
- function timestampFact(current, nowMs) {
41
- const facts = current.verdict?.facts;
42
- for (const key of ["completedAt", "failedAt", "dismissedAt", "killedAt"]) {
43
- const value = facts?.[key];
44
- if (typeof value === "string" && Number.isFinite(Date.parse(value)))
45
- return value;
46
- }
47
- return new Date(nowMs).toISOString();
48
- }
49
- function verdictFromCurrent(current, nowMs) {
50
- if (!current.verdict)
51
- return undefined;
52
- const state = current.verdict.facts.state;
53
- if (typeof state !== "string")
54
- return undefined;
55
- const detail = current.verdict.facts.detail;
56
- return {
57
- state: state,
58
- at: timestampFact(current, nowMs),
59
- ...(typeof detail === "string" && detail.trim() ? { detail } : {}),
60
- };
61
- }
62
- function outcomeText(current) {
63
- const finalMessage = current.verdict?.facts.finalMessage;
64
- if (typeof finalMessage === "string" && finalMessage.trim())
65
- return finalMessage;
66
- const detail = current.verdict?.facts.detail;
67
- return typeof detail === "string" && detail.trim() ? detail : undefined;
68
- }
69
- function buildSnapshot(input) {
70
- const { projectionDirectory, pact, phase, current, events, malformedEvents, nowMs } = input;
71
- const anchorAt = current?.verdict ? timestampFact(current, nowMs) : new Date(nowMs).toISOString();
72
- const anchorMs = Date.parse(anchorAt);
73
- const mintedAtMs = Date.parse(pact.mintedAt);
74
- const activityAgeMs = latestValidEventAgeMs(events, nowMs)
75
- ?? adoptionAgeMs(current, nowMs);
76
- const invalidActivity = invalidActivityEventDiagnostic(malformedEvents);
77
- const responsePath = current?.verdict?.facts.responsePath;
78
- const artifactId = current?.verdict?.facts.artifactId;
79
- const sourceArtifactId = current?.verdict?.facts.sourceArtifactId;
80
- const errorFact = current?.verdict?.facts.error;
81
- const failureCode = errorFact
82
- && typeof errorFact === "object"
83
- && !Array.isArray(errorFact)
84
- && typeof errorFact.code === "string"
85
- ? errorFact.code
86
- : undefined;
87
- return {
88
- phase,
89
- observedAtMs: Number.isFinite(anchorMs) ? anchorMs : nowMs,
90
- durationMs: Number.isFinite(mintedAtMs) && Number.isFinite(anchorMs)
91
- ? Math.max(0, anchorMs - mintedAtMs)
92
- : 0,
93
- ...(activityAgeMs !== undefined ? { activityAgeMs } : {}),
94
- tellsWaiting: waitingTellCount(projectionDirectory),
95
- activity: foldAgentActivity(events),
96
- ...(invalidActivity ? { eventDiagnostics: [invalidActivity] } : {}),
97
- workspaceRoot: pact.workspaceRoot,
98
- ...(current ? {
99
- executionId: current.launch.executionId,
100
- eventLedgerFile: relativeEventLedgerFile(current.launch.executionId),
101
- } : {}),
102
- ...(typeof responsePath === "string" && responsePath.trim() ? { responsePath } : {}),
103
- ...(typeof artifactId === "string" && artifactId.trim() ? { artifactId } : {}),
104
- ...(typeof sourceArtifactId === "string" && sourceArtifactId.trim() ? { sourceArtifactId } : {}),
105
- ...(failureCode ? { failureCode } : {}),
106
- };
107
- }
108
- export async function waitForProjection(input) {
109
- const now = input.now ?? Date.now;
110
- let pact;
111
- try {
112
- pact = readProjectionIdentity(input.projectionDirectory);
113
- }
114
- catch (error) {
115
- return {
116
- state: "unknown",
117
- diagnostic: `projection identity could not be observed: ${error instanceof Error ? error.message : String(error)}`,
118
- };
119
- }
120
- const deadline = input.timeoutMs === undefined ? undefined : now() + input.timeoutMs;
121
- for (;;) {
122
- input.signal?.throwIfAborted();
123
- const observedAtMs = now();
124
- const observation = observeProjectionLifeSnapshot(input.projectionDirectory, {
125
- nowMs: observedAtMs,
126
- startupTimeoutMs: PROJECTION_ADOPTION_TIMEOUT_MS,
127
- });
128
- const current = observation.records
129
- ? selectCurrentGeneration(observation.records)
130
- : null;
131
- const life = observation.life;
132
- const verdict = current ? verdictFromCurrent(current, observedAtMs) : undefined;
133
- const terminal = verdict !== undefined;
134
- if (terminal || (deadline !== undefined && observedAtMs >= deadline)) {
135
- const stored = current
136
- ? readGenerationEvents(input.projectionDirectory, current.launch.executionId)
137
- : [];
138
- const { events, malformed } = selectValidStoredAgentEvents(stored);
139
- const snapshot = buildSnapshot({
140
- projectionDirectory: input.projectionDirectory,
141
- pact,
142
- phase: life.phase,
143
- current,
144
- events,
145
- malformedEvents: malformed,
146
- nowMs: observedAtMs,
147
- });
148
- if (terminal && current) {
149
- const text = outcomeText(current);
150
- return {
151
- state: "terminal",
152
- pact,
153
- verdict,
154
- snapshot,
155
- ...(text ? { outcomeText: text } : {}),
156
- };
157
- }
158
- return { state: "timeout", pact, snapshot };
159
- }
160
- const waitMs = deadline === undefined
161
- ? WAIT_POLL_MS
162
- : Math.max(0, Math.min(WAIT_POLL_MS, deadline - observedAtMs));
163
- await sleep(waitMs);
164
- }
165
- }
@@ -1,136 +0,0 @@
1
- import { FlowError } from "../flow-error.js";
2
- import { parseResolvedAkumaLaunchSnapshot } from "../agents/launch-snapshot/model.js";
3
- import { ProjectionStateError } from "./atomic-publish.js";
4
- import { applyContinuationEffort, snapshotPendingTells, } from "./projection-generation-continuation.js";
5
- import { createProjectionExecutionId } from "./projection-generation-identity.js";
6
- import { startProjectionGeneration } from "./projection-generation-launcher.js";
7
- import { openProjectionGenerationStore, openProjectionGenerationStoreReadOnly, } from "./projection/generation/store.js";
8
- import { PROJECTION_ADOPTION_TIMEOUT_MS } from "./projection-generation-launcher.js";
9
- import { observeProjectionLife } from "./projection-life-observer.js";
10
- import { observeProjectionRunnerLock } from "./projection-runner-lock.js";
11
- function readCurrentGeneration(projectionDirectory) {
12
- const store = openProjectionGenerationStoreReadOnly(projectionDirectory);
13
- try {
14
- return store.readCurrentGeneration();
15
- }
16
- finally {
17
- store.close();
18
- }
19
- }
20
- function successorFacts(current, snapshot, nowMs) {
21
- const verdictFacts = current.verdict?.facts;
22
- const originalInputs = current.launch.facts.inputs;
23
- const inputs = originalInputs
24
- && typeof originalInputs === "object"
25
- && !Array.isArray(originalInputs)
26
- ? originalInputs
27
- : {};
28
- const continuedInputs = {
29
- ...inputs,
30
- ...(verdictFacts?.session ? { session: verdictFacts.session } : {}),
31
- ...(typeof verdictFacts?.responsePath === "string"
32
- ? { resumePath: verdictFacts.responsePath }
33
- : {}),
34
- };
35
- const { tellFence: _oldFence, ...inherited } = current.launch.facts;
36
- return {
37
- ...inherited,
38
- createdAt: new Date(nowMs).toISOString(),
39
- launchedBy: "tell-wake",
40
- parentExecutionId: current.launch.executionId,
41
- tellFence: snapshot.tellIds,
42
- inputs: applyContinuationEffort(continuedInputs, snapshot.effort),
43
- };
44
- }
45
- export function assertTellEffortSupported(projectionDirectory, effort) {
46
- if (!effort)
47
- return;
48
- const current = readCurrentGeneration(projectionDirectory);
49
- if (!current)
50
- throw new ProjectionStateError("projection has no immutable generation launch");
51
- const inputs = current.launch.facts.inputs;
52
- if (!inputs || typeof inputs !== "object" || Array.isArray(inputs)) {
53
- throw new ProjectionStateError("generation launch inputs are missing");
54
- }
55
- let launchSnapshot;
56
- try {
57
- launchSnapshot = parseResolvedAkumaLaunchSnapshot(inputs.launchSnapshot);
58
- }
59
- catch (error) {
60
- throw new ProjectionStateError("generation launch has an invalid immutable launchSnapshot", { cause: error });
61
- }
62
- if (launchSnapshot.akuma.model === undefined) {
63
- throw new FlowError("INVALID_EFFORT_OVERRIDE", `Effort '${effort}' requires an explicit model.`);
64
- }
65
- const effortOptions = launchSnapshot.akuma.effortOptions;
66
- if (effortOptions === undefined)
67
- return;
68
- if (!effortOptions.includes(effort)) {
69
- throw new FlowError("INVALID_EFFORT_OVERRIDE", `Effort '${effort}' is not permitted; legal values: ${effortOptions.join(", ")}.`);
70
- }
71
- }
72
- async function startCommittedSuccessor(projectionDirectory, executionId) {
73
- const started = await startProjectionGeneration(projectionDirectory, executionId);
74
- return started.status === "adopted" ? "woken" : "pending";
75
- }
76
- export async function tellProjection(projectionDirectory, effort) {
77
- const nowMs = Date.now();
78
- const life = observeProjectionLife(projectionDirectory, {
79
- nowMs,
80
- startupTimeoutMs: PROJECTION_ADOPTION_TIMEOUT_MS,
81
- });
82
- if (life.phase === "active")
83
- return "active";
84
- if (life.phase === "unknown" || life.phase === "minting" || life.phase === "quiescent") {
85
- return "pending";
86
- }
87
- const current = readCurrentGeneration(projectionDirectory);
88
- if (!current)
89
- return "pending";
90
- const snapshot = snapshotPendingTells(projectionDirectory);
91
- const successorExecutionId = createProjectionExecutionId(nowMs);
92
- const facts = successorFacts(current, { ...snapshot, ...(effort ? { effort } : {}) }, nowMs);
93
- const store = openProjectionGenerationStore(projectionDirectory);
94
- try {
95
- if (life.phase === "startup-timeout") {
96
- const transition = store.supersedeStartupTimeout({
97
- executionId: current.launch.executionId,
98
- observedAtMs: nowMs,
99
- startupTimeoutMs: PROJECTION_ADOPTION_TIMEOUT_MS,
100
- diagnostic: { detail: "runner did not adopt before startup timeout" },
101
- successorExecutionId,
102
- successorFacts: facts,
103
- });
104
- return transition.status === "committed"
105
- ? await startCommittedSuccessor(projectionDirectory, successorExecutionId)
106
- : "pending";
107
- }
108
- if (life.phase === "lost") {
109
- const lock = observeProjectionRunnerLock(projectionDirectory);
110
- if (lock.state !== "released")
111
- return lock.state === "held" ? "active" : "pending";
112
- const transition = store.replaceDeadRunner({
113
- executionId: current.launch.executionId,
114
- releasedLockEvidence: { observedAt: new Date(nowMs).toISOString() },
115
- successorExecutionId,
116
- successorFacts: facts,
117
- });
118
- return transition.status === "committed"
119
- ? await startCommittedSuccessor(projectionDirectory, successorExecutionId)
120
- : "pending";
121
- }
122
- if (life.phase !== "done") {
123
- return "pending";
124
- }
125
- const transition = store.launchIfSettled({
126
- executionId: successorExecutionId,
127
- facts,
128
- });
129
- if (transition.status !== "committed")
130
- return "pending";
131
- return await startCommittedSuccessor(projectionDirectory, successorExecutionId);
132
- }
133
- finally {
134
- store.close();
135
- }
136
- }