@astrosheep/keiyaku 4.5.11 → 4.5.13

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 (272) hide show
  1. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +135 -377
  2. package/build/integrations/pi/keiyaku.ts +11 -116
  3. package/build/src/akuma/akuma-errors.d.ts +1 -0
  4. package/build/src/akuma/akuma-errors.js +1 -0
  5. package/build/src/akuma/akuma-handle.d.ts +1 -0
  6. package/build/src/akuma/akuma-handle.js +6 -7
  7. package/build/src/akuma/akuma-product.d.ts +6 -8
  8. package/build/src/akuma/akuma-product.js +141 -57
  9. package/build/src/akuma/akuma.d.ts +5 -7
  10. package/build/src/akuma/akuma.js +1 -22
  11. package/build/src/akuma/archetype.d.ts +6 -5
  12. package/build/src/akuma/archetype.js +137 -38
  13. package/build/src/akuma/body.d.ts +5 -5
  14. package/build/src/akuma/body.js +223 -63
  15. package/build/src/akuma/call-input.d.ts +4 -0
  16. package/build/src/akuma/call-input.js +21 -0
  17. package/build/src/akuma/call-request.d.ts +5 -8
  18. package/build/src/akuma/call-request.js +28 -73
  19. package/build/src/akuma/fleet-execution.d.ts +26 -0
  20. package/build/src/akuma/fleet-execution.js +109 -0
  21. package/build/src/{library/fleet-result.d.ts → akuma/fleet-observation.d.ts} +13 -57
  22. package/build/src/{library/fleet-result.js → akuma/fleet-observation.js} +4 -25
  23. package/build/src/akuma/fleet-request.d.ts +122 -0
  24. package/build/src/akuma/fleet-request.js +168 -0
  25. package/build/src/akuma/heart/facts.d.ts +23 -0
  26. package/build/src/akuma/heart/facts.js +7 -0
  27. package/build/src/akuma/heart/index.d.ts +43 -4
  28. package/build/src/akuma/heart/index.js +107 -7
  29. package/build/src/akuma/heart/request-authority.d.ts +2 -0
  30. package/build/src/akuma/heart/request-authority.js +28 -3
  31. package/build/src/akuma/heart/request-rows.d.ts +2 -0
  32. package/build/src/akuma/heart/request-rows.js +24 -5
  33. package/build/src/akuma/heart/rows.d.ts +4 -1
  34. package/build/src/akuma/heart/rows.js +46 -19
  35. package/build/src/akuma/heart/schema.d.ts +1 -1
  36. package/build/src/akuma/heart/schema.js +28 -6
  37. package/build/src/akuma/heart/storage.d.ts +1 -1
  38. package/build/src/akuma/heart/tells.d.ts +29 -0
  39. package/build/src/akuma/heart/tells.js +136 -5
  40. package/build/src/akuma/heart/timeline.js +9 -3
  41. package/build/src/akuma/projection-read.js +36 -3
  42. package/build/src/akuma/projection.js +3 -4
  43. package/build/src/akuma/provider.d.ts +4 -0
  44. package/build/src/akuma/provider.js +56 -3
  45. package/build/src/akuma/providers/claude/index.js +3 -0
  46. package/build/src/akuma/providers/codex-app-server/index.js +14 -12
  47. package/build/src/akuma/providers/pi/index.js +7 -1
  48. package/build/src/akuma/publication.js +65 -49
  49. package/build/src/akuma/request-lifecycle.d.ts +5 -4
  50. package/build/src/akuma/request-lifecycle.js +29 -16
  51. package/build/src/akuma/request-rendezvous.d.ts +15 -12
  52. package/build/src/akuma/request-rendezvous.js +80 -51
  53. package/build/src/akuma/request-serve.d.ts +1 -2
  54. package/build/src/akuma/request-serve.js +94 -39
  55. package/build/src/akuma/request-wire.d.ts +57 -26
  56. package/build/src/akuma/request-wire.js +64 -25
  57. package/build/src/akuma/turn-drive.d.ts +5 -4
  58. package/build/src/akuma/turn-drive.js +27 -11
  59. package/build/src/akuma-body.d.ts +4 -6
  60. package/build/src/akuma-body.js +19 -17
  61. package/build/src/bounded-list.d.ts +8 -0
  62. package/build/src/bounded-list.js +14 -0
  63. package/build/src/cli/accepted.d.ts +1 -1
  64. package/build/src/cli/accepted.js +1 -0
  65. package/build/src/cli/commands/akuma-invoke.js +1 -25
  66. package/build/src/cli/commands/contract-help.d.ts +5 -2
  67. package/build/src/cli/commands/contract-help.js +62 -12
  68. package/build/src/cli/commands/contract-invoke.d.ts +5 -0
  69. package/build/src/cli/commands/contract-invoke.js +26 -1
  70. package/build/src/cli/commands/contract.js +50 -18
  71. package/build/src/cli/commands/task-invoke.js +10 -2
  72. package/build/src/cli/commands/task-query.js +3 -4
  73. package/build/src/cli/coordinates.d.ts +13 -0
  74. package/build/src/cli/coordinates.js +38 -24
  75. package/build/src/cli/draft.d.ts +1 -1
  76. package/build/src/cli/invoke.js +14 -1
  77. package/build/src/cli/render/akuma-activity.d.ts +0 -1
  78. package/build/src/cli/render/akuma-activity.js +5 -38
  79. package/build/src/cli/render/akuma.js +4 -1
  80. package/build/src/cli/render/audit.js +4 -1
  81. package/build/src/cli/render/catalog.js +13 -39
  82. package/build/src/cli/render/contract.js +4 -14
  83. package/build/src/cli/render/kanshi-akuma.js +3 -8
  84. package/build/src/cli/render/kanshi.js +8 -34
  85. package/build/src/cli/render/nuke.js +7 -3
  86. package/build/src/cli/render/receipt.d.ts +1 -0
  87. package/build/src/cli/render/receipt.js +8 -0
  88. package/build/src/cli/render/refusal.js +4 -3
  89. package/build/src/cli/render/task.js +4 -37
  90. package/build/src/cli/render/terminal.d.ts +2 -6
  91. package/build/src/cli/render/terminal.js +4 -9
  92. package/build/src/cli/result.d.ts +2 -1
  93. package/build/src/contract-guidance.js +13 -3
  94. package/build/src/contract-worktree.d.ts +1 -0
  95. package/build/src/contract-worktree.js +26 -2
  96. package/build/src/core/facts/codec.d.ts +2 -1
  97. package/build/src/core/facts/codec.js +3 -0
  98. package/build/src/core/facts/gate.d.ts +2 -1
  99. package/build/src/core/facts/gate.js +63 -0
  100. package/build/src/core/verbs/abandon.d.ts +2 -1
  101. package/build/src/core/verbs/abandon.js +16 -0
  102. package/build/src/core/verbs/amend.d.ts +2 -1
  103. package/build/src/core/verbs/amend.js +20 -0
  104. package/build/src/core/verbs/arc.d.ts +2 -1
  105. package/build/src/core/verbs/arc.js +16 -0
  106. package/build/src/core/verbs/attestation.d.ts +2 -1
  107. package/build/src/core/verbs/attestation.js +16 -0
  108. package/build/src/core/verbs/bind.d.ts +2 -1
  109. package/build/src/core/verbs/bind.js +16 -0
  110. package/build/src/core/verbs/deliver.d.ts +2 -1
  111. package/build/src/core/verbs/deliver.js +16 -0
  112. package/build/src/core/verbs/placement.d.ts +2 -1
  113. package/build/src/core/verbs/placement.js +58 -1
  114. package/build/src/dispatch/association.d.ts +13 -0
  115. package/build/src/dispatch/association.js +20 -0
  116. package/build/src/dispatch/index.d.ts +6 -0
  117. package/build/src/dispatch/index.js +27 -3
  118. package/build/src/git/hooks.d.ts +9 -1
  119. package/build/src/git/hooks.js +79 -1
  120. package/build/src/git/nuke.d.ts +2 -1
  121. package/build/src/git/nuke.js +6 -11
  122. package/build/src/git/private-state-seat.d.ts +26 -1
  123. package/build/src/git/private-state-seat.js +78 -13
  124. package/build/src/git/process.d.ts +2 -0
  125. package/build/src/git/reconcile.d.ts +1 -2
  126. package/build/src/git/reconcile.js +0 -6
  127. package/build/src/git/repository.d.ts +0 -2
  128. package/build/src/git/repository.js +27 -25
  129. package/build/src/git/result-codec.d.ts +29 -0
  130. package/build/src/git/result-codec.js +306 -0
  131. package/build/src/git/target-placement.js +2 -8
  132. package/build/src/git/workspace.d.ts +2 -0
  133. package/build/src/git/workspace.js +4 -0
  134. package/build/src/index.d.ts +1 -0
  135. package/build/src/kanshi/fleet.js +1 -1
  136. package/build/src/kanshi/read.js +55 -28
  137. package/build/src/kanshi/report.d.ts +4 -3
  138. package/build/src/kanshi/select.js +14 -1
  139. package/build/src/library/address.d.ts +1 -0
  140. package/build/src/library/address.js +4 -7
  141. package/build/src/library/akuma-creation.d.ts +5 -3
  142. package/build/src/library/akuma-creation.js +90 -33
  143. package/build/src/library/audit.js +2 -1
  144. package/build/src/library/catalog.d.ts +10 -2
  145. package/build/src/library/catalog.js +65 -25
  146. package/build/src/library/composition.d.ts +1 -0
  147. package/build/src/library/composition.js +1 -0
  148. package/build/src/library/configuration.d.ts +4 -21
  149. package/build/src/library/configuration.js +2 -158
  150. package/build/src/library/continuation.d.ts +20 -1
  151. package/build/src/library/continuation.js +36 -0
  152. package/build/src/library/contract-bind.d.ts +1 -0
  153. package/build/src/library/contract-bind.js +16 -5
  154. package/build/src/library/contract-forwarding.d.ts +2 -2
  155. package/build/src/library/contract-forwarding.js +18 -4
  156. package/build/src/library/contract-handle.js +4 -3
  157. package/build/src/library/contract-operations.d.ts +5 -9
  158. package/build/src/library/contract-operations.js +34 -47
  159. package/build/src/library/contract.d.ts +11 -2
  160. package/build/src/library/contract.js +21 -1
  161. package/build/src/library/delivery.d.ts +4 -1
  162. package/build/src/library/delivery.js +47 -0
  163. package/build/src/library/fleet.d.ts +4 -136
  164. package/build/src/library/fleet.js +31 -315
  165. package/build/src/library/keiyaku.d.ts +7 -3
  166. package/build/src/library/keiyaku.js +1 -0
  167. package/build/src/library/mutation.d.ts +431 -3
  168. package/build/src/library/mutation.js +192 -19
  169. package/build/src/library/nuke.d.ts +7 -1
  170. package/build/src/library/nuke.js +18 -4
  171. package/build/src/library/reconcile.d.ts +14 -0
  172. package/build/src/library/reconcile.js +22 -8
  173. package/build/src/library/refusal.d.ts +9 -1
  174. package/build/src/library/refusal.js +76 -0
  175. package/build/src/library/region.d.ts +0 -8
  176. package/build/src/library/region.js +1 -29
  177. package/build/src/library/result-codec.d.ts +2 -0
  178. package/build/src/library/result-codec.js +12 -0
  179. package/build/src/markdown/lex.js +9 -2
  180. package/build/src/markdown/types.d.ts +2 -1
  181. package/build/src/markdown/types.js +3 -1
  182. package/build/src/plugin/akuma-signals.d.ts +12 -0
  183. package/build/src/plugin/akuma-signals.js +14 -0
  184. package/build/src/plugin/public.d.ts +51 -0
  185. package/build/src/plugin/public.js +1 -0
  186. package/build/src/plugin/runtime.d.ts +14 -0
  187. package/build/src/plugin/runtime.js +357 -0
  188. package/build/src/protocol/amend.js +3 -3
  189. package/build/src/protocol/attempt.d.ts +2 -1
  190. package/build/src/protocol/attempt.js +1 -1
  191. package/build/src/protocol/audit.d.ts +1 -1
  192. package/build/src/protocol/audit.js +1 -1
  193. package/build/src/protocol/bind.d.ts +3 -1
  194. package/build/src/protocol/bind.js +26 -0
  195. package/build/src/protocol/completion.js +0 -1
  196. package/build/src/protocol/deliver.d.ts +1 -1
  197. package/build/src/protocol/deliver.js +136 -57
  198. package/build/src/protocol/intent.d.ts +0 -1
  199. package/build/src/protocol/intent.js +0 -1
  200. package/build/src/protocol/operations.d.ts +9 -2
  201. package/build/src/protocol/operations.js +16 -1
  202. package/build/src/protocol/outcome.d.ts +3 -0
  203. package/build/src/protocol/outcome.js +17 -1
  204. package/build/src/protocol/placement.js +10 -3
  205. package/build/src/protocol/read/status.d.ts +8 -0
  206. package/build/src/protocol/read/status.js +49 -0
  207. package/build/src/protocol/reintegrate.js +10 -3
  208. package/build/src/protocol/result-codec.d.ts +22 -0
  209. package/build/src/protocol/result-codec.js +442 -0
  210. package/build/src/protocol/review.d.ts +1 -1
  211. package/build/src/protocol/review.js +81 -46
  212. package/build/src/protocol/run.d.ts +22 -2
  213. package/build/src/protocol/run.js +119 -29
  214. package/build/src/runtime/proc/lifecycle.js +1 -1
  215. package/build/src/runtime/proc/line-rpc.d.ts +7 -1
  216. package/build/src/runtime/proc/line-rpc.js +49 -9
  217. package/build/src/runtime/proc/run.d.ts +0 -1
  218. package/build/src/runtime/proc/run.js +1 -11
  219. package/build/src/runtime/proc/termination.d.ts +1 -0
  220. package/build/src/runtime/proc/termination.js +63 -18
  221. package/build/src/runtime/proc/windows-launch.exe +0 -0
  222. package/build/src/settings.d.ts +10 -0
  223. package/build/src/settings.js +88 -2
  224. package/build/src/settlement/result-codec.d.ts +2 -0
  225. package/build/src/settlement/result-codec.js +56 -0
  226. package/build/src/settlement/settle.d.ts +5 -12
  227. package/build/src/settlement/settle.js +60 -55
  228. package/build/src/task/board.d.ts +3 -0
  229. package/build/src/task/board.js +22 -4
  230. package/build/src/task/catalog.d.ts +13 -2
  231. package/build/src/task/catalog.js +59 -5
  232. package/build/src/task/compose.d.ts +4 -2
  233. package/build/src/task/compose.js +56 -30
  234. package/build/src/task/created-observation.d.ts +39 -0
  235. package/build/src/task/created-observation.js +26 -0
  236. package/build/src/task/identity.d.ts +6 -0
  237. package/build/src/task/identity.js +48 -7
  238. package/build/src/task/index.d.ts +4 -3
  239. package/build/src/task/index.js +19 -16
  240. package/build/src/task/input.d.ts +3 -1
  241. package/build/src/task/input.js +7 -4
  242. package/build/src/task/lifecycle-operations.d.ts +6 -0
  243. package/build/src/task/lifecycle-operations.js +116 -0
  244. package/build/src/task/mutation-result.d.ts +762 -20
  245. package/build/src/task/mutation-result.js +34 -9
  246. package/build/src/task/mutation.d.ts +4 -9
  247. package/build/src/task/mutation.js +17 -52
  248. package/build/src/task/operation-types.d.ts +114 -0
  249. package/build/src/task/operation-types.js +1 -0
  250. package/build/src/task/operations.d.ts +6 -113
  251. package/build/src/task/operations.js +75 -117
  252. package/build/src/task/query.d.ts +8 -11
  253. package/build/src/task/query.js +7 -14
  254. package/build/src/task/store.d.ts +11 -1
  255. package/build/src/task/store.js +169 -55
  256. package/build/src/task/view.d.ts +4 -0
  257. package/build/src/task/view.js +7 -0
  258. package/build/src/verification/declaration.d.ts +1 -0
  259. package/build/src/verification/declaration.js +18 -1
  260. package/build/src/verification/execution.d.ts +0 -1
  261. package/build/src/verification/execution.js +5 -5
  262. package/build/src/world.d.ts +0 -2
  263. package/build/src/world.js +3 -7
  264. package/package.json +17 -5
  265. package/build/src/cli/square-edge.d.ts +0 -7
  266. package/build/src/cli/square-edge.js +0 -159
  267. package/build/src/git/ref-migration.d.ts +0 -22
  268. package/build/src/git/ref-migration.js +0 -55
  269. package/build/src/library/contract-forwarding-reconciliation-result.d.ts +0 -102
  270. package/build/src/library/contract-forwarding-reconciliation-result.js +0 -92
  271. package/build/src/library/contract-forwarding-result.d.ts +0 -4270
  272. package/build/src/library/contract-forwarding-result.js +0 -521
