@astrosheep/keiyaku 2.9.8 → 2.9.10

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 +50 -182
  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 +10 -7
  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 +242 -79
  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 +65 -29
  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 +13 -35
  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 +45 -69
  87. package/build/cli/subagent-guard.js +1 -1
  88. package/build/cli/types.js +1 -1
  89. package/build/config/env-keys.js +3 -1
  90. package/build/config/env.js +24 -1
  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 +13 -6
  129. package/build/core/projection/index.js +5 -4
  130. package/build/core/projection/projection-activity.js +29 -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 +35 -337
  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 +125 -127
  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
@@ -1,29 +1,7 @@
1
- import { formatTimelineDuration, renderProjectionActivity, renderProjectionActivitySummary, } from "./projection-activity.js";
1
+ import { formatTimelineDuration, renderPendingProjectionTell, renderProjectionActivity, } from "./projection-activity.js";
2
2
  import { displayColumns, resolveLineColumns, truncateColumns } from "./line-width.js";
3
- import { formatTellCommand, projectionRejoinHintLines, textResponse } from "./shared.js";
3
+ import { coreTextResponse, formatTellCommand, projectionRejoinHintLines, textResponse } from "./shared.js";
4
4
  import { renderTerminalFailureFace } from "./terminal-failure.js";
5
- const WAIT_HEADER_MAX_COLUMNS = 60;
6
- const WAIT_BODY_MAX_ROWS = 10;
7
- const WAIT_ROW_PRIORITY = {
8
- "end-anchor": 100,
9
- "storage-diagnostic": 90,
10
- diagnostic: 90,
11
- tell: 80,
12
- summary: 70,
13
- activity: 60,
14
- plan: 55,
15
- liveness: 50,
16
- silence: 65,
17
- file: 20,
18
- };
19
- /** One owner admits every wait-body row, then restores presentation order. */
20
- export function selectWaitBodyRows(rows, limit = WAIT_BODY_MAX_ROWS) {
21
- const selected = rows
22
- .slice()
23
- .sort((left, right) => WAIT_ROW_PRIORITY[right.kind] - WAIT_ROW_PRIORITY[left.kind] || left.order - right.order)
24
- .slice(0, limit);
25
- return selected.sort((left, right) => left.order - right.order);
26
- }
27
5
  function shortAddress(projectionId) {
28
6
  return /\/([0-9a-f]{8})$/.exec(projectionId)?.[1] ?? projectionId;
29
7
  }
@@ -56,8 +34,7 @@ function projectionIdentityParts(projectionId) {
56
34
  const match = /^(.*)\/([0-9a-f]{8})$/.exec(projectionId);
57
35
  return match ? { slug: match[1], shortId: match[2] } : { slug: "", shortId: projectionId };
58
36
  }
