@astrosheep/keiyaku 4.0.0 → 4.0.2

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 (308) hide show
  1. package/README.md +133 -8
  2. package/build/integrations/marketplace/plugins/keiyaku/.claude-plugin/plugin.json +2 -2
  3. package/build/integrations/marketplace/plugins/keiyaku/.codex-plugin/plugin.json +4 -4
  4. package/build/integrations/marketplace/plugins/keiyaku/opencode.js +2 -2
  5. package/build/integrations/marketplace/plugins/keiyaku/package.json +2 -2
  6. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku/SKILL.md +13 -5
  7. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +91 -32
  8. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +134 -0
  9. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/agents/openai.yaml +4 -0
  10. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-task/SKILL.md +41 -6
  11. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +262 -46
  12. package/build/src/akuma/abort.d.ts +2 -0
  13. package/build/src/akuma/abort.js +50 -0
  14. package/build/src/akuma/akuma.d.ts +50 -33
  15. package/build/src/akuma/akuma.js +175 -127
  16. package/build/src/akuma/archetype.d.ts +14 -5
  17. package/build/src/akuma/archetype.js +85 -39
  18. package/build/src/akuma/body.d.ts +3 -5
  19. package/build/src/akuma/body.js +490 -183
  20. package/build/src/akuma/coordinate.d.ts +9 -0
  21. package/build/src/akuma/coordinate.js +22 -0
  22. package/build/src/akuma/heart/facts.d.ts +88 -45
  23. package/build/src/akuma/heart/facts.js +19 -8
  24. package/build/src/akuma/heart/index.d.ts +64 -55
  25. package/build/src/akuma/heart/index.js +172 -252
  26. package/build/src/akuma/heart/rows.d.ts +38 -83
  27. package/build/src/akuma/heart/rows.js +117 -155
  28. package/build/src/akuma/heart/schema.d.ts +1 -1
  29. package/build/src/akuma/heart/schema.js +61 -22
  30. package/build/src/akuma/heart/soul.d.ts +8 -0
  31. package/build/src/akuma/heart/soul.js +136 -0
  32. package/build/src/akuma/heart/storage.d.ts +47 -0
  33. package/build/src/akuma/heart/storage.js +224 -0
  34. package/build/src/akuma/heart/tells.d.ts +12 -0
  35. package/build/src/akuma/heart/tells.js +79 -0
  36. package/build/src/akuma/heart/timeline.d.ts +15 -0
  37. package/build/src/akuma/heart/timeline.js +86 -0
  38. package/build/src/akuma/identity.d.ts +2 -2
  39. package/build/src/akuma/identity.js +9 -9
  40. package/build/src/akuma/index.d.ts +10 -3
  41. package/build/src/akuma/index.js +7 -1
  42. package/build/src/akuma/projection.d.ts +176 -0
  43. package/build/src/akuma/projection.js +256 -0
  44. package/build/src/akuma/provider-recipe.d.ts +24 -0
  45. package/build/src/akuma/provider-recipe.js +100 -0
  46. package/build/src/akuma/provider.d.ts +67 -13
  47. package/build/src/akuma/provider.js +172 -105
  48. package/build/src/akuma/providers/acp/core.d.ts +19 -0
  49. package/build/src/akuma/providers/acp/core.js +159 -0
  50. package/build/src/akuma/providers/acp/events.d.ts +20 -0
  51. package/build/src/akuma/providers/acp/events.js +73 -0
  52. package/build/src/akuma/providers/acp/index.d.ts +12 -0
  53. package/build/src/akuma/providers/acp/index.js +94 -0
  54. package/build/src/akuma/providers/{claude.d.ts → claude/events.d.ts} +9 -41
  55. package/build/src/akuma/providers/claude/events.js +238 -0
  56. package/build/src/akuma/providers/claude/index.d.ts +47 -0
  57. package/build/src/akuma/providers/claude/index.js +279 -0
  58. package/build/src/akuma/providers/claude/input.d.ts +13 -0
  59. package/build/src/akuma/providers/claude/input.js +109 -0
  60. package/build/src/akuma/providers/codex-app-server/events.d.ts +1 -1
  61. package/build/src/akuma/providers/codex-app-server/events.js +15 -12
  62. package/build/src/akuma/providers/codex-app-server/index.d.ts +15 -13
  63. package/build/src/akuma/providers/codex-app-server/index.js +77 -33
  64. package/build/src/akuma/providers/grok-build/index.d.ts +4 -0
  65. package/build/src/akuma/providers/grok-build/index.js +70 -0
  66. package/build/src/akuma/providers/index.d.ts +5 -3
  67. package/build/src/akuma/providers/index.js +35 -56
  68. package/build/src/akuma/providers/opencode-sdk/events.d.ts +54 -0
  69. package/build/src/akuma/providers/opencode-sdk/events.js +235 -0
  70. package/build/src/akuma/providers/opencode-sdk/index.d.ts +33 -0
  71. package/build/src/akuma/providers/opencode-sdk/index.js +308 -0
  72. package/build/src/akuma/providers/opencode-sdk/session.d.ts +26 -0
  73. package/build/src/akuma/providers/opencode-sdk/session.js +63 -0
  74. package/build/src/akuma/providers/pi/events.d.ts +33 -0
  75. package/build/src/akuma/providers/pi/events.js +166 -0
  76. package/build/src/akuma/providers/pi/index.d.ts +11 -0
  77. package/build/src/akuma/providers/pi/index.js +191 -0
  78. package/build/src/akuma/publication.d.ts +3 -3
  79. package/build/src/akuma/publication.js +28 -40
  80. package/build/src/akuma/requests.d.ts +9 -6
  81. package/build/src/akuma/requests.js +95 -65
  82. package/build/src/alias/index.d.ts +4 -3
  83. package/build/src/alias/index.js +12 -13
  84. package/build/src/body/decode.js +7 -1
  85. package/build/src/body/region.d.ts +2 -0
  86. package/build/src/body/region.js +77 -7
  87. package/build/src/body/render.js +2 -1
  88. package/build/src/body/shape.js +7 -1
  89. package/build/src/body/verification.js +19 -4
  90. package/build/src/cli/accepted.d.ts +18 -12
  91. package/build/src/cli/accepted.js +73 -34
  92. package/build/src/cli/actor.js +3 -3
  93. package/build/src/cli/commands/akuma-invoke.d.ts +44 -19
  94. package/build/src/cli/commands/akuma-invoke.js +101 -52
  95. package/build/src/cli/commands/akuma.d.ts +27 -9
  96. package/build/src/cli/commands/akuma.js +151 -80
  97. package/build/src/cli/commands/contract.d.ts +155 -0
  98. package/build/src/cli/commands/contract.js +20 -0
  99. package/build/src/cli/commands/install.js +2 -0
  100. package/build/src/cli/commands/task-invoke.d.ts +19 -4
  101. package/build/src/cli/commands/task-invoke.js +65 -17
  102. package/build/src/cli/commands/task-query.d.ts +5 -0
  103. package/build/src/cli/commands/task-query.js +247 -0
  104. package/build/src/cli/commands/task.d.ts +3 -1
  105. package/build/src/cli/commands/task.js +52 -14
  106. package/build/src/cli/coordinates.d.ts +18 -0
  107. package/build/src/cli/coordinates.js +120 -0
  108. package/build/src/cli/draft.d.ts +8 -0
  109. package/build/src/cli/draft.js +96 -0
  110. package/build/src/cli/invoke.d.ts +9 -3
  111. package/build/src/cli/invoke.js +287 -108
  112. package/build/src/cli/main.js +54 -7
  113. package/build/src/cli/parse.d.ts +21 -117
  114. package/build/src/cli/parse.js +79 -84
  115. package/build/src/cli/render/akuma-tool-command.d.ts +6 -0
  116. package/build/src/cli/render/akuma-tool-command.js +144 -0
  117. package/build/src/cli/render/akuma-tool.d.ts +4 -2
  118. package/build/src/cli/render/akuma-tool.js +35 -5
  119. package/build/src/cli/render/akuma.d.ts +3 -1
  120. package/build/src/cli/render/akuma.js +247 -212
  121. package/build/src/cli/render/audit.d.ts +3 -0
  122. package/build/src/cli/render/audit.js +104 -0
  123. package/build/src/cli/render/catalog.d.ts +2 -0
  124. package/build/src/cli/render/catalog.js +16 -0
  125. package/build/src/cli/render/contract.d.ts +3 -3
  126. package/build/src/cli/render/contract.js +200 -54
  127. package/build/src/cli/render/kanshi.js +272 -129
  128. package/build/src/cli/render/receipt.d.ts +19 -0
  129. package/build/src/cli/render/receipt.js +106 -0
  130. package/build/src/cli/render/refusal.d.ts +16 -2
  131. package/build/src/cli/render/refusal.js +88 -3
  132. package/build/src/cli/render/region.d.ts +2 -0
  133. package/build/src/cli/render/region.js +17 -0
  134. package/build/src/cli/render/task.d.ts +2 -1
  135. package/build/src/cli/render/task.js +223 -60
  136. package/build/src/cli/render/terminal.d.ts +20 -0
  137. package/build/src/cli/render/terminal.js +121 -0
  138. package/build/src/cli/render/text.js +11 -3
  139. package/build/src/cli/result.d.ts +126 -19
  140. package/build/src/cli/usage.d.ts +1 -0
  141. package/build/src/cli/usage.js +3 -0
  142. package/build/src/contract-worktree.d.ts +44 -0
  143. package/build/src/contract-worktree.js +251 -0
  144. package/build/src/coordination/durable-file.d.ts +5 -1
  145. package/build/src/coordination/durable-file.js +57 -10
  146. package/build/src/coordination/sqlite-transaction-lock.d.ts +4 -0
  147. package/build/src/coordination/sqlite-transaction-lock.js +22 -5
  148. package/build/src/core/facts/codec.js +23 -4
  149. package/build/src/core/facts/eligibility.d.ts +1 -10
  150. package/build/src/core/facts/eligibility.js +0 -49
  151. package/build/src/core/facts/fold.js +1 -6
  152. package/build/src/core/facts/gate.d.ts +1 -0
  153. package/build/src/core/facts/gate.js +1 -0
  154. package/build/src/core/facts/observation.d.ts +3 -0
  155. package/build/src/core/facts/observation.js +12 -0
  156. package/build/src/core/facts/types.d.ts +10 -3
  157. package/build/src/core/subject.js +2 -2
  158. package/build/src/core/verbs/amend.d.ts +1 -1
  159. package/build/src/core/verbs/amend.js +3 -18
  160. package/build/src/core/verbs/bind.js +2 -16
  161. package/build/src/core/verbs/deliver.d.ts +1 -1
  162. package/build/src/core/verbs/deliver.js +14 -4
  163. package/build/src/core/verbs/placement.d.ts +1 -1
  164. package/build/src/core/verbs/placement.js +7 -9
  165. package/build/src/dispatch/index.d.ts +5 -3
  166. package/build/src/dispatch/index.js +30 -21
  167. package/build/src/duration.d.ts +10 -0
  168. package/build/src/duration.js +22 -0
  169. package/build/src/git/admission.d.ts +2 -2
  170. package/build/src/git/admission.js +33 -23
  171. package/build/src/git/hooks.d.ts +15 -0
  172. package/build/src/git/hooks.js +70 -18
  173. package/build/src/git/identity.d.ts +5 -1
  174. package/build/src/git/identity.js +23 -4
  175. package/build/src/git/integration.d.ts +48 -0
  176. package/build/src/git/integration.js +250 -0
  177. package/build/src/git/observe.d.ts +29 -15
  178. package/build/src/git/observe.js +185 -76
  179. package/build/src/git/read-observation.d.ts +41 -0
  180. package/build/src/git/read-observation.js +361 -0
  181. package/build/src/git/reconcile.d.ts +17 -5
  182. package/build/src/git/reconcile.js +305 -109
  183. package/build/src/git/repository.d.ts +41 -18
  184. package/build/src/git/repository.js +220 -114
  185. package/build/src/git/scratch.d.ts +17 -0
  186. package/build/src/git/scratch.js +73 -0
  187. package/build/src/git/target-placement.d.ts +92 -0
  188. package/build/src/git/target-placement.js +375 -0
  189. package/build/src/git/tender.d.ts +49 -0
  190. package/build/src/git/tender.js +63 -0
  191. package/build/src/git/terminal-seal.d.ts +24 -0
  192. package/build/src/git/terminal-seal.js +89 -0
  193. package/build/src/git/tree.d.ts +2 -2
  194. package/build/src/git/tree.js +4 -0
  195. package/build/src/git/workspace.d.ts +53 -0
  196. package/build/src/git/workspace.js +139 -0
  197. package/build/src/identity/selector.d.ts +6 -0
  198. package/build/src/identity/selector.js +19 -0
  199. package/build/src/index.d.ts +4 -2
  200. package/build/src/index.js +2 -1
  201. package/build/src/kanshi/index.d.ts +2 -2
  202. package/build/src/kanshi/index.js +1 -1
  203. package/build/src/kanshi/read.d.ts +7 -3
  204. package/build/src/kanshi/read.js +245 -45
  205. package/build/src/kanshi/report.d.ts +81 -6
  206. package/build/src/kanshi/select.d.ts +5 -0
  207. package/build/src/kanshi/select.js +33 -1
  208. package/build/src/library/address.d.ts +57 -0
  209. package/build/src/library/address.js +165 -0
  210. package/build/src/library/akuma-creation.d.ts +16 -7
  211. package/build/src/library/akuma-creation.js +96 -22
  212. package/build/src/library/audit.d.ts +18 -0
  213. package/build/src/library/audit.js +44 -0
  214. package/build/src/library/bind.d.ts +21 -0
  215. package/build/src/library/bind.js +56 -0
  216. package/build/src/library/catalog.d.ts +58 -0
  217. package/build/src/library/catalog.js +69 -0
  218. package/build/src/library/configuration.d.ts +6 -15
  219. package/build/src/library/configuration.js +14 -17
  220. package/build/src/library/contract.d.ts +23 -49
  221. package/build/src/library/contract.js +171 -185
  222. package/build/src/library/delivery.d.ts +24 -0
  223. package/build/src/library/delivery.js +21 -0
  224. package/build/src/library/fleet.d.ts +65 -0
  225. package/build/src/library/fleet.js +153 -0
  226. package/build/src/library/input.d.ts +3 -0
  227. package/build/src/library/input.js +19 -0
  228. package/build/src/library/keiyaku.d.ts +18 -3
  229. package/build/src/library/keiyaku.js +12 -1
  230. package/build/src/library/mutation.d.ts +39 -0
  231. package/build/src/library/mutation.js +37 -0
  232. package/build/src/library/reconcile.d.ts +29 -0
  233. package/build/src/library/reconcile.js +179 -0
  234. package/build/src/library/refusal.d.ts +21 -0
  235. package/build/src/library/refusal.js +29 -0
  236. package/build/src/library/region.d.ts +14 -1
  237. package/build/src/library/region.js +18 -4
  238. package/build/src/library/repo.d.ts +4 -13
  239. package/build/src/library/repo.js +14 -24
  240. package/build/src/protocol/attempt.d.ts +16 -3
  241. package/build/src/protocol/attempt.js +41 -10
  242. package/build/src/protocol/bind.d.ts +9 -2
  243. package/build/src/protocol/bind.js +48 -40
  244. package/build/src/protocol/intent.d.ts +57 -20
  245. package/build/src/protocol/intent.js +55 -79
  246. package/build/src/protocol/operations.d.ts +152 -43
  247. package/build/src/protocol/operations.js +482 -166
  248. package/build/src/protocol/outcome.d.ts +14 -3
  249. package/build/src/protocol/outcome.js +11 -3
  250. package/build/src/protocol/placement.d.ts +41 -0
  251. package/build/src/protocol/placement.js +147 -0
  252. package/build/src/protocol/read/documents.d.ts +2 -2
  253. package/build/src/protocol/read/documents.js +4 -4
  254. package/build/src/protocol/read/status.d.ts +18 -5
  255. package/build/src/protocol/read/status.js +73 -13
  256. package/build/src/protocol/run.d.ts +49 -7
  257. package/build/src/protocol/run.js +53 -25
  258. package/build/src/runtime/proc/line-rpc.d.ts +4 -8
  259. package/build/src/runtime/proc/line-rpc.js +22 -28
  260. package/build/src/runtime/proc/run.d.ts +23 -21
  261. package/build/src/runtime/proc/run.js +123 -89
  262. package/build/src/runtime/proc/stdio.d.ts +18 -0
  263. package/build/src/runtime/proc/stdio.js +58 -0
  264. package/build/src/settings.d.ts +7 -1
  265. package/build/src/settings.js +32 -17
  266. package/build/src/settlement/fence.d.ts +5 -0
  267. package/build/src/settlement/fence.js +14 -0
  268. package/build/src/settlement/holder.d.ts +35 -4
  269. package/build/src/settlement/holder.js +127 -28
  270. package/build/src/settlement/settle.d.ts +9 -1
  271. package/build/src/settlement/settle.js +74 -37
  272. package/build/src/task/board.d.ts +23 -5
  273. package/build/src/task/board.js +17 -10
  274. package/build/src/task/compose.d.ts +2 -2
  275. package/build/src/task/compose.js +18 -10
  276. package/build/src/task/context.d.ts +3 -3
  277. package/build/src/task/context.js +15 -20
  278. package/build/src/task/document.d.ts +2 -1
  279. package/build/src/task/document.js +15 -5
  280. package/build/src/task/index.d.ts +27 -15
  281. package/build/src/task/index.js +57 -35
  282. package/build/src/task/operations.d.ts +38 -13
  283. package/build/src/task/operations.js +80 -46
  284. package/build/src/task/query.d.ts +67 -0
  285. package/build/src/task/query.js +279 -0
  286. package/build/src/task/store.d.ts +5 -7
  287. package/build/src/task/store.js +43 -28
  288. package/build/src/verification/declaration.d.ts +1 -0
  289. package/build/src/verification/execution.d.ts +51 -0
  290. package/build/src/verification/execution.js +108 -0
  291. package/build/src/workspace-place.d.ts +41 -0
  292. package/build/src/workspace-place.js +386 -0
  293. package/build/src/world.d.ts +24 -0
  294. package/build/src/world.js +136 -0
  295. package/package.json +8 -4
  296. package/build/src/akuma/activity.d.ts +0 -66
  297. package/build/src/akuma/activity.js +0 -139
  298. package/build/src/akuma/providers/claude.js +0 -305
  299. package/build/src/context-root.d.ts +0 -4
  300. package/build/src/context-root.js +0 -15
  301. package/build/src/git/delivery.d.ts +0 -20
  302. package/build/src/git/delivery.js +0 -109
  303. package/build/src/git/verification.d.ts +0 -14
  304. package/build/src/git/verification.js +0 -56
  305. package/build/src/protocol/read/audit.d.ts +0 -25
  306. package/build/src/protocol/read/audit.js +0 -39
  307. package/build/src/verification/producer.d.ts +0 -23
  308. package/build/src/verification/producer.js +0 -54
