@timurproko/a1 0.2.7-dev.1236 → 0.2.7-dev.1239
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/composition/owned-settings.js +1 -1
- package/dist/composition/release-update-observation.js +43 -14
- package/dist/contracts/owned-ui/session-workflows.d.ts +1 -1
- package/dist/features/owned-ui/plus-menu-dialog.d.ts +13 -7
- package/dist/features/owned-ui/plus-menu-dialog.js +17 -12
- package/dist/features/owned-ui/settings-app.js +94 -17
- package/dist/foundation/release/automatic-update.d.ts +12 -0
- package/dist/foundation/release/automatic-update.js +87 -5
- package/dist/integrations/pi/engine/default-model-setting.d.ts +12 -0
- package/dist/integrations/pi/engine/default-model-setting.js +70 -0
- package/dist/integrations/pi/engine/diagnostics-state.js +6 -5
- package/dist/integrations/pi/engine/index.d.ts +1 -1
- package/dist/integrations/pi/engine/index.js +1 -1
- package/dist/integrations/pi/engine/offline-settings-port.js +1 -0
- package/dist/integrations/pi/engine/runtime-integration.d.ts +1 -1
- package/dist/integrations/pi/engine/runtime-integration.js +12 -14
- package/dist/integrations/pi/engine/settings-bridge.d.ts +1 -2
- package/dist/integrations/pi/engine/settings-bridge.js +23 -29
- package/dist/integrations/pi/engine/settings-port.js +2 -1
- package/dist/integrations/pi/engine/workflow-runner.js +2 -2
- package/dist/native/darwin-arm64/manifest.json +1 -1
- package/dist/native/darwin-arm64/terminal-host.manifest.json +3 -3
- package/dist/native/darwin-arm64/terminal-host.node +0 -0
- package/dist/native/darwin-x64/manifest.json +1 -1
- package/dist/native/darwin-x64/terminal-host.manifest.json +3 -3
- package/dist/native/darwin-x64/terminal-host.node +0 -0
- package/dist/native/linux-x64/manifest.json +1 -1
- package/dist/native/linux-x64/terminal-host.manifest.json +3 -3
- package/dist/native/linux-x64/terminal-host.node +0 -0
- package/dist/native/win32-x64/manifest.json +2 -2
- package/dist/native/win32-x64/process-guardian.node +0 -0
- package/dist/native/win32-x64/terminal-host.manifest.json +3 -3
- package/dist/native/win32-x64/terminal-host.node +0 -0
- package/dist/ui/components/dialog-panel.d.ts +6 -3
- package/dist/ui/components/dialog-panel.js +10 -7
- package/dist/ui/components/theme.d.ts +1 -1
- package/dist/ui/settings/declarations.d.ts +23 -2
- package/dist/ui/settings/declarations.js +18 -2
- package/dist/ui/settings/migrations.js +7 -0
- package/docs/architecture/ui-reference-provenance.md +3 -3
- package/package.json +3 -3
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
export const DEFAULT_MODEL_SETTING_KEY = "defaultModel";
|
|
2
|
+
export const SUPPLEMENTAL_SETTING_KEYS = [DEFAULT_MODEL_SETTING_KEY];
|
|
3
|
+
const UNSET = "not set";
|
|
4
|
+
function read(settings) {
|
|
5
|
+
const provider = settings.getDefaultProvider();
|
|
6
|
+
const model = settings.getDefaultModel();
|
|
7
|
+
return provider && model ? `${provider}/${model}` : UNSET;
|
|
8
|
+
}
|
|
9
|
+
export function defaultModelDescriptor(settings, models) {
|
|
10
|
+
const value = read(settings);
|
|
11
|
+
return {
|
|
12
|
+
key: DEFAULT_MODEL_SETTING_KEY,
|
|
13
|
+
valueType: "enum",
|
|
14
|
+
writable: true,
|
|
15
|
+
application: "next-session",
|
|
16
|
+
owner: "startup",
|
|
17
|
+
available: true,
|
|
18
|
+
limitationReason: null,
|
|
19
|
+
storedValue: value,
|
|
20
|
+
effectiveValue: value,
|
|
21
|
+
choices: models.map(model => model.key),
|
|
22
|
+
flags: models.map(model => ({
|
|
23
|
+
key: model.key, label: model.label, description: model.name, fallback: false,
|
|
24
|
+
})),
|
|
25
|
+
label: "Default model",
|
|
26
|
+
description: "Model used when a new session starts",
|
|
27
|
+
resolvedWhenRead: true,
|
|
28
|
+
};
|
|
29
|
+
}
|
|
30
|
+
export async function writeDefaultModel(settings, models, value) {
|
|
31
|
+
if (typeof value !== "string" || !models.some(model => model.key === value)) {
|
|
32
|
+
throw new TypeError("setting value is invalid: defaultModel");
|
|
33
|
+
}
|
|
34
|
+
const previous = read(settings);
|
|
35
|
+
const at = value.indexOf("/");
|
|
36
|
+
settings.setDefaultModelAndProvider(value.slice(0, at), value.slice(at + 1));
|
|
37
|
+
try {
|
|
38
|
+
await settings.flush();
|
|
39
|
+
const errors = settings.drainErrors();
|
|
40
|
+
if (errors.length > 0)
|
|
41
|
+
throw new Error(errors.map(item => item.error.message).join("; "));
|
|
42
|
+
return {
|
|
43
|
+
status: "deferred", application: "next-session", storedValue: value, effectiveValue: previous,
|
|
44
|
+
failure: null, limitationReason: null,
|
|
45
|
+
};
|
|
46
|
+
}
|
|
47
|
+
catch (error) {
|
|
48
|
+
let failure = error instanceof Error ? error.message : String(error);
|
|
49
|
+
try {
|
|
50
|
+
if (previous === UNSET)
|
|
51
|
+
await settings.reload();
|
|
52
|
+
else {
|
|
53
|
+
const split = previous.indexOf("/");
|
|
54
|
+
settings.setDefaultModelAndProvider(previous.slice(0, split), previous.slice(split + 1));
|
|
55
|
+
await settings.flush();
|
|
56
|
+
const errors = settings.drainErrors();
|
|
57
|
+
if (errors.length > 0)
|
|
58
|
+
throw new Error(errors.map(item => item.error.message).join("; "));
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
catch (rollbackError) {
|
|
62
|
+
failure += `; persistence rollback failed: ${rollbackError instanceof Error ? rollbackError.message : String(rollbackError)}`;
|
|
63
|
+
}
|
|
64
|
+
const restored = read(settings);
|
|
65
|
+
return {
|
|
66
|
+
status: "failed", application: "next-session", storedValue: restored, effectiveValue: previous,
|
|
67
|
+
failure, limitationReason: null,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
}
|
|
@@ -22,11 +22,12 @@ export class EngineDiagnostics {
|
|
|
22
22
|
if (validSemver(version) === null)
|
|
23
23
|
return false;
|
|
24
24
|
return this.#remove(diagnostic => {
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
25
|
+
// Invariant: restart readiness describes this long-lived process, not the outer client that
|
|
26
|
+
// attached to it. A newer client can clear activation blocking, but only process exit clears
|
|
27
|
+
// an installed-update notice.
|
|
28
|
+
const target = diagnostic.code === "release-update-blocked"
|
|
29
|
+
? /^Update (\S+) prepared; activation blocked\.$/u.exec(diagnostic.message)?.[1]
|
|
30
|
+
: undefined;
|
|
30
31
|
return target !== undefined && validSemver(target) !== null && gte(version, target);
|
|
31
32
|
});
|
|
32
33
|
}
|
|
@@ -10,7 +10,7 @@ export { PiSessionSelectionError, openSelectedPiSession, resolveSessionArgumentP
|
|
|
10
10
|
export type { PiSessionForkPrompt, PiSessionSelection } from "./session-selection.js";
|
|
11
11
|
export { PiSessionCommandIntegration } from "./session-integration.js";
|
|
12
12
|
export type { PiDocumentedSessionCommands, PiSessionCommand, PiSessionCommandResult } from "./session-integration.js";
|
|
13
|
-
export { AUTOMATIC_THEME, EXPOSED_SETTING_KEYS, PI_SETTING_EFFECTS, PiSettingsBridge, PiSettingsCoordinator, parseAutomaticTheme, settingsEffectInventoryDrift, settingsInventoryDrift,
|
|
13
|
+
export { AUTOMATIC_THEME, EXPOSED_SETTING_KEYS, PI_SETTING_EFFECTS, PiSettingsBridge, PiSettingsCoordinator, parseAutomaticTheme, settingsEffectInventoryDrift, settingsInventoryDrift, } from "./settings-bridge.js";
|
|
14
14
|
export { assertPiSettingsMetadata, loadPiSettingsMetadata, PI_SETTINGS_METADATA_FILE } from "./settings-metadata.js";
|
|
15
15
|
export type { PiSettingBounds, PiSettingPresentation, PiSettingsMetadata } from "./settings-metadata.js";
|
|
16
16
|
export type { PiSettingEffectDefinition, PiSettingEffectHandler, PiSettingKey, PiSettingOwnerHandlers, PiSettingStorageOperation, PiSettingVisualClass, PiSettingVisualEvidence, PiSettingsCoordinatorOptions, PiSettingsModelChoice, PiSettingsProviders, } from "./settings-bridge.js";
|
|
@@ -4,7 +4,7 @@ export { detachedEngineHostPorts } from "./host-ports.js";
|
|
|
4
4
|
export { bindPiRuntimeSession, createPiRuntimeIntegration, createPiRuntimeServicesAfterTrust, disposePiRuntimeIntegration, replacePiRuntimeSession, resolveConfiguredModelScope, } from "./runtime-integration.js";
|
|
5
5
|
export { PiSessionSelectionError, openSelectedPiSession, resolveSessionArgumentPath } from "./session-selection.js";
|
|
6
6
|
export { PiSessionCommandIntegration } from "./session-integration.js";
|
|
7
|
-
export { AUTOMATIC_THEME, EXPOSED_SETTING_KEYS, PI_SETTING_EFFECTS, PiSettingsBridge, PiSettingsCoordinator, parseAutomaticTheme, settingsEffectInventoryDrift, settingsInventoryDrift,
|
|
7
|
+
export { AUTOMATIC_THEME, EXPOSED_SETTING_KEYS, PI_SETTING_EFFECTS, PiSettingsBridge, PiSettingsCoordinator, parseAutomaticTheme, settingsEffectInventoryDrift, settingsInventoryDrift, } from "./settings-bridge.js";
|
|
8
8
|
export { assertPiSettingsMetadata, loadPiSettingsMetadata, PI_SETTINGS_METADATA_FILE } from "./settings-metadata.js";
|
|
9
9
|
export { resolvePiProjectTrustPreflight } from "./project-trust-preflight.js";
|
|
10
10
|
export { configureOwnedHttpDispatcher, configuredOwnedHttpIdleTimeoutMs } from "./http-dispatcher.js";
|
|
@@ -40,6 +40,7 @@ function modelChoices(models, overrides) {
|
|
|
40
40
|
return {
|
|
41
41
|
key,
|
|
42
42
|
label: `${model.id} [${model.provider}]`,
|
|
43
|
+
name: model.name ?? model.id,
|
|
43
44
|
description: overrides[key] === undefined ? "global default" : `override: ${overrides[key]}`,
|
|
44
45
|
levels: supportedThinkingLevels(model),
|
|
45
46
|
};
|
|
@@ -41,7 +41,7 @@ interface ConfiguredModelScope {
|
|
|
41
41
|
* Mirrors pinned Pi's CLI startup: resolve the `models` patterns from settings
|
|
42
42
|
* into a scoped model list, keep the resolver's warnings (e.g. "No models match
|
|
43
43
|
* pattern ..."), and pick the same initial model pinned Pi would pick — the
|
|
44
|
-
* saved default
|
|
44
|
+
* saved authenticated default, otherwise the first scoped model.
|
|
45
45
|
*/
|
|
46
46
|
export declare function resolveConfiguredModelScope(services: Pick<AgentSessionServices, "settingsManager" | "modelRuntime">, signal?: AbortSignal): Promise<ConfiguredModelScope>;
|
|
47
47
|
export declare function createPiRuntimeServicesAfterTrust(options: Pick<PiRuntimeIntegrationOptions, "agentDir" | "projectTrustPrompt" | "preflightDependencies" | "markStartupPhase"> & {
|
|
@@ -62,7 +62,7 @@ const runtimeSessionWriters = new WeakMap();
|
|
|
62
62
|
* Mirrors pinned Pi's CLI startup: resolve the `models` patterns from settings
|
|
63
63
|
* into a scoped model list, keep the resolver's warnings (e.g. "No models match
|
|
64
64
|
* pattern ..."), and pick the same initial model pinned Pi would pick — the
|
|
65
|
-
* saved default
|
|
65
|
+
* saved authenticated default, otherwise the first scoped model.
|
|
66
66
|
*/
|
|
67
67
|
export async function resolveConfiguredModelScope(services, signal) {
|
|
68
68
|
const patterns = services.settingsManager.getEnabledModels();
|
|
@@ -70,21 +70,19 @@ export async function resolveConfiguredModelScope(services, signal) {
|
|
|
70
70
|
return { scopedModels: [], model: undefined, thinkingLevel: undefined, diagnostics: [] };
|
|
71
71
|
}
|
|
72
72
|
const { scopedModels, diagnostics } = await resolveModelScopeWithDiagnostics([...patterns], services.modelRuntime, { signal: signal === undefined ? AbortSignal.timeout(15_000) : AbortSignal.any([signal, AbortSignal.timeout(15_000)]) });
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
: undefined;
|
|
80
|
-
selected = (savedModel
|
|
81
|
-
? scopedModels.find(scoped => scoped.model.provider === savedModel.provider && scoped.model.id === savedModel.id)
|
|
82
|
-
: undefined) ?? scopedModels[0];
|
|
83
|
-
}
|
|
73
|
+
const savedProvider = services.settingsManager.getDefaultProvider();
|
|
74
|
+
const savedModelId = services.settingsManager.getDefaultModel();
|
|
75
|
+
const savedModel = savedProvider && savedModelId
|
|
76
|
+
? services.modelRuntime.getAvailableSnapshot().find(model => model.provider === savedProvider && model.id === savedModelId)
|
|
77
|
+
: undefined;
|
|
78
|
+
const fallback = scopedModels[0];
|
|
84
79
|
return {
|
|
85
80
|
scopedModels,
|
|
86
|
-
model:
|
|
87
|
-
thinkingLevel:
|
|
81
|
+
model: savedModel ?? fallback?.model,
|
|
82
|
+
thinkingLevel: savedModel
|
|
83
|
+
? services.settingsManager.getModelThinkingLevel(savedModel.provider, savedModel.id)
|
|
84
|
+
?? services.settingsManager.getDefaultThinkingLevel()
|
|
85
|
+
: fallback?.thinkingLevel,
|
|
88
86
|
diagnostics: diagnostics.map(diagnostic => ({ type: diagnostic.type, message: diagnostic.message })),
|
|
89
87
|
};
|
|
90
88
|
}
|
|
@@ -65,11 +65,9 @@ export declare function settingsEffectInventoryDrift(presented: readonly string[
|
|
|
65
65
|
readonly stale: readonly string[];
|
|
66
66
|
readonly duplicated: readonly string[];
|
|
67
67
|
};
|
|
68
|
-
export declare function settingsVisualInventoryViolations(presented: readonly string[], reviewed?: Readonly<Partial<Record<PiSettingKey, PiSettingEffectDefinition>>>): readonly string[];
|
|
69
68
|
/** Values only the running engine knows. */
|
|
70
69
|
export interface PiSettingsProviders {
|
|
71
70
|
readonly themes?: () => readonly string[];
|
|
72
|
-
/** Models a per-model thinking override may name, with the levels each one supports. */
|
|
73
71
|
readonly models?: () => readonly PiSettingsModelChoice[];
|
|
74
72
|
readonly productMode?: "bare" | "comparison";
|
|
75
73
|
}
|
|
@@ -77,6 +75,7 @@ export interface PiSettingsModelChoice {
|
|
|
77
75
|
/** `provider/modelId`, the key the engine stores the override under. */
|
|
78
76
|
readonly key: string;
|
|
79
77
|
readonly label: string;
|
|
78
|
+
readonly name: string;
|
|
80
79
|
readonly description: string;
|
|
81
80
|
readonly levels: readonly string[];
|
|
82
81
|
}
|
|
@@ -15,6 +15,7 @@ export const PI_SETTING_EFFECTS = Object.freeze({
|
|
|
15
15
|
transport: effect("live", "agent", "status-error", "pinned provider request status and failure rows", "settings-effects-provider-parity"),
|
|
16
16
|
httpIdleTimeoutMs: effect("live", "agent", "retry-error", "pinned timeout, retry, and terminal failure rows", "pinned-transcript-lifecycle-parity"),
|
|
17
17
|
cacheWarmingMode: effect("live", "agent", "footer-transcript", "pinned cache warming notices and session usage rows", "pinned-transcript-lifecycle-parity"),
|
|
18
|
+
defaultModel: effect("next-session", "startup", "selector", "pinned default-model selector", "owned-default-model-setting"),
|
|
18
19
|
modelThinkingLevels: effect("live", "agent", "footer-transcript", "pinned per-model thinking override, footer indicator, and thinking rows", "pinned-status-indicator-parity"),
|
|
19
20
|
theme: hiddenEffect("live", "shell", "pinned theme selector and complete themed shell", "pinned-theme-parity"),
|
|
20
21
|
hideThinkingBlock: effect("live", "shell", "transcript", "pinned thinking block presence and spacing", "pinned-transcript-lifecycle-parity"),
|
|
@@ -225,27 +226,6 @@ export function settingsEffectInventoryDrift(presented, reviewed = Object.keys(P
|
|
|
225
226
|
duplicated: [...counts].filter(([, count]) => count > 1).map(([key]) => key),
|
|
226
227
|
};
|
|
227
228
|
}
|
|
228
|
-
export function settingsVisualInventoryViolations(presented, reviewed = PI_SETTING_EFFECTS) {
|
|
229
|
-
const violations = [];
|
|
230
|
-
for (const candidate of presented) {
|
|
231
|
-
const key = candidate;
|
|
232
|
-
const definition = reviewed[key];
|
|
233
|
-
if (definition === undefined) {
|
|
234
|
-
violations.push(`${candidate}: missing visual classification`);
|
|
235
|
-
continue;
|
|
236
|
-
}
|
|
237
|
-
const visual = definition.visual;
|
|
238
|
-
if (!visual || visual.pinnedSurface.trim().length === 0)
|
|
239
|
-
violations.push(`${candidate}: missing pinned visual source`);
|
|
240
|
-
if (!visual || visual.evidence.trim().length === 0)
|
|
241
|
-
violations.push(`${candidate}: missing independent visual evidence`);
|
|
242
|
-
if (definition.hiddenInBare === true && visual?.class !== "hidden")
|
|
243
|
-
violations.push(`${candidate}: hidden setting declares a visible frame`);
|
|
244
|
-
if (definition.hiddenInBare !== true && visual?.class === "hidden")
|
|
245
|
-
violations.push(`${candidate}: visible setting declares hidden evidence`);
|
|
246
|
-
}
|
|
247
|
-
return violations;
|
|
248
|
-
}
|
|
249
229
|
function outcome(status, application, storedValue, effectiveValue, failure, limitationReason) {
|
|
250
230
|
return { status, application, storedValue, effectiveValue, failure, limitationReason };
|
|
251
231
|
}
|
|
@@ -271,6 +251,7 @@ export const AUTOMATIC_THEME = "automatic";
|
|
|
271
251
|
const LIGHT_APPEARANCE_THEME = "light";
|
|
272
252
|
const DARK_APPEARANCE_THEME = "dark";
|
|
273
253
|
const THEME_KEY = "theme";
|
|
254
|
+
const DEFAULT_MODEL_KEY = "defaultModel";
|
|
274
255
|
const MODEL_THINKING_KEY = "modelThinkingLevels";
|
|
275
256
|
export function parseAutomaticTheme(stored) {
|
|
276
257
|
const at = stored.indexOf("/");
|
|
@@ -307,13 +288,16 @@ export class PiSettingsBridge {
|
|
|
307
288
|
capabilities = { write: true, flush: true };
|
|
308
289
|
#operations;
|
|
309
290
|
#providers;
|
|
291
|
+
#settings;
|
|
310
292
|
#coordinator;
|
|
311
293
|
constructor(settings, providers = {}) {
|
|
312
294
|
this.#providers = providers;
|
|
295
|
+
this.#settings = settings;
|
|
313
296
|
const mapped = operations(settings, providers);
|
|
314
297
|
this.#operations = new Map(mapped.map(operation => [operation.key, operation]));
|
|
315
298
|
const presentationDrift = settingsInventoryDrift(EXPOSED_SETTING_KEYS, mapped.map(operation => operation.key));
|
|
316
|
-
const
|
|
299
|
+
const generatedEffects = Object.keys(PI_SETTING_EFFECTS).filter(key => key !== DEFAULT_MODEL_KEY);
|
|
300
|
+
const effectDrift = settingsEffectInventoryDrift(EXPOSED_SETTING_KEYS, generatedEffects);
|
|
317
301
|
if (presentationDrift.unmapped.length > 0 || presentationDrift.stale.length > 0
|
|
318
302
|
|| effectDrift.unmapped.length > 0 || effectDrift.stale.length > 0 || effectDrift.duplicated.length > 0) {
|
|
319
303
|
throw new Error([
|
|
@@ -331,7 +315,8 @@ export class PiSettingsBridge {
|
|
|
331
315
|
});
|
|
332
316
|
}
|
|
333
317
|
bindOwner(owner, handlers) {
|
|
334
|
-
|
|
318
|
+
const { defaultModel: _defaultModel, ...generated } = handlers;
|
|
319
|
+
return this.#coordinator.bindOwner(owner, generated);
|
|
335
320
|
}
|
|
336
321
|
unbindOwner(owner) {
|
|
337
322
|
this.#coordinator.unbindOwner(owner);
|
|
@@ -341,14 +326,14 @@ export class PiSettingsBridge {
|
|
|
341
326
|
const at = PRESENTATION.order.indexOf(key);
|
|
342
327
|
return at < 0 ? PRESENTATION.order.length : at;
|
|
343
328
|
};
|
|
344
|
-
|
|
329
|
+
const descriptors = [...this.#operations.values()]
|
|
345
330
|
.filter(operation => this.#coordinator.available(operation.key))
|
|
346
331
|
.map(operation => {
|
|
347
332
|
const key = operation.key;
|
|
348
333
|
const wording = PRESENTATION.settings[key];
|
|
349
334
|
const flags = PRESENTATION.dialogs[key];
|
|
350
335
|
const bounds = PRESENTATION.bounds[key];
|
|
351
|
-
|
|
336
|
+
return this.#resolved({
|
|
352
337
|
...operation.descriptor,
|
|
353
338
|
application: PI_SETTING_EFFECTS[key].application,
|
|
354
339
|
owner: PI_SETTING_EFFECTS[key].owner,
|
|
@@ -360,10 +345,11 @@ export class PiSettingsBridge {
|
|
|
360
345
|
...(bounds === undefined ? {} : bounds),
|
|
361
346
|
...(wording === undefined ? {} : { label: wording.label, description: wording.description }),
|
|
362
347
|
...(flags === undefined ? {} : { flags }),
|
|
363
|
-
};
|
|
364
|
-
|
|
365
|
-
})
|
|
366
|
-
|
|
348
|
+
});
|
|
349
|
+
});
|
|
350
|
+
const { defaultModelDescriptor } = await import("./default-model-setting.js");
|
|
351
|
+
descriptors.push(defaultModelDescriptor(this.#settings, this.#providers.models?.() ?? []));
|
|
352
|
+
return descriptors.sort((left, right) => rank(left.key) - rank(right.key));
|
|
367
353
|
}
|
|
368
354
|
#resolved(descriptor) {
|
|
369
355
|
if (descriptor.key === THEME_KEY) {
|
|
@@ -387,9 +373,17 @@ export class PiSettingsBridge {
|
|
|
387
373
|
return this.#providers.themes?.() ?? [];
|
|
388
374
|
}
|
|
389
375
|
async readSetting(key) {
|
|
376
|
+
if (key === DEFAULT_MODEL_KEY) {
|
|
377
|
+
const { defaultModelDescriptor } = await import("./default-model-setting.js");
|
|
378
|
+
return defaultModelDescriptor(this.#settings, this.#providers.models?.() ?? []).storedValue;
|
|
379
|
+
}
|
|
390
380
|
return isPiSettingKey(key) && this.#operations.has(key) ? this.#coordinator.storedValue(key) : undefined;
|
|
391
381
|
}
|
|
392
382
|
async writeSetting(key, value) {
|
|
383
|
+
if (key === DEFAULT_MODEL_KEY) {
|
|
384
|
+
const { writeDefaultModel } = await import("./default-model-setting.js");
|
|
385
|
+
return await writeDefaultModel(this.#settings, this.#providers.models?.() ?? [], value);
|
|
386
|
+
}
|
|
393
387
|
if (!isPiSettingKey(key) || !this.#operations.has(key))
|
|
394
388
|
throw new Error(`setting is unavailable: ${key}`);
|
|
395
389
|
return await this.#coordinator.apply(key, value);
|
|
@@ -77,7 +77,7 @@ export class PiEngineSettings {
|
|
|
77
77
|
});
|
|
78
78
|
this.#settingsIntegration.bindOwner("startup", {
|
|
79
79
|
// Invariant: deferred application is the owner operation: the next preflight reads
|
|
80
|
-
// the persisted
|
|
80
|
+
// the persisted defaults before constructing project-backed services.
|
|
81
81
|
defaultProjectTrust: { apply() { } },
|
|
82
82
|
collapseChangelog: { apply() { } },
|
|
83
83
|
});
|
|
@@ -167,6 +167,7 @@ export class PiEngineSettings {
|
|
|
167
167
|
return {
|
|
168
168
|
key,
|
|
169
169
|
label: `${model.id} [${model.provider}]`,
|
|
170
|
+
name: model.name,
|
|
170
171
|
description: overrides[key] === undefined ? "global default" : `override: ${overrides[key]}`,
|
|
171
172
|
levels: supportedThinkingLevels(model),
|
|
172
173
|
};
|
|
@@ -333,13 +333,13 @@ export class PiWorkflowRunner {
|
|
|
333
333
|
});
|
|
334
334
|
}
|
|
335
335
|
case "models": {
|
|
336
|
-
// Invariant: the bare dialog seeds its query from the argument; only an explicit selection switches
|
|
336
|
+
// Invariant: the bare dialog seeds its query from the argument; only an explicit selection switches the current session.
|
|
337
337
|
if (!selection)
|
|
338
338
|
return workflowResult(request.command, "requires-selection", "Select a model", argument || undefined, "silent");
|
|
339
339
|
return this.#selectModel(request, selection, {
|
|
340
340
|
pool: [...(runtime.services.modelRuntime.getAvailableSnapshot?.() ?? [])],
|
|
341
341
|
refreshOnMiss: true,
|
|
342
|
-
persist:
|
|
342
|
+
persist: false,
|
|
343
343
|
onMiss: "failed",
|
|
344
344
|
});
|
|
345
345
|
}
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"platform": "darwin",
|
|
8
8
|
"architecture": "arm64",
|
|
9
9
|
"capability": "supported",
|
|
10
|
-
"builtAt": "2026-11-
|
|
10
|
+
"builtAt": "2026-11-03T20:15:18.883Z",
|
|
11
11
|
"artifact": {
|
|
12
12
|
"filename": "process-guardian.node",
|
|
13
13
|
"sha256": "a87eaaffcd986b624c8b044b756446cc1bdaf4334a1775b97820542fe34f9fb7",
|
|
@@ -9,11 +9,11 @@
|
|
|
9
9
|
"architecture": "arm64",
|
|
10
10
|
"target": "aarch64-apple-darwin",
|
|
11
11
|
"capability": "supported",
|
|
12
|
-
"builtAt": "2026-11-
|
|
12
|
+
"builtAt": "2026-11-03T20:18:38.194Z",
|
|
13
13
|
"artifact": {
|
|
14
14
|
"filename": "terminal-host.node",
|
|
15
|
-
"sha256": "
|
|
16
|
-
"size":
|
|
15
|
+
"sha256": "b14f69c00c7d472bdc4d742c7fc7d8a517d23aa1233a3e1e9e76b5f884999baa",
|
|
16
|
+
"size": 6585648
|
|
17
17
|
},
|
|
18
18
|
"entry": {
|
|
19
19
|
"filename": "dist/foundation/resident-tabs/host-entry.js",
|
|
Binary file
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"platform": "darwin",
|
|
8
8
|
"architecture": "x64",
|
|
9
9
|
"capability": "supported",
|
|
10
|
-
"builtAt": "2026-11-
|
|
10
|
+
"builtAt": "2026-11-03T20:15:26.152Z",
|
|
11
11
|
"artifact": {
|
|
12
12
|
"filename": "process-guardian.node",
|
|
13
13
|
"sha256": "783a65f0de287a1c02cd5429dbe97bc8633f4cc8a7b92e3e961180b9bdcff814",
|
|
@@ -9,11 +9,11 @@
|
|
|
9
9
|
"architecture": "x64",
|
|
10
10
|
"target": "x86_64-apple-darwin",
|
|
11
11
|
"capability": "supported",
|
|
12
|
-
"builtAt": "2026-11-
|
|
12
|
+
"builtAt": "2026-11-03T20:21:22.213Z",
|
|
13
13
|
"artifact": {
|
|
14
14
|
"filename": "terminal-host.node",
|
|
15
|
-
"sha256": "
|
|
16
|
-
"size":
|
|
15
|
+
"sha256": "1c0471bb3f2f9520acd1808cce080600b7e3dd485c4d3a8bc6f8aa342768136b",
|
|
16
|
+
"size": 7182168
|
|
17
17
|
},
|
|
18
18
|
"entry": {
|
|
19
19
|
"filename": "dist/foundation/resident-tabs/host-entry.js",
|
|
Binary file
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"platform": "linux",
|
|
8
8
|
"architecture": "x64",
|
|
9
9
|
"capability": "supported",
|
|
10
|
-
"builtAt": "2026-11-
|
|
10
|
+
"builtAt": "2026-11-03T20:15:23.280Z",
|
|
11
11
|
"artifact": {
|
|
12
12
|
"filename": "process-guardian.node",
|
|
13
13
|
"sha256": "118e5954e3864672bd8482ab7edf419cb27dcdf2533720316979b7f5cc5a53a5",
|
|
@@ -9,11 +9,11 @@
|
|
|
9
9
|
"architecture": "x64",
|
|
10
10
|
"target": "x86_64-unknown-linux-gnu",
|
|
11
11
|
"capability": "supported",
|
|
12
|
-
"builtAt": "2026-11-
|
|
12
|
+
"builtAt": "2026-11-03T20:18:59.521Z",
|
|
13
13
|
"artifact": {
|
|
14
14
|
"filename": "terminal-host.node",
|
|
15
|
-
"sha256": "
|
|
16
|
-
"size":
|
|
15
|
+
"sha256": "54eb39f88b6bfe88b6fd6815be1196d678450d06d1de1169a6de79bd4bf5ebec",
|
|
16
|
+
"size": 7961616
|
|
17
17
|
},
|
|
18
18
|
"entry": {
|
|
19
19
|
"filename": "dist/foundation/resident-tabs/host-entry.js",
|
|
Binary file
|
|
@@ -7,10 +7,10 @@
|
|
|
7
7
|
"platform": "win32",
|
|
8
8
|
"architecture": "x64",
|
|
9
9
|
"capability": "supported",
|
|
10
|
-
"builtAt": "2026-11-
|
|
10
|
+
"builtAt": "2026-11-03T20:16:09.523Z",
|
|
11
11
|
"artifact": {
|
|
12
12
|
"filename": "process-guardian.node",
|
|
13
|
-
"sha256": "
|
|
13
|
+
"sha256": "9489c6ea57e8cf13e14afb173cef1b4bb87c2cadaf14e583f93f58e0b4dd57dd",
|
|
14
14
|
"size": 402432
|
|
15
15
|
},
|
|
16
16
|
"provenance": {
|
|
Binary file
|
|
@@ -9,11 +9,11 @@
|
|
|
9
9
|
"architecture": "x64",
|
|
10
10
|
"target": "x86_64-pc-windows-msvc",
|
|
11
11
|
"capability": "supported",
|
|
12
|
-
"builtAt": "2026-11-
|
|
12
|
+
"builtAt": "2026-11-03T20:20:00.737Z",
|
|
13
13
|
"artifact": {
|
|
14
14
|
"filename": "terminal-host.node",
|
|
15
|
-
"sha256": "
|
|
16
|
-
"size":
|
|
15
|
+
"sha256": "1b8c8a4dbdfad9873a196a5f2746fc86a92678876bfacdf4b28830f40e95f963",
|
|
16
|
+
"size": 7080960
|
|
17
17
|
},
|
|
18
18
|
"entry": {
|
|
19
19
|
"filename": "dist/foundation/resident-tabs/host-entry.js",
|
|
Binary file
|
|
@@ -9,6 +9,8 @@ import type { UiTheme } from "./theme.js";
|
|
|
9
9
|
export interface DialogRow {
|
|
10
10
|
readonly label: string;
|
|
11
11
|
readonly labelSuffix?: string;
|
|
12
|
+
/** Success-colored marker rendered after the complete label. */
|
|
13
|
+
readonly successSuffix?: string;
|
|
12
14
|
readonly value: string;
|
|
13
15
|
/** What this part does, shown while it is the one in hand. */
|
|
14
16
|
readonly description?: string;
|
|
@@ -31,8 +33,9 @@ export interface DialogPanelFrame {
|
|
|
31
33
|
}
|
|
32
34
|
export interface SteppedDialogPanelState {
|
|
33
35
|
readonly title: string;
|
|
34
|
-
|
|
35
|
-
readonly
|
|
36
|
+
/** Omitted for a one-step searchable selector whose title needs no step marker. */
|
|
37
|
+
readonly step?: number;
|
|
38
|
+
readonly steps?: number;
|
|
36
39
|
readonly description: string;
|
|
37
40
|
readonly input?: LineInput;
|
|
38
41
|
readonly rows: readonly DialogRow[];
|
|
@@ -55,7 +58,7 @@ export declare function renderCenteredDialogOverlay(frame: readonly string[], di
|
|
|
55
58
|
export declare function dialogValueColumn(rows: readonly DialogRow[]): number;
|
|
56
59
|
/** The semantic rows for one generic configure modal. */
|
|
57
60
|
export declare function renderDialogPanel(state: DialogPanelState, width: number, theme: UiTheme): readonly string[];
|
|
58
|
-
/** Owned
|
|
61
|
+
/** Owned searchable selector content, with an optional step marker for nested choices. */
|
|
59
62
|
export declare function renderSteppedDialogPanel(state: SteppedDialogPanelState, width: number, theme: UiTheme): readonly string[];
|
|
60
63
|
/** The row a pointer report lands on, or null when it is not on one. */
|
|
61
64
|
export declare function dialogRowAt(frame: DialogPanelFrame, row: number, column: number, valueWidth: number): number | null;
|
|
@@ -99,18 +99,19 @@ export function renderDialogPanel(state, width, theme) {
|
|
|
99
99
|
layout.blank,
|
|
100
100
|
];
|
|
101
101
|
}
|
|
102
|
-
/** Owned
|
|
102
|
+
/** Owned searchable selector content, with an optional step marker for nested choices. */
|
|
103
103
|
export function renderSteppedDialogPanel(state, width, theme) {
|
|
104
104
|
const layout = dialogPanelLayout(width, theme);
|
|
105
|
-
const labelColumn = Math.min(STEPPED_LABEL_COLUMN_CAP, Math.max(0, ...state.rows.map(row => displayWidth(`${row.label}${row.labelSuffix ?? ""}`))));
|
|
105
|
+
const labelColumn = Math.min(STEPPED_LABEL_COLUMN_CAP, Math.max(0, ...state.rows.map(row => displayWidth(`${row.label}${row.labelSuffix ?? ""}${row.successSuffix === undefined ? "" : ` ${row.successSuffix}`}`))));
|
|
106
106
|
const rows = state.rows.map((row, index) => {
|
|
107
107
|
const selected = index === state.index;
|
|
108
|
-
const
|
|
108
|
+
const success = row.successSuffix === undefined ? "" : ` ${row.successSuffix}`;
|
|
109
|
+
const completeLabel = `${row.label}${row.labelSuffix ?? ""}${success}`;
|
|
109
110
|
const padding = " ".repeat(Math.max(0, labelColumn - displayWidth(completeLabel)));
|
|
110
111
|
const suffix = row.value.length === 0 ? "" : ` ${row.value}`;
|
|
111
112
|
const cursor = selected ? "→ " : " ";
|
|
112
113
|
const raw = `${cursor}${completeLabel}${padding}${suffix}`;
|
|
113
|
-
const label = `${theme.fg("text", row.label)}${theme.fg("muted", row.labelSuffix ?? "")}${padding}`;
|
|
114
|
+
const label = `${theme.fg("text", row.label)}${theme.fg("muted", row.labelSuffix ?? "")}${theme.fg("success", success)}${padding}`;
|
|
114
115
|
const content = selected
|
|
115
116
|
? `${theme.fg("accent", cursor)}${label}${theme.fg("muted", suffix)}`
|
|
116
117
|
: `${cursor}${label}${theme.fg("muted", suffix)}`;
|
|
@@ -128,9 +129,11 @@ export function renderSteppedDialogPanel(state, width, theme) {
|
|
|
128
129
|
layout.blank,
|
|
129
130
|
];
|
|
130
131
|
const descriptionRows = wrapText(state.description, layout.contentWidth);
|
|
131
|
-
const step = `(step ${state.step}/${state.steps})`;
|
|
132
|
-
const title = `${state.title} ${step}`;
|
|
133
|
-
const paintedTitle =
|
|
132
|
+
const step = state.step === undefined || state.steps === undefined ? "" : `(step ${state.step}/${state.steps})`;
|
|
133
|
+
const title = step.length === 0 ? state.title : `${state.title} ${step}`;
|
|
134
|
+
const paintedTitle = step.length === 0
|
|
135
|
+
? theme.bold(theme.fg("accent", state.title))
|
|
136
|
+
: `${theme.bold(theme.fg("accent", state.title))} ${theme.fg("dim", step)}`;
|
|
134
137
|
return [
|
|
135
138
|
layout.blank,
|
|
136
139
|
layout.contentRow(paintedTitle, title),
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type UiThemeToken = "accent" | "mdHeading" | "text" | "muted" | "dim" | "border" | "error";
|
|
1
|
+
export type UiThemeToken = "accent" | "mdHeading" | "text" | "muted" | "dim" | "border" | "error" | "success";
|
|
2
2
|
export interface UiTheme {
|
|
3
3
|
fg(token: UiThemeToken, text: string): string;
|
|
4
4
|
bold(text: string): string;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export declare const OWNED_UI_SETTINGS_VERSION =
|
|
1
|
+
export declare const OWNED_UI_SETTINGS_VERSION = 20;
|
|
2
2
|
export type OwnedUiSettingValue = string | number | boolean;
|
|
3
3
|
export type OwnedUiSettingApplication = "live" | "restart";
|
|
4
4
|
export interface OwnedUiSettingDeclaration {
|
|
@@ -42,7 +42,7 @@ export declare const OWNED_SETTING_DECLARATIONS: Readonly<{
|
|
|
42
42
|
id: "generic";
|
|
43
43
|
title: "Generic";
|
|
44
44
|
}>;
|
|
45
|
-
description: "Format used by submitted-prompt timestamps and the resident tab clock.";
|
|
45
|
+
description: "Format used by submitted-prompt timestamps and the resident tab clock when Time is enabled.";
|
|
46
46
|
application: "live";
|
|
47
47
|
defaultValue: "8:00 PM";
|
|
48
48
|
allowedValues: readonly ["20:00", "8:00 PM"];
|
|
@@ -228,6 +228,27 @@ export declare const OWNED_SETTING_DECLARATIONS: Readonly<{
|
|
|
228
228
|
description: "Show the one Changelog tab.";
|
|
229
229
|
}>)[];
|
|
230
230
|
}>;
|
|
231
|
+
readonly tabBarRightItems: Readonly<{
|
|
232
|
+
id: "tabBarRightItems";
|
|
233
|
+
label: "Right side";
|
|
234
|
+
section: Readonly<{
|
|
235
|
+
id: "tabs";
|
|
236
|
+
title: "Tab Bar";
|
|
237
|
+
}>;
|
|
238
|
+
description: "Choose whether the tab bar's right side shows the executing Version, Time, both, or neither.";
|
|
239
|
+
application: "live";
|
|
240
|
+
defaultValue: "version,time";
|
|
241
|
+
allowedValues: readonly ["", "version", "time", "version,time"];
|
|
242
|
+
flags: readonly (Readonly<{
|
|
243
|
+
key: "version";
|
|
244
|
+
label: "Version";
|
|
245
|
+
description: "Show the executing A1 version.";
|
|
246
|
+
}> | Readonly<{
|
|
247
|
+
key: "time";
|
|
248
|
+
label: "Time";
|
|
249
|
+
description: "Show the current time.";
|
|
250
|
+
}>)[];
|
|
251
|
+
}>;
|
|
231
252
|
readonly tabsAutoName: Readonly<{
|
|
232
253
|
id: "tabsAutoName";
|
|
233
254
|
label: "Auto name";
|