@astrosheep/keiyaku 2.8.5 → 2.9.0

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 (228) 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 +39 -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 +35 -0
  55. package/build/cli/commands/projection/kill/meta.js +11 -0
  56. package/build/cli/commands/projection/revive/handler.js +53 -0
  57. package/build/cli/commands/projection/revive/meta.js +9 -0
  58. package/build/cli/commands/projection/status/handler.js +23 -0
  59. package/build/cli/commands/projection/status/meta.js +9 -0
  60. package/build/cli/commands/projection/tell/handler.js +34 -0
  61. package/build/cli/commands/projection/tell/meta.js +9 -0
  62. package/build/cli/commands/projection/wait/handler.js +21 -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.js +159 -72
  106. package/build/cli/projection-address.js +5 -0
  107. package/build/cli/render/arc.js +1 -1
  108. package/build/cli/render/errors.js +4 -3
  109. package/build/cli/render/format.js +14 -0
  110. package/build/cli/render/kanshi.js +106 -0
  111. package/build/cli/render/petition.js +24 -1
  112. package/build/cli/render/projection-activity.js +5 -1
  113. package/build/cli/render/shared.js +2 -2
  114. package/build/cli/render/status.js +79 -13
  115. package/build/cli/render/task.js +113 -0
  116. package/build/cli/render/wait.js +23 -3
  117. package/build/cli/types.js +1 -1
  118. package/build/config/{akuma-loader_v2.js → akuma-loader.js} +2 -2
  119. package/build/config/env.js +9 -4
  120. package/build/config/settings/disease.js +26 -0
  121. package/build/config/settings/knobs.js +8 -0
  122. package/build/config/settings/loader.js +244 -0
  123. package/build/config/settings/schema.js +276 -0
  124. package/build/core/addressing.js +1 -1
  125. package/build/core/amend.js +3 -3
  126. package/build/core/arc.js +5 -4
  127. package/build/core/bind-workspace.js +123 -0
  128. package/build/core/bind.js +75 -155
  129. package/build/core/call/call.js +224 -0
  130. package/build/core/call/context.js +238 -0
  131. package/build/core/call/execution.js +217 -0
  132. package/build/core/call/prompt.js +42 -0
  133. package/build/core/call/reference.js +24 -0
  134. package/build/core/call-persist.js +1 -1
  135. package/build/core/claim-delivery.js +247 -0
  136. package/build/core/claim.js +39 -277
  137. package/build/core/context.js +2 -1
  138. package/build/core/{render.js → contract-view.js} +12 -140
  139. package/build/core/draft.js +107 -9
  140. package/build/core/entry.js +9 -1
  141. package/build/core/execution-coordinate.js +4 -20
  142. package/build/core/execution-pact.js +16 -31
  143. package/build/core/forfeit.js +35 -22
  144. package/build/core/hints.js +2 -2
  145. package/build/core/log.js +2 -2
  146. package/build/core/petition-claim-gates.js +8 -6
  147. package/build/core/petition-preview.js +97 -0
  148. package/build/core/petition-run.js +3 -2
  149. package/build/core/petition.js +39 -26
  150. package/build/core/projection/generation/database.js +306 -0
  151. package/build/core/projection/generation/identity.js +84 -0
  152. package/build/core/projection/generation/model.js +201 -0
  153. package/build/core/projection/generation/store.js +73 -0
  154. package/build/core/projection/generation/transitions.js +258 -0
  155. package/build/core/projection/heart.js +0 -307
  156. package/build/core/projection/tell/database.js +109 -0
  157. package/build/core/projection/tell/model.js +97 -0
  158. package/build/core/{projection-tells.js → projection/tell/store.js} +3 -158
  159. package/build/core/projection-activity.js +23 -2
  160. package/build/core/projection-core.js +2 -1
  161. package/build/core/projection-execution-observer.js +259 -0
  162. package/build/core/projection-generation-continuation.js +1 -1
  163. package/build/core/projection-generation-execution.js +90 -20
  164. package/build/core/projection-generation-launcher.js +1 -1
  165. package/build/core/projection-generation-runner.js +198 -4
  166. package/build/core/projection-identity.js +1 -1
  167. package/build/core/projection-kill.js +50 -17
  168. package/build/core/projection-life-observer.js +1 -1
  169. package/build/core/projection-life-protocol.js +10 -0
  170. package/build/core/projection-mint.js +1 -1
  171. package/build/core/projection-status.js +45 -32
  172. package/build/core/projection-wait.js +12 -2
  173. package/build/core/projection-wake.js +5 -2
  174. package/build/core/{queue_v2.js → queue.js} +2 -1
  175. package/build/core/registry.js +1 -1
  176. package/build/core/renew.js +7 -7
  177. package/build/core/response-artifact-catalog-sqlite.js +112 -0
  178. package/build/core/response-artifact-catalog.js +7 -0
  179. package/build/core/seal.js +44 -16
  180. package/build/core/status/board.js +286 -0
  181. package/build/core/status/drift.js +99 -0
  182. package/build/core/status/lifecycle.js +84 -0
  183. package/build/core/status/reconciliation.js +131 -0
  184. package/build/core/stored-agent-event.js +28 -4
  185. package/build/core/target-ref.js +10 -0
  186. package/build/core/task/board.js +175 -0
  187. package/build/core/task/commands.js +211 -0
  188. package/build/core/task/document.js +189 -0
  189. package/build/core/task/model.js +1 -0
  190. package/build/core/task/settlement-git.js +207 -0
  191. package/build/core/task/settlement-policy.js +82 -0
  192. package/build/core/task/source-board.js +84 -0
  193. package/build/core/task/source-model.js +1 -0
  194. package/build/core/task/validation.js +44 -0
  195. package/build/core/task-contract.js +224 -0
  196. package/build/core/task-doctor.js +14 -0
  197. package/build/core/task-git-actor.js +38 -0
  198. package/build/core/task-git-runtime.js +34 -0
  199. package/build/core/task-git-store.js +375 -0
  200. package/build/core/task-repository.js +1 -0
  201. package/build/core/task-store-repository.js +86 -0
  202. package/build/core/task-store.js +1 -0
  203. package/build/core/task-worktree.js +51 -0
  204. package/build/core/task.js +4 -0
  205. package/build/core/transcripts.js +138 -56
  206. package/build/core/validation.js +17 -0
  207. package/build/core/verdict.js +2 -2
  208. package/build/core/worktree-path.js +24 -6
  209. package/build/flow-error.js +3 -2
  210. package/build/git/commits.js +3 -0
  211. package/build/git/diff/parsers.js +0 -94
  212. package/build/index.js +2 -0
  213. package/build/keiyaku-constants.js +2 -0
  214. package/build/keiyaku.js +4 -3
  215. package/package.json +3 -2
  216. package/skills/keiyaku/SKILL.md +1 -1
  217. package/skills/keiyaku-akuma/SKILL.md +11 -6
  218. package/build/agents/harness/pump.js +0 -158
  219. package/build/agents/providers/codex-app-server.js +0 -864
  220. package/build/agents/providers/opencode-sdk.js +0 -363
  221. package/build/agents/providers/pi.js +0 -557
  222. package/build/config/settings.js +0 -533
  223. package/build/core/call.js +0 -686
  224. package/build/core/projection/generation.js +0 -412
  225. package/build/core/projection/identity.js +0 -81
  226. package/build/core/projection/mint.js +0 -174
  227. package/build/core/projection-generation-store.js +0 -707
  228. package/build/core/status.js +0 -539
