@akagilnc/pi-workflow-roles 0.1.3826 → 0.1.3873

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 (52) hide show
  1. package/dist/acp-host/production-host.js +22757 -22676
  2. package/dist/canonical-skill-binding.js +0 -3
  3. package/dist/engine-detour-tool.js +2 -2
  4. package/dist/engine-detour.js +23 -7
  5. package/dist/headless-host/production-host.js +4658 -4593
  6. package/dist/host-descriptions.js +5 -2
  7. package/dist/pi/adapter.js +11 -0
  8. package/dist/pi/role-turn-host.js +44 -93
  9. package/dist/public-cli/invocation.js +4 -5
  10. package/dist/public-cli/load-production-acp-host.js +1 -1
  11. package/dist/public-cli/load-production-external-host.js +10 -0
  12. package/dist/public-cli/load-production-headless-host.js +1 -1
  13. package/dist/public-cli/main.js +145 -140
  14. package/dist/public-role-summons.js +7 -49
  15. package/dist/reviewer-agent.js +1 -0
  16. package/dist/reviewer-child-executor.js +3 -2
  17. package/dist/role-activation-flags.js +50 -0
  18. package/dist/role-runtime.js +12 -10
  19. package/dist/worker-role.js +14 -12
  20. package/package.json +1 -1
  21. package/scripts/build-package.mjs +2 -2
  22. package/src/acp-host/production-host.ts +31 -94
  23. package/src/acp-host/role-turn-host.ts +178 -263
  24. package/src/canonical-skill-binding.ts +4 -4
  25. package/src/diagnostic-tail.ts +18 -0
  26. package/src/engine-detour-tool.ts +5 -4
  27. package/src/engine-detour.ts +44 -9
  28. package/src/external-host-turn-loop.ts +172 -0
  29. package/src/headless-host/production-host.ts +10 -7
  30. package/src/headless-host/role-turn-host.ts +271 -263
  31. package/src/host-contracts.ts +6 -0
  32. package/src/host-descriptions.ts +5 -2
  33. package/src/host-session-record.ts +41 -0
  34. package/src/package-resources/method-skill-binding.ts +0 -3
  35. package/src/pi/adapter.ts +13 -0
  36. package/src/pi/role-turn-host.ts +46 -94
  37. package/src/prepared-role-turn.ts +68 -0
  38. package/src/public-cli/cli.ts +11 -20
  39. package/src/public-cli/invocation.ts +4 -5
  40. package/src/public-cli/load-production-acp-host.ts +2 -1
  41. package/src/public-cli/load-production-external-host.ts +17 -0
  42. package/src/public-cli/load-production-headless-host.ts +2 -1
  43. package/src/public-role-summons.ts +12 -69
  44. package/src/reviewer-agent.ts +12 -1
  45. package/src/reviewer-child-executor.ts +10 -2
  46. package/src/role-activation-flags.ts +53 -0
  47. package/src/{acp-host/role-envelope.ts → role-envelope.ts} +41 -98
  48. package/src/role-runtime-dependencies.ts +91 -0
  49. package/src/role-runtime.ts +21 -11
  50. package/src/{acp-host/session-identity.ts → session-identity.ts} +6 -6
  51. package/src/worker-role.ts +14 -13
  52. /package/src/{acp-host/mcp-relay.mjs → mcp-relay.mjs} +0 -0
