@akagilnc/pi-workflow-roles 0.1.2048 → 0.1.2052

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.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@akagilnc/pi-workflow-roles",
3
- "version": "0.1.2048",
3
+ "version": "0.1.2052",
4
4
  "description": "Soul-bound workflow roles for Pi",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -0,0 +1,32 @@
1
+ # codex engine method material
2
+
3
+ This file is packaged method material for the optional `codex` labor engine.
4
+ When a role run selects this engine, read these bytes and follow the local CLI's
5
+ actual interface for the labor detour. Return the labor result to the same role
6
+ session so typed submission stays on the existing in-session path.
7
+
8
+ Material is data for the model, not a code contract. Do not invent package flags.
9
+
10
+ ## Invocation examples (local Codex CLI)
11
+
12
+ Non-interactive labor prompt (working root = role project):
13
+
14
+ ```bash
15
+ codex exec -C "$PROJECT_ROOT" "YOUR_LABOR_PROMPT"
16
+ ```
17
+
18
+ Write the last agent message to a file, then bring that text back into the role
19
+ session:
20
+
21
+ ```bash
22
+ codex exec -C "$PROJECT_ROOT" -o /tmp/codex-labor-last.txt "YOUR_LABOR_PROMPT"
23
+ ```
24
+
25
+ JSON event stream when the host needs machine-readable progress:
26
+
27
+ ```bash
28
+ codex exec --json -C "$PROJECT_ROOT" "YOUR_LABOR_PROMPT"
29
+ ```
30
+
31
+ Prefer the installed `codex` binary's own `--help` / `codex exec --help` over
32
+ any remembered flag set. Do not wrap this engine behind `ak-role` flags.
@@ -0,0 +1,32 @@
1
+ # cursor engine method material
2
+
3
+ This file is packaged method material for the optional `cursor` labor engine.
4
+ When a role run selects this engine, read these bytes and follow the local CLI's
5
+ actual interface for the labor detour. Return the labor result to the same role
6
+ session so typed submission stays on the existing in-session path.
7
+
8
+ Material is data for the model, not a code contract. Do not invent package flags.
9
+
10
+ ## Invocation examples (local Cursor Agent CLI)
11
+
12
+ The machine entrypoint is `agent` (also exposed as `cursor-agent`). Run from the
13
+ role project root. Non-interactive print mode:
14
+
15
+ ```bash
16
+ agent -p --force --output-format text "YOUR_LABOR_PROMPT"
17
+ ```
18
+
19
+ Choose a model explicitly when the seat needs a known Cursor model id:
20
+
21
+ ```bash
22
+ agent -p --force --model grok-4.5 --output-format text "YOUR_LABOR_PROMPT"
23
+ ```
24
+
25
+ Stream JSON events for long labor:
26
+
27
+ ```bash
28
+ agent -p --force --output-format stream-json "YOUR_LABOR_PROMPT"
29
+ ```
30
+
31
+ Prefer `agent --help` on the host over any remembered flag set. Do not wrap this
32
+ engine behind `ak-role` flags.
@@ -0,0 +1,31 @@
1
+ # kimi engine method material
2
+
3
+ This file is packaged method material for the optional `kimi` labor engine.
4
+ When a role run selects this engine, read these bytes and follow the local CLI's
5
+ actual interface for the labor detour. Return the labor result to the same role
6
+ session so typed submission stays on the existing in-session path.
7
+
8
+ Material is data for the model, not a code contract. Do not invent package flags.
9
+
10
+ ## Invocation examples (local Kimi Code CLI)
11
+
12
+ One-shot non-interactive prompt from the role project root:
13
+
14
+ ```bash
15
+ kimi --yolo -p "YOUR_LABOR_PROMPT"
16
+ ```
17
+
18
+ Pin a model alias when needed:
19
+
20
+ ```bash
21
+ kimi --yolo -m <model-alias> -p "YOUR_LABOR_PROMPT"
22
+ ```
23
+
24
+ Machine-readable prompt mode:
25
+
26
+ ```bash
27
+ kimi --yolo --output-format text -p "YOUR_LABOR_PROMPT"
28
+ ```
29
+
30
+ Prefer `kimi --help` on the host over any remembered flag set. Do not wrap this
31
+ engine behind `ak-role` flags.
@@ -0,0 +1,111 @@
1
+ /**
2
+ * Packaged engine method-material seam (#356 T1 / ADR 0069).
3
+ * Legal engine names = directory stems under resources/engines/ — no code whitelist.
4
+ * Material body is data for the LLM, not a code contract.
5
+ */
6
+ import { existsSync, readdirSync } from "node:fs";
7
+ import { join } from "node:path";
8
+
9
+ const ENGINE_MATERIAL_RELATIVE_ROOT = "resources/engines" as const;
10
+
11
+ export type EngineSessionMaterial = Readonly<{
12
+ name: string;
13
+ materialPath: string;
14
+ }>;
15
+
16
+ /** Non-empty, trimmed, no path separators or traversal. */
17
+ export function isEngineNameSyntax(name: string): boolean {
18
+ if (typeof name !== "string") return false;
19
+ if (name.length === 0 || name.trim() !== name) return false;
20
+ if (name === "." || name === "..") return false;
21
+ if (name.includes("/") || name.includes("\\") || name.includes("\0")) return false;
22
+ if (name.includes("..")) return false;
23
+ return true;
24
+ }
25
+
26
+ export function engineMaterialRelativeDirectory(): string {
27
+ return ENGINE_MATERIAL_RELATIVE_ROOT;
28
+ }
29
+
30
+ export function resolveEngineMaterialDirectory(packageRoot: string): string {
31
+ return join(packageRoot, ENGINE_MATERIAL_RELATIVE_ROOT);
32
+ }
33
+
34
+ /**
35
+ * Enumerate legal engine names from packaged material files.
36
+ * Only `*.md` stems that pass name syntax are legal.
37
+ */
38
+ export function listEngineMaterialNames(packageRoot: string): readonly string[] {
39
+ const dir = resolveEngineMaterialDirectory(packageRoot);
40
+ if (!existsSync(dir)) return Object.freeze([]);
41
+ const names = readdirSync(dir)
42
+ .filter((entry) => entry.endsWith(".md"))
43
+ .map((entry) => entry.slice(0, -".md".length))
44
+ .filter((stem) => isEngineNameSyntax(stem))
45
+ .sort();
46
+ return Object.freeze([...names]);
47
+ }
48
+
49
+ export function resolveEngineMaterialPath(
50
+ packageRoot: string,
51
+ name: string,
52
+ ): string {
53
+ const legal = assertLegalEngineName(packageRoot, name);
54
+ return join(resolveEngineMaterialDirectory(packageRoot), `${legal}.md`);
55
+ }
56
+
57
+ /**
58
+ * Assert `name` is a legal engine material stem under packageRoot.
59
+ * Returns the canonical name on success; throws Error on illegal.
60
+ */
61
+ export function assertLegalEngineName(packageRoot: string, name: string): string {
62
+ if (!isEngineNameSyntax(name)) {
63
+ throw new Error(`illegal engine name: ${name}`);
64
+ }
65
+ const legal = listEngineMaterialNames(packageRoot);
66
+ if (!legal.includes(name)) {
67
+ throw new Error(
68
+ `unknown engine: ${name} (known: ${legal.length === 0 ? "(none)" : legal.join(", ")})`,
69
+ );
70
+ }
71
+ return name;
72
+ }
73
+
74
+ /**
75
+ * Resolve optional engine options into session material coordinates.
76
+ * No engine → undefined (caller keeps default prompt bytes).
77
+ */
78
+ export function engineSessionMaterialFromOptions(options: {
79
+ engine?: string;
80
+ packageRoot?: string;
81
+ }): EngineSessionMaterial | undefined {
82
+ if (options.engine === undefined) return undefined;
83
+ if (options.packageRoot === undefined || options.packageRoot.trim() === "") {
84
+ throw new Error("packageRoot is required when engine is configured");
85
+ }
86
+ const name = assertLegalEngineName(options.packageRoot, options.engine);
87
+ return Object.freeze({
88
+ name,
89
+ materialPath: resolveEngineMaterialPath(options.packageRoot, name),
90
+ });
91
+ }
92
+
93
+ /**
94
+ * Append engine method-material path delivery to session initial material lines.
95
+ * No material → identity copy (byte-stable when joined the same way).
96
+ * Delivers engine name + absolute material path only — never material body.
97
+ */
98
+ export function appendEngineSessionMaterial(
99
+ lines: readonly string[],
100
+ engineMaterial?: EngineSessionMaterial,
101
+ ): string[] {
102
+ if (engineMaterial === undefined) {
103
+ return [...lines];
104
+ }
105
+ const out = [...lines];
106
+ out.push("");
107
+ out.push("Engine method material (read these bytes and follow them):");
108
+ out.push(`- engine: ${engineMaterial.name}`);
109
+ out.push(`- ${engineMaterial.materialPath}`);
110
+ return out;
111
+ }
@@ -5,6 +5,9 @@ import { realpath } from "node:fs/promises";
5
5
  import { homedir } from "node:os";
