@akagilnc/pi-workflow-roles 0.1.2521 → 0.1.2653-next.71811ca

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 (109) hide show
  1. package/README.md +129 -39
  2. package/README.zh-CN.md +128 -39
  3. package/dist/activation-ledger-topology.js +1 -1
  4. package/dist/archivist-record-entry.js +47 -26
  5. package/dist/auditor-dossier-tool.js +3 -1
  6. package/dist/compliance-transport.js +17 -26
  7. package/dist/doctor-contracts.js +1 -2
  8. package/dist/dossier-resolution.js +4 -8
  9. package/dist/engine-detour-tool.js +33 -8
  10. package/dist/engine-detour.js +1 -0
  11. package/dist/evidence-child-executor.js +277 -424
  12. package/dist/host-contracts.js +22 -0
  13. package/dist/institutional-resolution.js +88 -0
  14. package/dist/merger-contracts.js +1 -2
  15. package/dist/navigator-attendance.js +16 -0
  16. package/dist/notary-contracts.js +2 -3
  17. package/dist/package-contracts/fixer-output.js +1 -2
  18. package/dist/packaged-role-registry.js +102 -9
  19. package/dist/pi/in-process-session.js +671 -0
  20. package/dist/public-cli/config.js +7 -5
  21. package/dist/public-cli/main.js +3767 -4113
  22. package/dist/reviewer-child-executor.js +6 -1
  23. package/dist/session-opening-materials.js +10 -38
  24. package/dist/sitian-appender.js +146 -0
  25. package/dist/sitian-contracts.js +21 -0
  26. package/dist/sitian-facade.js +15 -0
  27. package/dist/sitian-reader.js +52 -0
  28. package/extensions/role-runtime.ts +9 -7
  29. package/package.json +5 -5
  30. package/resources/engines/cursor.md +12 -26
  31. package/resources/engines/hermes.md +2 -23
  32. package/resources/engines/opus.md +1 -16
  33. package/resources/navigator-route-playbook.md +2 -2
  34. package/scripts/build-package.mjs +0 -1
  35. package/souls/quality-law.md +1 -1
  36. package/src/activation-ledger-topology.ts +1 -1
  37. package/src/archivist-record-entry.ts +57 -45
  38. package/src/auditor-dossier-tool.ts +4 -2
  39. package/src/canonical-skill-binding.ts +37 -27
  40. package/src/collector-role.ts +11 -20
  41. package/src/collector-tool-schemas.ts +1 -4
  42. package/src/compliance-transport.ts +19 -44
  43. package/src/doctor-auditor.ts +1 -5
  44. package/src/doctor-contracts.ts +1 -4
  45. package/src/doctor-role.ts +31 -8
  46. package/src/dossier-resolution.ts +8 -8
  47. package/src/engine-detour-tool.ts +48 -19
  48. package/src/engine-detour.ts +3 -0
  49. package/src/evidence-child-executor.ts +277 -485
  50. package/src/factory-board.ts +3 -3
  51. package/src/gatekeeper-role.ts +21 -10
  52. package/src/host-contracts.ts +386 -0
  53. package/src/in-process-session.ts +1 -115
  54. package/src/institutional-resolution.ts +135 -0
  55. package/src/judge-auditor.ts +1 -5
  56. package/src/judge-role.ts +37 -51
  57. package/src/merger-contracts.ts +1 -4
  58. package/src/merger-role.ts +7 -11
  59. package/src/navigator-attendance.ts +20 -1
  60. package/src/notary-contracts.ts +8 -11
  61. package/src/notary-role.ts +7 -23
  62. package/src/notary-source-run.ts +4 -3
  63. package/src/package-contracts/fixer-output.ts +1 -4
  64. package/src/package-resources/method-skill-binding.ts +10 -34
  65. package/src/packaged-role-registry.ts +122 -12
  66. package/src/pi/adapter.ts +192 -0
  67. package/src/pi/durable-principal.ts +98 -0
  68. package/src/pi/in-process-session.ts +819 -0
  69. package/src/pi/known-failure.ts +77 -0
  70. package/src/pi/pi-normalization.ts +284 -0
  71. package/src/pi/role-turn-host.ts +459 -0
  72. package/src/public-cli/auto-resume.ts +42 -44
  73. package/src/public-cli/cli.ts +171 -257
  74. package/src/public-cli/coder-run.ts +115 -433
  75. package/src/public-cli/collector-run.ts +62 -314
  76. package/src/public-cli/config.ts +7 -5
  77. package/src/public-cli/doctor-run.ts +41 -52
  78. package/src/public-cli/fixer-run.ts +122 -427
  79. package/src/public-cli/invocation.ts +287 -96
  80. package/src/public-cli/judge-run.ts +92 -422
  81. package/src/public-cli/merger-run.ts +167 -429
  82. package/src/public-cli/notary-run.ts +41 -47
  83. package/src/public-cli/option-definitions.ts +136 -3
  84. package/src/public-cli/post-admission.ts +497 -0
  85. package/src/public-cli/public-run-credentials.ts +4 -4
  86. package/src/public-cli/reviewer-dispatch-rejection.ts +106 -0
  87. package/src/public-cli/reviewer-run.ts +132 -449
  88. package/src/public-cli/run-lifecycle.ts +339 -327
  89. package/src/public-cli/settlement.ts +251 -134
  90. package/src/public-cli/terminal.ts +3 -9
  91. package/src/public-cli/turn-request.ts +87 -0
  92. package/src/reviewer-child-executor.ts +9 -1
  93. package/src/reviewer-role.ts +11 -20
  94. package/src/role-runtime.ts +129 -78
  95. package/src/session-opening-materials.ts +25 -39
  96. package/src/sitian-appender.ts +171 -0
  97. package/src/sitian-contracts.ts +106 -0
  98. package/src/sitian-facade.ts +18 -0
  99. package/src/sitian-reader.ts +62 -0
  100. package/src/worker-role.ts +42 -40
  101. package/src/worker-submission-gates.ts +33 -0
  102. package/dist/archivist-role-run-coordinates.js +0 -28
  103. package/dist/package-contracts/terminating-infrastructure.js +0 -90
  104. package/resources/engines/sonnet.md +0 -27
  105. package/resources/engines/zcode.md +0 -63
  106. package/src/archivist-role-run-coordinates.ts +0 -45
  107. package/src/package-contracts/terminating-infrastructure.ts +0 -132
  108. package/src/public-cli/explicit-internal.ts +0 -427
  109. package/src/public-cli/one-shot-dispatch.ts +0 -300
