@akagilnc/pi-workflow-roles 0.1.3572 → 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.
Files changed (129) hide show
  1. package/dist/acp-host/production-host.js +20239 -10556
  2. package/dist/analyst-gate-cycles-read.js +387 -0
  3. package/dist/archivist-record-entry.js +22 -1
  4. package/dist/audit-escalation.js +6 -0
  5. package/dist/auditor-soul.js +74 -0
  6. package/dist/collector-config.js +86 -0
  7. package/dist/collector-evidence.js +316 -0
  8. package/dist/collector-github.js +527 -0
  9. package/dist/collector-ledger.js +853 -0
  10. package/dist/collector-tool-schemas.js +33 -0
  11. package/dist/compliance-transport.js +104 -52
  12. package/dist/diarist-mechanical.js +411 -0
  13. package/dist/diarist-ticket-resolution.js +177 -0
  14. package/dist/diarist.js +311 -0
  15. package/dist/doctor-auditor.js +25 -0
  16. package/dist/doctor-contracts.js +2 -0
  17. package/dist/doctor-evidence.js +142 -0
  18. package/dist/gatekeeper-role.js +104 -81
  19. package/dist/host-transition-prior-native.js +78 -0
  20. package/dist/institutional-resolution.js +1 -95
  21. package/dist/judge-auditor.js +26 -0
  22. package/dist/ledger-session-read.js +227 -0
  23. package/dist/merger-git-state.js +78 -0
  24. package/dist/navigator-attendance.js +15 -7
  25. package/dist/navigator-public-session.js +170 -0
  26. package/dist/navigator-session-contracts.js +36 -40
  27. package/dist/notary-source-run.js +122 -0
  28. package/dist/package-contracts/auditor-output.js +66 -0
  29. package/dist/package-contracts/evidence-child-output.js +34 -0
  30. package/dist/package-contracts/judge-output.js +2 -0
  31. package/dist/package-contracts/terminating-tools.js +25 -2
  32. package/dist/package-resources/method-skill.js +254 -0
  33. package/dist/packaged-role-registry.js +36 -0
  34. package/dist/pi/durable-principal.js +61 -0
  35. package/dist/pi/in-process-session.js +25 -6
  36. package/dist/pi/known-failure.js +52 -0
  37. package/dist/pi/role-turn-host.js +430 -0
  38. package/dist/public-cli/auto-resume.js +414 -0
  39. package/dist/public-cli/cli-errors.js +8 -0
  40. package/dist/public-cli/cli-io.js +1 -0
  41. package/dist/public-cli/command-renderer.js +5 -0
  42. package/dist/public-cli/doctor-run.js +84 -0
  43. package/dist/public-cli/inspector-run.js +136 -0
  44. package/dist/public-cli/instruction-seat-run.js +256 -0
  45. package/dist/public-cli/invocation.js +2225 -0
  46. package/dist/public-cli/judge-run.js +118 -0
  47. package/dist/public-cli/load-production-acp-host.js +40 -0
  48. package/dist/public-cli/main.js +1140 -652
  49. package/dist/public-cli/notary-run.js +161 -0
  50. package/dist/public-cli/option-definitions.js +1192 -0
  51. package/dist/public-cli/post-admission.js +667 -0
  52. package/dist/public-cli/public-run-credentials.js +49 -0
  53. package/dist/public-cli/registry.js +4 -1
  54. package/dist/public-cli/reviewer-dispatch-rejection.js +77 -0
  55. package/dist/public-cli/run-lifecycle.js +1344 -0
  56. package/dist/public-cli/seat-ticket-binding.js +113 -0
  57. package/dist/public-cli/settlement.js +3441 -0
  58. package/dist/public-cli/terminal.js +135 -0
  59. package/dist/public-cli/turn-request.js +25 -0
  60. package/dist/public-role-summons.js +301 -0
  61. package/dist/receipt-delivery-policy.js +10 -0
  62. package/dist/reviewer-child-executor.js +80 -8
  63. package/dist/reviewer-execution-ledger.js +2 -1
  64. package/dist/run-terminal-artifacts.js +195 -0
  65. package/dist/run-ticket-number.js +40 -0
  66. package/dist/session-assistant-usage.js +107 -0
  67. package/dist/shape-unreadable-failure.js +34 -0
  68. package/dist/submission-errors.js +3 -0
  69. package/dist/submission-ledger.js +388 -0
  70. package/dist/ticket-provenance-contracts.js +115 -0
  71. package/dist/ticket-provenance.js +340 -0
  72. package/extensions/role-runtime.ts +7 -0
  73. package/package.json +1 -1
  74. package/scripts/build-package.mjs +2 -1
  75. package/souls/doctor-auditor.md +1 -0
  76. package/souls/evidence-child.md +1 -0
  77. package/src/acp-host/production-host.ts +3 -0
  78. package/src/acp-host/role-envelope.ts +2 -2
  79. package/src/acp-host/role-turn-host.ts +9 -1
  80. package/src/analyst-gate-cycles-read.ts +37 -2
  81. package/src/archivist-record-entry.ts +45 -1
  82. package/src/audit-escalation.ts +17 -0
  83. package/src/auditor-role.ts +22 -0
  84. package/src/auditor-soul.ts +42 -0
  85. package/src/compliance-transport.ts +177 -66
  86. package/src/doctor-auditor.ts +10 -14
  87. package/src/doctor-contracts.ts +1 -0
  88. package/src/doctor-role.ts +2 -2
  89. package/src/evidence-child-role.ts +22 -0
  90. package/src/gatekeeper-pass-envelope.ts +109 -0
  91. package/src/gatekeeper-role.ts +145 -104
  92. package/src/host-contracts.ts +9 -1
  93. package/src/institutional-resolution.ts +8 -163
  94. package/src/judge-auditor.ts +10 -15
  95. package/src/judge-role.ts +8 -0
  96. package/src/navigator-attendance.ts +25 -9
  97. package/src/navigator-public-session.ts +217 -0
  98. package/src/navigator-session-contracts.ts +61 -54
  99. package/src/notary-source-run.ts +3 -1
  100. package/src/package-contracts/auditor-output.ts +82 -0
  101. package/src/package-contracts/evidence-child-output.ts +51 -0
  102. package/src/package-contracts/judge-output.ts +1 -0
  103. package/src/package-contracts/reviewer-output.ts +2 -2
  104. package/src/package-contracts/terminating-tools.ts +31 -1
  105. package/src/packaged-role-registry.ts +43 -0
  106. package/src/pi/adapter.ts +2 -1
  107. package/src/pi/in-process-session.ts +38 -12
  108. package/src/pi/role-turn-host.ts +34 -0
  109. package/src/public-cli/cli.ts +14 -6
  110. package/src/public-cli/instruction-seat-run.ts +289 -50
  111. package/src/public-cli/invocation.ts +66 -25
  112. package/src/public-cli/option-definitions.ts +61 -0
  113. package/src/public-cli/post-admission.ts +7 -1
  114. package/src/public-cli/registry.ts +4 -1
  115. package/src/public-cli/run-lifecycle.ts +22 -3
  116. package/src/public-cli/settlement.ts +120 -5
  117. package/src/public-cli/terminal.ts +2 -0
  118. package/src/public-role-summons.ts +431 -0
  119. package/src/receipt-delivery-policy.ts +10 -0
  120. package/src/reviewer-agent.ts +1 -1
  121. package/src/reviewer-child-executor.ts +114 -12
  122. package/src/reviewer-execution-ledger.ts +3 -2
  123. package/src/role-runtime.ts +158 -17
  124. package/src/session-assistant-usage.ts +119 -0
  125. package/src/session-opening-materials.ts +1 -1
  126. package/src/shape-unreadable-failure.ts +49 -0
  127. package/src/submission-errors.ts +3 -0
  128. package/dist/evidence-child-executor.js +0 -829
  129. package/src/evidence-child-executor.ts +0 -1140
