@akagilnc/pi-workflow-roles 0.1.3412 → 0.1.3439

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.
Files changed (67) hide show
  1. package/dist/archivist-record-entry.js +21 -12
  2. package/dist/archivist-record-topology.js +20 -0
  3. package/dist/auditor-dossier-tool.js +67 -76
  4. package/dist/canonical-json.js +66 -69
  5. package/dist/compliance-transport.js +99 -86
  6. package/dist/countersign-contracts.js +23 -25
  7. package/dist/doctor-contracts.js +169 -145
  8. package/dist/engine-detour-tool.js +83 -87
  9. package/dist/engine-detour.js +148 -183
  10. package/dist/evidence-child-executor.js +10 -1
  11. package/dist/exact-utf8.js +11 -10
  12. package/dist/git-object-id.js +10 -5
  13. package/dist/gleaner-left-contracts.js +33 -35
  14. package/dist/grok/production-host.js +229 -118
  15. package/dist/inspector-contracts.js +28 -31
  16. package/dist/institutional-resolution.js +101 -104
  17. package/dist/ledger-session-read.js +241 -0
  18. package/dist/merger-contracts.js +66 -56
  19. package/dist/notary-contracts.js +91 -100
  20. package/dist/open-tool-schema.js +32 -31
  21. package/dist/package-contracts/collector-output.js +56 -43
  22. package/dist/package-contracts/fixer-output.js +52 -50
  23. package/dist/package-contracts/fixer-packet.js +67 -64
  24. package/dist/package-contracts/gatekeeper-output.js +48 -56
  25. package/dist/package-contracts/judge-output.js +23 -20
  26. package/dist/package-contracts/navigator-output.js +35 -40
  27. package/dist/package-contracts/reviewer-output.js +94 -110
  28. package/dist/package-contracts/terminating-infrastructure.js +62 -90
  29. package/dist/package-contracts/worker-output.js +30 -11
  30. package/dist/package-resources/engine-material.js +58 -94
  31. package/dist/public-cli/config.js +420 -484
  32. package/dist/public-cli/main.js +1219 -524
  33. package/dist/public-cli/registry.js +107 -114
  34. package/dist/receipt-delivery-policy.js +74 -76
  35. package/dist/session-opening-materials.js +44 -47
  36. package/dist/sha256.js +5 -3
  37. package/dist/sitian-appender.js +204 -210
  38. package/dist/sitian-contracts.js +15 -19
  39. package/dist/sitian-facade.js +5 -10
  40. package/dist/sitian-reader.js +37 -46
  41. package/dist/stream-idle-guard.js +63 -71
  42. package/dist/ticket-seat-memory.js +244 -0
  43. package/package.json +1 -1
  44. package/scripts/build-package.mjs +41 -0
  45. package/souls/audit-law.md +4 -0
  46. package/souls/countersign.md +1 -1
  47. package/souls/gleaner-left.md +1 -1
  48. package/souls/inspector.md +1 -1
  49. package/souls/notary.md +1 -1
  50. package/souls/reviewer.md +1 -1
  51. package/src/analyst-gate-cycles-read.ts +152 -83
  52. package/src/analyst-ledger.ts +170 -43
  53. package/src/archivist-record-entry.ts +32 -11
  54. package/src/archivist-record-topology.ts +39 -0
  55. package/src/evidence-child-executor.ts +14 -1
  56. package/src/grok/production-host.ts +44 -9
  57. package/src/host-contracts.ts +18 -0
  58. package/src/host-transition-prior-native.ts +8 -1
  59. package/src/ledger-session-read.ts +56 -0
  60. package/src/pi/durable-principal.ts +6 -0
  61. package/src/public-cli/inspector-run.ts +21 -10
  62. package/src/public-cli/invocation.ts +4 -20
  63. package/src/public-cli/notary-run.ts +21 -4
  64. package/src/public-cli/post-admission.ts +333 -42
  65. package/src/public-cli/settlement.ts +266 -81
  66. package/src/session-opening-materials.ts +4 -2
  67. package/src/ticket-seat-memory.ts +454 -0
@@ -1,4 +1,3 @@
1
- import { createHash } from "node:crypto";
2
1
  import { existsSync, readFileSync, realpathSync, writeFileSync } from "node:fs";
3
2
  import { dirname, resolve, join } from "node:path";
4
3
  import { SessionManager } from "@earendil-works/pi-coding-agent";
@@ -12,6 +11,8 @@ import {
12
11
  physicallyContainedIn,
13
12
  resolveActivationLedgerHomeForPath
14
13
  } from "./activation-ledger-topology.js";
14
+ import { subjectKeyedRecordDirectory } from "./archivist-record-topology.js";
15
+ import { subjectKeyedRecordDirectory as subjectKeyedRecordDirectory2 } from "./archivist-record-topology.js";
15
16
  const CURRENT_SESSION_LEDGER = "current-session.json";
16
17
  function readCurrentSession(sessionDir) {
17
18
  const ledger = join(sessionDir, CURRENT_SESSION_LEDGER);
@@ -73,22 +74,22 @@ function assertRecentFinalFileUnderSessionDir(sessionDir, recentFile) {
73
74
  );
74
75
  }
75
76
  }
76
- function createRecordSession(options) {
77
+ function createRecordSessionOpen(options) {
77
78
  const cwd = options.cwd;
78
79
  const parentFile = options.parent?.getSessionFile();
79
80
  const ledgerHome = resolveActivationLedgerHomeForPath(parentFile);
80
81
  let sessionDir;
81
82
  let parentSession;
82
83
  if (options.subject !== void 0) {
83
- const digest = createHash("sha256").update(options.subject).digest("hex").slice(0, 32);
84
- sessionDir = join(
85
- activationBookDirectory(ledgerHome, resolveBookKeyFromGit(cwd)),
86
- options.kind,
87
- digest
88
- );
84
+ sessionDir = subjectKeyedRecordDirectory({
85
+ cwd,
86
+ kind: options.kind,
87
+ subject: options.subject,
88
+ ...parentFile === void 0 || parentFile.length === 0 ? {} : { parentSessionFile: parentFile }
89
+ });
89
90
  parentSession = parentFile && parentFile.length > 0 ? parentFile : void 0;
90
91
  } else if (parentFile === void 0 || parentFile.length === 0) {
91
- return SessionManager.inMemory(cwd);
92
+ return { session: SessionManager.inMemory(cwd), resumed: false };
92
93
  } else {
93
94
  const parentResolved = resolve(parentFile);
94
95
  sessionDir = physicallyContainedIn(ledgerHome, parentResolved) ? join(dirname(parentResolved), options.kind) : join(activationBookDirectory(ledgerHome, resolveBookKeyFromGit(cwd)), options.kind);
@@ -100,7 +101,10 @@ function createRecordSession(options) {
100
101
  if (mayResumeSameNest && nestAlreadyExists) {
101
102
  const recentFile = readCurrentSession(sessionDir);
102
103
  assertRecentFinalFileUnderSessionDir(sessionDir, recentFile);
103
- return SessionManager.open(recentFile, sessionDir, cwd);
104
+ return {
105
+ session: SessionManager.open(recentFile, sessionDir, cwd),
106
+ resumed: true
107
+ };
104
108
  }
105
109
  const session = SessionManager.create(
106
110
  cwd,
@@ -121,9 +125,14 @@ function createRecordSession(options) {
121
125
  writeCurrentSession(sessionDir, file);
122
126
  }
123
127
  }
124
- return session;
128
+ return { session, resumed: false };
129
+ }
130
+ function createRecordSession(options) {
131
+ return createRecordSessionOpen(options).session;
125
132
  }
126
133
  export {
127
134
  WORKER_SUBMISSION_GATE_KIND,
128
- createRecordSession
135
+ createRecordSession,
136
+ createRecordSessionOpen,
137
+ subjectKeyedRecordDirectory2 as subjectKeyedRecordDirectory
129
138
  };
@@ -0,0 +1,20 @@
1
+ import { createHash } from "node:crypto";
2
+ import { join } from "node:path";
3
+ import { resolveBookKeyFromGit } from "./activation-ledger-git.js";
4
+ import {
5
+ activationBookDirectory,
6
+ resolveActivationLedgerHome,
7
+ resolveActivationLedgerHomeForPath
8
+ } from "./activation-ledger-topology.js";
9
+ function subjectKeyedRecordDirectory(input) {
10
+ const ledgerHome = input.parentSessionFile !== void 0 && input.parentSessionFile.length > 0 ? resolveActivationLedgerHomeForPath(input.parentSessionFile) : resolveActivationLedgerHome(input.home);
11
+ const digest = createHash("sha256").update(input.subject).digest("hex").slice(0, 32);
12
+ return join(
13
+ activationBookDirectory(ledgerHome, resolveBookKeyFromGit(input.cwd)),
14
+ input.kind,
15
+ digest
16
+ );
17
+ }
18
+ export {
19
+ subjectKeyedRecordDirectory
20
+ };
@@ -1,87 +1,78 @@
1
1
  import { mkdirSync, writeFileSync } from "node:fs";
2
2
  import { dirname, join, resolve } from "node:path";
3
3
  import { Type } from "typebox";
4
- export const AUDITOR_DOSSIER_TOOL_NAME = "ak_get_run_dossier";
5
- /** Run-relative leaf written before gate officer summons (#632 Grok header-only session). */
6
- export const GATE_SUBMISSION_CANDIDATE_FILE = "gate-submission-candidate.json";
4
+ const AUDITOR_DOSSIER_TOOL_NAME = "ak_get_run_dossier";
5
+ const GATE_SUBMISSION_CANDIDATE_FILE = "gate-submission-candidate.json";
7
6
  function isRecord(value) {
8
- return typeof value === "object" && value !== null && !Array.isArray(value);
7
+ return typeof value === "object" && value !== null && !Array.isArray(value);
9
8
  }
10
- /** Resolve the exact run binding already carried by the parent record session. */
11
- export function auditorRunDirectory(context) {
12
- const sessionFile = context.sessionManager?.getSessionFile?.();
13
- if (sessionFile === undefined)
14
- return undefined;
15
- // Sole layout: <run>/session/session.jsonl → climb two levels to the run directory.
16
- return resolve(dirname(dirname(sessionFile)));
9
+ function auditorRunDirectory(context) {
10
+ const sessionFile = context.sessionManager?.getSessionFile?.();
11
+ if (sessionFile === void 0) return void 0;
12
+ return resolve(dirname(dirname(sessionFile)));
17
13
  }
18
- /**
19
- * Latest assistant toolCall leaf on parent session books (memory or disk-backed).
20
- * Grok books the candidate in memory only (#617 DK-4); Pi books the same shape on JSONL.
21
- */
22
- export function readLatestToolCallLeaf(context) {
23
- const entries = [...(context.sessionManager?.getEntries?.() ?? [])];
24
- for (let i = entries.length - 1; i >= 0; i--) {
25
- const entry = entries[i];
26
- if (!isRecord(entry) || entry.type !== "message" || !isRecord(entry.message))
27
- continue;
28
- const message = entry.message;
29
- if (message.role !== "assistant" || !Array.isArray(message.content))
30
- continue;
31
- for (const part of message.content) {
32
- if (isRecord(part) && part.type === "toolCall") {
33
- return entry;
34
- }
35
- }
14
+ function readLatestToolCallLeaf(context) {
15
+ const entries = [...context.sessionManager?.getEntries?.() ?? []];
16
+ for (let i = entries.length - 1; i >= 0; i--) {
17
+ const entry = entries[i];
18
+ if (!isRecord(entry) || entry.type !== "message" || !isRecord(entry.message)) continue;
19
+ const message = entry.message;
20
+ if (message.role !== "assistant" || !Array.isArray(message.content)) continue;
21
+ for (const part of message.content) {
22
+ if (isRecord(part) && part.type === "toolCall") {
23
+ return entry;
24
+ }
36
25
  }
37
- return undefined;
26
+ }
27
+ return void 0;
38
28
  }
39
- export function gateSubmissionCandidatePath(runDirectory) {
40
- return join(runDirectory, "artifacts", GATE_SUBMISSION_CANDIDATE_FILE);
29
+ function gateSubmissionCandidatePath(runDirectory) {
30
+ return join(runDirectory, "artifacts", GATE_SUBMISSION_CANDIDATE_FILE);
41
31
  }
42
- /**
43
- * Persist the in-flight tool-call leaf as a run-directory artifact so pointer-only
44
- * officer summons resolve on hosts whose session.jsonl is header-only (#632 / DK-4).
45
- * Returns the written path, or undefined when no toolCall leaf is on the books.
46
- */
47
- export function persistGateSubmissionCandidate(runDirectory, context) {
48
- const leaf = readLatestToolCallLeaf(context);
49
- if (leaf === undefined)
50
- return undefined;
51
- const path = gateSubmissionCandidatePath(runDirectory);
52
- mkdirSync(dirname(path), { recursive: true });
53
- writeFileSync(path, `${JSON.stringify(leaf)}\n`, "utf8");
54
- return path;
32
+ function persistGateSubmissionCandidate(runDirectory, context) {
33
+ const leaf = readLatestToolCallLeaf(context);
34
+ if (leaf === void 0) return void 0;
35
+ const path = gateSubmissionCandidatePath(runDirectory);
36
+ mkdirSync(dirname(path), { recursive: true });
37
+ writeFileSync(path, `${JSON.stringify(leaf)}
38
+ `, "utf8");
39
+ return path;
55
40
  }
56
- /** The one shared, run-bound dossier locator exposed to every auditor seat. */
57
- export function createAuditorDossierTool(runDirectory, options) {
58
- return {
59
- name: AUDITOR_DOSSIER_TOOL_NAME,
60
- description: "定位本审计席绑定的 run 卷宗及其证据入口。",
61
- parameters: Type.Object({}, { additionalProperties: false }),
62
- async execute(_id, _params) {
63
- if (runDirectory === undefined) {
64
- return {
65
- content: [{ type: "text", text: "本审计席无绑定 run 卷宗记录。" }],
66
- details: undefined,
67
- };
68
- }
69
- const sessionPath = join(runDirectory, "session", "session.jsonl");
70
- const submissionCandidate = options?.submissionCandidate;
71
- // Prefer the persisted gate leaf when present: Grok session.jsonl is header-only
72
- // (#617 DK-4) and is not a candidate source after material deletion (#632).
73
- const details = {
74
- runDirectory,
75
- admittedRequest: join(runDirectory, "admitted-request.json"),
76
- parentSessionCandidate: submissionCandidate ?? sessionPath,
77
- attachments: join(runDirectory, "attachments"),
78
- artifacts: join(runDirectory, "artifacts"),
79
- ...(submissionCandidate === undefined ? {} : { submissionCandidate }),
80
- };
81
- return {
82
- content: [{ type: "text", text: JSON.stringify(details) }],
83
- details,
84
- };
85
- },
86
- };
41
+ function createAuditorDossierTool(runDirectory, options) {
42
+ return {
43
+ name: AUDITOR_DOSSIER_TOOL_NAME,
44
+ description: "\u5B9A\u4F4D\u672C\u5BA1\u8BA1\u5E2D\u7ED1\u5B9A\u7684 run \u5377\u5B97\u53CA\u5176\u8BC1\u636E\u5165\u53E3\u3002",
45
+ parameters: Type.Object({}, { additionalProperties: false }),
46
+ async execute(_id, _params) {
47
+ if (runDirectory === void 0) {
48
+ return {
49
+ content: [{ type: "text", text: "\u672C\u5BA1\u8BA1\u5E2D\u65E0\u7ED1\u5B9A run \u5377\u5B97\u8BB0\u5F55\u3002" }],
50
+ details: void 0
51
+ };
52
+ }
53
+ const sessionPath = join(runDirectory, "session", "session.jsonl");
54
+ const submissionCandidate = options?.submissionCandidate;
55
+ const details = {
56
+ runDirectory,
57
+ admittedRequest: join(runDirectory, "admitted-request.json"),
58
+ parentSessionCandidate: submissionCandidate ?? sessionPath,
59
+ attachments: join(runDirectory, "attachments"),
60
+ artifacts: join(runDirectory, "artifacts"),
61
+ ...submissionCandidate === void 0 ? {} : { submissionCandidate }
62
+ };
63
+ return {
64
+ content: [{ type: "text", text: JSON.stringify(details) }],
65
+ details
66
+ };
67
+ }
68
+ };
87
69
  }
70
+ export {
71
+ AUDITOR_DOSSIER_TOOL_NAME,
72
+ GATE_SUBMISSION_CANDIDATE_FILE,
73
+ auditorRunDirectory,
74
+ createAuditorDossierTool,
75
+ gateSubmissionCandidatePath,
76
+ persistGateSubmissionCandidate,
77
+ readLatestToolCallLeaf
78
+ };
@@ -1,78 +1,75 @@
1
- export const CANONICAL_JSON_VALIDATION_ERROR_CODE = "canonical-json-invalid";
2
- export class CanonicalJsonValidationError extends Error {
3
- path;
4
- reason;
5
- code = CANONICAL_JSON_VALIDATION_ERROR_CODE;
6
- constructor(path, reason) {
7
- super(`Canonical JSON validation failed at ${path}: ${reason}`);
8
- this.path = path;
9
- this.reason = reason;
10
- this.name = "CanonicalJsonValidationError";
11
- }
1
+ const CANONICAL_JSON_VALIDATION_ERROR_CODE = "canonical-json-invalid";
2
+ class CanonicalJsonValidationError extends Error {
3
+ constructor(path, reason) {
4
+ super(`Canonical JSON validation failed at ${path}: ${reason}`);
5
+ this.path = path;
6
+ this.reason = reason;
7
+ this.name = "CanonicalJsonValidationError";
8
+ }
9
+ path;
10
+ reason;
11
+ code = CANONICAL_JSON_VALIDATION_ERROR_CODE;
12
12
  }
13
13
  function childPath(path, segment) {
14
- return `${path}/${String(segment).replaceAll("~", "~0").replaceAll("/", "~1")}`;
14
+ return `${path}/${String(segment).replaceAll("~", "~0").replaceAll("/", "~1")}`;
15
15
  }
16
16
  function ownStringKeys(value, path) {
17
- const keys = Reflect.ownKeys(value);
18
- if (keys.some((key) => typeof key === "symbol")) {
19
- throw new CanonicalJsonValidationError(childPath(path, "<symbol>"), "symbol-keyed member is not a JSON member");
20
- }
21
- return keys;
17
+ const keys = Reflect.ownKeys(value);
18
+ if (keys.some((key) => typeof key === "symbol")) {
19
+ throw new CanonicalJsonValidationError(childPath(path, "<symbol>"), "symbol-keyed member is not a JSON member");
20
+ }
21
+ return keys;
22
22
  }
23
- /** Deterministic serialization of the closed JSON value domain. */
24
- export function canonicalJson(value) {
25
- const ancestors = new WeakSet();
26
- const serialize = (item, path) => {
27
- if (item === null)
28
- return "null";
29
- switch (typeof item) {
30
- case "boolean":
31
- case "string":
32
- return JSON.stringify(item);
33
- case "number":
34
- if (!Number.isFinite(item))
35
- throw new CanonicalJsonValidationError(path, "number must be finite");
36
- return JSON.stringify(item);
37
- case "undefined":
38
- case "function":
39
- case "symbol":
40
- case "bigint":
41
- throw new CanonicalJsonValidationError(path, `${typeof item} is not a JSON value`);
42
- case "object": {
43
- if (ancestors.has(item))
44
- throw new CanonicalJsonValidationError(path, "cycle is not a JSON value");
45
- ancestors.add(item);
46
- try {
47
- if (Array.isArray(item)) {
48
- if (Object.getPrototypeOf(item) !== Array.prototype)
49
- throw new CanonicalJsonValidationError(path, "array must not be a custom object");
50
- const keys = ownStringKeys(item, path);
51
- const extraKey = keys.find((key) => key !== "length" && (!/^(0|[1-9][0-9]*)$/.test(key) || Number(key) >= item.length));
52
- if (extraKey !== undefined)
53
- throw new CanonicalJsonValidationError(childPath(path, extraKey), "non-index array member is not a JSON member");
54
- const values = [];
55
- for (let index = 0; index < item.length; index += 1) {
56
- if (!Object.hasOwn(item, index))
57
- throw new CanonicalJsonValidationError(childPath(path, index), "sparse array slot is not a JSON value");
58
- values.push(serialize(item[index], childPath(path, index)));
59
- }
60
- return `[${values.join(",")}]`;
61
- }
62
- const prototype = Object.getPrototypeOf(item);
63
- if (prototype !== Object.prototype && prototype !== null)
64
- throw new CanonicalJsonValidationError(path, "object must be a plain record");
65
- return `{${ownStringKeys(item, path).sort().map((key) => `${JSON.stringify(key)}:${serialize(item[key], childPath(path, key))}`).join(",")}}`;
66
- }
67
- finally {
68
- ancestors.delete(item);
69
- }
23
+ function canonicalJson(value) {
24
+ const ancestors = /* @__PURE__ */ new WeakSet();
25
+ const serialize = (item, path) => {
26
+ if (item === null) return "null";
27
+ switch (typeof item) {
28
+ case "boolean":
29
+ case "string":
30
+ return JSON.stringify(item);
31
+ case "number":
32
+ if (!Number.isFinite(item)) throw new CanonicalJsonValidationError(path, "number must be finite");
33
+ return JSON.stringify(item);
34
+ case "undefined":
35
+ case "function":
36
+ case "symbol":
37
+ case "bigint":
38
+ throw new CanonicalJsonValidationError(path, `${typeof item} is not a JSON value`);
39
+ case "object": {
40
+ if (ancestors.has(item)) throw new CanonicalJsonValidationError(path, "cycle is not a JSON value");
41
+ ancestors.add(item);
42
+ try {
43
+ if (Array.isArray(item)) {
44
+ if (Object.getPrototypeOf(item) !== Array.prototype) throw new CanonicalJsonValidationError(path, "array must not be a custom object");
45
+ const keys = ownStringKeys(item, path);
46
+ const extraKey = keys.find((key) => key !== "length" && (!/^(0|[1-9][0-9]*)$/.test(key) || Number(key) >= item.length));
47
+ if (extraKey !== void 0) throw new CanonicalJsonValidationError(childPath(path, extraKey), "non-index array member is not a JSON member");
48
+ const values = [];
49
+ for (let index = 0; index < item.length; index += 1) {
50
+ if (!Object.hasOwn(item, index)) throw new CanonicalJsonValidationError(childPath(path, index), "sparse array slot is not a JSON value");
51
+ values.push(serialize(item[index], childPath(path, index)));
70
52
  }
53
+ return `[${values.join(",")}]`;
54
+ }
55
+ const prototype = Object.getPrototypeOf(item);
56
+ if (prototype !== Object.prototype && prototype !== null) throw new CanonicalJsonValidationError(path, "object must be a plain record");
57
+ return `{${ownStringKeys(item, path).sort().map((key) => `${JSON.stringify(key)}:${serialize(item[key], childPath(path, key))}`).join(",")}}`;
58
+ } finally {
59
+ ancestors.delete(item);
71
60
  }
72
- throw new Error("Unreachable canonical JSON value type");
73
- };
74
- return serialize(value, "$");
61
+ }
62
+ }
63
+ throw new Error("Unreachable canonical JSON value type");
64
+ };
65
+ return serialize(value, "$");
75
66
  }
76
- export function canonicalJsonBytes(value) {
77
- return new TextEncoder().encode(canonicalJson(value));
67
+ function canonicalJsonBytes(value) {
68
+ return new TextEncoder().encode(canonicalJson(value));
78
69
  }
70
+ export {
71
+ CANONICAL_JSON_VALIDATION_ERROR_CODE,
72
+ CanonicalJsonValidationError,
73
+ canonicalJson,
74
+ canonicalJsonBytes
75
+ };
@@ -1,98 +1,111 @@
1
1
  import { Type } from "typebox";
2
- import { executeAuditorChild, } from "./evidence-child-executor.js";
2
+ import {
3
+ executeAuditorChild
4
+ } from "./evidence-child-executor.js";
3
5
  import { createAuditorDossierTool } from "./auditor-dossier-tool.js";
4
- /** Unreadable compliance candidate — infrastructure failure, not a judgment status (#475). */
5
- export class ComplianceCandidateUnreadableError extends Error {
6
- observation;
7
- candidate;
8
- usage;
9
- constructor(observation, candidate, usage) {
10
- const detail = observation.kind === "non-object-arguments"
11
- ? `${observation.kind}:${observation.type}`
12
- : observation.kind === "object-status-unreadable"
13
- ? `${observation.kind}:${observation.status}`
14
- : observation.kind === "missing-subject"
15
- ? `${observation.kind}:${observation.subject}`
16
- : observation.kind;
17
- super(`Compliance candidate unreadable: ${detail}`);
18
- this.name = "ComplianceCandidateUnreadableError";
19
- this.observation = observation;
20
- this.candidate = candidate;
21
- if (usage !== undefined)
22
- this.usage = usage;
23
- }
6
+ class ComplianceCandidateUnreadableError extends Error {
7
+ observation;
8
+ candidate;
9
+ usage;
10
+ constructor(observation, candidate, usage) {
11
+ const detail = observation.kind === "non-object-arguments" ? `${observation.kind}:${observation.type}` : observation.kind === "object-status-unreadable" ? `${observation.kind}:${observation.status}` : observation.kind === "missing-subject" ? `${observation.kind}:${observation.subject}` : observation.kind;
12
+ super(`Compliance candidate unreadable: ${detail}`);
13
+ this.name = "ComplianceCandidateUnreadableError";
14
+ this.observation = observation;
15
+ this.candidate = candidate;
16
+ if (usage !== void 0) this.usage = usage;
17
+ }
24
18
  }
25
- /** Zero-projection kickoff — soul already carries dossier-fetch duty; no hand-delivered materials. */
26
- export const AUDITOR_DOSSIER_PROMPT = "本 run 卷宗已就绪。";
19
+ const AUDITOR_DOSSIER_PROMPT = "\u672C run \u5377\u5B97\u5DF2\u5C31\u7EEA\u3002";
27
20
  const nonblank = Type.String({ minLength: 1, pattern: "\\S" });
28
21
  const decisionGateSchema = Type.Object({ question: nonblank, options: Type.Array(nonblank, { minItems: 1 }) }, { additionalProperties: false });
29
- // Transport retains malformed candidates on ComplianceCandidateUnreadableError so
30
- // the existing failure channel can publish observation + candidate (#475).
31
- // Status values are guidance, not a schema gate.
32
- export const complianceDecisionSchema = Type.Object({ status: Type.Unknown({ description: "pass | revise | escalate — 形状指引,非 schema 闸" }), violations: Type.Array(nonblank, { description: "观察到的合规违规" }), conflicts: Type.Array(nonblank, { description: "未决权威或执行冲突" }), decisionGate: Type.Union([decisionGateSchema, Type.Null()], { description: "升级问题与可选选项" }) }, { additionalProperties: true, required: [] });
33
- export function createComplianceDecisionTool(name, description) {
34
- return { name, description, parameters: complianceDecisionSchema, async execute(_id, params) { return { content: [{ type: "text", text: "审计决议已收" }], details: params, terminate: true }; } };
22
+ const complianceDecisionSchema = Type.Object({ status: Type.Unknown({ description: "pass | revise | escalate \u2014 \u5F62\u72B6\u6307\u5F15\uFF0C\u975E schema \u95F8" }), violations: Type.Array(nonblank, { description: "\u89C2\u5BDF\u5230\u7684\u5408\u89C4\u8FDD\u89C4" }), conflicts: Type.Array(nonblank, { description: "\u672A\u51B3\u6743\u5A01\u6216\u6267\u884C\u51B2\u7A81" }), decisionGate: Type.Union([decisionGateSchema, Type.Null()], { description: "\u5347\u7EA7\u95EE\u9898\u4E0E\u53EF\u9009\u9009\u9879" }) }, { additionalProperties: true, required: [] });
23
+ function createComplianceDecisionTool(name, description) {
24
+ return { name, description, parameters: complianceDecisionSchema, async execute(_id, params) {
25
+ return { content: [{ type: "text", text: "\u5BA1\u8BA1\u51B3\u8BAE\u5DF2\u6536" }], details: params, terminate: true };
26
+ } };
35
27
  }
36
- export const COMPLIANCE_RESPONSE_ENTRY_TYPE = "ak_compliance_response";
37
- export const AUDITOR_PARENT_ATTEMPT_BINDING_ENTRY_TYPE = "ak_auditor_parent_attempt_binding";
38
- export const AUDITOR_COMPLIANCE_FAILURE_ENTRY_TYPE = "ak_auditor_compliance_failure";
28
+ const COMPLIANCE_RESPONSE_ENTRY_TYPE = "ak_compliance_response";
29
+ const AUDITOR_PARENT_ATTEMPT_BINDING_ENTRY_TYPE = "ak_auditor_parent_attempt_binding";
30
+ const AUDITOR_COMPLIANCE_FAILURE_ENTRY_TYPE = "ak_auditor_compliance_failure";
39
31
  import { attachDirectErrnoCode, sitianReport } from "./sitian-facade.js";
40
- export class ComplianceResponseRetentionError extends Error {
41
- constructor(message, options) {
42
- super(message, options);
43
- this.name = "ComplianceResponseRetentionError";
44
- attachDirectErrnoCode(this, options?.cause);
45
- }
32
+ class ComplianceResponseRetentionError extends Error {
33
+ constructor(message, options) {
34
+ super(message, options);
35
+ this.name = "ComplianceResponseRetentionError";
36
+ attachDirectErrnoCode(this, options?.cause);
37
+ }
46
38
  }
47
39
  function retainComplianceResponse(context, response) {
48
- try {
49
- sitianReport({
50
- level: "event",
51
- kind: "auditor",
52
- cwd: context.cwd,
53
- sessionParent: context.sessionManager.getSessionFile(),
54
- payload: { version: 1, response },
55
- source: "compliance-transport",
56
- });
57
- }
58
- catch (error) {
59
- throw new ComplianceResponseRetentionError(`compliance response retention failed: ${error instanceof Error ? error.message : String(error)}`, { cause: error });
60
- }
40
+ try {
41
+ sitianReport({
42
+ level: "event",
43
+ kind: "auditor",
44
+ cwd: context.cwd,
45
+ sessionParent: context.sessionManager.getSessionFile(),
46
+ payload: { version: 1, response },
47
+ source: "compliance-transport"
48
+ });
49
+ } catch (error) {
50
+ throw new ComplianceResponseRetentionError(
51
+ `compliance response retention failed: ${error instanceof Error ? error.message : String(error)}`,
52
+ { cause: error }
53
+ );
54
+ }
61
55
  }
62
- function readListField(value) { return Array.isArray(value) ? value : value === undefined ? [] : [value]; }
63
- export function readComplianceCandidate(arguments_, usage) {
64
- if (typeof arguments_ !== "object" || arguments_ === null || Array.isArray(arguments_)) {
65
- throw new ComplianceCandidateUnreadableError({ kind: "non-object-arguments", type: arguments_ === null ? "null" : Array.isArray(arguments_) ? "array" : typeof arguments_ }, arguments_, usage);
66
- }
67
- const args = arguments_;
68
- const status = args.status;
69
- if (status === "pass")
70
- return { status, ...(usage === undefined ? {} : { usage }) };
71
- if (status === "revise")
72
- return { status, violations: readListField(args.violations), ...(usage === undefined ? {} : { usage }) };
73
- if (status === "escalate")
74
- return { status, ...(Object.hasOwn(args, "conflicts") ? { conflicts: args.conflicts } : {}), ...(Object.hasOwn(args, "decisionGate") ? { decisionGate: args.decisionGate } : {}), ...(usage === undefined ? {} : { usage }) };
75
- throw new ComplianceCandidateUnreadableError({ kind: "object-status-unreadable", status: status === undefined ? "missing" : "unknown" }, arguments_, usage);
56
+ function readListField(value) {
57
+ return Array.isArray(value) ? value : value === void 0 ? [] : [value];
76
58
  }
77
- export async function runComplianceAudit(options) {
78
- const prompt = options.serializedInput ?? AUDITOR_DOSSIER_PROMPT;
79
- const receipt = await executeAuditorChild({
80
- tool: options.tool,
81
- dossierTool: createAuditorDossierTool(options.runDirectory),
82
- systemPrompt: options.systemPrompt,
83
- prompt,
84
- roleLabel: options.roleLabel,
85
- context: options.context,
86
- retainResponse: (response) => retainComplianceResponse(options.context, response),
87
- ...(options.runDirectory === undefined ? {} : { runDirectory: options.runDirectory }),
88
- ...(options.signal === undefined ? {} : { signal: options.signal }),
89
- });
90
- if (receipt.noReceiptLifecycle !== undefined) {
91
- return {
92
- status: "no-receipt",
93
- ...receipt.noReceiptLifecycle,
94
- ...(receipt.response.usage === undefined ? {} : { usage: receipt.response.usage }),
95
- };
96
- }
97
- return readComplianceCandidate(receipt.decision, receipt.response.usage);
59
+ function readComplianceCandidate(arguments_, usage) {
60
+ if (typeof arguments_ !== "object" || arguments_ === null || Array.isArray(arguments_)) {
61
+ throw new ComplianceCandidateUnreadableError(
62
+ { kind: "non-object-arguments", type: arguments_ === null ? "null" : Array.isArray(arguments_) ? "array" : typeof arguments_ },
63
+ arguments_,
64
+ usage
65
+ );
66
+ }
67
+ const args = arguments_;
68
+ const status = args.status;
69
+ if (status === "pass") return { status, ...usage === void 0 ? {} : { usage } };
70
+ if (status === "revise") return { status, violations: readListField(args.violations), ...usage === void 0 ? {} : { usage } };
71
+ if (status === "escalate") return { status, ...Object.hasOwn(args, "conflicts") ? { conflicts: args.conflicts } : {}, ...Object.hasOwn(args, "decisionGate") ? { decisionGate: args.decisionGate } : {}, ...usage === void 0 ? {} : { usage } };
72
+ throw new ComplianceCandidateUnreadableError(
73
+ { kind: "object-status-unreadable", status: status === void 0 ? "missing" : "unknown" },
74
+ arguments_,
75
+ usage
76
+ );
77
+ }
78
+ async function runComplianceAudit(options) {
79
+ const prompt = options.serializedInput ?? AUDITOR_DOSSIER_PROMPT;
80
+ const receipt = await executeAuditorChild({
81
+ tool: options.tool,
82
+ dossierTool: createAuditorDossierTool(options.runDirectory),
83
+ systemPrompt: options.systemPrompt,
84
+ prompt,
85
+ roleLabel: options.roleLabel,
86
+ context: options.context,
87
+ retainResponse: (response) => retainComplianceResponse(options.context, response),
88
+ ...options.runDirectory === void 0 ? {} : { runDirectory: options.runDirectory },
89
+ ...options.signal === void 0 ? {} : { signal: options.signal }
90
+ });
91
+ if (receipt.noReceiptLifecycle !== void 0) {
92
+ return {
93
+ status: "no-receipt",
94
+ ...receipt.noReceiptLifecycle,
95
+ ...receipt.response.usage === void 0 ? {} : { usage: receipt.response.usage }
96
+ };
97
+ }
98
+ return readComplianceCandidate(receipt.decision, receipt.response.usage);
98
99
  }
100
+ export {
101
+ AUDITOR_COMPLIANCE_FAILURE_ENTRY_TYPE,
102
+ AUDITOR_DOSSIER_PROMPT,
103
+ AUDITOR_PARENT_ATTEMPT_BINDING_ENTRY_TYPE,
104
+ COMPLIANCE_RESPONSE_ENTRY_TYPE,
105
+ ComplianceCandidateUnreadableError,
106
+ ComplianceResponseRetentionError,
107
+ complianceDecisionSchema,
108
+ createComplianceDecisionTool,
109
+ readComplianceCandidate,
110
+ runComplianceAudit
111
+ };