@@ -0,0 +1,21 @@
1
+ import { resolveContractAddress, withResolvedAddress, } from "../../../../core/addressing.js";
2
+ import { projectionDir } from "../../../../core/projection-core.js";
3
+ import { waitForProjection } from "../../../../core/projection-wait.js";
4
+ import { resolveProjectionAddress } from "../../../projection-address.js";
5
+ import { prependAddressReceipt } from "../../../render/address.js";
6
+ import { buildWaitResponse } from "../../../render/wait.js";
7
+ import { projectDirectory, repositoryDirectory } from "../../shared.js";
8
+ export const handler = async (_stdin, flags, signal, positional) => {
9
+ const cwd = flags.contractId ? await repositoryDirectory(flags) : await projectDirectory(flags);
10
+ const address = flags.contractId ? await resolveContractAddress(cwd, flags.contractId, flags.contractAddressSource) : undefined;
11
+ const operation = async () => {
12
+ const projection = await resolveProjectionAddress({
13
+ cwd,
14
+ address: positional[0],
15
+ scope: address,
16
+ verb: "wait",
17
+ });
18
+ return prependAddressReceipt(buildWaitResponse(projection.id, await waitForProjection({ projectionDirectory: projectionDir(cwd, projection.id), timeoutMs: flags.timeoutMs, signal }), { alias: projection.alias }), address, { projectionId: projection.id, projectionAlias: projection.alias });
19
+ };
20
+ return address ? await withResolvedAddress(address, operation) : await operation();
21
+ };
@@ -0,0 +1,11 @@
1
+ export const meta = {
2
+ command: "wait",
3
+ summary: "Wait for an akuma projection",
4
+ usage: [
5
+ "keiyaku wait <projection-address> [--timeout DURATION]",
6
+ "keiyaku @addr wait <projection-address> [--timeout DURATION]",
7
+ ],
8
+ stdin: "none",
9
+ flags: ["cwd", "repo", "contract", "timeout"],
10
+ purpose: "Read an akuma projection until its outcome is available, or show a timeout snapshot.",
11
+ };
@@ -0,0 +1,100 @@
1
+ import { FlowError } from "../../flow-error.js";
2
+ import { contractCatalog } from "./contract/catalog.js";
3
+ import { projectionCatalog } from "./projection/catalog.js";
4
+ import { akumaCatalog } from "./akuma/catalog.js";
5
+ import { skillsCatalog } from "./skills/catalog.js";
6
+ import { systemCatalog } from "./system/catalog.js";
7
+ import { taskCatalog } from "./task/catalog.js";
8
+ /** Stable metadata key order consumed by help and tests. */
9
+ const METADATA_ORDER = [
10
+ "bind",
11
+ "arc",
12
+ "call",
13
+ "revive",
14
+ "wait",
15
+ "tell",
16
+ "kill",
17
+ "log",
18
+ "akuma",
19
+ "akuma ls",
20
+ "akuma view",
21
+ "skills",
22
+ "skills install",
23
+ "amend",
24
+ "renew",
25
+ "petition",
26
+ "forfeit",
27
+ "guide",
28
+ "completion",
29
+ "status",
30
+ "task",
31
+ "task add",
32
+ "task view",
33
+ "task ls",
34
+ "task start",
35
+ "task stop",
36
+ "task done",
37
+ "task drop",
38
+ "task update",
39
+ "task doctor",
40
+ "dump-env",
41
+ ];
42
+ function buildRegistry(catalogs) {
43
+ const registrations = catalogs.flat();
44
+ const byCommand = new Map();
45
+ for (const registration of registrations) {
46
+ const command = registration.meta.command;
47
+ if (byCommand.has(command)) {
48
+ throw new FlowError("INTERNAL_STATE", `duplicate CLI command registration: ${command}`);
49
+ }
50
+ byCommand.set(command, registration);
51
+ }
52
+ const registry = {};
53
+ for (const command of METADATA_ORDER) {
54
+ const registration = byCommand.get(command);
55
+ if (!registration) {
56
+ throw new FlowError("INTERNAL_STATE", `missing CLI command registration: ${command}`);
57
+ }
58
+ registry[command] = registration;
59
+ byCommand.delete(command);
60
+ }
61
+ if (byCommand.size > 0) {
62
+ const extras = [...byCommand.keys()].join(", ");
63
+ throw new FlowError("INTERNAL_STATE", `unexpected CLI command registration: ${extras}`);
64
+ }
65
+ return Object.freeze(registry);
66
+ }
67
+ const REGISTRY = buildRegistry([
68
+ contractCatalog,
69
+ projectionCatalog,
70
+ akumaCatalog,
71
+ skillsCatalog,
72
+ systemCatalog,
73
+ taskCatalog,
74
+ ]);
75
+ /** Longest multi-token match first; same token count keeps METADATA_ORDER. */
76
+ function deriveParseOrder(order) {
77
+ return [...order].sort((a, b) => {
78
+ const tokenDelta = b.split(" ").length - a.split(" ").length;
79
+ if (tokenDelta !== 0)
80
+ return tokenDelta;
81
+ return order.indexOf(a) - order.indexOf(b);
82
+ });
83
+ }
84
+ const PARSE_ORDER = deriveParseOrder(METADATA_ORDER);
85
+ export function getCommandRegistration(command) {
86
+ return REGISTRY[command];
87
+ }
88
+ export function getCommandMetadata(command) {
89
+ return REGISTRY[command].meta;
90
+ }
91
+ export function allCommandMetadata() {
92
+ return METADATA_ORDER.map((command) => REGISTRY[command].meta);
93
+ }
94
+ export function commandParseOrder() {
95
+ return PARSE_ORDER;
96
+ }
97
+ export async function loadCommandHandler(command) {
98
+ const module = await REGISTRY[command].load();
99
+ return module.handler;
100
+ }
@@ -0,0 +1,71 @@
1
+ import { FlowError } from "../../flow-error.js";
2
+ import { AddressResolutionError, buildResolutionAttempt, } from "../../core/addressing.js";
3
+ import { isGitRepo } from "../../git/branches.js";
4
+ import { stableRepoRoot } from "../../core/worktree-path.js";
5
+ import { assertProjectionAlias } from "../../core/projection-alias.js";
6
+ export function titleFromCallPrompt(prompt) {
7
+ const firstLine = prompt
8
+ .split(/\r?\n/)
9
+ .map((line) => line.trim())
10
+ .find((line) => line.length > 0);
11
+ if (!firstLine)
12
+ return "Call";
13
+ return firstLine.replace(/^#+\s*/, "").slice(0, 80) || "Call";
14
+ }
15
+ export function repositoryCoordinateFromAddress(address) {
16
+ return address?.repo.kind === "repository" ? address.repo.stableRoot : undefined;
17
+ }
18
+ export function buildCallInput(content, flags, mode = "call") {
19
+ const cwd = flags.cwd ?? process.cwd();
20
+ const task = content.trim();
21
+ if (!task) {
22
+ throw new FlowError("EMPTY_PARAM", `${mode} body cannot be empty`);
23
+ }
24
+ return {
25
+ cwd,
26
+ repo: flags.repo,
27
+ mode,
28
+ contractId: flags.contractId,
29
+ contractAddressSource: flags.contractAddressSource,
30
+ title: titleFromCallPrompt(task),
31
+ task,
32
+ agent: flags.akuma,
33
+ model: flags.model,
34
+ effort: flags.effort,
35
+ incognito: flags.incognito,
36
+ bare: flags.bare,
37
+ detach: flags.detach,
38
+ ...(mode === "call" && flags.alias !== undefined ? { alias: assertProjectionAlias(flags.alias) } : {}),
39
+ };
40
+ }
41
+ export function revivePrompt(stdin) {
42
+ return stdin.trim() ? stdin : "Continue from the previous response.";
43
+ }
44
+ export function effectiveDirectory(flags) {
45
+ return flags.cwd ?? process.cwd();
46
+ }
47
+ export async function repositoryDirectory(flags) {
48
+ const candidate = flags.repo ?? effectiveDirectory(flags);
49
+ if (!(await isGitRepo(candidate))) {
50
+ if (flags.contractId) {
51
+ const asTyped = flags.contractAddressSource === "at-address"
52
+ ? `@${flags.contractId}`
53
+ : `--contract ${flags.contractId}`;
54
+ throw new AddressResolutionError("EMPTY_PARAM", `${asTyped} is a commission address, but ${candidate} has no repository ledger; contract addressing requires a ledger`, buildResolutionAttempt({
55
+ repo: { kind: "user" },
56
+ workdir: effectiveDirectory(flags),
57
+ spelling: {
58
+ asTyped,
59
+ source: flags.contractAddressSource ?? "explicit-flag",
60
+ },
61
+ }));
62
+ }
63
+ throw new FlowError("NOT_GIT_REPO", `${candidate} is not a git repository`);
64
+ }
65
+ return flags.repo ? await stableRepoRoot(candidate) : candidate;
66
+ }
67
+ export async function projectDirectory(flags) {
68
+ if (flags.repo)
69
+ return await repositoryDirectory(flags);
70
+ return effectiveDirectory(flags);
71
+ }
@@ -0,0 +1,6 @@
1
+ import { meta as skillsMeta } from "./skills/meta.js";
2
+ import { meta as installMeta } from "./install/meta.js";
3
+ export const skillsCatalog = [
4
+ { meta: skillsMeta, load: () => import("./skills/handler.js") },
5
+ { meta: installMeta, load: () => import("./install/handler.js") },
6
+ ];
@@ -0,0 +1,10 @@
1
+ import { installOfficialSkills } from "../../../skills-install.js";
2
+ import { textResponse } from "../../../render/shared.js";
3
+ export const handler = async (_stdin, flags) => {
4
+ const result = await installOfficialSkills(flags.force);
5
+ return textResponse([
6
+ "Installed official Keiyaku skills:",
7
+ ...result.targets.map((target) => `- ${target.path} -> ${target.source} (${target.status})`),
8
+ ...(result.warnings.length > 0 ? ["", "## Warning", ...result.warnings.map((warning) => `- ${warning}`)] : []),
9
+ ].join("\n"));
10
+ };
@@ -0,0 +1,9 @@
1
+ export const meta = {
2
+ command: "skills install",
3
+ summary: "Install the official Keiyaku skills",
4
+ usage: ["keiyaku skills install [-f|--force]"],
5
+ stdin: "none",
6
+ flags: ["force"],
7
+ purpose: "Install the bundled official Keiyaku skills into supported agent skill directories.",
8
+ notes: ["Force permits replacement of foreign collisions."],
9
+ };
@@ -0,0 +1,4 @@
1
+ import { missingSubcommandError } from "../../../help.js";
2
+ export const handler = async () => {
3
+ throw missingSubcommandError("skills", ["install"]);
4
+ };
@@ -0,0 +1,10 @@
1
+ export const meta = {
2
+ command: "skills",
3
+ summary: "Install official skills",
4
+ usage: ["keiyaku skills install"],
5
+ stdin: "none",
6
+ flags: [],
7
+ purpose: "Install bundled official Keiyaku skills into supported agent skill directories.",
8
+ subcommands: ["install"],
9
+ completionRank: 7,
10
+ };
@@ -0,0 +1,8 @@
1
+ import { meta as guideMeta } from "./guide/meta.js";
2
+ import { meta as completionMeta } from "./completion/meta.js";
3
+ import { meta as dumpEnvMeta } from "./dump-env/meta.js";
4
+ export const systemCatalog = [
5
+ { meta: guideMeta, load: () => import("./guide/handler.js") },
6
+ { meta: completionMeta, load: () => import("./completion/handler.js") },
7
+ { meta: dumpEnvMeta, load: () => import("./dump-env/handler.js") },
8
+ ];
@@ -0,0 +1,10 @@
1
+ import { renderCompletionCandidates, renderCompletionScript } from "../../../completion.js";
2
+ import { textResponse } from "../../../render/shared.js";
3
+ import { projectDirectory } from "../../shared.js";
4
+ export const handler = async (_stdin, flags) => {
5
+ const cwd = await projectDirectory(flags);
6
+ if (flags.complete) {
7
+ return textResponse(await renderCompletionCandidates({ cwd, word: flags.word, previous: flags.previous }));
8
+ }
9
+ return textResponse(renderCompletionScript(flags.shell));
10
+ };
@@ -0,0 +1,9 @@
1
+ export const meta = {
2
+ command: "completion",
3
+ summary: "Print shell completion",
4
+ usage: ["keiyaku completion [--shell bash|zsh]"],
5
+ stdin: "none",
6
+ flags: ["cwd", "repo", "shell", "word", "previous", "complete"],
7
+ purpose: "Print command and address candidates.",
8
+ completionRank: 13,
9
+ };
@@ -0,0 +1,3 @@
1
+ import { renderEnvExample } from "../../../../config/env-keys.js";
2
+ import { textResponse } from "../../../render/shared.js";
3
+ export const handler = async () => textResponse(renderEnvExample());
@@ -0,0 +1,10 @@
1
+ export const meta = {
2
+ command: "dump-env",
3
+ summary: "Print the environment template",
4
+ usage: ["keiyaku dump-env"],
5
+ stdin: "none",
6
+ flags: [],
7
+ purpose: "Print supported environment keys.",
8
+ notes: ["Keiyaku loads <KEIYAKU_HOME>/.env, then .keiyaku/.env; process environment values win."],
9
+ completionRank: 15,
10
+ };
@@ -0,0 +1,4 @@
1
+ import { VERSION } from "../../../../generated/version.js";
2
+ import { buildKeiyakuGuide } from "../../../help.js";
3
+ import { textResponse } from "../../../render/shared.js";
4
+ export const handler = async () => textResponse(buildKeiyakuGuide(VERSION));
@@ -0,0 +1,9 @@
1
+ export const meta = {
2
+ command: "guide",
3
+ summary: "Print the Keiyaku guide",
4
+ usage: ["keiyaku guide"],
5
+ stdin: "none",
6
+ flags: [],
7
+ purpose: "Print workflow guidance.",
8
+ completionRank: 12,
9
+ };
@@ -0,0 +1,21 @@
1
+ import { randomBytes } from "node:crypto";
2
+ import { resolveTaskCreator } from "../../../../core/task-git-actor.js";
3
+ import { openTaskCommandRepository } from "../../../../core/task-git-runtime.js";
4
+ import { createTask } from "../../../../core/task.js";
5
+ import { renderTaskMutationRow } from "../../../render/task.js";
6
+ import { textResponse } from "../../../render/shared.js";
7
+ import { effectiveDirectory } from "../../shared.js";
8
+ import { parseTaskAddInput } from "../shared.js";
9
+ export const handler = async (stdin, flags, _signal, positional) => {
10
+ const cwd = effectiveDirectory(flags);
11
+ const input = parseTaskAddInput(positional[0] === "-" ? stdin : positional[0]);
12
+ const task = await createTask(await openTaskCommandRepository(cwd), {
13
+ ...input,
14
+ creator: resolveTaskCreator(cwd),
15
+ ...(flags.taskPri === undefined ? {} : { pri: flags.taskPri }),
16
+ needs: flags.taskNeeds ?? [],
17
+ parent: flags.taskParent ?? null,
18
+ from: flags.taskFrom ?? [],
19
+ }, { randomBytes, now: () => new Date() });
20
+ return textResponse(renderTaskMutationRow(task));
21
+ };
@@ -0,0 +1,8 @@
1
+ export const meta = {
2
+ command: "task add",
3
+ summary: "Add a task",
4
+ usage: ["keiyaku task add [-C|--cwd DIR] [--needs ID] [--parent ID] [--from ID] [--pri 0-3] <BODY|->"],
5
+ stdin: "none",
6
+ flags: ["cwd", "needs", "parent", "from", "pri"],
7
+ purpose: "Create a lightweight task from a title and optional body.",
8
+ };
@@ -0,0 +1,22 @@
1
+ import { meta as taskMeta } from "./task/meta.js";
2
+ import { meta as addMeta } from "./add/meta.js";
3
+ import { meta as viewMeta } from "./view/meta.js";
4
+ import { meta as lsMeta } from "./ls/meta.js";
5
+ import { meta as startMeta } from "./start/meta.js";
6
+ import { meta as stopMeta } from "./stop/meta.js";
7
+ import { meta as doneMeta } from "./done/meta.js";
8
+ import { meta as dropMeta } from "./drop/meta.js";
9
+ import { meta as updateMeta } from "./update/meta.js";
10
+ import { meta as doctorMeta } from "./doctor/meta.js";
11
+ export const taskCatalog = [
12
+ { meta: taskMeta, load: () => import("./task/handler.js") },
13
+ { meta: addMeta, load: () => import("./add/handler.js") },
14
+ { meta: viewMeta, load: () => import("./view/handler.js") },
15
+ { meta: lsMeta, load: () => import("./ls/handler.js") },
16
+ { meta: startMeta, load: () => import("./start/handler.js") },
17
+ { meta: stopMeta, load: () => import("./stop/handler.js") },
18
+ { meta: doneMeta, load: () => import("./done/handler.js") },
19
+ { meta: dropMeta, load: () => import("./drop/handler.js") },
20
+ { meta: updateMeta, load: () => import("./update/handler.js") },
21
+ { meta: doctorMeta, load: () => import("./doctor/handler.js") },
22
+ ];
@@ -0,0 +1,4 @@
1
+ import { textResponse } from "../../../render/shared.js";
2
+ import { effectiveDirectory } from "../../shared.js";
3
+ import { renderTaskDoctor } from "../shared.js";
4
+ export const handler = async (_stdin, flags) => textResponse(await renderTaskDoctor(effectiveDirectory(flags)));
@@ -0,0 +1,8 @@
1
+ export const meta = {
2
+ command: "task doctor",
3
+ summary: "Diagnose the task board",
4
+ usage: ["keiyaku task doctor [-C|--cwd DIR]"],
5
+ stdin: "none",
6
+ flags: ["cwd"],
7
+ purpose: "Report task state counts, supported board diseases, and lock state without repair.",
8
+ };
@@ -0,0 +1,17 @@
1
+ import { openTaskCommandRepository } from "../../../../core/task-git-runtime.js";
2
+ import { doneTask } from "../../../../core/task.js";
3
+ import { renderTaskMutationRow } from "../../../render/task.js";
4
+ import { textResponse } from "../../../render/shared.js";
5
+ import { effectiveDirectory } from "../../shared.js";
6
+ import { mutationSelectionMessage, rejectBareContractTaskState } from "../shared.js";
7
+ export const handler = async (_stdin, flags, _signal, positional) => {
8
+ try {
9
+ const cwd = effectiveDirectory(flags);
10
+ if (positional[0] === undefined)
11
+ await rejectBareContractTaskState(cwd, "done");
12
+ return textResponse(renderTaskMutationRow(await doneTask(await openTaskCommandRepository(cwd), positional[0])));
13
+ }
14
+ catch (error) {
15
+ return mutationSelectionMessage(error);
16
+ }
17
+ };
@@ -0,0 +1,8 @@
1
+ export const meta = {
2
+ command: "task done",
3
+ summary: "Complete a task",
4
+ usage: ["keiyaku task done [-C|--cwd DIR] [ID]"],
5
+ stdin: "none",
6
+ flags: ["cwd"],
7
+ purpose: "Complete an open or in-progress task.",
8
+ };
@@ -0,0 +1,6 @@
1
+ import { openTaskCommandRepository } from "../../../../core/task-git-runtime.js";
2
+ import { dropTask } from "../../../../core/task.js";
3
+ import { renderTaskMutationRow } from "../../../render/task.js";
4
+ import { textResponse } from "../../../render/shared.js";
5
+ import { effectiveDirectory } from "../../shared.js";
6
+ export const handler = async (_stdin, flags, _signal, positional) => textResponse(renderTaskMutationRow(await dropTask(await openTaskCommandRepository(effectiveDirectory(flags)), positional[0])));
@@ -0,0 +1,8 @@
1
+ export const meta = {
2
+ command: "task drop",
3
+ summary: "Drop a task",
4
+ usage: ["keiyaku task drop [-C|--cwd DIR] ID"],
5
+ stdin: "none",
6
+ flags: ["cwd"],
7
+ purpose: "Abandon an open or in-progress task.",
8
+ };
@@ -0,0 +1,13 @@
1
+ import { openTaskCommandRepository } from "../../../../core/task-git-runtime.js";
2
+ import { readTaskBoard } from "../../../../core/task.js";
3
+ import { renderTaskList, renderTaskListJson } from "../../../render/task.js";
4
+ import { textResponse } from "../../../render/shared.js";
5
+ import { effectiveDirectory } from "../../shared.js";
6
+ import { taskJsonText, taskSelection } from "../shared.js";
7
+ export const handler = async (_stdin, flags) => {
8
+ const board = await readTaskBoard(await openTaskCommandRepository(effectiveDirectory(flags)));
9
+ const selection = taskSelection(flags);
10
+ return textResponse(flags.json
11
+ ? taskJsonText(renderTaskListJson(board.tasks, selection))
12
+ : renderTaskList(board.tasks, { selection }));
13
+ };
@@ -0,0 +1,8 @@
1
+ export const meta = {
2
+ command: "task ls",
3
+ summary: "List tasks",
4
+ usage: ["keiyaku task ls [-C|--cwd DIR] [--all|--done] [--json]"],
5
+ stdin: "none",
6
+ flags: ["cwd", "all", "done", "json"],
7
+ purpose: "List tasks from the working-tree board.",
8
+ };
@@ -0,0 +1,131 @@
1
+ import * as path from "node:path";
2
+ import { FlowError } from "../../../flow-error.js";
3
+ import { readTaskDoctor, taskCommandContractId } from "../../../core/task-git-runtime.js";
4
+ import { deriveTaskDisplay, renderTaskList, } from "../../render/task.js";
5
+ import { parseTaskDocument, } from "../../../core/task.js";
6
+ export function parseTaskAddInput(input) {
7
+ if (!input.trim())
8
+ throw new FlowError("EMPTY_PARAM", "task add input cannot be blank");
9
+ const lines = input.split(/\r?\n/);
10
+ const title = lines[0]?.trim() ?? "";
11
+ if (!title)
12
+ throw new FlowError("EMPTY_PARAM", "task title cannot be blank");
13
+ if (lines.length > 1 && lines[1].trim() !== "") {
14
+ throw new FlowError("EMPTY_PARAM", "task add body must follow the title after a blank line");
15
+ }
16
+ return { title, body: lines.slice(2).join("\n") };
17
+ }
18
+ export function taskSelection(flags) {
19
+ return flags.all ? "all" : flags.done ? "done" : "default";
20
+ }
21
+ export function taskJsonText(text) {
22
+ return text.endsWith("\n") ? text.slice(0, -1) : text;
23
+ }
24
+ export function mutationSelectionMessage(error) {
25
+ if (error instanceof FlowError) {
26
+ const candidates = error.candidateTasks;
27
+ if (candidates && candidates.length > 1) {
28
+ error.message = `${renderTaskList(candidates, { selection: "all" })}\n${error.message}`;
29
+ }
30
+ }
31
+ throw error;
32
+ }
33
+ function taskDocumentsById(sources) {
34
+ const documents = new Map();
35
+ for (const source of sources) {
36
+ try {
37
+ const document = parseTaskDocument(source);
38
+ documents.set(document.id, document);
39
+ }
40
+ catch {
41
+ // Invalid documents are reported from board diseases.
42
+ }
43
+ }
44
+ return documents;
45
+ }
46
+ function renderTaskDiseaseRows(diseases, documents) {
47
+ const rows = [];
48
+ const renderedCycles = new Set();
49
+ for (const disease of diseases) {
50
+ if (disease.code === "invalid_document") {
51
+ const name = path.basename(disease.path).replace(/\.md$/, "");
52
+ if (/^k-[0-9a-f]{12}$/.test(name))
53
+ rows.push(`! ${name} invalid front matter — quarantined`);
54
+ continue;
55
+ }
56
+ if (disease.code === "needs_cycle" && disease.id && disease.relatedIds) {
57
+ const cycleKey = disease.relatedIds.join("\0");
58
+ if (renderedCycles.has(cycleKey))
59
+ continue;
60
+ renderedCycles.add(cycleKey);
61
+ if (disease.relatedIds.length === 1) {
62
+ rows.push(`! ${disease.id} needs itself`);
63
+ continue;
64
+ }
65
+ const members = new Set(disease.relatedIds);
66
+ const start = [...members].sort()[0];
67
+ const cycle = [start];
68
+ let current = start;
69
+ for (let count = 0; count <= members.size; count += 1) {
70
+ const next = documents.get(current)?.needs.filter((id) => members.has(id)).sort()[0];
71
+ if (!next)
72
+ break;
73
+ cycle.push(next);
74
+ if (next === start)
75
+ break;
76
+ current = next;
77
+ }
78
+ if (cycle.at(-1) === start)
79
+ rows.push(`! cycle detected: ${cycle.join(" → ")}`);
80
+ continue;
81
+ }
82
+ if (disease.code === "missing_reference" && disease.id && disease.relatedIds) {
83
+ const document = documents.get(disease.id);
84
+ if (!document)
85
+ continue;
86
+ for (const related of disease.relatedIds) {
87
+ if (document.needs.includes(related))
88
+ rows.push(`! ${disease.id} needs missing task ${related}`);
89
+ if (document.parent === related)
90
+ rows.push(`? ${disease.id} parent ${related} does not exist`);
91
+ }
92
+ }
93
+ }
94
+ return rows;
95
+ }
96
+ export async function renderTaskDoctor(cwd) {
97
+ const result = await readTaskDoctor(cwd);
98
+ const board = result.board;
99
+ const tasks = board.tasks;
100
+ const counts = { inProgress: 0, ready: 0, blocked: 0, done: 0, dropped: 0, bound: 0 };
101
+ for (const task of tasks) {
102
+ const display = deriveTaskDisplay(task);
103
+ if (display === "in_progress")
104
+ counts.inProgress += 1;
105
+ else if (display === "ready")
106
+ counts.ready += 1;
107
+ else if (display === "blocked")
108
+ counts.blocked += 1;
109
+ else if (display === "done")
110
+ counts.done += 1;
111
+ else if (display === "dropped")
112
+ counts.dropped += 1;
113
+ else
114
+ counts.bound += 1;
115
+ }
116
+ const lines = [
117
+ `tasks · ${tasks.length} total`,
118
+ `${counts.inProgress} in_progress · ${counts.ready} ready · ${counts.blocked} blocked · ${counts.done} done · ${counts.dropped} dropped · ${counts.bound} bound`,
119
+ ...renderTaskDiseaseRows(board.diseases, taskDocumentsById(result.sources)),
120
+ ...result.orphans.map(({ taskId, contractId }) => `! ${taskId} points at contract ${contractId} which has no ledger entry — rolling back`),
121
+ ];
122
+ if (result.lockHeld)
123
+ lines.push("× board lock currently held by a live writer");
124
+ return lines.join("\n");
125
+ }
126
+ export async function rejectBareContractTaskState(cwd, verb) {
127
+ const contractId = await taskCommandContractId(cwd);
128
+ if (contractId) {
129
+ throw new FlowError("UNSUPPORTED_POLICY", `task ${verb} is not available in a contract worktree; task state follows the contract (${contractId})`);
130
+ }
131
+ }
@@ -0,0 +1,6 @@
1
+ import { openTaskCommandRepository } from "../../../../core/task-git-runtime.js";
2
+ import { startTask } from "../../../../core/task.js";
3
+ import { renderTaskMutationRow } from "../../../render/task.js";
4
+ import { textResponse } from "../../../render/shared.js";
5
+ import { effectiveDirectory } from "../../shared.js";
6
+ export const handler = async (_stdin, flags, _signal, positional) => textResponse(renderTaskMutationRow(await startTask(await openTaskCommandRepository(effectiveDirectory(flags)), positional[0], new Date())));
@@ -0,0 +1,8 @@
1
+ export const meta = {
2
+ command: "task start",
3
+ summary: "Start a task",
4
+ usage: ["keiyaku task start [-C|--cwd DIR] ID"],
5
+ stdin: "none",
6
+ flags: ["cwd"],
7
+ purpose: "Move an open task to in_progress.",
8
+ };
@@ -0,0 +1,17 @@
1
+ import { openTaskCommandRepository } from "../../../../core/task-git-runtime.js";
2
+ import { stopTask } from "../../../../core/task.js";
3
+ import { renderTaskMutationRow } from "../../../render/task.js";
4
+ import { textResponse } from "../../../render/shared.js";
5
+ import { effectiveDirectory } from "../../shared.js";
6
+ import { mutationSelectionMessage, rejectBareContractTaskState } from "../shared.js";
7
+ export const handler = async (_stdin, flags, _signal, positional) => {
8
+ try {
9
+ const cwd = effectiveDirectory(flags);
10
+ if (positional[0] === undefined)
11
+ await rejectBareContractTaskState(cwd, "stop");
12
+ return textResponse(renderTaskMutationRow(await stopTask(await openTaskCommandRepository(cwd), positional[0])));
13
+ }
14
+ catch (error) {
15
+ return mutationSelectionMessage(error);
16
+ }
17
+ };
@@ -0,0 +1,8 @@
1
+ export const meta = {
2
+ command: "task stop",
3
+ summary: "Stop a task",
4
+ usage: ["keiyaku task stop [-C|--cwd DIR] [ID]"],
5
+ stdin: "none",
6
+ flags: ["cwd"],
7
+ purpose: "Return an in-progress task to open.",
8
+ };
@@ -0,0 +1,5 @@
1
+ import { missingSubcommandError } from "../../../help.js";
2
+ import { TASK_SUBCOMMANDS } from "../../../types.js";
3
+ export const handler = async () => {
4
+ throw missingSubcommandError("task", TASK_SUBCOMMANDS);
5
+ };