@akagilnc/pi-workflow-roles 0.1.2076 → 0.1.2086

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/README.md CHANGED
@@ -114,7 +114,7 @@ Generated from `src/public-cli/option-definitions.ts`. Prefer `ak-role help <com
114
114
  | --- | --- | --- | --- | --- | --- | --- | --- |
115
115
  | `--model` | — | `provider/model` | no | no | option | — | Override the effective seat model for this invocation (before or after the command). |
116
116
  | `--thinking` | — | `level` | no | no | option | — | Override thinking level: off\|minimal\|low\|medium\|high\|xhigh\|max. |
117
- | `--engine` | — | `name` | no | no | option | — | Optional Judge labor engine for this invocation (name must exist in packaged engine materials; judge-only). |
117
+ | `--engine` | — | `name` | no | no | option | — | Optional Judge labor engine for this invocation (owner pool-directive name; packaged notes attached when present; judge-only). |
118
118
  | `--help` | `-h` | — | no | no | option | — | Show public CLI help and exit. |
119
119
 
120
120
  ### `judge`
package/README.zh-CN.md CHANGED
@@ -143,7 +143,7 @@ Codex fast 档:开启:`echo "fast_mode = on" > ~/.pi-codex-fast`;关闭:
143
143
  | --- | --- | --- | --- | --- | --- | --- | --- |
144
144
  | `--model` | — | `provider/model` | 否 | 否 | option | — | 覆盖本调用有效席位模型(可置于子命令前或后)。 |
145
145
  | `--thinking` | — | `level` | 否 | 否 | option | — | 覆盖 thinking 档位:off\|minimal\|low\|medium\|high\|xhigh\|max。 |
146
- | `--engine` | — | `name` | 否 | 否 | option | — | 本调用可选 Judge 劳动引擎(名字须存在于包内引擎调法材料;仅 Judge)。 |
146
+ | `--engine` | — | `name` | 否 | 否 | option | — | 本调用可选 Judge 劳动引擎(池令名字;有包内调法笔记则附卷;仅 Judge)。 |
147
147
  | `--help` | `-h` | — | 否 | 否 | option | — | 显示公开 CLI 帮助并退出。 |
148
148
 
149
149
  ### `judge`
@@ -23,32 +23,19 @@ function isEngineNameSyntax(name) {
23
23
  if (name.length === 0 || name.trim() !== name) return false;
24
24
  if (name === "." || name === "..") return false;
25
25
  if (name.includes("/") || name.includes("\\") || name.includes("\0")) return false;
26
- if (name.includes("..")) return false;
27
26
  return true;
28
27
  }
29
28
  function resolveEngineMaterialDirectory(packageRoot2) {
30
29
  return join2(packageRoot2, ENGINE_MATERIAL_RELATIVE_ROOT);
31
30
  }
32
- function listEngineMaterialNames(packageRoot2) {
33
- const dir = resolveEngineMaterialDirectory(packageRoot2);
34
- if (!existsSync2(dir)) return Object.freeze([]);
35
- const names = readdirSync(dir).filter((entry) => entry.endsWith(".md")).map((entry) => entry.slice(0, -".md".length)).filter((stem) => isEngineNameSyntax(stem)).sort();
36
- return Object.freeze([...names]);
37
- }
38
31
  function resolveEngineMaterialPath(packageRoot2, name) {
39
- const legal = assertLegalEngineName(packageRoot2, name);
32
+ const legal = assertLegalEngineName(name);
40
33
  return join2(resolveEngineMaterialDirectory(packageRoot2), `${legal}.md`);
41
34
  }
42
- function assertLegalEngineName(packageRoot2, name) {
35
+ function assertLegalEngineName(name) {
43
36
  if (!isEngineNameSyntax(name)) {
44
37
  throw new Error(`illegal engine name: ${name}`);
45
38
  }
46
- const legal = listEngineMaterialNames(packageRoot2);
47
- if (!legal.includes(name)) {
48
- throw new Error(
49
- `unknown engine: ${name} (known: ${legal.length === 0 ? "(none)" : legal.join(", ")})`
50
- );
51
- }
52
39
  return name;
53
40
  }
54
41
  function engineSessionMaterialFromOptions(options) {
@@ -56,11 +43,12 @@ function engineSessionMaterialFromOptions(options) {
56
43
  if (options.packageRoot === void 0 || options.packageRoot.trim() === "") {
57
44
  throw new Error("packageRoot is required when engine is configured");
58
45
  }
59
- const name = assertLegalEngineName(options.packageRoot, options.engine);
60
- return Object.freeze({
61
- name,
62
- materialPath: resolveEngineMaterialPath(options.packageRoot, name)
63
- });
46
+ const name = assertLegalEngineName(options.engine);
47
+ const materialPath = resolveEngineMaterialPath(options.packageRoot, name);
48
+ if (existsSync2(materialPath)) {
49
+ return Object.freeze({ name, materialPath });
50
+ }
51
+ return Object.freeze({ name });
64
52
  }
65
53
  function appendEngineSessionMaterial(lines, engineMaterial) {
66
54
  if (engineMaterial === void 0) {
@@ -68,9 +56,13 @@ function appendEngineSessionMaterial(lines, engineMaterial) {
68
56
  }
69
57
  const out = [...lines];
70
58
  out.push("");
71
- out.push("Engine method material (read these bytes and follow them):");
72
- out.push(`- engine: ${engineMaterial.name}`);
73
- out.push(`- ${engineMaterial.materialPath}`);
59
+ if (engineMaterial.materialPath !== void 0) {
60
+ out.push("Engine method material (read these bytes and follow them):");
61
+ out.push(`- engine: ${engineMaterial.name}`);
62
+ out.push(`- ${engineMaterial.materialPath}`);
63
+ } else {
64
+ out.push(`- engine: ${engineMaterial.name}`);
65
+ }
74
66
  return out;
75
67
  }
76
68
  var ENGINE_MATERIAL_RELATIVE_ROOT;
@@ -14476,7 +14468,7 @@ function setPersistentSeatEngine(config, seat, engine) {
14476
14468
  function seatModelOnly(seat) {
14477
14469
  return seat.thinking === void 0 ? { provider: seat.provider, model: seat.model } : { provider: seat.provider, model: seat.model, thinking: seat.thinking };
14478
14470
  }
14479
- function validatePublicCliConfigEngines(config, packageRoot2) {
14471
+ function validatePublicCliConfigEngines(config, _packageRoot) {
14480
14472
  for (const seat of Object.keys(config.seats)) {
14481
14473
  const row = config.seats[seat];
14482
14474
  if (row?.engine === void 0) continue;
@@ -14486,10 +14478,10 @@ function validatePublicCliConfigEngines(config, packageRoot2) {
14486
14478
  );
14487
14479
  }
14488
14480
  try {
14489
- assertLegalEngineName(packageRoot2, row.engine);
14481
+ assertLegalEngineName(row.engine);
14490
14482
  } catch (error) {
14491
14483
  throw new Error(
14492
- `config seat ${seat} engine is unknown: ${row.engine}`,
14484
+ `config seat ${seat} engine is illegal: ${row.engine}`,
14493
14485
  { cause: error }
14494
14486
  );
14495
14487
  }
@@ -15925,8 +15917,8 @@ var init_option_definitions = __esm({
15925
15917
  repeatable: false,
15926
15918
  form: "option",
15927
15919
  description: {
15928
- en: "Optional Judge labor engine for this invocation (name must exist in packaged engine materials; judge-only).",
15929
- zh: "\u672C\u8C03\u7528\u53EF\u9009 Judge \u52B3\u52A8\u5F15\u64CE\uFF08\u540D\u5B57\u987B\u5B58\u5728\u4E8E\u5305\u5185\u5F15\u64CE\u8C03\u6CD5\u6750\u6599\uFF1B\u4EC5 Judge\uFF09\u3002"
15920
+ en: "Optional Judge labor engine for this invocation (owner pool-directive name; packaged notes attached when present; judge-only).",
15921
+ zh: "\u672C\u8C03\u7528\u53EF\u9009 Judge \u52B3\u52A8\u5F15\u64CE\uFF08\u6C60\u4EE4\u540D\u5B57\uFF1B\u6709\u5305\u5185\u8C03\u6CD5\u7B14\u8BB0\u5219\u9644\u5377\uFF1B\u4EC5 Judge\uFF09\u3002"
15930
15922
  }
15931
15923
  },
15932
15924
  {
@@ -20720,13 +20712,11 @@ function auditIncompleteFromCandidate(candidate) {
20720
20712
  }
20721
20713
  function boundRetainedAuditResponse(entries, callIndex, resultIndex, auditToolName) {
20722
20714
  const matches = [];
20723
- let retainedResponseCount = 0;
20724
20715
  for (let index = callIndex + 1; index < resultIndex; index += 1) {
20725
20716
  const entry = entries[index];
20726
20717
  if (entry?.type !== "custom" || entry.customType !== COMPLIANCE_RESPONSE_ENTRY_TYPE) {
20727
20718
  continue;
20728
20719
  }
20729
- retainedResponseCount += 1;
20730
20720
  if (!isRecord5(entry.data) || !isRecord5(entry.data.response)) continue;
20731
20721
  const response = entry.data.response;
20732
20722
  if (!Array.isArray(response.content)) continue;
@@ -20736,7 +20726,7 @@ function boundRetainedAuditResponse(entries, callIndex, resultIndex, auditToolNa
20736
20726
  if (calls.length !== 1 || calls[0]?.name !== auditToolName) continue;
20737
20727
  matches.push({ candidate: calls[0]?.arguments });
20738
20728
  }
20739
- return retainedResponseCount === 1 && matches.length === 1 ? matches[0] : void 0;
20729
+ return matches.length === 1 ? matches[0] : void 0;
20740
20730
  }
20741
20731
  function extractComplianceAuditIncompleteRoleOutcome(entries, role, outputToolName) {
20742
20732
  if (outputToolName !== outputToolNameForAuditedRole(role)) return void 0;
@@ -26954,9 +26944,9 @@ function invocationFromParsed(parsed) {
26954
26944
  ...parsed.engine === void 0 ? {} : { engine: parsed.engine }
26955
26945
  };
26956
26946
  }
26957
- function requireLegalEngineName(packageRoot2, name) {
26947
+ function requireLegalEngineName(name) {
26958
26948
  try {
26959
- return assertLegalEngineName(packageRoot2, name);
26949
+ return assertLegalEngineName(name);
26960
26950
  } catch (error) {
26961
26951
  throw new CliUsageError(
26962
26952
  error instanceof Error ? error.message : String(error),
@@ -27153,7 +27143,7 @@ async function runConfigCommand(args, home, packageRoot2, io) {
27153
27143
  `engine axis is judge-only; refused seat ${seat}`
27154
27144
  );
27155
27145
  }
27156
- requireLegalEngineName(packageRoot2, name);
27146
+ requireLegalEngineName(name);
27157
27147
  let config = await loadAndValidateConfig(home, packageRoot2);
27158
27148
  try {
27159
27149
  config = setPersistentSeatEngine(config, seat, name);
@@ -27204,7 +27194,7 @@ async function runAkRole(argv, env) {
27204
27194
  env = { ...env, packageRoot: await realpath5(env.packageRoot) };
27205
27195
  const parsed = parseArgv(argv);
27206
27196
  if (parsed.engine !== void 0) {
27207
- requireLegalEngineName(env.packageRoot, parsed.engine);
27197
+ requireLegalEngineName(parsed.engine);
27208
27198
  if (!parsed.help && parsed.command !== void 0 && parsed.command !== "help" && parsed.command !== "judge") {
27209
27199
  throw new CliUsageError(
27210
27200
  `engine axis is judge-only; refused command ${parsed.command}`
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@akagilnc/pi-workflow-roles",
3
- "version": "0.1.2076",
3
+ "version": "0.1.2086",
4
4
  "description": "Soul-bound workflow roles for Pi",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -0,0 +1,31 @@
1
+ # opus engine method material
2
+
3
+ This file is packaged method material for the optional `opus` labor engine
4
+ (Claude Code CLI on the host). When a role run selects this engine, read these
5
+ bytes and follow the local CLI's actual interface for the labor detour. Return
6
+ the labor result to the same role session so typed submission stays on the
7
+ existing in-session path.
8
+
9
+ Material is data for the model, not a code contract. Do not invent package flags.
10
+
11
+ ## Invocation examples (local Claude Code CLI)
12
+
13
+ The machine entrypoint is `claude`. Run from the role project root. Non-interactive
14
+ print mode (`-p` / `--print`) is verified available on this host:
15
+
16
+ ```bash
17
+ claude -p "YOUR_LABOR_PROMPT"
18
+ ```
19
+
20
+ Pin the Opus model explicitly (`--model opus` verified accepted on this host):
21
+
22
+ ```bash
23
+ claude -p --model opus "YOUR_LABOR_PROMPT"
24
+ ```
25
+
26
+ Prefer `claude --help` on the host over any remembered flag set. Do not wrap this
27
+ engine behind `ak-role` flags.
28
+
29
+ When the package detour tool is available, start exactly one subprocess through
30
+ it with argv assembled from this material and the local CLI; return the stdout
31
+ labor content to the same session for the existing typed submission path.
@@ -24,7 +24,7 @@ const engineDetourArgsSchema = Type.Object(
24
24
  argv: Type.Array(Type.String({ minLength: 1 }), {
25
25
  minItems: 1,
26
26
  description:
27
- "Executable argv for one engine subprocess. First element is the command (PATH lookup); remaining elements are arguments. Assemble from engine method material do not invent package flags.",
27
+ "Executable argv for one engine subprocess. First element is the command (PATH lookup); remaining elements are arguments. Build argv from the host CLI actual interface for the configured engine name; when optional packaged notes are present in the session prompt, follow those bytes. Do not invent package flags.",
28
28
  }),
29
29
  },
30
30
  { additionalProperties: false },
@@ -70,11 +70,11 @@ export function registerEngineDetourTool(
70
70
  name: ENGINE_DETOUR_TOOL_NAME,
71
71
  label: "Engine Detour",
72
72
  description:
73
- `Run one labor-engine subprocess (engine=${engineName}) and return its stdout to this session. Call at most once per activation. Assemble argv from the engine method material path delivered in the session prompt.`,
73
+ `Run one labor-engine subprocess (engine=${engineName}) and return its stdout to this session. Call at most once per activation. Build argv from the host CLI actual interface for this engine name; when optional packaged notes are present in the session prompt, follow those bytes too.`,
74
74
  promptSnippet: "Run the configured labor engine once and return its stdout",
75
75
  promptGuidelines: [
76
- `Use ${ENGINE_DETOUR_TOOL_NAME} exactly once when engine method material is present.`,
77
- "Pass argv assembled from the material and the host CLI — first element is the executable name on PATH.",
76
+ `Use ${ENGINE_DETOUR_TOOL_NAME} exactly once for the configured engine (${engineName}). Optional packaged notes are guidance when present; a bare engine name alone is also a valid call path.`,
77
+ "Pass argv for the host CLI of this engine name — first element is the executable name on PATH. Follow optional packaged notes when delivered; otherwise act from the engine name and the host CLI actual interface. Do not invent package flags.",
78
78
  "On success, use the returned stdout as labor content for the existing typed submission tool.",
79
79
  ],
80
80
  parameters: engineDetourArgsSchema,
@@ -1,7 +1,8 @@
1
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.
2
+ * Packaged engine method-material seam (#356 T1 / ADR 0069 / #376).
3
+ * Engine names are owner pool-directive labelsnot a closed material catalog.
4
+ * Material body is optional data for the LLM, not a code contract.
5
+ * Only path-safety syntax is checked at real I/O seams.
5
6
  */
6
7
  import { existsSync, readdirSync } from "node:fs";
7
8
  import { join } from "node:path";
@@ -10,16 +11,17 @@ const ENGINE_MATERIAL_RELATIVE_ROOT = "resources/engines" as const;
10
11
 
11
12
  export type EngineSessionMaterial = Readonly<{
12
13
  name: string;
13
- materialPath: string;
14
+ /** Present only when a packaged notes file exists for this name. */
15
+ materialPath?: string;
14
16
  }>;
15
17
 
16
- /** Non-empty, trimmed, no path separators or traversal. */
18
+ /** Non-empty, trimmed; reject only real path hazards at the I/O seam. */
17
19
  export function isEngineNameSyntax(name: string): boolean {
18
20
  if (typeof name !== "string") return false;
19
21
  if (name.length === 0 || name.trim() !== name) return false;
22
+ // Exact "." / ".." are directory aliases; consecutive dots inside a label are not.
20
23
  if (name === "." || name === "..") return false;
21
24
  if (name.includes("/") || name.includes("\\") || name.includes("\0")) return false;
22
- if (name.includes("..")) return false;
23
25
  return true;
24
26
  }
25
27
 
@@ -32,8 +34,8 @@ export function resolveEngineMaterialDirectory(packageRoot: string): string {
32
34
  }
33
35
 
34
36
  /**
35
- * Enumerate legal engine names from packaged material files.
36
- * Only `*.md` stems that pass name syntax are legal.
37
+ * Enumerate packaged engine notes stems (discovery only — not a legal-name gate).
38
+ * Only `*.md` stems that pass name syntax are listed.
37
39
  */
38
40
  export function listEngineMaterialNames(packageRoot: string): readonly string[] {
39
41
  const dir = resolveEngineMaterialDirectory(packageRoot);
@@ -46,34 +48,35 @@ export function listEngineMaterialNames(packageRoot: string): readonly string[]
46
48
  return Object.freeze([...names]);
47
49
  }
48
50
 
51
+ /**
52
+ * Build the packaged notes path for a syntax-legal engine name.
53
+ * Does not require the file to exist (material is optional data).
54
+ */
49
55
  export function resolveEngineMaterialPath(
50
56
  packageRoot: string,
51
57
  name: string,
52
58
  ): string {
53
- const legal = assertLegalEngineName(packageRoot, name);
59
+ const legal = assertLegalEngineName(name);
54
60
  return join(resolveEngineMaterialDirectory(packageRoot), `${legal}.md`);
55
61
  }
56
62
 
57
63
  /**
58
- * Assert `name` is a legal engine material stem under packageRoot.
59
- * Returns the canonical name on success; throws Error on illegal.
64
+ * Path-safety syntax gate for engine labels at real I/O seams.
65
+ * Returns the canonical name on success; throws Error on illegal syntax.
66
+ * Does not consult any material catalog (ADR 0069 pool-directive axis).
60
67
  */
61
- export function assertLegalEngineName(packageRoot: string, name: string): string {
68
+ export function assertLegalEngineName(name: string): string {
62
69
  if (!isEngineNameSyntax(name)) {
63
70
  throw new Error(`illegal engine name: ${name}`);
64
71
  }
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
72
  return name;
72
73
  }
73
74
 
74
75
  /**
75
76
  * Resolve optional engine options into session material coordinates.
76
77
  * No engine → undefined (caller keeps default prompt bytes).
78
+ * Engine with packaged notes → name + absolute material path.
79
+ * Engine without notes → name only (pass-through; no warning).
77
80
  */
78
81
  export function engineSessionMaterialFromOptions(options: {
79
82
  engine?: string;
@@ -83,17 +86,20 @@ export function engineSessionMaterialFromOptions(options: {
83
86
  if (options.packageRoot === undefined || options.packageRoot.trim() === "") {
84
87
  throw new Error("packageRoot is required when engine is configured");
85
88
  }
86
- const name = assertLegalEngineName(options.packageRoot, options.engine);
87
- return Object.freeze({
88
- name,
89
- materialPath: resolveEngineMaterialPath(options.packageRoot, name),
90
- });
89
+ const name = assertLegalEngineName(options.engine);
90
+ const materialPath = resolveEngineMaterialPath(options.packageRoot, name);
91
+ if (existsSync(materialPath)) {
92
+ return Object.freeze({ name, materialPath });
93
+ }
94
+ return Object.freeze({ name });
91
95
  }
92
96
 
93
97
  /**
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.
98
+ * Append engine method-material delivery to session initial material lines.
99
+ * No engine → identity copy (byte-stable when joined the same way).
100
+ * With notes → read-these-bytes header + engine name + absolute material path.
101
+ * Name only → engine name coordinate only (no read-these-bytes header, no path, no warning).
102
+ * Never delivers material body.
97
103
  */
98
104
  export function appendEngineSessionMaterial(
99
105
  lines: readonly string[],
@@ -104,8 +110,13 @@ export function appendEngineSessionMaterial(
104
110
  }
105
111
  const out = [...lines];
106
112
  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}`);
