@akagilnc/pi-workflow-roles 0.1.5365 → 0.1.5375
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/dist/acp-host/production-host.js +5585 -5655
- package/dist/activation-ledger-git.js +2 -2
- package/dist/activation-ledger-topology.js +1 -7
- package/dist/analyst-entry.js +4 -8
- package/dist/analyst-gate-cycles-read.js +3 -11
- package/dist/analyst-index.js +3 -9
- package/dist/analyst-ledger.js +1 -11
- package/dist/analyst-metric-families/acceptance-success-rework.js +1 -3
- package/dist/analyst-metric-families/round-timeline.js +1 -3
- package/dist/analyst-page.js +2 -2
- package/dist/archivist-record-topology.js +2 -2
- package/dist/audit-escalation.js +2 -1
- package/dist/auditor-soul.js +2 -1
- package/dist/collector-config.js +6 -8
- package/dist/compliance-transport.js +2 -1
- package/dist/countersign-contracts.js +2 -1
- package/dist/diarist-contracts.js +3 -2
- package/dist/doctor-contracts.js +1 -3
- package/dist/doctor-evidence.js +7 -8
- package/dist/dossier-resolution.js +1 -3
- package/dist/engine-detour-usage.js +1 -3
- package/dist/gatekeeper-role.js +2 -9
- package/dist/gleaner-left-contracts.js +2 -1
- package/dist/headless-host/description.js +14 -17
- package/dist/headless-host/production-host.js +1665 -1737
- package/dist/host-session-record.js +3 -2
- package/dist/inspector-contracts.js +2 -1
- package/dist/ledger-session-read.js +1 -3
- package/dist/merger-contracts.js +9 -9
- package/dist/migrate-book-topology.js +348 -314
- package/dist/navigator-attendance.js +9 -11
- package/dist/navigator-invocation-identity.js +3 -2
- package/dist/navigator-public-session.js +3 -5
- package/dist/navigator-session-contracts.js +8 -10
- package/dist/navigator-work-base.js +5 -8
- package/dist/notary-contracts.js +3 -5
- package/dist/package-contracts/auditor-output.js +1 -3
- package/dist/package-contracts/fixer-packet.js +3 -6
- package/dist/package-contracts/gatekeeper-output.js +1 -3
- package/dist/package-contracts/navigator-output.js +8 -8
- package/dist/package-contracts/terminating-infrastructure.js +5 -9
- package/dist/package-contracts/terminating-tools.js +4 -3
- package/dist/public-cli/analyst-run.js +3 -2
- package/dist/public-cli/auto-resume.js +4 -9
- package/dist/public-cli/cli.js +66 -64
- package/dist/public-cli/config.js +12 -11
- package/dist/public-cli/countersign-run.js +1 -3
- package/dist/public-cli/host-providers.js +7 -14
- package/dist/public-cli/instruction-seat-run.js +69 -43
- package/dist/public-cli/invocation.js +141 -136
- package/dist/public-cli/main.js +1919 -1968
- package/dist/public-cli/post-admission.js +89 -89
- package/dist/public-cli/role-seat-runtime.js +29 -0
- package/dist/public-cli/run-lifecycle.js +20 -32
- package/dist/public-cli/settlement.js +10 -26
- package/dist/public-cli/turn-request.js +14 -0
- package/dist/public-role-summons.js +23 -35
- package/dist/receipt-delivery-policy.js +1 -3
- package/dist/role-run-placement.js +7 -5
- package/dist/role-run-relocation.js +12 -19
- package/dist/run-terminal-artifacts.js +1 -11
- package/dist/run-ticket-number.js +2 -4
- package/dist/session-assistant-usage.js +2 -1
- package/dist/session-dialogue.js +1 -14
- package/dist/sitian-reader.js +2 -4
- package/dist/submission-correctable-error.js +2 -1
- package/dist/submission-errors.js +2 -1
- package/dist/submission-gate.js +2 -1
- package/dist/submission-ledger.js +4 -5
- package/dist/ticket-provenance-contracts.js +1 -3
- package/dist/ticket-provenance.js +2 -1
- package/dist/typed-provider-http.js +4 -7
- package/dist/unknown-value.js +28 -0
- package/dist/user-dialogue-stdin.js +2 -1
- package/package.json +1 -1
- package/src/acp-host/role-turn-host.ts +4 -2
- package/src/activation-ledger-git.ts +3 -2
- package/src/activation-ledger-topology.ts +4 -12
- package/src/analyst-entry.ts +3 -11
- package/src/analyst-gate-cycles-read.ts +3 -15
- package/src/analyst-index.ts +3 -13
- package/src/analyst-ledger.ts +2 -16
- package/src/analyst-metric-families/acceptance-success-rework.ts +2 -4
- package/src/analyst-metric-families/round-timeline.ts +2 -4
- package/src/analyst-page.ts +2 -2
- package/src/archivist-record-topology.ts +2 -2
- package/src/audit-escalation.ts +2 -1
- package/src/auditor-soul.ts +3 -1
- package/src/book-topology-migration-placement.ts +8 -21
- package/src/book-topology-migrators-t11.ts +16 -15
- package/src/book-topology-mixed-volume-migrators.ts +3 -6
- package/src/book-topology-record-class-migrators.ts +7 -10
- package/src/book-topology-runs-migrator.ts +4 -3
- package/src/collector-config.ts +7 -9
- package/src/compliance-transport.ts +2 -1
- package/src/countersign-contracts.ts +2 -1
- package/src/diarist-contracts.ts +3 -2
- package/src/doctor-contracts.ts +3 -1
- package/src/doctor-evidence.ts +8 -7
- package/src/doctor-role.ts +4 -2
- package/src/dossier-resolution.ts +2 -4
- package/src/engine-detour-tool.ts +0 -2
- package/src/engine-detour-usage.ts +2 -4
- package/src/external-host-turn-loop.ts +3 -1
- package/src/factory-board.ts +1 -8
- package/src/gatekeeper-role.ts +2 -10
- package/src/gleaner-left-contracts.ts +3 -1
- package/src/headless-host/description.ts +15 -18
- package/src/headless-host/role-turn-host.ts +10 -9
- package/src/host-session-record.ts +4 -2
- package/src/inspector-contracts.ts +2 -1
- package/src/ledger-session-read.ts +2 -5
- package/src/merger-contracts.ts +10 -9
- package/src/navigator-attendance.ts +10 -12
- package/src/navigator-invocation-identity.ts +3 -2
- package/src/navigator-public-session.ts +4 -6
- package/src/navigator-session-contracts.ts +8 -11
- package/src/navigator-work-base.ts +5 -8
- package/src/navigator-work-context.ts +2 -1
- package/src/notary-contracts.ts +4 -6
- package/src/oauth-keepalive.ts +5 -18
- package/src/package-contracts/auditor-output.ts +2 -4
- package/src/package-contracts/fixer-packet.ts +4 -6
- package/src/package-contracts/gatekeeper-output.ts +2 -4
- package/src/package-contracts/judge-output.ts +0 -1
- package/src/package-contracts/navigator-output.ts +8 -8
- package/src/package-contracts/terminating-infrastructure.ts +6 -20
- package/src/package-contracts/terminating-tools.ts +8 -12
- package/src/pi/adapter.ts +0 -1
- package/src/pi/role-turn-host.ts +0 -1
- package/src/public-cli/analyst-run.ts +4 -2
- package/src/public-cli/auto-resume.ts +5 -12
- package/src/public-cli/cli.ts +77 -83
- package/src/public-cli/config.ts +16 -27
- package/src/public-cli/countersign-run.ts +2 -4
- package/src/public-cli/host-providers.ts +10 -27
- package/src/public-cli/instruction-seat-run.ts +87 -58
- package/src/public-cli/invocation.ts +159 -172
- package/src/public-cli/post-admission.ts +115 -103
- package/src/public-cli/role-seat-runtime.ts +72 -0
- package/src/public-cli/run-lifecycle.ts +27 -67
- package/src/public-cli/settlement.ts +11 -33
- package/src/public-cli/terminal.ts +2 -17
- package/src/public-cli/turn-request.ts +26 -0
- package/src/public-role-summons.ts +24 -48
- package/src/receipt-delivery-policy.ts +1 -4
- package/src/reviewer-role.ts +0 -1
- package/src/role-envelope.ts +5 -3
- package/src/role-run-placement.ts +9 -10
- package/src/role-run-relocation.ts +13 -23
- package/src/role-runtime.ts +9 -15
- package/src/run-terminal-artifacts.ts +2 -16
- package/src/run-ticket-number.ts +4 -10
- package/src/session-assistant-usage.ts +3 -1
- package/src/session-dialogue.ts +1 -4
- package/src/session-identity.ts +0 -1
- package/src/sitian-reader.ts +2 -4
- package/src/submission-correctable-error.ts +3 -1
- package/src/submission-errors.ts +2 -1
- package/src/submission-gate.ts +3 -1
- package/src/submission-ledger.ts +5 -6
- package/src/ticket-provenance-contracts.ts +1 -4
- package/src/ticket-provenance.ts +3 -1
- package/src/ticket-snapshot.ts +2 -4
- package/src/ticket-trajectory.ts +1 -8
- package/src/typed-provider-http.ts +5 -15
- package/src/unknown-value.ts +34 -0
- package/src/user-dialogue-stdin.ts +3 -1
- package/src/worker-role.ts +2 -5
- package/src/worker-submission-gates.ts +5 -7
|
@@ -3,7 +3,7 @@ import { existsSync } from "node:fs";
|
|
|
3
3
|
import { realpath } from "node:fs/promises";
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
import { promisify } from "node:util";
|
|
6
|
-
import {
|
|
6
|
+
import { isRecord, errorText } from "./unknown-value.js";
|
|
7
7
|
const AK_ROLE_PACKAGE_ROOT_ENV = "AK_ROLE_PACKAGE_ROOT";
|
|
8
8
|
const execFileAsync = promisify(execFile);
|
|
9
9
|
function createCapturingIo() {
|
|
@@ -69,12 +69,6 @@ async function resolveSummonHome(options) {
|
|
|
69
69
|
if (fromCwd !== void 0 && fromCwd.length > 0) return fromCwd;
|
|
70
70
|
return packageMachineHome();
|
|
71
71
|
}
|
|
72
|
-
function projectSeatEngine(seat) {
|
|
73
|
-
return pickEngineAxis(seat);
|
|
74
|
-
}
|
|
75
|
-
function projectSeatHost(seat) {
|
|
76
|
-
return seat.host === void 0 ? {} : { host: seat.host };
|
|
77
|
-
}
|
|
78
72
|
function hostSelectionFailureFromUnknown(error) {
|
|
79
73
|
if (typeof error !== "object" || error === null) return void 0;
|
|
80
74
|
if (error.name !== "HostSelectionError") return void 0;
|
|
@@ -85,44 +79,36 @@ async function createSummonEnv(options, afterHost) {
|
|
|
85
79
|
const [
|
|
86
80
|
{ piDurablePrincipalAuthority },
|
|
87
81
|
{ appendPiSessionCustomEntry },
|
|
88
|
-
{
|
|
89
|
-
{ missingResolvedSeatModelMessage
|
|
82
|
+
{ openRoleSeatRuntime },
|
|
83
|
+
{ missingResolvedSeatModelMessage }
|
|
90
84
|
] = await Promise.all([
|
|
91
85
|
import("./pi/durable-principal.js"),
|
|
92
86
|
import("./pi/role-turn-host.js"),
|
|
93
|
-
import("./public-cli/role-
|
|
87
|
+
import("./public-cli/role-seat-runtime.js"),
|
|
94
88
|
import("./public-cli/config.js")
|
|
95
89
|
]);
|
|
96
90
|
const principalAuthority = options.principalAuthority ?? piDurablePrincipalAuthority;
|
|
97
|
-
const
|
|
98
|
-
{
|
|
91
|
+
const opened = openRoleSeatRuntime({
|
|
92
|
+
resolution: {
|
|
99
93
|
packageRoot: options.packageRoot,
|
|
100
94
|
...options.roleTurnHost === void 0 ? {} : { roleTurnHost: options.roleTurnHost },
|
|
101
95
|
...options.hostAdapters === void 0 ? {} : { hostAdapters: options.hostAdapters },
|
|
102
96
|
...options.extraPiArgs === void 0 || options.extraPiArgs.length === 0 ? {} : { extraPiArgs: options.extraPiArgs },
|
|
103
97
|
...options.timeoutMs === void 0 ? {} : { timeoutMs: options.timeoutMs }
|
|
104
98
|
},
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
99
|
+
principalAuthority,
|
|
100
|
+
role: options.role,
|
|
101
|
+
seat: options.seat,
|
|
102
|
+
home: options.home,
|
|
103
|
+
...afterHost === void 0 ? {} : { afterHost },
|
|
104
|
+
...options.hostFacingModel === void 0 ? {} : { hostFacingModel: options.hostFacingModel }
|
|
105
|
+
});
|
|
106
|
+
if (!opened.ok) {
|
|
110
107
|
return {
|
|
111
108
|
ok: false,
|
|
112
109
|
missingModelMessage: missingResolvedSeatModelMessage(options.role)
|
|
113
110
|
};
|
|
114
111
|
}
|
|
115
|
-
const hostName = seatWithModel.host ?? "pi";
|
|
116
|
-
let hostFacingSelection = options.hostFacingModel;
|
|
117
|
-
if (hostFacingSelection === void 0) {
|
|
118
|
-
const { loadHostProvidersTable, projectHostFacingProvider } = await import("./public-cli/host-providers.js");
|
|
119
|
-
hostFacingSelection = projectHostFacingProvider(
|
|
120
|
-
seatWithModel.selection,
|
|
121
|
-
hostName,
|
|
122
|
-
loadHostProvidersTable(options.home),
|
|
123
|
-
options.home
|
|
124
|
-
);
|
|
125
|
-
}
|
|
126
112
|
return {
|
|
127
113
|
ok: true,
|
|
128
114
|
env: {
|
|
@@ -131,12 +117,13 @@ async function createSummonEnv(options, afterHost) {
|
|
|
131
117
|
agentDir: options.agentDir,
|
|
132
118
|
sessionAppender: appendPiSessionCustomEntry,
|
|
133
119
|
packageRoot: options.packageRoot,
|
|
134
|
-
roleTurnHost,
|
|
120
|
+
roleTurnHost: opened.roleTurnHost,
|
|
135
121
|
cwd: options.cwd,
|
|
136
122
|
credentials: options.credentials,
|
|
137
|
-
...
|
|
138
|
-
...
|
|
139
|
-
...
|
|
123
|
+
...opened.model === void 0 ? {} : { model: opened.model },
|
|
124
|
+
...opened.engine === void 0 ? {} : { engine: opened.engine },
|
|
125
|
+
...opened.engineModel === void 0 ? {} : { engineModel: opened.engineModel },
|
|
126
|
+
host: opened.host,
|
|
140
127
|
...options.timeoutMs === void 0 ? {} : { timeoutMs: options.timeoutMs }
|
|
141
128
|
}
|
|
142
129
|
};
|
|
@@ -144,13 +131,14 @@ async function createSummonEnv(options, afterHost) {
|
|
|
144
131
|
async function summonPublicRole(options) {
|
|
145
132
|
const packageRoot = resolveSummonsPackageRoot(options.packageRoot);
|
|
146
133
|
const home = await resolveSummonHome(options);
|
|
147
|
-
const agentDir = options.agentDir ?? process.env.PI_CODING_AGENT_DIR ?? join(home, ".pi", "agent");
|
|
148
134
|
const {
|
|
149
135
|
loadCredentialProviders,
|
|
150
136
|
loadPublicCliConfig,
|
|
151
137
|
resolveEffectiveSeat,
|
|
138
|
+
resolvePublicAgentDir,
|
|
152
139
|
validatePublicCliConfigAxes
|
|
153
140
|
} = await import("./public-cli/config.js");
|
|
141
|
+
const agentDir = resolvePublicAgentDir(options.agentDir, home);
|
|
154
142
|
const credentials = options.credentials ?? await loadCredentialProviders(agentDir);
|
|
155
143
|
const config = await loadPublicCliConfig(home);
|
|
156
144
|
validatePublicCliConfigAxes(config, packageRoot);
|
|
@@ -304,7 +292,7 @@ async function summonParallelReviewerLenses(options) {
|
|
|
304
292
|
if (error instanceof AggregateError) {
|
|
305
293
|
return [error.message, ...error.errors.map(describeFailure)].join("\n");
|
|
306
294
|
}
|
|
307
|
-
return
|
|
295
|
+
return errorText(error);
|
|
308
296
|
};
|
|
309
297
|
const failedResult = (error) => ({
|
|
310
298
|
exitCode: 1,
|
|
@@ -485,7 +473,7 @@ async function summonGateOfficer(options) {
|
|
|
485
473
|
const correlationId = parentRunId;
|
|
486
474
|
const { isSafePositiveTicketNumber, readBoardTicketNumber } = await import("./run-ticket-number.js");
|
|
487
475
|
const parentTicket = await readBoardTicketNumber(options.sourceRunDirectory);
|
|
488
|
-
const submittedTicket =
|
|
476
|
+
const submittedTicket = isRecord(options.submission) ? options.submission.ticketNumber : void 0;
|
|
489
477
|
const courtTicket = isSafePositiveTicketNumber(submittedTicket) ? submittedTicket : parentTicket;
|
|
490
478
|
const instruction = options.reask ?? gateReviewInstruction ?? "";
|
|
491
479
|
return summonPublicRole({
|
|
@@ -1,8 +1,6 @@
|
|
|
1
|
+
import { isRecord } from "./unknown-value.js";
|
|
1
2
|
const RECEIPT_DELIVERY_TURN_LIMIT = 2;
|
|
2
3
|
const NO_RECEIPT_LIFECYCLE_ENTRY_TYPE = "ak-no-receipt-lifecycle";
|
|
3
|
-
function isRecord(value) {
|
|
4
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5
|
-
}
|
|
6
4
|
function parseNoReceiptLifecycleFacts(input) {
|
|
7
5
|
if (!isRecord(input) || typeof input.terminalToolCalled !== "boolean" || input.deliveryTurns !== RECEIPT_DELIVERY_TURN_LIMIT || input.sessionCompletion !== "settled-without-accepted-receipt" || input.acceptedReceipt !== false || typeof input.runPointer !== "string" || input.runPointer.trim() === "" || typeof input.attemptPointer !== "string" || input.attemptPointer.trim() === "" || !Array.isArray(input.rejectedReceipts) || !input.rejectedReceipts.every((item) => isRecord(item) && typeof item.reason === "string")) {
|
|
8
6
|
throw new TypeError("malformed no-receipt lifecycle facts");
|
|
@@ -5,9 +5,7 @@ import {
|
|
|
5
5
|
ensureRealDirectoryTree
|
|
6
6
|
} from "./activation-ledger-topology.js";
|
|
7
7
|
import { requireSafePositiveTicketNumber } from "./run-ticket-number.js";
|
|
8
|
-
|
|
9
|
-
return error instanceof Error && "code" in error && error.code === "ENOENT";
|
|
10
|
-
}
|
|
8
|
+
import { isEnoent } from "./unknown-value.js";
|
|
11
9
|
async function listBookRunDirectories(bookDir) {
|
|
12
10
|
const out = [];
|
|
13
11
|
const seen = /* @__PURE__ */ new Set();
|
|
@@ -16,7 +14,7 @@ async function listBookRunDirectories(bookDir) {
|
|
|
16
14
|
try {
|
|
17
15
|
entries = await readdir(runsDir, { withFileTypes: true });
|
|
18
16
|
} catch (error) {
|
|
19
|
-
if (
|
|
17
|
+
if (isEnoent(error)) return;
|
|
20
18
|
throw error;
|
|
21
19
|
}
|
|
22
20
|
for (const entry of entries) {
|
|
@@ -32,7 +30,7 @@ async function listBookRunDirectories(bookDir) {
|
|
|
32
30
|
try {
|
|
33
31
|
subjects = await readdir(bookDir, { withFileTypes: true });
|
|
34
32
|
} catch (error) {
|
|
35
|
-
if (
|
|
33
|
+
if (isEnoent(error)) return out.sort();
|
|
36
34
|
throw error;
|
|
37
35
|
}
|
|
38
36
|
for (const subject of subjects) {
|
|
@@ -64,6 +62,9 @@ function roleRunPlacement(ledgerHome, input) {
|
|
|
64
62
|
function roleRunArtifactsDirectory(runDirectory) {
|
|
65
63
|
return join(runDirectory, "artifacts");
|
|
66
64
|
}
|
|
65
|
+
function isUnboundRunDirectory(runDirectory) {
|
|
66
|
+
return runDirectory.replaceAll("\\", "/").includes("/unbound/runs/");
|
|
67
|
+
}
|
|
67
68
|
function ensureRoleRunDirectory(ledgerHome, directory) {
|
|
68
69
|
return ensureRealDirectoryTree(ledgerHome, directory);
|
|
69
70
|
}
|
|
@@ -78,6 +79,7 @@ function ensureRoleRunPlacement(ledgerHome, placement) {
|
|
|
78
79
|
export {
|
|
79
80
|
ensureRoleRunDirectory,
|
|
80
81
|
ensureRoleRunPlacement,
|
|
82
|
+
isUnboundRunDirectory,
|
|
81
83
|
listBookRunDirectories,
|
|
82
84
|
roleRunArtifactsDirectory,
|
|
83
85
|
roleRunPlacement
|
|
@@ -10,6 +10,7 @@ import { existsSync } from "node:fs";
|
|
|
10
10
|
import { readdir, readFile, writeFile } from "node:fs/promises";
|
|
11
11
|
import { join, sep } from "node:path";
|
|
12
12
|
import { AUDITOR_PARENT_ATTEMPT_BINDING_ENTRY_TYPE } from "./compliance-transport.js";
|
|
13
|
+
import { isRecord, isEnoent } from "./unknown-value.js";
|
|
13
14
|
const ADMITTED_PAGE_FIELDS = [
|
|
14
15
|
"runDirectory",
|
|
15
16
|
"admittedRequestPath",
|
|
@@ -39,11 +40,6 @@ const OFFICER_POINTER_FIELDS = ["sessionFile", "runDirectory"];
|
|
|
39
40
|
const SITIAN_RECORD_FIELDS = ["sessionParent"];
|
|
40
41
|
const SESSION_HEADER_FIELDS = ["parentSession"];
|
|
41
42
|
const BINDING_PARENT_FIELDS = ["sessionFile"];
|
|
42
|
-
function isEnoent(error) {
|
|
43
|
-
return (error instanceof Error &&
|
|
44
|
-
"code" in error &&
|
|
45
|
-
error.code === "ENOENT");
|
|
46
|
-
}
|
|
47
43
|
/** Rewrite one path value that points at or under oldRunDirectory. */
|
|
48
44
|
export function rewriteRunDirectoryPathValue(value, oldRunDirectory, newRunDirectory) {
|
|
49
45
|
if (typeof value !== "string")
|
|
@@ -111,18 +107,15 @@ function collectRewrites(input) {
|
|
|
111
107
|
}
|
|
112
108
|
return out;
|
|
113
109
|
}
|
|
114
|
-
function isPlainObject(value) {
|
|
115
|
-
return value !== null && typeof value === "object" && !Array.isArray(value);
|
|
116
|
-
}
|
|
117
110
|
/** Typed notary/source-run locator: only runDirectory is a path. */
|
|
118
111
|
function rewriteSourceRunLocator(value, rewrites) {
|
|
119
|
-
if (!
|
|
112
|
+
if (!isRecord(value))
|
|
120
113
|
return;
|
|
121
114
|
rewriteRunDirectoryPathFieldsAgainstRewrites(value, SOURCE_RUN_LOCATOR_FIELDS, rewrites);
|
|
122
115
|
}
|
|
123
116
|
/** Same-ticket summons materials: typed source-run + frozen attachment pointers. */
|
|
124
117
|
function rewriteSummonsMaterials(value, rewrites) {
|
|
125
|
-
if (!
|
|
118
|
+
if (!isRecord(value))
|
|
126
119
|
return;
|
|
127
120
|
rewriteRunDirectoryPathFieldsAgainstRewrites(value, SUMMONS_PATH_FIELDS, rewrites);
|
|
128
121
|
rewriteSourceRunLocator(value.sourceRun, rewrites);
|
|
@@ -137,12 +130,12 @@ export function rewriteAdmittedRoleRunPage(page, rewrites) {
|
|
|
137
130
|
rewriteSourceRunLocator(page.sourceRun, rewrites);
|
|
138
131
|
if (Array.isArray(page.attachments)) {
|
|
139
132
|
for (const attachment of page.attachments) {
|
|
140
|
-
if (
|
|
133
|
+
if (isRecord(attachment)) {
|
|
141
134
|
rewriteRunDirectoryPathFieldsAgainstRewrites(attachment, ["frozenPath"], rewrites);
|
|
142
135
|
}
|
|
143
136
|
}
|
|
144
137
|
}
|
|
145
|
-
if (
|
|
138
|
+
if (isRecord(page.principal)) {
|
|
146
139
|
rewriteRunDirectoryPathFieldsAgainstRewrites(page.principal, ["sessionDirectory", "sessionFile"], rewrites);
|
|
147
140
|
}
|
|
148
141
|
}
|
|
@@ -150,7 +143,7 @@ async function rewriteOfficerPointerFile(path, rewrites) {
|
|
|
150
143
|
if (!existsSync(path))
|
|
151
144
|
return;
|
|
152
145
|
const page = JSON.parse(await readFile(path, "utf8"));
|
|
153
|
-
if (!
|
|
146
|
+
if (!isRecord(page))
|
|
154
147
|
return;
|
|
155
148
|
// Only the typed direct-officer pointer shape — never arbitrary .pointer.json.
|
|
156
149
|
if (page.kind !== "direct-officer-run-pointer")
|
|
@@ -190,7 +183,7 @@ async function rewriteSitianRecordsJsonl(path, rewrites) {
|
|
|
190
183
|
out.push(line);
|
|
191
184
|
continue;
|
|
192
185
|
}
|
|
193
|
-
if (!
|
|
186
|
+
if (!isRecord(parsed)) {
|
|
194
187
|
out.push(line);
|
|
195
188
|
continue;
|
|
196
189
|
}
|
|
@@ -241,7 +234,7 @@ async function rewriteSessionTranscriptBindings(path, rewrites) {
|
|
|
241
234
|
out.push(line);
|
|
242
235
|
continue;
|
|
243
236
|
}
|
|
244
|
-
if (!
|
|
237
|
+
if (!isRecord(parsed)) {
|
|
245
238
|
out.push(line);
|
|
246
239
|
continue;
|
|
247
240
|
}
|
|
@@ -254,8 +247,8 @@ async function rewriteSessionTranscriptBindings(path, rewrites) {
|
|
|
254
247
|
}
|
|
255
248
|
else if (parsed.type === "custom" &&
|
|
256
249
|
parsed.customType === AUDITOR_PARENT_ATTEMPT_BINDING_ENTRY_TYPE &&
|
|
257
|
-
|
|
258
|
-
|
|
250
|
+
isRecord(parsed.data) &&
|
|
251
|
+
isRecord(parsed.data.parent)) {
|
|
259
252
|
const parent = parsed.data.parent;
|
|
260
253
|
const before = parent.sessionFile;
|
|
261
254
|
rewriteRunDirectoryPathFieldsAgainstRewrites(parent, BINDING_PARENT_FIELDS, rewrites);
|
|
@@ -343,11 +336,11 @@ export async function rewriteRoleRunDurablePages(input) {
|
|
|
343
336
|
const page = JSON.parse(await readFile(statePath, "utf8"));
|
|
344
337
|
const before = JSON.stringify(page);
|
|
345
338
|
rewriteRunDirectoryPathFieldsAgainstRewrites(page, RUN_STATE_PAGE_FIELDS, rewrites);
|
|
346
|
-
if (
|
|
339
|
+
if (isRecord(page.principal)) {
|
|
347
340
|
rewriteRunDirectoryPathFieldsAgainstRewrites(page.principal, ["sessionDirectory", "sessionFile"], rewrites);
|
|
348
341
|
}
|
|
349
342
|
// Open court summons: source-run locators + frozen attachment path pointers.
|
|
350
|
-
if (
|
|
343
|
+
if (isRecord(page.currentCourt)) {
|
|
351
344
|
rewriteSummonsMaterials(page.currentCourt.summons, rewrites);
|
|
352
345
|
}
|
|
353
346
|
if (JSON.stringify(page) !== before) {
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
import { readdir, readFile } from "node:fs/promises";
|
|
10
10
|
import { basename, dirname, join } from "node:path";
|
|
11
11
|
import { roleRunArtifactsDirectory } from "./role-run-placement.js";
|
|
12
|
+
import { isRecord, errorText, isMissingPathError } from "./unknown-value.js";
|
|
12
13
|
export const RUN_TERMINAL_ARTIFACT_FILES = [
|
|
13
14
|
"report.json",
|
|
14
15
|
"error.json",
|
|
@@ -26,17 +27,6 @@ export const RUN_TERMINAL_ERROR_FALLBACK_RELATIVE_PATHS = [
|
|
|
26
27
|
];
|
|
27
28
|
/** Unique open-ended failure names: error.<uuid>.json (publisher stem + uuid). */
|
|
28
29
|
const UNIQUE_ERROR_FALLBACK_NAME = /^error\.[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}\.json$/i;
|
|
29
|
-
function isMissingPathError(error) {
|
|
30
|
-
return (error instanceof Error
|
|
31
|
-
&& "code" in error
|
|
32
|
-
&& (error.code === "ENOENT" || error.code === "ENOTDIR"));
|
|
33
|
-
}
|
|
34
|
-
function errorText(error) {
|
|
35
|
-
return error instanceof Error ? error.message : String(error);
|
|
36
|
-
}
|
|
37
|
-
function isRecord(value) {
|
|
38
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
39
|
-
}
|
|
40
30
|
/**
|
|
41
31
|
* Minimum producer-owned face shared by settlement terminal artifacts
|
|
42
32
|
* (report / error / audit-incomplete). Consumer-driven: enough to identify a
|
|
@@ -1,9 +1,7 @@
|
|
|
1
1
|
import { readFile } from "node:fs/promises";
|
|
2
2
|
import { join } from "node:path";
|
|
3
|
+
import { isEnoent, isRecord } from "./unknown-value.js";
|
|
3
4
|
const MIGRATION_TICKET_DERIVATION_PAGE = "migration-ticket-derivation.json";
|
|
4
|
-
function isEnoent(error) {
|
|
5
|
-
return error instanceof Error && "code" in error && error.code === "ENOENT";
|
|
6
|
-
}
|
|
7
5
|
function isSafePositiveTicketNumber(value) {
|
|
8
6
|
return typeof value === "number" && Number.isSafeInteger(value) && value >= 1;
|
|
9
7
|
}
|
|
@@ -30,7 +28,7 @@ function ticketFromRecord(record) {
|
|
|
30
28
|
async function readJsonObject(path) {
|
|
31
29
|
try {
|
|
32
30
|
const raw = JSON.parse(await readFile(path, "utf8"));
|
|
33
|
-
if (
|
|
31
|
+
if (!isRecord(raw)) {
|
|
34
32
|
return void 0;
|
|
35
33
|
}
|
|
36
34
|
return raw;
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { join } from "node:path";
|
|
2
|
+
import { errorText } from "./unknown-value.js";
|
|
2
3
|
export async function readAssistantUsageFromSessionFile(sessionFile) {
|
|
3
4
|
const { readFile } = await import("node:fs/promises");
|
|
4
5
|
let text;
|
|
@@ -19,7 +20,7 @@ export async function readAssistantUsageFromSessionFile(sessionFile) {
|
|
|
19
20
|
.map((line) => JSON.parse(line));
|
|
20
21
|
}
|
|
21
22
|
catch (error) {
|
|
22
|
-
throw new Error(`session usage parse failed (${sessionFile}): ${
|
|
23
|
+
throw new Error(`session usage parse failed (${sessionFile}): ${errorText(error)}`, { cause: error });
|
|
23
24
|
}
|
|
24
25
|
let total = 0;
|
|
25
26
|
let input = 0;
|
package/dist/session-dialogue.js
CHANGED
|
@@ -1,17 +1,4 @@
|
|
|
1
|
-
|
|
2
|
-
* 对话事实适配(ADR 0075 `dialogue-only` / `no-tool-output` / `speaker-required`)。
|
|
3
|
-
*
|
|
4
|
-
* 「对话」=人类输入内容 + 助手回话内容,由各宿主的**结构化会话事件**适配而来。
|
|
5
|
-
* 排除按来源、不按正文:说话人自己写下的文字一律原样保留,其中引用了 ADR 段落
|
|
6
|
-
* 或工具结果也不删(#901 Out of Scope「不做正文过滤」)。
|
|
7
|
-
*
|
|
8
|
-
* 不入录的是工具结果载荷、附件记录与注入块——它们是独立的机器事件,不是谁说的话。
|
|
9
|
-
*
|
|
10
|
-
* 适配规则按宿主并列,不硬套某一宿主的类型名;一行产出 0..n 条对话事实。
|
|
11
|
-
*/
|
|
12
|
-
function isRecord(value) {
|
|
13
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
14
|
-
}
|
|
1
|
+
import { isRecord } from "./unknown-value.js";
|
|
15
2
|
/**
|
|
16
3
|
* 原生 id:行级或消息体级主键的单一实现(bound 解析与落盘共用)。
|
|
17
4
|
* Pi/CC:行上 `uuid`/`id`;Codex:`response_item.payload.id`(或 `message.id`)。
|
package/dist/sitian-reader.js
CHANGED
|
@@ -1,8 +1,6 @@
|
|
|
1
1
|
import { existsSync } from "node:fs";
|
|
2
2
|
import { readFile } from "node:fs/promises";
|
|
3
|
-
|
|
4
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
5
|
-
}
|
|
3
|
+
import { isRecord, errorText } from "./unknown-value.js";
|
|
6
4
|
async function readSitianRecords(recordFile) {
|
|
7
5
|
if (!existsSync(recordFile)) {
|
|
8
6
|
return { records: [], diagnostics: [] };
|
|
@@ -32,7 +30,7 @@ async function readSitianRecords(recordFile) {
|
|
|
32
30
|
kind: "malformed",
|
|
33
31
|
line: index + 1,
|
|
34
32
|
raw: line,
|
|
35
|
-
error:
|
|
33
|
+
error: errorText(error)
|
|
36
34
|
});
|
|
37
35
|
}
|
|
38
36
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { GatekeeperDecisionError, ParentQueueReaskError, WorkerCommitReminderError, WorkerPrefixReminderError, WorkerUnfinishedReasonReminderError, } from "./submission-errors.js";
|
|
2
|
+
import { errorText } from "./unknown-value.js";
|
|
2
3
|
/** Shared, unforgeable identity for submission errors that the same session may correct. */
|
|
3
4
|
const correctableSubmissionErrorBrand = Symbol("ak-roles.correctable-submission-error");
|
|
4
5
|
export class CorrectableSubmissionError extends Error {
|
|
@@ -25,7 +26,7 @@ export function isCorrectableExecuteError(error) {
|
|
|
25
26
|
* Consumed by the ACP envelope tool catch; host adapters wrap transport shape only.
|
|
26
27
|
*/
|
|
27
28
|
export function projectCorrectableExecuteRejection(error) {
|
|
28
|
-
const diagnostic =
|
|
29
|
+
const diagnostic = errorText(error);
|
|
29
30
|
if (error instanceof GatekeeperDecisionError) {
|
|
30
31
|
return { diagnostic, details: { ...error.result } };
|
|
31
32
|
}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { readableGateItem } from "./readable-gate-item.js";
|
|
2
|
+
import { isRecord } from "./unknown-value.js";
|
|
2
3
|
/**
|
|
3
4
|
* Tool-result text the parent model sees (#753 / #750 evidence).
|
|
4
5
|
* continue | escalate → officer receipt verbatim (JSON when structured).
|
|
@@ -61,7 +62,7 @@ export function unreadableDiscriminatorNotice(field, received) {
|
|
|
61
62
|
}
|
|
62
63
|
/** The received discriminator only — never the rest of the receipt. */
|
|
63
64
|
export function receivedDiscriminator(receipt, field) {
|
|
64
|
-
if (
|
|
65
|
+
if (!isRecord(receipt))
|
|
65
66
|
return undefined;
|
|
66
67
|
if (!Object.hasOwn(receipt, field))
|
|
67
68
|
return undefined;
|
package/dist/submission-gate.js
CHANGED
|
@@ -10,7 +10,7 @@ export function latestQueueStatus(terminal) {
|
|
|
10
10
|
if (outcome.kind !== "accepted")
|
|
11
11
|
return undefined;
|
|
12
12
|
const latest = outcome.payloads?.[outcome.payloads.length - 1];
|
|
13
|
-
if (
|
|
13
|
+
if (isRecord(latest)) {
|
|
14
14
|
const status = latest.status;
|
|
15
15
|
if (typeof status === "string" && status.trim() !== "")
|
|
16
16
|
return status;
|
|
@@ -29,6 +29,7 @@ export function latestQueuePayload(terminal) {
|
|
|
29
29
|
return payloads.length === 0 ? undefined : payloads[payloads.length - 1];
|
|
30
30
|
}
|
|
31
31
|
import { sessionFileFromPublicSummon } from "./session-assistant-usage.js";
|
|
32
|
+
import { isRecord } from "./unknown-value.js";
|
|
32
33
|
/**
|
|
33
34
|
* Shared-envelope default officer summon (ADR 0018).
|
|
34
35
|
* Role modules must not own this drive seam — only project results.
|
|
@@ -7,6 +7,7 @@ import { findRunDirectoryById } from "./public-cli/run-lifecycle.js";
|
|
|
7
7
|
import { isCorrectableExecuteError } from "./submission-correctable-error.js";
|
|
8
8
|
import { failOnInfrastructureFailureDeclaration, infrastructureFailureDiagnostic } from "./package-contracts/terminating-infrastructure.js";
|
|
9
9
|
import { REVIEW_SUBMISSION_OUTPUT_TOOL_NAME } from "./review-submission.js";
|
|
10
|
+
import { isRecord, errorText } from "./unknown-value.js";
|
|
10
11
|
/**
|
|
11
12
|
* Admitted run identity for the ledger subject.
|
|
12
13
|
* Prefer AK_ROLE_RUN_DIR via sole runDirectory→runId parser (public-CLI correlation);
|
|
@@ -464,9 +465,7 @@ export function createSubmissionLedgerHost(host, outputTools, failInfrastructure
|
|
|
464
465
|
// host-failure seam. Tool identity comes from the registry map.
|
|
465
466
|
const reviewEscalate = tool.name === REVIEW_SUBMISSION_OUTPUT_TOOL_NAME
|
|
466
467
|
&& infrastructureFailureDiagnostic(params) !== undefined
|
|
467
|
-
&& params
|
|
468
|
-
&& typeof params === "object"
|
|
469
|
-
&& !Array.isArray(params)
|
|
468
|
+
&& isRecord(params)
|
|
470
469
|
&& params.status === "escalate";
|
|
471
470
|
if (!reviewEscalate) {
|
|
472
471
|
failOnInfrastructureFailureDeclaration(params, {
|
|
@@ -485,7 +484,7 @@ export function createSubmissionLedgerHost(host, outputTools, failInfrastructure
|
|
|
485
484
|
toolCallId,
|
|
486
485
|
outcome: "correctable-rejection",
|
|
487
486
|
code: "typed-bounce",
|
|
488
|
-
diagnostic:
|
|
487
|
+
diagnostic: errorText(error),
|
|
489
488
|
role,
|
|
490
489
|
accepted: params,
|
|
491
490
|
});
|
|
@@ -497,7 +496,7 @@ export function createSubmissionLedgerHost(host, outputTools, failInfrastructure
|
|
|
497
496
|
attemptId,
|
|
498
497
|
toolCallId,
|
|
499
498
|
outcome: "infrastructure",
|
|
500
|
-
diagnostic:
|
|
499
|
+
diagnostic: errorText(error),
|
|
501
500
|
role,
|
|
502
501
|
accepted: params,
|
|
503
502
|
});
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isRecord } from "./unknown-value.js";
|
|
1
2
|
/**
|
|
2
3
|
* 起居录(ticket-provenance)typed 形状 —— ADR 0075 / ADR 0081 / #1090。
|
|
3
4
|
*
|
|
@@ -7,9 +8,6 @@
|
|
|
7
8
|
*/
|
|
8
9
|
/** Sitian kind for per-ticket court diary volumes. */
|
|
9
10
|
export const TICKET_PROVENANCE_KIND = "ticket-provenance";
|
|
10
|
-
function isRecord(value) {
|
|
11
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
12
|
-
}
|
|
13
11
|
function positiveInteger(value) {
|
|
14
12
|
if (typeof value === "number" && Number.isSafeInteger(value) && value >= 1)
|
|
15
13
|
return value;
|
|
@@ -11,6 +11,7 @@ import { isSafePositiveTicketNumber } from "./run-ticket-number.js";
|
|
|
11
11
|
import { adaptSessionDialogue, nativeEventId } from "./session-dialogue.js";
|
|
12
12
|
import { appendSitianRecordBlock, appendSitianRecord, resolveSitianRecordPath, } from "./sitian-facade.js";
|
|
13
13
|
import { TICKET_PROVENANCE_KIND, } from "./ticket-provenance-contracts.js";
|
|
14
|
+
import { errorText } from "./unknown-value.js";
|
|
14
15
|
/**
|
|
15
16
|
* Typed input failure for diarist bounds/session path (reask, not infrastructure).
|
|
16
17
|
* Accept hook discriminates with instanceof — never Error.message prefixes.
|
|
@@ -199,7 +200,7 @@ async function projectSessionRanges(input) {
|
|
|
199
200
|
throw error;
|
|
200
201
|
const code = errnoCode(error);
|
|
201
202
|
if (code === "ENOENT" || code === "ENOTDIR" || code === "EISDIR") {
|
|
202
|
-
const detail =
|
|
203
|
+
const detail = errorText(error);
|
|
203
204
|
throw new TicketProvenanceInputError(`session unreadable: ${input.session.path} (${detail})`, { cause: error });
|
|
204
205
|
}
|
|
205
206
|
throw error;
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { readFile, unlink, writeFile } from "node:fs/promises";
|
|
2
2
|
import { join } from "node:path";
|
|
3
|
+
import { isEnoent, isRecord } from "./unknown-value.js";
|
|
3
4
|
const TYPED_HTTP_FILE = "typed-provider-http.json";
|
|
4
5
|
function typedProviderHttpPath(runDirectory) {
|
|
5
6
|
return join(runDirectory, TYPED_HTTP_FILE);
|
|
@@ -8,9 +9,7 @@ async function clearTypedProviderHttpObservation(runDirectory) {
|
|
|
8
9
|
try {
|
|
9
10
|
await unlink(typedProviderHttpPath(runDirectory));
|
|
10
11
|
} catch (error) {
|
|
11
|
-
if (error
|
|
12
|
-
return;
|
|
13
|
-
}
|
|
12
|
+
if (isEnoent(error)) return;
|
|
14
13
|
throw error;
|
|
15
14
|
}
|
|
16
15
|
}
|
|
@@ -35,13 +34,11 @@ async function readLatestTypedProviderHttpObservation(runDirectory) {
|
|
|
35
34
|
try {
|
|
36
35
|
text = await readFile(typedProviderHttpPath(runDirectory), "utf8");
|
|
37
36
|
} catch (error) {
|
|
38
|
-
if (error
|
|
39
|
-
return void 0;
|
|
40
|
-
}
|
|
37
|
+
if (isEnoent(error)) return void 0;
|
|
41
38
|
throw error;
|
|
42
39
|
}
|
|
43
40
|
const raw = JSON.parse(text);
|
|
44
|
-
if (
|
|
41
|
+
if (!isRecord(raw)) {
|
|
45
42
|
throw new Error("typed provider HTTP observation must be a JSON object");
|
|
46
43
|
}
|
|
47
44
|
const record = raw;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
import { Guard } from "typebox/guard";
|
|
2
|
+
/**
|
|
3
|
+
* Sole readers for a plain object, a Node errno, and an Error message.
|
|
4
|
+
* Callers choose which codes count; ENOTDIR is not ENOENT.
|
|
5
|
+
* Plain objects are TypeBox `Guard.IsObjectNotArray`.
|
|
6
|
+
*/
|
|
7
|
+
export function isRecord(value) {
|
|
8
|
+
return Guard.IsObjectNotArray(value);
|
|
9
|
+
}
|
|
10
|
+
export function errnoCode(error) {
|
|
11
|
+
return error !== null && typeof error === "object" && "code" in error
|
|
12
|
+
&& typeof error.code === "string"
|
|
13
|
+
? error.code
|
|
14
|
+
: undefined;
|
|
15
|
+
}
|
|
16
|
+
/** `Error.message`, otherwise `String(value)`. */
|
|
17
|
+
export function errorText(error) {
|
|
18
|
+
return error instanceof Error ? error.message : String(error);
|
|
19
|
+
}
|
|
20
|
+
/** True only for ENOENT on an Error. ENOTDIR and every other code stay distinct. */
|
|
21
|
+
export function isEnoent(error) {
|
|
22
|
+
return error instanceof Error && errnoCode(error) === "ENOENT";
|
|
23
|
+
}
|
|
24
|
+
/** ENOENT or ENOTDIR on an Error. */
|
|
25
|
+
export function isMissingPathError(error) {
|
|
26
|
+
const code = errnoCode(error);
|
|
27
|
+
return error instanceof Error && (code === "ENOENT" || code === "ENOTDIR");
|
|
28
|
+
}
|
|
@@ -3,12 +3,13 @@
|
|
|
3
3
|
* Pi's piped-stdin reader trims the wrapper; the body field keeps original bytes.
|
|
4
4
|
* No size cap and no path/pointer substitute — the whole dialogue rides the envelope.
|
|
5
5
|
*/
|
|
6
|
+
import { isRecord } from "./unknown-value.js";
|
|
6
7
|
export const USER_DIALOGUE_STDIN_KIND = "ak-user-dialogue";
|
|
7
8
|
export function encodeUserDialogueStdin(body) {
|
|
8
9
|
return JSON.stringify({ kind: USER_DIALOGUE_STDIN_KIND, body });
|
|
9
10
|
}
|
|
10
11
|
function isUserDialogueEnvelope(value) {
|
|
11
|
-
if (
|
|
12
|
+
if (!isRecord(value))
|
|
12
13
|
return false;
|
|
13
14
|
const record = value;
|
|
14
15
|
return record.kind === USER_DIALOGUE_STDIN_KIND && typeof record.body === "string";
|
package/package.json
CHANGED
|
@@ -27,6 +27,8 @@ import {
|
|
|
27
27
|
} from "../prepared-role-turn.ts";
|
|
28
28
|
import { acpModelId, type AcpHostDescription } from "./description.ts";
|
|
29
29
|
|
|
30
|
+
import { isRecord } from "../unknown-value.ts";
|
|
31
|
+
|
|
30
32
|
/**
|
|
31
33
|
* #959: collect free-form agent text from ACP session/update stream.
|
|
32
34
|
* Used only when the navigator seat spoke prose without calling the output tool.
|
|
@@ -42,7 +44,7 @@ function acpAgentTextChunk(params: Readonly<Record<string, unknown>>): string |
|
|
|
42
44
|
let textFallback: unknown;
|
|
43
45
|
|
|
44
46
|
const nested = params.update;
|
|
45
|
-
if (
|
|
47
|
+
if (isRecord(nested)) {
|
|
46
48
|
const record = nested as Record<string, unknown>;
|
|
47
49
|
kind = record.sessionUpdate;
|
|
48
50
|
content = record.content;
|
|
@@ -55,7 +57,7 @@ function acpAgentTextChunk(params: Readonly<Record<string, unknown>>): string |
|
|
|
55
57
|
|
|
56
58
|
if (kind !== "agent_message_chunk" && kind !== "agent_message") return undefined;
|
|
57
59
|
if (typeof content === "string" && content.length > 0) return content;
|
|
58
|
-
if (
|
|
60
|
+
if (isRecord(content)) {
|
|
59
61
|
const record = content as Record<string, unknown>;
|
|
60
62
|
if (typeof record.text === "string" && record.text.length > 0) return record.text;
|
|
61
63
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
import { execFileSync } from "node:child_process";
|
|
2
2
|
import { basename, dirname, isAbsolute, resolve } from "node:path";
|
|
3
3
|
|
|
4
|
+
import { errnoCode } from "./unknown-value.ts";
|
|
5
|
+
|
|
4
6
|
/** Git discovery env vars that must not influence book-key resolution from cwd. */
|
|
5
7
|
const GIT_DISCOVERY_ENV_KEYS = [
|
|
6
8
|
"GIT_DIR",
|
|
@@ -60,8 +62,7 @@ export class ActivationGitRepositoryRequiredError extends Error {
|
|
|
60
62
|
|
|
61
63
|
/** Spawn/OS failure identity for the git child — not a repository-status result. */
|
|
62
64
|
function isGitSpawnInfrastructureError(error: unknown): boolean {
|
|
63
|
-
|
|
64
|
-
const code = (error as { code: unknown }).code;
|
|
65
|
+
const code = errnoCode(error);
|
|
65
66
|
return code === "ENOENT" || code === "EACCES" || code === "EPERM";
|
|
66
67
|
}
|
|
67
68
|
|