@astrosheep/keiyaku 4.5.7 → 4.5.8
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 +10 -0
- package/build/integrations/marketplace/plugins/keiyaku/.claude-plugin/plugin.json +1 -1
- package/build/integrations/marketplace/plugins/keiyaku/.codex-plugin/plugin.json +1 -1
- package/build/integrations/marketplace/plugins/keiyaku/opencode.js +3 -2
- package/build/integrations/marketplace/plugins/keiyaku/package.json +1 -1
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku/SKILL.md +10 -9
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +22 -1
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-babysit/SKILL.md +35 -96
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +28 -49
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-task/SKILL.md +21 -15
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +148 -89
- package/build/src/akuma/abort.d.ts +2 -1
- package/build/src/akuma/abort.js +6 -23
- package/build/src/akuma/akuma-handle.js +4 -2
- package/build/src/akuma/akuma-observe.d.ts +2 -0
- package/build/src/akuma/akuma-observe.js +1 -0
- package/build/src/akuma/akuma-product.js +9 -7
- package/build/src/akuma/akuma.d.ts +372 -9
- package/build/src/akuma/akuma.js +31 -1
- package/build/src/akuma/allowed.d.ts +1 -1
- package/build/src/akuma/allowed.js +1 -0
- package/build/src/akuma/body.d.ts +6 -4
- package/build/src/akuma/body.js +5 -3
- package/build/src/akuma/call-request.d.ts +80 -0
- package/build/src/akuma/call-request.js +211 -0
- package/build/src/akuma/heart/facts.d.ts +6 -78
- package/build/src/akuma/heart/index.d.ts +1 -1
- package/build/src/akuma/heart/request-authority.d.ts +5 -4
- package/build/src/akuma/heart/request-authority.js +20 -34
- package/build/src/akuma/heart/request-rows.js +12 -23
- package/build/src/akuma/heart/schema.d.ts +1 -1
- package/build/src/akuma/heart/schema.js +5 -13
- package/build/src/akuma/index.d.ts +1 -1
- package/build/src/akuma/index.js +1 -1
- package/build/src/akuma/projection-read.d.ts +1 -0
- package/build/src/akuma/projection-read.js +8 -1
- package/build/src/akuma/projection.d.ts +856 -137
- package/build/src/akuma/projection.js +190 -0
- package/build/src/akuma/provider.d.ts +30 -3
- package/build/src/akuma/provider.js +104 -0
- package/build/src/akuma/providers/acp/core.d.ts +2 -2
- package/build/src/akuma/providers/acp/core.js +13 -6
- package/build/src/akuma/providers/acp/index.js +5 -4
- package/build/src/akuma/providers/claude/index.d.ts +3 -3
- package/build/src/akuma/providers/claude/index.js +16 -5
- package/build/src/akuma/providers/codex-app-server/events.js +1 -1
- package/build/src/akuma/providers/codex-app-server/index.js +18 -6
- package/build/src/akuma/providers/grok-build/index.js +5 -4
- package/build/src/akuma/providers/opencode-sdk/index.js +66 -25
- package/build/src/akuma/providers/opencode-sdk/session.d.ts +3 -2
- package/build/src/akuma/providers/opencode-sdk/session.js +28 -11
- package/build/src/akuma/providers/pi/index.js +42 -14
- package/build/src/akuma/request-lifecycle.d.ts +3 -9
- package/build/src/akuma/request-lifecycle.js +4 -4
- package/build/src/akuma/request-rendezvous.d.ts +26 -0
- package/build/src/akuma/request-rendezvous.js +100 -0
- package/build/src/akuma/request-serve.d.ts +5 -65
- package/build/src/akuma/request-serve.js +81 -208
- package/build/src/akuma/request-wire.d.ts +109 -115
- package/build/src/akuma/request-wire.js +63 -318
- package/build/src/akuma/requests.d.ts +19 -47
- package/build/src/akuma/requests.js +51 -107
- package/build/src/akuma/turn-drive.d.ts +5 -3
- package/build/src/akuma/turn-drive.js +32 -10
- package/build/src/akuma-body.d.ts +7 -2
- package/build/src/akuma-body.js +68 -46
- package/build/src/cli/accepted.d.ts +1 -1
- package/build/src/cli/accepted.js +2 -2
- package/build/src/cli/commands/akuma-invoke.d.ts +2 -0
- package/build/src/cli/commands/akuma-invoke.js +17 -9
- package/build/src/cli/commands/akuma.js +7 -7
- package/build/src/cli/commands/contract-invoke.d.ts +3 -2
- package/build/src/cli/commands/contract-invoke.js +26 -19
- package/build/src/cli/commands/contract.d.ts +13 -13
- package/build/src/cli/commands/contract.js +32 -17
- package/build/src/cli/commands/install.d.ts +1 -1
- package/build/src/cli/commands/install.js +1 -1
- package/build/src/cli/commands/task-invoke.d.ts +3 -0
- package/build/src/cli/commands/task-invoke.js +23 -140
- package/build/src/cli/commands/task.js +54 -20
- package/build/src/cli/invoke.js +39 -25
- package/build/src/cli/main.js +2 -1
- package/build/src/cli/parse.d.ts +2 -2
- package/build/src/cli/parse.js +37 -22
- package/build/src/cli/render/akuma-activity.d.ts +4 -1
- package/build/src/cli/render/akuma-activity.js +45 -30
- package/build/src/cli/render/akuma-tool.d.ts +5 -1
- package/build/src/cli/render/akuma.js +5 -9
- package/build/src/cli/render/audit.js +1 -1
- package/build/src/cli/render/catalog.js +80 -21
- package/build/src/cli/render/contract-observation.d.ts +2 -0
- package/build/src/cli/render/contract-observation.js +11 -0
- package/build/src/cli/render/contract.js +25 -65
- package/build/src/cli/render/kanshi-akuma.d.ts +8 -0
- package/build/src/cli/render/kanshi-akuma.js +111 -0
- package/build/src/cli/render/kanshi.js +108 -213
- package/build/src/cli/render/receipt.d.ts +1 -2
- package/build/src/cli/render/receipt.js +76 -26
- package/build/src/cli/render/refusal.js +2 -10
- package/build/src/cli/render/region.js +5 -2
- package/build/src/cli/render/settings.d.ts +1 -1
- package/build/src/cli/render/settings.js +27 -8
- package/build/src/cli/render/task.js +22 -5
- package/build/src/cli/render/terminal.d.ts +28 -0
- package/build/src/cli/render/terminal.js +65 -0
- package/build/src/cli/result.d.ts +3 -3
- package/build/src/cli/runtime.js +3 -1
- package/build/src/cli/selectors.d.ts +2 -1
- package/build/src/cli/selectors.js +4 -3
- package/build/src/cli/square-edge.js +120 -36
- package/build/src/cli/usage.js +2 -1
- package/build/src/contract-guidance.d.ts +5 -0
- package/build/src/contract-guidance.js +121 -0
- package/build/src/contract-worktree.d.ts +0 -1
- package/build/src/contract-worktree.js +32 -83
- package/build/src/coordination/sqlite-transaction-lock.d.ts +1 -0
- package/build/src/coordination/sqlite-transaction-lock.js +5 -0
- package/build/src/core/facts/codec.d.ts +2 -0
- package/build/src/core/facts/codec.js +4 -0
- package/build/src/core/verbs/placement.d.ts +6 -1
- package/build/src/core/verbs/placement.js +5 -3
- package/build/src/dispatch/index.d.ts +0 -2
- package/build/src/dispatch/index.js +54 -55
- package/build/src/git/admission.js +2 -2
- package/build/src/git/hooks.d.ts +9 -15
- package/build/src/git/hooks.js +23 -317
- package/build/src/git/nuke.d.ts +2 -1
- package/build/src/git/nuke.js +36 -18
- package/build/src/git/private-state-seat.d.ts +12 -0
- package/build/src/git/private-state-seat.js +39 -0
- package/build/src/git/process.d.ts +6 -0
- package/build/src/git/process.js +19 -7
- package/build/src/git/read-observation.js +29 -20
- package/build/src/git/reconcile.d.ts +11 -0
- package/build/src/git/reconcile.js +64 -11
- package/build/src/git/repository.d.ts +6 -2
- package/build/src/git/repository.js +8 -0
- package/build/src/git/target-placement.d.ts +1 -0
- package/build/src/git/target-placement.js +5 -0
- package/build/src/git/tender.d.ts +1 -0
- package/build/src/git/terminal-reconcile.d.ts +1 -1
- package/build/src/git/terminal-reconcile.js +22 -20
- package/build/src/git/workspace.d.ts +14 -0
- package/build/src/git/workspace.js +44 -0
- package/build/src/kanshi/index.d.ts +1 -1
- package/build/src/kanshi/read.js +16 -16
- package/build/src/kanshi/report.d.ts +2 -2
- package/build/src/library/address.d.ts +9 -3
- package/build/src/library/address.js +3 -2
- package/build/src/library/akuma-creation.d.ts +4 -3
- package/build/src/library/akuma-creation.js +19 -13
- package/build/src/library/audit.d.ts +1 -1
- package/build/src/library/audit.js +5 -3
- package/build/src/library/catalog.d.ts +3 -1
- package/build/src/library/catalog.js +20 -6
- package/build/src/library/composition.d.ts +371 -0
- package/build/src/library/composition.js +28 -0
- package/build/src/library/configuration.js +8 -2
- package/build/src/library/continuation.js +66 -30
- package/build/src/library/contract-bind.js +10 -2
- package/build/src/library/contract-forwarding-reconciliation-result.d.ts +96 -0
- package/build/src/library/contract-forwarding-reconciliation-result.js +83 -0
- package/build/src/library/contract-forwarding-result.d.ts +6723 -0
- package/build/src/library/contract-forwarding-result.js +521 -0
- package/build/src/library/contract-forwarding.d.ts +72 -0
- package/build/src/library/contract-forwarding.js +125 -0
- package/build/src/library/contract-handle.d.ts +36 -0
- package/build/src/library/contract-handle.js +313 -0
- package/build/src/library/contract-operations.d.ts +1044 -67
- package/build/src/library/contract-operations.js +190 -118
- package/build/src/library/contract.d.ts +11 -32
- package/build/src/library/contract.js +16 -289
- package/build/src/library/fleet-result.d.ts +1454 -0
- package/build/src/library/fleet-result.js +96 -0
- package/build/src/library/fleet.d.ts +112 -54
- package/build/src/library/fleet.js +211 -71
- package/build/src/library/input.d.ts +2 -0
- package/build/src/library/input.js +4 -0
- package/build/src/library/keiyaku.d.ts +371 -20
- package/build/src/library/keiyaku.js +8 -21
- package/build/src/library/mutation.d.ts +3 -3
- package/build/src/library/mutation.js +5 -9
- package/build/src/library/nuke.d.ts +1 -1
- package/build/src/library/nuke.js +4 -3
- package/build/src/library/reconcile.d.ts +4 -0
- package/build/src/library/reconcile.js +2 -0
- package/build/src/library/refusal.d.ts +0 -9
- package/build/src/library/refusal.js +0 -7
- package/build/src/protocol/amend.js +56 -50
- package/build/src/protocol/attempt.d.ts +2 -0
- package/build/src/protocol/attempt.js +8 -1
- package/build/src/protocol/completion.js +7 -0
- package/build/src/protocol/deliver.js +6 -2
- package/build/src/protocol/operations.d.ts +4 -1
- package/build/src/protocol/operations.js +5 -2
- package/build/src/protocol/placement.d.ts +1 -0
- package/build/src/protocol/placement.js +52 -38
- package/build/src/protocol/read/observation.d.ts +1 -4
- package/build/src/protocol/read/observation.js +2 -15
- package/build/src/protocol/reintegrate.js +62 -58
- package/build/src/protocol/review.js +5 -0
- package/build/src/protocol/run.js +17 -13
- package/build/src/runtime/proc/run.d.ts +8 -0
- package/build/src/runtime/proc/run.js +27 -0
- package/build/src/runtime/proc/termination.js +26 -22
- package/build/src/runtime/proc/windows-launch.exe +0 -0
- package/build/src/settlement/holder.d.ts +2 -1
- package/build/src/settlement/holder.js +15 -4
- package/build/src/settlement/settle.js +99 -33
- package/build/src/task/board.d.ts +68 -27
- package/build/src/task/board.js +31 -1
- package/build/src/task/catalog.d.ts +4 -0
- package/build/src/task/catalog.js +23 -0
- package/build/src/task/compose-language.js +33 -7
- package/build/src/task/compose-parser.d.ts +1 -1
- package/build/src/task/compose-parser.js +1 -1
- package/build/src/task/compose.js +2 -0
- package/build/src/task/index.d.ts +12 -4
- package/build/src/task/index.js +97 -16
- package/build/src/task/mutation-result.d.ts +923 -0
- package/build/src/task/mutation-result.js +140 -0
- package/build/src/task/mutation.d.ts +552 -28
- package/build/src/task/mutation.js +304 -97
- package/build/src/task/operations.d.ts +1 -4
- package/build/src/task/operations.js +0 -6
- package/build/src/task/public.d.ts +2 -0
- package/build/src/task/public.js +1 -0
- package/build/src/workspace-place.d.ts +7 -2
- package/build/src/workspace-place.js +34 -24
- package/build/src/world.d.ts +1 -0
- package/build/src/world.js +11 -0
- package/package.json +8 -6
- package/build/src/akuma/request-execution.d.ts +0 -8
- package/build/src/akuma/request-execution.js +0 -98
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { spawn } from "node:child_process";
|
|
2
1
|
import { AuthorityCorruptionError } from "../core/facts/errors.js";
|
|
2
|
+
import { spawnCancellableProcess } from "../runtime/proc/run.js";
|
|
3
3
|
import { gitObjectId } from "./identity.js";
|
|
4
4
|
import { parseTreeObject, validPath } from "./tree.js";
|
|
5
5
|
import { GIT_FORMAT_BYTES, GIT_FORMAT_PATH, GIT_REF, readRef } from "./repository.js";
|
|
@@ -36,11 +36,18 @@ function streamCursor(stream) {
|
|
|
36
36
|
};
|
|
37
37
|
return { line, exact };
|
|
38
38
|
}
|
|
39
|
+
async function batchObjects(oids, object) {
|
|
40
|
+
const unique = [...new Set(oids)];
|
|
41
|
+
for (const oid of unique)
|
|
42
|
+
gitObjectId(oid, "Git object");
|
|
43
|
+
const entries = await Promise.all(unique.map(async (oid) => [oid, await object(oid)]));
|
|
44
|
+
return new Map(entries);
|
|
45
|
+
}
|
|
39
46
|
function batchChild(repository) {
|
|
40
|
-
return
|
|
47
|
+
return spawnCancellableProcess({
|
|
48
|
+
argv: [repository.gitPath, "cat-file", "--batch"],
|
|
41
49
|
cwd: repository.effectiveCwd,
|
|
42
|
-
|
|
43
|
-
windowsHide: true,
|
|
50
|
+
...(repository.signal === undefined ? {} : { signal: repository.signal }),
|
|
44
51
|
});
|
|
45
52
|
}
|
|
46
53
|
function batchError(child, stderr, message, status) {
|
|
@@ -51,8 +58,18 @@ function batchError(child, stderr, message, status) {
|
|
|
51
58
|
pid: child.pid ?? null,
|
|
52
59
|
});
|
|
53
60
|
}
|
|
61
|
+
async function closeBatchProcess(process, child, closed, spawnError, stderr) {
|
|
62
|
+
if (!child.stdin.destroyed)
|
|
63
|
+
child.stdin.end();
|
|
64
|
+
const outcome = await closed;
|
|
65
|
+
await process.waitTermination();
|
|
66
|
+
if (spawnError !== null || outcome.code !== 0) {
|
|
67
|
+
throw batchError(child, stderr, process.cancelled() ? "git process cancelled" : "git cat-file --batch did not close cleanly", outcome.code);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
54
70
|
function batchObjectReader(repository) {
|
|
55
|
-
const
|
|
71
|
+
const process = batchChild(repository);
|
|
72
|
+
const child = process.child;
|
|
56
73
|
const cursor = streamCursor(child.stdout);
|
|
57
74
|
const cache = new Map();
|
|
58
75
|
const stderr = [];
|
|
@@ -101,9 +118,10 @@ function batchObjectReader(repository) {
|
|
|
101
118
|
catch (error) {
|
|
102
119
|
if (failure !== null)
|
|
103
120
|
throw failure;
|
|
104
|
-
|
|
121
|
+
await process.terminate(true);
|
|
105
122
|
await closed;
|
|
106
|
-
|
|
123
|
+
await process.waitTermination();
|
|
124
|
+
failure = batchError(child, stderr, process.cancelled() ? "git process cancelled" : error instanceof Error ? error.message : String(error), process.cancelled() ? null : child.exitCode);
|
|
107
125
|
throw failure;
|
|
108
126
|
}
|
|
109
127
|
};
|
|
@@ -116,23 +134,14 @@ function batchObjectReader(repository) {
|
|
|
116
134
|
cache.set(oid, requested);
|
|
117
135
|
return requested;
|
|
118
136
|
};
|
|
119
|
-
const objects =
|
|
120
|
-
const unique = [...new Set(oids)];
|
|
121
|
-
for (const oid of unique)
|
|
122
|
-
gitObjectId(oid, "Git object");
|
|
123
|
-
const entries = await Promise.all(unique.map(async (oid) => [oid, await object(oid)]));
|
|
124
|
-
return new Map(entries);
|
|
125
|
-
};
|
|
137
|
+
const objects = (oids) => batchObjects(oids, object);
|
|
126
138
|
const close = async () => {
|
|
127
139
|
await tail.catch(() => undefined);
|
|
128
|
-
if (failure !== null)
|
|
140
|
+
if (failure !== null) {
|
|
141
|
+
await process.waitTermination();
|
|
129
142
|
return;
|
|
130
|
-
if (!child.stdin.destroyed)
|
|
131
|
-
child.stdin.end();
|
|
132
|
-
const outcome = await closed;
|
|
133
|
-
if (spawnError !== null || outcome.code !== 0) {
|
|
134
|
-
throw batchError(child, stderr, "git cat-file --batch did not close cleanly", outcome.code);
|
|
135
143
|
}
|
|
144
|
+
await closeBatchProcess(process, child, closed, spawnError, stderr);
|
|
136
145
|
};
|
|
137
146
|
return { objects, close };
|
|
138
147
|
}
|
|
@@ -46,6 +46,7 @@ type WorktreeFollowRetained = Readonly<{
|
|
|
46
46
|
tender: SnapshotId;
|
|
47
47
|
head: SnapshotId;
|
|
48
48
|
reason: "head-moved" | "head-attached" | "operation-in-progress" | "unsupported-parent-shape";
|
|
49
|
+
paths?: readonly string[];
|
|
49
50
|
}>;
|
|
50
51
|
export type ReconcileFailure = Readonly<{
|
|
51
52
|
kind: "reconcile-failed";
|
|
@@ -56,6 +57,10 @@ export type ReconcileLag = WorktreeRetained | WorktreeFollowRetained | UnsealedB
|
|
|
56
57
|
export type ReconcileResult = Readonly<{
|
|
57
58
|
effects: readonly Effect[];
|
|
58
59
|
lag: readonly ReconcileLag[];
|
|
60
|
+
hookRuns?: readonly {
|
|
61
|
+
phase: "create" | "destroy";
|
|
62
|
+
name: string;
|
|
63
|
+
}[];
|
|
59
64
|
}>;
|
|
60
65
|
type ReconcileBatchItem = Readonly<{
|
|
61
66
|
contract: ContractId;
|
|
@@ -72,8 +77,14 @@ export type WorktreeTopology = Readonly<{
|
|
|
72
77
|
export type ReconcileAccumulation = Readonly<{
|
|
73
78
|
effects: Effect[];
|
|
74
79
|
lag: ReconcileLag[];
|
|
80
|
+
hookRuns: {
|
|
81
|
+
phase: "create" | "destroy";
|
|
82
|
+
name: string;
|
|
83
|
+
}[];
|
|
75
84
|
}>;
|
|
76
85
|
export declare function reconcile(input: ReconcileInput): Promise<GitReconcileObservation>;
|
|
86
|
+
/** Reconcile one retained dependent worktree under its normal per-Contract lock. */
|
|
87
|
+
export declare function reconcileDependentWorktree(repository: GitRepository, contractId: ContractId, path: string, target: SnapshotId): Promise<ReconcileResult>;
|
|
77
88
|
export declare function reconcileObservationFailure(error: unknown): ReconcileResult;
|
|
78
89
|
export declare function reconcileEffectFailure(error: unknown, prior?: ReconcileResult): ReconcileResult;
|
|
79
90
|
type ReconcileBatchOptions = Readonly<{
|
|
@@ -2,13 +2,13 @@ import { access, mkdir } from "node:fs/promises";
|
|
|
2
2
|
import { dirname, join } from "node:path";
|
|
3
3
|
import { acquireSqliteTransactionLock, } from "../coordination/sqlite-transaction-lock.js";
|
|
4
4
|
import { AuthorityCorruptionError } from "../core/facts/errors.js";
|
|
5
|
-
import { CANDIDATE_PIN_REF_NAMESPACE, commonGitDirectory, DELIVERY_REF_NAMESPACE, registeredWorktreePaths,
|
|
5
|
+
import { CANDIDATE_PIN_REF_NAMESPACE, commonGitDirectory, DELIVERY_REF_NAMESPACE, registeredWorktreePaths, } from "./repository.js";
|
|
6
6
|
import { runGit } from "./process.js";
|
|
7
7
|
import { contractLocator, contractPhysicalName, gitObjectIdForSnapshot } from "./identity.js";
|
|
8
8
|
import { observeContractAt } from "./observe.js";
|
|
9
9
|
import { acquireTargetPlacementFence, recoverTargetPlacement, } from "./target-placement.js";
|
|
10
10
|
import { runCreateHooks } from "./hooks.js";
|
|
11
|
-
import { followManagedWorktree, worktreePath } from "./workspace.js";
|
|
11
|
+
import { followDependentManagedWorktree, followManagedWorktree, worktreePath } from "./workspace.js";
|
|
12
12
|
import { removeCollectableScratchWorktrees } from "./scratch.js";
|
|
13
13
|
import { reconcileTerminalManagedWorktree, removeRef, updateRef } from "./terminal-reconcile.js";
|
|
14
14
|
const pathExists = (path) => access(path).then(() => true, () => false);
|
|
@@ -31,8 +31,8 @@ async function acquireWorktreeTopology(repository) {
|
|
|
31
31
|
function diagnostic(error) {
|
|
32
32
|
return error instanceof Error ? error.message : String(error);
|
|
33
33
|
}
|
|
34
|
-
function complete(effects = [], lag = []) {
|
|
35
|
-
return { effects, lag };
|
|
34
|
+
function complete(effects = [], lag = [], hookRuns = []) {
|
|
35
|
+
return hookRuns.length === 0 ? { effects, lag } : { effects, lag, hookRuns };
|
|
36
36
|
}
|
|
37
37
|
function failed(stage, error, effects = [], lag = []) {
|
|
38
38
|
if (error instanceof AuthorityCorruptionError || error instanceof TypeError)
|
|
@@ -103,7 +103,7 @@ async function reconcileTargetCheckouts(repository, state) {
|
|
|
103
103
|
result = failed("effect", releaseFailure, result.effects, result.lag);
|
|
104
104
|
return result;
|
|
105
105
|
}
|
|
106
|
-
async function reconcileActiveManagedWorktree({ repository, hooks, retryHooks, place }, state, topology, { effects, lag }) {
|
|
106
|
+
async function reconcileActiveManagedWorktree({ repository, hooks, retryHooks, place }, state, topology, { effects, lag, hookRuns }) {
|
|
107
107
|
if (place === undefined)
|
|
108
108
|
return complete(effects, [...lag, missingPlaceLag(repository)]);
|
|
109
109
|
const path = worktreePath(repository, place);
|
|
@@ -131,18 +131,22 @@ async function reconcileActiveManagedWorktree({ repository, hooks, retryHooks, p
|
|
|
131
131
|
else {
|
|
132
132
|
effects.push(projection);
|
|
133
133
|
}
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
134
|
+
if (projection.action === "created" || retryHooks) {
|
|
135
|
+
const hookRun = await runCreateHooks(path, hooks);
|
|
136
|
+
hookRuns.push(...hookRun.runs.map((name) => ({ phase: "create", name })));
|
|
137
|
+
if (hookRun.lag !== null)
|
|
138
|
+
lag.push(hookRun.lag);
|
|
139
|
+
}
|
|
137
140
|
effects.push(await (state.delivery
|
|
138
141
|
? await updateRef(repository, candidatePinRefFor(state.id), state.currentIntegration?.snapshot ?? state.delivery.data.integration.snapshot)
|
|
139
142
|
: await removeRef(repository, candidatePinRefFor(state.id))));
|
|
140
|
-
return complete(effects, lag);
|
|
143
|
+
return complete(effects, lag, hookRuns);
|
|
141
144
|
}
|
|
142
145
|
async function reconcileWithTopology(input, state, topology) {
|
|
143
146
|
const { repository } = input;
|
|
144
147
|
const effects = [];
|
|
145
148
|
const lag = [];
|
|
149
|
+
const hookRuns = [];
|
|
146
150
|
try {
|
|
147
151
|
await removeCollectableScratch(repository, topology, effects, lag);
|
|
148
152
|
if (!state)
|
|
@@ -151,9 +155,10 @@ async function reconcileWithTopology(input, state, topology) {
|
|
|
151
155
|
effects.push(...targetCheckouts.effects);
|
|
152
156
|
lag.push(...targetCheckouts.lag);
|
|
153
157
|
if (state.terminal) {
|
|
154
|
-
return await reconcileTerminalManagedWorktree(input, state, topology, { effects, lag }, { ref: deliveryRefFor(state.id), pin: candidatePinRefFor(state.id) });
|
|
158
|
+
return await reconcileTerminalManagedWorktree(input, state, topology, { effects, lag, hookRuns }, { ref: deliveryRefFor(state.id), pin: candidatePinRefFor(state.id) });
|
|
155
159
|
}
|
|
156
|
-
|
|
160
|
+
const result = await reconcileActiveManagedWorktree(input, state, topology, { effects, lag, hookRuns });
|
|
161
|
+
return hookRuns.length === 0 ? result : { ...result, hookRuns };
|
|
157
162
|
}
|
|
158
163
|
catch (error) {
|
|
159
164
|
return failed("effect", error, effects, lag);
|
|
@@ -206,6 +211,54 @@ export async function reconcile(input) {
|
|
|
206
211
|
throw new Error("reconcile produced no observation");
|
|
207
212
|
return observation;
|
|
208
213
|
}
|
|
214
|
+
/** Reconcile one retained dependent worktree under its normal per-Contract lock. */
|
|
215
|
+
export async function reconcileDependentWorktree(repository, contractId, path, target) {
|
|
216
|
+
let held;
|
|
217
|
+
try {
|
|
218
|
+
held = await acquireSqliteTransactionLock({ path: reconcileLockPath(repository, contractId), mode: "immediate" });
|
|
219
|
+
}
|
|
220
|
+
catch (error) {
|
|
221
|
+
return failed("effect", error);
|
|
222
|
+
}
|
|
223
|
+
let result;
|
|
224
|
+
try {
|
|
225
|
+
const follow = await followDependentManagedWorktree(repository, path, target);
|
|
226
|
+
if (follow.kind === "followed") {
|
|
227
|
+
result = {
|
|
228
|
+
effects: [{ kind: "worktree", path, action: "followed", before: follow.before, after: follow.after }],
|
|
229
|
+
lag: [],
|
|
230
|
+
};
|
|
231
|
+
}
|
|
232
|
+
else if (follow.kind === "unchanged") {
|
|
233
|
+
result = { effects: [], lag: [] };
|
|
234
|
+
}
|
|
235
|
+
else {
|
|
236
|
+
result = {
|
|
237
|
+
effects: [{ kind: "worktree", path, action: "unchanged" }],
|
|
238
|
+
lag: [
|
|
239
|
+
{
|
|
240
|
+
kind: "worktree-follow-retained",
|
|
241
|
+
path,
|
|
242
|
+
tender: target,
|
|
243
|
+
head: follow.head,
|
|
244
|
+
reason: follow.reason,
|
|
245
|
+
...(follow.paths.length === 0 ? {} : { paths: follow.paths }),
|
|
246
|
+
},
|
|
247
|
+
],
|
|
248
|
+
};
|
|
249
|
+
}
|
|
250
|
+
}
|
|
251
|
+
catch (error) {
|
|
252
|
+
result = failed("effect", error, [{ kind: "worktree", path, action: "unchanged" }]);
|
|
253
|
+
}
|
|
254
|
+
try {
|
|
255
|
+
held.close();
|
|
256
|
+
}
|
|
257
|
+
catch (error) {
|
|
258
|
+
result = failed("effect", error, result.effects, result.lag);
|
|
259
|
+
}
|
|
260
|
+
return result;
|
|
261
|
+
}
|
|
209
262
|
export function reconcileObservationFailure(error) {
|
|
210
263
|
return failed("observation", error);
|
|
211
264
|
}
|
|
@@ -8,6 +8,7 @@ export declare const MIGRATION_DELIVERY_REF_NAMESPACE = "refs/keiyaku/delivery";
|
|
|
8
8
|
export declare const MIGRATION_CANDIDATE_PIN_REF_NAMESPACE = "refs/keiyaku/candidate";
|
|
9
9
|
export declare const GIT_FORMAT_PATH = "meta/format.json";
|
|
10
10
|
export declare const GIT_FORMAT_BYTES = "{\"version\":4}\n";
|
|
11
|
+
export declare const STATE_COMMIT_SUBJECT = "keiyaku authority - do not delete or rewrite";
|
|
11
12
|
export declare function isKeiyakuOwnedRef(ref: string): boolean;
|
|
12
13
|
export type GitOid = string;
|
|
13
14
|
export type RefPublication = Readonly<{
|
|
@@ -54,14 +55,17 @@ export declare function readBlob(repository: GitRepository, oid: GitOid): Promis
|
|
|
54
55
|
export declare function updateGitTree(repository: GitRepository, baseTree: GitOid | null, changes: ReadonlyMap<string, TreeChange>): Promise<GitOid>;
|
|
55
56
|
/** Write a tree update from directory entries frozen with the admitted base tree. */
|
|
56
57
|
export declare function updateGitTreeFromFrozenDirectories(repository: GitRepository, baseTree: GitOid | null, directories: ReadonlyMap<string, ReadonlyMap<string, TreeEntry>>, changes: ReadonlyMap<string, TreeChange>): Promise<GitOid>;
|
|
57
|
-
|
|
58
|
+
type WriteCommitInput = Readonly<{
|
|
58
59
|
repository: GitRepository;
|
|
59
60
|
tree: GitOid;
|
|
60
61
|
parent: GitOid | null;
|
|
61
62
|
message?: string;
|
|
62
63
|
actor?: string;
|
|
63
64
|
at?: string;
|
|
64
|
-
}
|
|
65
|
+
}>;
|
|
66
|
+
export declare function writeCommit(input: WriteCommitInput): Promise<GitOid>;
|
|
67
|
+
/** Write a commit that will become the canonical keiyaku-state tip. */
|
|
68
|
+
export declare function writeStateCommit(input: WriteCommitInput): Promise<GitOid>;
|
|
65
69
|
export declare function updateRefsAtomically(repository: GitRepository, updates: readonly ({
|
|
66
70
|
readonly ref: typeof GIT_REF;
|
|
67
71
|
readonly newOid: GitOid;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable max-lines */
|
|
1
2
|
import { isAbsolute, resolve } from "node:path";
|
|
2
3
|
import { AuthorityCorruptionError } from "../core/facts/errors.js";
|
|
3
4
|
import { gitObjectId } from "./identity.js";
|
|
@@ -11,6 +12,7 @@ export const MIGRATION_CANDIDATE_PIN_REF_NAMESPACE = "refs/keiyaku/candidate";
|
|
|
11
12
|
export const GIT_FORMAT_PATH = "meta/format.json";
|
|
12
13
|
const CURRENT_FORMAT_VERSION = 4;
|
|
13
14
|
export const GIT_FORMAT_BYTES = `{"version":${CURRENT_FORMAT_VERSION}}\n`;
|
|
15
|
+
export const STATE_COMMIT_SUBJECT = "keiyaku authority - do not delete or rewrite";
|
|
14
16
|
export function isKeiyakuOwnedRef(ref) {
|
|
15
17
|
return (ref === GIT_REF ||
|
|
16
18
|
ref === DELIVERY_REF_NAMESPACE ||
|
|
@@ -380,6 +382,12 @@ export async function writeCommit(input) {
|
|
|
380
382
|
...(input.at === undefined ? {} : { at: input.at }),
|
|
381
383
|
});
|
|
382
384
|
}
|
|
385
|
+
/** Write a commit that will become the canonical keiyaku-state tip. */
|
|
386
|
+
export async function writeStateCommit(input) {
|
|
387
|
+
const detail = input.message;
|
|
388
|
+
const message = detail === undefined || detail.length === 0 ? STATE_COMMIT_SUBJECT : `${STATE_COMMIT_SUBJECT}\n\n${detail}`;
|
|
389
|
+
return await writeCommit({ ...input, message });
|
|
390
|
+
}
|
|
383
391
|
function refAssertionLine(assertion) {
|
|
384
392
|
assertAssertionRef(assertion.ref);
|
|
385
393
|
gitObjectId(assertion.oid, `expected oid for ${assertion.ref}`);
|
|
@@ -43,6 +43,7 @@ export type TargetPlacementPreparation = Readonly<{
|
|
|
43
43
|
refusal: TargetPlacementRefusal;
|
|
44
44
|
}>;
|
|
45
45
|
export declare function observeTargetHead(repository: GitRepository, target: string): Promise<SnapshotId | null>;
|
|
46
|
+
export declare function observedTreeEqualsCandidate(repository: GitRepository, observed: SnapshotId | null, candidate: SnapshotId): Promise<boolean>;
|
|
46
47
|
export declare function acquireTargetPlacementFence(repository: GitRepository, target: string): Promise<HeldSqliteTransactionLock>;
|
|
47
48
|
export type TargetedContractCoordinates = ContractState["coordinates"] & Readonly<{
|
|
48
49
|
target: string;
|
|
@@ -27,6 +27,11 @@ function literalPath(path) {
|
|
|
27
27
|
async function commitTree(repository, snapshot) {
|
|
28
28
|
return gitObjectId((await runGit(repository, ["show", "-s", "--format=%T", gitObjectIdForSnapshot(snapshot)])).toString("utf8").trim(), "commit tree");
|
|
29
29
|
}
|
|
30
|
+
export async function observedTreeEqualsCandidate(repository, observed, candidate) {
|
|
31
|
+
if (observed === null)
|
|
32
|
+
return false;
|
|
33
|
+
return (await commitTree(repository, observed)) === (await commitTree(repository, candidate));
|
|
34
|
+
}
|
|
30
35
|
function checkoutRefusal(contractId, target, path, reason, paths) {
|
|
31
36
|
return { kind: "checkout-not-followable", contractId, target: target.target, path, reason, paths };
|
|
32
37
|
}
|
|
@@ -9,6 +9,7 @@ export type TenderCaptureCoordinates = Readonly<{
|
|
|
9
9
|
place?: string;
|
|
10
10
|
workspacePath?: string;
|
|
11
11
|
captureMergeState?: boolean;
|
|
12
|
+
/** Opt-in real-index UU refusal. Omit or false when authorized capture must read current worktree bytes. */
|
|
12
13
|
rejectUnmerged?: boolean;
|
|
13
14
|
}>;
|
|
14
15
|
export type WorktreeMissingRefusal = Readonly<{
|
|
@@ -17,5 +17,5 @@ type TerminalCustodyRefs = Readonly<{
|
|
|
17
17
|
}>;
|
|
18
18
|
export declare function updateRef(repository: GitRepository, ref: string, desired: SnapshotId): Promise<Effect>;
|
|
19
19
|
export declare function removeRef(repository: GitRepository, ref: string): Promise<Effect>;
|
|
20
|
-
export declare function reconcileTerminalManagedWorktree({ repository, channel, hooks,
|
|
20
|
+
export declare function reconcileTerminalManagedWorktree({ repository, channel, hooks, retainTerminalWorktree, place }: TerminalReconcileInput, state: ContractState, topology: WorktreeTopology, acc: ReconcileAccumulation, { ref, pin }: TerminalCustodyRefs): Promise<ReconcileResult>;
|
|
21
21
|
export {};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { access } from "node:fs/promises";
|
|
2
|
-
import { isKeiyakuOwnedRef, readRef, writeCommit
|
|
2
|
+
import { isKeiyakuOwnedRef, readRef, writeCommit } from "./repository.js";
|
|
3
3
|
import { gitObjectIdForSnapshot, mintSnapshotId } from "./identity.js";
|
|
4
4
|
import { runDestroyHooks } from "./hooks.js";
|
|
5
5
|
import { terminalSealExpectations as decodeTerminalSealExpectations, terminalSealSnapshots, observeTerminalWorkspace, } from "./terminal-seal.js";
|
|
@@ -9,10 +9,7 @@ const pathExists = (path) => access(path).then(() => true, () => false);
|
|
|
9
9
|
async function removeTerminalWorktree(repository, topology, path) {
|
|
10
10
|
const registered = topology.paths.has(path);
|
|
11
11
|
if (!registered) {
|
|
12
|
-
return {
|
|
13
|
-
effect: { kind: "worktree", path, action: "unchanged" },
|
|
14
|
-
retained: await pathExists(path),
|
|
15
|
-
};
|
|
12
|
+
return { retained: await pathExists(path) };
|
|
16
13
|
}
|
|
17
14
|
if (!(await pathExists(path))) {
|
|
18
15
|
await runGit(repository, ["worktree", "remove", path]);
|
|
@@ -105,20 +102,20 @@ async function snapshotCustodian(repository, snapshot) {
|
|
|
105
102
|
function fromPrimaryWorktree(repository) {
|
|
106
103
|
return { ...repository, effectiveCwd: repository.primaryWorktree };
|
|
107
104
|
}
|
|
108
|
-
function complete(effects = [], lag = []) {
|
|
109
|
-
return { effects, lag };
|
|
105
|
+
function complete(effects = [], lag = [], hookRuns = []) {
|
|
106
|
+
return hookRuns.length === 0 ? { effects, lag } : { effects, lag, hookRuns };
|
|
110
107
|
}
|
|
111
|
-
function retainTerminalWorktree(path, retainedLag, { effects, lag }) {
|
|
108
|
+
function retainTerminalWorktree(path, retainedLag, { effects, lag, hookRuns }) {
|
|
112
109
|
effects.push({ kind: "worktree", path, action: "unchanged" });
|
|
113
110
|
lag.push(retainedLag);
|
|
114
|
-
return complete(effects, lag);
|
|
111
|
+
return complete(effects, lag, hookRuns);
|
|
115
112
|
}
|
|
116
113
|
async function terminalSealExpectations(channel, state) {
|
|
117
114
|
const snapshots = terminalSealSnapshots(state);
|
|
118
115
|
const objects = await channel.readObjects(snapshots.map(gitObjectIdForSnapshot));
|
|
119
116
|
return decodeTerminalSealExpectations(state, objects);
|
|
120
117
|
}
|
|
121
|
-
async function removeSealedTerminalWorktree({ repository, topology, path, state, expected, hooks,
|
|
118
|
+
async function removeSealedTerminalWorktree({ repository, topology, path, state, expected, hooks, acc, }) {
|
|
122
119
|
if (topology.paths.has(path) && (await pathExists(path))) {
|
|
123
120
|
const terminal = state.terminal;
|
|
124
121
|
if (terminal === null)
|
|
@@ -156,9 +153,10 @@ async function removeSealedTerminalWorktree({ repository, topology, path, state,
|
|
|
156
153
|
}
|
|
157
154
|
recovery = await recordRecovery(beforeWorkspace);
|
|
158
155
|
}
|
|
159
|
-
const
|
|
160
|
-
|
|
161
|
-
|
|
156
|
+
const hookRun = await runDestroyHooks(path, hooks);
|
|
157
|
+
acc.hookRuns.push(...hookRun.runs.map((name) => ({ phase: "destroy", name })));
|
|
158
|
+
if (hookRun.lag !== null)
|
|
159
|
+
return retainTerminalWorktree(path, hookRun.lag, acc);
|
|
162
160
|
const after = await observeTerminalWorkspace(repository, path, expected);
|
|
163
161
|
const afterWorkspace = after.workspace;
|
|
164
162
|
const afterHooks = after.unsealed;
|
|
@@ -180,7 +178,8 @@ async function removeSealedTerminalWorktree({ repository, topology, path, state,
|
|
|
180
178
|
const removal = await removeTerminalWorktree(repository, topology, path);
|
|
181
179
|
if (removal.retained)
|
|
182
180
|
return retainTerminalWorktree(path, { kind: "worktree-retained", path }, acc);
|
|
183
|
-
|
|
181
|
+
if (removal.effect !== undefined)
|
|
182
|
+
acc.effects.push(removal.effect);
|
|
184
183
|
return null;
|
|
185
184
|
}
|
|
186
185
|
async function targetCustodyForClaimedIntegration(repository, state, integration) {
|
|
@@ -244,23 +243,27 @@ async function releaseTerminalCustody({ repository, state, resolveSeal, ref, pin
|
|
|
244
243
|
}
|
|
245
244
|
}
|
|
246
245
|
}
|
|
247
|
-
export async function reconcileTerminalManagedWorktree({ repository, channel, hooks,
|
|
246
|
+
export async function reconcileTerminalManagedWorktree({ repository, channel, hooks, retainTerminalWorktree, place }, state, topology, acc, { ref, pin }) {
|
|
248
247
|
const primary = fromPrimaryWorktree(repository);
|
|
249
248
|
const path = place === undefined ? undefined : worktreePath(repository, place);
|
|
250
249
|
const resolveSeal = async () => await terminalSealExpectations(channel, state);
|
|
251
250
|
if (path === undefined) {
|
|
252
251
|
if (retainTerminalWorktree === true)
|
|
253
|
-
return complete(acc.effects, acc.lag);
|
|
252
|
+
return complete(acc.effects, acc.lag, acc.hookRuns);
|
|
254
253
|
await releaseTerminalCustody({ repository: primary, state, resolveSeal, ref, pin, acc });
|
|
255
|
-
return complete(acc.effects, acc.lag);
|
|
254
|
+
return complete(acc.effects, acc.lag, acc.hookRuns);
|
|
256
255
|
}
|
|
257
256
|
const expected = await resolveSeal();
|
|
258
257
|
acc.effects.push(await updateRef(primary, ref, state.delivery?.data.tenderSnapshot ?? state.coordinates.start));
|
|
259
258
|
if (state.delivery !== null) {
|
|
260
259
|
acc.effects.push(await updateRef(primary, pin, state.currentIntegration?.snapshot ?? state.delivery.data.integration.snapshot));
|
|
261
260
|
}
|
|
262
|
-
if (retainTerminalWorktree === true)
|
|
261
|
+
if (retainTerminalWorktree === true) {
|
|
262
|
+
if (topology.paths.has(path) && (await pathExists(path))) {
|
|
263
|
+
acc.effects.push({ kind: "worktree", path, action: "unchanged" });
|
|
264
|
+
}
|
|
263
265
|
return complete(acc.effects, acc.lag);
|
|
266
|
+
}
|
|
264
267
|
const retained = await removeSealedTerminalWorktree({
|
|
265
268
|
repository: primary,
|
|
266
269
|
topology,
|
|
@@ -268,11 +271,10 @@ export async function reconcileTerminalManagedWorktree({ repository, channel, ho
|
|
|
268
271
|
state,
|
|
269
272
|
expected,
|
|
270
273
|
hooks,
|
|
271
|
-
retryHooks,
|
|
272
274
|
acc,
|
|
273
275
|
});
|
|
274
276
|
if (retained !== null)
|
|
275
277
|
return retained;
|
|
276
278
|
await releaseTerminalCustody({ repository: primary, state, resolveSeal: async () => expected, ref, pin, acc });
|
|
277
|
-
return complete(acc.effects, acc.lag);
|
|
279
|
+
return complete(acc.effects, acc.lag, acc.hookRuns);
|
|
278
280
|
}
|
|
@@ -26,8 +26,22 @@ export type ManagedWorktreeFollow = Readonly<{
|
|
|
26
26
|
head: SnapshotId;
|
|
27
27
|
reason: "head-moved" | "head-attached" | "operation-in-progress" | "unsupported-parent-shape";
|
|
28
28
|
}>;
|
|
29
|
+
export type DependentWorktreeFollow = Readonly<{
|
|
30
|
+
kind: "followed";
|
|
31
|
+
before: SnapshotId;
|
|
32
|
+
after: SnapshotId;
|
|
33
|
+
}> | Readonly<{
|
|
34
|
+
kind: "unchanged";
|
|
35
|
+
}> | Readonly<{
|
|
36
|
+
kind: "retained";
|
|
37
|
+
head: SnapshotId;
|
|
38
|
+
reason: "head-moved" | "head-attached" | "operation-in-progress";
|
|
39
|
+
paths: readonly string[];
|
|
40
|
+
}>;
|
|
29
41
|
/** Follow an accepted tender only through the native index-and-HEAD transition. */
|
|
30
42
|
export declare function followManagedWorktree(repository: GitRepository, workspace: string, tender: SnapshotId): Promise<ManagedWorktreeFollow>;
|
|
43
|
+
/** Follow a dependency baseline only through a clean, detached fast-forward. */
|
|
44
|
+
export declare function followDependentManagedWorktree(repository: GitRepository, workspace: string, target: SnapshotId): Promise<DependentWorktreeFollow>;
|
|
31
45
|
export declare function withPrivateGitIndex<Value>(action: (environment: Readonly<{
|
|
32
46
|
GIT_INDEX_FILE: string;
|
|
33
47
|
}>) => Value | PromiseLike<Value>): Promise<Value>;
|
|
@@ -70,6 +70,50 @@ export async function followManagedWorktree(repository, workspace, tender) {
|
|
|
70
70
|
await runGit(repository, ["-C", workspace, "reset", "--mixed", gitObjectId(tender)]);
|
|
71
71
|
return { kind: "followed", before: head, after: tender };
|
|
72
72
|
}
|
|
73
|
+
/** Follow a dependency baseline only through a clean, detached fast-forward. */
|
|
74
|
+
export async function followDependentManagedWorktree(repository, workspace, target) {
|
|
75
|
+
const head = await workspaceRevision(repository, workspace, "HEAD");
|
|
76
|
+
if (head === null)
|
|
77
|
+
throw new Error("managed worktree HEAD is missing");
|
|
78
|
+
const status = await workspaceStatus(repository, workspace);
|
|
79
|
+
const gitDirectory = await worktreeGitDirectory(repository, workspace);
|
|
80
|
+
const operation = await workspaceOperationState(repository, workspace, gitDirectory);
|
|
81
|
+
const mergeHead = await workspaceRevision(repository, workspace, "MERGE_HEAD");
|
|
82
|
+
const paths = [
|
|
83
|
+
...new Set([
|
|
84
|
+
...status.staged,
|
|
85
|
+
...status.unstaged,
|
|
86
|
+
...status.untracked,
|
|
87
|
+
...status.submodules,
|
|
88
|
+
...status.unmergedPaths,
|
|
89
|
+
]),
|
|
90
|
+
].sort();
|
|
91
|
+
const attached = await runGit(repository, ["-C", workspace, "symbolic-ref", "--quiet", "HEAD"]).then(() => true, (error) => {
|
|
92
|
+
if (error instanceof GitPlumbingError && error.status === 1)
|
|
93
|
+
return false;
|
|
94
|
+
throw error;
|
|
95
|
+
});
|
|
96
|
+
if (attached)
|
|
97
|
+
return { kind: "retained", head, reason: "head-attached", paths };
|
|
98
|
+
if (mergeHead !== null || operation.other || operation.unmerged || paths.length > 0) {
|
|
99
|
+
return { kind: "retained", head, reason: "operation-in-progress", paths };
|
|
100
|
+
}
|
|
101
|
+
if (head === target)
|
|
102
|
+
return { kind: "unchanged" };
|
|
103
|
+
let ancestor = false;
|
|
104
|
+
try {
|
|
105
|
+
await runGit(repository, ["merge-base", "--is-ancestor", gitObjectId(head), gitObjectId(target)]);
|
|
106
|
+
ancestor = true;
|
|
107
|
+
}
|
|
108
|
+
catch (error) {
|
|
109
|
+
if (!(error instanceof GitPlumbingError) || error.status !== 1)
|
|
110
|
+
throw error;
|
|
111
|
+
}
|
|
112
|
+
if (!ancestor)
|
|
113
|
+
return { kind: "retained", head, reason: "head-moved", paths };
|
|
114
|
+
await runGit(repository, ["-C", workspace, "checkout", "--quiet", "--detach", gitObjectId(target)]);
|
|
115
|
+
return { kind: "followed", before: head, after: target };
|
|
116
|
+
}
|
|
73
117
|
export async function withPrivateGitIndex(action) {
|
|
74
118
|
const directory = await mkdtemp(join(tmpdir(), "keiyaku-v4-index-"));
|
|
75
119
|
try {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
export { kanshi, observeKanshi } from "./read.js";
|
|
2
2
|
export { selectKanshi, selectRegion } from "./select.js";
|
|
3
3
|
export type { KanshiInput } from "./read.js";
|
|
4
|
-
export type { AkumaKanshiRow, AkumaKanshiWorld, ContractEndpointObservation, ContractHolderObservation, ContractKanshiBoard, ContractKanshiRow,
|
|
4
|
+
export type { AkumaKanshiRow, AkumaKanshiWorld, ContractEndpointObservation, ContractHolderObservation, ContractKanshiBoard, ContractKanshiRow, KanshiReport, Section, TaskKanshiRow, TaskKanshiWorld, KanshiRegionSelection, RegionDeclaration, RegionOverlap, RegionRead, } from "./report.js";
|
|
5
5
|
export type { KanshiSelection } from "./select.js";
|
package/build/src/kanshi/read.js
CHANGED
|
@@ -122,22 +122,6 @@ async function readContracts(observation, include) {
|
|
|
122
122
|
return { kind: "failed", failure: { message: diagnostic(error) } };
|
|
123
123
|
}
|
|
124
124
|
}
|
|
125
|
-
async function attachSelectedIssue(observation, contracts, selected) {
|
|
126
|
-
if (contracts.kind !== "present")
|
|
127
|
-
return contracts;
|
|
128
|
-
try {
|
|
129
|
-
const rows = await Promise.all(contracts.value.rows.map(async (row) => {
|
|
130
|
-
if (row.id !== selected)
|
|
131
|
-
return row;
|
|
132
|
-
const issue = await observeCurrentPhysicalIssue(observation.repository, row);
|
|
133
|
-
return issue === undefined ? row : { ...row, issue };
|
|
134
|
-
}));
|
|
135
|
-
return { kind: "present", value: { ...contracts.value, rows } };
|
|
136
|
-
}
|
|
137
|
-
catch (error) {
|
|
138
|
-
return { kind: "failed", failure: { message: diagnostic(error) } };
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
125
|
async function readHolders(observation) {
|
|
142
126
|
try {
|
|
143
127
|
return { kind: "present", value: await readTaskHolderProjectionAt(observation) };
|
|
@@ -393,3 +377,19 @@ export async function observeKanshi(input) {
|
|
|
393
377
|
export async function kanshi(input) {
|
|
394
378
|
return (await observeKanshi(input)).report;
|
|
395
379
|
}
|
|
380
|
+
async function attachSelectedIssue(observation, contracts, selected) {
|
|
381
|
+
if (contracts.kind !== "present")
|
|
382
|
+
return contracts;
|
|
383
|
+
try {
|
|
384
|
+
const rows = await Promise.all(contracts.value.rows.map(async (row) => {
|
|
385
|
+
if (row.id !== selected)
|
|
386
|
+
return row;
|
|
387
|
+
const issue = await observeCurrentPhysicalIssue(observation.repository, row);
|
|
388
|
+
return issue === undefined ? row : { ...row, issue };
|
|
389
|
+
}));
|
|
390
|
+
return { kind: "present", value: { ...contracts.value, rows } };
|
|
391
|
+
}
|
|
392
|
+
catch (error) {
|
|
393
|
+
return { kind: "failed", failure: { message: diagnostic(error) } };
|
|
394
|
+
}
|
|
395
|
+
}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { ContractBoard, ContractDisposition, ContractPhase } from "../library/contract.js";
|
|
2
|
-
import type { CurrentPhysicalIssue } from "../protocol/read/observation.js";
|
|
3
2
|
import type { TaskId, TaskRef, TaskRow } from "../task/index.js";
|
|
4
3
|
import type { AkumaList, AkumaListRow, UnbornAkumaListRow, ActivitySnapshot } from "../akuma/index.js";
|
|
5
4
|
import type { AkumaAlias } from "../identity/selector.js";
|
|
6
5
|
import type { WorldRoot } from "../world.js";
|
|
7
6
|
import type { ContractId } from "../library/contract.js";
|
|
8
7
|
import type { RegionOverlap } from "../library/region.js";
|
|
8
|
+
import type { CurrentPhysicalIssue } from "../protocol/read/observation.js";
|
|
9
9
|
export type { RegionOverlap };
|
|
10
10
|
export type Section<Value> = Readonly<{
|
|
11
11
|
kind: "present";
|
|
@@ -31,7 +31,6 @@ export type ContractFleetAttachment = Readonly<{
|
|
|
31
31
|
id: string;
|
|
32
32
|
aliases: readonly AkumaAlias[];
|
|
33
33
|
}>;
|
|
34
|
-
export type { CurrentPhysicalIssue };
|
|
35
34
|
export type ContractKanshiRow = ContractBoard["rows"][number] & Readonly<{
|
|
36
35
|
phase: ContractPhase;
|
|
37
36
|
holder: ContractHolderObservation;
|
|
@@ -98,3 +97,4 @@ export type KanshiReport = Readonly<{
|
|
|
98
97
|
akuma: Section<AkumaKanshiWorld>;
|
|
99
98
|
region?: Section<RegionRead>;
|
|
100
99
|
}>;
|
|
100
|
+
export type { CurrentPhysicalIssue };
|
|
@@ -2,7 +2,7 @@ import { type AliasBinding } from "../alias/index.js";
|
|
|
2
2
|
import { type AkuId } from "../akuma/identity.js";
|
|
3
3
|
import { contractId } from "../core/facts/types.js";
|
|
4
4
|
import { type AkumaAlias, type AkumaGlob } from "../identity/selector.js";
|
|
5
|
-
import type
|
|
5
|
+
import { type WorldRoot } from "../world.js";
|
|
6
6
|
import type { KanshiReport, Section } from "../kanshi/index.js";
|
|
7
7
|
import { type Repo } from "./repo.js";
|
|
8
8
|
export type DirectAkumaSelector = AkuId | AkumaAlias;
|
|
@@ -17,6 +17,11 @@ export type AkumaSetAddressInput = Readonly<{
|
|
|
17
17
|
akuma: readonly string[];
|
|
18
18
|
repo?: Repo;
|
|
19
19
|
}>;
|
|
20
|
+
type UncheckedAkumaAddressInput = Readonly<{
|
|
21
|
+
path: unknown;
|
|
22
|
+
akuma: unknown;
|
|
23
|
+
repo?: unknown;
|
|
24
|
+
}>;
|
|
20
25
|
export type AkumaWorldScopeRefusal = Readonly<{
|
|
21
26
|
kind: "akuma-not-in-world";
|
|
22
27
|
ids: readonly AkuId[];
|
|
@@ -39,11 +44,12 @@ export type NamedAddressInput = Readonly<{
|
|
|
39
44
|
aliases: Section<readonly AliasBinding[]>;
|
|
40
45
|
}>;
|
|
41
46
|
export declare function resolveNamedAddress(input: NamedAddressInput): NamedAddress;
|
|
42
|
-
export declare function addressAkuma(input:
|
|
47
|
+
export declare function addressAkuma(input: UncheckedAkumaAddressInput): Promise<Readonly<{
|
|
43
48
|
path: WorldRoot;
|
|
44
49
|
id: AkuId;
|
|
45
50
|
}>>;
|
|
46
|
-
export declare function addressAkumaSet(input:
|
|
51
|
+
export declare function addressAkumaSet(input: UncheckedAkumaAddressInput): Promise<Readonly<{
|
|
47
52
|
path: WorldRoot;
|
|
48
53
|
ids: readonly AkuId[];
|
|
49
54
|
}>>;
|
|
55
|
+
export {};
|