@akagilnc/pi-workflow-roles 0.1.3414 → 0.1.3445
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/dist/archivist-record-entry.js +21 -12
- package/dist/archivist-record-topology.js +20 -0
- package/dist/auditor-dossier-tool.js +67 -76
- package/dist/canonical-json.js +66 -69
- package/dist/compliance-transport.js +99 -86
- package/dist/countersign-contracts.js +23 -25
- package/dist/doctor-contracts.js +169 -145
- package/dist/engine-detour-tool.js +83 -87
- package/dist/engine-detour.js +148 -183
- package/dist/evidence-child-executor.js +12 -9
- package/dist/exact-utf8.js +11 -10
- package/dist/git-object-id.js +10 -5
- package/dist/gleaner-left-contracts.js +33 -35
- package/dist/grok/production-host.js +239 -154
- package/dist/inspector-contracts.js +28 -31
- package/dist/institutional-resolution.js +101 -104
- package/dist/ledger-session-read.js +241 -0
- package/dist/merger-contracts.js +66 -56
- package/dist/navigator-attendance.js +0 -6
- package/dist/navigator-session-contracts.js +6 -10
- package/dist/notary-contracts.js +91 -100
- package/dist/open-tool-schema.js +32 -31
- package/dist/package-contracts/collector-output.js +56 -43
- package/dist/package-contracts/fixer-output.js +52 -50
- package/dist/package-contracts/fixer-packet.js +67 -64
- package/dist/package-contracts/gatekeeper-output.js +48 -56
- package/dist/package-contracts/judge-output.js +23 -20
- package/dist/package-contracts/navigator-output.js +35 -40
- package/dist/package-contracts/reviewer-output.js +94 -110
- package/dist/package-contracts/terminating-infrastructure.js +62 -90
- package/dist/package-contracts/worker-output.js +30 -11
- package/dist/package-resources/engine-material.js +58 -94
- package/dist/pi/in-process-session.js +2 -12
- package/dist/public-cli/config.js +403 -485
- package/dist/public-cli/main.js +1226 -561
- package/dist/public-cli/registry.js +107 -114
- package/dist/receipt-delivery-policy.js +74 -76
- package/dist/session-opening-materials.js +44 -47
- package/dist/sha256.js +5 -3
- package/dist/sitian-appender.js +204 -210
- package/dist/sitian-contracts.js +15 -19
- package/dist/sitian-facade.js +5 -10
- package/dist/sitian-reader.js +37 -46
- package/dist/stream-idle-guard.js +63 -71
- package/dist/ticket-seat-memory.js +244 -0
- package/package.json +1 -1
- package/scripts/build-package.mjs +41 -0
- package/src/analyst-gate-cycles-read.ts +152 -83
- package/src/analyst-ledger.ts +170 -43
- package/src/archivist-record-entry.ts +32 -11
- package/src/archivist-record-topology.ts +39 -0
- package/src/evidence-child-executor.ts +18 -10
- package/src/grok/production-host.ts +44 -9
- package/src/host-contracts.ts +18 -0
- package/src/host-transition-prior-native.ts +8 -1
- package/src/ledger-session-read.ts +56 -0
- package/src/navigator-attendance.ts +0 -6
- package/src/navigator-session-contracts.ts +15 -14
- package/src/pi/durable-principal.ts +6 -0
- package/src/pi/in-process-session.ts +10 -17
- package/src/public-cli/cli.ts +2 -14
- package/src/public-cli/config.ts +6 -28
- package/src/public-cli/inspector-run.ts +21 -10
- package/src/public-cli/invocation.ts +8 -25
- package/src/public-cli/notary-run.ts +21 -4
- package/src/public-cli/option-definitions.ts +2 -2
- package/src/public-cli/post-admission.ts +333 -42
- package/src/public-cli/registry.ts +2 -8
- package/src/public-cli/run-lifecycle.ts +1 -3
- package/src/public-cli/settlement.ts +266 -81
- package/src/session-opening-materials.ts +4 -2
- package/src/ticket-seat-memory.ts +454 -0
|
@@ -1,532 +1,450 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Persistent and effective per-seat model/thinking configuration for ak-role.
|
|
3
|
-
*/
|
|
4
1
|
import { mkdir, readFile, writeFile } from "node:fs/promises";
|
|
5
2
|
import { dirname, join } from "node:path";
|
|
6
3
|
import { assertLegalEngineName } from "../package-resources/engine-material.js";
|
|
7
4
|
import { resolveConfiguredProvinceOfficer } from "../institutional-resolution.js";
|
|
8
|
-
import {
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
5
|
+
import {
|
|
6
|
+
PUBLIC_CALLABLE_ROLES,
|
|
7
|
+
PUBLIC_CONFIGURABLE_SEATS,
|
|
8
|
+
isPublicCallableRole,
|
|
9
|
+
isPublicConfigurableSeat,
|
|
10
|
+
seatModelOnly,
|
|
11
|
+
publicStartupCandidates
|
|
12
|
+
} from "./registry.js";
|
|
13
|
+
const GATE_OFFICER_SEATS = [
|
|
14
|
+
"gatekeeper",
|
|
15
|
+
"inspector",
|
|
16
|
+
"notary"
|
|
14
17
|
];
|
|
15
|
-
|
|
16
|
-
|
|
18
|
+
function isGateOfficerSeat(value) {
|
|
19
|
+
return GATE_OFFICER_SEATS.includes(value);
|
|
17
20
|
}
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
"
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
"high",
|
|
24
|
-
"xhigh",
|
|
25
|
-
"max",
|
|
26
|
-
]);
|
|
27
|
-
export function publicCliConfigPath(home) {
|
|
28
|
-
if (typeof home !== "string" || home.trim() === "") {
|
|
29
|
-
throw new Error("home must be explicitly provided");
|
|
30
|
-
}
|
|
31
|
-
return join(home, ".ak-roles", "public-cli.json");
|
|
21
|
+
function publicCliConfigPath(home) {
|
|
22
|
+
if (typeof home !== "string" || home.trim() === "") {
|
|
23
|
+
throw new Error("home must be explicitly provided");
|
|
24
|
+
}
|
|
25
|
+
return join(home, ".ak-roles", "public-cli.json");
|
|
32
26
|
}
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
}
|
|
45
|
-
throw error;
|
|
46
|
-
}
|
|
27
|
+
async function loadPublicCliConfig(home) {
|
|
28
|
+
const path = publicCliConfigPath(home);
|
|
29
|
+
try {
|
|
30
|
+
const raw = await readFile(path, "utf8");
|
|
31
|
+
return parsePublicCliConfig(JSON.parse(raw));
|
|
32
|
+
} catch (error) {
|
|
33
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
34
|
+
return { seats: {} };
|
|
35
|
+
}
|
|
36
|
+
throw error;
|
|
37
|
+
}
|
|
47
38
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
39
|
+
async function savePublicCliConfig(config, home) {
|
|
40
|
+
const path = publicCliConfigPath(home);
|
|
41
|
+
await mkdir(dirname(path), { recursive: true });
|
|
42
|
+
const normalized = parsePublicCliConfig(config);
|
|
43
|
+
await writeFile(
|
|
44
|
+
path,
|
|
45
|
+
`${JSON.stringify(serializePublicCliConfig(normalized), null, 2)}
|
|
46
|
+
`,
|
|
47
|
+
"utf8"
|
|
48
|
+
);
|
|
55
49
|
}
|
|
56
|
-
|
|
57
|
-
|
|
50
|
+
function setPersistentSeatConfig(config, seat, selection) {
|
|
51
|
+
const previous = config.seats[seat];
|
|
52
|
+
return {
|
|
53
|
+
// Spread preserves sibling top-level keys such as autoResumeLimit (#422):
|
|
54
|
+
// a seat write must never silently drop them.
|
|
55
|
+
...config,
|
|
56
|
+
seats: {
|
|
57
|
+
...config.seats,
|
|
58
|
+
[seat]: {
|
|
59
|
+
...selection,
|
|
60
|
+
// Model rewrite preserves a previously configured engine axis.
|
|
61
|
+
...previous?.engine === void 0 ? {} : { engine: previous.engine },
|
|
62
|
+
...previous?.host === void 0 ? {} : { host: previous.host }
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
function clearPersistentSeatConfig(config, seat) {
|
|
68
|
+
const previous = config.seats[seat];
|
|
69
|
+
if (previous === void 0) return config;
|
|
70
|
+
if ((seat === "notary" || seat === "inspector") && (previous.engine !== void 0 || previous.host !== void 0)) {
|
|
58
71
|
return {
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
...config,
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
...(previous?.engine === undefined ? {} : { engine: previous.engine }),
|
|
68
|
-
...(previous?.host === undefined ? {} : { host: previous.host }),
|
|
69
|
-
},
|
|
70
|
-
},
|
|
72
|
+
...config,
|
|
73
|
+
seats: {
|
|
74
|
+
...config.seats,
|
|
75
|
+
[seat]: {
|
|
76
|
+
...previous.engine === void 0 ? {} : { engine: previous.engine },
|
|
77
|
+
...previous.host === void 0 ? {} : { host: previous.host }
|
|
78
|
+
}
|
|
79
|
+
}
|
|
71
80
|
};
|
|
81
|
+
}
|
|
82
|
+
const { [seat]: _dropped, ...seats } = config.seats;
|
|
83
|
+
return { ...config, seats };
|
|
72
84
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
(previous.engine !== undefined || previous.host !== undefined)) {
|
|
88
|
-
return {
|
|
89
|
-
...config,
|
|
90
|
-
seats: {
|
|
91
|
-
...config.seats,
|
|
92
|
-
[seat]: {
|
|
93
|
-
...(previous.engine === undefined ? {} : { engine: previous.engine }),
|
|
94
|
-
...(previous.host === undefined ? {} : { host: previous.host }),
|
|
95
|
-
},
|
|
96
|
-
},
|
|
97
|
-
};
|
|
98
|
-
}
|
|
99
|
-
const { [seat]: _dropped, ...seats } = config.seats;
|
|
100
|
-
return { ...config, seats };
|
|
85
|
+
function setPersistentSeatHost(config, seat, host) {
|
|
86
|
+
const previous = config.seats[seat];
|
|
87
|
+
if (previous === void 0) {
|
|
88
|
+
throw new Error(`config seat ${seat} has no persistent model; set provider/model[:thinking] before host`);
|
|
89
|
+
}
|
|
90
|
+
if (host === void 0) {
|
|
91
|
+
const { host: _dropped, ...rest } = previous;
|
|
92
|
+
if (seatModelOnly(rest) === void 0 && rest.engine === void 0) {
|
|
93
|
+
const { [seat]: _row, ...seats } = config.seats;
|
|
94
|
+
return { ...config, seats };
|
|
95
|
+
}
|
|
96
|
+
return { ...config, seats: { ...config.seats, [seat]: rest } };
|
|
97
|
+
}
|
|
98
|
+
return { ...config, seats: { ...config.seats, [seat]: { ...previous, host } } };
|
|
101
99
|
}
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
return { ...config, seats: { ...config.seats, [seat]: rest } };
|
|
100
|
+
function setPersistentSeatEngine(config, seat, engine) {
|
|
101
|
+
const previous = config.seats[seat];
|
|
102
|
+
if (previous === void 0) {
|
|
103
|
+
throw new Error(
|
|
104
|
+
`config seat ${seat} has no persistent model; set provider/model[:thinking] before engine`
|
|
105
|
+
);
|
|
106
|
+
}
|
|
107
|
+
if (engine === void 0) {
|
|
108
|
+
const { engine: _dropped, ...modelOnly } = previous;
|
|
109
|
+
if (seatModelOnly(modelOnly) === void 0 && modelOnly.host === void 0) {
|
|
110
|
+
const { [seat]: _row, ...seats } = config.seats;
|
|
111
|
+
return { ...config, seats };
|
|
115
112
|
}
|
|
116
|
-
return { ...config, seats: { ...config.seats, [seat]: { ...previous, host } } };
|
|
117
|
-
}
|
|
118
|
-
/**
|
|
119
|
-
* Set or clear persistent engine on a callable role seat (#356 / #378 / #391 / #453).
|
|
120
|
-
* First engine still requires an existing seat row (model, or residual axes).
|
|
121
|
-
* Clearing engine from an axis-only residual drops the empty row; clearing
|
|
122
|
-
* engine from a model+engine row leaves model-only. Seat type is PublicCallableRole
|
|
123
|
-
* (same as PublicConfigurableSeat; navigator included since #639).
|
|
124
|
-
*/
|
|
125
|
-
export function setPersistentSeatEngine(config, seat, engine) {
|
|
126
|
-
const previous = config.seats[seat];
|
|
127
|
-
if (previous === undefined) {
|
|
128
|
-
throw new Error(`config seat ${seat} has no persistent model; set provider/model[:thinking] before engine`);
|
|
129
|
-
}
|
|
130
|
-
if (engine === undefined) {
|
|
131
|
-
const { engine: _dropped, ...modelOnly } = previous;
|
|
132
|
-
// Drop the row only after the final independent axis is cleared.
|
|
133
|
-
if (seatModelOnly(modelOnly) === undefined && modelOnly.host === undefined) {
|
|
134
|
-
const { [seat]: _row, ...seats } = config.seats;
|
|
135
|
-
return { ...config, seats };
|
|
136
|
-
}
|
|
137
|
-
return {
|
|
138
|
-
...config,
|
|
139
|
-
seats: {
|
|
140
|
-
...config.seats,
|
|
141
|
-
[seat]: modelOnly,
|
|
142
|
-
},
|
|
143
|
-
};
|
|
144
|
-
}
|
|
145
|
-
// Engine-name path-safety syntax is owned solely by assertLegalEngineName
|
|
146
|
-
// (call-request + config-parse seams). Setter is pure seat mutation.
|
|
147
113
|
return {
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
114
|
+
...config,
|
|
115
|
+
seats: {
|
|
116
|
+
...config.seats,
|
|
117
|
+
[seat]: modelOnly
|
|
118
|
+
}
|
|
153
119
|
};
|
|
120
|
+
}
|
|
121
|
+
return {
|
|
122
|
+
...config,
|
|
123
|
+
seats: {
|
|
124
|
+
...config.seats,
|
|
125
|
+
[seat]: { ...previous, engine }
|
|
126
|
+
}
|
|
127
|
+
};
|
|
154
128
|
}
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
if (typeof value !== "number" || !Number.isInteger(value) || value < 0) {
|
|
163
|
-
throw new Error(`auto-resume limit must be a non-negative integer, got ${JSON.stringify(value)}`);
|
|
164
|
-
}
|
|
165
|
-
return value;
|
|
129
|
+
function parseAutoResumeLimit(value) {
|
|
130
|
+
if (typeof value !== "number" || !Number.isInteger(value) || value < 0) {
|
|
131
|
+
throw new Error(
|
|
132
|
+
`auto-resume limit must be a non-negative integer, got ${JSON.stringify(value)}`
|
|
133
|
+
);
|
|
134
|
+
}
|
|
135
|
+
return value;
|
|
166
136
|
}
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
* preserves all sibling keys (seats included).
|
|
170
|
-
*/
|
|
171
|
-
export function setAutoResumeLimit(config, limit) {
|
|
172
|
-
return { ...config, autoResumeLimit: parseAutoResumeLimit(limit) };
|
|
137
|
+
function setAutoResumeLimit(config, limit) {
|
|
138
|
+
return { ...config, autoResumeLimit: parseAutoResumeLimit(limit) };
|
|
173
139
|
}
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
}
|
|
188
|
-
catch (error) {
|
|
189
|
-
throw new Error(`config seat ${seat} engine is illegal: ${row.engine}`, { cause: error });
|
|
190
|
-
}
|
|
191
|
-
}
|
|
140
|
+
function validatePublicCliConfigAxes(config, _packageRoot) {
|
|
141
|
+
for (const seat of Object.keys(config.seats)) {
|
|
142
|
+
const row = config.seats[seat];
|
|
143
|
+
if (row?.engine === void 0) continue;
|
|
144
|
+
try {
|
|
145
|
+
assertLegalEngineName(row.engine);
|
|
146
|
+
} catch (error) {
|
|
147
|
+
throw new Error(
|
|
148
|
+
`config seat ${seat} engine is illegal: ${row.engine}`,
|
|
149
|
+
{ cause: error }
|
|
150
|
+
);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
192
153
|
}
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
throw new Error(`model specification must be provider/model[:thinking], got ${spec}`);
|
|
215
|
-
}
|
|
216
|
-
const provider = modelPart.slice(0, slash);
|
|
217
|
-
const model = modelPart.slice(slash + 1);
|
|
218
|
-
// #346/#384: bare provider/model is legal — do not invent thinking.
|
|
219
|
-
return thinking === undefined
|
|
220
|
-
? { provider, model }
|
|
221
|
-
: { provider, model, thinking };
|
|
154
|
+
function parseModelSpec(spec, fallbackThinking) {
|
|
155
|
+
const trimmed = spec.trim();
|
|
156
|
+
if (!trimmed) {
|
|
157
|
+
throw new Error("model specification must be non-empty");
|
|
158
|
+
}
|
|
159
|
+
const thinkingSplit = trimmed.lastIndexOf(":");
|
|
160
|
+
let modelPart = trimmed;
|
|
161
|
+
let thinking = fallbackThinking;
|
|
162
|
+
if (thinkingSplit !== -1) {
|
|
163
|
+
thinking = trimmed.slice(thinkingSplit + 1);
|
|
164
|
+
modelPart = trimmed.slice(0, thinkingSplit);
|
|
165
|
+
}
|
|
166
|
+
const slash = modelPart.indexOf("/");
|
|
167
|
+
if (slash <= 0 || slash === modelPart.length - 1) {
|
|
168
|
+
throw new Error(
|
|
169
|
+
`model specification must be provider/model[:thinking], got ${spec}`
|
|
170
|
+
);
|
|
171
|
+
}
|
|
172
|
+
const provider = modelPart.slice(0, slash);
|
|
173
|
+
const model = modelPart.slice(slash + 1);
|
|
174
|
+
return thinking === void 0 ? { provider, model } : { provider, model, thinking };
|
|
222
175
|
}
|
|
223
|
-
|
|
224
|
-
|
|
225
|
-
|
|
176
|
+
function formatModelSpec(selection) {
|
|
177
|
+
const base = `${selection.provider}/${selection.model}`;
|
|
178
|
+
return selection.thinking === void 0 ? base : `${base}:${selection.thinking}`;
|
|
226
179
|
}
|
|
227
|
-
|
|
228
|
-
|
|
229
|
-
|
|
230
|
-
|
|
231
|
-
|
|
232
|
-
|
|
233
|
-
|
|
234
|
-
|
|
235
|
-
|
|
236
|
-
model.provider,
|
|
237
|
-
"--model",
|
|
238
|
-
model.model,
|
|
239
|
-
...(model.thinking === undefined ? [] : ["--thinking", model.thinking]),
|
|
240
|
-
];
|
|
180
|
+
function buildSeatModelCliArgs(model) {
|
|
181
|
+
if (model === void 0) return [];
|
|
182
|
+
return [
|
|
183
|
+
"--provider",
|
|
184
|
+
model.provider,
|
|
185
|
+
"--model",
|
|
186
|
+
model.model,
|
|
187
|
+
...model.thinking === void 0 ? [] : ["--thinking", model.thinking]
|
|
188
|
+
];
|
|
241
189
|
}
|
|
242
|
-
/**
|
|
243
|
-
* Disk document shape for public-cli.json. Unknown seat rows live under
|
|
244
|
-
* `seats` (not a parallel top-level key) so every build — old or new — sees
|
|
245
|
-
* one seats map.
|
|
246
|
-
*/
|
|
247
190
|
function serializePublicCliConfig(config) {
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
: { autoResumeLimit: config.autoResumeLimit }),
|
|
258
|
-
};
|
|
191
|
+
return {
|
|
192
|
+
// Known seats win on any key clash; by construction the two maps are
|
|
193
|
+
// disjoint after parse, but prefer owned rows if a caller stuffed both.
|
|
194
|
+
seats: {
|
|
195
|
+
...config.unknownSeats ?? {},
|
|
196
|
+
...config.seats
|
|
197
|
+
},
|
|
198
|
+
...config.autoResumeLimit === void 0 ? {} : { autoResumeLimit: config.autoResumeLimit }
|
|
199
|
+
};
|
|
259
200
|
}
|
|
260
201
|
function parsePublicCliConfig(value) {
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
280
|
-
|
|
281
|
-
|
|
282
|
-
}
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
if (
|
|
292
|
-
|
|
293
|
-
|
|
294
|
-
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
// #592: shared machine-wide public-cli.json may hold seat rows a newer CLI
|
|
299
|
-
// wrote. Do not consume them (resolve/enum stay owned-seat only), but keep
|
|
300
|
-
// the raw value in the opaque bucket so save can put them back under seats.
|
|
301
|
-
// Unknown field-level keys on known seats keep their existing tolerance.
|
|
302
|
-
if (!isPublicConfigurableSeat(key)) {
|
|
303
|
-
unknownSeats[key] = raw;
|
|
304
|
-
continue;
|
|
305
|
-
}
|
|
306
|
-
seats[key] = parseSeatModelConfig(raw, key);
|
|
307
|
-
}
|
|
308
|
-
return withOpaque(seats);
|
|
202
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
203
|
+
throw new Error("public CLI config must be an object");
|
|
204
|
+
}
|
|
205
|
+
const record = value;
|
|
206
|
+
let autoResumeLimit;
|
|
207
|
+
if (record.autoResumeLimit !== void 0) {
|
|
208
|
+
autoResumeLimit = parseAutoResumeLimit(record.autoResumeLimit);
|
|
209
|
+
}
|
|
210
|
+
const unknownSeats = {};
|
|
211
|
+
if (record.unknownSeats !== void 0) {
|
|
212
|
+
if (record.unknownSeats === null || typeof record.unknownSeats !== "object" || Array.isArray(record.unknownSeats)) {
|
|
213
|
+
throw new Error("public CLI config.unknownSeats must be an object");
|
|
214
|
+
}
|
|
215
|
+
Object.assign(unknownSeats, record.unknownSeats);
|
|
216
|
+
}
|
|
217
|
+
const withOpaque = (seats2) => ({
|
|
218
|
+
seats: seats2,
|
|
219
|
+
...autoResumeLimit === void 0 ? {} : { autoResumeLimit },
|
|
220
|
+
...Object.keys(unknownSeats).length === 0 ? {} : { unknownSeats }
|
|
221
|
+
});
|
|
222
|
+
if (record.seats === void 0) {
|
|
223
|
+
return withOpaque({});
|
|
224
|
+
}
|
|
225
|
+
if (record.seats === null || typeof record.seats !== "object" || Array.isArray(record.seats)) {
|
|
226
|
+
throw new Error("public CLI config.seats must be an object");
|
|
227
|
+
}
|
|
228
|
+
const seats = {};
|
|
229
|
+
for (const [key, raw] of Object.entries(
|
|
230
|
+
record.seats
|
|
231
|
+
)) {
|
|
232
|
+
if (!isPublicConfigurableSeat(key)) {
|
|
233
|
+
unknownSeats[key] = raw;
|
|
234
|
+
continue;
|
|
235
|
+
}
|
|
236
|
+
seats[key] = parseSeatModelConfig(raw, key);
|
|
237
|
+
}
|
|
238
|
+
return withOpaque(seats);
|
|
309
239
|
}
|
|
310
240
|
function parseSeatModelConfig(value, seat) {
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
314
|
-
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
|
|
318
|
-
|
|
319
|
-
|
|
320
|
-
|
|
321
|
-
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
|
|
328
|
-
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
|
|
332
|
-
|
|
333
|
-
|
|
334
|
-
|
|
335
|
-
|
|
336
|
-
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
}
|
|
343
|
-
|
|
344
|
-
|
|
345
|
-
}
|
|
346
|
-
|
|
347
|
-
|
|
348
|
-
|
|
349
|
-
|
|
350
|
-
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
}
|
|
356
|
-
const parsed = {
|
|
357
|
-
provider: raw.provider,
|
|
358
|
-
model: raw.model,
|
|
359
|
-
...(raw.thinking === undefined
|
|
360
|
-
? {}
|
|
361
|
-
: { thinking: raw.thinking }),
|
|
362
|
-
...(raw.engine === undefined ? {} : { engine: raw.engine }),
|
|
363
|
-
...(raw.host === undefined ? {} : { host: raw.host }),
|
|
364
|
-
};
|
|
365
|
-
return parsed;
|
|
241
|
+
if (value === null || typeof value !== "object" || Array.isArray(value)) {
|
|
242
|
+
throw new Error(`config seat ${seat} must be an object`);
|
|
243
|
+
}
|
|
244
|
+
const raw = value;
|
|
245
|
+
const hasProvider = raw.provider !== void 0;
|
|
246
|
+
const hasModel = raw.model !== void 0;
|
|
247
|
+
if (hasProvider !== hasModel) {
|
|
248
|
+
throw new Error(`config seat ${seat} requires both provider and model`);
|
|
249
|
+
}
|
|
250
|
+
if (raw.host !== void 0 && (typeof raw.host !== "string" || raw.host.trim() === "")) {
|
|
251
|
+
throw new Error(`config seat ${seat} host must be a non-empty string`);
|
|
252
|
+
}
|
|
253
|
+
if (raw.engine !== void 0 && typeof raw.engine !== "string") {
|
|
254
|
+
throw new Error(`config seat ${seat} engine must be a string`);
|
|
255
|
+
}
|
|
256
|
+
if (!hasProvider) {
|
|
257
|
+
if ((seat === "notary" || seat === "inspector") && (typeof raw.engine === "string" || typeof raw.host === "string")) {
|
|
258
|
+
if (raw.thinking !== void 0) {
|
|
259
|
+
throw new Error(`config seat ${seat} thinking requires provider/model`);
|
|
260
|
+
}
|
|
261
|
+
return {
|
|
262
|
+
...raw.engine === void 0 ? {} : { engine: raw.engine },
|
|
263
|
+
...raw.host === void 0 ? {} : { host: raw.host }
|
|
264
|
+
};
|
|
265
|
+
}
|
|
266
|
+
throw new Error(`config seat ${seat} requires provider`);
|
|
267
|
+
}
|
|
268
|
+
if (typeof raw.provider !== "string" || raw.provider.trim() === "") {
|
|
269
|
+
throw new Error(`config seat ${seat} requires provider`);
|
|
270
|
+
}
|
|
271
|
+
if (typeof raw.model !== "string" || raw.model.trim() === "") {
|
|
272
|
+
throw new Error(`config seat ${seat} requires model`);
|
|
273
|
+
}
|
|
274
|
+
if (raw.thinking !== void 0 && typeof raw.thinking !== "string") {
|
|
275
|
+
throw new Error(`config seat ${seat} thinking must be a string`);
|
|
276
|
+
}
|
|
277
|
+
const parsed = {
|
|
278
|
+
provider: raw.provider,
|
|
279
|
+
model: raw.model,
|
|
280
|
+
...raw.thinking === void 0 ? {} : { thinking: raw.thinking },
|
|
281
|
+
...raw.engine === void 0 ? {} : { engine: raw.engine },
|
|
282
|
+
...raw.host === void 0 ? {} : { host: raw.host }
|
|
283
|
+
};
|
|
284
|
+
return parsed;
|
|
366
285
|
}
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
return credentials.xai === true;
|
|
372
|
-
return false;
|
|
286
|
+
function providerConfigured(credentials, provider) {
|
|
287
|
+
if (provider === "openai-codex") return credentials["openai-codex"] === true;
|
|
288
|
+
if (provider === "xai") return credentials.xai === true;
|
|
289
|
+
return false;
|
|
373
290
|
}
|
|
374
|
-
|
|
375
|
-
|
|
376
|
-
|
|
377
|
-
* Returns undefined for unknown/custom providers (not this package's credential map).
|
|
378
|
-
*/
|
|
379
|
-
export function missingPublicProviderCredential(provider, credentials) {
|
|
380
|
-
if (provider !== "openai-codex" && provider !== "xai")
|
|
381
|
-
return false;
|
|
382
|
-
return !providerConfigured(credentials, provider);
|
|
291
|
+
function missingPublicProviderCredential(provider, credentials) {
|
|
292
|
+
if (provider !== "openai-codex" && provider !== "xai") return false;
|
|
293
|
+
return !providerConfigured(credentials, provider);
|
|
383
294
|
}
|
|
384
295
|
function pickStartupCandidate(seat, credentials) {
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
}
|
|
296
|
+
for (const candidate of publicStartupCandidates(seat)) {
|
|
297
|
+
if (providerConfigured(credentials, candidate.provider)) {
|
|
298
|
+
return { ...candidate };
|
|
389
299
|
}
|
|
390
|
-
|
|
300
|
+
}
|
|
301
|
+
return void 0;
|
|
391
302
|
}
|
|
392
303
|
function attachHostAxis(seat, config, invocation) {
|
|
393
|
-
|
|
394
|
-
|
|
395
|
-
|
|
396
|
-
|
|
397
|
-
return { ...seat, host: persistent, hostSource: "persistent" };
|
|
398
|
-
return { ...seat, host: "pi", hostSource: "default" };
|
|
304
|
+
if (invocation?.host !== void 0) return { ...seat, host: invocation.host, hostSource: "invocation" };
|
|
305
|
+
const persistent = config.seats[seat.seat]?.host;
|
|
306
|
+
if (persistent !== void 0) return { ...seat, host: persistent, hostSource: "persistent" };
|
|
307
|
+
return { ...seat, host: "pi", hostSource: "default" };
|
|
399
308
|
}
|
|
400
309
|
function attachEngineAxis(seat, config, invocation) {
|
|
401
|
-
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
|
|
414
|
-
|
|
415
|
-
|
|
416
|
-
if (persistentEngine !== undefined) {
|
|
417
|
-
return {
|
|
418
|
-
...seat,
|
|
419
|
-
engine: persistentEngine,
|
|
420
|
-
engineSource: "persistent",
|
|
421
|
-
};
|
|
422
|
-
}
|
|
310
|
+
if (!isPublicCallableRole(seat.seat)) {
|
|
311
|
+
return {
|
|
312
|
+
...seat,
|
|
313
|
+
engineSource: "unconfigured"
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
const persistentEngine = config.seats[seat.seat]?.engine;
|
|
317
|
+
if (invocation?.engine !== void 0) {
|
|
318
|
+
return {
|
|
319
|
+
...seat,
|
|
320
|
+
engine: invocation.engine,
|
|
321
|
+
engineSource: "invocation"
|
|
322
|
+
};
|
|
323
|
+
}
|
|
324
|
+
if (persistentEngine !== void 0) {
|
|
423
325
|
return {
|
|
424
|
-
|
|
425
|
-
|
|
326
|
+
...seat,
|
|
327
|
+
engine: persistentEngine,
|
|
328
|
+
engineSource: "persistent"
|
|
426
329
|
};
|
|
330
|
+
}
|
|
331
|
+
return {
|
|
332
|
+
...seat,
|
|
333
|
+
engineSource: "unconfigured"
|
|
334
|
+
};
|
|
427
335
|
}
|
|
428
336
|
function resolveBaseSeat(config, seat, credentials) {
|
|
429
|
-
|
|
430
|
-
|
|
431
|
-
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
435
|
-
|
|
436
|
-
|
|
437
|
-
|
|
438
|
-
|
|
439
|
-
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
|
|
447
|
-
|
|
448
|
-
|
|
449
|
-
|
|
450
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
}
|
|
458
|
-
return { seat, source: "unconfigured", engineSource: "unconfigured" };
|
|
337
|
+
if (seat === "notary" || seat === "inspector") {
|
|
338
|
+
const resolved = resolveConfiguredProvinceOfficer(config, seat);
|
|
339
|
+
return {
|
|
340
|
+
seat,
|
|
341
|
+
source: resolved.source,
|
|
342
|
+
...resolved.selection === void 0 ? {} : { selection: resolved.selection },
|
|
343
|
+
engineSource: "unconfigured"
|
|
344
|
+
};
|
|
345
|
+
}
|
|
346
|
+
const persistentModel = seatModelOnly(config.seats[seat]);
|
|
347
|
+
if (persistentModel !== void 0) {
|
|
348
|
+
return {
|
|
349
|
+
seat,
|
|
350
|
+
source: "persistent",
|
|
351
|
+
selection: persistentModel,
|
|
352
|
+
engineSource: "unconfigured"
|
|
353
|
+
};
|
|
354
|
+
}
|
|
355
|
+
const startup = pickStartupCandidate(seat, credentials);
|
|
356
|
+
if (startup !== void 0) {
|
|
357
|
+
return {
|
|
358
|
+
seat,
|
|
359
|
+
source: "startup",
|
|
360
|
+
selection: startup,
|
|
361
|
+
engineSource: "unconfigured"
|
|
362
|
+
};
|
|
363
|
+
}
|
|
364
|
+
return { seat, source: "unconfigured", engineSource: "unconfigured" };
|
|
459
365
|
}
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
}
|
|
467
|
-
|
|
468
|
-
|
|
469
|
-
|
|
470
|
-
|
|
471
|
-
|
|
472
|
-
|
|
473
|
-
|
|
474
|
-
|
|
475
|
-
|
|
476
|
-
|
|
477
|
-
|
|
478
|
-
|
|
479
|
-
|
|
480
|
-
|
|
481
|
-
|
|
482
|
-
|
|
483
|
-
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
|
|
487
|
-
|
|
488
|
-
|
|
489
|
-
|
|
490
|
-
|
|
491
|
-
selection: { ...base.selection, thinking: invocation.thinking },
|
|
492
|
-
engineSource: "unconfigured",
|
|
493
|
-
};
|
|
494
|
-
}
|
|
495
|
-
}
|
|
496
|
-
return attachHostAxis(attachEngineAxis(modelSeat, config, invocation), config, invocation);
|
|
366
|
+
function resolveEffectiveSeat(config, seat, credentials, invocation) {
|
|
367
|
+
const hasModelInvocation = invocation !== void 0 && (invocation.model !== void 0 || invocation.thinking !== void 0);
|
|
368
|
+
let modelSeat;
|
|
369
|
+
if (!hasModelInvocation || invocation === void 0) {
|
|
370
|
+
modelSeat = resolveBaseSeat(config, seat, credentials);
|
|
371
|
+
} else if (invocation.model !== void 0) {
|
|
372
|
+
const spec = invocation.model.includes(":") || invocation.thinking === void 0 ? invocation.model : `${invocation.model}:${invocation.thinking}`;
|
|
373
|
+
modelSeat = {
|
|
374
|
+
seat,
|
|
375
|
+
source: "invocation",
|
|
376
|
+
selection: parseModelSpec(spec),
|
|
377
|
+
engineSource: "unconfigured"
|
|
378
|
+
};
|
|
379
|
+
} else {
|
|
380
|
+
const base = resolveBaseSeat(config, seat, credentials);
|
|
381
|
+
if (base.selection === void 0 || invocation.thinking === void 0) {
|
|
382
|
+
modelSeat = {
|
|
383
|
+
seat,
|
|
384
|
+
source: "unconfigured",
|
|
385
|
+
engineSource: "unconfigured"
|
|
386
|
+
};
|
|
387
|
+
} else {
|
|
388
|
+
modelSeat = {
|
|
389
|
+
seat,
|
|
390
|
+
source: "invocation",
|
|
391
|
+
selection: { ...base.selection, thinking: invocation.thinking },
|
|
392
|
+
engineSource: "unconfigured"
|
|
393
|
+
};
|
|
394
|
+
}
|
|
395
|
+
}
|
|
396
|
+
return attachHostAxis(attachEngineAxis(modelSeat, config, invocation), config, invocation);
|
|
497
397
|
}
|
|
498
|
-
|
|
499
|
-
|
|
398
|
+
function effectiveSeatConfigurations(config, credentials, invocation) {
|
|
399
|
+
return PUBLIC_CONFIGURABLE_SEATS.map(
|
|
400
|
+
(seat) => resolveEffectiveSeat(config, seat, credentials, invocation)
|
|
401
|
+
);
|
|
500
402
|
}
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
return effectiveSeatConfigurations(config, credentials, invocation);
|
|
403
|
+
function listRolesForDisplay(config, credentials, invocation) {
|
|
404
|
+
return effectiveSeatConfigurations(config, credentials, invocation);
|
|
504
405
|
}
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
|
|
512
|
-
|
|
513
|
-
|
|
514
|
-
return {
|
|
515
|
-
"openai-codex": Object.prototype.hasOwnProperty.call(record, "openai-codex"),
|
|
516
|
-
xai: Object.prototype.hasOwnProperty.call(record, "xai"),
|
|
517
|
-
};
|
|
406
|
+
function credentialProvidersFromAuthData(data) {
|
|
407
|
+
if (data === null || typeof data !== "object" || Array.isArray(data)) {
|
|
408
|
+
return { "openai-codex": false, xai: false };
|
|
409
|
+
}
|
|
410
|
+
const record = data;
|
|
411
|
+
return {
|
|
412
|
+
"openai-codex": Object.prototype.hasOwnProperty.call(record, "openai-codex"),
|
|
413
|
+
xai: Object.prototype.hasOwnProperty.call(record, "xai")
|
|
414
|
+
};
|
|
518
415
|
}
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
}
|
|
530
|
-
throw error;
|
|
531
|
-
}
|
|
416
|
+
async function loadCredentialProviders(agentDir) {
|
|
417
|
+
try {
|
|
418
|
+
const raw = await readFile(join(agentDir, "auth.json"), "utf8");
|
|
419
|
+
return credentialProvidersFromAuthData(JSON.parse(raw));
|
|
420
|
+
} catch (error) {
|
|
421
|
+
if (error instanceof Error && "code" in error && error.code === "ENOENT") {
|
|
422
|
+
return { "openai-codex": false, xai: false };
|
|
423
|
+
}
|
|
424
|
+
throw error;
|
|
425
|
+
}
|
|
532
426
|
}
|
|
427
|
+
export {
|
|
428
|
+
GATE_OFFICER_SEATS,
|
|
429
|
+
buildSeatModelCliArgs,
|
|
430
|
+
clearPersistentSeatConfig,
|
|
431
|
+
credentialProvidersFromAuthData,
|
|
432
|
+
effectiveSeatConfigurations,
|
|
433
|
+
formatModelSpec,
|
|
434
|
+
isGateOfficerSeat,
|
|
435
|
+
listRolesForDisplay,
|
|
436
|
+
loadCredentialProviders,
|
|
437
|
+
loadPublicCliConfig,
|
|
438
|
+
missingPublicProviderCredential,
|
|
439
|
+
parseAutoResumeLimit,
|
|
440
|
+
parseModelSpec,
|
|
441
|
+
providerConfigured,
|
|
442
|
+
publicCliConfigPath,
|
|
443
|
+
resolveEffectiveSeat,
|
|
444
|
+
savePublicCliConfig,
|
|
445
|
+
setAutoResumeLimit,
|
|
446
|
+
setPersistentSeatConfig,
|
|
447
|
+
setPersistentSeatEngine,
|
|
448
|
+
setPersistentSeatHost,
|
|
449
|
+
validatePublicCliConfigAxes
|
|
450
|
+
};
|