@astrosheep/keiyaku 2.9.9 → 2.9.11

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 (230) hide show
  1. package/README.md +93 -174
  2. package/build/.tsbuildinfo +1 -1
  3. package/build/agents/harness/control-types.js +18 -1
  4. package/build/agents/harness/index.js +2 -0
  5. package/build/agents/harness/outcome-error.js +81 -0
  6. package/build/agents/harness/projection.js +2 -1
  7. package/build/agents/harness/router.js +5 -1
  8. package/build/agents/providers/claude-agent-sdk/adapter.js +18 -4
  9. package/build/agents/providers/claude-agent-sdk/registration.js +11 -1
  10. package/build/agents/providers/claude-agent-sdk/session.js +19 -5
  11. package/build/agents/providers/codex-app-server/adapter.js +11 -6
  12. package/build/agents/providers/codex-app-server/events.js +67 -6
  13. package/build/agents/providers/codex-app-server/registration.js +11 -1
  14. package/build/agents/providers/opencode-sdk/adapter.js +8 -1
  15. package/build/agents/providers/opencode-sdk/events.js +24 -2
  16. package/build/agents/providers/opencode-sdk/registration.js +11 -1
  17. package/build/agents/providers/pi/checkpoint.js +9 -1
  18. package/build/agents/providers/pi/events.js +2 -0
  19. package/build/agents/providers/pi/registration.js +14 -1
  20. package/build/cli/commands/akuma/akuma/handler.js +1 -1
  21. package/build/cli/commands/akuma/akuma/meta.js +3 -3
  22. package/build/cli/commands/akuma/catalog.js +2 -2
  23. package/build/cli/commands/akuma/{view → show}/handler.js +5 -5
  24. package/build/cli/commands/akuma/{view → show}/meta.js +3 -3
  25. package/build/cli/commands/akuma.js +1 -1
  26. package/build/cli/commands/contract/amend/handler.js +5 -4
  27. package/build/cli/commands/contract/arc/handler.js +5 -4
  28. package/build/cli/commands/contract/audit/handler.js +2 -2
  29. package/build/cli/commands/contract/bind/handler.js +12 -3
  30. package/build/cli/commands/contract/bind/meta.js +45 -15
  31. package/build/cli/commands/contract/forfeit/handler.js +9 -5
  32. package/build/cli/commands/contract/log/handler.js +2 -2
  33. package/build/cli/commands/contract/petition/handler.js +34 -7
  34. package/build/cli/commands/contract/renew/handler.js +7 -7
  35. package/build/cli/commands/contract/renew/meta.js +3 -3
  36. package/build/cli/commands/metadata.js +10 -6
  37. package/build/cli/commands/projection/call/meta.js +1 -1
  38. package/build/cli/commands/projection/catalog.js +2 -0
  39. package/build/cli/commands/projection/history/handler.js +21 -0
  40. package/build/cli/commands/projection/history/meta.js +9 -0
  41. package/build/cli/commands/projection/shared.js +3 -4
  42. package/build/cli/commands/projection/status/handler.js +3 -3
  43. package/build/cli/commands/projection/wait/handler.js +20 -11
  44. package/build/cli/commands/task/add/handler.js +14 -5
  45. package/build/cli/commands/task/add/meta.js +2 -2
  46. package/build/cli/commands/task/catalog.js +4 -0
  47. package/build/cli/commands/task/done/handler.js +1 -4
  48. package/build/cli/commands/task/done/meta.js +1 -1
  49. package/build/cli/commands/task/drop/meta.js +1 -1
  50. package/build/cli/commands/task/hold/handler.js +3 -0
  51. package/build/cli/commands/task/hold/meta.js +8 -0
  52. package/build/cli/commands/task/log/handler.js +1 -1
  53. package/build/cli/commands/task/log/meta.js +2 -2
  54. package/build/cli/commands/task/resume/handler.js +3 -0
  55. package/build/cli/commands/task/resume/meta.js +8 -0
  56. package/build/cli/commands/task/shared.js +39 -14
  57. package/build/cli/commands/task/show/handler.js +1 -1
  58. package/build/cli/commands/task/show/meta.js +1 -1
  59. package/build/cli/commands/task/start/meta.js +1 -1
  60. package/build/cli/commands/task/stop/handler.js +1 -4
  61. package/build/cli/commands/task/stop/meta.js +1 -1
  62. package/build/cli/commands/task/update/handler.js +11 -3
  63. package/build/cli/commands/task/update/meta.js +3 -3
  64. package/build/cli/completion.js +3 -2
  65. package/build/cli/flags.js +51 -14
  66. package/build/cli/help.js +4 -1
  67. package/build/cli/index.js +40 -25
  68. package/build/cli/parse-flags.js +40 -7
  69. package/build/cli/parse-metadata.js +5 -2
  70. package/build/cli/parse-selectors.js +2 -3
  71. package/build/cli/parse.js +40 -6
  72. package/build/cli/projection-address.js +12 -10
  73. package/build/cli/render/amendment-warning.js +8 -0
  74. package/build/cli/render/arc.js +6 -2
  75. package/build/cli/render/audit.js +400 -81
  76. package/build/cli/render/kanshi.js +6 -1
  77. package/build/cli/render/lifecycle.js +56 -0
  78. package/build/cli/render/misc.js +24 -28
  79. package/build/cli/render/petition.js +5 -0
  80. package/build/cli/render/projection-activity.js +3 -2
  81. package/build/cli/render/projection-history.js +64 -0
  82. package/build/cli/render/shared.js +23 -9
  83. package/build/cli/render/status.js +9 -16
  84. package/build/cli/render/task.js +51 -26
  85. package/build/cli/render/terminal-failure.js +3 -1
  86. package/build/cli/render/wait.js +3 -5
  87. package/build/cli/subagent-guard.js +1 -1
  88. package/build/cli/types.js +1 -1
  89. package/build/config/env-keys.js +2 -0
  90. package/build/config/env.js +23 -0
  91. package/build/config/settings/schema.js +3 -1
  92. package/build/core/address-carrier.js +89 -0
  93. package/build/core/addressing.js +255 -196
  94. package/build/core/amend.js +115 -38
  95. package/build/core/amendment-criteria.js +17 -0
  96. package/build/core/amendment-warning.js +10 -0
  97. package/build/core/arc.js +184 -83
  98. package/build/core/audit/candidate.js +110 -9
  99. package/build/core/audit/coordinates.js +120 -65
  100. package/build/core/audit/evidence.js +19 -23
  101. package/build/core/audit/facade.js +34 -11
  102. package/build/core/audit/report.js +5 -5
  103. package/build/core/bind-reconciliation.js +390 -0
  104. package/build/core/bind-workspace.js +12 -20
  105. package/build/core/bind.js +242 -273
  106. package/build/core/call/call.js +1 -0
  107. package/build/core/call/context.js +46 -71
  108. package/build/core/call/prompt.js +6 -3
  109. package/build/core/context.js +49 -35
  110. package/build/core/contract-carrier-runtime.js +408 -0
  111. package/build/core/contract-carrier.js +270 -0
  112. package/build/core/contract-view.js +33 -27
  113. package/build/core/contract.js +5 -1
  114. package/build/core/derived-replay.js +207 -0
  115. package/build/core/draft.js +125 -57
  116. package/build/core/forfeit.js +113 -56
  117. package/build/core/identifier-slug.js +63 -13
  118. package/build/core/ids.js +4 -4
  119. package/build/core/lifecycle-history.js +35 -0
  120. package/build/core/lifecycle-recovery.js +117 -0
  121. package/build/core/lifecycle-runner.js +377 -0
  122. package/build/core/log.js +37 -11
  123. package/build/core/outcome-base.js +181 -0
  124. package/build/core/process-group.js +139 -0
  125. package/build/core/projection/generation/database.js +82 -7
  126. package/build/core/projection/generation/model.js +9 -36
  127. package/build/core/projection/generation/projection-generation-continuation.js +10 -22
  128. package/build/core/projection/generation/projection-generation-execution.js +6 -5
  129. package/build/core/projection/index.js +5 -4
  130. package/build/core/projection/projection-activity.js +27 -8
  131. package/build/core/projection/projection-alias.js +23 -10
  132. package/build/core/projection/projection-core.js +21 -7
  133. package/build/core/projection/projection-execution-observer.js +91 -39
  134. package/build/core/projection/projection-history.js +474 -0
  135. package/build/core/projection/projection-runner-lock.js +12 -0
  136. package/build/core/projection/projection-status-observation.js +365 -0
  137. package/build/core/projection/projection-status.js +21 -358
  138. package/build/core/projection/projection-terminal-failure.js +13 -8
  139. package/build/core/projection/projection-wait.js +7 -2
  140. package/build/core/projection/tell/launch-store.js +244 -0
  141. package/build/core/projection/tell/model.js +3 -3
  142. package/build/core/projection/tell/store.js +70 -118
  143. package/build/core/registry.js +22 -87
  144. package/build/core/renew-build.js +424 -0
  145. package/build/core/renew-plan.js +239 -0
  146. package/build/core/renew-rewrite.js +77 -0
  147. package/build/core/renew.js +295 -520
  148. package/build/core/repository-ledger/accepted-fold-read.js +19 -0
  149. package/build/core/repository-ledger/accepted-tail.js +116 -0
  150. package/build/core/repository-ledger/admission.js +38 -0
  151. package/build/core/repository-ledger/authoritative-transaction.js +1 -0
  152. package/build/core/repository-ledger/claim-evidence.js +147 -0
  153. package/build/core/repository-ledger/codec.js +297 -0
  154. package/build/core/repository-ledger/current-state-store.js +853 -0
  155. package/build/core/repository-ledger/fold-repository.js +375 -0
  156. package/build/core/repository-ledger/fold.js +248 -0
  157. package/build/core/repository-ledger/git-object-store.js +243 -0
  158. package/build/core/repository-ledger/history-read.js +15 -0
  159. package/build/core/repository-ledger/incremental-read.js +153 -0
  160. package/build/core/repository-ledger/index.js +15 -0
  161. package/build/core/repository-ledger/inventory-plan.js +75 -0
  162. package/build/core/repository-ledger/inventory.js +310 -0
  163. package/build/core/repository-ledger/publication-admission.js +125 -0
  164. package/build/core/repository-ledger/publication.js +353 -0
  165. package/build/core/repository-ledger/read-model.js +469 -0
  166. package/build/core/repository-ledger/transaction-membership.js +78 -0
  167. package/build/core/repository-ledger/traversal.js +404 -0
  168. package/build/core/repository-ledger/write-transaction.js +339 -0
  169. package/build/core/seal.js +168 -161
  170. package/build/core/settlement/claim-delivery.js +42 -215
  171. package/build/core/settlement/claim.js +235 -153
  172. package/build/core/settlement/index.js +4 -4
  173. package/build/core/settlement/petition-claim-gates.js +52 -33
  174. package/build/core/settlement/petition-forfeit.js +12 -5
  175. package/build/core/settlement/petition-head-guard.js +8 -5
  176. package/build/core/settlement/petition-preview.js +68 -56
  177. package/build/core/settlement/petition-window.js +50 -0
  178. package/build/core/settlement/petition.js +252 -131
  179. package/build/core/settlement/queue-read-model.js +72 -95
  180. package/build/core/settlement/queue-seat-allocation.js +35 -126
  181. package/build/core/settlement/queue.js +1 -1
  182. package/build/core/settlement/settlement.js +172 -80
  183. package/build/core/settlement/verdict.js +112 -66
  184. package/build/core/settlement/verification-coordination.js +305 -0
  185. package/build/core/settlement/verification-supervisor.js +275 -0
  186. package/build/core/settlement/verification.js +398 -31
  187. package/build/core/status/board.js +114 -119
  188. package/build/core/status/lifecycle.js +7 -80
  189. package/build/core/structured-query.js +23 -0
  190. package/build/core/target-ref.js +1 -1
  191. package/build/core/task/board.js +59 -24
  192. package/build/core/task/commands.js +181 -33
  193. package/build/core/task/coordinate.js +56 -0
  194. package/build/core/task/document.js +25 -9
  195. package/build/core/task/index.js +7 -4
  196. package/build/core/task/query.js +17 -27
  197. package/build/core/task/settlement-git.js +164 -179
  198. package/build/core/task/settlement-policy.js +15 -11
  199. package/build/core/task/source-board.js +31 -13
  200. package/build/core/task/task-bind-preparation.js +193 -0
  201. package/build/core/task/task-contract.js +102 -193
  202. package/build/core/task/task-file-transaction.js +171 -0
  203. package/build/core/task/task-git-runtime.js +76 -14
  204. package/build/core/task/task-git-store.js +68 -169
  205. package/build/core/task/task-store-repository.js +13 -6
  206. package/build/core/task/task-worktree.js +6 -33
  207. package/build/core/task/task.js +1 -1
  208. package/build/core/task/tree.js +3 -3
  209. package/build/core/task/validation.js +4 -3
  210. package/build/core/transcripts.js +93 -1
  211. package/build/core/worktree-bootstrap.js +44 -36
  212. package/build/core/worktree-path.js +210 -77
  213. package/build/flow-error.js +7 -7
  214. package/build/generated/version.js +2 -2
  215. package/build/git/core.js +76 -13
  216. package/build/git/refs.js +168 -46
  217. package/build/git/streaming-batch.js +73 -13
  218. package/package.json +1 -1
  219. package/skills/keiyaku/SKILL.md +1 -1
  220. package/skills/keiyaku-akuma/SKILL.md +3 -3
  221. package/skills/keiyaku-task/SKILL.md +4 -2
  222. package/skills/keiyaku-workflow/SKILL.md +88 -203
  223. package/build/core/entry.js +0 -305
  224. package/build/core/ledger-batch.js +0 -194
  225. package/build/core/ledger.js +0 -84
  226. package/build/core/projection/leash.js +0 -87
  227. package/build/core/ref-log.js +0 -119
  228. package/build/core/renew-session.js +0 -128
  229. package/build/core/status/ledger-batch.js +0 -1
  230. package/build/core/status/reconciliation.js +0 -137
