@astrosheep/keiyaku 2.8.5 → 2.9.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (238) hide show
  1. package/README.md +35 -15
  2. package/build/.tsbuildinfo +1 -1
  3. package/build/agents/{call-terms_v2.js → call-terms.js} +12 -8
  4. package/build/agents/harness/control-types.js +1 -0
  5. package/build/agents/harness/execution-handle.js +23 -3
  6. package/build/agents/harness/index.js +6 -607
  7. package/build/agents/harness/outcome.js +141 -0
  8. package/build/agents/harness/projection.js +310 -0
  9. package/build/agents/harness/router.js +201 -0
  10. package/build/agents/harness/runtime.js +2 -1
  11. package/build/agents/{launch-snapshot_v2.js → launch-snapshot/model.js} +69 -74
  12. package/build/agents/launch-snapshot/resolve.js +72 -0
  13. package/build/agents/opencode-sdk.js +24 -3
  14. package/build/agents/providers/{claude-agent-sdk.js → claude-agent-sdk/adapter.js} +46 -368
  15. package/build/agents/providers/claude-agent-sdk/events.js +218 -0
  16. package/build/agents/providers/claude-agent-sdk/session.js +158 -0
  17. package/build/agents/providers/codex-app-server/adapter.js +347 -0
  18. package/build/agents/providers/codex-app-server/events.js +352 -0
  19. package/build/agents/providers/codex-app-server/session.js +266 -0
  20. package/build/agents/providers/codex-sdk.js +23 -5
  21. package/build/agents/providers/opencode-sdk/adapter.js +344 -0
  22. package/build/agents/providers/opencode-sdk/events.js +354 -0
  23. package/build/agents/providers/opencode-sdk/session.js +180 -0
  24. package/build/agents/providers/pi/adapter.js +269 -0
  25. package/build/agents/providers/pi/checkpoint.js +41 -0
  26. package/build/agents/providers/pi/events.js +282 -0
  27. package/build/agents/{selector_v2.js → selector.js} +8 -6
  28. package/build/cli/commands/akuma/akuma/handler.js +4 -0
  29. package/build/cli/commands/akuma/akuma/meta.js +16 -0
  30. package/build/cli/commands/akuma/catalog.js +8 -0
  31. package/build/cli/commands/akuma/list/handler.js +15 -0
  32. package/build/cli/commands/akuma/list/meta-ls.js +9 -0
  33. package/build/cli/commands/akuma/view/handler.js +34 -0
  34. package/build/cli/commands/akuma/view/meta.js +8 -0
  35. package/build/cli/commands/akuma.js +1 -1
  36. package/build/cli/commands/contract/amend/handler.js +10 -0
  37. package/build/cli/commands/contract/amend/meta.js +12 -0
  38. package/build/cli/commands/contract/arc/handler.js +9 -0
  39. package/build/cli/commands/contract/arc/meta.js +26 -0
  40. package/build/cli/commands/contract/bind/handler.js +23 -0
  41. package/build/cli/commands/contract/bind/meta.js +30 -0
  42. package/build/cli/commands/contract/catalog.js +16 -0
  43. package/build/cli/commands/contract/forfeit/handler.js +13 -0
  44. package/build/cli/commands/contract/forfeit/meta.js +12 -0
  45. package/build/cli/commands/contract/log/handler.js +12 -0
  46. package/build/cli/commands/contract/log/meta.js +12 -0
  47. package/build/cli/commands/contract/petition/handler.js +26 -0
  48. package/build/cli/commands/contract/petition/meta.js +23 -0
  49. package/build/cli/commands/contract/renew/handler.js +10 -0
  50. package/build/cli/commands/contract/renew/meta.js +17 -0
  51. package/build/cli/commands/projection/call/handler.js +42 -0
  52. package/build/cli/commands/projection/call/meta.js +9 -0
  53. package/build/cli/commands/projection/catalog.js +14 -0
  54. package/build/cli/commands/projection/kill/handler.js +37 -0
  55. package/build/cli/commands/projection/kill/meta.js +11 -0
  56. package/build/cli/commands/projection/revive/handler.js +56 -0
  57. package/build/cli/commands/projection/revive/meta.js +9 -0
  58. package/build/cli/commands/projection/status/handler.js +25 -0
  59. package/build/cli/commands/projection/status/meta.js +9 -0
  60. package/build/cli/commands/projection/tell/handler.js +36 -0
  61. package/build/cli/commands/projection/tell/meta.js +9 -0
  62. package/build/cli/commands/projection/wait/handler.js +23 -0
  63. package/build/cli/commands/projection/wait/meta.js +11 -0
  64. package/build/cli/commands/registry.js +100 -0
  65. package/build/cli/commands/shared.js +71 -0
  66. package/build/cli/commands/skills/catalog.js +6 -0
  67. package/build/cli/commands/skills/install/handler.js +10 -0
  68. package/build/cli/commands/skills/install/meta.js +9 -0
  69. package/build/cli/commands/skills/skills/handler.js +4 -0
  70. package/build/cli/commands/skills/skills/meta.js +10 -0
  71. package/build/cli/commands/system/catalog.js +8 -0
  72. package/build/cli/commands/system/completion/handler.js +10 -0
  73. package/build/cli/commands/system/completion/meta.js +9 -0
  74. package/build/cli/commands/system/dump-env/handler.js +3 -0
  75. package/build/cli/commands/system/dump-env/meta.js +10 -0
  76. package/build/cli/commands/system/guide/handler.js +4 -0
  77. package/build/cli/commands/system/guide/meta.js +9 -0
  78. package/build/cli/commands/task/add/handler.js +21 -0
  79. package/build/cli/commands/task/add/meta.js +8 -0
  80. package/build/cli/commands/task/catalog.js +22 -0
  81. package/build/cli/commands/task/doctor/handler.js +4 -0
  82. package/build/cli/commands/task/doctor/meta.js +8 -0
  83. package/build/cli/commands/task/done/handler.js +17 -0
  84. package/build/cli/commands/task/done/meta.js +8 -0
  85. package/build/cli/commands/task/drop/handler.js +6 -0
  86. package/build/cli/commands/task/drop/meta.js +8 -0
  87. package/build/cli/commands/task/ls/handler.js +13 -0
  88. package/build/cli/commands/task/ls/meta.js +8 -0
  89. package/build/cli/commands/task/shared.js +131 -0
  90. package/build/cli/commands/task/start/handler.js +6 -0
  91. package/build/cli/commands/task/start/meta.js +8 -0
  92. package/build/cli/commands/task/stop/handler.js +17 -0
  93. package/build/cli/commands/task/stop/meta.js +8 -0
  94. package/build/cli/commands/task/task/handler.js +5 -0
  95. package/build/cli/commands/task/task/meta.js +11 -0
  96. package/build/cli/commands/task/update/handler.js +18 -0
  97. package/build/cli/commands/task/update/meta.js +8 -0
  98. package/build/cli/commands/task/view/handler.js +14 -0
  99. package/build/cli/commands/task/view/meta.js +8 -0
  100. package/build/cli/completion.js +26 -27
  101. package/build/cli/flags.js +79 -2
  102. package/build/cli/help.js +27 -49
  103. package/build/cli/index.js +121 -374
  104. package/build/cli/output-stream-error-policy.js +17 -0
  105. package/build/cli/parse-flags.js +197 -0
  106. package/build/cli/parse-metadata.js +129 -0
  107. package/build/cli/parse-selectors.js +65 -0
  108. package/build/cli/parse.js +46 -313
  109. package/build/cli/projection-address.js +5 -0
  110. package/build/cli/render/arc.js +1 -1
  111. package/build/cli/render/errors.js +4 -3
  112. package/build/cli/render/format.js +14 -0
  113. package/build/cli/render/kanshi.js +106 -0
  114. package/build/cli/render/petition.js +24 -1
  115. package/build/cli/render/projection-activity.js +5 -1
  116. package/build/cli/render/shared.js +2 -2
  117. package/build/cli/render/status.js +79 -13
  118. package/build/cli/render/task.js +113 -0
  119. package/build/cli/render/wait.js +23 -3
  120. package/build/cli/types.js +1 -1
  121. package/build/config/{akuma-loader_v2.js → akuma-loader.js} +7 -4
  122. package/build/config/env.js +9 -4
  123. package/build/config/settings/disease.js +26 -0
  124. package/build/config/settings/knobs.js +8 -0
  125. package/build/config/settings/loader.js +244 -0
  126. package/build/config/settings/schema.js +276 -0
  127. package/build/core/addressing.js +1 -1
  128. package/build/core/amend.js +5 -8
  129. package/build/core/arc.js +7 -8
  130. package/build/core/bind-workspace.js +123 -0
  131. package/build/core/bind.js +75 -155
  132. package/build/core/call/call.js +229 -0
  133. package/build/core/call/context.js +251 -0
  134. package/build/core/call/execution.js +217 -0
  135. package/build/core/call/prompt.js +42 -0
  136. package/build/core/call/reference.js +24 -0
  137. package/build/core/call-persist.js +10 -3
  138. package/build/core/claim-delivery.js +247 -0
  139. package/build/core/claim.js +39 -277
  140. package/build/core/context.js +2 -1
  141. package/build/core/{render.js → contract-view.js} +12 -140
  142. package/build/core/draft.js +107 -9
  143. package/build/core/entry.js +9 -1
  144. package/build/core/execution-coordinate.js +4 -20
  145. package/build/core/execution-pact.js +16 -31
  146. package/build/core/forfeit.js +35 -22
  147. package/build/core/hints.js +2 -2
  148. package/build/core/log.js +2 -2
  149. package/build/core/path-coordinate.js +27 -0
  150. package/build/core/petition-claim-gates.js +8 -6
  151. package/build/core/petition-preview.js +97 -0
  152. package/build/core/petition-run.js +5 -7
  153. package/build/core/petition.js +39 -26
  154. package/build/core/projection/generation/database.js +306 -0
  155. package/build/core/projection/generation/identity.js +84 -0
  156. package/build/core/projection/generation/model.js +201 -0
  157. package/build/core/projection/generation/store.js +73 -0
  158. package/build/core/projection/generation/transitions.js +258 -0
  159. package/build/core/projection/heart.js +0 -307
  160. package/build/core/projection/tell/database.js +109 -0
  161. package/build/core/projection/tell/model.js +97 -0
  162. package/build/core/{projection-tells.js → projection/tell/store.js} +3 -158
  163. package/build/core/projection-activity.js +23 -2
  164. package/build/core/projection-coordinate.js +14 -2
  165. package/build/core/projection-core.js +2 -1
  166. package/build/core/projection-execution-observer.js +259 -0
  167. package/build/core/projection-generation-continuation.js +1 -1
  168. package/build/core/projection-generation-execution.js +90 -20
  169. package/build/core/projection-generation-launcher.js +1 -1
  170. package/build/core/projection-generation-runner.js +198 -4
  171. package/build/core/projection-identity.js +1 -1
  172. package/build/core/projection-kill.js +50 -17
  173. package/build/core/projection-life-observer.js +1 -1
  174. package/build/core/projection-life-protocol.js +10 -0
  175. package/build/core/projection-mint.js +1 -1
  176. package/build/core/projection-status.js +45 -32
  177. package/build/core/projection-wait.js +12 -2
  178. package/build/core/projection-wake.js +5 -2
  179. package/build/core/{queue_v2.js → queue.js} +2 -1
  180. package/build/core/registry.js +1 -1
  181. package/build/core/renew.js +9 -11
  182. package/build/core/response-artifact-catalog-sqlite.js +112 -0
  183. package/build/core/response-artifact-catalog.js +7 -0
  184. package/build/core/seal.js +44 -16
  185. package/build/core/status/board.js +289 -0
  186. package/build/core/status/drift.js +99 -0
  187. package/build/core/status/lifecycle.js +84 -0
  188. package/build/core/status/reconciliation.js +131 -0
  189. package/build/core/stored-agent-event.js +28 -4
  190. package/build/core/target-ref.js +10 -0
  191. package/build/core/task/board.js +175 -0
  192. package/build/core/task/commands.js +211 -0
  193. package/build/core/task/document.js +189 -0
  194. package/build/core/task/model.js +1 -0
  195. package/build/core/task/settlement-git.js +207 -0
  196. package/build/core/task/settlement-policy.js +82 -0
  197. package/build/core/task/source-board.js +84 -0
  198. package/build/core/task/source-model.js +1 -0
  199. package/build/core/task/validation.js +44 -0
  200. package/build/core/task-contract.js +237 -0
  201. package/build/core/task-doctor.js +14 -0
  202. package/build/core/task-git-actor.js +38 -0
  203. package/build/core/task-git-runtime.js +37 -0
  204. package/build/core/task-git-store.js +385 -0
  205. package/build/core/task-repository.js +1 -0
  206. package/build/core/task-store-repository.js +86 -0
  207. package/build/core/task-store.js +1 -0
  208. package/build/core/task-worktree.js +51 -0
  209. package/build/core/task.js +4 -0
  210. package/build/core/transcripts.js +138 -56
  211. package/build/core/validation.js +17 -0
  212. package/build/core/verdict.js +2 -2
  213. package/build/core/worktree-path.js +33 -8
  214. package/build/flow-error.js +5 -2
  215. package/build/generated/version.js +1 -1
  216. package/build/git/branches.js +33 -9
  217. package/build/git/commits.js +3 -0
  218. package/build/git/core.js +9 -0
  219. package/build/git/diff/parsers.js +0 -94
  220. package/build/index.js +2 -0
  221. package/build/keiyaku-constants.js +2 -0
  222. package/build/keiyaku.js +4 -3
  223. package/package.json +3 -2
  224. package/skills/keiyaku/SKILL.md +30 -13
  225. package/skills/keiyaku-akuma/SKILL.md +30 -57
  226. package/skills/keiyaku-task/SKILL.md +51 -0
  227. package/skills/keiyaku-workflow/SKILL.md +71 -0
  228. package/build/agents/harness/pump.js +0 -158
  229. package/build/agents/providers/codex-app-server.js +0 -864
  230. package/build/agents/providers/opencode-sdk.js +0 -363
  231. package/build/agents/providers/pi.js +0 -557
  232. package/build/config/settings.js +0 -533
  233. package/build/core/call.js +0 -686
  234. package/build/core/projection/generation.js +0 -412
  235. package/build/core/projection/identity.js +0 -81
  236. package/build/core/projection/mint.js +0 -174
  237. package/build/core/projection-generation-store.js +0 -707
  238. package/build/core/status.js +0 -539
