@akagilnc/pi-workflow-roles 0.1.4444 → 0.1.4489

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 (44) hide show
  1. package/README.md +2 -0
  2. package/README.zh-CN.md +2 -0
  3. package/dist/acp-host/description.js +2 -3
  4. package/dist/acp-host/production-host.js +140 -107
  5. package/dist/auditor-soul.js +8 -1
  6. package/dist/headless-host/description.js +3 -3
  7. package/dist/headless-host/production-host.js +147 -76
  8. package/dist/host-descriptions.js +3 -18
  9. package/dist/method-host-plugin/.claude-plugin/plugin.json +5 -0
  10. package/dist/method-host-plugin/skills/ak-cross-m-review/CONTEXT.md +48 -0
  11. package/dist/method-host-plugin/skills/ak-cross-m-review/LICENSE +21 -0
  12. package/dist/method-host-plugin/skills/ak-cross-m-review/SKILL.md +170 -0
  13. package/dist/method-host-plugin/skills/ak-cross-m-review/prompts/cmr-completeness.md +118 -0
  14. package/dist/method-host-plugin/skills/ak-cross-m-review/prompts/cmr-reviewer.md +128 -0
  15. package/dist/method-host-plugin/skills/ak-cross-m-review/provenance.json +41 -0
  16. package/dist/method-host-plugin/skills/diagnosing-bugs/SKILL.md +134 -0
  17. package/dist/method-host-plugin/skills/diagnosing-bugs/agents/openai.yaml +3 -0
  18. package/dist/method-host-plugin/skills/diagnosing-bugs/provenance.json +31 -0
  19. package/dist/method-host-plugin/skills/diagnosing-bugs/scripts/hitl-loop.template.sh +41 -0
  20. package/dist/method-host-plugin/skills/resolving-merge-conflicts/SKILL.md +14 -0
  21. package/dist/method-host-plugin/skills/resolving-merge-conflicts/agents/openai.yaml +3 -0
  22. package/dist/method-host-plugin/skills/resolving-merge-conflicts/provenance.json +26 -0
  23. package/dist/method-host-plugin/skills/tdd/SKILL.md +38 -0
  24. package/dist/method-host-plugin/skills/tdd/agents/openai.yaml +3 -0
  25. package/dist/method-host-plugin/skills/tdd/mocking.md +59 -0
  26. package/dist/method-host-plugin/skills/tdd/provenance.json +36 -0
  27. package/dist/method-host-plugin/skills/tdd/tests.md +77 -0
  28. package/dist/public-cli/main.js +14 -21
  29. package/dist/session-opening-materials.js +17 -5
  30. package/extensions/role-runtime.ts +16 -6
  31. package/package.json +1 -1
  32. package/resources/method-host-plugin/.claude-plugin/plugin.json +5 -0
  33. package/scripts/build-package.mjs +6 -1
  34. package/src/acp-host/description.ts +2 -4
  35. package/src/acp-host/production-host.ts +0 -1
  36. package/src/auditor-soul.ts +10 -1
  37. package/src/headless-host/description.ts +4 -3
  38. package/src/headless-host/role-turn-host.ts +27 -4
  39. package/src/host-descriptions.ts +3 -23
  40. package/src/host-native-method.ts +67 -0
  41. package/src/role-envelope.ts +17 -47
  42. package/src/role-runtime-dependencies.ts +17 -2
  43. package/src/role-runtime.ts +12 -7
  44. package/src/session-opening-materials.ts +27 -11
package/README.md CHANGED
@@ -56,6 +56,8 @@ ak-role config set-auto-resume-limit 3
56
56
 
