@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.
Files changed (282) hide show
  1. package/build/.tsbuildinfo +1 -1
  2. package/build/agents/call-terms.js +14 -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 +26 -222
  6. package/build/agents/harness/index.js +3 -1
  7. package/build/agents/harness/outcome.js +68 -5
  8. package/build/agents/harness/projection.js +179 -124
  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 +82 -53
  21. package/build/agents/providers/codex-app-server/events.js +90 -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/events.js +4 -3
  36. package/build/agents/providers/pi/registration.js +145 -0
  37. package/build/agents/providers/pi/session-schema.js +6 -0
  38. package/build/agents/providers/pi/terms.js +1 -0
  39. package/build/agents/providers/registration.js +7 -0
  40. package/build/agents/providers/registry.js +76 -0
  41. package/build/agents/selector.js +2 -29
  42. package/build/agents/types.js +10 -0
  43. package/build/artifact-directories.js +22 -0
  44. package/build/cli/commands/akuma/akuma/handler.js +1 -1
  45. package/build/cli/commands/akuma/akuma/meta.js +1 -1
  46. package/build/cli/commands/akuma/list/meta-ls.js +1 -1
  47. package/build/cli/commands/akuma/view/handler.js +5 -4
  48. package/build/cli/commands/akuma/view/meta.js +1 -1
  49. package/build/cli/commands/akuma.js +6 -0
  50. package/build/cli/commands/contract/amend/handler.js +8 -2
  51. package/build/cli/commands/contract/amend/meta.js +4 -4
  52. package/build/cli/commands/contract/arc/handler.js +8 -2
  53. package/build/cli/commands/contract/arc/meta.js +4 -4
  54. package/build/cli/commands/contract/audit/handler.js +16 -0
  55. package/build/cli/commands/contract/audit/meta.js +16 -0
  56. package/build/cli/commands/contract/bind/handler.js +4 -3
  57. package/build/cli/commands/contract/bind/meta.js +44 -8
  58. package/build/cli/commands/contract/catalog.js +2 -0
  59. package/build/cli/commands/contract/forfeit/handler.js +4 -4
  60. package/build/cli/commands/contract/forfeit/meta.js +1 -1
  61. package/build/cli/commands/contract/log/handler.js +3 -3
  62. package/build/cli/commands/contract/log/meta.js +1 -1
  63. package/build/cli/commands/contract/petition/handler.js +5 -8
  64. package/build/cli/commands/contract/petition/meta.js +6 -6
  65. package/build/cli/commands/contract/renew/handler.js +20 -6
  66. package/build/cli/commands/contract/renew/meta.js +6 -5
  67. package/build/cli/commands/metadata.js +59 -0
  68. package/build/cli/commands/projection/call/handler.js +6 -5
  69. package/build/cli/commands/projection/call/meta.js +4 -1
  70. package/build/cli/commands/projection/kill/handler.js +16 -32
  71. package/build/cli/commands/projection/kill/meta.js +1 -1
  72. package/build/cli/commands/projection/revive/meta.js +4 -1
  73. package/build/cli/commands/projection/shared.js +28 -0
  74. package/build/cli/commands/projection/status/handler.js +1 -1
  75. package/build/cli/commands/projection/status/meta.js +1 -1
  76. package/build/cli/commands/projection/tell/handler.js +14 -30
  77. package/build/cli/commands/projection/tell/meta.js +4 -1
  78. package/build/cli/commands/projection/wait/handler.js +45 -22
  79. package/build/cli/commands/projection/wait/meta.js +8 -3
  80. package/build/cli/commands/registry.js +2 -54
  81. package/build/cli/commands/shared.js +10 -7
  82. package/build/cli/commands/skills/install/handler.js +2 -5
  83. package/build/cli/commands/skills/install/meta.js +1 -1
  84. package/build/cli/commands/skills/skills/handler.js +1 -1
  85. package/build/cli/commands/skills/skills/meta.js +1 -1
  86. package/build/cli/commands/system/completion/meta.js +1 -1
  87. package/build/cli/commands/system/dump-env/meta.js +1 -1
  88. package/build/cli/commands/system/guide/meta.js +1 -1
  89. package/build/cli/commands/task/add/handler.js +7 -15
  90. package/build/cli/commands/task/add/meta.js +4 -1
  91. package/build/cli/commands/task/catalog.js +2 -2
  92. package/build/cli/commands/task/doctor/meta.js +1 -1
  93. package/build/cli/commands/task/done/handler.js +4 -8
  94. package/build/cli/commands/task/done/meta.js +1 -1
  95. package/build/cli/commands/task/drop/handler.js +3 -6
  96. package/build/cli/commands/task/drop/meta.js +1 -1
  97. package/build/cli/commands/task/ls/handler.js +12 -8
  98. package/build/cli/commands/task/ls/meta.js +3 -3
  99. package/build/cli/commands/task/shared.js +14 -4
  100. package/build/cli/commands/task/{view → show}/handler.js +7 -8
  101. package/build/cli/commands/task/show/meta.js +8 -0
  102. package/build/cli/commands/task/start/handler.js +3 -6
  103. package/build/cli/commands/task/start/meta.js +1 -1
  104. package/build/cli/commands/task/stop/handler.js +4 -8
  105. package/build/cli/commands/task/stop/meta.js +1 -1
  106. package/build/cli/commands/task/task/handler.js +1 -1
  107. package/build/cli/commands/task/task/meta.js +1 -1
  108. package/build/cli/commands/task/update/handler.js +6 -11
  109. package/build/cli/commands/task/update/meta.js +4 -1
  110. package/build/cli/completion.js +1 -1
  111. package/build/cli/flags.js +37 -6
  112. package/build/cli/help.js +7 -14
  113. package/build/cli/index.js +112 -154
  114. package/build/cli/missing-subcommand.js +7 -0
  115. package/build/cli/output-stream-error-policy.js +19 -5
  116. package/build/cli/parse-flags.js +33 -7
  117. package/build/cli/parse-metadata.js +3 -9
  118. package/build/cli/parse-selectors.js +2 -1
  119. package/build/cli/parse.js +35 -5
  120. package/build/cli/projection-address.js +12 -12
  121. package/build/cli/render/address.js +41 -37
  122. package/build/cli/render/arc.js +24 -12
  123. package/build/cli/render/audit.js +121 -0
  124. package/build/cli/render/call.js +11 -5
  125. package/build/cli/render/errors.js +36 -1
  126. package/build/cli/render/format.js +4 -0
  127. package/build/cli/render/kanshi.js +6 -12
  128. package/build/cli/render/kill.js +9 -0
  129. package/build/cli/render/misc.js +58 -13
  130. package/build/cli/render/petition.js +20 -15
  131. package/build/cli/render/projection-activity.js +15 -6
  132. package/build/cli/render/shared.js +60 -21
  133. package/build/cli/render/skills.js +10 -0
  134. package/build/cli/render/status.js +56 -23
  135. package/build/cli/render/success-response.js +78 -0
  136. package/build/cli/render/task.js +66 -57
  137. package/build/cli/render/tell.js +5 -0
  138. package/build/cli/render/terminal-failure.js +63 -0
  139. package/build/cli/render/types.js +1 -0
  140. package/build/cli/render/wait.js +68 -38
  141. package/build/cli/types.js +1 -1
  142. package/build/config/akuma-loader.js +0 -5
  143. package/build/config/env-keys.js +3 -1
  144. package/build/config/env.js +3 -0
  145. package/build/config/provider-policy-ownership.js +3 -32
  146. package/build/config/settings/disease.js +8 -1
  147. package/build/config/settings/loader.js +11 -3
  148. package/build/config/settings/provider-instance-fields.js +51 -0
  149. package/build/config/settings/schema.js +6 -176
  150. package/build/core/addressing.js +66 -16
  151. package/build/core/amend.js +61 -18
  152. package/build/core/arc.js +33 -73
  153. package/build/core/audit.js +650 -0
  154. package/build/core/bind.js +82 -35
  155. package/build/core/call/call.js +15 -9
  156. package/build/core/call/context.js +6 -51
  157. package/build/core/call/execution.js +22 -22
  158. package/build/core/call/prompt.js +14 -1
  159. package/build/core/command-markdown.js +45 -0
  160. package/build/core/context.js +13 -7
  161. package/build/core/contract-view.js +22 -6
  162. package/build/core/draft.js +139 -19
  163. package/build/core/entry.js +3 -4
  164. package/build/core/forfeit.js +5 -2
  165. package/build/core/hints.js +1 -75
  166. package/build/core/identifier-slug.js +66 -0
  167. package/build/core/ids.js +25 -11
  168. package/build/core/ledger.js +20 -68
  169. package/build/core/markdown/lex.js +2 -1
  170. package/build/core/markdown/parser.js +0 -68
  171. package/build/core/markdown/render.js +68 -0
  172. package/build/core/markdown/sections.js +2 -1
  173. package/build/core/outcome-base.js +4 -0
  174. package/build/core/projection/generation/database.js +41 -52
  175. package/build/core/projection/generation/model.js +63 -2
  176. package/build/core/{projection-generation-continuation.js → projection/generation/projection-generation-continuation.js} +3 -3
  177. package/build/core/{projection-generation-execution.js → projection/generation/projection-generation-execution.js} +36 -53
  178. package/build/core/{projection-generation-identity.js → projection/generation/projection-generation-identity.js} +2 -2
  179. package/build/core/{projection-generation-launcher.js → projection/generation/projection-generation-launcher.js} +9 -7
  180. package/build/core/{projection-generation-process.js → projection/generation/projection-generation-process.js} +2 -1
  181. package/build/core/{projection-generation-runner.js → projection/generation/projection-generation-runner.js} +19 -3
  182. package/build/core/projection/generation/store.js +3 -3
  183. package/build/core/projection/generation/transitions.js +19 -3
  184. package/build/core/projection/index.js +27 -0
  185. package/build/core/{projection-activity.js → projection/projection-activity.js} +12 -0
  186. package/build/core/{projection-alias.js → projection/projection-alias.js} +13 -13
  187. package/build/core/projection/projection-coordinate.js +61 -0
  188. package/build/core/{projection-core.js → projection/projection-core.js} +9 -9
  189. package/build/core/{projection-execution-observer.js → projection/projection-execution-observer.js} +37 -78
  190. package/build/core/{projection-identity.js → projection/projection-identity.js} +1 -1
  191. package/build/core/{projection-kill.js → projection/projection-kill.js} +1 -1
  192. package/build/core/{projection-life-observer.js → projection/projection-life-observer.js} +16 -2
  193. package/build/core/{projection-mint.js → projection/projection-mint.js} +10 -10
  194. package/build/core/{projection-status.js → projection/projection-status.js} +163 -45
  195. package/build/core/projection/projection-terminal-failure.js +106 -0
  196. package/build/core/projection/projection-wait.js +275 -0
  197. package/build/core/projection/projection-wake.js +227 -0
  198. package/build/core/provider-loader-ports.js +4 -0
  199. package/build/core/ref-log.js +65 -40
  200. package/build/core/registry.js +63 -10
  201. package/build/core/renew-session.js +128 -0
  202. package/build/core/renew.js +448 -102
  203. package/build/core/scope.js +272 -68
  204. package/build/core/seal.js +165 -40
  205. package/build/core/{claim-delivery.js → settlement/claim-delivery.js} +8 -8
  206. package/build/core/{claim.js → settlement/claim.js} +32 -8
  207. package/build/core/settlement/index.js +19 -0
  208. package/build/core/{petition-claim-gates.js → settlement/petition-claim-gates.js} +24 -49
  209. package/build/core/{petition-forfeit.js → settlement/petition-forfeit.js} +2 -2
  210. package/build/core/{petition-head-guard.js → settlement/petition-head-guard.js} +2 -2
  211. package/build/core/settlement/petition-io.js +1 -0
  212. package/build/core/{petition-preview.js → settlement/petition-preview.js} +2 -2
  213. package/build/core/{petition.js → settlement/petition.js} +21 -12
  214. package/build/core/settlement/queue-read-model.js +143 -0
  215. package/build/core/settlement/queue-seat-allocation.js +156 -0
  216. package/build/core/settlement/queue.js +6 -0
  217. package/build/core/settlement/settlement.js +288 -0
  218. package/build/core/{verdict.js → settlement/verdict.js} +9 -37
  219. package/build/core/settlement/verification.js +59 -0
  220. package/build/core/status/board.js +62 -41
  221. package/build/core/status/ledger-batch.js +158 -0
  222. package/build/core/status/reconciliation.js +10 -4
  223. package/build/core/stored-agent-event.js +6 -2
  224. package/build/core/task/board.js +41 -4
  225. package/build/core/task/commands.js +45 -28
  226. package/build/core/task/document.js +5 -0
  227. package/build/core/task/index.js +12 -0
  228. package/build/core/task/model.js +8 -1
  229. package/build/core/task/query.js +172 -0
  230. package/build/core/task/settlement-git.js +265 -74
  231. package/build/core/task/settlement-policy.js +67 -29
  232. package/build/core/task/source-board.js +1 -0
  233. package/build/core/task/task-contract.js +444 -0
  234. package/build/core/{task-doctor.js → task/task-doctor.js} +1 -1
  235. package/build/core/{task-git-actor.js → task/task-git-actor.js} +5 -10
  236. package/build/core/{task-git-runtime.js → task/task-git-runtime.js} +3 -3
  237. package/build/core/{task-git-store.js → task/task-git-store.js} +90 -19
  238. package/build/core/task/task-repository.js +1 -0
  239. package/build/core/{task-store-repository.js → task/task-store-repository.js} +6 -4
  240. package/build/core/task/task-store.js +1 -0
  241. package/build/core/{task-worktree.js → task/task-worktree.js} +2 -1
  242. package/build/core/task/task.js +7 -0
  243. package/build/core/task/tree.js +37 -0
  244. package/build/core/task/validation.js +5 -2
  245. package/build/core/transcripts.js +15 -3
  246. package/build/core/worktree-path.js +43 -28
  247. package/build/flow-error.js +83 -39
  248. package/build/fs/path-coordinate.js +16 -0
  249. package/build/generated/version.js +3 -2
  250. package/build/git/branches.js +2 -1
  251. package/build/git/core.js +106 -2
  252. package/build/git/diff/parsers.js +23 -13
  253. package/build/git/diff/structured.js +127 -0
  254. package/build/git/path-coordinate.js +17 -0
  255. package/build/git/refs.js +57 -0
  256. package/build/git/streaming-batch.js +301 -0
  257. package/build/git/worktree.js +65 -0
  258. package/build/index.js +9 -9
  259. package/build/keiyaku.js +2 -36
  260. package/build/telemetry/logger.js +4 -2
  261. package/package.json +4 -10
  262. package/skills/keiyaku/SKILL.md +5 -4
  263. package/skills/keiyaku-akuma/SKILL.md +25 -11
  264. package/skills/keiyaku-task/SKILL.md +17 -8
  265. package/skills/keiyaku-workflow/SKILL.md +58 -9
  266. package/build/agents/providers/codex-sdk.js +0 -329
  267. package/build/cli/commands/task/view/meta.js +0 -8
  268. package/build/core/command-io.js +0 -174
  269. package/build/core/path-coordinate.js +0 -27
  270. package/build/core/petition-claim.js +0 -117
  271. package/build/core/petition-run.js +0 -83
  272. package/build/core/projection-coordinate.js +0 -63
  273. package/build/core/projection-wait.js +0 -165
  274. package/build/core/projection-wake.js +0 -136
  275. package/build/core/queue.js +0 -343
  276. package/build/core/task-contract.js +0 -237
  277. package/build/core/task.js +0 -4
  278. /package/build/{core/task-repository.js → agents/launch-snapshot/types.js} +0 -0
  279. /package/build/{core/task-store.js → agents/providers/claude-agent-sdk/terms.js} +0 -0
  280. /package/build/core/{projection-generation-runtime.js → projection/generation/projection-generation-runtime.js} +0 -0
  281. /package/build/core/{projection-life-protocol.js → projection/projection-life-protocol.js} +0 -0
  282. /package/build/core/{projection-runner-lock.js → projection/projection-runner-lock.js} +0 -0