@@ -194,7 +194,7 @@ function placeTicket(prepared: PreparedTicket): BoardPlacement {
194
194
  }
195
195
  if (latest.station === "coder") return "coder";
196
196
  if (latest.station === "fixer" || latest.station === "reviewer") return "marshal";
197
- // ADR 0053: marshal-driven runs land in 尚书省 once the seat ships (station maps now).
197
+ // ADR 0053: marshal-driven runs land in 刑部 once the seat ships (station maps now).
198
198
  if (latest.station === "marshal") return "marshal";
199
199
  if (latest.station === "collector") return "collector";
200
200
  return `other:${latest.station}`;
@@ -399,7 +399,7 @@ const YAMEN_LABELS: Readonly<Record<string, string>> = {
399
399
  collector: "通进司",
400
400
  doctor: "太医署",
401
401
  merger: "校书郎",
402
- marshal: "尚书省",
402
+ marshal: "刑部",
403
403
  };
404
404
 
405
405
  function latestKnownStation(runs: readonly TicketTrajectoryRun[]): string | undefined {
@@ -805,7 +805,7 @@ const COLUMN_LABELS: Readonly<Record<string, string>> = {
805
805
  pending: "待发",
806
806
  court: "大理寺 · 审票",
807
807
  coder: "将作监",
808
- marshal: "尚书省",
808
+ marshal: "刑部",
809
809
  collector: "通进司",
810
810
  done: "已完成",
811
811
  };
@@ -1,7 +1,8 @@
1
1
  import { Type } from "typebox";
2
2
  import type { ExtensionContext } from "@earendil-works/pi-coding-agent";
3
+ import type { HostContext } from "./host-contracts.ts";
3
4
 
4
- import { executeAuditorChild, type AuditorCompletion, type AuditorDecisionTool } from "./evidence-child-executor.ts";
5
+ import { executeAuditorChild, type AuditorDecisionTool } from "./evidence-child-executor.ts";
5
6
  import { openToolObject } from "./open-tool-schema.ts";
6
7
  import type { NoReceiptLifecycleFacts } from "./receipt-delivery-policy.ts";
7
8
  import { loadGatekeeperSessionMaterials } from "./session-opening-materials.ts";
@@ -69,17 +70,19 @@ export class GatekeeperDecisionError extends Error {
69
70
  }
70
71
 
71
72
  export type RunGatekeeperOptions = {
72
- readonly context: ExtensionContext;
73
+ readonly context: ExtensionContext | HostContext;
73
74
  readonly subject: GatekeeperSubject;
74
75
  readonly signal?: AbortSignal;
75
- readonly runCompletion?: AuditorCompletion;
76
76
  readonly loadSoul?: (role: "gatekeeper" | "inspector" | "notary") => Promise<string>;
77
+ /** Run directory carrying the institutional resolution page (#518). Derives
78
+ * from context when absent. */
79
+ readonly runDirectory?: string;
77
80
  };
78
81
 
79
82
  export type GatekeeperPassHostActions = {
80
- failInfrastructure(error: unknown, ctx: ExtensionContext, toolCallId?: string): never;
83
+ failInfrastructure(error: unknown, ctx: ExtensionContext | HostContext, toolCallId?: string): never;
81
84
  /** Envelope-owned execute→tool_result bridge (role-runtime); role module only throws typed error. */
82
- bindGatekeeperNonPass(toolCallId: string, result: GatekeeperNonPassResult): void;
85
+ bindSubmissionNonPass(toolCallId: string, result: GatekeeperNonPassResult): void;
83
86
  };
84
87
 
85
88
  // Unknown fields so wrong types/spellings still reach projection (ADR 0055/0057; 仓第 0 条).
@@ -144,10 +147,18 @@ function asStringArray(value: unknown): readonly string[] {
144
147
  /** Serializable stand-in when the child tool call had no arguments object. */
145
148
  export const MISSING_ARGUMENTS_SUBMISSION = Object.freeze({ missing: "arguments" as const });
146
149
 
150
+ function isRecord(value: unknown): value is Record<string, unknown> {
151
+ return typeof value === "object" && value !== null && !Array.isArray(value);
152
+ }
153
+
147
154
  /** Keep original decision bytes for the next reader; undefined becomes a serializable missing-args fact. */
148
155
  function retainedSubmission(decision: unknown): unknown {
149
156
  // undefined must not be stored: JSON drops it and the missing-args fact vanishes.
150
- return decision === undefined ? MISSING_ARGUMENTS_SUBMISSION : decision;
157
+ // Through the real provider adapter an undefined root argument arrives as an
158
+ // empty object after serialization; that must also project a missing-args fact.
159
+ return decision === undefined || (isRecord(decision) && Object.keys(decision).length === 0)
160
+ ? MISSING_ARGUMENTS_SUBMISSION
161
+ : decision;
151
162
  }
152
163
 
153
164
  /**
@@ -219,7 +230,7 @@ export async function runGatekeeper(options: RunGatekeeperOptions): Promise<Gate
219
230
  tool: createGatekeeperOutputTool(),
220
231
  dossierTool: subjectTool(options.subject),
221
232
  ...(options.signal === undefined ? {} : { signal: options.signal }),
222
- ...(options.runCompletion === undefined ? {} : { runCompletion: options.runCompletion }),
233
+ ...(options.runDirectory === undefined ? {} : { runDirectory: options.runDirectory }),
223
234
  });
224
235
  } catch (error) {
225
236
  return { status: "transport_failure", stage: "gatekeeper", reason: failureReason(error) };
@@ -242,7 +253,7 @@ export async function runGatekeeper(options: RunGatekeeperOptions): Promise<Gate
242
253
  tool: createOfficerDecisionTool(officer === "inspector" ? INSPECTOR_OUTPUT_TOOL : NOTARY_OUTPUT_TOOL),
243
254
  dossierTool: subjectTool(options.subject),
244
255
  ...(options.signal === undefined ? {} : { signal: options.signal }),
245
- ...(options.runCompletion === undefined ? {} : { runCompletion: options.runCompletion }),
256
+ ...(options.runDirectory === undefined ? {} : { runDirectory: options.runDirectory }),
246
257
  });
247
258
  if (officerRun.noReceiptLifecycle !== undefined) {
248
259
  return { status: "no_receipt", stage: officer, reason: `${gateSeatLabel(officer)}未产生已接受回执即散局`, facts: officerRun.noReceiptLifecycle };
@@ -255,7 +266,7 @@ export async function runGatekeeper(options: RunGatekeeperOptions): Promise<Gate
255
266
 
256
267
  /** Project GatekeeperResult onto a submit path: transport→failInfrastructure; bounce/no_receipt→typed throw; pass silent. */
257
268
  export async function requireGatekeeperPass(options: {
258
- readonly context: ExtensionContext;
269
+ readonly context: ExtensionContext | HostContext;
259
270
  readonly subject: GatekeeperSubject;
260
271
  readonly signal?: AbortSignal;
261
272
  readonly hostActions: GatekeeperPassHostActions;
@@ -280,6 +291,6 @@ export async function requireGatekeeperPass(options: {
280
291
  options.hostActions.failInfrastructure(error, options.context, options.toolCallId);
281
292
  }
282
293
  // Envelope owns the execute→tool_result bridge; this module only projects + throws.
283
- options.hostActions.bindGatekeeperNonPass(options.toolCallId, gatekeeper);
294
+ options.hostActions.bindSubmissionNonPass(options.toolCallId, gatekeeper);
284
295
  throw new GatekeeperDecisionError(gatekeeper);
285
296
  }
@@ -0,0 +1,386 @@
1
+ import { Type, type Static, type TLiteral, type TSchema } from "typebox";
2
+
3
+ type HostContentPart = { type: "text"; text: string } | { type: "toolCall"; id: string; name: string; arguments?: unknown } | { type: string };
4
+ type HostMessage = { role: string; content?: unknown; toolName?: string; isError?: boolean; stopReason?: string };
5
+ type HostEventMessage = { role: string; content: readonly HostContentPart[]; toolName?: string; isError?: boolean; stopReason?: string };
6
+ type HostSessionEntry = { type: string; message?: HostMessage };
7
+
8
+ export type HostToolResult<T = unknown> = {
9
+ content: Array<{ type: "text"; text: string } | { type: "image"; data: string; mimeType: string }>;
10
+ details: T;
11
+ terminate?: boolean;
12
+ };
13
+
14
+ /** Opaque host-owned identity persisted with a Role run. */
15
+ export type DurablePrincipal = object & { readonly __durablePrincipal?: never };
16
+
17
+ /** Controlled post-admission failure classes (ADR 0052 / #107). Owner = host contract. */
18
+ export type ControlledFailureCause =
19
+ | "activation"
20
+ | "provider"
21
+ | "session"
22
+ | "output"
23
+ | "timeout"
24
+ | "unrecognized";
25
+
26
+ /** Production-owned typed failure carried on a resolved turn result. */
27
+ export type RoleTurnKnownFailure = {
28
+ readonly cause: ControlledFailureCause;
29
+ readonly identity?: {
30
+ readonly name?: string;
31
+ readonly code?: string | number;
32
+ };
33
+ /**
34
+ * Optional diagnostic already owned by a typed production field (e.g. session
35
+ * assistant errorMessage). Settlement prefers this over child stderr selection.
36
+ */
37
+ readonly diagnostic?: string;
38
+ /** Secondary evidence attached to the same typed failure record. */
39
+ readonly details?: Readonly<Record<string, unknown>>;
40
+ };
41
+
42
+ /**
43
+ * Thrown activation failure with a production-owned typed cause.
44
+ * Prefer this over ad-hoc Error property tags so settlement retains typed identity.
45
+ * Final owner = host contract (#526); public-cli/pi/role-runtime all import here.
46
+ */
47
+ export class ExplicitInternalActivationError extends Error {
48
+ readonly knownCause: ControlledFailureCause;
49
+ readonly failureCode?: string | number;
50
+
51
+ constructor(
52
+ message: string,
53
+ options: {
54
+ knownCause: ControlledFailureCause;
55
+ code?: string | number;
56
+ name?: string;
57
+ cause?: unknown;
58
+ },
59
+ ) {
60
+ super(
61
+ message,
62
+ options.cause === undefined ? undefined : { cause: options.cause },
63
+ );
64
+ this.name = options.name ?? "ExplicitInternalActivationError";
65
+ this.knownCause = options.knownCause;
66
+ if (options.code !== undefined) {
67
+ this.failureCode = options.code;
68
+ }
69
+ }
70
+ }
71
+
72
+ /** Packaged method skill binding (zero/one/many). */
73
+ export type MethodBinding = {
74
+ readonly kind: "skill";
75
+ readonly path: string;
76
+ };
77
+
78
+ /**
79
+ * Host-neutral closed role activation projection.
80
+ * Adapter translates to host-specific flags; does not reverse-parse prompt prose.
81
+ */
82
+ export type RoleTurnActivation =
83
+ | { readonly role: "judge" }
84
+ | {
85
+ readonly role: "coder";
86
+ readonly phase: string;
87
+ readonly taskPath: string;
88
+ }
89
+ | {
90
+ readonly role: "fixer";
91
+ readonly phase: string;
92
+ readonly packetPath: string;
93
+ readonly prerequisitesPath?: string;
94
+ }
95
+ | {
96
+ readonly role: "reviewer";
97
+ readonly baseRevision: string;
98
+ readonly authorityRefs: readonly string[];
99
+ readonly ticketNumber?: number;
100
+ }
101
+ | { readonly role: "merger"; readonly inputPath: string }
102
+ | {
103
+ readonly role: "collector";
104
+ readonly repo: string;
105
+ readonly pr: string;
106
+ readonly requestManifestPath?: string;
107
+ }
108
+ | { readonly role: "doctor"; readonly casePath: string }
109
+ | { readonly role: "notary"; readonly sourceRun: string };
110
+
111
+ export type RoleTurnContinuation =
112
+ | { readonly kind: "initial"; readonly prompt: string }
113
+ | { readonly kind: "resume"; readonly prompt: string };
114
+
115
+ /** Seat model consumed by the turn host (provider/model/thinking). */
116
+ export type RoleTurnModelConfig = {
117
+ readonly provider: string;
118
+ readonly model: string;
119
+ readonly thinking?: string;
120
+ };
121
+
122
+ /** One main-session turn request over the host-neutral execution seam. */
123
+ export type RoleTurnRequest = {
124
+ readonly principal: DurablePrincipal;
125
+ readonly activation: RoleTurnActivation;
126
+ readonly methods: readonly MethodBinding[];
127
+ readonly continuation: RoleTurnContinuation;
128
+ readonly model?: RoleTurnModelConfig;
129
+ readonly engine?: string;
130
+ readonly cwd: string;
131
+ readonly home: string;
132
+ readonly agentDir: string;
133
+ readonly runDirectory: string;
134
+ readonly correlationId?: string;
135
+ readonly timeoutMs?: number;
136
+ };
137
+
138
+ /** Turn result — only fields upper layers currently consume. */
139
+ export type RoleTurnResult = {
140
+ readonly code: number | null;
141
+ readonly stderr: string;
142
+ readonly timedOut: boolean;
143
+ readonly knownFailure?: RoleTurnKnownFailure;
144
+ };
145
+
146
+ /** Host-neutral session custom-entry appender (Pi adapter provides the concrete codec). */
147
+ export type SessionCustomEntryAppender = (
148
+ authority: DurablePrincipalAuthority,
149
+ principal: DurablePrincipal,
150
+ customType: string,
151
+ data: unknown,
152
+ ) => Promise<void>;
153
+
154
+ /** Host-neutral main-session execution seam (S1b-2 / #526). */
155
+ export interface RoleTurnHost {
156
+ executeTurn(request: RoleTurnRequest): Promise<RoleTurnResult>;
157
+ }
158
+
159
+ export type DurablePrincipalCoordinates = {
160
+ readonly sessionDirectory: string;
161
+ readonly sessionFile: string;
162
+ };
163
+
164
+ export type NewDurablePrincipalRequest = {
165
+ readonly cwd: string;
166
+ readonly runId: string;
167
+ readonly role: string;
168
+ readonly home?: string;
169
+ };
170
+
171
+ /** Host authority for issuing, checking, and temporarily decoding durable principals. */
172
+ export interface DurablePrincipalAuthority {
173
+ issue(request: NewDurablePrincipalRequest): DurablePrincipal;
174
+ isAvailable(principal: DurablePrincipal): Promise<boolean>;
175
+ decode(principal: unknown): DurablePrincipalCoordinates;
176
+ }
177
+
178
+ type HostSessionManager = { getLeafEntry(): HostSessionEntry | undefined; getLeafId(): string | null | undefined; getEntries(): Iterable<HostSessionEntry>; getSessionDir(): string; getSessionFile(): string | undefined; getHeader?(): { readonly type: string; readonly id?: string } | null; setSessionFile?(path: string): void; appendCustomEntry?(customType: string, data?: unknown): unknown; };
179
+
180
+ /** Context supplied by a host for one activation and its interceptable events. */
181
+ export type HostContext = { cwd: string; mode: string; model: { readonly provider: string } | undefined; sessionManager: HostSessionManager; signal?: AbortSignal | undefined; ui?: { notify?(message: string, type?: "info" | "warning" | "error"): void }; transcript?(): string; abort(): void; };
182
+
183
+ export type HostToolDefinition<S extends TSchema = TSchema, D = unknown, C = HostContext> = { name: string; label: string; description: string; promptSnippet?: string; parameters: S; execute( toolCallId: string, params: Static<S>, signal: AbortSignal | undefined, update: ((result: HostToolResult<D>) => void) | undefined, context: C, ): Promise<HostToolResult<D>>; };
184
+
185
+ type BeforeAgentStartEvent = { prompt: string; systemPrompt: string; systemPromptOptions: { skills?: readonly unknown[]; contextFiles?: readonly unknown[]; appendSystemPrompt?: string } };
186
+ type InputEvent = { text: string; images?: Array<{ type: "image"; data: string; mimeType: string }>; source?: string };
187
+ type ToolCallEvent = { toolName: string; toolCallId: string; input: Record<string, unknown> };
188
+ type ToolResultEvent = { toolName: string; toolCallId: string; isError: boolean; content: HostToolResult["content"]; details: unknown };
189
+ type SessionStartEvent = { reason: string };
190
+ type ProviderResponseEvent = { status?: number };
191
+ type AgentEndEvent = { messages: readonly HostEventMessage[] };
192
+ type ToolExecutionEvent = { toolName: string; toolCallId: string };
193
+ type ToolExecutionUpdateEvent = ToolExecutionEvent & { partialResult: unknown };
194
+ type ToolExecutionEndEvent = ToolExecutionEvent & { isError: boolean };
195
+
196
+ type HostEventMap = {
197
+ before_agent_start: BeforeAgentStartEvent;
198
+ input: InputEvent;
199
+ tool_call: ToolCallEvent;
200
+ tool_result: ToolResultEvent;
201
+ session_start: SessionStartEvent;
202
+ session_shutdown: Record<never, never>;
203
+ after_provider_response: ProviderResponseEvent;
204
+ agent_end: AgentEndEvent;
205
+ agent_settled: Record<never, never>;
206
+ tool_execution_start: ToolExecutionEvent;
207
+ tool_execution_update: ToolExecutionUpdateEvent;
208
+ tool_execution_end: ToolExecutionEndEvent;
209
+ };
210
+
211
+ type HostInputResult = { action: "continue" } | { action: "transform"; text: string; images?: Array<{ type: "image"; data: string; mimeType: string }> } | { action: "handled" };
212
+ type HostEventResultMap = {
213
+ before_agent_start: { systemPrompt?: string };
214
+ input: HostInputResult;
215
+ tool_call: { block?: boolean; reason?: string; terminate?: boolean };
216
+ tool_result: { content?: HostToolResult["content"]; details?: unknown; isError?: boolean };
217
+ session_start: void;
218
+ session_shutdown: void;
219
+ after_provider_response: void;
220
+ agent_end: void;
221
+ agent_settled: void;
222
+ tool_execution_start: void;
223
+ tool_execution_update: void;
224
+ tool_execution_end: void;
225
+ };
226
+ type HostEventHandler<K extends keyof HostEventMap> = (event: HostEventMap[K], ctx: HostContext) => HostEventResultMap[K] | void | Promise<HostEventResultMap[K] | void>;
227
+ export type HostEventRegistration = { [K in keyof HostEventMap]: [event: K, handler: HostEventHandler<K>] }[keyof HostEventMap];
228
+
229
+ type HostGatekeeperSubject = { readonly kind: "worker_completion" | "judge_draft"; readonly material: string };
230
+ /** Gatekeeper bounce/no_receipt plus other correct submission rejects share one projection map. */
231
+ type HostGatekeeperNonPass = { readonly status: "bounce" | "no_receipt" } & Record<string, unknown>;
232
+ export type HostSubmissionNonPass =
233
+ | HostGatekeeperNonPass
234
+ | { readonly code: "coder_skill_expansion_evidence_missing" };
235
+ export type HostGatekeeperActions = {
236
+ failInfrastructure(error: unknown, context: HostContext, toolCallId?: string): never;
237
+ /** Envelope-owned execute→tool_result bridge for any structured submission non-pass. */
238
+ bindSubmissionNonPass(toolCallId: string, result: HostSubmissionNonPass): void;
239
+ };
240
+
241
+ export type HostSkillExpansionEvidence = Readonly<{
242
+ name: string;
243
+ location: string;
244
+ content: string;
245
+ userMessage: string;
246
+ }>;
247
+
248
+ /** Host capability declaration (contract verb ④). */
249
+ export type HostCapabilityDeclaration = Readonly<{
250
+ skillExpansion(prompt: string): HostSkillExpansionEvidence | undefined;
251
+ }>;
252
+
253
+ /** The activation surface consumed by package role factories. */
254
+ export interface RoleHost {
255
+ readonly capabilities?: HostCapabilityDeclaration;
256
+ registerFlag(name: string, definition: { description: string; type: "boolean" | "string"; default?: boolean | string }): void;
257
+ getFlag(name: string): boolean | string | undefined;
258
+ registerTool<S extends TSchema, D = unknown>(tool: HostToolDefinition<S, D>): void;
259
+ getAllTools(): Array<{ name: string; sourceInfo?: { path?: string } }>;
260
+ setActiveTools(names: string[]): void;
261
+ getActiveTools(): string[];
262
+ requireGatekeeperPass?(options: { context: HostContext; subject: HostGatekeeperSubject; signal?: AbortSignal; hostActions: HostGatekeeperActions; toolCallId: string }): Promise<void>;
263
+ on(event: "before_agent_start", handler: HostEventHandler<"before_agent_start">): void;
264
+ on(event: "input", handler: HostEventHandler<"input">): void;
265
+ on(event: "tool_call", handler: HostEventHandler<"tool_call">): void;
266
+ on(event: "tool_result", handler: HostEventHandler<"tool_result">): void;
267
+ on(event: "session_start", handler: HostEventHandler<"session_start">): void;
268
+ on(event: "session_shutdown", handler: HostEventHandler<"session_shutdown">): void;
269
+ on(event: "after_provider_response", handler: HostEventHandler<"after_provider_response">): void;
270
+ on(event: "agent_end", handler: HostEventHandler<"agent_end">): void;
271
+ on(event: "agent_settled", handler: HostEventHandler<"agent_settled">): void;
272
+ on(event: "tool_execution_start", handler: HostEventHandler<"tool_execution_start">): void;
273
+ on(event: "tool_execution_update", handler: HostEventHandler<"tool_execution_update">): void;
274
+ on(event: "tool_execution_end", handler: HostEventHandler<"tool_execution_end">): void;
275
+ getCommands?(): Array<{ name: string }>;
276
+ }
277
+
278
+ /** Institutional sub-session seats (#518 §1). */
279
+ export type InstitutionalSeat =
280
+ | "gatekeeper"
281
+ | "inspector"
282
+ | "notary"
283
+ | "auditor"
284
+ | "evidenceChild"
285
+ | (string & {});
286
+
287
+ /** Non-secret host-neutral seat model selection. Single truth source is RoleTurnModelConfig. */
288
+ export type HostInstitutionalModelSelection = RoleTurnModelConfig;
289
+
290
+ /** Usage statistics for institutional sub-session events and turns. */
291
+ export type HostSessionUsage = {
292
+ readonly input: number;
293
+ readonly output: number;
294
+ readonly cacheRead: number;
295
+ readonly cacheWrite: number;
296
+ readonly totalTokens: number;
297
+ readonly cost: {
298
+ readonly input: number;
299
+ readonly output: number;
300
+ readonly cacheRead: number;
301
+ readonly cacheWrite: number;
302
+ readonly total: number;
303
+ };
304
+ };
305
+
306
+ /** Closed stream event union consumed by institutional callers (#518 §1③). */
307
+ export type HostInstitutionalSessionEvent =
308
+ | {
309
+ readonly type: "message_end";
310
+ readonly role: "assistant" | "user" | string;
311
+ readonly message?: unknown;
312
+ readonly usage?: HostSessionUsage;
313
+ }
314
+ | {
315
+ readonly type: "turn_end";
316
+ readonly stopReason?: string;
317
+ }
318
+ | {
319
+ readonly type: "tool_call";
320
+ readonly toolCallId: string;
321
+ readonly toolName: string;
322
+ readonly args?: unknown;
323
+ }
324
+ | {
325
+ readonly type: "tool_result";
326
+ readonly toolCallId: string;
327
+ readonly toolName: string;
328
+ readonly isError?: boolean;
329
+ readonly details?: unknown;
330
+ };
331
+
332
+ /** Terminal result of an institutional assistant turn (#518 §1③). */
333
+ export type HostAssistantTurnResult = {
334
+ readonly text: string;
335
+ readonly stopReason?: string;
336
+ readonly errorMessage?: string;
337
+ readonly usage?: HostSessionUsage;
338
+ readonly messages?: readonly unknown[];
339
+ };
340
+
341
+ /**
342
+ * Handle to an active institutional sub-session (#518 §1②).
343
+ * Does not leak AgentSession, ModelRuntime, or Provider objects out of the adapter.
344
+ */
345
+ export interface HostInstitutionalSessionHandle {
346
+ readonly sessionFile?: string;
347
+ readonly sessionId?: string;
348
+ prompt(text: string): Promise<HostAssistantTurnResult>;
349
+ subscribe(listener: (event: HostInstitutionalSessionEvent) => void): () => void;
350
+ abort(): void;
351
+ close(): Promise<void>;
352
+ }
353
+
354
+ /** Open options for an institutional sub-session (#518 §1①). */
355
+ export type HostInstitutionalSessionOptions = {
356
+ readonly cwd: string;
357
+ readonly selection: HostInstitutionalModelSelection;
358
+ readonly systemPrompt: string;
359
+ readonly tools?: readonly HostToolDefinition[];
360
+ readonly customTools?: readonly unknown[];
361
+ readonly noTools?: "all" | "builtin";
362
+ readonly toolsAllowlist?: readonly string[];
363
+ readonly agentDir?: string;
364
+ readonly credentialScratchParent?: string;
365
+ readonly signal?: AbortSignal;
366
+ readonly idleRetry?: boolean;
367
+ readonly sessionIdentity?: {
368
+ readonly kind: string;
369
+ readonly subject?: string;
370
+ readonly parent?: { getSessionFile(): string | undefined };
371
+ };
372
+ readonly sessionManager?: unknown;
373
+ };
374
+
375
+ /** Host-neutral institutional sub-session open seam. */
376
+ export interface InstitutionalSessionHost {
377
+ openInstitutionalSession(
378
+ options: HostInstitutionalSessionOptions,
379
+ ): Promise<HostInstitutionalSessionHandle>;
380
+ }
381
+
382
+ /** Local replacement for Pi AI's convenience constructor. */
383
+ export function stringEnum<const V extends readonly string[]>(values: V, options: Record<string, unknown> = {}) {
384
+ return Type.Union(values.map((value) => Type.Literal(value)) as [TLiteral<V[number]>, ...TLiteral<V[number]>[]], options);
385
+ }
386
+
@@ -1,115 +1 @@
1
- /**
2
- * Thin shared in-process AgentSession open (#233).
3
- * Static Pi imports are safe for Navigator (same module instance as ModelRuntime).
4
- * Auditor/evidence callers must dynamic-import this module so public-cli bundling
5
- * does not statically reach @earendil-works/pi-coding-agent.
6
- */
7
- import {
8
- createAgentSession,
9
- DefaultResourceLoader,
10
- SettingsManager,
11
- type ModelRuntime,
12
- type SessionManager,
13
- type ToolDefinition,
14
- } from "@earendil-works/pi-coding-agent";
15
- import type { Api, Model } from "@earendil-works/pi-ai";
16
-
17
- import { createRecordSession } from "./archivist-record-entry.ts";
18
-
19
- type OpenInProcessAgentSessionBase = {
20
- readonly cwd: string;
21
- /** Required when loading a resource loader / systemPrompt. Callers own scratch lifecycle. */
22
- readonly agentDir?: string;
23
- readonly model: Model<Api>;
24
- readonly modelRuntime: ModelRuntime;
25
- readonly thinkingLevel?: "off" | "minimal" | "low" | "medium" | "high" | "xhigh" | "max";
26
- readonly systemPrompt?: string;
27
- readonly customTools?: ToolDefinition[];
28
- readonly noTools?: "all" | "builtin";
29
- /** Optional allowlist — omit for unrestricted Pi defaults (ADR 0064). */
30
- readonly tools?: string[];
31
- };
32
-
33
- /**
34
- * Shared open admits exactly one session source:
35
- * - pre-built sessionManager, or
36
- * - kind/subject/parent identity relations (Archivist obtains the manager).
37
- * Encoded as a type relation — no runtime missing-arg guard.
38
- */
39
- export type OpenInProcessAgentSessionOptions =
40
- | (OpenInProcessAgentSessionBase & {
41
- readonly sessionManager: SessionManager;
42
- readonly kind?: never;
43
- readonly subject?: never;
44
- readonly parent?: never;
45
- })
46
- | (OpenInProcessAgentSessionBase & {
47
- readonly sessionManager?: undefined;
48
- /** Record kind for the Archivist entry. */
49
- readonly kind: string;
50
- /** Stable work identity for book-level records which continue across role runs. */
51
- readonly subject?: string;
52
- /** Optional parent session — supplies parentSession link / nest principal. */
53
- readonly parent?: { getSessionFile(): string | undefined };
54
- });
55
-
56
- function resolveSessionManager(options: OpenInProcessAgentSessionOptions): SessionManager {
57
- if (options.sessionManager !== undefined) return options.sessionManager;
58
- return createRecordSession({
59
- cwd: options.cwd,
60
- kind: options.kind,
61
- ...(options.subject === undefined ? {} : { subject: options.subject }),
62
- ...(options.parent === undefined ? {} : { parent: options.parent }),
63
- });
64
- }
65
-
66
- /**
67
- * Single createAgentSession + Settings construction for all in-process children.
68
- * Child SessionManager construction for identity-declared records lives here so
69
- * role modules do not call createRecordSession directly.
70
- */
71
- export async function openInProcessAgentSession(
72
- options: OpenInProcessAgentSessionOptions,
73
- ): Promise<{ session: Awaited<ReturnType<typeof createAgentSession>>["session"]; dispose(): void }> {
74
- const settings = SettingsManager.inMemory({ compaction: { enabled: false }, retry: { enabled: false } });
75
- const sessionManager = resolveSessionManager(options);
76
-
77
- const createArgs: Parameters<typeof createAgentSession>[0] = {
78
- cwd: options.cwd,
79
- model: options.model,
80
- thinkingLevel: options.thinkingLevel ?? "off",
81
- modelRuntime: options.modelRuntime,
82
- sessionManager,
83
- settingsManager: settings,
84
- ...(options.noTools === undefined ? {} : { noTools: options.noTools }),
85
- ...(options.tools === undefined ? {} : { tools: options.tools }),
86
- ...(options.customTools === undefined ? {} : { customTools: options.customTools }),
87
- };
88
-
89
- if (options.agentDir !== undefined) {
90
- const loader = new DefaultResourceLoader({
91
- cwd: options.cwd,
92
- agentDir: options.agentDir,
93
- settingsManager: settings,
94
- noExtensions: true,
95
- noSkills: true,
96
- noPromptTemplates: true,
97
- noThemes: true,
98
- noContextFiles: true,
99
- ...(options.systemPrompt === undefined ? {} : { systemPrompt: options.systemPrompt }),
100
- });
101
- await loader.reload();
102
- createArgs.agentDir = options.agentDir;
103
- createArgs.resourceLoader = loader;
104
- } else if (options.systemPrompt !== undefined) {
105
- throw new Error("openInProcessAgentSession requires agentDir when systemPrompt is set");
106
- }
107
-
108
- const { session } = await createAgentSession(createArgs);
109
- return {
110
- session,
111
- dispose() {
112
- session.dispose();
113
- },
114
- };
115
- }
1
+ export * from "./pi/in-process-session.ts";