@astrosheep/keiyaku 4.6.11 → 4.6.13
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/plugins/claude/skills/keiyaku/SKILL.md +3 -1
- package/build/plugins/claude/skills/keiyaku-babysit/SKILL.md +1 -1
- package/build/plugins/claude/skills/keiyaku-bind/SKILL.md +3 -2
- package/build/plugins/claude/skills/keiyaku-workflow/SKILL.md +9 -8
- package/build/plugins/codex/skills/keiyaku/SKILL.md +3 -1
- package/build/plugins/codex/skills/keiyaku-babysit/SKILL.md +1 -1
- package/build/plugins/codex/skills/keiyaku-bind/SKILL.md +3 -2
- package/build/plugins/codex/skills/keiyaku-workflow/SKILL.md +9 -8
- package/build/plugins/opencode/skills/keiyaku/SKILL.md +3 -1
- package/build/plugins/opencode/skills/keiyaku-babysit/SKILL.md +1 -1
- package/build/plugins/opencode/skills/keiyaku-bind/SKILL.md +3 -2
- package/build/plugins/opencode/skills/keiyaku-workflow/SKILL.md +9 -8
- package/build/skills/keiyaku/SKILL.md +3 -1
- package/build/skills/keiyaku-babysit/SKILL.md +1 -1
- package/build/skills/keiyaku-bind/SKILL.md +3 -2
- package/build/skills/keiyaku-workflow/SKILL.md +9 -8
- package/build/src/akuma/akuma-errors.d.ts +5 -0
- package/build/src/akuma/akuma-errors.js +9 -0
- package/build/src/akuma/akuma-owner.d.ts +14 -19
- package/build/src/akuma/akuma-owner.js +56 -54
- package/build/src/akuma/akuma-selection-execution.d.ts +5 -4
- package/build/src/akuma/akuma-selection-execution.js +59 -17
- package/build/src/akuma/akuma.d.ts +1 -2
- package/build/src/akuma/allowed.d.ts +2 -3
- package/build/src/akuma/allowed.js +1 -3
- package/build/src/akuma/body.js +17 -7
- package/build/src/akuma/call-initial-tell.d.ts +18 -0
- package/build/src/akuma/call-initial-tell.js +18 -0
- package/build/src/akuma/call-request.d.ts +20 -4
- package/build/src/akuma/heart/facts.d.ts +13 -0
- package/build/src/akuma/heart/facts.js +6 -0
- package/build/src/akuma/heart/index.d.ts +29 -14
- package/build/src/akuma/heart/index.js +75 -29
- package/build/src/akuma/heart/rows.d.ts +9 -2
- package/build/src/akuma/heart/rows.js +72 -11
- package/build/src/akuma/heart/storage.d.ts +2 -8
- package/build/src/akuma/heart/storage.js +13 -13
- package/build/src/akuma/heart/tells.d.ts +3 -1
- package/build/src/akuma/heart/tells.js +18 -2
- package/build/src/akuma/provider.d.ts +2 -4
- package/build/src/akuma/provider.js +29 -6
- package/build/src/akuma/providers/acp/core.js +23 -21
- package/build/src/akuma/providers/claude/index.js +0 -8
- package/build/src/akuma/providers/codex-app-server/index.js +9 -8
- package/build/src/akuma/providers/execution-environment.d.ts +1 -1
- package/build/src/akuma/providers/execution-environment.js +1 -0
- package/build/src/akuma/providers/opencode-sdk/events.js +111 -81
- package/build/src/akuma/providers/opencode-sdk/index.js +179 -150
- package/build/src/akuma/providers/opencode-sdk/native-http.js +7 -3
- package/build/src/akuma/providers/opencode-sdk/session.d.ts +5 -3
- package/build/src/akuma/providers/opencode-sdk/session.js +32 -27
- package/build/src/akuma/providers/paseo/index.js +0 -2
- package/build/src/akuma/providers/pi/index.js +23 -20
- package/build/src/akuma/selection-observation.d.ts +78 -9
- package/build/src/akuma/selection-owner-port.d.ts +2 -1
- package/build/src/akuma/selection-owner-port.js +6 -1
- package/build/src/akuma/selection-request.d.ts +1 -1
- package/build/src/akuma/selection-request.js +8 -3
- package/build/src/akuma/turn-drive.js +79 -48
- package/build/src/akuma-body.js +5 -3
- package/build/src/cli/commands/akuma-grammar.js +2 -2
- package/build/src/cli/commands/akuma.js +24 -16
- package/build/src/cli/commands/contract-grammar.d.ts +3 -7
- package/build/src/cli/commands/contract-grammar.js +12 -10
- package/build/src/cli/commands/contract-help.d.ts +3 -13
- package/build/src/cli/commands/contract-help.js +7 -16
- package/build/src/cli/commands/contract.js +19 -35
- package/build/src/cli/commands/debt.js +30 -29
- package/build/src/cli/parse.js +0 -1
- package/build/src/cli/render/akuma-activity.d.ts +36 -9
- package/build/src/cli/render/akuma-activity.js +142 -65
- package/build/src/cli/render/akuma.d.ts +6 -0
- package/build/src/cli/render/akuma.js +67 -24
- package/build/src/cli/render/catalog.js +0 -1
- package/build/src/cli/render/contract-observation.d.ts +16 -3
- package/build/src/cli/render/contract-observation.js +3 -0
- package/build/src/cli/render/contract.d.ts +2 -2
- package/build/src/cli/render/contract.js +4 -4
- package/build/src/cli/render/delivery-preview.d.ts +7 -0
- package/build/src/cli/render/{audit.js → delivery-preview.js} +29 -27
- package/build/src/cli/render/kanshi-akuma.d.ts +3 -1
- package/build/src/cli/render/kanshi-akuma.js +23 -8
- package/build/src/cli/render/kanshi.js +4 -1
- package/build/src/cli/render/receipt.js +3 -3
- package/build/src/cli/render/refusal.js +2 -2
- package/build/src/cli/render/terminal.d.ts +0 -1
- package/build/src/cli/render/terminal.js +1 -1
- package/build/src/cli/square-identity.d.ts +15 -0
- package/build/src/cli/square-identity.js +180 -0
- package/build/src/contract-worktree.js +1 -1
- package/build/src/core/verbs/placement.d.ts +2 -1
- package/build/src/core/verbs/placement.js +1 -1
- package/build/src/debt/context.d.ts +0 -5
- package/build/src/debt/context.js +32 -44
- package/build/src/git/process.d.ts +1 -0
- package/build/src/git/process.js +18 -1
- package/build/src/git/read-observation.js +2 -1
- package/build/src/git/scratch.d.ts +5 -1
- package/build/src/git/scratch.js +41 -12
- package/build/src/git/target-placement.d.ts +22 -4
- package/build/src/git/target-placement.js +44 -20
- package/build/src/index.d.ts +2 -2
- package/build/src/kanshi/read.js +187 -105
- package/build/src/kanshi/report.d.ts +5 -0
- package/build/src/library/address.d.ts +18 -4
- package/build/src/library/address.js +27 -6
- package/build/src/library/contract-address.d.ts +6 -0
- package/build/src/library/contract-address.js +12 -1
- package/build/src/library/contract-execution.d.ts +2 -2
- package/build/src/library/contract-execution.js +13 -17
- package/build/src/library/contract-operations.d.ts +59 -94
- package/build/src/library/contract-operations.js +23 -19
- package/build/src/library/contract-outcomes.d.ts +3 -3
- package/build/src/library/contract-settings.d.ts +1 -0
- package/build/src/library/contract-settings.js +1 -1
- package/build/src/library/invocation.d.ts +2 -2
- package/build/src/library/invocation.js +1 -1
- package/build/src/library/keiyaku.d.ts +2 -2
- package/build/src/library/keiyaku.js +2 -2
- package/build/src/library/outcome.d.ts +148 -268
- package/build/src/library/outcome.js +4 -8
- package/build/src/library/refusal.d.ts +2 -2
- package/build/src/library/refusal.js +2 -2
- package/build/src/plugin/runtime.js +15 -19
- package/build/src/protocol/{audit.d.ts → delivery-preview.d.ts} +62 -97
- package/build/src/protocol/delivery-preview.js +167 -0
- package/build/src/protocol/progress.d.ts +1 -1
- package/build/src/runtime/proc/run.js +22 -4
- package/build/src/runtime/proc/windows-launch.exe +0 -0
- package/build/src/verification/execution.d.ts +1 -1
- package/build/src/verification/execution.js +5 -3
- package/package.json +5 -2
- package/skills/keiyaku/SKILL.md +3 -1
- package/skills/keiyaku-babysit/SKILL.md +1 -1
- package/skills/keiyaku-bind/SKILL.md +3 -2
- package/skills/keiyaku-workflow/SKILL.md +9 -8
- package/build/src/cli/render/audit.d.ts +0 -7
- package/build/src/protocol/audit.js +0 -203
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { effectCleanup, effectExecutionStops } from "./effects.js";
|
|
2
|
-
import { executionCleanupLines, executionStopLines, receiptPayload, receiptRow,
|
|
2
|
+
import { executionCleanupLines, executionStopLines, receiptPayload, receiptRow, titleLines } from "./receipt.js";
|
|
3
3
|
import { renderRefusalFacts } from "./refusal.js";
|
|
4
|
-
import { abbreviateGitIds, displayGitId } from "./contract-observation.js";
|
|
4
|
+
import { abbreviateGitIds, displayGitId, gateFact } from "./contract-observation.js";
|
|
5
5
|
import { DEFAULT_CLI_COLUMNS, gitShortStat, renderTextBlock, safeText } from "./terminal.js";
|
|
6
6
|
const CHILD = " ";
|
|
7
7
|
function workspaceEvidence(workspace) {
|
|
@@ -16,11 +16,16 @@ function candidateLines(report, columns, addressed, abbreviations) {
|
|
|
16
16
|
return lines;
|
|
17
17
|
}
|
|
18
18
|
const identity = candidate.identity;
|
|
19
|
-
receiptRow(lines, " ", "candidate", [{ text: "
|
|
19
|
+
receiptRow(lines, " ", "candidate", [{ text: "prepared" }, { text: displayGitId(identity.tenderSnapshot, abbreviations), opaque: true }], columns);
|
|
20
20
|
lines.push(`${CHILD}integration result ${displayGitId(identity.integration.snapshot, abbreviations)}`);
|
|
21
21
|
if (!/^0{40}$/u.test(identity.integration.changeId))
|
|
22
22
|
lines.push(`${CHILD}content identity ${displayGitId(identity.integration.changeId, abbreviations)}`);
|
|
23
23
|
lines.push(...workspaceEvidence(candidate.workspace));
|
|
24
|
+
for (const report of candidate.requirements.gates)
|
|
25
|
+
lines.push(`${CHILD}${gateFact(report)}`);
|
|
26
|
+
for (const prerequisite of candidate.requirements.unmetPrerequisites) {
|
|
27
|
+
receiptRow(lines, "!", "prerequisite", [{ text: prerequisite.contractId }, { text: prerequisite.state }], columns);
|
|
28
|
+
}
|
|
24
29
|
lines.push(...renderTextBlock(gitShortStat(candidate.scope), CHILD, columns));
|
|
25
30
|
if (candidate.scope.paths !== undefined) {
|
|
26
31
|
for (const path of candidate.scope.paths) {
|
|
@@ -31,32 +36,23 @@ function candidateLines(report, columns, addressed, abbreviations) {
|
|
|
31
36
|
receiptPayload(lines, "diff", candidate.diff);
|
|
32
37
|
return lines;
|
|
33
38
|
}
|
|
34
|
-
function verificationLines(verification, columns
|
|
39
|
+
function verificationLines(verification, columns) {
|
|
35
40
|
const lines = [];
|
|
36
|
-
if (verification.kind
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
}
|
|
44
|
-
if (verification.kind === "stopped") {
|
|
45
|
-
return stopLines(verification.stop, columns, addressed);
|
|
46
|
-
}
|
|
47
|
-
if (verification.kind === "reused") {
|
|
48
|
-
receiptRow(lines, " ", "verification", [{ text: "reused" }, { text: verification.verdict }], columns);
|
|
49
|
-
if (verification.summary !== undefined)
|
|
50
|
-
receiptPayload(lines, "summary", auditSummary(verification.summary));
|
|
41
|
+
if (verification.kind !== "recorded") {
|
|
42
|
+
const text = verification.kind === "undeclared"
|
|
43
|
+
? "none declared"
|
|
44
|
+
: verification.kind === "required"
|
|
45
|
+
? "required · not run"
|
|
46
|
+
: "not run";
|
|
47
|
+
receiptRow(lines, " ", "verification", [{ text }], columns);
|
|
51
48
|
return lines;
|
|
52
49
|
}
|
|
53
|
-
receiptRow(lines, verification.
|
|
54
|
-
if (verification.summary !== undefined)
|
|
55
|
-
receiptPayload(lines, "summary",
|
|
56
|
-
}
|
|
50
|
+
receiptRow(lines, verification.verdict === "unsatisfied" ? "!" : " ", "verification", [{ text: "recorded" }, { text: verification.verdict }], columns);
|
|
51
|
+
if (verification.summary !== undefined)
|
|
52
|
+
receiptPayload(lines, "summary", previewSummary(verification.summary));
|
|
57
53
|
return lines;
|
|
58
54
|
}
|
|
59
|
-
function
|
|
55
|
+
function previewSummary(summary) {
|
|
60
56
|
return summary.replace(/\[(\d+) (bash|zsh|pwsh) exit (-?\d+)( output-truncated)?\]/gu, (_, number, executor, exit, truncated) => `declaration ${number} · ${executor} exit ${exit}${truncated ?? ""}`);
|
|
61
57
|
}
|
|
62
58
|
function admittedCandidateLines(report, columns) {
|
|
@@ -86,6 +82,12 @@ function targetLines(report, columns, addressed, abbreviations) {
|
|
|
86
82
|
opaque: true,
|
|
87
83
|
},
|
|
88
84
|
], columns);
|
|
85
|
+
for (const checkout of target.checkouts) {
|
|
86
|
+
if (checkout.kind === "followable")
|
|
87
|
+
continue;
|
|
88
|
+
receiptRow(lines, "!", "checkout cannot follow", [{ text: checkout.path, opaque: true }], columns);
|
|
89
|
+
receiptPayload(lines, "reason", checkout.diagnostic);
|
|
90
|
+
}
|
|
89
91
|
return lines;
|
|
90
92
|
}
|
|
91
93
|
if (target.kind === "moved") {
|
|
@@ -114,7 +116,7 @@ function obligationLines(result, columns) {
|
|
|
114
116
|
...executionStopLines(effectExecutionStops(result.effects), columns),
|
|
115
117
|
];
|
|
116
118
|
}
|
|
117
|
-
export function
|
|
119
|
+
export function renderDeliveryPreview(result, context) {
|
|
118
120
|
const report = result.value;
|
|
119
121
|
const columns = context?.columns ?? DEFAULT_CLI_COLUMNS;
|
|
120
122
|
const ids = report.candidate.kind === "ready"
|
|
@@ -130,10 +132,10 @@ export function renderAcceptedAudit(result, context) {
|
|
|
130
132
|
ids.push(report.target.expected, report.target.observed ?? "");
|
|
131
133
|
const abbreviations = abbreviateGitIds(ids);
|
|
132
134
|
return [
|
|
133
|
-
...titleLines("✓", "
|
|
135
|
+
...titleLines("✓", "deliver --dry-run", result.contract, columns),
|
|
134
136
|
...candidateLines(report, columns, result.contract, abbreviations),
|
|
135
137
|
...admittedCandidateLines(report, columns),
|
|
136
|
-
...verificationLines(report.verification, columns
|
|
138
|
+
...verificationLines(report.verification, columns),
|
|
137
139
|
...targetLines(report, columns, result.contract, abbreviations),
|
|
138
140
|
...obligationLines(result, columns),
|
|
139
141
|
].join("\n");
|
|
@@ -5,7 +5,9 @@ declare function endpointFact(id: string, observed: string | undefined): string;
|
|
|
5
5
|
/**
|
|
6
6
|
* One Akuma board section. The World board omits an empty section because its other
|
|
7
7
|
* sections already say what the World holds; a category board states that emptiness
|
|
8
|
-
* itself, since it is the whole answer.
|
|
8
|
+
* itself, since it is the whole answer. A failed Alias observation belongs to the
|
|
9
|
+
* section, so an empty roster still states its emptiness rather than dropping that
|
|
10
|
+
* evidence.
|
|
9
11
|
*/
|
|
10
12
|
declare function renderAkumaBoard(section: Section<AkumaKanshiWorld>, observedAt: string, context: TextRenderContext, emptyRows: readonly string[]): readonly string[];
|
|
11
13
|
declare function renderAkuma(report: KanshiReport, context: TextRenderContext): readonly string[];
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { snapshotActivityLines } from "./akuma-activity.js";
|
|
2
2
|
import { akumaMark } from "./marks.js";
|
|
3
|
-
import { ageText, elapsedMilliseconds, entityLines, identityLine, RECENT_TONE_MS, renderSectionBlock, safeText, tone, } from "./terminal.js";
|
|
3
|
+
import { ageText, elapsedMilliseconds, emptyCatalogue, entityLines, identityLine, RECENT_TONE_MS, renderSectionBlock, safeText, tone, } from "./terminal.js";
|
|
4
4
|
const NARROW_COLUMNS = 72;
|
|
5
5
|
const ACTIVITY_INDENT = " ";
|
|
6
6
|
function mostRecentTimestamp(...values) {
|
|
@@ -29,9 +29,11 @@ function latestActivityLines(snapshot, context) {
|
|
|
29
29
|
const bounded = { ...context, columns: Math.max(1, context.columns - ACTIVITY_INDENT.length) };
|
|
30
30
|
return snapshotActivityLines(snapshot, bounded, { latest: true, tailAnswer: true }).map((line) => `${ACTIVITY_INDENT}${line}`);
|
|
31
31
|
}
|
|
32
|
-
function akumaLabel(row) {
|
|
32
|
+
function akumaLabel(row, aliasesUnavailable) {
|
|
33
33
|
const aliases = row.aliases ?? [];
|
|
34
|
-
|
|
34
|
+
if (aliases.length > 0)
|
|
35
|
+
return `(${aliases.join(" ")})`;
|
|
36
|
+
return aliasesUnavailable ? "(aliases unavailable)" : "";
|
|
35
37
|
}
|
|
36
38
|
function endpointFact(id, observed) {
|
|
37
39
|
// A bounded or failed Contract read leaves the disposition unknown; a parenthetical that
|
|
@@ -41,7 +43,9 @@ function endpointFact(id, observed) {
|
|
|
41
43
|
/**
|
|
42
44
|
* One Akuma board section. The World board omits an empty section because its other
|
|
43
45
|
* sections already say what the World holds; a category board states that emptiness
|
|
44
|
-
* itself, since it is the whole answer.
|
|
46
|
+
* itself, since it is the whole answer. A failed Alias observation belongs to the
|
|
47
|
+
* section, so an empty roster still states its emptiness rather than dropping that
|
|
48
|
+
* evidence.
|
|
45
49
|
*/
|
|
46
50
|
function renderAkumaBoard(section, observedAt, context, emptyRows) {
|
|
47
51
|
if (section.kind === "absent")
|
|
@@ -49,8 +53,15 @@ function renderAkumaBoard(section, observedAt, context, emptyRows) {
|
|
|
49
53
|
if (section.kind === "failed")
|
|
50
54
|
return ["AKUMA // unavailable", "", tone(`! ${safeText(section.failure.message)}`, "alert", context.color)];
|
|
51
55
|
const rows = section.value.rows;
|
|
52
|
-
|
|
53
|
-
|
|
56
|
+
const aliasesUnavailable = section.value.aliasesUnavailable === true;
|
|
57
|
+
if (rows.length === 0) {
|
|
58
|
+
if (!aliasesUnavailable)
|
|
59
|
+
return emptyRows;
|
|
60
|
+
return [
|
|
61
|
+
...(emptyRows.length === 0 ? [emptyCatalogue("akuma")] : emptyRows),
|
|
62
|
+
tone("! aliases unavailable", "alert", context.color),
|
|
63
|
+
];
|
|
64
|
+
}
|
|
54
65
|
const rowLines = rows.map((row) => {
|
|
55
66
|
const statusTone = akumaStatusTone(row, observedAt);
|
|
56
67
|
const mark = statusTone === null ? akumaMark(row.life) : tone(akumaMark(row.life), statusTone, context.color);
|
|
@@ -62,10 +73,14 @@ function renderAkumaBoard(section, observedAt, context, emptyRows) {
|
|
|
62
73
|
const key = row.life === "stranded" && "strandedReason" in row && row.strandedReason === "resume-unsupported"
|
|
63
74
|
? [life, ...activity, "resume unsupported"]
|
|
64
75
|
: [life, ...activity];
|
|
65
|
-
const relation = row.contract === undefined
|
|
76
|
+
const relation = row.contract === undefined
|
|
77
|
+
? row.contractAssociationUnavailable === true
|
|
78
|
+
? ["contract association unavailable"]
|
|
79
|
+
: []
|
|
80
|
+
: [endpointFact(row.contract.id, row.contract.observed)];
|
|
66
81
|
const snapshot = row.snapshot;
|
|
67
82
|
const snapshotLines = snapshot === undefined ? [] : latestActivityLines(snapshot, context);
|
|
68
|
-
const aliases = akumaLabel(row);
|
|
83
|
+
const aliases = akumaLabel(row, aliasesUnavailable);
|
|
69
84
|
if (context.columns > NARROW_COLUMNS) {
|
|
70
85
|
const lines = [identityLine(mark, row.id, `${aliases} · ${[...key, ...relation].join(" · ")}`.trim())];
|
|
71
86
|
return [...lines, ...snapshotLines];
|
|
@@ -64,6 +64,8 @@ function isTerminalAkuma(life) {
|
|
|
64
64
|
return life === "killed" || life === "stillborn";
|
|
65
65
|
}
|
|
66
66
|
function linkedAkumaSummary(row, akuma) {
|
|
67
|
+
if (row.rosterUnavailable === true)
|
|
68
|
+
return "akuma unavailable";
|
|
67
69
|
if (row.roster.length === 0)
|
|
68
70
|
return undefined;
|
|
69
71
|
if (akuma === undefined || akuma.kind !== "present")
|
|
@@ -98,7 +100,6 @@ function payload(label, text, context) {
|
|
|
98
100
|
columns: context.columns,
|
|
99
101
|
maxLines: 3,
|
|
100
102
|
quote: "“",
|
|
101
|
-
openQuote: false,
|
|
102
103
|
truncated: false,
|
|
103
104
|
});
|
|
104
105
|
}
|
|
@@ -248,6 +249,8 @@ function renderDebts(report, context) {
|
|
|
248
249
|
return [];
|
|
249
250
|
const rowLines = rows.map((row) => {
|
|
250
251
|
const relation = row.contract === undefined ? [] : [endpointFact(row.contract.id, row.contract.observed)];
|
|
252
|
+
if (row.contractAssociationUnavailable === true)
|
|
253
|
+
relation.push("contract association unavailable");
|
|
251
254
|
const childFacts = row.children === undefined ? [] : [`children ${row.children.live} live · ${row.children.total} total`];
|
|
252
255
|
const blockerFacts = (row.blockers ?? []).map((blocker) => `blocked ${blocker.id}`);
|
|
253
256
|
const association = relation.length === 0 ? "" : ` · ${relation.join(" · ")}`;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { gateDisplayName } from "./contract-observation.js";
|
|
1
|
+
import { gateDisplayName, contractOperationName } from "./contract-observation.js";
|
|
2
2
|
import { renderRefusalFacts } from "./refusal.js";
|
|
3
3
|
import { DEFAULT_CLI_COLUMNS, displayColumns, orderRefusalFacts, renderOpaqueBlock, safeText, quotedText, } from "./terminal.js";
|
|
4
4
|
export function receiptRow(lines, mark, label, segments, columns) {
|
|
@@ -25,7 +25,7 @@ export function receiptPayload(lines, label, payload) {
|
|
|
25
25
|
lines.push(` ${label.trim()}`, ...renderOpaqueBlock(payload, " ", DEFAULT_CLI_COLUMNS), "");
|
|
26
26
|
}
|
|
27
27
|
export function outcomeLines(mark, verb, word, contract, columns = DEFAULT_CLI_COLUMNS) {
|
|
28
|
-
const base = `${mark} ${verb} ${word}`;
|
|
28
|
+
const base = `${mark} ${contractOperationName(verb)} ${word}`;
|
|
29
29
|
if (contract === undefined)
|
|
30
30
|
return [base];
|
|
31
31
|
const inline = `${base} ${contract}`;
|
|
@@ -296,7 +296,7 @@ export function executionFailureLines(receipt, category, diagnostic, columns) {
|
|
|
296
296
|
cleanup.push(effect.issue);
|
|
297
297
|
}
|
|
298
298
|
const lines = [];
|
|
299
|
-
receiptRow(lines, "!", "execution failed after admission", [{ text: category }, ...(contract === undefined ? [] : [{ text: contract, opaque: true }])], columns);
|
|
299
|
+
receiptRow(lines, "!", receipt.operation === "deliver-preview" ? "deliver --dry-run failed" : "execution failed after admission", [{ text: category }, ...(contract === undefined ? [] : [{ text: contract, opaque: true }])], columns);
|
|
300
300
|
receiptPayload(lines, "reason", diagnostic);
|
|
301
301
|
lines.push(...executionStopLines(stops, columns), ...executionCleanupLines(cleanup, columns, contract));
|
|
302
302
|
return lines;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { usageAcceptanceLines } from "../usage.js";
|
|
2
|
-
import { shortGitId } from "./contract-observation.js";
|
|
2
|
+
import { shortGitId, contractOperationName } from "./contract-observation.js";
|
|
3
3
|
import { DEFAULT_CLI_COLUMNS, checkoutNotFollowableLines, gitShortStat, orderRefusalFacts, renderOpaqueBlock, safeText, } from "./terminal.js";
|
|
4
4
|
function wrap(lines, text, indent, columns) {
|
|
5
5
|
lines.push(...renderOpaqueBlock(text, indent, columns));
|
|
@@ -112,7 +112,7 @@ export function renderRefusalFacts(refusal, indent, columns, addressed) {
|
|
|
112
112
|
return orderRefusalFacts(refusalFacts(refusal, indent, columns, addressed).map((line) => line.slice(indent.length))).map((line) => `${indent}${line}`);
|
|
113
113
|
}
|
|
114
114
|
function refusalTitle(verb) {
|
|
115
|
-
return `× ${verb} refused`;
|
|
115
|
+
return `× ${contractOperationName(verb)} refused`;
|
|
116
116
|
}
|
|
117
117
|
/**
|
|
118
118
|
* The one refusal receipt assembly: a denied-verdict title, a labeled reason, labeled facts, and the
|
|
@@ -186,7 +186,7 @@ export function renderBoundedPayload(input) {
|
|
|
186
186
|
if (rest.length === 0 && !input.quote && index === 0)
|
|
187
187
|
return [prefix.trimEnd()];
|
|
188
188
|
const opening = input.quote && index === 0 ? input.quote : "";
|
|
189
|
-
const closing = input.quote
|
|
189
|
+
const closing = input.quote === "“" ? "”" : input.quote;
|
|
190
190
|
const budget = Math.max(0, input.columns - displayColumns(prefix + opening + closing));
|
|
191
191
|
if (budget === 0)
|
|
192
192
|
return lines.length === 0 ? [prefix.trimEnd()] : lines;
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import type { WorldRoot } from "../world.js";
|
|
2
|
+
export type SquareSeatInput = Readonly<{
|
|
3
|
+
path: WorldRoot;
|
|
4
|
+
environment: NodeJS.ProcessEnv;
|
|
5
|
+
}>;
|
|
6
|
+
export type SquareSeatControl = Readonly<{
|
|
7
|
+
signal?: AbortSignal;
|
|
8
|
+
budgetMs?: number;
|
|
9
|
+
}>;
|
|
10
|
+
/**
|
|
11
|
+
* The Square participant name this submitting session should speak as, or
|
|
12
|
+
* undefined when no honest choice exists. Identity preparation is optional, so it
|
|
13
|
+
* never refuses the enclosing operation and always settles within one budget.
|
|
14
|
+
*/
|
|
15
|
+
export declare function squareSeat(input: SquareSeatInput, control?: SquareSeatControl): Promise<string | undefined>;
|
|
@@ -0,0 +1,180 @@
|
|
|
1
|
+
import { createHash } from "node:crypto";
|
|
2
|
+
import { realpath } from "node:fs/promises";
|
|
3
|
+
import { join, resolve } from "node:path";
|
|
4
|
+
import { inbox, Square, SquareError, squareAssignedParticipantName } from "@astrosheep/square";
|
|
5
|
+
/**
|
|
6
|
+
* The Square integration's submitting-edge identity policy. Call, fork, tell, and
|
|
7
|
+
* ask share this one adapter, so no command and no generic caller decoder has to
|
|
8
|
+
* know how Square names a participant. Every Square read below is rooted in the
|
|
9
|
+
* submitted environment's own coordinates, never in this process's ambient ones.
|
|
10
|
+
*/
|
|
11
|
+
/** Square's own harness-session coordinates, in its resolution order. */
|
|
12
|
+
const HARNESS_SESSIONS = [
|
|
13
|
+
{ provider: "claude", variable: "CLAUDE_CODE_SESSION_ID" },
|
|
14
|
+
{ provider: "codex", variable: "CODEX_THREAD_ID" },
|
|
15
|
+
{ provider: "opencode", variable: "OPENCODE_SESSION_ID" },
|
|
16
|
+
{ provider: "pi", variable: "PI_SESSION_ID" },
|
|
17
|
+
{ provider: undefined, variable: "PASEO_AGENT_ID" },
|
|
18
|
+
];
|
|
19
|
+
const SEAT_PREFIX = "keiyaku-assigned-";
|
|
20
|
+
const SEAT_DIGEST_DOMAIN = "keiyaku/square-seat/v1";
|
|
21
|
+
const SEAT_DIGEST_LENGTH = 12;
|
|
22
|
+
/** One bounded identity observation; a non-cooperative Square never holds a submission. */
|
|
23
|
+
const IDENTITY_BUDGET_MS = 5_000;
|
|
24
|
+
function declared(environment, variable) {
|
|
25
|
+
const value = environment[variable]?.trim();
|
|
26
|
+
return value === undefined || value === "" ? undefined : value;
|
|
27
|
+
}
|
|
28
|
+
/** A stable, collision-resistant seat for one provider session coordinate. */
|
|
29
|
+
function squareSeatName(provider, session) {
|
|
30
|
+
const digest = createHash("sha256")
|
|
31
|
+
.update(`${SEAT_DIGEST_DOMAIN}\u0000${provider}\u0000${session}`, "utf8")
|
|
32
|
+
.digest("hex");
|
|
33
|
+
return `${SEAT_PREFIX}${digest.slice(0, SEAT_DIGEST_LENGTH)}`;
|
|
34
|
+
}
|
|
35
|
+
/** Every harness session coordinate this process declares, able to name a seat or not. */
|
|
36
|
+
function sessionIds(environment) {
|
|
37
|
+
return HARNESS_SESSIONS.flatMap(({ variable }) => {
|
|
38
|
+
const session = declared(environment, variable);
|
|
39
|
+
return session === undefined ? [] : [session];
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* The deterministic candidate for this process. Only one provider-backed session
|
|
44
|
+
* may exist: a second coordinate — another provider, or the same raw token under
|
|
45
|
+
* a different one — is ambiguous and selects nothing.
|
|
46
|
+
*/
|
|
47
|
+
function seatCandidate(environment) {
|
|
48
|
+
const names = HARNESS_SESSIONS.flatMap(({ provider, variable }) => {
|
|
49
|
+
const session = declared(environment, variable);
|
|
50
|
+
return provider === undefined || session === undefined ? [] : [squareSeatName(provider, session)];
|
|
51
|
+
});
|
|
52
|
+
return names.length === 1 ? names[0] : undefined;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Square owns the name grammar, so the edge borrows one of Square's own handles
|
|
56
|
+
* instead of restating it. An in-memory square validates without touching any
|
|
57
|
+
* artifact.
|
|
58
|
+
*/
|
|
59
|
+
async function usableName(name) {
|
|
60
|
+
try {
|
|
61
|
+
await Square.inMemory({ markdown: "" }).participant(name);
|
|
62
|
+
return true;
|
|
63
|
+
}
|
|
64
|
+
catch {
|
|
65
|
+
return false;
|
|
66
|
+
}
|
|
67
|
+
}
|
|
68
|
+
/** Square's own canonical coordinate for a location it already published. */
|
|
69
|
+
async function canonical(path) {
|
|
70
|
+
try {
|
|
71
|
+
return await realpath(path);
|
|
72
|
+
}
|
|
73
|
+
catch {
|
|
74
|
+
return resolve(path);
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Bindings this session already holds in this Square. Square's session inbox
|
|
79
|
+
* reads the same host registry as native hooks, and it is the only public read
|
|
80
|
+
* that takes the caller's own environment coordinate. Its page is bounded, so a
|
|
81
|
+
* view that hides rows proves nothing about absence here.
|
|
82
|
+
*/
|
|
83
|
+
async function joinedBindings(environment, ids, location, signal) {
|
|
84
|
+
const pages = await Promise.all(ids.map(async (session) => await inbox({ env: environment }, session, {}, { signal })));
|
|
85
|
+
const here = await canonical(location);
|
|
86
|
+
return {
|
|
87
|
+
here: pages.flatMap(({ rows }) => rows).filter(({ squarePath }) => squarePath === here).length,
|
|
88
|
+
complete: pages.every(({ rows, total }) => total === rows.length),
|
|
89
|
+
};
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* A session whose former participant already finished here has no replacement
|
|
93
|
+
* identity: releasing the binding leaves Square's roster as the only evidence of
|
|
94
|
+
* that standing, and a fresh seat would rename a finished caller into a new one.
|
|
95
|
+
*/
|
|
96
|
+
async function finishedHere(square, environment, signal) {
|
|
97
|
+
const former = squareAssignedParticipantName(environment);
|
|
98
|
+
const previous = seatCandidate(environment)?.replace(SEAT_PREFIX, "keiyaku-seat-");
|
|
99
|
+
if (former === undefined && previous === undefined)
|
|
100
|
+
return false;
|
|
101
|
+
const { participants } = await square.participants({}, { signal });
|
|
102
|
+
return participants.some(({ name, state }) => (name === former || name === previous) && state === "done");
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* A binding this edge cannot stand on is never replaced by a fresh name: Square
|
|
106
|
+
* adjudicates standing, ownership, and lifecycle. The edge only distinguishes a
|
|
107
|
+
* Square that is genuinely not there yet from evidence it cannot trust.
|
|
108
|
+
*/
|
|
109
|
+
async function standingAt(location, environment, ids, signal) {
|
|
110
|
+
let square;
|
|
111
|
+
try {
|
|
112
|
+
square = await Square.at({ path: location, env: environment }, { signal });
|
|
113
|
+
}
|
|
114
|
+
catch (error) {
|
|
115
|
+
// Only a Square that is genuinely not there yet may receive a new seat.
|
|
116
|
+
return error instanceof SquareError && error.code === "unavailable"
|
|
117
|
+
? { kind: "absent" }
|
|
118
|
+
: { kind: "indeterminate" };
|
|
119
|
+
}
|
|
120
|
+
try {
|
|
121
|
+
const recognized = await square.recognize(environment);
|
|
122
|
+
if (recognized !== null)
|
|
123
|
+
return { kind: "standing", name: recognized.name };
|
|
124
|
+
const bindings = await joinedBindings(environment, ids, square.location, signal);
|
|
125
|
+
if (bindings.here > 0 || !bindings.complete)
|
|
126
|
+
return { kind: "indeterminate" };
|
|
127
|
+
return (await finishedHere(square, environment, signal)) ? { kind: "indeterminate" } : { kind: "absent" };
|
|
128
|
+
}
|
|
129
|
+
catch {
|
|
130
|
+
return { kind: "indeterminate" };
|
|
131
|
+
}
|
|
132
|
+
finally {
|
|
133
|
+
await square.close().catch(() => undefined);
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* The one bounded attempt. A late settlement keeps no authority: the adapter only
|
|
138
|
+
* reads Square, so nothing arrives after the caller has settled, and no refusal
|
|
139
|
+
* escapes as an unhandled rejection.
|
|
140
|
+
*/
|
|
141
|
+
async function bounded(attempt, control) {
|
|
142
|
+
const budget = new AbortController();
|
|
143
|
+
const timer = setTimeout(() => budget.abort(new Error("Square identity observation expired")), control.budgetMs ?? IDENTITY_BUDGET_MS);
|
|
144
|
+
const signal = control.signal === undefined ? budget.signal : AbortSignal.any([control.signal, budget.signal]);
|
|
145
|
+
const pending = attempt(signal);
|
|
146
|
+
pending.catch(() => undefined);
|
|
147
|
+
try {
|
|
148
|
+
return await Promise.race([pending, whenAborted(signal)]);
|
|
149
|
+
}
|
|
150
|
+
finally {
|
|
151
|
+
clearTimeout(timer);
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
function whenAborted(signal) {
|
|
155
|
+
return new Promise((settle) => {
|
|
156
|
+
if (signal.aborted)
|
|
157
|
+
settle(undefined);
|
|
158
|
+
else
|
|
159
|
+
signal.addEventListener("abort", () => settle(undefined), { once: true });
|
|
160
|
+
});
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* The Square participant name this submitting session should speak as, or
|
|
164
|
+
* undefined when no honest choice exists. Identity preparation is optional, so it
|
|
165
|
+
* never refuses the enclosing operation and always settles within one budget.
|
|
166
|
+
*/
|
|
167
|
+
export async function squareSeat(input, control = {}) {
|
|
168
|
+
const name = declared(input.environment, "SQUARE_PARTICIPANT_NAME");
|
|
169
|
+
if (name !== undefined)
|
|
170
|
+
return (await usableName(name)) ? name : undefined;
|
|
171
|
+
const ids = sessionIds(input.environment);
|
|
172
|
+
// No session coordinate: nothing to reuse, nothing to derive, nothing to read.
|
|
173
|
+
if (ids.length === 0)
|
|
174
|
+
return undefined;
|
|
175
|
+
const location = join(input.path, ".square", "KEIYAKU.square");
|
|
176
|
+
const standing = await bounded(async (signal) => await standingAt(location, input.environment, ids, signal), control);
|
|
177
|
+
if (standing?.kind === "standing")
|
|
178
|
+
return standing.name;
|
|
179
|
+
return standing?.kind === "absent" ? seatCandidate(input.environment) : undefined;
|
|
180
|
+
}
|
|
@@ -9,7 +9,7 @@ import { appointmentFor, placeRegisterPath } from "./workspace-place.js";
|
|
|
9
9
|
import { repairNamespaceContext } from "./debt/context.js";
|
|
10
10
|
import { contractNamespace } from "./debt/identity.js";
|
|
11
11
|
const IGNORE_BYTES = ".gitignore\nKEIYAKU.md\n";
|
|
12
|
-
const PRIMARY_IGNORE_BYTES = "*\n!settings.json\n
|
|
12
|
+
const PRIMARY_IGNORE_BYTES = "*\n!settings.json\n";
|
|
13
13
|
const SEAT_IGNORE_BYTES = ".gitignore\nSKILL.md\n";
|
|
14
14
|
const SEAT_SKILLS = [
|
|
15
15
|
["keiyaku-onboarding", CONTRACT_ONBOARDING_SKILL],
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type GateReport } from "../facts/gate.js";
|
|
2
|
-
import { type ActorId, type ContractId } from "../facts/types.js";
|
|
2
|
+
import { type ActorId, type ContractId, type ContractState } from "../facts/types.js";
|
|
3
3
|
import type { DecideInput, OfferDecision } from "../decide.js";
|
|
4
4
|
type PlacementInput = Readonly<{
|
|
5
5
|
contractId: ContractId;
|
|
@@ -24,5 +24,6 @@ export type PlacementRefusal = Readonly<{
|
|
|
24
24
|
contractId: ContractId;
|
|
25
25
|
unmet: readonly UnmetPrerequisite[];
|
|
26
26
|
}>;
|
|
27
|
+
export declare function unmetPrerequisites(prerequisites: readonly ContractId[], observation: ReadonlyMap<ContractId, ContractState | null>): readonly UnmetPrerequisite[];
|
|
27
28
|
export declare function decidePlacement({ input, attempt, observation, }: DecideInput<PlacementInput>): OfferDecision<PlacementRefusal>;
|
|
28
29
|
export {};
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { gateReports } from "../facts/gate.js";
|
|
2
2
|
import { activeContract, contractState } from "../facts/observation.js";
|
|
3
3
|
import { journalEntry } from "../facts/types.js";
|
|
4
|
-
function unmetPrerequisites(prerequisites, observation) {
|
|
4
|
+
export function unmetPrerequisites(prerequisites, observation) {
|
|
5
5
|
const unmet = [];
|
|
6
6
|
for (const contractId of prerequisites) {
|
|
7
7
|
const state = contractState(observation, contractId);
|
|
@@ -1,7 +1,3 @@
|
|
|
1
|
-
export type NamespaceContextRead = readonly string[] | "absent" | Readonly<{
|
|
2
|
-
kind: "malformed";
|
|
3
|
-
path: string;
|
|
4
|
-
}>;
|
|
5
1
|
export type NamespaceContextInput = Readonly<{
|
|
6
2
|
directory: string;
|
|
7
3
|
boundary: string;
|
|
@@ -12,7 +8,6 @@ export type ResolvedNamespaceContext = Readonly<{
|
|
|
12
8
|
namespace: readonly string[];
|
|
13
9
|
source: NamespaceContextSource;
|
|
14
10
|
}>;
|
|
15
|
-
export declare function readNamespaceContext(coordinates: NamespaceContextInput): Promise<NamespaceContextRead>;
|
|
16
11
|
export declare function installNamespaceContext(root: string, segments: readonly string[]): Promise<void>;
|
|
17
12
|
export declare function repairNamespaceContext(root: string, segments: readonly string[]): Promise<"kept" | "installed">;
|
|
18
13
|
export declare function resolveDebtNamespaceContext(input: NamespaceContextInput): Promise<ResolvedNamespaceContext | Readonly<{
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { lstat, mkdir, readFile } from "node:fs/promises";
|
|
2
|
-
import { dirname, join, resolve } from "node:path";
|
|
2
|
+
import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
3
3
|
import { repairDerivedFile, replaceFileDurably } from "../coordination/durable-file.js";
|
|
4
4
|
import { normalizeIdentityStem } from "../identity/normalize.js";
|
|
5
5
|
function directory(root) {
|
|
@@ -21,9 +21,10 @@ function validNamespaceSegments(value) {
|
|
|
21
21
|
segment !== ".."));
|
|
22
22
|
}
|
|
23
23
|
async function readAt(root) {
|
|
24
|
+
const path = currentPath(root);
|
|
24
25
|
let bytes;
|
|
25
26
|
try {
|
|
26
|
-
const
|
|
27
|
+
const stat = await lstat(path);
|
|
27
28
|
if (!stat.isFile() || stat.isSymbolicLink())
|
|
28
29
|
return { kind: "malformed", path };
|
|
29
30
|
bytes = await readFile(path, "utf8");
|
|
@@ -33,33 +34,31 @@ async function readAt(root) {
|
|
|
33
34
|
return "absent";
|
|
34
35
|
throw error;
|
|
35
36
|
}
|
|
36
|
-
if (!bytes.endsWith("\n") || bytes.slice(0, -1).includes("\n"))
|
|
37
|
-
return { kind: "malformed", path
|
|
38
|
-
}
|
|
37
|
+
if (!bytes.endsWith("\n") || bytes.slice(0, -1).includes("\n"))
|
|
38
|
+
return { kind: "malformed", path };
|
|
39
39
|
const content = bytes.slice(0, -1);
|
|
40
40
|
const segments = content === "" ? [] : content.split("/");
|
|
41
|
-
return validNamespaceSegments(segments) ? segments : { kind: "malformed", path
|
|
42
|
-
}
|
|
43
|
-
async function readAtWithPath(root) {
|
|
44
|
-
const selected = await readAt(root);
|
|
45
|
-
if (selected === "absent" || (typeof selected === "object" && "kind" in selected))
|
|
46
|
-
return selected;
|
|
47
|
-
return { value: selected, path: currentPath(root) };
|
|
41
|
+
return validNamespaceSegments(segments) ? segments : { kind: "malformed", path };
|
|
48
42
|
}
|
|
49
|
-
|
|
50
|
-
|
|
43
|
+
/** One ancestor walk: the nearest context at or below the boundary, and the directory that answers it. */
|
|
44
|
+
async function walkNamespaceContext(coordinates) {
|
|
45
|
+
const boundary = resolve(coordinates.boundary);
|
|
46
|
+
let current = resolve(coordinates.directory);
|
|
51
47
|
for (;;) {
|
|
52
|
-
const
|
|
53
|
-
if (
|
|
54
|
-
return
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
return "absent";
|
|
60
|
-
current = resolvedParent;
|
|
48
|
+
const read = await readAt(current);
|
|
49
|
+
if (read !== "absent" || current === boundary)
|
|
50
|
+
return { read, root: current };
|
|
51
|
+
const parent = dirname(current);
|
|
52
|
+
if (parent === current || !descendsFrom(parent, boundary))
|
|
53
|
+
return { read, root: current };
|
|
54
|
+
current = parent;
|
|
61
55
|
}
|
|
62
56
|
}
|
|
57
|
+
/** Whether `candidate` is the boundary or lies beneath it; a sibling or ancestor never does. */
|
|
58
|
+
function descendsFrom(candidate, boundary) {
|
|
59
|
+
const step = relative(boundary, candidate);
|
|
60
|
+
return step === "" || (!isAbsolute(step) && step !== ".." && !step.startsWith(`..${sep}`));
|
|
61
|
+
}
|
|
63
62
|
export async function installNamespaceContext(root, segments) {
|
|
64
63
|
if (!validNamespaceSegments(segments))
|
|
65
64
|
throw new TypeError("namespace must contain normalized segments");
|
|
@@ -72,8 +71,7 @@ async function installIgnore(root) {
|
|
|
72
71
|
await repairDerivedFile(ignorePath(root), "*\n");
|
|
73
72
|
}
|
|
74
73
|
export async function repairNamespaceContext(root, segments) {
|
|
75
|
-
|
|
76
|
-
if (Array.isArray(current)) {
|
|
74
|
+
if (Array.isArray(await readAt(root))) {
|
|
77
75
|
await installIgnore(root);
|
|
78
76
|
return "kept";
|
|
79
77
|
}
|
|
@@ -81,23 +79,13 @@ export async function repairNamespaceContext(root, segments) {
|
|
|
81
79
|
return "installed";
|
|
82
80
|
}
|
|
83
81
|
export async function resolveDebtNamespaceContext(input) {
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
};
|
|
94
|
-
}
|
|
95
|
-
if (current === input.boundary)
|
|
96
|
-
return { namespace: [], source: "default-root" };
|
|
97
|
-
const resolvedParent = dirname(resolve(current));
|
|
98
|
-
if (resolvedParent === current || !resolvedParent.startsWith(`${input.boundary}/`)) {
|
|
99
|
-
return { namespace: [], source: "default-root" };
|
|
100
|
-
}
|
|
101
|
-
current = resolvedParent;
|
|
102
|
-
}
|
|
82
|
+
const { read, root } = await walkNamespaceContext(input);
|
|
83
|
+
if (read === "absent")
|
|
84
|
+
return { namespace: [], source: "default-root" };
|
|
85
|
+
if (typeof read === "object" && "kind" in read)
|
|
86
|
+
return { kind: "invalid-namespace-context", path: read.path };
|
|
87
|
+
return {
|
|
88
|
+
namespace: read,
|
|
89
|
+
source: root === resolve(input.boundary) && input.managed === true ? "contract-installed" : "local-override",
|
|
90
|
+
};
|
|
103
91
|
}
|
|
@@ -29,6 +29,7 @@ export declare class GitPlumbingError extends Error {
|
|
|
29
29
|
pid?: number | null;
|
|
30
30
|
}>);
|
|
31
31
|
}
|
|
32
|
+
export declare function gitChildEnvironment(environment?: NodeJS.ProcessEnv): NodeJS.ProcessEnv;
|
|
32
33
|
export declare function executeGit(repository: GitRepository, args: readonly string[], input?: string | Uint8Array, environment?: NodeJS.ProcessEnv): Promise<Buffer>;
|
|
33
34
|
/** Connect two owned Git commands without materializing the intermediate output. */
|
|
34
35
|
export declare function runGitPipe(repository: GitRepository, sourceArgs: readonly string[], sinkArgs: readonly string[]): Promise<Buffer>;
|