@astrosheep/keiyaku 4.6.3 → 4.6.6
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/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +47 -11
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/references/automation.md +2 -2
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-babysit/SKILL.md +1 -1
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-bind/SKILL.md +8 -9
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-workflow/SKILL.md +37 -25
- package/build/src/akuma/akuma-observe.d.ts +18 -15
- package/build/src/akuma/akuma-observe.js +75 -16
- package/build/src/akuma/akuma-wait.d.ts +4 -3
- package/build/src/akuma/akuma-wait.js +75 -53
- package/build/src/akuma/akuma.d.ts +6 -4
- package/build/src/akuma/akuma.js +4 -0
- package/build/src/akuma/call-initial-tell.d.ts +2 -2
- package/build/src/akuma/call-initial-tell.js +1 -1
- package/build/src/akuma/call-request.d.ts +2 -2
- package/build/src/akuma/heart/index.d.ts +7 -2
- package/build/src/akuma/heart/index.js +50 -5
- package/build/src/akuma/heart/tells.d.ts +33 -2
- package/build/src/akuma/heart/tells.js +24 -18
- package/build/src/akuma/heart/timeline.d.ts +23 -1
- package/build/src/akuma/heart/timeline.js +28 -21
- package/build/src/akuma/projection.d.ts +10 -10
- package/build/src/akuma/providers/pi/index.js +72 -39
- package/build/src/akuma/selection-observation.d.ts +20 -20
- package/build/src/akuma-body.js +1 -0
- package/build/src/alias/index.d.ts +0 -1
- package/build/src/alias/index.js +0 -4
- package/build/src/body/amend.d.ts +0 -4
- package/build/src/body/amend.js +0 -3
- package/build/src/body/region.d.ts +0 -1
- package/build/src/body/region.js +0 -3
- package/build/src/body/verification.d.ts +0 -1
- package/build/src/cli/commands/akuma-grammar.js +23 -66
- package/build/src/cli/commands/akuma.js +17 -30
- package/build/src/cli/commands/contract-grammar.d.ts +14 -1
- package/build/src/cli/commands/contract-grammar.js +54 -21
- package/build/src/cli/commands/contract-help.d.ts +9 -8
- package/build/src/cli/commands/contract-help.js +14 -7
- package/build/src/cli/commands/contract.js +57 -117
- package/build/src/cli/commands/install.d.ts +5 -5
- package/build/src/cli/commands/install.js +1 -4
- package/build/src/cli/commands/task-grammar.js +10 -66
- package/build/src/cli/commands/task.d.ts +0 -1
- package/build/src/cli/commands/task.js +34 -53
- package/build/src/cli/coordinates.d.ts +1 -2
- package/build/src/cli/coordinates.js +1 -4
- package/build/src/cli/parse.d.ts +2 -3
- package/build/src/cli/parse.js +24 -66
- package/build/src/cli/render/akuma.d.ts +3 -16
- package/build/src/cli/render/akuma.js +1 -13
- package/build/src/cli/render/audit.js +1 -1
- package/build/src/cli/render/contract.js +34 -32
- package/build/src/cli/render/kanshi-akuma.d.ts +8 -2
- package/build/src/cli/render/kanshi-akuma.js +14 -7
- package/build/src/cli/render/kanshi.d.ts +3 -1
- package/build/src/cli/render/kanshi.js +44 -32
- package/build/src/cli/render/receipt.js +6 -1
- package/build/src/cli/render/task.d.ts +1 -1
- package/build/src/cli/render/task.js +3 -27
- package/build/src/cli/render/terminal.d.ts +6 -2
- package/build/src/cli/render/terminal.js +8 -2
- package/build/src/cli/runtime.js +3 -16
- package/build/src/cli/scan.d.ts +26 -0
- package/build/src/cli/scan.js +82 -0
- package/build/src/cli/streams.d.ts +5 -0
- package/build/src/cli/streams.js +11 -0
- package/build/src/contract-worktree.js +38 -21
- package/build/src/core/facts/codec.d.ts +1 -2
- package/build/src/core/facts/codec.js +5 -11
- package/build/src/core/facts/types.d.ts +16 -2
- package/build/src/core/facts/types.js +15 -0
- package/build/src/core/verbs/abandon.js +3 -9
- package/build/src/core/verbs/amend.js +2 -9
- package/build/src/core/verbs/arc.js +6 -13
- package/build/src/core/verbs/attestation.js +2 -9
- package/build/src/core/verbs/bind.js +2 -9
- package/build/src/core/verbs/deliver.js +2 -9
- package/build/src/core/verbs/placement.d.ts +1 -1
- package/build/src/core/verbs/placement.js +2 -9
- package/build/src/core/verbs/reintegrate.d.ts +1 -1
- package/build/src/core/verbs/reintegrate.js +2 -9
- package/build/src/dispatch/index.d.ts +2 -2
- package/build/src/dispatch/index.js +33 -11
- package/build/src/git/hooks.d.ts +2 -4
- package/build/src/git/hooks.js +0 -12
- package/build/src/git/integration.d.ts +5 -3
- package/build/src/git/integration.js +36 -25
- package/build/src/git/nuke.js +4 -4
- package/build/src/git/observe.d.ts +4 -4
- package/build/src/git/observe.js +5 -5
- package/build/src/git/process.d.ts +1 -4
- package/build/src/git/process.js +1 -11
- package/build/src/git/read-observation.js +1 -1
- package/build/src/git/reconcile.d.ts +1 -1
- package/build/src/git/reconcile.js +15 -13
- package/build/src/git/repository.d.ts +2 -6
- package/build/src/git/repository.js +18 -31
- package/build/src/git/scratch.d.ts +6 -6
- package/build/src/git/scratch.js +110 -46
- package/build/src/git/target-placement.d.ts +5 -5
- package/build/src/git/target-placement.js +18 -33
- package/build/src/git/tender.d.ts +6 -2
- package/build/src/git/tender.js +19 -12
- package/build/src/git/terminal-reconcile.js +24 -13
- package/build/src/git/terminal-seal.d.ts +2 -5
- package/build/src/git/terminal-seal.js +5 -3
- package/build/src/git/workspace.d.ts +17 -13
- package/build/src/git/workspace.js +58 -41
- package/build/src/kanshi/index.d.ts +2 -2
- package/build/src/kanshi/index.js +1 -1
- package/build/src/kanshi/read.d.ts +8 -1
- package/build/src/kanshi/read.js +72 -7
- package/build/src/kanshi/report.d.ts +12 -0
- package/build/src/library/akuma-creation.d.ts +4 -4
- package/build/src/library/bind.d.ts +1 -63
- package/build/src/library/bind.js +3 -9
- package/build/src/library/contract-creation.js +2 -30
- package/build/src/library/contract-execution.d.ts +0 -1
- package/build/src/library/contract-execution.js +9 -34
- package/build/src/library/contract-operations.d.ts +5 -1
- package/build/src/library/contract-operations.js +7 -3
- package/build/src/library/contract-types.d.ts +1 -1
- package/build/src/library/delivery.d.ts +91 -93
- package/build/src/library/delivery.js +2 -1
- package/build/src/library/input.d.ts +0 -2
- package/build/src/library/input.js +0 -4
- package/build/src/library/invocation.d.ts +0 -1
- package/build/src/library/invocation.js +3 -25
- package/build/src/library/outcome.d.ts +651 -602
- package/build/src/library/outcome.js +4 -4
- package/build/src/library/reconcile.d.ts +6 -0
- package/build/src/library/reconcile.js +31 -1
- package/build/src/library/repo.d.ts +0 -1
- package/build/src/library/selection.d.ts +1 -10
- package/build/src/library/selection.js +14 -15
- package/build/src/protocol/abandon.d.ts +1 -1
- package/build/src/protocol/abandon.js +3 -10
- package/build/src/protocol/amend.js +2 -5
- package/build/src/protocol/arc.d.ts +1 -1
- package/build/src/protocol/arc.js +2 -9
- package/build/src/protocol/attempt.d.ts +3 -20
- package/build/src/protocol/attempt.js +6 -5
- package/build/src/protocol/audit.d.ts +1 -0
- package/build/src/protocol/audit.js +10 -11
- package/build/src/protocol/completion.d.ts +129 -55
- package/build/src/protocol/completion.js +62 -73
- package/build/src/protocol/deliver.d.ts +7 -5
- package/build/src/protocol/deliver.js +74 -44
- package/build/src/protocol/execution-observation.d.ts +2 -4
- package/build/src/protocol/execution-observation.js +3 -7
- package/build/src/protocol/intent.d.ts +1 -1
- package/build/src/protocol/intent.js +1 -0
- package/build/src/protocol/operations.d.ts +24 -12
- package/build/src/protocol/operations.js +36 -15
- package/build/src/protocol/placement.d.ts +2 -1
- package/build/src/protocol/placement.js +21 -5
- package/build/src/protocol/progress.d.ts +1 -1
- package/build/src/protocol/read/status.js +58 -41
- package/build/src/protocol/reintegrate.d.ts +1 -1
- package/build/src/protocol/reintegrate.js +10 -19
- package/build/src/protocol/review.d.ts +3 -28
- package/build/src/protocol/review.js +10 -37
- package/build/src/protocol/run.d.ts +19 -7
- package/build/src/protocol/run.js +19 -9
- package/build/src/runtime/proc/windows-launch.exe +0 -0
- package/build/src/settlement/holder.d.ts +2 -4
- package/build/src/settlement/holder.js +3 -6
- package/build/src/task/board.d.ts +6 -0
- package/build/src/task/board.js +30 -1
- package/build/src/task/catalog.js +1 -4
- package/build/src/task/compose.d.ts +0 -1
- package/build/src/task/compose.js +0 -1
- package/build/src/task/context.d.ts +0 -1
- package/build/src/task/context.js +0 -3
- package/build/src/task/created-observation.d.ts +5 -1
- package/build/src/task/created-observation.js +12 -5
- package/build/src/task/index.d.ts +1 -1
- package/build/src/task/index.js +7 -6
- package/build/src/task/input.d.ts +0 -6
- package/build/src/task/input.js +2 -14
- package/build/src/task/mutation.d.ts +3 -4
- package/build/src/task/mutation.js +11 -39
- package/build/src/task/operations.d.ts +2 -7
- package/build/src/task/operations.js +37 -49
- package/build/src/task/query.d.ts +0 -1
- package/build/src/task/query.js +1 -4
- package/build/src/task/store.d.ts +0 -2
- package/build/src/task/store.js +27 -11
- package/build/src/verification/declaration.js +3 -2
- package/build/src/verification/execution.d.ts +3 -2
- package/build/src/verification/execution.js +10 -6
- package/build/src/workspace-place.d.ts +0 -1
- package/build/src/workspace-place.js +0 -11
- package/package.json +7 -3
package/build/src/git/hooks.d.ts
CHANGED
|
@@ -61,14 +61,12 @@ export declare const worktreeHookLagSchema: z.ZodObject<{
|
|
|
61
61
|
}, z.core.$strict>]>;
|
|
62
62
|
}, z.core.$strict>;
|
|
63
63
|
export type WorktreeHookLag = z.infer<typeof worktreeHookLagSchema>;
|
|
64
|
-
export type HookPhase = "create" | "destroy";
|
|
65
64
|
type WorktreeHooksFromInput = Readonly<{
|
|
66
65
|
settings: Settings;
|
|
67
66
|
}>;
|
|
68
67
|
export declare function worktreeHooksFrom(input: WorktreeHooksFromInput): WorktreeHooks;
|
|
69
|
-
export declare function normalizedWorktreeHooks(value: unknown): WorktreeHooks;
|
|
70
68
|
export declare const EMPTY_WORKTREE_HOOKS: WorktreeHooks;
|
|
71
|
-
|
|
69
|
+
type HookCommandRun = Readonly<{
|
|
72
70
|
kind: "ok";
|
|
73
71
|
}> | Readonly<{
|
|
74
72
|
kind: "cancelled";
|
|
@@ -85,7 +83,7 @@ export declare function runHookCommands(worktree: string, commands: readonly Hoo
|
|
|
85
83
|
stream: "stdout" | "stderr";
|
|
86
84
|
text: string;
|
|
87
85
|
}>) => void): Promise<HookCommandRun>;
|
|
88
|
-
|
|
86
|
+
type HookPhaseRun = Readonly<{
|
|
89
87
|
lag: WorktreeHookLag | null;
|
|
90
88
|
runs: readonly string[];
|
|
91
89
|
}>;
|
package/build/src/git/hooks.js
CHANGED
|
@@ -94,18 +94,6 @@ export function worktreeHooksFrom(input) {
|
|
|
94
94
|
};
|
|
95
95
|
return Object.freeze({ create: selected("create"), destroy: selected("destroy") });
|
|
96
96
|
}
|
|
97
|
-
export function normalizedWorktreeHooks(value) {
|
|
98
|
-
if (!record(value))
|
|
99
|
-
throw new TypeError("hooks must be an object");
|
|
100
|
-
for (const key of Object.keys(value)) {
|
|
101
|
-
if (key !== "create" && key !== "destroy")
|
|
102
|
-
throw new TypeError(`hooks has unknown field: ${key}`);
|
|
103
|
-
}
|
|
104
|
-
return Object.freeze({
|
|
105
|
-
create: commands(value.create, "hooks.create", TypeError),
|
|
106
|
-
destroy: commands(value.destroy, "hooks.destroy", TypeError),
|
|
107
|
-
});
|
|
108
|
-
}
|
|
109
97
|
export const EMPTY_WORKTREE_HOOKS = Object.freeze({
|
|
110
98
|
create: Object.freeze([]),
|
|
111
99
|
destroy: Object.freeze([]),
|
|
@@ -3,7 +3,7 @@ import type { Preparation } from "../core/decide.js";
|
|
|
3
3
|
import type { ChangeId, ContractCoordinates, ContractId, SnapshotId } from "../core/facts/types.js";
|
|
4
4
|
import { type GitObjectId } from "./identity.js";
|
|
5
5
|
import { type GitRepository } from "./process.js";
|
|
6
|
-
import type
|
|
6
|
+
import { type DeliveryCommitMetadata, type TenderCapture } from "./tender.js";
|
|
7
7
|
import { workspaceMergeStatePresent } from "./workspace.js";
|
|
8
8
|
export { workspaceMergeStatePresent };
|
|
9
9
|
type IntegrationTender = Pick<TenderCapture, "head" | "tree">;
|
|
@@ -36,16 +36,18 @@ export declare const integrationPreparationRefusalSchema: z.ZodUnion<readonly [z
|
|
|
36
36
|
requiredGit: z.ZodLiteral<"2.38">;
|
|
37
37
|
}, z.core.$strict>]>;
|
|
38
38
|
export type IntegrationPreparationRefusal = z.infer<typeof integrationPreparationRefusalSchema>;
|
|
39
|
-
|
|
39
|
+
type IntegrationCoordinates = Readonly<{
|
|
40
40
|
contractId: ContractId;
|
|
41
41
|
coordinates: ContractCoordinates;
|
|
42
42
|
}>;
|
|
43
|
-
|
|
43
|
+
type IntegrationPlan = Readonly<{
|
|
44
44
|
predecessor: SnapshotId;
|
|
45
45
|
tree: GitObjectId;
|
|
46
46
|
}>;
|
|
47
47
|
/** Mint the one worktree-content identity shared by review and delivery. */
|
|
48
48
|
export declare function worktreeChangeId(repository: GitRepository, input: IntegrationCoordinates, tender: TenderCapture): Promise<ChangeId>;
|
|
49
|
+
/** Reuse only recorded commits with this exact tree and sole predecessor. */
|
|
50
|
+
export declare function reusableIntegrationSnapshot(repository: GitRepository, tree: GitObjectId, parent: SnapshotId, recordedSnapshots: readonly SnapshotId[]): Promise<SnapshotId | undefined>;
|
|
49
51
|
/** Materialize the exact integration tree against its observed predecessor. */
|
|
50
52
|
export declare function materializeIntegrationSnapshot(repository: GitRepository, tree: GitObjectId, parent: SnapshotId, metadata: DeliveryCommitMetadata): Promise<SnapshotId>;
|
|
51
53
|
export declare function persistedTender(repository: GitRepository, snapshot: SnapshotId): Promise<IntegrationTender>;
|
|
@@ -3,13 +3,15 @@ import { z } from "zod";
|
|
|
3
3
|
import { AuthorityCorruptionError } from "../core/facts/errors.js";
|
|
4
4
|
import { gitObjectId, gitObjectIdForSnapshot, mintChangeId, mintSnapshotId } from "./identity.js";
|
|
5
5
|
import { decodeGitNameOnly, decodeGitNumstat, readRef } from "./repository.js";
|
|
6
|
-
import {
|
|
6
|
+
import { executeGit, GitPlumbingError, runGitPipe } from "./process.js";
|
|
7
|
+
import { deliveryEnvironment, materializeSnapshotCommit, } from "./tender.js";
|
|
7
8
|
import { workspaceMergeStatePresent } from "./workspace.js";
|
|
9
|
+
import { withGitDecodeChannel } from "./read-observation.js";
|
|
8
10
|
export { workspaceMergeStatePresent };
|
|
9
11
|
const REQUIRED_GIT = "2.38";
|
|
10
12
|
async function runAllowingNonzero(repository, args, input) {
|
|
11
13
|
try {
|
|
12
|
-
return { stdout: await
|
|
14
|
+
return { stdout: await executeGit(repository, args, input), stderr: Buffer.alloc(0), status: 0 };
|
|
13
15
|
}
|
|
14
16
|
catch (error) {
|
|
15
17
|
if (!(error instanceof GitPlumbingError))
|
|
@@ -76,22 +78,34 @@ export async function worktreeChangeId(repository, input, tender) {
|
|
|
76
78
|
const id = result.toString("utf8").trim().split(/\s/, 1)[0] ?? "";
|
|
77
79
|
return mintChangeId(id === "" ? "0000000000000000000000000000000000000000" : id);
|
|
78
80
|
}
|
|
81
|
+
/** Reuse only recorded commits with this exact tree and sole predecessor. */
|
|
82
|
+
export async function reusableIntegrationSnapshot(repository, tree, parent, recordedSnapshots) {
|
|
83
|
+
if (recordedSnapshots.length === 0)
|
|
84
|
+
return undefined;
|
|
85
|
+
return await withGitDecodeChannel(repository, async (channel) => {
|
|
86
|
+
for (const snapshot of recordedSnapshots) {
|
|
87
|
+
const oid = gitObjectIdForSnapshot(snapshot);
|
|
88
|
+
const object = (await channel.readObjects([oid])).get(oid);
|
|
89
|
+
if (object.kind === "missing")
|
|
90
|
+
continue;
|
|
91
|
+
if (object.type !== "commit") {
|
|
92
|
+
throw new AuthorityCorruptionError(`recorded integration snapshot is not a Git commit: ${snapshot}`);
|
|
93
|
+
}
|
|
94
|
+
const headers = object.bytes.toString("utf8").split("\n\n", 1)[0].split("\n");
|
|
95
|
+
const parents = headers.filter((line) => line.startsWith("parent "));
|
|
96
|
+
if (headers[0] === `tree ${tree}` && parents.length === 1 && parents[0] === `parent ${parent}`) {
|
|
97
|
+
return snapshot;
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
return undefined;
|
|
101
|
+
});
|
|
102
|
+
}
|
|
79
103
|
/** Materialize the exact integration tree against its observed predecessor. */
|
|
80
104
|
export async function materializeIntegrationSnapshot(repository, tree, parent, metadata) {
|
|
81
|
-
|
|
82
|
-
GIT_AUTHOR_NAME: metadata.identity.name,
|
|
83
|
-
GIT_AUTHOR_EMAIL: metadata.identity.email,
|
|
84
|
-
GIT_COMMITTER_NAME: metadata.identity.name,
|
|
85
|
-
GIT_COMMITTER_EMAIL: metadata.identity.email,
|
|
86
|
-
GIT_AUTHOR_DATE: metadata.at,
|
|
87
|
-
GIT_COMMITTER_DATE: metadata.at,
|
|
88
|
-
}))
|
|
89
|
-
.toString("utf8")
|
|
90
|
-
.trim();
|
|
91
|
-
return mintSnapshotId(commit);
|
|
105
|
+
return await materializeSnapshotCommit(repository, tree, [parent], metadata.message, deliveryEnvironment(metadata));
|
|
92
106
|
}
|
|
93
107
|
export async function persistedTender(repository, snapshot) {
|
|
94
|
-
const tree = (await
|
|
108
|
+
const tree = (await executeGit(repository, ["show", "-s", "--format=%T", gitObjectIdForSnapshot(snapshot)]))
|
|
95
109
|
.toString("ascii")
|
|
96
110
|
.trim();
|
|
97
111
|
return { head: snapshot, tree: gitObjectId(tree, "persisted tender tree") };
|
|
@@ -100,7 +114,7 @@ export async function materializeReintegrationSnapshot(repository, tree, parent,
|
|
|
100
114
|
const templateObject = gitObjectIdForSnapshot(template);
|
|
101
115
|
let raw;
|
|
102
116
|
try {
|
|
103
|
-
raw = await
|
|
117
|
+
raw = await executeGit(repository, ["cat-file", "commit", templateObject]);
|
|
104
118
|
}
|
|
105
119
|
catch (error) {
|
|
106
120
|
if (error instanceof GitPlumbingError) {
|
|
@@ -114,7 +128,7 @@ export async function materializeReintegrationSnapshot(repository, tree, parent,
|
|
|
114
128
|
const message = raw.subarray(separator + 2);
|
|
115
129
|
let fields;
|
|
116
130
|
try {
|
|
117
|
-
const formatted = (await
|
|
131
|
+
const formatted = (await executeGit(repository, ["show", "-s", "--format=%an%x00%ae%x00%aI%x00%cn%x00%ce%x00%cI", templateObject]))
|
|
118
132
|
.toString("utf8")
|
|
119
133
|
.replace(/\n$/u, "");
|
|
120
134
|
fields = formatted.split("\0");
|
|
@@ -129,17 +143,14 @@ export async function materializeReintegrationSnapshot(repository, tree, parent,
|
|
|
129
143
|
throw new AuthorityCorruptionError(`recorded delivery snapshot metadata is malformed: ${template}`);
|
|
130
144
|
}
|
|
131
145
|
const [authorName, authorEmail, authorDate, committerName, committerEmail, committerDate] = fields;
|
|
132
|
-
|
|
146
|
+
return await materializeSnapshotCommit(repository, tree, [parent], message, {
|
|
133
147
|
GIT_AUTHOR_NAME: authorName,
|
|
134
148
|
GIT_AUTHOR_EMAIL: authorEmail,
|
|
135
149
|
GIT_AUTHOR_DATE: authorDate,
|
|
136
150
|
GIT_COMMITTER_NAME: committerName,
|
|
137
151
|
GIT_COMMITTER_EMAIL: committerEmail,
|
|
138
152
|
GIT_COMMITTER_DATE: committerDate,
|
|
139
|
-
})
|
|
140
|
-
.toString("utf8")
|
|
141
|
-
.trim();
|
|
142
|
-
return mintSnapshotId(commit);
|
|
153
|
+
});
|
|
143
154
|
}
|
|
144
155
|
async function isAncestor(repository, ancestor, descendant) {
|
|
145
156
|
const result = await runAllowingNonzero(repository, [
|
|
@@ -302,7 +313,7 @@ export async function planIntegration(repository, input, tender, requireBranches
|
|
|
302
313
|
}
|
|
303
314
|
async function deliverySnapshotAvailability(repository, predecessor, candidate) {
|
|
304
315
|
const objects = [gitObjectIdForSnapshot(predecessor), gitObjectIdForSnapshot(candidate)];
|
|
305
|
-
const types = (await
|
|
316
|
+
const types = (await executeGit(repository, ["cat-file", "--batch-check=%(objectname) %(objecttype)"], `${objects.join("\n")}\n`))
|
|
306
317
|
.toString("ascii")
|
|
307
318
|
.trimEnd()
|
|
308
319
|
.split("\n")
|
|
@@ -323,7 +334,7 @@ export const deliveryDiffScopeSchema = z
|
|
|
323
334
|
})
|
|
324
335
|
.strict();
|
|
325
336
|
export async function readDeliveryScope(repository, predecessor, candidate, includePaths) {
|
|
326
|
-
const scope = decodeGitNumstat(await
|
|
337
|
+
const scope = decodeGitNumstat(await executeGit(repository, [
|
|
327
338
|
"diff",
|
|
328
339
|
"--numstat",
|
|
329
340
|
"-z",
|
|
@@ -334,7 +345,7 @@ export async function readDeliveryScope(repository, predecessor, candidate, incl
|
|
|
334
345
|
return scope;
|
|
335
346
|
return {
|
|
336
347
|
...scope,
|
|
337
|
-
paths: decodeGitNameOnly(await
|
|
348
|
+
paths: decodeGitNameOnly(await executeGit(repository, [
|
|
338
349
|
"diff",
|
|
339
350
|
"--name-only",
|
|
340
351
|
"--no-renames",
|
|
@@ -349,7 +360,7 @@ export async function readDeliveryDiff(repository, predecessor, candidate) {
|
|
|
349
360
|
if ((await deliverySnapshotAvailability(repository, predecessor, candidate)) === "unavailable")
|
|
350
361
|
return null;
|
|
351
362
|
try {
|
|
352
|
-
return (await
|
|
363
|
+
return (await executeGit(repository, [
|
|
353
364
|
"diff",
|
|
354
365
|
"--no-ext-diff",
|
|
355
366
|
"--no-color",
|
package/build/src/git/nuke.js
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { access, lstat, realpath, rm } from "node:fs/promises";
|
|
2
2
|
import { isAbsolute, relative, sep } from "node:path";
|
|
3
3
|
import { nukeEmptyPlaceAuthority, readPlaceRegister, releaseManagedWorktrees, withPlaceAuthorityFence, } from "../workspace-place.js";
|
|
4
|
-
import { GitPlumbingError,
|
|
4
|
+
import { GitPlumbingError, executeGit } from "./process.js";
|
|
5
5
|
import { confirmPrivateStatePublication, withPrivateStatePublicationSeat, } from "./private-state-seat.js";
|
|
6
6
|
import { CANDIDATE_PIN_REF_NAMESPACE, DELIVERY_REF_NAMESPACE, GIT_REF, NoGitWorldError, readRef, registeredWorktrees, repositoryAt, worktreeGitDirectory, } from "./repository.js";
|
|
7
7
|
import { worktreePath } from "./workspace.js";
|
|
@@ -89,7 +89,7 @@ async function removeManagedWorktree(repository, entry) {
|
|
|
89
89
|
return await removeUnregisteredResidue(repository, entry);
|
|
90
90
|
if (registered.branch !== null)
|
|
91
91
|
return false;
|
|
92
|
-
await
|
|
92
|
+
await executeGit(repository, ["worktree", "remove", "--force", entry.path]);
|
|
93
93
|
if ((await registeredWorktrees(repository)).some((candidate) => candidate.path === entry.path)) {
|
|
94
94
|
throw new GitResetStopError(`managed Place worktree remains registered: ${entry.path}`);
|
|
95
95
|
}
|
|
@@ -104,7 +104,7 @@ async function removeManagedWorktree(repository, entry) {
|
|
|
104
104
|
throw new GitResetStopError(`managed Place worktree remains present: ${entry.path}`);
|
|
105
105
|
}
|
|
106
106
|
async function deleteRefAt(repository, ref, expectedOid) {
|
|
107
|
-
await
|
|
107
|
+
await executeGit(repository, ["update-ref", "--no-deref", "-d", ref, expectedOid]);
|
|
108
108
|
}
|
|
109
109
|
async function deleteObservedStateRef(repository, expectedOid, seat) {
|
|
110
110
|
try {
|
|
@@ -126,7 +126,7 @@ async function removeOwnedRefs(repository, onRemoved) {
|
|
|
126
126
|
let removed = 0;
|
|
127
127
|
const roots = [DELIVERY_REF_NAMESPACE, CANDIDATE_PIN_REF_NAMESPACE];
|
|
128
128
|
for (const root of roots) {
|
|
129
|
-
const refs = (await
|
|
129
|
+
const refs = (await executeGit(repository, ["for-each-ref", "--format=%(refname)", root]))
|
|
130
130
|
.toString("utf8")
|
|
131
131
|
.split("\n")
|
|
132
132
|
.filter((ref) => ref.length > root.length && ref.startsWith(`${root}/`));
|
|
@@ -3,7 +3,7 @@ import type { ContractsObservation } from "../core/facts/observation.js";
|
|
|
3
3
|
import { type GitSnapshot, type GitOid } from "./repository.js";
|
|
4
4
|
import { type GitRepository } from "./process.js";
|
|
5
5
|
import { type GitDecodeChannel, type GitReadObservation, type GitTreeSelection } from "./read-observation.js";
|
|
6
|
-
|
|
6
|
+
type TargetObservation = Readonly<{
|
|
7
7
|
head: SnapshotId | null;
|
|
8
8
|
drift: boolean;
|
|
9
9
|
}>;
|
|
@@ -12,11 +12,11 @@ type GitJournalRecord = Readonly<{
|
|
|
12
12
|
entries: readonly JournalEntry[];
|
|
13
13
|
state: ContractState | null;
|
|
14
14
|
}>;
|
|
15
|
-
|
|
15
|
+
type ContractWorldObservation = Readonly<{
|
|
16
16
|
snapshot: SnapshotId | null;
|
|
17
17
|
contracts: ReadonlyMap<ContractId, GitJournalRecord>;
|
|
18
18
|
}>;
|
|
19
|
-
|
|
19
|
+
type ActiveContractWorldObservation = ContractWorldObservation & Readonly<{
|
|
20
20
|
eligibility: ContractsObservation;
|
|
21
21
|
}>;
|
|
22
22
|
export type GitAdmissionSnapshot = Readonly<{
|
|
@@ -34,7 +34,7 @@ export type BindCoordinatesObservation = Readonly<{
|
|
|
34
34
|
target?: string;
|
|
35
35
|
branch: string | null;
|
|
36
36
|
}>;
|
|
37
|
-
|
|
37
|
+
type UnbornHeadObservation = Readonly<{
|
|
38
38
|
kind: "unborn-head";
|
|
39
39
|
branch: string | null;
|
|
40
40
|
}>;
|
package/build/src/git/observe.js
CHANGED
|
@@ -3,7 +3,7 @@ import { AuthorityCorruptionError } from "../core/facts/errors.js";
|
|
|
3
3
|
import { foldJournal } from "../core/facts/fold.js";
|
|
4
4
|
import { contractJournalPath, contractJournalPaths, mintContractHead, mintSnapshotId, } from "./identity.js";
|
|
5
5
|
import { isKeiyakuOwnedRef } from "./repository.js";
|
|
6
|
-
import { GitPlumbingError,
|
|
6
|
+
import { GitPlumbingError, executeGit } from "./process.js";
|
|
7
7
|
import { readBlobResults, readGitTreeSelection, withGitTargetedReadObservation, } from "./read-observation.js";
|
|
8
8
|
export async function observeDeliveryTargetAt(observation, state) {
|
|
9
9
|
const target = state.coordinates.target;
|
|
@@ -29,7 +29,7 @@ export async function normalizeTargetBranch(repository, input) {
|
|
|
29
29
|
if (branch.length === 0 || branch.startsWith("-") || isKeiyakuOwnedRef(target))
|
|
30
30
|
return null;
|
|
31
31
|
try {
|
|
32
|
-
const checked = (await
|
|
32
|
+
const checked = (await executeGit(repository, ["check-ref-format", "--branch", branch])).toString("utf8").trim();
|
|
33
33
|
return checked === branch ? target : null;
|
|
34
34
|
}
|
|
35
35
|
catch (error) {
|
|
@@ -41,7 +41,7 @@ export async function normalizeTargetBranch(repository, input) {
|
|
|
41
41
|
/** Read one worktree's attached branch, or null for detached HEAD. */
|
|
42
42
|
export async function currentBranch(repository, path) {
|
|
43
43
|
try {
|
|
44
|
-
const ref = (await
|
|
44
|
+
const ref = (await executeGit(repository, [...(path === undefined ? [] : ["-C", path]), "symbolic-ref", "--quiet", "HEAD"]))
|
|
45
45
|
.toString("utf8")
|
|
46
46
|
.trim();
|
|
47
47
|
return ref.startsWith("refs/heads/") ? ref : null;
|
|
@@ -64,7 +64,7 @@ function structuredFields(output, fieldCount) {
|
|
|
64
64
|
async function observeHeadCoordinates(repository) {
|
|
65
65
|
try {
|
|
66
66
|
return {
|
|
67
|
-
start: mintSnapshotId((await
|
|
67
|
+
start: mintSnapshotId((await executeGit(repository, ["rev-parse", "--verify", "HEAD"])).toString("utf8").trim()),
|
|
68
68
|
branch: await currentBranch(repository),
|
|
69
69
|
};
|
|
70
70
|
}
|
|
@@ -84,7 +84,7 @@ export async function observeBindCoordinates(repository, selection = { kind: "ta
|
|
|
84
84
|
if (isKeiyakuOwnedRef(requestedTarget)) {
|
|
85
85
|
throw new Error(`bind target names a Keiyaku-owned ref: ${requestedTarget}`);
|
|
86
86
|
}
|
|
87
|
-
const output = await
|
|
87
|
+
const output = await executeGit(repository, [
|
|
88
88
|
"for-each-ref",
|
|
89
89
|
`--format=${TARGET_COORDINATES_FORMAT}`,
|
|
90
90
|
"--",
|
|
@@ -16,8 +16,6 @@ export type GitRepository = Readonly<{
|
|
|
16
16
|
/** Test-only hook after the private-state seat close attempt. */
|
|
17
17
|
readonly onPrivateStateSeatClose?: () => void;
|
|
18
18
|
}>;
|
|
19
|
-
/** Give one caller's Git capability view its cancellation boundary. */
|
|
20
|
-
export declare function withGitAbortSignal(repository: GitRepository, signal: AbortSignal | undefined): GitRepository;
|
|
21
19
|
export declare class GitPlumbingError extends Error {
|
|
22
20
|
readonly stdout: Buffer;
|
|
23
21
|
readonly stderr: Buffer;
|
|
@@ -31,8 +29,7 @@ export declare class GitPlumbingError extends Error {
|
|
|
31
29
|
pid?: number | null;
|
|
32
30
|
}>);
|
|
33
31
|
}
|
|
34
|
-
export declare function
|
|
32
|
+
export declare function executeGit(repository: GitRepository, args: readonly string[], input?: string | Uint8Array, environment?: NodeJS.ProcessEnv): Promise<Buffer>;
|
|
35
33
|
/** Connect two owned Git commands without materializing the intermediate output. */
|
|
36
34
|
export declare function runGitPipe(repository: GitRepository, sourceArgs: readonly string[], sinkArgs: readonly string[]): Promise<Buffer>;
|
|
37
35
|
export declare function consumeGitStdout(repository: GitRepository, args: readonly string[], consume: (chunk: Buffer) => void): Promise<void>;
|
|
38
|
-
export declare function runGitWithEnvironment(repository: GitRepository, args: readonly string[], input: string | Uint8Array | undefined, environment: NodeJS.ProcessEnv): Promise<Buffer>;
|
package/build/src/git/process.js
CHANGED
|
@@ -1,9 +1,5 @@
|
|
|
1
1
|
import { consumeProcessStdout, spawnCancellableProcess } from "../runtime/proc/run.js";
|
|
2
2
|
import { pipeline } from "node:stream/promises";
|
|
3
|
-
/** Give one caller's Git capability view its cancellation boundary. */
|
|
4
|
-
export function withGitAbortSignal(repository, signal) {
|
|
5
|
-
return signal === undefined ? repository : { ...repository, signal };
|
|
6
|
-
}
|
|
7
3
|
export class GitPlumbingError extends Error {
|
|
8
4
|
stdout;
|
|
9
5
|
stderr;
|
|
@@ -32,7 +28,7 @@ function commandError(command, error) {
|
|
|
32
28
|
pid: candidate.pid ?? null,
|
|
33
29
|
});
|
|
34
30
|
}
|
|
35
|
-
async function executeGit(repository, args, input, environment) {
|
|
31
|
+
export async function executeGit(repository, args, input, environment) {
|
|
36
32
|
if (repository.signal?.aborted === true) {
|
|
37
33
|
throw commandError(args, { message: "git process cancelled", status: null });
|
|
38
34
|
}
|
|
@@ -81,9 +77,6 @@ async function executeGit(repository, args, input, environment) {
|
|
|
81
77
|
pid: child.pid,
|
|
82
78
|
});
|
|
83
79
|
}
|
|
84
|
-
export async function runGit(repository, args, input) {
|
|
85
|
-
return await executeGit(repository, args, input);
|
|
86
|
-
}
|
|
87
80
|
function boundedPipeOutput(child, args) {
|
|
88
81
|
const stdout = [];
|
|
89
82
|
let bytes = 0;
|
|
@@ -212,6 +205,3 @@ export async function consumeGitStdout(repository, args, consume) {
|
|
|
212
205
|
pid: result.pid ?? undefined,
|
|
213
206
|
});
|
|
214
207
|
}
|
|
215
|
-
export async function runGitWithEnvironment(repository, args, input, environment) {
|
|
216
|
-
return await executeGit(repository, args, input, environment);
|
|
217
|
-
}
|
|
@@ -6,7 +6,7 @@ import { GIT_FORMAT_BYTES, GIT_FORMAT_PATH, GIT_REF, readRef } from "./repositor
|
|
|
6
6
|
import { GitPlumbingError } from "./process.js";
|
|
7
7
|
const gitReadObservationBrand = Symbol("GitReadObservation");
|
|
8
8
|
const gitDecodeChannelBrand = Symbol("GitDecodeChannel");
|
|
9
|
-
const BATCH_RETIREMENT_GRACE_MS =
|
|
9
|
+
const BATCH_RETIREMENT_GRACE_MS = 5_000;
|
|
10
10
|
function streamCursor(stream) {
|
|
11
11
|
const iterator = stream[Symbol.asyncIterator]();
|
|
12
12
|
let buffer = Buffer.alloc(0);
|
|
@@ -142,7 +142,7 @@ type ReconcileBatchItem = Readonly<{
|
|
|
142
142
|
state: ContractState | null;
|
|
143
143
|
result: ReconcileResult;
|
|
144
144
|
}>;
|
|
145
|
-
|
|
145
|
+
type GitReconcileObservation = Readonly<{
|
|
146
146
|
state: ContractState | null;
|
|
147
147
|
result: ReconcileResult;
|
|
148
148
|
}>;
|
|
@@ -8,7 +8,7 @@ import { dirname, join } from "node:path";
|
|
|
8
8
|
import { acquireSqliteTransactionLock, SqliteTransactionLockError, } from "../coordination/sqlite-transaction-lock.js";
|
|
9
9
|
import { AuthorityCorruptionError } from "../core/facts/errors.js";
|
|
10
10
|
import { CANDIDATE_PIN_REF_NAMESPACE, commonGitDirectory, DELIVERY_REF_NAMESPACE, registeredWorktreePaths, } from "./repository.js";
|
|
11
|
-
import {
|
|
11
|
+
import { executeGit, GitPlumbingError } from "./process.js";
|
|
12
12
|
import { contractLocator, contractPhysicalName, gitObjectIdForSnapshot } from "./identity.js";
|
|
13
13
|
import { observeContractAt } from "./observe.js";
|
|
14
14
|
import { acquireTargetPlacementFence, recoverTargetPlacement } from "./target-placement.js";
|
|
@@ -158,25 +158,27 @@ async function worktree(repository, topology, path, desired) {
|
|
|
158
158
|
if (registered && (await pathExists(path)))
|
|
159
159
|
return { kind: "worktree", path, action: "unchanged" };
|
|
160
160
|
if (registered) {
|
|
161
|
-
await
|
|
161
|
+
await executeGit(repository, ["worktree", "remove", path]);
|
|
162
162
|
topology.paths.delete(path);
|
|
163
163
|
}
|
|
164
164
|
if (await pathExists(path))
|
|
165
165
|
throw new WorktreeCustodyError(`delivery worktree path is occupied: ${path}`);
|
|
166
166
|
await mkdir(dirname(path), { recursive: true });
|
|
167
|
-
await
|
|
167
|
+
await executeGit(repository, ["worktree", "add", "--detach", path, gitObjectIdForSnapshot(desired)]);
|
|
168
168
|
topology.paths.add(path);
|
|
169
169
|
return { kind: "worktree", path, action: "created" };
|
|
170
170
|
}
|
|
171
|
-
async function removeCollectableScratch(repository, topology, acc) {
|
|
172
|
-
for (const removal of await removeCollectableScratchWorktrees(repository, topology.paths)) {
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
171
|
+
async function removeCollectableScratch(repository, topology, acc, terminalContract) {
|
|
172
|
+
for (const removal of await removeCollectableScratchWorktrees(repository, topology.paths, terminalContract)) {
|
|
173
|
+
if (!removal.retained) {
|
|
174
|
+
acc.recordEffect({ kind: "worktree", path: removal.path, action: "removed" });
|
|
175
|
+
continue;
|
|
176
|
+
}
|
|
177
|
+
acc.recordLag({
|
|
178
|
+
kind: "worktree-retained",
|
|
179
|
+
path: removal.path,
|
|
180
|
+
...(removal.diagnostic === undefined ? {} : { diagnostic: removal.diagnostic }),
|
|
181
|
+
});
|
|
180
182
|
}
|
|
181
183
|
}
|
|
182
184
|
async function reconcileTargetCheckouts(repository, state, onPhysical) {
|
|
@@ -288,7 +290,7 @@ async function reconcileWithTopology(input, state, topology) {
|
|
|
288
290
|
const acc = reconcileAccumulation(input.onPhysical);
|
|
289
291
|
const { effects, lag, hookRuns } = acc;
|
|
290
292
|
try {
|
|
291
|
-
await removeCollectableScratch(repository, topology, acc);
|
|
293
|
+
await removeCollectableScratch(repository, topology, acc, state?.terminal ? state.id : undefined);
|
|
292
294
|
if (!state)
|
|
293
295
|
return complete(effects, lag);
|
|
294
296
|
const targetCheckouts = await reconcileTargetCheckouts(repository, state, input.onPhysical);
|
|
@@ -7,7 +7,6 @@ export declare const CANDIDATE_PIN_REF_NAMESPACE = "refs/keiyaku/candidate";
|
|
|
7
7
|
export declare const HANDOFF_RECEIPT_REF_NAMESPACE = "refs/keiyaku/handoff";
|
|
8
8
|
export declare const GIT_FORMAT_PATH = "meta/format.json";
|
|
9
9
|
export declare const GIT_FORMAT_BYTES = "{\"version\":4}\n";
|
|
10
|
-
export declare const STATE_COMMIT_SUBJECT = "keiyaku authority - do not delete or rewrite";
|
|
11
10
|
export declare function isKeiyakuOwnedRef(ref: string): boolean;
|
|
12
11
|
export type GitOid = string;
|
|
13
12
|
export type RefPublication = Readonly<{
|
|
@@ -31,7 +30,7 @@ export declare class NoGitWorldError extends Error {
|
|
|
31
30
|
readonly path: string;
|
|
32
31
|
constructor(path: string);
|
|
33
32
|
}
|
|
34
|
-
|
|
33
|
+
type RegisteredWorktree = Readonly<{
|
|
35
34
|
path: string;
|
|
36
35
|
branch: string | null;
|
|
37
36
|
}>;
|
|
@@ -40,12 +39,9 @@ export declare function registeredWorktreePaths(repository: GitRepository): Prom
|
|
|
40
39
|
export declare function repositoryAt(cwd: string, gitPath?: string): Promise<GitRepository>;
|
|
41
40
|
export declare function commonGitDirectory(repository: GitRepository): string;
|
|
42
41
|
export declare function worktreeGitDirectory(repository: GitRepository, worktree: string): Promise<string>;
|
|
43
|
-
export declare function worktreeRoot(repository: GitRepository): Promise<string>;
|
|
44
42
|
export declare function readRef(repository: GitRepository, ref: string): Promise<GitOid | null>;
|
|
45
43
|
/** Read an explicit set of asserted refs from one fresh Git observation. */
|
|
46
44
|
export declare function readRefs(repository: GitRepository, refs: readonly string[]): Promise<Map<any, any>>;
|
|
47
|
-
export declare function readTreeEntries(repository: GitRepository, tree: GitOid): Promise<Map<string, TreeEntry>>;
|
|
48
|
-
export declare function readGit(repository: GitRepository): Promise<GitSnapshot>;
|
|
49
45
|
/** Read only the requested private Git paths from one immutable Git tree. */
|
|
50
46
|
export declare function readGitPaths(repository: GitRepository, requestedPaths: readonly string[]): Promise<GitSnapshot>;
|
|
51
47
|
export declare function writeBlob(repository: GitRepository, bytes: string | Uint8Array): Promise<GitOid>;
|
|
@@ -74,7 +70,7 @@ export declare function updateRefsAtomically(repository: GitRepository, updates:
|
|
|
74
70
|
readonly newOid: GitOid;
|
|
75
71
|
readonly expectedOid: GitOid;
|
|
76
72
|
})[], assertions?: readonly GitRefAssertion[]): Promise<RefPublication>;
|
|
77
|
-
|
|
73
|
+
type GitDiffStat = Readonly<{
|
|
78
74
|
filesChanged: number;
|
|
79
75
|
insertions: number;
|
|
80
76
|
deletions: number;
|