6
6
  import { join } from "node:path";
7
7
 
8
+ import {
9
+ assertLegalEngineName,
10
+ } from "../package-resources/engine-material.ts";
8
11
  import {
9
12
  effectiveSeatConfigurations,
10
13
  formatModelSpec,
@@ -14,6 +17,8 @@ import {
14
17
  resolveEffectiveSeat,
15
18
  savePublicCliConfig,
16
19
  setPersistentSeatConfig,
20
+ setPersistentSeatEngine,
21
+ validatePublicCliConfigEngines,
17
22
  type CredentialProviders,
18
23
  type EffectiveSeat,
19
24
  type InvocationModelOverride,
@@ -94,7 +99,8 @@ export const PUBLIC_GLOBAL_OPTIONS: readonly PublicOptionDefinition[] =
94
99
  type TakenPublicGlobalFlag =
95
100
  | { flag: "help"; consume: 1 }
96
101
  | { flag: "model"; consume: 1 | 2; value: string | undefined }
97
- | { flag: "thinking"; consume: 1 | 2; raw: string | undefined };
102
+ | { flag: "thinking"; consume: 1 | 2; raw: string | undefined }
103
+ | { flag: "engine"; consume: 1 | 2; value: string | undefined };
98
104
 
99
105
  /**
100
106
  * If `argv[index]` is a public global flag, describe its span and payload.
@@ -127,6 +133,13 @@ function takePublicGlobalFlag(
127
133
  raw: taken.value,
128
134
  };
129
135
  }
136
+ if (taken.def.id === "engine") {
137
+ return {
138
+ flag: "engine",
139
+ consume: consumed as 1 | 2,
140
+ value: taken.value,
141
+ };
142
+ }
130
143
  return undefined;
131
144
  }
132
145
 
@@ -217,6 +230,7 @@ type ParsedGlobal = {
217
230
  args: string[];
218
231
  model?: string;
219
232
  thinking?: PublicThinkingLevel;
233
+ engine?: string;
220
234
  help: boolean;
221
235
  };
222
236
 
@@ -231,6 +245,7 @@ function parseArgv(argv: readonly string[]): ParsedGlobal {
231
245
  const args = [...argv];
232
246
  let model: string | undefined;
233
247
  let thinking: PublicThinkingLevel | undefined;
248
+ let engine: string | undefined;
234
249
  let help = false;
235
250
  const positional: string[] = [];
236
251
  const globalOptions = createTypedOptionConsumer(PUBLIC_GLOBAL_OPTIONS);
@@ -259,12 +274,24 @@ function parseArgv(argv: readonly string[]): ParsedGlobal {
259
274
  args.splice(0, taken.consume);
260
275
  continue;
261
276
  }
262
- if (taken.raw === undefined) {
263
- throw new CliUsageError("--thinking requires a value");
277
+ if (taken.flag === "thinking") {
278
+ if (taken.raw === undefined) {
279
+ throw new CliUsageError("--thinking requires a value");
280
+ }
281
+ thinking = parseThinking(taken.raw);
282
+ args.splice(0, taken.consume);
283
+ continue;
284
+ }
285
+ if (taken.flag === "engine") {
286
+ if (taken.value === undefined) {
287
+ throw new CliUsageError("--engine requires a value");
288
+ }
289
+ engine = taken.value;
290
+ args.splice(0, taken.consume);
291
+ continue;
264
292
  }
265
- thinking = parseThinking(taken.raw);
266
- args.splice(0, taken.consume);
267
- continue;
293
+ // Exhaustive for known global flags; unknown id is a table bug.
294
+ throw new CliUsageError(`unhandled global option: ${String((taken as { flag: string }).flag)}`);
268
295
  }
269
296
  // Subcommands may own additional flags later; unknown dashed tokens stay
270
297
  // positional here (same as pre-unification parseArgv).
@@ -277,18 +304,54 @@ function parseArgv(argv: readonly string[]): ParsedGlobal {
277
304
  args: rest,
278
305
  ...(model === undefined ? {} : { model }),
279
306
  ...(thinking === undefined ? {} : { thinking }),
307
+ ...(engine === undefined ? {} : { engine }),
280
308
  help,
281
309
  };
282
310
  }
283
311
 
284
312
  function invocationFromParsed(parsed: ParsedGlobal): InvocationModelOverride | undefined {
285
- if (parsed.model === undefined && parsed.thinking === undefined) return undefined;
313
+ if (
314
+ parsed.model === undefined &&
315
+ parsed.thinking === undefined &&
316
+ parsed.engine === undefined
317
+ ) {
318
+ return undefined;
319
+ }
286
320
  return {
287
321
  ...(parsed.model === undefined ? {} : { model: parsed.model }),
288
322
  ...(parsed.thinking === undefined ? {} : { thinking: parsed.thinking }),
323
+ ...(parsed.engine === undefined ? {} : { engine: parsed.engine }),
289
324
  };
290
325
  }
291
326
 
327
+ function requireLegalEngineName(packageRoot: string, name: string): string {
328
+ try {
329
+ return assertLegalEngineName(packageRoot, name);
330
+ } catch (error) {
331
+ throw new CliUsageError(
332
+ error instanceof Error ? error.message : String(error),
333
+ { cause: error },
334
+ );
335
+ }
336
+ }
337
+
338
+ function loadAndValidateConfig(
339
+ home: string,
340
+ packageRoot: string,
341
+ ): Promise<PublicCliConfig> {
342
+ return loadPublicCliConfig(home).then((config) => {
343
+ try {
344
+ validatePublicCliConfigEngines(config, packageRoot);
345
+ } catch (error) {
346
+ throw new CliUsageError(
347
+ error instanceof Error ? error.message : String(error),
348
+ { cause: error },
349
+ );
350
+ }
351
+ return config;
352
+ });
353
+ }
354
+
292
355
  /** Typed facts used by help presentation — not layout. */
293
356
  export function helpDocument() {
294
357
  return {
@@ -355,6 +418,7 @@ function renderHelp(): string {
355
418
  "",
356
419
  "Role options: ak-role help <command>",
357
420
  "Persistent config: ak-role config set <seat> <provider/model:thinking>",
421
+ "Persistent engine (judge only): ak-role config set-engine judge <name> | unset-engine judge",
358
422
  "Effective seats: ak-role roles",
359
423
  );
360
424
  return `${lines.join("\n")}\n`;
@@ -398,7 +462,7 @@ function renderRoles(seats: readonly EffectiveSeat[]): string {
398
462
  }
399
463
 
400
464
  function renderConfig(config: PublicCliConfig): string {
401
- const lines: string[] = ["seat\tmodel"];
465
+ const lines: string[] = ["seat\tmodel\tengine"];
402
466
  const keys = Object.keys(config.seats) as (keyof typeof config.seats)[];
403
467
  if (keys.length === 0) {
404
468
  lines.push("(empty)");
@@ -406,7 +470,8 @@ function renderConfig(config: PublicCliConfig): string {
406
470
  for (const seat of keys.sort()) {
407
471
  const selection = config.seats[seat];
408
472
  if (selection === undefined) continue;
409
- lines.push(`${seat}\t${formatModelSpec(selection)}`);
473
+ const engine = selection.engine === undefined ? "-" : selection.engine;
474
+ lines.push(`${seat}\t${formatModelSpec(selection)}\t${engine}`);
410
475
  }
411
476
  }
412
477
  return `${lines.join("\n")}\n`;
@@ -415,10 +480,11 @@ function renderConfig(config: PublicCliConfig): string {
415
480
  async function runConfigCommand(
416
481
  args: readonly string[],
417
482
  home: string,
483
+ packageRoot: string,
418
484
  io: CliIo,
419
485
  ): Promise<number> {
420
486
  if (args.length === 0 || args[0] === "get" || args[0] === "list" || args[0] === "show") {
421
- const config = await loadPublicCliConfig(home);
487
+ const config = await loadAndValidateConfig(home, packageRoot);
422
488
  if (args[0] === "get" && args[1] !== undefined) {
423
489
  if (!isPublicConfigurableSeat(args[1])) {
424
490
  throw new CliUsageError(`unknown configurable seat: ${args[1]}`);
@@ -427,7 +493,9 @@ async function runConfigCommand(
427
493
  if (selection === undefined) {
428
494
  io.stdout(`${args[1]}\t(unconfigured)\n`);
429
495
  } else {
430
- io.stdout(`${args[1]}\t${formatModelSpec(selection)}\n`);
496
+ const engine =
497
+ selection.engine === undefined ? "-" : selection.engine;
498
+ io.stdout(`${args[1]}\t${formatModelSpec(selection)}\t${engine}\n`);
431
499
  }
432
500
  return 0;
433
501
  }
@@ -448,7 +516,7 @@ async function runConfigCommand(
448
516
  "config set requires seat/spec pairs: ak-role config set <seat> <spec> [<seat> <spec> ...]",
449
517
  );
450
518
  }
451
- let config = await loadPublicCliConfig(home);
519
+ let config = await loadAndValidateConfig(home, packageRoot);
452
520
  for (let i = 0; i < pairs.length; i += 2) {
453
521
  const seat = pairs[i]!;
454
522
  const spec = pairs[i + 1]!;
@@ -462,6 +530,66 @@ async function runConfigCommand(
462
530
  return 0;
463
531
  }
464
532
 
533
+ if (args[0] === "set-engine") {
534
+ if (args.length !== 3) {
535
+ throw new CliUsageError(
536
+ "usage: ak-role config set-engine judge <name>",
537
+ );
538
+ }
539
+ const seat = args[1]!;
540
+ const name = args[2]!;
541
+ if (!isPublicConfigurableSeat(seat)) {
542
+ throw new CliUsageError(`unknown configurable seat: ${seat}`);
543
+ }
544
+ if (seat !== "judge") {
545
+ throw new CliUsageError(
546
+ `engine axis is judge-only; refused seat ${seat}`,
547
+ );
548
+ }
549
+ requireLegalEngineName(packageRoot, name);
550
+ let config = await loadAndValidateConfig(home, packageRoot);
551
+ try {
552
+ config = setPersistentSeatEngine(config, seat, name);
553
+ } catch (error) {
554
+ throw new CliUsageError(
555
+ error instanceof Error ? error.message : String(error),
556
+ { cause: error },
557
+ );
558
+ }
559
+ await savePublicCliConfig(config, home);
560
+ io.stdout(renderConfig(config));
561
+ return 0;
562
+ }
563
+
564
+ if (args[0] === "unset-engine") {
565
+ if (args.length !== 2) {
566
+ throw new CliUsageError(
567
+ "usage: ak-role config unset-engine judge",
568
+ );
569
+ }
570
+ const seat = args[1]!;
571
+ if (!isPublicConfigurableSeat(seat)) {
572
+ throw new CliUsageError(`unknown configurable seat: ${seat}`);
573
+ }
574
+ if (seat !== "judge") {
575
+ throw new CliUsageError(
576
+ `engine axis is judge-only; refused seat ${seat}`,
577
+ );
578
+ }
579
+ let config = await loadAndValidateConfig(home, packageRoot);
580
+ try {
581
+ config = setPersistentSeatEngine(config, seat, undefined);
582
+ } catch (error) {
583
+ throw new CliUsageError(
584
+ error instanceof Error ? error.message : String(error),
585
+ { cause: error },
586
+ );
587
+ }
588
+ await savePublicCliConfig(config, home);
589
+ io.stdout(renderConfig(config));
590
+ return 0;
591
+ }
592
+
465
593
  throw new CliUsageError(`unknown config subcommand: ${args[0]}`);
466
594
  }
467
595
 
@@ -477,6 +605,21 @@ export async function runAkRole(
477
605
  // runtime entry, activation argv, or invocation provenance is derived.
478
606
  env = { ...env, packageRoot: await realpath(env.packageRoot) };
479
607
  const parsed = parseArgv(argv);
608
+ // Invocation --engine rejects at the call-request seam (not role submission).
609
+ // #356 MVP: engine axis is Judge-only (not resume / non-Judge seats).
610
+ if (parsed.engine !== undefined) {
611
+ requireLegalEngineName(env.packageRoot, parsed.engine);
612
+ if (
613
+ !parsed.help &&
614
+ parsed.command !== undefined &&
615
+ parsed.command !== "help" &&
616
+ parsed.command !== "judge"
617
+ ) {
618
+ throw new CliUsageError(
619
+ `engine axis is judge-only; refused command ${parsed.command}`,
620
+ );
621
+ }
622
+ }
480
623
 
481
624
  if (
482
625
  parsed.help ||
@@ -501,7 +644,7 @@ export async function runAkRole(
501
644
  if (parsed.args.length > 0) {
502
645
  throw new CliUsageError("roles takes no arguments");
503
646
  }
504
- const config = await loadPublicCliConfig(home);
647
+ const config = await loadAndValidateConfig(home, env.packageRoot);
505
648
  const credentials =
506
649
  env.credentials ??
507
650
  (await loadCredentialProviders(resolveAgentDir(env, home)));
@@ -515,7 +658,9 @@ export async function runAkRole(
515
658
  }
516
659
 
517
660
  if (parsed.command === "config") {
518
- return { exitCode: await runConfigCommand(parsed.args, home, io) };
661
+ return {
662
+ exitCode: await runConfigCommand(parsed.args, home, env.packageRoot, io),
663
+ };
519
664
  }
520
665
 
521
666
  // Resume reopens an exact Role run after a typed HTTP 429 (#108/#109).
@@ -523,7 +668,7 @@ export async function runAkRole(
523
668
  if (parsed.command === "resume") {
524
669
  const agentDir = resolveAgentDir(env, home);
525
670
  const cwd = env.cwd ?? process.cwd();
526
- const config = await loadPublicCliConfig(home);
671
+ const config = await loadAndValidateConfig(home, env.packageRoot);
527
672
  const credentials =
528
673
  env.credentials ?? (await loadCredentialProviders(agentDir));
529
674
  const resumeRunId = parsed.args[0];
@@ -706,7 +851,7 @@ export async function runAkRole(
706
851
  if (parsed.command === "judge") {
707
852
  const agentDir = resolveAgentDir(env, home);
708
853
  const cwd = env.cwd ?? process.cwd();
709
- const config = await loadPublicCliConfig(home);
854
+ const config = await loadAndValidateConfig(home, env.packageRoot);
710
855
  const credentials =
711
856
  env.credentials ?? (await loadCredentialProviders(agentDir));
712
857
  const seat = resolveEffectiveSeat(
@@ -728,6 +873,7 @@ export async function runAkRole(
728
873
  : { correlationId: env.correlationId }),
729
874
  ...(env.piRunner === undefined ? {} : { piRunner: env.piRunner }),
730
875
  ...(seat.selection === undefined ? {} : { model: seat.selection }),
876
+ ...(seat.engine === undefined ? {} : { engine: seat.engine }),
731
877
  ...(env.judgeExtraPiArgs === undefined
732
878
  ? {}
733
879
  : { extraPiArgs: env.judgeExtraPiArgs }),
@@ -749,7 +895,7 @@ export async function runAkRole(
749
895
  if (parsed.command === "coder") {
750
896
  const agentDir = resolveAgentDir(env, home);
751
897
  const cwd = env.cwd ?? process.cwd();
752
- const config = await loadPublicCliConfig(home);
898
+ const config = await loadAndValidateConfig(home, env.packageRoot);
753
899
  const credentials =
754
900
  env.credentials ?? (await loadCredentialProviders(agentDir));
755
901
  const seat = resolveEffectiveSeat(
@@ -792,7 +938,7 @@ export async function runAkRole(
792
938
  if (parsed.command === "fixer") {
793
939
  const agentDir = resolveAgentDir(env, home);
794
940
  const cwd = env.cwd ?? process.cwd();
795
- const config = await loadPublicCliConfig(home);
941
+ const config = await loadAndValidateConfig(home, env.packageRoot);
796
942
  const credentials =
797
943
  env.credentials ?? (await loadCredentialProviders(agentDir));
798
944
  const seat = resolveEffectiveSeat(
@@ -835,7 +981,7 @@ export async function runAkRole(
835
981
  if (parsed.command === "collector") {
836
982
  const agentDir = resolveAgentDir(env, home);
837
983
  const cwd = env.cwd ?? process.cwd();
838
- const config = await loadPublicCliConfig(home);
984
+ const config = await loadAndValidateConfig(home, env.packageRoot);
839
985
  const credentials =
840
986
  env.credentials ?? (await loadCredentialProviders(agentDir));
841
987
  const seat = resolveEffectiveSeat(
@@ -878,7 +1024,7 @@ export async function runAkRole(
878
1024
  if (parsed.command === "reviewer") {
879
1025
  const agentDir = resolveAgentDir(env, home);
880
1026
  const cwd = env.cwd ?? process.cwd();
881
- const config = await loadPublicCliConfig(home);
1027
+ const config = await loadAndValidateConfig(home, env.packageRoot);
882
1028
  const credentials =
883
1029
  env.credentials ?? (await loadCredentialProviders(agentDir));
884
1030
  const seat = resolveEffectiveSeat(
@@ -921,7 +1067,7 @@ export async function runAkRole(
921
1067
  if (parsed.command === "doctor") {
922
1068
  const agentDir = resolveAgentDir(env, home);
923
1069
  const cwd = env.cwd ?? process.cwd();
924
- const config = await loadPublicCliConfig(home);
1070
+ const config = await loadAndValidateConfig(home, env.packageRoot);
925
1071
  const credentials =
926
1072
  env.credentials ?? (await loadCredentialProviders(agentDir));
927
1073
  const seat = resolveEffectiveSeat(
@@ -964,7 +1110,7 @@ export async function runAkRole(
964
1110
  if (parsed.command === "merger") {
965
1111
  const agentDir = resolveAgentDir(env, home);
966
1112
  const cwd = env.cwd ?? process.cwd();
967
- const config = await loadPublicCliConfig(home);
1113
+ const config = await loadAndValidateConfig(home, env.packageRoot);
968
1114
  const credentials =
969
1115
  env.credentials ?? (await loadCredentialProviders(agentDir));
970
1116
  const seat = resolveEffectiveSeat(