@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.
Files changed (142) hide show
  1. package/README.md +4 -1
  2. package/README.zh-CN.md +1 -1
  3. package/dist/acp-host/production-host.js +18477 -8099
  4. package/dist/analyst-gate-cycles-read.js +387 -0
  5. package/dist/archivist-record-entry.js +22 -1
  6. package/dist/audit-escalation.js +6 -0
  7. package/dist/auditor-soul.js +74 -0
  8. package/dist/collector-config.js +86 -0
  9. package/dist/collector-evidence.js +316 -0
  10. package/dist/collector-github.js +527 -0
  11. package/dist/collector-ledger.js +853 -0
  12. package/dist/collector-tool-schemas.js +33 -0
  13. package/dist/compliance-transport.js +104 -52
  14. package/dist/diarist-contracts.js +72 -0
  15. package/dist/diarist-mechanical.js +411 -0
  16. package/dist/diarist-ticket-resolution.js +177 -0
  17. package/dist/diarist.js +311 -0
  18. package/dist/doctor-auditor.js +25 -0
  19. package/dist/doctor-contracts.js +2 -0
  20. package/dist/doctor-evidence.js +142 -0
  21. package/dist/gatekeeper-role.js +104 -81
  22. package/dist/host-transition-prior-native.js +78 -0
  23. package/dist/institutional-resolution.js +1 -95
  24. package/dist/judge-auditor.js +26 -0
  25. package/dist/ledger-session-read.js +227 -0
  26. package/dist/merger-git-state.js +78 -0
  27. package/dist/navigator-attendance.js +15 -7
  28. package/dist/navigator-public-session.js +170 -0
  29. package/dist/navigator-session-contracts.js +36 -40
  30. package/dist/notary-source-run.js +122 -0
  31. package/dist/package-contracts/auditor-output.js +66 -0
  32. package/dist/package-contracts/evidence-child-output.js +34 -0
  33. package/dist/package-contracts/judge-output.js +2 -0
  34. package/dist/package-contracts/terminating-tools.js +44 -3
  35. package/dist/package-resources/method-skill.js +254 -0
  36. package/dist/packaged-role-registry.js +56 -0
  37. package/dist/pi/durable-principal.js +61 -0
  38. package/dist/pi/in-process-session.js +25 -6
  39. package/dist/pi/known-failure.js +52 -0
  40. package/dist/pi/role-turn-host.js +430 -0
  41. package/dist/public-cli/auto-resume.js +414 -0
  42. package/dist/public-cli/cli-errors.js +8 -0
  43. package/dist/public-cli/cli-io.js +1 -0
  44. package/dist/public-cli/command-renderer.js +5 -0
  45. package/dist/public-cli/doctor-run.js +84 -0
  46. package/dist/public-cli/inspector-run.js +136 -0
  47. package/dist/public-cli/instruction-seat-run.js +256 -0
  48. package/dist/public-cli/invocation.js +2225 -0
  49. package/dist/public-cli/judge-run.js +118 -0
  50. package/dist/public-cli/load-production-acp-host.js +40 -0
  51. package/dist/public-cli/main.js +1511 -1124
  52. package/dist/public-cli/notary-run.js +161 -0
  53. package/dist/public-cli/option-definitions.js +1192 -0
  54. package/dist/public-cli/post-admission.js +667 -0
  55. package/dist/public-cli/public-run-credentials.js +49 -0
  56. package/dist/public-cli/registry.js +8 -2
  57. package/dist/public-cli/reviewer-dispatch-rejection.js +77 -0
  58. package/dist/public-cli/run-lifecycle.js +1344 -0
  59. package/dist/public-cli/seat-ticket-binding.js +113 -0
  60. package/dist/public-cli/settlement.js +3441 -0
  61. package/dist/public-cli/terminal.js +135 -0
  62. package/dist/public-cli/turn-request.js +25 -0
  63. package/dist/public-role-summons.js +301 -0
  64. package/dist/receipt-delivery-policy.js +10 -0
  65. package/dist/reviewer-child-executor.js +80 -8
  66. package/dist/reviewer-execution-ledger.js +2 -1
  67. package/dist/run-terminal-artifacts.js +195 -0
  68. package/dist/run-ticket-number.js +40 -0
  69. package/dist/session-assistant-usage.js +107 -0
  70. package/dist/shape-unreadable-failure.js +34 -0
  71. package/dist/submission-errors.js +3 -0
  72. package/dist/submission-ledger.js +388 -0
  73. package/dist/ticket-provenance-contracts.js +115 -0
  74. package/dist/ticket-provenance.js +340 -0
  75. package/extensions/role-runtime.ts +8 -0
  76. package/package.json +1 -1
  77. package/resources/diarist-collect.md +6 -10
  78. package/scripts/build-package.mjs +2 -1
  79. package/souls/diarist.md +9 -0
  80. package/souls/doctor-auditor.md +1 -0
  81. package/souls/evidence-child.md +1 -0
  82. package/src/acp-host/production-host.ts +4 -0
  83. package/src/acp-host/role-envelope.ts +4 -3
  84. package/src/acp-host/role-turn-host.ts +9 -1
  85. package/src/analyst-gate-cycles-read.ts +37 -2
  86. package/src/archivist-record-entry.ts +45 -1
  87. package/src/audit-escalation.ts +17 -0
  88. package/src/auditor-role.ts +22 -0
  89. package/src/auditor-soul.ts +42 -0
  90. package/src/compliance-transport.ts +177 -66
  91. package/src/diarist-contracts.ts +88 -0
  92. package/src/diarist-role.ts +60 -0
  93. package/src/diarist.ts +253 -179
  94. package/src/doctor-auditor.ts +10 -14
  95. package/src/doctor-contracts.ts +1 -0
  96. package/src/doctor-role.ts +2 -2
  97. package/src/evidence-child-role.ts +22 -0
  98. package/src/gatekeeper-pass-envelope.ts +109 -0
  99. package/src/gatekeeper-role.ts +145 -104
  100. package/src/host-contracts.ts +15 -2
  101. package/src/institutional-resolution.ts +8 -163
  102. package/src/judge-auditor.ts +10 -15
  103. package/src/judge-role.ts +8 -0
  104. package/src/navigator-attendance.ts +25 -9
  105. package/src/navigator-public-session.ts +217 -0
  106. package/src/navigator-session-contracts.ts +61 -54
  107. package/src/notary-source-run.ts +3 -1
  108. package/src/package-contracts/auditor-output.ts +82 -0
  109. package/src/package-contracts/evidence-child-output.ts +51 -0
  110. package/src/package-contracts/judge-output.ts +1 -0
  111. package/src/package-contracts/reviewer-output.ts +2 -2
  112. package/src/package-contracts/terminating-tools.ts +53 -3
  113. package/src/packaged-role-registry.ts +63 -0
  114. package/src/pi/adapter.ts +2 -1
  115. package/src/pi/in-process-session.ts +38 -12
  116. package/src/pi/role-turn-host.ts +42 -0
  117. package/src/public-cli/cli.ts +43 -6
  118. package/src/public-cli/countersign-run.ts +9 -129
  119. package/src/public-cli/diarist-run.ts +312 -0
  120. package/src/public-cli/instruction-seat-run.ts +289 -50
  121. package/src/public-cli/invocation.ts +87 -25
  122. package/src/public-cli/option-definitions.ts +79 -0
  123. package/src/public-cli/post-admission.ts +9 -3
  124. package/src/public-cli/registry.ts +7 -1
  125. package/src/public-cli/run-lifecycle.ts +53 -6
  126. package/src/public-cli/settlement.ts +170 -7
  127. package/src/public-cli/terminal.ts +4 -1
  128. package/src/public-role-summons.ts +431 -0
  129. package/src/receipt-delivery-policy.ts +10 -0
  130. package/src/reviewer-agent.ts +1 -1
  131. package/src/reviewer-child-executor.ts +114 -12
  132. package/src/reviewer-execution-ledger.ts +3 -2
  133. package/src/role-runtime.ts +275 -23
  134. package/src/session-assistant-usage.ts +119 -0
  135. package/src/session-opening-materials.ts +1 -1
  136. package/src/shape-unreadable-failure.ts +49 -0
  137. package/src/submission-errors.ts +3 -0
  138. package/src/ticket-provenance-contracts.ts +1 -0
  139. package/src/ticket-provenance.ts +0 -23
  140. package/dist/evidence-child-executor.js +0 -829
  141. package/src/diarist-llm-collector.ts +0 -324
  142. package/src/evidence-child-executor.ts +0 -1140