@@ -1,15 +1,50 @@
1
- import { formatSettingsDiseases } from "../../config/settings.js";
2
- import { formatAgeMs, projectionGlyph, renderKanshiBoard, shortCommitHash } from "../../core/render.js";
1
+ import { formatSettingsDiseases } from "../../config/settings/disease.js";
2
+ import { shortCommitHash } from "../../git/commits.js";
3
+ import { formatAgeMs } from "./format.js";
4
+ import { renderKanshiBoard } from "./kanshi.js";
3
5
  import { renderProjectionActivitySummary, } from "./projection-activity.js";
4
6
  export const STATUS_DISEASES_SECTION_TITLE = "Diseases";
5
7
  export const STATUS_PROJECTION_SECTION_TITLE = "akuma";
6
8
  export const STATUS_CLAIM_RECEIPTS_SECTION_TITLE = "claim receipts";
7
- export function renderSettingsDiseasesSection(diseases) {
8
- if (diseases.length === 0)
9
+ function projectionGlyph(state) {
10
+ switch (state) {
11
+ case "out":
12
+ return "●";
13
+ case "lost":
14
+ return "○";
15
+ case "done":
16
+ return "◎";
17
+ case "dismissed":
18
+ return "×";
19
+ case "dead":
20
+ return "✕";
21
+ case "minting":
22
+ return "…";
23
+ case "startup-timeout":
24
+ return "!";
25
+ case "unknown":
26
+ return "?";
27
+ }
28
+ }
29
+ export function renderSettingsDiseasesSection(diseases, taskDiseases = []) {
30
+ if (diseases.length === 0 && taskDiseases.length === 0)
9
31
  return "";
10
32
  const lines = formatSettingsDiseases(diseases).map((line) => `- ${line}`);
33
+ lines.push(...taskDiseases.map((line) => `- ${line}`));
11
34
  return `${STATUS_DISEASES_SECTION_TITLE}\n${lines.join("\n")}\n`;
12
35
  }
36
+ function renderTaskStatusSection(tasks) {
37
+ if (!tasks || tasks.inProgress + tasks.ready + tasks.blocked === 0)
38
+ return "";
39
+ const segments = [
40
+ tasks.inProgress > 0 ? `${tasks.inProgress} in_progress` : undefined,
41
+ tasks.ready > 0 ? `${tasks.ready} ready` : undefined,
42
+ tasks.blocked > 0 ? `${tasks.blocked} blocked` : undefined,
43
+ ].filter((segment) => segment !== undefined);
44
+ const lines = [`tasks · ${segments.join(" / ")}`];
45
+ lines.push(...tasks.topTasks.map((task) => ` ${task.id.slice(0, 9)} · P${task.pri} · ${task.state === "in_progress" ? "in_progress" : "ready"} · ${task.title}`));
46
+ return `${lines.join("\n")}\n`;
47
+ }
13
48
  function renderProjectionDiagnostics(row) {
14
49
  if (row.diagnostics.length === 0)
15
50
  return "";
@@ -18,7 +53,7 @@ function renderProjectionDiagnostics(row) {
18
53
  function renderProjectionOmission(board) {
19
54
  if (!board.omitted)
20
55
  return undefined;
21
- const counts = ["failed", "dead", "done", "dismissed"]
56
+ const counts = ["failed", "dead", "done", "killed", "dismissed"]
22
57
  .flatMap((state) => {
23
58
  const count = board.omitted?.byState[state] ?? 0;
24
59
  return count > 0 ? [`${count} ${state}`] : [];
@@ -28,6 +63,8 @@ function renderProjectionOmission(board) {
28
63
  function renderProjectionAge(row) {
29
64
  if (row.state === "done")
30
65
  return "done";
66
+ if (row.state === "killed")
67
+ return "killed";
31
68
  if (row.state === "dismissed")
32
69
  return "dismissed";
33
70
  if (row.state === "failed")
@@ -50,6 +87,7 @@ function projectionActivityState(row) {
50
87
  case "failed":
51
88
  case "dead": return "dead";
52
89
  case "lost": return "lost";
90
+ case "killed":
53
91
  case "dismissed": return "dismissed";
54
92
  case "minting":
55
93
  case "out": return "running";
@@ -68,11 +106,13 @@ function renderProjectionActivityLine(row) {
68
106
  });
69
107
  }
70
108
  function renderProjectionRow(row) {
71
- const glyph = projectionGlyph(row.state === "failed"
72
- ? "lost"
73
- : row.state === "startup-timeout"
74
- ? "minting"
75
- : row.state);
109
+ const glyph = row.state === "killed"
110
+ ? "×"
111
+ : projectionGlyph(row.state === "failed"
112
+ ? "lost"
113
+ : row.state === "startup-timeout"
114
+ ? "minting"
115
+ : row.state);
76
116
  const identity = row.alias ? `${row.id} (${row.alias})` : row.id;
77
117
  let heading;
78
118
  if (row.state === "startup-timeout" || row.state === "unknown") {
@@ -90,6 +130,25 @@ function renderProjectionRow(row) {
90
130
  const activity = renderProjectionActivityLine(row);
91
131
  return activity ? [heading, activity] : [heading];
92
132
  }
133
+ function isTerminalProjectionStatus(row) {
134
+ return row.state === "done"
135
+ || row.state === "killed"
136
+ || row.state === "dismissed"
137
+ || row.state === "failed"
138
+ || row.state === "dead";
139
+ }
140
+ export function renderProjectionFilteredStatus(board, projectionId) {
141
+ const head = board.defaultHead ? shortCommitHash(board.defaultHead) : "(no HEAD)";
142
+ const heading = `現世 ${head} · projection ${projectionId}`;
143
+ const row = board.projections?.rows.find((candidate) => candidate.id === projectionId);
144
+ if (!row)
145
+ return `${heading}\nno projections on projection ${projectionId}\n`;
146
+ const lines = [heading, "", ...renderProjectionRow(row), ""];
147
+ if (!isTerminalProjectionStatus(row))
148
+ lines.push(`» keiyaku tell ${projectionId} "..."`);
149
+ lines.push(`» keiyaku wait ${projectionId}`);
150
+ return `${lines.join("\n")}\n`;
151
+ }
93
152
  export function renderProjectionStatusSection(board) {
94
153
  if (!board || board.rows.length === 0)
95
154
  return "";
@@ -116,17 +175,24 @@ export function renderStatusBoard(board) {
116
175
  const boardText = renderKanshiBoard(board);
117
176
  const projectionText = renderProjectionStatusSection(board.projections);
118
177
  const receiptsText = renderClaimReconciliationSection(board.claimReconciliation);
119
- const diseasesText = renderSettingsDiseasesSection(board.diseases);
120
- if (!projectionText && !receiptsText && board.diseases.length === 0)
178
+ const taskText = renderTaskStatusSection(board.tasks);
179
+ const taskDiseaseText = [
180
+ ...(board.tasks?.diseases ?? []).map((disease) => disease.message),
181
+ ...(board.tasks?.diagnostic ? [board.tasks.diagnostic] : []),
182
+ ];
183
+ const diseasesText = renderSettingsDiseasesSection(board.diseases, taskDiseaseText);
184
+ if (!projectionText && !receiptsText && !taskText && diseasesText === "")
121
185
  return boardText;
122
186
  const sections = [boardText.trimEnd()];
123
- if (board.targetFilter !== null) {
187
+ if (board.targetFilter !== null && (projectionText || receiptsText || diseasesText)) {
124
188
  sections.push("repository-wide — not filtered by target");
125
189
  }
126
190
  if (projectionText)
127
191
  sections.push(projectionText.trimEnd());
128
192
  if (receiptsText)
129
193
  sections.push(receiptsText.trimEnd());
194
+ if (taskText)
195
+ sections.push(taskText.trimEnd());
130
196
  if (diseasesText)
131
197
  sections.push(diseasesText.trimEnd());
132
198
  return `${sections.join("\n\n")}\n`;
@@ -0,0 +1,113 @@
1
+ export function shortTaskId(id) {
2
+ return id.slice(0, 9);
3
+ }
4
+ export function shortContractId(contractId) {
5
+ const separator = contractId.indexOf(".");
6
+ return separator > 0 ? contractId.slice(0, separator) : contractId;
7
+ }
8
+ export function deriveTaskDisplay(task) {
9
+ if (task.state === "done")
10
+ return "done";
11
+ if (task.state === "drop")
12
+ return "dropped";
13
+ if (task.contractId !== undefined)
14
+ return `bound(${shortContractId(task.contractId)})`;
15
+ if (task.state === "in_progress")
16
+ return "in_progress";
17
+ return task.blocked ? "blocked" : "ready";
18
+ }
19
+ function renderTaskRowWithId(task, id) {
20
+ return `${id} · P${task.pri} · ${deriveTaskDisplay(task)} · ${task.title}`;
21
+ }
22
+ export function renderTaskListRow(task) {
23
+ return renderTaskRowWithId(task, shortTaskId(task.id));
24
+ }
25
+ export function renderTaskMutationRow(task) {
26
+ return renderTaskRowWithId(task, task.id);
27
+ }
28
+ export function renderTaskRow(task, completeId = false) {
29
+ return completeId ? renderTaskMutationRow(task) : renderTaskListRow(task);
30
+ }
31
+ function displayOrder(display) {
32
+ if (display === "in_progress")
33
+ return 0;
34
+ if (display === "ready")
35
+ return 1;
36
+ if (display === "blocked")
37
+ return 2;
38
+ if (display.startsWith("bound("))
39
+ return 3;
40
+ return display === "done" ? 4 : 5;
41
+ }
42
+ function compareText(left, right) {
43
+ return left < right ? -1 : left > right ? 1 : 0;
44
+ }
45
+ function compareTasks(left, right) {
46
+ const displayDifference = displayOrder(deriveTaskDisplay(left)) - displayOrder(deriveTaskDisplay(right));
47
+ if (displayDifference !== 0)
48
+ return displayDifference;
49
+ if (left.pri !== right.pri)
50
+ return left.pri - right.pri;
51
+ const createdDifference = compareText(left.createdAt, right.createdAt);
52
+ return createdDifference || compareText(left.id, right.id);
53
+ }
54
+ function selected(task, selection) {
55
+ const display = deriveTaskDisplay(task);
56
+ const terminal = display === "done" || display === "dropped";
57
+ if (selection === "done")
58
+ return terminal;
59
+ if (selection === "default")
60
+ return !terminal;
61
+ return true;
62
+ }
63
+ export function groupAndSortTasks(tasks, selection = "default") {
64
+ return tasks.filter((task) => selected(task, selection)).sort(compareTasks);
65
+ }
66
+ export function renderTaskList(tasks, options = {}) {
67
+ return groupAndSortTasks(tasks, options.selection).map(renderTaskListRow).join("\n");
68
+ }
69
+ function renderIds(ids) {
70
+ return ids.length === 0 ? "(none)" : ids.map(shortTaskId).join(", ");
71
+ }
72
+ export function renderTaskShow(task) {
73
+ const released = new Set(task.releasedNeeds);
74
+ const needs = task.needs.length === 0
75
+ ? "(none)"
76
+ : task.needs
77
+ .map((id) => `${shortTaskId(id)}${released.has(id) ? " (dropped)" : ""}`)
78
+ .join(", ");
79
+ return [
80
+ `${shortTaskId(task.id)} · ${task.title}`,
81
+ `state: ${deriveTaskDisplay(task)}`,
82
+ `priority: ${task.pri}`,
83
+ `needs: ${needs}`,
84
+ `blocks: ${renderIds(task.blocks)}`,
85
+ `parent: ${task.parent === null ? "(none)" : shortTaskId(task.parent)}`,
86
+ `from: ${renderIds(task.from)}`,
87
+ `created: ${task.createdAt} by ${task.creator}`,
88
+ "",
89
+ task.body,
90
+ ].join("\n");
91
+ }
92
+ export function taskJson(task) {
93
+ return {
94
+ id: task.id,
95
+ title: task.title,
96
+ state: task.state,
97
+ display: deriveTaskDisplay(task),
98
+ priority: task.pri,
99
+ needs: [...task.needs],
100
+ blocks: [...task.blocks],
101
+ parent: task.parent,
102
+ from: [...task.from],
103
+ contractId: task.contractId ?? null,
104
+ createdAt: task.createdAt,
105
+ creator: task.creator,
106
+ };
107
+ }
108
+ export function renderTaskShowJson(task) {
109
+ return `${JSON.stringify({ ...taskJson(task), body: task.body })}\n`;
110
+ }
111
+ export function renderTaskListJson(tasks, selection = "default") {
112
+ return `${JSON.stringify(groupAndSortTasks(tasks, selection).map(taskJson))}\n`;
113
+ }
@@ -10,6 +10,7 @@ function phaseState(phase) {
10
10
  case "done": return "returned";
11
11
  case "failed": return "dead";
12
12
  case "lost": return "lost";
13
+ case "killed":
13
14
  case "dismissed": return "dismissed";
14
15
  case "startup-timeout": return "stalled";
15
16
  case "unknown": return "unknown";
@@ -35,6 +36,8 @@ function waitStateText(snapshot) {
35
36
  return `returned · lived ${formatTimelineDuration(snapshot.durationMs)}`;
36
37
  case "failed":
37
38
  return `dead · lived ${formatTimelineDuration(snapshot.durationMs)}`;
39
+ case "killed":
40
+ return "killed";
38
41
  case "dismissed":
39
42
  return "dismissed";
40
43
  case "lost":
@@ -68,7 +71,7 @@ function terminalDiagnostic(result) {
68
71
  }
69
72
  function ledgerHint(projectionId, snapshot) {
70
73
  const file = snapshot.eventLedgerFile ?? "events.jsonl";
71
- return `⟶ ledger: .keiyaku/projection/${projectionId}/${file}`;
74
+ return `· ledger: .keiyaku/projection/${projectionId}/${file}`;
72
75
  }
73
76
  function recordReviveLines(artifactId) {
74
77
  return [
@@ -98,6 +101,17 @@ function nextActionLines(projectionId, result, state) {
98
101
  : ["The akuma dropped dead mid-turn.", "no record survived — there is nothing to revive."];
99
102
  }
100
103
  if (result.state === "terminal" && result.verdict.state === "failed") {
104
+ if (snapshot.failureCode === "SUBAGENT_PROVIDER_UNAVAILABLE") {
105
+ return snapshot.sourceArtifactId
106
+ ? [
107
+ "× provider unavailable — no turn accepted",
108
+ `» nothing was consumed · retry from the same artifact: keiyaku revive ${snapshot.sourceArtifactId}`,
109
+ ]
110
+ : [
111
+ "× provider unavailable — no turn accepted",
112
+ "» nothing was consumed · safe to call again",
113
+ ];
114
+ }
101
115
  return [
102
116
  "The akuma failed and stopped.",
103
117
  ...(snapshot.artifactId ? [`record: ${snapshot.artifactId}`] : []),
@@ -117,7 +131,7 @@ function nextActionLines(projectionId, result, state) {
117
131
  ];
118
132
  }
119
133
  if (state === "stalled" || state === "unknown") {
120
- return [ledgerHint(projectionId, snapshot), "⟶ keiyaku status"];
134
+ return [ledgerHint(projectionId, snapshot), "» keiyaku status"];
121
135
  }
122
136
  return [];
123
137
  }
@@ -186,6 +200,12 @@ export function buildWaitResponse(projectionId, result, options = {}) {
186
200
  }
187
201
  const snapshot = result.snapshot;
188
202
  const maxColumns = options.maxColumns ?? resolveLineColumns();
203
+ if (result.state === "terminal" && result.verdict.state === "killed") {
204
+ return {
205
+ ...textResponse(`× killed ${projectionId}`),
206
+ exitCode: 1,
207
+ };
208
+ }
189
209
  if (snapshot.phase === "startup-timeout") {
190
210
  return startupTimeoutResponse(projectionId, result.pact.akuma);
191
211
  }
@@ -216,7 +236,7 @@ export function buildWaitResponse(projectionId, result, options = {}) {
216
236
  lines.push(" not a word out of it yet — pulse is steady");
217
237
  }
218
238
  const nextActions = nextActionLines(options.alias ?? projectionId, result, state);
219
- if (rendered.hasMutationFiles && nextActions.length > 0)
239
+ if (nextActions.length > 0)
220
240
  lines.push("");
221
241
  lines.push(...nextActions);
222
242
  const response = textResponse(lines.join("\n"));
@@ -1 +1 @@
1
- export {};
1
+ export const TASK_SUBCOMMANDS = ["add", "view", "ls", "start", "stop", "done", "drop", "update", "doctor"];
@@ -2,10 +2,10 @@ import * as fs from "node:fs/promises";
2
2
  import * as path from "node:path";
3
3
  import { z } from "zod";
4
4
  import { parseToAST } from "../core/markdown/parser.js";
5
- import { isGitRepo } from "../git/branches.js";
5
+ import { observeGitRepository } from "../git/branches.js";
6
6
  import { BUILTIN_AGENT_PROFILES } from "../keiyaku.js";
7
7
  import { getKeiyakuHome } from "./env.js";
8
- import { agentNameSchema, providerInstanceNameSchema } from "./settings.js";
8
+ import { agentNameSchema, providerInstanceNameSchema } from "./settings/schema.js";
9
9
  const nonblankString = z.string().refine((value) => value.trim().length > 0, { message: "must not be blank" });
10
10
  const effortOptionsSchema = z.array(nonblankString).superRefine((values, ctx) => {
11
11
  if (new Set(values).size !== values.length) {
@@ -187,7 +187,7 @@ function foldLayer(selected, shadows, allCandidates, source, layer) {
187
187
  selected[candidate.name] = candidate;
188
188
  }
189
189
  }
190
- export async function loadAkumaCatalogV2(cwd) {
190
+ export async function loadAkumaCatalog(cwd) {
191
191
  const candidates = [];
192
192
  const selected = {};
193
193
  const shadows = [];
@@ -211,7 +211,10 @@ export async function loadAkumaCatalogV2(cwd) {
211
211
  selected[name] = candidate;
212
212
  }
213
213
  foldLayer(selected, shadows, candidates, "user", await readLayer(path.join(getKeiyakuHome(), "akuma"), "user"));
214
- if (await isGitRepo(cwd)) {
214
+ const repository = await observeGitRepository(cwd);
215
+ if (repository.capability === "unknown")
216
+ throw repository.error;
217
+ if (repository.capability === "available" && repository.coordinate === "repository") {
215
218
  foldLayer(selected, shadows, candidates, "project", await readLayer(path.join(cwd, ".keiyaku", "akuma"), "project"));
216
219
  }
217
220
  return Object.freeze({
@@ -4,12 +4,14 @@ import * as path from "node:path";
4
4
  import { z } from "zod";
5
5
  import { isErrnoException } from "../errno.js";
6
6
  import { ENV_KEYS, getEnvDefaultValue } from "./env-keys.js";
7
- function readEnvHome() {
8
- const value = process.env.KEIYAKU_HOME?.trim();
7
+ import { configureResponseArtifactCatalog } from "../core/response-artifact-catalog.js";
8
+ import { createSqliteResponseArtifactCatalog } from "../core/response-artifact-catalog-sqlite.js";
9
+ function readEnvHome(env = process.env) {
10
+ const value = env.KEIYAKU_HOME?.trim();
9
11
  return value && value.length > 0 ? value : undefined;
10
12
  }
11
- export function getKeiyakuHome() {
12
- return readEnvHome() ?? path.join(os.homedir(), ".keiyaku");
13
+ export function getKeiyakuHome(env = process.env) {
14
+ return readEnvHome(env) ?? path.join(os.homedir(), ".keiyaku");
13
15
  }
14
16
  const DOTENV_FILE = ".env";
15
17
  function decodeQuotedValue(raw) {
@@ -260,6 +262,8 @@ export function initializeConfig(env = process.env, cwd = process.cwd()) {
260
262
  runtimeEnv: snapshotEnv({ ...dotenvEnv, ...env }),
261
263
  });
262
264
  activeConfig = runtimeConfig;
265
+ const homeEnv = { ...process.env, ...env };
266
+ configureResponseArtifactCatalog(createSqliteResponseArtifactCatalog({ keiyakuHome: getKeiyakuHome(homeEnv) }));
263
267
  return runtimeConfig;
264
268
  }
265
269
  export function getConfig() {
@@ -270,4 +274,5 @@ export function getConfig() {
270
274
  }
271
275
  export function resetConfigForTests() {
272
276
  activeConfig = undefined;
277
+ configureResponseArtifactCatalog(undefined);
273
278
  }
@@ -0,0 +1,26 @@
1
+ import { FlowError } from "../../flow-error.js";
2
+ import { SETTINGS_FILE } from "../../keiyaku.js";
3
+ export function findSettingsDiseasesForKnob(diseases, knob) {
4
+ return diseases.filter((disease) => disease.knob === knob);
5
+ }
6
+ export function formatSettingsDiseases(diseases) {
7
+ return diseases.map((disease) => {
8
+ const where = disease.knob ? `${disease.source}:${disease.knob}` : `${disease.source}:(root)`;
9
+ return `${where}: ${disease.reason}`;
10
+ });
11
+ }
12
+ /**
13
+ * Reject when a named knob is diseased and was not admitted into knobs.
14
+ * A healthy value from another source still wins; only failed-and-unset knobs reject.
15
+ */
16
+ export function assertSettingsKnobUsable(loaded, knob) {
17
+ const knobs = loaded.knobs;
18
+ if (knobs !== null && knobs[knob] !== undefined)
19
+ return;
20
+ const hits = findSettingsDiseasesForKnob(loaded.diseases, knob);
21
+ if (hits.length === 0)
22
+ return;
23
+ throw new FlowError("INVALID_SETTINGS", `Invalid settings in ${SETTINGS_FILE} (diseased knob '${knob}').`, {
24
+ hints: formatSettingsDiseases(hits),
25
+ });
26
+ }
@@ -0,0 +1,8 @@
1
+ export const KNOWN_SETTINGS_KNOBS = ["default", "reviewer", "gate", "defaultBranch", "worktreeBootstrap"];
2
+ export const KNOWN_SETTINGS_ROOT_KEYS = [...KNOWN_SETTINGS_KNOBS, "providers"];
3
+ export function resolveDefaultAgentName(settings) {
4
+ return settings?.default ?? "akuma-codex";
5
+ }
6
+ export function resolveReviewerAgentName(settings) {
7
+ return settings?.reviewer ?? resolveDefaultAgentName(settings);
8
+ }