@akagilnc/pi-workflow-roles 0.1.5037 → 0.1.5063

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 (82) hide show
  1. package/README.md +2 -2
  2. package/README.zh-CN.md +2 -2
  3. package/THIRD_PARTY_NOTICES.md +8 -8
  4. package/dist/acp-host/production-host.js +410 -878
  5. package/dist/headless-host/description.js +0 -2
  6. package/dist/headless-host/production-host.js +413 -914
  7. package/dist/host-descriptions.js +2 -3
  8. package/dist/migrate-book-topology.js +4 -10
  9. package/dist/packaged-role-registry.js +17 -16
  10. package/dist/pi/role-turn-host.js +3 -27
  11. package/dist/public-cli/cli.js +6 -0
  12. package/dist/public-cli/instruction-seat-run.js +12 -40
  13. package/dist/public-cli/machine-method-skills.js +150 -0
  14. package/dist/public-cli/main.js +378 -579
  15. package/dist/public-cli/post-admission.js +2 -0
  16. package/dist/public-cli/registry.js +2 -1
  17. package/dist/public-cli/settlement.js +12 -99
  18. package/dist/public-cli/turn-request.js +16 -8
  19. package/package.json +5 -1
  20. package/scripts/build-package.mjs +1 -6
  21. package/src/headless-host/description.ts +0 -3
  22. package/src/headless-host/role-turn-host.ts +2 -23
  23. package/src/host-contracts.ts +2 -23
  24. package/src/host-descriptions.ts +2 -3
  25. package/src/packaged-role-registry.ts +14 -14
  26. package/src/pi/adapter.ts +0 -27
  27. package/src/pi/role-turn-host.ts +3 -31
  28. package/src/public-cli/cli.ts +6 -0
  29. package/src/public-cli/instruction-seat-run.ts +9 -42
  30. package/src/public-cli/machine-method-skills.ts +153 -0
  31. package/src/public-cli/post-admission.ts +2 -0
  32. package/src/public-cli/registry.ts +1 -0
  33. package/src/public-cli/settlement.ts +6 -138
  34. package/src/public-cli/turn-request.ts +24 -16
  35. package/src/reviewer-role.ts +1 -12
  36. package/src/role-envelope.ts +0 -13
  37. package/src/role-runtime-dependencies.ts +0 -13
  38. package/src/role-runtime.ts +4 -56
  39. package/src/worker-role.ts +1 -81
  40. package/dist/method-host-plugin/.claude-plugin/plugin.json +0 -5
  41. package/dist/method-host-plugin/skills/ak-cross-m-review/CONTEXT.md +0 -48
  42. package/dist/method-host-plugin/skills/ak-cross-m-review/LICENSE +0 -21
  43. package/dist/method-host-plugin/skills/ak-cross-m-review/SKILL.md +0 -170
  44. package/dist/method-host-plugin/skills/ak-cross-m-review/prompts/cmr-completeness.md +0 -118
  45. package/dist/method-host-plugin/skills/ak-cross-m-review/prompts/cmr-reviewer.md +0 -128
  46. package/dist/method-host-plugin/skills/ak-cross-m-review/provenance.json +0 -41
  47. package/dist/method-host-plugin/skills/diagnosing-bugs/SKILL.md +0 -134
  48. package/dist/method-host-plugin/skills/diagnosing-bugs/agents/openai.yaml +0 -3
  49. package/dist/method-host-plugin/skills/diagnosing-bugs/provenance.json +0 -31
  50. package/dist/method-host-plugin/skills/diagnosing-bugs/scripts/hitl-loop.template.sh +0 -41
  51. package/dist/method-host-plugin/skills/resolving-merge-conflicts/SKILL.md +0 -14
  52. package/dist/method-host-plugin/skills/resolving-merge-conflicts/agents/openai.yaml +0 -3
  53. package/dist/method-host-plugin/skills/resolving-merge-conflicts/provenance.json +0 -26
  54. package/dist/method-host-plugin/skills/tdd/SKILL.md +0 -38
  55. package/dist/method-host-plugin/skills/tdd/agents/openai.yaml +0 -3
  56. package/dist/method-host-plugin/skills/tdd/mocking.md +0 -59
  57. package/dist/method-host-plugin/skills/tdd/provenance.json +0 -36
  58. package/dist/method-host-plugin/skills/tdd/tests.md +0 -77
  59. package/dist/package-resources/method-skill.js +0 -259
  60. package/resources/method-host-plugin/.claude-plugin/plugin.json +0 -5
  61. package/resources/methods/ak-cross-m-review/CONTEXT.md +0 -48
  62. package/resources/methods/ak-cross-m-review/LICENSE +0 -21
  63. package/resources/methods/ak-cross-m-review/SKILL.md +0 -170
  64. package/resources/methods/ak-cross-m-review/prompts/cmr-completeness.md +0 -118
  65. package/resources/methods/ak-cross-m-review/prompts/cmr-reviewer.md +0 -128
  66. package/resources/methods/ak-cross-m-review/provenance.json +0 -41
  67. package/resources/methods/diagnosing-bugs/SKILL.md +0 -134
  68. package/resources/methods/diagnosing-bugs/agents/openai.yaml +0 -3
  69. package/resources/methods/diagnosing-bugs/provenance.json +0 -31
  70. package/resources/methods/diagnosing-bugs/scripts/hitl-loop.template.sh +0 -41
  71. package/resources/methods/resolving-merge-conflicts/SKILL.md +0 -14
  72. package/resources/methods/resolving-merge-conflicts/agents/openai.yaml +0 -3
  73. package/resources/methods/resolving-merge-conflicts/provenance.json +0 -26
  74. package/resources/methods/tdd/SKILL.md +0 -38
  75. package/resources/methods/tdd/agents/openai.yaml +0 -3
  76. package/resources/methods/tdd/mocking.md +0 -59
  77. package/resources/methods/tdd/provenance.json +0 -36
  78. package/resources/methods/tdd/tests.md +0 -77
  79. package/src/canonical-skill-binding.ts +0 -118
  80. package/src/host-native-method.ts +0 -185
  81. package/src/package-resources/method-skill-binding.ts +0 -60
  82. package/src/package-resources/method-skill.ts +0 -363
