@astrosheep/keiyaku 2.8.5 → 2.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (238) hide show
  1. package/README.md +35 -15
  2. package/build/.tsbuildinfo +1 -1
  3. package/build/agents/{call-terms_v2.js → call-terms.js} +12 -8
  4. package/build/agents/harness/control-types.js +1 -0
  5. package/build/agents/harness/execution-handle.js +23 -3
  6. package/build/agents/harness/index.js +6 -607
  7. package/build/agents/harness/outcome.js +141 -0
  8. package/build/agents/harness/projection.js +310 -0
  9. package/build/agents/harness/router.js +201 -0
  10. package/build/agents/harness/runtime.js +2 -1
  11. package/build/agents/{launch-snapshot_v2.js → launch-snapshot/model.js} +69 -74
  12. package/build/agents/launch-snapshot/resolve.js +72 -0
  13. package/build/agents/opencode-sdk.js +24 -3
  14. package/build/agents/providers/{claude-agent-sdk.js → claude-agent-sdk/adapter.js} +46 -368
  15. package/build/agents/providers/claude-agent-sdk/events.js +218 -0
  16. package/build/agents/providers/claude-agent-sdk/session.js +158 -0
  17. package/build/agents/providers/codex-app-server/adapter.js +347 -0
  18. package/build/agents/providers/codex-app-server/events.js +352 -0
  19. package/build/agents/providers/codex-app-server/session.js +266 -0
  20. package/build/agents/providers/codex-sdk.js +23 -5
  21. package/build/agents/providers/opencode-sdk/adapter.js +344 -0
  22. package/build/agents/providers/opencode-sdk/events.js +354 -0
  23. package/build/agents/providers/opencode-sdk/session.js +180 -0
  24. package/build/agents/providers/pi/adapter.js +269 -0
  25. package/build/agents/providers/pi/checkpoint.js +41 -0
  26. package/build/agents/providers/pi/events.js +282 -0
  27. package/build/agents/{selector_v2.js → selector.js} +8 -6
  28. package/build/cli/commands/akuma/akuma/handler.js +4 -0
  29. package/build/cli/commands/akuma/akuma/meta.js +16 -0
  30. package/build/cli/commands/akuma/catalog.js +8 -0
  31. package/build/cli/commands/akuma/list/handler.js +15 -0
  32. package/build/cli/commands/akuma/list/meta-ls.js +9 -0
  33. package/build/cli/commands/akuma/view/handler.js +34 -0
  34. package/build/cli/commands/akuma/view/meta.js +8 -0
  35. package/build/cli/commands/akuma.js +1 -1
  36. package/build/cli/commands/contract/amend/handler.js +10 -0
  37. package/build/cli/commands/contract/amend/meta.js +12 -0
  38. package/build/cli/commands/contract/arc/handler.js +9 -0
  39. package/build/cli/commands/contract/arc/meta.js +26 -0
  40. package/build/cli/commands/contract/bind/handler.js +23 -0
  41. package/build/cli/commands/contract/bind/meta.js +30 -0
  42. package/build/cli/commands/contract/catalog.js +16 -0
  43. package/build/cli/commands/contract/forfeit/handler.js +13 -0
  44. package/build/cli/commands/contract/forfeit/meta.js +12 -0
  45. package/build/cli/commands/contract/log/handler.js +12 -0
  46. package/build/cli/commands/contract/log/meta.js +12 -0
  47. package/build/cli/commands/contract/petition/handler.js +26 -0
  48. package/build/cli/commands/contract/petition/meta.js +23 -0
  49. package/build/cli/commands/contract/renew/handler.js +10 -0
  50. package/build/cli/commands/contract/renew/meta.js +17 -0
  51. package/build/cli/commands/projection/call/handler.js +42 -0
  52. package/build/cli/commands/projection/call/meta.js +9 -0
  53. package/build/cli/commands/projection/catalog.js +14 -0
  54. package/build/cli/commands/projection/kill/handler.js +37 -0
  55. package/build/cli/commands/projection/kill/meta.js +11 -0
  56. package/build/cli/commands/projection/revive/handler.js +56 -0
  57. package/build/cli/commands/projection/revive/meta.js +9 -0
  58. package/build/cli/commands/projection/status/handler.js +25 -0
  59. package/build/cli/commands/projection/status/meta.js +9 -0
  60. package/build/cli/commands/projection/tell/handler.js +36 -0
  61. package/build/cli/commands/projection/tell/meta.js +9 -0
  62. package/build/cli/commands/projection/wait/handler.js +23 -0
  63. package/build/cli/commands/projection/wait/meta.js +11 -0
  64. package/build/cli/commands/registry.js +100 -0
  65. package/build/cli/commands/shared.js +71 -0
  66. package/build/cli/commands/skills/catalog.js +6 -0
  67. package/build/cli/commands/skills/install/handler.js +10 -0
  68. package/build/cli/commands/skills/install/meta.js +9 -0
  69. package/build/cli/commands/skills/skills/handler.js +4 -0
  70. package/build/cli/commands/skills/skills/meta.js +10 -0
  71. package/build/cli/commands/system/catalog.js +8 -0
  72. package/build/cli/commands/system/completion/handler.js +10 -0
  73. package/build/cli/commands/system/completion/meta.js +9 -0
  74. package/build/cli/commands/system/dump-env/handler.js +3 -0
  75. package/build/cli/commands/system/dump-env/meta.js +10 -0
  76. package/build/cli/commands/system/guide/handler.js +4 -0
  77. package/build/cli/commands/system/guide/meta.js +9 -0
  78. package/build/cli/commands/task/add/handler.js +21 -0
  79. package/build/cli/commands/task/add/meta.js +8 -0
  80. package/build/cli/commands/task/catalog.js +22 -0
  81. package/build/cli/commands/task/doctor/handler.js +4 -0
  82. package/build/cli/commands/task/doctor/meta.js +8 -0
  83. package/build/cli/commands/task/done/handler.js +17 -0
  84. package/build/cli/commands/task/done/meta.js +8 -0
  85. package/build/cli/commands/task/drop/handler.js +6 -0
  86. package/build/cli/commands/task/drop/meta.js +8 -0
  87. package/build/cli/commands/task/ls/handler.js +13 -0
  88. package/build/cli/commands/task/ls/meta.js +8 -0
  89. package/build/cli/commands/task/shared.js +131 -0
  90. package/build/cli/commands/task/start/handler.js +6 -0
  91. package/build/cli/commands/task/start/meta.js +8 -0
  92. package/build/cli/commands/task/stop/handler.js +17 -0
  93. package/build/cli/commands/task/stop/meta.js +8 -0
  94. package/build/cli/commands/task/task/handler.js +5 -0
  95. package/build/cli/commands/task/task/meta.js +11 -0
  96. package/build/cli/commands/task/update/handler.js +18 -0
  97. package/build/cli/commands/task/update/meta.js +8 -0
  98. package/build/cli/commands/task/view/handler.js +14 -0
  99. package/build/cli/commands/task/view/meta.js +8 -0
  100. package/build/cli/completion.js +26 -27
  101. package/build/cli/flags.js +79 -2
  102. package/build/cli/help.js +27 -49
  103. package/build/cli/index.js +121 -374
  104. package/build/cli/output-stream-error-policy.js +17 -0
  105. package/build/cli/parse-flags.js +197 -0
  106. package/build/cli/parse-metadata.js +129 -0
  107. package/build/cli/parse-selectors.js +65 -0
  108. package/build/cli/parse.js +46 -313
  109. package/build/cli/projection-address.js +5 -0
  110. package/build/cli/render/arc.js +1 -1
  111. package/build/cli/render/errors.js +4 -3
  112. package/build/cli/render/format.js +14 -0
  113. package/build/cli/render/kanshi.js +106 -0
  114. package/build/cli/render/petition.js +24 -1
  115. package/build/cli/render/projection-activity.js +5 -1
  116. package/build/cli/render/shared.js +2 -2
  117. package/build/cli/render/status.js +79 -13
  118. package/build/cli/render/task.js +113 -0
  119. package/build/cli/render/wait.js +23 -3
  120. package/build/cli/types.js +1 -1
  121. package/build/config/{akuma-loader_v2.js → akuma-loader.js} +7 -4
  122. package/build/config/env.js +9 -4
  123. package/build/config/settings/disease.js +26 -0
  124. package/build/config/settings/knobs.js +8 -0
  125. package/build/config/settings/loader.js +244 -0
  126. package/build/config/settings/schema.js +276 -0
  127. package/build/core/addressing.js +1 -1
  128. package/build/core/amend.js +5 -8
  129. package/build/core/arc.js +7 -8
  130. package/build/core/bind-workspace.js +123 -0
  131. package/build/core/bind.js +75 -155
  132. package/build/core/call/call.js +229 -0
  133. package/build/core/call/context.js +251 -0
  134. package/build/core/call/execution.js +217 -0
  135. package/build/core/call/prompt.js +42 -0
  136. package/build/core/call/reference.js +24 -0
  137. package/build/core/call-persist.js +10 -3
  138. package/build/core/claim-delivery.js +247 -0
  139. package/build/core/claim.js +39 -277
  140. package/build/core/context.js +2 -1
  141. package/build/core/{render.js → contract-view.js} +12 -140
  142. package/build/core/draft.js +107 -9
  143. package/build/core/entry.js +9 -1
  144. package/build/core/execution-coordinate.js +4 -20
  145. package/build/core/execution-pact.js +16 -31
  146. package/build/core/forfeit.js +35 -22
  147. package/build/core/hints.js +2 -2
  148. package/build/core/log.js +2 -2
  149. package/build/core/path-coordinate.js +27 -0
  150. package/build/core/petition-claim-gates.js +8 -6
  151. package/build/core/petition-preview.js +97 -0
  152. package/build/core/petition-run.js +5 -7
  153. package/build/core/petition.js +39 -26
  154. package/build/core/projection/generation/database.js +306 -0
  155. package/build/core/projection/generation/identity.js +84 -0
  156. package/build/core/projection/generation/model.js +201 -0
  157. package/build/core/projection/generation/store.js +73 -0
  158. package/build/core/projection/generation/transitions.js +258 -0
  159. package/build/core/projection/heart.js +0 -307
  160. package/build/core/projection/tell/database.js +109 -0
  161. package/build/core/projection/tell/model.js +97 -0
  162. package/build/core/{projection-tells.js → projection/tell/store.js} +3 -158
  163. package/build/core/projection-activity.js +23 -2
  164. package/build/core/projection-coordinate.js +14 -2
  165. package/build/core/projection-core.js +2 -1
  166. package/build/core/projection-execution-observer.js +259 -0
  167. package/build/core/projection-generation-continuation.js +1 -1
  168. package/build/core/projection-generation-execution.js +90 -20
  169. package/build/core/projection-generation-launcher.js +1 -1
  170. package/build/core/projection-generation-runner.js +198 -4
  171. package/build/core/projection-identity.js +1 -1
  172. package/build/core/projection-kill.js +50 -17
  173. package/build/core/projection-life-observer.js +1 -1
  174. package/build/core/projection-life-protocol.js +10 -0
  175. package/build/core/projection-mint.js +1 -1
  176. package/build/core/projection-status.js +45 -32
  177. package/build/core/projection-wait.js +12 -2
  178. package/build/core/projection-wake.js +5 -2
  179. package/build/core/{queue_v2.js → queue.js} +2 -1
  180. package/build/core/registry.js +1 -1
  181. package/build/core/renew.js +9 -11
  182. package/build/core/response-artifact-catalog-sqlite.js +112 -0
  183. package/build/core/response-artifact-catalog.js +7 -0
  184. package/build/core/seal.js +44 -16
  185. package/build/core/status/board.js +289 -0
  186. package/build/core/status/drift.js +99 -0
  187. package/build/core/status/lifecycle.js +84 -0
  188. package/build/core/status/reconciliation.js +131 -0
  189. package/build/core/stored-agent-event.js +28 -4
  190. package/build/core/target-ref.js +10 -0
  191. package/build/core/task/board.js +175 -0
  192. package/build/core/task/commands.js +211 -0
  193. package/build/core/task/document.js +189 -0
  194. package/build/core/task/model.js +1 -0
  195. package/build/core/task/settlement-git.js +207 -0
  196. package/build/core/task/settlement-policy.js +82 -0
  197. package/build/core/task/source-board.js +84 -0
  198. package/build/core/task/source-model.js +1 -0
  199. package/build/core/task/validation.js +44 -0
  200. package/build/core/task-contract.js +237 -0
  201. package/build/core/task-doctor.js +14 -0
  202. package/build/core/task-git-actor.js +38 -0
  203. package/build/core/task-git-runtime.js +37 -0
  204. package/build/core/task-git-store.js +385 -0
  205. package/build/core/task-repository.js +1 -0
  206. package/build/core/task-store-repository.js +86 -0
  207. package/build/core/task-store.js +1 -0
  208. package/build/core/task-worktree.js +51 -0
  209. package/build/core/task.js +4 -0
  210. package/build/core/transcripts.js +138 -56
  211. package/build/core/validation.js +17 -0
  212. package/build/core/verdict.js +2 -2
  213. package/build/core/worktree-path.js +33 -8
  214. package/build/flow-error.js +5 -2
  215. package/build/generated/version.js +1 -1
  216. package/build/git/branches.js +33 -9
  217. package/build/git/commits.js +3 -0
  218. package/build/git/core.js +9 -0
  219. package/build/git/diff/parsers.js +0 -94
  220. package/build/index.js +2 -0
  221. package/build/keiyaku-constants.js +2 -0
  222. package/build/keiyaku.js +4 -3
  223. package/package.json +3 -2
  224. package/skills/keiyaku/SKILL.md +30 -13
  225. package/skills/keiyaku-akuma/SKILL.md +30 -57
  226. package/skills/keiyaku-task/SKILL.md +51 -0
  227. package/skills/keiyaku-workflow/SKILL.md +71 -0
  228. package/build/agents/harness/pump.js +0 -158
  229. package/build/agents/providers/codex-app-server.js +0 -864
  230. package/build/agents/providers/opencode-sdk.js +0 -363
  231. package/build/agents/providers/pi.js +0 -557
  232. package/build/config/settings.js +0 -533
  233. package/build/core/call.js +0 -686
  234. package/build/core/projection/generation.js +0 -412
  235. package/build/core/projection/identity.js +0 -81
  236. package/build/core/projection/mint.js +0 -174
  237. package/build/core/projection-generation-store.js +0 -707
  238. package/build/core/status.js +0 -539