@@ -0,0 +1,9 @@
1
+ export const meta = {
2
+ command: "history",
3
+ summary: "Discover retained Akuma runs or inspect one run",
4
+ usage: ["keiyaku history [PROJECTION|ALIAS|ARTIFACT] [-C|--cwd DIR] [--filter EXPR] [--sort KEYS] [--json]"],
5
+ stdin: { mode: "argument" },
6
+ flags: ["cwd", "repo", "filter", "sort", "json"],
7
+ purpose: "Read retained projection history and the public response-file path without reading response content.",
8
+ completionRank: 15,
9
+ };
@@ -1,5 +1,4 @@
1
1
  import { resolveContractAddress, withResolvedAddress, } from "../../../core/addressing.js";
2
- import { projectionDir } from "../../../core/projection/index.js";
3
2
  import { resolveProjectionAddress, } from "../../projection-address.js";
4
3
  import { projectDirectory, repositoryDirectory } from "../shared.js";
5
4
  /** Resolve cwd + optional contract address, then run the verb under that carrier. */
@@ -13,16 +12,16 @@ export async function runProjectionCommand(flags, verb, operation) {
13
12
  const run = () => operation({ cwd, address });
14
13
  return address ? await withResolvedAddress(address, run) : await run();
15
14
  }
16
- export function resolveProjectionCommandAddress(ctx, projectionAddress, verb) {
15
+ export function resolveProjectionCommandAddress(ctx, projectionAddress, verb, coordinate) {
17
16
  return resolveProjectionAddress({
18
17
  cwd: ctx.cwd,
19
18
  address: projectionAddress,
20
19
  scope: ctx.address,
20
+ coordinate,
21
21
  verb,
22
22
  });
23
23
  }
24
24
  export async function resolveProjectionCommandTarget(ctx, projectionAddress, verb) {
25
25
  const projection = await resolveProjectionCommandAddress(ctx, projectionAddress, verb);
26
- const directory = await projectionDir(ctx.cwd, projection.id);
27
- return { ...projection, directory };
26
+ return projection;
28
27
  }
@@ -3,7 +3,7 @@ import { normalizeTargetRef } from "../../../../core/target-ref.js";
3
3
  import { isProjectionId } from "../../../../core/projection/index.js";
4
4
  import { FlowError } from "../../../../flow-error.js";
5
5
  import { renderProjectionFilteredStatus, renderStatusBoard } from "../../../render/status.js";
6
- import { textResponse } from "../../../render/shared.js";
6
+ import { coreTextResponse } from "../../../render/shared.js";
7
7
  import { projectDirectory, repositoryDirectory } from "../../shared.js";
8
8
  export const handler = async (_stdin, flags, _signal, positional) => {
9
9
  const [projectionId] = positional;
@@ -21,6 +21,6 @@ export const handler = async (_stdin, flags, _signal, positional) => {
21
21
  ...(projectionId === undefined ? {} : { projectionId }),
22
22
  });
23
23
  if (projectionId === undefined)
24
- return textResponse(renderStatusBoard(board));
25
- return textResponse(renderProjectionFilteredStatus(board, projectionId));
24
+ return coreTextResponse(renderStatusBoard(board), board);
25
+ return coreTextResponse(renderProjectionFilteredStatus(board, projectionId), board);
26
26
  };