@@ -3,12 +3,12 @@ import { assertSettingsKnobUsable } from "../config/settings/disease.js";
3
3
  import { loadKeiyakuSettings } from "../config/settings/loader.js";
4
4
  import { FlowError } from "../flow-error.js";
5
5
  import { activeLedgerRef, appendEntry, appendWithRetry, readLedger } from "./ledger.js";
6
- import { parseBindDraft } from "./draft.js";
6
+ import { describeMissingBindSections, materializeBindDraft, mergeBindDraft, missingBindDraftSections, parseBindDraft, parsePartialBindDraft, renderMissingBindSectionsTemplate, } from "./draft.js";
7
7
  import { assertValidContractId, buildContractId } from "./ids.js";
8
8
  import { registerScope, releaseScope } from "./registry.js";
9
9
  import { resolveDefaultBranch } from "./status/drift.js";
10
10
  import { normalizeTargetRef } from "./target-ref.js";
11
- import { reconcileTaskForfeit, settleTaskBoardForBind } from "./task-contract.js";
11
+ import { reconcileTaskForfeit, settleTaskBoardForBind } from "./task/index.js";
12
12
  import { bootstrapEntryDataFromObservation, isBootstrapSuccess, runWorktreeBootstrap, } from "./worktree-bootstrap.js";
