@astrosheep/keiyaku 4.1.0 → 4.1.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 (278) hide show
  1. package/README.md +1 -1
  2. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku/SKILL.md +3 -0
  3. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +3 -0
  4. package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +3 -6
  5. package/build/src/akuma/akuma-errors.d.ts +6 -0
  6. package/build/src/akuma/akuma-errors.js +9 -0
  7. package/build/src/akuma/akuma-handle.d.ts +39 -0
  8. package/build/src/akuma/akuma-handle.js +263 -0
  9. package/build/src/akuma/akuma-observe.d.ts +19 -0
  10. package/build/src/akuma/akuma-observe.js +74 -0
  11. package/build/src/akuma/akuma-product-symbols.d.ts +1 -0
  12. package/build/src/akuma/akuma-product-symbols.js +1 -0
  13. package/build/src/akuma/akuma-product.d.ts +18 -0
  14. package/build/src/akuma/akuma-product.js +154 -0
  15. package/build/src/akuma/akuma.d.ts +37 -81
  16. package/build/src/akuma/akuma.js +39 -447
  17. package/build/src/akuma/allowed.d.ts +1 -0
  18. package/build/src/akuma/allowed.js +6 -0
  19. package/build/src/akuma/archetype.js +8 -5
  20. package/build/src/akuma/body-supervisor.d.ts +26 -0
  21. package/build/src/akuma/body-supervisor.js +89 -0
  22. package/build/src/akuma/body.d.ts +45 -4
  23. package/build/src/akuma/body.js +145 -35
  24. package/build/src/akuma/coordinate.js +17 -7
  25. package/build/src/akuma/heart/facts.js +1 -1
  26. package/build/src/akuma/heart/index.d.ts +1 -1
  27. package/build/src/akuma/heart/index.js +2 -4
  28. package/build/src/akuma/heart/request-authority.js +4 -4
  29. package/build/src/akuma/heart/request-rows.js +27 -16
  30. package/build/src/akuma/heart/rows.js +79 -41
  31. package/build/src/akuma/heart/soul.js +1 -1
  32. package/build/src/akuma/heart/storage.d.ts +1 -0
  33. package/build/src/akuma/heart/storage.js +76 -11
  34. package/build/src/akuma/heart/tells.js +35 -18
  35. package/build/src/akuma/heart/timeline.js +19 -11
  36. package/build/src/akuma/identity.d.ts +1 -0
  37. package/build/src/akuma/identity.js +1 -0
  38. package/build/src/akuma/index.d.ts +3 -3
  39. package/build/src/akuma/index.js +1 -1
  40. package/build/src/akuma/nuke.js +106 -14
  41. package/build/src/akuma/projection-read.d.ts +17 -0
  42. package/build/src/akuma/projection-read.js +135 -0
  43. package/build/src/akuma/projection.d.ts +1 -16
  44. package/build/src/akuma/projection.js +77 -154
  45. package/build/src/akuma/provider-recipe.js +11 -5
  46. package/build/src/akuma/provider.js +105 -62
  47. package/build/src/akuma/providers/acp/config.js +5 -6
  48. package/build/src/akuma/providers/acp/core.js +17 -10
  49. package/build/src/akuma/providers/acp/events.js +38 -29
  50. package/build/src/akuma/providers/acp/index.js +13 -9
  51. package/build/src/akuma/providers/claude/events.js +8 -12
  52. package/build/src/akuma/providers/claude/index.d.ts +1 -0
  53. package/build/src/akuma/providers/claude/index.js +55 -26
  54. package/build/src/akuma/providers/claude/input.js +6 -2
  55. package/build/src/akuma/providers/codex-app-server/events.js +61 -36
  56. package/build/src/akuma/providers/codex-app-server/index.js +25 -13
  57. package/build/src/akuma/providers/grok-build/index.js +22 -25
  58. package/build/src/akuma/providers/index.js +2 -18
  59. package/build/src/akuma/providers/opencode-sdk/events.js +32 -18
  60. package/build/src/akuma/providers/opencode-sdk/index.js +26 -17
  61. package/build/src/akuma/providers/opencode-sdk/session.js +21 -5
  62. package/build/src/akuma/providers/pi/events.js +26 -19
  63. package/build/src/akuma/providers/pi/index.js +58 -40
  64. package/build/src/akuma/publication.js +9 -9
  65. package/build/src/akuma/request-execution.d.ts +6 -0
  66. package/build/src/akuma/request-execution.js +86 -0
  67. package/build/src/akuma/request-serve.d.ts +12 -1
  68. package/build/src/akuma/request-serve.js +19 -122
  69. package/build/src/akuma/request-wire.d.ts +2 -2
  70. package/build/src/akuma/request-wire.js +75 -102
  71. package/build/src/akuma/requests.js +2 -2
  72. package/build/src/akuma/{body-turn.d.ts → turn-drive.d.ts} +2 -25
  73. package/build/src/akuma/{body-turn.js → turn-drive.js} +20 -103
  74. package/build/src/akuma-body.js +6 -5
  75. package/build/src/body/amend.d.ts +4 -1
  76. package/build/src/body/amend.js +14 -6
  77. package/build/src/body/decode.js +2 -4
  78. package/build/src/body/envelope.js +2 -4
  79. package/build/src/body/region.d.ts +1 -2
  80. package/build/src/body/region.js +2 -70
  81. package/build/src/body/render.js +17 -12
  82. package/build/src/body/shape.js +1 -7
  83. package/build/src/cli/accepted.d.ts +1 -1
  84. package/build/src/cli/accepted.js +8 -1
  85. package/build/src/cli/commands/akuma-invoke.js +18 -6
  86. package/build/src/cli/commands/akuma.d.ts +0 -6
  87. package/build/src/cli/commands/akuma.js +11 -24
  88. package/build/src/cli/commands/amend.d.ts +2 -2
  89. package/build/src/cli/commands/amend.js +2 -4
  90. package/build/src/cli/commands/bind.d.ts +4 -4
  91. package/build/src/cli/commands/bind.js +16 -6
  92. package/build/src/cli/commands/contract-invoke.d.ts +25 -0
  93. package/build/src/cli/commands/contract-invoke.js +193 -0
  94. package/build/src/cli/commands/contract.d.ts +109 -10
  95. package/build/src/cli/commands/contract.js +339 -16
  96. package/build/src/cli/commands/install.d.ts +1 -1
  97. package/build/src/cli/commands/install.js +23 -15
  98. package/build/src/cli/commands/task-invoke.js +187 -67
  99. package/build/src/cli/commands/task-query.js +48 -24
  100. package/build/src/cli/commands/task.js +150 -38
  101. package/build/src/cli/coordinates.js +2 -4
  102. package/build/src/cli/invoke.js +92 -208
  103. package/build/src/cli/main.js +4 -2
  104. package/build/src/cli/parse.d.ts +3 -90
  105. package/build/src/cli/parse.js +27 -233
  106. package/build/src/cli/render/akuma-activity.d.ts +38 -0
  107. package/build/src/cli/render/akuma-activity.js +362 -0
  108. package/build/src/cli/render/akuma-tool-command.js +6 -7
  109. package/build/src/cli/render/akuma-tool.js +10 -8
  110. package/build/src/cli/render/akuma.d.ts +1 -1
  111. package/build/src/cli/render/akuma.js +61 -353
  112. package/build/src/cli/render/audit.js +5 -15
  113. package/build/src/cli/render/board.d.ts +1 -0
  114. package/build/src/cli/render/board.js +17 -0
  115. package/build/src/cli/render/catalog.js +81 -8
  116. package/build/src/cli/render/contract-history.d.ts +2 -0
  117. package/build/src/cli/render/contract-history.js +83 -0
  118. package/build/src/cli/render/contract-observation.d.ts +10 -0
  119. package/build/src/cli/render/contract-observation.js +58 -0
  120. package/build/src/cli/render/contract.d.ts +1 -2
  121. package/build/src/cli/render/contract.js +41 -142
  122. package/build/src/cli/render/kanshi.js +239 -215
  123. package/build/src/cli/render/receipt.js +2 -9
  124. package/build/src/cli/render/refusal.js +10 -15
  125. package/build/src/cli/render/region.js +22 -6
  126. package/build/src/cli/render/settings.js +4 -4
  127. package/build/src/cli/render/task.js +34 -14
  128. package/build/src/cli/render/terminal.js +16 -5
  129. package/build/src/cli/result.d.ts +3 -3
  130. package/build/src/cli/runtime.d.ts +6 -1
  131. package/build/src/cli/runtime.js +84 -63
  132. package/build/src/cli/selectors.js +2 -4
  133. package/build/src/cli/usage.js +6 -5
  134. package/build/src/contract-worktree.d.ts +1 -23
  135. package/build/src/contract-worktree.js +79 -155
  136. package/build/src/coordination/durable-file.js +7 -3
  137. package/build/src/coordination/sqlite-transaction-lock.js +29 -12
  138. package/build/src/core/facts/codec.js +7 -3
  139. package/build/src/core/facts/types.d.ts +1 -1
  140. package/build/src/core/subject.js +16 -9
  141. package/build/src/core/verbs/abandon.d.ts +1 -1
  142. package/build/src/core/verbs/abandon.js +1 -1
  143. package/build/src/core/verbs/amend.d.ts +1 -1
  144. package/build/src/core/verbs/amend.js +7 -7
  145. package/build/src/core/verbs/attestation.js +4 -1
  146. package/build/src/core/verbs/bind.d.ts +1 -1
  147. package/build/src/core/verbs/bind.js +1 -1
  148. package/build/src/core/verbs/placement.d.ts +1 -1
  149. package/build/src/core/verbs/placement.js +10 -8
  150. package/build/src/dispatch/index.js +8 -6
  151. package/build/src/duration.js +5 -1
  152. package/build/src/git/admission.js +5 -3
  153. package/build/src/git/hooks.d.ts +8 -0
  154. package/build/src/git/hooks.js +63 -14
  155. package/build/src/git/identity.js +1 -4
  156. package/build/src/git/integration.d.ts +2 -3
  157. package/build/src/git/integration.js +32 -39
  158. package/build/src/git/nuke.d.ts +1 -1
  159. package/build/src/git/nuke.js +110 -57
  160. package/build/src/git/observe.d.ts +13 -1
  161. package/build/src/git/observe.js +51 -44
  162. package/build/src/git/process.js +4 -2
  163. package/build/src/git/read-observation.js +10 -8
  164. package/build/src/git/reconcile.d.ts +22 -2
  165. package/build/src/git/reconcile.js +38 -274
  166. package/build/src/git/repository.d.ts +2 -0
  167. package/build/src/git/repository.js +13 -22
  168. package/build/src/git/scratch.d.ts +8 -5
  169. package/build/src/git/scratch.js +29 -2
  170. package/build/src/git/target-placement.d.ts +9 -10
  171. package/build/src/git/target-placement.js +59 -62
  172. package/build/src/git/tender.js +13 -46
  173. package/build/src/git/terminal-reconcile.d.ts +21 -0
  174. package/build/src/git/terminal-reconcile.js +278 -0
  175. package/build/src/git/terminal-seal.js +15 -12
  176. package/build/src/git/tree.js +5 -2
  177. package/build/src/git/workspace.d.ts +24 -2
  178. package/build/src/git/workspace.js +120 -16
  179. package/build/src/identity/coordinates.js +3 -1
  180. package/build/src/identity/selector.js +6 -3
  181. package/build/src/kanshi/fleet.d.ts +6 -0
  182. package/build/src/kanshi/fleet.js +27 -0
  183. package/build/src/kanshi/index.d.ts +1 -1
  184. package/build/src/kanshi/read.js +60 -48
  185. package/build/src/kanshi/report.d.ts +11 -23
  186. package/build/src/kanshi/select.js +25 -24
  187. package/build/src/library/address.d.ts +2 -1
  188. package/build/src/library/address.js +7 -8
  189. package/build/src/library/akuma-creation.js +20 -12
  190. package/build/src/library/audit.d.ts +0 -1
  191. package/build/src/library/audit.js +1 -2
  192. package/build/src/library/bind.d.ts +53 -5
  193. package/build/src/library/bind.js +98 -22
  194. package/build/src/library/catalog.d.ts +1 -0
  195. package/build/src/library/catalog.js +6 -3
  196. package/build/src/library/configuration.js +3 -1
  197. package/build/src/library/continuation.d.ts +15 -4
  198. package/build/src/library/continuation.js +24 -16
  199. package/build/src/library/contract-bind.d.ts +26 -0
  200. package/build/src/library/contract-bind.js +106 -0
  201. package/build/src/library/contract-operations.d.ts +77 -0
  202. package/build/src/library/contract-operations.js +130 -0
  203. package/build/src/library/contract-types.d.ts +95 -0
  204. package/build/src/library/contract-types.js +1 -0
  205. package/build/src/library/contract.d.ts +19 -154
  206. package/build/src/library/contract.js +46 -261
  207. package/build/src/library/fleet.d.ts +1 -1
  208. package/build/src/library/fleet.js +19 -11
  209. package/build/src/library/input.d.ts +2 -0
  210. package/build/src/library/input.js +14 -0
  211. package/build/src/library/keiyaku.d.ts +8 -7
  212. package/build/src/library/keiyaku.js +3 -3
  213. package/build/src/library/nuke.js +14 -5
  214. package/build/src/library/reconcile.d.ts +9 -4
  215. package/build/src/library/reconcile.js +30 -24
  216. package/build/src/library/refusal.d.ts +13 -5
  217. package/build/src/library/refusal.js +7 -0
  218. package/build/src/library/region.d.ts +8 -7
  219. package/build/src/library/region.js +31 -11
  220. package/build/src/library/repo.js +2 -2
  221. package/build/src/markdown/lex.js +9 -2
  222. package/build/src/markdown/parse.js +11 -7
  223. package/build/src/markdown/query.js +4 -2
  224. package/build/src/protocol/amend.js +3 -1
  225. package/build/src/protocol/attempt.d.ts +7 -3
  226. package/build/src/protocol/attempt.js +9 -5
  227. package/build/src/protocol/audit.d.ts +1 -1
  228. package/build/src/protocol/audit.js +4 -14
  229. package/build/src/protocol/bind.d.ts +19 -6
  230. package/build/src/protocol/bind.js +28 -13
  231. package/build/src/protocol/completion.d.ts +0 -1
  232. package/build/src/protocol/completion.js +1 -3
  233. package/build/src/protocol/deliver.d.ts +1 -3
  234. package/build/src/protocol/deliver.js +15 -39
  235. package/build/src/protocol/intent.d.ts +1 -0
  236. package/build/src/protocol/intent.js +9 -7
  237. package/build/src/protocol/operations.d.ts +3 -7
  238. package/build/src/protocol/operations.js +5 -3
  239. package/build/src/protocol/placement.d.ts +0 -1
  240. package/build/src/protocol/placement.js +6 -6
  241. package/build/src/protocol/read/observation.d.ts +11 -0
  242. package/build/src/protocol/read/observation.js +37 -0
  243. package/build/src/protocol/read/status.d.ts +23 -12
  244. package/build/src/protocol/read/status.js +90 -72
  245. package/build/src/protocol/reconcile.d.ts +1 -0
  246. package/build/src/protocol/reconcile.js +2 -3
  247. package/build/src/protocol/reintegrate.js +1 -1
  248. package/build/src/protocol/review.d.ts +0 -1
  249. package/build/src/protocol/review.js +15 -22
  250. package/build/src/protocol/run.d.ts +1 -0
  251. package/build/src/protocol/run.js +4 -5
  252. package/build/src/runtime/proc/launch.d.ts +33 -0
  253. package/build/src/runtime/proc/launch.js +98 -0
  254. package/build/src/runtime/proc/line-rpc.js +9 -3
  255. package/build/src/runtime/proc/run.d.ts +12 -6
  256. package/build/src/runtime/proc/run.js +78 -21
  257. package/build/src/runtime/proc/stdio.js +7 -10
  258. package/build/src/settings.js +6 -2
  259. package/build/src/settlement/holder.js +13 -10
  260. package/build/src/settlement/settle.js +39 -6
  261. package/build/src/task/board.js +12 -6
  262. package/build/src/task/compose.js +85 -22
  263. package/build/src/task/context.js +21 -8
  264. package/build/src/task/document.js +46 -10
  265. package/build/src/task/identity.js +5 -2
  266. package/build/src/task/index.d.ts +0 -1
  267. package/build/src/task/index.js +119 -34
  268. package/build/src/task/input.js +29 -7
  269. package/build/src/task/mutation.js +61 -19
  270. package/build/src/task/operations.d.ts +6 -1
  271. package/build/src/task/operations.js +83 -29
  272. package/build/src/task/query.js +55 -26
  273. package/build/src/task/store.d.ts +3 -1
  274. package/build/src/task/store.js +81 -17
  275. package/build/src/verification/execution.js +14 -11
  276. package/build/src/workspace-place.js +19 -7
  277. package/build/src/world.js +16 -6
  278. package/package.json +8 -3
