@akagilnc/pi-workflow-roles 0.1.5015 → 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 (95) 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 +525 -978
  5. package/dist/headless-host/description.js +0 -2
  6. package/dist/headless-host/production-host.js +528 -1014
  7. package/dist/host-descriptions.js +2 -3
  8. package/dist/migrate-book-topology.js +7 -12
  9. package/dist/packaged-role-registry.js +20 -18
  10. package/dist/pi/role-turn-host.js +3 -27
  11. package/dist/public-cli/cli.js +23 -2
  12. package/dist/public-cli/countersign-run.js +13 -8
  13. package/dist/public-cli/instruction-seat-run.js +75 -107
  14. package/dist/public-cli/invocation.js +13 -32
  15. package/dist/public-cli/machine-method-skills.js +150 -0
  16. package/dist/public-cli/main.js +549 -679
  17. package/dist/public-cli/post-admission.js +10 -5
  18. package/dist/public-cli/registry.js +2 -1
  19. package/dist/public-cli/run-lifecycle.js +12 -15
  20. package/dist/public-cli/seat-ticket-binding.js +5 -8
  21. package/dist/public-cli/settlement.js +12 -99
  22. package/dist/public-cli/turn-request.js +16 -8
  23. package/dist/public-role-summons.js +8 -3
  24. package/package.json +5 -1
  25. package/resources/countersign-ticket-issue.md +5 -0
  26. package/resources/diarist-collect.md +1 -0
  27. package/resources/secretariat-ticket-identity.md +15 -0
  28. package/scripts/build-package.mjs +1 -6
  29. package/src/headless-host/description.ts +0 -3
  30. package/src/headless-host/role-turn-host.ts +2 -23
  31. package/src/host-contracts.ts +2 -23
  32. package/src/host-descriptions.ts +2 -3
  33. package/src/packaged-role-registry.ts +17 -16
  34. package/src/pi/adapter.ts +0 -27
  35. package/src/pi/role-turn-host.ts +3 -31
  36. package/src/public-cli/cli.ts +24 -2
  37. package/src/public-cli/countersign-run.ts +17 -10
  38. package/src/public-cli/instruction-seat-run.ts +75 -105
  39. package/src/public-cli/invocation.ts +10 -38
  40. package/src/public-cli/machine-method-skills.ts +153 -0
  41. package/src/public-cli/post-admission.ts +12 -6
  42. package/src/public-cli/registry.ts +1 -0
  43. package/src/public-cli/run-lifecycle.ts +12 -13
  44. package/src/public-cli/seat-ticket-binding.ts +5 -8
  45. package/src/public-cli/settlement.ts +6 -138
  46. package/src/public-cli/turn-request.ts +24 -16
  47. package/src/public-role-summons.ts +16 -3
  48. package/src/reviewer-role.ts +1 -12
  49. package/src/role-envelope.ts +0 -13
  50. package/src/role-runtime-dependencies.ts +0 -13
  51. package/src/role-runtime.ts +4 -56
  52. package/src/worker-role.ts +1 -81
  53. package/dist/method-host-plugin/.claude-plugin/plugin.json +0 -5
  54. package/dist/method-host-plugin/skills/ak-cross-m-review/CONTEXT.md +0 -48
  55. package/dist/method-host-plugin/skills/ak-cross-m-review/LICENSE +0 -21
  56. package/dist/method-host-plugin/skills/ak-cross-m-review/SKILL.md +0 -170
  57. package/dist/method-host-plugin/skills/ak-cross-m-review/prompts/cmr-completeness.md +0 -118
  58. package/dist/method-host-plugin/skills/ak-cross-m-review/prompts/cmr-reviewer.md +0 -128
  59. package/dist/method-host-plugin/skills/ak-cross-m-review/provenance.json +0 -41
  60. package/dist/method-host-plugin/skills/diagnosing-bugs/SKILL.md +0 -134
  61. package/dist/method-host-plugin/skills/diagnosing-bugs/agents/openai.yaml +0 -3
  62. package/dist/method-host-plugin/skills/diagnosing-bugs/provenance.json +0 -31
  63. package/dist/method-host-plugin/skills/diagnosing-bugs/scripts/hitl-loop.template.sh +0 -41
  64. package/dist/method-host-plugin/skills/resolving-merge-conflicts/SKILL.md +0 -14
  65. package/dist/method-host-plugin/skills/resolving-merge-conflicts/agents/openai.yaml +0 -3
  66. package/dist/method-host-plugin/skills/resolving-merge-conflicts/provenance.json +0 -26
  67. package/dist/method-host-plugin/skills/tdd/SKILL.md +0 -38
  68. package/dist/method-host-plugin/skills/tdd/agents/openai.yaml +0 -3
  69. package/dist/method-host-plugin/skills/tdd/mocking.md +0 -59
  70. package/dist/method-host-plugin/skills/tdd/provenance.json +0 -36
  71. package/dist/method-host-plugin/skills/tdd/tests.md +0 -77
  72. package/dist/package-resources/method-skill.js +0 -259
  73. package/resources/method-host-plugin/.claude-plugin/plugin.json +0 -5
  74. package/resources/methods/ak-cross-m-review/CONTEXT.md +0 -48
  75. package/resources/methods/ak-cross-m-review/LICENSE +0 -21
  76. package/resources/methods/ak-cross-m-review/SKILL.md +0 -170
  77. package/resources/methods/ak-cross-m-review/prompts/cmr-completeness.md +0 -118
  78. package/resources/methods/ak-cross-m-review/prompts/cmr-reviewer.md +0 -128
  79. package/resources/methods/ak-cross-m-review/provenance.json +0 -41
  80. package/resources/methods/diagnosing-bugs/SKILL.md +0 -134
  81. package/resources/methods/diagnosing-bugs/agents/openai.yaml +0 -3
  82. package/resources/methods/diagnosing-bugs/provenance.json +0 -31
  83. package/resources/methods/diagnosing-bugs/scripts/hitl-loop.template.sh +0 -41
  84. package/resources/methods/resolving-merge-conflicts/SKILL.md +0 -14
  85. package/resources/methods/resolving-merge-conflicts/agents/openai.yaml +0 -3
  86. package/resources/methods/resolving-merge-conflicts/provenance.json +0 -26
  87. package/resources/methods/tdd/SKILL.md +0 -38
  88. package/resources/methods/tdd/agents/openai.yaml +0 -3
  89. package/resources/methods/tdd/mocking.md +0 -59
  90. package/resources/methods/tdd/provenance.json +0 -36
  91. package/resources/methods/tdd/tests.md +0 -77
  92. package/src/canonical-skill-binding.ts +0 -118
  93. package/src/host-native-method.ts +0 -185
  94. package/src/package-resources/method-skill-binding.ts +0 -60
  95. package/src/package-resources/method-skill.ts +0 -363
