@akagilnc/pi-workflow-roles 0.1.2048 → 0.1.2052
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 +1 -0
- package/README.zh-CN.md +1 -0
- package/dist/public-cli/main.js +489 -183
- package/package.json +1 -1
- package/resources/engines/codex.md +32 -0
- package/resources/engines/cursor.md +32 -0
- package/resources/engines/kimi.md +31 -0
- package/src/package-resources/engine-material.ts +111 -0
- package/src/public-cli/cli.ts +168 -22
- package/src/public-cli/config.ts +167 -22
- package/src/public-cli/invocation.ts +7 -1
- package/src/public-cli/judge-run.ts +11 -1
- package/src/public-cli/option-definitions.ts +14 -0
package/src/public-cli/config.ts
CHANGED
|
@@ -5,6 +5,7 @@ import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
|
5
5
|
import { homedir } from "node:os";
|
|
6
6
|
import { dirname, join } from "node:path";
|
|
7
7
|
|
|
8
|
+
import { assertLegalEngineName } from "../package-resources/engine-material.ts";
|
|
8
9
|
import {
|
|
9
10
|
AUTOMATIC_NAVIGATOR_SEAT,
|
|
10
11
|
PUBLIC_CALLABLE_ROLES,
|
|
@@ -22,23 +23,36 @@ export type CredentialProviders = {
|
|
|
22
23
|
|
|
23
24
|
export type SeatModelConfig = ModelRef;
|
|
24
25
|
|
|
26
|
+
/** Persistent seat row: required model triple + optional engine axis (#356). */
|
|
27
|
+
export type PersistentSeatConfig = SeatModelConfig & {
|
|
28
|
+
engine?: string;
|
|
29
|
+
};
|
|
30
|
+
|
|
25
31
|
export type PublicCliConfig = {
|
|
26
|
-
seats: Partial<Record<PublicConfigurableSeat,
|
|
32
|
+
seats: Partial<Record<PublicConfigurableSeat, PersistentSeatConfig>>;
|
|
27
33
|
};
|
|
28
34
|
|
|
29
35
|
export type EffectiveSource = "persistent" | "startup" | "invocation" | "unconfigured";
|
|
30
36
|
|
|
37
|
+
/** Engine axis source is independent of model source (#356). */
|
|
38
|
+
export type EngineSource = "invocation" | "persistent" | "unconfigured";
|
|
39
|
+
|
|
31
40
|
export type EffectiveSeat = {
|
|
32
41
|
seat: PublicConfigurableSeat;
|
|
33
42
|
/** True when the seat is automatic Navigator attendance rather than caller-selected. */
|
|
34
43
|
automatic: boolean;
|
|
35
44
|
source: EffectiveSource;
|
|
36
45
|
selection?: SeatModelConfig;
|
|
46
|
+
/** Selected engine name when configured; undefined = no engine (default path). */
|
|
47
|
+
engine?: string;
|
|
48
|
+
engineSource: EngineSource;
|
|
37
49
|
};
|
|
38
50
|
|
|
39
51
|
export type InvocationModelOverride = {
|
|
40
52
|
model?: string;
|
|
41
53
|
thinking?: PublicThinkingLevel;
|
|
54
|
+
/** Optional engine override for this invocation only (#356). */
|
|
55
|
+
engine?: string;
|
|
42
56
|
};
|
|
43
57
|
|
|
44
58
|
const THINKING_LEVELS = new Set<PublicThinkingLevel>([
|
|
@@ -89,14 +103,91 @@ export function setPersistentSeatConfig(
|
|
|
89
103
|
seat: PublicConfigurableSeat,
|
|
90
104
|
selection: SeatModelConfig,
|
|
91
105
|
): PublicCliConfig {
|
|
106
|
+
const previous = config.seats[seat];
|
|
92
107
|
return {
|
|
93
108
|
seats: {
|
|
94
109
|
...config.seats,
|
|
95
|
-
[seat]: {
|
|
110
|
+
[seat]: {
|
|
111
|
+
...selection,
|
|
112
|
+
// Model rewrite preserves a previously configured engine axis.
|
|
113
|
+
...(previous?.engine === undefined ? {} : { engine: previous.engine }),
|
|
114
|
+
},
|
|
96
115
|
},
|
|
97
116
|
};
|
|
98
117
|
}
|
|
99
118
|
|
|
119
|
+
/**
|
|
120
|
+
* Set or clear persistent engine on the Judge seat only (#356 MVP).
|
|
121
|
+
* Engine-only seats are rejected — model triple remains required.
|
|
122
|
+
*/
|
|
123
|
+
export function setPersistentSeatEngine(
|
|
124
|
+
config: PublicCliConfig,
|
|
125
|
+
seat: PublicConfigurableSeat,
|
|
126
|
+
engine: string | undefined,
|
|
127
|
+
): PublicCliConfig {
|
|
128
|
+
if (seat !== "judge") {
|
|
129
|
+
throw new Error(`engine axis is judge-only; refused seat ${seat}`);
|
|
130
|
+
}
|
|
131
|
+
const previous = config.seats[seat];
|
|
132
|
+
if (previous === undefined) {
|
|
133
|
+
throw new Error(
|
|
134
|
+
`config seat ${seat} has no persistent model; set provider/model:thinking before engine`,
|
|
135
|
+
);
|
|
136
|
+
}
|
|
137
|
+
if (engine === undefined) {
|
|
138
|
+
const { engine: _dropped, ...modelOnly } = previous;
|
|
139
|
+
return {
|
|
140
|
+
seats: {
|
|
141
|
+
...config.seats,
|
|
142
|
+
[seat]: modelOnly,
|
|
143
|
+
},
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
// Engine-name legality is owned solely by assertLegalEngineName
|
|
147
|
+
// (call-request + config-parse seams). Setter is pure seat mutation.
|
|
148
|
+
return {
|
|
149
|
+
seats: {
|
|
150
|
+
...config.seats,
|
|
151
|
+
[seat]: { ...previous, engine },
|
|
152
|
+
},
|
|
153
|
+
};
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
/** Strip optional engine so activation model argv never sees the engine axis. */
|
|
157
|
+
export function seatModelOnly(seat: PersistentSeatConfig): SeatModelConfig {
|
|
158
|
+
return seat.thinking === undefined
|
|
159
|
+
? { provider: seat.provider, model: seat.model }
|
|
160
|
+
: { provider: seat.provider, model: seat.model, thinking: seat.thinking };
|
|
161
|
+
}
|
|
162
|
+
|
|
163
|
+
/**
|
|
164
|
+
* Config-parse seam: engine axis is Judge-only; Judge engine names must exist
|
|
165
|
+
* in package materials. Call with packageRoot after load / before dispatch (#356).
|
|
166
|
+
* Legality authority = assertLegalEngineName (no injected duplicate).
|
|
167
|
+
*/
|
|
168
|
+
export function validatePublicCliConfigEngines(
|
|
169
|
+
config: PublicCliConfig,
|
|
170
|
+
packageRoot: string,
|
|
171
|
+
): void {
|
|
172
|
+
for (const seat of Object.keys(config.seats) as PublicConfigurableSeat[]) {
|
|
173
|
+
const row = config.seats[seat];
|
|
174
|
+
if (row?.engine === undefined) continue;
|
|
175
|
+
if (seat !== "judge") {
|
|
176
|
+
throw new Error(
|
|
177
|
+
`config seat ${seat} engine is not allowed; engine axis is judge-only`,
|
|
178
|
+
);
|
|
179
|
+
}
|
|
180
|
+
try {
|
|
181
|
+
assertLegalEngineName(packageRoot, row.engine);
|
|
182
|
+
} catch (error) {
|
|
183
|
+
throw new Error(
|
|
184
|
+
`config seat ${seat} engine is unknown: ${row.engine}`,
|
|
185
|
+
{ cause: error },
|
|
186
|
+
);
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
100
191
|
export function parseModelSpec(
|
|
101
192
|
spec: string,
|
|
102
193
|
fallbackThinking?: PublicThinkingLevel,
|
|
@@ -200,7 +291,7 @@ function parsePublicCliConfig(value: unknown): PublicCliConfig {
|
|
|
200
291
|
return { seats };
|
|
201
292
|
}
|
|
202
293
|
|
|
203
|
-
function parseSeatModelConfig(value: unknown, seat: string):
|
|
294
|
+
function parseSeatModelConfig(value: unknown, seat: string): PersistentSeatConfig {
|
|
204
295
|
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
205
296
|
throw new Error(`config seat ${seat} must be an object`);
|
|
206
297
|
}
|
|
@@ -217,11 +308,20 @@ function parseSeatModelConfig(value: unknown, seat: string): SeatModelConfig {
|
|
|
217
308
|
) {
|
|
218
309
|
throw new Error(`config seat ${seat} requires a valid thinking level`);
|
|
219
310
|
}
|
|
220
|
-
|
|
311
|
+
const parsed: PersistentSeatConfig = {
|
|
221
312
|
provider: raw.provider,
|
|
222
313
|
model: raw.model,
|
|
223
314
|
thinking: raw.thinking as PublicThinkingLevel,
|
|
224
315
|
};
|
|
316
|
+
if (raw.engine !== undefined) {
|
|
317
|
+
// Shape only: engine must be a string field. Name legality is deferred to
|
|
318
|
+
// validatePublicCliConfigEngines → assertLegalEngineName (single authority).
|
|
319
|
+
if (typeof raw.engine !== "string") {
|
|
320
|
+
throw new Error(`config seat ${seat} engine must be a string`);
|
|
321
|
+
}
|
|
322
|
+
parsed.engine = raw.engine;
|
|
323
|
+
}
|
|
324
|
+
return parsed;
|
|
225
325
|
}
|
|
226
326
|
|
|
227
327
|
export function providerConfigured(
|
|
@@ -258,6 +358,39 @@ function pickStartupCandidate(
|
|
|
258
358
|
return undefined;
|
|
259
359
|
}
|
|
260
360
|
|
|
361
|
+
function attachEngineAxis(
|
|
362
|
+
seat: EffectiveSeat,
|
|
363
|
+
config: PublicCliConfig,
|
|
364
|
+
invocation?: InvocationModelOverride,
|
|
365
|
+
): EffectiveSeat {
|
|
366
|
+
// #356 MVP: engine axis is Judge-only. Other seats stay unconfigured.
|
|
367
|
+
if (seat.seat !== "judge") {
|
|
368
|
+
return {
|
|
369
|
+
...seat,
|
|
370
|
+
engineSource: "unconfigured",
|
|
371
|
+
};
|
|
372
|
+
}
|
|
373
|
+
const persistentEngine = config.seats.judge?.engine;
|
|
374
|
+
if (invocation?.engine !== undefined) {
|
|
375
|
+
return {
|
|
376
|
+
...seat,
|
|
377
|
+
engine: invocation.engine,
|
|
378
|
+
engineSource: "invocation",
|
|
379
|
+
};
|
|
380
|
+
}
|
|
381
|
+
if (persistentEngine !== undefined) {
|
|
382
|
+
return {
|
|
383
|
+
...seat,
|
|
384
|
+
engine: persistentEngine,
|
|
385
|
+
engineSource: "persistent",
|
|
386
|
+
};
|
|
387
|
+
}
|
|
388
|
+
return {
|
|
389
|
+
...seat,
|
|
390
|
+
engineSource: "unconfigured",
|
|
391
|
+
};
|
|
392
|
+
}
|
|
393
|
+
|
|
261
394
|
function resolveBaseSeat(
|
|
262
395
|
config: PublicCliConfig,
|
|
263
396
|
seat: PublicConfigurableSeat,
|
|
@@ -270,7 +403,8 @@ function resolveBaseSeat(
|
|
|
270
403
|
seat,
|
|
271
404
|
automatic,
|
|
272
405
|
source: "persistent",
|
|
273
|
-
selection:
|
|
406
|
+
selection: seatModelOnly(persistent),
|
|
407
|
+
engineSource: "unconfigured",
|
|
274
408
|
};
|
|
275
409
|
}
|
|
276
410
|
const startup = pickStartupCandidate(seat, credentials);
|
|
@@ -280,9 +414,10 @@ function resolveBaseSeat(
|
|
|
280
414
|
automatic,
|
|
281
415
|
source: "startup",
|
|
282
416
|
selection: startup,
|
|
417
|
+
engineSource: "unconfigured",
|
|
283
418
|
};
|
|
284
419
|
}
|
|
285
|
-
return { seat, automatic, source: "unconfigured" };
|
|
420
|
+
return { seat, automatic, source: "unconfigured", engineSource: "unconfigured" };
|
|
286
421
|
}
|
|
287
422
|
|
|
288
423
|
export function resolveEffectiveSeat(
|
|
@@ -292,36 +427,46 @@ export function resolveEffectiveSeat(
|
|
|
292
427
|
invocation?: InvocationModelOverride,
|
|
293
428
|
): EffectiveSeat {
|
|
294
429
|
const automatic = seat === AUTOMATIC_NAVIGATOR_SEAT;
|
|
295
|
-
const
|
|
430
|
+
const hasModelInvocation =
|
|
296
431
|
invocation !== undefined &&
|
|
297
432
|
(invocation.model !== undefined || invocation.thinking !== undefined);
|
|
298
|
-
if (!hasInvocation || invocation === undefined) {
|
|
299
|
-
return resolveBaseSeat(config, seat, credentials);
|
|
300
|
-
}
|
|
301
433
|
|
|
302
|
-
|
|
434
|
+
let modelSeat: EffectiveSeat;
|
|
435
|
+
if (!hasModelInvocation || invocation === undefined) {
|
|
436
|
+
modelSeat = resolveBaseSeat(config, seat, credentials);
|
|
437
|
+
} else if (invocation.model !== undefined) {
|
|
303
438
|
const spec =
|
|
304
439
|
invocation.model.includes(":") || invocation.thinking === undefined
|
|
305
440
|
? invocation.model
|
|
306
441
|
: `${invocation.model}:${invocation.thinking}`;
|
|
307
|
-
|
|
442
|
+
modelSeat = {
|
|
308
443
|
seat,
|
|
309
444
|
automatic,
|
|
310
445
|
source: "invocation",
|
|
311
446
|
selection: parseModelSpec(spec),
|
|
447
|
+
engineSource: "unconfigured",
|
|
312
448
|
};
|
|
449
|
+
} else {
|
|
450
|
+
const base = resolveBaseSeat(config, seat, credentials);
|
|
451
|
+
if (base.selection === undefined || invocation.thinking === undefined) {
|
|
452
|
+
modelSeat = {
|
|
453
|
+
seat,
|
|
454
|
+
automatic,
|
|
455
|
+
source: "unconfigured",
|
|
456
|
+
engineSource: "unconfigured",
|
|
457
|
+
};
|
|
458
|
+
} else {
|
|
459
|
+
modelSeat = {
|
|
460
|
+
seat,
|
|
461
|
+
automatic,
|
|
462
|
+
source: "invocation",
|
|
463
|
+
selection: { ...base.selection, thinking: invocation.thinking },
|
|
464
|
+
engineSource: "unconfigured",
|
|
465
|
+
};
|
|
466
|
+
}
|
|
313
467
|
}
|
|
314
468
|
|
|
315
|
-
|
|
316
|
-
if (base.selection === undefined || invocation.thinking === undefined) {
|
|
317
|
-
return { seat, automatic, source: "unconfigured" };
|
|
318
|
-
}
|
|
319
|
-
return {
|
|
320
|
-
seat,
|
|
321
|
-
automatic,
|
|
322
|
-
source: "invocation",
|
|
323
|
-
selection: { ...base.selection, thinking: invocation.thinking },
|
|
324
|
-
};
|
|
469
|
+
return attachEngineAxis(modelSeat, config, invocation);
|
|
325
470
|
}
|
|
326
471
|
|
|
327
472
|
export function effectiveSeatConfigurations(
|
|
@@ -47,6 +47,10 @@ import {
|
|
|
47
47
|
} from "../merger-contracts.ts";
|
|
48
48
|
import { sha256Hex } from "../sha256.ts";
|
|
49
49
|
import { uuidv7 } from "../uuidv7.ts";
|
|
50
|
+
import {
|
|
51
|
+
appendEngineSessionMaterial,
|
|
52
|
+
type EngineSessionMaterial,
|
|
53
|
+
} from "../package-resources/engine-material.ts";
|
|
50
54
|
import { CliUsageError } from "./cli-errors.ts";
|
|
51
55
|
import {
|
|
52
56
|
REJECTED_PUBLIC_SPELLINGS,
|
|
@@ -809,6 +813,7 @@ export async function admitJudgeInvocation(
|
|
|
809
813
|
/** Build the Pi prompt transport for an admitted Judge request. */
|
|
810
814
|
export function buildJudgeTransportPrompt(
|
|
811
815
|
admitted: AdmittedJudgeInvocation,
|
|
816
|
+
engineMaterial?: EngineSessionMaterial,
|
|
812
817
|
): string {
|
|
813
818
|
const lines: string[] = [admitted.instructionEmpty ? "" : admitted.instruction];
|
|
814
819
|
if (admitted.attachments.length > 0) {
|
|
@@ -818,7 +823,7 @@ export function buildJudgeTransportPrompt(
|
|
|
818
823
|
lines.push(`- ${attachment.frozenPath}`);
|
|
819
824
|
}
|
|
820
825
|
}
|
|
821
|
-
return lines.join("\n");
|
|
826
|
+
return appendEngineSessionMaterial(lines, engineMaterial).join("\n");
|
|
822
827
|
}
|
|
823
828
|
|
|
824
829
|
/** Load admitted-request.json written at admission (Navigator work-context seam). */
|
|
@@ -1404,6 +1409,7 @@ export async function admitCollectorInvocation(
|
|
|
1404
1409
|
export function buildCollectorTransportPrompt(
|
|
1405
1410
|
_admitted: AdmittedCollectorInvocation,
|
|
1406
1411
|
): string {
|
|
1412
|
+
// Exact historical fixed kickoff bytes (one-shot observation).
|
|
1407
1413
|
return COLLECTOR_FIXED_KICKOFF;
|
|
1408
1414
|
}
|
|
1409
1415
|
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
import { writeFile } from "node:fs/promises";
|
|
7
7
|
import { join } from "node:path";
|
|
8
8
|
|
|
9
|
+
import { engineSessionMaterialFromOptions } from "../package-resources/engine-material.ts";
|
|
9
10
|
import {
|
|
10
11
|
runExplicitInternalActivation,
|
|
11
12
|
type ExplicitInternalKnownFailure,
|
|
@@ -76,6 +77,8 @@ export type JudgeRunEnv = {
|
|
|
76
77
|
piRunner?: ExplicitInternalPiRunner;
|
|
77
78
|
/** Effective judge seat model (persistent/startup/invocation). */
|
|
78
79
|
model?: SeatModelConfig;
|
|
80
|
+
/** Optional labor engine name (config→activation; session material only). */
|
|
81
|
+
engine?: string;
|
|
79
82
|
/**
|
|
80
83
|
* Credential presence for public providers (auth.json shape).
|
|
81
84
|
* Used as the production-owned typed channel when a selected public provider
|
|
@@ -100,10 +103,15 @@ export function buildJudgeActivationExtraArgs(
|
|
|
100
103
|
admitted: AdmittedJudgeInvocation,
|
|
101
104
|
options: {
|
|
102
105
|
model?: SeatModelConfig;
|
|
106
|
+
engine?: string;
|
|
107
|
+
packageRoot?: string;
|
|
103
108
|
extraPiArgs?: readonly string[];
|
|
104
109
|
} = {},
|
|
105
110
|
): string[] {
|
|
106
|
-
const prompt = buildJudgeTransportPrompt(
|
|
111
|
+
const prompt = buildJudgeTransportPrompt(
|
|
112
|
+
admitted,
|
|
113
|
+
engineSessionMaterialFromOptions(options),
|
|
114
|
+
);
|
|
107
115
|
return [
|
|
108
116
|
"--no-skills",
|
|
109
117
|
"--no-prompt-templates",
|
|
@@ -436,7 +444,9 @@ export async function runPublicJudge(
|
|
|
436
444
|
}
|
|
437
445
|
|
|
438
446
|
const extraArgs = buildJudgeActivationExtraArgs(admitted, {
|
|
447
|
+
packageRoot: env.packageRoot,
|
|
439
448
|
...(env.model === undefined ? {} : { model: env.model }),
|
|
449
|
+
...(env.engine === undefined ? {} : { engine: env.engine }),
|
|
440
450
|
...(env.extraPiArgs === undefined ? {} : { extraPiArgs: env.extraPiArgs }),
|
|
441
451
|
});
|
|
442
452
|
|
|
@@ -278,6 +278,20 @@ const GLOBAL_OPTIONS = [
|
|
|
278
278
|
zh: "覆盖 thinking 档位:off|minimal|low|medium|high|xhigh|max。",
|
|
279
279
|
},
|
|
280
280
|
},
|
|
281
|
+
{
|
|
282
|
+
id: "engine",
|
|
283
|
+
owner: "global",
|
|
284
|
+
canonical: "--engine",
|
|
285
|
+
aliases: [],
|
|
286
|
+
valueMetavar: "name",
|
|
287
|
+
required: false,
|
|
288
|
+
repeatable: false,
|
|
289
|
+
form: "option",
|
|
290
|
+
description: {
|
|
291
|
+
en: "Optional Judge labor engine for this invocation (name must exist in packaged engine materials; judge-only).",
|
|
292
|
+
zh: "本调用可选 Judge 劳动引擎(名字须存在于包内引擎调法材料;仅 Judge)。",
|
|
293
|
+
},
|
|
294
|
+
},
|
|
281
295
|
{
|
|
282
296
|
id: "help",
|
|
283
297
|
owner: "global",
|