@@ -0,0 +1,278 @@
1
+ import { access } from "node:fs/promises";
2
+ import { isKeiyakuOwnedRef, readRef, writeCommit, worktreeGitDirectory } from "./repository.js";
3
+ import { gitObjectIdForSnapshot, mintSnapshotId } from "./identity.js";
4
+ import { runDestroyHooks } from "./hooks.js";
5
+ import { terminalSealExpectations as decodeTerminalSealExpectations, terminalSealSnapshots, observeTerminalWorkspace, } from "./terminal-seal.js";
6
+ import { GitPlumbingError, runGit } from "./process.js";
7
+ import { worktreePath } from "./workspace.js";
8
+ const pathExists = (path) => access(path).then(() => true, () => false);
9
+ async function removeTerminalWorktree(repository, topology, path) {
10
+ const registered = topology.paths.has(path);
11
+ if (!registered) {
12
+ return {
13
+ effect: { kind: "worktree", path, action: "unchanged" },
14
+ retained: await pathExists(path),
15
+ };
16
+ }
17
+ if (!(await pathExists(path))) {
18
+ await runGit(repository, ["worktree", "remove", path]);
19
+ topology.paths.delete(path);
20
+ return { effect: { kind: "worktree", path, action: "removed" }, retained: false };
21
+ }
22
+ try {
23
+ await runGit(repository, ["worktree", "remove", "--force", path]);
24
+ }
25
+ catch {
26
+ return { effect: { kind: "worktree", path, action: "unchanged" }, retained: true };
27
+ }
28
+ topology.paths.delete(path);
29
+ return { effect: { kind: "worktree", path, action: "removed" }, retained: false };
30
+ }
31
+ export async function updateRef(repository, ref, desired) {
32
+ const before = await readRef(repository, ref);
33
+ if (before === desired)
34
+ return { kind: "ref", name: ref, action: "unchanged", before, after: desired };
35
+ await runGit(repository, [
36
+ "update-ref",
37
+ "--no-deref",
38
+ ref,
39
+ gitObjectIdForSnapshot(desired),
40
+ before ?? "0".repeat(desired.length),
41
+ ]);
42
+ return { kind: "ref", name: ref, action: before === null ? "created" : "updated", before, after: desired };
43
+ }
44
+ export async function removeRef(repository, ref) {
45
+ const before = await readRef(repository, ref);
46
+ if (before === null)
47
+ return { kind: "ref", name: ref, action: "unchanged", before: null, after: null };
48
+ await runGit(repository, ["update-ref", "--no-deref", "-d", ref, before]);
49
+ return { kind: "ref", name: ref, action: "removed", before, after: null };
50
+ }
51
+ async function removeRefWithCustody(repository, ref, custodian, expectedCustodian) {
52
+ const before = await readRef(repository, ref);
53
+ if (before === null)
54
+ return { kind: "ref", name: ref, action: "unchanged", before: null, after: null };
55
+ if ((await readRef(repository, custodian)) !== expectedCustodian) {
56
+ return { kind: "ref", name: ref, action: "unchanged", before, after: before };
57
+ }
58
+ await runGit(repository, ["update-ref", "--stdin", "--no-deref"], [
59
+ "start",
60
+ `verify ${custodian} ${gitObjectIdForSnapshot(expectedCustodian)}`,
61
+ `delete ${ref} ${before}`,
62
+ "prepare",
63
+ "commit",
64
+ "",
65
+ ].join("\n"));
66
+ return { kind: "ref", name: ref, action: "removed", before, after: null };
67
+ }
68
+ function retainedRefEffect(ref, snapshot) {
69
+ return { kind: "ref", name: ref, action: "unchanged", before: snapshot, after: snapshot };
70
+ }
71
+ async function refRows(repository) {
72
+ const output = (await runGit(repository, ["for-each-ref", "--format=%(refname)%00%(objectname)"])).toString("utf8");
73
+ if (output.length === 0)
74
+ return [];
75
+ return output
76
+ .trimEnd()
77
+ .split("\n")
78
+ .map((row) => {
79
+ const [ref, oid, extra] = row.split("\0");
80
+ if (ref === undefined || oid === undefined || extra !== undefined)
81
+ throw new Error("Git ref row is malformed");
82
+ return { ref, oid };
83
+ });
84
+ }
85
+ async function commitIsAncestor(repository, ancestor, descendant) {
86
+ try {
87
+ await runGit(repository, ["merge-base", "--is-ancestor", gitObjectIdForSnapshot(ancestor), descendant]);
88
+ return true;
89
+ }
90
+ catch (error) {
91
+ if (error instanceof GitPlumbingError && error.status === 1)
92
+ return false;
93
+ throw error;
94
+ }
95
+ }
96
+ async function snapshotCustodian(repository, snapshot) {
97
+ for (const row of await refRows(repository)) {
98
+ if (isKeiyakuOwnedRef(row.ref))
99
+ continue;
100
+ if (await commitIsAncestor(repository, snapshot, row.oid))
101
+ return { ref: row.ref, oid: mintSnapshotId(row.oid) };
102
+ }
103
+ return null;
104
+ }
105
+ function fromPrimaryWorktree(repository) {
106
+ return { ...repository, effectiveCwd: repository.primaryWorktree };
107
+ }
108
+ function complete(effects = [], lag = []) {
109
+ return { effects, lag };
110
+ }
111
+ function retainTerminalWorktree(path, retainedLag, { effects, lag }) {
112
+ effects.push({ kind: "worktree", path, action: "unchanged" });
113
+ lag.push(retainedLag);
114
+ return complete(effects, lag);
115
+ }
116
+ async function terminalSealExpectations(channel, state) {
117
+ const snapshots = terminalSealSnapshots(state);
118
+ const objects = await channel.readObjects(snapshots.map(gitObjectIdForSnapshot));
119
+ return decodeTerminalSealExpectations(state, objects);
120
+ }
121
+ async function removeSealedTerminalWorktree({ repository, topology, path, state, expected, hooks, retryHooks, acc, }) {
122
+ if (topology.paths.has(path) && (await pathExists(path))) {
123
+ const terminal = state.terminal;
124
+ if (terminal === null)
125
+ throw new Error(`terminal worktree cleanup received active Contract ${state.id}`);
126
+ const canRecover = terminal.kind === "abandoned";
127
+ let recovery = null;
128
+ const recordRecovery = async (workspace) => {
129
+ const snapshot = mintSnapshotId(await writeCommit({
130
+ repository,
131
+ tree: workspace.tree,
132
+ parent: gitObjectIdForSnapshot(recovery?.snapshot ?? workspace.head),
133
+ message: `${state.id}: ephemeral abandoned-workspace recovery\n\nKeiyaku-Contract: ${state.id}`,
134
+ actor: "Keiyaku Recovery",
135
+ at: terminal.at,
136
+ }));
137
+ const effect = {
138
+ kind: "recovery-snapshot",
139
+ action: "created",
140
+ snapshot,
141
+ retention: "ephemeral",
142
+ };
143
+ const existing = acc.effects.findIndex((item) => item.kind === "recovery-snapshot");
144
+ if (existing < 0)
145
+ acc.effects.push(effect);
146
+ else
147
+ acc.effects[existing] = effect;
148
+ return { snapshot, workspace };
149
+ };
150
+ const before = await observeTerminalWorkspace(repository, path, expected);
151
+ const beforeWorkspace = before.workspace;
152
+ const beforeHooks = before.unsealed;
153
+ if (beforeHooks !== null) {
154
+ if (!canRecover || beforeWorkspace.submodules.length > 0) {
155
+ return retainTerminalWorktree(path, beforeHooks, acc);
156
+ }
157
+ recovery = await recordRecovery(beforeWorkspace);
158
+ }
159
+ const hookLag = await runDestroyHooks(path, await worktreeGitDirectory(repository, path), hooks, retryHooks);
160
+ if (hookLag !== null)
161
+ return retainTerminalWorktree(path, hookLag, acc);
162
+ const after = await observeTerminalWorkspace(repository, path, expected);
163
+ const afterWorkspace = after.workspace;
164
+ const afterHooks = after.unsealed;
165
+ if (afterHooks !== null) {
166
+ if (!canRecover || afterWorkspace.submodules.length > 0) {
167
+ return retainTerminalWorktree(path, afterHooks, acc);
168
+ }
169
+ }
170
+ if (canRecover &&
171
+ (recovery === null ||
172
+ recovery.workspace.head !== afterWorkspace.head ||
173
+ recovery.workspace.tree !== afterWorkspace.tree) &&
174
+ (recovery !== null ||
175
+ beforeWorkspace.head !== afterWorkspace.head ||
176
+ beforeWorkspace.tree !== afterWorkspace.tree)) {
177
+ recovery = await recordRecovery(afterWorkspace);
178
+ }
179
+ }
180
+ const removal = await removeTerminalWorktree(repository, topology, path);
181
+ if (removal.retained)
182
+ return retainTerminalWorktree(path, { kind: "worktree-retained", path }, acc);
183
+ acc.effects.push(removal.effect);
184
+ return null;
185
+ }
186
+ async function targetCustodyForClaimedIntegration(repository, state, integration) {
187
+ if (state.terminal?.kind !== "claimed" || state.coordinates.target === undefined)
188
+ return null;
189
+ const target = await readRef(repository, state.coordinates.target);
190
+ if (target === null)
191
+ return null;
192
+ const oid = mintSnapshotId(target);
193
+ return (await commitIsAncestor(repository, integration, oid)) ? { ref: state.coordinates.target, oid } : null;
194
+ }
195
+ function sealedTree(expected, snapshot) {
196
+ const tree = expected.treeBySnapshot.get(snapshot);
197
+ if (tree === undefined)
198
+ throw new Error(`terminal seal tree was not resolved: ${snapshot}`);
199
+ return tree;
200
+ }
201
+ async function releaseTerminalCustody({ repository, state, resolveSeal, ref, pin, acc: { effects }, }) {
202
+ const [deliveryRef, candidatePin] = await Promise.all([readRef(repository, ref), readRef(repository, pin)]);
203
+ if (deliveryRef === null && candidatePin === null)
204
+ return;
205
+ if (state.delivery === null) {
206
+ const custodian = await snapshotCustodian(repository, state.coordinates.start);
207
+ if (deliveryRef !== null) {
208
+ effects.push(custodian === null
209
+ ? retainedRefEffect(ref, deliveryRef)
210
+ : await removeRefWithCustody(repository, ref, custodian.ref, custodian.oid));
211
+ }
212
+ if (candidatePin !== null)
213
+ effects.push(await removeRef(repository, pin));
214
+ return;
215
+ }
216
+ const tender = state.delivery.data.tenderSnapshot;
217
+ const integration = state.currentIntegration?.snapshot ?? state.delivery.data.integration.snapshot;
218
+ const target = await targetCustodyForClaimedIntegration(repository, state, integration);
219
+ if (deliveryRef !== null && target !== null) {
220
+ if (tender === integration) {
221
+ effects.push(await removeRefWithCustody(repository, ref, target.ref, target.oid));
222
+ }
223
+ else {
224
+ const expected = await resolveSeal();
225
+ if (sealedTree(expected, tender) === sealedTree(expected, integration)) {
226
+ effects.push(await removeRefWithCustody(repository, ref, target.ref, target.oid));
227
+ }
228
+ else {
229
+ effects.push(retainedRefEffect(ref, deliveryRef));
230
+ }
231
+ }
232
+ }
233
+ else if (deliveryRef !== null) {
234
+ effects.push(retainedRefEffect(ref, deliveryRef));
235
+ }
236
+ if (candidatePin !== null) {
237
+ if (target !== null || (tender === integration && deliveryRef !== null)) {
238
+ effects.push(target !== null
239
+ ? await removeRefWithCustody(repository, pin, target.ref, target.oid)
240
+ : await removeRefWithCustody(repository, pin, ref, tender));
241
+ }
242
+ else {
243
+ effects.push(retainedRefEffect(pin, candidatePin));
244
+ }
245
+ }
246
+ }
247
+ export async function reconcileTerminalManagedWorktree({ repository, channel, hooks, retryHooks, retainTerminalWorktree, place }, state, topology, acc, { ref, pin }) {
248
+ const primary = fromPrimaryWorktree(repository);
249
+ const path = place === undefined ? undefined : worktreePath(repository, place);
250
+ const resolveSeal = async () => await terminalSealExpectations(channel, state);
251
+ if (path === undefined) {
252
+ if (retainTerminalWorktree === true)
253
+ return complete(acc.effects, acc.lag);
254
+ await releaseTerminalCustody({ repository: primary, state, resolveSeal, ref, pin, acc });
255
+ return complete(acc.effects, acc.lag);
256
+ }
257
+ const expected = await resolveSeal();
258
+ acc.effects.push(await updateRef(primary, ref, state.delivery?.data.tenderSnapshot ?? state.coordinates.start));
259
+ if (state.delivery !== null) {
260
+ acc.effects.push(await updateRef(primary, pin, state.currentIntegration?.snapshot ?? state.delivery.data.integration.snapshot));
261
+ }
262
+ if (retainTerminalWorktree === true)
263
+ return complete(acc.effects, acc.lag);
264
+ const retained = await removeSealedTerminalWorktree({
265
+ repository: primary,
266
+ topology,
267
+ path,
268
+ state,
269
+ expected,
270
+ hooks,
271
+ retryHooks,
272
+ acc,
273
+ });
274
+ if (retained !== null)
275
+ return retained;
276
+ await releaseTerminalCustody({ repository: primary, state, resolveSeal: async () => expected, ref, pin, acc });
277
+ return complete(acc.effects, acc.lag);
278
+ }
@@ -2,13 +2,17 @@ import { gitObjectId, gitObjectIdForSnapshot, mintSnapshotId } from "./identity.
2
2
  import { runGit } from "./process.js";
