@astrosheep/keiyaku 4.5.8 → 4.5.9
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 +2 -2
- package/build/integrations/marketplace/plugins/keiyaku/skills/keiyaku-akuma/SKILL.md +15 -15
- package/build/src/akuma/akuma.d.ts +24 -4
- package/build/src/akuma/archetype.js +1 -1
- package/build/src/akuma/body.d.ts +2 -1
- package/build/src/akuma/body.js +7 -2
- package/build/src/akuma/call-request.js +1 -1
- package/build/src/akuma/heart/facts.d.ts +10 -0
- package/build/src/akuma/heart/facts.js +11 -0
- package/build/src/akuma/heart/index.d.ts +3 -2
- package/build/src/akuma/heart/index.js +4 -1
- package/build/src/akuma/projection.d.ts +63 -12
- package/build/src/akuma/projection.js +5 -11
- package/build/src/akuma/provider.js +8 -1
- package/build/src/akuma/providers/claude/events.d.ts +2 -2
- package/build/src/akuma/providers/claude/events.js +16 -3
- package/build/src/akuma/providers/codex-app-server/events.d.ts +2 -2
- package/build/src/akuma/providers/codex-app-server/events.js +25 -4
- package/build/src/akuma/providers/pi/index.js +55 -69
- package/build/src/akuma/request-lifecycle.d.ts +1 -1
- package/build/src/akuma/request-lifecycle.js +3 -1
- package/build/src/akuma/request-serve.d.ts +1 -1
- package/build/src/akuma/request-serve.js +4 -4
- package/build/src/akuma/turn-drive.js +8 -2
- package/build/src/body/amend.js +18 -19
- package/build/src/cli/commands/akuma.js +2 -2
- package/build/src/cli/commands/contract-invoke.js +27 -22
- package/build/src/cli/commands/contract.d.ts +6 -10
- package/build/src/cli/commands/contract.js +29 -11
- package/build/src/cli/commands/install.d.ts +1 -0
- package/build/src/cli/commands/install.js +2 -1
- package/build/src/cli/parse.js +23 -9
- package/build/src/cli/render/akuma-activity.d.ts +1 -1
- package/build/src/cli/render/akuma-activity.js +4 -3
- package/build/src/cli/render/akuma.js +1 -1
- package/build/src/cli/render/catalog.js +1 -1
- package/build/src/cli/render/contract.js +13 -0
- package/build/src/cli/render/kanshi-akuma.js +26 -5
- package/build/src/cli/render/kanshi.js +26 -3
- package/build/src/cli/render/terminal.d.ts +4 -1
- package/build/src/cli/render/terminal.js +12 -1
- package/build/src/cli/runtime.js +1 -1
- package/build/src/git/nuke.js +3 -3
- package/build/src/git/process.js +7 -4
- package/build/src/git/read-observation.js +1 -1
- package/build/src/git/reconcile.d.ts +2 -1
- package/build/src/git/reconcile.js +6 -0
- package/build/src/git/ref-migration.d.ts +22 -0
- package/build/src/git/ref-migration.js +55 -0
- package/build/src/git/repository.d.ts +4 -4
- package/build/src/git/repository.js +8 -8
- package/build/src/library/audit.d.ts +13 -5
- package/build/src/library/audit.js +9 -21
- package/build/src/library/composition.d.ts +41 -27
- package/build/src/library/composition.js +3 -3
- package/build/src/library/contract-forwarding-reconciliation-result.d.ts +17 -11
- package/build/src/library/contract-forwarding-reconciliation-result.js +11 -2
- package/build/src/library/contract-forwarding-result.d.ts +1628 -3887
- package/build/src/library/contract-forwarding-result.js +1 -1
- package/build/src/library/contract-forwarding.d.ts +12 -13
- package/build/src/library/contract-forwarding.js +17 -28
- package/build/src/library/contract-handle.d.ts +3 -1
- package/build/src/library/contract-handle.js +23 -22
- package/build/src/library/contract-operations.d.ts +61 -893
- package/build/src/library/contract-operations.js +2 -3
- package/build/src/library/contract-types.d.ts +7 -3
- package/build/src/library/contract.d.ts +12 -4
- package/build/src/library/contract.js +21 -6
- package/build/src/library/fleet-result.d.ts +138 -12
- package/build/src/library/fleet-result.js +2 -0
- package/build/src/library/input.d.ts +1 -1
- package/build/src/library/input.js +7 -1
- package/build/src/library/keiyaku.d.ts +44 -27
- package/build/src/library/keiyaku.js +6 -1
- package/build/src/runtime/proc/run.d.ts +1 -0
- package/build/src/runtime/proc/run.js +25 -5
- package/build/src/runtime/proc/windows-launch.exe +0 -0
- package/package.json +1 -1
|
@@ -34,11 +34,11 @@ export const CONTRACT_COMMAND_SPECS = {
|
|
|
34
34
|
usage: "amend [<contract>|@<contract>] [--after <kei/...> ... | --clear-after] [--gates <name,...>] [--actor <actor>] [--json] [-]",
|
|
35
35
|
purpose: "Amend one Contract's document operations or structured terms.",
|
|
36
36
|
details: [
|
|
37
|
+
" ## Context|Objective|Design|Region|Criteria|Verification|<extension> (replace, or add new extension)",
|
|
37
38
|
" ## Replace: Context|Objective|Design|Region|Criteria|Verification|<extension>",
|
|
38
39
|
" ## Append: Context|Objective|Design|Criteria|<extension>",
|
|
39
40
|
" ## Add: Criteria|<new-extension-title>",
|
|
40
41
|
" ## Update: <existing-extension-title>",
|
|
41
|
-
" ## Remove: Criterion <existing-title>",
|
|
42
42
|
" ## Remove: <existing-extension-title>",
|
|
43
43
|
].join("\n"),
|
|
44
44
|
},
|
|
@@ -46,13 +46,12 @@ export const CONTRACT_COMMAND_SPECS = {
|
|
|
46
46
|
positional: "optional",
|
|
47
47
|
stdin: "none",
|
|
48
48
|
flags: {
|
|
49
|
-
actor: "value",
|
|
50
49
|
message: "value",
|
|
51
50
|
"include-dirty": "boolean",
|
|
52
51
|
"materialize-conflict": "boolean",
|
|
53
52
|
json: "boolean",
|
|
54
53
|
},
|
|
55
|
-
usage: "deliver [<contract>|@<contract>] [--message <text>] [--include-dirty] [--materialize-conflict] [--
|
|
54
|
+
usage: "deliver [<contract>|@<contract>] [--message <text>] [--include-dirty] [--materialize-conflict] [--json]",
|
|
56
55
|
purpose: "Deliver one Contract candidate from the appointed worktree.",
|
|
57
56
|
details: [
|
|
58
57
|
" --include-dirty Capture the complete non-ignored worktree tree as the",
|
|
@@ -66,8 +65,8 @@ export const CONTRACT_COMMAND_SPECS = {
|
|
|
66
65
|
review: {
|
|
67
66
|
positional: "optional",
|
|
68
67
|
stdin: "optional",
|
|
69
|
-
flags: {
|
|
70
|
-
usage: "review [<contract>|@<contract>] (--satisfied | --unsatisfied) (--summary <text> | -) [--
|
|
68
|
+
flags: { satisfied: "boolean", unsatisfied: "boolean", summary: "value", json: "boolean" },
|
|
69
|
+
usage: "review [<contract>|@<contract>] (--satisfied | --unsatisfied) (--summary <text> | -) [--json]",
|
|
71
70
|
purpose: "Record one review verdict.",
|
|
72
71
|
},
|
|
73
72
|
arc: {
|
|
@@ -108,8 +107,8 @@ export const CONTRACT_COMMAND_SPECS = {
|
|
|
108
107
|
audit: {
|
|
109
108
|
positional: "optional",
|
|
110
109
|
stdin: "none",
|
|
111
|
-
flags: { "include-dirty": "boolean", diff: "boolean",
|
|
112
|
-
usage: "audit [<contract>|@<contract>] [--include-dirty] [--diff] [--
|
|
110
|
+
flags: { "include-dirty": "boolean", diff: "boolean", json: "boolean" },
|
|
111
|
+
usage: "audit [<contract>|@<contract>] [--include-dirty] [--diff] [--json]",
|
|
113
112
|
purpose: "Ask what candidate preparation, Verification, and target placement would do.",
|
|
114
113
|
},
|
|
115
114
|
reconcile: {
|
|
@@ -131,7 +130,7 @@ export const CONTRACT_COMMAND_SPECS = {
|
|
|
131
130
|
stdin: "none",
|
|
132
131
|
flags: { json: "boolean" },
|
|
133
132
|
usage: "settings [--json]",
|
|
134
|
-
purpose: "
|
|
133
|
+
purpose: "Show effective Settings (user + project, read-only)",
|
|
135
134
|
},
|
|
136
135
|
region: {
|
|
137
136
|
positional: "optional",
|
|
@@ -218,7 +217,6 @@ function parseDeliver(parts) {
|
|
|
218
217
|
return {
|
|
219
218
|
command: "deliver",
|
|
220
219
|
...(contract === undefined ? {} : { contract }),
|
|
221
|
-
...(parts.actor === undefined ? {} : { actor: parts.actor }),
|
|
222
220
|
...(message === undefined ? {} : { message }),
|
|
223
221
|
includeDirty: parts.flags["include-dirty"] === true,
|
|
224
222
|
materializeConflict: parts.flags["materialize-conflict"] === true,
|
|
@@ -240,7 +238,6 @@ function parseReview(parts) {
|
|
|
240
238
|
verdict: parts.flags.satisfied === true ? "satisfied" : "unsatisfied",
|
|
241
239
|
...(summary === undefined ? {} : { summary }),
|
|
242
240
|
...(parts.stdin ? { summaryFromStdin: true } : {}),
|
|
243
|
-
...(parts.actor === undefined ? {} : { actor: parts.actor }),
|
|
244
241
|
output: parts.output,
|
|
245
242
|
};
|
|
246
243
|
}
|
|
@@ -301,6 +298,28 @@ function parseLs(parts) {
|
|
|
301
298
|
}
|
|
302
299
|
export function renderContractHelp(command) {
|
|
303
300
|
const spec = CONTRACT_COMMAND_SPECS[command];
|
|
301
|
+
if (command === "settings") {
|
|
302
|
+
return [
|
|
303
|
+
"Show effective Settings — the merged read-only view of:",
|
|
304
|
+
" user ~/.keiyaku/settings.json",
|
|
305
|
+
" project <WorldRoot>/.keiyaku/settings.json",
|
|
306
|
+
"A project record wholly shadows the same-name user record.",
|
|
307
|
+
"",
|
|
308
|
+
"Shape: namespace -> entry -> JSON value. There is no write",
|
|
309
|
+
"command; edit the files directly.",
|
|
310
|
+
"",
|
|
311
|
+
"Recognized settings:",
|
|
312
|
+
" gates gate bundles selected by bind and amend",
|
|
313
|
+
" worktree commands run when worktrees are created or destroyed",
|
|
314
|
+
" git.requireBranchesToBeUpToDate whether deliver and audit require up-to-date target branches",
|
|
315
|
+
" providers the available Akuma and how each is run",
|
|
316
|
+
"",
|
|
317
|
+
"Each entry is validated by the feature that reads it. A rejected",
|
|
318
|
+
"value's diagnostic states the expected shape.",
|
|
319
|
+
"",
|
|
320
|
+
usageLine(spec.usage),
|
|
321
|
+
].join("\n");
|
|
322
|
+
}
|
|
304
323
|
const help = `${spec.purpose}\n\n${usageLine(spec.usage)}`;
|
|
305
324
|
return spec.details === undefined ? help : `${help}\n\n${spec.details}`;
|
|
306
325
|
}
|
|
@@ -352,7 +371,6 @@ export function parseContractCommand(parts) {
|
|
|
352
371
|
...(contract === undefined ? {} : { contract }),
|
|
353
372
|
includeDirty: parts.flags["include-dirty"] === true,
|
|
354
373
|
showDiff: parts.flags.diff === true,
|
|
355
|
-
...(parts.actor === undefined ? {} : { actor: parts.actor }),
|
|
356
374
|
output: parts.output,
|
|
357
375
|
};
|
|
358
376
|
}
|
|
@@ -17,6 +17,7 @@ export type InstallInvocationResult = Readonly<{
|
|
|
17
17
|
}>;
|
|
18
18
|
export type InstallRunner = (input: ProcessInput) => Promise<ProcessOutcome>;
|
|
19
19
|
export declare const INSTALL_USAGE = "install <codex|claude|opencode|pi> [--json]\ninstall --all [--json]";
|
|
20
|
+
export declare const INSTALL_ROOT_PURPOSE = "Install Keiyaku into coding harnesses";
|
|
20
21
|
export declare function parseInstallCommand(argv: readonly string[]): ParsedInstallCommand;
|
|
21
22
|
export declare function renderInstallHelp(): string;
|
|
22
23
|
export declare function installAssetsRoot(): string;
|
|
@@ -3,6 +3,7 @@ import { fileURLToPath } from "node:url";
|
|
|
3
3
|
import { CliUsageError, usageLine } from "../usage.js";
|
|
4
4
|
export const HARNESS_NAMES = ["codex", "claude", "opencode", "pi"];
|
|
5
5
|
export const INSTALL_USAGE = "install <codex|claude|opencode|pi> [--json]\ninstall --all [--json]";
|
|
6
|
+
export const INSTALL_ROOT_PURPOSE = "Install Keiyaku into coding harnesses";
|
|
6
7
|
function isHarness(value) {
|
|
7
8
|
return value !== undefined && HARNESS_NAMES.includes(value);
|
|
8
9
|
}
|
|
@@ -42,7 +43,7 @@ export function parseInstallCommand(argv) {
|
|
|
42
43
|
};
|
|
43
44
|
}
|
|
44
45
|
export function renderInstallHelp() {
|
|
45
|
-
return `Install
|
|
46
|
+
return `Install Keiyaku into your coding harnesses via each harness's native plugin/package installer. --all continues past failures; any failure exits 1.\n\n${usageLine(INSTALL_USAGE)}`;
|
|
46
47
|
}
|
|
47
48
|
const INSTALL_TIMEOUT_MS = 5 * 60 * 1000;
|
|
48
49
|
const ASSET_ROOT = resolve(dirname(fileURLToPath(import.meta.url)), "../../../integrations/marketplace");
|
package/build/src/cli/parse.js
CHANGED
|
@@ -1,25 +1,39 @@
|
|
|
1
1
|
import { isTaskAction, parseTaskCommand, renderTaskHelp, renderTaskUsage, } from "./commands/task.js";
|
|
2
2
|
import { isAkumaAction, parseAkumaCommand, renderAkumaHelp, renderAkumaRootRows, renderAkumaUsage, } from "./commands/akuma.js";
|
|
3
|
-
import { parseInstallCommand, renderInstallHelp } from "./commands/install.js";
|
|
3
|
+
import { INSTALL_ROOT_PURPOSE, parseInstallCommand, renderInstallHelp, } from "./commands/install.js";
|
|
4
4
|
import { CONTRACT_COMMAND_SPECS, parseContractCommand, renderContractHelp as renderContractHelpForOwner, renderContractUsage, } from "./commands/contract.js";
|
|
5
5
|
import { renderTextBlock } from "./render/terminal.js";
|
|
6
6
|
import { CliUsageError, isBlankInput } from "./usage.js";
|
|
7
7
|
export { CliUsageError } from "./usage.js";
|
|
8
8
|
export { renderContractHelp } from "./commands/contract.js";
|
|
9
|
-
const ROOT_USAGE =
|
|
9
|
+
const ROOT_USAGE = [
|
|
10
|
+
"usage: keiyaku <command> [options]",
|
|
11
|
+
" keiyaku <command> --help shows that command's complete usage",
|
|
12
|
+
].join("\n");
|
|
10
13
|
export function renderRootHelp(columns) {
|
|
11
14
|
return renderHelpText([
|
|
15
|
+
"keiyaku — Contract, Task, and Akuma control for one repository",
|
|
16
|
+
"",
|
|
12
17
|
ROOT_USAGE,
|
|
13
18
|
"",
|
|
14
|
-
"
|
|
15
|
-
|
|
16
|
-
|
|
19
|
+
"Contract — standing acceptance",
|
|
20
|
+
...Object.entries(CONTRACT_COMMAND_SPECS)
|
|
21
|
+
.filter(([command]) => command !== "settings")
|
|
22
|
+
.map(([command, spec]) => ` ${command.padEnd(10)} ${spec.purpose}`),
|
|
23
|
+
"",
|
|
24
|
+
"Task — plan memory",
|
|
25
|
+
" task Task coordination; see `keiyaku task --help`.",
|
|
17
26
|
"",
|
|
18
|
-
"
|
|
19
|
-
...Object.entries(CONTRACT_COMMAND_SPECS).map(([command, spec]) => ` keiyaku ${command} ${spec.purpose}`),
|
|
20
|
-
" keiyaku install Install the Keiyaku skills into an agent harness.",
|
|
21
|
-
" keiyaku task Task coordination; see `keiyaku task --help`.",
|
|
27
|
+
"Akuma — invoke capability",
|
|
22
28
|
...renderAkumaRootRows(),
|
|
29
|
+
"",
|
|
30
|
+
"Workspace",
|
|
31
|
+
` install ${INSTALL_ROOT_PURPOSE}`,
|
|
32
|
+
` settings ${CONTRACT_COMMAND_SPECS.settings.purpose}`,
|
|
33
|
+
"",
|
|
34
|
+
"Global options:",
|
|
35
|
+
" -C, --cwd <path> Set the invocation working directory.",
|
|
36
|
+
" --repo <path> Select the Git repository coordinate.",
|
|
23
37
|
].join("\n"), columns);
|
|
24
38
|
}
|
|
25
39
|
function renderHelpText(help, columns) {
|
|
@@ -377,12 +377,13 @@ export function historyText(command, result, context) {
|
|
|
377
377
|
...groupedRows(result.history.rows, context, true),
|
|
378
378
|
].join("\n");
|
|
379
379
|
}
|
|
380
|
-
export function tellText(result) {
|
|
380
|
+
export function tellText(result, context) {
|
|
381
381
|
const wake = result.result.tell.wake;
|
|
382
382
|
const target = identity(result.result.akuma, result.alias);
|
|
383
|
+
const row = groupedRows([result.result.tell.row], context).join("\n");
|
|
383
384
|
if (wake.kind === "failed") {
|
|
384
385
|
const child = "child" in wake ? wake.child : undefined;
|
|
385
|
-
return `${target}\n${SNAPSHOT_RULER}\n! tell delivery failed · ${safeText(wake.diagnostic)}${child === undefined ? "" : ` · log ${child.log.path} ${child.log.from}..${child.log.to}`}`;
|
|
386
|
+
return `${target}\n${SNAPSHOT_RULER}\n${row}\n! tell delivery failed · ${safeText(wake.diagnostic)}${child === undefined ? "" : ` · log ${child.log.path} ${child.log.from}..${child.log.to}`}`;
|
|
386
387
|
}
|
|
387
|
-
return `${target}\n${SNAPSHOT_RULER}\n
|
|
388
|
+
return `${target}\n${SNAPSHOT_RULER}\n${row}`;
|
|
388
389
|
}
|
|
@@ -69,7 +69,7 @@ export function renderAkumaText(command, result, context = DEFAULT_CONTEXT) {
|
|
|
69
69
|
return waitText(result, context);
|
|
70
70
|
case "tell":
|
|
71
71
|
return result.mode === "ordinary"
|
|
72
|
-
? tellText(result)
|
|
72
|
+
? tellText(result, context)
|
|
73
73
|
: mutationObservationStageText(result.result.id, result.result.observation, context, {
|
|
74
74
|
...(result.alias === undefined ? {} : { alias: result.alias }),
|
|
75
75
|
showLife: false,
|
|
@@ -140,7 +140,7 @@ export function renderCatalogText(catalog) {
|
|
|
140
140
|
return renderContractCatalog(catalog);
|
|
141
141
|
if (catalog.kind === "archetypes") {
|
|
142
142
|
return [
|
|
143
|
-
`
|
|
143
|
+
`available Akuma ${catalog.rows.length}`,
|
|
144
144
|
"",
|
|
145
145
|
...catalog.rows.flatMap((row) => [
|
|
146
146
|
`${safeText(row.name)}${row.model === undefined ? "" : ` - ${safeText(row.model)}`}`,
|
|
@@ -11,6 +11,16 @@ function retryLines(detail, indent, columns) {
|
|
|
11
11
|
}
|
|
12
12
|
return renderOpaqueBlock(detail.kind, indent, columns);
|
|
13
13
|
}
|
|
14
|
+
function refMigrationConflictRows(lag, columns) {
|
|
15
|
+
const lines = [];
|
|
16
|
+
receiptRow(lines, "!", "lag", [
|
|
17
|
+
{
|
|
18
|
+
text: `ref-migration-conflict legacy=${lag.legacyRef}@${lag.legacyOid} current=${lag.currentRef}@${lag.currentOid}`,
|
|
19
|
+
opaque: true,
|
|
20
|
+
},
|
|
21
|
+
], columns);
|
|
22
|
+
return lines;
|
|
23
|
+
}
|
|
14
24
|
function lagRows(lag, columns) {
|
|
15
25
|
const lines = [];
|
|
16
26
|
if (lag.kind === "worktree-retained") {
|
|
@@ -49,6 +59,9 @@ function lagRows(lag, columns) {
|
|
|
49
59
|
receiptRow(lines, "!", "lag", [{ text: `contract-file-failed ${lag.worktree} ${lag.path}`, opaque: true }], columns);
|
|
50
60
|
receiptPayload(lines, "diagnostic", lag.diagnostic);
|
|
51
61
|
}
|
|
62
|
+
else if (lag.kind === "ref-migration-conflict") {
|
|
63
|
+
return refMigrationConflictRows(lag, columns);
|
|
64
|
+
}
|
|
52
65
|
else {
|
|
53
66
|
receiptRow(lines, "!", "lag", [{ text: `reconcile-failed ${lag.stage}`, opaque: true }], columns);
|
|
54
67
|
receiptPayload(lines, "diagnostic", lag.diagnostic);
|
|
@@ -1,7 +1,28 @@
|
|
|
1
1
|
import { visibleFleetRows } from "../../kanshi/fleet.js";
|
|
2
|
-
import { boundedActivity, entityLines, identityLine, plumbFacts, renderSectionBlock, safeText, tone, } from "./terminal.js";
|
|
2
|
+
import { boundedActivity, elapsedMilliseconds, entityLines, identityLine, plumbFacts, RECENT_TONE_MS, renderSectionBlock, safeText, tone, } from "./terminal.js";
|
|
3
3
|
const PLUMB = " │ ";
|
|
4
4
|
const NARROW_COLUMNS = 72;
|
|
5
|
+
function mostRecentTimestamp(...values) {
|
|
6
|
+
return values.reduce((latest, value) => {
|
|
7
|
+
if (value === null || value === undefined)
|
|
8
|
+
return latest;
|
|
9
|
+
return latest === null || value > latest ? value : latest;
|
|
10
|
+
}, null);
|
|
11
|
+
}
|
|
12
|
+
function akumaStatusTone(row, observedAt) {
|
|
13
|
+
if (row.life === "stillborn" || row.life === "hung" || row.life === "stranded")
|
|
14
|
+
return "alert";
|
|
15
|
+
if (row.life === "killed")
|
|
16
|
+
return "dim";
|
|
17
|
+
const lifeAt = "lifeAt" in row ? row.lifeAt : null;
|
|
18
|
+
const lastActivityAt = "lastActivityAt" in row ? row.lastActivityAt : null;
|
|
19
|
+
const latestAge = elapsedMilliseconds(mostRecentTimestamp(lifeAt, lastActivityAt), observedAt);
|
|
20
|
+
if (row.life === "asleep")
|
|
21
|
+
return latestAge !== null && latestAge <= RECENT_TONE_MS ? "recent" : "dim";
|
|
22
|
+
if (row.life === "running" && latestAge !== null && latestAge <= RECENT_TONE_MS)
|
|
23
|
+
return "recent";
|
|
24
|
+
return null;
|
|
25
|
+
}
|
|
5
26
|
function akumaMark(life) {
|
|
6
27
|
return life === "running"
|
|
7
28
|
? "●"
|
|
@@ -48,6 +69,8 @@ function renderAkuma(report, context) {
|
|
|
48
69
|
return ["AKUMA // unavailable", "", tone(`! ${safeText(section.failure.message)}`, "alert", context.color)];
|
|
49
70
|
const rows = visibleFleetRows(section.value.rows);
|
|
50
71
|
const rowLines = rows.map((row) => {
|
|
72
|
+
const statusTone = akumaStatusTone(row, report.observedAt);
|
|
73
|
+
const mark = statusTone === null ? akumaMark(row.life) : tone(akumaMark(row.life), statusTone, context.color);
|
|
51
74
|
const lifeAt = "lifeAt" in row ? row.lifeAt : null;
|
|
52
75
|
const life = `${row.life} · ${formatAge(lifeAt, report.observedAt)}`;
|
|
53
76
|
const activity = "lastActivityAt" in row && row.lastActivityAt !== null
|
|
@@ -60,16 +83,14 @@ function renderAkuma(report, context) {
|
|
|
60
83
|
const snapshot = activitySnapshotLine(row);
|
|
61
84
|
const aliases = akumaLabel(row);
|
|
62
85
|
if (context.columns > NARROW_COLUMNS) {
|
|
63
|
-
const lines = [
|
|
64
|
-
identityLine(akumaMark(row.life), row.id, `${aliases} · ${[...key, ...relation].join(" · ")}`.trim()),
|
|
65
|
-
];
|
|
86
|
+
const lines = [identityLine(mark, row.id, `${aliases} · ${[...key, ...relation].join(" · ")}`.trim())];
|
|
66
87
|
return snapshot === undefined
|
|
67
88
|
? lines
|
|
68
89
|
: [...lines, ...plumbFacts([boundedActivity(snapshot, context.columns, PLUMB)], context.columns)];
|
|
69
90
|
}
|
|
70
91
|
const identity = aliases.length === 0 ? row.id : `${row.id} ${aliases}`;
|
|
71
92
|
const lines = entityLines({
|
|
72
|
-
mark
|
|
93
|
+
mark,
|
|
73
94
|
identity,
|
|
74
95
|
state: key[0],
|
|
75
96
|
title: "",
|
|
@@ -1,8 +1,29 @@
|
|
|
1
1
|
import { abbreviateGitIds, afterWording, candidateFact, dependentWording, displayGitId, gateFact, gitIdsInRow, mergeSummary, targetMovementFacts, } from "./contract-observation.js";
|
|
2
|
-
import { entityLines, identityLine, plumbFacts, renderTextBlock, renderSectionBlock, safeText, tone, } from "./terminal.js";
|
|
2
|
+
import { entityLines, elapsedMilliseconds, identityLine, plumbFacts, RECENT_TONE_MS, renderTextBlock, renderSectionBlock, safeText, tone, } from "./terminal.js";
|
|
3
3
|
import { akumaMark, endpointFact, formatAge, NARROW_COLUMNS, renderAkuma } from "./kanshi-akuma.js";
|
|
4
4
|
const PLUMB = " │ ";
|
|
5
5
|
const MAX_VISIBLE_ROWS = 10;
|
|
6
|
+
const REVIEW_ATTENTION_MS = 15 * 60 * 1_000;
|
|
7
|
+
const PENDING_ATTENTION_MS = 60 * 60 * 1_000;
|
|
8
|
+
function contractHasError(row) {
|
|
9
|
+
return (row.title === null ||
|
|
10
|
+
row.gates.reports.some((report) => report.current.kind === "attested" && report.current.verdict === "unsatisfied") ||
|
|
11
|
+
row.targetLag.kind === "unknown" ||
|
|
12
|
+
row.workspaceObservation.kind === "failed" ||
|
|
13
|
+
row.workspaceObservation.kind === "unavailable" ||
|
|
14
|
+
row.issue !== undefined);
|
|
15
|
+
}
|
|
16
|
+
function contractStatusTone(row, observedAt) {
|
|
17
|
+
if (contractHasError(row))
|
|
18
|
+
return "alert";
|
|
19
|
+
const phaseAge = elapsedMilliseconds(row.phaseAt, observedAt);
|
|
20
|
+
if (row.phase === "tendered" && phaseAge !== null && phaseAge >= REVIEW_ATTENTION_MS)
|
|
21
|
+
return "attention";
|
|
22
|
+
if ((row.phase === "waiting" || row.phase === "bound") && phaseAge !== null && phaseAge >= PENDING_ATTENTION_MS)
|
|
23
|
+
return "attention";
|
|
24
|
+
const journalAge = elapsedMilliseconds(row.lastJournalAt, observedAt);
|
|
25
|
+
return journalAge !== null && journalAge <= RECENT_TONE_MS ? "recent" : null;
|
|
26
|
+
}
|
|
6
27
|
function contractMark(row) {
|
|
7
28
|
if (row.phase === "claimed")
|
|
8
29
|
return "✓";
|
|
@@ -189,9 +210,10 @@ function namespaceTaskFacts(row) {
|
|
|
189
210
|
}
|
|
190
211
|
function renderSelectedContractRow(row, report, context, abbreviations) {
|
|
191
212
|
const title = row.title ?? "title unavailable";
|
|
213
|
+
const statusTone = contractStatusTone(row, report.observedAt);
|
|
192
214
|
const lines = [
|
|
193
215
|
...entityLines({
|
|
194
|
-
mark: contractMark(row),
|
|
216
|
+
mark: statusTone === null ? contractMark(row) : tone(contractMark(row), statusTone, context.color),
|
|
195
217
|
identity: row.id,
|
|
196
218
|
state: `${row.phase} · ${formatAge(row.phaseAt, report.observedAt)}`,
|
|
197
219
|
title,
|
|
@@ -255,8 +277,9 @@ function renderWorldContractRow(row, report, context) {
|
|
|
255
277
|
...(row.holder.kind === "unavailable" ? ["! task · unavailable"] : []),
|
|
256
278
|
...(linkedAkumaSummary(row, report) === undefined ? [] : [linkedAkumaSummary(row, report)]),
|
|
257
279
|
];
|
|
280
|
+
const statusTone = contractStatusTone(row, report.observedAt);
|
|
258
281
|
return entityLines({
|
|
259
|
-
mark: contractMark(row),
|
|
282
|
+
mark: statusTone === null ? contractMark(row) : tone(contractMark(row), statusTone, context.color),
|
|
260
283
|
identity: row.id,
|
|
261
284
|
state: `${row.phase} · ${formatAge(row.lastJournalAt, report.observedAt)}`,
|
|
262
285
|
title,
|
|
@@ -32,7 +32,10 @@ type CheckoutNotFollowable = Readonly<{
|
|
|
32
32
|
export declare function checkoutNotFollowableLines(refusal: CheckoutNotFollowable): readonly string[];
|
|
33
33
|
export declare function renderTextBlock(value: string, indent: string, columns: number): readonly string[];
|
|
34
34
|
export declare function renderOpaqueBlock(value: string, indent: string, columns: number): readonly string[];
|
|
35
|
-
export
|
|
35
|
+
export type SemanticTone = "dim" | "recent" | "attention" | "alert";
|
|
36
|
+
export declare const RECENT_TONE_MS: number;
|
|
37
|
+
export declare function elapsedMilliseconds(source: string | null | undefined, observedAt: string): number | null;
|
|
38
|
+
export declare function tone(value: string, kind: SemanticTone, color: boolean): string;
|
|
36
39
|
export declare function boundedActivity(value: string, columns: number, prefix: string): string;
|
|
37
40
|
export declare function plumbFacts(facts: readonly string[], columns: number): readonly string[];
|
|
38
41
|
export declare function identityLine(mark: string, identity: string, extra?: string): string;
|
|
@@ -188,10 +188,21 @@ export function renderOpaqueBlock(value, indent, columns) {
|
|
|
188
188
|
}
|
|
189
189
|
return lines;
|
|
190
190
|
}
|
|
191
|
+
export const RECENT_TONE_MS = 5 * 60 * 1_000;
|
|
192
|
+
export function elapsedMilliseconds(source, observedAt) {
|
|
193
|
+
if (source === null || source === undefined)
|
|
194
|
+
return null;
|
|
195
|
+
const sourceMs = Date.parse(source);
|
|
196
|
+
const observedMs = Date.parse(observedAt);
|
|
197
|
+
if (!Number.isFinite(sourceMs) || !Number.isFinite(observedMs))
|
|
198
|
+
return null;
|
|
199
|
+
return Math.max(0, observedMs - sourceMs);
|
|
200
|
+
}
|
|
191
201
|
export function tone(value, kind, color) {
|
|
192
202
|
if (!color)
|
|
193
203
|
return value;
|
|
194
|
-
|
|
204
|
+
const code = kind === "dim" ? 2 : kind === "recent" ? 32 : kind === "attention" ? 33 : 31;
|
|
205
|
+
return `\u001b[${code}m${value}\u001b[0m`;
|
|
195
206
|
}
|
|
196
207
|
const KANSHI_NARROW_COLUMNS = 72;
|
|
197
208
|
export function boundedActivity(value, columns, prefix) {
|
package/build/src/cli/runtime.js
CHANGED
|
@@ -11,7 +11,7 @@ export function invocationStart(command) {
|
|
|
11
11
|
return "⧖ auditing";
|
|
12
12
|
if (command.command === "reconcile")
|
|
13
13
|
return "⧖ reconciling";
|
|
14
|
-
return command.command === "install" ? "⧖ installing
|
|
14
|
+
return command.command === "install" ? "⧖ installing harness integrations" : undefined;
|
|
15
15
|
}
|
|
16
16
|
function writeCliStream(stream, body) {
|
|
17
17
|
stream.write(body.endsWith("\n") ? body : `${body}\n`);
|
package/build/src/git/nuke.js
CHANGED
|
@@ -3,7 +3,7 @@ import { isAbsolute, relative, sep } from "node:path";
|
|
|
3
3
|
import { nukeEmptyPlaceAuthority, readPlaceRegister, releaseManagedWorktrees, withPlaceAuthorityFence, } from "../workspace-place.js";
|
|
4
4
|
import { GitPlumbingError, runGit } from "./process.js";
|
|
5
5
|
import { confirmPrivateStatePublication, withPrivateStatePublicationSeat } from "./private-state-seat.js";
|
|
6
|
-
import { CANDIDATE_PIN_REF_NAMESPACE, DELIVERY_REF_NAMESPACE, GIT_REF,
|
|
6
|
+
import { CANDIDATE_PIN_REF_NAMESPACE, DELIVERY_REF_NAMESPACE, GIT_REF, LEGACY_CANDIDATE_PIN_REF_NAMESPACE, LEGACY_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);
|
|
@@ -120,8 +120,8 @@ async function removeOwnedRefs(repository) {
|
|
|
120
120
|
const roots = [
|
|
121
121
|
DELIVERY_REF_NAMESPACE,
|
|
122
122
|
CANDIDATE_PIN_REF_NAMESPACE,
|
|
123
|
-
|
|
124
|
-
|
|
123
|
+
LEGACY_DELIVERY_REF_NAMESPACE,
|
|
124
|
+
LEGACY_CANDIDATE_PIN_REF_NAMESPACE,
|
|
125
125
|
];
|
|
126
126
|
for (const root of roots) {
|
|
127
127
|
const refs = (await runGit(repository, ["for-each-ref", "--format=%(refname)", root]))
|
package/build/src/git/process.js
CHANGED
|
@@ -58,10 +58,13 @@ async function executeGit(repository, args, input, environment) {
|
|
|
58
58
|
inputError = error;
|
|
59
59
|
});
|
|
60
60
|
child.stdin.end(input);
|
|
61
|
-
const terminal = await
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
61
|
+
const terminal = await Promise.race([
|
|
62
|
+
new Promise((resolveTerminal) => {
|
|
63
|
+
child.once("error", (error) => resolveTerminal({ code: null, error }));
|
|
64
|
+
child.once("close", (code) => resolveTerminal({ code }));
|
|
65
|
+
}),
|
|
66
|
+
owned.terminationFailure,
|
|
67
|
+
]);
|
|
65
68
|
await owned.waitTermination();
|
|
66
69
|
const output = Buffer.concat(stdout);
|
|
67
70
|
if (!owned.cancelled() && terminal.code === 0 && inputError === undefined)
|
|
@@ -61,7 +61,7 @@ function batchError(child, stderr, message, status) {
|
|
|
61
61
|
async function closeBatchProcess(process, child, closed, spawnError, stderr) {
|
|
62
62
|
if (!child.stdin.destroyed)
|
|
63
63
|
child.stdin.end();
|
|
64
|
-
const outcome = await closed;
|
|
64
|
+
const outcome = await Promise.race([closed, process.terminationFailure]);
|
|
65
65
|
await process.waitTermination();
|
|
66
66
|
if (spawnError !== null || outcome.code !== 0) {
|
|
67
67
|
throw batchError(child, stderr, process.cancelled() ? "git process cancelled" : "git cat-file --batch did not close cleanly", outcome.code);
|
|
@@ -4,6 +4,7 @@ import type { ContractId, ContractState, SnapshotId } from "../core/facts/types.
|
|
|
4
4
|
import type { GitDecodeChannel } from "./read-observation.js";
|
|
5
5
|
import { type TargetCheckoutEffect, type TargetCheckoutLag } from "./target-placement.js";
|
|
6
6
|
import { type WorktreeHookLag, type WorktreeHooks } from "./hooks.js";
|
|
7
|
+
import { type RefMigrationConflict } from "./ref-migration.js";
|
|
7
8
|
import type { UnsealedBytes } from "./terminal-seal.js";
|
|
8
9
|
export type Effect = Readonly<{
|
|
9
10
|
kind: "worktree";
|
|
@@ -53,7 +54,7 @@ export type ReconcileFailure = Readonly<{
|
|
|
53
54
|
stage: "observation" | "effect";
|
|
54
55
|
diagnostic: string;
|
|
55
56
|
}>;
|
|
56
|
-
export type ReconcileLag = WorktreeRetained | WorktreeFollowRetained | UnsealedBytes | TargetCheckoutLag | WorktreeHookLag | ReconcileFailure;
|
|
57
|
+
export type ReconcileLag = WorktreeRetained | WorktreeFollowRetained | UnsealedBytes | TargetCheckoutLag | WorktreeHookLag | RefMigrationConflict | ReconcileFailure;
|
|
57
58
|
export type ReconcileResult = Readonly<{
|
|
58
59
|
effects: readonly Effect[];
|
|
59
60
|
lag: readonly ReconcileLag[];
|
|
@@ -10,6 +10,7 @@ import { acquireTargetPlacementFence, recoverTargetPlacement, } from "./target-p
|
|
|
10
10
|
import { runCreateHooks } from "./hooks.js";
|
|
11
11
|
import { followDependentManagedWorktree, followManagedWorktree, worktreePath } from "./workspace.js";
|
|
12
12
|
import { removeCollectableScratchWorktrees } from "./scratch.js";
|
|
13
|
+
import { migrateContractCustodyRefs } from "./ref-migration.js";
|
|
13
14
|
import { reconcileTerminalManagedWorktree, removeRef, updateRef } from "./terminal-reconcile.js";
|
|
14
15
|
const pathExists = (path) => access(path).then(() => true, () => false);
|
|
15
16
|
function deliveryRefFor(contract) {
|
|
@@ -151,6 +152,11 @@ async function reconcileWithTopology(input, state, topology) {
|
|
|
151
152
|
await removeCollectableScratch(repository, topology, effects, lag);
|
|
152
153
|
if (!state)
|
|
153
154
|
return complete(effects, lag);
|
|
155
|
+
const migration = await migrateContractCustodyRefs(repository, state.id);
|
|
156
|
+
effects.push(...migration.effects);
|
|
157
|
+
lag.push(...migration.lag);
|
|
158
|
+
if (migration.lag.length > 0)
|
|
159
|
+
return complete(effects, lag);
|
|
154
160
|
const targetCheckouts = await reconcileTargetCheckouts(repository, state);
|
|
155
161
|
effects.push(...targetCheckouts.effects);
|
|
156
162
|
lag.push(...targetCheckouts.lag);
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import type { ContractId } from "../core/facts/types.js";
|
|
2
|
+
import { type GitRepository } from "./process.js";
|
|
3
|
+
import { type GitOid } from "./repository.js";
|
|
4
|
+
export type RefMigrationEffect = Readonly<{
|
|
5
|
+
kind: "ref";
|
|
6
|
+
name: string;
|
|
7
|
+
before: GitOid | null;
|
|
8
|
+
after: GitOid | null;
|
|
9
|
+
action: "created" | "removed";
|
|
10
|
+
}>;
|
|
11
|
+
export type RefMigrationConflict = Readonly<{
|
|
12
|
+
kind: "ref-migration-conflict";
|
|
13
|
+
legacyRef: string;
|
|
14
|
+
legacyOid: GitOid;
|
|
15
|
+
currentRef: string;
|
|
16
|
+
currentOid: GitOid;
|
|
17
|
+
}>;
|
|
18
|
+
export type RefMigrationResult = Readonly<{
|
|
19
|
+
effects: readonly RefMigrationEffect[];
|
|
20
|
+
lag: readonly RefMigrationConflict[];
|
|
21
|
+
}>;
|
|
22
|
+
export declare function migrateContractCustodyRefs(repository: GitRepository, contract: ContractId): Promise<RefMigrationResult>;
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
import { contractPhysicalName } from "./identity.js";
|
|
2
|
+
import { runGit } from "./process.js";
|
|
3
|
+
import { CANDIDATE_PIN_REF_NAMESPACE, DELIVERY_REF_NAMESPACE, LEGACY_CANDIDATE_PIN_REF_NAMESPACE, LEGACY_DELIVERY_REF_NAMESPACE, readRef, } from "./repository.js";
|
|
4
|
+
export async function migrateContractCustodyRefs(repository, contract) {
|
|
5
|
+
const leaf = contractPhysicalName(contract);
|
|
6
|
+
const pairs = [
|
|
7
|
+
{
|
|
8
|
+
legacy: `${LEGACY_DELIVERY_REF_NAMESPACE}/${leaf}`,
|
|
9
|
+
current: `${DELIVERY_REF_NAMESPACE}/${leaf}`,
|
|
10
|
+
},
|
|
11
|
+
{
|
|
12
|
+
legacy: `${LEGACY_CANDIDATE_PIN_REF_NAMESPACE}/${leaf}`,
|
|
13
|
+
current: `${CANDIDATE_PIN_REF_NAMESPACE}/${leaf}`,
|
|
14
|
+
},
|
|
15
|
+
];
|
|
16
|
+
const observed = await Promise.all(pairs.map(async (pair) => {
|
|
17
|
+
const [legacyOid, currentOid] = await Promise.all([
|
|
18
|
+
readRef(repository, pair.legacy),
|
|
19
|
+
readRef(repository, pair.current),
|
|
20
|
+
]);
|
|
21
|
+
return { ...pair, legacyOid, currentOid };
|
|
22
|
+
}));
|
|
23
|
+
const lag = observed.flatMap((pair) => pair.legacyOid !== null && pair.currentOid !== null && pair.currentOid !== pair.legacyOid
|
|
24
|
+
? [
|
|
25
|
+
{
|
|
26
|
+
kind: "ref-migration-conflict",
|
|
27
|
+
legacyRef: pair.legacy,
|
|
28
|
+
legacyOid: pair.legacyOid,
|
|
29
|
+
currentRef: pair.current,
|
|
30
|
+
currentOid: pair.currentOid,
|
|
31
|
+
},
|
|
32
|
+
]
|
|
33
|
+
: []);
|
|
34
|
+
if (lag.length > 0)
|
|
35
|
+
return { effects: [], lag };
|
|
36
|
+
const migrating = observed.filter((pair) => pair.legacyOid !== null);
|
|
37
|
+
if (migrating.length === 0)
|
|
38
|
+
return { effects: [], lag: [] };
|
|
39
|
+
const lines = ["start"];
|
|
40
|
+
const effects = [];
|
|
41
|
+
for (const pair of migrating) {
|
|
42
|
+
if (pair.currentOid === null) {
|
|
43
|
+
lines.push(`create ${pair.current} ${pair.legacyOid}`);
|
|
44
|
+
effects.push({ kind: "ref", name: pair.current, before: null, after: pair.legacyOid, action: "created" });
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
lines.push(`verify ${pair.current} ${pair.currentOid}`);
|
|
48
|
+
}
|
|
49
|
+
lines.push(`delete ${pair.legacy} ${pair.legacyOid}`);
|
|
50
|
+
effects.push({ kind: "ref", name: pair.legacy, before: pair.legacyOid, after: null, action: "removed" });
|
|
51
|
+
}
|
|
52
|
+
lines.push("prepare", "commit", "");
|
|
53
|
+
await runGit(repository, ["update-ref", "--stdin", "--no-deref"], lines.join("\n"));
|
|
54
|
+
return { effects, lag: [] };
|
|
55
|
+
}
|
|
@@ -2,10 +2,10 @@ import { type GitRepository } from "./process.js";
|
|
|
2
2
|
import { type TreeChange, type TreeEntry } from "./tree.js";
|
|
3
3
|
export type { TreeChange } from "./tree.js";
|
|
4
4
|
export declare const GIT_REF = "refs/heads/keiyaku-state";
|
|
5
|
-
export declare const DELIVERY_REF_NAMESPACE = "refs/
|
|
6
|
-
export declare const CANDIDATE_PIN_REF_NAMESPACE = "refs/
|
|
7
|
-
export declare const
|
|
8
|
-
export declare const
|
|
5
|
+
export declare const DELIVERY_REF_NAMESPACE = "refs/keiyaku/delivery";
|
|
6
|
+
export declare const CANDIDATE_PIN_REF_NAMESPACE = "refs/keiyaku/candidate";
|
|
7
|
+
export declare const LEGACY_DELIVERY_REF_NAMESPACE = "refs/heads/keiyaku-delivery";
|
|
8
|
+
export declare const LEGACY_CANDIDATE_PIN_REF_NAMESPACE = "refs/heads/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
11
|
export declare const STATE_COMMIT_SUBJECT = "keiyaku authority - do not delete or rewrite";
|
|
@@ -5,10 +5,10 @@ import { gitObjectId } from "./identity.js";
|
|
|
5
5
|
import { GitPlumbingError, runGit, runGitWithEnvironment } from "./process.js";
|
|
6
6
|
import { parseTreeObject, prepareTreeUpdate, treeUpdate, validPath, } from "./tree.js";
|
|
7
7
|
export const GIT_REF = "refs/heads/keiyaku-state";
|
|
8
|
-
export const DELIVERY_REF_NAMESPACE = "refs/
|
|
9
|
-
export const CANDIDATE_PIN_REF_NAMESPACE = "refs/
|
|
10
|
-
export const
|
|
11
|
-
export const
|
|
8
|
+
export const DELIVERY_REF_NAMESPACE = "refs/keiyaku/delivery";
|
|
9
|
+
export const CANDIDATE_PIN_REF_NAMESPACE = "refs/keiyaku/candidate";
|
|
10
|
+
export const LEGACY_DELIVERY_REF_NAMESPACE = "refs/heads/keiyaku-delivery";
|
|
11
|
+
export const LEGACY_CANDIDATE_PIN_REF_NAMESPACE = "refs/heads/keiyaku-candidate";
|
|
12
12
|
export const GIT_FORMAT_PATH = "meta/format.json";
|
|
13
13
|
const CURRENT_FORMAT_VERSION = 4;
|
|
14
14
|
export const GIT_FORMAT_BYTES = `{"version":${CURRENT_FORMAT_VERSION}}\n`;
|
|
@@ -19,10 +19,10 @@ export function isKeiyakuOwnedRef(ref) {
|
|
|
19
19
|
ref.startsWith(`${DELIVERY_REF_NAMESPACE}/`) ||
|
|
20
20
|
ref === CANDIDATE_PIN_REF_NAMESPACE ||
|
|
21
21
|
ref.startsWith(`${CANDIDATE_PIN_REF_NAMESPACE}/`) ||
|
|
22
|
-
ref ===
|
|
23
|
-
ref.startsWith(`${
|
|
24
|
-
ref ===
|
|
25
|
-
ref.startsWith(`${
|
|
22
|
+
ref === LEGACY_DELIVERY_REF_NAMESPACE ||
|
|
23
|
+
ref.startsWith(`${LEGACY_DELIVERY_REF_NAMESPACE}/`) ||
|
|
24
|
+
ref === LEGACY_CANDIDATE_PIN_REF_NAMESPACE ||
|
|
25
|
+
ref.startsWith(`${LEGACY_CANDIDATE_PIN_REF_NAMESPACE}/`));
|
|
26
26
|
}
|
|
27
27
|
export class NoGitWorldError extends Error {
|
|
28
28
|
path;
|