@akagilnc/pi-workflow-roles 0.1.3718 → 0.1.3733

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.
@@ -1,21 +1,35 @@
1
1
  /**
2
2
  * One ACP host description. Every host-specific value the generic ACP adapter
3
- * needs — binary location, argv shape, resume verb, binding filename, child env
4
- * — is data here; the lifecycle in role-turn-host.ts stays one copy (#732).
3
+ * needs — binary location, argv shape, resume verb, binding filename, child env,
4
+ * optional seat-profile soul — is data here; the lifecycle in role-turn-host.ts
5
+ * stays one copy (#732).
5
6
  */
6
7
  import { join } from "node:path";
7
8
  /** Absolute agent binary for one operator home. */
8
9
  export function resolveAcpBinary(description, operatorHome) {
9
10
  return join(operatorHome, ...description.binaryFromHome);
10
11
  }
11
- /** Stdio argv: prefix, optional model/thinking flag pairs, suffix. */
12
- export function acpStdioArgs(description, model) {
12
+ /** Stdio argv: optional profile flag, thinking flag (before the subcommand),
13
+ * prefix, optional model flag pair, suffix. */
14
+ export function acpStdioArgs(description, model, seat) {
13
15
  const { prefix, suffix, modelFlag, thinkingFlag } = description.argv;
14
16
  const pair = (flag, value) => flag === undefined || value === undefined ? [] : [flag, value];
15
17
  return [
18
+ ...pair(description.seatProfileSoul?.flag, seat?.profileName),
19
+ ...pair(thinkingFlag, model?.thinking),
16
20
  ...prefix,
17
21
  ...pair(modelFlag, model?.model),
18
- ...pair(thinkingFlag, model?.thinking),
19
22
  ...suffix,
20
23
  ];
21
24
  }
25
+ /**
26
+ * The modelId the host addresses the seat model by.
27
+ * "argv" hosts address by bare model name; "set_model" hosts address by the
28
+ * `provider:model` modelId the ACP catalog exposes (seat provider after host
29
+ * alias projection, concatenated — never a package provider map).
30
+ */
31
+ export function acpModelId(modelPassing, model) {
32
+ if (model?.model === undefined)
33
+ return undefined;
34
+ return modelPassing === "set_model" ? `${model.provider}:${model.model}` : model.model;
35
+ }
@@ -164,7 +164,7 @@ function normalizeReviewComment(raw) {
164
164
  function createGhApiRunner(options = {}) {
165
165
  const spawnImpl = options.spawnImpl ?? spawn;
166
166
  return async (args, runOptions = {}) => {
167
- return await new Promise((resolve19, reject) => {
167
+ return await new Promise((resolve20, reject) => {
168
168
  const signal = runOptions.signal;
169
169
  if (signal?.aborted) {
170
170
  reject(signal.reason ?? new Error("aborted"));
@@ -237,11 +237,11 @@ function createGhApiRunner(options = {}) {
237
237
  const value = line2.slice(idx + 1).trim();
238
238
  headers[name] = value;
239
239
  }
240
- resolve19({ status, headers, bodyText });
240
+ resolve20({ status, headers, bodyText });
241
241
  return;
242
242
  }
243
243
  if (code === 0) {
244
- resolve19({ status: 200, headers: {}, bodyText: stdout });
244
+ resolve20({ status: 200, headers: {}, bodyText: stdout });
245
245
  return;
246
246
  }
247
247
  const failure2 = new Error(
@@ -502,6 +502,19 @@ var init_collector_github = __esm({
502
502
  }
503
503
  });
504
504
 
505
+ // src/readable-gate-item.ts
506
+ function readableGateItem(value) {
507
+ return typeof value === "string" ? value : JSON.stringify(value);
508
+ }
509
+ function joinReadableGateItems(items, separator = "; ") {
510
+ return items.map(readableGateItem).join(separator);
511
+ }
512
+ var init_readable_gate_item = __esm({
513
+ "src/readable-gate-item.ts"() {
514
+ "use strict";
515
+ }
516
+ });
517
+
505
518
  // src/auditor-dossier-tool.ts
506
519
  var auditor_dossier_tool_exports = {};
507
520
  __export(auditor_dossier_tool_exports, {
@@ -512,6 +525,7 @@ __export(auditor_dossier_tool_exports, {
512
525
  createAuditorDossierTool: () => createAuditorDossierTool,
513
526
  gateSubmissionCandidatePath: () => gateSubmissionCandidatePath,
514
527
  persistGateSubmissionCandidate: () => persistGateSubmissionCandidate,
528
+ readLatestSubmissionArguments: () => readLatestSubmissionArguments,
515
529
  readLatestToolCallLeaf: () => readLatestToolCallLeaf
516
530
  });
517
531
  import { mkdirSync, writeFileSync } from "node:fs";
@@ -543,16 +557,20 @@ function readLatestToolCallLeaf(context) {
543
557
  function gateSubmissionCandidatePath(runDirectory) {
544
558
  return join(runDirectory, "artifacts", GATE_SUBMISSION_CANDIDATE_FILE);
545
559
  }
546
- function buildGateOfficerReviewInstruction(input) {
547
- const lines = [
548
- "\u672C\u8F6E\u7236\u5E2D\u4EA4\u5377\u5F85\u5BA1\u3002",
549
- `\u6765\u6E90 run\uFF1A${input.sourceRunDirectory}`
550
- ];
551
- const candidate = input.submissionCandidatePath?.trim();
552
- if (candidate !== void 0 && candidate.length > 0) {
553
- lines.push(`\u4EA4\u5377\u5019\u9009\uFF08\u51BB\u7ED3\u5FEB\u7167\uFF09\uFF1A${candidate}`);
560
+ function readLatestSubmissionArguments(context) {
561
+ const leaf = readLatestToolCallLeaf(context);
562
+ if (!isRecord2(leaf) || !isRecord2(leaf.message) || !Array.isArray(leaf.message.content)) {
563
+ return void 0;
554
564
  }
555
- return lines.join("\n");
565
+ for (const part of leaf.message.content) {
566
+ if (isRecord2(part) && part.type === "toolCall" && "arguments" in part) {
567
+ return part.arguments;
568
+ }
569
+ }
570
+ return void 0;
571
+ }
572
+ function buildGateOfficerReviewInstruction(input) {
573
+ return readableGateItem(input.submission);
556
574
  }
557
575
  function persistGateSubmissionCandidate(runDirectory, context) {
558
576
  const leaf = readLatestToolCallLeaf(context);
@@ -596,6 +614,7 @@ var AUDITOR_DOSSIER_TOOL_NAME, GATE_SUBMISSION_CANDIDATE_FILE;
596
614
  var init_auditor_dossier_tool = __esm({
597
615
  "src/auditor-dossier-tool.ts"() {
598
616
  "use strict";
617
+ init_readable_gate_item();
599
618
  AUDITOR_DOSSIER_TOOL_NAME = "ak_get_run_dossier";
600
619
  GATE_SUBMISSION_CANDIDATE_FILE = "gate-submission-candidate.json";
601
620
  }
@@ -1208,7 +1227,7 @@ async function spawnEngineDetourOnce(input) {
1208
1227
  }
1209
1228
  const command = input.argv[0];
1210
1229
  const args = input.argv.slice(1);
1211
- return await new Promise((resolve19, reject) => {
1230
+ return await new Promise((resolve20, reject) => {
1212
1231
  let settled = false;
1213
1232
  const signal = input.signal;
1214
1233
  const child = spawn2(command, args, {
@@ -1238,7 +1257,7 @@ async function spawnEngineDetourOnce(input) {
1238
1257
  if (signal !== void 0) {
1239
1258
  signal.removeEventListener("abort", onAbort);
1240
1259
  }
1241
- resolve19(result);
1260
+ resolve20(result);
1242
1261
  };
1243
1262
  const onAbort = () => {
1244
1263
  fail5(signal !== void 0 ? abortReasonError(signal) : new Error("aborted"));
@@ -2235,19 +2254,6 @@ var init_reviewer_output = __esm({
2235
2254
  }
2236
2255
  });
2237
2256
 
2238
- // src/readable-gate-item.ts
2239
- function readableGateItem(value) {
2240
- return typeof value === "string" ? value : JSON.stringify(value);
2241
- }
2242
- function joinReadableGateItems(items, separator = "; ") {
2243
- return items.map(readableGateItem).join(separator);
2244
- }
2245
- var init_readable_gate_item = __esm({
2246
- "src/readable-gate-item.ts"() {
2247
- "use strict";
2248
- }
2249
- });
2250
-
2251
2257
  // src/audit-escalation.ts
2252
2258
  function buildAuditEscalationResult(decision, deliveredOutput) {
2253
2259
  const auditOwned = {
@@ -8392,6 +8398,7 @@ var init_host_descriptions = __esm({
8392
8398
  suffix: Object.freeze(["stdio"]),
8393
8399
  modelFlag: "--model"
8394
8400
  }),
8401
+ modelPassing: "argv",
8395
8402
  boundResume: "session/load",
8396
8403
  sessionBindingFile: "grok-acp-session.json",
8397
8404
  childEnv: Object.freeze({
@@ -8399,6 +8406,31 @@ var init_host_descriptions = __esm({
8399
8406
  GROK_MEMORY: "0",
8400
8407
  GROK_SUBAGENTS: "0"
8401
8408
  })
8409
+ }),
8410
+ /**
8411
+ * Operator home `~/.hermes`, native session/load resume, `acp` subcommand.
8412
+ * Model arrives as an ACP `session/set_model` RPC with modelId `provider:model`
8413
+ * (seat table provider + model concatenated). Reasoning is the global
8414
+ * `--reasoning` flag before `acp`. Soul is the seat profile SOUL.md symlink
8415
+ * (`hermes -p ak-<role> …`); package `souls/<role>.md` is the sole source.
8416
+ */
8417
+ "hermes": Object.freeze({
8418
+ binaryFromHome: Object.freeze([".local", "bin", "hermes"]),
8419
+ argv: Object.freeze({
8420
+ prefix: Object.freeze(["acp"]),
8421
+ suffix: Object.freeze([]),
8422
+ thinkingFlag: "--reasoning"
8423
+ }),
8424
+ modelPassing: "set_model",
8425
+ boundResume: "session/load",
8426
+ sessionBindingFile: "hermes-acp-session.json",
8427
+ childEnv: Object.freeze({}),
8428
+ seatProfileSoul: Object.freeze({
8429
+ flag: "-p",
8430
+ namePrefix: "ak-",
8431
+ profilesRootFromHome: Object.freeze([".hermes", "profiles"]),
8432
+ soulFileName: "SOUL.md"
8433
+ })
8402
8434
  })
8403
8435
  });
8404
8436
  }
@@ -11445,12 +11477,12 @@ function createSystemCollectorClock() {
11445
11477
  return {
11446
11478
  wallNow: () => /* @__PURE__ */ new Date(),
11447
11479
  monoNow: () => Number(process.hrtime.bigint() - start) / 1e6,
11448
- sleep: (ms, signal) => new Promise((resolve19, reject) => {
11480
+ sleep: (ms, signal) => new Promise((resolve20, reject) => {
11449
11481
  if (signal?.aborted) {
11450
11482
  reject(signal.reason ?? new Error("aborted"));
11451
11483
  return;
11452
11484
  }
11453
- const timer = setTimeout(resolve19, ms);
11485
+ const timer = setTimeout(resolve20, ms);
11454
11486
  const onAbort = () => {
11455
11487
  clearTimeout(timer);
11456
11488
  reject(signal?.reason ?? new Error("aborted"));
@@ -14871,10 +14903,10 @@ function presentFailureTerminal(terminal, io) {
14871
14903
  }
14872
14904
  function defaultNavigatorGraceSleep() {
14873
14905
  let timer;
14874
- const sleep = ((ms) => new Promise((resolve19) => {
14906
+ const sleep = ((ms) => new Promise((resolve20) => {
14875
14907
  timer = setTimeout(() => {
14876
14908
  timer = void 0;
14877
- resolve19();
14909
+ resolve20();
14878
14910
  }, ms);
14879
14911
  }));
14880
14912
  sleep.cancel = () => {
@@ -14886,7 +14918,7 @@ function defaultNavigatorGraceSleep() {
14886
14918
  return sleep;
14887
14919
  }
14888
14920
  function raceNavigatorGrace(work, graceMs = NAVIGATOR_POST_ROLE_GRACE_MS, sleep = defaultNavigatorGraceSleep()) {
14889
- return new Promise((resolve19, reject) => {
14921
+ return new Promise((resolve20, reject) => {
14890
14922
  let settled = false;
14891
14923
  const finish = (action) => {
14892
14924
  if (settled) return;
@@ -14895,11 +14927,11 @@ function raceNavigatorGrace(work, graceMs = NAVIGATOR_POST_ROLE_GRACE_MS, sleep
14895
14927
  action();
14896
14928
  };
14897
14929
  void work.then(
14898
- (value) => finish(() => resolve19({ status: "done", value })),
14930
+ (value) => finish(() => resolve20({ status: "done", value })),
14899
14931
  (error) => finish(() => reject(error))
14900
14932
  );
14901
14933
  void sleep(graceMs).then(() => {
14902
- finish(() => resolve19({ status: "timeout" }));
14934
+ finish(() => resolve20({ status: "timeout" }));
14903
14935
  });
14904
14936
  });
14905
14937
  }
@@ -16929,8 +16961,11 @@ async function summonPublicRole(options) {
16929
16961
  ...options.signal === void 0 ? {} : { signal: options.signal },
16930
16962
  // #753: reask rides the existing notary same-ticket resume summons.instruction.
16931
16963
  ...options.reviewReask === void 0 ? {} : { reviewReask: options.reviewReask },
16932
- // #753/#750: new-submission pointers on same-parent resume (not conclusion re-ask).
16933
- ...options.gateReviewInstruction === void 0 ? {} : { gateReviewInstruction: options.gateReviewInstruction }
16964
+ // #786: verbatim submission body on same-parent resume (not conclusion re-ask).
16965
+ ...options.gateReviewInstruction === void 0 ? {} : { gateReviewInstruction: options.gateReviewInstruction },
16966
+ // Offline test injects — same faces as public CLI env (production leaves unset).
16967
+ ...options.roleTurnHost === void 0 ? {} : { roleTurnHost: options.roleTurnHost },
16968
+ ...options.createRunId === void 0 ? {} : { createRunId: options.createRunId }
16934
16969
  };
16935
16970
  const captured = options.io === void 0 ? createCapturingIo() : void 0;
16936
16971
  const io = options.io ?? captured.io;
@@ -17027,11 +17062,10 @@ async function summonGateOfficer(options) {
17027
17062
  home = homeFromRunDirectory2(options.sourceRunDirectory);
17028
17063
  }
17029
17064
  let gateReviewInstruction;
17030
- if (options.reask === void 0) {
17065
+ if (options.reask === void 0 && options.submission !== void 0) {
17031
17066
  const { buildGateOfficerReviewInstruction: buildGateOfficerReviewInstruction2 } = await Promise.resolve().then(() => (init_auditor_dossier_tool(), auditor_dossier_tool_exports));
17032
17067
  gateReviewInstruction = buildGateOfficerReviewInstruction2({
17033
- sourceRunDirectory: options.sourceRunDirectory,
17034
- ...options.submissionCandidatePath === void 0 ? {} : { submissionCandidatePath: options.submissionCandidatePath }
17068
+ submission: options.submission
17035
17069
  });
17036
17070
  }
17037
17071
  const common = {
@@ -17041,7 +17075,9 @@ async function summonGateOfficer(options) {
17041
17075
  ...options.io === void 0 ? {} : { io: options.io },
17042
17076
  ...options.signal === void 0 ? {} : { signal: options.signal },
17043
17077
  ...options.reask === void 0 ? {} : { reviewReask: options.reask },
17044
- ...gateReviewInstruction === void 0 ? {} : { gateReviewInstruction }
17078
+ ...gateReviewInstruction === void 0 ? {} : { gateReviewInstruction },
17079
+ ...options.roleTurnHost === void 0 ? {} : { roleTurnHost: options.roleTurnHost },
17080
+ ...options.createRunId === void 0 ? {} : { createRunId: options.createRunId }
17045
17081
  };
17046
17082
  if (options.officer === "notary") {
17047
17083
  return summonPublicRole({
@@ -18670,13 +18706,11 @@ async function projectGatekeeperRun(options) {
18670
18706
  }
18671
18707
  };
18672
18708
  }
18673
- const submissionCandidatePath = persistGateSubmissionCandidate(
18674
- runDirectory,
18675
- options.context
18676
- );
18709
+ persistGateSubmissionCandidate(runDirectory, options.context);
18710
+ const submission = readLatestSubmissionArguments(options.context);
18677
18711
  let summoned;
18678
18712
  try {
18679
- const summon = options.summonOfficer ?? (async (nextOfficer, sourceRunDirectory, officerSignal, reask) => {
18713
+ const summon = options.summonOfficer ?? (async (nextOfficer, sourceRunDirectory, officerSignal, reask, nextSubmission) => {
18680
18714
  const { summonGateOfficer: summonGateOfficer2 } = await Promise.resolve().then(() => (init_public_role_summons(), public_role_summons_exports));
18681
18715
  return summonGateOfficer2({
18682
18716
  officer: nextOfficer,
@@ -18684,10 +18718,20 @@ async function projectGatekeeperRun(options) {
18684
18718
  cwd: options.context.cwd ?? process.cwd(),
18685
18719
  ...officerSignal === void 0 ? {} : { signal: officerSignal },
18686
18720
  ...reask === void 0 ? {} : { reask },
18687
- ...submissionCandidatePath === void 0 ? {} : { submissionCandidatePath }
18721
+ ...nextSubmission === void 0 ? {} : { submission: nextSubmission },
18722
+ ...options.home === void 0 ? {} : { home: options.home },
18723
+ ...options.packageRoot === void 0 ? {} : { packageRoot: options.packageRoot },
18724
+ ...options.roleTurnHost === void 0 ? {} : { roleTurnHost: options.roleTurnHost },
18725
+ ...options.createRunId === void 0 ? {} : { createRunId: options.createRunId }
18688
18726
  });
18689
18727
  });
18690
- summoned = await summon(officer, runDirectory, options.signal, options.reask);
18728
+ summoned = await summon(
18729
+ officer,
18730
+ runDirectory,
18731
+ options.signal,
18732
+ options.reask,
18733
+ submission
18734
+ );
18691
18735
  } catch (error) {
18692
18736
  return {
18693
18737
  officer,
@@ -24137,7 +24181,7 @@ import { mkdtemp as mkdtemp3, rm as rm3 } from "node:fs/promises";
24137
24181
  import { tmpdir as tmpdir3 } from "node:os";
24138
24182
  import { join as join32 } from "node:path";
24139
24183
  async function runCommand(command, args, options = {}) {
24140
- return await new Promise((resolve19, reject) => {
24184
+ return await new Promise((resolve20, reject) => {
24141
24185
  const child = spawn4(command, args, { ...options.cwd === void 0 ? {} : { cwd: options.cwd }, stdio: ["ignore", "pipe", "pipe"], signal: options.signal });
24142
24186
  let stdout = "", stderr = "";
24143
24187
  child.stdout.setEncoding("utf8").on("data", (chunk) => {
@@ -24157,7 +24201,7 @@ async function runCommand(command, args, options = {}) {
24157
24201
  const actual = code ?? 1;
24158
24202
  if ((options.allowedCodes ?? [0]).includes(actual)) {
24159
24203
  settled = true;
24160
- resolve19({ stdout, stderr, code: actual });
24204
+ resolve20({ stdout, stderr, code: actual });
24161
24205
  } else fail5(void 0, code, signal);
24162
24206
  });
24163
24207
  });
@@ -24621,16 +24665,21 @@ import { join as join33 } from "node:path";
24621
24665
  function resolveAcpBinary(description, operatorHome) {
24622
24666
  return join33(operatorHome, ...description.binaryFromHome);
24623
24667
  }
24624
- function acpStdioArgs(description, model) {
24668
+ function acpStdioArgs(description, model, seat) {
24625
24669
  const { prefix, suffix, modelFlag, thinkingFlag } = description.argv;
24626
24670
  const pair = (flag, value) => flag === void 0 || value === void 0 ? [] : [flag, value];
24627
24671
  return [
24672
+ ...pair(description.seatProfileSoul?.flag, seat?.profileName),
24673
+ ...pair(thinkingFlag, model?.thinking),
24628
24674
  ...prefix,
24629
24675
  ...pair(modelFlag, model?.model),
24630
- ...pair(thinkingFlag, model?.thinking),
24631
24676
  ...suffix
24632
24677
  ];
24633
24678
  }
24679
+ function acpModelId(modelPassing, model) {
24680
+ if (model?.model === void 0) return void 0;
24681
+ return modelPassing === "set_model" ? `${model.provider}:${model.model}` : model.model;
24682
+ }
24634
24683
 
24635
24684
  // src/acp-host/role-envelope.ts
24636
24685
  init_gatekeeper_pass_envelope();
@@ -24732,8 +24781,8 @@ function connectAcpStdio(options) {
24732
24781
  request(method, params) {
24733
24782
  if (closed) return Promise.reject(terminalError ?? acpError("acp-connection-closed", "ACP connection is closed"));
24734
24783
  const id = ++nextId;
24735
- return new Promise((resolve19, reject) => {
24736
- pending.set(id, { resolve: resolve19, reject });
24784
+ return new Promise((resolve20, reject) => {
24785
+ pending.set(id, { resolve: resolve20, reject });
24737
24786
  child.stdin.write(`${JSON.stringify({ jsonrpc: "2.0", id, method, params })}
24738
24787
  `, (error) => {
24739
24788
  if (error === null || error === void 0) return;
@@ -24757,7 +24806,7 @@ function connectAcpStdio(options) {
24757
24806
  settleClosed(acpError("acp-connection-closed", "ACP connection is closed"));
24758
24807
  child.stdin.end();
24759
24808
  child.kill("SIGTERM");
24760
- await new Promise((resolve19) => child.once("close", () => resolve19()));
24809
+ await new Promise((resolve20) => child.once("close", () => resolve20()));
24761
24810
  }
24762
24811
  });
24763
24812
  }
@@ -24768,6 +24817,7 @@ function createAcpRoleTurnHost(config) {
24768
24817
  const execution = serial.then(async () => {
24769
24818
  const continuation = request.continuation;
24770
24819
  const prepared = await config.prepare(request);
24820
+ const systemPromptOverride = renderAcpSystemPromptOverride(prepared.systemPrompt);
24771
24821
  let connection;
24772
24822
  let sessionId;
24773
24823
  let accepted = false;
@@ -24783,40 +24833,47 @@ function createAcpRoleTurnHost(config) {
24783
24833
  const initializeMeta = initialized._meta;
24784
24834
  const modelState = initializeMeta?.modelState;
24785
24835
  const availableModels = Array.isArray(modelState?.availableModels) ? modelState.availableModels : void 0;
24786
- if (request.model !== void 0 && availableModels !== void 0 && !availableModels.some((entry) => typeof entry === "object" && entry !== null && entry.modelId === request.model?.model)) {
24836
+ if (request.model !== void 0 && availableModels !== void 0 && !availableModels.some((entry) => typeof entry === "object" && entry !== null && entry.modelId === acpModelId(config.modelPassing, request.model))) {
24787
24837
  return failure("activation", "AcpHostModelMismatch", "host-model-mismatch", {
24788
24838
  provider: request.model.provider,
24789
24839
  model: request.model.model
24790
24840
  });
24791
24841
  }
24792
24842
  const priorNativePaths = continuation.kind === "resume" ? request.hostTransition?.priorNativePaths : void 0;
24843
+ const loadConnection = connection;
24844
+ const sessionBindParams = {
24845
+ cwd: request.cwd,
24846
+ mcpServers: prepared.mcpServers,
24847
+ _meta: { systemPromptOverride, yoloMode: false }
24848
+ };
24849
+ const loadSession = async (bindSessionId) => {
24850
+ const loaded = await loadConnection.request("session/load", {
24851
+ sessionId: bindSessionId,
24852
+ ...sessionBindParams
24853
+ });
24854
+ return typeof loaded.sessionId === "string" && loaded.sessionId !== "" ? loaded.sessionId : bindSessionId;
24855
+ };
24793
24856
  if (continuation.kind === "resume" && config.boundResume === "session/load") {
24794
24857
  const boundSessionId = await config.sessionIdentity.load(request.principal);
24795
24858
  if (boundSessionId !== void 0 && boundSessionId !== "") {
24796
- const loaded = await connection.request("session/load", {
24797
- sessionId: boundSessionId,
24798
- cwd: request.cwd,
24799
- mcpServers: prepared.mcpServers,
24800
- _meta: { systemPromptOverride: renderAcpSystemPromptOverride(prepared.systemPrompt), yoloMode: false }
24801
- });
24802
- sessionId = typeof loaded.sessionId === "string" && loaded.sessionId !== "" ? loaded.sessionId : boundSessionId;
24859
+ sessionId = await loadSession(boundSessionId);
24803
24860
  }
24804
24861
  }
24805
24862
  if (sessionId === void 0) {
24806
- const session = await connection.request(
24807
- "session/new",
24808
- {
24809
- cwd: request.cwd,
24810
- mcpServers: prepared.mcpServers,
24811
- _meta: { systemPromptOverride: renderAcpSystemPromptOverride(prepared.systemPrompt), yoloMode: false }
24812
- }
24813
- );
24863
+ const session = await connection.request("session/new", sessionBindParams);
24814
24864
  sessionId = typeof session.sessionId === "string" ? session.sessionId : void 0;
24815
24865
  if (sessionId === void 0 || sessionId === "") {
24816
24866
  return failure("session", "AcpSessionFailure", "session-id-missing");
24817
24867
  }
24818
24868
  await config.sessionIdentity.bind(request.principal, sessionId);
24819
24869
  }
24870
+ if (config.modelPassing === "set_model" && request.model !== void 0 && sessionId !== void 0) {
24871
+ await connection.request("session/set_model", {
24872
+ sessionId,
24873
+ modelId: acpModelId(config.modelPassing, request.model)
24874
+ });
24875
+ sessionId = await loadSession(sessionId);
24876
+ }
24820
24877
  let prompt = priorNativePaths !== void 0 && priorNativePaths.length > 0 ? `${prepared.prompt}
24821
24878
  ${priorNativePaths.join("\n")}` : prepared.prompt;
24822
24879
  const abortSignal = request.signal === void 0 ? prepared.abortSignal : prepared.abortSignal === void 0 ? request.signal : AbortSignal.any([prepared.abortSignal, request.signal]);
@@ -24827,7 +24884,7 @@ ${priorNativePaths.join("\n")}` : prepared.prompt;
24827
24884
  }
24828
24885
  const promptRequest = activeConnection.request("session/prompt", params);
24829
24886
  if (abortSignal === void 0) return promptRequest;
24830
- return new Promise((resolve19, reject) => {
24887
+ return new Promise((resolve20, reject) => {
24831
24888
  let settled = false;
24832
24889
  const onAbort = () => {
24833
24890
  if (settled) return;
@@ -24842,7 +24899,7 @@ ${priorNativePaths.join("\n")}` : prepared.prompt;
24842
24899
  if (settled) return;
24843
24900
  settled = true;
24844
24901
  abortSignal.removeEventListener("abort", onAbort);
24845
- resolve19(value);
24902
+ resolve20(value);
24846
24903
  },
24847
24904
  (error) => {
24848
24905
  if (settled) return;
@@ -24856,12 +24913,9 @@ ${priorNativePaths.join("\n")}` : prepared.prompt;
24856
24913
  for (let attempt = 0; attempt < 8; attempt += 1) {
24857
24914
  let result;
24858
24915
  try {
24859
- const promptParts = [
24860
- { type: "text", text: prompt }
24861
- ];
24862
24916
  result = await promptOrAbort({
24863
24917
  sessionId,
24864
- prompt: promptParts
24918
+ prompt: [{ type: "text", text: prompt }]
24865
24919
  });
24866
24920
  } catch (error) {
24867
24921
  if (typeof error === "object" && error !== null && error.code === "host-aborted") {
@@ -24966,11 +25020,11 @@ function projectAcpActivationFlags(request) {
24966
25020
  return flags;
24967
25021
  }
24968
25022
  async function listen(server, path) {
24969
- await new Promise((resolve19, reject) => {
25023
+ await new Promise((resolve20, reject) => {
24970
25024
  server.once("error", reject);
24971
25025
  server.listen(path, () => {
24972
25026
  server.off("error", reject);
24973
- resolve19();
25027
+ resolve20();
24974
25028
  });
24975
25029
  });
24976
25030
  }
@@ -25361,8 +25415,8 @@ async function prepareAcpRoleEnvelope(options) {
25361
25415
  try {
25362
25416
  const closeAll = server.closeAllConnections;
25363
25417
  if (typeof closeAll === "function") closeAll.call(server);
25364
- await new Promise((resolve19, reject) => {
25365
- server.close((error) => error ? reject(error) : resolve19());
25418
+ await new Promise((resolve20, reject) => {
25419
+ server.close((error) => error ? reject(error) : resolve20());
25366
25420
  });
25367
25421
  } catch (error) {
25368
25422
  cleanupFailures.push(error);
@@ -25470,11 +25524,70 @@ async function prepareAcpRoleEnvelope(options) {
25470
25524
  }
25471
25525
  }
25472
25526
 
25527
+ // src/acp-host/seat-profile-soul.ts
25528
+ import { constants as constants3 } from "node:fs";
25529
+ import { access as access4, copyFile, lstat as lstat6, mkdir as mkdir6, readlink, symlink, unlink as unlink4 } from "node:fs/promises";
25530
+ import { dirname as dirname18, join as join35, relative as relative3, resolve as resolve19 } from "node:path";
25531
+ function seatProfileName(spec, role) {
25532
+ return `${spec.namePrefix}${role}`;
25533
+ }
25534
+ function packageRoleSoulPath(packageRoot, role) {
25535
+ return join35(packageRoot, "souls", `${role}.md`);
25536
+ }
25537
+ async function pathExists(path) {
25538
+ try {
25539
+ await access4(path, constants3.F_OK);
25540
+ return true;
25541
+ } catch {
25542
+ return false;
25543
+ }
25544
+ }
25545
+ async function ensureSeatProfileSoul(options) {
25546
+ const { spec, operatorHome, packageRoot, role } = options;
25547
+ const profileName = seatProfileName(spec, role);
25548
+ const soulTarget = resolve19(packageRoleSoulPath(packageRoot, role));
25549
+ if (!await pathExists(soulTarget)) {
25550
+ throw new Error(`packaged role soul missing: ${soulTarget}`);
25551
+ }
25552
+ const profilesRoot = join35(operatorHome, ...spec.profilesRootFromHome);
25553
+ const profileDir = join35(profilesRoot, profileName);
25554
+ const hostRoot = dirname18(profilesRoot);
25555
+ const soulPath = join35(profileDir, spec.soulFileName);
25556
+ if (!await pathExists(profileDir)) {
25557
+ await mkdir6(profileDir, { recursive: true });
25558
+ for (const name of ["auth.json", ".env", "config.yaml"]) {
25559
+ const source = join35(hostRoot, name);
25560
+ if (!await pathExists(source)) continue;
25561
+ await copyFile(source, join35(profileDir, name));
25562
+ }
25563
+ } else {
25564
+ await mkdir6(profileDir, { recursive: true });
25565
+ }
25566
+ const desiredLink = relative3(profileDir, soulTarget);
25567
+ let current;
25568
+ try {
25569
+ const st = await lstat6(soulPath);
25570
+ if (st.isSymbolicLink()) {
25571
+ current = await readlink(soulPath);
25572
+ }
25573
+ } catch {
25574
+ current = void 0;
25575
+ }
25576
+ if (current === desiredLink || current === soulTarget) {
25577
+ return profileName;
25578
+ }
25579
+ if (await pathExists(soulPath) || current !== void 0) {
25580
+ await unlink4(soulPath);
25581
+ }
25582
+ await symlink(desiredLink, soulPath);
25583
+ return profileName;
25584
+ }
25585
+
25473
25586
  // src/acp-host/session-identity.ts
25474
- import { mkdir as mkdir6, readFile as readFile19, rename, writeFile as writeFile9 } from "node:fs/promises";
25475
- import { dirname as dirname18, join as join35 } from "node:path";
25587
+ import { mkdir as mkdir7, readFile as readFile19, rename, writeFile as writeFile9 } from "node:fs/promises";
25588
+ import { dirname as dirname19, join as join36 } from "node:path";
25476
25589
  function createAcpSessionIdentityAuthority(authority, sessionBindingFile) {
25477
- const bindingPath = (principal) => join35(authority.decode(principal).sessionDirectory, sessionBindingFile);
25590
+ const bindingPath = (principal) => join36(authority.decode(principal).sessionDirectory, sessionBindingFile);
25478
25591
  return {
25479
25592
  resolveSessionFile(principal) {
25480
25593
  return authority.decode(principal).sessionFile;
@@ -25493,7 +25606,7 @@ function createAcpSessionIdentityAuthority(authority, sessionBindingFile) {
25493
25606
  },
25494
25607
  async bind(principal, sessionId) {
25495
25608
  const target = bindingPath(principal);
25496
- await mkdir6(dirname18(target), { recursive: true });
25609
+ await mkdir7(dirname19(target), { recursive: true });
25497
25610
  const temporary = `${target}.${process.pid}.tmp`;
25498
25611
  await writeFile9(temporary, `${JSON.stringify({ sessionId })}
25499
25612
  `, { encoding: "utf8", mode: 384 });
@@ -25580,11 +25693,23 @@ function createProductionAcpRoleTurnHost(options) {
25580
25693
  return createComposedAcpRoleTurnHost({
25581
25694
  sessionIdentity: createAcpSessionIdentityAuthority(principalAuthority, description.sessionBindingFile),
25582
25695
  boundResume: description.boundResume,
25696
+ modelPassing: description.modelPassing,
25583
25697
  roleRuntimeDependencies: createAcpRoleRuntimeDependencies(packageRoot),
25584
25698
  async connect(request) {
25699
+ const seatProfile = description.seatProfileSoul;
25700
+ const profileName = seatProfile === void 0 ? void 0 : await ensureSeatProfileSoul({
25701
+ spec: seatProfile,
25702
+ operatorHome: request.home,
25703
+ packageRoot,
25704
+ role: request.activation.role
25705
+ });
25585
25706
  return connectAcpStdio({
25586
25707
  binary: resolveAcpBinary(description, request.home),
25587
- args: acpStdioArgs(description, request.model),
25708
+ args: acpStdioArgs(
25709
+ description,
25710
+ request.model,
25711
+ profileName === void 0 ? void 0 : { profileName }
25712
+ ),
25588
25713
  cwd: request.cwd,
25589
25714
  env
25590
25715
  });