@@ -48,6 +48,7 @@ export const HOST_DESCRIPTIONS = Object.freeze({
48
48
  /**
49
49
  * Headless CLI family (#645). Claude is the first row; codex (#646) adds another.
50
50
  * fixedArgs: print mode, isolation without `--bare` (OAuth stays), full permissions.
51
+ * stream-json + verbose: live host events for sitian records (#811); result is last line.
51
52
  * `--setting-sources` empty = load no user/project/local CLAUDE.md/hooks/skills
52
53
  * (role envelope is delivered via `--system-prompt` wholesale replace).
53
54
  * `--strict-mcp-config` with no `--mcp-config` drops operator MCP + claude.ai connectors.
@@ -57,8 +58,10 @@ export const HEADLESS_HOST_DESCRIPTIONS = Object.freeze({
57
58
  binaryFromHome: Object.freeze([".local", "bin", "claude"]),
58
59
  sessionBindingFile: "claude-headless-session.json",
59
60
  fixedArgs: Object.freeze([
60
- // One result envelope (not stream-json): typed receipt only; no event-stream copy.
61
- "--output-format", "json",
61
+ // Live NDJSON events → sitian host-session records (#811); last line is the result receipt.
62
+ "--output-format", "stream-json",
63
+ // Intermediate assistant/tool/system events require verbose with stream-json.
64
+ "--verbose",
62
65
  "--permission-mode", "bypassPermissions",
63
66
  // Empty sources: no user/project/local operator surface (envelope owns materials).
64
67
  "--setting-sources", "",
@@ -106,6 +106,17 @@ export function createPiRoleHostAdapter(pi, options = {}) {
106
106
  userMessage,
107
107
  });
108
108
  },
109
+ /** Recover plain original request from Pi-native `/skill:` turn text (ADR 0082). */
110
+ skillOriginalRequest(name, text) {
111
+ const token = `/skill:${name}`;
112
+ const trimmed = text.trimStart();
113
+ if (trimmed === token
114
+ || trimmed.startsWith(`${token} `)
115
+ || trimmed.startsWith(`${token}\n`)) {
116
+ return text.slice(text.indexOf(token) + token.length).trim();
117
+ }
118
+ return text.trim();
119
+ },
109
120
  },
110
121
  registerFlag: (name, definition) => pi.registerFlag(name, definition),
111
122
  getFlag: (name) => pi.getFlag(name),
@@ -6,12 +6,13 @@
6
6
  import { execFile, spawn } from "node:child_process";
7
7
  import { constants } from "node:fs";
8
8
  import { access, appendFile, readFile, realpath } from "node:fs/promises";
9
- import { delimiter, isAbsolute, join, resolve } from "node:path";
9
+ import { basename, delimiter, dirname, isAbsolute, join, resolve } from "node:path";
10
10
  import { platform } from "node:process";
11
11
  import { promisify } from "node:util";
12
12
  import { randomUUID } from "node:crypto";
13
13
  import { ExplicitInternalActivationError } from "../host-contracts.js";
14
14
  import { applyEngineChildEnv } from "../engine-detour.js";
15
+ import { projectActivationFlags } from "../role-activation-flags.js";
15
16
  /** Package-relative Internal role entrypoint (ADR 0052; same path as public-cli registry). */
16
17
  const INTERNAL_ROLE_ENTRYPOINT_RELATIVE = "extensions/role-runtime.ts";
17
18
  export function resolveInternalRoleEntrypoint(packageRoot) {
@@ -45,95 +46,20 @@ function buildSeatModelCliArgs(model) {
45
46
  ...(model.thinking === undefined ? [] : ["--thinking", model.thinking]),
46
47
  ];
47
48
  }
48
- function buildActivationFlagArgs(activation) {
49
- switch (activation.role) {
50
- case "judge":
51
- return ["--ak-role", "judge"];
52
- case "coder":
53
- return [
54
- "--ak-role",
55
- "coder",
56
- "--ak-coder-phase",
57
- activation.phase,
58
- "--ak-coder-task",
59
- activation.taskPath,
60
- ];
61
- case "fixer":
62
- return [
63
- "--ak-role",
64
- "fixer",
65
- "--ak-fixer-phase",
66
- activation.phase,
67
- "--ak-fix-packet",
68
- activation.packetPath,
69
- ...(activation.prerequisitesPath === undefined
70
- ? []
71
- : ["--ak-fixer-prerequisites", activation.prerequisitesPath]),
72
- ];
73
- case "reviewer":
74
- return [
75
- "--ak-role",
76
- "reviewer",
77
- "--ak-review-base",
78
- activation.baseRevision,
79
- ...(activation.authorityRefs.length === 0
80
- ? []
81
- : ["--ak-review-authority-refs", JSON.stringify([...activation.authorityRefs])]),
82
- ...(activation.ticketNumber === undefined
83
- ? []
84
- : ["--ak-review-ticket-number", String(activation.ticketNumber)]),
85
- ];
86
- case "merger":
87
- return ["--ak-role", "merger", "--ak-merger-input", activation.inputPath];
88
- case "collector":
89
- return [
90
- "--ak-role",
91
- "collector",
92
- "--ak-collector-repo",
93
- activation.repo,
94
- ...(activation.pr === undefined ? [] : ["--ak-collector-pr", activation.pr]),
95
- ...(activation.requestManifestPath === undefined
96
- ? []
97
- : ["--ak-collector-request-manifest", activation.requestManifestPath]),
98
- ...(activation.waitMs === undefined ? [] : ["--ak-collector-wait-ms", activation.waitMs]),
99
- ];
100
- case "doctor":
101
- return ["--ak-role", "doctor", "--ak-doctor-case", activation.casePath];
102
- case "notary":
103
- return [
104
- "--ak-role",
105
- "notary",
106
- "--ak-notary-source-run",
107
- activation.sourceRun,
108
- ...(activation.ticketNumber === undefined
109
- ? []
110
- : ["--ak-notary-ticket-number", String(activation.ticketNumber)]),
111
- ];
112
- case "countersign":
113
- // ticketNumber rides activation/admission/invocation only (#632: no private flag).
114
- return ["--ak-role", "countersign"];
115
- case "gleaner-left":
116
- return [
117
- "--ak-role",
118
- "gleaner-left",
119
- "--ak-gleaner-left-base",
120
- activation.baseRevision,
121
- ];
122
- case "inspector":
123
- return ["--ak-role", "inspector"];
124
- case "gatekeeper":
125
- return ["--ak-role", "gatekeeper"];
126
- case "navigator":
127
- return ["--ak-role", "navigator"];
128
- case "auditor":
129
- return ["--ak-role", "auditor"];
130
- case "diarist":
131
- return ["--ak-role", "diarist"];
132
- default: {
133
- const _exhaustive = activation;
134
- return _exhaustive;
135
- }
49
+ /**
50
+ * Pi last hop only: shared envelope flags → controlled-session argv pairs (#819).
51
+ * Flag membership/values stay in projectActivationFlags (middle layer).
52
+ */
53
+ function activationFlagsToPiArgv(flags) {
54
+ const args = [];
55
+ for (const [name, value] of flags) {
56
+ if (value === false)
57
+ continue;
58
+ args.push(`--${name}`);
59
+ if (value !== true)
60
+ args.push(String(value));
136
61
  }
62
+ return args;
137
63
  }
138
64
  function buildMethodArgs(methods) {
139
65
  const skillArgs = [];
@@ -145,17 +71,41 @@ function buildMethodArgs(methods) {
145
71
  return skillArgs;
146
72
  }
147
73
  /**
148
- * Translate a closed RoleTurnRequest into Pi argv after `--no-extensions -e entry`.
149
- * Controlled session constants and session coordinates are adapter-internal.
74
+ * Pi-native `/skill:<name>` for a single forced method (ADR 0082 `pi-no-privilege`).
75
+ * Driven by typed RoleTurnRequest.methods — middle-layer decision, Pi-only syntax.
76
+ * Zero/many methods leave the prompt alone (Fixer optional pair stays `--skill` only).
77
+ */
78
+ export function applyPiNativeSkillInvocation(methods, prompt) {
79
+ const skills = methods.filter((method) => method.kind === "skill");
80
+ if (skills.length !== 1)
81
+ return prompt;
82
+ const name = basename(dirname(skills[0].path));
83
+ if (name.length === 0)
84
+ return prompt;
85
+ const token = `/skill:${name}`;
86
+ const trimmed = prompt.trimStart();
87
+ if (trimmed === token
88
+ || trimmed.startsWith(`${token} `)
89
+ || trimmed.startsWith(`${token}\n`)) {
90
+ return prompt;
91
+ }
92
+ return prompt.length === 0 ? token : `${token} ${prompt}`;
93
+ }
94
+ /**
95
+ * Pi last-hop argv after `--no-extensions -e entry` (#819).
96
+ * Activation flag membership comes from middle-layer projectActivationFlags;
97
+ * this function only renders session coords, controlled constants, and pairs.
98
+ * Single forced method → Pi-native `/skill:` on the argv prompt (#822).
150
99
  */
151
100
  export function buildPiTurnExtraArgs(request, authority, extraPiArgs = []) {
152
101
  const { sessionFile, sessionDirectory } = authority.decode(request.principal);
153
- const prompt = request.continuation.kind === "initial" || request.continuation.kind === "resume"
102
+ const rawPrompt = request.continuation.kind === "initial" || request.continuation.kind === "resume"
154
103
  ? request.continuation.prompt
155
104
  : (() => {
156
105
  const _exhaustive = request.continuation;
157
106
  return _exhaustive;
158
107
  })();
108
+ const prompt = applyPiNativeSkillInvocation(request.methods, rawPrompt);
159
109
  return [
160
110
  "--no-skills",
161
111
  ...buildMethodArgs(request.methods),
@@ -167,7 +117,8 @@ export function buildPiTurnExtraArgs(request, authority, extraPiArgs = []) {
167
117
  "--session-dir",
168
118
  sessionDirectory,
169
119
  ...extraPiArgs,
170
- ...buildActivationFlagArgs(request.activation),
120
+ // Envelope assembly = projectActivationFlags; pi only renders argv pairs.
121
+ ...activationFlagsToPiArgv(projectActivationFlags(request)),
171
122
  "--mode",
172
123
  "json",
173
124
  ...buildSeatModelCliArgs(request.model),
@@ -2025,13 +2025,12 @@ export async function admitMergerInvocation(options) {
2025
2025
  };
2026
2026
  }
2027
2027
  /**
2028
- * Build the Pi prompt transport for an admitted Merger request.
2029
- * Every invocation forces package merge-only method expansion before conflict work.
2028
+ * Build the host-neutral prompt transport for an admitted Merger request.
2029
+ * Method material binds on RoleTurnRequest.methods; Pi-native `/skill:` form
2030
+ * is adapter-internal only (ADR 0082).
2030
2031
  */
2031
2032
  export function buildMergerTransportPrompt(admitted, engineMaterial) {
2032
- const lines = [
2033
- `/skill:resolving-merge-conflicts ${admitted.instruction}`,
2034
- ];
2033
+ const lines = [admitted.instruction];
2035
2034
  if (admitted.attachments.length > 0) {
2036
2035
  lines.push("");
2037
2036
  lines.push("已受理附件(冻结快照路径):");
@@ -36,5 +36,5 @@ export async function loadProductionAcpHostFactory(packageRoot, host) {
36
36
  const href = pathToFileURL(target).href;
37
37
  const mod = (await import(__rewriteRelativeImportExtension(href)));
38
38
  const create = mod.createProductionAcpRoleTurnHost;
39
- return (options) => create({ ...options, description });
39
+ return (options) => create({ ...options, description, hostName: host });
40
40
  }
@@ -17,3 +17,13 @@ export async function loadProductionExternalHostFactory(packageRoot, host) {
17
17
  }
18
18
  throw new Error(`unregistered host: ${host}`);
19
19
  }
20
+ /** Lazy production external host — sole builder for CLI adapter table + public summons (#820). */
21
+ export function createLazyProductionExternalHost(options) {
22
+ let hostPromise;
23
+ return {
24
+ executeTurn: async (request) => {
25
+ hostPromise ??= loadProductionExternalHostFactory(options.packageRoot, options.hostName).then((create) => create({ packageRoot: options.packageRoot, principalAuthority: options.principalAuthority }));
26
+ return (await hostPromise).executeTurn(request);
27
+ },
28
+ };
29
+ }
@@ -32,5 +32,5 @@ export async function loadProductionHeadlessHostFactory(packageRoot, host) {
32
32
  const href = pathToFileURL(target).href;
33
33
  const mod = (await import(__rewriteRelativeImportExtension(href)));
34
34
  const create = mod.createProductionHeadlessRoleTurnHost;
35
- return (options) => create({ ...options, description });
35
+ return (options) => create({ ...options, description, hostName: host });
36
36
  }