57
57
  **Host providers (#788):** seat rows keep one provider name. Owner edits `~/.ak-roles/host-providers.json` (`{ "hermes": { "xai": "xai-oauth" } }`); code only reads it. Missing table entries ask the host directory (hermes this ticket): unique match wins, zero or many fail loud. Priority is table > unique > fail — no package discretion. `config show` prints the table as written.
58
58
 
59
+ **Forced method skills (#922):** Pi uses `--skill`. Claude uses `--plugin-dir` and its native slash command when a role binds exactly one Skill; its current print harness cannot issue multiple slash commands for one turn, so multi-Skill roles such as Fixer have no forced-method call on Claude. Codex discovers the packaged methods through its documented project `.agents/skills` catalog, which is created only when absent and then left in place; existing entries are never replaced, and Codex receives every official `$skill-name` invocation. Hermes ACP and Grok ACP cannot force a Skill call through their current harness interfaces. These gaps are documentation only: the package does not invent an adapter, capability probe, typed failure, catalog, or operator prerequisite for them. The package never changes host trust or configuration.
60
+
59
61
  For Gate officers (`gatekeeper` / `inspector` / `notary`) resolution is officer pin → province (`gatekeeper`) pin → inherit parent session; an explicit selection that fails is loud and does not fall back. Configuration usage and refusal text are owned by `ak-role config` / `ak-role help config`. The persistent file is machine-wide and shared across CLI builds: seat keys this build does not know are skipped on read (not an error); unknown field-level keys on known seats keep their existing tolerance.
60
62
 
61
63
  Receipts are typed, so callers compose roles without parsing prose; ordering and stopping stay caller-owned ([ADR 0010](docs/adr/0010-callers-own-role-composition-and-repetition.md)). Programmatic consumers derive contracts from the exported schemas in `src/package-contracts/`, not from this guide.
package/README.zh-CN.md CHANGED
@@ -56,6 +56,8 @@ ak-role config set-auto-resume-limit 3
56
56
 
57
57
  **宿主 provider 表(#788):** 席位行只写一份 provider 名。owner 手改 `~/.ak-roles/host-providers.json`(形如 `{ "hermes": { "xai": "xai-oauth" } }`);代码只读。表里没有的问宿主目录(本票 hermes):唯一即用,零个或多个响亮失败。优先级:表 > 唯一 > 失败,代码无裁量。`config show` 原样打印该表。
58
58
 
59
+ **强制方法 Skill(#922):** Pi 使用 `--skill`。角色只绑定一个 Skill 时,Claude 使用 `--plugin-dir` 与原生 slash command;当前 print harness 无法在一轮发出多个 slash command,所以 Fixer 等多 Skill 角色在 Claude 上没有强制方法调用。Codex 通过官方项目 `.agents/skills` 目录发现随包方法:目录缺失时创建常设软链,既有项不覆盖;调用时显式传入每个官方 `$skill-name`。Hermes ACP 与 Grok ACP 当前 harness 无法强制 Skill 调用。这些缺口只在文档说明:本包不为其另造适配、能力探测、typed failure、catalog 或操作员前置,也不改宿主 trust/配置。
60
+
59
61
  门下省官席解析顺序:官自钉 → 省钉(`gatekeeper`)→ 继承父 session;显式指定失败响亮、不回退。配置用法与拒绝文案以 `ak-role config`/`ak-role help config` 为准。持久配置是全机共享单文件、多 CLI 版本同读:本构建不认识的席位键读时跳过(不报错);已知席位上的未知字段沿用现行容忍。
60
62
 
61
63
  回执是 typed 的,调用者不必解析散文即可组合角色;顺序与停止归调用者([ADR 0010](docs/adr/0010-callers-own-role-composition-and-repetition.md))。编程消费者从 `src/package-contracts/` 导出推导契约,不从本文。
@@ -1,6 +1,6 @@
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,
3
+ * needs — binary location, argv shape, resume verb, binding filename,
4
4
  * optional seat-profile soul — is data here; the lifecycle in role-turn-host.ts
5
5
  * stays one copy (#732).
6
6
  */
@@ -9,8 +9,7 @@ import { join } from "node:path";
9
9
  export function resolveAcpBinary(description, operatorHome) {
10
10
  return join(operatorHome, ...description.binaryFromHome);
11
11
  }
12
- /** Stdio argv: optional profile flag, thinking flag (before the subcommand),
13
- * prefix, optional model flag pair, suffix. */
12
+ /** Stdio argv: optional profile flag, thinking flag, prefix, model, suffix. */
14
13
  export function acpStdioArgs(description, model, seat) {
15
14
  const { prefix, suffix, modelFlag, thinkingFlag } = description.argv;
16
15
  const pair = (flag, value) => flag === undefined || value === undefined ? [] : [flag, value];
@@ -1521,10 +1521,10 @@ __export(session_assistant_usage_exports, {
1521
1521
  });
1522
1522
  import { join as join8 } from "node:path";
1523
1523
  async function readAssistantUsageFromSessionFile(sessionFile) {
1524
- const { readFile: readFile24 } = await import("node:fs/promises");
1524
+ const { readFile: readFile23 } = await import("node:fs/promises");
1525
1525
  let text;
1526
1526
  try {
1527
- text = await readFile24(sessionFile, "utf8");
1527
+ text = await readFile23(sessionFile, "utf8");
1528
1528
  } catch (error) {
1529
1529
  if (error?.code === "ENOENT") return void 0;
1530
1530
  throw error;
@@ -3498,13 +3498,10 @@ function assertRegisteredHostName(host) {
3498
3498
  }
3499
3499
  throw new Error(`unregistered host: ${host}`);
3500
3500
  }
3501
- var PRIVATE_COMPAT_ENV, DEFAULT_ROLE_TURN_HOST, HOST_DESCRIPTIONS, HEADLESS_HOST_DESCRIPTIONS;
3501
+ var DEFAULT_ROLE_TURN_HOST, HOST_DESCRIPTIONS, HEADLESS_HOST_DESCRIPTIONS;
3502
3502
  var init_host_descriptions = __esm({
3503
3503
  "src/host-descriptions.ts"() {
3504
3504
  "use strict";
3505
- PRIVATE_COMPAT_ENV = Object.fromEntries(
3506
- ["CLAUDE", "CURSOR", "CODEX"].flatMap((vendor) => ["SKILLS", "RULES", "AGENTS", "MCPS", "HOOKS", "SESSIONS"].map((kind) => [`GROK_${vendor}_${kind}_ENABLED`, "false"]))
3507
- );
3508
3505
  DEFAULT_ROLE_TURN_HOST = "pi";
3509
3506
  HOST_DESCRIPTIONS = Object.freeze({
3510
3507
  /** Operator home `~/.grok`, native session/load resume, `agent [--model X] stdio`. */
@@ -3517,12 +3514,7 @@ var init_host_descriptions = __esm({
3517
3514
  }),
3518
3515
  modelPassing: "argv",
3519
3516
  boundResume: "session/load",
3520
- sessionBindingFile: "grok-acp-session.json",
3521
- childEnv: Object.freeze({
3522
- ...PRIVATE_COMPAT_ENV,
3523
- GROK_MEMORY: "0",
3524
- GROK_SUBAGENTS: "0"
3525
- })
3517
+ sessionBindingFile: "grok-acp-session.json"
3526
3518
  }),
3527
3519
  /**
3528
3520
  * Operator home `~/.hermes`, native session/load resume, `acp` subcommand.
@@ -3541,7 +3533,6 @@ var init_host_descriptions = __esm({
3541
3533
  modelPassing: "set_model",
3542
3534
  boundResume: "session/load",
3543
3535
  sessionBindingFile: "hermes-acp-session.json",
3544
- childEnv: Object.freeze({}),
3545
3536
  seatProfileSoul: Object.freeze({
3546
3537
  flag: "-p",
3547
3538
  namePrefix: "ak-",
@@ -3562,12 +3553,7 @@ var init_host_descriptions = __esm({
3562
3553
  // Intermediate assistant/tool/system events require verbose with stream-json.
3563
3554
  "--verbose",
3564
3555
  "--permission-mode",
3565
- "bypassPermissions",
3566
- // Empty sources: no user/project/local operator surface (envelope owns materials).
3567
- "--setting-sources",
3568
- "",
3569
- // With adapter-supplied --mcp-config only (AK relay); drops operator + claude.ai MCP.
3570
- "--strict-mcp-config"
3556
+ "bypassPermissions"
3571
3557
  ]),
3572
3558
  promptFlag: "-p",
3573
3559
  modelFlag: "--model",
@@ -11273,10 +11259,10 @@ function pairGateRounds(volumes) {
11273
11259
  return rounds.sort((a, b) => a.officerStartedAt.localeCompare(b.officerStartedAt)).map((round, index) => ({ ...round, roundIndex: index + 1 }));
11274
11260
  }
11275
11261
  async function resolveOfficerSessionFromPointerFile(pointerPath) {
11276
- const { readFile: readFile24 } = await import("node:fs/promises");
11262
+ const { readFile: readFile23 } = await import("node:fs/promises");
11277
11263
  let raw;
11278
11264
  try {
11279
- raw = JSON.parse(await readFile24(pointerPath, "utf8"));
11265
+ raw = JSON.parse(await readFile23(pointerPath, "utf8"));
11280
11266
  } catch (error) {
11281
11267
  throw new Error(
11282
11268
  `direct officer run pointer unreadable in ${pointerPath}: ${error instanceof Error ? error.message : String(error)}`,
@@ -11877,16 +11863,27 @@ async function readPackageMaterial(relativePath) {
11877
11863
  }
11878
11864
  async function joinPackageMaterials(relativePaths) {
11879
11865
  const chunks = [];
11880
- for (const relativePath of relativePaths) {
11881
- chunks.push(await readPackageMaterial(relativePath));
11882
- }
11866
+ for (const relativePath of relativePaths) chunks.push(await readPackageMaterial(relativePath));
11883
11867
  return chunks.join("\n\n");
11884
11868
  }
11869
+ function roleSoulPath(role, materials) {
11870
+ const suffix = `/souls/${role}.md`;
11871
+ const path = materials.find((candidate) => `/${candidate}`.endsWith(suffix));
11872
+ if (path === void 0) throw new Error(`session materials omit the ${role} Soul`);
11873
+ return path;
11874
+ }
11875
+ async function loadSeparatedSessionPart(role, materials, part) {
11876
+ const soul = roleSoulPath(role, materials);
11877
+ return part === "soul" ? readPackageMaterial(soul) : joinPackageMaterials(materials.filter((path) => path !== soul));
11878
+ }
11885
11879
  function loadMainRoleSessionMaterials(role) {
11886
- return joinPackageMaterials(MAIN_ROLE_SESSION_MATERIALS[role]);
11880
+ return loadSeparatedSessionPart(role, MAIN_ROLE_SESSION_MATERIALS[role], "soul");
11881
+ }
11882
+ function loadMainRoleReferenceMaterials(role) {
11883
+ return loadSeparatedSessionPart(role, MAIN_ROLE_SESSION_MATERIALS[role], "references");
11887
11884
  }
11888
11885
  function loadGatekeeperSessionMaterials(role) {
11889
- return joinPackageMaterials(GATEKEEPER_SESSION_MATERIALS[role]);
11886
+ return loadSeparatedSessionPart(role, GATEKEEPER_SESSION_MATERIALS[role], "soul");
11890
11887
  }
11891
11888
  var packageRootUrl, MAIN_ROLE_SESSION_MATERIALS, GATEKEEPER_SESSION_MATERIALS;
11892
11889
  var init_session_opening_materials = __esm({
@@ -11916,6 +11913,8 @@ __export(auditor_soul_exports, {
11916
11913
  AUDITOR_SESSION_MATERIALS: () => AUDITOR_SESSION_MATERIALS,
11917
11914
  AUDITOR_SOUL_ROLES: () => AUDITOR_SOUL_ROLES,
11918
11915
  isAuditorSoulRole: () => isAuditorSoulRole,
11916
+ loadAuditorReferenceMaterials: () => loadAuditorReferenceMaterials,
11917
+ loadAuditorReferenceMaterialsFromSubjectInput: () => loadAuditorReferenceMaterialsFromSubjectInput,
11919
11918
  loadAuditorSoul: () => loadAuditorSoul,
11920
11919
  loadAuditorSoulFromSubjectInput: () => loadAuditorSoulFromSubjectInput,
11921
11920
  resolveAuditorSubject: () => resolveAuditorSubject
@@ -11942,11 +11941,18 @@ async function loadAuditorSoul(role) {
11942
11941
  if (soul.trim().length === 0) {
11943
11942
  throw new Error(`The ${role} auditor Soul is blank`);
11944
11943
  }
11945
- return joinPackageMaterials(materials);
11944
+ return soul;
11945
+ }
11946
+ function loadAuditorReferenceMaterials(role) {
11947
+ const soulPath = auditorSoulRelativePath(role);
11948
+ return joinPackageMaterials(AUDITOR_SESSION_MATERIALS[role].filter((path) => path !== soulPath));
11946
11949
  }
11947
11950
  async function loadAuditorSoulFromSubjectInput(raw) {
11948
11951
  return loadAuditorSoul(resolveAuditorSubject(raw));
11949
11952
  }
11953
+ function loadAuditorReferenceMaterialsFromSubjectInput(raw) {
11954
+ return loadAuditorReferenceMaterials(resolveAuditorSubject(raw));
11955
+ }
11950
11956
  var AUDITOR_SOUL_ROLES, AK_ROLE_AUDITOR_SUBJECT_ENV, AK_ROLE_AUDITOR_SOURCE_RUN_ENV, AUDITOR_SESSION_MATERIALS;
11951
11957
  var init_auditor_soul = __esm({
11952
11958
  "src/auditor-soul.ts"() {
@@ -20717,9 +20723,9 @@ import { randomUUID as randomUUID9 } from "node:crypto";
20717
20723
  // src/role-envelope.ts
20718
20724
  init_engine_detour();
20719
20725
  import { randomUUID as randomUUID8 } from "node:crypto";
20720
- import { mkdir as mkdir5, readFile as readFile20, writeFile as writeFile12 } from "node:fs/promises";
20726
+ import { mkdir as mkdir6, writeFile as writeFile12 } from "node:fs/promises";
20721
20727
  import { createServer } from "node:net";
20722
- import { basename as basename9, dirname as dirname21, join as join40 } from "node:path";
20728
+ import { dirname as dirname22, join as join41 } from "node:path";
20723
20729
  import { fileURLToPath as fileURLToPath2 } from "node:url";
20724
20730
 
20725
20731
  // src/gatekeeper-pass-envelope.ts
@@ -20804,9 +20810,43 @@ async function requireGatekeeperPass(options) {
20804
20810
  }
20805
20811
  }
20806
20812
 
20813
+ // src/host-native-method.ts
20814
+ import { lstat as lstat7, mkdir as mkdir5, readlink, realpath as realpath6, symlink } from "node:fs/promises";
20815
+ import { basename as basename9, dirname as dirname18, join as join36 } from "node:path";
20816
+ var packagedMethodsDir = (root) => join36(root, "resources", "methods");
20817
+ function hostMethodSkills(methods) {
20818
+ return Object.freeze(methods.flatMap((method) => {
20819
+ if (method.kind !== "skill") return [];
20820
+ const name = basename9(dirname18(method.path));
20821
+ return name ? [Object.freeze({ name })] : [];
20822
+ }));
20823
+ }
20824
+ async function installWorkspaceMethodSkills(cwd, packageRoot) {
20825
+ const target = await realpath6(packagedMethodsDir(packageRoot));
20826
+ const link = join36(cwd, ".agents", "skills");
20827
+ try {
20828
+ const stat2 = await lstat7(link);
20829
+ if (!stat2.isSymbolicLink() || await realpath6(link) !== target) {
20830
+ const detail = stat2.isSymbolicLink() ? `symlink to ${await readlink(link)}` : "non-symlink entry";
20831
+ throw new Error(`workspace method catalog conflict at ${link}: ${detail}`);
20832
+ }
20833
+ return;
20834
+ } catch (error) {
20835
+ if (error.code !== "ENOENT") throw error;
20836
+ }
20837
+ await mkdir5(dirname18(link), { recursive: true });
20838
+ try {
20839
+ await symlink(target, link);
20840
+ } catch (error) {
20841
+ if (error.code !== "EEXIST") throw error;
20842
+ if (await realpath6(link).catch(() => "") !== target) {
20843
+ throw new Error(`workspace method catalog conflict at ${link}`);
20844
+ }
20845
+ }
20846
+ }
20847
+
20807
20848
  // src/role-envelope.ts
20808
20849
  init_packaged_role_registry();
20809
- init_method_skill();
20810
20850
 
20811
20851
  // src/role-runtime.ts
20812
20852
  init_host_contracts();
@@ -20814,7 +20854,7 @@ init_sitian_facade();
20814
20854
  init_submission_ledger();
20815
20855
  init_collector_ledger();
20816
20856
  import { readFileSync as readFileSync6, writeSync as writeSync4 } from "node:fs";
20817
- import { join as join39 } from "node:path";
20857
+ import { join as join40 } from "node:path";
20818
20858
  import { Value as Value4 } from "typebox/value";
20819
20859
 
20820
20860
  // src/activation-trace.ts
@@ -20864,7 +20904,7 @@ import {
20864
20904
  openSync as openSync2,
20865
20905
  writeSync
20866
20906
  } from "node:fs";
20867
- import { dirname as dirname18, isAbsolute as isAbsolute10, resolve as resolve15 } from "node:path";
20907
+ import { dirname as dirname19, isAbsolute as isAbsolute10, resolve as resolve15 } from "node:path";
20868
20908
 
20869
20909
  // src/activation-ledger-session.ts
20870
20910
  init_activation_ledger_topology();
@@ -21013,7 +21053,7 @@ function appendActivationLedgerLine(ledgerPath, line2, options) {
21013
21053
  }
21014
21054
  const resolvedLedger = resolve15(ledgerPath);
21015
21055
  const resolvedHome = resolve15(options.ledgerHome);
21016
- const parent = dirname18(resolvedLedger);
21056
+ const parent = dirname19(resolvedLedger);
21017
21057
  ensureRealDirectoryTree(resolvedHome, parent);
21018
21058
  assertLedgerFileInsideHome(resolvedLedger, resolvedHome);
21019
21059
  if (typeof constants2.O_NOFOLLOW !== "number") {
@@ -21373,15 +21413,15 @@ init_collector_github();
21373
21413
 
21374
21414
  // src/collector-handbook.ts
21375
21415
  import { readFile as readFile19 } from "node:fs/promises";
21376
- import { join as join37, sep as sep5 } from "node:path";
21416
+ import { join as join38, sep as sep5 } from "node:path";
21377
21417
 
21378
21418
  // src/atomic-write.ts
21379
21419
  import { randomUUID as randomUUID7 } from "node:crypto";
21380
21420
  import { rename as rename3, rm as rm3, writeFile as writeFile11 } from "node:fs/promises";
21381
- import { dirname as dirname19, join as join36 } from "node:path";
21421
+ import { dirname as dirname20, join as join37 } from "node:path";
21382
21422
  async function writeFileAtomically(destination, contents) {
21383
- const parent = dirname19(destination);
21384
- const temporary = join36(parent, `.atomic-write-${randomUUID7()}.tmp`);
21423
+ const parent = dirname20(destination);
21424
+ const temporary = join37(parent, `.atomic-write-${randomUUID7()}.tmp`);
21385
21425
  try {
21386
21426
  await writeFile11(temporary, contents);
21387
21427
  await rename3(temporary, destination);
@@ -21507,7 +21547,7 @@ function resolveCollectorHandbookRoot(sessionPath) {
21507
21547
  throw new Error(`\u901A\u8FDB\u53F8\u624B\u518C\u62D2\u7EDD\u4E0D\u5B89\u5168 bookKey ${JSON.stringify(bookKey)}`);
21508
21548
  }
21509
21549
  const ledgerHome = resolveActivationLedgerHomeForPath(sessionPath);
21510
- const root = join37(activationBookDirectory(ledgerHome, bookKey), "collector-handbook");
21550
+ const root = join38(activationBookDirectory(ledgerHome, bookKey), "collector-handbook");
21511
21551
  return { ledgerHome, bookKey, root };
21512
21552
  }
21513
21553
  function collectorHandbookRepoFileName(repositoryCanonical) {
@@ -21519,9 +21559,9 @@ function collectorHandbookRepoFileName(repositoryCanonical) {
21519
21559
  return `${repositoryCanonical.replaceAll("/", "__")}.md`;
21520
21560
  }
21521
21561
  function createCollectorHandbookStore(input) {
21522
- const generalPath = join37(input.handbookRoot, "general.md");
21523
- const repoDir = join37(input.handbookRoot, "repos");
21524
- const repoPath = join37(repoDir, collectorHandbookRepoFileName(input.repositoryCanonical));
21562
+ const generalPath = join38(input.handbookRoot, "general.md");
21563
+ const repoDir = join38(input.handbookRoot, "repos");
21564
+ const repoPath = join38(repoDir, collectorHandbookRepoFileName(input.repositoryCanonical));
21525
21565
  const assertHandbookBudget = (body, label) => {
21526
21566
  const byteLength = Buffer.byteLength(body, "utf8");
21527
21567
  if (byteLength > COLLECTOR_HANDBOOK_MAX_BYTES) {
@@ -24929,7 +24969,7 @@ function readDiaristTicketAssertion(submitted) {
24929
24969
  function readRoleRunCoordinates(ctx, label) {
24930
24970
  const runDirectory = runDirectoryFromHostContext(ctx);
24931
24971
  if (runDirectory === void 0) throw new Error(`${label} requires AK_ROLE_RUN_DIR`);
24932
- const admittedPath = join39(runDirectory, "admitted-request.json");
24972
+ const admittedPath = join40(runDirectory, "admitted-request.json");
24933
24973
  const admitted = JSON.parse(readFileSync6(admittedPath, "utf8"));
24934
24974
  if (typeof admitted.projectRoot !== "string" || admitted.projectRoot.trim() === "") {
24935
24975
  throw new Error(`${label} admitted-request missing projectRoot (${admittedPath})`);
@@ -25162,6 +25202,7 @@ function createRoleRuntimeExtension(dependencies) {
25162
25202
  });
25163
25203
  let admitted = false;
25164
25204
  let selectedRole;
25205
+ let roleReferenceMaterials = "";
25165
25206
  let activeReviewerParent;
25166
25207
  let reviewerOriginalRequest;
25167
25208
  let reviewerExpansionCaptured = false;
@@ -25255,10 +25296,10 @@ function createRoleRuntimeExtension(dependencies) {
25255
25296
  activeReviewerParent.skillBinding.name,
25256
25297
  text
25257
25298
  ) ?? text;
25258
- return text === event.text ? { action: "continue" } : { action: "transform", text };
25259
25299
  }
25260
- return text === event.text ? { action: "continue" } : { action: "transform", text };
25300
+ return { action: "continue" };
25261
25301
  });
25302
+ roleHost.on("before_agent_start", () => roleReferenceMaterials === "" ? void 0 : { readingMaterial: { kind: "role-reference-materials", content: roleReferenceMaterials } });
25262
25303
  roleHost.on("before_agent_start", async (event, ctx) => {
25263
25304
  const role = roleHost.getFlag(ROLE_FLAG.name);
25264
25305
  const prompt = event.prompt;
@@ -25824,6 +25865,7 @@ function createRoleRuntimeExtension(dependencies) {
25824
25865
  }
25825
25866
  admitted = false;
25826
25867
  selectedRole = void 0;
25868
+ roleReferenceMaterials = "";
25827
25869
  activeReviewerParent = void 0;
25828
25870
  reviewerOriginalRequest = void 0;
25829
25871
  reviewerExpansionCaptured = false;
@@ -25958,6 +26000,7 @@ function createRoleRuntimeExtension(dependencies) {
25958
26000
  }
25959
26001
  }
25960
26002
  await executeActivationStage(entry.role, activationStage(entry.role, runtime), { clock, writeTrace });
26003
+ roleReferenceMaterials = await dependencies.loadRoleReferenceMaterials?.(entry.role) ?? "";
25961
26004
  if (!engineDetourRegistered) {
25962
26005
  engineDetourRegistered = registerEngineDetourTool(roleHost, hostActions);
25963
26006
  }
@@ -25992,19 +26035,6 @@ function createRoleRuntimeExtension(dependencies) {
25992
26035
  init_role_activation_flags();
25993
26036
  init_submission_correctable_error();
25994
26037
  init_navigator_invocation_identity();
25995
- function buildSkillExpansion(methodSkills, prompt) {
25996
- if (methodSkills.size !== 1) return void 0;
25997
- const entry = methodSkills.entries().next().value;
25998
- if (entry === void 0) return void 0;
25999
- const [name, method] = entry;
26000
- return Object.freeze({
26001
- name,
26002
- location: method.path,
26003
- content: method.body,
26004
- // Non-pi typed chain keeps original task bytes (ticket #822 r3); no consumer trim.
26005
- userMessage: prompt
26006
- });
26007
- }
26008
26038
  async function listen(server, path) {
26009
26039
  await new Promise((resolve21, reject) => {
26010
26040
  server.once("error", reject);
@@ -26039,21 +26069,14 @@ async function prepareRoleEnvelope(options) {
26039
26069
  const calls = [];
26040
26070
  const customEntries = [];
26041
26071
  const sessionEntries = [];
26042
- const methodSkills = /* @__PURE__ */ new Map();
26043
26072
  let preferredTools = [];
26044
26073
  let rejection;
26045
26074
  let infrastructureRoundFailure;
26046
26075
  const hostAbort = new AbortController();
26047
26076
  const runId = request.runDirectory.split("/").filter(Boolean).at(-1) ?? randomUUID8();
26048
- await mkdir5(request.runDirectory, { recursive: true });
26049
- for (const method of request.methods) {
26050
- if (method.kind !== "skill") continue;
26051
- const name = basename9(dirname21(method.path));
26052
- const raw = await readFile20(method.path, "utf8");
26053
- methodSkills.set(name, { path: method.path, body: stripSkillFrontmatter(raw).trim() });
26054
- }
26055
- let sessionFile = options.sessionFile ?? join40(request.runDirectory, "session", "session.jsonl");
26056
- await mkdir5(dirname21(sessionFile), { recursive: true });
26077
+ await mkdir6(request.runDirectory, { recursive: true });
26078
+ let sessionFile = options.sessionFile ?? join41(request.runDirectory, "session", "session.jsonl");
26079
+ await mkdir6(dirname22(sessionFile), { recursive: true });
26057
26080
  if (request.continuation.kind !== "resume") {
26058
26081
  try {
26059
26082
  await writeFile12(
@@ -26084,7 +26107,7 @@ async function prepareRoleEnvelope(options) {
26084
26107
  getLeafEntry: () => sessionEntries.at(-1),
26085
26108
  getLeafId: () => runId,
26086
26109
  getEntries: () => sessionEntries,
26087
- getSessionDir: () => dirname21(sessionFile),
26110
+ getSessionDir: () => dirname22(sessionFile),
26088
26111
  getSessionFile: () => sessionFile,
26089
26112
  getHeader: () => ({ type: "session", id: runId }),
26090
26113
  setSessionFile(path) {
@@ -26119,8 +26142,9 @@ async function prepareRoleEnvelope(options) {
26119
26142
  deliverSubmissionRejection(_value) {
26120
26143
  },
26121
26144
  capabilities: {
26122
- skillExpansion(prompt) {
26123
- return buildSkillExpansion(methodSkills, prompt);
26145
+ // #922: native loaders own expansion; package does not pre-read bodies (ADR 0032).
26146
+ skillExpansion() {
26147
+ return void 0;
26124
26148
  }
26125
26149
  },
26126
26150
  registerFlag(name, definition) {
@@ -26459,10 +26483,9 @@ async function prepareRoleEnvelope(options) {
26459
26483
  message: { role: "user", content: prompt }
26460
26484
  });
26461
26485
  }
26462
- const methodPrompt = (await Promise.all(request.methods.map(({ path }) => readFile20(path, "utf8")))).join("\n\n");
26463
26486
  const promptResults = await emit("before_agent_start", {
26464
26487
  prompt,
26465
- systemPrompt: methodPrompt,
26488
+ systemPrompt: "",
26466
26489
  systemPromptOptions: {}
26467
26490
  });
26468
26491
  const systemPromptParts = promptResults.flatMap((value) => {
@@ -26470,7 +26493,7 @@ async function prepareRoleEnvelope(options) {
26470
26493
  if (!("systemPrompt" in value) || typeof value.systemPrompt !== "string") return [];
26471
26494
  return [value.systemPrompt];
26472
26495
  });
26473
- const systemPromptBody = systemPromptParts.length > 0 ? systemPromptParts.join("\n\n") : methodPrompt;
26496
+ const systemPromptBody = systemPromptParts.join("\n\n");
26474
26497
  const readingMaterials = [];
26475
26498
  for (const value of promptResults) {
26476
26499
  if (typeof value !== "object" || value === null) continue;
@@ -26483,6 +26506,13 @@ async function prepareRoleEnvelope(options) {
26483
26506
  throw new Error(`terminating tool not registered after activation: ${terminatingToolName}`);
26484
26507
  }
26485
26508
  const jsonSchema = terminatingToolJsonSchema(terminating.parameters);
26509
+ if (request.host === "codex" && hostMethodSkills(request.methods).length > 0) {
26510
+ const packageRoot = options.dependencies.packageRoot;
26511
+ if (typeof packageRoot !== "string" || packageRoot === "") {
26512
+ throw new Error("codex project Skill catalog requires packageRoot");
26513
+ }
26514
+ await installWorkspaceMethodSkills(request.cwd, packageRoot);
26515
+ }
26486
26516
  return {
26487
26517
  mcpServers: [{
26488
26518
  name: `ak-${request.activation.role}`,
@@ -26517,18 +26547,18 @@ async function prepareRoleEnvelope(options) {
26517
26547
  }
26518
26548
 
26519
26549
  // src/role-runtime-dependencies.ts
26520
- import { readFile as readFile23 } from "node:fs/promises";
26550
+ import { readFile as readFile22 } from "node:fs/promises";
26521
26551
  import { fileURLToPath as fileURLToPath3 } from "node:url";
26522
26552
 
26523
26553
  // src/canonical-skill-binding.ts
26524
- import { readFile as readFile21, realpath as realpath6 } from "node:fs/promises";
26554
+ import { readFile as readFile20, realpath as realpath7 } from "node:fs/promises";
26525
26555
  import { homedir } from "node:os";
26526
- import { dirname as dirname22, resolve as resolve18 } from "node:path";
26556
+ import { dirname as dirname23, resolve as resolve18 } from "node:path";
26527
26557
  import { stripFrontmatter } from "@earendil-works/pi-coding-agent";
26528
26558
  function captureCanonicalSkillExpansion(name, snapshot, configuredPath, evidence, originalRequest) {
26529
26559
  const matchedPath = evidence?.location === configuredPath ? configuredPath : evidence?.location === snapshot.path ? snapshot.path : void 0;
26530
26560
  const expectedContent = matchedPath === void 0 ? void 0 : snapshot.body;
26531
- const prefixedContent = matchedPath === void 0 ? void 0 : `References are relative to ${dirname22(matchedPath)}.
26561
+ const prefixedContent = matchedPath === void 0 ? void 0 : `References are relative to ${dirname23(matchedPath)}.
26532
26562
 
26533
26563
  ${snapshot.body}`;
26534
26564
  if (evidence?.name !== name || matchedPath === void 0 || evidence.content !== expectedContent && evidence.content !== prefixedContent || evidence.userMessage !== originalRequest) {
@@ -26553,8 +26583,8 @@ async function loadCanonicalSkillBinding(name) {
26553
26583
  let path;
26554
26584
  let raw;
26555
26585
  try {
26556
- path = await realpath6(configuredPath);
26557
- raw = await readFile21(path, "utf8");
26586
+ path = await realpath7(configuredPath);
26587
+ raw = await readFile20(path, "utf8");
26558
26588
  } catch (error) {
26559
26589
  throw new CanonicalSkillUnavailableError(name, configuredPath, error);
26560
26590
  }
@@ -26565,7 +26595,7 @@ async function loadCanonicalSkillBinding(name) {
26565
26595
  const snapshot = Object.freeze({
26566
26596
  raw,
26567
26597
  path,
26568
- baseDir: dirname22(path),
26598
+ baseDir: dirname23(path),
26569
26599
  body,
26570
26600
  snapshotIdentity: Object.freeze({ text: raw })
26571
26601
  });
@@ -26593,7 +26623,7 @@ init_doctor_evidence();
26593
26623
  // src/navigator-work-context.ts
26594
26624
  init_doctor_evidence();
26595
26625
  init_host_contracts();
26596
- import { readFile as readFile22 } from "node:fs/promises";
26626
+ import { readFile as readFile21 } from "node:fs/promises";
26597
26627
  import { resolve as resolve19 } from "node:path";
26598
26628
  init_notary_source_run();
26599
26629
  init_packaged_role_registry();
@@ -26606,7 +26636,7 @@ function navigatorInputReference(getFlag, role) {
26606
26636
  }
26607
26637
  async function loadNavigatorWorkContext(options) {
26608
26638
  const reference = navigatorInputReference(options.getFlag, options.role);
26609
- const input = reference === void 0 || options.role === "doctor" || options.role === "notary" ? void 0 : await readFile22(reference, "utf8");
26639
+ const input = reference === void 0 || options.role === "doctor" || options.role === "notary" ? void 0 : await readFile21(reference, "utf8");
26610
26640
  const subjectRoot = subjectPath(reference ?? options.context.sessionManager.getSessionDir(), options.context.cwd);
26611
26641
  let subjectKey = reference === void 0 ? subjectRoot : navigatorSubjectKeyForInput(subjectRoot, reference, options.context.cwd);
26612
26642
  let subject = input ?? `work subject: ${subjectKey}`;
@@ -26663,7 +26693,7 @@ async function loadNavigatorWorkContext(options) {
26663
26693
  let authorityMaterial;
26664
26694
  for (const path of authorityFiles) {
26665
26695
  try {
26666
- const content = await readFile22(path, "utf8");
26696
+ const content = await readFile21(path, "utf8");
26667
26697
  if (content.trim() !== "") {
26668
26698
  authorityMaterial = content;
26669
26699
  break;
@@ -26688,7 +26718,7 @@ async function loadNavigatorWorkContext(options) {
26688
26718
  init_notary_source_run();
26689
26719
 
26690
26720
  // src/package-resources/method-skill-binding.ts
26691
- import { dirname as dirname23 } from "node:path";
26721
+ import { dirname as dirname24 } from "node:path";
26692
26722
  init_method_skill();
26693
26723
  async function loadPackagedCanonicalSkillBinding(packageRoot, name) {
26694
26724
  const material = await loadPackagedMethodSkillMaterial(packageRoot, name);
@@ -26696,7 +26726,7 @@ async function loadPackagedCanonicalSkillBinding(packageRoot, name) {
26696
26726
  const snapshot = Object.freeze({
26697
26727
  raw: material.raw,
26698
26728
  path: material.skillPath,
26699
- baseDir: dirname23(material.skillPath),
26729
+ baseDir: dirname24(material.skillPath),
26700
26730
  body: material.body,
26701
26731
  snapshotIdentity: Object.freeze({ text: material.raw })
26702
26732
  });
@@ -26725,19 +26755,23 @@ var navigatorRoutePlaybookPath = fileURLToPath3(
26725
26755
  var collectorHandbookSeedPath = fileURLToPath3(
26726
26756
  new URL("../resources/collector-bot-handbook.md", import.meta.url)
26727
26757
  );
26758
+ function loadPackagedRoleReferenceMaterials(role) {
26759
+ return role === "auditor" ? loadAuditorReferenceMaterialsFromSubjectInput() : loadMainRoleReferenceMaterials(role);
26760
+ }
26728
26761
  function createRoleRuntimeDependencies(packageRoot) {
26729
26762
  const doctorAuditor = createPiDoctorAuditor();
26730
26763
  const navigatorSessionFactory = createNativeNavigatorSessionFactory();
26731
26764
  return {
26732
26765
  packageRoot,
26766
+ loadRoleReferenceMaterials: loadPackagedRoleReferenceMaterials,
26733
26767
  loadJudgeSoul: () => loadMainRoleSessionMaterials("judge"),
26734
26768
  loadFixerSoul: () => loadMainRoleSessionMaterials("fixer"),
26735
- loadFixPacket: (path) => readFile23(path, "utf8"),
26769
+ loadFixPacket: (path) => readFile22(path, "utf8"),
26736
26770
  loadCoderSoul: () => loadMainRoleSessionMaterials("coder"),
26737
- loadCoderTask: (path) => readFile23(path, "utf8"),
26771
+ loadCoderTask: (path) => readFile22(path, "utf8"),
26738
26772
  loadReviewerSoul: () => loadMainRoleSessionMaterials("reviewer"),
26739
26773
  loadCollectorSoul: () => loadMainRoleSessionMaterials("collector"),
26740
- loadCollectorHandbookSeed: () => readFile23(collectorHandbookSeedPath, "utf8"),
26774
+ loadCollectorHandbookSeed: () => readFile22(collectorHandbookSeedPath, "utf8"),
26741
26775
  createCollectorTransport: () => createGhCollectorGitHubTransport(),
26742
26776
  loadDoctorSoul: () => loadMainRoleSessionMaterials("doctor"),
26743
26777
  loadDoctorCase,
@@ -26752,7 +26786,7 @@ function createRoleRuntimeDependencies(packageRoot) {
26752
26786
  loadSecretariatSoul: () => loadMainRoleSessionMaterials("secretariat"),
26753
26787
  loadNotarySourceRun: loadNotarySourceRunLocator,
26754
26788
  loadMergerSoul: () => loadMainRoleSessionMaterials("merger"),
26755
- loadMergerInput: async (path) => JSON.parse(await readFile23(path, "utf8")),
26789
+ loadMergerInput: async (path) => JSON.parse(await readFile22(path, "utf8")),
26756
26790
  async loadCanonicalSkillBinding(name) {
26757
26791
  if (name === "tdd") {
26758
26792
  return loadPackagedCanonicalSkillBinding(packageRoot, "tdd");
@@ -26778,7 +26812,7 @@ function createRoleRuntimeDependencies(packageRoot) {
26778
26812
  authority: options.authority,
26779
26813
  invocationId: options.invocationId,
26780
26814
  loadSoul: () => loadMainRoleSessionMaterials("navigator"),
26781
- loadRoutePlaybook: () => readFile23(navigatorRoutePlaybookPath, "utf8"),
26815
+ loadRoutePlaybook: () => readFile22(navigatorRoutePlaybookPath, "utf8"),
26782
26816
  loadRoleHelp: async (role) => formatNavigatorRoleHelp(role),
26783
26817
  createSession: navigatorSessionFactory,
26784
26818
  ...options.contextError === void 0 ? {} : { contextError: options.contextError },
@@ -26791,9 +26825,9 @@ function createRoleRuntimeDependencies(packageRoot) {
26791
26825
  init_session_identity();
26792
26826
 
26793
26827
  // src/acp-host/description.ts
26794
- import { join as join41 } from "node:path";
26828
+ import { join as join42 } from "node:path";
26795
26829
  function resolveAcpBinary(description, operatorHome) {
26796
- return join41(operatorHome, ...description.binaryFromHome);
26830
+ return join42(operatorHome, ...description.binaryFromHome);
26797
26831
  }
26798
26832
  function acpStdioArgs(description, model, seat) {
26799
26833
  const { prefix, suffix, modelFlag, thinkingFlag } = description.argv;
@@ -27239,13 +27273,13 @@ function createAcpRoleTurnHost(config) {
27239
27273
 
27240
27274
  // src/acp-host/seat-profile-soul.ts
27241
27275
  import { constants as constants3 } from "node:fs";
27242
- import { access as access4, copyFile, lstat as lstat7, mkdir as mkdir6, readlink, symlink, unlink as unlink3 } from "node:fs/promises";
27243
- import { dirname as dirname24, join as join42, relative as relative3, resolve as resolve20 } from "node:path";
27276
+ import { access as access4, copyFile, lstat as lstat8, mkdir as mkdir7, readlink as readlink2, symlink as symlink2, unlink as unlink3 } from "node:fs/promises";
27277
+ import { dirname as dirname25, join as join43, relative as relative3, resolve as resolve20 } from "node:path";
27244
27278
  function seatProfileName(spec, role) {
27245
27279
  return `${spec.namePrefix}${role}`;
27246
27280
  }
27247
27281
  function packageRoleSoulPath(packageRoot, role) {
27248
- return join42(packageRoot, "souls", `${role}.md`);
27282
+ return join43(packageRoot, "souls", `${role}.md`);
27249
27283
  }
27250
27284
  async function pathExists2(path) {
27251
27285
  try {
@@ -27262,26 +27296,26 @@ async function ensureSeatProfileSoul(options) {
27262
27296
  if (!await pathExists2(soulTarget)) {
27263
27297
  throw new Error(`packaged role soul missing: ${soulTarget}`);
27264
27298
  }
27265
- const profilesRoot = join42(operatorHome, ...spec.profilesRootFromHome);
27266
- const profileDir = join42(profilesRoot, profileName);
27267
- const hostRoot = dirname24(profilesRoot);
27268
- const soulPath = join42(profileDir, spec.soulFileName);
27299
+ const profilesRoot = join43(operatorHome, ...spec.profilesRootFromHome);
27300
+ const profileDir = join43(profilesRoot, profileName);
27301
+ const hostRoot = dirname25(profilesRoot);
27302
+ const soulPath = join43(profileDir, spec.soulFileName);
27269
27303
  if (!await pathExists2(profileDir)) {
27270
- await mkdir6(profileDir, { recursive: true });
27304
+ await mkdir7(profileDir, { recursive: true });
27271
27305
  for (const name of ["auth.json", ".env", "config.yaml"]) {
27272
- const source = join42(hostRoot, name);
27306
+ const source = join43(hostRoot, name);
27273
27307
  if (!await pathExists2(source)) continue;
27274
- await copyFile(source, join42(profileDir, name));
27308
+ await copyFile(source, join43(profileDir, name));
27275
27309
  }
27276
27310
  } else {
27277
- await mkdir6(profileDir, { recursive: true });
27311
+ await mkdir7(profileDir, { recursive: true });
27278
27312
  }
27279
27313
  const desiredLink = relative3(profileDir, soulTarget);
27280
27314
  let current;
27281
27315
  try {
27282
- const st = await lstat7(soulPath);
27316
+ const st = await lstat8(soulPath);
27283
27317
  if (st.isSymbolicLink()) {
27284
- current = await readlink(soulPath);
27318
+ current = await readlink2(soulPath);
27285
27319
  }
27286
27320
  } catch {
27287
27321
  current = void 0;
@@ -27292,7 +27326,7 @@ async function ensureSeatProfileSoul(options) {
27292
27326
  if (await pathExists2(soulPath) || current !== void 0) {
27293
27327
  await unlink3(soulPath);
27294
27328
  }
27295
- await symlink(desiredLink, soulPath);
27329
+ await symlink2(desiredLink, soulPath);
27296
27330
  return profileName;
27297
27331
  }
27298
27332
 
@@ -27312,7 +27346,6 @@ function createProductionAcpRoleTurnHost(options) {
27312
27346
  const { packageRoot, principalAuthority, description, hostName } = options;
27313
27347
  const env = {
27314
27348
  ...process.env,
27315
- ...description.childEnv,
27316
27349
  AK_PACKAGE_ROOT: packageRoot
27317
27350
  };
27318
27351
  return createComposedAcpRoleTurnHost({