113
+ if (engineMaterial.materialPath !== undefined) {
114
+ out.push("Engine method material (read these bytes and follow them):");
115
+ out.push(`- engine: ${engineMaterial.name}`);
116
+ out.push(`- ${engineMaterial.materialPath}`);
117
+ } else {
118
+ // Name-only pass-through: no packaged bytes to read.
119
+ out.push(`- engine: ${engineMaterial.name}`);
120
+ }
110
121
  return out;
111
122
  }
@@ -324,9 +324,9 @@ function invocationFromParsed(parsed: ParsedGlobal): InvocationModelOverride | u
324
324
  };
325
325
  }
326
326
 
327
- function requireLegalEngineName(packageRoot: string, name: string): string {
327
+ function requireLegalEngineName(name: string): string {
328
328
  try {
329
- return assertLegalEngineName(packageRoot, name);
329
+ return assertLegalEngineName(name);
330
330
  } catch (error) {
331
331
  throw new CliUsageError(
332
332
  error instanceof Error ? error.message : String(error),
@@ -546,7 +546,7 @@ async function runConfigCommand(
546
546
  `engine axis is judge-only; refused seat ${seat}`,
547
547
  );
548
548
  }
549
- requireLegalEngineName(packageRoot, name);
549
+ requireLegalEngineName(name);
550
550
  let config = await loadAndValidateConfig(home, packageRoot);
551
551
  try {
552
552
  config = setPersistentSeatEngine(config, seat, name);
@@ -608,7 +608,7 @@ export async function runAkRole(
608
608
  // Invocation --engine rejects at the call-request seam (not role submission).
609
609
  // #356 MVP: engine axis is Judge-only (not resume / non-Judge seats).
610
610
  if (parsed.engine !== undefined) {
611
- requireLegalEngineName(env.packageRoot, parsed.engine);
611
+ requireLegalEngineName(parsed.engine);
612
612
  if (
613
613
  !parsed.help &&
614
614
  parsed.command !== undefined &&
@@ -143,7 +143,7 @@ export function setPersistentSeatEngine(
143
143
  },
144
144
  };
145
145
  }
146
- // Engine-name legality is owned solely by assertLegalEngineName
146
+ // Engine-name path-safety syntax is owned solely by assertLegalEngineName
147
147
  // (call-request + config-parse seams). Setter is pure seat mutation.
148
148
  return {
149
149
  seats: {
@@ -161,13 +161,14 @@ export function seatModelOnly(seat: PersistentSeatConfig): SeatModelConfig {
161
161
  }
162
162
 
163
163
  /**
164
- * Config-parse seam: engine axis is Judge-only; Judge engine names must exist
165
- * in package materials. Call with packageRoot after load / before dispatch (#356).
166
- * Legality authority = assertLegalEngineName (no injected duplicate).
164
+ * Config-parse seam: engine axis is Judge-only; Judge engine names need only
165
+ * path-safety syntax (no closed material catalog; #376 / ADR 0069).
166
+ * Call with packageRoot after load / before dispatch (#356).
167
+ * Syntax authority = assertLegalEngineName (no injected duplicate).
167
168
  */
168
169
  export function validatePublicCliConfigEngines(
169
170
  config: PublicCliConfig,
170
- packageRoot: string,
171
+ _packageRoot: string,
171
172
  ): void {
172
173
  for (const seat of Object.keys(config.seats) as PublicConfigurableSeat[]) {
173
174
  const row = config.seats[seat];
@@ -178,10 +179,10 @@ export function validatePublicCliConfigEngines(
178
179
  );
179
180
  }
180
181
  try {
181
- assertLegalEngineName(packageRoot, row.engine);
182
+ assertLegalEngineName(row.engine);
182
183
  } catch (error) {
183
184
  throw new Error(
184
- `config seat ${seat} engine is unknown: ${row.engine}`,
185
+ `config seat ${seat} engine is illegal: ${row.engine}`,
185
186
  { cause: error },
186
187
  );
187
188
  }
@@ -314,7 +315,7 @@ function parseSeatModelConfig(value: unknown, seat: string): PersistentSeatConfi
314
315
  thinking: raw.thinking as PublicThinkingLevel,
315
316
  };
316
317
  if (raw.engine !== undefined) {
317
- // Shape only: engine must be a string field. Name legality is deferred to
318
+ // Shape only: engine must be a string field. Path-safety syntax is deferred to
318
319
  // validatePublicCliConfigEngines → assertLegalEngineName (single authority).
319
320
  if (typeof raw.engine !== "string") {
320
321
  throw new Error(`config seat ${seat} engine must be a string`);
@@ -288,8 +288,8 @@ const GLOBAL_OPTIONS = [
288
288
  repeatable: false,
289
289
  form: "option",
290
290
  description: {
291
- en: "Optional Judge labor engine for this invocation (name must exist in packaged engine materials; judge-only).",
292
- zh: "本调用可选 Judge 劳动引擎(名字须存在于包内引擎调法材料;仅 Judge)。",
291
+ en: "Optional Judge labor engine for this invocation (owner pool-directive name; packaged notes attached when present; judge-only).",
292
+ zh: "本调用可选 Judge 劳动引擎(池令名字;有包内调法笔记则附卷;仅 Judge)。",
293
293
  },
294
294
  },
295
295
  {
@@ -1696,13 +1696,11 @@ function boundRetainedAuditResponse(
1696
1696
  auditToolName: string,
1697
1697
  ): BoundRetainedAuditResponse | undefined {
1698
1698
  const matches: BoundRetainedAuditResponse[] = [];
1699
- let retainedResponseCount = 0;
1700
1699
  for (let index = callIndex + 1; index < resultIndex; index += 1) {
1701
1700
  const entry = entries[index];
1702
1701
  if (entry?.type !== "custom" || entry.customType !== COMPLIANCE_RESPONSE_ENTRY_TYPE) {
1703
1702
  continue;
1704
1703
  }
1705
- retainedResponseCount += 1;
1706
1704
  if (!isRecord(entry.data) || !isRecord(entry.data.response)) continue;
1707
1705
  const response = entry.data.response;
1708
1706
  if (!Array.isArray(response.content)) continue;
@@ -1713,7 +1711,9 @@ function boundRetainedAuditResponse(
1713
1711
  if (calls.length !== 1 || calls[0]?.name !== auditToolName) continue;
1714
1712
  matches.push({ candidate: calls[0]?.arguments });
1715
1713
  }
1716
- return retainedResponseCount === 1 && matches.length === 1 ? matches[0] : undefined;
1714
+ // Unique seat-bound match binds even when multi-turn investigation retained
1715
+ // intermediate non-decision responses in the same call/result interval.
1716
+ return matches.length === 1 ? matches[0] : undefined;
1717
1717
  }
1718
1718
 
1719
1719
  export function extractComplianceAuditIncompleteRoleOutcome(
@@ -1,32 +0,0 @@
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.
@@ -1,35 +0,0 @@
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.
32
-
33
- When the package detour tool is available, start exactly one subprocess through
34
- it with argv assembled from this material and the local CLI; return the stdout
35
- labor content to the same session for the existing typed submission path.