@@ -104,8 +104,9 @@ function withOnceSuccessfulBeforeDispatch(adapters) {
104
104
  beforeDispatch: async (admitted, lease) => {
105
105
  if (succeeded)
106
106
  return;
107
- await hook(admitted, lease);
107
+ const result = await hook(admitted, lease);
108
108
  succeeded = true;
109
+ return result;
109
110
  },
110
111
  };
111
112
  }
@@ -333,9 +334,8 @@ export async function dispatchPostAdmissionTurn(input) {
333
334
  };
334
335
  }
335
336
  try {
336
- // #858: an unbound seat may assert its ticket on the existing receipt.
337
- // Read the original accepted payload; do not rewrite it, infer from prose,
338
- // or reject missing/malformed declarations. An existing binding wins.
337
+ // #858: the first typed assertion files an unbound run. Later receipts
338
+ // remain untouched; this seam does not adjudicate a ticket change.
339
339
  if (admitted.ticketNumber === undefined) {
340
340
  const rows = await readRecordedSubmissionRows(admitted.projectRoot, admitted.runId, { home: homeFromRunDirectory(admitted.runDirectory), sessionParent: join(admitted.runDirectory, "session", "session.jsonl") });
341
341
  const asserted = rows
@@ -429,7 +429,10 @@ export async function dispatchPostAdmissionTurn(input) {
429
429
  // (#840 父子不层叠).
430
430
  if (adapters.beforeDispatch !== undefined) {
431
431
  try {
432
- await adapters.beforeDispatch(admitted, lease);
432
+ const paused = await adapters.beforeDispatch(admitted, lease);
433
+ if (paused !== undefined) {
434
+ return { exitCode: 0, admitted, terminal: paused, skipAutoResume: true };
435
+ }
433
436
  }
434
437
  catch (error) {
435
438
  const settled = (await presentControlledFailure(admitted, withEngineDetourInvocationScope({
@@ -860,6 +863,7 @@ export function resumeTurnRequestProjectionOptions(admitted, request, env, summo
860
863
  return {
861
864
  packageRoot: env.packageRoot,
862
865
  home: env.home,
866
+ ...(env.host === undefined ? {} : { host: env.host }),
863
867
  agentDir: env.agentDir,
864
868
  ...(env.model === undefined ? {} : { model: env.model }),
865
869
  ...pickEngineAxis(env),
@@ -881,6 +885,7 @@ export function roleTurnOptions(env, admitted, continuation) {
881
885
  return {
882
886
  packageRoot: env.packageRoot,
883
887
  home: env.home,
888
+ ...(env.host === undefined ? {} : { host: env.host }),
884
889
  agentDir: env.agentDir,
885
890
  ...(env.model === undefined ? {} : { model: env.model }),
886
891
  ...pickEngineAxis(env),
@@ -13,7 +13,8 @@ const PUBLIC_CLI_SUPPORT_COMMANDS = [
13
13
  "config",
14
14
  "help",
15
15
  "resume",
16
- "new"
16
+ "new",
17
+ "setup"
17
18
  ];
18
19
  function seatModelOnly(seat) {
19
20
  if (seat?.provider === void 0 || seat.model === void 0) return void 0;
@@ -816,11 +816,10 @@ async function runHasFormedSessionPrincipal(runDirectory) {
816
816
  /**
817
817
  * Locate the latest retained run for one seat under a book (#637 / #747).
818
818
  * Same walk surface as findRunDirectoryById (listBookRunDirectories). Match by
819
- * parent run path (officer / gate seats, #747 / #987). A typed ticket number
820
- * does not select a run. runId is UUIDv7 — lexicographic max is latest among
821
- * runs that formed a session principal. No parallel index. Public ticket-number
822
- * selection of a prior run was deleted (#987 Result 7); callers use explicit
823
- * `ak-role resume <runId>`.
819
+ * parent run path (officer / gate seats, #747 / #987), narrowed to a supplied
820
+ * typed ticket for same-ticket gate re-summons. runId is UUIDv7 — lexicographic
821
+ * max is latest among runs that formed a session principal. No parallel index;
822
+ * callers can use explicit `ak-role resume <runId>`.
824
823
  * Only a truly missing book directory means no history; damage/permission errors propagate.
825
824
  */
826
825
  export async function findLatestRunIdForSeatTicket(input) {
@@ -831,11 +830,7 @@ export async function findLatestRunIdForSeatTicket(input) {
831
830
  const bookDir = activationBookDirectory(ledgerHome, input.bookKey);
832
831
  let runDirectories;
833
832
  try {
834
- // A typed ticket narrows the existing walk surface to that ticket's runs;
835
- // same-parent matching below still selects the actual prior leg.
836
- runDirectories = await listBookRunDirectories(input.ticketNumber === undefined
837
- ? bookDir
838
- : join(bookDir, String(input.ticketNumber)));
833
+ runDirectories = await listBookRunDirectories(input.ticketNumber === undefined ? bookDir : join(bookDir, String(input.ticketNumber)));
839
834
  }
840
835
  catch (error) {
841
836
  if (errorCodeOf(error) === "ENOENT")
@@ -852,7 +847,9 @@ export async function findLatestRunIdForSeatTicket(input) {
852
847
  if (runId.length === 0)
853
848
  continue;
854
849
  const parentPath = await readRunParentPath(runDirectory);
855
- if (parentPath !== input.parentRunPath)
850
+ // The parent's ticket can change after this child was admitted. Within one
851
+ // book the run leaf is its stable identity; directory placement is not.
852
+ if (parentPath !== input.parentRunPath && basename(parentPath ?? "") !== basename(input.parentRunPath))
856
853
  continue;
857
854
  // Durable fact: never resume-select a provisional that never formed principal.
858
855
  if (!(await runHasFormedSessionPrincipal(runDirectory)))
@@ -935,7 +932,7 @@ function restoredTicketFields(fields) {
935
932
  : { courtTicketNumbers: fields.courtTicketNumbers }),
936
933
  };
937
934
  }
938
- async function loadResumableRunRecord(home, runId, authority) {
935
+ async function loadResumableRunRecord(home, runId, authority, allowUnformedAdmitted = false) {
939
936
  const runDirectory = await findRunDirectoryById(home, runId);
940
937
  if (runDirectory === undefined) {
941
938
  throw new CliUsageError(`unknown role run id: ${runId}`);
@@ -952,7 +949,7 @@ async function loadResumableRunRecord(home, runId, authority) {
952
949
  throw new CliUsageError(`unknown role run id: ${runId}`);
953
950
  }
954
951
  const { run, principal } = materialized;
955
- if (!(await isDurablePrincipalAvailable(principal, authority))) {
952
+ if (!(allowUnformedAdmitted && run.state === "admitted") && !(await isDurablePrincipalAvailable(principal, authority))) {
956
953
  throw new CliUsageError(`role run Pi session principal is unavailable: ${runId}`);
957
954
  }
958
955
  // Reconstruct admitted identity from durable run record + admitted-request.json.
@@ -1271,8 +1268,8 @@ export async function peekRoleRunRole(home, runId) {
1271
1268
  * selects the existing restore checks. The stored native host session id is
1272
1269
  * read on the public explicit resume seam, not from this load.
1273
1270
  */
1274
- export async function loadResumablePublicRole(home, runId, authority) {
1275
- const loaded = await loadResumableRunRecord(home, runId, authority);
1271
+ export async function loadResumablePublicRole(home, runId, authority, allowUnformedAdmitted = false) {
1272
+ const loaded = await loadResumableRunRecord(home, runId, authority, allowUnformedAdmitted);
1276
1273
  return seatLoadedResult(loaded, admitResumedRole(loaded));
1277
1274
  }
1278
1275
  /**
@@ -1,10 +1,9 @@
1
1
  /**
2
2
  * Shared same-parent resume seam for gate / officer seats (#635 / #637 / #747 / #987).
3
3
  *
4
- * Lookup key is parent run path only (#747 / #987 Result 7). Public seats no
5
- * longer select a prior run by ticket number — callers use explicit
6
- * `ak-role resume <runId>`. Officer and gate countersign same-parent re-summons
7
- * keep this seam. Lookup/resume failures propagate (失败诚实) — never wash into
4
+ * Lookup uses the parent run path; a typed ticket narrows same-ticket gate
5
+ * re-summons, never creates an issue identity. Callers can also use explicit
6
+ * `ak-role resume <runId>`. Lookup/resume failures propagate (失败诚实) — never wash into
8
7
  * a fresh mint. Returns undefined when the caller declared an explicit fresh
9
8
  * summons (`ak-role new`) or when no prior run exists; both mint new.
10
9
  * freshSummons is required so no seat can drift back into its own skip branch.
@@ -13,7 +12,7 @@ import { resolveBookKeyFromGit } from "../activation-ledger-git.js";
13
12
  import { findLatestRunIdForSeatTicket, } from "./run-lifecycle.js";
14
13
  /**
15
14
  * Sole same-seat → resume decision by parent run path (#637 / #724 / #747 / #987).
16
- * A typed ticket number is a bind key, not a resume key. When a prior run is
15
+ * A supplied typed ticket only narrows the prior-run search. When a prior run is
17
16
  * found, resume carries this summons' materials. Lookup/resume failures
18
17
  * propagate (失败诚实) — never wash into a fresh mint. Returns undefined when
19
18
  * the caller declared an explicit fresh summons (`ak-role new`), the parent
@@ -30,9 +29,7 @@ export async function tryResumeSameTicketSeatRun(input) {
30
29
  bookKey: resolveBookKeyFromGit(input.projectRoot),
31
30
  role: input.role,
32
31
  parentRunPath: input.parentRunPath,
33
- ...(input.ticketNumber === undefined
34
- ? {}
35
- : { ticketNumber: input.ticketNumber }),
32
+ ...(input.ticketNumber === undefined ? {} : { ticketNumber: input.ticketNumber }),
36
33
  });
37
34
  if (previousRunId === undefined)
38
35
  return undefined;
@@ -28,7 +28,6 @@ import { DOCTOR_CANDIDATE_ENTRY_TYPE } from "../dossier-resolution.js";
28
28
  import { REVIEWER_OUTPUT_TOOL_NAME, } from "../package-contracts/reviewer-output.js";
29
29
  import { packagedAuditToolName, packagedDurableOfficerEntry, packagedProjectsTargetBindRejection, packagedRoleAcceptedOutputTool, packagedRoleMetadata, packagedSkipsGateOnInfrastructureStage, } from "../packaged-role-registry.js";
30
30
  import { SECRETARIAT_COUNTERSIGN_TERMINAL_FACT_KEY, SECRETARIAT_GATE_OFFICER_ENTRY_TYPE, } from "../secretariat-contracts.js";
31
- import { observePackagedMethodSkillInvocation, resolvePackagedMethodSkillPath, } from "../package-resources/method-skill.js";
32
31
  import { classifyPackagedRoleTerminalResult, findLatestDurablePackagedRoleTerminal, hasNavigatorInfrastructureFailureBase, isAcceptedPackagedRoleTerminalResult, isReceiptSettlementBindingClear, NAVIGATOR_INVOCATION_ENTRY, parseInvocationMarkerIdentity, } from "../navigator-invocation-identity.js";
33
32
  import { NO_RECEIPT_LIFECYCLE_ENTRY_TYPE, RECEIPT_DELIVERY_TURN_LIMIT, noReceiptLifecycleFacts, parseNoReceiptLifecycleFacts, } from "../receipt-delivery-policy.js";
34
33
  import { roleRunArtifactsDirectory } from "../role-run-placement.js";
@@ -1784,8 +1783,8 @@ async function publishAcceptedTerminalArtifacts(admitted, roleOutcome, coordinat
1784
1783
  ];
1785
1784
  }
1786
1785
  /** Publish one accepted seat's report/evidence face from the shared leaf table. */
1787
- export async function publishSeatAcceptedArtifacts(admitted, roleOutcome, coordinates, entries = [], options = {}) {
1788
- return publishDeclaredSeatArtifacts(admitted, roleOutcome, coordinates, entries, options);
1786
+ export async function publishSeatAcceptedArtifacts(admitted, roleOutcome, coordinates, entries = []) {
1787
+ return publishDeclaredSeatArtifacts(admitted, roleOutcome, coordinates, entries);
1789
1788
  }
1790
1789
  /**
1791
1790
  * Read session entries for lawful settlement. Missing path → undefined (absence).
@@ -1871,9 +1870,9 @@ async function settleSealedAcceptedOrToolResidual(admitted, authority, scope, ro
1871
1870
  /**
1872
1871
  * One settlement for every registered seat. The registry `settlement` leaf
1873
1872
  * picks sealed ledger, sealed-or-residual, or the accepted-tool scan.
1874
- * Seat evidence and the observed-method tail stay on the artifact face.
1873
+ * Seat evidence stays on the artifact face.
1875
1874
  */
1876
- async function settleSeat(admitted, authority, scope, options) {
1875
+ async function settleSeat(admitted, authority, scope) {
1877
1876
  const record = packagedRoleMetadata(admitted.role);
1878
1877
  if (record === undefined) {
1879
1878
  throw new Error(`no settlement for ${admitted.role}`);
@@ -1881,7 +1880,7 @@ async function settleSeat(admitted, authority, scope, options) {
1881
1880
  if (record.settlement === "accepted") {
1882
1881
  return trySettleAcceptedSeatTerminalResult(admitted, authority, scope);
1883
1882
  }
1884
- const publish = (roleOutcome, coordinates, entries) => publishDeclaredSeatArtifacts(admitted, roleOutcome, coordinates, entries, options);
1883
+ const publish = (roleOutcome, coordinates, entries) => publishDeclaredSeatArtifacts(admitted, roleOutcome, coordinates, entries);
1885
1884
  if (record.settlement === "residual") {
1886
1885
  return settleSealedAcceptedOrToolResidual(admitted, authority, scope, admitted.role, record.residualTool, record.residualScan, publish);
1887
1886
  }
@@ -1894,75 +1893,21 @@ async function settleSeat(admitted, authority, scope, options) {
1894
1893
  * Try to settle any registered seat. Undefined only for genuine absence.
1895
1894
  * Session malformation and publication exceptions keep their typed identity.
1896
1895
  */
1897
- export async function trySettleSeatTerminalResult(admitted, authority, options = {}, scope) {
1898
- return settleSeat(admitted, authority, scope, options);
1896
+ export async function trySettleSeatTerminalResult(admitted, authority, scope) {
1897
+ return settleSeat(admitted, authority, scope);
1899
1898
  }
1900
1899
  /**
1901
1900
  * Settle any registered seat. Throws when no lawful outcome is present.
1902
1901
  * Session-read and publication failures retain their typed identity.
1903
1902
  */
1904
- export async function settleSeatTerminalResult(admitted, authority, options = {}, scope) {
1905
- const settled = await settleSeat(admitted, authority, scope, options);
1903
+ export async function settleSeatTerminalResult(admitted, authority, scope) {
1904
+ const settled = await settleSeat(admitted, authority, scope);
1906
1905
  if (settled === undefined) {
1907
1906
  const label = admitted.role.charAt(0).toUpperCase() + admitted.role.slice(1);
1908
1907
  throw new Error(`${label} Role run completed without a lawful typed terminal result`);
1909
1908
  }
1910
1909
  return settled;
1911
1910
  }
1912
- function sessionMessageText(message) {
1913
- if (message === undefined)
1914
- return "";
1915
- if (typeof message.content === "string")
1916
- return message.content;
1917
- if (!Array.isArray(message.content))
1918
- return "";
1919
- const parts = [];
1920
- for (const part of message.content) {
1921
- if (typeof part === "object" &&
1922
- part !== null &&
1923
- !Array.isArray(part) &&
1924
- part.type === "text" &&
1925
- typeof part.text === "string") {
1926
- parts.push(part.text);
1927
- }
1928
- }
1929
- return parts.join("\n");
1930
- }
1931
- /**
1932
- * Locations a loaded packaged method may be observed at.
1933
- * The name is the loaded material; the configured path is the package copy.
1934
- */
1935
- export function observedMethodSkillOptions(packageRoot, material) {
1936
- return {
1937
- methodProvenance: material.provenance,
1938
- methodSkillPath: material.skillPath,
1939
- methodSkillConfiguredPath: resolvePackagedMethodSkillPath(packageRoot, material.name),
1940
- };
1941
- }
1942
- /**
1943
- * Observe packaged method Skill expansions from the session.
1944
- * The skill name is the caller's packaged method; home locations never count.
1945
- */
1946
- function extractObservedMethodInvocations(entries, options) {
1947
- const observed = [];
1948
- for (const entry of entries) {
1949
- if (entry?.type !== "message")
1950
- continue;
1951
- const message = entry.message;
1952
- if (message?.role !== "user")
1953
- continue;
1954
- const text = sessionMessageText(message);
1955
- if (text.length === 0)
1956
- continue;
1957
- const hit = observePackagedMethodSkillInvocation(text, {
1958
- name: options.name,
1959
- allowedLocations: options.allowedLocations,
1960
- });
1961
- if (hit !== undefined)
1962
- observed.push(hit);
1963
- }
1964
- return Object.freeze(observed);
1965
- }
1966
1911
  /**
1967
1912
  * #836: cost and the auditor's no-receipt facts ride beside the role's
1968
1913
  * testimony on the current attempt's candidate entry. Absence is omitted,
@@ -2027,30 +1972,7 @@ function doctorReportFacts(face, roleOutcome, entries) {
2027
1972
  ...(facts.auditNoReceipt === undefined ? {} : { auditNoReceipt: facts.auditNoReceipt }),
2028
1973
  };
2029
1974
  }
2030
- function observedMethodTail(face, entries, options) {
2031
- if (face.method === undefined)
2032
- return {};
2033
- if (face.method === "optional") {
2034
- return options.methodProvenance === undefined
2035
- ? {}
2036
- : { methodProvenance: options.methodProvenance };
2037
- }
2038
- if (options.methodProvenance === undefined
2039
- || options.methodSkillPath === undefined
2040
- || options.methodSkillConfiguredPath === undefined) {
2041
- throw new Error("observed method publication is missing packaged method coordinates");
2042
- }
2043
- const methodInvocations = extractObservedMethodInvocations(entries, {
2044
- name: options.methodProvenance.name,
2045
- allowedLocations: [options.methodSkillPath, options.methodSkillConfiguredPath],
2046
- });
2047
- return {
2048
- methodProvenance: options.methodProvenance,
2049
- methodInvocationObserved: methodInvocations.length > 0,
2050
- methodInvocations,
2051
- };
2052
- }
2053
- async function publishDeclaredSeatArtifacts(admitted, roleOutcome, coordinates, entries, options = {}) {
1975
+ async function publishDeclaredSeatArtifacts(admitted, roleOutcome, coordinates, entries) {
2054
1976
  const face = seatArtifactFace(admitted.role);
2055
1977
  const phase = face.reportPhase === true
2056
1978
  ? { phase: readAdmittedPath(admitted, "phase") }
@@ -2071,7 +1993,6 @@ async function publishDeclaredSeatArtifacts(admitted, roleOutcome, coordinates,
2071
1993
  sessionFile: coordinates.sessionFile,
2072
1994
  admittedRequestPath: admitted.admittedRequestPath,
2073
1995
  attachments: acceptedArtifactAttachmentRefs(admitted.attachments),
2074
- ...observedMethodTail(face, entries, options),
2075
1996
  },
2076
1997
  });
2077
1998
  }
@@ -2163,16 +2084,8 @@ export async function trySettleAcceptedSeatTerminalResult(admitted, authority, s
2163
2084
  return applySecretariatCountersignTerminal(admitted, authority, settled);
2164
2085
  }
2165
2086
  /** One settlement dispatch. The registry `settlement` leaf selects the path. */
2166
- export async function trySettlePublicSeat(admitted, authority, scope, material, packageRoot) {
2167
- const face = seatArtifactFace(admitted.role);
2168
- if (face.method === "observed" && material === undefined)
2169
- return undefined;
2170
- const options = face.method === "observed" && material !== undefined
2171
- ? observedMethodSkillOptions(packageRoot, material)
2172
- : face.method === "optional" && material !== undefined
2173
- ? { methodProvenance: material.provenance }
2174
- : {};
2175
- return settleSeat(admitted, authority, scope, options);
2087
+ export async function trySettlePublicSeat(admitted, authority, scope) {
2088
+ return settleSeat(admitted, authority, scope);
2176
2089
  }
2177
2090
  /**
2178
2091
  * #969 seat projection sole authority: 给事中 terminal (署|上呈) booked as a
@@ -1,6 +1,6 @@
1
1
  import { pickEngineAxis } from "../package-resources/engine-material.js";
2
- import { resolvePackagedMethodSkillPath, } from "../package-resources/method-skill.js";
3
2
  import { packagedRoleActivationFlags, packagedRoleMetadata, } from "../packaged-role-registry.js";
3
+ import { installedMethodSkillPath } from "./machine-method-skills.js";
4
4
  import { parentRunPathFromGatePointerInstruction } from "./run-lifecycle.js";
5
5
  export function projectRoleTurnRequest(admitted, roleDetails, options) {
6
6
  const cwd = admitted.projectRoot ?? admitted.repoRoot ?? admitted.cwd;
@@ -86,7 +86,7 @@ function activationForAdmitted(admitted) {
86
86
  return activation;
87
87
  }
88
88
  /** Skill bindings declared on the composition-root record for this admitted run. */
89
- function methodBindings(admitted, packageRoot) {
89
+ export function requiredMethodSkills(admitted) {
90
90
  const record = packagedRoleMetadata(admitted.role);
91
91
  const names = [];
92
92
  if (record !== undefined && "methodSkills" in record && record.methodSkills !== undefined) {
@@ -95,15 +95,23 @@ function methodBindings(admitted, packageRoot) {
95
95
  const apply = packagedSettleSkill(admitted);
96
96
  if (apply !== undefined && !names.includes(apply))
97
97
  names.push(apply);
98
- return names.map((name) => ({
99
- kind: "skill",
100
- path: resolvePackagedMethodSkillPath(packageRoot, name),
101
- }));
98
+ return names;
99
+ }
100
+ function methodBindings(admitted, home, host) {
101
+ if (host !== undefined && host !== "pi")
102
+ return [];
103
+ return requiredMethodSkills(admitted).flatMap((name) => {
104
+ const path = installedMethodSkillPath(home, name);
105
+ return path === undefined ? [] : [{
106
+ kind: "skill",
107
+ path,
108
+ }];
109
+ });
102
110
  }
103
111
  /** Registry activation and method bindings for one admitted public seat. */
104
- export function admittedSeatTurnDetails(admitted, packageRoot) {
112
+ export function admittedSeatTurnDetails(admitted, home, host) {
105
113
  return {
106
114
  activation: activationForAdmitted(admitted),
107
- methods: methodBindings(admitted, packageRoot),
115
+ methods: methodBindings(admitted, home, host),
108
116
  };
109
117
  }
@@ -274,7 +274,10 @@ async function summonPublicRole(options) {
274
274
  result = stepped.ok;
275
275
  }
276
276
  const stderr = captured?.stderrText();
277
- const runDirectory = result.admitted?.runDirectory;
277
+ const runDirectory = result.terminal !== void 0 && result.terminal.roleOutcome.role !== options.role && typeof result.terminal.runId === "string" ? await (await import("./public-cli/run-lifecycle.js")).findRunDirectoryById(
278
+ home,
279
+ result.terminal.runId
280
+ ) : result.admitted?.runDirectory;
278
281
  return {
279
282
  exitCode: result.exitCode,
280
283
  ...result.terminal === void 0 ? {} : { terminal: result.terminal },
@@ -478,8 +481,10 @@ async function summonGateOfficer(options) {
478
481
  `countersign gate summon requires parent runId from sourceRunDirectory: ${options.sourceRunDirectory}`
479
482
  );
480
483
  }
481
- const { readBoardTicketNumber } = await import("./run-ticket-number.js");
484
+ const { isSafePositiveTicketNumber, readBoardTicketNumber } = await import("./run-ticket-number.js");
482
485
  const parentTicket = await readBoardTicketNumber(options.sourceRunDirectory);
486
+ const submittedTicket = options.submission !== null && typeof options.submission === "object" && !Array.isArray(options.submission) ? options.submission.ticketNumber : void 0;
487
+ const courtTicket = isSafePositiveTicketNumber(submittedTicket) ? submittedTicket : parentTicket;
483
488
  const instruction = options.reask ?? gateReviewInstruction ?? "";
484
489
  return summonPublicRole({
485
490
  role: options.officer,
@@ -487,7 +492,7 @@ async function summonGateOfficer(options) {
487
492
  ...common,
488
493
  correlationId,
489
494
  parentRunPath: options.sourceRunDirectory,
490
- ...parentTicket === void 0 ? {} : { boundTicketNumber: parentTicket }
495
+ ...courtTicket === void 0 ? {} : { boundTicketNumber: courtTicket }
491
496
  });
492
497
  }
493
498
  return summonPublicRole({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@akagilnc/pi-workflow-roles",
3
- "version": "0.1.5015",
3
+ "version": "0.1.5063",
4
4
  "description": "Soul-bound workflow roles for Pi",
5
5
  "type": "module",
6
6
  "license": "Apache-2.0",
@@ -26,6 +26,8 @@
26
26
  },
27
27
  "files": [
28
28
  "dist",
29
+ "!dist/package-resources/method-skill.js",
30
+ "!dist/package-resources/method-skill-binding.js",
29
31
  "extensions",
30
32
  "scripts/generate-tool-execution-observation-schema.ts",
31
33
  "scripts/build-package.mjs",
@@ -34,6 +36,8 @@
34
36
  "schemas",
35
37
  "packets",
36
38
  "resources",
39
+ "!resources/methods",
40
+ "!resources/methods/**",
37
41
  "README.md",
38
42
  "LICENSE",
39
43
  "THIRD_PARTY_NOTICES.md",
@@ -0,0 +1,5 @@
1
+ # 给事中票面审读方法
2
+
3
+ 中书省交卷时,以交卷原文所指的实际 GitHub issue 为审读对象;传召附带的绑定票号只用于绑卷,不替中书省决定票号。先在当前项目的 GitHub 仓库用宿主已有 CLI 读取该 issue 的现行正文(例如 `gh issue view <票号> --json body`);不得只看中书省交卷文字或本地草稿,就声称已审 GitHub 票面。对照原交卷和实际 issue 正文,按《票面法》审读。
4
+
5
+ 中书省以 `converged` 交卷却没有可审的实际 GitHub issue 身份时,封驳退回中书省补齐;不得以无号草稿署票。此类封驳走现有重交通道,不由代码按回执形状拒收。issue 不存在或正文读取失败时,如实说明现场失败,不把未读到的票面判作已审。交卷与绑卷票号冲突也须说明,不猜测替代票号。
@@ -33,6 +33,7 @@
33
33
 
34
34
  - 认得出本庭对象:`status: completed` 且 `ticketNumber: N`,并交边界。
35
35
  - 真无票对象(方案/派单/处置案等):`status: completed` 且 `ticketNumber: null`(或省略)。真无票是合法结果,不入录。
36
+ - 本庭明确要新建票、但 issue 尚未建号:不是认票失败。以 `status: completed`、`ticketNumber: null` 交出已辨明的本案对话边界;起居录先随无号 run 暂存,建号后由既有归卷流程补归该号。不要借用旁票号。
36
37
  - 认不出本庭对象是哪一张:`status: escalate` 并写明 `reason`。识别不了就上抛,不得省略票号假装无录,也不得猜一个号。
37
38
  - 不得从旁及的他票或任何猜测里挑一个号顶替认不出的身份。
38
39
  - 传召文自然会提轮次、决定编号、commit sha、邻票号;你认的是本庭对象,不是文中出现的每一个数字。
@@ -0,0 +1,15 @@
1
+ # 中书省票身份与落票方法
2
+
3
+ 本方法适用于公开中书省调用。票面范围、审读职责和交卷形状仍以各自法源为准。
4
+
5
+ ## 先辨票,再改票
6
+
7
+ 调用者可以给票号,也可以不给。给了票号,先读取并核对该 issue,再在原 issue 上更新票面;不要另建一票。没有给票号,不等于新票:先结合本次对话、本票起居录和当前 GitHub 仓库中的 issue 判断是否已有对应票。找到已有票就更新那张;只有确认没有对应票,才在当前仓库创建 issue。不得仅凭内容相似就认定已有票,也不得因没找到就忽略搜索范围或不确定性。
8
+
9
+ 票面改定后,应将实际要执行的正文落到对应 GitHub issue。不能确认已有票还是新票、无法读取或更新目标 issue,或创建 issue 失败时,不得把草稿当成已落票结果送庭;可上呈或重交,并说明现场观察到的真实失败原因。若信息不足以区分多个候选 issue,可上呈请裁定,不猜票号、不另建重复票。
10
+
11
+ ## 落地后送庭
12
+
13
+ 只有确认目标 issue 存在且正文已更新为本票最终票面后,才以 `converged` 交卷,并携带该 issue 的实际票号。沿用既有交卷闸,将交卷原文交给给事中审这张有票号 issue;不以无号草稿替代 issue 审读。不另造传召或记账机制。
14
+
15
+ 执行 GitHub 操作时使用当前宿主实际提供的 CLI / 能力;不在包内另造 GitHub 适配层。记录足以核对身份和落地结果的证据,不把模型自报冒充为现场观察。
@@ -1,4 +1,4 @@
1
- import { chmod, copyFile, cp, mkdir, readFile, rm, writeFile } from "node:fs/promises";
1
+ import { chmod, copyFile, mkdir, readFile, rm, writeFile } from "node:fs/promises";
2
2
  import { dirname, join, resolve } from "node:path";
3
3
  import { fileURLToPath } from "node:url";
4
4
  import { build } from "esbuild";
@@ -203,11 +203,6 @@ export async function buildPackageArtifacts() {
203
203
  await buildAcpProductionHost();
204
204
  await buildHeadlessProductionHost();
205
205
  await buildMigrateBookTopology();
206
- const pluginDir = join("dist", "method-host-plugin");
207
- await rm(pluginDir, { recursive: true, force: true });
208
- await mkdir(pluginDir, { recursive: true });
209
- await cp("resources/method-host-plugin/.claude-plugin", join(pluginDir, ".claude-plugin"), { recursive: true });
210
- await cp("resources/methods", join(pluginDir, "skills"), { recursive: true });
211
206
  // Packaged handbook/playbook paths resolve via injected packageRoot (#962) —
212
207
  // do not mirror resources/ into dist/resources (one authority, no parallel copy).
213
208
  }
@@ -94,8 +94,6 @@ export function headlessTurnArgs(options: {
94
94
  readonly effort?: string;
95
95
  /** Fresh session: pass as session id. Resume: pass as resume id. */
96
96
  readonly session: { readonly kind: "new"; readonly id: string } | { readonly kind: "resume"; readonly id: string };
97
- /** Packaged method plugin dir (`--plugin-dir`). */
98
- readonly pluginDir?: string;
99
97
  }): string[] {
100
98
  const { description } = options;
101
99
  const args: string[] = [
@@ -107,7 +105,6 @@ export function headlessTurnArgs(options: {
107
105
  if (options.jsonSchema !== undefined) {
108
106
  args.push(description.jsonSchemaFlag, JSON.stringify(options.jsonSchema));
109
107
  }
110
- if (options.pluginDir) args.push("--plugin-dir", options.pluginDir);
111
108
  if (options.mcpConfigPath !== undefined && options.mcpConfigPath !== "") {
112
109
  args.push(description.mcpConfigFlag, options.mcpConfigPath);
113
110
  }
@@ -23,12 +23,6 @@ import {
23
23
  } from "../prepared-role-turn.ts";
24
24
 
25
25
  import { reportHostSessionEvent } from "../host-session-record.ts";
26
- import {
27
- applyClaudeSkillInvocation,
28
- applyCodexSkillInvocation,
29
- hostMethodSkills,
30
- packagedMethodPluginDir,
31
- } from "../host-native-method.ts";
32
26
  import {
33
27
  closeJsonSchemaForCodex,
34
28
  codexTurnArgs,
@@ -418,7 +412,6 @@ function buildTurnArgs(options: {
418
412
  readonly sessionKind: "new" | "resume";
419
413
  readonly cwd: string;
420
414
  readonly writableRoots?: readonly string[];
421
- readonly pluginDir?: string;
422
415
  }): readonly string[] {
423
416
  if (isCodexExecDescription(options.description)) {
424
417
  if (options.sessionKind === "resume" && !options.sessionId) {
@@ -451,7 +444,6 @@ function buildTurnArgs(options: {
451
444
  ...(options.model === undefined ? {} : { model: options.model }),
452
445
  ...(options.effort === undefined ? {} : { effort: options.effort }),
453
446
  session: { kind: options.sessionKind, id: options.sessionId },
454
- ...(options.pluginDir === undefined ? {} : { pluginDir: options.pluginDir }),
455
447
  });
456
448
  }
457
449
 
@@ -460,7 +452,7 @@ export function createHeadlessRoleTurnHost(config: HeadlessRoleTurnHostConfig):
460
452
  return createSerializedRoleTurnHost(async (request): Promise<RoleTurnResult> => {
461
453
  const prepared = await config.prepare(request);
462
454
  const systemPrompt = renderSystemPromptOverride(prepared.systemPrompt);
463
- const codex = isCodexExecDescription(config.description);
455
+ const codex = isCodexExecDescription(config.description);
464
456
  let outcome: RoleTurnResult = failure("session", "HeadlessNoOutcome", "no-outcome");
465
457
  try {
466
458
  // Claude mints a package UUID for --session-id; codex waits for thread.started.
@@ -486,10 +478,6 @@ export function createHeadlessRoleTurnHost(config: HeadlessRoleTurnHostConfig):
486
478
  await writeFile(systemPromptPath, systemPrompt, "utf8");
487
479
  let mcpConfigPath: string | undefined;
488
480
  let outputSchemaPath: string | undefined;
489
- let pluginDir: string | undefined;
490
- let applyMethodPrompt: (prompt: string) => string = codex
491
- ? (prompt) => applyCodexSkillInvocation(request.methods, prompt)
492
- : (prompt) => prompt;
493
481
  if (codex) {
494
482
  // #959: navigator is a prose-exit seat — no closed output-schema.
495
483
  if (prepared.terminatingToolName !== NAVIGATOR_OUTPUT_TOOL_NAME) {
@@ -507,14 +495,6 @@ export function createHeadlessRoleTurnHost(config: HeadlessRoleTurnHostConfig):
507
495
  `${JSON.stringify(headlessMcpConfigDocument(prepared.mcpServers), null, 2)}\n`,
508
496
  "utf8",
509
497
  );
510
- if (hostMethodSkills(request.methods).length > 0) {
511
- const packageRoot = env.AK_PACKAGE_ROOT ?? process.env.AK_PACKAGE_ROOT;
512
- if (typeof packageRoot !== "string" || packageRoot === "") {
513
- throw new Error("claude method plugin-dir requires AK_PACKAGE_ROOT");
514
- }
515
- pluginDir = packagedMethodPluginDir(packageRoot);
516
- applyMethodPrompt = (prompt) => applyClaudeSkillInvocation(request.methods, prompt);
517
- }
518
498
  }
519
499
 
520
500
  const sessionParent = config.sessionIdentity.resolveSessionFile(request.principal);
@@ -542,7 +522,6 @@ export function createHeadlessRoleTurnHost(config: HeadlessRoleTurnHostConfig):
542
522
  sessionKind,
543
523
  cwd: request.cwd,
544
524
  ...(gitCommonDir === undefined ? {} : { writableRoots: [gitCommonDir] }),
545
- ...(pluginDir === undefined ? {} : { pluginDir }),
546
525
  });
547
526
  } catch (error) {
548
527
  const message = error instanceof Error ? error.message : String(error);
@@ -560,7 +539,7 @@ export function createHeadlessRoleTurnHost(config: HeadlessRoleTurnHostConfig):
560
539
  args,
561
540
  cwd: request.cwd,
562
541
  env,
563
- stdin: request.continuation.kind === "resume" ? prompt : applyMethodPrompt(prompt),
542
+ stdin: prompt,
564
543
  ...(abortSignal === undefined ? {} : { signal: abortSignal }),
565
544
  ...(request.timeoutMs === undefined ? {} : { timeoutMs: request.timeoutMs }),
566
545
  onStdoutLine(line) {
@@ -74,7 +74,7 @@ export class ExplicitInternalActivationError extends Error {
74
74
  }
75
75
  }
76
76
 
77
- /** Packaged method skill binding (zero/one/many). */
77
+ /** Required machine-installed method Skill (zero/one/many). */
78
78
  export type MethodBinding = {
79
79
  readonly kind: "skill";
80
80
  readonly path: string;
@@ -350,33 +350,13 @@ type HostGatekeeperSubject = {
350
350
  };
351
351
  /** Gatekeeper non-pass faces returned to parent (#836 includes transport_failure; never kill leg). */
352
352
  type HostGatekeeperNonPass = { readonly status: "continue" | "escalate" | "no_receipt" | "transport_failure" } & Record<string, unknown>;
353
- export type HostSubmissionNonPass =
354
- | HostGatekeeperNonPass
355
- | { readonly code: "coder_skill_expansion_evidence_missing" };
353
+ export type HostSubmissionNonPass = HostGatekeeperNonPass;
356
354
  export type HostGatekeeperActions = {
357
355
  failInfrastructure(error: unknown, context: HostContext, toolCallId?: string): never;
358
356
  /** Envelope-owned execute→tool_result bridge for any structured submission non-pass. */
359
357
  bindSubmissionNonPass(toolCallId: string, result: HostSubmissionNonPass): void;
360
358
  };
361
359
 
362
- export type HostSkillExpansionEvidence = Readonly<{
363
- name: string;
364
- location: string;
365
- content: string;
366
- userMessage: string;
367
- }>;
368
-
369
- /** Host capability declaration (contract verb ④). */
370
- export type HostCapabilityDeclaration = Readonly<{
371
- skillExpansion(prompt: string): HostSkillExpansionEvidence | undefined;
372
- /**
373
- * Pi-only: recover the plain original request from a native skill turn text
374
- * (argv may already carry `/skill:<name>` from the Pi adapter). Absent on
375
- * non-pi hosts so role body never parses Pi slash syntax (ADR 0082).
376
- */
377
- skillOriginalRequest?(name: string, text: string): string;
378
- }>;
379
-
380
360
  /** Host-owned effects used by the shared activation envelope. */
381
361
  export interface RoleEnvelopeHost {
382
362
  readonly host: RoleHost;
@@ -388,7 +368,6 @@ export interface RoleEnvelopeHost {
388
368
 
389
369
  /** The activation surface consumed by package role factories. */
390
370
  export interface RoleHost {
391
- readonly capabilities?: HostCapabilityDeclaration;
392
371
  /** Deliver a typed correctable rejection into the current durable session's model context. */
393
372
  deliverSubmissionRejection?(rejection: { readonly kind: "correctable-rejection"; readonly code: string; readonly toolCallIds: readonly string[] }): void | Promise<void>;
394
373
  registerFlag(name: string, definition: