@astrosheep/keiyaku 4.0.1 → 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 (245) hide show
  1. package/README.md +137 -5
  2. package/build/integrations/marketplace/plugins/keiyaku/.claude-plugin/plugin.json +1 -1
  3. package/build/integrations/marketplace/plugins/keiyaku/.codex-plugin/plugin.json +1 -1
  4. package/build/integrations/marketplace/plugins/keiyaku/package.json +1 -1
  5. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku/SKILL.md +3 -3
  6. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +91 -35
  7. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +98 -58
  8. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +152 -53
  9. package/build/src/akuma/abort.d.ts +2 -0
  10. package/build/src/akuma/abort.js +50 -0
  11. package/build/src/akuma/akuma.d.ts +23 -14
  12. package/build/src/akuma/akuma.js +120 -104
  13. package/build/src/akuma/archetype.d.ts +7 -6
  14. package/build/src/akuma/archetype.js +68 -41
  15. package/build/src/akuma/body.d.ts +3 -5
  16. package/build/src/akuma/body.js +408 -213
  17. package/build/src/akuma/heart/facts.d.ts +25 -34
  18. package/build/src/akuma/heart/facts.js +18 -7
  19. package/build/src/akuma/heart/index.d.ts +39 -42
  20. package/build/src/akuma/heart/index.js +134 -93
  21. package/build/src/akuma/heart/rows.d.ts +9 -31
  22. package/build/src/akuma/heart/rows.js +26 -44
  23. package/build/src/akuma/heart/schema.d.ts +1 -1
  24. package/build/src/akuma/heart/schema.js +7 -15
  25. package/build/src/akuma/heart/soul.d.ts +8 -0
  26. package/build/src/akuma/heart/soul.js +136 -0
  27. package/build/src/akuma/heart/storage.d.ts +28 -14
  28. package/build/src/akuma/heart/storage.js +86 -26
  29. package/build/src/akuma/identity.d.ts +2 -2
  30. package/build/src/akuma/identity.js +9 -9
  31. package/build/src/akuma/index.d.ts +6 -1
  32. package/build/src/akuma/index.js +6 -0
  33. package/build/src/akuma/projection.d.ts +117 -38
  34. package/build/src/akuma/projection.js +208 -97
  35. package/build/src/akuma/provider-recipe.d.ts +24 -0
  36. package/build/src/akuma/provider-recipe.js +100 -0
  37. package/build/src/akuma/provider.d.ts +12 -4
  38. package/build/src/akuma/provider.js +117 -70
  39. package/build/src/akuma/providers/acp/core.d.ts +19 -0
  40. package/build/src/akuma/providers/acp/core.js +159 -0
  41. package/build/src/akuma/providers/acp/events.d.ts +20 -0
  42. package/build/src/akuma/providers/acp/events.js +73 -0
  43. package/build/src/akuma/providers/acp/index.d.ts +12 -0
  44. package/build/src/akuma/providers/acp/index.js +94 -0
  45. package/build/src/akuma/providers/claude/events.js +66 -13
  46. package/build/src/akuma/providers/claude/index.d.ts +2 -1
  47. package/build/src/akuma/providers/claude/index.js +35 -21
  48. package/build/src/akuma/providers/codex-app-server/events.js +4 -1
  49. package/build/src/akuma/providers/codex-app-server/index.d.ts +3 -3
  50. package/build/src/akuma/providers/codex-app-server/index.js +24 -31
  51. package/build/src/akuma/providers/grok-build/index.d.ts +4 -0
  52. package/build/src/akuma/providers/grok-build/index.js +70 -0
  53. package/build/src/akuma/providers/index.d.ts +5 -3
  54. package/build/src/akuma/providers/index.js +24 -59
  55. package/build/src/akuma/providers/opencode-sdk/events.d.ts +40 -34
  56. package/build/src/akuma/providers/opencode-sdk/events.js +220 -101
  57. package/build/src/akuma/providers/opencode-sdk/index.d.ts +3 -2
  58. package/build/src/akuma/providers/opencode-sdk/index.js +233 -128
  59. package/build/src/akuma/providers/opencode-sdk/session.d.ts +11 -26
  60. package/build/src/akuma/providers/opencode-sdk/session.js +10 -9
  61. package/build/src/akuma/providers/pi/events.js +49 -11
  62. package/build/src/akuma/providers/pi/index.d.ts +1 -1
  63. package/build/src/akuma/providers/pi/index.js +50 -21
  64. package/build/src/akuma/publication.d.ts +3 -3
  65. package/build/src/akuma/publication.js +28 -40
  66. package/build/src/akuma/requests.d.ts +9 -7
  67. package/build/src/akuma/requests.js +92 -65
  68. package/build/src/alias/index.d.ts +2 -2
  69. package/build/src/alias/index.js +10 -10
  70. package/build/src/body/decode.js +7 -1
  71. package/build/src/body/region.d.ts +2 -0
  72. package/build/src/body/region.js +77 -7
  73. package/build/src/cli/accepted.d.ts +17 -13
  74. package/build/src/cli/accepted.js +72 -34
  75. package/build/src/cli/actor.js +3 -3
  76. package/build/src/cli/commands/akuma-invoke.d.ts +4 -3
  77. package/build/src/cli/commands/akuma-invoke.js +14 -9
  78. package/build/src/cli/commands/akuma.d.ts +13 -3
  79. package/build/src/cli/commands/akuma.js +67 -34
  80. package/build/src/cli/commands/contract.d.ts +18 -5
  81. package/build/src/cli/commands/contract.js +9 -3
  82. package/build/src/cli/commands/task-invoke.d.ts +17 -4
  83. package/build/src/cli/commands/task-invoke.js +43 -20
  84. package/build/src/cli/commands/task-query.d.ts +5 -0
  85. package/build/src/cli/commands/task-query.js +247 -0
  86. package/build/src/cli/commands/task.d.ts +3 -1
  87. package/build/src/cli/commands/task.js +51 -13
  88. package/build/src/cli/coordinates.d.ts +18 -0
  89. package/build/src/cli/coordinates.js +120 -0
  90. package/build/src/cli/draft.d.ts +8 -0
  91. package/build/src/cli/draft.js +96 -0
  92. package/build/src/cli/invoke.d.ts +4 -3
  93. package/build/src/cli/invoke.js +160 -179
  94. package/build/src/cli/main.js +34 -6
  95. package/build/src/cli/parse.d.ts +9 -2
  96. package/build/src/cli/parse.js +29 -7
  97. package/build/src/cli/render/akuma-tool-command.d.ts +6 -0
  98. package/build/src/cli/render/akuma-tool-command.js +144 -0
  99. package/build/src/cli/render/akuma-tool.d.ts +2 -2
  100. package/build/src/cli/render/akuma-tool.js +30 -4
  101. package/build/src/cli/render/akuma.d.ts +1 -0
  102. package/build/src/cli/render/akuma.js +211 -116
  103. package/build/src/cli/render/audit.d.ts +3 -0
  104. package/build/src/cli/render/audit.js +104 -0
  105. package/build/src/cli/render/contract.d.ts +3 -3
  106. package/build/src/cli/render/contract.js +192 -79
  107. package/build/src/cli/render/kanshi.js +263 -168
  108. package/build/src/cli/render/receipt.d.ts +19 -0
  109. package/build/src/cli/render/receipt.js +106 -0
  110. package/build/src/cli/render/refusal.d.ts +16 -2
  111. package/build/src/cli/render/refusal.js +88 -20
  112. package/build/src/cli/render/region.d.ts +2 -0
  113. package/build/src/cli/render/region.js +17 -0
  114. package/build/src/cli/render/task.d.ts +2 -1
  115. package/build/src/cli/render/task.js +223 -60
  116. package/build/src/cli/render/terminal.d.ts +7 -0
  117. package/build/src/cli/render/terminal.js +46 -0
  118. package/build/src/cli/render/text.js +6 -3
  119. package/build/src/cli/result.d.ts +115 -20
  120. package/build/src/cli/usage.d.ts +1 -0
  121. package/build/src/cli/usage.js +3 -0
  122. package/build/src/contract-worktree.d.ts +6 -5
  123. package/build/src/contract-worktree.js +95 -57
  124. package/build/src/coordination/durable-file.d.ts +4 -3
  125. package/build/src/coordination/durable-file.js +29 -25
  126. package/build/src/coordination/sqlite-transaction-lock.d.ts +4 -0
  127. package/build/src/coordination/sqlite-transaction-lock.js +22 -5
  128. package/build/src/core/facts/fold.js +1 -6
  129. package/build/src/core/facts/gate.d.ts +1 -0
  130. package/build/src/core/facts/gate.js +1 -0
  131. package/build/src/core/verbs/amend.d.ts +1 -1
  132. package/build/src/core/verbs/amend.js +0 -11
  133. package/build/src/core/verbs/deliver.d.ts +1 -1
  134. package/build/src/core/verbs/deliver.js +1 -7
  135. package/build/src/core/verbs/placement.d.ts +1 -1
  136. package/build/src/core/verbs/placement.js +4 -1
  137. package/build/src/dispatch/index.d.ts +2 -2
  138. package/build/src/dispatch/index.js +17 -17
  139. package/build/src/git/admission.d.ts +1 -1
  140. package/build/src/git/admission.js +11 -11
  141. package/build/src/git/hooks.js +13 -13
  142. package/build/src/git/integration.d.ts +14 -15
  143. package/build/src/git/integration.js +80 -44
  144. package/build/src/git/observe.d.ts +5 -3
  145. package/build/src/git/observe.js +18 -12
  146. package/build/src/git/read-observation.js +9 -9
  147. package/build/src/git/reconcile.d.ts +2 -0
  148. package/build/src/git/reconcile.js +138 -95
  149. package/build/src/git/repository.d.ts +27 -19
  150. package/build/src/git/repository.js +155 -83
  151. package/build/src/git/scratch.d.ts +7 -3
  152. package/build/src/git/scratch.js +44 -37
  153. package/build/src/git/target-placement.d.ts +40 -4
  154. package/build/src/git/target-placement.js +221 -101
  155. package/build/src/git/tender.d.ts +6 -5
  156. package/build/src/git/tender.js +24 -43
  157. package/build/src/git/terminal-seal.d.ts +1 -1
  158. package/build/src/git/terminal-seal.js +7 -5
  159. package/build/src/git/workspace.d.ts +36 -4
  160. package/build/src/git/workspace.js +53 -18
  161. package/build/src/identity/selector.js +1 -1
  162. package/build/src/index.d.ts +3 -3
  163. package/build/src/index.js +1 -1
  164. package/build/src/kanshi/index.d.ts +2 -2
  165. package/build/src/kanshi/index.js +1 -1
  166. package/build/src/kanshi/read.d.ts +2 -1
  167. package/build/src/kanshi/read.js +118 -27
  168. package/build/src/kanshi/report.d.ts +50 -0
  169. package/build/src/kanshi/select.d.ts +5 -0
  170. package/build/src/kanshi/select.js +32 -0
  171. package/build/src/library/address.d.ts +12 -3
  172. package/build/src/library/address.js +77 -46
  173. package/build/src/library/akuma-creation.d.ts +6 -1
  174. package/build/src/library/akuma-creation.js +86 -13
  175. package/build/src/library/audit.d.ts +18 -0
  176. package/build/src/library/audit.js +44 -0
  177. package/build/src/library/bind.js +4 -4
  178. package/build/src/library/catalog.d.ts +1 -1
  179. package/build/src/library/catalog.js +5 -8
  180. package/build/src/library/contract.d.ts +5 -6
  181. package/build/src/library/contract.js +11 -35
  182. package/build/src/library/delivery.d.ts +2 -1
  183. package/build/src/library/fleet.d.ts +2 -2
  184. package/build/src/library/fleet.js +35 -71
  185. package/build/src/library/keiyaku.d.ts +3 -2
  186. package/build/src/library/keiyaku.js +1 -0
  187. package/build/src/library/mutation.d.ts +7 -6
  188. package/build/src/library/mutation.js +23 -25
  189. package/build/src/library/reconcile.d.ts +29 -0
  190. package/build/src/library/reconcile.js +179 -0
  191. package/build/src/library/region.d.ts +12 -0
  192. package/build/src/library/region.js +15 -1
  193. package/build/src/library/repo.d.ts +4 -16
  194. package/build/src/library/repo.js +13 -38
  195. package/build/src/protocol/attempt.js +6 -6
  196. package/build/src/protocol/bind.js +4 -4
  197. package/build/src/protocol/intent.d.ts +15 -2
  198. package/build/src/protocol/intent.js +21 -6
  199. package/build/src/protocol/operations.d.ts +73 -22
  200. package/build/src/protocol/operations.js +292 -88
  201. package/build/src/protocol/outcome.d.ts +9 -3
  202. package/build/src/protocol/outcome.js +3 -1
  203. package/build/src/protocol/placement.d.ts +15 -4
  204. package/build/src/protocol/placement.js +58 -25
  205. package/build/src/protocol/read/status.d.ts +8 -1
  206. package/build/src/protocol/read/status.js +61 -14
  207. package/build/src/runtime/proc/line-rpc.d.ts +3 -8
  208. package/build/src/runtime/proc/line-rpc.js +16 -43
  209. package/build/src/runtime/proc/run.d.ts +15 -29
  210. package/build/src/runtime/proc/run.js +113 -105
  211. package/build/src/runtime/proc/stdio.d.ts +18 -0
  212. package/build/src/runtime/proc/stdio.js +58 -0
  213. package/build/src/settings.d.ts +2 -2
  214. package/build/src/settings.js +8 -8
  215. package/build/src/settlement/fence.d.ts +0 -4
  216. package/build/src/settlement/fence.js +0 -9
  217. package/build/src/settlement/holder.d.ts +11 -1
  218. package/build/src/settlement/holder.js +25 -0
  219. package/build/src/settlement/settle.d.ts +1 -1
  220. package/build/src/settlement/settle.js +52 -89
  221. package/build/src/task/board.d.ts +3 -3
  222. package/build/src/task/board.js +6 -9
  223. package/build/src/task/compose.d.ts +1 -1
  224. package/build/src/task/compose.js +18 -10
  225. package/build/src/task/context.d.ts +3 -3
  226. package/build/src/task/context.js +14 -14
  227. package/build/src/task/document.d.ts +2 -1
  228. package/build/src/task/document.js +15 -5
  229. package/build/src/task/index.d.ts +19 -7
  230. package/build/src/task/index.js +42 -23
  231. package/build/src/task/operations.d.ts +15 -9
  232. package/build/src/task/operations.js +78 -48
  233. package/build/src/task/query.d.ts +67 -0
  234. package/build/src/task/query.js +279 -0
  235. package/build/src/task/store.d.ts +2 -2
  236. package/build/src/task/store.js +40 -25
  237. package/build/src/verification/execution.d.ts +4 -2
  238. package/build/src/verification/execution.js +9 -5
  239. package/build/src/workspace-place.d.ts +41 -0
  240. package/build/src/workspace-place.js +386 -0
  241. package/build/src/world.d.ts +13 -2
  242. package/build/src/world.js +81 -48
  243. package/package.json +3 -2
  244. package/build/src/protocol/read/audit.d.ts +0 -31
  245. package/build/src/protocol/read/audit.js +0 -55
@@ -1,4 +1,4 @@
1
- import { existsSync, mkdirSync } from "node:fs";
1
+ import { access, mkdir } from "node:fs/promises";
2
2
  import { dirname, join } from "node:path";
3
3
  import { acquireSqliteTransactionLock } from "../coordination/sqlite-transaction-lock.js";
4
4
  import { AuthorityCorruptionError } from "../core/facts/errors.js";
@@ -7,33 +7,51 @@ import { contractLocator, contractPhysicalName, gitObjectIdForSnapshot, mintSnap
7
7
  import { observeContractAt } from "./observe.js";
8
8
  import { acquireTargetPlacementFence, recoverTargetPlacement, } from "./target-placement.js";
9
9
  import { runCreateHooks, runDestroyHooks, } from "./hooks.js";
10
- import { deliveryWorktreePath } from "./workspace.js";
11
- import { orphanedScratchWorktrees } from "./scratch.js";
10
+ import { worktreePath } from "./workspace.js";
11
+ import { collectableScratchWorktrees } from "./scratch.js";
12
12
  import { terminalSealExpectations as decodeTerminalSealExpectations, terminalSealSnapshots, unsealedBytes, } from "./terminal-seal.js";
13
- function deliveryRefFor(contract) { return `${DELIVERY_REF_NAMESPACE}/${contractPhysicalName(contract)}`; }
14
- function candidatePinRefFor(contract) { return `${CANDIDATE_PIN_REF_NAMESPACE}/${contractPhysicalName(contract)}`; }
15
- function updateRef(repository, ref, desired) {
16
- const before = readRef(repository, ref);
13
+ const pathExists = (path) => access(path).then(() => true, () => false);
14
+ function deliveryRefFor(contract) {
15
+ return `${DELIVERY_REF_NAMESPACE}/${contractPhysicalName(contract)}`;
16
+ }
17
+ function candidatePinRefFor(contract) {
18
+ return `${CANDIDATE_PIN_REF_NAMESPACE}/${contractPhysicalName(contract)}`;
19
+ }
20
+ function missingPlaceLag(repository) {
21
+ return {
22
+ kind: "reconcile-failed",
23
+ stage: "effect",
24
+ diagnostic: `managed Contract is unappointed: ${join(repository.commonDirectory, "keiyaku", "places.json")}`,
25
+ };
26
+ }
27
+ async function updateRef(repository, ref, desired) {
28
+ const before = await readRef(repository, ref);
17
29
  if (before === desired)
18
30
  return { kind: "ref", name: ref, action: "unchanged", before, after: desired };
19
- runGit(repository, ["update-ref", "--no-deref", ref, gitObjectIdForSnapshot(desired), before ?? "0".repeat(desired.length)]);
31
+ await runGit(repository, [
32
+ "update-ref",
33
+ "--no-deref",
34
+ ref,
35
+ gitObjectIdForSnapshot(desired),
36
+ before ?? "0".repeat(desired.length),
37
+ ]);
20
38
  return { kind: "ref", name: ref, action: before === null ? "created" : "updated", before, after: desired };
21
39
  }
22
- function removeRef(repository, ref) {
23
- const before = readRef(repository, ref);
40
+ async function removeRef(repository, ref) {
41
+ const before = await readRef(repository, ref);
24
42
  if (before === null)
25
43
  return { kind: "ref", name: ref, action: "unchanged", before: null, after: null };
26
- runGit(repository, ["update-ref", "--no-deref", "-d", ref, before]);
44
+ await runGit(repository, ["update-ref", "--no-deref", "-d", ref, before]);
27
45
  return { kind: "ref", name: ref, action: "removed", before, after: null };
28
46
  }
29
- function removeRefWithCustody(repository, ref, custodian, expectedCustodian) {
30
- const before = readRef(repository, ref);
47
+ async function removeRefWithCustody(repository, ref, custodian, expectedCustodian) {
48
+ const before = await readRef(repository, ref);
31
49
  if (before === null)
32
50
  return { kind: "ref", name: ref, action: "unchanged", before: null, after: null };
33
- if (readRef(repository, custodian) !== expectedCustodian) {
51
+ if (await readRef(repository, custodian) !== expectedCustodian) {
34
52
  return { kind: "ref", name: ref, action: "unchanged", before, after: before };
35
53
  }
36
- runGit(repository, ["update-ref", "--stdin", "--no-deref"], [
54
+ await runGit(repository, ["update-ref", "--stdin", "--no-deref"], [
37
55
  "start",
38
56
  `verify ${custodian} ${gitObjectIdForSnapshot(expectedCustodian)}`,
39
57
  `delete ${ref} ${before}`,
@@ -43,8 +61,8 @@ function removeRefWithCustody(repository, ref, custodian, expectedCustodian) {
43
61
  ].join("\n"));
44
62
  return { kind: "ref", name: ref, action: "removed", before, after: null };
45
63
  }
46
- function acquireWorktreeTopology(repository) {
47
- return { paths: new Set(registeredWorktreePaths(repository)) };
64
+ async function acquireWorktreeTopology(repository) {
65
+ return { paths: new Set(await registeredWorktreePaths(repository)) };
48
66
  }
49
67
  function fromPrimaryWorktree(repository) {
50
68
  return { ...repository, effectiveCwd: repository.primaryWorktree };
@@ -64,32 +82,36 @@ function reconcileLockPath(repository, contract) {
64
82
  const locator = contractLocator(contract);
65
83
  return join(commonGitDirectory(repository), "keiyaku", "locks", "reconcile", locator.slice(0, 2), `${locator.slice(2)}.sqlite`);
66
84
  }
67
- function worktree(repository, topology, path, desired) {
85
+ async function worktree(repository, topology, path, desired) {
68
86
  const registered = topology.paths.has(path);
69
- if (registered && existsSync(path))
87
+ if (registered && await pathExists(path))
70
88
  return { kind: "worktree", path, action: "unchanged" };
71
89
  if (registered) {
72
- runGit(repository, ["worktree", "remove", path]);
90
+ await runGit(repository, ["worktree", "remove", path]);
73
91
  topology.paths.delete(path);
74
92
  }
75
- if (existsSync(path))
93
+ if (await pathExists(path))
76
94
  throw new Error(`delivery worktree path is occupied: ${path}`);
77
- mkdirSync(dirname(path), { recursive: true });
78
- runGit(repository, ["worktree", "add", "--detach", path, gitObjectIdForSnapshot(desired)]);
95
+ await mkdir(dirname(path), { recursive: true });
96
+ await runGit(repository, ["worktree", "add", "--detach", path, gitObjectIdForSnapshot(desired)]);
79
97
  topology.paths.add(path);
80
98
  return { kind: "worktree", path, action: "created" };
81
99
  }
82
- function removeWorktree(repository, topology, path, force = false) {
100
+ async function removeWorktree(repository, topology, path, force = false) {
83
101
  const registered = topology.paths.has(path);
84
- if (!registered)
85
- return { effect: { kind: "worktree", path, action: "unchanged" }, retained: false };
86
- if (!existsSync(path)) {
87
- runGit(repository, ["worktree", "remove", path]);
102
+ if (!registered) {
103
+ return {
104
+ effect: { kind: "worktree", path, action: "unchanged" },
105
+ retained: await pathExists(path),
106
+ };
107
+ }
108
+ if (!await pathExists(path)) {
109
+ await runGit(repository, ["worktree", "remove", path]);
88
110
  topology.paths.delete(path);
89
111
  return { effect: { kind: "worktree", path, action: "removed" }, retained: false };
90
112
  }
91
113
  try {
92
- runGit(repository, ["worktree", "remove", ...(force ? ["--force"] : []), path]);
114
+ await runGit(repository, ["worktree", "remove", ...(force ? ["--force"] : []), path]);
93
115
  }
94
116
  catch {
95
117
  return { effect: { kind: "worktree", path, action: "unchanged" }, retained: true };
@@ -97,19 +119,24 @@ function removeWorktree(repository, topology, path, force = false) {
97
119
  topology.paths.delete(path);
98
120
  return { effect: { kind: "worktree", path, action: "removed" }, retained: false };
99
121
  }
100
- function removeOrphanedScratch(repository, topology, effects, lag) {
101
- for (const path of orphanedScratchWorktrees(topology.paths)) {
102
- const removal = removeWorktree(repository, topology, path, true);
103
- effects.push(removal.effect);
104
- if (removal.retained)
105
- lag.push({ kind: "worktree-retained", path });
122
+ async function removeCollectableScratch(repository, topology, effects, lag) {
123
+ for (const scratch of await collectableScratchWorktrees(topology.paths)) {
124
+ try {
125
+ const removal = await removeWorktree(repository, topology, scratch.path, true);
126
+ effects.push(removal.effect);
127
+ if (removal.retained)
128
+ lag.push({ kind: "worktree-retained", path: scratch.path });
129
+ }
130
+ finally {
131
+ scratch.release();
132
+ }
106
133
  }
107
134
  }
108
- function refRows(repository) {
109
- const output = runGit(repository, [
135
+ async function refRows(repository) {
136
+ const output = (await runGit(repository, [
110
137
  "for-each-ref",
111
138
  "--format=%(refname)%00%(objectname)",
112
- ]).toString("utf8");
139
+ ])).toString("utf8");
113
140
  if (output.length === 0)
114
141
  return [];
115
142
  return output.trimEnd().split("\n").map((row) => {
@@ -119,12 +146,12 @@ function refRows(repository) {
119
146
  return { ref, oid };
120
147
  });
121
148
  }
122
- function snapshotCustodian(repository, snapshot) {
123
- for (const row of refRows(repository)) {
149
+ async function snapshotCustodian(repository, snapshot) {
150
+ for (const row of await refRows(repository)) {
124
151
  if (isKeiyakuOwnedRef(row.ref))
125
152
  continue;
126
153
  try {
127
- runGit(repository, ["merge-base", "--is-ancestor", gitObjectIdForSnapshot(snapshot), row.oid]);
154
+ await runGit(repository, ["merge-base", "--is-ancestor", gitObjectIdForSnapshot(snapshot), row.oid]);
128
155
  return { ref: row.ref, oid: mintSnapshotId(row.oid) };
129
156
  }
130
157
  catch (error) {
@@ -149,7 +176,7 @@ async function reconcileTargetCheckouts(repository, state) {
149
176
  let result;
150
177
  let exceptional;
151
178
  try {
152
- const recovered = recoverTargetPlacement(repository, state);
179
+ const recovered = await recoverTargetPlacement(repository, state);
153
180
  result = complete(recovered.effects, recovered.lag);
154
181
  }
155
182
  catch (error) {
@@ -173,23 +200,23 @@ async function reconcileTargetCheckouts(repository, state) {
173
200
  result = failed("effect", releaseFailure, result.effects, result.lag);
174
201
  return result;
175
202
  }
176
- function reconcileHereWorkspaceRefs({ repository }, state, { effects, lag }) {
203
+ async function reconcileHereWorkspaceRefs({ repository }, state, { effects, lag }) {
177
204
  const pin = candidatePinRefFor(state.id);
178
205
  if (state.terminal) {
179
206
  if (state.delivery === null)
180
- effects.push(removeRef(repository, pin));
207
+ effects.push(await removeRef(repository, pin));
181
208
  else {
182
209
  const integration = state.delivery.data.integration.snapshot;
183
- const custodian = snapshotCustodian(repository, integration);
184
- effects.push(custodian === null
185
- ? updateRef(repository, pin, integration)
186
- : removeRefWithCustody(repository, pin, custodian.ref, custodian.oid));
210
+ const custodian = await snapshotCustodian(repository, integration);
211
+ effects.push(await (custodian === null
212
+ ? await updateRef(repository, pin, integration)
213
+ : await removeRefWithCustody(repository, pin, custodian.ref, custodian.oid)));
187
214
  }
188
215
  }
189
216
  else if (state.bound) {
190
- effects.push(state.delivery === null
191
- ? removeRef(repository, pin)
192
- : updateRef(repository, pin, state.delivery.data.integration.snapshot));
217
+ effects.push(await (state.delivery === null
218
+ ? await removeRef(repository, pin)
219
+ : await updateRef(repository, pin, state.delivery.data.integration.snapshot)));
193
220
  }
194
221
  return complete(effects, lag);
195
222
  }
@@ -204,26 +231,26 @@ async function terminalSealExpectations(channel, state) {
204
231
  return decodeTerminalSealExpectations(state, objects);
205
232
  }
206
233
  async function removeSealedTerminalWorktree({ repository, topology, path, expected, hooks, retryHooks, acc }) {
207
- if (topology.paths.has(path) && existsSync(path)) {
208
- const beforeHooks = unsealedBytes(repository, path, expected);
234
+ if (topology.paths.has(path) && await pathExists(path)) {
235
+ const beforeHooks = await unsealedBytes(repository, path, expected);
209
236
  if (beforeHooks !== null)
210
237
  return retainTerminalWorktree(path, beforeHooks, acc);
211
- const hookLag = await runDestroyHooks(path, worktreeGitDirectory(repository, path), hooks, retryHooks);
238
+ const hookLag = await runDestroyHooks(path, await worktreeGitDirectory(repository, path), hooks, retryHooks);
212
239
  if (hookLag !== null)
213
240
  return retainTerminalWorktree(path, hookLag, acc);
214
- const afterHooks = unsealedBytes(repository, path, expected);
241
+ const afterHooks = await unsealedBytes(repository, path, expected);
215
242
  if (afterHooks !== null)
216
243
  return retainTerminalWorktree(path, afterHooks, acc);
217
244
  }
218
- const removal = removeWorktree(repository, topology, path, true);
245
+ const removal = await removeWorktree(repository, topology, path, true);
219
246
  if (removal.retained)
220
247
  return retainTerminalWorktree(path, { kind: "worktree-retained", path }, acc);
221
248
  acc.effects.push(removal.effect);
222
249
  return null;
223
250
  }
224
- function targetCustodyForClaimedIntegration(repository, state, integration) {
251
+ async function targetCustodyForClaimedIntegration(repository, state, integration) {
225
252
  return state.terminal?.kind === "claimed" && state.coordinates.target !== undefined
226
- && readRef(repository, state.coordinates.target) === integration
253
+ && await readRef(repository, state.coordinates.target) === integration
227
254
  ? { ref: state.coordinates.target, oid: integration }
228
255
  : null;
229
256
  }
@@ -233,56 +260,69 @@ function sealedTree(expected, snapshot) {
233
260
  throw new Error(`terminal seal tree was not resolved: ${snapshot}`);
234
261
  return tree;
235
262
  }
236
- function releaseTerminalCustody({ repository, state, expected, ref, pin, acc: { effects } }) {
263
+ async function releaseTerminalCustody({ repository, state, expected, ref, pin, acc: { effects } }) {
237
264
  if (state.delivery === null) {
238
- const custodian = snapshotCustodian(repository, state.coordinates.start);
265
+ const custodian = await snapshotCustodian(repository, state.coordinates.start);
239
266
  if (custodian !== null)
240
- effects.push(removeRefWithCustody(repository, ref, custodian.ref, custodian.oid));
241
- effects.push(removeRef(repository, pin));
267
+ effects.push(await removeRefWithCustody(repository, ref, custodian.ref, custodian.oid));
268
+ effects.push(await removeRef(repository, pin));
242
269
  return;
243
270
  }
244
271
  const tender = state.delivery.data.tenderSnapshot;
245
272
  const integration = state.delivery.data.integration.snapshot;
246
- const target = targetCustodyForClaimedIntegration(repository, state, integration);
273
+ const target = await targetCustodyForClaimedIntegration(repository, state, integration);
247
274
  if (sealedTree(expected, tender) === sealedTree(expected, integration) && target !== null) {
248
- effects.push(removeRefWithCustody(repository, ref, target.ref, target.oid));
249
- effects.push(removeRefWithCustody(repository, pin, target.ref, target.oid));
275
+ effects.push(await removeRefWithCustody(repository, ref, target.ref, target.oid));
276
+ effects.push(await removeRefWithCustody(repository, pin, target.ref, target.oid));
250
277
  }
251
278
  else if (tender === integration) {
252
- effects.push(removeRefWithCustody(repository, pin, ref, tender));
279
+ effects.push(await removeRefWithCustody(repository, pin, ref, tender));
253
280
  }
254
281
  else if (target !== null) {
255
- effects.push(removeRefWithCustody(repository, pin, target.ref, target.oid));
282
+ effects.push(await removeRefWithCustody(repository, pin, target.ref, target.oid));
256
283
  }
257
284
  }
258
- async function reconcileTerminalManagedWorktree({ repository, channel, hooks, retryHooks, retainTerminalWorktree }, state, topology, acc) {
285
+ async function reconcileTerminalManagedWorktree({ repository, channel, hooks, retryHooks, retainTerminalWorktree, place }, state, topology, acc) {
259
286
  const primary = fromPrimaryWorktree(repository);
260
287
  const ref = deliveryRefFor(state.id);
261
288
  const pin = candidatePinRefFor(state.id);
262
- const path = deliveryWorktreePath(repository, state.id);
289
+ const path = place === undefined ? undefined : worktreePath(repository, place);
290
+ if (path === undefined)
291
+ return complete(acc.effects, acc.lag);
263
292
  const expected = await terminalSealExpectations(channel, state);
264
- acc.effects.push(updateRef(primary, ref, state.delivery?.data.tenderSnapshot ?? state.coordinates.start));
265
- if (state.delivery !== null)
266
- acc.effects.push(updateRef(primary, pin, state.delivery.data.integration.snapshot));
293
+ acc.effects.push(await updateRef(primary, ref, state.delivery?.data.tenderSnapshot ?? state.coordinates.start));
294
+ if (state.delivery !== null) {
295
+ acc.effects.push(await updateRef(primary, pin, state.delivery.data.integration.snapshot));
296
+ }
267
297
  if (retainTerminalWorktree === true)
268
298
  return complete(acc.effects, acc.lag);
269
- const retained = await removeSealedTerminalWorktree({ repository: primary, topology, path, expected, hooks, retryHooks, acc });
299
+ const retained = await removeSealedTerminalWorktree({
300
+ repository: primary,
301
+ topology,
302
+ path,
303
+ expected,
304
+ hooks,
305
+ retryHooks,
306
+ acc,
307
+ });
270
308
  if (retained !== null)
271
309
  return retained;
272
- releaseTerminalCustody({ repository: primary, state, expected, ref, pin, acc });
310
+ await releaseTerminalCustody({ repository: primary, state, expected, ref, pin, acc });
273
311
  return complete(acc.effects, acc.lag);
274
312
  }
275
- async function reconcileActiveManagedWorktree({ repository, hooks, retryHooks }, state, topology, { effects, lag }) {
276
- const path = deliveryWorktreePath(repository, state.id);
313
+ async function reconcileActiveManagedWorktree({ repository, hooks, retryHooks, place }, state, topology, { effects, lag }) {
314
+ if (place === undefined)
315
+ return complete(effects, [...lag, missingPlaceLag(repository)]);
316
+ const path = worktreePath(repository, place);
277
317
  const desired = state.delivery?.data.tenderSnapshot ?? state.coordinates.start;
278
- effects.push(updateRef(repository, deliveryRefFor(state.id), desired));
279
- effects.push(worktree(repository, topology, path, desired));
280
- const hookLag = await runCreateHooks(path, worktreeGitDirectory(repository, path), hooks, retryHooks);
318
+ effects.push(await updateRef(repository, deliveryRefFor(state.id), desired));
319
+ effects.push(await worktree(repository, topology, path, desired));
320
+ const hookLag = await runCreateHooks(path, await worktreeGitDirectory(repository, path), hooks, retryHooks);
281
321
  if (hookLag !== null)
282
322
  lag.push(hookLag);
283
- effects.push(state.delivery
284
- ? updateRef(repository, candidatePinRefFor(state.id), state.delivery.data.integration.snapshot)
285
- : removeRef(repository, candidatePinRefFor(state.id)));
323
+ effects.push(await (state.delivery
324
+ ? await updateRef(repository, candidatePinRefFor(state.id), state.delivery.data.integration.snapshot)
325
+ : await removeRef(repository, candidatePinRefFor(state.id))));
286
326
  return complete(effects, lag);
287
327
  }
288
328
  async function reconcileWithTopology(input, state, topology) {
@@ -290,14 +330,14 @@ async function reconcileWithTopology(input, state, topology) {
290
330
  const effects = [];
291
331
  const lag = [];
292
332
  try {
293
- removeOrphanedScratch(repository, topology, effects, lag);
333
+ await removeCollectableScratch(repository, topology, effects, lag);
294
334
  if (!state)
295
335
  return complete(effects, lag);
296
336
  const targetCheckouts = await reconcileTargetCheckouts(repository, state);
297
337
  effects.push(...targetCheckouts.effects);
298
338
  lag.push(...targetCheckouts.lag);
299
339
  if (state.coordinates.workspace === "here")
300
- return reconcileHereWorkspaceRefs(input, state, { effects, lag });
340
+ return await reconcileHereWorkspaceRefs(input, state, { effects, lag });
301
341
  if (state.terminal)
302
342
  return await reconcileTerminalManagedWorktree(input, state, topology, { effects, lag });
303
343
  return await reconcileActiveManagedWorktree(input, state, topology, { effects, lag });
@@ -334,7 +374,7 @@ export async function reconcile(input) {
334
374
  let exceptional;
335
375
  try {
336
376
  const state = (await observeContractAt(input.repository, input.channel, input.contractId)).state;
337
- const topology = acquireWorktreeTopology(input.repository);
377
+ const topology = await acquireWorktreeTopology(input.repository);
338
378
  observation = {
339
379
  state,
340
380
  result: await reconcileWithTopology(input, state, topology),
@@ -359,18 +399,21 @@ export function reconcileObservationFailure(error) {
359
399
  export function reconcileEffectFailure(error, prior) {
360
400
  return failed("effect", error, prior?.effects, prior?.lag);
361
401
  }
362
- async function reconcileBatchItem(repository, channel, contract, options) {
363
- const observation = await reconcile({ repository, channel, contractId: contract, ...options });
364
- return {
365
- contract,
366
- state: observation.state,
367
- result: observation.result,
368
- };
369
- }
370
402
  /** Reconcile each discovered Contract through its own serialized, fresh observation. */
371
403
  export async function reconcileBatch(repository, channel, contracts, options) {
372
404
  const items = [];
373
- for (const contract of contracts)
374
- items.push(await reconcileBatchItem(repository, channel, contract, options));
405
+ for (const contract of contracts) {
406
+ const place = options.places?.get(contract);
407
+ const observation = await reconcile({
408
+ repository,
409
+ channel,
410
+ contractId: contract,
411
+ hooks: options.hooks,
412
+ retryHooks: options.retryHooks,
413
+ retainTerminalWorktree: options.retainTerminalWorktree,
414
+ ...(place === undefined ? {} : { place }),
415
+ });
416
+ items.push({ contract, state: observation.state, result: observation.result });
417
+ }
375
418
  return items;
376
419
  }
@@ -53,29 +53,30 @@ export type RegisteredWorktree = Readonly<{
53
53
  path: string;
54
54
  branch: string | null;
55
55
  }>;
56
- export declare function registeredWorktrees(repository: GitRepository): readonly RegisteredWorktree[];
57
- export declare function registeredWorktreePaths(repository: GitRepository): readonly string[];
58
- export declare function repositoryAt(cwd: string): GitRepository;
56
+ export declare function registeredWorktrees(repository: GitRepository): Promise<readonly RegisteredWorktree[]>;
57
+ export declare function registeredWorktreePaths(repository: GitRepository): Promise<readonly string[]>;
58
+ export declare function repositoryAt(cwd: string): Promise<GitRepository>;
59
59
  export declare function commonGitDirectory(repository: GitRepository): string;
60
- export declare function worktreeGitDirectory(repository: GitRepository, worktree: string): string;
61
- export declare function worktreeRoot(repository: GitRepository): string;
62
- export declare function runGit(repository: GitRepository, args: readonly string[], input?: string | Uint8Array): Buffer;
63
- export declare function runGitWithEnvironment(repository: GitRepository, args: readonly string[], input: string | Uint8Array | undefined, environment: NodeJS.ProcessEnv): Buffer;
64
- export declare function readRef(repository: GitRepository, ref: string): GitOid | null;
65
- export declare function readTreeEntries(repository: GitRepository, tree: GitOid): Map<string, TreeEntry>;
66
- export declare function readGit(repository: GitRepository): GitSnapshot;
60
+ export declare function worktreeGitDirectory(repository: GitRepository, worktree: string): Promise<string>;
61
+ export declare function worktreeRoot(repository: GitRepository): Promise<string>;
62
+ export declare function runGit(repository: GitRepository, args: readonly string[], input?: string | Uint8Array): Promise<Buffer>;
63
+ export declare function consumeGitStdout(repository: GitRepository, args: readonly string[], consume: (chunk: Buffer) => void): Promise<void>;
64
+ export declare function runGitWithEnvironment(repository: GitRepository, args: readonly string[], input: string | Uint8Array | undefined, environment: NodeJS.ProcessEnv): Promise<Buffer>;
65
+ export declare function readRef(repository: GitRepository, ref: string): Promise<GitOid | null>;
66
+ export declare function readTreeEntries(repository: GitRepository, tree: GitOid): Promise<Map<string, TreeEntry>>;
67
+ export declare function readGit(repository: GitRepository): Promise<GitSnapshot>;
67
68
  /** Read only the requested private Git paths from one immutable Git tree. */
68
- export declare function readGitPaths(repository: GitRepository, requestedPaths: readonly string[]): GitSnapshot;
69
+ export declare function readGitPaths(repository: GitRepository, requestedPaths: readonly string[]): Promise<GitSnapshot>;
69
70
  /** Add paths from the same immutable Git tree without rereading its ref. */
70
- export declare function extendGitPaths(repository: GitRepository, snapshot: GitSnapshot, requestedPaths: readonly string[]): GitSnapshot;
71
+ export declare function extendGitPaths(repository: GitRepository, snapshot: GitSnapshot, requestedPaths: readonly string[]): Promise<GitSnapshot>;
71
72
  /** Expand a targeted immutable snapshot to its complete already-pinned tree. */
72
- export declare function expandGitSnapshot(repository: GitRepository, snapshot: GitSnapshot): GitSnapshot;
73
- export declare function writeBlob(repository: GitRepository, bytes: string | Uint8Array): GitOid;
74
- export declare function readBlob(repository: GitRepository, oid: GitOid): Buffer;
73
+ export declare function expandGitSnapshot(repository: GitRepository, snapshot: GitSnapshot): Promise<GitSnapshot>;
74
+ export declare function writeBlob(repository: GitRepository, bytes: string | Uint8Array): Promise<GitOid>;
75
+ export declare function readBlob(repository: GitRepository, oid: GitOid): Promise<Buffer>;
75
76
  /** Copy only the changed paths' tree ancestors, preserving untouched subtrees by object ID. */
76
- export declare function updateGitTree(repository: GitRepository, baseTree: GitOid | null, changes: ReadonlyMap<string, TreeChange>): GitOid;
77
+ export declare function updateGitTree(repository: GitRepository, baseTree: GitOid | null, changes: ReadonlyMap<string, TreeChange>): Promise<GitOid>;
77
78
  /** Write a tree update from directory entries frozen with the admitted base tree. */
78
- export declare function updateGitTreeFromFrozenDirectories(repository: GitRepository, baseTree: GitOid | null, directories: ReadonlyMap<string, ReadonlyMap<string, TreeEntry>>, changes: ReadonlyMap<string, TreeChange>): GitOid;
79
+ export declare function updateGitTreeFromFrozenDirectories(repository: GitRepository, baseTree: GitOid | null, directories: ReadonlyMap<string, ReadonlyMap<string, TreeEntry>>, changes: ReadonlyMap<string, TreeChange>): Promise<GitOid>;
79
80
  export declare function writeCommit(input: Readonly<{
80
81
  repository: GitRepository;
81
82
  tree: GitOid;
@@ -83,7 +84,7 @@ export declare function writeCommit(input: Readonly<{
83
84
  message?: string;
84
85
  actor?: string;
85
86
  at?: string;
86
- }>): GitOid;
87
+ }>): Promise<GitOid>;
87
88
  export declare function updateRefsAtomically(repository: GitRepository, updates: readonly ({
88
89
  readonly ref: typeof GIT_REF;
89
90
  readonly newOid: GitOid;
@@ -92,4 +93,11 @@ export declare function updateRefsAtomically(repository: GitRepository, updates:
92
93
  readonly ref: string;
93
94
  readonly newOid: GitOid;
94
95
  readonly expectedOid: GitOid;
95
- })[], assertions?: readonly GitRefAssertion[]): RefPublication;
96
+ })[], assertions?: readonly GitRefAssertion[]): Promise<RefPublication>;
97
+ export type GitDiffStat = Readonly<{
98
+ filesChanged: number;
99
+ insertions: number;
100
+ deletions: number;
101
+ }>;
102
+ export declare function decodeGitNumstat(output: Buffer): GitDiffStat;
103
+ export declare function decodeGitNameOnly(output: Buffer): readonly string[];