@@ -10,13 +10,16 @@ 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";
16
18
  import { GLEANER_LEFT_ACCEPTED_TEXT, GLEANER_LEFT_OUTPUT_TOOL_NAME, validateRecordedGleanerLeftOutput } from "../gleaner-left-contracts.js";
17
19
  import { INSPECTOR_ACCEPTED_TEXT, INSPECTOR_OUTPUT_TOOL_NAME, validateRecordedInspectorOutput } from "../inspector-contracts.js";
20
+ import { DIARIST_ACCEPTED_TEXT, DIARIST_OUTPUT_TOOL_NAME, validateRecordedDiaristOutput } from "../diarist-contracts.js";
18
21
  import { CODER_ACCEPTED_TEXT, CODER_OUTPUT_TOOL_NAME, FIXER_ACCEPTED_TEXT, FIXER_OUTPUT_TOOL_NAME, validateAcceptedWorkerDetails, } from "./worker-output.js";
19
- 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, };
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, };
20
23
  export const TERMINATING_TOOL_NAMES = [
21
24
  CODER_OUTPUT_TOOL_NAME,
22
25
  FIXER_OUTPUT_TOOL_NAME,
@@ -31,6 +34,9 @@ export const TERMINATING_TOOL_NAMES = [
31
34
  INSPECTOR_OUTPUT_TOOL_NAME,
32
35
  GATEKEEPER_OUTPUT_TOOL_NAME,
33
36
  NAVIGATOR_OUTPUT_TOOL_NAME,
37
+ AUDITOR_OUTPUT_TOOL_NAME,
38
+ EVIDENCE_CHILD_OUTPUT_TOOL_NAME,
39
+ DIARIST_OUTPUT_TOOL_NAME,
34
40
  ];
35
41
  export function isTerminatingToolName(name) {
36
42
  return TERMINATING_TOOL_NAMES.includes(name);
@@ -63,6 +69,12 @@ export function acceptedTextFor(toolName) {
63
69
  return GATEKEEPER_ACCEPTED_TEXT;
64
70
  case NAVIGATOR_OUTPUT_TOOL_NAME:
65
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;
76
+ case DIARIST_OUTPUT_TOOL_NAME:
77
+ return DIARIST_ACCEPTED_TEXT;
66
78
  }
67
79
  }
68
80
  export class AcceptedDetailsContractError extends CorrectableSubmissionError {
@@ -114,13 +126,21 @@ export function validateAcceptedDetails(toolName, details) {
114
126
  [INSPECTOR_OUTPUT_TOOL_NAME]: ["pass", "bounce"],
115
127
  [GATEKEEPER_OUTPUT_TOOL_NAME]: ["dispatch", "pass"],
116
128
  [NAVIGATOR_OUTPUT_TOOL_NAME]: ["advice"],
129
+ [AUDITOR_OUTPUT_TOOL_NAME]: ["pass", "revise", "escalate"],
130
+ [EVIDENCE_CHILD_OUTPUT_TOOL_NAME]: [],
131
+ [DIARIST_OUTPUT_TOOL_NAME]: ["completed"],
117
132
  };
118
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);
119
139
  const baseDiscriminator = discriminator;
120
140
  const runtimeBindingMissing = (toolName === DOCTOR_OUTPUT_TOOL_NAME && baseDiscriminator === "completed" && !(candidate?.cost !== null && typeof candidate?.cost === "object")) ||
121
141
  (toolName === REVIEWER_OUTPUT_TOOL_NAME && candidate?.version !== 2);
122
142
  if (runtimeBindingMissing ||
123
- (!collectorDiscriminator && (typeof discriminator !== "string" || !lawfulStatuses[toolName].includes(baseDiscriminator)))) {
143
+ (!collectorDiscriminator && !evidenceChildDiscriminator && (typeof discriminator !== "string" || !lawfulStatuses[toolName].includes(baseDiscriminator)))) {
124
144
  throw new AcceptedDetailsContractError("terminating receipt has no recognized execution discriminator");
125
145
  }
126
146
  try {
@@ -151,6 +171,12 @@ export function validateAcceptedDetails(toolName, details) {
151
171
  return validateRecordedGatekeeperOutput(details);
152
172
  case NAVIGATOR_OUTPUT_TOOL_NAME:
153
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);
178
+ case DIARIST_OUTPUT_TOOL_NAME:
179
+ return validateRecordedDiaristOutput(details);
154
180
  }
155
181
  }