@@ -10,6 +10,8 @@ import { CorrectableSubmissionError } from "../submission-correctable-error.js";
10
10
  import { DOCTOR_ACCEPTED_TEXT, DOCTOR_OUTPUT_TOOL_NAME, validateDoctorSubmissionShape, validateRecordedDoctorOutput } from "../doctor-contracts.js";
11
11
  import { GATEKEEPER_ACCEPTED_TEXT, GATEKEEPER_OUTPUT_TOOL_NAME, validateRecordedGatekeeperOutput } from "./gatekeeper-output.js";
12
12
  import { NAVIGATOR_ACCEPTED_TEXT, NAVIGATOR_OUTPUT_TOOL_NAME, validateRecordedNavigatorOutput } from "./navigator-output.js";
13
+ import { AUDITOR_ACCEPTED_TEXT, AUDITOR_OUTPUT_TOOL_NAME, validateRecordedAuditorOutput } from "./auditor-output.js";
14
+ import { EVIDENCE_CHILD_ACCEPTED_TEXT, EVIDENCE_CHILD_OUTPUT_TOOL_NAME, validateRecordedEvidenceChildOutput } from "./evidence-child-output.js";
13
15
  import { MERGER_ACCEPTED_TEXT, MERGER_OUTPUT_TOOL_NAME, validateMergerOutput } from "../merger-contracts.js";
14
16
  import { NOTARY_ACCEPTED_TEXT, NOTARY_OUTPUT_TOOL_NAME, validateRecordedNotaryOutput } from "../notary-contracts.js";
15
17
  import { COUNTERSIGN_ACCEPTED_TEXT, COUNTERSIGN_OUTPUT_TOOL_NAME, validateRecordedCountersignOutput } from "../countersign-contracts.js";