@@ -0,0 +1,237 @@
1
+ import { FlowError } from "../flow-error.js";
2
+ import { assertGitObservation, requireGitRepository } from "../git/branches.js";
3
+ import { withLockHeldTaskBoard } from "./task-git-store.js";
4
+ import { prepareTaskDocumentReplacements, taskRepositoryFromLockedBoard } from "./task-store-repository.js";
5
+ import { containsCommit, createLandingCommit, createTaskBoardCommit, inspectCurrentBranch, publishForwardTaskBoardCommit, readableRefHead, reconcileTaskIndex, refHead, sameTaskSourceBytes, taskContractAtCommit, taskWritesFromSources, updateBranch, updateTargetRef, } from "./task/settlement-git.js";
6
+ import { contractPointerDocument, doneTaskReplacement, reopenedTaskDocument, requireHealthySettlementBoard, requireSettledTask, selectReadyTaskForBind, taskForContract, } from "./task/settlement-policy.js";
7
+ import { stableRepoRoot } from "./worktree-path.js";
8
+ async function clearAttemptedPointer(input) {
9
+ const current = requireSettledTask(await input.repository.read(), input.task.id);
10
+ if (current.contractId === input.contractId) {
11
+ await replaceTaskDocument(input.repository, contractPointerDocument(current, undefined));
12
+ }
13
+ }
14
+ async function replaceTaskDocument(repository, replacement) {
15
+ return repository.mutate(() => ({
16
+ replacements: [replacement],
17
+ select: (resulting) => requireSettledTask(resulting, replacement.id),
18
+ }));
19
+ }
20
+ export async function settleTaskBoardForBind(input, deps = {}) {
21
+ await requireGitRepository(input.cwd, "task bind");
22
+ return withLockHeldTaskBoard(input.cwd, async (transaction) => {
23
+ if (transaction.location.mode !== "git") {
24
+ if (transaction.location.capability === "unavailable") {
25
+ assertGitObservation({ capability: "unavailable" }, "task bind");
26
+ }
27
+ throw new FlowError("NOT_GIT_REPO", "task bind requires Git task storage");
28
+ }
29
+ const hubCwd = transaction.location.root;
30
+ const repository = taskRepositoryFromLockedBoard(transaction);
31
+ const branch = inspectCurrentBranch(hubCwd);
32
+ const board = requireHealthySettlementBoard(await repository.read());
33
+ const selected = input.taskId === undefined
34
+ ? undefined
35
+ : selectReadyTaskForBind(board, input.taskId);
36
+ if (selected) {
37
+ await replaceTaskDocument(repository, contractPointerDocument(selected, input.contractId));
38
+ }
39
+ const firstCommit = createTaskBoardCommit({
40
+ cwd: hubCwd,
41
+ gitDir: transaction.location.gitDir,
42
+ root: transaction.location.root,
43
+ parent: branch.head,
44
+ sources: transaction.sources,
45
+ subject: selected
46
+ ? `Bind task ${selected.id} to contract ${input.contractId}`
47
+ : `Flush task board for contract ${input.contractId}`,
48
+ });
49
+ try {
50
+ await updateBranch({ cwd: hubCwd, ref: branch.ref, next: firstCommit, expected: branch.head }, deps);
51
+ }
52
+ catch (error) {
53
+ if (selected) {
54
+ await clearAttemptedPointer({ repository, task: selected, contractId: input.contractId });
55
+ const concurrentHead = refHead(hubCwd, branch.ref);
56
+ if (taskContractAtCommit(hubCwd, concurrentHead, selected.id) === input.contractId) {
57
+ await publishForwardTaskBoardCommit({
58
+ cwd: hubCwd,
59
+ ref: branch.ref,
60
+ gitDir: transaction.location.gitDir,
61
+ root: transaction.location.root,
62
+ sources: transaction.sources,
63
+ subject: `Clear failed contract ${input.contractId} from task ${selected.id}`,
64
+ }, deps);
65
+ }
66
+ }
67
+ throw error;
68
+ }
69
+ try {
70
+ reconcileTaskIndex(hubCwd, firstCommit);
71
+ }
72
+ catch (indexError) {
73
+ if (selected) {
74
+ await clearAttemptedPointer({ repository, task: selected, contractId: input.contractId });
75
+ await publishForwardTaskBoardCommit({
76
+ cwd: hubCwd,
77
+ ref: branch.ref,
78
+ gitDir: transaction.location.gitDir,
79
+ root: transaction.location.root,
80
+ sources: transaction.sources,
81
+ subject: `Clear failed contract ${input.contractId} from task ${selected.id}`,
82
+ }, deps);
83
+ }
84
+ throw indexError;
85
+ }
86
+ try {
87
+ const ledger = await input.publishLedger(firstCommit);
88
+ return {
89
+ boardCommit: firstCommit,
90
+ ledger,
91
+ ...(selected ? { task: requireSettledTask(await repository.read(), selected.id) } : {}),
92
+ };
93
+ }
94
+ catch (publishError) {
95
+ if (!selected)
96
+ throw publishError;
97
+ await clearAttemptedPointer({ repository, task: selected, contractId: input.contractId });
98
+ await publishForwardTaskBoardCommit({
99
+ cwd: hubCwd,
100
+ ref: branch.ref,
101
+ gitDir: transaction.location.gitDir,
102
+ root: transaction.location.root,
103
+ sources: transaction.sources,
104
+ subject: `Clear failed contract ${input.contractId} from task ${selected.id}`,
105
+ }, deps);
106
+ throw publishError;
107
+ }
108
+ });
109
+ }
110
+ export async function reconcileTaskForfeit(input) {
111
+ await requireGitRepository(input.cwd, "task forfeit");
112
+ const hubRoot = await stableRepoRoot(input.cwd);
113
+ return withLockHeldTaskBoard(hubRoot, async (transaction) => {
114
+ if (transaction.location.mode !== "git") {
115
+ if (transaction.location.capability === "unavailable") {
116
+ assertGitObservation({ capability: "unavailable" }, "task forfeit");
117
+ }
118
+ throw new FlowError("NOT_GIT_REPO", "task forfeit requires Git task storage");
119
+ }
120
+ const repository = taskRepositoryFromLockedBoard(transaction);
121
+ const matched = taskForContract(await repository.read(), input.contractId);
122
+ const ledger = await input.publishLedger();
123
+ if (!matched)
124
+ return { ledger };
125
+ const task = await replaceTaskDocument(repository, reopenedTaskDocument(matched));
126
+ return {
127
+ ledger,
128
+ task,
129
+ };
130
+ });
131
+ }
132
+ /**
133
+ * Claim owns the sole task-board settlement after target CAS. Contract branch
134
+ * task trees are fossils: the candidate is the code-only three-way merge plus
135
+ * one complete snapshot of the common hub board held under its repository lock.
136
+ */
137
+ export async function settleTaskBoardForLanding(input) {
138
+ await requireGitRepository(input.cwd, "task landing");
139
+ const hubRoot = await stableRepoRoot(input.cwd);
140
+ let lastTargetHead = input.targetHead;
141
+ let lastPublishError;
142
+ let acceptedMovement;
143
+ for (let attempt = 0; attempt < 4; attempt += 1) {
144
+ const result = await withLockHeldTaskBoard(hubRoot, async (transaction) => {
145
+ if (transaction.location.mode !== "git") {
146
+ if (transaction.location.capability === "unavailable") {
147
+ assertGitObservation({ capability: "unavailable" }, "task landing");
148
+ }
149
+ throw new FlowError("NOT_GIT_REPO", "task landing requires Git task storage");
150
+ }
151
+ // Each attempt reads fresh target and board facts while holding the
152
+ // common task lock. A losing CAS exits before the next attempt.
153
+ const targetHead = refHead(input.cwd, input.targetRef);
154
+ lastTargetHead = targetHead;
155
+ const repository = taskRepositoryFromLockedBoard(transaction);
156
+ const board = requireHealthySettlementBoard(await repository.read());
157
+ const replacement = doneTaskReplacement(board, input.contractId);
158
+ const prepared = replacement
159
+ ? prepareTaskDocumentReplacements(transaction.sources, [replacement])
160
+ : { sources: transaction.sources, board };
161
+ const finalSources = prepared.sources;
162
+ requireHealthySettlementBoard(prepared.board);
163
+ let mergeCommit = targetHead;
164
+ let movement = acceptedMovement?.mergeCommit === targetHead ? acceptedMovement : undefined;
165
+ if (!containsCommit(input.cwd, input.deliveryHead, targetHead)) {
166
+ mergeCommit = createLandingCommit({
167
+ cwd: input.cwd,
168
+ gitDir: transaction.location.gitDir,
169
+ root: transaction.location.root,
170
+ base: input.baseCommit,
171
+ target: targetHead,
172
+ delivery: input.deliveryHead,
173
+ sources: finalSources,
174
+ contractId: input.contractId,
175
+ targetBranch: input.targetBranch,
176
+ });
177
+ await input.beforeCas?.(mergeCommit, targetHead);
178
+ try {
179
+ updateTargetRef(input.cwd, input.targetRef, mergeCommit, targetHead);
180
+ movement = { mergeCommit, oldHead: targetHead };
181
+ acceptedMovement = movement;
182
+ }
183
+ catch {
184
+ const current = readableRefHead(input.cwd, input.targetRef);
185
+ if (!current || !containsCommit(input.cwd, input.deliveryHead, current)) {
186
+ return { kind: "retry" };
187
+ }
188
+ mergeCommit = current;
189
+ movement = acceptedMovement?.mergeCommit === mergeCommit ? acceptedMovement : undefined;
190
+ }
191
+ }
192
+ const warnings = [];
193
+ if (!sameTaskSourceBytes(transaction.location.root, transaction.sources, finalSources)) {
194
+ await transaction.replace(taskWritesFromSources(finalSources));
195
+ }
196
+ try {
197
+ reconcileTaskIndex(transaction.location.root, mergeCommit);
198
+ }
199
+ catch (error) {
200
+ warnings.push(`Accepted landing ${mergeCommit}, but task index reconciliation failed: ${error instanceof Error ? error.message : String(error)}`);
201
+ }
202
+ try {
203
+ await input.publishLedger?.(mergeCommit);
204
+ }
205
+ catch (error) {
206
+ lastPublishError = error;
207
+ return { kind: "retry" };
208
+ }
209
+ const reconcileWarnings = movement
210
+ ? await input.afterCas?.(mergeCommit, movement.oldHead)
211
+ : undefined;
212
+ warnings.push(...(reconcileWarnings ?? []));
213
+ return {
214
+ kind: movement ? "accepted" : "idempotent",
215
+ mergeCommit,
216
+ ...(movement ? { oldHead: movement.oldHead } : {}),
217
+ ...(warnings.length > 0 ? { warnings } : {}),
218
+ };
219
+ });
220
+ if (result.kind === "retry")
221
+ continue;
222
+ if (result.kind === "idempotent") {
223
+ return {
224
+ mergeCommit: result.mergeCommit,
225
+ ...(result.warnings ? { warnings: result.warnings } : {}),
226
+ };
227
+ }
228
+ return {
229
+ mergeCommit: result.mergeCommit,
230
+ oldHead: result.oldHead,
231
+ ...(result.warnings ? { warnings: result.warnings } : {}),
232
+ };
233
+ }
234
+ if (lastPublishError !== undefined)
235
+ throw lastPublishError;
236
+ throw new FlowError("CONCURRENT_MODIFICATION", `target branch kept moving while claiming ${input.contractId}; last observed ${lastTargetHead}`);
237
+ }
@@ -0,0 +1,14 @@
1
+ import { rollbackOrphanTaskPointers } from "./task.js";
2
+ import { buildTaskSourceBoard } from "./task/source-board.js";
3
+ export async function inspectTaskDoctor(store, repository, facts) {
4
+ const orphans = facts.lockHeld ? [] : await rollbackOrphanTaskPointers(repository, facts.contractIds);
5
+ const sources = await store.read();
6
+ const board = buildTaskSourceBoard(sources);
7
+ return {
8
+ board,
9
+ sources,
10
+ orphans,
11
+ landingDiagnostics: facts.landingDiagnostics ?? [],
12
+ lockHeld: facts.lockHeld === true,
13
+ };
14
+ }
@@ -0,0 +1,38 @@
1
+ import { spawnSync } from "node:child_process";
2
+ const ANONYMOUS_TASK_CREATOR = "(anonymous)";
3
+ const TASK_ACTOR_ENV = "KEIYAKU_ACTOR";
4
+ const GIT_ACTOR_KEYS = ["keiyaku.actor", "user.name"];
5
+ function defaultRunGit(cwd, args, env) {
6
+ return spawnSync("git", [...args], {
7
+ cwd,
8
+ encoding: "utf8",
9
+ env,
10
+ stdio: ["ignore", "pipe", "pipe"],
11
+ });
12
+ }
13
+ function attribution(value) {
14
+ const trimmed = value?.trim();
15
+ return trimmed ? trimmed : undefined;
16
+ }
17
+ export function resolveTaskCreator(cwd, deps = {}) {
18
+ const sourceEnv = deps.env ?? process.env;
19
+ const environmentActor = attribution(sourceEnv[TASK_ACTOR_ENV]);
20
+ if (environmentActor)
21
+ return environmentActor;
22
+ const gitEnv = { ...sourceEnv, GIT_TERMINAL_PROMPT: "0", LC_ALL: "C" };
23
+ const runGit = deps.runGit ?? defaultRunGit;
24
+ for (const key of GIT_ACTOR_KEYS) {
25
+ try {
26
+ const result = runGit(cwd, ["config", "--get", key], gitEnv);
27
+ if (!result.error && result.status === 0) {
28
+ const configuredActor = attribution(result.stdout);
29
+ if (configuredActor)
30
+ return configuredActor;
31
+ }
32
+ }
33
+ catch {
34
+ // Creator attribution is advisory and must not prevent task creation.
35
+ }
36
+ }
37
+ return ANONYMOUS_TASK_CREATOR;
38
+ }
@@ -0,0 +1,37 @@
1
+ import { observeGitRepository } from "../git/branches.js";
2
+ import { listContractIds } from "./ledger.js";
3
+ import { contractBoundByEngineWorktree, stableRepoRoot } from "./worktree-path.js";
4
+ import { inspectTaskLock, openTaskStore } from "./task-git-store.js";
5
+ import { taskRepositoryFromStore } from "./task-store-repository.js";
6
+ import { withTaskWorktreePolicy } from "./task-worktree.js";
7
+ import { inspectTaskDoctor } from "./task-doctor.js";
8
+ export async function taskCommandContractId(cwd) {
9
+ const observation = await observeGitRepository(cwd);
10
+ if (observation.capability === "unknown")
11
+ throw observation.error;
12
+ if (observation.capability !== "available" || observation.coordinate !== "repository")
13
+ return undefined;
14
+ return contractBoundByEngineWorktree(cwd);
15
+ }
16
+ export async function openTaskCommandRepository(cwd) {
17
+ const store = await openTaskStore(cwd);
18
+ const repository = taskRepositoryFromStore(store);
19
+ if (store.mode !== "git")
20
+ return repository;
21
+ const contractId = await contractBoundByEngineWorktree(cwd);
22
+ return contractId ? withTaskWorktreePolicy(repository, contractId) : repository;
23
+ }
24
+ export async function taskContractIds(cwd) {
25
+ return new Set(await listContractIds(await stableRepoRoot(cwd)));
26
+ }
27
+ export async function readTaskDoctor(cwd) {
28
+ const store = await openTaskStore(cwd);
29
+ const repository = taskRepositoryFromStore(store);
30
+ const gitMode = store.mode === "git";
31
+ const lockHeld = (await inspectTaskLock(cwd)).state === "held";
32
+ return inspectTaskDoctor(store, repository, {
33
+ contractIds: gitMode ? await taskContractIds(cwd) : new Set(),
34
+ landingDiagnostics: [],
35
+ lockHeld,
36
+ });
37
+ }