@@ -1,5 +1,4 @@
1
- import { projectionDir } from "../../../../core/projection/index.js";
2
- import { snapshotCommissionProjectionIds, waitForProjection, waitForProjectionSet } from "../../../../core/projection/index.js";
1
+ import { projectionDirAtCoordinate, resolveProjectionCoordinate, snapshotCommissionProjectionIdsAtCoordinate, waitForProjection, waitForProjectionSet, } from "../../../../core/projection/index.js";
3
2
  import { FlowError } from "../../../../flow-error.js";
4
3
  import { prependAddressReceipt } from "../../../render/address.js";
5
4
  import { buildProjectionWaitSetResponse, buildWaitResponse } from "../../../render/wait.js";
@@ -15,30 +14,40 @@ export const handler = async (_stdin, flags, signal, positional) => runProjectio
15
14
  signal,
16
15
  }), { alias: projection.alias }), ctx.address, { projectionId: projection.id, projectionAlias: projection.alias });
17
16
  }
18
- const selected = [];
17
+ const selected = new Map();
18
+ let coordinate;
19
+ if (ctx.address) {
20
+ coordinate = {
21
+ physicalRoot: ctx.address.repo.stableRoot,
22
+ authority: { kind: "repository", stableRoot: ctx.address.repo.stableRoot },
23
+ };
24
+ }
25
+ else {
26
+ coordinate = await resolveProjectionCoordinate(ctx.cwd);
27
+ }
19
28
  if (positional.length === 0) {
20
29
  if (ctx.address?.binding.kind === "commission") {
21
- selected.push(...await snapshotCommissionProjectionIds(ctx.cwd, ctx.address.binding.commissionId));
30
+ for (const id of await snapshotCommissionProjectionIdsAtCoordinate(coordinate, ctx.address.binding.commissionId)) {
31
+ selected.set(id, { id, projectionDirectory: projectionDirAtCoordinate(coordinate, id) });
32
+ }
22
33
  }
23
34
  }
