@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.
- package/README.md +8 -122
- package/README.zh-CN.md +9 -123
- package/dist/gatekeeper-role.js +22 -16
- package/dist/grok/production-host.js +745 -571
- package/dist/package-contracts/gatekeeper-output.js +71 -0
- package/dist/package-contracts/navigator-output.js +48 -0
- package/dist/package-contracts/terminating-tools.js +18 -2
- package/dist/packaged-role-registry.js +24 -0
- package/dist/public-cli/config.js +7 -21
- package/dist/public-cli/main.js +689 -365
- package/dist/public-cli/registry.js +2 -14
- package/dist/session-opening-materials.js +6 -11
- package/extensions/role-runtime.ts +3 -1
- package/package.json +1 -1
- package/resources/navigator-route-playbook.md +1 -1
- package/src/gatekeeper-role.ts +32 -17
- package/src/grok/production-host.ts +3 -1
- package/src/host-contracts.ts +3 -1
- package/src/navigator-role.ts +17 -0
- package/src/package-contracts/gatekeeper-output.ts +89 -0
- package/src/package-contracts/navigator-output.ts +59 -0
- package/src/package-contracts/terminating-tools.ts +24 -2
- package/src/packaged-role-registry.ts +25 -2
- package/src/pi/role-turn-host.ts +4 -0
- package/src/public-cli/cli.ts +37 -10
- package/src/public-cli/config.ts +6 -30
- package/src/public-cli/instruction-seat-run.ts +147 -0
- package/src/public-cli/invocation.ts +47 -3
- package/src/public-cli/option-definitions.ts +36 -3
- package/src/public-cli/registry.ts +3 -26
- package/src/public-cli/run-lifecycle.ts +8 -2
- package/src/public-cli/settlement.ts +115 -3
- package/src/public-cli/terminal.ts +3 -1
- package/src/role-runtime.ts +64 -1
- package/src/session-opening-materials.ts +6 -11
package/src/public-cli/config.ts
CHANGED
|
@@ -7,10 +7,8 @@ import { dirname, join } from "node:path";
|
|
|
7
7
|
import { assertLegalEngineName } from "../package-resources/engine-material.ts";
|
|
8
8
|
import { resolveConfiguredProvinceOfficer } from "../institutional-resolution.ts";
|
|
9
9
|
import {
|
|
10
|
-
AUTOMATIC_CONFIGURABLE_SEATS,
|
|
11
10
|
PUBLIC_CALLABLE_ROLES,
|
|
12
11
|
PUBLIC_CONFIGURABLE_SEATS,
|
|
13
|
-
isAutomaticConfigurableSeat,
|
|
14
12
|
isPublicCallableRole,
|
|
15
13
|
isPublicConfigurableSeat,
|
|
16
14
|
seatModelOnly,
|
|
@@ -87,8 +85,6 @@ export type HostSource = "invocation" | "persistent" | "default";
|
|
|
87
85
|
|
|
88
86
|
export type EffectiveSeat = {
|
|
89
87
|
seat: PublicConfigurableSeat;
|
|
90
|
-
/** True when the seat is automatic (no caller command) rather than caller-selected. */
|
|
91
|
-
automatic: boolean;
|
|
92
88
|
source: EffectiveSource;
|
|
93
89
|
selection?: SeatModelConfig;
|
|
94
90
|
/** Selected engine name when configured; undefined = no engine (default path). */
|
|
@@ -240,7 +236,7 @@ export function setPersistentSeatHost(
|
|
|
240
236
|
* First engine still requires an existing seat row (model, or residual axes).
|
|
241
237
|
* Clearing engine from an axis-only residual drops the empty row; clearing
|
|
242
238
|
* engine from a model+engine row leaves model-only. Seat type is PublicCallableRole
|
|
243
|
-
* (
|
|
239
|
+
* (same as PublicConfigurableSeat; navigator included since #639).
|
|
244
240
|
*/
|
|
245
241
|
export function setPersistentSeatEngine(
|
|
246
242
|
config: PublicCliConfig,
|
|
@@ -308,8 +304,8 @@ export function setAutoResumeLimit(
|
|
|
308
304
|
/**
|
|
309
305
|
* Config-parse seam: persistent call axes belong to PUBLIC_CALLABLE_ROLES;
|
|
310
306
|
* engine names need only path-safety syntax (no closed material catalog;
|
|
311
|
-
* #376 / #378 / #391 / ADR 0069).
|
|
312
|
-
*
|
|
307
|
+
* #376 / #378 / #391 / ADR 0069). Syntax authority = assertLegalEngineName
|
|
308
|
+
* (no injected duplicate).
|
|
313
309
|
*/
|
|
314
310
|
export function validatePublicCliConfigAxes(
|
|
315
311
|
config: PublicCliConfig,
|
|
@@ -317,11 +313,6 @@ export function validatePublicCliConfigAxes(
|
|
|
317
313
|
): void {
|
|
318
314
|
for (const seat of Object.keys(config.seats) as PublicConfigurableSeat[]) {
|
|
319
315
|
const row = config.seats[seat];
|
|
320
|
-
if ((row?.engine !== undefined || row?.host !== undefined) && !isPublicCallableRole(seat)) {
|
|
321
|
-
throw new Error(
|
|
322
|
-
`config seat ${seat} cannot persist call axes: no independent activation path; storing would be silently ineffective`,
|
|
323
|
-
);
|
|
324
|
-
}
|
|
325
316
|
if (row?.engine === undefined) continue;
|
|
326
317
|
try {
|
|
327
318
|
assertLegalEngineName(row.engine);
|
|
@@ -622,13 +613,11 @@ function resolveBaseSeat(
|
|
|
622
613
|
seat: PublicConfigurableSeat,
|
|
623
614
|
credentials: CredentialProviders,
|
|
624
615
|
): UnhostedEffectiveSeat {
|
|
625
|
-
const automatic = isAutomaticConfigurableSeat(seat);
|
|
626
616
|
// #620: subordinate officers consume institutional-resolution authority result.
|
|
627
617
|
if (seat === "notary" || seat === "inspector") {
|
|
628
618
|
const resolved = resolveConfiguredProvinceOfficer(config, seat);
|
|
629
619
|
return {
|
|
630
620
|
seat,
|
|
631
|
-
automatic,
|
|
632
621
|
source: resolved.source,
|
|
633
622
|
...(resolved.selection === undefined ? {} : { selection: resolved.selection }),
|
|
634
623
|
engineSource: "unconfigured",
|
|
@@ -639,7 +628,6 @@ function resolveBaseSeat(
|
|
|
639
628
|
if (persistentModel !== undefined) {
|
|
640
629
|
return {
|
|
641
630
|
seat,
|
|
642
|
-
automatic,
|
|
643
631
|
source: "persistent",
|
|
644
632
|
selection: persistentModel,
|
|
645
633
|
engineSource: "unconfigured",
|
|
@@ -649,13 +637,12 @@ function resolveBaseSeat(
|
|
|
649
637
|
if (startup !== undefined) {
|
|
650
638
|
return {
|
|
651
639
|
seat,
|
|
652
|
-
automatic,
|
|
653
640
|
source: "startup",
|
|
654
641
|
selection: startup,
|
|
655
642
|
engineSource: "unconfigured",
|
|
656
643
|
};
|
|
657
644
|
}
|
|
658
|
-
return { seat,
|
|
645
|
+
return { seat, source: "unconfigured", engineSource: "unconfigured" };
|
|
659
646
|
}
|
|
660
647
|
|
|
661
648
|
export function resolveEffectiveSeat(
|
|
@@ -664,7 +651,6 @@ export function resolveEffectiveSeat(
|
|
|
664
651
|
credentials: CredentialProviders,
|
|
665
652
|
invocation?: InvocationModelOverride,
|
|
666
653
|
): EffectiveSeat {
|
|
667
|
-
const automatic = isAutomaticConfigurableSeat(seat);
|
|
668
654
|
const hasModelInvocation =
|
|
669
655
|
invocation !== undefined &&
|
|
670
656
|
(invocation.model !== undefined || invocation.thinking !== undefined);
|
|
@@ -679,7 +665,6 @@ export function resolveEffectiveSeat(
|
|
|
679
665
|
: `${invocation.model}:${invocation.thinking}`;
|
|
680
666
|
modelSeat = {
|
|
681
667
|
seat,
|
|
682
|
-
automatic,
|
|
683
668
|
source: "invocation",
|
|
684
669
|
selection: parseModelSpec(spec),
|
|
685
670
|
engineSource: "unconfigured",
|
|
@@ -689,14 +674,12 @@ export function resolveEffectiveSeat(
|
|
|
689
674
|
if (base.selection === undefined || invocation.thinking === undefined) {
|
|
690
675
|
modelSeat = {
|
|
691
676
|
seat,
|
|
692
|
-
automatic,
|
|
693
677
|
source: "unconfigured",
|
|
694
678
|
engineSource: "unconfigured",
|
|
695
679
|
};
|
|
696
680
|
} else {
|
|
697
681
|
modelSeat = {
|
|
698
682
|
seat,
|
|
699
|
-
automatic,
|
|
700
683
|
source: "invocation",
|
|
701
684
|
selection: { ...base.selection, thinking: invocation.thinking },
|
|
702
685
|
engineSource: "unconfigured",
|
|
@@ -717,20 +700,13 @@ export function effectiveSeatConfigurations(
|
|
|
717
700
|
);
|
|
718
701
|
}
|
|
719
702
|
|
|
720
|
-
/** Callable roles
|
|
703
|
+
/** Callable roles in package order. */
|
|
721
704
|
export function listRolesForDisplay(
|
|
722
705
|
config: PublicCliConfig,
|
|
723
706
|
credentials: CredentialProviders,
|
|
724
707
|
invocation?: InvocationModelOverride,
|
|
725
708
|
): EffectiveSeat[] {
|
|
726
|
-
|
|
727
|
-
const callable = PUBLIC_CALLABLE_ROLES.map(
|
|
728
|
-
(role) => all.find((entry) => entry.seat === role)!,
|
|
729
|
-
);
|
|
730
|
-
const automatic = AUTOMATIC_CONFIGURABLE_SEATS.map(
|
|
731
|
-
(seat) => all.find((entry) => entry.seat === seat)!,
|
|
732
|
-
);
|
|
733
|
-
return [...callable, ...automatic];
|
|
709
|
+
return effectiveSeatConfigurations(config, credentials, invocation);
|
|
734
710
|
}
|
|
735
711
|
|
|
736
712
|
/**
|
|
@@ -0,0 +1,147 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared instruction-seat run (#639 repair seam): gatekeeper and navigator are
|
|
3
|
+
* the same admit → turn-request → post-admission → settle shape, parameterized
|
|
4
|
+
* by seat. Same direction as the settlement one-shot shared skeleton. cli.ts
|
|
5
|
+
* calls this parameterized module directly; no per-seat wrappers.
|
|
6
|
+
*/
|
|
7
|
+
import type { DurablePrincipalAuthority, RoleTurnRequest } from "../host-contracts.ts";
|
|
8
|
+
import { engineSessionMaterialFromOptions } from "../package-resources/engine-material.ts";
|
|
9
|
+
import { CliUsageError } from "./cli-errors.ts";
|
|
10
|
+
import {
|
|
11
|
+
admitGatekeeperInvocation,
|
|
12
|
+
admitNavigatorInvocation,
|
|
13
|
+
buildInstructionTransportPrompt,
|
|
14
|
+
type AdmittedGatekeeperInvocation,
|
|
15
|
+
type AdmittedNavigatorInvocation,
|
|
16
|
+
type ParseInstructionArgvResult,
|
|
17
|
+
} from "./invocation.ts";
|
|
18
|
+
import {
|
|
19
|
+
runPostAdmissionOneShot,
|
|
20
|
+
type PostAdmissionEnv,
|
|
21
|
+
} from "./post-admission.ts";
|
|
22
|
+
import {
|
|
23
|
+
markRunAdmitted,
|
|
24
|
+
} from "./run-lifecycle.ts";
|
|
25
|
+
import {
|
|
26
|
+
presentStructuralRejection,
|
|
27
|
+
trySettleGatekeeperTerminalResult,
|
|
28
|
+
trySettleNavigatorTerminalResult,
|
|
29
|
+
} from "./settlement.ts";
|
|
30
|
+
import type { CliIo } from "./cli-io.ts";
|
|
31
|
+
import type { TerminalResult } from "./terminal.ts";
|
|
32
|
+
import {
|
|
33
|
+
projectRoleTurnRequest,
|
|
34
|
+
type RoleTurnRequestProjectionOptions,
|
|
35
|
+
} from "./turn-request.ts";
|
|
36
|
+
|
|
37
|
+
export type InstructionSeatRole = "gatekeeper" | "navigator";
|
|
38
|
+
|
|
39
|
+
export type AdmittedInstructionSeatInvocation =
|
|
40
|
+
| AdmittedGatekeeperInvocation
|
|
41
|
+
| AdmittedNavigatorInvocation;
|
|
42
|
+
|
|
43
|
+
export type InstructionSeatRunEnv = PostAdmissionEnv & {
|
|
44
|
+
principalAuthority: DurablePrincipalAuthority;
|
|
45
|
+
createRunId?: () => string;
|
|
46
|
+
};
|
|
47
|
+
|
|
48
|
+
/** Project an admitted instruction-seat invocation onto the host-neutral turn request. */
|
|
49
|
+
export function buildInstructionSeatTurnRequest(
|
|
50
|
+
admitted: AdmittedInstructionSeatInvocation,
|
|
51
|
+
options: RoleTurnRequestProjectionOptions,
|
|
52
|
+
): RoleTurnRequest {
|
|
53
|
+
return projectRoleTurnRequest(
|
|
54
|
+
admitted,
|
|
55
|
+
{
|
|
56
|
+
activation: {
|
|
57
|
+
role: admitted.role,
|
|
58
|
+
},
|
|
59
|
+
},
|
|
60
|
+
options,
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
function instructionSeatAdapters() {
|
|
65
|
+
return {
|
|
66
|
+
trySettle: (
|
|
67
|
+
admitted: AdmittedInstructionSeatInvocation,
|
|
68
|
+
authority: DurablePrincipalAuthority,
|
|
69
|
+
) =>
|
|
70
|
+
admitted.role === "gatekeeper"
|
|
71
|
+
? trySettleGatekeeperTerminalResult(admitted, authority)
|
|
72
|
+
: trySettleNavigatorTerminalResult(admitted, authority),
|
|
73
|
+
// Accepted receipts and failure terminals both present via shared path.
|
|
74
|
+
shouldPresentSettled: () => true,
|
|
75
|
+
};
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export async function runPublicInstructionSeat(
|
|
79
|
+
argv: readonly string[],
|
|
80
|
+
env: InstructionSeatRunEnv,
|
|
81
|
+
io: CliIo,
|
|
82
|
+
role: InstructionSeatRole,
|
|
83
|
+
parseArgv: (args: readonly string[]) => ParseInstructionArgvResult,
|
|
84
|
+
): Promise<{
|
|
85
|
+
exitCode: number;
|
|
86
|
+
admitted?: AdmittedInstructionSeatInvocation;
|
|
87
|
+
terminal?: TerminalResult;
|
|
88
|
+
}> {
|
|
89
|
+
let admitted: AdmittedInstructionSeatInvocation;
|
|
90
|
+
try {
|
|
91
|
+
const parsed = parseArgv(argv);
|
|
92
|
+
const options = {
|
|
93
|
+
home: env.home,
|
|
94
|
+
principalAuthority: env.principalAuthority,
|
|
95
|
+
cwd: env.cwd,
|
|
96
|
+
instruction: parsed.instruction,
|
|
97
|
+
attachmentPaths: parsed.attachmentPaths,
|
|
98
|
+
...(parsed.project === undefined ? {} : { project: parsed.project }),
|
|
99
|
+
...(env.createRunId === undefined ? {} : { createRunId: env.createRunId }),
|
|
100
|
+
...(env.model === undefined ? {} : { model: env.model }),
|
|
101
|
+
...(env.correlationId === undefined ? {} : { correlationId: env.correlationId }),
|
|
102
|
+
};
|
|
103
|
+
admitted =
|
|
104
|
+
role === "gatekeeper"
|
|
105
|
+
? await admitGatekeeperInvocation(options)
|
|
106
|
+
: await admitNavigatorInvocation(options);
|
|
107
|
+
} catch (error) {
|
|
108
|
+
if (error instanceof CliUsageError) {
|
|
109
|
+
presentStructuralRejection(error, io);
|
|
110
|
+
return { exitCode: 2 };
|
|
111
|
+
}
|
|
112
|
+
throw error;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
await markRunAdmitted(admitted, env.principalAuthority);
|
|
116
|
+
|
|
117
|
+
const turnRequest = buildInstructionSeatTurnRequest(admitted, {
|
|
118
|
+
packageRoot: env.packageRoot,
|
|
119
|
+
home: env.home,
|
|
120
|
+
agentDir: env.agentDir,
|
|
121
|
+
...(env.model === undefined ? {} : { model: env.model }),
|
|
122
|
+
...(env.engine === undefined ? {} : { engine: env.engine }),
|
|
123
|
+
...(env.timeoutMs === undefined ? {} : { timeoutMs: env.timeoutMs }),
|
|
124
|
+
...(env.correlationId === undefined || env.correlationId.trim() === ""
|
|
125
|
+
? {}
|
|
126
|
+
: { correlationId: env.correlationId }),
|
|
127
|
+
continuation: {
|
|
128
|
+
kind: "initial",
|
|
129
|
+
prompt: buildInstructionTransportPrompt(
|
|
130
|
+
admitted,
|
|
131
|
+
engineSessionMaterialFromOptions({
|
|
132
|
+
...(env.engine === undefined ? {} : { engine: env.engine }),
|
|
133
|
+
packageRoot: env.packageRoot,
|
|
134
|
+
}),
|
|
135
|
+
),
|
|
136
|
+
},
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
return await runPostAdmissionOneShot({
|
|
140
|
+
admitted,
|
|
141
|
+
env,
|
|
142
|
+
io,
|
|
143
|
+
request: turnRequest,
|
|
144
|
+
adapters: instructionSeatAdapters(),
|
|
145
|
+
...(env.engine === undefined ? {} : { effectiveEngine: env.engine }),
|
|
146
|
+
});
|
|
147
|
+
}
|
|
@@ -136,6 +136,14 @@ export type AdmittedInspectorInvocation = AdmittedRoleInvocationBase & {
|
|
|
136
136
|
readonly role: "inspector";
|
|
137
137
|
};
|
|
138
138
|
|
|
139
|
+
export type AdmittedGatekeeperInvocation = AdmittedRoleInvocationBase & {
|
|
140
|
+
readonly role: "gatekeeper";
|
|
141
|
+
};
|
|
142
|
+
|
|
143
|
+
export type AdmittedNavigatorInvocation = AdmittedRoleInvocationBase & {
|
|
144
|
+
readonly role: "navigator";
|
|
145
|
+
};
|
|
146
|
+
|
|
139
147
|
export type CoderPhase = "plan" | "apply";
|
|
140
148
|
|
|
141
149
|
export type AdmittedCoderInvocation = AdmittedRoleInvocationBase & {
|
|
@@ -217,6 +225,8 @@ export type AdmittedRoleInvocation =
|
|
|
217
225
|
| AdmittedCountersignInvocation
|
|
218
226
|
| AdmittedGleanerLeftInvocation
|
|
219
227
|
| AdmittedInspectorInvocation
|
|
228
|
+
| AdmittedGatekeeperInvocation
|
|
229
|
+
| AdmittedNavigatorInvocation
|
|
220
230
|
| AdmittedCoderInvocation
|
|
221
231
|
| AdmittedFixerInvocation
|
|
222
232
|
| AdmittedCollectorInvocation
|
|
@@ -535,6 +545,8 @@ export type ParseInstructionArgvResult = {
|
|
|
535
545
|
export type ParseJudgeArgvResult = ParseInstructionArgvResult;
|
|
536
546
|
export type ParseCountersignArgvResult = ParseInstructionArgvResult;
|
|
537
547
|
export type ParseInspectorArgvResult = ParseInstructionArgvResult;
|
|
548
|
+
export type ParseGatekeeperArgvResult = ParseInstructionArgvResult;
|
|
549
|
+
export type ParseNavigatorArgvResult = ParseInstructionArgvResult;
|
|
538
550
|
|
|
539
551
|
/** Positive ticket number shared by countersign/notary/analyst faces. */
|
|
540
552
|
export function parsePositiveTicketNumber(
|
|
@@ -555,7 +567,7 @@ export function parsePositiveTicketNumber(
|
|
|
555
567
|
/** 共享解析体:同形 owner 的 argv → instruction/attachments/project。 */
|
|
556
568
|
function parseInstructionArgv(
|
|
557
569
|
args: readonly string[],
|
|
558
|
-
owner: "judge" | "countersign" | "inspector",
|
|
570
|
+
owner: "judge" | "countersign" | "inspector" | "gatekeeper" | "navigator",
|
|
559
571
|
): ParseInstructionArgvResult {
|
|
560
572
|
const attachmentPaths: string[] = [];
|
|
561
573
|
let project: string | undefined;
|
|
@@ -799,6 +811,14 @@ export function parseInspectorArgv(args: readonly string[]): ParseInspectorArgvR
|
|
|
799
811
|
return parseInstructionArgv(args, "inspector");
|
|
800
812
|
}
|
|
801
813
|
|
|
814
|
+
export function parseGatekeeperArgv(args: readonly string[]): ParseGatekeeperArgvResult {
|
|
815
|
+
return parseInstructionArgv(args, "gatekeeper");
|
|
816
|
+
}
|
|
817
|
+
|
|
818
|
+
export function parseNavigatorArgv(args: readonly string[]): ParseNavigatorArgvResult {
|
|
819
|
+
return parseInstructionArgv(args, "navigator");
|
|
820
|
+
}
|
|
821
|
+
|
|
802
822
|
/**
|
|
803
823
|
* Parse Coder-specific argv after the `coder` token.
|
|
804
824
|
* Phase defaults to apply; spellings from PUBLIC_OPTION_TABLE.coder (#342).
|
|
@@ -988,6 +1008,9 @@ export type AdmitInspectorInvocationOptions = AdmitJudgeInvocationOptions & {
|
|
|
988
1008
|
correlationId?: string;
|
|
989
1009
|
};
|
|
990
1010
|
|
|
1011
|
+
export type AdmitGatekeeperInvocationOptions = AdmitInspectorInvocationOptions;
|
|
1012
|
+
export type AdmitNavigatorInvocationOptions = AdmitInspectorInvocationOptions;
|
|
1013
|
+
|
|
991
1014
|
/**
|
|
992
1015
|
* Shared instruction-seat admission for Judge and Inspector: project check,
|
|
993
1016
|
* principal/placement issue, attachment freeze, ticket extract, admitted-request
|
|
@@ -995,7 +1018,7 @@ export type AdmitInspectorInvocationOptions = AdmitJudgeInvocationOptions & {
|
|
|
995
1018
|
* (Inspector). Countersign keeps its own path for ticket-override specialty.
|
|
996
1019
|
*/
|
|
997
1020
|
async function admitStandardMaterialInvocation<
|
|
998
|
-
R extends "judge" | "inspector",
|
|
1021
|
+
R extends "judge" | "inspector" | "gatekeeper" | "navigator",
|
|
999
1022
|
>(
|
|
1000
1023
|
role: R,
|
|
1001
1024
|
options: AdmitJudgeInvocationOptions & { correlationId?: string },
|
|
@@ -1101,8 +1124,28 @@ export async function admitInspectorInvocation(
|
|
|
1101
1124
|
return admitStandardMaterialInvocation("inspector", options);
|
|
1102
1125
|
}
|
|
1103
1126
|
|
|
1127
|
+
/**
|
|
1128
|
+
* Admit a direct Gatekeeper (门下省) run (#639): freeze attachments, persist
|
|
1129
|
+
* the request, reserve session placement — same instruction-seat face.
|
|
1130
|
+
*/
|
|
1131
|
+
export async function admitGatekeeperInvocation(
|
|
1132
|
+
options: AdmitGatekeeperInvocationOptions,
|
|
1133
|
+
): Promise<AdmittedGatekeeperInvocation> {
|
|
1134
|
+
return admitStandardMaterialInvocation("gatekeeper", options);
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
/**
|
|
1138
|
+
* Admit a direct Navigator (游奕使) run (#639): freeze attachments, persist
|
|
1139
|
+
* the request, reserve session placement — same instruction-seat face.
|
|
1140
|
+
*/
|
|
1141
|
+
export async function admitNavigatorInvocation(
|
|
1142
|
+
options: AdmitNavigatorInvocationOptions,
|
|
1143
|
+
): Promise<AdmittedNavigatorInvocation> {
|
|
1144
|
+
return admitStandardMaterialInvocation("navigator", options);
|
|
1145
|
+
}
|
|
1146
|
+
|
|
1104
1147
|
/** Shared prompt transport for instruction-seat roles (judge/countersign/inspector). */
|
|
1105
|
-
function buildInstructionTransportPrompt(
|
|
1148
|
+
export function buildInstructionTransportPrompt(
|
|
1106
1149
|
admitted: { instruction: string; instructionEmpty: boolean; attachments: readonly { frozenPath: string }[] },
|
|
1107
1150
|
engineMaterial?: EngineSessionMaterial,
|
|
1108
1151
|
): string {
|
|
@@ -1132,6 +1175,7 @@ export function buildInspectorTransportPrompt(
|
|
|
1132
1175
|
return buildInstructionTransportPrompt(admitted, engineMaterial);
|
|
1133
1176
|
}
|
|
1134
1177
|
|
|
1178
|
+
|
|
1135
1179
|
export type AdmitCountersignInvocationOptions = {
|
|
1136
1180
|
home: string;
|
|
1137
1181
|
cwd: string;
|
|
@@ -32,6 +32,8 @@ export type OptionOwner =
|
|
|
32
32
|
| "notary"
|
|
33
33
|
| "gleaner-left"
|
|
34
34
|
| "inspector"
|
|
35
|
+
| "gatekeeper"
|
|
36
|
+
| "navigator"
|
|
35
37
|
| "analyst";
|
|
36
38
|
|
|
37
39
|
/**
|
|
@@ -410,6 +412,16 @@ const INSPECTOR_OPTIONS = [
|
|
|
410
412
|
bindOwner("inspector", SHARED_ATTACH_SEMANTICS),
|
|
411
413
|
] as const satisfies readonly PublicOptionDefinition[];
|
|
412
414
|
|
|
415
|
+
const GATEKEEPER_OPTIONS = [
|
|
416
|
+
bindOwner("gatekeeper", SHARED_PROJECT_SEMANTICS),
|
|
417
|
+
bindOwner("gatekeeper", SHARED_ATTACH_SEMANTICS),
|
|
418
|
+
] as const satisfies readonly PublicOptionDefinition[];
|
|
419
|
+
|
|
420
|
+
const NAVIGATOR_OPTIONS = [
|
|
421
|
+
bindOwner("navigator", SHARED_PROJECT_SEMANTICS),
|
|
422
|
+
bindOwner("navigator", SHARED_ATTACH_SEMANTICS),
|
|
423
|
+
] as const satisfies readonly PublicOptionDefinition[];
|
|
424
|
+
|
|
413
425
|
const COUNTERSIGN_OPTIONS = [
|
|
414
426
|
bindOwner("countersign", SHARED_PROJECT_SEMANTICS),
|
|
415
427
|
bindOwner("countersign", SHARED_ATTACH_SEMANTICS),
|
|
@@ -798,6 +810,8 @@ export const PUBLIC_OPTION_TABLE = {
|
|
|
798
810
|
merger: MERGER_OPTIONS,
|
|
799
811
|
notary: NOTARY_OPTIONS,
|
|
800
812
|
inspector: INSPECTOR_OPTIONS,
|
|
813
|
+
gatekeeper: GATEKEEPER_OPTIONS,
|
|
814
|
+
navigator: NAVIGATOR_OPTIONS,
|
|
801
815
|
analyst: ANALYST_OPTIONS,
|
|
802
816
|
} as const satisfies Record<OptionOwner, readonly PublicOptionDefinition[]>;
|
|
803
817
|
|
|
@@ -816,6 +830,8 @@ export const PUBLIC_ROLE_OPTION_OWNERS = [
|
|
|
816
830
|
"merger",
|
|
817
831
|
"notary",
|
|
818
832
|
"inspector",
|
|
833
|
+
"gatekeeper",
|
|
834
|
+
"navigator",
|
|
819
835
|
"analyst",
|
|
820
836
|
] as const satisfies readonly PublicRoleOptionOwner[];
|
|
821
837
|
|
|
@@ -1089,11 +1105,12 @@ export type PublicCommandHelpFacts = {
|
|
|
1089
1105
|
};
|
|
1090
1106
|
|
|
1091
1107
|
/**
|
|
1092
|
-
* Top-level public help short note for automatic
|
|
1093
|
-
*
|
|
1108
|
+
* Top-level public help short note for Navigator automatic attendance (#639:
|
|
1109
|
+
* attendance is orthogonal to callability — the direct command face lives on
|
|
1110
|
+
* the role list like every other role).
|
|
1094
1111
|
*/
|
|
1095
1112
|
export const PUBLIC_NAVIGATOR_HELP_NOTE =
|
|
1096
|
-
"Navigator attends automatically on every run;
|
|
1113
|
+
"Navigator also attends automatically on every run; that sidecar is unchanged by direct `ak-role navigator` calls." as const;
|
|
1097
1114
|
|
|
1098
1115
|
const TOP_LEVEL_HELP = {
|
|
1099
1116
|
command: "top",
|
|
@@ -1196,6 +1213,22 @@ const ROLE_COMMAND_HELP = {
|
|
|
1196
1213
|
'ak-role inspector --attach ./change.patch "Review this material."',
|
|
1197
1214
|
],
|
|
1198
1215
|
},
|
|
1216
|
+
gatekeeper: {
|
|
1217
|
+
command: "gatekeeper",
|
|
1218
|
+
summary: "Direct Gatekeeper (门下省) review: dispatch an officer or pass.",
|
|
1219
|
+
usage: ["ak-role gatekeeper [options] [instruction]"],
|
|
1220
|
+
examples: [
|
|
1221
|
+
'ak-role gatekeeper --attach ./submission.json "审:这批材料该谁审?"',
|
|
1222
|
+
],
|
|
1223
|
+
},
|
|
1224
|
+
navigator: {
|
|
1225
|
+
command: "navigator",
|
|
1226
|
+
summary: "Direct Navigator (游奕使) route advice: ordered next-role candidates.",
|
|
1227
|
+
usage: ["ak-role navigator [options] [instruction]"],
|
|
1228
|
+
examples: [
|
|
1229
|
+
'ak-role navigator "刚完成 coder apply 收敛,下一步?"',
|
|
1230
|
+
],
|
|
1231
|
+
},
|
|
1199
1232
|
notary: {
|
|
1200
1233
|
command: "notary",
|
|
1201
1234
|
summary: "Direct Notary document check (quote fidelity + ticket alignment); zero prompt/attachment.",
|
|
@@ -16,36 +16,12 @@ export const PUBLIC_CALLABLE_ROLES = PACKAGED_ROLE_REGISTRY.map(
|
|
|
16
16
|
|
|
17
17
|
export type PublicCallableRole = (typeof PUBLIC_CALLABLE_ROLES)[number];
|
|
18
18
|
|
|
19
|
-
|
|
20
|
-
export const AUTOMATIC_NAVIGATOR_SEAT = "navigator" as const;
|
|
21
|
-
|
|
22
|
-
/** Automatic province seat — configurable model only; never a caller command. */
|
|
23
|
-
export const AUTOMATIC_GATEKEEPER_SEAT = "gatekeeper" as const;
|
|
24
|
-
|
|
25
|
-
/** Automatic-only configurable seats. Inspector remains automatic-capable via its callable seat. */
|
|
26
|
-
export const AUTOMATIC_CONFIGURABLE_SEATS = [
|
|
27
|
-
AUTOMATIC_GATEKEEPER_SEAT,
|
|
28
|
-
AUTOMATIC_NAVIGATOR_SEAT,
|
|
29
|
-
] as const;
|
|
30
|
-
|
|
31
|
-
export type AutomaticConfigurableSeat =
|
|
32
|
-
(typeof AUTOMATIC_CONFIGURABLE_SEATS)[number];
|
|
33
|
-
|
|
34
|
-
export type PublicConfigurableSeat =
|
|
35
|
-
| PublicCallableRole
|
|
36
|
-
| AutomaticConfigurableSeat;
|
|
19
|
+
export type PublicConfigurableSeat = PublicCallableRole;
|
|
37
20
|
|
|
38
21
|
export const PUBLIC_CONFIGURABLE_SEATS = [
|
|
39
22
|
...PUBLIC_CALLABLE_ROLES,
|
|
40
|
-
...AUTOMATIC_CONFIGURABLE_SEATS,
|
|
41
23
|
] as const satisfies readonly PublicConfigurableSeat[];
|
|
42
24
|
|
|
43
|
-
export function isAutomaticConfigurableSeat(
|
|
44
|
-
value: string,
|
|
45
|
-
): value is AutomaticConfigurableSeat {
|
|
46
|
-
return (AUTOMATIC_CONFIGURABLE_SEATS as readonly string[]).includes(value);
|
|
47
|
-
}
|
|
48
|
-
|
|
49
25
|
export const PUBLIC_CLI_SUPPORT_COMMANDS = [
|
|
50
26
|
"roles",
|
|
51
27
|
"config",
|
|
@@ -127,7 +103,8 @@ const STARTUP_CANDIDATES: Record<PublicConfigurableSeat, readonly ModelRef[]> =
|
|
|
127
103
|
],
|
|
128
104
|
// #620: subordinate officers inherit gatekeeper; no package startup model.
|
|
129
105
|
notary: [],
|
|
130
|
-
// #453/#620: gatekeeper
|
|
106
|
+
// #453/#620/#639: gatekeeper callable but no package startup model — caller
|
|
107
|
+
// configures it or the institutional resolution applies on the province path.
|
|
131
108
|
gatekeeper: [],
|
|
132
109
|
inspector: [],
|
|
133
110
|
navigator: [
|
|
@@ -84,7 +84,9 @@ export type RoleRunRecord = {
|
|
|
84
84
|
| "notary"
|
|
85
85
|
| "countersign"
|
|
86
86
|
| "gleaner-left"
|
|
87
|
-
| "inspector"
|
|
87
|
+
| "inspector"
|
|
88
|
+
| "gatekeeper"
|
|
89
|
+
| "navigator";
|
|
88
90
|
readonly state: RoleRunState;
|
|
89
91
|
readonly bookKey: string;
|
|
90
92
|
readonly projectRoot: string;
|
|
@@ -244,7 +246,9 @@ async function readRoleRunStateDisk(
|
|
|
244
246
|
record.role !== "notary" &&
|
|
245
247
|
record.role !== "countersign" &&
|
|
246
248
|
record.role !== "gleaner-left" &&
|
|
247
|
-
record.role !== "inspector"
|
|
249
|
+
record.role !== "inspector" &&
|
|
250
|
+
record.role !== "gatekeeper" &&
|
|
251
|
+
record.role !== "navigator"
|
|
248
252
|
) {
|
|
249
253
|
return undefined;
|
|
250
254
|
}
|
|
@@ -1475,6 +1479,8 @@ export async function peekRoleRunRole(
|
|
|
1475
1479
|
| "countersign"
|
|
1476
1480
|
| "gleaner-left"
|
|
1477
1481
|
| "inspector"
|
|
1482
|
+
| "gatekeeper"
|
|
1483
|
+
| "navigator"
|
|
1478
1484
|
| undefined
|
|
1479
1485
|
> {
|
|
1480
1486
|
const runDirectory = await findRunDirectoryById(home, runId);
|