59
- function waitHeader(projectionId, akuma, snapshot, outputColumns) {
60
- const maxColumns = Math.min(WAIT_HEADER_MAX_COLUMNS, outputColumns);
37
+ function waitHeader(projectionId, akuma, snapshot, maxColumns) {
61
38
  const state = waitStateText(snapshot);
62
39
  const identity = projectionIdentityParts(projectionId);
63
40
  // Slug often mirrors the Akuma name; print once when they are the same fact.
@@ -70,12 +47,23 @@ function waitHeader(projectionId, akuma, snapshot, outputColumns) {
70
47
  const dashCount = Math.max(1, maxColumns - displayColumns(`${prefix} ${state}`));
71
48
  return `${prefix} ${"─".repeat(dashCount)} ${state}`;
72
49
  }
73
- function pendingTellLines(snapshot, maxColumns) {
74
- return snapshot.tells.window.map((tell) => {
75
- const age = Math.max(0, snapshot.observedAtMs - Date.parse(tell.createdAt));
76
- const fixed = `${"".padStart(5)}│ ${"tell".padEnd(7)} `;
77
- const suffix = ` · undelivered ${formatTimelineDuration(Number.isFinite(age) ? age : 0)}`;
78
- return `${fixed}${truncateColumns(`“${tell.text}”`, Math.max(0, maxColumns - displayColumns(fixed) - displayColumns(suffix)))}${suffix}`;
50
+ function pendingTellRows(snapshot, maxColumns, orderOffset) {
51
+ return snapshot.tells.window.map((tell, index) => ({
52
+ line: renderPendingProjectionTell(tell, {
53
+ anchorMs: snapshot.observedAtMs,
54
+ maxColumns,
55
+ }),
56
+ at: tell.createdAt,
57
+ order: orderOffset + index,
58
+ }));
59
+ }
60
+ function orderFlowRows(rows) {
61
+ return rows.slice().sort((left, right) => {
62
+ const leftAt = Date.parse(left.at ?? "");
63
+ const rightAt = Date.parse(right.at ?? "");
64
+ const safeLeft = Number.isFinite(leftAt) ? leftAt : Number.POSITIVE_INFINITY;
65
+ const safeRight = Number.isFinite(rightAt) ? rightAt : Number.POSITIVE_INFINITY;
66
+ return safeLeft - safeRight || left.order - right.order;
79
67
  });
80
68
  }
81
69
  function ledgerHint(projectionId, snapshot) {
@@ -142,14 +130,13 @@ function unknownResponse(projectionId, akuma, snapshot, maxColumns) {
142
130
  anchorMs: snapshot.observedAtMs,
143
131
  state: "unknown",
144
132
  showPlan: false,
133
+ showSilence: false,
134
+ showTerminalFiles: false,
145
135
  ...(snapshot.workspaceRoot ? { workspaceRoot: snapshot.workspaceRoot } : {}),
146
136
  maxColumns,
137
+ leadingOmittedCount: snapshot.activity.omittedSettledCount,
147
138
  });
148
- const historicalLines = selectWaitBodyRows(rendered.lines.map((line, index) => ({
149
- kind: rendered.rowKinds[index] ?? "activity",
150
- line,
151
- order: index,
152
- }))).map((row) => row.line.replace(/[┆├]/, "│"));
139
+ const historicalLines = rendered.lines.map((line) => line.replace(/[┆├]/, "│"));
153
140
  return {
154
141
  ...textResponse([
155
142
  `? ${akuma} · projection: ${projectionId} · unknown`,
@@ -216,50 +203,39 @@ export function buildWaitResponse(projectionId, result, options = {}) {
216
203
  if (state === "returned") {
217
204
  return returnedResponse(projectionId, result);
218
205
  }
219
- const tells = pendingTellLines(snapshot, maxColumns);
220
- const summary = ["running", "stalled", "unknown"].includes(state)
221
- ? renderProjectionActivitySummary(snapshot.activity, {
222
- state,
223
- ...(snapshot.workspaceRoot ? { workspaceRoot: snapshot.workspaceRoot } : {}),
224
- maxColumns,
225
- })
226
- : undefined;
227
206
  const rendered = renderProjectionActivity(snapshot.activity, {
228
207
  anchorMs: snapshot.observedAtMs,
229
208
  state,
230
- showPlan: state === "running",
209
+ showPlan: false,
210
+ showSilence: false,
211
+ showTerminalFiles: false,
231
212
  ...(snapshot.workspaceRoot ? { workspaceRoot: snapshot.workspaceRoot } : {}),
232
213
  maxColumns,
214
+ leadingOmittedCount: snapshot.activity.omittedSettledCount,
233
215
  });
234
- let order = 0;
235
- const bodyPlan = [];
236
- for (const diagnostic of snapshot.eventDiagnostics ?? []) {
237
- bodyPlan.push({ kind: "storage-diagnostic", line: `‼ ${diagnostic.kind} · ${diagnostic.detail}`, order: order++ });
238
- }
239
- rendered.lines.forEach((line, index) => {
240
- bodyPlan.push({ kind: rendered.rowKinds[index] ?? "activity", line, order: order++ });
241
- });
242
- for (const line of tells)
243
- bodyPlan.push({ kind: "tell", line, order: order++ });
244
- if (rendered.lines.length === 0 && tells.length === 0 && state === "running") {
245
- bodyPlan.push({ kind: "liveness", line: " not a word out of it yet — idle", order: order++ });
246
- }
247
- if (!rendered.hasEndAnchor && summary) {
248
- bodyPlan.push({ kind: "summary", line: summary, order: order++ });
249
- }
250
- const bodyLines = selectWaitBodyRows(bodyPlan).map((row) => truncateColumns(row.line, maxColumns));
251
- const lines = [waitHeader(projectionId, result.pact.akuma, snapshot, maxColumns), ...bodyLines];
252
- const pendingTellCount = snapshot.tells.totals.undelivered;
253
- if (pendingTellCount > 0) {
254
- lines.push(`${pendingTellCount} tell${pendingTellCount === 1 ? "" : "s"} undelivered`);
255
- }
216
+ const diagnosticLines = (snapshot.eventDiagnostics ?? [])
217
+ .map((diagnostic) => `‼ ${diagnostic.kind} · ${diagnostic.detail}`);
218
+ const activityRows = rendered.lines.map((line, index) => ({
219
+ line,
220
+ at: rendered.rowAts[index],
221
+ order: index,
222
+ }));
223
+ const flowLines = orderFlowRows([
224
+ ...activityRows,
225
+ ...pendingTellRows(snapshot, maxColumns, activityRows.length),
226
+ ]).map((row) => truncateColumns(row.line, maxColumns));
227
+ const lines = [
228
+ waitHeader(projectionId, result.pact.akuma, snapshot, maxColumns),
229
+ ...diagnosticLines,
230
+ ...flowLines,
231
+ ];
256
232
  const nextActions = state === "running" && options.runningActions === false
257
233
  ? []
258
234
  : nextActionLines(options.alias ?? projectionId, result, state);
259
235
  if (nextActions.length > 0)
260
236
  lines.push("");
261
237
  lines.push(...nextActions);
262
- const response = textResponse(lines.join("\n"));
238
+ const response = coreTextResponse(lines.join("\n"), result);
263
239
  if (snapshot.phase === "dismissed")
264
240
  return { ...response, exitCode: 130 };
265
241
  if (["failed", "lost", "startup-timeout", "unknown"].includes(snapshot.phase)) {
@@ -1,4 +1,4 @@
1
- const SUBAGENT_SAFE_COMMANDS = new Set(["status", "log", "guide", "dump-env", "wait"]);
1
+ const SUBAGENT_SAFE_COMMANDS = new Set(["status", "history", "log", "guide", "dump-env", "wait"]);
2
2
  const SUBAGENT_SAFE_FLAGS = new Set(["--help", "-h", "--version"]);
3
3
  function isSubagentSafeCommand(args) {
4
4
  if (args.length === 0)
@@ -1 +1 @@
1
- export const TASK_SUBCOMMANDS = ["add", "show", "ls", "log", "start", "stop", "done", "drop", "update", "doctor"];
1
+ export const TASK_SUBCOMMANDS = ["add", "show", "ls", "log", "start", "stop", "hold", "resume", "done", "drop", "update", "doctor"];
@@ -22,18 +22,20 @@ export const ENV_KEYS = {
22
22
  REVIEW_ENABLED: "KEIYAKU_REVIEW_ENABLED",
23
23
  REVIEW_MIN_LINES: "KEIYAKU_REVIEW_MIN_LINES",
24
24
  REVIEW_RESUME_SESSION: "KEIYAKU_REVIEW_RESUME_SESSION",
25
+ AMENDMENT_WARNING_THRESHOLD: "KEIYAKU_AMENDMENT_WARNING_THRESHOLD",
25
26
  };
26
27
  const ENV_KEY_ENTRIES = [
27
28
  { key: ENV_KEYS.AGENT_OVERRIDE, defaultValue: "", description: "Override default agent name", category: "subagent" },
28
29
  { key: ENV_KEYS.DISABLE_SUBAGENT_SPAWN, defaultValue: "0", description: "Disable subprocess subagent spawning when set to 1", category: "subagent" },
29
30
  { key: ENV_KEYS.SUBAGENT_EXEC_IDLE_TIMEOUT_MS, defaultValue: "300000", description: "Subagent provider-ingress idle timeout in milliseconds", category: "subagent" },
30
- { key: ENV_KEYS.SUBAGENT_EXEC_MAX_DURATION_MS, defaultValue: "3600000", description: "Subagent absolute execution policy budget in milliseconds", category: "subagent" },
31
+ { key: ENV_KEYS.SUBAGENT_EXEC_MAX_DURATION_MS, defaultValue: "0", description: "Subagent absolute execution policy budget in milliseconds; 0 disables it", category: "subagent" },
31
32
  { key: ENV_KEYS.CODEX_EXEC_MAX_CAPTURE_CHARS, defaultValue: "200000", description: "Codex runtime output/diagnostics capture cap", category: "subagent" },
32
33
  { key: ENV_KEYS.CLAUDE_EXEC_MAX_CAPTURE_CHARS, defaultValue: "200000", description: "Claude runtime output/diagnostics capture cap", category: "subagent" },
33
34
  { key: ENV_KEYS.OPENCODE_EXEC_MAX_CAPTURE_CHARS, defaultValue: "200000", description: "OpenCode runtime output/diagnostics capture cap", category: "subagent" },
34
35
  { key: ENV_KEYS.REVIEW_ENABLED, defaultValue: "1", description: "Run the reviewer gate when set to 1", category: "workflow" },
35
36
  { key: ENV_KEYS.REVIEW_MIN_LINES, defaultValue: "200", description: "Minimum changed lines required before running the reviewer gate", category: "workflow" },
36
37
  { key: ENV_KEYS.REVIEW_RESUME_SESSION, defaultValue: "1", description: "Resume reviewer sessions from the prior persisted response path when set to 1", category: "workflow" },
38
+ { key: ENV_KEYS.AMENDMENT_WARNING_THRESHOLD, defaultValue: "5", description: "Advisory amendment-count threshold for open contracts", category: "workflow" },
37
39
  { key: ENV_KEYS.DEBUG_LOG_PATH, defaultValue: "", description: "Optional debug log output file path", category: "debug" },
38
40
  { key: ENV_KEYS.TEST_SILENT, defaultValue: "0", description: "Suppress progress logs during tests when set to 1", category: "debug" },
39
41
  { key: ENV_KEYS.GIT_TIMEOUT_MS, defaultValue: "15000", description: "Git command timeout in milliseconds", category: "git" },
@@ -95,6 +95,22 @@ function positiveIntEnv(key) {
95
95
  }
96
96
  });
97
97
  }
98
+ function strictPositiveIntEnv(key) {
99
+ return z
100
+ .string()
101
+ .default(getEnvDefaultValue(key))
102
+ .transform((value, ctx) => {
103
+ const trimmed = value.trim();
104
+ const parsed = Number(trimmed);
105
+ if (/^\d+$/.test(trimmed) && Number.isSafeInteger(parsed) && parsed > 0)
106
+ return parsed;
107
+ ctx.addIssue({
108
+ code: z.ZodIssueCode.custom,
109
+ message: `${key} must be a positive integer, received '${value}'.`,
110
+ });
111
+ return z.NEVER;
112
+ });
113
+ }
98
114
  function parseNonNegativeInt(value, key) {
99
115
  const trimmed = value.trim();
100
116
  const parsed = Number.parseInt(trimmed, 10);
@@ -141,7 +157,7 @@ const subagentSchema = z.object({
141
157
  nameOverride: z.string().default(getEnvDefaultValue(ENV_KEYS.AGENT_OVERRIDE)).transform((value) => value.trim()),
142
158
  disableSpawn: booleanFlagEnv(ENV_KEYS.DISABLE_SUBAGENT_SPAWN),
143
159
  execIdleTimeoutMs: positiveIntEnv(ENV_KEYS.SUBAGENT_EXEC_IDLE_TIMEOUT_MS),
144
- execMaxDurationMs: positiveIntEnv(ENV_KEYS.SUBAGENT_EXEC_MAX_DURATION_MS),
160
+ execMaxDurationMs: nonNegativeIntEnv(ENV_KEYS.SUBAGENT_EXEC_MAX_DURATION_MS),
145
161
  });
146
162
  const codexSchema = z.object({
147
163
  execMaxCaptureChars: positiveIntEnv(ENV_KEYS.CODEX_EXEC_MAX_CAPTURE_CHARS),
@@ -166,6 +182,9 @@ const reviewSchema = z.object({
166
182
  minLines: nonNegativeIntEnv(ENV_KEYS.REVIEW_MIN_LINES),
167
183
  resumeSession: booleanFlagEnv(ENV_KEYS.REVIEW_RESUME_SESSION),
168
184
  });
185
+ const amendmentWarningSchema = z.object({
186
+ threshold: strictPositiveIntEnv(ENV_KEYS.AMENDMENT_WARNING_THRESHOLD),
187
+ });
169
188
  const terminalSchema = z.object({
170
189
  noColor: z.string().optional(),
171
190
  forceColor: z.string().optional(),
@@ -188,6 +207,7 @@ const envSchema = z
188
207
  [ENV_KEYS.REVIEW_ENABLED]: z.string().optional(),
189
208
  [ENV_KEYS.REVIEW_MIN_LINES]: z.string().optional(),
190
209
  [ENV_KEYS.REVIEW_RESUME_SESSION]: z.string().optional(),
210
+ [ENV_KEYS.AMENDMENT_WARNING_THRESHOLD]: z.string().optional(),
191
211
  NO_COLOR: z.string().optional(),
192
212
  FORCE_COLOR: z.string().optional(),
193
213
  TERM: z.string().optional(),
@@ -222,6 +242,9 @@ const envSchema = z
222
242
  minLines: rawEnv[ENV_KEYS.REVIEW_MIN_LINES],
223
243
  resumeSession: rawEnv[ENV_KEYS.REVIEW_RESUME_SESSION],
224
244
  }),
245
+ amendmentWarning: amendmentWarningSchema.parse({
246
+ threshold: rawEnv[ENV_KEYS.AMENDMENT_WARNING_THRESHOLD],
247
+ }),
225
248
  terminal: terminalSchema.parse({
226
249
  noColor: rawEnv.NO_COLOR,
227
250
  forceColor: rawEnv.FORCE_COLOR,
@@ -55,8 +55,10 @@ const gateCommandSchema = z
55
55
  const gateSchema = z
56
56
  .object({
57
57
  commands: z.array(gateCommandSchema).optional(),
58
+ timeoutMs: z.number().int("timeoutMs must be an integer.").min(1).max(3_600_000).optional(),
58
59
  })
59
- .strict();
60
+ .strict()
61
+ .transform((value) => ({ ...value, timeoutMs: value.timeoutMs ?? 300_000 }));
60
62
  const WORKTREE_BOOTSTRAP_DEFAULT_TIMEOUT_MS = 300_000;
61
63
  const WORKTREE_BOOTSTRAP_MIN_TIMEOUT_MS = 1;
62
64
  const WORKTREE_BOOTSTRAP_MAX_TIMEOUT_MS = 3_600_000;
@@ -0,0 +1,89 @@
1
+ import * as path from "node:path";
2
+ import { FlowError } from "../flow-error.js";
3
+ const ADDRESS_CARRIER = Symbol.for("keiyaku.address-carrier");
4
+ export class AddressResolutionError extends FlowError {
5
+ attempt;
6
+ constructor(code, message, attempt, options) {
7
+ super(code, message, options);
8
+ this.name = "AddressResolutionError";
9
+ this.attempt = attempt;
10
+ }
11
+ }
12
+ class AddressedFlowError extends FlowError {
13
+ [ADDRESS_CARRIER];
14
+ constructor(error, carrier) {
15
+ super(error.code, error.message, {
16
+ cause: error,
17
+ review: error.review,
18
+ facts: error.facts,
19
+ });
20
+ this.name = error.name;
21
+ this[ADDRESS_CARRIER] = carrier;
22
+ }
23
+ }
24
+ class AddressedError extends Error {
25
+ [ADDRESS_CARRIER];
26
+ constructor(error, carrier) {
27
+ super(error instanceof Error ? error.message : String(error), { cause: error });
28
+ this.name = error instanceof Error ? error.name : "Error";
29
+ this[ADDRESS_CARRIER] = carrier;
30
+ }
31
+ }
32
+ export function attachAddressCarrier(error, carrier) {
33
+ if (addressCarrierFromError(error))
34
+ return error;
35
+ return error instanceof FlowError
36
+ ? new AddressedFlowError(error, carrier)
37
+ : new AddressedError(error, carrier);
38
+ }
39
+ export function addressCarrierFromError(error) {
40
+ const seen = new Set();
41
+ let current = error;
42
+ while (((typeof current === "object" && current !== null) || typeof current === "function") && !seen.has(current)) {
43
+ seen.add(current);
44
+ if (current instanceof AddressResolutionError)
45
+ return current.attempt;
46
+ const addressed = current;
47
+ if (addressed[ADDRESS_CARRIER])
48
+ return addressed[ADDRESS_CARRIER];
49
+ current = addressed.cause;
50
+ }
51
+ return undefined;
52
+ }
53
+ export async function withResolvedAddress(address, operation) {
54
+ try {
55
+ return await operation();
56
+ }
57
+ catch (error) {
58
+ throw attachAddressCarrier(error, address);
59
+ }
60
+ }
61
+ export function buildResolutionAttempt(input) {
62
+ return {
63
+ repo: input.repo,
64
+ workdir: path.resolve(input.workdir),
65
+ expected: "commission",
66
+ ...(input.spelling ? { spelling: input.spelling } : {}),
67
+ ...(input.actual !== undefined ? { actual: input.actual } : {}),
68
+ candidates: [...(input.candidates ?? [])],
69
+ inference: [...(input.inference ?? [])],
70
+ };
71
+ }
72
+ export function buildObjectResolutionAttempt(input) {
73
+ return {
74
+ repo: input.repo,
75
+ workdir: path.resolve(input.workdir),
76
+ expected: input.expected,
77
+ supplied: input.supplied,
78
+ ...(input.actual !== undefined ? { actual: input.actual } : {}),
79
+ ...(input.scope ? { scope: input.scope } : {}),
80
+ candidates: [...(input.candidates ?? [])],
81
+ inference: [...(input.inference ?? [])],
82
+ };
83
+ }
84
+ export function buildArtifactResolutionAttempt(input) {
85
+ return {
86
+ ...buildObjectResolutionAttempt({ ...input, expected: "artifact" }),
87
+ expected: "artifact",
88
+ };
89
+ }