@astrosheep/keiyaku 2.9.8 → 2.9.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (230) hide show
  1. package/README.md +50 -182
  2. package/build/.tsbuildinfo +1 -1
  3. package/build/agents/harness/control-types.js +18 -1
  4. package/build/agents/harness/index.js +2 -0
  5. package/build/agents/harness/outcome-error.js +81 -0
  6. package/build/agents/harness/projection.js +10 -7
  7. package/build/agents/harness/router.js +5 -1
  8. package/build/agents/providers/claude-agent-sdk/adapter.js +18 -4
  9. package/build/agents/providers/claude-agent-sdk/registration.js +11 -1
  10. package/build/agents/providers/claude-agent-sdk/session.js +19 -5
  11. package/build/agents/providers/codex-app-server/adapter.js +11 -6
  12. package/build/agents/providers/codex-app-server/events.js +67 -6
  13. package/build/agents/providers/codex-app-server/registration.js +11 -1
  14. package/build/agents/providers/opencode-sdk/adapter.js +8 -1
  15. package/build/agents/providers/opencode-sdk/events.js +24 -2
  16. package/build/agents/providers/opencode-sdk/registration.js +11 -1
  17. package/build/agents/providers/pi/checkpoint.js +9 -1
  18. package/build/agents/providers/pi/events.js +2 -0
  19. package/build/agents/providers/pi/registration.js +14 -1
  20. package/build/cli/commands/akuma/akuma/handler.js +1 -1
  21. package/build/cli/commands/akuma/akuma/meta.js +3 -3
  22. package/build/cli/commands/akuma/catalog.js +2 -2
  23. package/build/cli/commands/akuma/{view → show}/handler.js +5 -5
  24. package/build/cli/commands/akuma/{view → show}/meta.js +3 -3
  25. package/build/cli/commands/akuma.js +1 -1
  26. package/build/cli/commands/contract/amend/handler.js +5 -4
  27. package/build/cli/commands/contract/arc/handler.js +5 -4
  28. package/build/cli/commands/contract/audit/handler.js +2 -2
  29. package/build/cli/commands/contract/bind/handler.js +12 -3
  30. package/build/cli/commands/contract/bind/meta.js +45 -15
  31. package/build/cli/commands/contract/forfeit/handler.js +9 -5
  32. package/build/cli/commands/contract/log/handler.js +2 -2
  33. package/build/cli/commands/contract/petition/handler.js +34 -7
  34. package/build/cli/commands/contract/renew/handler.js +7 -7
  35. package/build/cli/commands/contract/renew/meta.js +3 -3
  36. package/build/cli/commands/metadata.js +10 -6
  37. package/build/cli/commands/projection/call/meta.js +1 -1
  38. package/build/cli/commands/projection/catalog.js +2 -0
  39. package/build/cli/commands/projection/history/handler.js +21 -0
  40. package/build/cli/commands/projection/history/meta.js +9 -0
  41. package/build/cli/commands/projection/shared.js +3 -4
  42. package/build/cli/commands/projection/status/handler.js +3 -3
  43. package/build/cli/commands/projection/wait/handler.js +20 -11
  44. package/build/cli/commands/task/add/handler.js +14 -5
  45. package/build/cli/commands/task/add/meta.js +2 -2
  46. package/build/cli/commands/task/catalog.js +4 -0
  47. package/build/cli/commands/task/done/handler.js +1 -4
  48. package/build/cli/commands/task/done/meta.js +1 -1
  49. package/build/cli/commands/task/drop/meta.js +1 -1
  50. package/build/cli/commands/task/hold/handler.js +3 -0
  51. package/build/cli/commands/task/hold/meta.js +8 -0
  52. package/build/cli/commands/task/log/handler.js +1 -1
  53. package/build/cli/commands/task/log/meta.js +2 -2
  54. package/build/cli/commands/task/resume/handler.js +3 -0
  55. package/build/cli/commands/task/resume/meta.js +8 -0
  56. package/build/cli/commands/task/shared.js +39 -14
  57. package/build/cli/commands/task/show/handler.js +1 -1
  58. package/build/cli/commands/task/show/meta.js +1 -1
  59. package/build/cli/commands/task/start/meta.js +1 -1
  60. package/build/cli/commands/task/stop/handler.js +1 -4
  61. package/build/cli/commands/task/stop/meta.js +1 -1
  62. package/build/cli/commands/task/update/handler.js +11 -3
  63. package/build/cli/commands/task/update/meta.js +3 -3
  64. package/build/cli/completion.js +3 -2
  65. package/build/cli/flags.js +51 -14
  66. package/build/cli/help.js +4 -1
  67. package/build/cli/index.js +40 -25
  68. package/build/cli/parse-flags.js +40 -7
  69. package/build/cli/parse-metadata.js +5 -2
  70. package/build/cli/parse-selectors.js +2 -3
  71. package/build/cli/parse.js +40 -6
  72. package/build/cli/projection-address.js +12 -10
  73. package/build/cli/render/amendment-warning.js +8 -0
  74. package/build/cli/render/arc.js +6 -2
  75. package/build/cli/render/audit.js +400 -81
  76. package/build/cli/render/kanshi.js +242 -79
  77. package/build/cli/render/lifecycle.js +56 -0
  78. package/build/cli/render/misc.js +24 -28
  79. package/build/cli/render/petition.js +5 -0
  80. package/build/cli/render/projection-activity.js +65 -29
  81. package/build/cli/render/projection-history.js +64 -0
  82. package/build/cli/render/shared.js +23 -9
  83. package/build/cli/render/status.js +13 -35
  84. package/build/cli/render/task.js +51 -26
  85. package/build/cli/render/terminal-failure.js +3 -1
  86. package/build/cli/render/wait.js +45 -69
  87. package/build/cli/subagent-guard.js +1 -1
  88. package/build/cli/types.js +1 -1
  89. package/build/config/env-keys.js +3 -1
  90. package/build/config/env.js +24 -1
  91. package/build/config/settings/schema.js +3 -1
  92. package/build/core/address-carrier.js +89 -0
  93. package/build/core/addressing.js +255 -196
  94. package/build/core/amend.js +115 -38
  95. package/build/core/amendment-criteria.js +17 -0
  96. package/build/core/amendment-warning.js +10 -0
  97. package/build/core/arc.js +184 -83
  98. package/build/core/audit/candidate.js +110 -9
  99. package/build/core/audit/coordinates.js +120 -65
  100. package/build/core/audit/evidence.js +19 -23
  101. package/build/core/audit/facade.js +34 -11
  102. package/build/core/audit/report.js +5 -5
  103. package/build/core/bind-reconciliation.js +390 -0
  104. package/build/core/bind-workspace.js +12 -20
  105. package/build/core/bind.js +242 -273
  106. package/build/core/call/call.js +1 -0
  107. package/build/core/call/context.js +46 -71
  108. package/build/core/call/prompt.js +6 -3
  109. package/build/core/context.js +49 -35
  110. package/build/core/contract-carrier-runtime.js +408 -0
  111. package/build/core/contract-carrier.js +270 -0
  112. package/build/core/contract-view.js +33 -27
  113. package/build/core/contract.js +5 -1
  114. package/build/core/derived-replay.js +207 -0
  115. package/build/core/draft.js +125 -57
  116. package/build/core/forfeit.js +113 -56
  117. package/build/core/identifier-slug.js +63 -13
  118. package/build/core/ids.js +4 -4
  119. package/build/core/lifecycle-history.js +35 -0
  120. package/build/core/lifecycle-recovery.js +117 -0
  121. package/build/core/lifecycle-runner.js +377 -0
  122. package/build/core/log.js +37 -11
  123. package/build/core/outcome-base.js +181 -0
  124. package/build/core/process-group.js +139 -0
  125. package/build/core/projection/generation/database.js +82 -7
  126. package/build/core/projection/generation/model.js +9 -36
  127. package/build/core/projection/generation/projection-generation-continuation.js +10 -22
  128. package/build/core/projection/generation/projection-generation-execution.js +13 -6
  129. package/build/core/projection/index.js +5 -4
  130. package/build/core/projection/projection-activity.js +29 -8
  131. package/build/core/projection/projection-alias.js +23 -10
  132. package/build/core/projection/projection-core.js +21 -7
  133. package/build/core/projection/projection-execution-observer.js +91 -39
  134. package/build/core/projection/projection-history.js +474 -0
  135. package/build/core/projection/projection-runner-lock.js +12 -0
  136. package/build/core/projection/projection-status-observation.js +365 -0
  137. package/build/core/projection/projection-status.js +35 -337
  138. package/build/core/projection/projection-terminal-failure.js +13 -8
  139. package/build/core/projection/projection-wait.js +7 -2
  140. package/build/core/projection/tell/launch-store.js +244 -0
  141. package/build/core/projection/tell/model.js +3 -3
  142. package/build/core/projection/tell/store.js +70 -118
  143. package/build/core/registry.js +22 -87
  144. package/build/core/renew-build.js +424 -0
  145. package/build/core/renew-plan.js +239 -0
  146. package/build/core/renew-rewrite.js +77 -0
  147. package/build/core/renew.js +295 -520
  148. package/build/core/repository-ledger/accepted-fold-read.js +19 -0
  149. package/build/core/repository-ledger/accepted-tail.js +116 -0
  150. package/build/core/repository-ledger/admission.js +38 -0
  151. package/build/core/repository-ledger/authoritative-transaction.js +1 -0
  152. package/build/core/repository-ledger/claim-evidence.js +147 -0
  153. package/build/core/repository-ledger/codec.js +297 -0
  154. package/build/core/repository-ledger/current-state-store.js +853 -0
  155. package/build/core/repository-ledger/fold-repository.js +375 -0
  156. package/build/core/repository-ledger/fold.js +248 -0
  157. package/build/core/repository-ledger/git-object-store.js +243 -0
  158. package/build/core/repository-ledger/history-read.js +15 -0
  159. package/build/core/repository-ledger/incremental-read.js +153 -0
  160. package/build/core/repository-ledger/index.js +15 -0
  161. package/build/core/repository-ledger/inventory-plan.js +75 -0
  162. package/build/core/repository-ledger/inventory.js +310 -0
  163. package/build/core/repository-ledger/publication-admission.js +125 -0
  164. package/build/core/repository-ledger/publication.js +353 -0
  165. package/build/core/repository-ledger/read-model.js +469 -0
  166. package/build/core/repository-ledger/transaction-membership.js +78 -0
  167. package/build/core/repository-ledger/traversal.js +404 -0
  168. package/build/core/repository-ledger/write-transaction.js +339 -0
  169. package/build/core/seal.js +168 -161
  170. package/build/core/settlement/claim-delivery.js +42 -215
  171. package/build/core/settlement/claim.js +235 -153
  172. package/build/core/settlement/index.js +4 -4
  173. package/build/core/settlement/petition-claim-gates.js +52 -33
  174. package/build/core/settlement/petition-forfeit.js +12 -5
  175. package/build/core/settlement/petition-head-guard.js +8 -5
  176. package/build/core/settlement/petition-preview.js +68 -56
  177. package/build/core/settlement/petition-window.js +50 -0
  178. package/build/core/settlement/petition.js +252 -131
  179. package/build/core/settlement/queue-read-model.js +72 -95
  180. package/build/core/settlement/queue-seat-allocation.js +35 -126
  181. package/build/core/settlement/queue.js +1 -1
  182. package/build/core/settlement/settlement.js +172 -80
  183. package/build/core/settlement/verdict.js +112 -66
  184. package/build/core/settlement/verification-coordination.js +305 -0
  185. package/build/core/settlement/verification-supervisor.js +275 -0
  186. package/build/core/settlement/verification.js +398 -31
  187. package/build/core/status/board.js +125 -127
  188. package/build/core/status/lifecycle.js +7 -80
  189. package/build/core/structured-query.js +23 -0
  190. package/build/core/target-ref.js +1 -1
  191. package/build/core/task/board.js +59 -24
  192. package/build/core/task/commands.js +181 -33
  193. package/build/core/task/coordinate.js +56 -0
  194. package/build/core/task/document.js +25 -9
  195. package/build/core/task/index.js +7 -4
  196. package/build/core/task/query.js +17 -27
  197. package/build/core/task/settlement-git.js +164 -179
  198. package/build/core/task/settlement-policy.js +15 -11
  199. package/build/core/task/source-board.js +31 -13
  200. package/build/core/task/task-bind-preparation.js +193 -0
  201. package/build/core/task/task-contract.js +102 -193
  202. package/build/core/task/task-file-transaction.js +171 -0
  203. package/build/core/task/task-git-runtime.js +76 -14
  204. package/build/core/task/task-git-store.js +68 -169
  205. package/build/core/task/task-store-repository.js +13 -6
  206. package/build/core/task/task-worktree.js +6 -33
  207. package/build/core/task/task.js +1 -1
  208. package/build/core/task/tree.js +3 -3
  209. package/build/core/task/validation.js +4 -3
  210. package/build/core/transcripts.js +93 -1
  211. package/build/core/worktree-bootstrap.js +44 -36
  212. package/build/core/worktree-path.js +210 -77
  213. package/build/flow-error.js +7 -7
  214. package/build/generated/version.js +2 -2
  215. package/build/git/core.js +76 -13
  216. package/build/git/refs.js +168 -46
  217. package/build/git/streaming-batch.js +73 -13
  218. package/package.json +1 -1
  219. package/skills/keiyaku/SKILL.md +1 -1
  220. package/skills/keiyaku-akuma/SKILL.md +3 -3
  221. package/skills/keiyaku-task/SKILL.md +4 -2
  222. package/skills/keiyaku-workflow/SKILL.md +88 -203
  223. package/build/core/entry.js +0 -305
  224. package/build/core/ledger-batch.js +0 -194
  225. package/build/core/ledger.js +0 -84
  226. package/build/core/projection/leash.js +0 -87
  227. package/build/core/ref-log.js +0 -119
  228. package/build/core/renew-session.js +0 -128
  229. package/build/core/status/ledger-batch.js +0 -1
  230. package/build/core/status/reconciliation.js +0 -137