3
3
  import { captureWorkspaceTree } from "./workspace.js";
4
4
  export function terminalSealSnapshots(state) {
5
- return [...new Set([
5
+ return [
6
+ ...new Set([
6
7
  state.coordinates.start,
7
- ...(state.delivery === null ? [] : [
8
- state.delivery.data.tenderSnapshot,
9
- ...(state.currentIntegration === null ? [] : [state.currentIntegration.snapshot]),
10
- ]),
11
- ])];
8
+ ...(state.delivery === null
9
+ ? []
10
+ : [
11
+ state.delivery.data.tenderSnapshot,
12
+ ...(state.currentIntegration === null ? [] : [state.currentIntegration.snapshot]),
13
+ ]),
14
+ ]),
15
+ ];
12
16
  }
13
17
  function commitMetadata(snapshot, result) {
14
18
  if (result === undefined || result.kind === "missing") {
@@ -33,10 +37,7 @@ function commitMetadata(snapshot, result) {
33
37
  }
34
38
  export function terminalSealExpectations(state, objects) {
35
39
  const snapshots = terminalSealSnapshots(state);
36
- const metadata = new Map(snapshots.map((snapshot) => [
37
- snapshot,
38
- commitMetadata(snapshot, objects.get(gitObjectIdForSnapshot(snapshot))),
39
- ]));
40
+ const metadata = new Map(snapshots.map((snapshot) => [snapshot, commitMetadata(snapshot, objects.get(gitObjectIdForSnapshot(snapshot)))]));
40
41
  const treeBySnapshot = new Map([...metadata].map(([snapshot, commit]) => [snapshot, commit.tree]));
41
42
  if (state.delivery === null) {
42
43
  return { heads: [state.coordinates.start], trees: [...treeBySnapshot.values()], treeBySnapshot };
@@ -47,12 +48,14 @@ export function terminalSealExpectations(state, objects) {
47
48
  throw new Error(`terminal seal metadata was not resolved: ${tender}`);
48
49
  const [tenderParent] = tenderMetadata.parents;
49
50
  return {
50
- heads: [...new Set([
51
+ heads: [
52
+ ...new Set([
51
53
  state.coordinates.start,
52
54
  ...(tenderParent === undefined ? [] : [tenderParent]),
53
55
  tender,
54
56
  state.currentIntegration?.snapshot ?? state.delivery.data.integration.snapshot,
55
- ])],
57
+ ]),
58
+ ],
56
59
  trees: [...treeBySnapshot.values()],
57
60
  treeBySnapshot,
58
61
  };
@@ -1,8 +1,11 @@
1
1
  import { createHash } from "node:crypto";
2
2
  import { gitObjectId } from "./identity.js";
3
3
  export function validPath(path) {
4
- if (path.length === 0 || path.startsWith("/") || path.endsWith("/") || path.includes("\0")
5
- || path.split("/").some((part) => part.length === 0 || part === "." || part === ".."))
4
+ if (path.length === 0 ||
5
+ path.startsWith("/") ||
6
+ path.endsWith("/") ||
7
+ path.includes("\0") ||
8
+ path.split("/").some((part) => part.length === 0 || part === "." || part === ".."))
6
9
  throw new Error(`invalid Git path: ${path}`);
7
10
  }
8
11
  function addEntry(root, path, change) {
@@ -15,9 +15,28 @@ export type WorkspaceTree = Readonly<{
15
15
  changes: WorkspaceChanges;
16
16
  }>;
17
17
  export declare function worktreePath(repository: GitRepository, place: string): string;
18
+ export type ManagedWorktreeFollow = Readonly<{
19
+ kind: "followed";
20
+ before: SnapshotId;
21
+ after: SnapshotId;
22
+ }> | Readonly<{
23
+ kind: "unchanged";
24
+ }> | Readonly<{
25
+ kind: "retained";
26
+ head: SnapshotId;
27
+ reason: "head-moved" | "head-attached" | "operation-in-progress" | "unsupported-parent-shape";
28
+ }>;
29
+ /** Follow an accepted tender only through the native index-and-HEAD transition. */
30
+ export declare function followManagedWorktree(repository: GitRepository, workspace: string, tender: SnapshotId): Promise<ManagedWorktreeFollow>;
18
31
  export declare function withPrivateGitIndex<Value>(action: (environment: Readonly<{
19
32
  GIT_INDEX_FILE: string;
20
33
  }>) => Value | PromiseLike<Value>): Promise<Value>;
34
+ /** Observe MERGE_HEAD in an appointed workspace, or undefined when absent. */
35
+ export declare function workspaceMergeHead(repository: GitRepository, workspace: string): Promise<SnapshotId | undefined>;
36
+ /** True when the appointed workspace already has Git MERGE_HEAD. */
37
+ export declare function workspaceMergeStatePresent(repository: GitRepository, workspace: string): Promise<boolean>;
38
+ /** Sorted unique unmerged index paths from porcelain status. */
39
+ export declare function unmergedWorkspacePaths(repository: GitRepository, workspace: string): Promise<readonly string[]>;
21
40
  export type WorkspaceChangeCounts = Readonly<{
22
41
  staged: number;
23
42
  unstaged: number;
@@ -27,13 +46,16 @@ export type WorkspaceChangeCounts = Readonly<{
27
46
  export type ContractWorkspaceLocation = Readonly<{
28
47
  kind: "worktree";
29
48
  path: string;
30
- }> | Readonly<{
31
- kind: "here";
49
+ }>;
50
+ export type ContractWorkspaceMerge = Readonly<{
51
+ head: SnapshotId;
52
+ unmergedPaths: readonly string[];
32
53
  }>;
33
54
  export type ContractWorkspaceObservation = Readonly<{
34
55
  kind: "clean" | "dirty";
35
56
  location: ContractWorkspaceLocation;
36
57
  counts: WorkspaceChangeCounts;
58
+ merge: ContractWorkspaceMerge | null;
37
59
  }> | Readonly<{
38
60
  kind: "unavailable";
39
61
  location: ContractWorkspaceLocation;
@@ -1,11 +1,74 @@
1
- import { mkdtemp, rm } from "node:fs/promises";
1
+ import { access, mkdtemp, rm } from "node:fs/promises";
2
2
  import { tmpdir } from "node:os";
3
3
  import { join, resolve } from "node:path";
4
4
  import { gitObjectId, mintSnapshotId } from "./identity.js";
5
- import { runGit, runGitWithEnvironment } from "./process.js";
6
- const WORKTREE_DIRECTORY = ["keiyaku", "wt"];
5
+ import { GitPlumbingError, runGit, runGitWithEnvironment } from "./process.js";
6
+ import { worktreeGitDirectory } from "./repository.js";
7
+ const WORKTREE_DIRECTORY = [".keiyaku", "wt"];
7
8
  export function worktreePath(repository, place) {
8
- return resolve(repository.commonDirectory, ...WORKTREE_DIRECTORY, place);
9
+ return resolve(repository.primaryWorktree, ...WORKTREE_DIRECTORY, place);
10
+ }
11
+ async function workspaceRevision(repository, workspace, revision) {
12
+ try {
13
+ const value = (await runGit(repository, ["-C", workspace, "rev-parse", "--verify", "--quiet", revision]))
14
+ .toString("utf8")
15
+ .trim();
16
+ return value.length === 0 ? null : mintSnapshotId(value);
17
+ }
18
+ catch (error) {
19
+ if (error instanceof GitPlumbingError && error.status === 1)
20
+ return null;
21
+ throw error;
22
+ }
23
+ }
24
+ async function workspaceOperationState(repository, workspace, gitDirectory) {
25
+ const paths = ["rebase-merge", "rebase-apply", "CHERRY_PICK_HEAD", "REVERT_HEAD"];
26
+ const other = await Promise.all(paths.map(async (path) => {
27
+ try {
28
+ await access(join(gitDirectory, path));
29
+ return true;
30
+ }
31
+ catch {
32
+ return false;
33
+ }
34
+ }));
35
+ const unmerged = (await runGit(repository, ["-C", workspace, "ls-files", "--unmerged", "-z"])).length > 0;
36
+ return { other: other.some(Boolean), unmerged };
37
+ }
38
+ /** Follow an accepted tender only through the native index-and-HEAD transition. */
39
+ export async function followManagedWorktree(repository, workspace, tender) {
40
+ const head = await workspaceRevision(repository, workspace, "HEAD");
41
+ if (head === null)
42
+ throw new Error("managed worktree HEAD is missing");
43
+ const attached = await runGit(repository, ["-C", workspace, "symbolic-ref", "--quiet", "HEAD"]).then(() => true, (error) => {
44
+ if (error instanceof GitPlumbingError && error.status === 1)
45
+ return false;
46
+ throw error;
47
+ });
48
+ if (attached)
49
+ return { kind: "retained", head, reason: "head-attached" };
50
+ if (head === tender)
51
+ return { kind: "unchanged" };
52
+ const parents = (await runGit(repository, ["show", "-s", "--format=%P", gitObjectId(tender)]))
53
+ .toString("utf8")
54
+ .trim()
55
+ .split(" ")
56
+ .filter((parent) => parent.length > 0)
57
+ .map((parent) => mintSnapshotId(parent));
58
+ if (parents.length > 0 && head !== parents[0])
59
+ return { kind: "retained", head, reason: "head-moved" };
60
+ if (parents.length !== 1 && parents.length !== 2)
61
+ return { kind: "retained", head, reason: "unsupported-parent-shape" };
62
+ const gitDirectory = await worktreeGitDirectory(repository, workspace);
63
+ const mergeHead = await workspaceRevision(repository, workspace, "MERGE_HEAD");
64
+ const operation = await workspaceOperationState(repository, workspace, gitDirectory);
65
+ const admitted = parents.length === 1
66
+ ? mergeHead === null && !operation.other && !operation.unmerged
67
+ : mergeHead === parents[1] && !operation.other && !operation.unmerged;
68
+ if (!admitted)
69
+ return { kind: "retained", head, reason: "operation-in-progress" };
70
+ await runGit(repository, ["-C", workspace, "reset", "--mixed", gitObjectId(tender)]);
71
+ return { kind: "followed", before: head, after: tender };
9
72
  }
10
73
  export async function withPrivateGitIndex(action) {
11
74
  const directory = await mkdtemp(join(tmpdir(), "keiyaku-v4-index-"));
@@ -29,15 +92,23 @@ function fields(record, count) {
29
92
  result.push(record.slice(start));
30
93
  return result;
31
94
  }
32
- async function workspaceChanges(repository, workspace) {
95
+ async function workspaceStatus(repository, workspace) {
33
96
  const records = (await runGit(repository, [
34
- "-C", workspace,
35
- "status", "--porcelain=v2", "-z", "--untracked-files=all", "--ignore-submodules=none",
36
- ])).toString("utf8").split("\0");
97
+ "-C",
98
+ workspace,
99
+ "status",
100
+ "--porcelain=v2",
101
+ "-z",
102
+ "--untracked-files=all",
103
+ "--ignore-submodules=none",
104
+ ]))
105
+ .toString("utf8")
106
+ .split("\0");
37
107
  const staged = new Set();
38
108
  const unstaged = new Set();
39
109
  const untracked = new Set();
40
110
  const submodules = new Set();
111
+ const unmerged = new Set();
41
112
  for (let index = 0; index < records.length - 1; index += 1) {
42
113
  const record = records[index];
43
114
  const kind = record[0];
@@ -50,6 +121,8 @@ async function workspaceChanges(repository, workspace) {
50
121
  const xy = parts[1];
51
122
  const sub = parts[2];
52
123
  const path = parts.at(-1);
124
+ if (kind === "u")
125
+ unmerged.add(path);
53
126
  if (xy[0] !== ".")
54
127
  staged.add(path);
55
128
  if (xy[1] !== ".")
@@ -75,8 +148,34 @@ async function workspaceChanges(repository, workspace) {
75
148
  unstaged: [...unstaged].sort(),
76
149
  untracked: [...untracked].sort(),
77
150
  submodules: [...submodules].sort(),
151
+ unmergedPaths: [...unmerged].sort(),
78
152
  };
79
153
  }
154
+ async function workspaceChanges(repository, workspace) {
155
+ const { unmergedPaths: _unmergedPaths, ...changes } = await workspaceStatus(repository, workspace);
156
+ return changes;
157
+ }
158
+ /** Observe MERGE_HEAD in an appointed workspace, or undefined when absent. */
159
+ export async function workspaceMergeHead(repository, workspace) {
160
+ try {
161
+ return mintSnapshotId((await runGit(repository, ["-C", workspace, "rev-parse", "-q", "--verify", "MERGE_HEAD"]))
162
+ .toString("utf8")
163
+ .trim());
164
+ }
165
+ catch (error) {
166
+ if (error instanceof GitPlumbingError && error.status === 1)
167
+ return undefined;
168
+ throw error;
169
+ }
170
+ }
171
+ /** True when the appointed workspace already has Git MERGE_HEAD. */
172
+ export async function workspaceMergeStatePresent(repository, workspace) {
173
+ return (await workspaceMergeHead(repository, workspace)) !== undefined;
174
+ }
175
+ /** Sorted unique unmerged index paths from porcelain status. */
176
+ export async function unmergedWorkspacePaths(repository, workspace) {
177
+ return (await workspaceStatus(repository, workspace)).unmergedPaths;
178
+ }
80
179
  function countsOf(changes) {
81
180
  return {
82
181
  staged: changes.staged.length,
@@ -87,9 +186,12 @@ function countsOf(changes) {
87
186
  }
88
187
  export async function observeWorkspace(repository, location, workspace) {
89
188
  try {
90
- const counts = countsOf(await workspaceChanges(repository, workspace));
189
+ const status = await workspaceStatus(repository, workspace);
190
+ const counts = countsOf(status);
91
191
  const dirty = counts.staged > 0 || counts.unstaged > 0 || counts.untracked > 0 || counts.submodules > 0;
92
- return { kind: dirty ? "dirty" : "clean", location, counts };
192
+ const head = await workspaceMergeHead(repository, workspace);
193
+ const merge = head === undefined ? null : { head, unmergedPaths: status.unmergedPaths };
194
+ return { kind: dirty ? "dirty" : "clean", location, counts, merge };
93
195
  }
94
196
  catch {
95
197
  return { kind: "unavailable", location };
@@ -117,11 +219,11 @@ export async function captureWorkspaceTree(repository, workspace) {
117
219
  const identities = (await runGit(repository, ["-C", workspace, "show", "-s", "--format=%H%n%T%n%cI", "HEAD"]))
118
220
  .toString("utf8")
119
221
  .split("\n");
120
- if (identities.length !== 4
121
- || identities[0] === undefined
122
- || identities[1] === undefined
123
- || identities[2] === undefined
124
- || identities[3] !== "") {
222
+ if (identities.length !== 4 ||
223
+ identities[0] === undefined ||
224
+ identities[1] === undefined ||
225
+ identities[2] === undefined ||
226
+ identities[3] !== "") {
125
227
  throw new Error("workspace HEAD/tree/time resolution returned an unexpected shape");
126
228
  }
127
229
  const head = mintSnapshotId(identities[0]);
@@ -137,7 +239,9 @@ export async function captureWorkspaceTree(repository, workspace) {
137
239
  await runGitWithEnvironment(repository, ["-C", workspace, "read-tree", "HEAD"], undefined, environment);
138
240
  await runGitWithEnvironment(repository, ["-C", workspace, "add", "--all"], undefined, environment);
139
241
  return {
140
- tree: gitObjectId((await runGitWithEnvironment(repository, ["-C", workspace, "write-tree"], undefined, environment)).toString("utf8").trim(), "workspace tree"),
242
+ tree: gitObjectId((await runGitWithEnvironment(repository, ["-C", workspace, "write-tree"], undefined, environment))
243
+ .toString("utf8")
244
+ .trim(), "workspace tree"),
141
245
  head,
142
246
  at,
143
247
  dirty,
@@ -1,4 +1,6 @@
1
- function prefix(family) { return `${family}/`; }
1
+ function prefix(family) {
2
+ return `${family}/`;
3
+ }
2
4
  function validSegment(segment) {
3
5
  return segment.length > 0 && !/[\/\s\p{Cc}]/u.test(segment);
4
6
  }
@@ -10,9 +10,12 @@ export function parseAkumaGlob(value) {
10
10
  const segments = value.split("/");
11
11
  const archetype = segments[1] ?? "";
12
12
  const archetypeProbe = archetype.replaceAll("*", "x");
13
- if (segments.length !== 3 || segments[0] !== "aku" || !value.includes("*")
14
- || archetype.length === 0 || normalizeIdentityStem({ source: archetypeProbe }) !== archetypeProbe
15
- || !AKUMA_GLOB_SUFFIX.test(segments[2] ?? "")) {
13
+ if (segments.length !== 3 ||
14
+ segments[0] !== "aku" ||
15
+ !value.includes("*") ||
16
+ archetype.length === 0 ||
17
+ normalizeIdentityStem({ source: archetypeProbe }) !== archetypeProbe ||
18
+ !AKUMA_GLOB_SUFFIX.test(segments[2] ?? "")) {
16
19
  throw new TypeError("Akuma glob must be aku/<akuma-pattern>/<hex-pattern> and contain *");
17
20
  }
18
21
  return value;
@@ -0,0 +1,6 @@
1
+ import type { AkumaKanshiRow } from "./report.js";
2
+ export declare const FLEET_VISIBLE_ROWS = 10;
3
+ export declare const FLEET_SNAPSHOT_ROWS = 3;
4
+ export declare function fleetUpdatedAt(row: AkumaKanshiRow): string | null;
5
+ /** The Fleet aperture and snapshot readers share this one visible-row order. */
6
+ export declare function visibleFleetRows(rows: readonly AkumaKanshiRow[]): readonly AkumaKanshiRow[];
@@ -0,0 +1,27 @@
1
+ export const FLEET_VISIBLE_ROWS = 10;
2
+ export const FLEET_SNAPSHOT_ROWS = 3;
3
+ export function fleetUpdatedAt(row) {
4
+ const lifeAt = "lifeAt" in row ? row.lifeAt : null;
5
+ const lastActivityAt = "lastActivityAt" in row ? row.lastActivityAt : null;
6
+ if (lifeAt === null)
7
+ return lastActivityAt;
8
+ if (lastActivityAt === null)
9
+ return lifeAt;
10
+ return lifeAt > lastActivityAt ? lifeAt : lastActivityAt;
11
+ }
12
+ /** The Fleet aperture and snapshot readers share this one visible-row order. */
13
+ export function visibleFleetRows(rows) {
14
+ return [...rows]
15
+ .sort((left, right) => {
16
+ const leftAt = fleetUpdatedAt(left);
17
+ const rightAt = fleetUpdatedAt(right);
18
+ if (leftAt === rightAt)
19
+ return 0;
20
+ if (leftAt === null)
21
+ return 1;
22
+ if (rightAt === null)
23
+ return -1;
24
+ return leftAt > rightAt ? -1 : 1;
25
+ })
26
+ .slice(0, FLEET_VISIBLE_ROWS);
27
+ }
@@ -1,5 +1,5 @@
1
1
  export { kanshi, observeKanshi } from "./read.js";
2
2
  export { selectKanshi, selectRegion } from "./select.js";
3
3
  export type { KanshiInput } from "./read.js";
4
- export type { AkumaKanshiRow, AkumaKanshiWorld, ContractEndpointObservation, ContractHolderObservation, ContractKanshiBoard, ContractKanshiRow, KanshiReport, Section, TaskKanshiRow, TaskKanshiWorld, KanshiRegionSelection, RegionDeclaration, RegionIntersection, RegionPathMatch, RegionRead, } from "./report.js";
4
+ export type { AkumaKanshiRow, AkumaKanshiWorld, ContractEndpointObservation, ContractHolderObservation, ContractKanshiBoard, ContractKanshiRow, CurrentPhysicalIssue, KanshiReport, Section, TaskKanshiRow, TaskKanshiWorld, KanshiRegionSelection, RegionDeclaration, RegionOverlap, RegionRead, } from "./report.js";
5
5
  export type { KanshiSelection } from "./select.js";