@timurproko/a1 0.2.7-dev.1252 → 0.2.7-dev.1264
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/bin/ui.js +3 -3
- package/dist/app/session-shell/clipboard-diagnostics.d.ts +2 -2
- package/dist/app/session-shell/clipboard-image.d.ts +0 -1
- package/dist/app/session-shell/clipboard-image.js +1 -1
- package/dist/app/session-shell/dialog-coordinator.d.ts +6 -5
- package/dist/app/session-shell/dialog-coordinator.js +3 -4
- package/dist/app/session-shell/dock-chrome.d.ts +11 -6
- package/dist/app/session-shell/dock-chrome.js +5 -8
- package/dist/app/session-shell/editor-hyperlink-budget.d.ts +0 -2
- package/dist/app/session-shell/editor-hyperlink-budget.js +1 -1
- package/dist/app/session-shell/exit-notice.d.ts +2 -2
- package/dist/app/session-shell/exit-notice.js +1 -1
- package/dist/app/session-shell/extension-surface.d.ts +8 -7
- package/dist/app/session-shell/helper-pool.d.ts +3 -4
- package/dist/app/session-shell/helper-pool.js +1 -1
- package/dist/app/session-shell/image-preparation-client.d.ts +4 -3
- package/dist/app/session-shell/image-preparation.d.ts +0 -2
- package/dist/app/session-shell/image-preparation.js +2 -2
- package/dist/app/session-shell/image-source.d.ts +2 -3
- package/dist/app/session-shell/image-source.js +2 -2
- package/dist/app/session-shell/input-surface-switch.d.ts +9 -7
- package/dist/app/session-shell/input-surface-switch.js +1 -2
- package/dist/app/session-shell/login-interaction.d.ts +5 -4
- package/dist/app/session-shell/login-interaction.js +2 -3
- package/dist/app/session-shell/paste-executor.d.ts +4 -8
- package/dist/app/session-shell/paste-executor.js +2 -2
- package/dist/app/session-shell/paste-protocol.d.ts +2 -2
- package/dist/app/session-shell/path-chip-presentation.d.ts +0 -5
- package/dist/app/session-shell/path-chip-presentation.js +3 -3
- package/dist/app/session-shell/prompt-chips.d.ts +8 -7
- package/dist/app/session-shell/prompt-history-controller.d.ts +3 -3
- package/dist/app/session-shell/prompt-submission.d.ts +5 -2
- package/dist/app/session-shell/prompt-submission.js +13 -14
- package/dist/app/session-shell/quit-outro-effects.d.ts +3 -3
- package/dist/app/session-shell/quit-outro-effects.js +1 -4
- package/dist/app/session-shell/quit-outro.d.ts +9 -12
- package/dist/app/session-shell/quit-outro.js +11 -11
- package/dist/app/session-shell/resource-labels.d.ts +2 -0
- package/dist/app/session-shell/resource-labels.js +158 -0
- package/dist/app/session-shell/response-copy-protocol.d.ts +3 -2
- package/dist/app/session-shell/response-copy-transport.d.ts +2 -14
- package/dist/app/session-shell/response-copy-transport.js +1 -1
- package/dist/app/session-shell/session-lifecycle.d.ts +2 -1
- package/dist/app/session-shell/session-prompt-history.d.ts +29 -0
- package/dist/app/session-shell/session-prompt-history.js +80 -0
- package/dist/app/session-shell/session-selectors.d.ts +46 -0
- package/dist/app/session-shell/session-selectors.js +269 -0
- package/dist/app/session-shell/session-shell-root.d.ts +76 -113
- package/dist/app/session-shell/session-shell-root.js +103 -329
- package/dist/app/session-shell/session-shell.d.ts +14 -37
- package/dist/app/session-shell/session-shell.js +177 -612
- package/dist/app/session-shell/session-viewport-controller.d.ts +9 -16
- package/dist/app/session-shell/session-viewport-controller.js +42 -320
- package/dist/app/session-shell/settings-bindings.d.ts +25 -3
- package/dist/app/session-shell/settings-bindings.js +26 -2
- package/dist/app/session-shell/share-operation.d.ts +3 -3
- package/dist/app/session-shell/share-operation.js +4 -6
- package/dist/app/session-shell/shell-clipboard.d.ts +59 -0
- package/dist/app/session-shell/shell-clipboard.js +119 -0
- package/dist/app/session-shell/shell-editor-factory.d.ts +8 -4
- package/dist/app/session-shell/shell-editor-factory.js +13 -15
- package/dist/app/session-shell/shell-host.d.ts +16 -17
- package/dist/app/session-shell/shell-host.js +18 -19
- package/dist/app/session-shell/shell-layout.d.ts +2 -2
- package/dist/app/session-shell/shell-prompt-suggestions.d.ts +26 -0
- package/dist/app/session-shell/shell-prompt-suggestions.js +48 -0
- package/dist/app/session-shell/suggestion-surface.d.ts +1 -6
- package/dist/app/session-shell/suggestion-surface.js +1 -1
- package/dist/app/session-shell/system-clipboard.d.ts +2 -14
- package/dist/app/session-shell/system-clipboard.js +2 -7
- package/dist/app/session-shell/transcript-document.d.ts +11 -8
- package/dist/app/session-shell/transcript-document.js +13 -14
- package/dist/app/session-shell/viewport-layout.d.ts +2 -2
- package/dist/app/session-shell/viewport-pointer.d.ts +83 -0
- package/dist/app/session-shell/viewport-pointer.js +361 -0
- package/dist/app/session-shell/workflow-output.d.ts +5 -3
- package/dist/app/session-shell/workflow-output.js +13 -15
- package/dist/cli/package-messages.d.ts +0 -1
- package/dist/cli/package-messages.js +1 -1
- package/dist/cli/session-context.d.ts +1 -1
- package/dist/cli/uninstall.d.ts +3 -2
- package/dist/composition/owned-settings.d.ts +2 -1
- package/dist/composition/owned-settings.js +0 -3
- package/dist/composition/owned-ui.d.ts +1 -1
- package/dist/composition/owned-ui.js +77 -73
- package/dist/composition/reference-selection-options.d.ts +1 -1
- package/dist/composition/reference-selection-options.js +1 -1
- package/dist/composition/session-runtime-registry.d.ts +2 -1
- package/dist/composition/settings-route-host.js +3 -10
- package/dist/composition/settings-search-input.d.ts +2 -1
- package/dist/composition/startup-route.d.ts +2 -2
- package/dist/composition/startup-route.js +2 -2
- package/dist/contracts/owned-ui/extension-ui.d.ts +2 -1
- package/dist/contracts/owned-ui/index.d.ts +2 -1
- package/dist/contracts/owned-ui/index.js +1 -1
- package/dist/contracts/owned-ui/session-presenters.d.ts +3 -0
- package/dist/contracts/owned-ui/shell-components.d.ts +543 -0
- package/dist/contracts/owned-ui/validation.d.ts +1 -11
- package/dist/contracts/owned-ui/validation.js +8 -104
- package/dist/contracts/presentation/component.d.ts +17 -0
- package/dist/contracts/presentation/component.js +8 -0
- package/dist/contracts/presentation/index.d.ts +6 -15
- package/dist/contracts/presentation/index.js +2 -0
- package/dist/contracts/presentation/terminal.d.ts +284 -0
- package/dist/contracts/presentation/terminal.js +1 -0
- package/dist/contracts/presentation/theme.d.ts +46 -0
- package/dist/contracts/presentation/theme.js +1 -0
- package/dist/features/launch/development-launch.js +1 -1
- package/dist/features/launch/runtime-selection.d.ts +2 -2
- package/dist/features/launch/runtime-selection.js +2 -2
- package/dist/features/owned-ui/project-trust-prompt.d.ts +2 -2
- package/dist/features/owned-ui/project-trust-prompt.js +1 -1
- package/dist/features/owned-ui/release-note-state.d.ts +2 -1
- package/dist/features/owned-ui/settings-app.js +49 -425
- package/dist/features/owned-ui/settings-edits.d.ts +31 -0
- package/dist/features/owned-ui/settings-edits.js +139 -0
- package/dist/features/owned-ui/settings-model-dialog.d.ts +41 -0
- package/dist/features/owned-ui/settings-model-dialog.js +194 -0
- package/dist/features/owned-ui/settings-scroll-rail.d.ts +29 -0
- package/dist/features/owned-ui/settings-scroll-rail.js +79 -0
- package/dist/features/owned-ui/settings-search-input.d.ts +2 -1
- package/dist/features/prompt-history/service.d.ts +3 -2
- package/dist/foundation/lifecycle/claim-gate.d.ts +2 -1
- package/dist/foundation/release/automatic-update.d.ts +5 -14
- package/dist/foundation/release/automatic-update.js +15 -22
- package/dist/foundation/release/bootstrap.js +4 -4
- package/dist/foundation/release/dependency-certification.d.ts +0 -1
- package/dist/foundation/release/dependency-certification.js +1 -1
- package/dist/foundation/release/dependency-layer.js +3 -3
- package/dist/foundation/release/early-accent.d.ts +2 -2
- package/dist/foundation/release/early-accent.js +1 -1
- package/dist/foundation/release/index.d.ts +2 -2
- package/dist/foundation/release/index.js +1 -1
- package/dist/foundation/release/latest-release.d.ts +3 -18
- package/dist/foundation/release/latest-release.js +11 -11
- package/dist/foundation/release/managed-path.d.ts +10 -0
- package/dist/foundation/release/managed-path.js +26 -0
- package/dist/foundation/release/ordinary-launch-selection.d.ts +1 -1
- package/dist/foundation/release/ordinary-launch-selection.js +1 -1
- package/dist/foundation/release/release-gc.d.ts +3 -3
- package/dist/foundation/release/release-gc.js +10 -12
- package/dist/foundation/release/{cohort-state.d.ts → release-state.d.ts} +23 -23
- package/dist/foundation/release/{cohort-state.js → release-state.js} +8 -8
- package/dist/foundation/release/restart-certification.js +3 -4
- package/dist/foundation/release/update-activation.js +3 -3
- package/dist/foundation/release/update-execution-lease.d.ts +2 -3
- package/dist/foundation/release/update-execution-lease.js +2 -8
- package/dist/foundation/release/update-installer.d.ts +45 -0
- package/dist/foundation/release/update-installer.js +57 -0
- package/dist/foundation/release/update-launch.d.ts +2 -2
- package/dist/foundation/release/update-recovery.js +2 -9
- package/dist/foundation/release/update.d.ts +4 -25
- package/dist/foundation/release/update.js +164 -183
- package/dist/foundation/startup/startup-budget.d.ts +5 -5
- package/dist/foundation/startup/startup-budget.js +2 -2
- package/dist/integrations/pi/components/bracketed-paste.d.ts +33 -0
- package/dist/integrations/pi/components/bracketed-paste.js +123 -0
- package/dist/integrations/pi/components/editor-interaction.d.ts +4 -12
- package/dist/integrations/pi/components/index.d.ts +15 -9
- package/dist/integrations/pi/components/index.js +9 -5
- package/dist/integrations/pi/components/lazy-selectors.d.ts +2 -10
- package/dist/integrations/pi/components/lazy-selectors.js +1 -1
- package/dist/integrations/pi/components/modal-frame.d.ts +5 -22
- package/dist/integrations/pi/components/modal-frame.js +3 -23
- package/dist/integrations/pi/components/owned-editor-ux.d.ts +4 -3
- package/dist/integrations/pi/components/owned-editor-ux.js +46 -140
- package/dist/integrations/pi/components/prompt-input-port.d.ts +2 -19
- package/dist/integrations/pi/components/resources/builtin-themes.d.ts +2 -1
- package/dist/integrations/pi/components/shell-editor-autocomplete.d.ts +3 -2
- package/dist/integrations/pi/components/shell-footer-status.d.ts +2 -2
- package/dist/integrations/pi/components/shell-footer-status.js +3 -2
- package/dist/integrations/pi/components/shell-presenters-info.d.ts +6 -5
- package/dist/integrations/pi/components/shell-presenters-info.js +2 -1
- package/dist/integrations/pi/components/shell-session-info-reference.d.ts +2 -1
- package/dist/integrations/pi/components/shell-shared-facade.d.ts +33 -227
- package/dist/integrations/pi/components/shell-shared-facade.js +8 -1
- package/dist/integrations/pi/components/skills-command.d.ts +1 -9
- package/dist/integrations/pi/components/skills-command.js +5 -5
- package/dist/integrations/pi/components/theme.d.ts +9 -2
- package/dist/integrations/pi/components/theme.js +17 -2
- package/dist/integrations/pi/components/thinking-selector-dialog.d.ts +2 -1
- package/dist/integrations/pi/components/upstream/adjacent/core/keybindings.d.ts +2 -2
- package/dist/integrations/pi/engine/adapter.d.ts +4 -13
- package/dist/integrations/pi/engine/adapter.js +9 -61
- package/dist/integrations/pi/engine/changelog.d.ts +2 -2
- package/dist/integrations/pi/engine/changelog.js +3 -3
- package/dist/integrations/pi/engine/compaction-progress.d.ts +2 -3
- package/dist/integrations/pi/engine/compaction-progress.js +1 -1
- package/dist/integrations/pi/engine/conformance.d.ts +2 -1
- package/dist/integrations/pi/engine/default-model-setting.d.ts +0 -2
- package/dist/integrations/pi/engine/default-model-setting.js +1 -2
- package/dist/integrations/pi/engine/event-delivery.d.ts +2 -1
- package/dist/integrations/pi/engine/extension-ui-binding.d.ts +2 -1
- package/dist/integrations/pi/engine/host.js +3 -3
- package/dist/integrations/pi/engine/message-values.d.ts +0 -1
- package/dist/integrations/pi/engine/message-values.js +1 -1
- package/dist/integrations/pi/engine/pending-delivery.d.ts +0 -4
- package/dist/integrations/pi/engine/pending-delivery.js +3 -3
- package/dist/integrations/pi/engine/ports.d.ts +7 -1
- package/dist/integrations/pi/engine/ports.js +4 -0
- package/dist/integrations/pi/engine/project-trust-preflight.d.ts +2 -1
- package/dist/integrations/pi/engine/prompt-suggestions.d.ts +3 -2
- package/dist/integrations/pi/engine/provider-authentication.d.ts +1 -1
- package/dist/integrations/pi/engine/public-main-entry.d.ts +1 -5
- package/dist/integrations/pi/engine/public-main-entry.js +1 -1
- package/dist/integrations/pi/engine/repository-metadata.d.ts +49 -0
- package/dist/integrations/pi/engine/repository-metadata.js +189 -0
- package/dist/integrations/pi/engine/repository-pr-rest.d.ts +1 -9
- package/dist/integrations/pi/engine/repository-pr-rest.js +2 -2
- package/dist/integrations/pi/engine/repository-pr.d.ts +1 -3
- package/dist/integrations/pi/engine/repository-pr.js +1 -1
- package/dist/integrations/pi/engine/resource-catalog.d.ts +2 -1
- package/dist/integrations/pi/engine/session-integration.d.ts +1 -1
- package/dist/integrations/pi/engine/session-runtime.d.ts +7 -12
- package/dist/integrations/pi/engine/session-runtime.js +21 -178
- package/dist/integrations/pi/engine/settings-bridge.d.ts +0 -2
- package/dist/integrations/pi/engine/settings-bridge.js +1 -1
- package/dist/integrations/pi/engine/settings-port.d.ts +3 -2
- package/dist/integrations/pi/engine/transcript-projection.d.ts +2 -1
- package/dist/integrations/pi/engine/view-state.d.ts +21 -2
- package/dist/integrations/pi/engine/view-state.js +129 -1
- package/dist/integrations/pi/engine/workflow-contexts.d.ts +1 -1
- package/dist/integrations/pi/engine/workflow-runner.d.ts +1 -2
- package/dist/integrations/pi/engine/workflow-runner.js +254 -365
- package/dist/integrations/pi/engine/workflow-share.d.ts +9 -0
- package/dist/integrations/pi/engine/workflow-share.js +168 -0
- package/dist/integrations/pi/engine/workflow-support.d.ts +0 -20
- package/dist/integrations/pi/engine/workflow-support.js +4 -65
- package/dist/integrations/pi/engine/workflows.d.ts +5 -5
- package/dist/integrations/pi/session-presenters/components.d.ts +3 -0
- package/dist/integrations/pi/session-presenters/components.js +75 -0
- package/dist/integrations/pi/session-presenters/index.d.ts +1 -0
- package/dist/integrations/pi/session-presenters/index.js +1 -0
- package/dist/integrations/pi/session-presenters/presentation.d.ts +3 -0
- package/dist/integrations/pi/session-presenters/presentation.js +10 -0
- package/dist/integrations/pi/session-presenters/presenters.d.ts +2 -1
- package/dist/integrations/pi/session-presenters/presenters.js +3 -1
- package/dist/integrations/pi/tui-runtime/adapter.d.ts +9 -19
- package/dist/integrations/pi/tui-runtime/adapter.js +56 -174
- package/dist/integrations/pi/tui-runtime/damage-aware-terminal.d.ts +9 -44
- package/dist/integrations/pi/tui-runtime/index.d.ts +1 -1
- package/dist/integrations/pi/tui-runtime/index.js +1 -0
- package/dist/integrations/pi/tui-runtime/input-presentation-coordinator.d.ts +4 -6
- package/dist/integrations/pi/tui-runtime/overlay-geometry.d.ts +4 -10
- package/dist/integrations/pi/tui-runtime/overlay-geometry.js +3 -9
- package/dist/integrations/pi/tui-runtime/presentation-adapter.d.ts +2 -2
- package/dist/integrations/pi/tui-runtime/runtime-factory.d.ts +3 -0
- package/dist/integrations/pi/tui-runtime/runtime-factory.js +11 -0
- package/dist/ui/components/index.d.ts +2 -2
- package/dist/ui/components/index.js +1 -1
- package/dist/ui/components/selection-copy.d.ts +0 -1
- package/dist/ui/components/selection-copy.js +0 -12
- package/dist/ui/components/theme.d.ts +4 -19
- package/dist/ui/components/theme.js +6 -0
- package/dist/ui/components/transcript-viewport-frame.d.ts +120 -0
- package/dist/ui/components/transcript-viewport-frame.js +314 -0
- package/dist/ui/components/transcript-viewport-types.d.ts +147 -0
- package/dist/ui/components/transcript-viewport-types.js +1 -0
- package/dist/ui/components/transcript-viewport.d.ts +2 -147
- package/dist/ui/components/transcript-viewport.js +87 -315
- package/dist/ui/settings/declarations.d.ts +2 -3
- package/dist/ui/settings/declarations.js +2 -3
- package/dist/ui/settings/early-accent.js +1 -1
- package/dist/ui/settings/index.d.ts +3 -5
- package/dist/ui/settings/index.js +2 -3
- package/dist/ui/settings/manager.d.ts +0 -4
- package/dist/ui/settings/manager.js +6 -62
- package/dist/ui/settings/resolution.d.ts +6 -18
- package/dist/ui/settings/resolution.js +4 -103
- package/dist/ui/settings/sections.d.ts +0 -4
- package/dist/ui/settings/sections.js +1 -1
- package/docs/architecture/boundaries.md +2 -2
- package/docs/architecture/internal-naming.md +2 -0
- package/docs/architecture/project-structure.md +4 -2
- package/docs/validation.md +1 -1
- package/package.json +3 -4
- package/dist/integrations/pi/components/components.d.ts +0 -4
- package/dist/integrations/pi/components/components.js +0 -48
- package/dist/integrations/pi/components/conformance.d.ts +0 -18
- package/dist/integrations/pi/components/conformance.js +0 -70
- package/dist/integrations/pi/components/shell-components.d.ts +0 -7
- package/dist/integrations/pi/components/shell-components.js +0 -7
- package/dist/integrations/pi/components/upstream/theme/theme-controller.d.ts +0 -33
- package/dist/integrations/pi/components/upstream/theme/theme-controller.js +0 -114
- package/dist/integrations/pi/engine/diagnostics-state.d.ts +0 -9
- package/dist/integrations/pi/engine/diagnostics-state.js +0 -34
- package/dist/integrations/pi/engine/usage-view.d.ts +0 -4
- package/dist/integrations/pi/engine/usage-view.js +0 -56
- package/dist/integrations/pi/tui-runtime/contracts.d.ts +0 -166
- package/dist/ui/settings/migrations.d.ts +0 -19
- package/dist/ui/settings/migrations.js +0 -225
- package/dist/ui/settings/progress-palette.generated.d.ts +0 -139
- package/dist/ui/settings/progress-palette.generated.js +0 -139
- /package/dist/{integrations/pi/tui-runtime/contracts.js → contracts/owned-ui/shell-components.js} +0 -0
- /package/dist/{foundation/release → contracts/presentation}/progress-palette.generated.d.ts +0 -0
- /package/dist/{foundation/release → contracts/presentation}/progress-palette.generated.js +0 -0
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { OwnedUiSettingValue, OwnedUiSettingsChangeOutcome, OwnedUiSettingsEntry, OwnedSettingsManager } from "../../ui/settings/index.js";
|
|
2
|
+
type SettingsRecord = Record<string, boolean | string>;
|
|
3
|
+
/** The structured dialog an undo may need to roll back in place; null when none is open. */
|
|
4
|
+
export interface OpenStructuredRecord {
|
|
5
|
+
readonly entry: OwnedUiSettingsEntry;
|
|
6
|
+
readonly record: SettingsRecord;
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* The settings screen's edits: values shown ahead of the source, and an undo history ordered by edit
|
|
10
|
+
* sequence. Undo requests drain one at a time so each restores against the result of the one before.
|
|
11
|
+
*/
|
|
12
|
+
export declare class SettingsEdits {
|
|
13
|
+
#private;
|
|
14
|
+
constructor(session: Pick<OwnedSettingsManager, "change" | "changeStructured">, openStructured: () => OpenStructuredRecord | null);
|
|
15
|
+
/** The value a row shows: a pending edit, or the source's value. */
|
|
16
|
+
shown(entry: OwnedUiSettingsEntry): OwnedUiSettingValue | null;
|
|
17
|
+
apply(entry: OwnedUiSettingsEntry, value: OwnedUiSettingValue): void;
|
|
18
|
+
/** Saves a structured dialog's record; `rollback` runs when the change fails. */
|
|
19
|
+
saveStructured(entry: OwnedUiSettingsEntry, previous: Readonly<SettingsRecord>, forward: Readonly<SettingsRecord>, rollback: () => void): void;
|
|
20
|
+
undo(): void;
|
|
21
|
+
open(): void;
|
|
22
|
+
/** Drops the history and queued requests; late results no longer record undo steps. */
|
|
23
|
+
close(): void;
|
|
24
|
+
}
|
|
25
|
+
/** The record the engine stores: a choice part at its fallback is unset, so the engine's default applies. */
|
|
26
|
+
export declare function structuredValue(entry: OwnedUiSettingsEntry, record: Readonly<SettingsRecord>): SettingsRecord;
|
|
27
|
+
export declare function sameRecord(left: Readonly<SettingsRecord>, right: Readonly<SettingsRecord>): boolean;
|
|
28
|
+
export declare function replaceRecord(target: SettingsRecord, source: Readonly<SettingsRecord>): void;
|
|
29
|
+
/** Why a change did not take effect, or null when it did. */
|
|
30
|
+
export declare function changeFailure(outcome: OwnedUiSettingsChangeOutcome): string | null;
|
|
31
|
+
export {};
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The settings screen's edits: values shown ahead of the source, and an undo history ordered by edit
|
|
3
|
+
* sequence. Undo requests drain one at a time so each restores against the result of the one before.
|
|
4
|
+
*/
|
|
5
|
+
export class SettingsEdits {
|
|
6
|
+
#session;
|
|
7
|
+
#openStructured;
|
|
8
|
+
#pending = new Map();
|
|
9
|
+
#history = [];
|
|
10
|
+
#sequence = 0;
|
|
11
|
+
#requests = 0;
|
|
12
|
+
#active = false;
|
|
13
|
+
#closed = false;
|
|
14
|
+
constructor(session, openStructured) {
|
|
15
|
+
this.#session = session;
|
|
16
|
+
this.#openStructured = openStructured;
|
|
17
|
+
}
|
|
18
|
+
/** The value a row shows: a pending edit, or the source's value. */
|
|
19
|
+
shown(entry) {
|
|
20
|
+
return this.#pending.get(pendingKey(entry)) ?? entry.value;
|
|
21
|
+
}
|
|
22
|
+
apply(entry, value) {
|
|
23
|
+
const key = pendingKey(entry);
|
|
24
|
+
const previous = this.shown(entry);
|
|
25
|
+
const sequence = ++this.#sequence;
|
|
26
|
+
// Invariant: shown immediately so the row never lags a keypress, and so the next press
|
|
27
|
+
// steps from here rather than from a value the source has not caught up to.
|
|
28
|
+
this.#pending.set(key, value);
|
|
29
|
+
void this.#session.change(entry.backend, entry.id, value).then(outcome => {
|
|
30
|
+
const failed = changeFailure(outcome) !== null;
|
|
31
|
+
if (!failed && previous !== null && previous !== value)
|
|
32
|
+
this.#record({ kind: "scalar", sequence, entry, previous });
|
|
33
|
+
// Concurrency: a later press may have moved on; only the last request clears itself.
|
|
34
|
+
if (this.#pending.get(key) === value)
|
|
35
|
+
this.#pending.delete(key);
|
|
36
|
+
});
|
|
37
|
+
}
|
|
38
|
+
/** Saves a structured dialog's record; `rollback` runs when the change fails. */
|
|
39
|
+
saveStructured(entry, previous, forward, rollback) {
|
|
40
|
+
const sequence = ++this.#sequence;
|
|
41
|
+
void this.#session.changeStructured(entry.backend, entry.id, structuredValue(entry, forward)).then(outcome => {
|
|
42
|
+
if (changeFailure(outcome) === null)
|
|
43
|
+
this.#record({ kind: "structured", sequence, entry, previous, forward });
|
|
44
|
+
else
|
|
45
|
+
rollback();
|
|
46
|
+
});
|
|
47
|
+
}
|
|
48
|
+
undo() {
|
|
49
|
+
this.#requests++;
|
|
50
|
+
this.#drain();
|
|
51
|
+
}
|
|
52
|
+
open() { this.#closed = false; }
|
|
53
|
+
/** Drops the history and queued requests; late results no longer record undo steps. */
|
|
54
|
+
close() {
|
|
55
|
+
this.#closed = true;
|
|
56
|
+
this.#history.length = 0;
|
|
57
|
+
this.#requests = 0;
|
|
58
|
+
}
|
|
59
|
+
#record(record) {
|
|
60
|
+
if (this.#closed)
|
|
61
|
+
return;
|
|
62
|
+
const after = this.#history.findIndex(candidate => candidate.sequence > record.sequence);
|
|
63
|
+
if (after < 0)
|
|
64
|
+
this.#history.push(record);
|
|
65
|
+
else
|
|
66
|
+
this.#history.splice(after, 0, record);
|
|
67
|
+
}
|
|
68
|
+
#drain() {
|
|
69
|
+
if (this.#active || this.#requests === 0)
|
|
70
|
+
return;
|
|
71
|
+
const record = this.#history.pop();
|
|
72
|
+
if (record === undefined) {
|
|
73
|
+
this.#requests = 0;
|
|
74
|
+
return;
|
|
75
|
+
}
|
|
76
|
+
this.#requests--;
|
|
77
|
+
this.#active = true;
|
|
78
|
+
if (record.kind === "scalar") {
|
|
79
|
+
const key = pendingKey(record.entry);
|
|
80
|
+
this.#pending.set(key, record.previous);
|
|
81
|
+
void this.#session.change(record.entry.backend, record.entry.id, record.previous).then(outcome => {
|
|
82
|
+
if (this.#pending.get(key) === record.previous)
|
|
83
|
+
this.#pending.delete(key);
|
|
84
|
+
this.#finish(record, outcome);
|
|
85
|
+
});
|
|
86
|
+
return;
|
|
87
|
+
}
|
|
88
|
+
const open = this.#openStructured();
|
|
89
|
+
const target = open !== null && sameEntry(open.entry, record.entry) ? open : null;
|
|
90
|
+
if (target !== null)
|
|
91
|
+
replaceRecord(target.record, record.previous);
|
|
92
|
+
void this.#session.changeStructured(record.entry.backend, record.entry.id, structuredValue(record.entry, record.previous)).then(outcome => {
|
|
93
|
+
if (changeFailure(outcome) !== null && target !== null && this.#openStructured() === target && sameRecord(target.record, record.previous)) {
|
|
94
|
+
replaceRecord(target.record, record.forward);
|
|
95
|
+
}
|
|
96
|
+
this.#finish(record, outcome);
|
|
97
|
+
});
|
|
98
|
+
}
|
|
99
|
+
#finish(record, outcome) {
|
|
100
|
+
if (changeFailure(outcome) !== null)
|
|
101
|
+
this.#record(record);
|
|
102
|
+
this.#active = false;
|
|
103
|
+
this.#drain();
|
|
104
|
+
}
|
|
105
|
+
}
|
|
106
|
+
function pendingKey(entry) {
|
|
107
|
+
return `${entry.backend}:${entry.id}`;
|
|
108
|
+
}
|
|
109
|
+
/** The record the engine stores: a choice part at its fallback is unset, so the engine's default applies. */
|
|
110
|
+
export function structuredValue(entry, record) {
|
|
111
|
+
return Object.fromEntries(Object.entries(record).filter(([key, value]) => {
|
|
112
|
+
const part = entry.flags.find(candidate => candidate.key === key);
|
|
113
|
+
return part?.choices === undefined || value !== part.fallback;
|
|
114
|
+
}));
|
|
115
|
+
}
|
|
116
|
+
export function sameRecord(left, right) {
|
|
117
|
+
const leftEntries = Object.entries(left);
|
|
118
|
+
const rightEntries = Object.entries(right);
|
|
119
|
+
return leftEntries.length === rightEntries.length
|
|
120
|
+
&& leftEntries.every(([key, value]) => right[key] === value);
|
|
121
|
+
}
|
|
122
|
+
export function replaceRecord(target, source) {
|
|
123
|
+
for (const key of Object.keys(target))
|
|
124
|
+
delete target[key];
|
|
125
|
+
Object.assign(target, source);
|
|
126
|
+
}
|
|
127
|
+
/** Why a change did not take effect, or null when it did. */
|
|
128
|
+
export function changeFailure(outcome) {
|
|
129
|
+
if (outcome.failure !== null)
|
|
130
|
+
return outcome.failure;
|
|
131
|
+
if (outcome.status === "failed")
|
|
132
|
+
return "the effect failed";
|
|
133
|
+
if (outcome.status === "unavailable")
|
|
134
|
+
return outcome.limitationReason ?? "the setting is unavailable";
|
|
135
|
+
return outcome.limitationReason;
|
|
136
|
+
}
|
|
137
|
+
function sameEntry(left, right) {
|
|
138
|
+
return left.backend === right.backend && left.id === right.id;
|
|
139
|
+
}
|
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import type { DialogRow } from "../../ui/components/index.js";
|
|
2
|
+
import { LineInput, type PaneInputResult, type UiTheme } from "../../ui/components/index.js";
|
|
3
|
+
import type { OwnedSettingsManager, OwnedUiSettingsEntry } from "../../ui/settings/index.js";
|
|
4
|
+
/**
|
|
5
|
+
* A structured setting being edited: its parts, the row in hand, and their values. A part is a
|
|
6
|
+
* toggle when the declaration offers no choices, and a choice cycle otherwise; a choice part at its
|
|
7
|
+
* fallback is unset and leaves the record.
|
|
8
|
+
*/
|
|
9
|
+
export interface StructuredEdit {
|
|
10
|
+
readonly entry: OwnedUiSettingsEntry;
|
|
11
|
+
readonly flags: readonly string[];
|
|
12
|
+
readonly modelDialog: "thinking" | "default" | null;
|
|
13
|
+
/** Searchable flag dialog for owned tab-bar configuration. */
|
|
14
|
+
readonly filter: LineInput | null;
|
|
15
|
+
step: "model" | "level";
|
|
16
|
+
modelKey: string | null;
|
|
17
|
+
modelIndex: number;
|
|
18
|
+
index: number;
|
|
19
|
+
error: string | null;
|
|
20
|
+
readonly record: Record<string, boolean | string>;
|
|
21
|
+
}
|
|
22
|
+
/** What the model dialog asks of the settings screen that owns it. */
|
|
23
|
+
export interface ModelDialogActions {
|
|
24
|
+
readonly session: Pick<OwnedSettingsManager, "change">;
|
|
25
|
+
close(): void;
|
|
26
|
+
/** Show the dialog again, as after a failed save. */
|
|
27
|
+
reopen(open: StructuredEdit): void;
|
|
28
|
+
/** Save a changed record, rolling back if the source refuses it. */
|
|
29
|
+
save(open: StructuredEdit, previous: Readonly<Record<string, boolean | string>>, forward: Readonly<Record<string, boolean | string>>): void;
|
|
30
|
+
}
|
|
31
|
+
/**
|
|
32
|
+
* One key in the default-model selector or the two-step thinking-level dialog. `key` is the
|
|
33
|
+
* named key for `data`; typed text that names no shortcut edits the search.
|
|
34
|
+
*/
|
|
35
|
+
export declare function modelDialogKey(open: StructuredEdit, data: string, key: string, actions: ModelDialogActions): PaneInputResult;
|
|
36
|
+
export declare function modelDialogLines(open: StructuredEdit, width: number, height: number, theme: UiTheme): readonly string[];
|
|
37
|
+
/** The rows a dialog of `maximum` rows shows, centred on `index` where the list allows. */
|
|
38
|
+
export declare function dialogWindow(rows: readonly DialogRow[], index: number, maximum: number): {
|
|
39
|
+
readonly rows: readonly DialogRow[];
|
|
40
|
+
readonly index: number;
|
|
41
|
+
};
|
|
@@ -0,0 +1,194 @@
|
|
|
1
|
+
import { DIALOG_BACK_SHORTCUT_HINT, DIALOG_CLOSE_SHORTCUT_HINT } from "../../contracts/presentation/index.js";
|
|
2
|
+
import { LineInput, ShortcutRegistry, assertNoShortcutConflicts, configureDialogChoiceCapacity, configureDialogTextRows, handleLineInputKey, humanizeLabel, renderSteppedDialogPanel, } from "../../ui/components/index.js";
|
|
3
|
+
import { changeFailure, structuredValue } from "./settings-edits.js";
|
|
4
|
+
import { SETTINGS_APP_ID } from "./settings-route.js";
|
|
5
|
+
const MODEL_SCOPE = `${SETTINGS_APP_ID}-models`;
|
|
6
|
+
const MODEL_LEVEL_SCOPE = `${SETTINGS_APP_ID}-model-levels`;
|
|
7
|
+
const MODEL_SHORTCUTS = new ShortcutRegistry();
|
|
8
|
+
MODEL_SHORTCUTS.declare({ key: "edit", scope: MODEL_SCOPE, description: "Search models", section: "Choose", hint: { keys: "Type", does: "search" } }, "edit-filter");
|
|
9
|
+
MODEL_SHORTCUTS.declare({ key: "up", scope: MODEL_SCOPE, description: "Previous model", section: "Choose" }, "previous");
|
|
10
|
+
MODEL_SHORTCUTS.declare({ key: "down", scope: MODEL_SCOPE, description: "Next model", section: "Choose" }, "next");
|
|
11
|
+
MODEL_SHORTCUTS.declare({ key: "enter", scope: MODEL_SCOPE, description: "Select model", section: "Choose", hint: { keys: "Enter", does: "select" } }, "select");
|
|
12
|
+
MODEL_SHORTCUTS.declare({ key: "escape", scope: MODEL_SCOPE, description: "Close selector", section: "Choose", hint: { keys: DIALOG_CLOSE_SHORTCUT_HINT.key, does: DIALOG_CLOSE_SHORTCUT_HINT.action } }, "close");
|
|
13
|
+
MODEL_SHORTCUTS.declare({ key: "up", scope: MODEL_LEVEL_SCOPE, description: "Previous level", section: "Choose", hint: { keys: "↑↓", does: "navigate" } }, "previous");
|
|
14
|
+
MODEL_SHORTCUTS.declare({ key: "down", scope: MODEL_LEVEL_SCOPE, description: "Next level", section: "Choose", hint: { keys: "↑↓", does: "navigate" } }, "next");
|
|
15
|
+
MODEL_SHORTCUTS.declare({ key: "enter", scope: MODEL_LEVEL_SCOPE, description: "Select level", section: "Choose", hint: { keys: "Enter", does: "select" } }, "select");
|
|
16
|
+
MODEL_SHORTCUTS.declare({ key: "escape", scope: MODEL_LEVEL_SCOPE, description: "Return to models", section: "Choose", hint: { keys: DIALOG_BACK_SHORTCUT_HINT.key, does: DIALOG_BACK_SHORTCUT_HINT.action } }, "back");
|
|
17
|
+
assertNoShortcutConflicts(MODEL_SHORTCUTS.assemble());
|
|
18
|
+
/**
|
|
19
|
+
* One key in the default-model selector or the two-step thinking-level dialog. `key` is the
|
|
20
|
+
* named key for `data`; typed text that names no shortcut edits the search.
|
|
21
|
+
*/
|
|
22
|
+
export function modelDialogKey(open, data, key, actions) {
|
|
23
|
+
if (open.modelDialog === "default" || open.step === "model") {
|
|
24
|
+
const flags = filteredModelFlags(open);
|
|
25
|
+
const action = MODEL_SHORTCUTS.resolve(key, MODEL_SCOPE) ?? "edit-filter";
|
|
26
|
+
if (action === "close") {
|
|
27
|
+
actions.close();
|
|
28
|
+
return { consumed: true };
|
|
29
|
+
}
|
|
30
|
+
if (action === "previous" || action === "next") {
|
|
31
|
+
open.index = Math.min(Math.max(0, flags.length - 1), Math.max(0, open.index + (action === "next" ? 1 : -1)));
|
|
32
|
+
return { consumed: true };
|
|
33
|
+
}
|
|
34
|
+
if (action === "select") {
|
|
35
|
+
const selected = flags[open.index];
|
|
36
|
+
if (selected === undefined)
|
|
37
|
+
return { consumed: true, render: false };
|
|
38
|
+
if (open.modelDialog === "default")
|
|
39
|
+
selectDefaultModel(open, selected.key, actions);
|
|
40
|
+
else {
|
|
41
|
+
open.modelIndex = open.index;
|
|
42
|
+
open.modelKey = selected.key;
|
|
43
|
+
open.step = "level";
|
|
44
|
+
const options = modelLevelOptions(open, selected);
|
|
45
|
+
const current = structuredValue(open.entry, open.record)[selected.key];
|
|
46
|
+
open.index = Math.max(0, options.findIndex(option => option.value === current));
|
|
47
|
+
}
|
|
48
|
+
return { consumed: true };
|
|
49
|
+
}
|
|
50
|
+
if (open.filter === null)
|
|
51
|
+
return { consumed: true, render: false };
|
|
52
|
+
handleLineInputKey(open.filter, data);
|
|
53
|
+
open.index = 0;
|
|
54
|
+
return { consumed: true };
|
|
55
|
+
}
|
|
56
|
+
const selected = open.entry.flags.find(flag => flag.key === open.modelKey);
|
|
57
|
+
const choices = selected === undefined ? [] : modelLevelOptions(open, selected);
|
|
58
|
+
const action = MODEL_SHORTCUTS.resolve(key, MODEL_LEVEL_SCOPE);
|
|
59
|
+
if (action === "back") {
|
|
60
|
+
returnToModels(open);
|
|
61
|
+
return { consumed: true };
|
|
62
|
+
}
|
|
63
|
+
if (action === "previous" || action === "next") {
|
|
64
|
+
open.index = Math.min(Math.max(0, choices.length - 1), Math.max(0, open.index + (action === "next" ? 1 : -1)));
|
|
65
|
+
return { consumed: true };
|
|
66
|
+
}
|
|
67
|
+
if (action === "select") {
|
|
68
|
+
const choice = choices[open.index];
|
|
69
|
+
if (selected === undefined || choice === undefined)
|
|
70
|
+
return { consumed: true, render: false };
|
|
71
|
+
const previous = { ...open.record };
|
|
72
|
+
open.record[selected.key] = choice.value;
|
|
73
|
+
const forward = { ...open.record };
|
|
74
|
+
actions.save(open, previous, forward);
|
|
75
|
+
returnToModels(open);
|
|
76
|
+
return { consumed: true };
|
|
77
|
+
}
|
|
78
|
+
return { consumed: true, render: false };
|
|
79
|
+
}
|
|
80
|
+
export function modelDialogLines(open, width, height, theme) {
|
|
81
|
+
if (open.modelDialog === "default") {
|
|
82
|
+
const flags = filteredModelFlags(open);
|
|
83
|
+
const current = typeof open.entry.rawValue === "string" ? open.entry.rawValue : null;
|
|
84
|
+
const rows = flags.length === 0
|
|
85
|
+
? [{ label: "No models found", value: "" }]
|
|
86
|
+
: flags.map(flag => ({
|
|
87
|
+
...modelLabelParts(flag.label ?? humanizeLabel(flag.key)),
|
|
88
|
+
...(flag.key === current ? { successSuffix: "✓" } : {}),
|
|
89
|
+
value: "",
|
|
90
|
+
}));
|
|
91
|
+
const description = open.error ?? "Select the model used for new sessions";
|
|
92
|
+
const visible = dialogWindow(rows, open.index, configureDialogChoiceCapacity(height, true, configureDialogTextRows(description, width)));
|
|
93
|
+
return renderSteppedDialogPanel({
|
|
94
|
+
title: "Default Model", description, input: open.filter ?? new LineInput(""),
|
|
95
|
+
rows: visible.rows, index: visible.index, hint: MODEL_SHORTCUTS.hintEntries(MODEL_SCOPE),
|
|
96
|
+
}, width, theme);
|
|
97
|
+
}
|
|
98
|
+
if (open.step === "model") {
|
|
99
|
+
const flags = filteredModelFlags(open);
|
|
100
|
+
const stored = structuredValue(open.entry, open.record);
|
|
101
|
+
const allRows = flags.length === 0
|
|
102
|
+
? [{ label: "No models found", value: "" }]
|
|
103
|
+
: flags.map(flag => ({
|
|
104
|
+
...modelLabelParts(flag.label ?? humanizeLabel(flag.key)),
|
|
105
|
+
value: stored[flag.key] === undefined ? "" : String(stored[flag.key]),
|
|
106
|
+
}));
|
|
107
|
+
const description = "Select a model to configure";
|
|
108
|
+
const visible = dialogWindow(allRows, open.index, configureDialogChoiceCapacity(height, true, configureDialogTextRows(description, width)));
|
|
109
|
+
return renderSteppedDialogPanel({
|
|
110
|
+
title: "Thinking Level",
|
|
111
|
+
step: 1,
|
|
112
|
+
steps: 2,
|
|
113
|
+
description,
|
|
114
|
+
...(open.filter === null ? {} : { input: open.filter }),
|
|
115
|
+
rows: visible.rows,
|
|
116
|
+
index: visible.index,
|
|
117
|
+
hint: MODEL_SHORTCUTS.hintEntries(MODEL_SCOPE),
|
|
118
|
+
}, width, theme);
|
|
119
|
+
}
|
|
120
|
+
const selected = open.entry.flags.find(flag => flag.key === open.modelKey);
|
|
121
|
+
const current = selected === undefined ? undefined : structuredValue(open.entry, open.record)[selected.key];
|
|
122
|
+
const allRows = (selected === undefined ? [] : modelLevelOptions(open, selected)).map(choice => ({
|
|
123
|
+
label: choice.value === current ? `✓ ${choice.label}` : choice.label,
|
|
124
|
+
value: choice.description,
|
|
125
|
+
}));
|
|
126
|
+
const description = `Select default thinking level for ${selected?.label ?? open.modelKey ?? "model"}`;
|
|
127
|
+
const visible = dialogWindow(allRows, open.index, configureDialogChoiceCapacity(height, false, configureDialogTextRows(description, width)));
|
|
128
|
+
return renderSteppedDialogPanel({
|
|
129
|
+
title: "Thinking Level",
|
|
130
|
+
step: 2,
|
|
131
|
+
steps: 2,
|
|
132
|
+
description,
|
|
133
|
+
rows: visible.rows,
|
|
134
|
+
index: visible.index,
|
|
135
|
+
hint: MODEL_SHORTCUTS.hintEntries(MODEL_LEVEL_SCOPE),
|
|
136
|
+
}, width, theme);
|
|
137
|
+
}
|
|
138
|
+
/** The rows a dialog of `maximum` rows shows, centred on `index` where the list allows. */
|
|
139
|
+
export function dialogWindow(rows, index, maximum) {
|
|
140
|
+
if (rows.length <= maximum)
|
|
141
|
+
return { rows, index: Math.min(Math.max(0, rows.length - 1), Math.max(0, index)) };
|
|
142
|
+
const start = Math.min(rows.length - maximum, Math.max(0, index - Math.floor(maximum / 2)));
|
|
143
|
+
return { rows: rows.slice(start, start + maximum), index: index - start };
|
|
144
|
+
}
|
|
145
|
+
// Concurrency: the dialog closes at once; a refused save reopens it with the reason.
|
|
146
|
+
function selectDefaultModel(open, model, actions) {
|
|
147
|
+
open.error = null;
|
|
148
|
+
actions.close();
|
|
149
|
+
void actions.session.change(open.entry.backend, open.entry.id, model).then(outcome => {
|
|
150
|
+
const failure = changeFailure(outcome);
|
|
151
|
+
if (failure !== null) {
|
|
152
|
+
open.error = `Could not save: ${failure}`;
|
|
153
|
+
actions.reopen(open);
|
|
154
|
+
}
|
|
155
|
+
});
|
|
156
|
+
}
|
|
157
|
+
function returnToModels(open) {
|
|
158
|
+
open.step = "model";
|
|
159
|
+
open.modelKey = null;
|
|
160
|
+
open.index = open.modelIndex;
|
|
161
|
+
}
|
|
162
|
+
function filteredModelFlags(open) {
|
|
163
|
+
const needle = open.filter?.value.trim().toLowerCase() ?? "";
|
|
164
|
+
return open.entry.flags.filter(flag => needle.length === 0
|
|
165
|
+
|| (flag.label ?? humanizeLabel(flag.key)).toLowerCase().includes(needle)
|
|
166
|
+
|| flag.description.toLowerCase().includes(needle)
|
|
167
|
+
|| flag.key.toLowerCase().includes(needle));
|
|
168
|
+
}
|
|
169
|
+
function modelLevelOptions(open, selected) {
|
|
170
|
+
const fallback = String(selected.fallback);
|
|
171
|
+
const supported = (selected.choices ?? [])
|
|
172
|
+
.filter(choice => choice !== fallback)
|
|
173
|
+
.map(choice => ({ value: choice, label: choice, description: thinkingLevelDescription(choice) }));
|
|
174
|
+
return structuredValue(open.entry, open.record)[selected.key] === undefined
|
|
175
|
+
? supported
|
|
176
|
+
: [...supported, { value: fallback, label: "(clear override)", description: "Revert to global default" }];
|
|
177
|
+
}
|
|
178
|
+
function modelLabelParts(label) {
|
|
179
|
+
const match = /^(.*?)(\s+\[[^\]]+\])$/u.exec(label);
|
|
180
|
+
return match === null ? { label } : { label: match[1] ?? label, labelSuffix: match[2] ?? "" };
|
|
181
|
+
}
|
|
182
|
+
function thinkingLevelDescription(level) {
|
|
183
|
+
switch (level) {
|
|
184
|
+
case "default": return "global default";
|
|
185
|
+
case "off": return "No reasoning";
|
|
186
|
+
case "minimal": return "Very brief reasoning (~1k tokens)";
|
|
187
|
+
case "low": return "Light reasoning (~2k tokens)";
|
|
188
|
+
case "medium": return "Moderate reasoning (~8k tokens)";
|
|
189
|
+
case "high": return "Deep reasoning (~16k tokens)";
|
|
190
|
+
case "xhigh": return "Extra-high reasoning (~32k tokens)";
|
|
191
|
+
case "max": return "Maximum reasoning";
|
|
192
|
+
default: return "";
|
|
193
|
+
}
|
|
194
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { type PaneMouseEvent, type RailPosition, type ScrollbarGeometry, type ScrollbarPresentation, type ScrollbarPresentationInput } from "../../ui/components/index.js";
|
|
2
|
+
/** Where the rail was painted in the last frame, with the list page it scrolls by. */
|
|
3
|
+
export interface SettingsRailFrame {
|
|
4
|
+
readonly rail: RailPosition;
|
|
5
|
+
readonly geometry: ScrollbarGeometry;
|
|
6
|
+
readonly page: number;
|
|
7
|
+
}
|
|
8
|
+
/** How a pointer report landed on the rail: owned keeps it from the list, and `scroll` is the list's new offset. */
|
|
9
|
+
export interface SettingsRailPointer {
|
|
10
|
+
readonly owned: boolean;
|
|
11
|
+
readonly changed: boolean;
|
|
12
|
+
readonly overRail: boolean;
|
|
13
|
+
readonly scroll?: number;
|
|
14
|
+
}
|
|
15
|
+
/** The settings list's scrollbar rail: hover, thumb drag, track paging, and the lingering highlight after a scroll. */
|
|
16
|
+
export declare class SettingsScrollRail {
|
|
17
|
+
#private;
|
|
18
|
+
/** Notes the frame's scroll; a moved list keeps the rail lit and repaints once the highlight lapses. */
|
|
19
|
+
noteRenderedScroll(scroll: number, now: number, requestRender: () => void): void;
|
|
20
|
+
presentation(input: Omit<ScrollbarPresentationInput, "hovered" | "dragging" | "activeUntil">): ScrollbarPresentation;
|
|
21
|
+
/** Records where the rail was painted, or null when this frame has no rail. */
|
|
22
|
+
setFrame(frame: Omit<SettingsRailFrame, "rail"> & {
|
|
23
|
+
readonly rail: Omit<RailPosition, "key">;
|
|
24
|
+
} | null): void;
|
|
25
|
+
pointer(event: PaneMouseEvent, scroll: number): SettingsRailPointer;
|
|
26
|
+
/** Drops hover and any drag, as when a dialog takes the screen. */
|
|
27
|
+
clear(): void;
|
|
28
|
+
dispose(): void;
|
|
29
|
+
}
|
|
@@ -0,0 +1,79 @@
|
|
|
1
|
+
import { scrollForTrackPage, scrollbarPresentation, ScrollbarRails, } from "../../ui/components/index.js";
|
|
2
|
+
/** Identity of the settings list rail in the shared rail state. */
|
|
3
|
+
const RAIL_KEY = "settings";
|
|
4
|
+
// Compatibility: the transcript rail stays lit this long after a scroll, and repaints just after.
|
|
5
|
+
const SCROLL_LINGER_MS = 900;
|
|
6
|
+
const SCROLL_LINGER_REPAINT_MS = 925;
|
|
7
|
+
/** The settings list's scrollbar rail: hover, thumb drag, track paging, and the lingering highlight after a scroll. */
|
|
8
|
+
export class SettingsScrollRail {
|
|
9
|
+
#rails = new ScrollbarRails();
|
|
10
|
+
#frame = null;
|
|
11
|
+
#activeUntil = 0;
|
|
12
|
+
#activityTimer;
|
|
13
|
+
#renderedScroll;
|
|
14
|
+
/** Notes the frame's scroll; a moved list keeps the rail lit and repaints once the highlight lapses. */
|
|
15
|
+
noteRenderedScroll(scroll, now, requestRender) {
|
|
16
|
+
// Rationale: every way of scrolling ends in this frame, so a moved list is noticed here
|
|
17
|
+
// once rather than at each wheel, drag, key, and search branch.
|
|
18
|
+
if (this.#renderedScroll !== undefined && this.#renderedScroll !== scroll) {
|
|
19
|
+
this.#activeUntil = Math.max(this.#activeUntil, now + SCROLL_LINGER_MS);
|
|
20
|
+
this.#clearTimer();
|
|
21
|
+
this.#activityTimer = setTimeout(() => {
|
|
22
|
+
this.#activityTimer = undefined;
|
|
23
|
+
requestRender();
|
|
24
|
+
}, SCROLL_LINGER_REPAINT_MS);
|
|
25
|
+
this.#activityTimer.unref?.();
|
|
26
|
+
}
|
|
27
|
+
this.#renderedScroll = scroll;
|
|
28
|
+
}
|
|
29
|
+
presentation(input) {
|
|
30
|
+
return scrollbarPresentation({
|
|
31
|
+
...input,
|
|
32
|
+
hovered: this.#rails.isHovered(RAIL_KEY),
|
|
33
|
+
dragging: this.#rails.isDragging(RAIL_KEY),
|
|
34
|
+
activeUntil: this.#activeUntil,
|
|
35
|
+
});
|
|
36
|
+
}
|
|
37
|
+
/** Records where the rail was painted, or null when this frame has no rail. */
|
|
38
|
+
setFrame(frame) {
|
|
39
|
+
this.#frame = frame === null ? null : { ...frame, rail: { ...frame.rail, key: RAIL_KEY } };
|
|
40
|
+
}
|
|
41
|
+
// Rationale: the rail takes its share of a pointer report first: hover, a thumb drag, or a
|
|
42
|
+
// track page. Owned means the list must not see the report; changed means the rail looks different.
|
|
43
|
+
pointer(event, scroll) {
|
|
44
|
+
const frame = this.#frame;
|
|
45
|
+
const wasHovered = this.#rails.isHovered(RAIL_KEY);
|
|
46
|
+
if (frame === null) {
|
|
47
|
+
this.#rails.clear();
|
|
48
|
+
return { owned: false, changed: wasHovered, overRail: false };
|
|
49
|
+
}
|
|
50
|
+
const pointer = { column: event.column, row: event.row - 1 };
|
|
51
|
+
if (this.#rails.isDragging(RAIL_KEY)) {
|
|
52
|
+
// Invariant: a drag keeps the pointer wherever it goes until the button comes up.
|
|
53
|
+
if (event.kind === "release") {
|
|
54
|
+
this.#rails.endDrag();
|
|
55
|
+
return { owned: true, changed: true, overRail: false };
|
|
56
|
+
}
|
|
57
|
+
const target = this.#rails.dragTo(frame.rail, frame.geometry, pointer);
|
|
58
|
+
return target === null ? { owned: true, changed: true, overRail: false } : { owned: true, changed: true, overRail: false, scroll: target };
|
|
59
|
+
}
|
|
60
|
+
const over = this.#rails.notePointer([frame.rail], pointer) !== null;
|
|
61
|
+
if (!over)
|
|
62
|
+
return { owned: false, changed: wasHovered, overRail: false };
|
|
63
|
+
if (event.kind === "press" && !this.#rails.beginDrag(frame.rail, frame.geometry, pointer)) {
|
|
64
|
+
return { owned: true, changed: true, overRail: true, scroll: scrollForTrackPage(frame.geometry, pointer.row - frame.rail.rowStart, scroll, frame.page) };
|
|
65
|
+
}
|
|
66
|
+
return { owned: true, changed: true, overRail: true };
|
|
67
|
+
}
|
|
68
|
+
/** Drops hover and any drag, as when a dialog takes the screen. */
|
|
69
|
+
clear() { this.#rails.clear(); }
|
|
70
|
+
dispose() {
|
|
71
|
+
this.#clearTimer();
|
|
72
|
+
this.#rails.clear();
|
|
73
|
+
}
|
|
74
|
+
#clearTimer() {
|
|
75
|
+
if (this.#activityTimer !== undefined)
|
|
76
|
+
clearTimeout(this.#activityTimer);
|
|
77
|
+
this.#activityTimer = undefined;
|
|
78
|
+
}
|
|
79
|
+
}
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { UiTheme } from "../../ui/components/index.js";
|
|
2
|
-
|
|
2
|
+
interface SettingsSearchPointerEvent {
|
|
3
3
|
readonly kind: "press" | "motion" | "release";
|
|
4
4
|
readonly button: number;
|
|
5
5
|
readonly column: number;
|
|
@@ -27,3 +27,4 @@ export interface SettingsSearchInputFactory {
|
|
|
27
27
|
create(options: SettingsSearchInputOptions): SettingsSearchInput;
|
|
28
28
|
isTextInput(data: string): boolean;
|
|
29
29
|
}
|
|
30
|
+
export {};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import type { Worker } from "node:worker_threads";
|
|
2
2
|
import { type PromptHistoryFailure, type PromptHistoryPort, type PromptHistoryResult, type PromptHistorySnapshot, type PromptHistorySubmission } from "../../contracts/owned-ui/index.js";
|
|
3
3
|
import { type PromptHistoryScope } from "./paths.js";
|
|
4
|
-
|
|
5
|
-
|
|
4
|
+
type HistoryRecoveryState = "starting" | "ready" | "recovering" | "blocked-storage" | "closing" | "closed";
|
|
5
|
+
interface HistoryClock {
|
|
6
6
|
now(): number;
|
|
7
7
|
setTimeout(callback: () => void, milliseconds: number): ReturnType<typeof setTimeout>;
|
|
8
8
|
clearTimeout(timer: ReturnType<typeof setTimeout> | undefined): void;
|
|
@@ -57,3 +57,4 @@ export declare class PromptHistoryService implements PromptHistoryPort {
|
|
|
57
57
|
onFailure(listener: (code: PromptHistoryFailure) => void): () => void;
|
|
58
58
|
close(): Promise<void>;
|
|
59
59
|
}
|
|
60
|
+
export {};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
|
|
1
|
+
interface ClaimGateHandle {
|
|
2
2
|
release(): void;
|
|
3
3
|
}
|
|
4
4
|
/**
|
|
@@ -6,3 +6,4 @@ export interface ClaimGateHandle {
|
|
|
6
6
|
* file; contention returns null so the caller keeps its own bounded retry.
|
|
7
7
|
*/
|
|
8
8
|
export declare function tryAcquireClaimGate(path: string): ClaimGateHandle | null;
|
|
9
|
+
export {};
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
import { type AvailableRelease, type ReleaseChannel } from "./latest-release.js";
|
|
2
|
-
|
|
3
|
-
export declare const AUTOMATIC_UPDATE_RETRY_MS: number;
|
|
4
|
-
export declare const ACTIVE_RELEASE_FALLBACK_MS = 5000;
|
|
2
|
+
declare const AUTOMATIC_UPDATE_STATE_SCHEMA = 1;
|
|
5
3
|
export interface AutomaticUpdateState {
|
|
6
4
|
readonly schema: typeof AUTOMATIC_UPDATE_STATE_SCHEMA;
|
|
7
5
|
readonly channel: ReleaseChannel;
|
|
@@ -12,24 +10,16 @@ export interface AutomaticUpdateState {
|
|
|
12
10
|
readonly installedVersion: string | null;
|
|
13
11
|
readonly failure: string | null;
|
|
14
12
|
}
|
|
15
|
-
|
|
16
|
-
readonly path: string;
|
|
17
|
-
constructor(dataDir: string);
|
|
18
|
-
read(): Promise<AutomaticUpdateState | null>;
|
|
19
|
-
write(value: AutomaticUpdateState): Promise<void>;
|
|
20
|
-
}
|
|
21
|
-
export interface ActiveReleaseObservationOptions {
|
|
13
|
+
interface ActiveReleaseObservationOptions {
|
|
22
14
|
readonly runningVersion: string;
|
|
23
15
|
readonly environment?: NodeJS.ProcessEnv;
|
|
24
16
|
readonly signal?: AbortSignal;
|
|
25
17
|
readonly onNewer: (version: string) => void;
|
|
26
18
|
readonly fallbackMs?: number;
|
|
27
19
|
}
|
|
28
|
-
/** Read the approved active release only when this process executes an older release on that channel. */
|
|
29
|
-
export declare function readNewerActiveRelease(runningVersion: string, environment?: NodeJS.ProcessEnv): Promise<string | null>;
|
|
30
20
|
/** Observe local release activation promptly, with a bounded fallback for missed filesystem events. */
|
|
31
21
|
export declare function observeNewerActiveRelease(options: ActiveReleaseObservationOptions): () => void;
|
|
32
|
-
|
|
22
|
+
interface AutomaticUpdateRequestOptions {
|
|
33
23
|
readonly release: AvailableRelease;
|
|
34
24
|
readonly runningVersion: string;
|
|
35
25
|
readonly environment?: NodeJS.ProcessEnv;
|
|
@@ -37,7 +27,7 @@ export interface AutomaticUpdateRequestOptions {
|
|
|
37
27
|
readonly now?: () => number;
|
|
38
28
|
readonly spawnWorker?: (entry: string, arguments_: readonly string[], environment: NodeJS.ProcessEnv) => Promise<void>;
|
|
39
29
|
readonly sleep?: (durationMs: number) => Promise<void>;
|
|
40
|
-
/** Focused-test seams; production resolves both from the certified launch
|
|
30
|
+
/** Focused-test seams; production resolves both from the certified launch release. */
|
|
41
31
|
readonly worker?: {
|
|
42
32
|
readonly entry: string;
|
|
43
33
|
readonly packageRoot: string;
|
|
@@ -47,3 +37,4 @@ export interface AutomaticUpdateRequestOptions {
|
|
|
47
37
|
/** Start or observe one silent update and resolve with the active newer version once restart is useful. */
|
|
48
38
|
export declare function requestAutomaticUpdate(options: AutomaticUpdateRequestOptions): Promise<string | null>;
|
|
49
39
|
export declare function runAutomaticUpdateWorker(argv: readonly string[], environment?: NodeJS.ProcessEnv): Promise<number>;
|
|
40
|
+
export {};
|