@@ -0,0 +1,353 @@
1
+ import * as fs from "node:fs/promises";
2
+ import * as os from "node:os";
3
+ import * as path from "node:path";
4
+ import { runGitProcess } from "../../git/core.js";
5
+ import { commitRefTransaction, resolveLocalBranchHead } from "../../git/refs.js";
6
+ import { REPOSITORY_LEDGER_REF, formatStructuralJoin, } from "./codec.js";
7
+ import { admitJoin, cleanTip } from "./publication-admission.js";
8
+ import { assertHostObjectId, assertReadableCommitClosure, deriveHostGitCoordinates, writeCommitObject, } from "./git-object-store.js";
9
+ import { traverseRepositoryLedger, } from "./traversal.js";
10
+ import { readRepositoryLifecycle } from "./read-model.js";
11
+ import { readPinnedAcceptedTraversal } from "./current-state-store.js";
12
+ const VIRTUAL_JOIN_OBJECT_ID = "publication-admission:join";
13
+ const ADOPTED_REMOTE_NAME = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
14
+ const NO_PROMPT_ENV = {
15
+ GIT_NO_LAZY_FETCH: "1",
16
+ GIT_TERMINAL_PROMPT: "0",
17
+ GCM_INTERACTIVE: "Never",
18
+ };
19
+ async function recoverPublicationTip(cwd, head) {
20
+ return traverseRepositoryLedger(cwd, head, undefined, { historicalSemanticEvidence: false });
21
+ }
22
+ function gitFailure(result) {
23
+ return result.stderr.trim() || result.error?.message || `git exited ${String(result.status)}`;
24
+ }
25
+ async function successfulGit(cwd, args) {
26
+ const result = await runGitProcess(cwd, args, { env: NO_PROMPT_ENV });
27
+ if (result.status !== 0 || result.error)
28
+ throw new Error(gitFailure(result), { cause: result.error });
29
+ return result.stdout;
30
+ }
31
+ async function observeLocalTip(cwd) {
32
+ return (await resolveLocalBranchHead(cwd, REPOSITORY_LEDGER_REF))?.head ?? null;
33
+ }
34
+ async function resolveConfiguredRemote(cwd, remote) {
35
+ if (!ADOPTED_REMOTE_NAME.test(remote.name)) {
36
+ throw new Error("adopted remote name is not a canonical configured Git remote name");
37
+ }
38
+ const output = await successfulGit(cwd, ["remote", "get-url", "--push", "--all", remote.name]);
39
+ const endpoints = output.split(/\r?\n/);
40
+ if (endpoints.at(-1) === "")
41
+ endpoints.pop();
42
+ if (endpoints.length !== 1 || endpoints[0].trim() === "") {
43
+ throw new Error(`adopted remote ${remote.name} must resolve exactly one publication endpoint`);
44
+ }
45
+ return { publicationEndpoint: endpoints[0] };
46
+ }
47
+ async function targetObjectDirectory(cwd) {
48
+ const observed = (await successfulGit(cwd, ["rev-parse", "--path-format=absolute", "--git-path", "objects"])).trim();
49
+ if (!path.isAbsolute(observed))
50
+ throw new Error("Git returned a non-absolute object directory");
51
+ const canonical = await fs.realpath(observed);
52
+ if (canonical.includes("\n") || canonical.includes("\r")) {
53
+ throw new Error("Git object directory cannot be represented by an alternates file");
54
+ }
55
+ return canonical;
56
+ }
57
+ async function observeRemoteTip(cwd, endpoint, coordinates) {
58
+ const result = await runGitProcess(cwd, ["ls-remote", "--refs", "--", endpoint, REPOSITORY_LEDGER_REF], {
59
+ env: NO_PROMPT_ENV,
60
+ });
61
+ if (result.status !== 0 || result.error)
62
+ throw new Error(gitFailure(result), { cause: result.error });
63
+ if (result.stdout === "")
64
+ return null;
65
+ const rows = result.stdout.trimEnd().split(/\r?\n/);
66
+ if (rows.length !== 1)
67
+ throw new Error("adopted remote advertised more than one exact ledger ref");
68
+ const [objectId, ref, extra] = rows[0].split("\t");
69
+ if (!objectId || ref !== REPOSITORY_LEDGER_REF || extra !== undefined) {
70
+ throw new Error("adopted remote returned an invalid exact ledger advertisement");
71
+ }
72
+ assertHostObjectId(coordinates, objectId);
73
+ return objectId;
74
+ }
75
+ async function prepareScratch(input) {
76
+ const scratch = await fs.mkdtemp(path.join(os.tmpdir(), "keiyaku-publication-observation-"));
77
+ try {
78
+ await successfulGit(scratch, ["init", "--quiet", "--bare", `--object-format=${input.coordinates.objectFormat}`, "."]);
79
+ const alternate = await targetObjectDirectory(input.cwd);
80
+ await fs.writeFile(path.join(scratch, "objects", "info", "alternates"), `${alternate}\n`, { encoding: "utf8", mode: 0o600 });
81
+ return scratch;
82
+ }
83
+ catch (error) {
84
+ await fs.rm(scratch, { recursive: true, force: true });
85
+ throw error;
86
+ }
87
+ }
88
+ async function observeStableRemoteInScratch(cwd, scratch, endpoint, coordinates) {
89
+ const before = await observeRemoteTip(cwd, endpoint, coordinates);
90
+ if (before !== null) {
91
+ await successfulGit(cwd, [
92
+ `--git-dir=${scratch}`,
93
+ "fetch",
94
+ "--quiet",
95
+ "--no-tags",
96
+ "--no-write-fetch-head",
97
+ "--",
98
+ endpoint,
99
+ REPOSITORY_LEDGER_REF,
100
+ ]);
101
+ }
102
+ const after = await observeRemoteTip(cwd, endpoint, coordinates);
103
+ return before === after ? { status: "stable", tip: after } : { status: "changed", before, after };
104
+ }
105
+ async function promoteRemoteClosure(input) {
106
+ await successfulGit(input.cwd, [
107
+ "fetch",
108
+ "--quiet",
109
+ "--no-tags",
110
+ "--no-write-fetch-head",
111
+ "--",
112
+ input.endpoint,
113
+ REPOSITORY_LEDGER_REF,
114
+ ]);
115
+ return await observeRemoteTip(input.cwd, input.endpoint, input.coordinates) === input.expectedTip
116
+ ? "promoted"
117
+ : "changed";
118
+ }
119
+ async function publishRemote(input) {
120
+ const pushed = await runGitProcess(input.cwd, [
121
+ "push",
122
+ "--porcelain",
123
+ "--",
124
+ input.endpoint,
125
+ `${input.newTip}:${REPOSITORY_LEDGER_REF}`,
126
+ ], { env: NO_PROMPT_ENV });
127
+ if (pushed.status !== 0 || pushed.error)
128
+ return "failed";
129
+ return await observeRemoteTip(input.cwd, input.endpoint, input.coordinates) === input.newTip
130
+ ? "published"
131
+ : "unconfirmed";
132
+ }
133
+ /**
134
+ * Internal adopted-remote convergence. The caller supplies the sole authority
135
+ * name explicitly; this owner never scans tracking refs or user-visible state.
136
+ */
137
+ export async function publishAdoptedRepositoryLedger(input) {
138
+ formatStructuralJoin(input.join);
139
+ const coordinates = await deriveHostGitCoordinates(input.cwd);
140
+ const initialLocalTip = await observeLocalTip(input.cwd);
141
+ let configured;
142
+ try {
143
+ configured = await resolveConfiguredRemote(input.cwd, input.remote);
144
+ }
145
+ catch (error) {
146
+ return {
147
+ status: "lag",
148
+ code: "REMOTE_CONFIGURATION_INVALID",
149
+ localTip: initialLocalTip,
150
+ remoteTip: null,
151
+ cause: error instanceof Error ? error.message : String(error),
152
+ };
153
+ }
154
+ let scratch;
155
+ try {
156
+ scratch = await prepareScratch({ cwd: input.cwd, coordinates });
157
+ }
158
+ catch (error) {
159
+ return {
160
+ status: "lag",
161
+ code: "REMOTE_OBSERVATION_FAILED",
162
+ localTip: initialLocalTip,
163
+ remoteTip: null,
164
+ cause: error instanceof Error ? error.message : String(error),
165
+ };
166
+ }
167
+ try {
168
+ let remoteObservation;
169
+ try {
170
+ remoteObservation = await observeStableRemoteInScratch(input.cwd, scratch, configured.publicationEndpoint, coordinates);
171
+ }
172
+ catch (error) {
173
+ return {
174
+ status: "lag",
175
+ code: "REMOTE_OBSERVATION_FAILED",
176
+ localTip: initialLocalTip,
177
+ remoteTip: null,
178
+ cause: error instanceof Error ? error.message : String(error),
179
+ };
180
+ }
181
+ if (remoteObservation.status === "changed") {
182
+ return {
183
+ status: "lag",
184
+ code: "REMOTE_OBSERVATION_CHANGED",
185
+ localTip: initialLocalTip,
186
+ remoteTip: remoteObservation.after,
187
+ cause: "adopted remote ledger changed during observation",
188
+ };
189
+ }
190
+ const remoteTip = remoteObservation.tip;
191
+ if (initialLocalTip === null && remoteTip === null) {
192
+ return { status: "current", localTip: null, remoteTip: null };
193
+ }
194
+ let local = null;
195
+ if (initialLocalTip !== null) {
196
+ const current = await readRepositoryLifecycle(input.cwd);
197
+ if (current.observedLedgerHead !== initialLocalTip) {
198
+ return { status: "refused", code: "LEDGER_LOCAL_CAS_CONFLICT", localTip: current.observedLedgerHead, remoteTip, cause: "local ledger changed during publication admission" };
199
+ }
200
+ const traversal = await readPinnedAcceptedTraversal(input.cwd, initialLocalTip) ?? await recoverPublicationTip(input.cwd, initialLocalTip);
201
+ const clean = cleanTip(initialLocalTip, traversal);
202
+ if (clean.status === "refused")
203
+ return { ...clean, localTip: initialLocalTip, remoteTip };
204
+ local = clean;
205
+ }
206
+ let remote = null;
207
+ if (remoteTip !== null) {
208
+ const clean = cleanTip(remoteTip, await recoverPublicationTip(scratch, remoteTip));
209
+ if (clean.status === "refused")
210
+ return { ...clean, localTip: initialLocalTip, remoteTip };
211
+ remote = clean;
212
+ }
213
+ if (initialLocalTip === remoteTip) {
214
+ return { status: "current", localTip: initialLocalTip, remoteTip };
215
+ }
216
+ if (remote !== null && local !== null) {
217
+ const admission = admitJoin(remote, local, input.join);
218
+ if (admission.status === "refused")
219
+ return admission;
220
+ }
221
+ if (remoteTip !== null) {
222
+ try {
223
+ if (await promoteRemoteClosure({
224
+ cwd: input.cwd,
225
+ endpoint: configured.publicationEndpoint,
226
+ coordinates,
227
+ expectedTip: remoteTip,
228
+ }) === "changed") {
229
+ return {
230
+ status: "lag",
231
+ code: "REMOTE_OBSERVATION_CHANGED",
232
+ localTip: initialLocalTip,
233
+ remoteTip,
234
+ cause: "adopted remote ledger changed before closure promotion",
235
+ };
236
+ }
237
+ await assertReadableCommitClosure(input.cwd, remoteTip);
238
+ }
239
+ catch (error) {
240
+ return {
241
+ status: "lag",
242
+ code: "REMOTE_CLOSURE_PROMOTION_FAILED",
243
+ localTip: initialLocalTip,
244
+ remoteTip,
245
+ cause: error instanceof Error ? error.message : String(error),
246
+ };
247
+ }
248
+ }
249
+ if (local === null && remote !== null) {
250
+ const transaction = await commitRefTransaction(input.cwd, [{
251
+ kind: "update",
252
+ ref: REPOSITORY_LEDGER_REF,
253
+ newOid: remote.head,
254
+ expectedOldOid: null,
255
+ }], coordinates.objectIdLength);
256
+ if (transaction.status === "refused") {
257
+ return {
258
+ status: "refused",
259
+ code: "LEDGER_LOCAL_CAS_CONFLICT",
260
+ localTip: await observeLocalTip(input.cwd),
261
+ remoteTip: remote.head,
262
+ cause: transaction.cause,
263
+ };
264
+ }
265
+ if (transaction.status === "indeterminate") {
266
+ return {
267
+ status: "indeterminate",
268
+ code: "LEDGER_LOCAL_CAS_INDETERMINATE",
269
+ localTip: await observeLocalTip(input.cwd),
270
+ remoteTip: remote.head,
271
+ cause: transaction.cause,
272
+ };
273
+ }
274
+ return { status: "seeded", localTip: remote.head, remoteTip: remote.head };
275
+ }
276
+ let publishTip = local.head;
277
+ let joinObjectId;
278
+ if (remote !== null) {
279
+ joinObjectId = await writeCommitObject({
280
+ cwd: input.cwd,
281
+ coordinates,
282
+ tree: coordinates.emptyTree,
283
+ parents: [remote.head, local.head],
284
+ author: { name: "Keiyaku", email: "keiyaku@localhost", date: input.join.at },
285
+ committer: { name: "Keiyaku", email: "keiyaku@localhost", date: input.join.at },
286
+ message: formatStructuralJoin(input.join),
287
+ });
288
+ const transaction = await commitRefTransaction(input.cwd, [{
289
+ kind: "update",
290
+ ref: REPOSITORY_LEDGER_REF,
291
+ newOid: joinObjectId,
292
+ expectedOldOid: local.head,
293
+ }], coordinates.objectIdLength);
294
+ if (transaction.status === "refused") {
295
+ return {
296
+ status: "refused",
297
+ code: "LEDGER_LOCAL_CAS_CONFLICT",
298
+ localTip: await observeLocalTip(input.cwd),
299
+ remoteTip: remote.head,
300
+ cause: transaction.cause,
301
+ };
302
+ }
303
+ if (transaction.status === "indeterminate") {
304
+ return {
305
+ status: "indeterminate",
306
+ code: "LEDGER_LOCAL_CAS_INDETERMINATE",
307
+ localTip: await observeLocalTip(input.cwd),
308
+ remoteTip: remote.head,
309
+ cause: transaction.cause,
310
+ };
311
+ }
312
+ publishTip = joinObjectId;
313
+ }
314
+ let publication;
315
+ try {
316
+ publication = await publishRemote({
317
+ cwd: input.cwd,
318
+ endpoint: configured.publicationEndpoint,
319
+ coordinates,
320
+ newTip: publishTip,
321
+ });
322
+ }
323
+ catch (error) {
324
+ return {
325
+ status: "lag",
326
+ code: "REMOTE_PUBLICATION_FAILED",
327
+ localTip: publishTip,
328
+ remoteTip,
329
+ cause: error instanceof Error ? error.message : String(error),
330
+ };
331
+ }
332
+ if (publication !== "published") {
333
+ return {
334
+ status: "lag",
335
+ code: publication === "failed" ? "REMOTE_PUBLICATION_FAILED" : "REMOTE_PUBLICATION_UNCONFIRMED",
336
+ localTip: publishTip,
337
+ remoteTip,
338
+ cause: publication === "failed"
339
+ ? "adopted remote rejected or could not complete ledger publication"
340
+ : "adopted remote did not read back the published ledger tip",
341
+ };
342
+ }
343
+ return {
344
+ status: "published",
345
+ localTip: publishTip,
346
+ remoteTip: publishTip,
347
+ ...(joinObjectId === undefined ? {} : { joinObjectId }),
348
+ };
349
+ }
350
+ finally {
351
+ await fs.rm(scratch, { recursive: true, force: true });
352
+ }
353
+ }