@akagilnc/pi-workflow-roles 0.1.3837 → 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 (42) hide show
  1. package/dist/acp-host/production-host.js +24606 -24532
  2. package/dist/engine-detour-tool.js +2 -2
  3. package/dist/engine-detour.js +23 -7
  4. package/dist/headless-host/production-host.js +4197 -4139
  5. package/dist/host-descriptions.js +5 -2
  6. package/dist/pi/role-turn-host.js +20 -92
  7. package/dist/public-cli/load-production-acp-host.js +1 -1
  8. package/dist/public-cli/load-production-external-host.js +10 -0
  9. package/dist/public-cli/load-production-headless-host.js +1 -1
  10. package/dist/public-cli/main.js +95 -102
  11. package/dist/public-role-summons.js +7 -49
  12. package/dist/reviewer-agent.js +1 -0
  13. package/dist/reviewer-child-executor.js +3 -2
  14. package/dist/role-activation-flags.js +50 -0
  15. package/dist/role-runtime.js +8 -3
  16. package/package.json +1 -1
  17. package/scripts/build-package.mjs +2 -2
  18. package/src/acp-host/production-host.ts +31 -94
  19. package/src/acp-host/role-turn-host.ts +178 -263
  20. package/src/diagnostic-tail.ts +18 -0
  21. package/src/engine-detour-tool.ts +5 -4
  22. package/src/engine-detour.ts +44 -9
  23. package/src/external-host-turn-loop.ts +172 -0
  24. package/src/headless-host/production-host.ts +10 -7
  25. package/src/headless-host/role-turn-host.ts +271 -263
  26. package/src/host-descriptions.ts +5 -2
  27. package/src/host-session-record.ts +41 -0
  28. package/src/pi/role-turn-host.ts +18 -93
  29. package/src/prepared-role-turn.ts +68 -0
  30. package/src/public-cli/cli.ts +11 -20
  31. package/src/public-cli/load-production-acp-host.ts +2 -1
  32. package/src/public-cli/load-production-external-host.ts +17 -0
  33. package/src/public-cli/load-production-headless-host.ts +2 -1
  34. package/src/public-role-summons.ts +12 -69
  35. package/src/reviewer-agent.ts +12 -1
  36. package/src/reviewer-child-executor.ts +10 -2
  37. package/src/role-activation-flags.ts +53 -0
  38. package/src/{acp-host/role-envelope.ts → role-envelope.ts} +28 -84
  39. package/src/role-runtime-dependencies.ts +91 -0
  40. package/src/role-runtime.ts +14 -4
  41. package/src/{acp-host/session-identity.ts → session-identity.ts} +6 -6
  42. /package/src/{acp-host/mcp-relay.mjs → mcp-relay.mjs} +0 -0
@@ -4,7 +4,8 @@ import { createServer, type Server, type Socket } from "node:net";
4
4
  import { basename, dirname, join } from "node:path";
5
5
  import { fileURLToPath } from "node:url";
6
6
 
7
- import { requireGatekeeperPass } from "../gatekeeper-pass-envelope.ts";
7
+ import { ENGINE_FLAG_NAME, normalizeEngineName } from "./engine-detour.ts";
8
+ import { requireGatekeeperPass } from "./gatekeeper-pass-envelope.ts";
8
9
  import type {
9
10
  HostContext,
10
11
  HostEventRegistration,
@@ -14,27 +15,26 @@ import type {
14
15
  RoleHost,
15
16
  RoleTurnKnownFailure,
16
17
  RoleTurnRequest,
17
- } from "../host-contracts.ts";
18
- import { packagedRoleInputFlag, packagedRoleOutputTool, packagedRolePhaseFlag } from "../packaged-role-registry.ts";
19
- import { stripSkillFrontmatter } from "../package-resources/method-skill.ts";
18
+ } from "./host-contracts.ts";
19
+ import { packagedRoleOutputTool } from "./packaged-role-registry.ts";
20
+ import { stripSkillFrontmatter } from "./package-resources/method-skill.ts";
20
21
  import {
21
22
  createRoleRuntimeExtension,
22
23
  type RoleRuntimeDependencies,
23
- } from "../role-runtime.ts";
24
- import {
25
- createAcpRoleTurnHost,
26
- type AcpPreparedTurn,
27
- type AcpRoleTurnHostConfig,
28
- } from "./role-turn-host.ts";
24
+ } from "./role-runtime.ts";
25
+ import type { PreparedRoleTurn } from "./prepared-role-turn.ts";
26
+ import { projectActivationFlags } from "./role-activation-flags.ts";
29
27
  import {
30
28
  isCorrectableExecuteError,
31
29
  mechanicalSubmissionRejectionResumeMessage,
32
30
  projectCorrectableExecuteRejection,
33
- } from "../submission-correctable-error.ts";
31
+ } from "./submission-correctable-error.ts";
34
32
  import {
35
33
  buildNavigatorInfrastructureFailureFact,
36
34
  extractInfrastructureFailureEvidence,
37
- } from "../navigator-invocation-identity.ts";
35
+ } from "./navigator-invocation-identity.ts";
36
+
37
+ export { projectActivationFlags };
38
38
 