@@ -17,7 +19,7 @@ import { GLEANER_LEFT_ACCEPTED_TEXT, GLEANER_LEFT_OUTPUT_TOOL_NAME, validateReco
17
19
  import { INSPECTOR_ACCEPTED_TEXT, INSPECTOR_OUTPUT_TOOL_NAME, validateRecordedInspectorOutput } from "../inspector-contracts.js";
18
20
  import { DIARIST_ACCEPTED_TEXT, DIARIST_OUTPUT_TOOL_NAME, validateRecordedDiaristOutput } from "../diarist-contracts.js";
19
21
  import { CODER_ACCEPTED_TEXT, CODER_OUTPUT_TOOL_NAME, FIXER_ACCEPTED_TEXT, FIXER_OUTPUT_TOOL_NAME, validateAcceptedWorkerDetails, } from "./worker-output.js";
20
- export { CODER_ACCEPTED_TEXT, CODER_OUTPUT_TOOL_NAME, COLLECTOR_ACCEPTED_TEXT, COLLECTOR_OUTPUT_TOOL, FIXER_ACCEPTED_TEXT, FIXER_OUTPUT_TOOL_NAME, JUDGE_ACCEPTED_TEXT, JUDGE_OUTPUT_TOOL_NAME, REVIEWER_ACCEPTED_TEXT, REVIEWER_OUTPUT_TOOL_NAME, MERGER_ACCEPTED_TEXT, MERGER_OUTPUT_TOOL_NAME, validateAcceptedCollectorReceipt, validateAcceptedJudgeDetails, projectReviewerIntentToReceipt, validateReviewerIntent, validateRuntimeReviewerReceipt, validateAcceptedWorkerDetails, validateDoctorSubmissionShape, validateRecordedDoctorOutput, validateMergerOutput, validateRecordedNotaryOutput, validateRecordedCountersignOutput, validateRecordedGleanerLeftOutput, validateRecordedInspectorOutput, validateRecordedGatekeeperOutput, validateRecordedNavigatorOutput, validateRecordedDiaristOutput, };
22
+ export { CODER_ACCEPTED_TEXT, CODER_OUTPUT_TOOL_NAME, COLLECTOR_ACCEPTED_TEXT, COLLECTOR_OUTPUT_TOOL, FIXER_ACCEPTED_TEXT, FIXER_OUTPUT_TOOL_NAME, JUDGE_ACCEPTED_TEXT, JUDGE_OUTPUT_TOOL_NAME, REVIEWER_ACCEPTED_TEXT, REVIEWER_OUTPUT_TOOL_NAME, MERGER_ACCEPTED_TEXT, MERGER_OUTPUT_TOOL_NAME, validateAcceptedCollectorReceipt, validateAcceptedJudgeDetails, projectReviewerIntentToReceipt, validateReviewerIntent, validateRuntimeReviewerReceipt, validateAcceptedWorkerDetails, validateDoctorSubmissionShape, validateRecordedDoctorOutput, validateMergerOutput, validateRecordedNotaryOutput, validateRecordedCountersignOutput, validateRecordedGleanerLeftOutput, validateRecordedInspectorOutput, validateRecordedGatekeeperOutput, validateRecordedNavigatorOutput, validateRecordedAuditorOutput, validateRecordedEvidenceChildOutput, validateRecordedDiaristOutput, };
21
23
  export const TERMINATING_TOOL_NAMES = [
22
24
  CODER_OUTPUT_TOOL_NAME,
23
25
  FIXER_OUTPUT_TOOL_NAME,
@@ -32,6 +34,8 @@ export const TERMINATING_TOOL_NAMES = [
32
34
  INSPECTOR_OUTPUT_TOOL_NAME,
33
35
  GATEKEEPER_OUTPUT_TOOL_NAME,
34
36
  NAVIGATOR_OUTPUT_TOOL_NAME,
37
+ AUDITOR_OUTPUT_TOOL_NAME,
38
+ EVIDENCE_CHILD_OUTPUT_TOOL_NAME,
35
39
  DIARIST_OUTPUT_TOOL_NAME,
36
40
  ];
37
41
  export function isTerminatingToolName(name) {
@@ -65,6 +69,10 @@ export function acceptedTextFor(toolName) {
65
69
  return GATEKEEPER_ACCEPTED_TEXT;
66
70
  case NAVIGATOR_OUTPUT_TOOL_NAME:
67
71
  return NAVIGATOR_ACCEPTED_TEXT;
72
+ case AUDITOR_OUTPUT_TOOL_NAME:
73
+ return AUDITOR_ACCEPTED_TEXT;
74
+ case EVIDENCE_CHILD_OUTPUT_TOOL_NAME:
75
+ return EVIDENCE_CHILD_ACCEPTED_TEXT;
68
76
  case DIARIST_OUTPUT_TOOL_NAME:
69
77
  return DIARIST_ACCEPTED_TEXT;
70
78
  }
@@ -118,14 +126,21 @@ export function validateAcceptedDetails(toolName, details) {
118
126
  [INSPECTOR_OUTPUT_TOOL_NAME]: ["pass", "bounce"],
119
127
  [GATEKEEPER_OUTPUT_TOOL_NAME]: ["dispatch", "pass"],
120
128
  [NAVIGATOR_OUTPUT_TOOL_NAME]: ["advice"],
129
+ [AUDITOR_OUTPUT_TOOL_NAME]: ["pass", "revise", "escalate"],
130
+ [EVIDENCE_CHILD_OUTPUT_TOOL_NAME]: [],
121
131
  [DIARIST_OUTPUT_TOOL_NAME]: ["completed"],
122
132
  };
123
133
  const collectorDiscriminator = toolName === COLLECTOR_OUTPUT_TOOL && Array.isArray(candidate?.groups);
134
+ // Evidence-child: any object is a candidate body — no report-field presence gate (#675 / ADR 0055).
135
+ const evidenceChildDiscriminator = toolName === EVIDENCE_CHILD_OUTPUT_TOOL_NAME
136
+ && candidate !== null
137
+ && typeof candidate === "object"
138
+ && !Array.isArray(candidate);
124
139
  const baseDiscriminator = discriminator;
125
140
  const runtimeBindingMissing = (toolName === DOCTOR_OUTPUT_TOOL_NAME && baseDiscriminator === "completed" && !(candidate?.cost !== null && typeof candidate?.cost === "object")) ||
126
141
  (toolName === REVIEWER_OUTPUT_TOOL_NAME && candidate?.version !== 2);
127
142
  if (runtimeBindingMissing ||
128
- (!collectorDiscriminator && (typeof discriminator !== "string" || !lawfulStatuses[toolName].includes(baseDiscriminator)))) {
143
+ (!collectorDiscriminator && !evidenceChildDiscriminator && (typeof discriminator !== "string" || !lawfulStatuses[toolName].includes(baseDiscriminator)))) {
129
144
  throw new AcceptedDetailsContractError("terminating receipt has no recognized execution discriminator");
130
145
  }
131
146
  try {
@@ -156,6 +171,10 @@ export function validateAcceptedDetails(toolName, details) {
156
171
  return validateRecordedGatekeeperOutput(details);
157
172
  case NAVIGATOR_OUTPUT_TOOL_NAME:
158
173
  return validateRecordedNavigatorOutput(details);
174
+ case AUDITOR_OUTPUT_TOOL_NAME:
175
+ return validateRecordedAuditorOutput(details);
176
+ case EVIDENCE_CHILD_OUTPUT_TOOL_NAME:
177
+ return validateRecordedEvidenceChildOutput(details);
159
178
  case DIARIST_OUTPUT_TOOL_NAME:
160
179
  return validateRecordedDiaristOutput(details);
161
180
  }
@@ -210,6 +229,10 @@ export function acceptedFacts(toolName, details) {
210
229
  case INSPECTOR_OUTPUT_TOOL_NAME:
211
230
  case GATEKEEPER_OUTPUT_TOOL_NAME:
212
231
  case NAVIGATOR_OUTPUT_TOOL_NAME:
232
+ case AUDITOR_OUTPUT_TOOL_NAME:
233
+ return { status: details.status };
234
+ case EVIDENCE_CHILD_OUTPUT_TOOL_NAME:
235
+ return { status: "report" };
213
236
  case DIARIST_OUTPUT_TOOL_NAME: return { status: details.status };
214
237
  case JUDGE_OUTPUT_TOOL_NAME: return { status: details.judgeStatus };
215
238
  case COUNTERSIGN_OUTPUT_TOOL_NAME: return { status: details.countersignStatus };
@@ -0,0 +1,254 @@
1
+ /**
2
+ * Package-owned role method Skill seam (ADR 0052 / #109).
3
+ * Forced methods load from the installed package copy — never ambient home discovery.
4
+ *
5
+ * This module is intentionally free of @earendil-works/pi-coding-agent so the
6
+ * public ak-role bin can load provenance/path without bundling peer runtime.
7
+ */
8
+ import { createHash } from "node:crypto";
9
+ import { readFile, realpath } from "node:fs/promises";
10
+ import { join } from "node:path";
11
+ import { sha256Hex } from "../sha256.js";
12
+ /** Package-side unavailable method Skill (mirrors CanonicalSkillUnavailableError identity). */
13
+ export class PackagedMethodSkillUnavailableError extends Error {
14
+ skillName;
15
+ code = "canonical-skill-unavailable";
16
+ constructor(skillName, path, cause) {
17
+ super(`Canonical ${skillName} Skill is unavailable at ${path}`, { cause });
18
+ this.skillName = skillName;
19
+ this.name = "CanonicalSkillUnavailableError";
20
+ }
21
+ }
22
+ const METHOD_SKILL_RELATIVE_ROOT = "resources/methods";
23
+ const GIT_COMMIT_RE = /^[0-9a-f]{40}$/;
24
+ const GIT_BLOB_RE = /^[0-9a-f]{40}$/;
25
+ const SHA256_RE = /^[0-9a-f]{64}$/;
26
+ const REQUIRED_COMPANIONS = {
27
+ tdd: ["tests.md", "mocking.md", "agents/openai.yaml"],
28
+ "diagnosing-bugs": ["agents/openai.yaml", "scripts/hitl-loop.template.sh"],
29
+ "code-review": ["agents/openai.yaml"],
30
+ "resolving-merge-conflicts": ["agents/openai.yaml"],
31
+ };
32
+ /** Git blob OID for raw file bytes (sha1 of `blob <size>\\0` + content). */
33
+ export function gitBlobOid(bytes) {
34
+ const body = typeof bytes === "string" ? Buffer.from(bytes, "utf8") : Buffer.from(bytes);
35
+ const header = Buffer.from(`blob ${body.byteLength}\0`, "utf8");
36
+ return createHash("sha1").update(header).update(body).digest("hex");
37
+ }
38
+ /** Minimal frontmatter strip — body after closing `---` fence (or full text). */
39
+ export function stripSkillFrontmatter(content) {
40
+ if (!content.startsWith("---"))
41
+ return content;
42
+ const end = content.indexOf("\n---", 3);
43
+ if (end === -1)
44
+ return content;
45
+ const after = content.slice(end + "\n---".length);
46
+ return after.replace(/^\r?\n/, "");
47
+ }
48
+ export function packagedMethodSkillRelativeDirectory(name) {
49
+ return `${METHOD_SKILL_RELATIVE_ROOT}/${name}`;
50
+ }
51
+ export function resolvePackagedMethodSkillRoot(packageRoot, name) {
52
+ return join(packageRoot, packagedMethodSkillRelativeDirectory(name));
53
+ }
54
+ export function resolvePackagedMethodSkillPath(packageRoot, name) {
55
+ return join(resolvePackagedMethodSkillRoot(packageRoot, name), "SKILL.md");
56
+ }
57
+ function isRecord(value) {
58
+ return typeof value === "object" && value !== null && !Array.isArray(value);
59
+ }
60
+ function parseProvenance(raw, expectedName) {
61
+ if (!isRecord(raw)) {
62
+ throw new Error(`Packaged method provenance must be an object for ${expectedName}`);
63
+ }
64
+ if (raw.name !== expectedName) {
65
+ throw new Error(`Packaged method provenance name mismatch: expected ${expectedName}, got ${String(raw.name)}`);
66
+ }
67
+ if (raw.kind !== "role-method-skill") {
68
+ throw new Error(`Packaged method provenance kind must be role-method-skill`);
69
+ }
70
+ if (typeof raw.packageAdaptation !== "string" || raw.packageAdaptation.trim() === "") {
71
+ throw new Error(`Packaged method provenance packageAdaptation must be nonblank`);
72
+ }
73
+ if (!isRecord(raw.upstream)) {
74
+ throw new Error(`Packaged method provenance upstream must be an object`);
75
+ }
76
+ const upstream = raw.upstream;
77
+ for (const key of [
78
+ "repository",
79
+ "path",
80
+ "license",
81
+ "copyright",
82
+ "attribution",
83
+ ]) {
84
+ if (typeof upstream[key] !== "string" || upstream[key].trim() === "") {
85
+ throw new Error(`Packaged method provenance upstream.${key} must be nonblank`);
86
+ }
87
+ }
88
+ if (typeof upstream.commit !== "string" || !GIT_COMMIT_RE.test(upstream.commit)) {
89
+ throw new Error(`Packaged method provenance upstream.commit must be a 40-char lowercase git object id`);
90
+ }
91
+ const tag = typeof upstream.tag === "string" && upstream.tag.trim() !== ""
92
+ ? upstream.tag.trim()
93
+ : undefined;
94
+ const version = typeof upstream.version === "string" && upstream.version.trim() !== ""
95
+ ? upstream.version.trim()
96
+ : undefined;
97
+ if (tag === undefined && version === undefined) {
98
+ throw new Error(`Packaged method provenance upstream must include nonblank tag or version`);
99
+ }
100
+ if (!isRecord(raw.files)) {
101
+ throw new Error(`Packaged method provenance files must be an object`);
102
+ }
103
+ const files = {};
104
+ for (const [rel, entry] of Object.entries(raw.files)) {
105
+ if (!isRecord(entry)) {
106
+ throw new Error(`Packaged method provenance file entry must be an object: ${rel}`);
107
+ }
108
+ if (typeof entry.sha256 !== "string" || !SHA256_RE.test(entry.sha256)) {
109
+ throw new Error(`Packaged method provenance file sha256 invalid: ${rel}`);
110
+ }
111
+ if (typeof entry.byteLength !== "number" ||
112
+ !Number.isInteger(entry.byteLength) ||
113
+ entry.byteLength < 0) {
114
+ throw new Error(`Packaged method provenance file byteLength invalid: ${rel}`);
115
+ }
116
+ if (typeof entry.gitBlob !== "string" || !GIT_BLOB_RE.test(entry.gitBlob)) {
117
+ throw new Error(`Packaged method provenance file gitBlob must be a 40-char lowercase git object id: ${rel}`);
118
+ }
119
+ files[rel] = {
120
+ sha256: entry.sha256,
121
+ byteLength: entry.byteLength,
122
+ gitBlob: entry.gitBlob,
123
+ };
124
+ }
125
+ if (files["SKILL.md"] === undefined) {
126
+ throw new Error(`Packaged method provenance must include SKILL.md`);
127
+ }
128
+ return Object.freeze({
129
+ name: expectedName,
130
+ kind: "role-method-skill",
131
+ packageAdaptation: raw.packageAdaptation,
132
+ upstream: Object.freeze({
133
+ repository: upstream.repository,
134
+ path: upstream.path,
135
+ commit: upstream.commit,
136
+ ...(tag === undefined ? {} : { tag }),
137
+ ...(version === undefined ? {} : { version }),
138
+ license: upstream.license,
139
+ copyright: upstream.copyright,
140
+ attribution: upstream.attribution,
141
+ }),
142
+ files: Object.freeze(files),
143
+ });
144
+ }
145
+ /**
146
+ * Load a package-owned method Skill and verify per-file provenance digests.
147
+ * Does not consult HOME or ambient Skill discovery paths.
148
+ */
149
+ export async function loadPackagedMethodSkillMaterial(packageRoot, name) {
150
+ const rootDirectory = resolvePackagedMethodSkillRoot(packageRoot, name);
151
+ const skillPathConfigured = join(rootDirectory, "SKILL.md");
152
+ const provenancePath = join(rootDirectory, "provenance.json");
153
+ let provenanceRaw;
154
+ try {
155
+ provenanceRaw = await readFile(provenancePath, "utf8");
156
+ }
157
+ catch (error) {
158
+ throw new PackagedMethodSkillUnavailableError(name, provenancePath, error);
159
+ }
160
+ let provenanceJson;
161
+ try {
162
+ provenanceJson = JSON.parse(provenanceRaw);
163
+ }
164
+ catch (error) {
165
+ throw new Error(`Packaged method provenance is not valid JSON at ${provenancePath}`, {
166
+ cause: error,
167
+ });
168
+ }
169
+ const provenance = parseProvenance(provenanceJson, name);
170
+ // Verify every declared file digest + independent git blob against package bytes (no network).
171
+ for (const [rel, expected] of Object.entries(provenance.files)) {
172
+ const absolute = join(rootDirectory, rel);
173
+ let bytes;
174
+ try {
175
+ bytes = await readFile(absolute);
176
+ }
177
+ catch (error) {
178
+ throw new PackagedMethodSkillUnavailableError(name, absolute, error);
179
+ }
180
+ const actualSha = sha256Hex(bytes);
181
+ const actualBlob = gitBlobOid(bytes);
182
+ if (actualSha !== expected.sha256 ||
183
+ bytes.byteLength !== expected.byteLength ||
184
+ actualBlob !== expected.gitBlob) {
185
+ throw new Error(`Packaged method file digest mismatch for ${name}/${rel}: expected sha256=${expected.sha256} byteLength=${expected.byteLength} gitBlob=${expected.gitBlob}, got sha256=${actualSha} byteLength=${bytes.byteLength} gitBlob=${actualBlob}`);
186
+ }
187
+ }
188
+ let skillPath;
189
+ let raw;
190
+ try {
191
+ skillPath = await realpath(skillPathConfigured);
192
+ raw = await readFile(skillPath, "utf8");
193
+ }
194
+ catch (error) {
195
+ throw new PackagedMethodSkillUnavailableError(name, skillPathConfigured, error);
196
+ }
197
+ const body = stripSkillFrontmatter(raw).trim();
198
+ if (body.length === 0) {
199
+ throw new Error(`Canonical ${name} Skill is empty at ${skillPath}`);
200
+ }
201
+ const companionRelativePaths = REQUIRED_COMPANIONS[name].filter((rel) => provenance.files[rel] !== undefined);
202
+ for (const rel of REQUIRED_COMPANIONS[name]) {
203
+ if (provenance.files[rel] === undefined) {
204
+ throw new Error(`Packaged method ${name} missing required companion in provenance: ${rel}`);
205
+ }
206
+ }
207
+ return Object.freeze({
208
+ name,
209
+ rootDirectory,
210
+ skillPath,
211
+ raw,
212
+ body,
213
+ provenance,
214
+ companionRelativePaths: Object.freeze([...companionRelativePaths]),
215
+ });
216
+ }
217
+ /**
218
+ * Observe one Pi-native packaged method Skill expansion from a user-turn text.
219
+ * Matches the structured `<skill name location>` block format only; rejects ambient
220
+ * home locations that are not in the allowed package path set.
221
+ */
222
+ export function observePackagedMethodSkillInvocation(text, expected) {
223
+ // Structured skill-block grammar (same shape Pi expands); not free-text classification.
224
+ if (!text.startsWith("<skill name=\""))
225
+ return undefined;
226
+ const nameStart = "<skill name=\"".length;
227
+ const nameEnd = text.indexOf("\"", nameStart);
228
+ if (nameEnd <= nameStart)
229
+ return undefined;
230
+ const name = text.slice(nameStart, nameEnd);
231
+ if (name !== expected.name)
232
+ return undefined;
233
+ const locationMarker = "\" location=\"";
234
+ if (!text.startsWith(locationMarker, nameEnd))
235
+ return undefined;
236
+ const locationStart = nameEnd + locationMarker.length;
237
+ const locationEnd = text.indexOf("\"", locationStart);
238
+ if (locationEnd <= locationStart)
239
+ return undefined;
240
+ const location = text.slice(locationStart, locationEnd);
241
+ const openTail = ">\n";
242
+ if (!text.startsWith(openTail, locationEnd + 1))
243
+ return undefined;
244
+ const closeTag = "\n</skill>";
245
+ const closeAt = text.indexOf(closeTag, locationEnd + 1 + openTail.length);
246
+ if (closeAt === -1)
247
+ return undefined;
248
+ const afterClose = text.slice(closeAt + closeTag.length);
249
+ if (afterClose.length > 0 && !afterClose.startsWith("\n"))
250
+ return undefined;
251
+ if (!expected.allowedLocations.includes(location))
252
+ return undefined;
253
+ return Object.freeze({ name: expected.name, location });
254
+ }
@@ -10,6 +10,8 @@ import { NOTARY_OUTPUT_TOOL_NAME } from "./notary-contracts.js";
10
10
  import { COUNTERSIGN_OUTPUT_TOOL_NAME } from "./countersign-contracts.js";
11
11
  import { GLEANER_LEFT_OUTPUT_TOOL_NAME } from "./gleaner-left-contracts.js";
12
12
  import { INSPECTOR_OUTPUT_TOOL_NAME } from "./inspector-contracts.js";
13
+ import { AUDITOR_OUTPUT_TOOL_NAME } from "./package-contracts/auditor-output.js";
14
+ import { EVIDENCE_CHILD_OUTPUT_TOOL_NAME } from "./package-contracts/evidence-child-output.js";
13
15
  import {
14
16
  DIARIST_OUTPUT_TOOL_NAME,
15
17
  DIARIST_SOURCES_FLAG
@@ -27,6 +29,19 @@ const INSPECTOR_SESSION_MATERIALS = [
27
29
  "souls/quality-law.md",
28
30
  "souls/gate-output-guide.md"
29
31
  ];
32
+ const AUDITOR_PUBLIC_SESSION_MATERIALS = [
33
+ "CLAUDE.md",
34
+ "souls/judge-auditor.md",
35
+ "souls/doctor-auditor.md",
36
+ "souls/audit-law.md",
37
+ "souls/quality-law.md"
38
+ ];
39
+ const EVIDENCE_CHILD_SESSION_MATERIALS = [
40
+ "CLAUDE.md",
41
+ "souls/evidence-child.md",
42
+ "souls/audit-law.md",
43
+ "souls/quality-law.md"
44
+ ];
30
45
  const PUBLIC_ROLE_RECORDS = [
31
46
  {
32
47
  role: "judge",
@@ -180,6 +195,25 @@ const PUBLIC_ROLE_RECORDS = [
180
195
  activationStage: "load-and-install",
181
196
  sessionMaterials: ["CLAUDE.md", "souls/navigator.md"]
182
197
  },
198
+ // #675: 审刑院 / evidence-child are roles like any other — public ak-role entries.
199
+ {
200
+ role: "auditor",
201
+ phases: [null],
202
+ outputTool: AUDITOR_OUTPUT_TOOL_NAME,
203
+ inputFlag: void 0,
204
+ phaseFlag: void 0,
205
+ activationStage: "load-and-install",
206
+ sessionMaterials: AUDITOR_PUBLIC_SESSION_MATERIALS
207
+ },
208
+ {
209
+ role: "evidence-child",
210
+ phases: [null],
211
+ outputTool: EVIDENCE_CHILD_OUTPUT_TOOL_NAME,
212
+ inputFlag: void 0,
213
+ phaseFlag: void 0,
214
+ activationStage: "load-and-install",
215
+ sessionMaterials: EVIDENCE_CHILD_SESSION_MATERIALS
216
+ },
183
217
  // #708 / ADR 0075 `diarist-is-role`: 起居郎 is a seat like any other. The
184
218
  // frozen source catalog rides the shared input-flag seam; it is absent for a
185
219
  // true-unbound summons (no ticket → no diary).
@@ -211,6 +245,8 @@ function packagedRoleOutputTool(role) {
211
245
  return packagedRoleMetadata(role)?.outputTool;
212
246
  }
213
247
  export {
248
+ AUDITOR_PUBLIC_SESSION_MATERIALS,
249
+ EVIDENCE_CHILD_SESSION_MATERIALS,
214
250
  INSPECTOR_SESSION_MATERIALS,
215
251
  NOTARY_SESSION_MATERIALS,
216
252
  PACKAGED_ROLE_REGISTRY,
@@ -0,0 +1,61 @@
1
+ import { lstat } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ import { resolveBookKeyFromGit } from "../activation-ledger-git.js";
4
+ import { activationBookDirectory, resolveActivationLedgerHome, } from "../activation-ledger-topology.js";
5
+ function encode(coordinates) {
6
+ return coordinates;
7
+ }
8
+ export function issuePiDurablePrincipalCoordinates(request) {
9
+ const ledgerHome = resolveActivationLedgerHome(request.home);
10
+ const bookKey = resolveBookKeyFromGit(request.cwd);
11
+ const runDirectory = join(activationBookDirectory(ledgerHome, bookKey), "runs", `${request.runId}@${request.role}`);
12
+ const sessionDirectory = join(runDirectory, "session");
13
+ return {
14
+ ledgerHome,
15
+ bookKey,
16
+ runDirectory,
17
+ sessionDirectory,
18
+ sessionFile: join(sessionDirectory, "session.jsonl"),
19
+ };
20
+ }
21
+ /** Pi's durable-principal codec and availability authority. */
22
+ export const piDurablePrincipalAuthority = {
23
+ issue(request) {
24
+ const coordinates = issuePiDurablePrincipalCoordinates(request);
25
+ return encode({
26
+ sessionDirectory: coordinates.sessionDirectory,
27
+ sessionFile: coordinates.sessionFile,
28
+ });
29
+ },
30
+ seal(coordinates) {
31
+ return encode({
32
+ sessionDirectory: coordinates.sessionDirectory,
33
+ sessionFile: coordinates.sessionFile,
34
+ });
35
+ },
36
+ decode(value) {
37
+ const record = value;
38
+ if (record === null || typeof record !== "object") {
39
+ throw new Error("durable principal payload is missing");
40
+ }
41
+ if (typeof record.sessionDirectory !== "string" || record.sessionDirectory.trim() === "") {
42
+ throw new Error("durable principal session directory is missing");
43
+ }
44
+ return {
45
+ sessionDirectory: record.sessionDirectory,
46
+ sessionFile: typeof record.sessionFile === "string" && record.sessionFile.trim() !== ""
47
+ ? record.sessionFile
48
+ : join(record.sessionDirectory, "session.jsonl"),
49
+ };
50
+ },
51
+ async isAvailable(principal) {
52
+ const { sessionFile } = this.decode(principal);
53
+ try {
54
+ const stat = await lstat(sessionFile);
55
+ return stat.isFile() && !stat.isSymbolicLink();
56
+ }
57
+ catch {
58
+ return false;
59
+ }
60
+ },
61
+ };
@@ -129,7 +129,7 @@ function enrichStreamEvent(event, observedHttpStatus) {
129
129
  }
130
130
  return event;
131
131
  }
132
- async function openPiInstitutionalSession(options) {
132
+ async function openPiInProcessSession(options) {
133
133
  const label = options.label ?? "Institutional sub-session";
134
134
  const selection = options.selection;
135
135
  let scratchDir;
@@ -457,10 +457,17 @@ async function openPiInstitutionalSession(options) {
457
457
  });
458
458
  }
459
459
  }
460
+ const requestedThinking = selection.thinking;
461
+ const priorEntries = typeof sessionManager.getEntries === "function" ? sessionManager.getEntries() : [];
462
+ const reusedSession = priorEntries.some((entry) => {
463
+ if (typeof entry !== "object" || entry === null) return false;
464
+ const type = entry.type;
465
+ return type === "message" || type === "model_change" || type === "thinking_level_change";
466
+ });
460
467
  const { session } = await createAgentSession({
461
468
  cwd: options.cwd,
462
469
  model: effectiveModel,
463
- ...options.selection.thinking === void 0 ? {} : { thinkingLevel: options.selection.thinking },
470
+ ...requestedThinking === void 0 ? {} : { thinkingLevel: requestedThinking },
464
471
  modelRuntime: runtime,
465
472
  sessionManager,
466
473
  settingsManager: settings,
@@ -470,9 +477,21 @@ async function openPiInstitutionalSession(options) {
470
477
  ...options.toolsAllowlist === void 0 ? {} : { tools: options.toolsAllowlist },
471
478
  ...customTools.length === 0 ? {} : { customTools }
472
479
  });
473
- await session.setModel(effectiveModel);
474
- if (options.selection.thinking !== void 0) {
475
- session.setThinkingLevel(options.selection.thinking);
480
+ if (reusedSession) {
481
+ try {
482
+ await session.setModel(effectiveModel);
483
+ if (requestedThinking !== void 0) {
484
+ session.setThinkingLevel(requestedThinking);
485
+ }
486
+ } catch (error) {
487
+ session.dispose();
488
+ throw withTypedReason(
489
+ error instanceof Error ? error : new Error(
490
+ `${label} failed to apply seat model/thinking for ${selection.provider}/${selection.model}`
491
+ ),
492
+ requestedThinking !== void 0 ? "thinking" : "model"
493
+ );
494
+ }
476
495
  }
477
496
  const listeners = /* @__PURE__ */ new Set();
478
497
  const accumulatedUsage = emptyUsage();
@@ -637,5 +656,5 @@ async function openPiInstitutionalSession(options) {
637
656
  }
638
657
  export {
639
658
  DEFAULT_COMPLIANCE_IDLE_MAX_RETRIES,
640
- openPiInstitutionalSession
659
+ openPiInProcessSession
641
660
  };
@@ -0,0 +1,52 @@
1
+ import { hasUpstreamErrorTestimony, projectConfirmedRemotePayload, } from "../upstream-error-testimony.js";
2
+ export { hasUpstreamErrorTestimony } from "../upstream-error-testimony.js";
3
+ function nonEmptyString(value) {
4
+ return typeof value === "string" && value.trim() !== "" ? value : undefined;
5
+ }
6
+ function sessionStopDetails(input) {
7
+ const details = {};
8
+ const errorMessage = nonEmptyString(input.errorMessage);
9
+ if (errorMessage !== undefined)
10
+ details.errorMessage = errorMessage;
11
+ const api = nonEmptyString(input.api);
12
+ if (api !== undefined)
13
+ details.api = api;
14
+ const rawStopReason = nonEmptyString(input.rawStopReason);
15
+ if (rawStopReason !== undefined)
16
+ details.rawStopReason = rawStopReason;
17
+ const testimony = hasUpstreamErrorTestimony(input);
18
+ if (testimony) {
19
+ const provider = nonEmptyString(input.provider);
20
+ if (provider !== undefined)
21
+ details.provider = provider;
22
+ const model = nonEmptyString(input.model);
23
+ if (model !== undefined)
24
+ details.model = model;
25
+ }
26
+ if (typeof input.httpStatus === "number")
27
+ details.httpStatus = input.httpStatus;
28
+ if (input.diagnostics !== undefined)
29
+ details.diagnostics = input.diagnostics;
30
+ // SDK structured payload fields: project only when held on a confirmed-remote node.
31
+ if (testimony)
32
+ Object.assign(details, projectConfirmedRemotePayload(input));
33
+ return details;
34
+ }
35
+ /**
36
+ * Project a native session assistant stop onto the existing knownFailure chain.
37
+ * Classification follows two-way testimony: typed HTTP status or SDK structure
38
+ * keeps provider; stopReason, configured provider/model, or errorMessage prose
39
+ * alone is the existing unrecognized value. Present upstream payload is preserved
40
+ * in details without rewriting; missing fields are omitted.
41
+ */
42
+ export function knownFailureFromProviderStop(input) {
43
+ if (input.stopReason !== "error" && input.stopReason !== "aborted")
44
+ return undefined;
45
+ const diagnostic = nonEmptyString(input.errorMessage);
46
+ const details = sessionStopDetails(input);
47
+ return {
48
+ cause: hasUpstreamErrorTestimony(input) ? "provider" : "unrecognized",
49
+ ...(diagnostic === undefined ? {} : { diagnostic }),
50
+ ...(Object.keys(details).length === 0 ? {} : { details }),
51
+ };
52
+ }