@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.
- package/README.md +1 -1
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku/SKILL.md +3 -0
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +3 -0
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +3 -6
- package/build/src/akuma/akuma-errors.d.ts +6 -0
- package/build/src/akuma/akuma-errors.js +9 -0
- package/build/src/akuma/akuma-handle.d.ts +39 -0
- package/build/src/akuma/akuma-handle.js +263 -0
- package/build/src/akuma/akuma-observe.d.ts +19 -0
- package/build/src/akuma/akuma-observe.js +74 -0
- package/build/src/akuma/akuma-product-symbols.d.ts +1 -0
- package/build/src/akuma/akuma-product-symbols.js +1 -0
- package/build/src/akuma/akuma-product.d.ts +18 -0
- package/build/src/akuma/akuma-product.js +154 -0
- package/build/src/akuma/akuma.d.ts +37 -81
- package/build/src/akuma/akuma.js +39 -447
- package/build/src/akuma/allowed.d.ts +1 -0
- package/build/src/akuma/allowed.js +6 -0
- package/build/src/akuma/archetype.js +8 -5
- package/build/src/akuma/body-supervisor.d.ts +26 -0
- package/build/src/akuma/body-supervisor.js +89 -0
- package/build/src/akuma/body.d.ts +45 -4
- package/build/src/akuma/body.js +145 -35
- package/build/src/akuma/coordinate.js +17 -7
- package/build/src/akuma/heart/facts.js +1 -1
- package/build/src/akuma/heart/index.d.ts +1 -1
- package/build/src/akuma/heart/index.js +2 -4
- package/build/src/akuma/heart/request-authority.js +4 -4
- package/build/src/akuma/heart/request-rows.js +27 -16
- package/build/src/akuma/heart/rows.js +79 -41
- package/build/src/akuma/heart/soul.js +1 -1
- package/build/src/akuma/heart/storage.d.ts +1 -0
- package/build/src/akuma/heart/storage.js +76 -11
- package/build/src/akuma/heart/tells.js +35 -18
- package/build/src/akuma/heart/timeline.js +19 -11
- package/build/src/akuma/identity.d.ts +1 -0
- package/build/src/akuma/identity.js +1 -0
- package/build/src/akuma/index.d.ts +3 -3
- package/build/src/akuma/index.js +1 -1
- package/build/src/akuma/nuke.js +106 -14
- package/build/src/akuma/projection-read.d.ts +17 -0
- package/build/src/akuma/projection-read.js +135 -0
- package/build/src/akuma/projection.d.ts +1 -16
- package/build/src/akuma/projection.js +77 -154
- package/build/src/akuma/provider-recipe.js +11 -5
- package/build/src/akuma/provider.js +105 -62
- package/build/src/akuma/providers/acp/config.js +5 -6
- package/build/src/akuma/providers/acp/core.js +17 -10
- package/build/src/akuma/providers/acp/events.js +38 -29
- package/build/src/akuma/providers/acp/index.js +13 -9
- package/build/src/akuma/providers/claude/events.js +8 -12
- package/build/src/akuma/providers/claude/index.d.ts +1 -0
- package/build/src/akuma/providers/claude/index.js +55 -26
- package/build/src/akuma/providers/claude/input.js +6 -2
- package/build/src/akuma/providers/codex-app-server/events.js +61 -36
- package/build/src/akuma/providers/codex-app-server/index.js +25 -13
- package/build/src/akuma/providers/grok-build/index.js +22 -25
- package/build/src/akuma/providers/index.js +2 -18
- package/build/src/akuma/providers/opencode-sdk/events.js +32 -18
- package/build/src/akuma/providers/opencode-sdk/index.js +26 -17
- package/build/src/akuma/providers/opencode-sdk/session.js +21 -5
- package/build/src/akuma/providers/pi/events.js +26 -19
- package/build/src/akuma/providers/pi/index.js +58 -40
- package/build/src/akuma/publication.js +9 -9
- package/build/src/akuma/request-execution.d.ts +6 -0
- package/build/src/akuma/request-execution.js +86 -0
- package/build/src/akuma/request-serve.d.ts +12 -1
- package/build/src/akuma/request-serve.js +19 -122
- package/build/src/akuma/request-wire.d.ts +2 -2
- package/build/src/akuma/request-wire.js +75 -102
- package/build/src/akuma/requests.js +2 -2
- package/build/src/akuma/{body-turn.d.ts → turn-drive.d.ts} +2 -25
- package/build/src/akuma/{body-turn.js → turn-drive.js} +20 -103
- package/build/src/akuma-body.js +6 -5
- package/build/src/body/amend.d.ts +4 -1
- package/build/src/body/amend.js +14 -6
- package/build/src/body/decode.js +2 -4
- package/build/src/body/envelope.js +2 -4
- package/build/src/body/region.d.ts +1 -2
- package/build/src/body/region.js +2 -70
- package/build/src/body/render.js +17 -12
- package/build/src/body/shape.js +1 -7
- package/build/src/cli/accepted.d.ts +1 -1
- package/build/src/cli/accepted.js +8 -1
- package/build/src/cli/commands/akuma-invoke.js +18 -6
- package/build/src/cli/commands/akuma.d.ts +0 -6
- package/build/src/cli/commands/akuma.js +11 -24
- package/build/src/cli/commands/amend.d.ts +2 -2
- package/build/src/cli/commands/amend.js +2 -4
- package/build/src/cli/commands/bind.d.ts +4 -4
- package/build/src/cli/commands/bind.js +16 -6
- package/build/src/cli/commands/contract-invoke.d.ts +25 -0
- package/build/src/cli/commands/contract-invoke.js +193 -0
- package/build/src/cli/commands/contract.d.ts +109 -10
- package/build/src/cli/commands/contract.js +339 -16
- package/build/src/cli/commands/install.d.ts +1 -1
- package/build/src/cli/commands/install.js +23 -15
- package/build/src/cli/commands/task-invoke.js +187 -67
- package/build/src/cli/commands/task-query.js +48 -24
- package/build/src/cli/commands/task.js +150 -38
- package/build/src/cli/coordinates.js +2 -4
- package/build/src/cli/invoke.js +92 -208
- package/build/src/cli/main.js +4 -2
- package/build/src/cli/parse.d.ts +3 -90
- package/build/src/cli/parse.js +27 -233
- package/build/src/cli/render/akuma-activity.d.ts +38 -0
- package/build/src/cli/render/akuma-activity.js +362 -0
- package/build/src/cli/render/akuma-tool-command.js +6 -7
- package/build/src/cli/render/akuma-tool.js +10 -8
- package/build/src/cli/render/akuma.d.ts +1 -1
- package/build/src/cli/render/akuma.js +61 -353
- package/build/src/cli/render/audit.js +5 -15
- package/build/src/cli/render/board.d.ts +1 -0
- package/build/src/cli/render/board.js +17 -0
- package/build/src/cli/render/catalog.js +81 -8
- package/build/src/cli/render/contract-history.d.ts +2 -0
- package/build/src/cli/render/contract-history.js +83 -0
- package/build/src/cli/render/contract-observation.d.ts +10 -0
- package/build/src/cli/render/contract-observation.js +58 -0
- package/build/src/cli/render/contract.d.ts +1 -2
- package/build/src/cli/render/contract.js +41 -142
- package/build/src/cli/render/kanshi.js +239 -215
- package/build/src/cli/render/receipt.js +2 -9
- package/build/src/cli/render/refusal.js +10 -15
- package/build/src/cli/render/region.js +22 -6
- package/build/src/cli/render/settings.js +4 -4
- package/build/src/cli/render/task.js +34 -14
- package/build/src/cli/render/terminal.js +16 -5
- package/build/src/cli/result.d.ts +3 -3
- package/build/src/cli/runtime.d.ts +6 -1
- package/build/src/cli/runtime.js +84 -63
- package/build/src/cli/selectors.js +2 -4
- package/build/src/cli/usage.js +6 -5
- package/build/src/contract-worktree.d.ts +1 -23
- package/build/src/contract-worktree.js +79 -155
- package/build/src/coordination/durable-file.js +7 -3
- package/build/src/coordination/sqlite-transaction-lock.js +29 -12
- package/build/src/core/facts/codec.js +7 -3
- package/build/src/core/facts/types.d.ts +1 -1
- package/build/src/core/subject.js +16 -9
- package/build/src/core/verbs/abandon.d.ts +1 -1
- package/build/src/core/verbs/abandon.js +1 -1
- package/build/src/core/verbs/amend.d.ts +1 -1
- package/build/src/core/verbs/amend.js +7 -7
- package/build/src/core/verbs/attestation.js +4 -1
- package/build/src/core/verbs/bind.d.ts +1 -1
- package/build/src/core/verbs/bind.js +1 -1
- package/build/src/core/verbs/placement.d.ts +1 -1
- package/build/src/core/verbs/placement.js +10 -8
- package/build/src/dispatch/index.js +8 -6
- package/build/src/duration.js +5 -1
- package/build/src/git/admission.js +5 -3
- package/build/src/git/hooks.d.ts +8 -0
- package/build/src/git/hooks.js +63 -14
- package/build/src/git/identity.js +1 -4
- package/build/src/git/integration.d.ts +2 -3
- package/build/src/git/integration.js +32 -39
- package/build/src/git/nuke.d.ts +1 -1
- package/build/src/git/nuke.js +110 -57
- package/build/src/git/observe.d.ts +13 -1
- package/build/src/git/observe.js +51 -44
- package/build/src/git/process.js +4 -2
- package/build/src/git/read-observation.js +10 -8
- package/build/src/git/reconcile.d.ts +22 -2
- package/build/src/git/reconcile.js +38 -274
- package/build/src/git/repository.d.ts +2 -0
- package/build/src/git/repository.js +13 -22
- package/build/src/git/scratch.d.ts +8 -5
- package/build/src/git/scratch.js +29 -2
- package/build/src/git/target-placement.d.ts +9 -10
- package/build/src/git/target-placement.js +59 -62
- package/build/src/git/tender.js +13 -46
- package/build/src/git/terminal-reconcile.d.ts +21 -0
- package/build/src/git/terminal-reconcile.js +278 -0
- package/build/src/git/terminal-seal.js +15 -12
- package/build/src/git/tree.js +5 -2
- package/build/src/git/workspace.d.ts +24 -2
- package/build/src/git/workspace.js +120 -16
- package/build/src/identity/coordinates.js +3 -1
- package/build/src/identity/selector.js +6 -3
- package/build/src/kanshi/fleet.d.ts +6 -0
- package/build/src/kanshi/fleet.js +27 -0
- package/build/src/kanshi/index.d.ts +1 -1
- package/build/src/kanshi/read.js +60 -48
- package/build/src/kanshi/report.d.ts +11 -23
- package/build/src/kanshi/select.js +25 -24
- package/build/src/library/address.d.ts +2 -1
- package/build/src/library/address.js +7 -8
- package/build/src/library/akuma-creation.js +20 -12
- package/build/src/library/audit.d.ts +0 -1
- package/build/src/library/audit.js +1 -2
- package/build/src/library/bind.d.ts +53 -5
- package/build/src/library/bind.js +98 -22
- package/build/src/library/catalog.d.ts +1 -0
- package/build/src/library/catalog.js +6 -3
- package/build/src/library/configuration.js +3 -1
- package/build/src/library/continuation.d.ts +15 -4
- package/build/src/library/continuation.js +24 -16
- package/build/src/library/contract-bind.d.ts +26 -0
- package/build/src/library/contract-bind.js +106 -0
- package/build/src/library/contract-operations.d.ts +77 -0
- package/build/src/library/contract-operations.js +130 -0
- package/build/src/library/contract-types.d.ts +95 -0
- package/build/src/library/contract-types.js +1 -0
- package/build/src/library/contract.d.ts +19 -154
- package/build/src/library/contract.js +46 -261
- package/build/src/library/fleet.d.ts +1 -1
- package/build/src/library/fleet.js +19 -11
- package/build/src/library/input.d.ts +2 -0
- package/build/src/library/input.js +14 -0
- package/build/src/library/keiyaku.d.ts +8 -7
- package/build/src/library/keiyaku.js +3 -3
- package/build/src/library/nuke.js +14 -5
- package/build/src/library/reconcile.d.ts +9 -4
- package/build/src/library/reconcile.js +30 -24
- package/build/src/library/refusal.d.ts +13 -5
- package/build/src/library/refusal.js +7 -0
- package/build/src/library/region.d.ts +8 -7
- package/build/src/library/region.js +31 -11
- package/build/src/library/repo.js +2 -2
- package/build/src/markdown/lex.js +9 -2
- package/build/src/markdown/parse.js +11 -7
- package/build/src/markdown/query.js +4 -2
- package/build/src/protocol/amend.js +3 -1
- package/build/src/protocol/attempt.d.ts +7 -3
- package/build/src/protocol/attempt.js +9 -5
- package/build/src/protocol/audit.d.ts +1 -1
- package/build/src/protocol/audit.js +4 -14
- package/build/src/protocol/bind.d.ts +19 -6
- package/build/src/protocol/bind.js +28 -13
- package/build/src/protocol/completion.d.ts +0 -1
- package/build/src/protocol/completion.js +1 -3
- package/build/src/protocol/deliver.d.ts +1 -3
- package/build/src/protocol/deliver.js +15 -39
- package/build/src/protocol/intent.d.ts +1 -0
- package/build/src/protocol/intent.js +9 -7
- package/build/src/protocol/operations.d.ts +3 -7
- package/build/src/protocol/operations.js +5 -3
- package/build/src/protocol/placement.d.ts +0 -1
- package/build/src/protocol/placement.js +6 -6
- package/build/src/protocol/read/observation.d.ts +11 -0
- package/build/src/protocol/read/observation.js +37 -0
- package/build/src/protocol/read/status.d.ts +23 -12
- package/build/src/protocol/read/status.js +90 -72
- package/build/src/protocol/reconcile.d.ts +1 -0
- package/build/src/protocol/reconcile.js +2 -3
- package/build/src/protocol/reintegrate.js +1 -1
- package/build/src/protocol/review.d.ts +0 -1
- package/build/src/protocol/review.js +15 -22
- package/build/src/protocol/run.d.ts +1 -0
- package/build/src/protocol/run.js +4 -5
- package/build/src/runtime/proc/launch.d.ts +33 -0
- package/build/src/runtime/proc/launch.js +98 -0
- package/build/src/runtime/proc/line-rpc.js +9 -3
- package/build/src/runtime/proc/run.d.ts +12 -6
- package/build/src/runtime/proc/run.js +78 -21
- package/build/src/runtime/proc/stdio.js +7 -10
- package/build/src/settings.js +6 -2
- package/build/src/settlement/holder.js +13 -10
- package/build/src/settlement/settle.js +39 -6
- package/build/src/task/board.js +12 -6
- package/build/src/task/compose.js +85 -22
- package/build/src/task/context.js +21 -8
- package/build/src/task/document.js +46 -10
- package/build/src/task/identity.js +5 -2
- package/build/src/task/index.d.ts +0 -1
- package/build/src/task/index.js +119 -34
- package/build/src/task/input.js +29 -7
- package/build/src/task/mutation.js +61 -19
- package/build/src/task/operations.d.ts +6 -1
- package/build/src/task/operations.js +83 -29
- package/build/src/task/query.js +55 -26
- package/build/src/task/store.d.ts +3 -1
- package/build/src/task/store.js +81 -17
- package/build/src/verification/execution.js +14 -11
- package/build/src/workspace-place.js +19 -7
- package/build/src/world.js +16 -6
- package/package.json +8 -3
|
@@ -41,8 +41,9 @@ function decode(path, bytes) {
|
|
|
41
41
|
if (keys.length !== 3 || keys.some((key) => !["akuId", "contractId", "dispatchedAt"].includes(key))) {
|
|
42
42
|
corruption(`Dispatch has invalid fields: ${path}`);
|
|
43
43
|
}
|
|
44
|
-
if (typeof record.akuId !== "string" ||
|
|
45
|
-
|
|
44
|
+
if (typeof record.akuId !== "string" ||
|
|
45
|
+
typeof record.contractId !== "string" ||
|
|
46
|
+
typeof record.dispatchedAt !== "string") {
|
|
46
47
|
corruption(`Dispatch has invalid values: ${path}`);
|
|
47
48
|
}
|
|
48
49
|
let akuId;
|
|
@@ -81,8 +82,7 @@ export async function readDispatch(repository, value) {
|
|
|
81
82
|
return await dispatchFromSnapshot(repository, await readGitPaths(repository, [path]), akuId);
|
|
82
83
|
}
|
|
83
84
|
export async function readDispatchesAt(observation) {
|
|
84
|
-
const entries = [...observation.snapshot.paths]
|
|
85
|
-
.filter(([path, entry]) => path.startsWith(DISPATCH_PREFIX) && entry.type === "blob");
|
|
85
|
+
const entries = [...observation.snapshot.paths].filter(([path, entry]) => path.startsWith(DISPATCH_PREFIX) && entry.type === "blob");
|
|
86
86
|
const blobs = await observation.readBlobs(entries.map(([, entry]) => entry.oid));
|
|
87
87
|
const dispatches = [];
|
|
88
88
|
const seen = new Set();
|
|
@@ -151,11 +151,13 @@ export async function publishDispatch(input) {
|
|
|
151
151
|
message: `dispatch ${akuId}`,
|
|
152
152
|
at: intended.dispatchedAt,
|
|
153
153
|
});
|
|
154
|
-
const publication = await updateRefsAtomically(input.repository, [
|
|
154
|
+
const publication = await updateRefsAtomically(input.repository, [
|
|
155
|
+
{
|
|
155
156
|
ref: GIT_REF,
|
|
156
157
|
newOid: commit,
|
|
157
158
|
expectedOid: snapshot.commit,
|
|
158
|
-
}
|
|
159
|
+
},
|
|
160
|
+
]);
|
|
159
161
|
if (publication.kind === "published")
|
|
160
162
|
return { kind: "dispatched", dispatch: intended };
|
|
161
163
|
const observed = await observedPublication(input.repository, akuId, owner);
|
package/build/src/duration.js
CHANGED
|
@@ -14,7 +14,11 @@ export function parseDuration(value) {
|
|
|
14
14
|
return { kind: "parsed", milliseconds: Number(milliseconds) };
|
|
15
15
|
}
|
|
16
16
|
export function formatDuration(milliseconds) {
|
|
17
|
-
for (const [unit, multiplier] of [
|
|
17
|
+
for (const [unit, multiplier] of [
|
|
18
|
+
["h", 3_600_000],
|
|
19
|
+
["m", 60_000],
|
|
20
|
+
["s", 1_000],
|
|
21
|
+
]) {
|
|
18
22
|
if (milliseconds >= multiplier && milliseconds % multiplier === 0)
|
|
19
23
|
return `${milliseconds / multiplier}${unit}`;
|
|
20
24
|
}
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { decodeJournal, encodeEntry
|
|
1
|
+
import { decodeJournal, encodeEntry } from "../core/facts/codec.js";
|
|
2
2
|
import { GIT_FORMAT_BYTES, GIT_FORMAT_PATH, GIT_REF, updateGitTreeFromFrozenDirectories, updateRefsAtomically, writeBlob, writeCommit, } from "./repository.js";
|
|
3
3
|
import { contractJournalPath, contractJournalPaths, gitObjectIdForSnapshot, mintContractHead, mintSnapshotId, } from "./identity.js";
|
|
4
4
|
import { validPath } from "./tree.js";
|
|
@@ -95,11 +95,13 @@ async function publishOffer(repository, admission, target, changes, assertions)
|
|
|
95
95
|
{ ref: GIT_REF, newOid: gitObjectIdForSnapshot(gitCommit), expectedOid: snapshot.commit },
|
|
96
96
|
...(target === null
|
|
97
97
|
? []
|
|
98
|
-
: [
|
|
98
|
+
: [
|
|
99
|
+
{
|
|
99
100
|
ref: target.target,
|
|
100
101
|
newOid: gitObjectIdForSnapshot(target.newOid),
|
|
101
102
|
expectedOid: gitObjectIdForSnapshot(target.expectedOid),
|
|
102
|
-
}
|
|
103
|
+
},
|
|
104
|
+
]),
|
|
103
105
|
], assertions);
|
|
104
106
|
}
|
|
105
107
|
export async function admit(repository, offer, admission, assertions = []) {
|
package/build/src/git/hooks.d.ts
CHANGED
|
@@ -29,6 +29,14 @@ export type WorktreeHookLag = Readonly<{
|
|
|
29
29
|
}>;
|
|
30
30
|
type HookPhase = "create" | "destroy";
|
|
31
31
|
export declare function hookMarkerPath(administrationDirectory: string): string;
|
|
32
|
+
export type WorktreeHookMarkerObservation = Readonly<{
|
|
33
|
+
kind: "absent" | "pending" | "ok";
|
|
34
|
+
}> | Readonly<{
|
|
35
|
+
kind: "failed";
|
|
36
|
+
diagnostic: string;
|
|
37
|
+
}>;
|
|
38
|
+
/** Read the durable hook marker without executing commands or taking locks. */
|
|
39
|
+
export declare function observeWorktreeHookMarker(administrationDirectory: string): Promise<WorktreeHookMarkerObservation>;
|
|
32
40
|
export type HookCommandRun = Readonly<{
|
|
33
41
|
kind: "ok";
|
|
34
42
|
}> | Readonly<{
|
package/build/src/git/hooks.js
CHANGED
|
@@ -24,7 +24,9 @@ function decodeCommand(value, coordinate) {
|
|
|
24
24
|
}
|
|
25
25
|
if (value.argv[0].trim().length === 0)
|
|
26
26
|
throw new Error(`${coordinate}.argv[0] must be nonblank`);
|
|
27
|
-
if (!Number.isSafeInteger(value.timeoutMs) ||
|
|
27
|
+
if (!Number.isSafeInteger(value.timeoutMs) ||
|
|
28
|
+
value.timeoutMs < 1 ||
|
|
29
|
+
value.timeoutMs > 2_147_483_647) {
|
|
28
30
|
throw new Error(`${coordinate}.timeoutMs is invalid`);
|
|
29
31
|
}
|
|
30
32
|
return { argv: value.argv, timeoutMs: value.timeoutMs };
|
|
@@ -40,10 +42,19 @@ function decodeFailure(value, coordinate) {
|
|
|
40
42
|
switch (value.kind) {
|
|
41
43
|
case "exit":
|
|
42
44
|
exactKeys(value, ["kind", "code", "stdout", "stderr", "truncated"], coordinate);
|
|
43
|
-
if (!Number.isInteger(value.code) ||
|
|
45
|
+
if (!Number.isInteger(value.code) ||
|
|
46
|
+
typeof value.stdout !== "string" ||
|
|
47
|
+
typeof value.stderr !== "string" ||
|
|
48
|
+
typeof value.truncated !== "boolean") {
|
|
44
49
|
throw new Error(`${coordinate} is invalid`);
|
|
45
50
|
}
|
|
46
|
-
return {
|
|
51
|
+
return {
|
|
52
|
+
kind: "exit",
|
|
53
|
+
code: value.code,
|
|
54
|
+
stdout: value.stdout,
|
|
55
|
+
stderr: value.stderr,
|
|
56
|
+
truncated: value.truncated,
|
|
57
|
+
};
|
|
47
58
|
case "timeout":
|
|
48
59
|
case "unknown-exit":
|
|
49
60
|
exactKeys(value, ["kind"], coordinate);
|
|
@@ -76,7 +87,11 @@ function decodeProgress(value, commands, coordinate) {
|
|
|
76
87
|
if (!Number.isInteger(value.command) || value.command < 0 || value.command >= commands) {
|
|
77
88
|
throw new Error(`${coordinate}.command is invalid`);
|
|
78
89
|
}
|
|
79
|
-
return {
|
|
90
|
+
return {
|
|
91
|
+
status: "failed",
|
|
92
|
+
command: value.command,
|
|
93
|
+
failure: decodeFailure(value.failure, `${coordinate}.failure`),
|
|
94
|
+
};
|
|
80
95
|
}
|
|
81
96
|
throw new Error(`${coordinate}.status is invalid`);
|
|
82
97
|
}
|
|
@@ -114,6 +129,28 @@ async function readMarker(administrationDirectory) {
|
|
|
114
129
|
throw error;
|
|
115
130
|
}
|
|
116
131
|
}
|
|
132
|
+
function hookFailureDiagnostic(phase, progress) {
|
|
133
|
+
const failure = progress.failure;
|
|
134
|
+
const detail = failure.kind === "exit"
|
|
135
|
+
? `exit=${failure.code}`
|
|
136
|
+
: failure.kind === "spawn-error"
|
|
137
|
+
? failure.diagnostic
|
|
138
|
+
: failure.kind;
|
|
139
|
+
return `worktree-hook-failed ${phase} command=${progress.command} ${detail}`;
|
|
140
|
+
}
|
|
141
|
+
/** Read the durable hook marker without executing commands or taking locks. */
|
|
142
|
+
export async function observeWorktreeHookMarker(administrationDirectory) {
|
|
143
|
+
const marker = await readMarker(administrationDirectory);
|
|
144
|
+
if (marker === null)
|
|
145
|
+
return { kind: "absent" };
|
|
146
|
+
if (marker.create.status === "failed")
|
|
147
|
+
return { kind: "failed", diagnostic: hookFailureDiagnostic("create", marker.create) };
|
|
148
|
+
if (marker.destroy.status === "failed")
|
|
149
|
+
return { kind: "failed", diagnostic: hookFailureDiagnostic("destroy", marker.destroy) };
|
|
150
|
+
if (marker.create.status === "pending" || marker.destroy.status === "pending")
|
|
151
|
+
return { kind: "pending" };
|
|
152
|
+
return { kind: "ok" };
|
|
153
|
+
}
|
|
117
154
|
async function writeMarker(administrationDirectory, marker) {
|
|
118
155
|
const path = hookMarkerPath(administrationDirectory);
|
|
119
156
|
await mkdir(dirname(path), { recursive: true });
|
|
@@ -129,13 +166,15 @@ function freshMarker(commands, createPending) {
|
|
|
129
166
|
}
|
|
130
167
|
function failedOutcome(outcome) {
|
|
131
168
|
if (outcome.kind === "terminal") {
|
|
132
|
-
return outcome.code === 0
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
169
|
+
return outcome.code === 0
|
|
170
|
+
? null
|
|
171
|
+
: {
|
|
172
|
+
kind: "exit",
|
|
173
|
+
code: outcome.code,
|
|
174
|
+
stdout: outcome.stdout,
|
|
175
|
+
stderr: outcome.stderr,
|
|
176
|
+
truncated: outcome.truncated,
|
|
177
|
+
};
|
|
139
178
|
}
|
|
140
179
|
return outcome;
|
|
141
180
|
}
|
|
@@ -239,7 +278,9 @@ async function executePendingCommand(input) {
|
|
|
239
278
|
const failure = result.kind === "failed" ? result.failure : null;
|
|
240
279
|
const next = input.command + 1;
|
|
241
280
|
await writeMarker(input.administrationDirectory, withProgress(marker, input.phase, failure === null
|
|
242
|
-
? next === marker.commands[input.phase].length
|
|
281
|
+
? next === marker.commands[input.phase].length
|
|
282
|
+
? { status: "ok" }
|
|
283
|
+
: { status: "pending", next }
|
|
243
284
|
: { status: "failed", command: input.command, failure }));
|
|
244
285
|
}
|
|
245
286
|
finally {
|
|
@@ -280,7 +321,13 @@ async function runPhase(worktree, administrationDirectory, hooks, phase, retryHo
|
|
|
280
321
|
return null;
|
|
281
322
|
if (progress.status === "failed") {
|
|
282
323
|
if (!retryFailure) {
|
|
283
|
-
return {
|
|
324
|
+
return {
|
|
325
|
+
kind: "worktree-hook-failed",
|
|
326
|
+
phase,
|
|
327
|
+
path: worktree,
|
|
328
|
+
command: progress.command,
|
|
329
|
+
failure: progress.failure,
|
|
330
|
+
};
|
|
284
331
|
}
|
|
285
332
|
retryFailure = false;
|
|
286
333
|
await writeMarker(administrationDirectory, withProgress(marker, phase, { status: "pending", next: progress.command }));
|
|
@@ -299,7 +346,9 @@ export function runCreateHooks(worktree, administrationDirectory, hooks, retryHo
|
|
|
299
346
|
export function runDestroyHooks(worktree, administrationDirectory, hooks, retryHooks) {
|
|
300
347
|
return runPhase(worktree, administrationDirectory, hooks, "destroy", retryHooks);
|
|
301
348
|
}
|
|
302
|
-
if (process.argv[1] !== undefined &&
|
|
349
|
+
if (process.argv[1] !== undefined &&
|
|
350
|
+
fileURLToPath(import.meta.url) === process.argv[1] &&
|
|
351
|
+
process.argv[2] === "--run-hook") {
|
|
303
352
|
const encoded = process.argv[3];
|
|
304
353
|
if (encoded === undefined)
|
|
305
354
|
throw new Error("Hook runner input is missing");
|
|
@@ -23,10 +23,7 @@ export function contractJournalPath(contract, journalClass = "active") {
|
|
|
23
23
|
return `contracts/${journalClass}/${contractJournalSuffix(contract)}`;
|
|
24
24
|
}
|
|
25
25
|
export function contractJournalPaths(contract) {
|
|
26
|
-
return [
|
|
27
|
-
contractJournalPath(contract, "active"),
|
|
28
|
-
contractJournalPath(contract, "terminal"),
|
|
29
|
-
];
|
|
26
|
+
return [contractJournalPath(contract, "active"), contractJournalPath(contract, "terminal")];
|
|
30
27
|
}
|
|
31
28
|
export function gitObjectId(value, label = "Git object ID") {
|
|
32
29
|
if (!GIT_OBJECT_ID.test(value))
|
|
@@ -3,6 +3,8 @@ import type { ChangeId, ContractCoordinates, ContractId, SnapshotId } from "../c
|
|
|
3
3
|
import { type GitObjectId } from "./identity.js";
|
|
4
4
|
import { type GitRepository } from "./process.js";
|
|
5
5
|
import type { DeliveryCommitMetadata, TenderCapture } from "./tender.js";
|
|
6
|
+
import { workspaceMergeStatePresent } from "./workspace.js";
|
|
7
|
+
export { workspaceMergeStatePresent };
|
|
6
8
|
type IntegrationTender = Pick<TenderCapture, "head" | "tree">;
|
|
7
9
|
declare const REQUIRED_GIT: "2.38";
|
|
8
10
|
export type IntegrationPreparationRefusal = Readonly<{
|
|
@@ -30,8 +32,6 @@ export declare function worktreeChangeId(repository: GitRepository, input: Integ
|
|
|
30
32
|
export declare function materializeIntegrationSnapshot(repository: GitRepository, tree: GitObjectId, parent: SnapshotId, metadata: DeliveryCommitMetadata): Promise<SnapshotId>;
|
|
31
33
|
export declare function persistedTender(repository: GitRepository, snapshot: SnapshotId): Promise<IntegrationTender>;
|
|
32
34
|
export declare function materializeReintegrationSnapshot(repository: GitRepository, tree: GitObjectId, parent: SnapshotId, template: SnapshotId): Promise<SnapshotId>;
|
|
33
|
-
/** True when the appointed workspace already has Git MERGE_HEAD. */
|
|
34
|
-
export declare function workspaceMergeStatePresent(repository: GitRepository, workspace: string): Promise<boolean>;
|
|
35
35
|
/** Project the already-judged conflict as `git merge --no-commit <targetHead>`. */
|
|
36
36
|
export declare function materializeJudgedConflict(repository: GitRepository, workspace: string, targetHead: SnapshotId): Promise<void>;
|
|
37
37
|
export declare function planIntegration(repository: GitRepository, input: IntegrationCoordinates, tender: IntegrationTender, requireBranchesToBeUpToDate: boolean): Promise<Preparation<IntegrationPlan, Readonly<{
|
|
@@ -48,4 +48,3 @@ export type DeliveryDiffScope = Readonly<{
|
|
|
48
48
|
export declare function readDeliveryScope(repository: GitRepository, predecessor: SnapshotId, candidate: SnapshotId, includePaths: boolean): Promise<DeliveryDiffScope>;
|
|
49
49
|
/** Read a recorded integration pair's patch, or null when Git no longer has it. */
|
|
50
50
|
export declare function readDeliveryDiff(repository: GitRepository, predecessor: SnapshotId, candidate: SnapshotId): Promise<string | null>;
|
|
51
|
-
export {};
|
|
@@ -1,7 +1,9 @@
|
|
|
1
1
|
import { AuthorityCorruptionError } from "../core/facts/errors.js";
|
|
2
2
|
import { gitObjectId, gitObjectIdForSnapshot, mintChangeId, mintSnapshotId } from "./identity.js";
|
|
3
|
-
import { decodeGitNameOnly, decodeGitNumstat, readRef
|
|
4
|
-
import { GitPlumbingError, runGit, runGitWithEnvironment
|
|
3
|
+
import { decodeGitNameOnly, decodeGitNumstat, readRef } from "./repository.js";
|
|
4
|
+
import { GitPlumbingError, runGit, runGitWithEnvironment } from "./process.js";
|
|
5
|
+
import { workspaceMergeStatePresent } from "./workspace.js";
|
|
6
|
+
export { workspaceMergeStatePresent };
|
|
5
7
|
const REQUIRED_GIT = "2.38";
|
|
6
8
|
async function runAllowingNonzero(repository, args, input) {
|
|
7
9
|
try {
|
|
@@ -16,12 +18,18 @@ async function runAllowingNonzero(repository, args, input) {
|
|
|
16
18
|
/** Mint the one worktree-content identity shared by review and delivery. */
|
|
17
19
|
export async function worktreeChangeId(repository, input, tender) {
|
|
18
20
|
const patch = await runGit(repository, [
|
|
19
|
-
"-c",
|
|
20
|
-
"
|
|
21
|
-
"-c",
|
|
22
|
-
"
|
|
23
|
-
"-c",
|
|
24
|
-
"
|
|
21
|
+
"-c",
|
|
22
|
+
"core.quotePath=false",
|
|
23
|
+
"-c",
|
|
24
|
+
"core.abbrev=40",
|
|
25
|
+
"-c",
|
|
26
|
+
"diff.algorithm=myers",
|
|
27
|
+
"-c",
|
|
28
|
+
"diff.renames=false",
|
|
29
|
+
"-c",
|
|
30
|
+
"diff.indentHeuristic=false",
|
|
31
|
+
"-c",
|
|
32
|
+
"diff.suppressBlankEmpty=false",
|
|
25
33
|
"diff",
|
|
26
34
|
"--no-ext-diff",
|
|
27
35
|
"--no-textconv",
|
|
@@ -53,7 +61,9 @@ export async function materializeIntegrationSnapshot(repository, tree, parent, m
|
|
|
53
61
|
GIT_COMMITTER_EMAIL: metadata.identity.email,
|
|
54
62
|
GIT_AUTHOR_DATE: metadata.at,
|
|
55
63
|
GIT_COMMITTER_DATE: metadata.at,
|
|
56
|
-
}))
|
|
64
|
+
}))
|
|
65
|
+
.toString("utf8")
|
|
66
|
+
.trim();
|
|
57
67
|
return mintSnapshotId(commit);
|
|
58
68
|
}
|
|
59
69
|
export async function persistedTender(repository, snapshot) {
|
|
@@ -80,12 +90,9 @@ export async function materializeReintegrationSnapshot(repository, tree, parent,
|
|
|
80
90
|
const message = raw.subarray(separator + 2);
|
|
81
91
|
let fields;
|
|
82
92
|
try {
|
|
83
|
-
const formatted = (await runGit(repository, [
|
|
84
|
-
"
|
|
85
|
-
"
|
|
86
|
-
"--format=%an%x00%ae%x00%aI%x00%cn%x00%ce%x00%cI",
|
|
87
|
-
templateObject,
|
|
88
|
-
])).toString("utf8").replace(/\n$/u, "");
|
|
93
|
+
const formatted = (await runGit(repository, ["show", "-s", "--format=%an%x00%ae%x00%aI%x00%cn%x00%ce%x00%cI", templateObject]))
|
|
94
|
+
.toString("utf8")
|
|
95
|
+
.replace(/\n$/u, "");
|
|
89
96
|
fields = formatted.split("\0");
|
|
90
97
|
}
|
|
91
98
|
catch (error) {
|
|
@@ -105,7 +112,9 @@ export async function materializeReintegrationSnapshot(repository, tree, parent,
|
|
|
105
112
|
GIT_COMMITTER_NAME: committerName,
|
|
106
113
|
GIT_COMMITTER_EMAIL: committerEmail,
|
|
107
114
|
GIT_COMMITTER_DATE: committerDate,
|
|
108
|
-
}))
|
|
115
|
+
}))
|
|
116
|
+
.toString("utf8")
|
|
117
|
+
.trim();
|
|
109
118
|
return mintSnapshotId(commit);
|
|
110
119
|
}
|
|
111
120
|
async function isAncestor(repository, ancestor, descendant) {
|
|
@@ -192,26 +201,6 @@ async function mergedTree(repository, contractId, base, targetHead, tenderTree)
|
|
|
192
201
|
message: "git merge-tree --write-tree failed",
|
|
193
202
|
});
|
|
194
203
|
}
|
|
195
|
-
/** True when the appointed workspace already has Git MERGE_HEAD. */
|
|
196
|
-
export async function workspaceMergeStatePresent(repository, workspace) {
|
|
197
|
-
const result = await runAllowingNonzero(repository, [
|
|
198
|
-
"-C",
|
|
199
|
-
workspace,
|
|
200
|
-
"rev-parse",
|
|
201
|
-
"-q",
|
|
202
|
-
"--verify",
|
|
203
|
-
"MERGE_HEAD",
|
|
204
|
-
]);
|
|
205
|
-
if (result.status === 0)
|
|
206
|
-
return true;
|
|
207
|
-
if (result.status === 1)
|
|
208
|
-
return false;
|
|
209
|
-
throw new GitPlumbingError({
|
|
210
|
-
stderr: result.stderr,
|
|
211
|
-
status: result.status,
|
|
212
|
-
message: "git rev-parse --verify MERGE_HEAD failed",
|
|
213
|
-
});
|
|
214
|
-
}
|
|
215
204
|
/** Project the already-judged conflict as `git merge --no-commit <targetHead>`. */
|
|
216
205
|
export async function materializeJudgedConflict(repository, workspace, targetHead) {
|
|
217
206
|
const result = await runAllowingNonzero(repository, [
|
|
@@ -289,7 +278,11 @@ export async function planIntegration(repository, input, tender, requireBranches
|
|
|
289
278
|
}
|
|
290
279
|
async function deliverySnapshotAvailability(repository, predecessor, candidate) {
|
|
291
280
|
const objects = [gitObjectIdForSnapshot(predecessor), gitObjectIdForSnapshot(candidate)];
|
|
292
|
-
const types = (await runGit(repository, ["cat-file", "--batch-check=%(objectname) %(objecttype)"], `${objects.join("\n")}\n`))
|
|
281
|
+
const types = (await runGit(repository, ["cat-file", "--batch-check=%(objectname) %(objecttype)"], `${objects.join("\n")}\n`))
|
|
282
|
+
.toString("ascii")
|
|
283
|
+
.trimEnd()
|
|
284
|
+
.split("\n")
|
|
285
|
+
.map((record) => record.split(" ")[1]);
|
|
293
286
|
if (types.includes("missing"))
|
|
294
287
|
return "unavailable";
|
|
295
288
|
if (types.some((type) => type !== "commit")) {
|
|
@@ -322,7 +315,7 @@ export async function readDeliveryScope(repository, predecessor, candidate, incl
|
|
|
322
315
|
}
|
|
323
316
|
/** Read a recorded integration pair's patch, or null when Git no longer has it. */
|
|
324
317
|
export async function readDeliveryDiff(repository, predecessor, candidate) {
|
|
325
|
-
if (await deliverySnapshotAvailability(repository, predecessor, candidate) === "unavailable")
|
|
318
|
+
if ((await deliverySnapshotAvailability(repository, predecessor, candidate)) === "unavailable")
|
|
326
319
|
return null;
|
|
327
320
|
try {
|
|
328
321
|
return (await runGit(repository, [
|
|
@@ -334,7 +327,7 @@ export async function readDeliveryDiff(repository, predecessor, candidate) {
|
|
|
334
327
|
])).toString("utf8");
|
|
335
328
|
}
|
|
336
329
|
catch (error) {
|
|
337
|
-
if (await deliverySnapshotAvailability(repository, predecessor, candidate) === "unavailable")
|
|
330
|
+
if ((await deliverySnapshotAvailability(repository, predecessor, candidate)) === "unavailable")
|
|
338
331
|
return null;
|
|
339
332
|
throw error;
|
|
340
333
|
}
|
package/build/src/git/nuke.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
import type { WorldRoot } from "../world.js";
|
|
2
|
-
export declare function nukeGit(world: WorldRoot): Promise<void>;
|
|
2
|
+
export declare function nukeGit(world: WorldRoot, gitPath?: string): Promise<void>;
|
package/build/src/git/nuke.js
CHANGED
|
@@ -1,52 +1,90 @@
|
|
|
1
|
-
import { access } from "node:fs/promises";
|
|
2
|
-
import {
|
|
3
|
-
import { nukeEmptyPlaceAuthority, readPlaceRegister, releaseManagedWorktrees
|
|
1
|
+
import { access, lstat, realpath, rm } from "node:fs/promises";
|
|
2
|
+
import { isAbsolute, relative, sep } from "node:path";
|
|
3
|
+
import { nukeEmptyPlaceAuthority, readPlaceRegister, releaseManagedWorktrees } from "../workspace-place.js";
|
|
4
4
|
import { nukeWorktreeHookResidue } from "./hooks.js";
|
|
5
5
|
import { runGit } from "./process.js";
|
|
6
|
-
import { NoGitWorldError, registeredWorktrees, repositoryAt, worktreeGitDirectory } from "./repository.js";
|
|
6
|
+
import { CANDIDATE_PIN_REF_NAMESPACE, DELIVERY_REF_NAMESPACE, GIT_REF, MIGRATION_CANDIDATE_PIN_REF_NAMESPACE, MIGRATION_DELIVERY_REF_NAMESPACE, NoGitWorldError, readRef, registeredWorktrees, repositoryAt, worktreeGitDirectory, } from "./repository.js";
|
|
7
7
|
import { worktreePath } from "./workspace.js";
|
|
8
8
|
async function managedCustody(repository) {
|
|
9
9
|
const register = await readPlaceRegister(repository);
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
try {
|
|
17
|
-
await access(path);
|
|
18
|
-
}
|
|
19
|
-
catch {
|
|
20
|
-
entries.push({ contract: appointment.contract, path });
|
|
21
|
-
continue;
|
|
22
|
-
}
|
|
23
|
-
throw new Error(`managed Place path has foreign custody: ${path}`);
|
|
24
|
-
}
|
|
25
|
-
if (registered.branch !== null)
|
|
26
|
-
throw new Error(`managed Place path has a branch: ${path}`);
|
|
27
|
-
entries.push({ contract: appointment.contract, path });
|
|
28
|
-
}
|
|
29
|
-
const refs = (await runGit(repository, [
|
|
30
|
-
"for-each-ref", "--format=%(refname)", "refs/heads/keiyaku-delivery", "refs/heads/keiyaku-candidate",
|
|
31
|
-
])).toString("utf8").split("\n").filter((ref) => ref.length > 0);
|
|
32
|
-
const state = await runGit(repository, ["show-ref", "--verify", "--quiet", "refs/heads/keiyaku-state"])
|
|
33
|
-
.then(() => true, () => false);
|
|
34
|
-
return { entries, refs, state };
|
|
10
|
+
return {
|
|
11
|
+
entries: register.appointments.map((appointment) => ({
|
|
12
|
+
contract: appointment.contract,
|
|
13
|
+
path: worktreePath(repository, appointment.place),
|
|
14
|
+
})),
|
|
15
|
+
};
|
|
35
16
|
}
|
|
36
|
-
|
|
37
|
-
const
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
17
|
+
function underCommonDirectory(commonDirectory, administrationDirectory) {
|
|
18
|
+
const suffix = relative(commonDirectory, administrationDirectory);
|
|
19
|
+
return suffix.length > 0 && suffix !== ".." && !suffix.startsWith(`..${sep}`) && !isAbsolute(suffix);
|
|
20
|
+
}
|
|
21
|
+
async function unregisteredResidueBelongsToRepository(repository, path) {
|
|
22
|
+
let physical;
|
|
23
|
+
try {
|
|
24
|
+
physical = await lstat(path);
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
if (error.code === "ENOENT")
|
|
28
|
+
return true;
|
|
29
|
+
throw error;
|
|
30
|
+
}
|
|
31
|
+
if (!physical.isDirectory() || physical.isSymbolicLink())
|
|
32
|
+
return false;
|
|
33
|
+
let administrationDirectory;
|
|
34
|
+
try {
|
|
35
|
+
administrationDirectory = await worktreeGitDirectory(repository, path);
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return false;
|
|
39
|
+
}
|
|
40
|
+
try {
|
|
41
|
+
const [common, administration] = await Promise.all([
|
|
42
|
+
realpath(repository.commonDirectory),
|
|
43
|
+
realpath(administrationDirectory),
|
|
44
|
+
]);
|
|
45
|
+
return underCommonDirectory(common, administration);
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
if (error.code === "ENOENT")
|
|
49
|
+
return false;
|
|
50
|
+
throw error;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
53
|
+
async function removeUnregisteredResidue(repository, entry) {
|
|
54
|
+
let present = true;
|
|
55
|
+
try {
|
|
56
|
+
await access(entry.path);
|
|
57
|
+
}
|
|
58
|
+
catch (error) {
|
|
59
|
+
if (error.code === "ENOENT")
|
|
60
|
+
present = false;
|
|
61
|
+
else
|
|
62
|
+
throw error;
|
|
63
|
+
}
|
|
64
|
+
if (!present)
|
|
65
|
+
return true;
|
|
66
|
+
if (!(await unregisteredResidueBelongsToRepository(repository, entry.path))) {
|
|
46
67
|
throw new Error(`managed Place path has foreign custody: ${entry.path}`);
|
|
47
68
|
}
|
|
69
|
+
const administrationDirectory = await worktreeGitDirectory(repository, entry.path);
|
|
70
|
+
await nukeWorktreeHookResidue(administrationDirectory);
|
|
71
|
+
await rm(entry.path, { recursive: true, force: true });
|
|
72
|
+
try {
|
|
73
|
+
await access(entry.path);
|
|
74
|
+
}
|
|
75
|
+
catch (error) {
|
|
76
|
+
if (error.code === "ENOENT")
|
|
77
|
+
return true;
|
|
78
|
+
throw error;
|
|
79
|
+
}
|
|
80
|
+
throw new Error(`managed Place worktree remains present: ${entry.path}`);
|
|
81
|
+
}
|
|
82
|
+
async function removeManagedWorktree(repository, entry) {
|
|
83
|
+
const registered = (await registeredWorktrees(repository)).find((candidate) => candidate.path === entry.path);
|
|
84
|
+
if (registered === undefined)
|
|
85
|
+
return await removeUnregisteredResidue(repository, entry);
|
|
48
86
|
if (registered.branch !== null)
|
|
49
|
-
|
|
87
|
+
return false;
|
|
50
88
|
await nukeWorktreeHookResidue(await worktreeGitDirectory(repository, entry.path));
|
|
51
89
|
await runGit(repository, ["worktree", "remove", "--force", entry.path]);
|
|
52
90
|
if ((await registeredWorktrees(repository)).some((candidate) => candidate.path === entry.path)) {
|
|
@@ -55,38 +93,53 @@ async function removeManagedWorktree(repository, entry) {
|
|
|
55
93
|
try {
|
|
56
94
|
await access(entry.path);
|
|
57
95
|
}
|
|
58
|
-
catch {
|
|
59
|
-
|
|
96
|
+
catch (error) {
|
|
97
|
+
if (error.code === "ENOENT")
|
|
98
|
+
return true;
|
|
99
|
+
throw error;
|
|
60
100
|
}
|
|
61
101
|
throw new Error(`managed Place worktree remains present: ${entry.path}`);
|
|
62
102
|
}
|
|
63
|
-
async function
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
103
|
+
async function deleteRefAt(repository, ref, expectedOid) {
|
|
104
|
+
await runGit(repository, ["update-ref", "--no-deref", "-d", ref, expectedOid]);
|
|
105
|
+
}
|
|
106
|
+
async function removeOwnedRefs(repository) {
|
|
107
|
+
const roots = [
|
|
108
|
+
DELIVERY_REF_NAMESPACE,
|
|
109
|
+
CANDIDATE_PIN_REF_NAMESPACE,
|
|
110
|
+
MIGRATION_DELIVERY_REF_NAMESPACE,
|
|
111
|
+
MIGRATION_CANDIDATE_PIN_REF_NAMESPACE,
|
|
112
|
+
];
|
|
113
|
+
for (const root of roots) {
|
|
114
|
+
const refs = (await runGit(repository, ["for-each-ref", "--format=%(refname)", root]))
|
|
115
|
+
.toString("utf8")
|
|
116
|
+
.split("\n")
|
|
117
|
+
.filter((ref) => ref.length > root.length && ref.startsWith(`${root}/`));
|
|
118
|
+
for (const ref of refs) {
|
|
119
|
+
const oid = await readRef(repository, ref);
|
|
120
|
+
if (oid !== null)
|
|
121
|
+
await deleteRefAt(repository, ref, oid);
|
|
122
|
+
}
|
|
68
123
|
}
|
|
69
124
|
}
|
|
70
|
-
export async function nukeGit(world) {
|
|
125
|
+
export async function nukeGit(world, gitPath = "git") {
|
|
71
126
|
let repository;
|
|
72
127
|
try {
|
|
73
|
-
repository = await repositoryAt(world);
|
|
128
|
+
repository = await repositoryAt(world, gitPath);
|
|
74
129
|
}
|
|
75
130
|
catch (error) {
|
|
76
131
|
if (error instanceof NoGitWorldError)
|
|
77
132
|
return;
|
|
78
133
|
throw error;
|
|
79
134
|
}
|
|
135
|
+
const state = await readRef(repository, GIT_REF);
|
|
136
|
+
if (state !== null)
|
|
137
|
+
await deleteRefAt(repository, GIT_REF, state);
|
|
80
138
|
const custody = await managedCustody(repository);
|
|
81
139
|
for (const entry of custody.entries) {
|
|
82
|
-
await removeManagedWorktree(repository, entry)
|
|
83
|
-
|
|
140
|
+
if (await removeManagedWorktree(repository, entry))
|
|
141
|
+
await releaseManagedWorktrees(repository, [entry.contract]);
|
|
84
142
|
}
|
|
85
|
-
await nukeHereAppointments(repository);
|
|
86
143
|
await nukeEmptyPlaceAuthority(repository);
|
|
87
|
-
await removeOwnedRefs(repository
|
|
88
|
-
if (custody.state) {
|
|
89
|
-
const oid = (await runGit(repository, ["rev-parse", "--verify", "refs/heads/keiyaku-state"])).toString("utf8").trim();
|
|
90
|
-
await runGit(repository, ["update-ref", "--no-deref", "-d", "refs/heads/keiyaku-state", oid]);
|
|
91
|
-
}
|
|
144
|
+
await removeOwnedRefs(repository);
|
|
92
145
|
}
|
|
@@ -34,11 +34,23 @@ export type BindCoordinatesObservation = Readonly<{
|
|
|
34
34
|
target?: string;
|
|
35
35
|
branch: string | null;
|
|
36
36
|
}>;
|
|
37
|
+
export type UnbornHeadObservation = Readonly<{
|
|
38
|
+
kind: "unborn-head";
|
|
39
|
+
branch: string | null;
|
|
40
|
+
}>;
|
|
41
|
+
export type BindTargetSelection = Readonly<{
|
|
42
|
+
kind: "explicit";
|
|
43
|
+
target: string;
|
|
44
|
+
}> | Readonly<{
|
|
45
|
+
kind: "current-branch";
|
|
46
|
+
}> | Readonly<{
|
|
47
|
+
kind: "targetless";
|
|
48
|
+
}>;
|
|
37
49
|
export declare function normalizeTargetBranch(repository: GitRepository, input: string): Promise<string | null>;
|
|
38
50
|
/** Read one worktree's attached branch, or null for detached HEAD. */
|
|
39
51
|
export declare function currentBranch(repository: GitRepository, path?: string): Promise<string | null>;
|
|
40
52
|
/** Observe bind's tender start and optional reward target without creating persistent state. */
|
|
41
|
-
export declare function observeBindCoordinates(repository: GitRepository,
|
|
53
|
+
export declare function observeBindCoordinates(repository: GitRepository, selection?: BindTargetSelection): Promise<BindCoordinatesObservation | UnbornHeadObservation | null>;
|
|
42
54
|
export declare function observeActiveContractWorld(observation: GitReadObservation): Promise<ActiveContractWorldObservation>;
|
|
43
55
|
export declare function observeContractWorld(observation: GitReadObservation, requested?: readonly ContractId[]): Promise<ContractWorldObservation>;
|
|
44
56
|
export declare function observeContractsForAdmissionAt(repository: GitRepository, channel: GitDecodeChannel, ids: readonly ContractId[], selection?: GitTreeSelection): Promise<GitDecisionObservation>;
|