39
39
  type Handler = HostEventRegistration[1];
40
40
  type RpcRequest = { readonly id: number; readonly token: string; readonly method: string; readonly params?: Record<string, unknown> };
@@ -47,7 +47,7 @@ type ContentPart = { type: "text"; text: string } | { type: "image"; data: strin
47
47
  * a single bound method treats the plain prompt as the preserved user message.
48
48
  * Pi-native slash forms stay inside `src/pi/` only.
49
49
  */
50
- export function buildAcpSkillExpansion(
50
+ export function buildSkillExpansion(
51
51
  methodSkills: ReadonlyMap<string, { readonly path: string; readonly body: string }>,
52
52
  prompt: string,
53
53
  ): HostSkillExpansionEvidence | undefined {
@@ -64,45 +64,6 @@ export function buildAcpSkillExpansion(
64
64
  });
65
65
  }
66
66
 
67
- export function projectAcpActivationFlags(request: RoleTurnRequest): Map<string, boolean | string> {
68
- const activation = request.activation;
69
- const flags = new Map<string, boolean | string>([["ak-role", activation.role]]);
70
- const inputFlag = packagedRoleInputFlag(activation.role);
71
- const phaseFlag = packagedRolePhaseFlag(activation.role);
72
- if ("phase" in activation && phaseFlag !== undefined) flags.set(phaseFlag, activation.phase);
73
- if (inputFlag !== undefined) {
74
- const path = "taskPath" in activation ? activation.taskPath
75
- : "packetPath" in activation ? activation.packetPath
76
- : "casePath" in activation ? activation.casePath
77
- : "inputPath" in activation ? activation.inputPath
78
- : "sourceRun" in activation ? activation.sourceRun
79
- : undefined;
80
- if (path !== undefined) flags.set(inputFlag, path);
81
- }
82
- if (activation.role === "fixer" && activation.prerequisitesPath !== undefined) flags.set("ak-fixer-prerequisites", activation.prerequisitesPath);
83
- if (activation.role === "reviewer") {
84
- flags.set("ak-review-base", activation.baseRevision);
85
- flags.set("ak-review-authority-refs", JSON.stringify(activation.authorityRefs));
86
- if (activation.ticketNumber !== undefined) flags.set("ak-review-ticket-number", String(activation.ticketNumber));
87
- }
88
- // countersign ticketNumber stays on activation/admission/invocation only —
89
- // no private transport flag (inner-gate material path deleted in #632).
90
- if (activation.role === "notary" && activation.ticketNumber !== undefined) {
91
- flags.set("ak-notary-ticket-number", String(activation.ticketNumber));
92
- }
93
- if (activation.role === "gleaner-left") {
94
- flags.set("ak-gleaner-left-base", activation.baseRevision);
95
- }
96
- if (activation.role === "collector") {
97
- flags.set("ak-collector-repo", activation.repo);
98
- // #676 D1: pr optional at admission; omit flag when role binds from materials.
99
- if (activation.pr !== undefined) flags.set("ak-collector-pr", activation.pr);
100
- if (activation.requestManifestPath !== undefined) flags.set("ak-collector-request-manifest", activation.requestManifestPath);
101
- if (activation.waitMs !== undefined) flags.set("ak-collector-wait-ms", activation.waitMs);
102
- }
103
- return flags;
104
- }
105
-
106
67
  async function listen(server: Server, path: string): Promise<void> {
107
68
  await new Promise<void>((resolve, reject) => {
108
69
  server.once("error", reject);
@@ -110,28 +71,6 @@ async function listen(server: Server, path: string): Promise<void> {
110
71
  });
111
72
  }
112
73
 
113
- /**
114
- * Build one AK-owned MCP projection from the shared eight-seat envelope.
115
- * The child process is a protocol relay only; all tools execute in this process.
116
- */
117
- export function createComposedAcpRoleTurnHost(
118
- config: Omit<AcpRoleTurnHostConfig, "prepare"> & {
119
- readonly roleRuntimeDependencies: RoleRuntimeDependencies;
120
- readonly socketPath?: (request: RoleTurnRequest) => string;
121
- },
122
- ) {
123
- return createAcpRoleTurnHost({
124
- ...config,
125
- prepare: (request) => prepareAcpRoleEnvelope({
126
- request,
127
- dependencies: config.roleRuntimeDependencies,
128
- // Same durable-principal path settlement uses for isAvailable (#617 DK-4 layout).
129
- sessionFile: config.sessionIdentity.resolveSessionFile(request.principal),
130
- socketPath: config.socketPath?.(request) ?? `/tmp/ak-acp-mcp-${randomUUID()}.sock`,
131
- }),
132
- });
133
- }
134
-
135
74
  /** JSON Schema draft-07 document for host-native `--json-schema` (headless). */
136
75
  export function terminatingToolJsonSchema(parameters: unknown): Readonly<Record<string, unknown>> {
137
76
  const cloned = JSON.parse(JSON.stringify(parameters)) as Record<string, unknown>;
@@ -142,7 +81,7 @@ export function terminatingToolJsonSchema(parameters: unknown): Readonly<Record<
142
81
  });
143
82
  }