@@ -0,0 +1,361 @@
1
+ import { spawn } from "node:child_process";
2
+ import { AuthorityCorruptionError } from "../core/facts/errors.js";
3
+ import { gitObjectId } from "./identity.js";
4
+ import { parseTreeObject, validPath } from "./tree.js";
5
+ import { GIT_FORMAT_BYTES, GIT_FORMAT_PATH, GIT_REF, GitPlumbingError, readRef, } from "./repository.js";
6
+ const gitReadObservationBrand = Symbol("GitReadObservation");
7
+ const gitDecodeChannelBrand = Symbol("GitDecodeChannel");
8
+ function streamCursor(stream) {
9
+ const iterator = stream[Symbol.asyncIterator]();
10
+ let buffer = Buffer.alloc(0);
11
+ const pull = async (expected) => {
12
+ const next = await iterator.next();
13
+ if (next.done)
14
+ throw new Error(`git cat-file --batch ended while reading ${expected}`);
15
+ const chunk = Buffer.from(next.value);
16
+ buffer = buffer.length === 0 ? chunk : Buffer.concat([buffer, chunk]);
17
+ };
18
+ const line = async () => {
19
+ for (;;) {
20
+ const newline = buffer.indexOf(0x0a);
21
+ if (newline >= 0) {
22
+ const value = buffer.subarray(0, newline);
23
+ buffer = buffer.subarray(newline + 1);
24
+ return value;
25
+ }
26
+ await pull("line");
27
+ }
28
+ };
29
+ const exact = async (length) => {
30
+ while (buffer.length < length)
31
+ await pull(`${length} bytes`);
32
+ const value = buffer.subarray(0, length);
33
+ buffer = buffer.subarray(length);
34
+ return value;
35
+ };
36
+ return { line, exact };
37
+ }
38
+ function batchObjectReader(repository) {
39
+ const child = spawn("git", ["cat-file", "--batch"], {
40
+ cwd: repository.effectiveCwd,
41
+ stdio: ["pipe", "pipe", "pipe"],
42
+ });
43
+ const cursor = streamCursor(child.stdout);
44
+ const cache = new Map();
45
+ const stderr = [];
46
+ const closed = new Promise((resolve) => {
47
+ child.once("close", (code, signal) => resolve({ code, signal }));
48
+ });
49
+ let tail = Promise.resolve();
50
+ let spawnError = null;
51
+ let failure = null;
52
+ child.stderr.on("data", (chunk) => stderr.push(Buffer.from(chunk)));
53
+ child.on("error", (error) => { spawnError = error; });
54
+ child.stdin.on("error", (error) => { spawnError ??= error; });
55
+ const plumbingError = (message, status) => new GitPlumbingError({
56
+ stderr: Buffer.concat(stderr),
57
+ status,
58
+ message: `git cat-file --batch: ${message}`,
59
+ pid: child.pid ?? null,
60
+ });
61
+ const write = async (value) => {
62
+ if (spawnError !== null)
63
+ throw spawnError;
64
+ await new Promise((resolve, reject) => {
65
+ child.stdin.write(value, (error) => error === null || error === undefined ? resolve() : reject(error));
66
+ });
67
+ };
68
+ const read = async (oid) => {
69
+ if (failure !== null)
70
+ throw failure;
71
+ try {
72
+ await write(`${oid}\n`);
73
+ const header = (await cursor.line()).toString("ascii").split(" ");
74
+ if (header.length === 2 && header[0] === oid && header[1] === "missing")
75
+ return { kind: "missing" };
76
+ if (header.length !== 3 || header[0] !== oid || header[1] === undefined || header[2] === undefined) {
77
+ throw new Error(`unexpected header for ${oid}`);
78
+ }
79
+ if (!/^(0|[1-9][0-9]*)$/.test(header[2]))
80
+ throw new Error(`invalid size for ${oid}`);
81
+ const size = Number(header[2]);
82
+ if (!Number.isSafeInteger(size))
83
+ throw new Error(`unsafe size for ${oid}`);
84
+ const bytes = await cursor.exact(size);
85
+ const delimiter = await cursor.exact(1);
86
+ if (delimiter[0] !== 0x0a)
87
+ throw new Error(`missing content delimiter for ${oid}`);
88
+ return { kind: "present", type: header[1], bytes };
89
+ }
90
+ catch (error) {
91
+ if (failure !== null)
92
+ throw failure;
93
+ child.kill();
94
+ await closed;
95
+ failure = plumbingError(error instanceof Error ? error.message : String(error), child.exitCode);
96
+ throw failure;
97
+ }
98
+ };
99
+ const object = (oid) => {
100
+ const cached = cache.get(oid);
101
+ if (cached !== undefined)
102
+ return cached;
103
+ const requested = tail.then(async () => await read(oid));
104
+ tail = requested.then(() => undefined, () => undefined);
105
+ cache.set(oid, requested);
106
+ return requested;
107
+ };
108
+ const objects = async (oids) => {
109
+ const unique = [...new Set(oids)];
110
+ for (const oid of unique)
111
+ gitObjectId(oid, "Git object");
112
+ const entries = await Promise.all(unique.map(async (oid) => [oid, await object(oid)]));
113
+ return new Map(entries);
114
+ };
115
+ const close = async () => {
116
+ await tail.catch(() => undefined);
117
+ if (failure !== null)
118
+ return;
119
+ if (!child.stdin.destroyed)
120
+ child.stdin.end();
121
+ const outcome = await closed;
122
+ if (spawnError !== null || outcome.code !== 0) {
123
+ throw plumbingError("git cat-file --batch did not close cleanly", outcome.code);
124
+ }
125
+ };
126
+ return { objects, close };
127
+ }
128
+ function commitTree(result, commit) {
129
+ if (result.kind === "missing")
130
+ throw new AuthorityCorruptionError(`Git state commit is missing: ${commit}`);
131
+ if (result.type !== "commit")
132
+ throw new AuthorityCorruptionError(`Git state ref does not name a commit: ${commit}`);
133
+ const newline = result.bytes.indexOf(0x0a);
134
+ if (newline < 0)
135
+ throw new AuthorityCorruptionError(`Git state commit has no headers: ${commit}`);
136
+ const firstLine = result.bytes.subarray(0, newline).toString("ascii");
137
+ if (!firstLine.startsWith("tree "))
138
+ throw new AuthorityCorruptionError(`Git state commit has no root tree: ${commit}`);
139
+ return gitObjectId(firstLine.slice("tree ".length), "Git state tree");
140
+ }
141
+ async function completeTree(channel, root) {
142
+ const paths = new Map();
143
+ const directories = new Map();
144
+ let level = [{ path: "", oid: root }];
145
+ while (level.length > 0) {
146
+ const objects = await channel.readObjects(level.map(({ oid }) => oid));
147
+ const next = [];
148
+ for (const tree of level) {
149
+ const object = objects.get(tree.oid);
150
+ if (object?.kind !== "present")
151
+ throw new AuthorityCorruptionError(`Git tree is missing: ${tree.oid}`);
152
+ if (object.type !== "tree")
153
+ throw new AuthorityCorruptionError(`Git object is not a tree: ${tree.oid}`);
154
+ const entries = parseTreeObject(object.bytes, tree.oid.length / 2);
155
+ directories.set(tree.path, entries);
156
+ for (const [name, entry] of entries) {
157
+ const path = tree.path.length === 0 ? name : `${tree.path}/${name}`;
158
+ if (entry.type === "tree")
159
+ next.push({ path, oid: entry.oid });
160
+ else
161
+ paths.set(path, entry);
162
+ }
163
+ }
164
+ level = next;
165
+ }
166
+ return { paths, directories };
167
+ }
168
+ function selectionTree(selection) {
169
+ const root = { exact: false, subtree: false, children: new Map() };
170
+ const add = (path, kind) => {
171
+ validPath(path);
172
+ let node = root;
173
+ for (const segment of path.split("/")) {
174
+ let child = node.children.get(segment);
175
+ if (child === undefined) {
176
+ child = { exact: false, subtree: false, children: new Map() };
177
+ node.children.set(segment, child);
178
+ }
179
+ node = child;
180
+ }
181
+ node[kind] = true;
182
+ };
183
+ add(GIT_FORMAT_PATH, "exact");
184
+ for (const path of selection.paths ?? [])
185
+ add(path, "exact");
186
+ for (const path of selection.subtrees ?? [])
187
+ add(path, "subtree");
188
+ return root;
189
+ }
190
+ export async function readGitTreeSelection(channel, root, selection) {
191
+ const paths = new Map();
192
+ const directories = new Map();
193
+ const readDirectory = async (path, oid) => {
194
+ const object = (await channel.readObjects([oid])).get(oid);
195
+ if (object?.kind !== "present")
196
+ throw new AuthorityCorruptionError(`Git tree is missing: ${oid}`);
197
+ if (object.type !== "tree")
198
+ throw new AuthorityCorruptionError(`Git object is not a tree: ${oid}`);
199
+ const entries = parseTreeObject(object.bytes, oid.length / 2);
200
+ directories.set(path, entries);
201
+ return entries;
202
+ };
203
+ const enumerate = async (path, oid) => {
204
+ const entries = await readDirectory(path, oid);
205
+ await Promise.all([...entries].map(async ([name, entry]) => {
206
+ const childPath = path.length === 0 ? name : `${path}/${name}`;
207
+ if (entry.type === "tree")
208
+ await enumerate(childPath, entry.oid);
209
+ else
210
+ paths.set(childPath, entry);
211
+ }));
212
+ };
213
+ const visit = async (path, oid, node) => {
214
+ const entries = await readDirectory(path, oid);
215
+ await Promise.all([...node.children].map(async ([name, child]) => {
216
+ const entry = entries.get(name);
217
+ if (entry === undefined)
218
+ return;
219
+ const childPath = path.length === 0 ? name : `${path}/${name}`;
220
+ if (entry.type !== "tree") {
221
+ paths.set(childPath, entry);
222
+ return;
223
+ }
224
+ if (child.exact || child.subtree)
225
+ paths.set(childPath, entry);
226
+ if (child.exact && child.children.size === 0 && !child.subtree) {
227
+ paths.set(childPath, entry);
228
+ return;
229
+ }
230
+ if (child.subtree)
231
+ await enumerate(childPath, entry.oid);
232
+ else if (child.children.size > 0)
233
+ await visit(childPath, entry.oid, child);
234
+ }));
235
+ };
236
+ await visit("", root, selectionTree(selection));
237
+ return { paths, directories };
238
+ }
239
+ async function readFormat(observation) {
240
+ const entry = observation.snapshot.paths.get(GIT_FORMAT_PATH);
241
+ if (entry === undefined)
242
+ throw new AuthorityCorruptionError(`Git is missing ${GIT_FORMAT_PATH}`);
243
+ if (entry.type !== "blob")
244
+ throw new AuthorityCorruptionError(`Git format is not a blob: ${GIT_FORMAT_PATH}`);
245
+ const result = (await observation.readBlobs([entry.oid])).get(entry.oid);
246
+ if (result?.kind !== "present" || result.bytes.toString("utf8") !== GIT_FORMAT_BYTES) {
247
+ throw new AuthorityCorruptionError(`Git format is not current: ${GIT_FORMAT_PATH}`);
248
+ }
249
+ }
250
+ export async function withGitDecodeChannel(repository, consume) {
251
+ const transport = { reader: null };
252
+ let active = true;
253
+ const objectReader = () => transport.reader ??= batchObjectReader(repository);
254
+ const channel = {
255
+ [gitDecodeChannelBrand]: true,
256
+ readObjects: (oids) => {
257
+ if (!active)
258
+ throw new Error("Git decode channel is closed");
259
+ return oids.length === 0 ? Promise.resolve(new Map()) : objectReader().objects(oids);
260
+ },
261
+ };
262
+ let result;
263
+ let failure;
264
+ try {
265
+ result = await consume(channel);
266
+ }
267
+ catch (error) {
268
+ failure = error;
269
+ }
270
+ active = false;
271
+ try {
272
+ if (transport.reader !== null)
273
+ await transport.reader.close();
274
+ }
275
+ catch (error) {
276
+ failure ??= error;
277
+ }
278
+ if (failure !== undefined)
279
+ throw failure;
280
+ return result;
281
+ }
282
+ async function observeEpoch(repository, channel, selection, consume) {
283
+ const commit = await readRef(repository, GIT_REF);
284
+ let active = true;
285
+ const refs = new Map();
286
+ const assertActive = () => {
287
+ if (!active)
288
+ throw new Error("Git read observation is closed");
289
+ };
290
+ const resolveRef = async (ref) => {
291
+ assertActive();
292
+ let resolved = refs.get(ref);
293
+ if (resolved === undefined) {
294
+ resolved = readRef(repository, ref);
295
+ refs.set(ref, resolved);
296
+ }
297
+ return await resolved;
298
+ };
299
+ const readBlobResults = async (oids) => {
300
+ assertActive();
301
+ if (oids.length === 0)
302
+ return new Map();
303
+ const objects = await channel.readObjects(oids);
304
+ const blobs = new Map();
305
+ for (const [oid, object] of objects) {
306
+ if (object.kind === "missing")
307
+ blobs.set(oid, object);
308
+ else {
309
+ if (object.type !== "blob")
310
+ throw new AuthorityCorruptionError(`Git object is not a blob: ${oid}`);
311
+ blobs.set(oid, { kind: "present", bytes: object.bytes });
312
+ }
313
+ }
314
+ return blobs;
315
+ };
316
+ let result;
317
+ let failure;
318
+ try {
319
+ let snapshot;
320
+ let treeDirectories;
321
+ if (commit === null) {
322
+ snapshot = { commit: null, tree: null, paths: new Map() };
323
+ treeDirectories = new Map();
324
+ }
325
+ else {
326
+ const commitObject = (await channel.readObjects([commit])).get(commit);
327
+ if (commitObject === undefined)
328
+ throw new Error(`missing state commit result: ${commit}`);
329
+ const tree = await commitTree(commitObject, commit);
330
+ const observed = selection === null
331
+ ? await completeTree(channel, tree)
332
+ : await readGitTreeSelection(channel, tree, selection);
333
+ snapshot = { commit, tree, paths: observed.paths };
334
+ treeDirectories = observed.directories;
335
+ }
336
+ const observation = {
337
+ [gitReadObservationBrand]: true,
338
+ repository,
339
+ snapshot,
340
+ treeDirectories,
341
+ readBlobs: readBlobResults,
342
+ resolveRef,
343
+ };
344
+ if (commit !== null)
345
+ await readFormat(observation);
346
+ result = await consume(observation);
347
+ }
348
+ catch (error) {
349
+ failure = error;
350
+ }
351
+ active = false;
352
+ if (failure !== undefined)
353
+ throw failure;
354
+ return result;
355
+ }
356
+ export async function withGitReadObservation(repository, channel, consume) {
357
+ return await observeEpoch(repository, channel, null, consume);
358
+ }
359
+ export async function withGitTargetedReadObservation(repository, channel, selection, consume) {
360
+ return await observeEpoch(repository, channel, selection, consume);
361
+ }
@@ -1,11 +1,14 @@
1
1
  import { type GitOid, type GitRepository } from "./repository.js";
