@akagilnc/pi-workflow-roles 0.1.5153 → 0.1.5196

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 (52) hide show
  1. package/README.md +2 -2
  2. package/README.zh-CN.md +2 -2
  3. package/dist/acp-host/production-host.js +13086 -13034
  4. package/dist/archivist-record-entry.js +4 -20
  5. package/dist/archivist-record-pointer.js +28 -0
  6. package/dist/audit-escalation.js +3 -119
  7. package/dist/auditor-soul.js +32 -0
  8. package/dist/doctor-auditor.js +26 -0
  9. package/dist/headless-host/production-host.js +11218 -11166
  10. package/dist/judge-role.js +73 -0
  11. package/dist/migrate-book-topology.js +8 -0
  12. package/dist/package-contracts/judge-output.js +1 -18
  13. package/dist/package-contracts/terminating-tools.js +2 -2
  14. package/dist/public-cli/cli.js +2 -2
  15. package/dist/public-cli/countersign-run.js +11 -0
  16. package/dist/public-cli/instruction-seat-run.js +428 -48
  17. package/dist/public-cli/invocation.js +10 -5
  18. package/dist/public-cli/main.js +10049 -8911
  19. package/dist/public-cli/settlement.js +28 -8
  20. package/dist/public-role-summons.js +6 -4
  21. package/dist/submission-errors.js +1 -1
  22. package/dist/submission-gate.js +165 -0
  23. package/dist/submission-ledger.js +0 -27
  24. package/dist/worker-submission-contracts.js +8 -0
  25. package/package.json +1 -1
  26. package/src/archivist-record-entry.ts +5 -49
  27. package/src/archivist-record-pointer.ts +49 -0
  28. package/src/audit-escalation.ts +4 -217
  29. package/src/auditor-soul.ts +33 -0
  30. package/src/doctor-role.ts +11 -5
  31. package/src/gatekeeper-role.ts +2 -2
  32. package/src/host-contracts.ts +0 -25
  33. package/src/judge-role.ts +63 -90
  34. package/src/package-contracts/judge-output.ts +0 -17
  35. package/src/package-contracts/terminating-tools.ts +0 -2
  36. package/src/pi/adapter.ts +1 -33
  37. package/src/public-cli/cli.ts +2 -2
  38. package/src/public-cli/countersign-run.ts +11 -0
  39. package/src/public-cli/instruction-seat-run.ts +433 -16
  40. package/src/public-cli/invocation.ts +9 -3
  41. package/src/public-cli/post-admission.ts +0 -1
  42. package/src/public-cli/settlement.ts +32 -8
  43. package/src/public-role-summons.ts +9 -6
  44. package/src/role-envelope.ts +0 -32
  45. package/src/role-runtime-dependencies.ts +0 -4
  46. package/src/role-runtime.ts +15 -218
  47. package/src/submission-errors.ts +1 -1
  48. package/src/submission-gate.ts +46 -10
  49. package/src/submission-ledger.ts +0 -27
  50. package/src/worker-role.ts +23 -102
  51. package/src/worker-submission-contracts.ts +8 -0
  52. package/src/worker-submission-gates.ts +2 -2
@@ -3,18 +3,18 @@
3
3
  * Owns officer-pointer book + host abort/non-pass faces + review queue loop.
4
4
  * Role modules only project via projectGatekeeperRun / runGatekeeper — no book, no catch.
5
5
  *