156
182
  catch (error) {
@@ -177,6 +203,16 @@ export function validateAcceptedLifecycle(toolName, argumentsValue, detailsValue
177
203
  throw new Error("accepted tool lifecycle details mismatch");
178
204
  return details;
179
205
  }
206
+ if (toolName === DIARIST_OUTPUT_TOOL_NAME) {
207
+ // Envelope-owned mechanical sitian facts are runtime-bound on details only
208
+ // (same shape as the Doctor runtime cost); the submitted arguments carry the
209
+ // role's own selections. Machine facts never come from model self-report.
210
+ const { sitian: _mechanical, ...submitted } = details;
211
+ const testimony = validateAcceptedDetails(toolName, argumentsValue);
212
+ if (!deepEqual(testimony, submitted))
213
+ throw new Error("accepted tool lifecycle details mismatch");
214
+ return details;
215
+ }
180
216
  const argumentsDetails = validateAcceptedDetails(toolName, argumentsValue);
181
217
  if (!deepEqual(argumentsDetails, details))
182
218
  throw new Error("accepted tool lifecycle details mismatch");
@@ -192,7 +228,12 @@ export function acceptedFacts(toolName, details) {
192
228
  case GLEANER_LEFT_OUTPUT_TOOL_NAME:
193
229
  case INSPECTOR_OUTPUT_TOOL_NAME:
194
230
  case GATEKEEPER_OUTPUT_TOOL_NAME:
195
- case NAVIGATOR_OUTPUT_TOOL_NAME: return { status: details.status };
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" };
236
+ case DIARIST_OUTPUT_TOOL_NAME: return { status: details.status };
196
237
  case JUDGE_OUTPUT_TOOL_NAME: return { status: details.judgeStatus };
197
238
  case COUNTERSIGN_OUTPUT_TOOL_NAME: return { status: details.countersignStatus };
198
239
  case MERGER_OUTPUT_TOOL_NAME: {
@@ -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,12 @@ 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";
15
+ import {
16
+ DIARIST_OUTPUT_TOOL_NAME,
17
+ DIARIST_SOURCES_FLAG
18
+ } from "./diarist-contracts.js";
13
19
  const NOTARY_SESSION_MATERIALS = [
14
20
  "CLAUDE.md",
15
21
  "souls/notary.md",
@@ -23,6 +29,19 @@ const INSPECTOR_SESSION_MATERIALS = [
23
29
  "souls/quality-law.md",
24
30
  "souls/gate-output-guide.md"
25
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
+ ];
26
45
  const PUBLIC_ROLE_RECORDS = [
27
46
  {
28
47
  role: "judge",
@@ -175,6 +194,41 @@ const PUBLIC_ROLE_RECORDS = [
175
194
  phaseFlag: void 0,
176
195
  activationStage: "load-and-install",
177
196
  sessionMaterials: ["CLAUDE.md", "souls/navigator.md"]
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
+ },
217
+ // #708 / ADR 0075 `diarist-is-role`: 起居郎 is a seat like any other. The
218
+ // frozen source catalog rides the shared input-flag seam; it is absent for a
219
+ // true-unbound summons (no ticket → no diary).
220
+ {
221
+ role: "diarist",
222
+ phases: [null],
223
+ outputTool: DIARIST_OUTPUT_TOOL_NAME,
224
+ inputFlag: DIARIST_SOURCES_FLAG.name,
225
+ phaseFlag: void 0,
226
+ activationStage: "load-and-install",
227
+ sessionMaterials: [
228
+ "CLAUDE.md",
229
+ "souls/diarist.md",
230
+ "resources/diarist-collect.md"
231
+ ]
178
232
  }
179
233
  ];
180
234
  const PACKAGED_ROLE_REGISTRY = PUBLIC_ROLE_RECORDS.map(({ sessionMaterials: _omit, ...metadata }) => metadata);
@@ -191,6 +245,8 @@ function packagedRoleOutputTool(role) {
191
245
  return packagedRoleMetadata(role)?.outputTool;
192
246
  }
193
247
  export {
248
+ AUDITOR_PUBLIC_SESSION_MATERIALS,
249
+ EVIDENCE_CHILD_SESSION_MATERIALS,
194
250
  INSPECTOR_SESSION_MATERIALS,
195
251
  NOTARY_SESSION_MATERIALS,
196
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
+ }