@@ -1,20 +1,18 @@
1
1
  import { type ContractId, type ContractState } from "../core/facts/types.js";
2
+ import { type PrivateStateSeatCloseLag } from "../git/private-state-seat.js";
2
3
  import type { GitDecodeChannel } from "../git/read-observation.js";
3
4
  import type { Effect } from "../git/reconcile.js";
4
5
  import type { GitRepository } from "../git/process.js";
5
- import type { TaskId } from "../task/identity.js";
6
+ import { type TaskId } from "../task/identity.js";
7
+ export { decodeSettlementLag } from "./result-codec.js";
6
8
  export type SettlementAction = Readonly<{
7
9
  kind: "task";
8
10
  taskId: TaskId;
9
11
  action: "done";
10
- }> | Readonly<{
11
- kind: "namespace-context";
12
- path: string;
13
- action: "installed" | "kept";
14
12
  }>;
15
13
  export type SettlementLag = Readonly<{
16
14
  kind: "settlement-failed";
17
- surface: "task-holder" | "task" | "namespace-context";
15
+ surface: "task-holder" | "task";
18
16
  contractId: ContractId;
19
17
  taskId?: TaskId;
20
18
  path?: string;
@@ -23,13 +21,8 @@ export type SettlementLag = Readonly<{
23
21
  export type SettlementReport = Readonly<{
24
22
  actions: readonly SettlementAction[];
25
23
  lags: readonly SettlementLag[];
24
+ seatClose?: readonly PrivateStateSeatCloseLag[];
26
25
  }>;
27
- export declare function deferredTaskHolderSettlement(input: Readonly<{
28
- contractId: ContractId;
29
- taskId: TaskId;
30
- diagnostic: string;
31
- }>): SettlementReport;
32
- export declare function contractNamespace(id: ContractId): readonly [string];
33
26
  export type SettlementInput = Readonly<{
34
27
  repository: GitRepository;
35
28
  channel: GitDecodeChannel;
@@ -1,17 +1,10 @@
1
- import { contractSegment } from "../core/facts/types.js";
2
1
  import { observeContractsForAdmissionAt } from "../git/observe.js";
3
- import { withPrivateStatePublicationSeat } from "../git/private-state-seat.js";
4
- import { repairNamespaceContext } from "../task/context.js";
2
+ import { appendPrivateStateSeatClose, withPrivateStatePublicationSeat, } from "../git/private-state-seat.js";
5
3
  import { settleTask } from "../task/operations.js";
6
4
  import { publishTaskHolderRelease, readTaskHolderProjectionFromDecision, taskHolderObservationSelection, } from "./holder.js";
7
5
  import { acquireTaskSettlementFence } from "./fence.js";
8
6
  import { World } from "../world.js";
9
- export function deferredTaskHolderSettlement(input) {
10
- return { actions: [], lags: [{ kind: "settlement-failed", surface: "task-holder", ...input }] };
11
- }
12
- export function contractNamespace(id) {
13
- return [contractSegment(id)];
14
- }
7
+ export { decodeSettlementLag } from "./result-codec.js";
15
8
  function diagnostic(error) {
16
9
  return error instanceof Error ? error.message : String(error);
17
10
  }
@@ -73,6 +66,17 @@ async function completeHeldTask(input) {
73
66
  }
74
67
  if (result.kind === "changed")
75
68
  actions.push({ kind: "task", taskId, action: "done" });
69
+ if (result.kind === "changed" && result.cleanup !== undefined) {
70
+ for (const detail of result.cleanup.diagnostics) {
71
+ lags.push({
72
+ kind: "settlement-failed",
73
+ surface: "task",
74
+ contractId: candidate.id,
75
+ taskId,
76
+ diagnostic: detail,
77
+ });
78
+ }
79
+ }
76
80
  if (result.kind === "changed" || result.kind === "unchanged")
77
81
  return true;
78
82
  lags.push({
@@ -85,16 +89,16 @@ async function completeHeldTask(input) {
85
89
  return false;
86
90
  }
87
91
  async function releaseHeldTaskHolder(input) {
88
- const { repository, channel, candidate, lags, taskId } = input;
92
+ const { repository, channel, candidate, lags, seatClose, taskId } = input;
89
93
  try {
90
- await withPrivateStatePublicationSeat(repository, async (seat) => {
94
+ const outcome = await withPrivateStatePublicationSeat(repository, async (seat) => {
91
95
  const observation = await observeContractsForAdmissionAt(repository, channel, [candidate.id], taskHolderObservationSelection());
92
96
  const state = observation.journals.get(candidate.id)?.state ?? null;
93
97
  if (state === null || state.terminal?.kind !== "claimed")
94
- return;
98
+ return "inert";
95
99
  const holder = (await readTaskHolderProjectionFromDecision(channel, observation)).get(candidate.id) ?? null;
96
100
  if (holder === null || holder.disposition !== "held" || holder.taskId !== taskId)
97
- return;
101
+ return "inert";
98
102
  const publication = await publishTaskHolderRelease(repository, channel, observation, candidate.id, seat);
99
103
  if (publication.kind === "non-published") {
100
104
  lags.push({
@@ -104,8 +108,14 @@ async function releaseHeldTaskHolder(input) {
104
108
  taskId,
105
109
  diagnostic: `Task holder release requires retry: ${publication.diagnostic}`,
106
110
  });
111
+ return "held";
107
112
  }
113
+ return publication.kind === "released" ? "released" : "inert";
108
114
  });
115
+ if (outcome.closeLag !== undefined) {
116
+ seatClose.push(...appendPrivateStateSeatClose(undefined, outcome.closeLag));
117
+ }
118
+ return outcome.value;
109
119
  }
110
120
  catch (error) {
111
121
  lags.push({
@@ -115,10 +125,11 @@ async function releaseHeldTaskHolder(input) {
115
125
  taskId,
116
126
  diagnostic: diagnostic(error),
117
127
  });
128
+ return "held";
118
129
  }
119
130
  }
120
131
  async function settleTasks(input) {
121
- const { repository, channel, candidate, actions, lags } = input;
132
+ const { repository, channel, candidate, actions, lags, seatClose } = input;
122
133
  const hint = await observeApplicableHolder({ repository, channel, candidate, lags });
123
134
  if (hint === null)
124
135
  return false;
@@ -138,14 +149,22 @@ async function settleTasks(input) {
138
149
  return true;
139
150
  }
140
151
  let taskSettled = false;
152
+ let holderDisposition = null;
141
153
  try {
142
154
  const holder = await observeApplicableHolder({ repository, channel, candidate, lags });
143
155
  if (holder === null || holder.taskId !== taskId)
144
156
  return false;
145
- if (!(await completeHeldTask({ repository, candidate, actions, lags, taskId })))
157
+ taskSettled = await completeHeldTask({ repository, candidate, actions, lags, taskId });
158
+ if (!taskSettled)
146
159
  return true;
147
- taskSettled = true;
148
- await releaseHeldTaskHolder({ repository, channel, candidate, taskId, lags });
160
+ holderDisposition = await releaseHeldTaskHolder({
161
+ repository,
162
+ channel,
163
+ candidate,
164
+ taskId,
165
+ lags,
166
+ seatClose,
167
+ });
149
168
  return true;
150
169
  }
151
170
  finally {
@@ -155,66 +174,52 @@ async function settleTasks(input) {
155
174
  catch (error) {
156
175
  if (!taskSettled)
157
176
  throw error;
158
- lags.push({
159
- kind: "settlement-failed",
160
- surface: "task-holder",
161
- contractId: candidate.id,
162
- taskId,
163
- diagnostic: diagnostic(error),
164
- });
177
+ // Post-release fence teardown is custodial residue, not an owed holder publication.
178
+ if (holderDisposition !== "released") {
179
+ lags.push({
180
+ kind: "settlement-failed",
181
+ surface: "task-holder",
182
+ contractId: candidate.id,
183
+ taskId,
184
+ diagnostic: diagnostic(error),
185
+ });
186
+ }
165
187
  }
166
188
  }
167
189
  }
168
- async function settleNamespace(state, effects, actions, lags) {
169
- if (state.coordinates.workspace !== "worktree")
170
- return;
171
- const worktrees = effects.filter((effect) => effect.kind === "worktree" && effect.action !== "removed");
172
- for (const effect of worktrees) {
173
- try {
174
- actions.push({
175
- kind: "namespace-context",
176
- path: effect.path,
177
- action: await repairNamespaceContext(effect.path, contractNamespace(state.id)),
178
- });
179
- }
180
- catch (error) {
181
- lags.push({
182
- kind: "settlement-failed",
183
- surface: "namespace-context",
184
- contractId: state.id,
185
- path: effect.path,
186
- diagnostic: diagnostic(error),
187
- });
188
- }
189
- }
190
+ function settlementReport(actions, lags, seatClose) {
191
+ return {
192
+ actions,
193
+ lags,
194
+ ...(seatClose.length === 0 ? {} : { seatClose }),
195
+ };
190
196
  }
191
197
  async function settleObserved(input) {
192
198
  if (input.state === null)
193
199
  return { actions: [], lags: [] };
194
- const actions = [], lags = [];
195
- let holderApplies = false;
196
- if (input.state.terminal?.kind === "claimed") {
200
+ const actions = [], lags = [], seatClose = [];
201
+ const candidate = input.state;
202
+ if (candidate.terminal?.kind === "claimed") {
197
203
  try {
198
- holderApplies = await settleTasks({
204
+ await settleTasks({
199
205
  repository: input.repository,
200
206
  channel: input.channel,
201
- candidate: input.state,
207
+ candidate,
202
208
  actions,
203
209
  lags,
210
+ seatClose,
204
211
  });
205
212
  }
206
213
  catch (error) {
207
214
  lags.push({
208
215
  kind: "settlement-failed",
209
216
  surface: "task",
210
- contractId: input.state.id,
217
+ contractId: candidate.id,
211
218
  diagnostic: diagnostic(error),
212
219
  });
213
220
  }
214
221
  }
215
- if (holderApplies)
216
- await settleNamespace(input.state, input.effects, actions, lags);
217
- return { actions, lags };
222
+ return settlementReport(actions, lags, seatClose);
218
223
  }
219
224
  function onPrimaryWorktree(repository) {
220
225
  return { ...repository, effectiveCwd: repository.primaryWorktree };
@@ -1,6 +1,7 @@
1
1
  import type { TaskDocument, TaskPriority, TaskState } from "./document.js";
2
2
  import { type TaskId } from "./identity.js";
3
3
  import { z } from "zod";
4
+ import { type BoundedList } from "../bounded-list.js";
4
5
  export type TaskRef = Readonly<{
5
6
  id: TaskId;
6
7
  title: string | null;
@@ -111,6 +112,7 @@ export type TaskRelationProjection = Readonly<{
111
112
  export declare function createTaskRelations(board: TaskBoard): TaskRelationProjection;
112
113
  export declare function taskDisposition(board: TaskBoard, task: TaskDocument): TaskDisposition;
113
114
  export declare function taskBlocked(board: TaskBoard, task: TaskDocument): boolean;
115
+ export declare function projectOwnedDetailFacts(board: TaskBoard, id: TaskId): TaskDetailFacts | null;
114
116
  export declare function projectDetailFacts(board: TaskBoard, id: TaskId, relations: TaskRelationProjection): TaskDetailFacts | null;
115
117
  export declare function projectTaskRow(board: TaskBoard, relations: TaskRelationProjection, task: TaskDocument): TaskRow;
116
118
  export declare function projectRows(board: TaskBoard, relations: TaskRelationProjection, scope: readonly string[] | null, selection: "active" | "closed" | "all"): readonly TaskRow[];
@@ -147,6 +149,7 @@ export declare function projectStatusRows(board: TaskBoard, relations: TaskRelat
147
149
  })[];
148
150
  export type TaskBoardObservation = Readonly<{
149
151
  statusRows: ReturnType<typeof projectStatusRows>;
152
+ selectRecentStatus(limit?: number): BoundedList<ReturnType<typeof projectStatusRows>[number]>;
150
153
  selectNamespace(namespace: readonly string[]): readonly TaskRow[];
151
154
  selectCreatedBy(createdBy: string): readonly TaskRow[];
152
155
  }>;
@@ -1,5 +1,6 @@
1
1
  import { formatTaskId, parseTaskId, sameNamespace } from "./identity.js";
2
2
  import { z } from "zod";
3
+ import { boundedListLimit, projectBoundedList } from "../bounded-list.js";
3
4
  const taskRowIdSchema = z.string().transform((value, context) => {
4
5
  try {
5
6
  const id = formatTaskId(parseTaskId(value));
@@ -93,7 +94,7 @@ export function taskDisposition(board, task) {
93
94
  export function taskBlocked(board, task) {
94
95
  return (task.state === "open" || task.state === "in_progress") && hasUnresolvedNeeds(board, task);
95
96
  }
96
- export function projectDetailFacts(board, id, relations) {
97
+ export function projectOwnedDetailFacts(board, id) {
97
98
  const task = board.tasks.get(id);
98
99
  if (task === undefined)
99
100
  return null;
@@ -102,10 +103,22 @@ export function projectDetailFacts(board, id, relations) {
102
103
  task,
103
104
  needs,
104
105
  blockers: needs.filter((need) => !need.released).map(({ released: _released, ...ref }) => ref),
105
- blocks: relations.blocks(id),
106
+ blocks: none,
106
107
  parent: task.parent === null ? null : taskRef(board, task.parent),
107
- children: relations.children(id),
108
+ children: none,
108
109
  supersedes: task.supersedes.map((target) => taskRef(board, target)),
110
+ supersededBy: none,
111
+ related: task.relates.length === 0 ? none : sorted(task.relates.map((target) => taskRef(board, target))),
112
+ };
113
+ }
114
+ export function projectDetailFacts(board, id, relations) {
115
+ const owned = projectOwnedDetailFacts(board, id);
116
+ if (owned === null)
117
+ return null;
118
+ return {
119
+ ...owned,
120
+ blocks: relations.blocks(id),
121
+ children: relations.children(id),
109
122
  supersededBy: relations.supersededBy(id),
110
123
  related: relations.related(id),
111
124
  };
@@ -152,8 +165,13 @@ export function projectStatusRows(board, relations, scope) {
152
165
  export function projectTaskBoardObservation(board) {
153
166
  const relations = createTaskRelations(board);
154
167
  const rows = projectRows(board, relations, null, "all");
168
+ const statusRows = projectStatusRows(board, relations, null);
155
169
  return {
156
- statusRows: projectStatusRows(board, relations, null),
170
+ statusRows,
171
+ selectRecentStatus: (limit) => projectBoundedList(statusRows
172
+ .filter((row) => row.state !== "done" && row.state !== "drop")
173
+ .sort((left, right) => right.updatedAt.localeCompare(left.updatedAt) ||
174
+ Buffer.compare(Buffer.from(left.id), Buffer.from(right.id))), boundedListLimit(limit)),
157
175
  selectNamespace: (namespace) => projectRows(board, relations, namespace, "all"),
158
176
  selectCreatedBy: (createdBy) => rows.filter((row) => board.tasks.get(row.id)?.createdBy === createdBy),
159
177
  };
@@ -1,4 +1,15 @@
1
- import { type TaskRow } from "./board.js";
1
+ import type { BoundedList } from "../bounded-list.js";
2
+ import type { TaskRef, TaskRow } from "./board.js";
2
3
  import type { WorldRoot } from "../world.js";
3
4
  export declare function parseTaskNamespaceSelector(value: string): readonly string[];
4
- export declare function observeTaskCatalogRows(world: WorldRoot, namespace?: readonly string[]): Promise<readonly TaskRow[]>;
5
+ export type RecentTaskStatusRow = TaskRow & Readonly<{
6
+ blockers?: readonly TaskRef[];
7
+ }>;
8
+ export declare function observeRecentTaskStatus(world: WorldRoot, input?: Readonly<{
9
+ namespace?: readonly string[];
10
+ limit?: number;
11
+ }>): Promise<BoundedList<RecentTaskStatusRow>>;
12
+ export declare function observeTaskCatalog(world: WorldRoot, input?: Readonly<{
13
+ namespace?: readonly string[];
14
+ limit?: number;
15
+ }>): Promise<BoundedList<TaskRow>>;
@@ -1,6 +1,5 @@
1
- import { createTaskRelations, projectRows } from "./board.js";
2
1
  import { isTaskSegment, parseTaskId } from "./identity.js";
3
- import { readBoard } from "./store.js";
2
+ import { readRecentTaskDocuments, readTaskDocument } from "./store.js";
4
3
  export function parseTaskNamespaceSelector(value) {
5
4
  if (value === "task/")
6
5
  return [];
@@ -14,10 +13,65 @@ export function parseTaskNamespaceSelector(value) {
14
13
  }
15
14
  return parseTaskId(`task/${body}/placeholder`).namespace;
16
15
  }
17
- export async function observeTaskCatalogRows(world, namespace) {
16
+ function terminal(task) {
17
+ return task?.state === "done" || task?.state === "drop";
18
+ }
19
+ async function catalogRow(world, task, documents) {
20
+ const needs = await Promise.all(task.needs.map(async (id) => documents.get(id) ?? (await readTaskDocument(world, id))));
21
+ const blockers = [];
22
+ if (task.state === "open" || task.state === "in_progress") {
23
+ for (const [index, need] of needs.entries()) {
24
+ if (terminal(need))
25
+ continue;
26
+ blockers.push({ id: task.needs[index], title: need?.title ?? null, state: need?.state ?? "missing" });
27
+ }
28
+ }
29
+ return {
30
+ id: task.id,
31
+ title: task.title,
32
+ state: task.state,
33
+ priority: task.priority,
34
+ disposition: task.state === "open" && needs.some((need) => !terminal(need))
35
+ ? "blocked"
36
+ : task.state === "open"
37
+ ? "ready"
38
+ : task.state,
39
+ updatedAt: task.updatedAt,
40
+ bodyPresent: task.body.length > 0,
41
+ ...(blockers.length === 0 ? {} : { blockers }),
42
+ };
43
+ }
44
+ async function recentTaskStatus(world, input) {
45
+ const { namespace } = input;
46
+ if (namespace !== undefined && !namespace.every(isTaskSegment)) {
47
+ throw new TypeError("namespace must contain canonical segments");
48
+ }
49
+ const documents = await readRecentTaskDocuments(world, {
50
+ ...(namespace === undefined ? {} : { namespace }),
51
+ selection: "active",
52
+ ...(input.limit === undefined ? {} : { limit: input.limit }),
53
+ });
54
+ const known = new Map(documents.rows.map((document) => [document.id, document]));
55
+ return {
56
+ rows: await Promise.all(documents.rows.map((document) => catalogRow(world, document, known))),
57
+ hasMore: documents.hasMore,
58
+ };
59
+ }
60
+ export async function observeRecentTaskStatus(world, input = {}) {
61
+ return recentTaskStatus(world, input);
62
+ }
63
+ export async function observeTaskCatalog(world, input = {}) {
64
+ const { namespace } = input;
18
65
  if (namespace !== undefined && !namespace.every(isTaskSegment)) {
19
66
  throw new TypeError("namespace must contain canonical segments");
20
67
  }
21
- const board = (await readBoard(world)).board;
22
- return projectRows(board, createTaskRelations(board), namespace ?? null, "all");
68
+ const documents = await readRecentTaskDocuments(world, {
69
+ ...(namespace === undefined ? {} : { namespace }),
70
+ ...(input.limit === undefined ? {} : { limit: input.limit }),
71
+ });
72
+ const known = new Map(documents.rows.map((document) => [document.id, document]));
73
+ return {
74
+ rows: (await Promise.all(documents.rows.map((document) => catalogRow(world, document, known)))).map(({ blockers: _blockers, ...row }) => row),
75
+ hasMore: documents.hasMore,
76
+ };
23
77
  }
@@ -1,7 +1,7 @@
1
1
  import type { WorldRoot } from "../world.js";
2
2
  import { type TaskCompositionAlias, type TaskCompositionBodyPreview } from "./compose-language.js";
3
- import type { TaskId } from "./identity.js";
4
- import type { TaskRefusal, TaskRetry } from "./operations.js";
3
+ import { type TaskId } from "./identity.js";
4
+ import type { TaskCleanupFailure, TaskRefusal, TaskRetry } from "./operations.js";
5
5
  export type { TaskCompositionAlias, TaskCompositionBodyPreview } from "./compose-language.js";
6
6
  export { taskCompositionNamespaceHeader } from "./compose-language.js";
7
7
  export type TaskDocumentChange = Readonly<{
@@ -21,6 +21,7 @@ export type TaskCompositionResult = Readonly<{
21
21
  }> | Readonly<{
22
22
  kind: "accepted";
23
23
  documentChanges: readonly TaskDocumentChange[];
24
+ cleanup?: TaskCleanupFailure;
24
25
  } & TaskCompositionFacts> | Readonly<{
25
26
  kind: "refused";
26
27
  refusal: Extract<TaskRefusal, {
@@ -29,6 +30,7 @@ export type TaskCompositionResult = Readonly<{
29
30
  }> | (Readonly<{
30
31
  kind: "incomplete";
31
32
  documentChanges: readonly TaskDocumentChange[];
33
+ cleanup?: TaskCleanupFailure;
32
34
  stopped: TaskRefusal | Readonly<{
33
35
  kind: "retry";
34
36
  reason: TaskRetry;
@@ -1,7 +1,8 @@
1
1
  import { documentDiff } from "../markdown/diff.js";
2
2
  import { planTaskComposition, } from "./compose-language.js";
3
3
  import { serializeTaskDocument } from "./document.js";
4
- import { authorityPath, readBoard, replaceAuthority, withTaskLocks } from "./store.js";
4
+ import { parseTaskId, taskAuthorityPath } from "./identity.js";
5
+ import { readBoard, replaceAuthority, withTaskLocks } from "./store.js";
5
6
  export { taskCompositionNamespaceHeader } from "./compose-language.js";
6
7
  function refusal(diagnostics) {
7
8
  return { kind: "refused", refusal: { kind: "invalid-composition", diagnostics } };
@@ -57,6 +58,19 @@ function recoveryDraft(namespace, remaining) {
57
58
  function plannedResult(plan) {
58
59
  return { kind: "planned", ...facts(plan), bodies: plan.bodies };
59
60
  }
61
+ function physicalPlanDiagnostics(plan) {
62
+ try {
63
+ taskAuthorityPath("", { namespace: plan.namespace, localId: "placeholder" });
64
+ for (const task of plan.tasks)
65
+ taskAuthorityPath("", parseTaskId(task.after.id));
66
+ return [];
67
+ }
68
+ catch (error) {
69
+ return [
70
+ { line: 1, reason: error instanceof Error ? error.message : String(error), token: plan.namespace.join("/") },
71
+ ];
72
+ }
73
+ }
60
74
  function planAgainst(markdown, board, namespace, at, actor) {
61
75
  return planTaskComposition({ markdown, board, namespace, at, ...(actor === undefined ? {} : { actor }) });
62
76
  }
@@ -70,7 +84,8 @@ async function admitPlan(world, snapshot, plan, signal) {
70
84
  const before = beforeBytes === null ? "" : Buffer.from(beforeBytes).toString("utf8");
71
85
  const after = Buffer.from(afterBytes).toString("utf8");
72
86
  const replaced = await replaceAuthority({
73
- path: authorityPath(world, item.after.id),
87
+ world,
88
+ id: item.after.id,
74
89
  expected: beforeBytes,
75
90
  next: afterBytes,
76
91
  });
@@ -115,32 +130,43 @@ function composeInput(input) {
115
130
  }
116
131
  export async function composeTasks(input) {
117
132
  const { world, markdown, signal, actor, defaultNamespace = [], planOnly = false } = input;
118
- const at = currentTimestamp();
119
- const initial = await readBoard(world);
120
- const initialPlan = planAgainst(markdown, initial.board, defaultNamespace, at, actor);
121
- if (initialPlan.kind === "refused")
122
- return refusal(initialPlan.diagnostics);
123
- if (planOnly)
124
- return plannedResult(initialPlan.plan);
125
- const request = composeInput({
126
- world,
127
- markdown,
128
- namespace: defaultNamespace,
129
- at,
130
- ...(actor === undefined ? {} : { actor }),
131
- ...(signal === undefined ? {} : { signal }),
132
- });
133
- const allocation = initialPlan.plan.tasks.some((task) => task.kind === "new");
134
- const admitted = allocation
135
- ? await withTaskLocks({ world, allocation: true, ids: [], ...(signal === undefined ? {} : { signal }) }, async () => await composeUnderLocks(request))
136
- : await composeUnderLocks(request);
137
- if (admitted !== "busy")
138
- return admitted;
139
- return {
140
- kind: "incomplete",
141
- ...facts(initialPlan.plan),
142
- documentChanges: [],
143
- stopped: { kind: "retry", reason: "busy" },
144
- draft: recoveryDraft(initialPlan.plan.namespace, initialPlan.plan.tasks),
145
- };
133
+ try {
134
+ const at = currentTimestamp();
135
+ const initial = await readBoard(world);
136
+ const initialPlan = planAgainst(markdown, initial.board, defaultNamespace, at, actor);
137
+ if (initialPlan.kind === "refused")
138
+ return refusal(initialPlan.diagnostics);
139
+ const physicalDiagnostics = physicalPlanDiagnostics(initialPlan.plan);
140
+ if (physicalDiagnostics.length > 0)
141
+ return refusal(physicalDiagnostics);
142
+ if (planOnly)
143
+ return plannedResult(initialPlan.plan);
144
+ const request = composeInput({
145
+ world,
146
+ markdown,
147
+ namespace: defaultNamespace,
148
+ at,
149
+ ...(actor === undefined ? {} : { actor }),
150
+ ...(signal === undefined ? {} : { signal }),
151
+ });
152
+ const allocation = initialPlan.plan.tasks.some((task) => task.kind === "new");
153
+ const admitted = allocation
154
+ ? await withTaskLocks({ world, allocation: true, ids: [], ...(signal === undefined ? {} : { signal }) }, async () => await composeUnderLocks(request))
155
+ : await composeUnderLocks(request);
156
+ if (admitted !== "busy")
157
+ return admitted;
158
+ return {
159
+ kind: "incomplete",
160
+ ...facts(initialPlan.plan),
161
+ documentChanges: [],
162
+ stopped: { kind: "retry", reason: "busy" },
163
+ draft: recoveryDraft(initialPlan.plan.namespace, initialPlan.plan.tasks),
164
+ };
165
+ }
166
+ catch (error) {
167
+ if (error instanceof TypeError &&
168
+ /task identity (?:cannot fit the physical filename budget|contains a Windows-reserved physical segment)/u.test(error.message))
169
+ return refusal([{ line: 1, reason: error.message, token: defaultNamespace.join("/") }]);
170
+ throw error;
171
+ }
146
172
  }
@@ -0,0 +1,39 @@
1
+ import type { WorldRoot } from "../world.js";
2
+ import { z } from "zod";
3
+ export declare const createdTaskObservationSchema: z.ZodUnion<readonly [z.ZodObject<{
4
+ kind: z.ZodLiteral<"present">;
5
+ rows: z.ZodReadonly<z.ZodArray<z.ZodObject<{
6
+ id: z.ZodPipe<z.ZodString, z.ZodTransform<`task/${string}`, string>>;
7
+ title: z.ZodString;
8
+ state: z.ZodEnum<{
9
+ open: "open";
10
+ in_progress: "in_progress";
11
+ on_hold: "on_hold";
12
+ done: "done";
13
+ drop: "drop";
14
+ }>;
15
+ priority: z.ZodUnion<readonly [z.ZodLiteral<0>, z.ZodLiteral<1>, z.ZodLiteral<2>, z.ZodLiteral<3>]>;
16
+ disposition: z.ZodEnum<{
17
+ in_progress: "in_progress";
18
+ on_hold: "on_hold";
19
+ done: "done";
20
+ drop: "drop";
21
+ ready: "ready";
22
+ blocked: "blocked";
23
+ }>;
24
+ updatedAt: z.ZodString;
25
+ bodyPresent: z.ZodBoolean;
26
+ children: z.ZodOptional<z.ZodObject<{
27
+ live: z.ZodNumber;
28
+ total: z.ZodNumber;
29
+ }, z.core.$strict>>;
30
+ }, z.core.$strict>>>;
31
+ }, z.core.$strict>, z.ZodObject<{
32
+ kind: z.ZodLiteral<"failed">;
33
+ diagnostic: z.ZodString;
34
+ }, z.core.$strict>]>;
35
+ export type CreatedTaskObservation = z.infer<typeof createdTaskObservationSchema>;
36
+ export declare const EMPTY_CREATED_TASK_OBSERVATION: CreatedTaskObservation;
37
+ export declare function parseCreatedTaskObservation(value: unknown): CreatedTaskObservation;
38
+ /** Project Task board rows created by each identity, preserving input order. */
39
+ export declare function observeCreatedTaskObservations(world: WorldRoot, createdByIds: readonly string[]): Promise<readonly CreatedTaskObservation[]>;
@@ -0,0 +1,26 @@
1
+ import { z } from "zod";
2
+ import { taskRowsSchema } from "./board.js";
3
+ import { observeTaskBoard } from "./operations.js";
4
+ export const createdTaskObservationSchema = z.union([
5
+ z.object({ kind: z.literal("present"), rows: taskRowsSchema }).strict(),
6
+ z.object({ kind: z.literal("failed"), diagnostic: z.string() }).strict(),
7
+ ]);
8
+ export const EMPTY_CREATED_TASK_OBSERVATION = { kind: "present", rows: [] };
9
+ export function parseCreatedTaskObservation(value) {
10
+ return createdTaskObservationSchema.parse(value);
11
+ }
12
+ function observationDiagnostic(error) {
13
+ return error instanceof Error ? error.message : String(error);
14
+ }
15
+ /** Project Task board rows created by each identity, preserving input order. */
16
+ export async function observeCreatedTaskObservations(world, createdByIds) {
17
+ let board;
18
+ try {
19
+ board = await observeTaskBoard(world);
20
+ }
21
+ catch (error) {
22
+ const failed = { kind: "failed", diagnostic: observationDiagnostic(error) };
23
+ return createdByIds.map(() => failed);
24
+ }
25
+ return createdByIds.map((createdBy) => parseCreatedTaskObservation({ kind: "present", rows: board.selectCreatedBy(createdBy) }));
26
+ }
@@ -1,12 +1,18 @@
1
+ import { type ContractId } from "../core/facts/types.js";
1
2
  export type TaskId = `task/${string}`;
2
3
  export type TaskCoordinate = Readonly<{
3
4
  namespace: readonly string[];
4
5
  localId: string;
5
6
  }>;
7
+ export declare const TASK_LOCK_ID_BYTES: number;
8
+ export declare const TASK_LOCAL_ID_BYTES: number;
6
9
  export declare function isTaskSegment(value: string): boolean;
7
10
  export declare function parseTaskId(value: string): TaskCoordinate;
8
11
  export declare function formatTaskId(coordinate: TaskCoordinate): TaskId;
12
+ export declare function canonicalTaskId(value: string): TaskId;
13
+ export declare function contractNamespace(id: ContractId): readonly string[];
9
14
  export declare function taskAuthorityPath(tasksDirectory: string, coordinate: TaskCoordinate): string;
10
15
  export declare function deriveLocalStem(title: string): string;
11
16
  export declare function allocateLocalId(stem: string, occupied: ReadonlySet<string>): string;
17
+ export declare function physicalTaskSegment(segment: string, maxBytes?: number): string;
12
18
  export declare function sameNamespace(left: readonly string[], right: readonly string[]): boolean;