6
- * Queue guarantee only (#753 / #756 / #750):
7
- * parent submit → summon officer → read conclusion field
8
- * converged → accept end
9
- * continue → raw officer receipt as a nonterminal result; parent may resubmit
10
- * escalate → audit_escalation terminal, without binding a correctable parent submission
6
+ * Public continuation after submission settlement (#753 / #756 / #750):
7
+ * accepted submission → summon officer → read conclusion field
8
+ * converged → continue remaining review and settle
9
+ * continue → raw officer receipt; caller resumes the submitted seat for revision
10
+ * escalate → return the officer run so the caller can resume that officer directly
11
11
  * unrecognized status → resume officer with plain-language re-ask (no round cap)
12
12
  * transport / no_receipt → present honestly
13
13
  * Four pairs: countersign↔notary, judge↔auditor, worker↔inspector, secretariat↔countersign (#969).
14
14
  * Code does not judge content, map next-step for parent, or label unreadable/unusable.
15
15
  */
16
16
  import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
17
- import { bookDirectOfficerRunPointer } from "./archivist-record-entry.ts";
17
+ import { bookDirectOfficerRunPointer } from "./archivist-record-pointer.ts";
18
18
  import type { HostContext, RoleTurnHost } from "./host-contracts.ts";
19
19
  import {
20
20
  GatekeeperDecisionError,
@@ -27,7 +27,31 @@ import {
27
27
  type GateOfficerSummon,
28
28
  } from "./gatekeeper-role.ts";
29
29
  import type { PublicSummonResult } from "./public-role-summons.ts";
30
+ import type { TerminalResult } from "./public-cli/terminal.ts";
30
31
 
32
+ /** Queue word of the latest this-terminal payload. History does not outrank it. */
33
+ export function latestQueueStatus(terminal: TerminalResult | undefined): string | undefined {
34
+ const outcome = terminal?.roleOutcome;
35
+ if (outcome === undefined) return undefined;
36
+ if (outcome.kind === "audit_escalation") return "escalate";
37
+ if (outcome.kind !== "accepted") return undefined;
38
+ const latest = outcome.payloads?.[outcome.payloads.length - 1];
39
+ if (latest !== null && typeof latest === "object" && !Array.isArray(latest)) {
40
+ const status = (latest as { status?: unknown }).status;
41
+ if (typeof status === "string" && status.trim() !== "") return status;
42
+ }
43
+ return typeof outcome.status === "string" && outcome.status.trim() !== ""
44
+ ? outcome.status
45
+ : undefined;
46
+ }
47
+
48
+ export function latestQueuePayload(terminal: TerminalResult | undefined): unknown {
49
+ const outcome = terminal?.roleOutcome;
50
+ if (outcome === undefined) return undefined;
51
+ if (outcome.kind !== "accepted" && outcome.kind !== "audit_escalation") return undefined;
52
+ const payloads = outcome.payloads ?? [];
53
+ return payloads.length === 0 ? undefined : payloads[payloads.length - 1];
54
+ }
31
55
  import { sessionFileFromPublicSummon } from "./session-assistant-usage.ts";
32
56
 
33
57
  /**
@@ -38,6 +62,7 @@ export function createDefaultGateOfficerSummon(options: {
38
62
  readonly cwd: string;
39
63
  readonly home?: string;
40
64
  readonly packageRoot?: string;
65
+ readonly io?: import("./public-cli/cli-io.ts").CliIo;
41
66
  readonly roleTurnHost?: RoleTurnHost;
42
67
  /** Composition-root adapters for nested court stations (tests / #969). */
43
68
  readonly hostAdapters?: readonly import("./public-cli/role-turn-host-resolution.ts").NamedRoleTurnHostAdapter[];
@@ -54,6 +79,7 @@ export function createDefaultGateOfficerSummon(options: {
54
79
  ...(submission === undefined ? {} : { submission }),
55
80
  ...(options.home === undefined ? {} : { home: options.home }),
56
81
  ...(options.packageRoot === undefined ? {} : { packageRoot: options.packageRoot }),
82
+ ...(options.io === undefined ? {} : { io: options.io }),
57
83
  ...(options.roleTurnHost === undefined ? {} : { roleTurnHost: options.roleTurnHost }),
58
84
  ...(options.hostAdapters === undefined ? {} : { hostAdapters: options.hostAdapters }),
59
85
  ...(options.createRunId === undefined ? {} : { createRunId: options.createRunId }),
@@ -103,10 +129,11 @@ function bookDirectOfficerPointer(
103
129
  * public terminal without a second authority.
104
130
  */
105
131
  export type SubmissionGateOutcome = {
106
- readonly status: "converged" | "continue";
132
+ readonly status: "converged" | "continue" | "escalate";
107
133
  readonly officer: GateOfficer;
108
134
  readonly receipt: unknown;
109
135
  readonly runId?: string;
136
+ readonly runDirectory?: string;
110
137
  };
111
138
 
112
139
  /**
@@ -189,10 +216,19 @@ export async function requireSubmissionGate(options: {
189
216
  });
190
217
  options.hostActions.failInfrastructure(failure, options.context, options.toolCallId);
191
218
  }
192
- // Escalation ends the parent without a correctable tool error or resubmission.
193
- // Each caller projects the existing audit_escalation terminal.
194
219
  if (gatekeeper.status === "escalate") {
195
- throw new GatekeeperDecisionError(gatekeeper);
220
+ return {
221
+ status: "escalate",
222
+ officer: projected.officer,
223
+ receipt: gatekeeper.receipt,
224
+ ...(typeof gatekeeper.runId === "string" && gatekeeper.runId.trim() !== ""
225
+ ? { runId: gatekeeper.runId }
226
+ : {}),
227
+ ...(typeof projected.summoned?.runDirectory === "string"
228
+ && projected.summoned.runDirectory.trim() !== ""
229
+ ? { runDirectory: projected.summoned.runDirectory }
230
+ : {}),
231
+ };
196
232
  }
197
233
  // no_receipt: keep the lifecycle failure channel; continue is an ordinary
198
234
  // nonterminal tool result above, not an exception or correctable rejection.
@@ -11,7 +11,6 @@ import {
11
11
  type HostToolResult,
12
12
  type RoleHost,
13
13
  } from "./host-contracts.ts";
14
- import { isAuditEscalationProjection } from "./audit-escalation.ts";
15
14
 
16
15
 
17
16
  import { runIdFromRunDirectory } from "./run-terminal-artifacts.ts";
@@ -730,32 +729,6 @@ export function createSubmissionLedgerHost(
730
729
  }
731
730
  // #836: ledger authority is the LLM tool-call params as-is (角色原话), never result.details.
732
731
  // Machine facts on result.details stay on the tool-result face returned to the model.
733
- if (isAuditEscalationProjection(result.details) || isAuditEscalationProjection(params)) {
734
- const audit = isAuditEscalationProjection(result.details)
735
- && typeof result.details.audit === "object"
736
- && result.details.audit !== null
737
- ? result.details.audit as Record<string, unknown>
738
- : undefined;
739
- const closed: ClosedSubmission = {
740
- role,
741
- kind: "audit_escalation",
742
- accepted: params,
743
- };
744
- append({
745
- type: "outcome",
746
- attemptId,
747
- toolCallId,
748
- outcome: "audit-escalation",
749
- role,
750
- accepted: params,
751
- ...(audit !== undefined && (Object.hasOwn(audit, "receipt") || Object.hasOwn(audit, "conflicts"))
752
- ? { auditReceipt: Object.hasOwn(audit, "receipt") ? audit.receipt : audit.conflicts }
753
- : {}),
754
- ...(audit !== undefined && Object.hasOwn(audit, "officer") ? { auditOfficer: audit.officer } : {}),
755
- });
756
- await projectClosure(closed, context);
757
- return result;
758
- }
759
732
  // A continuing gate leaves the candidate recorded but has not accepted it.
760
733
  if (result.terminate === false) return result;
761
734
  const closed: ClosedSubmission = {
@@ -3,9 +3,6 @@ import { Type, type Static } from "typebox";
3
3
  import { openToolObjectFromUnion } from "./open-tool-schema.ts";
4
4
  import { withTerminatingOutputDeclarations } from "./package-contracts/terminating-infrastructure.ts";
5
5
 
6
- import { readableGateItem } from "./readable-gate-item.ts";
7
- import { projectGatekeeperEscalation } from "./audit-escalation.ts";
8
- import { GatekeeperDecisionError, ParentQueueReaskError, unreadableDiscriminatorNotice } from "./submission-errors.ts";
9
6
  import {
10
7
  CODER_OUTPUT_TOOL_NAME,
11
8
  FIXER_OUTPUT_TOOL_NAME,
@@ -23,7 +20,6 @@ import {
23
20
  } from "./package-contracts/fixer-packet.ts";
24
21
  import {
25
22
  createWorkerSubmissionGate,
26
- WORKER_DONE_STATUSES,
27
23
  WorkerCommitReminderError,
28
24
  WorkerPrefixReminderError,
29
25
  WorkerUnfinishedReasonReminderError,
@@ -127,15 +123,6 @@ function isRecord(value: unknown): value is Record<string, unknown> {
127
123
  return typeof value === "object" && value !== null && !Array.isArray(value);
128
124
  }
129
125
 
130
- /** Routing words shared by Coder and Fixer; provider schemas remain open. */
131
- const WORKER_ROUTING_STATUSES = new Set([
132
- "planned",
133
- "completed",
134
- "refused",
135
- "partially_completed",
136
- "unfinished",
137
- ]);
138
-
139
126
  /** Read only the field that selects the worker's next package-owned path. */
140
127
  function workerStatusOf(output: WorkerOutput): string | undefined {
141
128
  return isRecord(output) && typeof output.status === "string"
@@ -143,14 +130,6 @@ function workerStatusOf(output: WorkerOutput): string | undefined {
143
130
  : undefined;
144
131
  }
145
132
 
146
- function requireReadableWorkerStatus(output: WorkerOutput): string {
147
- const status = workerStatusOf(output);
148
- if (status === undefined || !WORKER_ROUTING_STATUSES.has(status)) {
149
- throw new ParentQueueReaskError(unreadableDiscriminatorNotice("status", isRecord(output) ? output.status : undefined));
150
- }
151
- return status;
152
- }
153
-
154
133
  function deepFreeze<T>(value: T): T {
155
134
  if (typeof value !== "object" || value === null || Object.isFrozen(value)) return value;
156
135
  for (const child of Object.values(value)) deepFreeze(child);
@@ -262,47 +241,18 @@ export function createFixerRoleRuntime(
262
241
  throw new Error("修内司修理包与阶段未装载");
263
242
  }
264
243
  const output = deepFreeze(validateFixerOutput(parameters, phase));
265
- const status = requireReadableWorkerStatus(output);
266
- assertAcceptableThroughHost(
267
- submissionGate,
268
- status,
269
- output,
270
- hostActions,
271
- ctx,
272
- toolCallId,
273
- );
274
- let pass;
275
- try {
276
- pass = WORKER_DONE_STATUSES.has(status)
277
- ? await pi.requireSubmissionGate!({
278
- context: ctx,
279
- subject: { kind: "worker_completion" },
280
- ...(_signal === undefined ? {} : { signal: _signal }),
281
- hostActions,
282
- toolCallId,
283
- // #879: this-turn typed payload — identity-bound at submit site.
284
- submission: output,
285
- })
286
- : undefined;
287
- } catch (error) {
288
- if (error instanceof GatekeeperDecisionError && error.result.status === "escalate") {
289
- return projectGatekeeperEscalation(error.result, output);
290
- }
291
- throw error;
292
- }
293
- if (pass?.status === "continue") {
294
- return {
295
- content: [{ type: "text" as const, text: readableGateItem(pass.receipt) }],
296
- details: output,
297
- terminate: false,
298
- };
244
+ const status = workerStatusOf(output);
245
+ if (status !== undefined) {
246
+ assertAcceptableThroughHost(
247
+ submissionGate,
248
+ status,
249
+ output,
250
+ hostActions,
251
+ ctx,
252
+ toolCallId,
253
+ );
299
254
  }
300
- const acceptedDetails = output;
301
- return {
302
- content: pass === undefined ? [] : [{ type: "text" as const, text: readableGateItem(pass.receipt) }],
303
- details: acceptedDetails,
304
- terminate: true as const,
305
- };
255
+ return { content: [], details: output, terminate: true as const };
306
256
  },
307
257
  });
308
258
  pi.on("tool_call", (event) => {
@@ -389,49 +339,20 @@ export function createCoderRoleRuntime(
389
339
  throw new Error("将作监任务与阶段未装载");
390
340
  }
391
341
  const output = validateWorkerOutput(parameters, phase, "Coder");
392
- const status = requireReadableWorkerStatus(output);
342
+ const status = workerStatusOf(output);
393
343
  // #836: skill-expansion evidence rejection deleted (陛下「2.4/5 删」).
394
- // Missing method Skills do not reject a receipt.
395
- assertAcceptableThroughHost(
396
- submissionGate,
397
- status,
398
- output,
399
- hostActions,
400
- ctx,
401
- toolCallId,
402
- );
403
- let pass;
404
- try {
405
- pass = WORKER_DONE_STATUSES.has(status)
406
- ? await pi.requireSubmissionGate!({
407
- context: ctx,
408
- subject: { kind: "worker_completion" },
409
- ...(_signal === undefined ? {} : { signal: _signal }),
410
- hostActions,
411
- toolCallId,
412
- // #879: this-turn typed payload — identity-bound at submit site.
413
- submission: output,
414
- })
415
- : undefined;
416
- } catch (error) {
417
- if (error instanceof GatekeeperDecisionError && error.result.status === "escalate") {
418
- return projectGatekeeperEscalation(error.result, output);
419
- }
420
- throw error;
421
- }
422
- if (pass?.status === "continue") {
423
- return {
424
- content: [{ type: "text" as const, text: readableGateItem(pass.receipt) }],
425
- details: output,
426
- terminate: false,
427
- };
344
+ // Skill still ships with the package (ADR 0052); code no longer refuses on it.
345
+ if (status !== undefined) {
346
+ assertAcceptableThroughHost(
347
+ submissionGate,
348
+ status,
349
+ output,
350
+ hostActions,
351
+ ctx,
352
+ toolCallId,
353
+ );
428
354
  }
429
- const acceptedDetails = output;
430
- return {
431
- content: pass === undefined ? [] : [{ type: "text" as const, text: readableGateItem(pass.receipt) }],
432
- details: acceptedDetails,
433
- terminate: true as const,
434
- };
355
+ return { content: [], details: output, terminate: true as const };
435
356
  },
436
357
  });
437
358
  pi.on("before_agent_start", (event, ctx) => {
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Statuses that enter the worker officer submission gate (ADR 0066):
3
+ * completed/partially_completed enter gate ①; planned/refused/unfinished do not.
4
+ */
5
+ export const WORKER_DONE_STATUSES: ReadonlySet<string> = new Set([
6
+ "completed",
7
+ "partially_completed",
8
+ ]);
@@ -15,16 +15,16 @@ import {
15
15
  WorkerPrefixReminderError,
16
16
  WorkerUnfinishedReasonReminderError,
17
17
  } from "./submission-errors.ts";
18
+ import { WORKER_DONE_STATUSES } from "./worker-submission-contracts.ts";
18
19
 
19
20
  export { WorkerCommitReminderError, WorkerPrefixReminderError, WorkerUnfinishedReasonReminderError } from "./submission-errors.ts";
21
+ export { WORKER_DONE_STATUSES } from "./worker-submission-contracts.ts";
20
22
 
21
23
  export const WORKER_SUBMISSION_GATE_RECORD_KIND = WORKER_SUBMISSION_GATE_KIND;
22
24
  export const WORKER_COMMIT_BASELINE_ENTRY_TYPE = "commit-baseline";
23
25
  export const WORKER_COMMIT_REMINDER_BOUNCE_ENTRY_TYPE = "commit-reminder-bounce";
24
26
  export const WORKER_PREFIX_REMINDER_BOUNCE_ENTRY_TYPE = "prefix-reminder-bounce";
25
27
 
26
- /** Statuses that enter the officer submission gate (ADR 0066: completed/partially_completed 进闸①;planned/refused/unfinished 零 commit 合法). */
27
- export const WORKER_DONE_STATUSES: ReadonlySet<string> = new Set(["completed", "partially_completed"]);
28
28
  /** Historical package hook ownership marker — uninstall criterion only. */
29
29
  const HOOK_MARKER = "ak-roles: worker-submission-gates reference-transaction";
30
30
  const HOOKS_DIR = "ak-roles-hooks";