@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
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { execFileSync } from "node:child_process";
|
|
2
2
|
import { basename, dirname, isAbsolute, resolve } from "node:path";
|
|
3
|
+
import { errnoCode } from "./unknown-value.js";
|
|
3
4
|
const GIT_DISCOVERY_ENV_KEYS = [
|
|
4
5
|
"GIT_DIR",
|
|
5
6
|
"GIT_COMMON_DIR",
|
|
@@ -31,8 +32,7 @@ class ActivationGitRepositoryRequiredError extends Error {
|
|
|
31
32
|
}
|
|
32
33
|
}
|
|
33
34
|
function isGitSpawnInfrastructureError(error) {
|
|
34
|
-
|
|
35
|
-
const code = error.code;
|
|
35
|
+
const code = errnoCode(error);
|
|
36
36
|
return code === "ENOENT" || code === "EACCES" || code === "EPERM";
|
|
37
37
|
}
|
|
38
38
|
function gitChildExitedNonzero(error) {
|
|
@@ -6,6 +6,7 @@ import {
|
|
|
6
6
|
} from "node:fs";
|
|
7
7
|
import { userInfo } from "node:os";
|
|
8
8
|
import { basename, dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
|
|
9
|
+
import { errnoCode, errorText } from "./unknown-value.js";
|
|
9
10
|
class ActivationLedgerError extends Error {
|
|
10
11
|
code = "AK_ACTIVATION_LEDGER";
|
|
11
12
|
constructor(message, options) {
|
|
@@ -83,13 +84,6 @@ function physicalPathIdentity(path) {
|
|
|
83
84
|
function physicallyContainedIn(root, candidate) {
|
|
84
85
|
return pathContainedIn(physicalPathIdentity(root), physicalPathIdentity(candidate));
|
|
85
86
|
}
|
|
86
|
-
function errnoCode(error) {
|
|
87
|
-
return error !== null && typeof error === "object" && "code" in error && typeof error.code === "string" ? error.code : void 0;
|
|
88
|
-
}
|
|
89
|
-
function errorText(error) {
|
|
90
|
-
if (!(error instanceof Error)) return String(error);
|
|
91
|
-
return error.message;
|
|
92
|
-
}
|
|
93
87
|
function assertPhysicalLedgerRoot(absoluteRoot) {
|
|
94
88
|
let st;
|
|
95
89
|
try {
|
package/dist/analyst-entry.js
CHANGED
|
@@ -19,6 +19,7 @@ import { scanAnalystIssueRuns, } from "./analyst-ledger.js";
|
|
|
19
19
|
import { mergeAnalystLibraryIndexRows, rowFromIssueMetricsPage, } from "./analyst-index.js";
|
|
20
20
|
import { buildAnalystModelGroupsPage, } from "./analyst-model-groups.js";
|
|
21
21
|
import { assertAnalystChangedLinesInput, buildAnalystIssueMetricsPage, analystIssuePagePath, writeAnalystIssueMetricsPage, } from "./analyst-page.js";
|
|
22
|
+
import { isMissingPathError } from "./unknown-value.js";
|
|
22
23
|
/** #338 compute-if-missing failure — issue identity + real cause (CLI → ControlledFailure). */
|
|
23
24
|
export class AnalystIssueComputeError extends Error {
|
|
24
25
|
code = "analyst-issue-compute-failed";
|
|
@@ -44,16 +45,11 @@ export class AnalystIssueComputeError extends Error {
|
|
|
44
45
|
}
|
|
45
46
|
}
|
|
46
47
|
}
|
|
47
|
-
function isMissingPathError(error) {
|
|
48
|
-
return (error instanceof Error
|
|
49
|
-
&& "code" in error
|
|
50
|
-
&& (error.code === "ENOENT" || error.code === "ENOTDIR"));
|
|
51
|
-
}
|
|
52
48
|
/**
|
|
53
49
|
* Sole sweep-mode input contract (#298/#329/#337).
|
|
54
50
|
* Schema is the single definition; TS types are derived (no parallel hand shape).
|
|
55
51
|
* projectRoot = string (not nonempty); changedLines optional finite non-negative;
|
|
56
|
-
* 0 remains typed
|
|
52
|
+
* 0 remains typed 空缺. Extra keys are not a reject reason.
|
|
57
53
|
*/
|
|
58
54
|
export const analystSweepModeInputSchema = Type.Object({
|
|
59
55
|
mode: Type.Literal("sweep"),
|
|
@@ -61,8 +57,8 @@ export const analystSweepModeInputSchema = Type.Object({
|
|
|
61
57
|
projectRoot: Type.String(),
|
|
62
58
|
/** 排除后改动行数 — omit or 0 → typed 空缺; finite ≥ 0 only. */
|
|
63
59
|
changedLines: Type.Optional(Type.Number({ minimum: 0, maximum: Number.MAX_VALUE })),
|
|
64
|
-
}
|
|
65
|
-
}
|
|
60
|
+
})),
|
|
61
|
+
});
|
|
66
62
|
/**
|
|
67
63
|
* #338 retrieval primitive (sync): use persisted page when present; otherwise
|
|
68
64
|
* await the sole issue compute kernel (runAnalystIssueMode) which writes via the
|
|
@@ -29,6 +29,7 @@ import { readdir } from "node:fs/promises";
|
|
|
29
29
|
import { join } from "node:path";
|
|
30
30
|
import { AUDITOR_PARENT_ATTEMPT_BINDING_ENTRY_TYPE, } from "./compliance-transport.js";
|
|
31
31
|
import { extractSessionTimestampSpan, intervalRowsAroundAnchor, readLedgerSessionJsonl, } from "./ledger-session-read.js";
|
|
32
|
+
import { isRecord, errorText, isEnoent } from "./unknown-value.js";
|
|
32
33
|
const DISPATCH_TOOLS = new Set(["ak_menxia_output", "ak_gatekeeper_output"]);
|
|
33
34
|
/** Officer terminating tool → current English officer identity. */
|
|
34
35
|
const OFFICER_TOOL_TO_FACE = {
|
|
@@ -44,9 +45,6 @@ const OFFICER_ARG_ALIASES = {
|
|
|
44
45
|
fubaolang: "notary",
|
|
45
46
|
notary: "notary",
|
|
46
47
|
};
|
|
47
|
-
function isRecord(value) {
|
|
48
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
49
|
-
}
|
|
50
48
|
function isParentAttemptBindingRow(row) {
|
|
51
49
|
return row.type === "custom" && row.customType === AUDITOR_PARENT_ATTEMPT_BINDING_ENTRY_TYPE;
|
|
52
50
|
}
|
|
@@ -54,12 +52,6 @@ function isParentAttemptBindingRow(row) {
|
|
|
54
52
|
function intervalRowsForGateCall(rows, callRowIndex) {
|
|
55
53
|
return intervalRowsAroundAnchor(rows, callRowIndex, isParentAttemptBindingRow).rows;
|
|
56
54
|
}
|
|
57
|
-
/** Only true absence (ENOENT). ENOTDIR is damaged topology — must stay loud. */
|
|
58
|
-
function isMissingDirectoryError(error) {
|
|
59
|
-
return (error instanceof Error
|
|
60
|
-
&& "code" in error
|
|
61
|
-
&& error.code === "ENOENT");
|
|
62
|
-
}
|
|
63
55
|
function normalizeOfficerArg(raw) {
|
|
64
56
|
if (typeof raw !== "string")
|
|
65
57
|
return undefined;
|
|
@@ -325,7 +317,7 @@ async function resolveOfficerSessionFromPointerFile(pointerPath) {
|
|
|
325
317
|
raw = JSON.parse(await readFile(pointerPath, "utf8"));
|
|
326
318
|
}
|
|
327
319
|
catch (error) {
|
|
328
|
-
throw new Error(`direct officer run pointer unreadable in ${pointerPath}: ${
|
|
320
|
+
throw new Error(`direct officer run pointer unreadable in ${pointerPath}: ${errorText(error)}`, { cause: error });
|
|
329
321
|
}
|
|
330
322
|
if (!isRecord(raw) || raw.kind !== "direct-officer-run-pointer" || raw.version !== 1) {
|
|
331
323
|
throw new Error(`direct officer run pointer has unknown shape in ${pointerPath}`);
|
|
@@ -367,7 +359,7 @@ export async function readAnalystGateCyclesFromAuditorRoles(auditorRolesDirector
|
|
|
367
359
|
.sort();
|
|
368
360
|
}
|
|
369
361
|
catch (error) {
|
|
370
|
-
if (
|
|
362
|
+
if (isEnoent(error))
|
|
371
363
|
continue;
|
|
372
364
|
throw error;
|
|
373
365
|
}
|
package/dist/analyst-index.js
CHANGED
|
@@ -20,17 +20,14 @@
|
|
|
20
20
|
*/
|
|
21
21
|
import { open, readFile, unlink } from "node:fs/promises";
|
|
22
22
|
import { dirname, join } from "node:path";
|
|
23
|
+
import { setTimeout as sleep } from "node:timers/promises";
|
|
23
24
|
import { writeFileAtomically } from "./atomic-write.js";
|
|
24
25
|
import { assertLedgerFileInsideHome, ensureRealDirectoryTree, physicalPathIdentity, } from "./activation-ledger-topology.js";
|
|
25
26
|
import { resolveAnalystBookKey } from "./analyst-book-key.js";
|
|
27
|
+
import { isMissingPathError } from "./unknown-value.js";
|
|
26
28
|
const LIBRARY_INDEX_LOCK_NAME = ".library-index.lock";
|
|
27
29
|
const LIBRARY_INDEX_LOCK_TIMEOUT_MS = 30_000;
|
|
28
30
|
const LIBRARY_INDEX_LOCK_RETRY_MS = 15;
|
|
29
|
-
function sleep(ms) {
|
|
30
|
-
return new Promise((resolve) => {
|
|
31
|
-
setTimeout(resolve, ms);
|
|
32
|
-
});
|
|
33
|
-
}
|
|
34
31
|
/**
|
|
35
32
|
* Exclusive create lock for the library-index read→upsert→write critical section.
|
|
36
33
|
* Same-directory sibling of the index file; not a second index and not a daemon.
|
|
@@ -198,11 +195,8 @@ export async function readAnalystLibraryIndexPage(ledgerHome) {
|
|
|
198
195
|
raw = await readFile(path, "utf8");
|
|
199
196
|
}
|
|
200
197
|
catch (error) {
|
|
201
|
-
if (error
|
|
202
|
-
&& "code" in error
|
|
203
|
-
&& (error.code === "ENOENT" || error.code === "ENOTDIR")) {
|
|
198
|
+
if (isMissingPathError(error))
|
|
204
199
|
return undefined;
|
|
205
|
-
}
|
|
206
200
|
throw error;
|
|
207
201
|
}
|
|
208
202
|
const parsed = JSON.parse(raw);
|
package/dist/analyst-ledger.js
CHANGED
|
@@ -22,17 +22,7 @@ import { readRunTicketNumber } from "./run-ticket-number.js";
|
|
|
22
22
|
import { extractSessionModelSequence, extractSessionTimestampSpan, extractSessionToolIntervals, LedgerSessionJsonlError, readLedgerSessionJsonl, } from "./ledger-session-read.js";
|
|
23
23
|
import { readRunTerminalArtifact, } from "./run-terminal-artifacts.js";
|
|
24
24
|
import { readAnalystGateCyclesFromAuditorRoles, } from "./analyst-gate-cycles-read.js";
|
|
25
|
-
|
|
26
|
-
return (error instanceof Error
|
|
27
|
-
&& "code" in error
|
|
28
|
-
&& (error.code === "ENOENT" || error.code === "ENOTDIR"));
|
|
29
|
-
}
|
|
30
|
-
function errorText(error) {
|
|
31
|
-
return error instanceof Error ? error.message : String(error);
|
|
32
|
-
}
|
|
33
|
-
function isRecord(value) {
|
|
34
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
35
|
-
}
|
|
25
|
+
import { isRecord, errorText, isMissingPathError } from "./unknown-value.js";
|
|
36
26
|
/** Existing public-cli run-state live phases — not a new state machine. */
|
|
37
27
|
const LIVE_RUN_STATES = new Set(["admitted", "running", "resumable"]);
|
|
38
28
|
/**
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
import { compareAnalystLegs, sumAnalystRunWallMs } from "../analyst-ledger.js";
|
|
13
13
|
import { medianNumber } from "../analyst-median.js";
|
|
14
14
|
import { packagedAnalystTerminal } from "../packaged-role-registry.js";
|
|
15
|
+
import { isRecord } from "../unknown-value.js";
|
|
15
16
|
const WORKER_ROLES = new Set(["coder", "fixer"]);
|
|
16
17
|
/** Lawful acceptance vocabulary by role (PRD 受理终态映射). */
|
|
17
18
|
const ACCEPTED_STATUS = {
|
|
@@ -32,9 +33,6 @@ const SUCCESS_STATUS = {
|
|
|
32
33
|
doctor: new Set(["completed"]),
|
|
33
34
|
merger: new Set(["completed"]),
|
|
34
35
|
};
|
|
35
|
-
function isRecord(value) {
|
|
36
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
37
|
-
}
|
|
38
36
|
/** Locate collector groups array: receipt.groups or top-level groups. */
|
|
39
37
|
function findCollectorGroups(body) {
|
|
40
38
|
if (Array.isArray(body.groups))
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { extractStatus } from "./acceptance-success-rework.js";
|
|
2
|
-
|
|
3
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
4
|
-
}
|
|
2
|
+
import { isRecord } from "../unknown-value.js";
|
|
5
3
|
function readClassCount(body) {
|
|
6
4
|
if (!isRecord(body.outcome))
|
|
7
5
|
return undefined;
|
package/dist/analyst-page.js
CHANGED
|
@@ -6,8 +6,8 @@
|
|
|
6
6
|
* top-level sections via directory discovery — B/C waves add family files
|
|
7
7
|
* without forking the page writer or editing a shared registry list.
|
|
8
8
|
*/
|
|
9
|
-
import { createHash } from "node:crypto";
|
|
10
9
|
import { dirname, join } from "node:path";
|
|
10
|
+
import { sha256Hex } from "./sha256.js";
|
|
11
11
|
import { writeFileAtomically } from "./atomic-write.js";
|
|
12
12
|
import { assertLedgerFileInsideHome, ensureRealDirectoryTree, physicalPathIdentity, } from "./activation-ledger-topology.js";
|
|
13
13
|
import { compareAnalystLegs, sumAnalystRunWallMs } from "./analyst-ledger.js";
|
|
@@ -21,7 +21,7 @@ export function analystIssuePageKey(address) {
|
|
|
21
21
|
else if (address.scopeRootIdentity !== undefined) {
|
|
22
22
|
parts.push("root", physicalPathIdentity(address.scopeRootIdentity));
|
|
23
23
|
}
|
|
24
|
-
return
|
|
24
|
+
return sha256Hex(parts.join("\0")).slice(0, 32);
|
|
25
25
|
}
|
|
26
26
|
export function analystIssuePagePath(ledgerHome, address) {
|
|
27
27
|
return join(ledgerHome, "analyst", "issues", `${analystIssuePageKey(address)}.json`);
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { createHash } from "node:crypto";
|
|
2
1
|
import { join } from "node:path";
|
|
2
|
+
import { sha256Hex } from "./sha256.js";
|
|
3
3
|
import { resolveBookKeyFromGit } from "./activation-ledger-git.js";
|
|
4
4
|
import {
|
|
5
5
|
activationBookDirectory,
|
|
@@ -16,7 +16,7 @@ function resolveNavigatorWorkSubjectPlacement(input) {
|
|
|
16
16
|
}
|
|
17
17
|
}
|
|
18
18
|
ledgerHome ??= resolveActivationLedgerHome(input.home);
|
|
19
|
-
const digest =
|
|
19
|
+
const digest = sha256Hex(input.subject).slice(0, 32);
|
|
20
20
|
return {
|
|
21
21
|
ledgerHome,
|
|
22
22
|
sessionDir: join(
|
package/dist/audit-escalation.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
|
+
import { isRecord } from "./unknown-value.js";
|
|
1
2
|
/** Historical audit-escalation discriminator retained for reading pre-#1057 run artifacts. */
|
|
2
3
|
export const AUDIT_ESCALATION_KIND = "audit_escalation";
|
|
3
4
|
export function isAuditEscalationResult(value) {
|
|
4
|
-
return
|
|
5
|
+
return isRecord(value)
|
|
5
6
|
&& value.kind === AUDIT_ESCALATION_KIND;
|
|
6
7
|
}
|
package/dist/auditor-soul.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { readFile } from "node:fs/promises";
|
|
2
2
|
import { basename, join } from "node:path";
|
|
3
|
+
import { isRecord } from "./unknown-value.js";
|
|
3
4
|
import { joinPackageMaterials, readPackageMaterial, } from "./session-opening-materials.js";
|
|
4
5
|
/**
|
|
5
6
|
* Active auditor seats.
|
|
@@ -100,7 +101,7 @@ export async function readAuditorResumeBinding(runDirectory) {
|
|
|
100
101
|
return undefined;
|
|
101
102
|
throw error;
|
|
102
103
|
}
|
|
103
|
-
if (
|
|
104
|
+
if (!isRecord(raw))
|
|
104
105
|
return undefined;
|
|
105
106
|
const record = raw;
|
|
106
107
|
if (typeof record.sourceRunPath !== "string" || record.sourceRunPath.trim() === "")
|
package/dist/collector-config.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
|
-
import { createHash } from "node:crypto";
|
|
2
1
|
import { readFile } from "node:fs/promises";
|
|
2
|
+
import { sha256Hex } from "./sha256.js";
|
|
3
|
+
import { isRecord } from "./unknown-value.js";
|
|
3
4
|
export const COLLECTOR_OWNER_PATTERN = /^[A-Za-z0-9](?:[A-Za-z0-9-]{0,37}[A-Za-z0-9])?$/;
|
|
4
5
|
export const COLLECTOR_REPO_PATTERN = /^[A-Za-z0-9](?:[A-Za-z0-9._-]{0,98}[A-Za-z0-9])?$/;
|
|
5
6
|
function fail(message, cause) {
|
|
@@ -38,15 +39,12 @@ export function parseCollectorPrNumber(raw) {
|
|
|
38
39
|
fail("Collector pull request number must be a positive safe integer");
|
|
39
40
|
return value;
|
|
40
41
|
}
|
|
41
|
-
function record(value) {
|
|
42
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
43
|
-
}
|
|
44
42
|
function canonicalManifest(requests) {
|
|
45
43
|
return `${JSON.stringify({ requests: requests.map((request) => ({ id: request.id, body: request.requestBody })) })}\n`;
|
|
46
44
|
}
|
|
47
45
|
export function emptyCollectorManifest() {
|
|
48
46
|
const canonicalJson = canonicalManifest([]);
|
|
49
|
-
return { requests: [], canonicalJson, digest:
|
|
47
|
+
return { requests: [], canonicalJson, digest: sha256Hex(canonicalJson) };
|
|
50
48
|
}
|
|
51
49
|
/** Optional request configuration. It names requests, never expected observers. */
|
|
52
50
|
export async function loadCollectorManifest(path) {
|
|
@@ -64,7 +62,7 @@ export async function loadCollectorManifest(path) {
|
|
|
64
62
|
catch (error) {
|
|
65
63
|
fail("Collector request manifest must be UTF-8 JSON", error);
|
|
66
64
|
}
|
|
67
|
-
if (!
|
|
65
|
+
if (!isRecord(parsed))
|
|
68
66
|
fail("Collector request manifest must be an object");
|
|
69
67
|
const rawRequests = parsed.requests ?? [];
|
|
70
68
|
if (!Array.isArray(rawRequests))
|
|
@@ -72,7 +70,7 @@ export async function loadCollectorManifest(path) {
|
|
|
72
70
|
const requests = [];
|
|
73
71
|
const ids = new Set();
|
|
74
72
|
for (const [index, item] of rawRequests.entries()) {
|
|
75
|
-
if (!
|
|
73
|
+
if (!isRecord(item) || typeof item.id !== "string" || item.id.length === 0 || typeof item.body !== "string" || item.body.trim() === "")
|
|
76
74
|
fail(`Collector request manifest requests[${index}] is invalid`);
|
|
77
75
|
if (ids.has(item.id))
|
|
78
76
|
fail(`Collector request manifest has duplicate request id "${item.id}"`);
|
|
@@ -80,5 +78,5 @@ export async function loadCollectorManifest(path) {
|
|
|
80
78
|
requests.push({ id: item.id, requestBody: item.body });
|
|
81
79
|
}
|
|
82
80
|
const canonicalJson = canonicalManifest(requests);
|
|
83
|
-
return { requests, canonicalJson, digest:
|
|
81
|
+
return { requests, canonicalJson, digest: sha256Hex(canonicalJson), sourcePath: path };
|
|
84
82
|
}
|
|
@@ -3,6 +3,7 @@ import { officerConclusionReask } from "./gatekeeper-role.js";
|
|
|
3
3
|
import { receivedDiscriminator } from "./submission-errors.js";
|
|
4
4
|
import { coalesceSubmissionRows } from "./public-cli/terminal.js";
|
|
5
5
|
import { readableGateItem } from "./readable-gate-item.js";
|
|
6
|
+
import { isRecord } from "./unknown-value.js";
|
|
6
7
|
const AUDITOR_DOSSIER_PROMPT = "\u5377\u5B97\u6307\u9488\uFF1A";
|
|
7
8
|
const COMPLIANCE_RESPONSE_ENTRY_TYPE = "ak_compliance_response";
|
|
8
9
|
const AUDITOR_PARENT_ATTEMPT_BINDING_ENTRY_TYPE = "ak_auditor_parent_attempt_binding";
|
|
@@ -17,7 +18,7 @@ function readListField(value) {
|
|
|
17
18
|
return Array.isArray(value) ? value : value === void 0 ? [] : [value];
|
|
18
19
|
}
|
|
19
20
|
function tryReadComplianceCandidate(arguments_, usage) {
|
|
20
|
-
if (
|
|
21
|
+
if (!isRecord(arguments_)) {
|
|
21
22
|
return void 0;
|
|
22
23
|
}
|
|
23
24
|
const args = arguments_;
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import { REVIEW_QUEUE_STATUSES, REVIEW_SUBMISSION_OUTPUT_TOOL_NAME } from "./review-submission.js";
|
|
2
|
+
import { isRecord } from "./unknown-value.js";
|
|
2
3
|
const COUNTERSIGN_OUTPUT_TOOL_NAME = REVIEW_SUBMISSION_OUTPUT_TOOL_NAME;
|
|
3
4
|
function validateRecordedCountersignOutput(verdict) {
|
|
4
|
-
if (
|
|
5
|
+
if (!isRecord(verdict)) {
|
|
5
6
|
throw new Error("Countersign verdict has no execution discriminator");
|
|
6
7
|
}
|
|
7
8
|
let status;
|
|
@@ -8,9 +8,10 @@
|
|
|
8
8
|
*/
|
|
9
9
|
import { projectTicketProvenanceSessions, } from "./ticket-provenance-contracts.js";
|
|
10
10
|
import { isSafePositiveTicketNumber } from "./run-ticket-number.js";
|
|
11
|
+
import { isRecord } from "./unknown-value.js";
|
|
11
12
|
export const DIARIST_OUTPUT_TOOL_NAME = "ak_diarist_output";
|
|
12
13
|
export function validateRecordedDiaristOutput(value) {
|
|
13
|
-
if (
|
|
14
|
+
if (!isRecord(value)) {
|
|
14
15
|
throw new Error("Diarist output has no execution discriminator");
|
|
15
16
|
}
|
|
16
17
|
let status;
|
|
@@ -42,7 +43,7 @@ export function projectDiaristTicketSessions(value) {
|
|
|
42
43
|
return undefined;
|
|
43
44
|
const perTicket = new Map();
|
|
44
45
|
for (const entry of raw) {
|
|
45
|
-
if (
|
|
46
|
+
if (!isRecord(entry))
|
|
46
47
|
return undefined;
|
|
47
48
|
const { ticketNumber, sessions: rawSessions } = entry;
|
|
48
49
|
if (!isSafePositiveTicketNumber(ticketNumber))
|
package/dist/doctor-contracts.js
CHANGED
|
@@ -2,6 +2,7 @@ import { Type } from "typebox";
|
|
|
2
2
|
import { canonicalJson } from "./canonical-json.js";
|
|
3
3
|
import { openToolObject } from "./open-tool-schema.js";
|
|
4
4
|
import { withTerminatingOutputDeclarations } from "./package-contracts/terminating-infrastructure.js";
|
|
5
|
+
import { isRecord } from "./unknown-value.js";
|
|
5
6
|
const DOCTOR_EVIDENCE_TOOL_NAME = "ak_doctor_evidence";
|
|
6
7
|
const DOCTOR_OUTPUT_TOOL_NAME = "ak_doctor_output";
|
|
7
8
|
const DOCTOR_AUDIT_TOOL_NAME = "ak_doctor_audit_decision";
|
|
@@ -35,9 +36,6 @@ const doctorEvidenceReadSchema = Type.Object({ evidenceId: Type.String({ minLeng
|
|
|
35
36
|
class DoctorSubmissionContractError extends Error {
|
|
36
37
|
name = "DoctorSubmissionContractError";
|
|
37
38
|
}
|
|
38
|
-
function isRecord(value) {
|
|
39
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
40
|
-
}
|
|
41
39
|
function read(value, key) {
|
|
42
40
|
if (!isRecord(value)) return void 0;
|
|
43
41
|
try {
|
package/dist/doctor-evidence.js
CHANGED
|
@@ -2,7 +2,7 @@ import { readdir, readFile, realpath, stat } from "node:fs/promises";
|
|
|
2
2
|
import { dirname, relative, resolve, sep } from "node:path";
|
|
3
3
|
import { sha256Hex } from "./sha256.js";
|
|
4
4
|
import { AcceptedDetailsContractError, acceptedFacts, isTerminatingToolName, validateAcceptedDetails } from "./package-contracts/terminating-tools.js";
|
|
5
|
-
|
|
5
|
+
import { isRecord, isMissingPathError } from "./unknown-value.js";
|
|
6
6
|
async function discoverCaseFiles(root) { const found = []; async function walk(dir, depth) { for (const item of await readdir(dir, { withFileTypes: true })) {
|
|
7
7
|
const path = resolve(dir, item.name);
|
|
8
8
|
if (item.isDirectory()) {
|
|
@@ -15,7 +15,6 @@ function sourceList(count, sources) { return { count, sources: [...new Set(sourc
|
|
|
15
15
|
function accumulate(metric, value, source) { metric.count += value; if (value)
|
|
16
16
|
metric.sources.push(source); }
|
|
17
17
|
function timestamp(row) { return typeof row.timestamp === "string" && Number.isFinite(Date.parse(row.timestamp)) ? row.timestamp : undefined; }
|
|
18
|
-
function isMissingPathError(error) { return error instanceof Error && "code" in error && (error.code === "ENOENT" || error.code === "ENOTDIR"); }
|
|
19
18
|
async function stableRunsIdentity(root) { let cursor = root; while (true) {
|
|
20
19
|
try {
|
|
21
20
|
const git = await stat(resolve(cursor, ".git"));
|
|
@@ -38,7 +37,7 @@ function deriveSession(content, id) {
|
|
|
38
37
|
if (line.trim()) {
|
|
39
38
|
try {
|
|
40
39
|
const row = JSON.parse(line);
|
|
41
|
-
if (!
|
|
40
|
+
if (!isRecord(row)) {
|
|
42
41
|
degradationReasons.push(`non-object session row in ${id}`);
|
|
43
42
|
break;
|
|
44
43
|
}
|
|
@@ -59,21 +58,21 @@ function deriveSession(content, id) {
|
|
|
59
58
|
let accepted, observedCommit, turns = 0, calls = 0, tokens = 0;
|
|
60
59
|
const statuses = [], commits = [];
|
|
61
60
|
for (const row of rows) {
|
|
62
|
-
if (row.type === "custom" && row.customType === "ak-role-submission-closure" &&
|
|
61
|
+
if (row.type === "custom" && row.customType === "ak-role-submission-closure" && isRecord(row.data) && row.data.isError === false && typeof row.data.toolName === "string" && isTerminatingToolName(row.data.toolName))
|
|
63
62
|
accepted = row;
|
|
64
|
-
const message =
|
|
63
|
+
const message = isRecord(row.message) ? row.message : undefined;
|
|
65
64
|
if (message?.role === "assistant") {
|
|
66
65
|
for (const part of Array.isArray(message.content) ? message.content : [])
|
|
67
|
-
if (
|
|
66
|
+
if (isRecord(part) && part.type === "toolCall")
|
|
68
67
|
calls++;
|
|
69
68
|
if (typeof message.responseId === "string") {
|
|
70
69
|
turns++;
|
|
71
|
-
const usage =
|
|
70
|
+
const usage = isRecord(message.usage) ? message.usage : undefined;
|
|
72
71
|
if (usage && typeof usage.output === "number")
|
|
73
72
|
tokens += usage.output;
|
|
74
73
|
}
|
|
75
74
|
}
|
|
76
|
-
if (message?.role === "toolResult" && message.isError !== true && typeof message.toolName === "string" && isTerminatingToolName(message.toolName) &&
|
|
75
|
+
if (message?.role === "toolResult" && message.isError !== true && typeof message.toolName === "string" && isTerminatingToolName(message.toolName) && isRecord(message.details)) {
|
|
77
76
|
let details;
|
|
78
77
|
try {
|
|
79
78
|
details = validateAcceptedDetails(message.toolName, message.details);
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
import { existsSync, statSync } from "node:fs";
|
|
8
8
|
import { resolve } from "node:path";
|
|
9
9
|
import { runDirectoryFromHostContext } from "./host-contracts.js";
|
|
10
|
+
import { isRecord } from "./unknown-value.js";
|
|
10
11
|
export const AUDIT_RUN_DIR_ENV = "AK_ROLE_RUN_DIR";
|
|
11
12
|
export const DOCTOR_CANDIDATE_ENTRY_TYPE = "ak_doctor_audit_candidate";
|
|
12
13
|
function isHostContext(value) {
|
|
@@ -45,9 +46,6 @@ export function resolveAuditDossier(source) {
|
|
|
45
46
|
}
|
|
46
47
|
return { status: "ok", runDirectory };
|
|
47
48
|
}
|
|
48
|
-
function isRecord(value) {
|
|
49
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
50
|
-
}
|
|
51
49
|
/**
|
|
52
50
|
* Doctor candidate testimony must be recorded before audit.
|
|
53
51
|
*/
|
|
@@ -20,6 +20,7 @@ import { readFileSync } from "node:fs";
|
|
|
20
20
|
import { dirname, join } from "node:path";
|
|
21
21
|
import { ENGINE_DETOUR_TOOL_NAME } from "./engine-detour.js";
|
|
22
22
|
import { readSitianRecords, resolveSitianRecordPath, sitianReport, } from "./sitian-facade.js";
|
|
23
|
+
import { isRecord } from "./unknown-value.js";
|
|
23
24
|
/** Sitian event kind for one detour-tool call (volume under session/). */
|
|
24
25
|
export const ENGINE_DETOUR_CALL_KIND = "engine-detour-call";
|
|
25
26
|
/** decisiveFacts key — name states detour-tool scope, not full engine usage. */
|
|
@@ -99,9 +100,6 @@ export function reportEngineDetourCall(input) {
|
|
|
99
100
|
recordPointer: pointer,
|
|
100
101
|
};
|
|
101
102
|
}
|
|
102
|
-
function isRecord(value) {
|
|
103
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
104
|
-
}
|
|
105
103
|
function callFactFromSitianPayload(payload, pointer) {
|
|
106
104
|
if (!isRecord(payload))
|
|
107
105
|
return undefined;
|
package/dist/gatekeeper-role.js
CHANGED
|
@@ -5,6 +5,7 @@ import { INSPECTOR_OUTPUT_TOOL_NAME } from "./inspector-contracts.js";
|
|
|
5
5
|
import { REVIEW_QUEUE_STATUSES, REVIEW_SUBMISSION_OUTPUT_TOOL_NAME } from "./review-submission.js";
|
|
6
6
|
import { GATEKEEPER_OUTPUT_TOOL_NAME, gatekeeperOutputSchema, } from "./package-contracts/gatekeeper-output.js";
|
|
7
7
|
import { runIdFromRunDirectory } from "./run-terminal-artifacts.js";
|
|
8
|
+
import { isRecord } from "./unknown-value.js";
|
|
8
9
|
export const INSPECTOR_OUTPUT_TOOL = INSPECTOR_OUTPUT_TOOL_NAME;
|
|
9
10
|
export const NOTARY_OUTPUT_TOOL = REVIEW_SUBMISSION_OUTPUT_TOOL_NAME;
|
|
10
11
|
function gateSeatLabel(stage) {
|
|
@@ -40,18 +41,10 @@ function failureReason(error) {
|
|
|
40
41
|
return error.errors.map(failureReason).join("; ");
|
|
41
42
|
return error instanceof Error ? `${error.name}: ${error.message}` : String(error);
|
|
42
43
|
}
|
|
43
|
-
function isRecord(value) {
|
|
44
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
45
|
-
}
|
|
46
44
|
/** Original decision bytes — no sentinel replacement (#836). */
|
|
47
45
|
function retainedReceipt(decision) {
|
|
48
46
|
return decision;
|
|
49
47
|
}
|
|
50
|
-
function readRecord(value) {
|
|
51
|
-
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
52
|
-
return undefined;
|
|
53
|
-
return value;
|
|
54
|
-
}
|
|
55
48
|
/**
|
|
56
49
|
* Read only the conclusion field for queueing (#753).
|
|
57
50
|
* converged | continue | escalate → queue signal + raw receipt.
|
|
@@ -65,7 +58,7 @@ function reviewQueueStatus(status) {
|
|
|
65
58
|
}
|
|
66
59
|
function projectOfficerDecision(officer, decision, fallbackStatus) {
|
|
67
60
|
const receipt = retainedReceipt(decision);
|
|
68
|
-
const record =
|
|
61
|
+
const record = isRecord(decision) ? decision : undefined;
|
|
69
62
|
const status = (record !== undefined && typeof record.status === "string" ? record.status : undefined)
|
|
70
63
|
?? fallbackStatus;
|
|
71
64
|
const queueStatus = typeof status === "string" ? reviewQueueStatus(status) : undefined;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isRecord } from "./unknown-value.js";
|
|
1
2
|
const GLEANER_LEFT_OUTPUT_TOOL_NAME = "ak_gleaner_left_output";
|
|
2
3
|
const GLEANER_LEFT_BASE_FLAG = {
|
|
3
4
|
name: "ak-gleaner-left-base",
|
|
@@ -7,7 +8,7 @@ const GLEANER_LEFT_BASE_FLAG = {
|
|
|
7
8
|
}
|
|
8
9
|
};
|
|
9
10
|
function validateRecordedGleanerLeftOutput(value) {
|
|
10
|
-
if (
|
|
11
|
+
if (!isRecord(value)) {
|
|
11
12
|
throw new Error("Gleaner-left output has no execution discriminator");
|
|
12
13
|
}
|
|
13
14
|
let status;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { isRecord } from "../unknown-value.js";
|
|
1
2
|
export function isClaudePrintDescription(description) {
|
|
2
3
|
return description.protocol === "claude-print";
|
|
3
4
|
}
|
|
@@ -89,7 +90,7 @@ const CODEX_JSON_VALUE_SCHEMA = Object.freeze({
|
|
|
89
90
|
*/
|
|
90
91
|
export function closeJsonSchemaForCodex(schema) {
|
|
91
92
|
const closed = closeSchemaNode(schema);
|
|
92
|
-
const existingDefs =
|
|
93
|
+
const existingDefs = isRecord(closed.$defs)
|
|
93
94
|
? closed.$defs
|
|
94
95
|
: {};
|
|
95
96
|
return {
|
|
@@ -100,13 +101,9 @@ export function closeJsonSchemaForCodex(schema) {
|
|
|
100
101
|
},
|
|
101
102
|
};
|
|
102
103
|
}
|
|
103
|
-
/** Shared plain-object guard for headless host schema/event reduction. */
|
|
104
|
-
export function isPlainObject(value) {
|
|
105
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
106
|
-
}
|
|
107
104
|
/** Pure null leaf only — composite type|null is stripped in-leaf, not dropped whole. */
|
|
108
105
|
function isPureNullTypeSchema(value) {
|
|
109
|
-
if (!
|
|
106
|
+
if (!isRecord(value))
|
|
110
107
|
return false;
|
|
111
108
|
if (value.type === "null")
|
|
112
109
|
return true;
|
|
@@ -120,7 +117,7 @@ function isPureNullTypeSchema(value) {
|
|
|
120
117
|
* Required edges keep the non-null type(s); optional edges re-add null once.
|
|
121
118
|
*/
|
|
122
119
|
function stripNullFromLeafType(leaf) {
|
|
123
|
-
if (!
|
|
120
|
+
if (!isRecord(leaf) || !Array.isArray(leaf.type))
|
|
124
121
|
return leaf;
|
|
125
122
|
const nonNull = leaf.type.filter((t) => t !== "null");
|
|
126
123
|
if (nonNull.length === leaf.type.length)
|
|
@@ -137,7 +134,7 @@ function stripNullFromLeafType(leaf) {
|
|
|
137
134
|
* lack `type`; strict structured output rejects those intermediate nodes.
|
|
138
135
|
*/
|
|
139
136
|
function flattenUnionLeaves(schema) {
|
|
140
|
-
if (!
|
|
137
|
+
if (!isRecord(schema))
|
|
141
138
|
return [schema];
|
|
142
139
|
if (Array.isArray(schema.anyOf)) {
|
|
143
140
|
return schema.anyOf.flatMap(flattenUnionLeaves);
|
|
@@ -155,7 +152,7 @@ function nonNullLeaves(schema) {
|
|
|
155
152
|
* Required → closed non-null leaf(s). Optional → closed leaf(s) + null.
|
|
156
153
|
*/
|
|
157
154
|
function closePropertySchema(schema, optional) {
|
|
158
|
-
const description =
|
|
155
|
+
const description = isRecord(schema) && typeof schema.description === "string"
|
|
159
156
|
? { description: schema.description }
|
|
160
157
|
: {};
|
|
161
158
|
const leaves = nonNullLeaves(schema).map(closeSchemaNode);
|
|
@@ -165,10 +162,10 @@ function closePropertySchema(schema, optional) {
|
|
|
165
162
|
const closed = leaves.length === 1 ? leaves[0] : { anyOf: leaves };
|
|
166
163
|
// Codex strict does not allow sibling keys on $ref; put property guidance
|
|
167
164
|
// on an enclosing schema instead of losing it or weakening the free-JSON ref.
|
|
168
|
-
if (
|
|
165
|
+
if (isRecord(closed) && typeof closed.$ref === "string") {
|
|
169
166
|
return { anyOf: [closed], ...description };
|
|
170
167
|
}
|
|
171
|
-
return
|
|
168
|
+
return isRecord(closed) ? { ...closed, ...description } : closed;
|
|
172
169
|
}
|
|
173
170
|
return { anyOf: [...leaves, { type: "null" }], ...description };
|
|
174
171
|
}
|
|
@@ -182,7 +179,7 @@ function ensureTypedLeaf(schema) {
|
|
|
182
179
|
return schema;
|
|
183
180
|
if (typeof schema.$ref === "string")
|
|
184
181
|
return schema;
|
|
185
|
-
if (
|
|
182
|
+
if (isRecord(schema.properties) || schema.additionalProperties !== undefined) {
|
|
186
183
|
return { ...schema, type: "object" };
|
|
187
184
|
}
|
|
188
185
|
if (schema.items !== undefined) {
|
|
@@ -211,7 +208,7 @@ function originalRequiredNames(node) {
|
|
|
211
208
|
return new Set(node.required.filter((item) => typeof item === "string"));
|
|
212
209
|
}
|
|
213
210
|
function closeSchemaNode(node) {
|
|
214
|
-
if (!
|
|
211
|
+
if (!isRecord(node))
|
|
215
212
|
return node;
|
|
216
213
|
// Already a ref (free-JSON leaf or pre-existing) — do not retype.
|
|
217
214
|
if (typeof node.$ref === "string")
|
|
@@ -229,10 +226,10 @@ function closeSchemaNode(node) {
|
|
|
229
226
|
if (node.items !== undefined) {
|
|
230
227
|
out.items = closeSchemaNode(node.items);
|
|
231
228
|
}
|
|
232
|
-
if (
|
|
229
|
+
if (isRecord(node.$defs)) {
|
|
233
230
|
out.$defs = Object.fromEntries(Object.entries(node.$defs).map(([key, value]) => [key, closeSchemaNode(value)]));
|
|
234
231
|
}
|
|
235
|
-
const hasProperties =
|
|
232
|
+
const hasProperties = isRecord(node.properties);
|
|
236
233
|
const isObjectType = node.type === "object"
|
|
237
234
|
|| (Array.isArray(node.type) && node.type.includes("object"))
|
|
238
235
|
|| hasProperties
|
|
@@ -273,11 +270,11 @@ function closeSchemaNode(node) {
|
|
|
273
270
|
function stringEnvironment(value) {
|
|
274
271
|
const entries = Array.isArray(value)
|
|
275
272
|
? value.flatMap((item) => {
|
|
276
|
-
if (!
|
|
273
|
+
if (!isRecord(item) || typeof item.name !== "string" || typeof item.value !== "string")
|
|
277
274
|
return [];
|
|
278
275
|
return [[item.name, item.value]];
|
|
279
276
|
})
|
|
280
|
-
:
|
|
277
|
+
: isRecord(value)
|
|
281
278
|
? Object.entries(value).filter((entry) => typeof entry[1] === "string")
|
|
282
279
|
: [];
|
|
283
280
|
return entries.length === 0 ? undefined : Object.fromEntries(entries);
|