@akagilnc/pi-workflow-roles 0.1.3837 → 0.1.3873

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 (42) hide show
  1. package/dist/acp-host/production-host.js +24606 -24532
  2. package/dist/engine-detour-tool.js +2 -2
  3. package/dist/engine-detour.js +23 -7
  4. package/dist/headless-host/production-host.js +4197 -4139
  5. package/dist/host-descriptions.js +5 -2
  6. package/dist/pi/role-turn-host.js +20 -92
  7. package/dist/public-cli/load-production-acp-host.js +1 -1
  8. package/dist/public-cli/load-production-external-host.js +10 -0
  9. package/dist/public-cli/load-production-headless-host.js +1 -1
  10. package/dist/public-cli/main.js +95 -102
  11. package/dist/public-role-summons.js +7 -49
  12. package/dist/reviewer-agent.js +1 -0
  13. package/dist/reviewer-child-executor.js +3 -2
  14. package/dist/role-activation-flags.js +50 -0
  15. package/dist/role-runtime.js +8 -3
  16. package/package.json +1 -1
  17. package/scripts/build-package.mjs +2 -2
  18. package/src/acp-host/production-host.ts +31 -94
  19. package/src/acp-host/role-turn-host.ts +178 -263
  20. package/src/diagnostic-tail.ts +18 -0
  21. package/src/engine-detour-tool.ts +5 -4
  22. package/src/engine-detour.ts +44 -9
  23. package/src/external-host-turn-loop.ts +172 -0
  24. package/src/headless-host/production-host.ts +10 -7
  25. package/src/headless-host/role-turn-host.ts +271 -263
  26. package/src/host-descriptions.ts +5 -2
  27. package/src/host-session-record.ts +41 -0
  28. package/src/pi/role-turn-host.ts +18 -93
  29. package/src/prepared-role-turn.ts +68 -0
  30. package/src/public-cli/cli.ts +11 -20
  31. package/src/public-cli/load-production-acp-host.ts +2 -1
  32. package/src/public-cli/load-production-external-host.ts +17 -0
  33. package/src/public-cli/load-production-headless-host.ts +2 -1
  34. package/src/public-role-summons.ts +12 -69
  35. package/src/reviewer-agent.ts +12 -1
  36. package/src/reviewer-child-executor.ts +10 -2
  37. package/src/role-activation-flags.ts +53 -0
  38. package/src/{acp-host/role-envelope.ts → role-envelope.ts} +28 -84
  39. package/src/role-runtime-dependencies.ts +91 -0
  40. package/src/role-runtime.ts +14 -4
  41. package/src/{acp-host/session-identity.ts → session-identity.ts} +6 -6
  42. /package/src/{acp-host/mcp-relay.mjs → mcp-relay.mjs} +0 -0