13
13
  import { contractWorktreePathFromBind, stableRepoRoot } from "./worktree-path.js";
14
14
  import { allocateWorktreePlace, cleanupCreatedBindResources, createContractBranch, defaultCreateWorktree, materializeContractView, resolveTreeRoot, } from "./bind-workspace.js";
@@ -107,8 +107,40 @@ function makeBindEntry(input) {
107
107
  },
108
108
  };
109
109
  }
110
+ function taskBindDefaults(task) {
111
+ const defaults = { name: task.title };
112
+ const objective = task.body.trim();
113
+ if (objective.length > 0)
114
+ defaults.objective = objective;
115
+ return defaults;
116
+ }
117
+ function incompleteTaskBindError(taskId, missing) {
118
+ const coordinate = taskId;
119
+ const template = renderMissingBindSectionsTemplate(missing);
120
+ const message = [
121
+ `task ${coordinate} carries no ${describeMissingBindSections(missing)}`,
122
+ `» keiyaku bind --task ${coordinate} - <<'KEIYAKU'`,
123
+ template,
124
+ "KEIYAKU",
125
+ ].join("\n");
126
+ return new FlowError("BIND_TASK_INCOMPLETE", message);
127
+ }
128
+ /**
129
+ * Section-level merge for `bind --task`: task title/body are name/objective
130
+ * defaults; stdin partial markdown sections override. Missing required sections
131
+ * fail with a paste-ready partial heredoc template.
132
+ */
133
+ export function composeTaskBindDraft(input) {
134
+ const merged = mergeBindDraft(taskBindDefaults(input.task), parsePartialBindDraft(input.draft));
135
+ const missing = missingBindDraftSections(merged);
136
+ if (missing.length > 0) {
137
+ throw incompleteTaskBindError(input.task.id, missing);
138
+ }
139
+ return materializeBindDraft(merged);
140
+ }
110
141
  export async function bindContract(input) {
111
- const draft = parseBindDraft(input.draft);
142
+ const isTaskBound = input.taskIds !== undefined && input.taskIds.length > 0;
143
+ const ordinaryDraft = !isTaskBound ? parseBindDraft(input.draft) : undefined;
112
144
  const workspace = input.workspace ?? "here";
113
145
  const at = new Date(input.nowMs).toISOString();
114
146
  const defaultBranch = await resolveDefaultBranch(input.cwd);
@@ -126,47 +158,60 @@ export async function bindContract(input) {
126
158
  for (let attempt = 0; attempt < 2; attempt += 1) {
127
159
  const randomBytes = input.randomBytes?.(attempt) ?? randomBytesDefault();
128
160
  const place = workspace === "worktree" ? await allocateWorktreePlace(input.cwd, randomBytes) : undefined;
129
- const id = buildContractId({
130
- name: draft.name,
131
- nowMs: input.nowMs,
132
- randomBytes,
133
- });
134
- await assertValidContractId(input.cwd, id);
135
- const ref = activeLedgerRef(id);
136
161
  let settlement;
137
162
  try {
138
- settlement = await settleTaskBoardForBind({
139
- cwd: input.cwd,
140
- ...(input.taskId === undefined ? {} : { taskId: input.taskId }),
141
- contractId: id,
142
- publishLedger: async (base) => {
143
- const entry = makeBindEntry({
144
- id,
145
- at,
146
- actor: input.actor,
147
- draft,
148
- base,
149
- target,
150
- after: input.after ?? [],
151
- workspace,
152
- place,
153
- bootstrap: bootstrapPlan,
163
+ const prepare = async (draft) => {
164
+ const id = buildContractId({ name: draft.name, nowMs: input.nowMs, randomBytes });
165
+ await assertValidContractId(input.cwd, id);
166
+ const ref = activeLedgerRef(id);
167
+ return {
168
+ contractId: id,
169
+ publishLedger: async (base) => {
170
+ const entry = makeBindEntry({
171
+ id,
172
+ at,
173
+ actor: input.actor,
174
+ draft,
175
+ base,
176
+ target,
177
+ after: input.after ?? [],
178
+ workspace,
179
+ place,
180
+ bootstrap: bootstrapPlan,
181
+ });
182
+ const appended = await appendEntry(input.cwd, ref, entry, null);
183
+ if (!appended.ok)
184
+ throw new BindLedgerCollisionError(id);
185
+ return { entry, appended };
186
+ },
187
+ };
188
+ };
189
+ settlement = !isTaskBound
190
+ ? await (async () => {
191
+ const prepared = await prepare(ordinaryDraft);
192
+ return settleTaskBoardForBind({ cwd: input.cwd, signal: input.signal, ...prepared });
193
+ })()
194
+ : await (async () => {
195
+ return settleTaskBoardForBind({
196
+ cwd: input.cwd,
197
+ taskIds: input.taskIds,
198
+ signal: input.signal,
199
+ prepare: async (tasks) => prepare(composeTaskBindDraft({ task: tasks[0], draft: input.draft })),
154
200
  });
155
- const appended = await appendEntry(input.cwd, ref, entry, null);
156
- if (!appended.ok)
157
- throw new BindLedgerCollisionError(id);
158
- return { entry, appended };
159
- },
160
- });
201
+ })();
161
202
  }
162
203
  catch (error) {
163
204
  if (error instanceof BindLedgerCollisionError) {
164
- collidedIds.push(id);
205
+ // The selected task's locked snapshot chose this attempted identity.
206
+ // Record the concrete id only when preparation reached publication.
207
+ collidedIds.push(error.contractId);
165
208
  continue;
166
209
  }
167
210
  throw error;
168
211
  }
169
212
  const { entry, appended } = settlement.ledger;
213
+ const id = settlement.contractId;
214
+ const ref = activeLedgerRef(id);
170
215
  const base = settlement.boardCommit;
171
216
  const resources = { id };
172
217
  const branch = `keiyaku/${id}`;
@@ -179,7 +224,7 @@ export async function bindContract(input) {
179
224
  const tree = await resolveTreeRoot(input.cwd, workspace, id, entry);
180
225
  const registration = await registerScope(input.cwd, {
181
226
  contractId: id,
182
- scope: draft.scope,
227
+ scope: entry.data.scope,
183
228
  tree,
184
229
  actor: input.actor,
185
230
  at,
@@ -219,11 +264,13 @@ export async function bindContract(input) {
219
264
  return {
220
265
  id,
221
266
  ref,
267
+ target,
268
+ place: workspace === "worktree" ? entry.data.place ?? null : null,
222
269
  branch: workspace === "worktree" ? branch : undefined,
223
270
  worktreePath: targetRoot,
224
271
  workspace,
225
272
  ledgerHead,
226
- warnings: registration.warnings,
273
+ scopeOverlaps: registration.overlaps,
227
274
  };
228
275
  }
229
276
  catch (error) {
@@ -8,10 +8,8 @@ import { ACTOR_IDENTITY } from "../../keiyaku.js";
8
8
  import { appendDebugBlock } from "../../telemetry/debug-log.js";
9
9
  import { logInfo } from "../../telemetry/logger.js";
10
10
  import { withResolvedAddress } from "../addressing.js";
11
- import { assertProjectionAlias } from "../projection-alias.js";
12
- import { PROJECTION_ADOPTION_TIMEOUT_MS } from "../projection-generation-launcher.js";
13
- import { observeProjectionLife } from "../projection-life-observer.js";
14
- import { waitForProjection } from "../projection-wait.js";
11
+ import { assertProjectionAlias, PROJECTION_ADOPTION_TIMEOUT_MS, observeProjectionLife, waitForProjection, } from "../projection/index.js";
12
+ import { normalizeFilesystemCoordinate } from "../../fs/path-coordinate.js";
15
13
  import { requireResumableArtifact } from "../transcripts.js";
16
14
  import { stableRepoRoot } from "../worktree-path.js";
17
15
  import { readCallKeiyakuContext } from "./context.js";
@@ -23,6 +21,9 @@ function renderSubagentWarning(warning) {
23
21
  const status = warning.errorStatus === null ? "no response" : String(warning.errorStatus);
24
22
  return `Provider warning: retry. attempt=${warning.attempt}, maxRetries=${warning.maxRetries}, retryDelayMs=${warning.retryDelayMs}, errorStatus=${status}`;
25
23
  }
24
+ if (warning.reason === "rate-limit") {
25
+ return "Provider warning: rate limit exhausted.";
26
+ }
26
27
  const modelTransition = warning.originalModel && warning.fallbackModel
27
28
  ? `${warning.originalModel} -> ${warning.fallbackModel}`
28
29
  : warning.originalModel ?? warning.fallbackModel;
@@ -42,18 +43,18 @@ export async function execSubagent(agentName, prompt, cwd, options) {
42
43
  export async function runCall(input) {
43
44
  const { signal, agent } = input;
44
45
  const reviveArtifact = input.reviveArtifact ? requireResumableArtifact(input.reviveArtifact) : undefined;
45
- let rawCwd = input.cwd;
46
- let rawRepo = input.repo;
46
+ let rawCwd = normalizeFilesystemCoordinate(input.cwd);
47
+ let rawRepo = input.repo === undefined ? undefined : normalizeFilesystemCoordinate(input.repo);
47
48
  if (reviveArtifact?.provenance.authority.kind === "user") {
48
49
  if (!("workdir" in reviveArtifact.provenance.evidence)) {
49
50
  throw new FlowError("INVALID_RESPONSE_PATH", `Invalid response artifact '${reviveArtifact.artifactId}': field 'provenance.evidence.workdir' is missing.`);
50
51
  }
51
- rawCwd = reviveArtifact.provenance.evidence.workdir;
52
+ rawCwd = normalizeFilesystemCoordinate(reviveArtifact.provenance.evidence.workdir);
52
53
  rawRepo = undefined;
53
54
  }
54
55
  else if (reviveArtifact?.provenance.authority.kind === "repository") {
55
56
  const artifactHome = await fs.realpath(reviveArtifact.storageRoot);
56
- const addressed = input.repo ?? input.cwd;
57
+ const addressed = normalizeFilesystemCoordinate(input.repo ?? input.cwd);
57
58
  const observation = await observeGitRepository(addressed);
58
59
  const coordinate = assertGitObservation(observation, "revive");
59
60
  if (coordinate === "repository") {
@@ -91,6 +92,7 @@ export async function runCall(input) {
91
92
  context: input.context,
92
93
  referenceFiles,
93
94
  currentIntent: keiyakuContext.currentIntent,
95
+ commissioned: keiyakuContext.address.binding.kind === "commission",
94
96
  });
95
97
  const launchSnapshot = reviveArtifact
96
98
  ? input.effort !== undefined
@@ -146,7 +148,11 @@ export async function runCall(input) {
146
148
  ...(launched.projection.alias ? { alias: launched.projection.alias } : {}),
147
149
  ...(launched.projection.previousAliasTarget ? { previousAliasTarget: launched.projection.previousAliasTarget } : {}),
148
150
  };
149
- input.onLaunch?.({ address: keiyakuContext.address, projection: adoptedProjection });
151
+ input.onLaunch?.({
152
+ address: keiyakuContext.address,
153
+ projection: adoptedProjection,
154
+ akumaName: launchSnapshot.akuma.name,
155
+ });
150
156
  if (input.detach) {
151
157
  return {
152
158
  state: "launched",
@@ -3,10 +3,11 @@ import { FlowError } from "../../flow-error.js";
3
3
  import { assertGitObservation, observeGitRepository } from "../../git/branches.js";
4
4
  import { createGit, wrapGitError } from "../../git/core.js";
5
5
  import { AddressResolutionError, buildResolutionAttempt, buildUncommissionedAddress, buildUncommissionedRepositoryAddress, resolveContractAddress, withResolvedAddress, } from "../addressing.js";
6
+ import { normalizeFilesystemCoordinate } from "../../fs/path-coordinate.js";
6
7
  import { findOpenArcView } from "../arc.js";
7
8
  import { readLedger } from "../ledger.js";
8
9
  import { deriveContractState, isTerminalState } from "../status/lifecycle.js";
9
- import { contractPresentedByWorktree, contractWorktreePathFromBind, stableRepoRoot } from "../worktree-path.js";
10
+ import { contractWorktreePathFromBind, stableRepoRoot } from "../worktree-path.js";
10
11
  async function findWorktreePathForContract(cwd, contractId) {
11
12
  const git = createGit(cwd);
12
13
  let output;
@@ -47,6 +48,8 @@ async function resolveWorkspaceCwd(cwd, contractId, bind) {
47
48
  return worktreePath;
48
49
  }
49
50
  export async function readCallKeiyakuContext(executionCwd, input) {
51
+ executionCwd = normalizeFilesystemCoordinate(executionCwd);
52
+ input.repoCwd = input.repoCwd === undefined ? undefined : normalizeFilesystemCoordinate(input.repoCwd);
50
53
  const ledgerCandidate = input.repoCwd ?? executionCwd;
51
54
  const ledgerObservation = await observeGitRepository(ledgerCandidate);
52
55
  if (ledgerObservation.capability === "unknown")
@@ -136,7 +139,7 @@ export async function readCallKeiyakuContext(executionCwd, input) {
136
139
  },
137
140
  }));
138
141
  }
139
- if (input.bare) {
142
+ if (input.bare || !input.contractId) {
140
143
  return {
141
144
  activeKeiyaku: false,
142
145
  effectiveCwd: executionCwd,
@@ -150,55 +153,7 @@ export async function readCallKeiyakuContext(executionCwd, input) {
150
153
  }),
151
154
  };
152
155
  }
153
- let address;
154
- if (input.contractId) {
155
- address = await resolveContractAddress(ledgerCwd, input.contractId, input.contractAddressSource);
156
- }
157
- else {
158
- const executionObservation = await observeGitRepository(executionCwd);
159
- if (executionObservation.capability === "unknown")
160
- throw executionObservation.error;
161
- if (executionObservation.capability === "available" && executionObservation.coordinate === "repository") {
162
- const executionRepo = await stableRepoRoot(executionCwd);
163
- if (input.repoCwd && executionRepo !== ledgerCwd) {
164
- const presented = await contractPresentedByWorktree(executionCwd);
165
- if (presented) {
166
- throw new FlowError("EMPTY_PARAM", `cross-repository contract-worktree addressing is pending: -C presents @${presented} from ${executionRepo}, but --repo selects ${ledgerCwd}`);
167
- }
168
- }
169
- else {
170
- const presented = await contractPresentedByWorktree(executionCwd);
171
- if (presented) {
172
- address = await resolveContractAddress(ledgerCwd, presented, "worktree-presented");
173
- }
174
- }
175
- }
176
- }
177
- if (!address) {
178
- try {
179
- address = await resolveContractAddress(ledgerCwd);
180
- }
181
- catch (error) {
182
- if (error instanceof AddressResolutionError
183
- && error.code === "EMPTY_PARAM"
184
- && error.attempt.expected === "commission"
185
- && error.attempt.candidates.length === 0) {
186
- return {
187
- activeKeiyaku: false,
188
- effectiveCwd: executionCwd,
189
- historyCwd: ledgerCwd,
190
- profileCwd: ledgerCwd,
191
- projectionCwd: ledgerCwd,
192
- address: buildUncommissionedRepositoryAddress({
193
- stableRoot: ledgerCwd,
194
- workdir: executionCwd,
195
- binding: "unbound",
196
- }),
197
- };
198
- }
199
- throw error;
200
- }
201
- }
156
+ const address = await resolveContractAddress(ledgerCwd, input.contractId, input.contractAddressSource);
202
157
  return await withResolvedAddress(address, async () => {
203
158
  const contractId = address.binding.commissionId;
204
159
  const ledger = await readLedger(ledgerCwd, contractId);
@@ -3,14 +3,14 @@ import { createAbortError, restoreOutcome, SubagentFailure, } from "../../agents
3
3
  import { resolveAkumaLaunchSnapshot } from "../../agents/launch-snapshot/resolve.js";
4
4
  import { selectSubagent } from "../../agents/selector.js";
5
5
  import { FlowError } from "../../flow-error.js";
6
- import { assertProjectionAlias, moveProjectionAlias } from "../projection-alias.js";
7
- import { projectionDir } from "../projection-core.js";
8
- import { createProjectionExecutionId } from "../projection-generation-identity.js";
9
- import { PROJECTION_ADOPTION_TIMEOUT_MS, startProjectionGeneration } from "../projection-generation-launcher.js";
10
- import { openProjectionGenerationStore, openProjectionGenerationStoreReadOnly, } from "../projection/generation/store.js";
11
- import { observeProjectionLife } from "../projection-life-observer.js";
12
- import { mintProjection, mintRepositoryProjection } from "../projection-mint.js";
13
- import { waitForProjection } from "../projection-wait.js";
6
+ import { assertProjectionAlias, moveProjectionAlias } from "../projection/index.js";
7
+ import { projectionDir } from "../projection/index.js";
8
+ import { createProjectionExecutionId } from "../projection/index.js";
9
+ import { PROJECTION_ADOPTION_TIMEOUT_MS, startProjectionGeneration } from "../projection/index.js";
10
+ import { openProjectionGenerationStore, openProjectionGenerationStoreReadOnly, } from "../projection/index.js";
11
+ import { observeProjectionLife } from "../projection/index.js";
12
+ import { mintProjection, mintRepositoryProjection } from "../projection/index.js";
13
+ import { waitForProjection } from "../projection/index.js";
14
14
  export function readCurrentGenerationOrThrow(projectionDirectory) {
15
15
  const store = openProjectionGenerationStoreReadOnly(projectionDirectory);
16
16
  try {
@@ -148,7 +148,7 @@ export async function buildCallConfig(agentName, prompt, cwd, options) {
148
148
  };
149
149
  const minted = options.authority.kind === "repository"
150
150
  ? await mintRepositoryProjection({ ...mintInput, authority: { kind: "repository" } })
151
- : mintProjection({ ...mintInput, authority: { kind: "user" } });
151
+ : await mintProjection({ ...mintInput, authority: { kind: "user" } });
152
152
  const executionId = createProjectionExecutionId();
153
153
  const launchFacts = JSON.parse(JSON.stringify({
154
154
  executionId,
@@ -159,6 +159,7 @@ export async function buildCallConfig(agentName, prompt, cwd, options) {
159
159
  task: options.task ?? prompt,
160
160
  launchSnapshot,
161
161
  idleTimeoutMs: resolvedTerms.idleTimeoutMs,
162
+ executionTimeoutMs: resolvedTerms.executionTimeoutMs,
162
163
  cwd,
163
164
  historyCwd: options.historyStorageCwd ?? cwd,
164
165
  ...(options.evidenceCwd !== undefined ? { evidenceCwd: options.evidenceCwd } : {}),
@@ -184,20 +185,19 @@ export async function buildCallConfig(agentName, prompt, cwd, options) {
184
185
  }
185
186
  const previousAliasTarget = options.alias === undefined
186
187
  ? undefined
187
- : moveProjectionAlias(options.projectionCwd ?? cwd, assertProjectionAlias(options.alias), minted.id);
188
- const previousAliasTargetStillRunning = previousAliasTarget === undefined
189
- ? undefined
190
- : (() => {
191
- try {
192
- const phase = observeProjectionLife(projectionDir(options.projectionCwd ?? cwd, previousAliasTarget), { nowMs: Date.now(), startupTimeoutMs: PROJECTION_ADOPTION_TIMEOUT_MS }).phase;
193
- return phase === "minting" || phase === "active" || phase === "quiescent"
194
- ? previousAliasTarget
195
- : undefined;
196
- }
197
- catch {
198
- return undefined;
188
+ : await moveProjectionAlias(options.projectionCwd ?? cwd, assertProjectionAlias(options.alias), minted.id);
189
+ let previousAliasTargetStillRunning;
190
+ if (previousAliasTarget !== undefined) {
191
+ try {
192
+ const phase = observeProjectionLife(await projectionDir(options.projectionCwd ?? cwd, previousAliasTarget), { nowMs: Date.now(), startupTimeoutMs: PROJECTION_ADOPTION_TIMEOUT_MS }).phase;
193
+ if (phase === "minting" || phase === "active" || phase === "quiescent") {
194
+ previousAliasTargetStillRunning = previousAliasTarget;
199
195
  }
200
- })();
196
+ }
197
+ catch {
198
+ previousAliasTargetStillRunning = undefined;
199
+ }
200
+ }
201
201
  return {
202
202
  id: minted.id,
203
203
  dir: minted.dir,
@@ -1,4 +1,10 @@
1
1
  import { ACTOR_IDENTITY } from "../../keiyaku.js";
2
+ const COMMISSIONED_DELIVERY_BOUNDARY = [
3
+ "Delivery boundary: edit and test only inside this linked contract worktree.",
4
+ "Leave source changes uncommitted as a dirty working tree, then report changed files and checks run.",
5
+ "Do not run git add, git commit, or any command that writes Git metadata. A refused Git metadata write is not a failed delivery.",
6
+ "The host coordinator reviews and commits accepted bytes, then continues arc, renew, or petition settlement.",
7
+ ].join(" ");
2
8
  export function buildCallPrompt(input) {
3
9
  const references = [...new Set((input.referenceFiles ?? []).map((file) => file.trim()).filter(Boolean))];
4
10
  if (input.currentIntent?.source === "arc") {
@@ -9,6 +15,7 @@ export function buildCallPrompt(input) {
9
15
  `Title: ${arc.title}`,
10
16
  `Objective: ${arc.objective}`,
11
17
  `Brief:\n${arc.brief}`,
18
+ COMMISSIONED_DELIVERY_BOUNDARY,
12
19
  "",
13
20
  `Task:\n${input.task}`,
14
21
  `Context:\n${input.context?.trim() || "(none provided)"}`,
@@ -30,13 +37,19 @@ export function buildCallPrompt(input) {
30
37
  `Scope:\n${bind.scope.map((value) => `- ${value}`).join("\n")}`,
31
38
  `Checks:\n${bind.checks.map((value) => `- ${value}`).join("\n")}`,
32
39
  extensionsBlock,
40
+ COMMISSIONED_DELIVERY_BOUNDARY,
33
41
  `Task:\n${input.task}`,
34
42
  trimmedContext ? `Context:\n${trimmedContext}` : "",
35
43
  references.length > 0 ? `Reference files:\n${references.map((file) => `- ${file}`).join("\n")}` : "",
36
44
  "Provide the final result for the caller/main agent.",
37
45
  ].filter(Boolean).join("\n\n");
38
46
  }
39
- return [input.task, input.context?.trim() ?? "", references.length > 0 ? `Reference files:\n${references.map((file) => `- ${file}`).join("\n")}` : ""]
47
+ return [
48
+ input.task,
49
+ input.context?.trim() ?? "",
50
+ input.commissioned ? COMMISSIONED_DELIVERY_BOUNDARY : "",
51
+ references.length > 0 ? `Reference files:\n${references.map((file) => `- ${file}`).join("\n")}` : "",
52
+ ]
40
53
  .filter(Boolean)
41
54
  .join("\n\n");
42
55
  }
@@ -0,0 +1,45 @@
1
+ import { FlowError } from "../flow-error.js";
2
+ import { parseMarkdownListSection, parseMarkdownStructure } from "./markdown/sections.js";
3
+ import { KeiyakuParseError } from "./markdown/types.js";
4
+ import { normalizeSectionTitle } from "./markdown/titles.js";
5
+ export function parseCommandMarkdown(content) {
6
+ try {
7
+ const parsed = parseMarkdownStructure(content);
8
+ const sections = new Map();
9
+ for (const [key, lines] of parsed.sections.entries()) {
10
+ sections.set(key, lines.join("\n").trim());
11
+ }
12
+ return { title: parsed.title, sections };
13
+ }
14
+ catch (error) {
15
+ if (error instanceof KeiyakuParseError) {
16
+ throw new FlowError("INVALID_KEIYAKU_DRAFT", error.message, { cause: error });
17
+ }
18
+ throw error;
19
+ }
20
+ }
21
+ export function requireMarkdownTextSection(parts, name) {
22
+ const normalized = normalizeSectionTitle(name);
23
+ const value = parts.sections.get(normalized)?.trim();
24
+ if (!value) {
25
+ throw new FlowError("INVALID_KEIYAKU_DRAFT", `missing required section: ## ${name}`);
26
+ }
27
+ return value;
28
+ }
29
+ export function requireMarkdownListSection(parts, name) {
30
+ const text = requireMarkdownTextSection(parts, name);
31
+ const items = parseMarkdownListSection(text)
32
+ .map((item) => item.trim())
33
+ .filter((item) => item.length > 0);
34
+ if (items.length === 0) {
35
+ throw new FlowError("INVALID_KEIYAKU_DRAFT", `missing required section: ## ${name}`);
36
+ }
37
+ return items;
38
+ }
39
+ export function requireMarkdownTitle(parts) {
40
+ const title = parts.title?.trim();
41
+ if (!title) {
42
+ throw new FlowError("INVALID_KEIYAKU_DRAFT", "missing required title: # Title");
43
+ }
44
+ return title;
45
+ }
@@ -1,13 +1,12 @@
1
- import * as path from "node:path";
2
1
  import { KEIYAKU_BRANCH_PREFIX } from "../keiyaku.js";
3
2
  import { FlowError } from "../flow-error.js";
4
- import { createGit, errorContainsAnyPattern, MISSING_HEAD_PATTERNS, wrapGitError } from "../git/core.js";
3
+ import { createGit, errorContainsAnyPattern, MISSING_HEAD_PATTERNS, NOT_GIT_REPOSITORY_PATTERNS, wrapGitError } from "../git/core.js";
5
4
  import { getCurrentBranch, listLocalBranches } from "../git/branches.js";
6
5
  import { readLedger } from "./ledger.js";
7
6
  import { listContractIds } from "./ledger.js";
8
7
  import { deriveContractState, isTerminalState } from "./status/lifecycle.js";
9
8
  import { latestBase } from "./status/drift.js";
10
- import { activeContractIdForWorktreeDir } from "./worktree-path.js";
9
+ import { activeContractBoundByEngineWorktree } from "./worktree-path.js";
11
10
  function isOperableLedger(entries) {
12
11
  const state = deriveContractState(entries);
13
12
  return state.state !== "corrupt" && !isTerminalState(state);
@@ -25,6 +24,17 @@ async function isOperableContract(cwd, contractId) {
25
24
  return (await operableContractIds(cwd)).includes(contractId);
26
25
  }
27
26
  export async function resolveImplicitCurrentContractId(cwd) {
27
+ // Prefer the verified engine-worktree binding (same tier as existing-commission verbs).
28
+ try {
29
+ const bound = await activeContractBoundByEngineWorktree(cwd);
30
+ if (bound)
31
+ return bound;
32
+ }
33
+ catch (error) {
34
+ if (!errorContainsAnyPattern(error, NOT_GIT_REPOSITORY_PATTERNS))
35
+ throw error;
36
+ }
37
+ // Branch remains a residual signal for workspace:here checkouts without an engine worktree.
28
38
  const git = createGit(cwd);
29
39
  try {
30
40
  const branch = (await git.raw(["branch", "--show-current"])).trim();
@@ -39,10 +49,6 @@ export async function resolveImplicitCurrentContractId(cwd) {
39
49
  throw wrapGitError("branch --show-current", error, cwd);
40
50
  }
41
51
  }
42
- const worktreeId = path.basename(cwd);
43
- const worktreeContractId = await activeContractIdForWorktreeDir(cwd, worktreeId);
44
- if (worktreeContractId)
45
- return worktreeContractId;
46
52
  return undefined;
47
53
  }
48
54
  export async function resolveCurrentContractId(cwd) {
@@ -1,5 +1,11 @@
1
+ import * as fs from "node:fs/promises";
2
+ import * as path from "node:path";
3
+ import { FlowError } from "../flow-error.js";
1
4
  import { shortCommitHash } from "../git/commits.js";
5
+ import { KEIYAKU_FILE } from "../keiyaku.js";
6
+ import { readLedger } from "./ledger.js";
2
7
  import { deriveContractState } from "./status/lifecycle.js";
8
+ import { renderScopeFragment } from "./scope.js";
3
9
  const VERB_COLUMN_WIDTH = 11;
4
10
  const TIME_COLUMN_WIDTH = 6;
5
11
  const ACTOR_COLUMN_WIDTH = 11;
@@ -36,8 +42,6 @@ function sealAggregate(entries) {
36
42
  function scopeStatusFact(entry) {
37
43
  if (entry.data.scopeAudit.violations.length === 0)
38
44
  return "scope ✓ clean";
39
- if (entry.data.scopeAudit.waived)
40
- return `scope ▲ waived ${entry.data.scopeAudit.violations.length}`;
41
45
  return `scope ✕ ${entry.data.scopeAudit.violations.length}`;
42
46
  }
43
47
  function formatDiffstat(insertions, deletions) {
@@ -208,6 +212,18 @@ export function renderVerticalLog(input) {
208
212
  }
209
213
  return renderLedgerRows(input.entries).join("\n");
210
214
  }
215
+ /**
216
+ * Sole post-mutation KEIYAKU.md refresh: read the authoritative ledger at
217
+ * ledgerCwd, then write the projection at renderCwd. ledgerCwd and renderCwd
218
+ * are distinct coordinates (hub vs linked delivery worktree).
219
+ */
220
+ export async function refreshContractView(input) {
221
+ const ledger = await readLedger(input.ledgerCwd, input.contractId);
222
+ if (!ledger) {
223
+ throw new FlowError("INTERNAL_STATE", `contract ${input.contractId} active ledger disappeared before render`);
224
+ }
225
+ await fs.writeFile(path.join(input.renderCwd, KEIYAKU_FILE), renderContractView({ id: input.contractId, entries: ledger.entries }), "utf8");
226
+ }
211
227
  export function renderContractView(input) {
212
228
  const bind = input.entries.find((entry) => entry.kind === "bind");
213
229
  const state = deriveContractState(input.entries);
@@ -237,13 +253,13 @@ export function renderContractView(input) {
237
253
  `place: ${bind.data.place ?? "(none)"}`,
238
254
  `after: ${(bind.data.after ?? []).join(", ") || "(none)"}`,
239
255
  "",
240
- "objective:",
256
+ "## Objective",
241
257
  bind.data.objective,
242
258
  "",
243
- "scope:",
244
- ...bind.data.scope.map((pattern) => `- ${pattern}`),
259
+ "## Scope",
260
+ ...renderScopeFragment(bind.data.scope).split("\n"),
245
261
  "",
246
- "checks:",
262
+ "## Checks",
247
263
  ...bind.data.checks.map((check) => `- ${check}`),
248
264
  "",
249
265
  ...(bind.data.extensions.length > 0