@akagilnc/pi-workflow-roles 0.1.3262 → 0.1.3280

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 (35) hide show
  1. package/README.md +8 -122
  2. package/README.zh-CN.md +9 -123
  3. package/dist/gatekeeper-role.js +22 -16
  4. package/dist/grok/production-host.js +745 -571
  5. package/dist/package-contracts/gatekeeper-output.js +71 -0
  6. package/dist/package-contracts/navigator-output.js +48 -0
  7. package/dist/package-contracts/terminating-tools.js +18 -2
  8. package/dist/packaged-role-registry.js +24 -0
  9. package/dist/public-cli/config.js +7 -21
  10. package/dist/public-cli/main.js +689 -365
  11. package/dist/public-cli/registry.js +2 -14
  12. package/dist/session-opening-materials.js +6 -11
  13. package/extensions/role-runtime.ts +3 -1
  14. package/package.json +1 -1
  15. package/resources/navigator-route-playbook.md +1 -1
  16. package/src/gatekeeper-role.ts +32 -17
  17. package/src/grok/production-host.ts +3 -1
  18. package/src/host-contracts.ts +3 -1
  19. package/src/navigator-role.ts +17 -0
  20. package/src/package-contracts/gatekeeper-output.ts +89 -0
  21. package/src/package-contracts/navigator-output.ts +59 -0
  22. package/src/package-contracts/terminating-tools.ts +24 -2
  23. package/src/packaged-role-registry.ts +25 -2
  24. package/src/pi/role-turn-host.ts +4 -0
  25. package/src/public-cli/cli.ts +37 -10
  26. package/src/public-cli/config.ts +6 -30
  27. package/src/public-cli/instruction-seat-run.ts +147 -0
  28. package/src/public-cli/invocation.ts +47 -3
  29. package/src/public-cli/option-definitions.ts +36 -3
  30. package/src/public-cli/registry.ts +3 -26
  31. package/src/public-cli/run-lifecycle.ts +8 -2
  32. package/src/public-cli/settlement.ts +115 -3
  33. package/src/public-cli/terminal.ts +3 -1
  34. package/src/role-runtime.ts +64 -1
  35. package/src/session-opening-materials.ts +6 -11
