@akagilnc/pi-workflow-roles 0.1.2107 → 0.1.2114

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.
@@ -7,6 +7,8 @@
7
7
  import { writeFile } from "node:fs/promises";
8
8
  import { join } from "node:path";
9
9
 
10
+ import { applyEngineChildEnv } from "../engine-detour.ts";
11
+ import { engineSessionMaterialFromOptions } from "../package-resources/engine-material.ts";
10
12
  import {
11
13
  loadPackagedMethodSkillMaterial,
12
14
  resolvePackagedMethodSkillPath,
@@ -82,6 +84,8 @@ export type FixerRunEnv = {
82
84
  correlationId?: string;
83
85
  piRunner?: ExplicitInternalPiRunner;
84
86
  model?: SeatModelConfig;
87
+ /** Optional labor engine name (config→activation; session material + env signal). */
88
+ engine?: string;
85
89
  credentials?: CredentialProviders;
86
90
  createRunId?: () => string;
87
91
  extraPiArgs?: readonly string[];
@@ -99,10 +103,14 @@ export function buildFixerActivationExtraArgs(
99
103
  options: {
100
104
  packageRoot: string;
101
105
  model?: SeatModelConfig;
106
+ engine?: string;
102
107
  extraPiArgs?: readonly string[];
103
108
  },
104
109
  ): string[] {
105
- const prompt = buildFixerTransportPrompt(admitted);
110
+ const prompt = buildFixerTransportPrompt(
111
+ admitted,
112
+ engineSessionMaterialFromOptions(options),
113
+ );
106
114
  const diagnosisSkillPath = resolvePackagedMethodSkillPath(
107
115
  options.packageRoot,
108
116
  "diagnosing-bugs",
@@ -275,12 +283,14 @@ async function dispatchAdmittedFixer(input: {
275
283
  extraArgs: string[];
276
284
  lease: RunWriterLease;
277
285
  methodMaterial: PackagedMethodSkillMaterial;
286
+ /** Mechanical engine provenance for initial Fixer dispatch only. */
287
+ effectiveEngine?: string;
278
288
  }): Promise<{
279
289
  exitCode: number;
280
290
  admitted: AdmittedFixerInvocation;
281
291
  terminal?: TerminalResult;
282
292
  }> {
283
- const { admitted, env, io, extraArgs, lease, methodMaterial } = input;
293
+ const { admitted, env, io, extraArgs, lease, methodMaterial, effectiveEngine } = input;
284
294
  try {
285
295
  const missingCredential = missingCredentialPreDispatchFailure(
286
296
  env.model,
@@ -293,7 +303,7 @@ async function dispatchAdmittedFixer(input: {
293
303
  io,
294
304
  );
295
305
  }
296
- await markRunRunning(admitted.runDirectory, env.model);
306
+ await markRunRunning(admitted.runDirectory, env.model, effectiveEngine);
297
307
  await clearTypedProviderHttpObservation(admitted.runDirectory);
298
308
 
299
309
  const childEnv: NodeJS.ProcessEnv = {
@@ -302,6 +312,7 @@ async function dispatchAdmittedFixer(input: {
302
312
  PI_CODING_AGENT_DIR: env.agentDir,
303
313
  AK_ROLE_RUN_DIR: admitted.runDirectory,
304
314
  };
315
+ applyEngineChildEnv(childEnv, env.engine);
305
316
  const correlationId = admitted.correlationId ?? env.correlationId;
306
317
  if (correlationId !== undefined && correlationId.trim() !== "") {
307
318
  childEnv.AK_CORRELATION_ID = correlationId;
@@ -494,6 +505,7 @@ export async function runPublicFixer(
494
505
  const extraArgs = buildFixerActivationExtraArgs(admitted, {
495
506
  packageRoot: env.packageRoot,
496
507
  ...(env.model === undefined ? {} : { model: env.model }),
508
+ ...(env.engine === undefined ? {} : { engine: env.engine }),
497
509
  ...(env.extraPiArgs === undefined ? {} : { extraPiArgs: env.extraPiArgs }),
498
510
  });
499
511
 
@@ -507,6 +519,8 @@ export async function runPublicFixer(
507
519
  extraArgs,
508
520
  lease,
509
521
  methodMaterial,
522
+ // #391: only initial Fixer dispatch records mechanical engine provenance.
523
+ ...(env.engine === undefined ? {} : { effectiveEngine: env.engine }),
510
524
  });
511
525
  }
512
526
 
@@ -967,6 +967,7 @@ export async function admitCoderInvocation(
967
967
  */
968
968
  export function buildCoderTransportPrompt(
969
969
  admitted: AdmittedCoderInvocation,
970
+ engineMaterial?: EngineSessionMaterial,
970
971
  ): string {
971
972
  const lines: string[] = [admitted.instruction];
972
973
  if (admitted.attachments.length > 0) {
@@ -976,7 +977,7 @@ export function buildCoderTransportPrompt(
976
977
  lines.push(`- ${attachment.frozenPath}`);
977
978
  }
978
979
  }
979
- return lines.join("\n");
980
+ return appendEngineSessionMaterial(lines, engineMaterial).join("\n");
980
981
  }
981
982
 
982
983
  export type AdmitFixerInvocationOptions = {
@@ -1123,6 +1124,7 @@ export async function admitFixerInvocation(
1123
1124
  */
1124
1125
  export function buildFixerTransportPrompt(
1125
1126
  admitted: AdmittedFixerInvocation,
1127
+ engineMaterial?: EngineSessionMaterial,
1126
1128
  ): string {
1127
1129
  const lines: string[] = [admitted.instruction];
1128
1130
  if (admitted.attachments.length > 0) {
@@ -1132,7 +1134,7 @@ export function buildFixerTransportPrompt(
1132
1134
  lines.push(`- ${attachment.frozenPath}`);
1133
1135
  }
1134
1136
  }
1135
- return lines.join("\n");
1137
+ return appendEngineSessionMaterial(lines, engineMaterial).join("\n");
1136
1138
  }
1137
1139
 
1138
1140
  function parsePositivePrOption(raw: string | undefined): number {
@@ -1415,9 +1417,10 @@ export async function admitCollectorInvocation(
1415
1417
  */
1416
1418
  export function buildCollectorTransportPrompt(
1417
1419
  _admitted: AdmittedCollectorInvocation,
1420
+ engineMaterial?: EngineSessionMaterial,
1418
1421
  ): string {
1419
1422
  // Exact historical fixed kickoff bytes (one-shot observation).
1420
- return COLLECTOR_FIXED_KICKOFF;
1423
+ return appendEngineSessionMaterial([COLLECTOR_FIXED_KICKOFF], engineMaterial).join("\n");
1421
1424
  }
1422
1425
 
1423
1426
  /** Positive Issue number grammar shared with Doctor case path identity. */
@@ -1727,6 +1730,7 @@ export async function admitDoctorInvocation(
1727
1730
  /** Build the Pi prompt transport for an admitted Doctor request. */
1728
1731
  export function buildDoctorTransportPrompt(
1729
1732
  admitted: AdmittedDoctorInvocation,
1733
+ engineMaterial?: EngineSessionMaterial,
1730
1734
  ): string {
1731
1735
  const lines: string[] = [admitted.instructionEmpty ? "" : admitted.instruction];
1732
1736
  if (admitted.attachments.length > 0) {
@@ -1736,7 +1740,7 @@ export function buildDoctorTransportPrompt(
1736
1740
  lines.push(`- ${attachment.frozenPath}`);
1737
1741
  }
1738
1742
  }
1739
- return lines.join("\n");
1743
+ return appendEngineSessionMaterial(lines, engineMaterial).join("\n");
1740
1744
  }
1741
1745
 
1742
1746
  /**
@@ -2160,6 +2164,7 @@ export async function admitMergerInvocation(
2160
2164
  */
2161
2165
  export function buildMergerTransportPrompt(
2162
2166
  admitted: AdmittedMergerInvocation,
2167
+ engineMaterial?: EngineSessionMaterial,
2163
2168
  ): string {
2164
2169
  const lines: string[] = [
2165
2170
  `/skill:resolving-merge-conflicts ${admitted.instruction}`,
@@ -2171,7 +2176,7 @@ export function buildMergerTransportPrompt(
2171
2176
  lines.push(`- ${attachment.frozenPath}`);
2172
2177
  }
2173
2178
  }
2174
- return lines.join("\n");
2179
+ return appendEngineSessionMaterial(lines, engineMaterial).join("\n");
2175
2180
  }
2176
2181
 
2177
2182
  const TAISHI_TICKET_NUMBER_PATTERN = /^[1-9]\d*$/;
@@ -6,7 +6,7 @@
6
6
  import { writeFile } from "node:fs/promises";
7
7
  import { join } from "node:path";
8
8
 
9
- import { AK_ROLE_ENGINE_ENV } from "../engine-detour.ts";
9
+ import { applyEngineChildEnv } from "../engine-detour.ts";
10
10
  import { engineSessionMaterialFromOptions } from "../package-resources/engine-material.ts";
11
11
  import {
12
12
  runExplicitInternalActivation,
@@ -298,14 +298,7 @@ async function dispatchAdmittedJudge(input: {
298
298
  // and role-runtime can record typed provider HTTP observations.
299
299
  AK_ROLE_RUN_DIR: admitted.runDirectory,
300
300
  };
301
- // Engine presence/name signal: registration gate + label only (no per-engine branch).
302
- // Delete ambient inheritance first; own-key undefined mask survives process.env re-merge.
303
- delete childEnv[AK_ROLE_ENGINE_ENV];
304
- if (env.engine !== undefined && env.engine.trim() !== "") {
305
- childEnv[AK_ROLE_ENGINE_ENV] = env.engine.trim();
306
- } else {
307
- childEnv[AK_ROLE_ENGINE_ENV] = undefined;
308
- }
301
+ applyEngineChildEnv(childEnv, env.engine);
309
302
  const correlationId = admitted.correlationId ?? env.correlationId;
310
303
  if (correlationId !== undefined && correlationId.trim() !== "") {
311
304
  childEnv.AK_CORRELATION_ID = correlationId;
@@ -8,6 +8,8 @@ import { join, resolve } from "node:path";
8
8
 
9
9
  import { ensureRealDirectoryTree } from "../activation-ledger-topology.ts";
10
10
  import { roleRunSessionCoordinates } from "../sitian-role-run-coordinates.ts";
11
+ import { applyEngineChildEnv } from "../engine-detour.ts";
12
+ import { engineSessionMaterialFromOptions } from "../package-resources/engine-material.ts";
11
13
  import {
12
14
  loadPackagedMethodSkillMaterial,
13
15
  resolvePackagedMethodSkillPath,
@@ -83,6 +85,8 @@ export type MergerRunEnv = {
83
85
  correlationId?: string;
84
86
  piRunner?: ExplicitInternalPiRunner;
85
87
  model?: SeatModelConfig;
88
+ /** Optional labor engine name (config→activation; session material + env signal). */
89
+ engine?: string;
86
90
  credentials?: CredentialProviders;
87
91
  createRunId?: () => string;
88
92
  extraPiArgs?: readonly string[];
@@ -100,10 +104,14 @@ export function buildMergerActivationExtraArgs(
100
104
  options: {
101
105
  packageRoot: string;
102
106
  model?: SeatModelConfig;
107
+ engine?: string;
103
108
  extraPiArgs?: readonly string[];
104
109
  },
105
110
  ): string[] {
106
- const prompt = buildMergerTransportPrompt(admitted);
111
+ const prompt = buildMergerTransportPrompt(
112
+ admitted,
113
+ engineSessionMaterialFromOptions(options),
114
+ );
107
115
  const skillPath = resolvePackagedMethodSkillPath(
108
116
  options.packageRoot,
109
117
  "resolving-merge-conflicts",
@@ -271,12 +279,13 @@ async function dispatchAdmittedMerger(input: {
271
279
  extraArgs: string[];
272
280
  lease: RunWriterLease;
273
281
  methodMaterial: PackagedMethodSkillMaterial;
282
+ effectiveEngine?: string;
274
283
  }): Promise<{
275
284
  exitCode: number;
276
285
  admitted: AdmittedMergerInvocation;
277
286
  terminal?: TerminalResult;
278
287
  }> {
279
- const { admitted, env, io, extraArgs, lease, methodMaterial } = input;
288
+ const { admitted, env, io, extraArgs, lease, methodMaterial, effectiveEngine } = input;
280
289
  try {
281
290
  const missingCredential = missingCredentialPreDispatchFailure(
282
291
  env.model,
@@ -289,7 +298,7 @@ async function dispatchAdmittedMerger(input: {
289
298
  io,
290
299
  );
291
300
  }
292
- await markRunRunning(admitted.runDirectory, env.model);
301
+ await markRunRunning(admitted.runDirectory, env.model, effectiveEngine);
293
302
  await clearTypedProviderHttpObservation(admitted.runDirectory);
294
303
 
295
304
  const childEnv: NodeJS.ProcessEnv = {
@@ -298,6 +307,7 @@ async function dispatchAdmittedMerger(input: {
298
307
  PI_CODING_AGENT_DIR: env.agentDir,
299
308
  AK_ROLE_RUN_DIR: admitted.runDirectory,
300
309
  };
310
+ applyEngineChildEnv(childEnv, env.engine);
301
311
  const correlationId = admitted.correlationId ?? env.correlationId;
302
312
  if (correlationId !== undefined && correlationId.trim() !== "") {
303
313
  childEnv.AK_CORRELATION_ID = correlationId;
@@ -576,6 +586,7 @@ export async function runPublicMerger(
576
586
  const extraArgs = buildMergerActivationExtraArgs(admitted, {
577
587
  packageRoot: env.packageRoot,
578
588
  ...(env.model === undefined ? {} : { model: env.model }),
589
+ ...(env.engine === undefined ? {} : { engine: env.engine }),
579
590
  ...(env.extraPiArgs === undefined ? {} : { extraPiArgs: env.extraPiArgs }),
580
591
  });
581
592
 
@@ -589,6 +600,7 @@ export async function runPublicMerger(
589
600
  extraArgs,
590
601
  lease,
591
602
  methodMaterial,
603
+ ...(env.engine === undefined ? {} : { effectiveEngine: env.engine }),
592
604
  });
593
605
  }
594
606
 
@@ -288,8 +288,8 @@ const GLOBAL_OPTIONS = [
288
288
  repeatable: false,
289
289
  form: "option",
290
290
  description: {
291
- en: "Optional Judge/Reviewer labor engine for this invocation (owner pool-directive name; packaged notes attached when present; judge+reviewer only).",
292
- zh: "本调用可选 Judge/Reviewer 劳动引擎(池令名字;有包内调法笔记则附卷;仅 Judge+Reviewer)。",
291
+ en: "Optional labor engine for this invocation (owner pool-directive name; packaged notes attached when present; any role).",
292
+ zh: "本调用可选劳动引擎(池令名字;有包内调法笔记则附卷;全部角色可用)。",
293
293
  },
294
294
  },
295
295
  {
@@ -7,7 +7,7 @@
7
7
  import { writeFile } from "node:fs/promises";
8
8
  import { join } from "node:path";
9
9
 
10
- import { AK_ROLE_ENGINE_ENV } from "../engine-detour.ts";
10
+ import { applyEngineChildEnv } from "../engine-detour.ts";
11
11
  import { engineSessionMaterialFromOptions } from "../package-resources/engine-material.ts";
12
12
  import {
13
13
  loadPackagedMethodSkillMaterial,
@@ -320,14 +320,7 @@ async function dispatchAdmittedReviewer(input: {
320
320
  PI_CODING_AGENT_DIR: env.agentDir,
321
321
  AK_ROLE_RUN_DIR: admitted.runDirectory,
322
322
  };
323
- // Engine presence/name signal: registration gate + leg channel (no per-engine branch).
324
- // Delete ambient inheritance first; own-key undefined mask survives process.env re-merge.
325
- delete childEnv[AK_ROLE_ENGINE_ENV];
326
- if (env.engine !== undefined && env.engine.trim() !== "") {
327
- childEnv[AK_ROLE_ENGINE_ENV] = env.engine.trim();
328
- } else {
329
- childEnv[AK_ROLE_ENGINE_ENV] = undefined;
330
- }
323
+ applyEngineChildEnv(childEnv, env.engine);
331
324
  const correlationId = admitted.correlationId ?? env.correlationId;
332
325
  if (correlationId !== undefined && correlationId.trim() !== "") {
333
326
  childEnv.AK_CORRELATION_ID = correlationId;
@@ -233,7 +233,7 @@ export async function markRunAdmitted(
233
233
  * resume override) and optional initial effective engine onto invocation.json
234
234
  * when known, then transition to running.
235
235
  * Role runners must not coordinate lifecycle ledger writes themselves.
236
- * Engine is write-if-present only — callers that omit it (resume / non-Judge)
236
+ * Engine is write-if-present only — callers that omit it (resume paths)
237
237
  * never touch the engine key.
238
238
  */
239
239
  export async function markRunRunning(
@@ -597,7 +597,7 @@ export function createRoleRuntimeExtension(
597
597
  let pendingNavigatorSettlement: Promise<void> | undefined;
598
598
  let navigatorWorkContext: NavigatorWorkContext | undefined;
599
599
  const pendingInfrastructureToolCallIds = new Set<string>();
600
- // #357 T2 / #378 / #380: engine detour once-latch + seat-fallback latch (Judge|Reviewer+engine).
600
+ // #357 T2 / #378 / #380 / #391: engine detour once-latch + seat-fallback latch (any role+engine).
601
601
  let engineDetourRegistration: ReturnType<typeof registerEngineDetourTool> | undefined;
602
602
  let engineLaborFallbackLatch = createEngineLaborFallbackLatch();
603
603
  // #288 primary-session thin adapter. The policy is the sole budget owner;
@@ -1187,13 +1187,10 @@ export function createRoleRuntimeExtension(
1187
1187
  }
1188
1188
 
1189
1189
  await executeActivationStage(entry.role, activationStage(entry.role, runtime), { clock, writeTrace });
1190
- // #357 T2 / #378 / #380: Judge|Reviewer+engine activation registers the package detour tool once.
1190
+ // #357 T2 / #378 / #380 / #391: any role+engine activation registers the package detour tool once.
1191
1191
  // Gate is env presence only — no per-engine execute branch; no role-module spawn.
1192
1192
  // Seat-fallback latch is activation-scoped (installed at session_start) so legs share it.
1193
- if (
1194
- (entry.role === "judge" || entry.role === "reviewer") &&
1195
- engineDetourRegistration === undefined
1196
- ) {
1193
+ if (engineDetourRegistration === undefined) {
1197
1194
  engineDetourRegistration = registerEngineDetourTool(pi, hostActions);
1198
1195
  if (!engineDetourRegistration.registered) {
1199
1196
  engineDetourRegistration = undefined;
@@ -6,6 +6,10 @@ import type {
6
6
  } from "@earendil-works/pi-coding-agent";
7
7
  import { Type, type Static } from "typebox";
8
8
  import { openToolObjectFromUnion } from "./open-tool-schema.ts";
9
+ import {
10
+ readActivationEngineLaborFallbackField,
11
+ withEngineLaborFallbackField,
12
+ } from "./engine-labor-fallback.ts";
9
13
 
10
14
  import type {
11
15
  AnyCanonicalSkillBinding,
@@ -288,9 +292,14 @@ export function createFixerRoleRuntime(
288
292
  ctx,
289
293
  toolCallId,
290
294
  );
295
+ // #391: attach sole-built engineLaborFallback when detour fell back to seat labor.
296
+ const acceptedDetails = withEngineLaborFallbackField(
297
+ output,
298
+ readActivationEngineLaborFallbackField(),
299
+ );
291
300
  return {
292
301
  content: [{ type: "text" as const, text: "Fixer report accepted" }],
293
- details: output,
302
+ details: acceptedDetails,
294
303
  terminate: true as const,
295
304
  };
296
305
  },
@@ -427,9 +436,14 @@ export function createCoderRoleRuntime(
427
436
  ctx,
428
437
  toolCallId,
429
438
  );
439
+ // #391: attach sole-built engineLaborFallback when detour fell back to seat labor.
440
+ const acceptedDetails = withEngineLaborFallbackField(
441
+ output,
442
+ readActivationEngineLaborFallbackField(),
443
+ );
430
444
  return {
431
445
  content: [{ type: "text" as const, text: "Coder report accepted" }],
432
- details: output,
446
+ details: acceptedDetails,
433
447
  terminate: true as const,
434
448
  };
435
449
  },