@akagilnc/pi-workflow-roles 0.1.3565 → 0.1.3621
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -1
- package/README.zh-CN.md +1 -1
- package/dist/acp-host/production-host.js +18477 -8099
- package/dist/analyst-gate-cycles-read.js +387 -0
- package/dist/archivist-record-entry.js +22 -1
- package/dist/audit-escalation.js +6 -0
- package/dist/auditor-soul.js +74 -0
- package/dist/collector-config.js +86 -0
- package/dist/collector-evidence.js +316 -0
- package/dist/collector-github.js +527 -0
- package/dist/collector-ledger.js +853 -0
- package/dist/collector-tool-schemas.js +33 -0
- package/dist/compliance-transport.js +104 -52
- package/dist/diarist-contracts.js +72 -0
- package/dist/diarist-mechanical.js +411 -0
- package/dist/diarist-ticket-resolution.js +177 -0
- package/dist/diarist.js +311 -0
- package/dist/doctor-auditor.js +25 -0
- package/dist/doctor-contracts.js +2 -0
- package/dist/doctor-evidence.js +142 -0
- package/dist/gatekeeper-role.js +104 -81
- package/dist/host-transition-prior-native.js +78 -0
- package/dist/institutional-resolution.js +1 -95
- package/dist/judge-auditor.js +26 -0
- package/dist/ledger-session-read.js +227 -0
- package/dist/merger-git-state.js +78 -0
- package/dist/navigator-attendance.js +15 -7
- package/dist/navigator-public-session.js +170 -0
- package/dist/navigator-session-contracts.js +36 -40
- package/dist/notary-source-run.js +122 -0
- package/dist/package-contracts/auditor-output.js +66 -0
- package/dist/package-contracts/evidence-child-output.js +34 -0
- package/dist/package-contracts/judge-output.js +2 -0
- package/dist/package-contracts/terminating-tools.js +44 -3
- package/dist/package-resources/method-skill.js +254 -0
- package/dist/packaged-role-registry.js +56 -0
- package/dist/pi/durable-principal.js +61 -0
- package/dist/pi/in-process-session.js +25 -6
- package/dist/pi/known-failure.js +52 -0
- package/dist/pi/role-turn-host.js +430 -0
- package/dist/public-cli/auto-resume.js +414 -0
- package/dist/public-cli/cli-errors.js +8 -0
- package/dist/public-cli/cli-io.js +1 -0
- package/dist/public-cli/command-renderer.js +5 -0
- package/dist/public-cli/doctor-run.js +84 -0
- package/dist/public-cli/inspector-run.js +136 -0
- package/dist/public-cli/instruction-seat-run.js +256 -0
- package/dist/public-cli/invocation.js +2225 -0
- package/dist/public-cli/judge-run.js +118 -0
- package/dist/public-cli/load-production-acp-host.js +40 -0
- package/dist/public-cli/main.js +1511 -1124
- package/dist/public-cli/notary-run.js +161 -0
- package/dist/public-cli/option-definitions.js +1192 -0
- package/dist/public-cli/post-admission.js +667 -0
- package/dist/public-cli/public-run-credentials.js +49 -0
- package/dist/public-cli/registry.js +8 -2
- package/dist/public-cli/reviewer-dispatch-rejection.js +77 -0
- package/dist/public-cli/run-lifecycle.js +1344 -0
- package/dist/public-cli/seat-ticket-binding.js +113 -0
- package/dist/public-cli/settlement.js +3441 -0
- package/dist/public-cli/terminal.js +135 -0
- package/dist/public-cli/turn-request.js +25 -0
- package/dist/public-role-summons.js +301 -0
- package/dist/receipt-delivery-policy.js +10 -0
- package/dist/reviewer-child-executor.js +80 -8
- package/dist/reviewer-execution-ledger.js +2 -1
- package/dist/run-terminal-artifacts.js +195 -0
- package/dist/run-ticket-number.js +40 -0
- package/dist/session-assistant-usage.js +107 -0
- package/dist/shape-unreadable-failure.js +34 -0
- package/dist/submission-errors.js +3 -0
- package/dist/submission-ledger.js +388 -0
- package/dist/ticket-provenance-contracts.js +115 -0
- package/dist/ticket-provenance.js +340 -0
- package/extensions/role-runtime.ts +8 -0
- package/package.json +1 -1
- package/resources/diarist-collect.md +6 -10
- package/scripts/build-package.mjs +2 -1
- package/souls/diarist.md +9 -0
- package/souls/doctor-auditor.md +1 -0
- package/souls/evidence-child.md +1 -0
- package/src/acp-host/production-host.ts +4 -0
- package/src/acp-host/role-envelope.ts +4 -3
- package/src/acp-host/role-turn-host.ts +9 -1
- package/src/analyst-gate-cycles-read.ts +37 -2
- package/src/archivist-record-entry.ts +45 -1
- package/src/audit-escalation.ts +17 -0
- package/src/auditor-role.ts +22 -0
- package/src/auditor-soul.ts +42 -0
- package/src/compliance-transport.ts +177 -66
- package/src/diarist-contracts.ts +88 -0
- package/src/diarist-role.ts +60 -0
- package/src/diarist.ts +253 -179
- package/src/doctor-auditor.ts +10 -14
- package/src/doctor-contracts.ts +1 -0
- package/src/doctor-role.ts +2 -2
- package/src/evidence-child-role.ts +22 -0
- package/src/gatekeeper-pass-envelope.ts +109 -0
- package/src/gatekeeper-role.ts +145 -104
- package/src/host-contracts.ts +15 -2
- package/src/institutional-resolution.ts +8 -163
- package/src/judge-auditor.ts +10 -15
- package/src/judge-role.ts +8 -0
- package/src/navigator-attendance.ts +25 -9
- package/src/navigator-public-session.ts +217 -0
- package/src/navigator-session-contracts.ts +61 -54
- package/src/notary-source-run.ts +3 -1
- package/src/package-contracts/auditor-output.ts +82 -0
- package/src/package-contracts/evidence-child-output.ts +51 -0
- package/src/package-contracts/judge-output.ts +1 -0
- package/src/package-contracts/reviewer-output.ts +2 -2
- package/src/package-contracts/terminating-tools.ts +53 -3
- package/src/packaged-role-registry.ts +63 -0
- package/src/pi/adapter.ts +2 -1
- package/src/pi/in-process-session.ts +38 -12
- package/src/pi/role-turn-host.ts +42 -0
- package/src/public-cli/cli.ts +43 -6
- package/src/public-cli/countersign-run.ts +9 -129
- package/src/public-cli/diarist-run.ts +312 -0
- package/src/public-cli/instruction-seat-run.ts +289 -50
- package/src/public-cli/invocation.ts +87 -25
- package/src/public-cli/option-definitions.ts +79 -0
- package/src/public-cli/post-admission.ts +9 -3
- package/src/public-cli/registry.ts +7 -1
- package/src/public-cli/run-lifecycle.ts +53 -6
- package/src/public-cli/settlement.ts +170 -7
- package/src/public-cli/terminal.ts +4 -1
- package/src/public-role-summons.ts +431 -0
- package/src/receipt-delivery-policy.ts +10 -0
- package/src/reviewer-agent.ts +1 -1
- package/src/reviewer-child-executor.ts +114 -12
- package/src/reviewer-execution-ledger.ts +3 -2
- package/src/role-runtime.ts +275 -23
- package/src/session-assistant-usage.ts +119 -0
- package/src/session-opening-materials.ts +1 -1
- package/src/shape-unreadable-failure.ts +49 -0
- package/src/submission-errors.ts +3 -0
- package/src/ticket-provenance-contracts.ts +1 -0
- package/src/ticket-provenance.ts +0 -23
- package/dist/evidence-child-executor.js +0 -829
- package/src/diarist-llm-collector.ts +0 -324
- package/src/evidence-child-executor.ts +0 -1140
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
import { execFile } from "node:child_process";
|
|
2
|
+
import { promisify } from "node:util";
|
|
3
|
+
import { exactUtf8 } from "./exact-utf8.js";
|
|
4
|
+
import { isFullGitObjectId } from "./git-object-id.js";
|
|
5
|
+
const execFileAsync = promisify(execFile);
|
|
6
|
+
async function git(cwd, args) {
|
|
7
|
+
const { stdout } = await execFileAsync("git", args, { cwd, encoding: "buffer", maxBuffer: 16 * 1024 * 1024 });
|
|
8
|
+
return new Uint8Array(stdout);
|
|
9
|
+
}
|
|
10
|
+
function line(bytes, label) {
|
|
11
|
+
const value = exactUtf8(bytes, label).trim();
|
|
12
|
+
if (!value)
|
|
13
|
+
throw new Error(`${label} is empty`);
|
|
14
|
+
return value;
|
|
15
|
+
}
|
|
16
|
+
function nulPaths(bytes, label) {
|
|
17
|
+
const raw = exactUtf8(bytes, label);
|
|
18
|
+
if (raw.length > 0 && !raw.endsWith("\0"))
|
|
19
|
+
throw new Error(`${label} is not NUL terminated`);
|
|
20
|
+
return raw.split("\0").filter(Boolean).sort((a, b) => Buffer.compare(Buffer.from(a), Buffer.from(b)));
|
|
21
|
+
}
|
|
22
|
+
async function unmerged(cwd) {
|
|
23
|
+
const raw = exactUtf8(await git(cwd, ["ls-files", "-u", "-z"]), "Git unmerged index");
|
|
24
|
+
const paths = new Set();
|
|
25
|
+
for (const row of raw.split("\0")) {
|
|
26
|
+
if (!row)
|
|
27
|
+
continue;
|
|
28
|
+
const tab = row.indexOf("\t");
|
|
29
|
+
if (tab < 0 || tab === row.length - 1)
|
|
30
|
+
throw new Error("Git returned a malformed unmerged index row");
|
|
31
|
+
paths.add(row.slice(tab + 1));
|
|
32
|
+
}
|
|
33
|
+
return [...paths].sort((a, b) => Buffer.compare(Buffer.from(a), Buffer.from(b)));
|
|
34
|
+
}
|
|
35
|
+
export function createProductionMergerGitState(repositoryRoot = process.cwd()) {
|
|
36
|
+
return {
|
|
37
|
+
async activeMerge() {
|
|
38
|
+
const targetObjectId = line(await git(repositoryRoot, ["rev-parse", "--verify", "HEAD"]), "Git HEAD");
|
|
39
|
+
let mergeHeadRaw;
|
|
40
|
+
try {
|
|
41
|
+
mergeHeadRaw = await git(repositoryRoot, ["rev-parse", "--verify", "MERGE_HEAD"]);
|
|
42
|
+
}
|
|
43
|
+
catch {
|
|
44
|
+
throw new Error("Assigned repository does not have one ordinary in-progress merge");
|
|
45
|
+
}
|
|
46
|
+
const mergeHeads = exactUtf8(mergeHeadRaw, "Git MERGE_HEAD").trim().split(/\r?\n/).filter(Boolean);
|
|
47
|
+
if (mergeHeads.length !== 1 || !isFullGitObjectId(targetObjectId) || !isFullGitObjectId(mergeHeads[0]) || targetObjectId.length !== mergeHeads[0].length)
|
|
48
|
+
throw new Error("Assigned repository does not have one ordinary in-progress merge");
|
|
49
|
+
let automaticMergeTreeRaw;
|
|
50
|
+
try {
|
|
51
|
+
automaticMergeTreeRaw = await git(repositoryRoot, ["rev-parse", "--verify", "AUTO_MERGE^{tree}"]);
|
|
52
|
+
}
|
|
53
|
+
catch {
|
|
54
|
+
throw new Error("Git automatic merge tree identity is unavailable or invalid");
|
|
55
|
+
}
|
|
56
|
+
const automaticMergeTreeId = line(automaticMergeTreeRaw, "Git automatic merge tree");
|
|
57
|
+
if (!isFullGitObjectId(automaticMergeTreeId) || automaticMergeTreeId.length !== targetObjectId.length)
|
|
58
|
+
throw new Error("Git automatic merge tree identity is unavailable or invalid");
|
|
59
|
+
return { targetObjectId, sourceObjectId: mergeHeads[0], unmergedPaths: await unmerged(repositoryRoot), automaticMergeTreeId };
|
|
60
|
+
},
|
|
61
|
+
async completedMerge(mergeCommitId, automaticMergeTreeId) {
|
|
62
|
+
if (!isFullGitObjectId(mergeCommitId) || !isFullGitObjectId(automaticMergeTreeId) || mergeCommitId.length !== automaticMergeTreeId.length)
|
|
63
|
+
throw new Error("Merger completion object ID is invalid");
|
|
64
|
+
const identity = exactUtf8(await git(repositoryRoot, ["show", "-s", "--format=%H%x00%P", mergeCommitId]), "Git merge commit").trimEnd().split("\0");
|
|
65
|
+
if (identity.length !== 2 || identity[0] !== mergeCommitId)
|
|
66
|
+
throw new Error("Git merge completion identity drifted");
|
|
67
|
+
const parentObjectIds = identity[1].split(" ").filter(Boolean);
|
|
68
|
+
const currentHead = line(await git(repositoryRoot, ["rev-parse", "--verify", "HEAD"]), "Git HEAD");
|
|
69
|
+
const status = await git(repositoryRoot, ["status", "--porcelain=v1", "-z", "--untracked-files=all"]);
|
|
70
|
+
const frozenTree = line(await git(repositoryRoot, ["rev-parse", "--verify", `${automaticMergeTreeId}^{tree}`]), "Git frozen automatic merge tree");
|
|
71
|
+
if (frozenTree !== automaticMergeTreeId)
|
|
72
|
+
throw new Error("Git frozen automatic merge tree identity drifted");
|
|
73
|
+
const mergeTree = line(await git(repositoryRoot, ["rev-parse", "--verify", `${mergeCommitId}^{tree}`]), "Git completed merge tree");
|
|
74
|
+
const resolutionChangedPaths = nulPaths(await git(repositoryRoot, ["diff-tree", "--no-commit-id", "--name-only", "-r", "-z", "--no-renames", automaticMergeTreeId, mergeTree]), "Git resolution path delta");
|
|
75
|
+
return { mergeCommitId: currentHead, parentObjectIds, unmergedPaths: await unmerged(repositoryRoot), worktreeClean: status.byteLength === 0 && currentHead === mergeCommitId, resolutionChangedPaths };
|
|
76
|
+
},
|
|
77
|
+
};
|
|
78
|
+
}
|
|
@@ -13,7 +13,7 @@ import {
|
|
|
13
13
|
activationBookDirectory,
|
|
14
14
|
resolveActivationLedgerHome
|
|
15
15
|
} from "./activation-ledger-topology.js";
|
|
16
|
-
import { createNativeNavigatorSessionFactory } from "./
|
|
16
|
+
import { createNativeNavigatorSessionFactory } from "./navigator-public-session.js";
|
|
17
17
|
import {
|
|
18
18
|
NAVIGATOR_DEFAULT_MODEL,
|
|
19
19
|
NAVIGATOR_PREPARE_TOOL_NAME,
|
|
@@ -340,11 +340,7 @@ function createNavigatorAttendance(options) {
|
|
|
340
340
|
routePlaybookSettlement = routePlaybookPromise.then(() => void 0);
|
|
341
341
|
const modelPromise = (async () => {
|
|
342
342
|
try {
|
|
343
|
-
const resolved = await resolveNavigatorSeatSelection(
|
|
344
|
-
options.context,
|
|
345
|
-
options.modelSettingPath,
|
|
346
|
-
options.modelSettingPath ?? navigatorModelSettingPath()
|
|
347
|
-
);
|
|
343
|
+
const resolved = await resolveNavigatorSeatSelection(options.context);
|
|
348
344
|
return resolved.configuredLabel;
|
|
349
345
|
} catch (error) {
|
|
350
346
|
if (error instanceof NavigatorUnavailableError) throw error;
|
|
@@ -489,6 +485,11 @@ ${helpContext}
|
|
|
489
485
|
return;
|
|
490
486
|
}
|
|
491
487
|
if (promptFailure !== void 0) throw promptFailure;
|
|
488
|
+
const sessionNoReceipt = activeSession.noReceipt?.();
|
|
489
|
+
if (sessionNoReceipt !== void 0) {
|
|
490
|
+
delivery.recordNestedNoReceipt(sessionNoReceipt);
|
|
491
|
+
return;
|
|
492
|
+
}
|
|
492
493
|
if (deliveryRequest && output === void 0) delivery.recordDeliveryRequest();
|
|
493
494
|
};
|
|
494
495
|
await promptAllowingRejectedPrepare(request, false);
|
|
@@ -578,6 +579,7 @@ ${helpContext}
|
|
|
578
579
|
}
|
|
579
580
|
};
|
|
580
581
|
async function settleOnce(settlement) {
|
|
582
|
+
if (disposed) return;
|
|
581
583
|
const invocationId = activeInvocationId ?? invocationPrincipal;
|
|
582
584
|
let report;
|
|
583
585
|
if (settlement.kind === "human_decision" || settlement.kind === "role_infrastructure_failure") {
|
|
@@ -626,8 +628,10 @@ ${helpContext}
|
|
|
626
628
|
session?.appendEntry(SETTLEMENT_ENTRY, { invocationId, subjectKey, role: settlement.role, phase: settlement.phase, kind: settlement.kind, ...settlement.status === void 0 ? {} : { status: settlement.status } });
|
|
627
629
|
let selected = selectNavigatorCandidate(prepared, settlement);
|
|
628
630
|
if (selected?.candidate.next !== void 0 && !selected.matchedToSettlement) {
|
|
631
|
+
if (disposed) return;
|
|
629
632
|
prepareBoundSettlement = settlement;
|
|
630
633
|
prepared = await prepare();
|
|
634
|
+
if (disposed) return;
|
|
631
635
|
selected = selectNavigatorCandidate(prepared, settlement);
|
|
632
636
|
}
|
|
633
637
|
const selectedCandidate = selected?.candidate;
|
|
@@ -676,8 +680,12 @@ ${helpContext}
|
|
|
676
680
|
...report.routePlaybookReadFailure === void 0 ? {} : { routePlaybookReadFailure: report.routePlaybookReadFailure },
|
|
677
681
|
...report.arrivalMessage === void 0 ? {} : { arrivalMessage: report.arrivalMessage }
|
|
678
682
|
};
|
|
679
|
-
if (
|
|
683
|
+
if (disposed) return;
|
|
684
|
+
try {
|
|
680
685
|
await options.onEvent(event, report);
|
|
686
|
+
} catch (error) {
|
|
687
|
+
if (disposed) return;
|
|
688
|
+
throw error;
|
|
681
689
|
}
|
|
682
690
|
preparation = void 0;
|
|
683
691
|
sessionReady = void 0;
|
|
@@ -0,0 +1,170 @@
|
|
|
1
|
+
import { sitianReport } from "./sitian-facade.js";
|
|
2
|
+
import {
|
|
3
|
+
NavigatorUnavailableError,
|
|
4
|
+
navigatorProviderFailureFromDiagnostics,
|
|
5
|
+
navigatorProviderFailureFromError,
|
|
6
|
+
navigatorProviderFailureFromStatus,
|
|
7
|
+
navigatorUnavailableError,
|
|
8
|
+
parseNavigatorModelSetting,
|
|
9
|
+
resolveNavigatorSeatSelection
|
|
10
|
+
} from "./navigator-session-contracts.js";
|
|
11
|
+
function providerFailureFromPublicTerminal(outcome) {
|
|
12
|
+
const facts = outcome.decisiveFacts;
|
|
13
|
+
const secondary = typeof facts.secondaryEvidence === "object" && facts.secondaryEvidence !== null ? facts.secondaryEvidence : void 0;
|
|
14
|
+
const httpStatus = typeof secondary?.httpStatus === "number" ? secondary.httpStatus : typeof facts.httpStatus === "number" ? facts.httpStatus : typeof facts.errorCode === "number" ? facts.errorCode : void 0;
|
|
15
|
+
const fromStatus = navigatorProviderFailureFromStatus(httpStatus);
|
|
16
|
+
if (fromStatus !== void 0) return fromStatus;
|
|
17
|
+
const diagnostics = secondary?.diagnostics ?? facts.diagnostics;
|
|
18
|
+
const fromDiagnostics = navigatorProviderFailureFromDiagnostics(diagnostics);
|
|
19
|
+
if (fromDiagnostics !== void 0) return fromDiagnostics;
|
|
20
|
+
const fromCode = navigatorProviderFailureFromError({
|
|
21
|
+
code: secondary?.code ?? facts.errorCode
|
|
22
|
+
});
|
|
23
|
+
if (fromCode !== void 0) return fromCode;
|
|
24
|
+
if (outcome.cause === "provider") return { source: "transport", cause: "transport" };
|
|
25
|
+
return { source: "session", cause: "session" };
|
|
26
|
+
}
|
|
27
|
+
function createNativeNavigatorSessionFactory() {
|
|
28
|
+
return async ({ context, subject, tool }) => {
|
|
29
|
+
const resolved = await resolveNavigatorSeatSelection(context);
|
|
30
|
+
let thinkingLevel = resolved.thinkingLevel;
|
|
31
|
+
const { createRecordSession } = await import("./archivist-record-entry.js");
|
|
32
|
+
const sessionManager = createRecordSession({
|
|
33
|
+
cwd: context.cwd,
|
|
34
|
+
kind: "navigator",
|
|
35
|
+
subject,
|
|
36
|
+
parent: context.sessionManager
|
|
37
|
+
});
|
|
38
|
+
let providerFailure;
|
|
39
|
+
let noReceipt;
|
|
40
|
+
let disposed = false;
|
|
41
|
+
let inFlightPrompt;
|
|
42
|
+
const resolveHome = async () => {
|
|
43
|
+
const parentFile = context.sessionManager?.getSessionFile?.();
|
|
44
|
+
if (typeof parentFile === "string" && parentFile.trim() !== "") {
|
|
45
|
+
try {
|
|
46
|
+
const { tryHomeFromAkRolesPath, homeFromRunDirectory } = await import("./activation-ledger-topology.js");
|
|
47
|
+
const fromParent = tryHomeFromAkRolesPath(parentFile);
|
|
48
|
+
if (fromParent !== void 0 && fromParent.length > 0) return fromParent;
|
|
49
|
+
const runDir = parentFile.replace(/\/session\/session\.jsonl$/, "");
|
|
50
|
+
if (runDir !== parentFile) {
|
|
51
|
+
try {
|
|
52
|
+
return homeFromRunDirectory(runDir);
|
|
53
|
+
} catch {
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
} catch {
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
const envHome = process.env.HOME;
|
|
60
|
+
return typeof envHome === "string" && envHome.trim() !== "" ? envHome : void 0;
|
|
61
|
+
};
|
|
62
|
+
return {
|
|
63
|
+
prompt: async (text) => {
|
|
64
|
+
if (disposed) {
|
|
65
|
+
throw navigatorUnavailableError("session", new Error("Navigator attendance was disposed"));
|
|
66
|
+
}
|
|
67
|
+
providerFailure = void 0;
|
|
68
|
+
noReceipt = void 0;
|
|
69
|
+
const run = (async () => {
|
|
70
|
+
try {
|
|
71
|
+
const { summonPublicRole } = await import("./public-role-summons.js");
|
|
72
|
+
const home = await resolveHome();
|
|
73
|
+
const summoned = await summonPublicRole({
|
|
74
|
+
role: "navigator",
|
|
75
|
+
argv: [text],
|
|
76
|
+
cwd: context.cwd,
|
|
77
|
+
...home === void 0 ? {} : { home }
|
|
78
|
+
});
|
|
79
|
+
const outcome = summoned.terminal?.roleOutcome;
|
|
80
|
+
if (outcome === void 0) {
|
|
81
|
+
const detail = summoned.stderr?.trim() || `exit ${summoned.exitCode}`;
|
|
82
|
+
providerFailure = { source: "transport", cause: "transport" };
|
|
83
|
+
throw navigatorUnavailableError(
|
|
84
|
+
"transport",
|
|
85
|
+
new Error(`Navigator public summon produced no terminal (${detail})`)
|
|
86
|
+
);
|
|
87
|
+
}
|
|
88
|
+
if (outcome.kind === "failure") {
|
|
89
|
+
providerFailure = providerFailureFromPublicTerminal(outcome);
|
|
90
|
+
throw navigatorUnavailableError(
|
|
91
|
+
providerFailure.source,
|
|
92
|
+
new Error(outcome.diagnostic),
|
|
93
|
+
providerFailure.cause
|
|
94
|
+
);
|
|
95
|
+
}
|
|
96
|
+
if (outcome.kind === "no_receipt") {
|
|
97
|
+
noReceipt = outcome;
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
if (outcome.kind !== "accepted") {
|
|
101
|
+
providerFailure = { source: "session", cause: "session" };
|
|
102
|
+
throw navigatorUnavailableError(
|
|
103
|
+
"session",
|
|
104
|
+
new Error("Navigator public summon returned unusable terminal")
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
const candidates = outcome.decisiveFacts.candidates;
|
|
108
|
+
if (!Array.isArray(candidates)) {
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
await tool.execute(
|
|
112
|
+
"navigator-public-prepare",
|
|
113
|
+
{ candidates },
|
|
114
|
+
void 0,
|
|
115
|
+
void 0,
|
|
116
|
+
context
|
|
117
|
+
);
|
|
118
|
+
} catch (error) {
|
|
119
|
+
if (error instanceof NavigatorUnavailableError) throw error;
|
|
120
|
+
const fact = navigatorProviderFailureFromError(error);
|
|
121
|
+
providerFailure = fact ?? { source: "transport", cause: "transport" };
|
|
122
|
+
throw navigatorUnavailableError(providerFailure.source, error, providerFailure.cause);
|
|
123
|
+
}
|
|
124
|
+
})();
|
|
125
|
+
inFlightPrompt = run;
|
|
126
|
+
try {
|
|
127
|
+
await run;
|
|
128
|
+
} finally {
|
|
129
|
+
if (inFlightPrompt === run) inFlightPrompt = void 0;
|
|
130
|
+
}
|
|
131
|
+
},
|
|
132
|
+
providerFailure: () => providerFailure,
|
|
133
|
+
noReceipt: () => noReceipt,
|
|
134
|
+
appendEntry: (customType, data) => {
|
|
135
|
+
sessionManager.appendCustomEntry(customType, data);
|
|
136
|
+
try {
|
|
137
|
+
sitianReport({
|
|
138
|
+
level: "event",
|
|
139
|
+
kind: "attendance",
|
|
140
|
+
cwd: context.cwd,
|
|
141
|
+
sessionParent: sessionManager.getSessionFile(),
|
|
142
|
+
payload: { customType, data },
|
|
143
|
+
source: "navigator-public-session"
|
|
144
|
+
});
|
|
145
|
+
} catch {
|
|
146
|
+
}
|
|
147
|
+
},
|
|
148
|
+
entries: () => sessionManager.getEntries(),
|
|
149
|
+
setModel: async (next, nextThinking) => {
|
|
150
|
+
let nextParsed;
|
|
151
|
+
try {
|
|
152
|
+
nextParsed = parseNavigatorModelSetting(next);
|
|
153
|
+
} catch (error) {
|
|
154
|
+
throw navigatorUnavailableError("model", error);
|
|
155
|
+
}
|
|
156
|
+
thinkingLevel = nextThinking ?? nextParsed.thinkingLevel;
|
|
157
|
+
},
|
|
158
|
+
getThinkingLevel: () => thinkingLevel,
|
|
159
|
+
recordPointer: () => sessionManager.getSessionDir(),
|
|
160
|
+
dispose: async () => {
|
|
161
|
+
disposed = true;
|
|
162
|
+
const pending = inFlightPrompt;
|
|
163
|
+
if (pending !== void 0) await pending.catch(() => void 0);
|
|
164
|
+
}
|
|
165
|
+
};
|
|
166
|
+
};
|
|
167
|
+
}
|
|
168
|
+
export {
|
|
169
|
+
createNativeNavigatorSessionFactory
|
|
170
|
+
};
|
|
@@ -3,11 +3,6 @@ import { homedir } from "node:os";
|
|
|
3
3
|
import { dirname, join } from "node:path";
|
|
4
4
|
import { Type } from "typebox";
|
|
5
5
|
import { Value } from "typebox/value";
|
|
6
|
-
import { auditorRunDirectory } from "./auditor-dossier-tool.js";
|
|
7
|
-
import {
|
|
8
|
-
InstitutionalResolutionError,
|
|
9
|
-
readInstitutionalSeatSelection
|
|
10
|
-
} from "./institutional-resolution.js";
|
|
11
6
|
const NAVIGATOR_PREPARE_TOOL_NAME = "ak_navigator_prepare";
|
|
12
7
|
const NAVIGATOR_DEFAULT_MODEL = "openai-codex/gpt-5.6-luna:max";
|
|
13
8
|
const NAVIGATOR_UNAVAILABLE_KEYS = /* @__PURE__ */ new Set([
|
|
@@ -159,50 +154,51 @@ function parseNavigatorModelSetting(value) {
|
|
|
159
154
|
const suffix = colon < 0 ? void 0 : modelWithThinking.slice(colon + 1);
|
|
160
155
|
const model = colon < 0 ? modelWithThinking : modelWithThinking.slice(0, colon);
|
|
161
156
|
if (model === "") throw new Error("Navigator model setting must include a model");
|
|
162
|
-
|
|
157
|
+
if (suffix !== void 0 && suffix.trim() === "") {
|
|
158
|
+
throw new Error("Navigator model setting thinking suffix must be non-blank");
|
|
159
|
+
}
|
|
160
|
+
return {
|
|
161
|
+
provider,
|
|
162
|
+
model,
|
|
163
|
+
...suffix === void 0 ? {} : { thinkingLevel: suffix }
|
|
164
|
+
};
|
|
163
165
|
}
|
|
164
|
-
async function resolveNavigatorSeatSelection(context
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
166
|
+
async function resolveNavigatorSeatSelection(context) {
|
|
167
|
+
try {
|
|
168
|
+
const { loadPublicCliConfig } = await import("./public-cli/config.js");
|
|
169
|
+
const { seatModelOnly } = await import("./public-cli/registry.js");
|
|
170
|
+
const { packageMachineHome } = await import("./activation-ledger-topology.js");
|
|
171
|
+
const homeCandidate = context.home;
|
|
172
|
+
const envHome = process.env.HOME;
|
|
173
|
+
const home = typeof homeCandidate === "string" ? homeCandidate : typeof envHome === "string" && envHome.trim() !== "" ? envHome : packageMachineHome();
|
|
174
|
+
const config = await loadPublicCliConfig(home);
|
|
175
|
+
const modelOnly = seatModelOnly(config.seats.navigator);
|
|
176
|
+
if (modelOnly === void 0) {
|
|
177
|
+
const parsed = parseNavigatorModelSetting(NAVIGATOR_DEFAULT_MODEL);
|
|
169
178
|
return {
|
|
170
179
|
selection: {
|
|
171
|
-
provider:
|
|
172
|
-
model:
|
|
173
|
-
...
|
|
180
|
+
provider: parsed.provider,
|
|
181
|
+
model: parsed.model,
|
|
182
|
+
...parsed.thinkingLevel === void 0 ? {} : { thinking: parsed.thinkingLevel }
|
|
174
183
|
},
|
|
175
|
-
configuredLabel:
|
|
176
|
-
...
|
|
184
|
+
configuredLabel: NAVIGATOR_DEFAULT_MODEL,
|
|
185
|
+
...parsed.thinkingLevel === void 0 ? {} : { thinkingLevel: parsed.thinkingLevel }
|
|
177
186
|
};
|
|
178
|
-
} catch (error) {
|
|
179
|
-
if (error instanceof InstitutionalResolutionError && (error.reason === "missing-page" || error.reason === "missing-seat")) {
|
|
180
|
-
} else {
|
|
181
|
-
throw error instanceof NavigatorUnavailableError ? error : navigatorUnavailableError("model", error);
|
|
182
|
-
}
|
|
183
187
|
}
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
+
const thinkingRaw = modelOnly.thinking;
|
|
189
|
+
const configuredLabel = thinkingRaw === void 0 ? `${modelOnly.provider}/${modelOnly.model}` : `${modelOnly.provider}/${modelOnly.model}:${thinkingRaw}`;
|
|
190
|
+
return {
|
|
191
|
+
selection: {
|
|
192
|
+
provider: modelOnly.provider,
|
|
193
|
+
model: modelOnly.model,
|
|
194
|
+
...thinkingRaw === void 0 ? {} : { thinking: thinkingRaw }
|
|
195
|
+
},
|
|
196
|
+
configuredLabel,
|
|
197
|
+
...thinkingRaw === void 0 ? {} : { thinkingLevel: thinkingRaw }
|
|
198
|
+
};
|
|
188
199
|
} catch (error) {
|
|
189
200
|
throw navigatorUnavailableError("model", error);
|
|
190
201
|
}
|
|
191
|
-
let parsed;
|
|
192
|
-
try {
|
|
193
|
-
parsed = parseNavigatorModelSetting(configured);
|
|
194
|
-
} catch (error) {
|
|
195
|
-
throw navigatorUnavailableError("model", error);
|
|
196
|
-
}
|
|
197
|
-
return {
|
|
198
|
-
selection: {
|
|
199
|
-
provider: parsed.provider,
|
|
200
|
-
model: parsed.model,
|
|
201
|
-
...parsed.thinkingLevel === void 0 ? {} : { thinking: parsed.thinkingLevel }
|
|
202
|
-
},
|
|
203
|
-
configuredLabel: configured,
|
|
204
|
-
...parsed.thinkingLevel === void 0 ? {} : { thinkingLevel: parsed.thinkingLevel }
|
|
205
|
-
};
|
|
206
202
|
}
|
|
207
203
|
export {
|
|
208
204
|
NAVIGATOR_DEFAULT_MODEL,
|
|
@@ -0,0 +1,122 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve and validate the public Notary source-run locator.
|
|
3
|
+
* Only machine-ledger retained runs are authoritative: no project-tree projection,
|
|
4
|
+
* no attachment substitute. Caller supplies a run/case pointer; Notary self-fetches.
|
|
5
|
+
*/
|
|
6
|
+
import { dirname, isAbsolute, join, resolve, basename } from "node:path";
|
|
7
|
+
import { lstat, realpath } from "node:fs/promises";
|
|
8
|
+
import { resolveBookKeyFromGit } from "./activation-ledger-git.js";
|
|
9
|
+
import { activationBookDirectory, physicalPathIdentity, resolveActivationLedgerHome, } from "./activation-ledger-topology.js";
|
|
10
|
+
import { readRoleRunIdentity } from "./public-cli/run-lifecycle.js";
|
|
11
|
+
// Run directory leaf: <runId>@<role>. Production uses uuidv7 runIds; offline tracers
|
|
12
|
+
// may use deterministic non-uuid leaves. Role token stays identifier-shaped.
|
|
13
|
+
const RUN_DIR_NAME = /^([A-Za-z0-9][A-Za-z0-9._-]*)@([A-Za-z][A-Za-z0-9_-]*)$/;
|
|
14
|
+
export class NotarySourceRunError extends Error {
|
|
15
|
+
constructor(message, options) {
|
|
16
|
+
super(message, options);
|
|
17
|
+
this.name = "NotarySourceRunError";
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function parseRunDirectoryName(name) {
|
|
21
|
+
const match = RUN_DIR_NAME.exec(name);
|
|
22
|
+
if (match === null)
|
|
23
|
+
return undefined;
|
|
24
|
+
return { runId: match[1], role: match[2] };
|
|
25
|
+
}
|
|
26
|
+
async function requireRunDirectory(candidate, display) {
|
|
27
|
+
let real;
|
|
28
|
+
try {
|
|
29
|
+
real = await realpath(candidate);
|
|
30
|
+
}
|
|
31
|
+
catch (error) {
|
|
32
|
+
throw new NotarySourceRunError(`notary --source-run is not a readable run directory: ${display}`, { cause: error });
|
|
33
|
+
}
|
|
34
|
+
let stat;
|
|
35
|
+
try {
|
|
36
|
+
stat = await lstat(real);
|
|
37
|
+
}
|
|
38
|
+
catch (error) {
|
|
39
|
+
throw new NotarySourceRunError(`notary --source-run is not a readable run directory: ${display}`, { cause: error });
|
|
40
|
+
}
|
|
41
|
+
if (!stat.isDirectory()) {
|
|
42
|
+
throw new NotarySourceRunError(`notary --source-run must be a run directory: ${display}`);
|
|
43
|
+
}
|
|
44
|
+
const identity = parseRunDirectoryName(basename(real));
|
|
45
|
+
if (identity === undefined) {
|
|
46
|
+
throw new NotarySourceRunError(`notary --source-run must be named <runId>@<role>: ${basename(real)}`);
|
|
47
|
+
}
|
|
48
|
+
return real;
|
|
49
|
+
}
|
|
50
|
+
/**
|
|
51
|
+
* Resolve `--source-run` to a machine-ledger retained run directory and typed identity.
|
|
52
|
+
* Accepts:
|
|
53
|
+
* - bare `<runId>@<role>` under the project's book runs home
|
|
54
|
+
* - absolute/relative path that realpath's to that same book runs slot
|
|
55
|
+
*
|
|
56
|
+
* Rejects project-tree projections and any path outside the project's ledger book runs.
|
|
57
|
+
* Retained `run-state.json` must match basename identity and book binding.
|
|
58
|
+
*/
|
|
59
|
+
export async function resolveNotarySourceRunLocator(options) {
|
|
60
|
+
const raw = options.sourceRun.trim();
|
|
61
|
+
if (raw === "") {
|
|
62
|
+
throw new NotarySourceRunError("notary --source-run requires a run locator");
|
|
63
|
+
}
|
|
64
|
+
const ledgerHome = resolveActivationLedgerHome(options.home);
|
|
65
|
+
const bookKey = resolveBookKeyFromGit(options.projectRoot);
|
|
66
|
+
const bookRunsRoot = join(activationBookDirectory(ledgerHome, bookKey), "runs");
|
|
67
|
+
let candidate;
|
|
68
|
+
const bare = parseRunDirectoryName(raw);
|
|
69
|
+
if (bare !== undefined && !raw.includes("/") && !raw.includes("\\")) {
|
|
70
|
+
candidate = join(bookRunsRoot, `${bare.runId}@${bare.role}`);
|
|
71
|
+
}
|
|
72
|
+
else {
|
|
73
|
+
candidate = isAbsolute(raw) ? raw : resolve(options.projectRoot, raw);
|
|
74
|
+
}
|
|
75
|
+
const real = await requireRunDirectory(candidate, raw);
|
|
76
|
+
const identity = parseRunDirectoryName(basename(real));
|
|
77
|
+
const runsRootIdentity = physicalPathIdentity(bookRunsRoot);
|
|
78
|
+
const parentIdentity = physicalPathIdentity(dirname(real));
|
|
79
|
+
if (parentIdentity !== runsRootIdentity) {
|
|
80
|
+
throw new NotarySourceRunError("notary --source-run must resolve to a retained run under the project machine-ledger book");
|
|
81
|
+
}
|
|
82
|
+
// Authoritative retained record only — legal role/state via shared reader (DRY #14).
|
|
83
|
+
// Identity envelope only: principal payload is not interpreted here.
|
|
84
|
+
const runState = await readRoleRunIdentity(real);
|
|
85
|
+
if (runState === undefined) {
|
|
86
|
+
throw new NotarySourceRunError("notary --source-run lacks retained run-state identity");
|
|
87
|
+
}
|
|
88
|
+
if (runState.runId !== identity.runId || runState.role !== identity.role) {
|
|
89
|
+
throw new NotarySourceRunError("notary --source-run retained identity does not match directory name");
|
|
90
|
+
}
|
|
91
|
+
if (runState.bookKey !== bookKey) {
|
|
92
|
+
throw new NotarySourceRunError("notary --source-run retained book binding does not match project case");
|
|
93
|
+
}
|
|
94
|
+
if (physicalPathIdentity(runState.runDirectory) !== physicalPathIdentity(real)) {
|
|
95
|
+
throw new NotarySourceRunError("notary --source-run retained runDirectory does not match locator path");
|
|
96
|
+
}
|
|
97
|
+
return {
|
|
98
|
+
runDirectory: real,
|
|
99
|
+
runId: identity.runId,
|
|
100
|
+
role: identity.role,
|
|
101
|
+
};
|
|
102
|
+
}
|
|
103
|
+
/** Internal activation loader: path is the admitted absolute source run directory. */
|
|
104
|
+
export async function loadNotarySourceRunLocator(path) {
|
|
105
|
+
const real = await requireRunDirectory(path, path);
|
|
106
|
+
const identity = parseRunDirectoryName(basename(real));
|
|
107
|
+
const runState = await readRoleRunIdentity(real);
|
|
108
|
+
if (runState === undefined) {
|
|
109
|
+
throw new NotarySourceRunError("notary source-run lacks retained run-state identity");
|
|
110
|
+
}
|
|
111
|
+
if (runState.runId !== identity.runId || runState.role !== identity.role) {
|
|
112
|
+
throw new NotarySourceRunError("notary source-run retained identity does not match directory name");
|
|
113
|
+
}
|
|
114
|
+
if (physicalPathIdentity(runState.runDirectory) !== physicalPathIdentity(real)) {
|
|
115
|
+
throw new NotarySourceRunError("notary source-run retained runDirectory does not match locator path");
|
|
116
|
+
}
|
|
117
|
+
return {
|
|
118
|
+
runDirectory: real,
|
|
119
|
+
runId: identity.runId,
|
|
120
|
+
role: identity.role,
|
|
121
|
+
};
|
|
122
|
+
}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public Auditor (审刑院) terminating receipt contracts (#675).
|
|
3
|
+
* Lawful explicit releases: pass | revise | escalate.
|
|
4
|
+
*/
|
|
5
|
+
import { Type } from "typebox";
|
|
6
|
+
import { openToolObject } from "../open-tool-schema.js";
|
|
7
|
+
import { withInfrastructureFailureDeclaration } from "./terminating-infrastructure.js";
|
|
8
|
+
export const AUDITOR_OUTPUT_TOOL_NAME = "ak_auditor_output";
|
|
9
|
+
export const AUDITOR_ACCEPTED_TEXT = "审刑院回执已接受";
|
|
10
|
+
export const auditorOutputSchema = withInfrastructureFailureDeclaration(openToolObject(Type.Object({
|
|
11
|
+
status: Type.Unknown({
|
|
12
|
+
description: "pass | revise | escalate — 形状指引,非 schema 闸",
|
|
13
|
+
}),
|
|
14
|
+
violations: Type.Optional(Type.Unknown({
|
|
15
|
+
description: "status 为 revise 时的违规条目",
|
|
16
|
+
})),
|
|
17
|
+
conflicts: Type.Optional(Type.Unknown({
|
|
18
|
+
description: "status 为 escalate 时的冲突",
|
|
19
|
+
})),
|
|
20
|
+
decisionGate: Type.Optional(Type.Unknown({
|
|
21
|
+
description: "status 为 escalate 时的决策闸",
|
|
22
|
+
})),
|
|
23
|
+
})));
|
|
24
|
+
function isRecord(value) {
|
|
25
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
26
|
+
}
|
|
27
|
+
export function projectLawfulAuditorOutput(value) {
|
|
28
|
+
if (!isRecord(value))
|
|
29
|
+
return undefined;
|
|
30
|
+
if (value.status === "pass")
|
|
31
|
+
return { status: "pass" };
|
|
32
|
+
if (value.status === "revise") {
|
|
33
|
+
return {
|
|
34
|
+
status: "revise",
|
|
35
|
+
...(Object.hasOwn(value, "violations") ? { violations: value.violations } : {}),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
if (value.status === "escalate") {
|
|
39
|
+
return {
|
|
40
|
+
status: "escalate",
|
|
41
|
+
...(Object.hasOwn(value, "conflicts") ? { conflicts: value.conflicts } : {}),
|
|
42
|
+
...(Object.hasOwn(value, "decisionGate") ? { decisionGate: value.decisionGate } : {}),
|
|
43
|
+
};
|
|
44
|
+
}
|
|
45
|
+
return undefined;
|
|
46
|
+
}
|
|
47
|
+
export function validateRecordedAuditorOutput(value) {
|
|
48
|
+
const projected = projectLawfulAuditorOutput(value);
|
|
49
|
+
if (projected === undefined) {
|
|
50
|
+
throw new Error("Auditor output has no recognized execution discriminator");
|
|
51
|
+
}
|
|
52
|
+
return projected;
|
|
53
|
+
}
|
|
54
|
+
export function auditorDecisiveFacts(output) {
|
|
55
|
+
const facts = { status: output.status };
|
|
56
|
+
if (output.status === "revise" && output.violations !== undefined) {
|
|
57
|
+
facts.violations = output.violations;
|
|
58
|
+
}
|
|
59
|
+
if (output.status === "escalate") {
|
|
60
|
+
if (output.conflicts !== undefined)
|
|
61
|
+
facts.conflicts = output.conflicts;
|
|
62
|
+
if (output.decisionGate !== undefined)
|
|
63
|
+
facts.decisionGate = output.decisionGate;
|
|
64
|
+
}
|
|
65
|
+
return facts;
|
|
66
|
+
}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Public Evidence-Child terminating receipt contracts (#675).
|
|
3
|
+
* One report body; shape is not an admission gate (ADR 0055).
|
|
4
|
+
*/
|
|
5
|
+
import { Type } from "typebox";
|
|
6
|
+
import { openToolObject } from "../open-tool-schema.js";
|
|
7
|
+
import { withInfrastructureFailureDeclaration } from "./terminating-infrastructure.js";
|
|
8
|
+
export const EVIDENCE_CHILD_OUTPUT_TOOL_NAME = "ak_evidence_child_output";
|
|
9
|
+
export const EVIDENCE_CHILD_ACCEPTED_TEXT = "取证回执已接受";
|
|
10
|
+
export const evidenceChildOutputSchema = withInfrastructureFailureDeclaration(openToolObject(Type.Object({
|
|
11
|
+
report: Type.Unknown({
|
|
12
|
+
description: "取证报告正文 — 形状指引,非 schema 闸",
|
|
13
|
+
}),
|
|
14
|
+
})));
|
|
15
|
+
function isRecord(value) {
|
|
16
|
+
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
17
|
+
}
|
|
18
|
+
export function projectLawfulEvidenceChildOutput(value) {
|
|
19
|
+
// No field-presence gate (ADR 0055 / CLAUDE.md §0 / #675). Retain delivered bytes:
|
|
20
|
+
// report key when present, otherwise the whole object as the report body.
|
|
21
|
+
if (!isRecord(value))
|
|
22
|
+
return undefined;
|
|
23
|
+
return { report: Object.hasOwn(value, "report") ? value.report : value };
|
|
24
|
+
}
|
|
25
|
+
export function validateRecordedEvidenceChildOutput(value) {
|
|
26
|
+
const projected = projectLawfulEvidenceChildOutput(value);
|
|
27
|
+
if (projected === undefined) {
|
|
28
|
+
throw new Error("Evidence-child output is not an object");
|
|
29
|
+
}
|
|
30
|
+
return projected;
|
|
31
|
+
}
|
|
32
|
+
export function evidenceChildDecisiveFacts(output) {
|
|
33
|
+
return { report: output.report };
|
|
34
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
const JUDGE_OUTPUT_TOOL_NAME = "ak_judge_output";
|
|
2
2
|
const JUDGE_ACCEPTED_TEXT = "\u5927\u7406\u5BFA\u56DE\u6267\u5DF2\u63A5\u53D7";
|
|
3
3
|
const JUDGE_ACCEPTED_AUDIT_NO_RECEIPT_TEXT = "\u5927\u7406\u5BFA\u56DE\u6267\u5DF2\u63A5\u53D7\uFF1B\u5BA1\u8BA1\u65E0\u56DE\u6267";
|
|
4
|
+
const JUDGE_ACCEPTED_AUDIT_UNREADABLE_TEXT = "\u5927\u7406\u5BFA\u56DE\u6267\u5DF2\u63A5\u53D7\uFF1B\u5BA1\u8BA1\u5F62\u72B6\u4E0D\u53EF\u8BFB";
|
|
4
5
|
function validateAcceptedJudgeDetails(verdict) {
|
|
5
6
|
if (verdict === null || typeof verdict !== "object" || Array.isArray(verdict)) throw new Error("Judge verdict has no execution discriminator");
|
|
6
7
|
let judgeStatus;
|
|
@@ -19,6 +20,7 @@ function validateAcceptedJudgeDetails(verdict) {
|
|
|
19
20
|
}
|
|
20
21
|
export {
|
|
21
22
|
JUDGE_ACCEPTED_AUDIT_NO_RECEIPT_TEXT,
|
|
23
|
+
JUDGE_ACCEPTED_AUDIT_UNREADABLE_TEXT,
|
|
22
24
|
JUDGE_ACCEPTED_TEXT,
|
|
23
25
|
JUDGE_OUTPUT_TOOL_NAME,
|
|
24
26
|
validateAcceptedJudgeDetails
|