24
35
  else {
25
36
  // Resolve in argument order so multiple bad coordinates have one stable failure.
26
37
  for (const projectionAddress of positional) {
27
- selected.push((await resolveProjectionCommandAddress(ctx, projectionAddress, "wait")).id);
38
+ const projection = await resolveProjectionCommandAddress(ctx, projectionAddress, "wait", coordinate);
39
+ selected.set(projection.id, { id: projection.id, projectionDirectory: projection.directory });
28
40
  }
29
41
  }
30
- const ids = [...new Set(selected)].sort();
31
- if (ids.length === 0) {
42
+ const projections = [...selected.values()].sort((left, right) => left.id.localeCompare(right.id));
43
+ if (projections.length === 0) {
32
44
  throw new FlowError("EMPTY_PARAM", "wait commission snapshot contains no projections");
33
45
  }
34
46
  if (!flags.any && !flags.all) {
35
47
  throw new FlowError("EMPTY_PARAM", WAIT_SET_SELECTION_ERROR);
36
48
  }
37
49
  return prependAddressReceipt(buildProjectionWaitSetResponse(await waitForProjectionSet({
38
- projections: await Promise.all(ids.map(async (id) => ({
39
- id,
40
- projectionDirectory: await projectionDir(ctx.cwd, id),
41
- }))),
50
+ projections,
42
51
  selection: flags.any ? "any" : "all",
43
52
  timeoutMs: flags.timeoutMs,
44
53
  signal,
@@ -1,13 +1,22 @@
1
- import { createTask, resolveTaskCreator, } from "../../../../core/task/index.js";
2
- import { parseTaskAddInput, runTaskMutationCommand } from "../shared.js";
3
- export const handler = async (stdin, flags) => {
1
+ import { createTask, openTaskMutationContext, resolveTaskCreator, } from "../../../../core/task/index.js";
2
+ import { renderTaskMutationRow } from "../../../render/task.js";
3
+ import { textResponse } from "../../../render/shared.js";
4
+ import { effectiveDirectory } from "../../shared.js";
5
+ import { parseTaskAddInput } from "../shared.js";
6
+ export const handler = async (stdin, flags, signal) => {
4
7
  const input = parseTaskAddInput(stdin);
5
- return runTaskMutationCommand(flags, async (repository, cwd) => createTask(repository, {
8
+ const cwd = effectiveDirectory(flags);
9
+ const context = await openTaskMutationContext(cwd, signal);
10
+ const task = await createTask(context.repository, {
6
11
  ...input,
12
+ namespace: context.namespace,
7
13
  creator: await resolveTaskCreator(cwd),
8
14
  ...(flags.taskPri === undefined ? {} : { pri: flags.taskPri }),
9
15
  needs: flags.taskNeeds ?? [],
10
16
  parent: flags.taskParent ?? null,
11
17
  from: flags.taskFrom ?? [],
12
- }, { now: () => new Date() }));
18
+ supersedes: flags.taskSupersedes ?? [],
19
+ relatesTo: flags.taskRelatesTo ?? [],
20
+ }, { now: () => new Date() });
21
+ return textResponse(renderTaskMutationRow(task));
13
22
  };
@@ -1,4 +1,4 @@
1
- const TASK_ADD_USAGE_PREFIX = "keiyaku task add [-C|--cwd DIR] [--needs ID]... [--parent ID] [--from ID]... [--pri 0-3]";
1
+ const TASK_ADD_USAGE_PREFIX = "keiyaku task add [-C|--cwd DIR] [--needs COORDINATE]... [--parent COORDINATE] [--from COORDINATE]... [--supersedes COORDINATE]... [--relates-to COORDINATE]... [--pri 0-3]";
2
2
  export const meta = {
3
3
  command: "task add",
4
4
  summary: "Add a task",
@@ -10,7 +10,7 @@ export const meta = {
10
10
  mode: "argument",
11
11
  selector: { kind: "positional", index: 0, required: true, rejectBlank: true },
12
12
  },
13
- flags: ["cwd", "needs", "parent", "from", "pri"],
13
+ flags: ["cwd", "needs", "parent", "from", "supersedes", "relates-to", "pri"],
14
14
  purpose: "Create a lightweight task from a title and optional body.",
15
15
  notes: [
16
16
  "<BODY> and literal - are mutually exclusive body selectors. Use literal - with stdin for multiline prose.",
@@ -5,6 +5,8 @@ import { meta as lsMeta } from "./ls/meta.js";
5
5
  import { meta as logMeta } from "./log/meta.js";
6
6
  import { meta as startMeta } from "./start/meta.js";
7
7
  import { meta as stopMeta } from "./stop/meta.js";
8
+ import { meta as holdMeta } from "./hold/meta.js";
9
+ import { meta as resumeMeta } from "./resume/meta.js";
8
10
  import { meta as doneMeta } from "./done/meta.js";
9
11
  import { meta as dropMeta } from "./drop/meta.js";
10
12
  import { meta as updateMeta } from "./update/meta.js";
@@ -17,6 +19,8 @@ export const taskCatalog = [
17
19
  { meta: logMeta, load: () => import("./log/handler.js") },
18
20
  { meta: startMeta, load: () => import("./start/handler.js") },
19
21
  { meta: stopMeta, load: () => import("./stop/handler.js") },
22
+ { meta: holdMeta, load: () => import("./hold/handler.js") },
23
+ { meta: resumeMeta, load: () => import("./resume/handler.js") },
20
24
  { meta: doneMeta, load: () => import("./done/handler.js") },
21
25
  { meta: dropMeta, load: () => import("./drop/handler.js") },
22
26
  { meta: updateMeta, load: () => import("./update/handler.js") },
@@ -1,10 +1,7 @@
1
1
  import { doneTask } from "../../../../core/task/index.js";
2
- import { effectiveDirectory } from "../../shared.js";
3
- import { mutationSelectionMessage, rejectBareContractTaskState, runTaskMutationCommand } from "../shared.js";
2
+ import { mutationSelectionMessage, runTaskMutationCommand } from "../shared.js";
4
3
  export const handler = async (_stdin, flags, _signal, positional) => {
5
4
  try {
6
- if (positional[0] === undefined)
7
- await rejectBareContractTaskState(effectiveDirectory(flags), "done");
8
5
  return await runTaskMutationCommand(flags, (repository) => doneTask(repository, positional[0]));
9
6
  }
10
7
  catch (error) {
@@ -1,7 +1,7 @@
1
1
  export const meta = {
2
2
  command: "task done",
3
3
  summary: "Complete a task",
4
- usage: ["keiyaku task done [-C|--cwd DIR] [ID]"],
4
+ usage: ["keiyaku task done [-C|--cwd DIR] [COORDINATE]"],
5
5
  stdin: { mode: "argument" },
6
6
  flags: ["cwd"],
7
7
  purpose: "Complete an open or in-progress task.",
@@ -1,7 +1,7 @@
1
1
  export const meta = {
2
2
  command: "task drop",
3
3
  summary: "Drop a task",
4
- usage: ["keiyaku task drop [-C|--cwd DIR] ID"],
4
+ usage: ["keiyaku task drop [-C|--cwd DIR] COORDINATE"],
5
5
  stdin: { mode: "argument" },
6
6
  flags: ["cwd"],
7
7
  purpose: "Abandon an open or in-progress task.",
@@ -0,0 +1,3 @@
1
+ import { holdTask } from "../../../../core/task/index.js";
2
+ import { runTaskMutationCommand } from "../shared.js";
3
+ export const handler = async (_stdin, flags, _signal, positional) => runTaskMutationCommand(flags, (repository) => holdTask(repository, positional[0]));
@@ -0,0 +1,8 @@
1
+ export const meta = {
2
+ command: "task hold",
3
+ summary: "Put a task on hold",
4
+ usage: ["keiyaku task hold [-C|--cwd DIR] COORDINATE"],
5
+ stdin: { mode: "argument" },
6
+ flags: ["cwd"],
7
+ purpose: "Move an open or in-progress task to on hold.",
8
+ };
@@ -7,6 +7,6 @@ export const handler = async (_stdin, flags, _signal, positional) => withTaskCom
7
7
  const task = board.byId.get(resolveTaskReadId(board, positional[0]));
8
8
  if (!task)
9
9
  throw new FlowError("INTERNAL_STATE", "resolved task disappeared from the board");
10
- const rows = await readTaskHistory(cwd, task.id);
10
+ const rows = await readTaskHistory(cwd, task.coordinate);
11
11
  return textResponse(rows.map(({ timestamp, actor, subject }) => `${timestamp}\t${actor}\t${subject}`).join("\n"));
12
12
  });
@@ -1,8 +1,8 @@
1
1
  export const meta = {
2
2
  command: "task log",
3
3
  summary: "Show one task's Git history",
4
- usage: ["keiyaku task log [-C|--cwd DIR] ID"],
4
+ usage: ["keiyaku task log [-C|--cwd DIR] COORDINATE"],
5
5
  stdin: { mode: "argument" },
6
6
  flags: ["cwd"],
7
- purpose: "Read the current hub branch's task micro-commit history.",
7
+ purpose: "Read the current checkout branch's task micro-commit history.",
8
8
  };
@@ -0,0 +1,3 @@
1
+ import { resumeTask } from "../../../../core/task/index.js";
2
+ import { runTaskMutationCommand } from "../shared.js";
3
+ export const handler = async (_stdin, flags, _signal, positional) => runTaskMutationCommand(flags, (repository) => resumeTask(repository, positional[0]));
@@ -0,0 +1,8 @@
1
+ export const meta = {
2
+ command: "task resume",
3
+ summary: "Resume a task on hold",
4
+ usage: ["keiyaku task resume [-C|--cwd DIR] COORDINATE"],
5
+ stdin: { mode: "argument" },
6
+ flags: ["cwd"],
7
+ purpose: "Return an on-hold task to open.",
8
+ };
@@ -1,6 +1,5 @@
1
- import * as path from "node:path";
2
1
  import { FlowError } from "../../../flow-error.js";
3
- import { isTaskId, openTaskCommandRepository, parseTaskDocument, readTaskDoctor, taskCommandContractId, } from "../../../core/task/index.js";
2
+ import { openTaskCommandRepository, parseTaskDocument, readTaskDoctor, taskCoordinateFromSourcePath, } from "../../../core/task/index.js";
4
3
  import { deriveTaskDisplay, renderTaskList, renderTaskMutationRow, } from "../../render/task.js";
5
4
  import { textResponse } from "../../render/shared.js";
6
5
  import { effectiveDirectory } from "../shared.js";
@@ -46,7 +45,7 @@ function taskDocumentsById(sources) {
46
45
  for (const source of sources) {
47
46
  try {
48
47
  const document = parseTaskDocument(source);
49
- documents.set(document.id, document);
48
+ documents.set(taskCoordinateFromSourcePath(source.path).coordinate, document);
50
49
  }
51
50
  catch {
52
51
  // Invalid documents are reported from board diseases.
@@ -59,9 +58,13 @@ function renderTaskDiseaseRows(diseases, documents) {
59
58
  const renderedCycles = new Set();
60
59
  for (const disease of diseases) {
61
60
  if (disease.code === "invalid_document") {
62
- const name = path.basename(disease.path).replace(/\.md$/, "");
63
- if (isTaskId(name))
64
- rows.push(`! ${name} invalid front matter — quarantined`);
61
+ try {
62
+ const coordinate = taskCoordinateFromSourcePath(disease.path).coordinate;
63
+ rows.push(`! ${coordinate} invalid front matter — quarantined`);
64
+ }
65
+ catch {
66
+ // A malformed non-coordinate path has no copyable task identity to render.
67
+ }
65
68
  continue;
66
69
  }
67
70
  if (disease.code === "needs_cycle" && disease.id && disease.relatedIds) {
@@ -90,6 +93,28 @@ function renderTaskDiseaseRows(diseases, documents) {
90
93
  rows.push(`! cycle detected: ${cycle.join(" → ")}`);
91
94
  continue;
92
95
  }
96
+ if (disease.code === "supersedes_cycle" && disease.id && disease.relatedIds) {
97
+ const cycleKey = `supersedes\0${disease.relatedIds.join("\0")}`;
98
+ if (renderedCycles.has(cycleKey))
99
+ continue;
100
+ renderedCycles.add(cycleKey);
101
+ const members = new Set(disease.relatedIds);
102
+ const start = [...members].sort()[0];
103
+ const cycle = [start];
104
+ let current = start;
105
+ for (let count = 0; count <= members.size; count += 1) {
106
+ const next = documents.get(current)?.supersedes.filter((id) => members.has(id)).sort()[0];
107
+ if (!next)
108
+ break;
109
+ cycle.push(next);
110
+ if (next === start)
111
+ break;
112
+ current = next;
113
+ }
114
+ if (cycle.at(-1) === start)
115
+ rows.push(`! supersedes cycle detected: ${cycle.join(" → ")}`);
116
+ continue;
117
+ }
93
118
  if (disease.code === "missing_reference" && disease.id && disease.relatedIds) {
94
119
  const document = documents.get(disease.id);
95
120
  if (!document)
@@ -99,6 +124,10 @@ function renderTaskDiseaseRows(diseases, documents) {
99
124
  rows.push(`! ${disease.id} needs missing task ${related}`);
100
125
  if (document.parent === related)
101
126
  rows.push(`? ${disease.id} parent ${related} does not exist`);
127
+ if (document.supersedes.includes(related))
128
+ rows.push(`! ${disease.id} supersedes missing task ${related}`);
129
+ if (document.relatesTo.includes(related))
130
+ rows.push(`! ${disease.id} relates to missing task ${related}`);
102
131
  }
103
132
  }
104
133
  }
@@ -108,11 +137,13 @@ export async function renderTaskDoctor(cwd) {
108
137
  const result = await readTaskDoctor(cwd);
109
138
  const board = result.board;
110
139
  const tasks = board.tasks;
111
- const counts = { inProgress: 0, ready: 0, blocked: 0, done: 0, dropped: 0, bound: 0 };
140
+ const counts = { inProgress: 0, onHold: 0, ready: 0, blocked: 0, done: 0, dropped: 0, bound: 0 };
112
141
  for (const task of tasks) {
113
142
  const display = deriveTaskDisplay(task);
114
143
  if (display === "in_progress")
115
144
  counts.inProgress += 1;
145
+ else if (display === "on_hold")
146
+ counts.onHold += 1;
116
147
  else if (display === "ready")
117
148
  counts.ready += 1;
118
149
  else if (display === "blocked")
@@ -126,7 +157,7 @@ export async function renderTaskDoctor(cwd) {
126
157
  }
127
158
  const lines = [
128
159
  `tasks · ${tasks.length} total`,
129
- `${counts.inProgress} in_progress · ${counts.ready} ready · ${counts.blocked} blocked · ${counts.done} done · ${counts.dropped} dropped · ${counts.bound} bound`,
160
+ `${counts.inProgress} in_progress · ${counts.onHold} on hold · ${counts.ready} ready · ${counts.blocked} blocked · ${counts.done} done · ${counts.dropped} dropped · ${counts.bound} bound`,
130
161
  ...renderTaskDiseaseRows(board.diseases, taskDocumentsById(result.sources)),
131
162
  ...result.orphans.map(({ taskId, contractId }) => `! ${taskId} points at contract ${contractId} which has no ledger entry — rolling back`),
132
163
  ];
@@ -134,9 +165,3 @@ export async function renderTaskDoctor(cwd) {
134
165
  lines.push("× board lock currently held by a live writer");
135
166
  return lines.join("\n");
136
167
  }
137
- export async function rejectBareContractTaskState(cwd, verb) {
138
- const contractId = await taskCommandContractId(cwd);
139
- if (contractId) {
140
- throw new FlowError("UNSUPPORTED_POLICY", `task ${verb} is not available in a contract worktree; task state follows the contract (${contractId})`);
141
- }
142
- }
@@ -8,6 +8,6 @@ export const handler = async (_stdin, flags, _signal, positional) => withTaskCom
8
8
  const task = board.byId.get(resolveTaskReadId(board, positional[0]));
9
9
  if (!task)
10
10
  throw new FlowError("INTERNAL_STATE", "resolved task disappeared from the board");
11
- const tree = buildTaskTree(board, task.id);
11
+ const tree = buildTaskTree(board, task.coordinate);
12
12
  return textResponse(flags.json ? taskJsonText(renderTaskShowJson(task, tree)) : renderTaskShow(task, tree));
13
13
  });
@@ -1,7 +1,7 @@
1
1
  export const meta = {
2
2
  command: "task show",
3
3
  summary: "Show one task and its children tree",
4
- usage: ["keiyaku task show [-C|--cwd DIR] ID [--json]"],
4
+ usage: ["keiyaku task show [-C|--cwd DIR] COORDINATE [--json]"],
5
5
  stdin: { mode: "argument" },
6
6
  flags: ["cwd", "json"],
7
7
  purpose: "Read one task and every descendant linked by parent edges.",
@@ -1,7 +1,7 @@
1
1
  export const meta = {
2
2
  command: "task start",
3
3
  summary: "Start a task",
4
- usage: ["keiyaku task start [-C|--cwd DIR] ID"],
4
+ usage: ["keiyaku task start [-C|--cwd DIR] COORDINATE"],
5
5
  stdin: { mode: "argument" },
6
6
  flags: ["cwd"],
7
7
  purpose: "Move an open task to in_progress.",
@@ -1,10 +1,7 @@
1
1
  import { stopTask } from "../../../../core/task/index.js";
2
- import { effectiveDirectory } from "../../shared.js";
3
- import { mutationSelectionMessage, rejectBareContractTaskState, runTaskMutationCommand } from "../shared.js";
2
+ import { mutationSelectionMessage, runTaskMutationCommand } from "../shared.js";
4
3
  export const handler = async (_stdin, flags, _signal, positional) => {
5
4
  try {
6
- if (positional[0] === undefined)
7
- await rejectBareContractTaskState(effectiveDirectory(flags), "stop");
8
5
  return await runTaskMutationCommand(flags, (repository) => stopTask(repository, positional[0]));
9
6
  }
10
7
  catch (error) {
@@ -1,7 +1,7 @@
1
1
  export const meta = {
2
2
  command: "task stop",
3
3
  summary: "Stop a task",
4
- usage: ["keiyaku task stop [-C|--cwd DIR] [ID]"],
4
+ usage: ["keiyaku task stop [-C|--cwd DIR] [COORDINATE]"],
5
5
  stdin: { mode: "argument" },
6
6
  flags: ["cwd"],
7
7
  purpose: "Return an in-progress task to open.",
@@ -1,13 +1,21 @@
1
- import { updateTask } from "../../../../core/task/index.js";
2
- import { runTaskMutationCommand } from "../shared.js";
1
+ import { updateTaskWithReceipt } from "../../../../core/task/index.js";
2
+ import { renderTaskUpdate, renderTaskUpdateJson } from "../../../render/task.js";
3
+ import { textResponse } from "../../../render/shared.js";
4
+ import { withTaskCommandRepository } from "../shared.js";
3
5
  export const handler = async (_stdin, flags, _signal, positional) => {
4
- return runTaskMutationCommand(flags, (repository) => updateTask(repository, positional[0], {
6
+ const result = await withTaskCommandRepository(flags, (repository) => updateTaskWithReceipt(repository, positional[0], {
5
7
  ...(flags.taskTitle === undefined ? {} : { title: flags.taskTitle }),
6
8
  ...(flags.taskBody === undefined ? {} : { body: flags.taskBody }),
9
+ ...(flags.taskAppend === undefined ? {} : { appendBody: flags.taskAppend }),
7
10
  ...(flags.taskPri === undefined ? {} : { pri: flags.taskPri }),
8
11
  ...(flags.taskNeeds === undefined ? {} : { addNeeds: flags.taskNeeds }),
9
12
  ...(flags.taskDropNeeds === undefined ? {} : { dropNeeds: flags.taskDropNeeds }),
10
13
  ...(flags.taskParent !== undefined ? { parent: flags.taskParent } : flags.taskNoParent ? { parent: null } : {}),
11
14
  ...(flags.taskFrom === undefined ? {} : { from: flags.taskFrom }),
15
+ ...(flags.taskSupersedes === undefined ? {} : { addSupersedes: flags.taskSupersedes }),
16
+ ...(flags.taskDropSupersedes === undefined ? {} : { dropSupersedes: flags.taskDropSupersedes }),
17
+ ...(flags.taskRelatesTo === undefined ? {} : { addRelatesTo: flags.taskRelatesTo }),
18
+ ...(flags.taskDropRelatesTo === undefined ? {} : { dropRelatesTo: flags.taskDropRelatesTo }),
12
19
  }));
20
+ return textResponse(flags.json ? renderTaskUpdateJson(result) : renderTaskUpdate(result));
13
21
  };
@@ -1,11 +1,11 @@
1
1
  export const meta = {
2
2
  command: "task update",
3
3
  summary: "Update task facts",
4
- usage: ["keiyaku task update [-C|--cwd DIR] ID [--title TEXT] [--body TEXT|-] [--pri 0-3] [--needs ID] [--drop-needs ID] [--parent ID|--no-parent] [--from ID]"],
4
+ usage: ["keiyaku task update [-C|--cwd DIR] COORDINATE [--title TEXT] [--body TEXT|-|--append TEXT|-] [--pri 0-3] [--needs COORDINATE] [--drop-needs COORDINATE] [--parent COORDINATE|--no-parent] [--from COORDINATE] [--supersedes COORDINATE] [--drop-supersedes COORDINATE] [--relates-to COORDINATE] [--drop-relates-to COORDINATE] [--json]"],
5
5
  stdin: {
6
6
  mode: "argument",
7
- selector: { kind: "flag", name: "taskBody", required: false, rejectBlank: false },
7
+ selector: { kind: "flag", names: ["taskBody", "taskAppend"], required: false, rejectBlank: false },
8
8
  },
9
- flags: ["cwd", "title", "body", "pri", "needs", "drop-needs", "parent", "no-parent", "from"],
9
+ flags: ["cwd", "title", "body", "append", "pri", "needs", "drop-needs", "parent", "no-parent", "from", "supersedes", "drop-supersedes", "relates-to", "drop-relates-to", "json"],
10
10
  purpose: "Change mutable task facts.",
11
11
  };
@@ -1,7 +1,7 @@
1
1
  import { assertSettingsKnobUsable } from "../config/settings/disease.js";
2
2
  import { loadKeiyakuSettings } from "../config/settings/loader.js";
3
3
  import { loadAkumaCatalog } from "../config/akuma-loader.js";
4
- import { listContractIds } from "../core/ledger.js";
4
+ import { readRepositoryLifecycle } from "../core/repository-ledger/read-model.js";
5
5
  import { TASK_FILTER_COMPLETION } from "../core/task/query.js";
6
6
  import { allCommandMetadata, getCommandMetadata } from "./commands/metadata.js";
7
7
  function topLevelCommands() {
@@ -27,7 +27,8 @@ function filterPrefix(items, word) {
27
27
  return items.filter((item) => item.startsWith(word));
28
28
  }
29
29
  async function contractAddressCandidates(cwd, word) {
30
- return filterPrefix((await listContractIds(cwd)).map((id) => `@${id}`), word);
30
+ const read = await readRepositoryLifecycle(cwd);
31
+ return filterPrefix(read.contracts.map((model) => `@${model.contract}`), word);
31
32
  }
32
33
  async function akumaCandidates(cwd, word) {
33
34
  const loaded = await loadKeiyakuSettings(cwd);
@@ -83,22 +83,37 @@ export const FLAG_SPECS = {
83
83
  place: {
84
84
  kind: "value",
85
85
  placeholder: "NAME",
86
- description: "Set the H1 contract name for flag-generated bind Markdown.",
86
+ description: "Legacy bind title spelling; bind rejects it with --title migration guidance.",
87
87
  },
88
88
  objective: {
89
89
  kind: "value",
90
90
  placeholder: "TEXT",
91
91
  description: "Set the objective for flag-generated bind Markdown.",
92
92
  },
93
+ context: {
94
+ kind: "value",
95
+ placeholder: "TEXT",
96
+ description: "Set established facts and constraints for flag-generated bind Markdown.",
97
+ },
98
+ design: {
99
+ kind: "value",
100
+ placeholder: "TEXT",
101
+ description: "Set the settled design for flag-generated bind Markdown.",
102
+ },
93
103
  scope: {
94
104
  kind: "value",
95
105
  placeholder: "GLOB",
96
106
  description: "Set the single scope pattern for flag-generated bind Markdown.",
97
107
  },
98
- checks: {
108
+ criteria: {
99
109
  kind: "value",
100
- placeholder: "CHECK",
101
- description: "Set the single acceptance check for flag-generated bind Markdown.",
110
+ placeholder: "CRITERION",
111
+ description: "Set the single declarative acceptance criterion for flag-generated bind Markdown.",
112
+ },
113
+ verification: {
114
+ kind: "value",
115
+ placeholder: "DECLARATION",
116
+ description: "Set the single executable verification declaration for flag-generated bind Markdown.",
102
117
  },
103
118
  task: {
104
119
  kind: "value",
@@ -132,17 +147,13 @@ export const FLAG_SPECS = {
132
147
  kind: "boolean",
133
148
  description: "Renew onto the current target before petitioning.",
134
149
  },
135
- resolve: {
136
- kind: "boolean",
137
- description: "Open a durable Keiyaku-owned renew recovery session when the rewrite conflicts.",
138
- },
139
150
  continue: {
140
151
  kind: "boolean",
141
- description: "Continue the open Keiyaku-owned renew recovery session.",
152
+ description: "Continue from the derived renew conflict scratch.",
142
153
  },
143
154
  abort: {
144
155
  kind: "boolean",
145
- description: "Restore and remove the open Keiyaku-owned renew recovery session.",
156
+ description: "Delete the derived renew conflict scratch without moving authoritative refs.",
146
157
  },
147
158
  shell: {
148
159
  kind: "value",
@@ -174,7 +185,7 @@ export const FLAG_SPECS = {
174
185
  },
175
186
  json: {
176
187
  kind: "boolean",
177
- description: "Render task data as JSON.",
188
+ description: "Render structured data as JSON.",
178
189
  },
179
190
  "diff-budget": {
180
191
  kind: "value",
@@ -188,12 +199,12 @@ export const FLAG_SPECS = {
188
199
  filter: {
189
200
  kind: "value",
190
201
  placeholder: TASK_FILTER_GRAMMAR,
191
- description: "Filter structured task facts. Repeat --filter for AND; comma values or | terms are OR.",
202
+ description: "Filter structured facts. Repeat --filter for AND; comma values or | terms are OR.",
192
203
  },
193
204
  sort: {
194
205
  kind: "value",
195
206
  placeholder: "KEY[,KEY...]",
196
- description: "Sort by priority ascending, modified descending, or created descending.",
207
+ description: "Sort the selected structured collection.",
197
208
  },
198
209
  pri: {
199
210
  kind: "value",
@@ -224,16 +235,41 @@ export const FLAG_SPECS = {
224
235
  placeholder: "ID",
225
236
  description: "Add a discovery-lineage task. May be repeated.",
226
237
  },
238
+ supersedes: {
239
+ kind: "value",
240
+ placeholder: "ID",
241
+ description: "Record that this task supersedes another task. May be repeated.",
242
+ },
243
+ "drop-supersedes": {
244
+ kind: "value",
245
+ placeholder: "ID",
246
+ description: "Remove a supersedes relation. May be repeated.",
247
+ },
248
+ "relates-to": {
249
+ kind: "value",
250
+ placeholder: "ID",
251
+ description: "Record related work. May be repeated.",
252
+ },
253
+ "drop-relates-to": {
254
+ kind: "value",
255
+ placeholder: "ID",
256
+ description: "Remove a related-work relation. May be repeated.",
257
+ },
227
258
  title: {
228
259
  kind: "value",
229
260
  placeholder: "TEXT",
230
- description: "Replace the task title.",
261
+ description: "Set the bind document title or replace the task title.",
231
262
  },
232
263
  body: {
233
264
  kind: "value",
234
265
  placeholder: "TEXT|-",
235
266
  description: "Replace the task body; literal - reads stdin.",
236
267
  },
268
+ append: {
269
+ kind: "value",
270
+ placeholder: "TEXT|-",
271
+ description: "Append a Markdown paragraph to the task body; literal - reads stdin.",
272
+ },
237
273
  };
238
274
  export const CONTROL_FLAGS = new Set(Object.keys(FLAG_SPECS));
239
275
  export const VALUE_FLAGS = new Set(Object.entries(FLAG_SPECS)
@@ -244,5 +280,6 @@ export const BOOLEAN_FLAGS = new Set(Object.entries(FLAG_SPECS)
244
280
  .map(([name]) => name));
245
281
  export const SHORT_FLAG_ALIASES = {
246
282
  C: "cwd",
283
+ d: "detach",
247
284
  f: "force",
248
285
  };
package/build/cli/help.js CHANGED
@@ -13,6 +13,9 @@ function flagUsage(name, specs) {
13
13
  if (name === "cwd") {
14
14
  return `-C, --cwd ${spec?.placeholder ?? "DIR"}`;
15
15
  }
16
+ if (name === "detach") {
17
+ return "-d, --detach";
18
+ }
16
19
  return spec?.kind === "value" ? `--${name} ${spec.placeholder ?? "VALUE"}` : `--${name}`;
17
20
  }
18
21
  export { CLI_COMMAND_METADATA };
@@ -69,7 +72,7 @@ export function renderCliHelp(version) {
69
72
  "Configuration:",
70
73
  " Akuma profiles <KEIYAKU_HOME>/akuma/*.md or .keiyaku/akuma/*.md",
71
74
  " Settings <KEIYAKU_HOME>/settings.json or .keiyaku/settings.json",
72
- " Inspect keiyaku akuma ls | keiyaku akuma view NAME",
75
+ " Inspect keiyaku akuma ls | keiyaku akuma show NAME",
73
76
  " Environment keiyaku dump-env",
74
77
  " Full format README Configuration",
75
78
  ].join("\n");