@@ -10,15 +10,10 @@ import type { DurablePrincipalAuthority, RoleTurnRequest } from "../host-contrac
10
10
  import { isSafePositiveTicketNumber, readBoardTicketNumber } from "../run-ticket-number.ts";
11
11
  import { NotarySourceRunError, resolveNotarySourceRunLocator } from "../notary-source-run.ts";
12
12
  import { engineSessionMaterialFromOptions, pickEngineAxis } from "../package-resources/engine-material.ts";
13
- import {
14
- loadPackagedMethodSkillMaterial,
15
- type PackagedMethodSkillMaterial,
16
- } from "../package-resources/method-skill.ts";
17
13
  import type { PackagedRole } from "../packaged-role-registry.ts";
18
14
  import {
19
15
  packagedAdmitsCountersign,
20
16
  packagedBindsBoardTicket,
21
- packagedMethodLoadFailureCause,
22
17
  packagedRebindSourceOnResume,
23
18
  packagedRoleMetadata,
24
19
  } from "../packaged-role-registry.ts";
@@ -42,7 +37,6 @@ import {
42
37
  import {
43
38
  presentControlledFailure,
44
39
  prepareSummonsResumeMaterials,
45
- resolveResumeMethodMaterialAdapters,
46
40
  roleTurnOptions,
47
41
  runPostAdmissionOneShot,
48
42
  runPostAdmissionResumable,
@@ -67,6 +61,7 @@ import {
67
61
  trySettlePublicSeat,
68
62
  } from "./settlement.ts";
69
63
  import type { CliIo } from "./cli-io.ts";
64
+ import { warnMissingMethodSkills } from "./machine-method-skills.ts";
70
65
  import {
71
66
  formatTerminalResult,
72
67
  isLawfulTypedTerminalOutcome,
@@ -74,8 +69,8 @@ import {
74
69
  } from "./terminal.ts";
75
70
  import {
76
71
  admittedSeatTurnDetails,
77
- packagedSettleSkill,
78
72
  projectRoleTurnRequest,
73
+ requiredMethodSkills,
79
74
  type RoleTurnRequestProjectionOptions,
80
75
  } from "./turn-request.ts";
81
76
  import {
@@ -110,7 +105,7 @@ export function buildInstructionSeatTurnRequest(
110
105
  ): RoleTurnRequest {
111
106
  return projectRoleTurnRequest(
112
107
  admitted,
113
- admittedSeatTurnDetails(admitted, options.packageRoot),
108
+ admittedSeatTurnDetails(admitted, options.home, options.host),
114
109
  options,
115
110
  );
116
111
  }
@@ -160,13 +155,12 @@ async function bindAndRelocateDiarist(
160
155
  function seatAdapters(
161
156
  admitted: AdmittedRoleInvocation,
162
157
  env: InstructionSeatRunEnv,
163
- material?: PackagedMethodSkillMaterial,
164
158
  ): PostAdmissionAdapters<AdmittedRoleInvocation> {
165
159
  const record = roleRecord(admitted.role);
166
160
  const present = "presentSettled" in record ? record.presentSettled : "default";
167
161
  return {
168
162
  trySettle: (seat, authority, scope) =>
169
- trySettlePublicSeat(seat, authority, scope, material, env.packageRoot),
163
+ trySettlePublicSeat(seat, authority, scope),
170
164
  ...(present === "always" ? { shouldPresentSettled: () => true } : {}),
171
165
  ...(present === "typed"
172
166
  ? { shouldPresentSettled: (terminal: TerminalResult) => isLawfulTypedTerminalOutcome(terminal.roleOutcome) }
@@ -233,23 +227,8 @@ async function dispatchAdmitted(
233
227
  io: CliIo,
234
228
  ): Promise<SeatRunResult> {
235
229
  const record = roleRecord(admitted.role);
236
- let material: PackagedMethodSkillMaterial | undefined;
237
- const skill = packagedSettleSkill(admitted);
238
- if (skill !== undefined) {
239
- try {
240
- material = await loadPackagedMethodSkillMaterial(env.packageRoot, skill);
241
- } catch (error) {
242
- const knownCause = packagedMethodLoadFailureCause(admitted.role);
243
- return await presentControlledFailure(admitted, {
244
- timedOut: false,
245
- code: null,
246
- stderr: "",
247
- thrown: error,
248
- ...(knownCause === undefined ? {} : { knownCause }),
249
- }, seatAdapters(admitted, env), env.principalAuthority, io) as SeatRunResult;
250
- }
251
- }
252
- const adapters = seatAdapters(admitted, env, material);
230
+ await warnMissingMethodSkills(env.home, env.host, admitted.role, requiredMethodSkills(admitted), io.stdout);
231
+ const adapters = seatAdapters(admitted, env);
253
232
  const execute = async (activeEnv: InstructionSeatRunEnv): Promise<SeatRunResult> => {
254
233
  const auto = "inCallAutoResume" in record && record.inCallAutoResume === true;
255
234
  if (auto) {
@@ -818,21 +797,9 @@ export async function runPublicInstructionSeatResume(
818
797
  adapters: {
819
798
  trySettle: async () => undefined,
820
799
  },
821
- afterAdmittedLoad: (admitted) => {
822
- const skill = packagedSettleSkill(admitted);
823
- if (skill === undefined) {
824
- return Promise.resolve({ kind: "continue" as const, adapters: seatAdapters(admitted, env) });
825
- }
826
- const knownCause = packagedMethodLoadFailureCause(admitted.role);
827
- return resolveResumeMethodMaterialAdapters({
828
- admitted,
829
- authority: env.principalAuthority,
830
- io,
831
- loadMaterial: () => loadPackagedMethodSkillMaterial(env.packageRoot, skill),
832
- adaptersWith: (material) => seatAdapters(admitted, env, material),
833
- emptyAdapters: seatAdapters(admitted, env),
834
- ...(knownCause === undefined ? {} : { knownCause }),
835
- });
800
+ afterAdmittedLoad: async (admitted) => {
801
+ await warnMissingMethodSkills(env.home, env.host, admitted.role, requiredMethodSkills(admitted), io.stdout);
802
+ return { kind: "continue" as const, adapters: seatAdapters(admitted, env) };
836
803
  },
837
804
  ...(env.engine === undefined ? {} : { effectiveEngine: env.engine }),
838
805
  });
@@ -0,0 +1,153 @@
1
+ import { accessSync, constants, statSync } from "node:fs";
2
+ import { lstat, mkdir, symlink } from "node:fs/promises";
3
+ import { join } from "node:path";
4
+ import { spawnSync } from "node:child_process";
5
+ import { HEADLESS_HOST_DESCRIPTIONS, HOST_DESCRIPTIONS } from "../host-descriptions.ts";
6
+ import { packagedMethodSkillNames } from "../packaged-role-registry.ts";
7
+
8
+ /** Install source only. Which names are required comes from the role registry. */
9
+ const SKILL_SOURCE: Readonly<Record<string, string>> = {
10
+ tdd: "mattpocock/skills",
11
+ "diagnosing-bugs": "mattpocock/skills",
12
+ "resolving-merge-conflicts": "mattpocock/skills",
13
+ "ak-cross-m-review": "Akagilnc/ak-cross-m-review",
14
+ };
15
+
16
+ function skillRoot(home: string): string {
17
+ return join(home, ".agents/skills");
18
+ }
19
+
20
+ export function installedMethodSkillPath(home: string, name: string): string | undefined {
21
+ return installedSkillPath(skillRoot(home), name);
22
+ }
23
+
24
+ function installedSkillPath(root: string, name: string): string | undefined {
25
+ const path = join(root, name, "SKILL.md");
26
+ try {
27
+ if (!statSync(path).isFile()) return undefined;
28
+ accessSync(path, constants.R_OK);
29
+ return path;
30
+ } catch (error) {
31
+ const code = (error as NodeJS.ErrnoException).code;
32
+ if (code === "ENOENT" || code === "ENOTDIR" || code === "EACCES" || code === "EPERM" || code === "ELOOP") return undefined;
33
+ throw error;
34
+ }
35
+ }
36
+
37
+ function linkedSkillRoot(home: string, host: string | undefined): string | undefined {
38
+ if (host === "claude" || host === "claude-code") {
39
+ return join(process.env.CLAUDE_CONFIG_DIR?.trim() || join(home, ".claude"), "skills");
40
+ }
41
+ if (host === "hermes") return join(home, ".hermes/skills");
42
+ return undefined;
43
+ }
44
+
45
+ async function occupied(path: string): Promise<boolean> {
46
+ try {
47
+ await lstat(path);
48
+ return true;
49
+ } catch (error) {
50
+ if ((error as NodeJS.ErrnoException).code !== "ENOENT") throw error;
51
+ return false;
52
+ }
53
+ }
54
+
55
+ function warnOccupied(path: string, stdout: (text: string) => void): void {
56
+ stdout(`Warning: ${path} is already occupied; left untouched.\n`);
57
+ }
58
+
59
+ export async function warnMissingMethodSkills(
60
+ home: string,
61
+ host: string | undefined,
62
+ role: string,
63
+ skills: readonly string[],
64
+ stdout: (text: string) => void,
65
+ ): Promise<void> {
66
+ const missing: string[] = [];
67
+ const linkedRoot = linkedSkillRoot(home, host);
68
+ for (const skill of skills) {
69
+ if (installedMethodSkillPath(home, skill) === undefined ||
70
+ (linkedRoot !== undefined && installedSkillPath(linkedRoot, skill) === undefined)) missing.push(skill);
71
+ }
72
+ for (const skill of missing) {
73
+ stdout(`Warning: required machine Skill "${skill}" is missing for ${role}; its method guidance may be unavailable and reduce work quality. Run \`ak-role setup\` to install required Skills.\n`);
74
+ }
75
+ }
76
+
77
+ function runSkillsCli(args: readonly string[], home: string): boolean {
78
+ const result = spawnSync("npx", ["--yes", "skills", ...args], {
79
+ stdio: "inherit",
80
+ env: { ...process.env, HOME: home },
81
+ });
82
+ if (result.error !== undefined) throw result.error;
83
+ return result.status === 0;
84
+ }
85
+
86
+ function addSkills(source: string, skills: readonly string[], home: string): boolean {
87
+ if (skills.length === 0) return true;
88
+ return runSkillsCli([
89
+ "add", source,
90
+ ...skills.flatMap((skill) => ["--skill", skill]),
91
+ "--agent", "codex", "--global", "--yes",
92
+ ], home);
93
+ }
94
+
95
+ function updateRequiredSkills(home: string): boolean {
96
+ const names = packagedMethodSkillNames();
97
+ if (names.length === 0) return true;
98
+ return runSkillsCli(["update", "-g", "-y", ...names], home);
99
+ }
100
+
101
+ /** Explicit user-run setup; delegates acquisition/install to the ecosystem Skills CLI. */
102
+ export async function runMachineSkillSetup(home: string, stdout: (text: string) => void): Promise<number> {
103
+ const canonical = skillRoot(home);
104
+ const missingBySource = new Map<string, string[]>();
105
+ let unsourced = false;
106
+ for (const name of packagedMethodSkillNames()) {
107
+ const path = join(canonical, name);
108
+ if (await occupied(path)) {
109
+ warnOccupied(path, stdout);
110
+ continue;
111
+ }
112
+ const source = SKILL_SOURCE[name];
113
+ if (source === undefined) {
114
+ unsourced = true;
115
+ stdout(`Warning: required machine Skill "${name}" has no install source; setup did not install it.\n`);
116
+ continue;
117
+ }
118
+ const missing = missingBySource.get(source) ?? [];
119
+ missing.push(name);
120
+ missingBySource.set(source, missing);
121
+ }
122
+ for (const [source, missing] of missingBySource) {
123
+ if (!addSkills(source, missing, home)) return 1;
124
+ }
125
+ if (unsourced) return 1;
126
+
127
+ for (const host of ["claude-code", "hermes"] as const) {
128
+ const root = linkedSkillRoot(home, host)!;
129
+ const binaryFromHome = host === "claude-code"
130
+ ? HEADLESS_HOST_DESCRIPTIONS.claude!.binaryFromHome
131
+ : HOST_DESCRIPTIONS.hermes!.binaryFromHome;
132
+ try {
133
+ accessSync(join(home, ...binaryFromHome), constants.X_OK);
134
+ } catch (error) {
135
+ if (["ENOENT", "ENOTDIR", "EACCES"].includes((error as NodeJS.ErrnoException).code ?? "")) continue;
136
+ throw error;
137
+ }
138
+ for (const name of packagedMethodSkillNames()) {
139
+ const target = join(canonical, name);
140
+ if (installedMethodSkillPath(home, name) === undefined) continue;
141
+ const link = join(root, name);
142
+ if (await occupied(link)) {
143
+ warnOccupied(link, stdout);
144
+ continue;
145
+ }
146
+ await mkdir(root, { recursive: true });
147
+ await symlink(target, link, "dir");
148
+ }
149
+ }
150
+ if (!updateRequiredSkills(home)) return 1;
151
+ stdout("Machine method Skills setup finished. Existing same-name Skills were left untouched.\n");
152
+ return 0;
153
+ }
@@ -1367,6 +1367,7 @@ export function resumeTurnRequestProjectionOptions(
1367
1367
  return {
1368
1368
  packageRoot: env.packageRoot,
1369
1369
  home: env.home,
1370
+ ...(env.host === undefined ? {} : { host: env.host }),
1370
1371
  agentDir: env.agentDir,
1371
1372
  ...(env.model === undefined ? {} : { model: env.model }),
1372
1373
  ...pickEngineAxis(env),
@@ -1393,6 +1394,7 @@ export function roleTurnOptions(
1393
1394
  return {
1394
1395
  packageRoot: env.packageRoot,
1395
1396
  home: env.home,
1397
+ ...(env.host === undefined ? {} : { host: env.host }),
1396
1398
  agentDir: env.agentDir,
1397
1399
  ...(env.model === undefined ? {} : { model: env.model }),
1398
1400
  ...pickEngineAxis(env),
@@ -28,6 +28,7 @@ export const PUBLIC_CLI_SUPPORT_COMMANDS = [
28
28
  "help",
29
29
  "resume",
30
30
  "new",
31
+ "setup",
31
32
  ] as const;
32
33
 
33
34
  export type PublicCliSupportCommand = (typeof PUBLIC_CLI_SUPPORT_COMMANDS)[number];
@@ -92,14 +92,6 @@ import {
92
92
  SECRETARIAT_COUNTERSIGN_TERMINAL_FACT_KEY,
93
93
  SECRETARIAT_GATE_OFFICER_ENTRY_TYPE,
94
94
  } from "../secretariat-contracts.ts";
95
- import {
96
- observePackagedMethodSkillInvocation,
97
- resolvePackagedMethodSkillPath,
98
- type ObservedPackagedMethodSkillInvocation,
99
- type PackagedMethodSkillMaterial,
100
- type PackagedMethodSkillName,
101
- type PackagedMethodSkillProvenance,
102
- } from "../package-resources/method-skill.ts";
103
95
  import {
104
96
  classifyPackagedRoleTerminalResult,
105
97
  findLatestDurablePackagedRoleTerminal,
@@ -2482,21 +2474,14 @@ async function publishAcceptedTerminalArtifacts(
2482
2474
  ];
2483
2475
  }
2484
2476
 
2485
- type MethodPublicationOptions = {
2486
- readonly methodProvenance?: PackagedMethodSkillProvenance;
2487
- readonly methodSkillPath?: string;
2488
- readonly methodSkillConfiguredPath?: string;
2489
- };
2490
-
2491
2477
  /** Publish one accepted seat's report/evidence face from the shared leaf table. */
2492
2478
  export async function publishSeatAcceptedArtifacts(
2493
2479
  admitted: AdmittedRoleInvocation,
2494
2480
  roleOutcome: TerminalRoleOutcome,
2495
2481
  coordinates: DurablePrincipalCoordinates,
2496
2482
  entries: readonly SessionEntry[] = [],
2497
- options: MethodPublicationOptions = {},
2498
2483
  ): Promise<TerminalArtifactRef[]> {
2499
- return publishDeclaredSeatArtifacts(admitted, roleOutcome, coordinates, entries, options);
2484
+ return publishDeclaredSeatArtifacts(admitted, roleOutcome, coordinates, entries);
2500
2485
  }
2501
2486
 
2502
2487
  /**
@@ -2623,13 +2608,12 @@ async function settleSealedAcceptedOrToolResidual(
2623
2608
  /**
2624
2609
  * One settlement for every registered seat. The registry `settlement` leaf
2625
2610
  * picks sealed ledger, sealed-or-residual, or the accepted-tool scan.
2626
- * Seat evidence and the observed-method tail stay on the artifact face.
2611
+ * Seat evidence stays on the artifact face.
2627
2612
  */
2628
2613
  async function settleSeat(
2629
2614
  admitted: AdmittedRoleInvocation,
2630
2615
  authority: DurablePrincipalAuthority,
2631
2616
  scope: SettlementCourtScope | undefined,
2632
- options: MethodPublicationOptions,
2633
2617
  ): Promise<TerminalResult | undefined> {
2634
2618
  const record = packagedRoleMetadata(admitted.role);
2635
2619
  if (record === undefined) {
@@ -2642,7 +2626,7 @@ async function settleSeat(
2642
2626
  roleOutcome: Extract<TerminalRoleOutcome, { kind: "accepted" | "audit_escalation" }>,
2643
2627
  coordinates: DurablePrincipalCoordinates,
2644
2628
  entries: readonly SessionEntry[],
2645
- ) => publishDeclaredSeatArtifacts(admitted, roleOutcome, coordinates, entries, options);
2629
+ ) => publishDeclaredSeatArtifacts(admitted, roleOutcome, coordinates, entries);
2646
2630
  if (record.settlement === "residual") {
2647
2631
  return settleSealedAcceptedOrToolResidual(
2648
2632
  admitted,
@@ -2669,10 +2653,9 @@ async function settleSeat(
2669
2653
  export async function trySettleSeatTerminalResult(
2670
2654
  admitted: AdmittedRoleInvocation,
2671
2655
  authority: DurablePrincipalAuthority,
2672
- options: MethodPublicationOptions = {},
2673
2656
  scope?: SettlementCourtScope,
2674
2657
  ): Promise<TerminalResult | undefined> {
2675
- return settleSeat(admitted, authority, scope, options);
2658
+ return settleSeat(admitted, authority, scope);
2676
2659
  }
2677
2660
 
2678
2661
  /**
@@ -2682,10 +2665,9 @@ export async function trySettleSeatTerminalResult(
2682
2665
  export async function settleSeatTerminalResult(
2683
2666
  admitted: AdmittedRoleInvocation,
2684
2667
  authority: DurablePrincipalAuthority,
2685
- options: MethodPublicationOptions = {},
2686
2668
  scope?: SettlementCourtScope,
2687
2669
  ): Promise<TerminalResult> {
2688
- const settled = await settleSeat(admitted, authority, scope, options);
2670
+ const settled = await settleSeat(admitted, authority, scope);
2689
2671
  if (settled === undefined) {
2690
2672
  const label = admitted.role.charAt(0).toUpperCase() + admitted.role.slice(1);
2691
2673
  throw new Error(
@@ -2695,71 +2677,6 @@ export async function settleSeatTerminalResult(
2695
2677
  return settled;
2696
2678
  }
2697
2679
 
2698
- function sessionMessageText(message: SessionMessage | undefined): string {
2699
- if (message === undefined) return "";
2700
- if (typeof message.content === "string") return message.content;
2701
- if (!Array.isArray(message.content)) return "";
2702
- const parts: string[] = [];
2703
- for (const part of message.content) {
2704
- if (
2705
- typeof part === "object" &&
2706
- part !== null &&
2707
- !Array.isArray(part) &&
2708
- (part as { type?: unknown }).type === "text" &&
2709
- typeof (part as { text?: unknown }).text === "string"
2710
- ) {
2711
- parts.push((part as { text: string }).text);
2712
- }
2713
- }
2714
- return parts.join("\n");
2715
- }
2716
-
2717
- /**
2718
- * Locations a loaded packaged method may be observed at.
2719
- * The name is the loaded material; the configured path is the package copy.
2720
- */
2721
- export function observedMethodSkillOptions(
2722
- packageRoot: string,
2723
- material: PackagedMethodSkillMaterial,
2724
- ): {
2725
- readonly methodProvenance: PackagedMethodSkillProvenance;
2726
- readonly methodSkillPath: string;
2727
- readonly methodSkillConfiguredPath: string;
2728
- } {
2729
- return {
2730
- methodProvenance: material.provenance,
2731
- methodSkillPath: material.skillPath,
2732
- methodSkillConfiguredPath: resolvePackagedMethodSkillPath(packageRoot, material.name),
2733
- };
2734
- }
2735
-
2736
- /**
2737
- * Observe packaged method Skill expansions from the session.
2738
- * The skill name is the caller's packaged method; home locations never count.
2739
- */
2740
- function extractObservedMethodInvocations(
2741
- entries: readonly SessionEntry[],
2742
- options: {
2743
- readonly name: PackagedMethodSkillName;
2744
- readonly allowedLocations: readonly string[];
2745
- },
2746
- ): readonly ObservedPackagedMethodSkillInvocation[] {
2747
- const observed: ObservedPackagedMethodSkillInvocation[] = [];
2748
- for (const entry of entries) {
2749
- if (entry?.type !== "message") continue;
2750
- const message = entry.message;
2751
- if (message?.role !== "user") continue;
2752
- const text = sessionMessageText(message);
2753
- if (text.length === 0) continue;
2754
- const hit = observePackagedMethodSkillInvocation(text, {
2755
- name: options.name,
2756
- allowedLocations: options.allowedLocations,
2757
- });
2758
- if (hit !== undefined) observed.push(hit);
2759
- }
2760
- return Object.freeze(observed);
2761
- }
2762
-
2763
2680
  /**
2764
2681
  * #836: cost and the auditor's no-receipt facts ride beside the role's
2765
2682
  * testimony on the current attempt's candidate entry. Absence is omitted,
@@ -2834,49 +2751,11 @@ function doctorReportFacts(
2834
2751
  };
2835
2752
  }
2836
2753
 
2837
- function observedMethodTail(
2838
- face: PackagedArtifactFace,
2839
- entries: readonly SessionEntry[],
2840
- options: {
2841
- readonly methodProvenance?: PackagedMethodSkillProvenance;
2842
- readonly methodSkillPath?: string;
2843
- readonly methodSkillConfiguredPath?: string;
2844
- },
2845
- ): Record<string, unknown> {
2846
- if (face.method === undefined) return {};
2847
- if (face.method === "optional") {
2848
- return options.methodProvenance === undefined
2849
- ? {}
2850
- : { methodProvenance: options.methodProvenance };
2851
- }
2852
- if (
2853
- options.methodProvenance === undefined
2854
- || options.methodSkillPath === undefined
2855
- || options.methodSkillConfiguredPath === undefined
2856
- ) {
2857
- throw new Error("observed method publication is missing packaged method coordinates");
2858
- }
2859
- const methodInvocations = extractObservedMethodInvocations(entries, {
2860
- name: options.methodProvenance.name,
2861
- allowedLocations: [options.methodSkillPath, options.methodSkillConfiguredPath],
2862
- });
2863
- return {
2864
- methodProvenance: options.methodProvenance,
2865
- methodInvocationObserved: methodInvocations.length > 0,
2866
- methodInvocations,
2867
- };
2868
- }
2869
-
2870
2754
  async function publishDeclaredSeatArtifacts(
2871
2755
  admitted: AdmittedRoleInvocation,
2872
2756
  roleOutcome: TerminalRoleOutcome,
2873
2757
  coordinates: DurablePrincipalCoordinates,
2874
2758
  entries: readonly SessionEntry[],
2875
- options: {
2876
- readonly methodProvenance?: PackagedMethodSkillProvenance;
2877
- readonly methodSkillPath?: string;
2878
- readonly methodSkillConfiguredPath?: string;
2879
- } = {},
2880
2759
  ): Promise<TerminalArtifactRef[]> {
2881
2760
  const face = seatArtifactFace(admitted.role);
2882
2761
  const phase = face.reportPhase === true
@@ -2898,7 +2777,6 @@ async function publishDeclaredSeatArtifacts(
2898
2777
  sessionFile: coordinates.sessionFile,
2899
2778
  admittedRequestPath: admitted.admittedRequestPath,
2900
2779
  attachments: acceptedArtifactAttachmentRefs(admitted.attachments),
2901
- ...observedMethodTail(face, entries, options),
2902
2780
  },
2903
2781
  });
2904
2782
  }
@@ -3040,18 +2918,8 @@ export async function trySettlePublicSeat(
3040
2918
  admitted: AdmittedRoleInvocation,
3041
2919
  authority: DurablePrincipalAuthority,
3042
2920
  scope: { readonly courtAttemptId?: string } | undefined,
3043
- material: PackagedMethodSkillMaterial | undefined,
3044
- packageRoot: string,
3045
2921
  ): Promise<TerminalResult | undefined> {
3046
- const face = seatArtifactFace(admitted.role);
3047
- if (face.method === "observed" && material === undefined) return undefined;
3048
- const options: MethodPublicationOptions =
3049
- face.method === "observed" && material !== undefined
3050
- ? observedMethodSkillOptions(packageRoot, material)
3051
- : face.method === "optional" && material !== undefined
3052
- ? { methodProvenance: material.provenance }
3053
- : {};
3054
- return settleSeat(admitted, authority, scope, options);
2922
+ return settleSeat(admitted, authority, scope);
3055
2923
  }
3056
2924
 
3057
2925
  /**
@@ -10,16 +10,13 @@ import type {
10
10
  RoleTurnRequest,
11
11
  } from "../host-contracts.ts";
12
12
  import { pickEngineAxis } from "../package-resources/engine-material.ts";
13
- import {
14
- resolvePackagedMethodSkillPath,
15
- type PackagedMethodSkillName,
16
- } from "../package-resources/method-skill.ts";
17
13
  import {
18
14
  packagedRoleActivationFlags,
19
15
  packagedRoleMetadata,
20
16
  } from "../packaged-role-registry.ts";
21
17
  import type { SeatModelConfig } from "./config.ts";
22
18
  import type { AdmittedRoleInvocation } from "./invocation.ts";
19
+ import { installedMethodSkillPath } from "./machine-method-skills.ts";
23
20
  import { parentRunPathFromGatePointerInstruction } from "./run-lifecycle.ts";
24
21
  import type { PublicThinkingLevel } from "./registry.ts";
25
22
 
@@ -33,6 +30,7 @@ export type ResumeModelConfig = {
33
30
  export type RoleTurnRequestProjectionOptions = {
34
31
  packageRoot: string;
35
32
  home: string;
33
+ host?: string;
36
34
  agentDir: string;
37
35
  model?: SeatModelConfig;
38
36
  engine?: string;
@@ -103,7 +101,7 @@ export function projectRoleTurnRequest(
103
101
  */
104
102
  export function packagedSettleSkill(
105
103
  admitted: AdmittedRoleInvocation,
106
- ): PackagedMethodSkillName | undefined {
104
+ ): string | undefined {
107
105
  const record = packagedRoleMetadata(admitted.role);
108
106
  if (record === undefined) return undefined;
109
107
  if ("applyMethod" in record && record.applyMethod !== undefined) {
@@ -148,33 +146,43 @@ function activationForAdmitted(admitted: AdmittedRoleInvocation): RoleTurnActiva
148
146
  }
149
147
 
150
148
  /** Skill bindings declared on the composition-root record for this admitted run. */
151
- function methodBindings(
152
- admitted: AdmittedRoleInvocation,
153
- packageRoot: string,
154
- ): readonly MethodBinding[] {
149
+ export function requiredMethodSkills(admitted: AdmittedRoleInvocation): readonly string[] {
155
150
  const record = packagedRoleMetadata(admitted.role);
156
- const names: PackagedMethodSkillName[] = [];
151
+ const names: string[] = [];
157
152
  if (record !== undefined && "methodSkills" in record && record.methodSkills !== undefined) {
158
153
  names.push(...record.methodSkills);
159
154
  }
160
155
  const apply = packagedSettleSkill(admitted);
161
156
  if (apply !== undefined && !names.includes(apply)) names.push(apply);
162
- return names.map((name) => ({
163
- kind: "skill" as const,
164
- path: resolvePackagedMethodSkillPath(packageRoot, name),
165
- }));
157
+ return names;
158
+ }
159
+
160
+ function methodBindings(
161
+ admitted: AdmittedRoleInvocation,
162
+ home: string,
163
+ host: string | undefined,
164
+ ): readonly MethodBinding[] {
165
+ if (host !== undefined && host !== "pi") return [];
166
+ return requiredMethodSkills(admitted).flatMap((name) => {
167
+ const path = installedMethodSkillPath(home, name);
168
+ return path === undefined ? [] : [{
169
+ kind: "skill" as const,
170
+ path,
171
+ }];
172
+ });
166
173
  }
167
174
 
168
175
  /** Registry activation and method bindings for one admitted public seat. */
169
176
  export function admittedSeatTurnDetails(
170
177
  admitted: AdmittedRoleInvocation,
171
- packageRoot: string,
178
+ home: string,
179
+ host: string | undefined,
172
180
  ): {
173
181
  readonly activation: RoleTurnActivation;
174
182
  readonly methods: readonly MethodBinding[];
175
183
  } {
176
184
  return {
177
185
  activation: activationForAdmitted(admitted),
178
- methods: methodBindings(admitted, packageRoot),
186
+ methods: methodBindings(admitted, home, host),
179
187
  };
180
188
  }
@@ -3,8 +3,6 @@ import { Type } from "typebox";
3
3
  import { openToolObjectFromUnion } from "./open-tool-schema.ts";
4
4
  import { withTerminatingOutputDeclarations } from "./package-contracts/terminating-infrastructure.ts";
5
5
 
6
- import type { AnyCanonicalSkillBinding, CanonicalSkillBinding } from "./canonical-skill-binding.ts";
7
- export type { CanonicalSkillBinding };
8
6
  import { REVIEWER_OUTPUT_TOOL_NAME, type ReviewerIntent } from "./package-contracts/reviewer-output.ts";
9
7
 
10
8
  export { REVIEWER_OUTPUT_TOOL_NAME };
@@ -59,7 +57,6 @@ export const reviewerOutputSchema = withTerminatingOutputDeclarations(
59
57
  );
60
58
  export type ReviewerRoleDependencies = {
61
59
  loadSoul(): Promise<string>;
62
- loadCanonicalSkillBinding(name: "ak-cross-m-review"): Promise<AnyCanonicalSkillBinding>;
63
60
  };
64
61
  export type ReviewerRoleHostActions = { failInfrastructure(error: unknown, ctx: HostContext, toolCallId?: string): never };
65
62
 
@@ -67,8 +64,6 @@ export type ReviewerRoleHostActions = { failInfrastructure(error: unknown, ctx:
67
64
  export type ReviewerActivation = Readonly<{
68
65
  fixedBaseRevision: string;
69
66
  soul: string;
70
- /** Frozen ak-cross-m-review binding — envelope owns expansion capture against this data. */
71
- skillBinding: CanonicalSkillBinding<"ak-cross-m-review">;
72
67
  }>;
73
68
 
74
69
  /**
@@ -84,7 +79,6 @@ export function createReviewerRoleRuntime(
84
79
  activate(ctx: HostContext | undefined, admitted: ReviewerAdmittedInputs): Promise<ReviewerActivation>;
85
80
  } {
86
81
  let soul: string | undefined;
87
- let binding: CanonicalSkillBinding<"ak-cross-m-review"> | undefined;
88
82
  let registered = false;
89
83
  let fixedBaseRevision: string | undefined;
90
84
 
@@ -93,15 +87,12 @@ export function createReviewerRoleRuntime(
93
87
  soul = (await dependencies.loadSoul()).trim();
94
88
  if (!soul) throw new Error("Reviewer soul is empty");
95
89
  fixedBaseRevision = admitted.baseRevision;
96
- const loaded = await dependencies.loadCanonicalSkillBinding("ak-cross-m-review");
97
- if (loaded.name !== "ak-cross-m-review") throw new Error("Canonical Skill binding loader returned tdd for ak-cross-m-review");
98
- binding = loaded;
99
90
 
100
91
  if (!registered) {
101
92
  registered = true;
102
93
  pi.registerTool({ name: REVIEWER_OUTPUT_TOOL_NAME, label: "御史台输出", description: "提交御史台终局回执。本席自调 ak-cross-m-review skill。", promptSnippet: "提交御史台终局回执", parameters: reviewerOutputSchema,
103
94
  async execute(_id: string, parameters: unknown): Promise<HostToolResult<unknown>> {
104
- if (!soul || !binding) throw new Error("御史台输入未装载");
95
+ if (!soul) throw new Error("御史台输入未装载");
105
96
  return {
106
97
  content: [],
107
98
  details: parameters,
@@ -111,11 +102,9 @@ export function createReviewerRoleRuntime(
111
102
  }
112
103
  const activatedSoul = soul;
113
104
  const activatedBase = fixedBaseRevision;
114
- const activatedBinding = binding;
115
105
  return Object.freeze({
116
106
  fixedBaseRevision: activatedBase,
117
107
  soul: activatedSoul,
118
- skillBinding: activatedBinding,
119
108
  });
120
109
  },
121
110
  };