@@ -0,0 +1,71 @@
1
+ /**
2
+ * Public Gatekeeper (门下省) terminating receipt contracts (#639).
3
+ * Direct public seat shares the province decision shape: dispatch | pass.
4
+ * No usable result is infrastructure failure via public settlement, not a judgment status (#475).
5
+ */
6
+ import { Type } from "typebox";
7
+ import { openToolObject } from "../open-tool-schema.js";
8
+ import { withInfrastructureFailureDeclaration } from "./terminating-infrastructure.js";
9
+ export const GATEKEEPER_OUTPUT_TOOL_NAME = "ak_gatekeeper_output";
10
+ export const GATEKEEPER_ACCEPTED_TEXT = "门下省决议已受理";
11
+ /** Same open decision shape the province uses inside audit sessions. */
12
+ export const gatekeeperDecisionSchema = openToolObject(Type.Object({
13
+ status: Type.Unknown({
14
+ description: "dispatch | pass — 形状指引,非 schema 闸",
15
+ }),
16
+ officer: Type.Unknown({
17
+ description: "status 为 dispatch 时为 inspector | notary",
18
+ }),
19
+ findings: Type.Unknown({
20
+ description: "status 为 pass 时可选 string[] findings",
21
+ }),
22
+ }));
23
+ export const gatekeeperOutputSchema = withInfrastructureFailureDeclaration(gatekeeperDecisionSchema);
24
+ function isRecord(value) {
25
+ return typeof value === "object" && value !== null && !Array.isArray(value);
26
+ }
27
+ function asStringArray(value) {
28
+ if (!Array.isArray(value))
29
+ return [];
30
+ return value.filter((item) => typeof item === "string");
31
+ }
32
+ /**
33
+ * Project one lawful explicit Gatekeeper decision (dispatch | pass).
34
+ * No throw on shape — ADR 0055 / 第 0 条: already-submitted params are retained as-is;
35
+ * public-terminal projects non-usable releases via typed failure cause.
36
+ */
37
+ export function projectLawfulGatekeeperOutput(value) {
38
+ if (!isRecord(value))
39
+ return undefined;
40
+ if (value.status === "pass") {
41
+ return Array.isArray(value.findings)
42
+ ? { status: "pass", findings: asStringArray(value.findings) }
43
+ : { status: "pass" };
44
+ }
45
+ if (value.status === "dispatch" &&
46
+ (value.officer === "inspector" || value.officer === "notary")) {
47
+ return { status: "dispatch", officer: value.officer };
48
+ }
49
+ return undefined;
50
+ }
51
+ /**
52
+ * Settlement/recording path: only lawful recorded dispatch/pass.
53
+ * Does not gate role admission — callers must not use this to reject a submission.
54
+ */
55
+ export function validateRecordedGatekeeperOutput(value) {
56
+ const projected = projectLawfulGatekeeperOutput(value);
57
+ if (projected === undefined) {
58
+ throw new Error("Gatekeeper output has no recognized execution discriminator");
59
+ }
60
+ return projected;
61
+ }
62
+ export function gatekeeperDecisiveFacts(output) {
63
+ const facts = { status: output.status };
64
+ if (output.status === "dispatch") {
65
+ facts.officer = output.officer;
66
+ }
67
+ else if (Array.isArray(output.findings)) {
68
+ facts.findingsCount = output.findings.length;
69
+ }
70
+ return facts;
71
+ }
@@ -0,0 +1,48 @@
1
+ /**
2
+ * Public Navigator (游奕使) terminating receipt contracts (#639).
3
+ * Direct public seat submits route advice with the same candidate shape the
4
+ * attendance prepare tool owns — one shape authority for navigator advice.
5
+ * No usable result is infrastructure failure via public settlement, not a judgment status (#475).
6
+ */
7
+ import { Type } from "typebox";
8
+ import { openToolObject } from "../open-tool-schema.js";
9
+ import { withInfrastructureFailureDeclaration } from "./terminating-infrastructure.js";
10
+ export const NAVIGATOR_OUTPUT_TOOL_NAME = "ak_navigator_output";
11
+ export const NAVIGATOR_ACCEPTED_TEXT = "游奕使建议已受理";
12
+ export const navigatorOutputSchema = withInfrastructureFailureDeclaration(openToolObject(Type.Object({
13
+ status: Type.Unknown({
14
+ description: "advice — 形状指引,非 schema 闸",
15
+ }),
16
+ candidates: Type.Unknown({
17
+ description: "排好序的路线建议数组,元素含 next/phase/reason — 形状指引,非 schema 闸",
18
+ }),
19
+ })));
20
+ function isRecord(value) {
21
+ return typeof value === "object" && value !== null && !Array.isArray(value);
22
+ }
23
+ /**
24
+ * Project one lawful explicit Navigator advice receipt: candidates array,
25
+ * each candidate a record. Broken ancillary fields are preserved as submitted —
26
+ * shape is not an admission gate (ADR 0055 / 第 0 条).
27
+ */
28
+ export function projectLawfulNavigatorOutput(value) {
29
+ if (!isRecord(value) || !Array.isArray(value.candidates))
30
+ return undefined;
31
+ if (value.status !== "advice")
32
+ return undefined;
33
+ return { status: "advice", candidates: value.candidates.filter(isRecord) };
34
+ }
35
+ /**
36
+ * Settlement/recording path: only lawful recorded candidate arrays.
37
+ * Does not gate role admission — callers must not use this to reject a submission.
38
+ */
39
+ export function validateRecordedNavigatorOutput(value) {
40
+ const projected = projectLawfulNavigatorOutput(value);
41
+ if (projected === undefined) {
42
+ throw new Error("Navigator output has no recognized execution discriminator");
43
+ }
44
+ return projected;
45
+ }
46
+ export function navigatorDecisiveFacts(output) {
47
+ return { status: "advice", candidates: output.candidates };
48
+ }
@@ -8,13 +8,15 @@ import { REVIEWER_ACCEPTED_TEXT, REVIEWER_OUTPUT_TOOL_NAME, projectReviewerInten
8
8
  import { isAuditEscalationResult } from "../audit-escalation.js";
9
9
  import { CorrectableSubmissionError } from "../submission-correctable-error.js";
10
10
  import { DOCTOR_ACCEPTED_TEXT, DOCTOR_OUTPUT_TOOL_NAME, validateDoctorSubmissionShape, validateRecordedDoctorOutput } from "../doctor-contracts.js";
11
+ import { GATEKEEPER_ACCEPTED_TEXT, GATEKEEPER_OUTPUT_TOOL_NAME, validateRecordedGatekeeperOutput } from "./gatekeeper-output.js";
12
+ import { NAVIGATOR_ACCEPTED_TEXT, NAVIGATOR_OUTPUT_TOOL_NAME, validateRecordedNavigatorOutput } from "./navigator-output.js";
11
13
  import { MERGER_ACCEPTED_TEXT, MERGER_OUTPUT_TOOL_NAME, validateMergerOutput } from "../merger-contracts.js";
12
14
  import { NOTARY_ACCEPTED_TEXT, NOTARY_OUTPUT_TOOL_NAME, validateRecordedNotaryOutput } from "../notary-contracts.js";
13
15
  import { COUNTERSIGN_ACCEPTED_TEXT, COUNTERSIGN_OUTPUT_TOOL_NAME, validateRecordedCountersignOutput } from "../countersign-contracts.js";
14
16
  import { GLEANER_LEFT_ACCEPTED_TEXT, GLEANER_LEFT_OUTPUT_TOOL_NAME, validateRecordedGleanerLeftOutput } from "../gleaner-left-contracts.js";
15
17
  import { INSPECTOR_ACCEPTED_TEXT, INSPECTOR_OUTPUT_TOOL_NAME, validateRecordedInspectorOutput } from "../inspector-contracts.js";
16
18
  import { CODER_ACCEPTED_TEXT, CODER_OUTPUT_TOOL_NAME, FIXER_ACCEPTED_TEXT, FIXER_OUTPUT_TOOL_NAME, validateAcceptedWorkerDetails, } from "./worker-output.js";
17
- export { CODER_ACCEPTED_TEXT, CODER_OUTPUT_TOOL_NAME, COLLECTOR_ACCEPTED_TEXT, COLLECTOR_OUTPUT_TOOL, FIXER_ACCEPTED_TEXT, FIXER_OUTPUT_TOOL_NAME, JUDGE_ACCEPTED_TEXT, JUDGE_OUTPUT_TOOL_NAME, REVIEWER_ACCEPTED_TEXT, REVIEWER_OUTPUT_TOOL_NAME, MERGER_ACCEPTED_TEXT, MERGER_OUTPUT_TOOL_NAME, validateAcceptedCollectorReceipt, validateAcceptedJudgeDetails, projectReviewerIntentToReceipt, validateReviewerIntent, validateRuntimeReviewerReceipt, validateAcceptedWorkerDetails, validateDoctorSubmissionShape, validateRecordedDoctorOutput, validateMergerOutput, validateRecordedNotaryOutput, validateRecordedCountersignOutput, validateRecordedGleanerLeftOutput, validateRecordedInspectorOutput, };
19
+ export { CODER_ACCEPTED_TEXT, CODER_OUTPUT_TOOL_NAME, COLLECTOR_ACCEPTED_TEXT, COLLECTOR_OUTPUT_TOOL, FIXER_ACCEPTED_TEXT, FIXER_OUTPUT_TOOL_NAME, JUDGE_ACCEPTED_TEXT, JUDGE_OUTPUT_TOOL_NAME, REVIEWER_ACCEPTED_TEXT, REVIEWER_OUTPUT_TOOL_NAME, MERGER_ACCEPTED_TEXT, MERGER_OUTPUT_TOOL_NAME, validateAcceptedCollectorReceipt, validateAcceptedJudgeDetails, projectReviewerIntentToReceipt, validateReviewerIntent, validateRuntimeReviewerReceipt, validateAcceptedWorkerDetails, validateDoctorSubmissionShape, validateRecordedDoctorOutput, validateMergerOutput, validateRecordedNotaryOutput, validateRecordedCountersignOutput, validateRecordedGleanerLeftOutput, validateRecordedInspectorOutput, validateRecordedGatekeeperOutput, validateRecordedNavigatorOutput, };
18
20
  export const TERMINATING_TOOL_NAMES = [
19
21
  CODER_OUTPUT_TOOL_NAME,
20
22
  FIXER_OUTPUT_TOOL_NAME,
@@ -27,6 +29,8 @@ export const TERMINATING_TOOL_NAMES = [
27
29
  COUNTERSIGN_OUTPUT_TOOL_NAME,
28
30
  GLEANER_LEFT_OUTPUT_TOOL_NAME,
29
31
  INSPECTOR_OUTPUT_TOOL_NAME,
32
+ GATEKEEPER_OUTPUT_TOOL_NAME,
33
+ NAVIGATOR_OUTPUT_TOOL_NAME,
30
34
  ];
31
35
  export function isTerminatingToolName(name) {
32
36
  return TERMINATING_TOOL_NAMES.includes(name);
@@ -55,6 +59,10 @@ export function acceptedTextFor(toolName) {
55
59
  return GLEANER_LEFT_ACCEPTED_TEXT;
56
60
  case INSPECTOR_OUTPUT_TOOL_NAME:
57
61
  return INSPECTOR_ACCEPTED_TEXT;
62
+ case GATEKEEPER_OUTPUT_TOOL_NAME:
63
+ return GATEKEEPER_ACCEPTED_TEXT;
64
+ case NAVIGATOR_OUTPUT_TOOL_NAME:
65
+ return NAVIGATOR_ACCEPTED_TEXT;
58
66
  }
59
67
  }
60
68
  export class AcceptedDetailsContractError extends CorrectableSubmissionError {
@@ -104,6 +112,8 @@ export function validateAcceptedDetails(toolName, details) {
104
112
  [COUNTERSIGN_OUTPUT_TOOL_NAME]: ["converged", "continue", "escalate"],
105
113
  [GLEANER_LEFT_OUTPUT_TOOL_NAME]: ["completed"],
106
114
  [INSPECTOR_OUTPUT_TOOL_NAME]: ["pass", "bounce"],
115
+ [GATEKEEPER_OUTPUT_TOOL_NAME]: ["dispatch", "pass"],
116
+ [NAVIGATOR_OUTPUT_TOOL_NAME]: ["advice"],
107
117
  };
108
118
  const collectorDiscriminator = toolName === COLLECTOR_OUTPUT_TOOL && Array.isArray(candidate?.groups);
109
119
  const baseDiscriminator = discriminator;
@@ -137,6 +147,10 @@ export function validateAcceptedDetails(toolName, details) {
137
147
  return validateRecordedGleanerLeftOutput(details);
138
148
  case INSPECTOR_OUTPUT_TOOL_NAME:
139
149
  return validateRecordedInspectorOutput(details);
150
+ case GATEKEEPER_OUTPUT_TOOL_NAME:
151
+ return validateRecordedGatekeeperOutput(details);
152
+ case NAVIGATOR_OUTPUT_TOOL_NAME:
153
+ return validateRecordedNavigatorOutput(details);
140
154
  }
141
155
  }
142
156
  catch (error) {
@@ -176,7 +190,9 @@ export function acceptedFacts(toolName, details) {
176
190
  case DOCTOR_OUTPUT_TOOL_NAME:
177
191
  case NOTARY_OUTPUT_TOOL_NAME:
178
192
  case GLEANER_LEFT_OUTPUT_TOOL_NAME:
179
- case INSPECTOR_OUTPUT_TOOL_NAME: return { status: details.status };
193
+ case INSPECTOR_OUTPUT_TOOL_NAME:
194
+ case GATEKEEPER_OUTPUT_TOOL_NAME:
195
+ case NAVIGATOR_OUTPUT_TOOL_NAME: return { status: details.status };
180
196
  case JUDGE_OUTPUT_TOOL_NAME: return { status: details.judgeStatus };
181
197
  case COUNTERSIGN_OUTPUT_TOOL_NAME: return { status: details.countersignStatus };
182
198
  case MERGER_OUTPUT_TOOL_NAME: {
@@ -1,4 +1,6 @@
1
1
  import { COLLECTOR_OUTPUT_TOOL } from "./package-contracts/collector-output.js";
2
+ import { GATEKEEPER_OUTPUT_TOOL_NAME } from "./package-contracts/gatekeeper-output.js";
3
+ import { NAVIGATOR_OUTPUT_TOOL_NAME } from "./package-contracts/navigator-output.js";
2
4
  import { JUDGE_OUTPUT_TOOL_NAME } from "./package-contracts/judge-output.js";
3
5
  import { REVIEWER_OUTPUT_TOOL_NAME } from "./package-contracts/reviewer-output.js";
4
6
  import { CODER_OUTPUT_TOOL_NAME, FIXER_OUTPUT_TOOL_NAME } from "./package-contracts/worker-output.js";
@@ -151,6 +153,28 @@ const PUBLIC_ROLE_RECORDS = [
151
153
  phaseFlag: void 0,
152
154
  activationStage: "load-and-install",
153
155
  sessionMaterials: INSPECTOR_SESSION_MATERIALS
156
+ },
157
+ // #639: gatekeeper and navigator are roles like any other — public ak-role
158
+ // entries; automatic attendance (province dispatch, navigator sidecar) is
159
+ // unchanged and orthogonal to callability.
160
+ {
161
+ role: "gatekeeper",
162
+ phases: [null],
163
+ outputTool: GATEKEEPER_OUTPUT_TOOL_NAME,
164
+ inputFlag: void 0,
165
+ phaseFlag: void 0,
166
+ activationStage: "load-and-install",
167
+ // Province materials; officers reuse their own public records below.
168
+ sessionMaterials: ["CLAUDE.md", "souls/gatekeeper.md", "souls/quality-law.md", "souls/gate-output-guide.md"]
169
+ },
170
+ {
171
+ role: "navigator",
172
+ phases: [null],
173
+ outputTool: NAVIGATOR_OUTPUT_TOOL_NAME,
174
+ inputFlag: void 0,
175
+ phaseFlag: void 0,
176
+ activationStage: "load-and-install",
177
+ sessionMaterials: ["CLAUDE.md", "souls/navigator.md"]
154
178
  }
155
179
  ];
156
180
  const ONE_SHOT_ROLES = [
@@ -5,7 +5,7 @@ import { mkdir, readFile, writeFile } from "node:fs/promises";
5
5
  import { dirname, join } from "node:path";
6
6
  import { assertLegalEngineName } from "../package-resources/engine-material.js";
7
7
  import { resolveConfiguredProvinceOfficer } from "../institutional-resolution.js";
8
- import { AUTOMATIC_CONFIGURABLE_SEATS, PUBLIC_CALLABLE_ROLES, PUBLIC_CONFIGURABLE_SEATS, isAutomaticConfigurableSeat, isPublicCallableRole, isPublicConfigurableSeat, seatModelOnly, publicStartupCandidates, } from "./registry.js";
8
+ import { PUBLIC_CALLABLE_ROLES, PUBLIC_CONFIGURABLE_SEATS, isPublicCallableRole, isPublicConfigurableSeat, seatModelOnly, publicStartupCandidates, } from "./registry.js";
9
9
  /** Province officers that may carry a persistent model override (#453). */
10
10
  export const GATE_OFFICER_SEATS = [
11
11
  "gatekeeper",
@@ -120,7 +120,7 @@ export function setPersistentSeatHost(config, seat, host) {
120
120
  * First engine still requires an existing seat row (model, or residual axes).
121
121
  * Clearing engine from an axis-only residual drops the empty row; clearing
122
122
  * engine from a model+engine row leaves model-only. Seat type is PublicCallableRole
123
- * (navigator excluded at the type boundary).
123
+ * (same as PublicConfigurableSeat; navigator included since #639).
124
124
  */
125
125
  export function setPersistentSeatEngine(config, seat, engine) {
126
126
  const previous = config.seats[seat];
@@ -174,15 +174,12 @@ export function setAutoResumeLimit(config, limit) {
174
174
  /**
175
175
  * Config-parse seam: persistent call axes belong to PUBLIC_CALLABLE_ROLES;
176
176
  * engine names need only path-safety syntax (no closed material catalog;
177
- * #376 / #378 / #391 / ADR 0069). Disk-handwritten automatic-seat axes are
178
- * rejected. Syntax authority = assertLegalEngineName (no injected duplicate).
177
+ * #376 / #378 / #391 / ADR 0069). Syntax authority = assertLegalEngineName
178
+ * (no injected duplicate).
179
179
  */
180
180
  export function validatePublicCliConfigAxes(config, _packageRoot) {
181
181
  for (const seat of Object.keys(config.seats)) {
182
182
  const row = config.seats[seat];
183
- if ((row?.engine !== undefined || row?.host !== undefined) && !isPublicCallableRole(seat)) {
184
- throw new Error(`config seat ${seat} cannot persist call axes: no independent activation path; storing would be silently ineffective`);
185
- }
186
183
  if (row?.engine === undefined)
187
184
  continue;
188
185
  try {
@@ -429,13 +426,11 @@ function attachEngineAxis(seat, config, invocation) {
429
426
  };
430
427
  }
431
428
  function resolveBaseSeat(config, seat, credentials) {
432
- const automatic = isAutomaticConfigurableSeat(seat);
433
429
  // #620: subordinate officers consume institutional-resolution authority result.
434
430
  if (seat === "notary" || seat === "inspector") {
435
431
  const resolved = resolveConfiguredProvinceOfficer(config, seat);
436
432
  return {
437
433
  seat,
438
- automatic,
439
434
  source: resolved.source,
440
435
  ...(resolved.selection === undefined ? {} : { selection: resolved.selection }),
441
436
  engineSource: "unconfigured",
@@ -446,7 +441,6 @@ function resolveBaseSeat(config, seat, credentials) {
446
441
  if (persistentModel !== undefined) {
447
442
  return {
448
443
  seat,
449
- automatic,
450
444
  source: "persistent",
451
445
  selection: persistentModel,
452
446
  engineSource: "unconfigured",
@@ -456,16 +450,14 @@ function resolveBaseSeat(config, seat, credentials) {
456
450
  if (startup !== undefined) {
457
451
  return {
458
452
  seat,
459
- automatic,
460
453
  source: "startup",
461
454
  selection: startup,
462
455
  engineSource: "unconfigured",
463
456
  };
464
457
  }
465
- return { seat, automatic, source: "unconfigured", engineSource: "unconfigured" };
458
+ return { seat, source: "unconfigured", engineSource: "unconfigured" };
466
459
  }
467
460
  export function resolveEffectiveSeat(config, seat, credentials, invocation) {
468
- const automatic = isAutomaticConfigurableSeat(seat);
469
461
  const hasModelInvocation = invocation !== undefined &&
470
462
  (invocation.model !== undefined || invocation.thinking !== undefined);
471
463
  let modelSeat;
@@ -478,7 +470,6 @@ export function resolveEffectiveSeat(config, seat, credentials, invocation) {
478
470
  : `${invocation.model}:${invocation.thinking}`;
479
471
  modelSeat = {
480
472
  seat,
481
- automatic,
482
473
  source: "invocation",
483
474
  selection: parseModelSpec(spec),
484
475
  engineSource: "unconfigured",
@@ -489,7 +480,6 @@ export function resolveEffectiveSeat(config, seat, credentials, invocation) {
489
480
  if (base.selection === undefined || invocation.thinking === undefined) {
490
481
  modelSeat = {
491
482
  seat,
492
- automatic,
493
483
  source: "unconfigured",
494
484
  engineSource: "unconfigured",
495
485
  };
@@ -497,7 +487,6 @@ export function resolveEffectiveSeat(config, seat, credentials, invocation) {
497
487
  else {
498
488
  modelSeat = {
499
489
  seat,
500
- automatic,
501
490
  source: "invocation",
502
491
  selection: { ...base.selection, thinking: invocation.thinking },
503
492
  engineSource: "unconfigured",
@@ -509,12 +498,9 @@ export function resolveEffectiveSeat(config, seat, credentials, invocation) {
509
498
  export function effectiveSeatConfigurations(config, credentials, invocation) {
510
499
  return PUBLIC_CONFIGURABLE_SEATS.map((seat) => resolveEffectiveSeat(config, seat, credentials, invocation));
511
500
  }
512
- /** Callable roles first (package order), then automatic configurable seats. */
501
+ /** Callable roles in package order. */
513
502
  export function listRolesForDisplay(config, credentials, invocation) {
514
- const all = effectiveSeatConfigurations(config, credentials, invocation);
515
- const callable = PUBLIC_CALLABLE_ROLES.map((role) => all.find((entry) => entry.seat === role));
516
- const automatic = AUTOMATIC_CONFIGURABLE_SEATS.map((seat) => all.find((entry) => entry.seat === seat));
517
- return [...callable, ...automatic];
503
+ return effectiveSeatConfigurations(config, credentials, invocation);
518
504
  }
519
505
  /**
520
506
  * Read configured credential presence from a Pi auth.json document.