@akagilnc/pi-workflow-roles 0.1.5368 → 0.1.5382
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 +1192 -1195
- 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/collector-tool-schemas.js +18 -0
- package/dist/compliance-transport.js +2 -1
- package/dist/countersign-contracts.js +2 -1
- package/dist/diarist-contracts.js +29 -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/filed-submission.js +28 -0
- package/dist/gatekeeper-role.js +8 -19
- package/dist/gleaner-left-contracts.js +18 -1
- package/dist/headless-host/description.js +14 -17
- package/dist/headless-host/production-host.js +1210 -1215
- package/dist/host-session-record.js +3 -2
- package/dist/inspector-contracts.js +2 -1
- package/dist/judge-role.js +8 -16
- package/dist/ledger-session-read.js +1 -3
- package/dist/merger-contracts.js +9 -9
- package/dist/migrate-book-topology.js +610 -321
- 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/reviewer-output.js +16 -0
- package/dist/package-contracts/terminating-infrastructure.js +5 -9
- package/dist/package-contracts/terminating-tools.js +4 -3
- package/dist/package-contracts/worker-output.js +18 -2
- package/dist/public-cli/analyst-run.js +3 -2
- package/dist/public-cli/auto-resume.js +3 -8
- package/dist/public-cli/cli.js +9 -8
- package/dist/public-cli/config.js +8 -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 +12 -14
- package/dist/public-cli/invocation.js +9 -8
- package/dist/public-cli/main.js +1820 -1599
- package/dist/public-cli/post-admission.js +4 -3
- package/dist/public-cli/run-lifecycle.js +14 -26
- package/dist/public-cli/settlement.js +10 -26
- package/dist/public-role-summons.js +3 -2
- package/dist/receipt-delivery-policy.js +1 -3
- package/dist/role-run-placement.js +3 -5
- package/dist/role-run-relocation.js +12 -19
- package/dist/role-submission-declarations.js +131 -0
- package/dist/run-terminal-artifacts.js +1 -11
- package/dist/run-ticket-number.js +2 -4
- package/dist/secretariat-contracts.js +23 -1
- 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 +6 -8
- 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-role.ts +2 -8
- package/src/auditor-soul.ts +3 -1
- package/src/book-topology-migration-placement.ts +5 -16
- 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/collector-role.ts +5 -28
- package/src/compliance-transport.ts +2 -1
- package/src/countersign-contracts.ts +2 -1
- package/src/countersign-role.ts +2 -7
- package/src/diarist-contracts.ts +40 -2
- package/src/diarist-role.ts +4 -44
- package/src/doctor-contracts.ts +3 -1
- package/src/doctor-evidence.ts +8 -7
- package/src/doctor-role.ts +20 -13
- 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/filed-submission.ts +44 -0
- package/src/gatekeeper-role.ts +8 -24
- package/src/gleaner-left-contracts.ts +29 -2
- package/src/gleaner-left-role.ts +4 -32
- 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/inspector-role.ts +2 -7
- package/src/judge-role.ts +12 -24
- package/src/ledger-session-read.ts +2 -5
- package/src/merger-contracts.ts +10 -9
- package/src/merger-role.ts +5 -8
- 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-role.ts +2 -8
- 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/notary-role.ts +5 -20
- 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/reviewer-output.ts +25 -0
- package/src/package-contracts/terminating-infrastructure.ts +6 -20
- package/src/package-contracts/terminating-tools.ts +8 -12
- package/src/package-contracts/worker-output.ts +43 -5
- 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 +4 -11
- package/src/public-cli/cli.ts +10 -10
- package/src/public-cli/config.ts +8 -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 +14 -15
- package/src/public-cli/invocation.ts +11 -10
- package/src/public-cli/post-admission.ts +5 -3
- package/src/public-cli/run-lifecycle.ts +20 -41
- package/src/public-cli/settlement.ts +11 -33
- package/src/public-role-summons.ts +4 -3
- package/src/receipt-delivery-policy.ts +1 -4
- package/src/reviewer-role.ts +7 -36
- package/src/role-envelope.ts +5 -3
- package/src/role-run-placement.ts +4 -10
- package/src/role-run-relocation.ts +13 -23
- package/src/role-runtime.ts +16 -50
- package/src/role-submission-declarations.ts +143 -0
- package/src/run-terminal-artifacts.ts +2 -16
- package/src/run-ticket-number.ts +4 -10
- package/src/secretariat-contracts.ts +35 -0
- package/src/secretariat-role.ts +4 -40
- 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 +10 -9
- 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 +63 -83
- package/src/worker-submission-gates.ts +8 -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
|
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
import { Type } from "typebox";
|
|
2
|
+
import { openToolObject } from "./open-tool-schema.js";
|
|
3
|
+
import { withTerminatingOutputDeclarations } from "./package-contracts/terminating-infrastructure.js";
|
|
4
|
+
/**
|
|
5
|
+
* #1088: LLM gathers evidence via host CLI and submits the receipt.
|
|
6
|
+
* Field declarations guide the model — host must not pure-shape-reject (第 0 条 / ADR 0057).
|
|
7
|
+
* Presence of `groups` remains the Collector terminal discriminator for settlement/analyst.
|
|
8
|
+
*/
|
|
9
|
+
export const collectorOutputBaseSchema = openToolObject(Type.Object({
|
|
10
|
+
groups: Type.Unsafe({
|
|
11
|
+
description: "按机器身份归组的出席、材料与逐条 findings(LLM 自行从宿主 CLI 取证整理;代码不代收不归并)。",
|
|
12
|
+
}),
|
|
13
|
+
unfinishedReasons: Type.Unknown({
|
|
14
|
+
description: "未完成原因;取证受限时如实报告。",
|
|
15
|
+
}),
|
|
16
|
+
}));
|
|
17
|
+
/** Runtime does not enrich findings; the model submits the receipt and signals sole-final. */
|
|
18
|
+
export const collectorOutputArgsSchema = withTerminatingOutputDeclarations(collectorOutputBaseSchema);
|
|
@@ -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;
|
|
@@ -6,11 +6,15 @@
|
|
|
6
6
|
*
|
|
7
7
|
* #901: LLM submits bounds; the mechanical layer projects source bytes.
|
|
8
8
|
*/
|
|
9
|
+
import { Type } from "typebox";
|
|
10
|
+
import { openToolObject } from "./open-tool-schema.js";
|
|
11
|
+
import { withTerminatingOutputDeclarations } from "./package-contracts/terminating-infrastructure.js";
|
|
9
12
|
import { projectTicketProvenanceSessions, } from "./ticket-provenance-contracts.js";
|
|
10
13
|
import { isSafePositiveTicketNumber } from "./run-ticket-number.js";
|
|
14
|
+
import { isRecord } from "./unknown-value.js";
|
|
11
15
|
export const DIARIST_OUTPUT_TOOL_NAME = "ak_diarist_output";
|
|
12
16
|
export function validateRecordedDiaristOutput(value) {
|
|
13
|
-
if (
|
|
17
|
+
if (!isRecord(value)) {
|
|
14
18
|
throw new Error("Diarist output has no execution discriminator");
|
|
15
19
|
}
|
|
16
20
|
let status;
|
|
@@ -42,7 +46,7 @@ export function projectDiaristTicketSessions(value) {
|
|
|
42
46
|
return undefined;
|
|
43
47
|
const perTicket = new Map();
|
|
44
48
|
for (const entry of raw) {
|
|
45
|
-
if (
|
|
49
|
+
if (!isRecord(entry))
|
|
46
50
|
return undefined;
|
|
47
51
|
const { ticketNumber, sessions: rawSessions } = entry;
|
|
48
52
|
if (!isSafePositiveTicketNumber(ticketNumber))
|
|
@@ -54,3 +58,26 @@ export function projectDiaristTicketSessions(value) {
|
|
|
54
58
|
}
|
|
55
59
|
return Array.from(perTicket, ([ticketNumber, sessions]) => ({ ticketNumber, sessions }));
|
|
56
60
|
}
|
|
61
|
+
/**
|
|
62
|
+
* 起居郎交卷形状。
|
|
63
|
+
* #901:交边界(sessions);正文与不可解析原字节由机械投影。
|
|
64
|
+
* status 的合法词(completed | escalate)写在 description,结算认这些词。
|
|
65
|
+
* sessions / ticketSessions 是投影所读的边界:卷路径或端点读不出时走既有 reask,不中止本轮。
|
|
66
|
+
* 声明只留字段名和语义说明,不留类型、嵌套、长度、必填。
|
|
67
|
+
*/
|
|
68
|
+
const DIARIST_SESSIONS_DESCRIPTION = "对话边界。每卷含 path(会话卷绝对或可读路径)与 ranges(本卷本轮各区间)。每段区间含 from / to;起点与终点各写 id(原生 id)或 line(本轮行号),二选一。空列表=本轮无对话可划。端点无法指名时走 reask,不中止。";
|
|
69
|
+
export const diaristOutputSchema = withTerminatingOutputDeclarations(openToolObject(Type.Object({
|
|
70
|
+
status: Type.Unknown({
|
|
71
|
+
description: "completed | escalate",
|
|
72
|
+
}),
|
|
73
|
+
ticketNumber: Type.Optional(Type.Unknown({
|
|
74
|
+
description: "本庭对象票号(正整数)或 null/省略=真无票;下游走 typed 键;认不出用 status=escalate,不洗成无录。机械层不重判。",
|
|
75
|
+
})),
|
|
76
|
+
reason: Type.Unknown({
|
|
77
|
+
description: "status 为 escalate 时:认不出本庭对象的原因",
|
|
78
|
+
}),
|
|
79
|
+
sessions: Type.Optional(Type.Unknown({ description: DIARIST_SESSIONS_DESCRIPTION })),
|
|
80
|
+
ticketSessions: Type.Unknown({
|
|
81
|
+
description: `多票庭逐票对话边界;每票含 ticketNumber(本条边界所归票号,正整数)与 sessions(${DIARIST_SESSIONS_DESCRIPTION})。一次交卷各票各自分录。与单票 sessions 二选一。`,
|
|
82
|
+
}),
|
|
83
|
+
})));
|
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;
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One host-neutral submission execute for every public seat.
|
|
3
|
+
* Records nothing itself — the ledger seam already appends the original payload.
|
|
4
|
+
* Ends this tool call. Does not summon an auditor and does not end the role run.
|
|
5
|
+
* Shape is not an admission gate (ADR 0055). Seat reminders stay on beforeAccept.
|
|
6
|
+
*/
|
|
7
|
+
export function registerFiledSubmissionTool(roleHost, tool, options) {
|
|
8
|
+
roleHost.registerTool({
|
|
9
|
+
name: tool.name,
|
|
10
|
+
label: tool.label,
|
|
11
|
+
description: tool.description,
|
|
12
|
+
...(tool.promptSnippet === undefined ? {} : { promptSnippet: tool.promptSnippet }),
|
|
13
|
+
parameters: tool.parameters,
|
|
14
|
+
async execute(toolCallId, parameters, signal, _onUpdate, ctx) {
|
|
15
|
+
const blocked = options.readyError();
|
|
16
|
+
if (blocked !== undefined)
|
|
17
|
+
throw new Error(blocked);
|
|
18
|
+
const projected = options.beforeAccept === undefined
|
|
19
|
+
? undefined
|
|
20
|
+
: await options.beforeAccept({ toolCallId, parameters, signal, ctx });
|
|
21
|
+
return {
|
|
22
|
+
content: [],
|
|
23
|
+
details: projected === undefined ? parameters : projected,
|
|
24
|
+
terminate: true,
|
|
25
|
+
};
|
|
26
|
+
},
|
|
27
|
+
});
|
|
28
|
+
}
|
package/dist/gatekeeper-role.js
CHANGED
|
@@ -3,8 +3,10 @@ import { packagedGateStageLabel } from "./packaged-role-registry.js";
|
|
|
3
3
|
import { GatekeeperDecisionError, receivedDiscriminator, unreadableDiscriminatorNotice } from "./submission-errors.js";
|
|
4
4
|
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
|
-
import { GATEKEEPER_OUTPUT_TOOL_NAME
|
|
6
|
+
import { GATEKEEPER_OUTPUT_TOOL_NAME } from "./package-contracts/gatekeeper-output.js";
|
|
7
|
+
import { roleSubmissionDeclaration } from "./role-submission-declarations.js";
|
|
7
8
|
import { runIdFromRunDirectory } from "./run-terminal-artifacts.js";
|
|
9
|
+
import { isRecord } from "./unknown-value.js";
|
|
8
10
|
export const INSPECTOR_OUTPUT_TOOL = INSPECTOR_OUTPUT_TOOL_NAME;
|
|
9
11
|
export const NOTARY_OUTPUT_TOOL = REVIEW_SUBMISSION_OUTPUT_TOOL_NAME;
|
|
10
12
|
function gateSeatLabel(stage) {
|
|
@@ -28,30 +30,16 @@ export { GatekeeperDecisionError } from "./submission-errors.js";
|
|
|
28
30
|
* registration envelope — src/role-runtime.ts (ADR 0018). Schema authority is
|
|
29
31
|
* the shared contract module (with infrastructure-failure declaration).
|
|
30
32
|
*/
|
|
31
|
-
export const GATEKEEPER_TOOL_SPEC =
|
|
32
|
-
name: GATEKEEPER_OUTPUT_TOOL_NAME,
|
|
33
|
-
label: "门下省决议",
|
|
34
|
-
description: "门下省终局决议。status 为 dispatch 或 pass。",
|
|
35
|
-
promptSnippet: "门下省决议",
|
|
36
|
-
parameters: gatekeeperOutputSchema,
|
|
37
|
-
};
|
|
33
|
+
export const GATEKEEPER_TOOL_SPEC = roleSubmissionDeclaration("gatekeeper");
|
|
38
34
|
function failureReason(error) {
|
|
39
35
|
if (error instanceof AggregateError)
|
|
40
36
|
return error.errors.map(failureReason).join("; ");
|
|
41
37
|
return error instanceof Error ? `${error.name}: ${error.message}` : String(error);
|
|
42
38
|
}
|
|
43
|
-
function isRecord(value) {
|
|
44
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
45
|
-
}
|
|
46
39
|
/** Original decision bytes — no sentinel replacement (#836). */
|
|
47
40
|
function retainedReceipt(decision) {
|
|
48
41
|
return decision;
|
|
49
42
|
}
|
|
50
|
-
function readRecord(value) {
|
|
51
|
-
if (typeof value !== "object" || value === null || Array.isArray(value))
|
|
52
|
-
return undefined;
|
|
53
|
-
return value;
|
|
54
|
-
}
|
|
55
43
|
/**
|
|
56
44
|
* Read only the conclusion field for queueing (#753).
|
|
57
45
|
* converged | continue | escalate → queue signal + raw receipt.
|
|
@@ -65,9 +53,10 @@ function reviewQueueStatus(status) {
|
|
|
65
53
|
}
|
|
66
54
|
function projectOfficerDecision(officer, decision, fallbackStatus) {
|
|
67
55
|
const receipt = retainedReceipt(decision);
|
|
68
|
-
const record =
|
|
69
|
-
const status =
|
|
70
|
-
|
|
56
|
+
const record = isRecord(decision) ? decision : undefined;
|
|
57
|
+
const status = record !== undefined && Object.hasOwn(record, "status")
|
|
58
|
+
? receivedDiscriminator(record, "status")
|
|
59
|
+
: fallbackStatus;
|
|
71
60
|
const queueStatus = typeof status === "string" ? reviewQueueStatus(status) : undefined;
|
|
72
61
|
if (queueStatus === "converged") {
|
|
73
62
|
return { status: "converged", officer, receipt };
|