@@ -48,6 +48,7 @@ export const HOST_DESCRIPTIONS = Object.freeze({
48
48
  /**
49
49
  * Headless CLI family (#645). Claude is the first row; codex (#646) adds another.
50
50
  * fixedArgs: print mode, isolation without `--bare` (OAuth stays), full permissions.
51
+ * stream-json + verbose: live host events for sitian records (#811); result is last line.
51
52
  * `--setting-sources` empty = load no user/project/local CLAUDE.md/hooks/skills
52
53
  * (role envelope is delivered via `--system-prompt` wholesale replace).
53
54
  * `--strict-mcp-config` with no `--mcp-config` drops operator MCP + claude.ai connectors.
@@ -57,8 +58,10 @@ export const HEADLESS_HOST_DESCRIPTIONS = Object.freeze({
57
58
  binaryFromHome: Object.freeze([".local", "bin", "claude"]),
58
59
  sessionBindingFile: "claude-headless-session.json",
59
60
  fixedArgs: Object.freeze([
60
- // One result envelope (not stream-json): typed receipt only; no event-stream copy.
61
- "--output-format", "json",
61
+ // Live NDJSON events → sitian host-session records (#811); last line is the result receipt.
62
+ "--output-format", "stream-json",
63
+ // Intermediate assistant/tool/system events require verbose with stream-json.
64
+ "--verbose",
62
65
  "--permission-mode", "bypassPermissions",
63
66
  // Empty sources: no user/project/local operator surface (envelope owns materials).
64
67
  "--setting-sources", "",
@@ -12,6 +12,7 @@ import { promisify } from "node:util";
12
12
  import { randomUUID } from "node:crypto";
13
13
  import { ExplicitInternalActivationError } from "../host-contracts.js";
14
14
  import { applyEngineChildEnv } from "../engine-detour.js";
15
+ import { projectActivationFlags } from "../role-activation-flags.js";
15
16
  /** Package-relative Internal role entrypoint (ADR 0052; same path as public-cli registry). */
16
17
  const INTERNAL_ROLE_ENTRYPOINT_RELATIVE = "extensions/role-runtime.ts";
17
18
  export function resolveInternalRoleEntrypoint(packageRoot) {
@@ -45,95 +46,20 @@ function buildSeatModelCliArgs(model) {
45
46
  ...(model.thinking === undefined ? [] : ["--thinking", model.thinking]),
46
47
  ];
47
48
  }
48
- function buildActivationFlagArgs(activation) {
49
- switch (activation.role) {
50
- case "judge":
51
- return ["--ak-role", "judge"];
52
- case "coder":
53
- return [
54
- "--ak-role",
55
- "coder",
56
- "--ak-coder-phase",
57
- activation.phase,
58
- "--ak-coder-task",
59
- activation.taskPath,
60
- ];
61
- case "fixer":
62
- return [
63
- "--ak-role",
64
- "fixer",
65
- "--ak-fixer-phase",
66
- activation.phase,
67
- "--ak-fix-packet",
68
- activation.packetPath,
69
- ...(activation.prerequisitesPath === undefined
70
- ? []
71
- : ["--ak-fixer-prerequisites", activation.prerequisitesPath]),
72
- ];
73
- case "reviewer":
74
- return [
75
- "--ak-role",
76
- "reviewer",
77
- "--ak-review-base",
78
- activation.baseRevision,
79
- ...(activation.authorityRefs.length === 0
80
- ? []
81
- : ["--ak-review-authority-refs", JSON.stringify([...activation.authorityRefs])]),
82
- ...(activation.ticketNumber === undefined
83
- ? []
84
- : ["--ak-review-ticket-number", String(activation.ticketNumber)]),
85
- ];
86
- case "merger":
87
- return ["--ak-role", "merger", "--ak-merger-input", activation.inputPath];
88
- case "collector":
89
- return [
90
- "--ak-role",
91
- "collector",
92
- "--ak-collector-repo",
93
- activation.repo,
94
- ...(activation.pr === undefined ? [] : ["--ak-collector-pr", activation.pr]),
95
- ...(activation.requestManifestPath === undefined
96
- ? []
97
- : ["--ak-collector-request-manifest", activation.requestManifestPath]),
98
- ...(activation.waitMs === undefined ? [] : ["--ak-collector-wait-ms", activation.waitMs]),
99
- ];
100
- case "doctor":
101
- return ["--ak-role", "doctor", "--ak-doctor-case", activation.casePath];
102
- case "notary":
103
- return [
104
- "--ak-role",
105
- "notary",
106
- "--ak-notary-source-run",
107
- activation.sourceRun,
108
- ...(activation.ticketNumber === undefined
109
- ? []
110
- : ["--ak-notary-ticket-number", String(activation.ticketNumber)]),
111
- ];
112
- case "countersign":
113
- // ticketNumber rides activation/admission/invocation only (#632: no private flag).
114
- return ["--ak-role", "countersign"];
115
- case "gleaner-left":
116
- return [
117
- "--ak-role",
118
- "gleaner-left",
119
- "--ak-gleaner-left-base",
120
- activation.baseRevision,
121
- ];
122
- case "inspector":
123
- return ["--ak-role", "inspector"];
124
- case "gatekeeper":
125
- return ["--ak-role", "gatekeeper"];
126
- case "navigator":
127
- return ["--ak-role", "navigator"];
128
- case "auditor":
129
- return ["--ak-role", "auditor"];
130
- case "diarist":
131
- return ["--ak-role", "diarist"];
132
- default: {
133
- const _exhaustive = activation;
134
- return _exhaustive;
135
- }
49
+ /**
50
+ * Pi last hop only: shared envelope flags → controlled-session argv pairs (#819).
51
+ * Flag membership/values stay in projectActivationFlags (middle layer).
52
+ */
53
+ function activationFlagsToPiArgv(flags) {
54
+ const args = [];
55
+ for (const [name, value] of flags) {
56
+ if (value === false)
57
+ continue;
58
+ args.push(`--${name}`);
59
+ if (value !== true)
60
+ args.push(String(value));
136
61
  }
62
+ return args;
137
63
  }
138
64
  function buildMethodArgs(methods) {
139
65
  const skillArgs = [];
@@ -166,9 +92,10 @@ export function applyPiNativeSkillInvocation(methods, prompt) {
166
92
  return prompt.length === 0 ? token : `${token} ${prompt}`;
167
93
  }
168
94
  /**
169
- * Translate a closed RoleTurnRequest into Pi argv after `--no-extensions -e entry`.
170
- * Controlled session constants and session coordinates are adapter-internal.
171
- * Single forced method → Pi-native `/skill:` on the argv prompt (coder/reviewer/merger).
95
+ * Pi last-hop argv after `--no-extensions -e entry` (#819).
96
+ * Activation flag membership comes from middle-layer projectActivationFlags;
97
+ * this function only renders session coords, controlled constants, and pairs.
98
+ * Single forced method → Pi-native `/skill:` on the argv prompt (#822).
172
99
  */
173
100
  export function buildPiTurnExtraArgs(request, authority, extraPiArgs = []) {
174
101
  const { sessionFile, sessionDirectory } = authority.decode(request.principal);
@@ -190,7 +117,8 @@ export function buildPiTurnExtraArgs(request, authority, extraPiArgs = []) {
190
117
  "--session-dir",
191
118
  sessionDirectory,
192
119
  ...extraPiArgs,
193
- ...buildActivationFlagArgs(request.activation),
120
+ // Envelope assembly = projectActivationFlags; pi only renders argv pairs.
121
+ ...activationFlagsToPiArgv(projectActivationFlags(request)),
194
122
  "--mode",
195
123
  "json",
196
124
  ...buildSeatModelCliArgs(request.model),
@@ -36,5 +36,5 @@ export async function loadProductionAcpHostFactory(packageRoot, host) {
36
36
  const href = pathToFileURL(target).href;
37
37
  const mod = (await import(__rewriteRelativeImportExtension(href)));
38
38
  const create = mod.createProductionAcpRoleTurnHost;
39
- return (options) => create({ ...options, description });
39
+ return (options) => create({ ...options, description, hostName: host });
40
40
  }
@@ -17,3 +17,13 @@ export async function loadProductionExternalHostFactory(packageRoot, host) {
17
17
  }
18
18
  throw new Error(`unregistered host: ${host}`);
19
19
  }
20
+ /** Lazy production external host — sole builder for CLI adapter table + public summons (#820). */
21
+ export function createLazyProductionExternalHost(options) {
22
+ let hostPromise;
23
+ return {
24
+ executeTurn: async (request) => {
25
+ hostPromise ??= loadProductionExternalHostFactory(options.packageRoot, options.hostName).then((create) => create({ packageRoot: options.packageRoot, principalAuthority: options.principalAuthority }));
26
+ return (await hostPromise).executeTurn(request);
27
+ },
28
+ };
29
+ }
@@ -32,5 +32,5 @@ export async function loadProductionHeadlessHostFactory(packageRoot, host) {
32
32
  const href = pathToFileURL(target).href;
33
33
  const mod = (await import(__rewriteRelativeImportExtension(href)));
34
34
  const create = mod.createProductionHeadlessRoleTurnHost;
35
- return (options) => create({ ...options, description });
35
+ return (options) => create({ ...options, description, hostName: host });
36
36
  }
@@ -15090,6 +15090,12 @@ var init_diarist_contracts = __esm({
15090
15090
  function packagedRoleMetadata(role) {
15091
15091
  return PACKAGED_ROLE_REGISTRY.find((entry) => entry.role === role);
15092
15092
  }
15093
+ function packagedRoleInputFlag(role) {
15094
+ return packagedRoleMetadata(role)?.inputFlag;
15095
+ }
15096
+ function packagedRolePhaseFlag(role) {
15097
+ return packagedRoleMetadata(role)?.phaseFlag;
15098
+ }
15093
15099
  var NOTARY_SESSION_MATERIALS, INSPECTOR_SESSION_MATERIALS, AUDITOR_PUBLIC_SESSION_MATERIALS, PUBLIC_ROLE_RECORDS, PACKAGED_ROLE_REGISTRY;
15094
15100
  var init_packaged_role_registry = __esm({
15095
15101
  "src/packaged-role-registry.ts"() {
@@ -15527,9 +15533,11 @@ var init_host_descriptions = __esm({
15527
15533
  binaryFromHome: Object.freeze([".local", "bin", "claude"]),
15528
15534
  sessionBindingFile: "claude-headless-session.json",
15529
15535
  fixedArgs: Object.freeze([
15530
- // One result envelope (not stream-json): typed receipt only; no event-stream copy.
15536
+ // Live NDJSON events → sitian host-session records (#811); last line is the result receipt.
15531
15537
  "--output-format",
15532
- "json",
15538
+ "stream-json",
15539
+ // Intermediate assistant/tool/system events require verbose with stream-json.
15540
+ "--verbose",
15533
15541
  "--permission-mode",
15534
15542
  "bypassPermissions",
15535
15543
  // Empty sources: no user/project/local operator surface (envelope owns materials).
@@ -16180,7 +16188,7 @@ async function loadProductionAcpHostFactory(packageRoot2, host) {
16180
16188
  const href = pathToFileURL(target).href;
16181
16189
  const mod = await import(href);
16182
16190
  const create = mod.createProductionAcpRoleTurnHost;
16183
- return (options) => create({ ...options, description });
16191
+ return (options) => create({ ...options, description, hostName: host });
16184
16192
  }
16185
16193
  var init_load_production_acp_host = __esm({
16186
16194
  "src/public-cli/load-production-acp-host.ts"() {
@@ -16204,7 +16212,7 @@ async function loadProductionHeadlessHostFactory(packageRoot2, host) {
16204
16212
  const href = pathToFileURL2(target).href;
16205
16213
  const mod = await import(href);
16206
16214
  const create = mod.createProductionHeadlessRoleTurnHost;
16207
- return (options) => create({ ...options, description });
16215
+ return (options) => create({ ...options, description, hostName: host });
16208
16216
  }
16209
16217
  var init_load_production_headless_host = __esm({
16210
16218
  "src/public-cli/load-production-headless-host.ts"() {
@@ -16224,6 +16232,17 @@ async function loadProductionExternalHostFactory(packageRoot2, host) {
16224
16232
  }
16225
16233
  throw new Error(`unregistered host: ${host}`);
16226
16234
  }
16235
+ function createLazyProductionExternalHost(options) {
16236
+ let hostPromise;
16237
+ return {
16238
+ executeTurn: async (request) => {
16239
+ hostPromise ??= loadProductionExternalHostFactory(options.packageRoot, options.hostName).then(
16240
+ (create) => create({ packageRoot: options.packageRoot, principalAuthority: options.principalAuthority })
16241
+ );
16242
+ return (await hostPromise).executeTurn(request);
16243
+ }
16244
+ };
16245
+ }
16227
16246
  var init_load_production_external_host = __esm({
16228
16247
  "src/public-cli/load-production-external-host.ts"() {
16229
16248
  "use strict";
@@ -16258,11 +16277,17 @@ var init_host_contracts = __esm({
16258
16277
  });
16259
16278
 
16260
16279
  // src/engine-detour.ts
16280
+ function normalizeEngineName(engine) {
16281
+ if (engine === void 0) return void 0;
16282
+ const trimmed = engine.trim();
16283
+ return trimmed === "" ? void 0 : trimmed;
16284
+ }
16261
16285
  function applyEngineChildEnv(childEnv, engine) {
16262
16286
  delete childEnv[AK_ROLE_ENGINE_ENV];
16263
- if (engine !== void 0 && engine.trim() !== "") {
16264
- childEnv[AK_ROLE_ENGINE_ENV] = engine.trim();
16265
- } else {
16287
+ const normalized = normalizeEngineName(engine);
16288
+ if (normalized !== void 0) {
16289
+ childEnv[AK_ROLE_ENGINE_ENV] = normalized;
16290
+ } else if (childEnv !== process.env) {
16266
16291
  childEnv[AK_ROLE_ENGINE_ENV] = void 0;
16267
16292
  }
16268
16293
  }
@@ -16275,6 +16300,50 @@ var init_engine_detour = __esm({
16275
16300
  }
16276
16301
  });
16277
16302
 
16303
+ // src/role-activation-flags.ts
16304
+ function projectActivationFlags(request) {
16305
+ const activation = request.activation;
16306
+ const flags = /* @__PURE__ */ new Map([["ak-role", activation.role]]);
16307
+ const inputFlag = packagedRoleInputFlag(activation.role);
16308
+ const phaseFlag = packagedRolePhaseFlag(activation.role);
16309
+ if ("phase" in activation && phaseFlag !== void 0) flags.set(phaseFlag, activation.phase);
16310
+ if (inputFlag !== void 0) {
16311
+ const path = "taskPath" in activation ? activation.taskPath : "packetPath" in activation ? activation.packetPath : "casePath" in activation ? activation.casePath : "inputPath" in activation ? activation.inputPath : "sourceRun" in activation ? activation.sourceRun : void 0;
16312
+ if (path !== void 0) flags.set(inputFlag, path);
16313
+ }
16314
+ if (activation.role === "fixer" && activation.prerequisitesPath !== void 0) {
16315
+ flags.set("ak-fixer-prerequisites", activation.prerequisitesPath);
16316
+ }
16317
+ if (activation.role === "reviewer") {
16318
+ flags.set("ak-review-base", activation.baseRevision);
16319
+ flags.set("ak-review-authority-refs", JSON.stringify(activation.authorityRefs));
16320
+ if (activation.ticketNumber !== void 0) {
16321
+ flags.set("ak-review-ticket-number", String(activation.ticketNumber));
16322
+ }
16323
+ }
16324
+ if (activation.role === "notary" && activation.ticketNumber !== void 0) {
16325
+ flags.set("ak-notary-ticket-number", String(activation.ticketNumber));
16326
+ }
16327
+ if (activation.role === "gleaner-left") {
16328
+ flags.set("ak-gleaner-left-base", activation.baseRevision);
16329
+ }
16330
+ if (activation.role === "collector") {
16331
+ flags.set("ak-collector-repo", activation.repo);
16332
+ if (activation.pr !== void 0) flags.set("ak-collector-pr", activation.pr);
16333
+ if (activation.requestManifestPath !== void 0) {
16334
+ flags.set("ak-collector-request-manifest", activation.requestManifestPath);
16335
+ }
16336
+ if (activation.waitMs !== void 0) flags.set("ak-collector-wait-ms", activation.waitMs);
16337
+ }
16338
+ return flags;
16339
+ }
16340
+ var init_role_activation_flags = __esm({
16341
+ "src/role-activation-flags.ts"() {
16342
+ "use strict";
16343
+ init_packaged_role_registry();
16344
+ }
16345
+ });
16346
+
16278
16347
  // src/sitian-contracts.ts
16279
16348
  function attachDirectErrnoCode(error, cause) {
16280
16349
  if (cause === null || typeof cause !== "object" || !("code" in cause)) return;
@@ -16604,84 +16673,14 @@ function buildSeatModelCliArgs(model) {
16604
16673
  ...model.thinking === void 0 ? [] : ["--thinking", model.thinking]
16605
16674
  ];
16606
16675
  }
16607
- function buildActivationFlagArgs(activation) {
16608
- switch (activation.role) {
16609
- case "judge":
16610
- return ["--ak-role", "judge"];
16611
- case "coder":
16612
- return [
16613
- "--ak-role",
16614
- "coder",
16615
- "--ak-coder-phase",
16616
- activation.phase,
16617
- "--ak-coder-task",
16618
- activation.taskPath
16619
- ];
16620
- case "fixer":
16621
- return [
16622
- "--ak-role",
16623
- "fixer",
16624
- "--ak-fixer-phase",
16625
- activation.phase,
16626
- "--ak-fix-packet",
16627
- activation.packetPath,
16628
- ...activation.prerequisitesPath === void 0 ? [] : ["--ak-fixer-prerequisites", activation.prerequisitesPath]
16629
- ];
16630
- case "reviewer":
16631
- return [
16632
- "--ak-role",
16633
- "reviewer",
16634
- "--ak-review-base",
16635
- activation.baseRevision,
16636
- ...activation.authorityRefs.length === 0 ? [] : ["--ak-review-authority-refs", JSON.stringify([...activation.authorityRefs])],
16637
- ...activation.ticketNumber === void 0 ? [] : ["--ak-review-ticket-number", String(activation.ticketNumber)]
16638
- ];
16639
- case "merger":
16640
- return ["--ak-role", "merger", "--ak-merger-input", activation.inputPath];
16641
- case "collector":
16642
- return [
16643
- "--ak-role",
16644
- "collector",
16645
- "--ak-collector-repo",
16646
- activation.repo,
16647
- ...activation.pr === void 0 ? [] : ["--ak-collector-pr", activation.pr],
16648
- ...activation.requestManifestPath === void 0 ? [] : ["--ak-collector-request-manifest", activation.requestManifestPath],
16649
- ...activation.waitMs === void 0 ? [] : ["--ak-collector-wait-ms", activation.waitMs]
16650
- ];
16651
- case "doctor":
16652
- return ["--ak-role", "doctor", "--ak-doctor-case", activation.casePath];
16653
- case "notary":
16654
- return [
16655
- "--ak-role",
16656
- "notary",
16657
- "--ak-notary-source-run",
16658
- activation.sourceRun,
16659
- ...activation.ticketNumber === void 0 ? [] : ["--ak-notary-ticket-number", String(activation.ticketNumber)]
16660
- ];
16661
- case "countersign":
16662
- return ["--ak-role", "countersign"];
16663
- case "gleaner-left":
16664
- return [
16665
- "--ak-role",
16666
- "gleaner-left",
16667
- "--ak-gleaner-left-base",
16668
- activation.baseRevision
16669
- ];
16670
- case "inspector":
16671
- return ["--ak-role", "inspector"];
16672
- case "gatekeeper":
16673
- return ["--ak-role", "gatekeeper"];
16674
- case "navigator":
16675
- return ["--ak-role", "navigator"];
16676
- case "auditor":
16677
- return ["--ak-role", "auditor"];
16678
- case "diarist":
16679
- return ["--ak-role", "diarist"];
16680
- default: {
16681
- const _exhaustive = activation;
16682
- return _exhaustive;
16683
- }
16676
+ function activationFlagsToPiArgv(flags) {
16677
+ const args = [];
16678
+ for (const [name, value] of flags) {
16679
+ if (value === false) continue;
16680
+ args.push(`--${name}`);
16681
+ if (value !== true) args.push(String(value));
16684
16682
  }
16683
+ return args;
16685
16684
  }
16686
16685
  function buildMethodArgs(methods) {
16687
16686
  const skillArgs = [];
@@ -16723,7 +16722,8 @@ function buildPiTurnExtraArgs(request, authority, extraPiArgs = []) {
16723
16722
  "--session-dir",
16724
16723
  sessionDirectory,
16725
16724
  ...extraPiArgs,
16726
- ...buildActivationFlagArgs(request.activation),
16725
+ // Envelope assembly = projectActivationFlags; pi only renders argv pairs.
16726
+ ...activationFlagsToPiArgv(projectActivationFlags(request)),
16727
16727
  "--mode",
16728
16728
  "json",
16729
16729
  ...buildSeatModelCliArgs(request.model),
@@ -16940,6 +16940,7 @@ var init_role_turn_host = __esm({
16940
16940
  "use strict";
16941
16941
  init_host_contracts();
16942
16942
  init_engine_detour();
16943
+ init_role_activation_flags();
16943
16944
  init_sitian_facade();
16944
16945
  INTERNAL_ROLE_ENTRYPOINT_RELATIVE2 = "extensions/role-runtime.ts";
16945
16946
  execFileAsync = promisify(execFile);
@@ -32019,23 +32020,15 @@ function resolveRoleTurnHost(env, options) {
32019
32020
  { name: "pi", create: () => ({ ok: true, host: piHost }) },
32020
32021
  ...packagedExternalHostNames().map((name) => ({
32021
32022
  name,
32022
- create: () => {
32023
- let hostPromise;
32024
- return {
32025
- ok: true,
32026
- host: {
32027
- executeTurn: async (request) => {
32028
- hostPromise ??= loadProductionExternalHostFactory(env.packageRoot, name).then(
32029
- (create) => create({
32030
- packageRoot: env.packageRoot,
32031
- principalAuthority: options.principalAuthority
32032
- })
32033
- );
32034
- return (await hostPromise).executeTurn(request);
32035
- }
32036
- }
32037
- };
32038
- }
32023
+ create: () => ({
32024
+ ok: true,
32025
+ // Factory loads outside the public bin static graph (ADR 0052 peer-free discovery).
32026
+ host: createLazyProductionExternalHost({
32027
+ packageRoot: env.packageRoot,
32028
+ hostName: name,
32029
+ principalAuthority: options.principalAuthority
32030
+ })
32031
+ })
32039
32032
  }))
32040
32033
  ];
32041
32034
  const hostName = options.seat.host;
@@ -100,24 +100,17 @@ async function createSummonEnv(options) {
100
100
  let roleTurnHost = piHost;
101
101
  if (hostName !== "pi") {
102
102
  const { lookupHostFamily } = await import("./host-descriptions.js");
103
- const { loadProductionExternalHostFactory } = await import("./public-cli/load-production-external-host.js");
103
+ const { createLazyProductionExternalHost } = await import("./public-cli/load-production-external-host.js");
104
104
  if (lookupHostFamily(hostName) === void 0) {
105
105
  throw new Error(
106
106
  `public role summons host unregistered: host=${hostName} seat=${options.role}`
107
107
  );
108
108
  }
109
- let hostPromise;
110
- roleTurnHost = {
111
- executeTurn: async (request) => {
112
- hostPromise ??= loadProductionExternalHostFactory(options.packageRoot, hostName).then(
113
- (create) => create({
114
- packageRoot: options.packageRoot,
115
- principalAuthority
116
- })
117
- );
118
- return (await hostPromise).executeTurn(request);
119
- }
120
- };
109
+ roleTurnHost = createLazyProductionExternalHost({
110
+ packageRoot: options.packageRoot,
111
+ hostName,
112
+ principalAuthority
113
+ });
121
114
  }
122
115
  const { loadHostProvidersTable, projectHostFacingProvider } = await import("./public-cli/host-providers.js");
123
116
  const hostFacingSelection = options.seat.selection === void 0 ? void 0 : projectHostFacingProvider(
@@ -151,8 +144,7 @@ async function summonPublicRole(options) {
151
144
  } = await import("./public-cli/config.js");
152
145
  const credentials = options.credentials ?? await loadCredentialProviders(agentDir);
153
146
  const config = await loadPublicCliConfig(home);
154
- const invocation = options.host === void 0 ? void 0 : { host: options.host };
155
- const seat = resolveEffectiveSeat(config, options.role, credentials, invocation);
147
+ const seat = resolveEffectiveSeat(config, options.role, credentials);
156
148
  const env = {
157
149
  ...await createSummonEnv({
158
150
  role: options.role,
@@ -264,38 +256,6 @@ async function summonPublicRole(options) {
264
256
  ...stderr === void 0 || stderr === "" ? {} : { stderr }
265
257
  };
266
258
  }
267
- async function parentInvocationHost(sourceRunDirectory) {
268
- const { readFile } = await import("node:fs/promises");
269
- const path = join(sourceRunDirectory, "invocation.json");
270
- let text;
271
- try {
272
- text = await readFile(path, "utf8");
273
- } catch (error) {
274
- const code = error instanceof Error && "code" in error ? error.code : void 0;
275
- throw new Error(
276
- `parent invocation.json required for gate source run at ${path}: ${code ?? (error instanceof Error ? error.message : String(error))}`,
277
- { cause: error }
278
- );
279
- }
280
- let raw;
281
- try {
282
- raw = JSON.parse(text);
283
- } catch (error) {
284
- throw new Error(
285
- `parent invocation.json unreadable at ${path}: ${error instanceof Error ? error.message : String(error)}`,
286
- { cause: error }
287
- );
288
- }
289
- if (typeof raw !== "object" || raw === null || Array.isArray(raw)) {
290
- throw new Error(`parent invocation.json has non-object shape at ${path}`);
291
- }
292
- const host = raw.host;
293
- if (host === void 0) return void 0;
294
- if (typeof host !== "string" || host.trim() === "") {
295
- throw new Error(`parent invocation.json host must be a non-empty string at ${path}`);
296
- }
297
- return host;
298
- }
299
259
  async function summonGateOfficer(options) {
300
260
  let home = options.home;
301
261
  if (home === void 0) {
@@ -309,7 +269,6 @@ async function summonGateOfficer(options) {
309
269
  submission: options.submission
310
270
  });
311
271
  }
312
- const parentHost = await parentInvocationHost(options.sourceRunDirectory);
313
272
  const common = {
314
273
  cwd: options.cwd,
315
274
  ...home === void 0 ? {} : { home },
@@ -318,7 +277,6 @@ async function summonGateOfficer(options) {
318
277
  ...options.signal === void 0 ? {} : { signal: options.signal },
319
278
  ...options.reask === void 0 ? {} : { reviewReask: options.reask },
320
279
  ...gateReviewInstruction === void 0 ? {} : { gateReviewInstruction },
321
- ...parentHost === void 0 ? {} : { host: parentHost },
322
280
  ...options.roleTurnHost === void 0 ? {} : { roleTurnHost: options.roleTurnHost },
323
281
  ...options.createRunId === void 0 ? {} : { createRunId: options.createRunId }
324
282
  };
@@ -76,6 +76,7 @@ export function createReviewerAgentRunner(dependencies = {}) {
76
76
  ...(dependencies.packageRoot === undefined
77
77
  ? {}
78
78
  : { packageRoot: dependencies.packageRoot }),
79
+ ...(options.getFlag === undefined ? {} : { getFlag: options.getFlag }),
79
80
  });
80
81
  const disposition = await workspaceOwner.dispose(workspace);
81
82
  return [leg.axis, Object.freeze({ status: "successful", report: child.report, usage: child.usage, target: batch.target, prompt: child.prompt, workspaceDisposition: disposition })];
@@ -1,5 +1,5 @@
1
1
  import { createEngineDetourToolDefinition } from "./engine-detour-tool.js";
2
- import { engineNameFromEnv } from "./engine-detour.js";
2
+ import { resolveEngineName } from "./engine-detour.js";
3
3
  import { appendEngineSessionMaterial, engineSessionMaterialFromOptions, } from "./package-resources/engine-material.js";
4
4
  import { readPackageMaterial } from "./session-opening-materials.js";
5
5
  import { hasUpstreamErrorTestimony, isNonSuccessHttpStatus } from "./upstream-error-testimony.js";
@@ -98,7 +98,8 @@ export async function executeReviewerChild(workspace, leg, context, options = {}
98
98
  const selection = await parentSelection(context);
99
99
  const { openPiInProcessSession } = await import("./pi/in-process-session.js");
100
100
  const { createRecordSession } = await import("./archivist-record-entry.js");
101
- const engineName = engineNameFromEnv();
101
+ // One gate with parent registration (#818): request flag, else pi child env.
102
+ const engineName = resolveEngineName(options.getFlag);
102
103
  const engineMaterial = engineName === undefined
103
104
  ? undefined
104
105
  : options.packageRoot === undefined || options.packageRoot.trim() === ""
@@ -0,0 +1,50 @@
1
+ import { packagedRoleInputFlag, packagedRolePhaseFlag } from "./packaged-role-registry.js";
2
+ /** Project closed RoleTurnActivation onto the shared host flag map. */
3
+ export function projectActivationFlags(request) {
4
+ const activation = request.activation;
5
+ const flags = new Map([["ak-role", activation.role]]);
6
+ const inputFlag = packagedRoleInputFlag(activation.role);
7
+ const phaseFlag = packagedRolePhaseFlag(activation.role);
8
+ if ("phase" in activation && phaseFlag !== undefined)
9
+ flags.set(phaseFlag, activation.phase);
10
+ if (inputFlag !== undefined) {
11
+ const path = "taskPath" in activation ? activation.taskPath
12
+ : "packetPath" in activation ? activation.packetPath
13
+ : "casePath" in activation ? activation.casePath
14
+ : "inputPath" in activation ? activation.inputPath
15
+ : "sourceRun" in activation ? activation.sourceRun
16
+ : undefined;
17
+ if (path !== undefined)
18
+ flags.set(inputFlag, path);
19
+ }
20
+ if (activation.role === "fixer" && activation.prerequisitesPath !== undefined) {
21
+ flags.set("ak-fixer-prerequisites", activation.prerequisitesPath);
22
+ }
23
+ if (activation.role === "reviewer") {
24
+ flags.set("ak-review-base", activation.baseRevision);
25
+ flags.set("ak-review-authority-refs", JSON.stringify(activation.authorityRefs));
26
+ if (activation.ticketNumber !== undefined) {
27
+ flags.set("ak-review-ticket-number", String(activation.ticketNumber));
28
+ }
29
+ }
30
+ // countersign ticketNumber stays on activation/admission/invocation only —
31
+ // no private transport flag (inner-gate material path deleted in #632).
32
+ if (activation.role === "notary" && activation.ticketNumber !== undefined) {
33
+ flags.set("ak-notary-ticket-number", String(activation.ticketNumber));
34
+ }
35
+ if (activation.role === "gleaner-left") {
36
+ flags.set("ak-gleaner-left-base", activation.baseRevision);
37
+ }
38
+ if (activation.role === "collector") {
39
+ flags.set("ak-collector-repo", activation.repo);
40
+ // #676 D1: pr optional at admission; omit flag when role binds from materials.
41
+ if (activation.pr !== undefined)
42
+ flags.set("ak-collector-pr", activation.pr);
43
+ if (activation.requestManifestPath !== undefined) {
44
+ flags.set("ak-collector-request-manifest", activation.requestManifestPath);
45
+ }
46
+ if (activation.waitMs !== undefined)
47
+ flags.set("ak-collector-wait-ms", activation.waitMs);
48
+ }
49
+ return flags;
50
+ }