144
83
 
145
- export async function prepareAcpRoleEnvelope(options: {
84
+ export async function prepareRoleEnvelope(options: {
146
85
  readonly request: RoleTurnRequest;
147
86
  readonly dependencies: RoleRuntimeDependencies;
148
87
  /**
@@ -165,17 +104,20 @@ export async function prepareAcpRoleEnvelope(options: {
165
104
  * isAvailable and envelope mint the same file. Tests may omit → runDirectory default.
166
105
  */
167
106
  readonly sessionFile?: string;
168
- }): Promise<AcpPreparedTurn> {
107
+ }): Promise<PreparedRoleTurn> {
169
108
  const { request } = options;
170
109
  if (options.socketPath === "") {
171
- throw new Error("prepareAcpRoleEnvelope requires socketPath");
110
+ throw new Error("prepareRoleEnvelope requires socketPath");
172
111
  }
173
112
  const listTerminatingToolOnMcp = options.listTerminatingToolOnMcp !== false;
174
113
  const earlyTerminatingTool = packagedRoleOutputTool(request.activation.role);
175
114
  if (earlyTerminatingTool === undefined) {
176
115
  throw new Error(`role has no terminating tool: ${request.activation.role}`);
177
116
  }
178
- const flags = projectAcpActivationFlags(request);
117
+ const flags = projectActivationFlags(request);
118
+ // #818 P1: engine axis is request-scoped on this RoleHost — never process.env.
119
+ // Always project ("" = no engine) so ambient AK_ROLE_ENGINE cannot arm detour.
120
+ flags.set(ENGINE_FLAG_NAME, normalizeEngineName(request.engine) ?? "");
179
121
  const tools = new Map<string, HostToolDefinition>();
180
122
  const handlers = new Map<string, Handler[]>();
181
123
  const calls: Array<{ toolCallId: string; toolName: string }> = [];
@@ -275,7 +217,7 @@ export async function prepareAcpRoleEnvelope(options: {
275
217
  },
276
218
  capabilities: {
277
219
  skillExpansion(prompt): HostSkillExpansionEvidence | undefined {
278
- return buildAcpSkillExpansion(methodSkills, prompt);
220
+ return buildSkillExpansion(methodSkills, prompt);
279
221
  },
280
222
  },
281
223
  registerFlag(name, definition) { if (!flags.has(name) && definition.default !== undefined) flags.set(name, definition.default); },
@@ -589,8 +531,9 @@ export async function prepareAcpRoleEnvelope(options: {
589
531
  let disposed = false;
590
532
  // Tools execute in this process (relay is protocol-only). Mirror Pi's child-env
591
533
  // AK_ROLE_RUN_DIR / AK_ROLE_COURT_ATTEMPT injection onto the parent so ledger
592
- // runIdentity and court-attempt identity correlate with settlement. Inject only
593
- // after prepare succeeds (below); dispose must restore including unset.
534
+ // identity sees the same signals. Engine axis is request-scoped via RoleHost
535
+ // flag — never process.env (#818 P1). Run-dir may wait
536
+ // until prepare succeeds. Dispose restores including unset.
594
537
  let priorAkRoleRunDir: string | undefined;
595
538
  let priorAkRoleCourtAttempt: string | undefined;
596
539
  let runDirInjected = false;
@@ -641,7 +584,7 @@ export async function prepareAcpRoleEnvelope(options: {
641
584
  await invokeAkTool(terminatingToolName, params ?? {});
642
585
  }
643
586
 
644
- const closeRound: AcpPreparedTurn["closeRound"] = async () => {
587
+ const closeRound: PreparedRoleTurn["closeRound"] = async () => {
645
588
  // Typed round boundary: hand the complete call list to the shared ledger once.
646
589
  if (calls.length > 0) {
647
590
  const roundCalls = [...calls];
@@ -683,7 +626,8 @@ export async function prepareAcpRoleEnvelope(options: {
683
626
 
684
627
  // Shared envelope activation. systemPrompt must be ready before session/new
685
628
  // (delivered via _meta.systemPromptOverride where the host honors it), so
686
- // activation runs during prepare.
629
+ // activation runs during prepare. Engine axis already on RoleHost flags
630
+ // (request-scoped); registerEngineDetourTool resolves via resolveEngineName.
687
631
  try {
688
632
  await emit("session_start", { reason: request.continuation.kind });
689
633
  const inputResults = await emit("input", { text: request.continuation.prompt, source: "interactive" });
@@ -761,7 +705,7 @@ export async function prepareAcpRoleEnvelope(options: {
761
705
  } catch (cleanupFailure) {
762
706
  throw new AggregateError(
763
707
  [error, cleanupFailure],
764
- "prepareAcpRoleEnvelope activation failed and its dispose cleanup also failed",
708
+ "prepareRoleEnvelope activation failed and its dispose cleanup also failed",
765
709
  { cause: error },
766
710
  );
767
711
  }
@@ -0,0 +1,91 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { fileURLToPath } from "node:url";
3
+
4
+ import { loadCanonicalSkillBinding as loadHomeCanonicalSkillBinding } from "./canonical-skill-binding.ts";
5
+ import { createGhCollectorGitHubTransport, createGhIssueSoftFetcher } from "./collector-github.ts";
6
+ import { createPiDoctorAuditor } from "./doctor-auditor.ts";
7
+ import { loadDoctorCase } from "./doctor-evidence.ts";
8
+ import { createProductionMergerGitState } from "./merger-git-state.ts";
9
+ import { createNativeNavigatorSessionFactory, createNavigatorAttendance } from "./navigator-attendance.ts";
10
+ import { loadNavigatorWorkContext } from "./navigator-work-context.ts";
11
+ import { loadNotarySourceRunLocator } from "./notary-source-run.ts";
12
+ import { loadPackagedCanonicalSkillBinding } from "./package-resources/method-skill-binding.ts";
13
+ import { createPerDispatchReviewerAgent } from "./reviewer-agent.ts";
14
+ import { formatNavigatorRoleHelp, type RoleRuntimeDependencies } from "./role-runtime.ts";
15
+ import { createReviewerPinnedGitReader } from "./reviewer-pinned-git.ts";
16
+ import { loadAuditorSoulFromSubjectInput } from "./auditor-soul.ts";
17
+ import { loadGatekeeperSessionMaterials, loadMainRoleSessionMaterials } from "./session-opening-materials.ts";
18
+
19
+ const navigatorRoutePlaybookPath = fileURLToPath(
20
+ new URL("../resources/navigator-route-playbook.md", import.meta.url),
21
+ );
22
+ const collectorHandbookSeedPath = fileURLToPath(
23
+ new URL("../resources/collector-bot-handbook.md", import.meta.url),
24
+ );
25
+
26
+ /** Host-neutral packaged role runtime deps for the parent-process envelope. */
27
+ export function createRoleRuntimeDependencies(packageRoot: string): RoleRuntimeDependencies {
28
+ const doctorAuditor = createPiDoctorAuditor();
29
+ const reviewerAgent = createPerDispatchReviewerAgent({ packageRoot });
30
+ const navigatorSessionFactory = createNativeNavigatorSessionFactory();
31
+ return {
32
+ loadJudgeSoul: () => loadMainRoleSessionMaterials("judge"),
33
+ loadFixerSoul: () => loadMainRoleSessionMaterials("fixer"),
34
+ loadFixPacket: (path) => readFile(path, "utf8"),
35
+ loadCoderSoul: () => loadMainRoleSessionMaterials("coder"),
36
+ loadCoderTask: (path) => readFile(path, "utf8"),
37
+ loadReviewerSoul: () => loadMainRoleSessionMaterials("reviewer"),
38
+ createReviewerPinnedGitReader: () => createReviewerPinnedGitReader(),
39
+ createReviewerIssueFetcher: () => createGhIssueSoftFetcher(),
40
+ loadCollectorSoul: () => loadMainRoleSessionMaterials("collector"),
41
+ loadCollectorHandbookSeed: () => readFile(collectorHandbookSeedPath, "utf8"),
42
+ createCollectorTransport: () => createGhCollectorGitHubTransport(),
43
+ loadDoctorSoul: () => loadMainRoleSessionMaterials("doctor"),
44
+ loadDoctorCase,
45
+ loadInspectorSoul: () => loadMainRoleSessionMaterials("inspector"),
46
+ loadGatekeeperSoul: () => loadGatekeeperSessionMaterials("gatekeeper"),
47
+ loadNavigatorSoul: () => loadMainRoleSessionMaterials("navigator"),
48
+ loadAuditorSoul: () => loadAuditorSoulFromSubjectInput(),
49
+ loadNotarySoul: () => loadMainRoleSessionMaterials("notary"),
50
+ loadCountersignSoul: () => loadMainRoleSessionMaterials("countersign"),
51
+ loadGleanerLeftSoul: () => loadMainRoleSessionMaterials("gleaner-left"),
52
+ loadDiaristSoul: () => loadMainRoleSessionMaterials("diarist"),
53
+ loadNotarySourceRun: loadNotarySourceRunLocator,
54
+ loadMergerSoul: () => loadMainRoleSessionMaterials("merger"),
55
+ loadMergerInput: async (path) => JSON.parse(await readFile(path, "utf8")),
56
+ createMergerGitState: (repositoryRoot) => createProductionMergerGitState(repositoryRoot),
57
+ async loadCanonicalSkillBinding(name) {
58
+ if (name === "tdd") {
59
+ return loadPackagedCanonicalSkillBinding(packageRoot, "tdd");
60
+ }
61
+ if (name === "code-review") {
62
+ return loadPackagedCanonicalSkillBinding(packageRoot, "code-review");
63
+ }
64
+ return loadHomeCanonicalSkillBinding(name);
65
+ },
66
+ // #590: doctor compliance still on disposeCompliance path; judge→auditor is gate queue (#756).
67
+ auditDoctorCompliance: (options) => doctorAuditor(options),
68
+ runReviewerDispatch: (dispatch, options) => reviewerAgent.run(dispatch, options),
69
+ shutdownReviewerAgent: () => reviewerAgent.shutdown(),
70
+ loadNavigatorWorkContext: (options) => loadNavigatorWorkContext({
71
+ context: options.context,
72
+ role: options.role,
73
+ ...(options.getFlag === undefined ? {} : { getFlag: options.getFlag }),
74
+ }),
75
+ createNavigatorAttendance: (options) => createNavigatorAttendance({
76
+ context: options.context,
77
+ role: options.role,
78
+ phase: options.phase,
79
+ subjectKey: options.subjectKey,
80
+ subject: options.subject,
81
+ authority: options.authority,
82
+ invocationId: options.invocationId,
83
+ loadSoul: () => loadMainRoleSessionMaterials("navigator"),
84
+ loadRoutePlaybook: () => readFile(navigatorRoutePlaybookPath, "utf8"),
85
+ loadRoleHelp: async (role) => formatNavigatorRoleHelp(role),
86
+ createSession: navigatorSessionFactory,
87
+ ...(options.contextError === undefined ? {} : { contextError: options.contextError }),
88
+ onEvent: options.onEvent,
89
+ }),
90
+ };
91
+ }
@@ -638,7 +638,12 @@ export type RoleRuntimeDependencies = {
638
638
  ): Promise<AnyCanonicalSkillBinding>;
639
639
  runReviewerDispatch?(
640
640
  dispatch: AcceptedReviewerExecution,
641
- options: { context: HostContext; signal?: AbortSignal },
641
+ options: {
642
+ context: HostContext;
643
+ signal?: AbortSignal;
644
+ /** Request-scoped RoleHost flag reader for engine axis (#818). */
645
+ getFlag?: (name: string) => boolean | string | undefined;
646
+ },
642
647
  ): Promise<ReviewerDispatchRunResult>;
643
648
  shutdownReviewerAgent?(): Promise<void>;
644
649
  activationClock?(): string;
@@ -1598,7 +1603,12 @@ export function createRoleRuntimeExtension(
1598
1603
  : { fetchIssue: dependencies.createReviewerIssueFetcher() }),
1599
1604
  async runDispatch(dispatch, options) {
1600
1605
  if (dependencies.runReviewerDispatch === undefined) throw new Error("Reviewer runtime dependencies are not configured");
1601
- return dependencies.runReviewerDispatch(dispatch, options);
1606
+ // #818: request-scoped engine flag reaches axis sub-session via same RoleHost
1607
+ // that parent registerEngineDetourTool reads — never ambient process.env.
1608
+ return dependencies.runReviewerDispatch(dispatch, {
1609
+ ...options,
1610
+ getFlag: (name) => roleHost.getFlag(name),
1611
+ });
1602
1612
  },
1603
1613
  ...(dependencies.shutdownReviewerAgent === undefined
1604
1614
  ? {}
@@ -2093,8 +2103,8 @@ export function createRoleRuntimeExtension(
2093
2103
  }
2094
2104
 
2095
2105
  await executeActivationStage(entry.role, activationStage(entry.role, runtime), { clock, writeTrace });
2096
- // #357 T2 / #378 / #380 / #391: any role+engine activation registers the package detour tool once.
2097
- // Gate is env presence only — no per-engine execute branch; no role-module spawn.
2106
+ // #357 T2 / #378 / #380 / #391 / #818: any role+engine activation registers the package detour tool once.
2107
+ // Gate is resolveEngineName (RoleHost flag → env fallback) — no per-engine execute branch; no role-module spawn.
2098
2108
  if (!engineDetourRegistered) {
2099
2109
  engineDetourRegistered = registerEngineDetourTool(roleHost, hostActions);
2100
2110
  }
@@ -1,14 +1,14 @@
1
1
  import { mkdir, readFile, rename, writeFile } from "node:fs/promises";
2
2
  import { dirname, join } from "node:path";
3
3
 
4
- import type { DurablePrincipal, DurablePrincipalAuthority } from "../host-contracts.ts";
5
- import type { AcpSessionIdentityAuthority } from "./role-turn-host.ts";
4
+ import type { DurablePrincipal, DurablePrincipalAuthority } from "./host-contracts.ts";
5
+ import type { SessionIdentityAuthority } from "./prepared-role-turn.ts";
6
6
 
7
- /** Durable ACP binding stored beside the host-owned session principal. */
8
- export function createAcpSessionIdentityAuthority(
7
+ /** Durable session binding stored beside the host-owned session principal. */
8
+ export function createSessionIdentityAuthority(
9
9
  authority: DurablePrincipalAuthority,
10
10
  sessionBindingFile: string,
11
- ): AcpSessionIdentityAuthority {
11
+ ): SessionIdentityAuthority {
12
12
  const bindingPath = (principal: DurablePrincipal): string =>
13
13
  join(authority.decode(principal).sessionDirectory, sessionBindingFile);
14
14
  return {
@@ -19,7 +19,7 @@ export function createAcpSessionIdentityAuthority(
19
19
  try {
20
20
  const value: unknown = JSON.parse(await readFile(bindingPath(principal), "utf8"));
21
21
  if (typeof value !== "object" || value === null || typeof (value as { sessionId?: unknown }).sessionId !== "string") {
22
- throw new Error("durable ACP session binding is invalid");
22
+ throw new Error("durable session binding is invalid");
23
23
  }
24
24
  return (value as { sessionId: string }).sessionId;
25
25
  } catch (error) {
File without changes