@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.
- package/README.md +50 -182
- package/build/.tsbuildinfo +1 -1
- package/build/agents/harness/control-types.js +18 -1
- package/build/agents/harness/index.js +2 -0
- package/build/agents/harness/outcome-error.js +81 -0
- package/build/agents/harness/projection.js +10 -7
- package/build/agents/harness/router.js +5 -1
- package/build/agents/providers/claude-agent-sdk/adapter.js +18 -4
- package/build/agents/providers/claude-agent-sdk/registration.js +11 -1
- package/build/agents/providers/claude-agent-sdk/session.js +19 -5
- package/build/agents/providers/codex-app-server/adapter.js +11 -6
- package/build/agents/providers/codex-app-server/events.js +67 -6
- package/build/agents/providers/codex-app-server/registration.js +11 -1
- package/build/agents/providers/opencode-sdk/adapter.js +8 -1
- package/build/agents/providers/opencode-sdk/events.js +24 -2
- package/build/agents/providers/opencode-sdk/registration.js +11 -1
- package/build/agents/providers/pi/checkpoint.js +9 -1
- package/build/agents/providers/pi/events.js +2 -0
- package/build/agents/providers/pi/registration.js +14 -1
- package/build/cli/commands/akuma/akuma/handler.js +1 -1
- package/build/cli/commands/akuma/akuma/meta.js +3 -3
- package/build/cli/commands/akuma/catalog.js +2 -2
- package/build/cli/commands/akuma/{view → show}/handler.js +5 -5
- package/build/cli/commands/akuma/{view → show}/meta.js +3 -3
- package/build/cli/commands/akuma.js +1 -1
- package/build/cli/commands/contract/amend/handler.js +5 -4
- package/build/cli/commands/contract/arc/handler.js +5 -4
- package/build/cli/commands/contract/audit/handler.js +2 -2
- package/build/cli/commands/contract/bind/handler.js +12 -3
- package/build/cli/commands/contract/bind/meta.js +45 -15
- package/build/cli/commands/contract/forfeit/handler.js +9 -5
- package/build/cli/commands/contract/log/handler.js +2 -2
- package/build/cli/commands/contract/petition/handler.js +34 -7
- package/build/cli/commands/contract/renew/handler.js +7 -7
- package/build/cli/commands/contract/renew/meta.js +3 -3
- package/build/cli/commands/metadata.js +10 -6
- package/build/cli/commands/projection/call/meta.js +1 -1
- package/build/cli/commands/projection/catalog.js +2 -0
- package/build/cli/commands/projection/history/handler.js +21 -0
- package/build/cli/commands/projection/history/meta.js +9 -0
- package/build/cli/commands/projection/shared.js +3 -4
- package/build/cli/commands/projection/status/handler.js +3 -3
- package/build/cli/commands/projection/wait/handler.js +20 -11
- package/build/cli/commands/task/add/handler.js +14 -5
- package/build/cli/commands/task/add/meta.js +2 -2
- package/build/cli/commands/task/catalog.js +4 -0
- package/build/cli/commands/task/done/handler.js +1 -4
- package/build/cli/commands/task/done/meta.js +1 -1
- package/build/cli/commands/task/drop/meta.js +1 -1
- package/build/cli/commands/task/hold/handler.js +3 -0
- package/build/cli/commands/task/hold/meta.js +8 -0
- package/build/cli/commands/task/log/handler.js +1 -1
- package/build/cli/commands/task/log/meta.js +2 -2
- package/build/cli/commands/task/resume/handler.js +3 -0
- package/build/cli/commands/task/resume/meta.js +8 -0
- package/build/cli/commands/task/shared.js +39 -14
- package/build/cli/commands/task/show/handler.js +1 -1
- package/build/cli/commands/task/show/meta.js +1 -1
- package/build/cli/commands/task/start/meta.js +1 -1
- package/build/cli/commands/task/stop/handler.js +1 -4
- package/build/cli/commands/task/stop/meta.js +1 -1
- package/build/cli/commands/task/update/handler.js +11 -3
- package/build/cli/commands/task/update/meta.js +3 -3
- package/build/cli/completion.js +3 -2
- package/build/cli/flags.js +51 -14
- package/build/cli/help.js +4 -1
- package/build/cli/index.js +40 -25
- package/build/cli/parse-flags.js +40 -7
- package/build/cli/parse-metadata.js +5 -2
- package/build/cli/parse-selectors.js +2 -3
- package/build/cli/parse.js +40 -6
- package/build/cli/projection-address.js +12 -10
- package/build/cli/render/amendment-warning.js +8 -0
- package/build/cli/render/arc.js +6 -2
- package/build/cli/render/audit.js +400 -81
- package/build/cli/render/kanshi.js +242 -79
- package/build/cli/render/lifecycle.js +56 -0
- package/build/cli/render/misc.js +24 -28
- package/build/cli/render/petition.js +5 -0
- package/build/cli/render/projection-activity.js +65 -29
- package/build/cli/render/projection-history.js +64 -0
- package/build/cli/render/shared.js +23 -9
- package/build/cli/render/status.js +13 -35
- package/build/cli/render/task.js +51 -26
- package/build/cli/render/terminal-failure.js +3 -1
- package/build/cli/render/wait.js +45 -69
- package/build/cli/subagent-guard.js +1 -1
- package/build/cli/types.js +1 -1
- package/build/config/env-keys.js +3 -1
- package/build/config/env.js +24 -1
- package/build/config/settings/schema.js +3 -1
- package/build/core/address-carrier.js +89 -0
- package/build/core/addressing.js +255 -196
- package/build/core/amend.js +115 -38
- package/build/core/amendment-criteria.js +17 -0
- package/build/core/amendment-warning.js +10 -0
- package/build/core/arc.js +184 -83
- package/build/core/audit/candidate.js +110 -9
- package/build/core/audit/coordinates.js +120 -65
- package/build/core/audit/evidence.js +19 -23
- package/build/core/audit/facade.js +34 -11
- package/build/core/audit/report.js +5 -5
- package/build/core/bind-reconciliation.js +390 -0
- package/build/core/bind-workspace.js +12 -20
- package/build/core/bind.js +242 -273
- package/build/core/call/call.js +1 -0
- package/build/core/call/context.js +46 -71
- package/build/core/call/prompt.js +6 -3
- package/build/core/context.js +49 -35
- package/build/core/contract-carrier-runtime.js +408 -0
- package/build/core/contract-carrier.js +270 -0
- package/build/core/contract-view.js +33 -27
- package/build/core/contract.js +5 -1
- package/build/core/derived-replay.js +207 -0
- package/build/core/draft.js +125 -57
- package/build/core/forfeit.js +113 -56
- package/build/core/identifier-slug.js +63 -13
- package/build/core/ids.js +4 -4
- package/build/core/lifecycle-history.js +35 -0
- package/build/core/lifecycle-recovery.js +117 -0
- package/build/core/lifecycle-runner.js +377 -0
- package/build/core/log.js +37 -11
- package/build/core/outcome-base.js +181 -0
- package/build/core/process-group.js +139 -0
- package/build/core/projection/generation/database.js +82 -7
- package/build/core/projection/generation/model.js +9 -36
- package/build/core/projection/generation/projection-generation-continuation.js +10 -22
- package/build/core/projection/generation/projection-generation-execution.js +13 -6
- package/build/core/projection/index.js +5 -4
- package/build/core/projection/projection-activity.js +29 -8
- package/build/core/projection/projection-alias.js +23 -10
- package/build/core/projection/projection-core.js +21 -7
- package/build/core/projection/projection-execution-observer.js +91 -39
- package/build/core/projection/projection-history.js +474 -0
- package/build/core/projection/projection-runner-lock.js +12 -0
- package/build/core/projection/projection-status-observation.js +365 -0
- package/build/core/projection/projection-status.js +35 -337
- package/build/core/projection/projection-terminal-failure.js +13 -8
- package/build/core/projection/projection-wait.js +7 -2
- package/build/core/projection/tell/launch-store.js +244 -0
- package/build/core/projection/tell/model.js +3 -3
- package/build/core/projection/tell/store.js +70 -118
- package/build/core/registry.js +22 -87
- package/build/core/renew-build.js +424 -0
- package/build/core/renew-plan.js +239 -0
- package/build/core/renew-rewrite.js +77 -0
- package/build/core/renew.js +295 -520
- package/build/core/repository-ledger/accepted-fold-read.js +19 -0
- package/build/core/repository-ledger/accepted-tail.js +116 -0
- package/build/core/repository-ledger/admission.js +38 -0
- package/build/core/repository-ledger/authoritative-transaction.js +1 -0
- package/build/core/repository-ledger/claim-evidence.js +147 -0
- package/build/core/repository-ledger/codec.js +297 -0
- package/build/core/repository-ledger/current-state-store.js +853 -0
- package/build/core/repository-ledger/fold-repository.js +375 -0
- package/build/core/repository-ledger/fold.js +248 -0
- package/build/core/repository-ledger/git-object-store.js +243 -0
- package/build/core/repository-ledger/history-read.js +15 -0
- package/build/core/repository-ledger/incremental-read.js +153 -0
- package/build/core/repository-ledger/index.js +15 -0
- package/build/core/repository-ledger/inventory-plan.js +75 -0
- package/build/core/repository-ledger/inventory.js +310 -0
- package/build/core/repository-ledger/publication-admission.js +125 -0
- package/build/core/repository-ledger/publication.js +353 -0
- package/build/core/repository-ledger/read-model.js +469 -0
- package/build/core/repository-ledger/transaction-membership.js +78 -0
- package/build/core/repository-ledger/traversal.js +404 -0
- package/build/core/repository-ledger/write-transaction.js +339 -0
- package/build/core/seal.js +168 -161
- package/build/core/settlement/claim-delivery.js +42 -215
- package/build/core/settlement/claim.js +235 -153
- package/build/core/settlement/index.js +4 -4
- package/build/core/settlement/petition-claim-gates.js +52 -33
- package/build/core/settlement/petition-forfeit.js +12 -5
- package/build/core/settlement/petition-head-guard.js +8 -5
- package/build/core/settlement/petition-preview.js +68 -56
- package/build/core/settlement/petition-window.js +50 -0
- package/build/core/settlement/petition.js +252 -131
- package/build/core/settlement/queue-read-model.js +72 -95
- package/build/core/settlement/queue-seat-allocation.js +35 -126
- package/build/core/settlement/queue.js +1 -1
- package/build/core/settlement/settlement.js +172 -80
- package/build/core/settlement/verdict.js +112 -66
- package/build/core/settlement/verification-coordination.js +305 -0
- package/build/core/settlement/verification-supervisor.js +275 -0
- package/build/core/settlement/verification.js +398 -31
- package/build/core/status/board.js +125 -127
- package/build/core/status/lifecycle.js +7 -80
- package/build/core/structured-query.js +23 -0
- package/build/core/target-ref.js +1 -1
- package/build/core/task/board.js +59 -24
- package/build/core/task/commands.js +181 -33
- package/build/core/task/coordinate.js +56 -0
- package/build/core/task/document.js +25 -9
- package/build/core/task/index.js +7 -4
- package/build/core/task/query.js +17 -27
- package/build/core/task/settlement-git.js +164 -179
- package/build/core/task/settlement-policy.js +15 -11
- package/build/core/task/source-board.js +31 -13
- package/build/core/task/task-bind-preparation.js +193 -0
- package/build/core/task/task-contract.js +102 -193
- package/build/core/task/task-file-transaction.js +171 -0
- package/build/core/task/task-git-runtime.js +76 -14
- package/build/core/task/task-git-store.js +68 -169
- package/build/core/task/task-store-repository.js +13 -6
- package/build/core/task/task-worktree.js +6 -33
- package/build/core/task/task.js +1 -1
- package/build/core/task/tree.js +3 -3
- package/build/core/task/validation.js +4 -3
- package/build/core/transcripts.js +93 -1
- package/build/core/worktree-bootstrap.js +44 -36
- package/build/core/worktree-path.js +210 -77
- package/build/flow-error.js +7 -7
- package/build/generated/version.js +2 -2
- package/build/git/core.js +76 -13
- package/build/git/refs.js +168 -46
- package/build/git/streaming-batch.js +73 -13
- package/package.json +1 -1
- package/skills/keiyaku/SKILL.md +1 -1
- package/skills/keiyaku-akuma/SKILL.md +3 -3
- package/skills/keiyaku-task/SKILL.md +4 -2
- package/skills/keiyaku-workflow/SKILL.md +88 -203
- package/build/core/entry.js +0 -305
- package/build/core/ledger-batch.js +0 -194
- package/build/core/ledger.js +0 -84
- package/build/core/projection/leash.js +0 -87
- package/build/core/ref-log.js +0 -119
- package/build/core/renew-session.js +0 -128
- package/build/core/status/ledger-batch.js +0 -1
- 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
|
+
}
|