2
- import { type ContractId, type ContractState } from "../core/facts/types.js";
2
+ import type { ContractId, ContractState } from "../core/facts/types.js";
3
+ import type { GitDecodeChannel } from "./read-observation.js";
4
+ import { type TargetCheckoutEffect, type TargetCheckoutLag } from "./target-placement.js";
3
5
  import { type WorktreeHookLag, type WorktreeHooks } from "./hooks.js";
6
+ import { type UnsealedBytes } from "./terminal-seal.js";
4
7
  export type Effect = Readonly<{
5
8
  kind: "worktree";
6
9
  path: string;
7
10
  action: "created" | "removed" | "unchanged";
8
- }> | Readonly<{
11
+ }> | TargetCheckoutEffect | Readonly<{
9
12
  kind: "ref";
10
13
  name: string;
11
14
  before: GitOid | null;
@@ -14,9 +17,12 @@ export type Effect = Readonly<{
14
17
  }>;
15
18
  type ReconcileInput = Readonly<{
16
19
  repository: GitRepository;
20
+ channel: GitDecodeChannel;
17
21
  contractId: ContractId;
18
22
  hooks: WorktreeHooks;
19
23
  retryHooks: boolean;
24
+ retainTerminalWorktree?: boolean;
25
+ place?: string;
20
26
  }>;
21
27
  type WorktreeRetained = Readonly<{
22
28
  kind: "worktree-retained";
@@ -27,7 +33,7 @@ export type ReconcileFailure = Readonly<{
27
33
  stage: "observation" | "effect";
28
34
  diagnostic: string;
29
35
  }>;
30
- export type ReconcileLag = WorktreeRetained | WorktreeHookLag | ReconcileFailure;
36
+ export type ReconcileLag = WorktreeRetained | UnsealedBytes | TargetCheckoutLag | WorktreeHookLag | ReconcileFailure;
31
37
  export type ReconcileResult = Readonly<{
32
38
  effects: readonly Effect[];
33
39
  lag: readonly ReconcileLag[];
@@ -41,9 +47,15 @@ export type GitReconcileObservation = Readonly<{
41
47
  state: ContractState | null;
42
48
  result: ReconcileResult;
43
49
  }>;
44
- export declare function deliveryWorktreePath(repository: GitRepository, contract: ContractId): string;
45
50
  export declare function reconcile(input: ReconcileInput): Promise<GitReconcileObservation>;
46
51
  export declare function reconcileObservationFailure(error: unknown): ReconcileResult;
52
+ export declare function reconcileEffectFailure(error: unknown, prior?: ReconcileResult): ReconcileResult;
53
+ type ReconcileBatchOptions = Readonly<{
54
+ hooks: WorktreeHooks;
55
+ retryHooks: boolean;
56
+ retainTerminalWorktree: boolean;
57
+ places?: ReadonlyMap<ContractId, string>;
58
+ }>;
47
59
  /** Reconcile each discovered Contract through its own serialized, fresh observation. */
48
- export declare function reconcileBatch(repository: GitRepository, contracts: Iterable<ContractId>, hooks: WorktreeHooks, retryHooks: boolean): Promise<readonly ReconcileBatchItem[]>;
60
+ export declare function reconcileBatch(repository: GitRepository, channel: GitDecodeChannel, contracts: Iterable<ContractId>, options: ReconcileBatchOptions): Promise<readonly ReconcileBatchItem[]>;
49
61
  export {};