@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
|
@@ -1,6 +1,9 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { GLOBAL_SCOPE, LineInput, PLAIN_THEME, ShortcutRegistry, assertNoShortcutConflicts, blockJumpTarget, configureDialogChoiceCapacity, configureDialogTextRows, configureDialogWidth, numericValues, RAIL_COLUMNS, renderCenteredDialogOverlay, renderDialogPanel,
|
|
1
|
+
import { DIALOG_CLOSE_SHORTCUT_HINT } from "../../contracts/presentation/index.js";
|
|
2
|
+
import { GLOBAL_SCOPE, LineInput, PLAIN_THEME, ShortcutRegistry, assertNoShortcutConflicts, blockJumpTarget, configureDialogChoiceCapacity, configureDialogTextRows, configureDialogWidth, numericValues, RAIL_COLUMNS, renderCenteredDialogOverlay, renderDialogPanel, renderEmptyState, renderGroupHeader, renderListRow, renderNote, renderShortcutHintsWithClose, menuRowAt, regionAt, renderValueMenu, withScrollbarRail, stepperEnds, steppedValue, truncateToWidth, valueColumnFor, valueMenuFrame, blockRowSpan, displayWidth, humanizeLabel, humanizeTitle, indexOfKey, layoutList, moveSelection, rowKey, scrollForSelection, scrollbarGeometry, scrollbarWheelRows, selectableIndexes, } from "../../ui/components/index.js";
|
|
3
|
+
import { SettingsScrollRail } from "./settings-scroll-rail.js";
|
|
4
|
+
import { SettingsEdits, replaceRecord, sameRecord } from "./settings-edits.js";
|
|
3
5
|
import { SETTINGS_APP_ID } from "./settings-route.js";
|
|
6
|
+
import { dialogWindow, modelDialogKey, modelDialogLines } from "./settings-model-dialog.js";
|
|
4
7
|
export { SETTINGS_APP_ID, SETTINGS_ROUTE } from "./settings-route.js";
|
|
5
8
|
const SCOPE = SETTINGS_APP_ID;
|
|
6
9
|
const SETTINGS_TOP_RULE_ROWS = 1;
|
|
@@ -11,14 +14,7 @@ const SETTINGS_STATUS_ROWS = 1;
|
|
|
11
14
|
const SETTINGS_CONTENT_INSET = 1;
|
|
12
15
|
/** The panel a setting with parts opens: its own keys, its own hint. */
|
|
13
16
|
const DIALOG_SCOPE = `${SETTINGS_APP_ID}-parts`;
|
|
14
|
-
const MODEL_SCOPE = `${SETTINGS_APP_ID}-models`;
|
|
15
|
-
const MODEL_LEVEL_SCOPE = `${SETTINGS_APP_ID}-model-levels`;
|
|
16
17
|
const SCROLLBAR_TOP_INSET = 0;
|
|
17
|
-
/** Identity of the settings list rail in the shared rail state. */
|
|
18
|
-
const RAIL_KEY = "settings";
|
|
19
|
-
// Compatibility: the transcript rail stays lit this long after a scroll, and repaints just after.
|
|
20
|
-
const SCROLL_LINGER_MS = 900;
|
|
21
|
-
const SCROLL_LINGER_REPAINT_MS = 925;
|
|
22
18
|
/** What a structured value offers instead of printing itself. */
|
|
23
19
|
const CONFIGURE = "configure";
|
|
24
20
|
export const SETTINGS_SHORTCUTS = new ShortcutRegistry();
|
|
@@ -48,17 +44,6 @@ SETTINGS_SHORTCUTS.declare({
|
|
|
48
44
|
hint: { keys: DIALOG_CLOSE_SHORTCUT_HINT.key, does: DIALOG_CLOSE_SHORTCUT_HINT.action },
|
|
49
45
|
}, "close");
|
|
50
46
|
assertNoShortcutConflicts(SETTINGS_SHORTCUTS.assemble());
|
|
51
|
-
const MODEL_SHORTCUTS = new ShortcutRegistry();
|
|
52
|
-
MODEL_SHORTCUTS.declare({ key: "edit", scope: MODEL_SCOPE, description: "Search models", section: "Choose", hint: { keys: "Type", does: "search" } }, "edit-filter");
|
|
53
|
-
MODEL_SHORTCUTS.declare({ key: "up", scope: MODEL_SCOPE, description: "Previous model", section: "Choose" }, "previous");
|
|
54
|
-
MODEL_SHORTCUTS.declare({ key: "down", scope: MODEL_SCOPE, description: "Next model", section: "Choose" }, "next");
|
|
55
|
-
MODEL_SHORTCUTS.declare({ key: "enter", scope: MODEL_SCOPE, description: "Select model", section: "Choose", hint: { keys: "Enter", does: "select" } }, "select");
|
|
56
|
-
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");
|
|
57
|
-
MODEL_SHORTCUTS.declare({ key: "up", scope: MODEL_LEVEL_SCOPE, description: "Previous level", section: "Choose", hint: { keys: "↑↓", does: "navigate" } }, "previous");
|
|
58
|
-
MODEL_SHORTCUTS.declare({ key: "down", scope: MODEL_LEVEL_SCOPE, description: "Next level", section: "Choose", hint: { keys: "↑↓", does: "navigate" } }, "next");
|
|
59
|
-
MODEL_SHORTCUTS.declare({ key: "enter", scope: MODEL_LEVEL_SCOPE, description: "Select level", section: "Choose", hint: { keys: "Enter", does: "select" } }, "select");
|
|
60
|
-
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");
|
|
61
|
-
assertNoShortcutConflicts(MODEL_SHORTCUTS.assemble());
|
|
62
47
|
const KEYS = {
|
|
63
48
|
"\u001b[A": "up",
|
|
64
49
|
"\u001b[B": "down",
|
|
@@ -96,12 +81,7 @@ export class SettingsApp {
|
|
|
96
81
|
#menu = null;
|
|
97
82
|
#structured = null;
|
|
98
83
|
// Invariant: pending values remain visible until the source reflects them.
|
|
99
|
-
#
|
|
100
|
-
#undoHistory = [];
|
|
101
|
-
#editSequence = 0;
|
|
102
|
-
#undoRequests = 0;
|
|
103
|
-
#undoActive = false;
|
|
104
|
-
#closed = false;
|
|
84
|
+
#edits;
|
|
105
85
|
#bodyTopForFrame = SETTINGS_TOP_RULE_ROWS + SETTINGS_TITLE_ROWS;
|
|
106
86
|
#bodyHeightForFrame = 0;
|
|
107
87
|
#panelTopForFrame = 0;
|
|
@@ -110,16 +90,12 @@ export class SettingsApp {
|
|
|
110
90
|
#frameRows = [];
|
|
111
91
|
#menuFrame = null;
|
|
112
92
|
// Invariant: rail hover and drag live in the shared keyed state, as the transcript's do.
|
|
113
|
-
#
|
|
93
|
+
#rail = new SettingsScrollRail();
|
|
114
94
|
// Rationale: the rail as drawn in the last frame, or null when nothing can be pointed at.
|
|
115
|
-
#railFrame = null;
|
|
116
|
-
// Invariant: a scroll lights the rail until this time; the timer repaints once it has passed.
|
|
117
|
-
#activeUntil = 0;
|
|
118
|
-
#activityTimer;
|
|
119
|
-
#renderedScroll;
|
|
120
95
|
#options;
|
|
121
96
|
constructor(session, options) {
|
|
122
97
|
this.#session = session;
|
|
98
|
+
this.#edits = new SettingsEdits(session, () => this.#structured);
|
|
123
99
|
this.#options = {
|
|
124
100
|
dialogPanel: options.dialogPanel ?? null,
|
|
125
101
|
};
|
|
@@ -131,17 +107,14 @@ export class SettingsApp {
|
|
|
131
107
|
};
|
|
132
108
|
}
|
|
133
109
|
onActivate(host) {
|
|
134
|
-
this.#
|
|
110
|
+
this.#edits.open();
|
|
135
111
|
void this.#session.load().then(() => host.requestRender());
|
|
136
112
|
}
|
|
137
113
|
onClose(_host) {
|
|
138
|
-
this.#
|
|
139
|
-
this.#undoHistory.length = 0;
|
|
140
|
-
this.#undoRequests = 0;
|
|
114
|
+
this.#edits.close();
|
|
141
115
|
this.#search.input?.setFocused(false);
|
|
142
116
|
this.#search.input = null;
|
|
143
|
-
this.#
|
|
144
|
-
this.#rails.clear();
|
|
117
|
+
this.#rail.dispose();
|
|
145
118
|
}
|
|
146
119
|
render(rect, host) {
|
|
147
120
|
const theme = host.theme ?? PLAIN_THEME;
|
|
@@ -174,11 +147,7 @@ export class SettingsApp {
|
|
|
174
147
|
this.#panelTopForFrame = topRows + contentHeight + dividerRows;
|
|
175
148
|
this.#scroll = layout.scroll;
|
|
176
149
|
const now = Date.now();
|
|
177
|
-
|
|
178
|
-
// once rather than at each wheel, drag, key, and search branch.
|
|
179
|
-
if (this.#renderedScroll !== undefined && this.#renderedScroll !== layout.scroll)
|
|
180
|
-
this.#noteScrollActivity(host, now);
|
|
181
|
-
this.#renderedScroll = layout.scroll;
|
|
150
|
+
this.#rail.noteRenderedScroll(layout.scroll, now, () => host.requestRender());
|
|
182
151
|
// Invariant: auto and always keep the rail columns while the list fits, so a revealed
|
|
183
152
|
// rail never reflows the rows; hidden gives the columns back to the rows.
|
|
184
153
|
const appearance = this.#scrollbarAppearance();
|
|
@@ -191,22 +160,10 @@ export class SettingsApp {
|
|
|
191
160
|
scroll: layout.scroll,
|
|
192
161
|
trackHeight: Math.max(0, titleRows + bodyHeight - SCROLLBAR_TOP_INSET),
|
|
193
162
|
});
|
|
194
|
-
const presentation =
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
hovered: this.#rails.isHovered(RAIL_KEY),
|
|
199
|
-
dragging: this.#rails.isDragging(RAIL_KEY),
|
|
200
|
-
activeUntil: this.#activeUntil,
|
|
201
|
-
now,
|
|
202
|
-
});
|
|
203
|
-
this.#railFrame = reservesRail && geometry !== null
|
|
204
|
-
? {
|
|
205
|
-
rail: { key: RAIL_KEY, column: rect.width, rowStart: topRows + SCROLLBAR_TOP_INSET, trackHeight: geometry.trackHeight },
|
|
206
|
-
geometry,
|
|
207
|
-
page: layout.visible,
|
|
208
|
-
}
|
|
209
|
-
: null;
|
|
163
|
+
const presentation = this.#rail.presentation({ geometry, appearance, style: this.#scrollbarStyle(), now });
|
|
164
|
+
this.#rail.setFrame(reservesRail && geometry !== null
|
|
165
|
+
? { rail: { column: rect.width, rowStart: topRows + SCROLLBAR_TOP_INSET, trackHeight: geometry.trackHeight }, geometry, page: layout.visible }
|
|
166
|
+
: null);
|
|
210
167
|
const body = [];
|
|
211
168
|
this.#frameRows = [];
|
|
212
169
|
if (rows.length === 0) {
|
|
@@ -275,7 +232,7 @@ export class SettingsApp {
|
|
|
275
232
|
const row = rows[selected];
|
|
276
233
|
if (row?.kind === "element" && (row.value.structured || isDefaultModelEntry(row.value)))
|
|
277
234
|
this.#openStructured(row.value);
|
|
278
|
-
else if (row?.kind === "element" && typeof this.#
|
|
235
|
+
else if (row?.kind === "element" && typeof this.#edits.shown(row.value) === "number")
|
|
279
236
|
this.#cycle(rows, selected, 1);
|
|
280
237
|
else
|
|
281
238
|
this.#openMenu(rows, selected, true);
|
|
@@ -313,7 +270,7 @@ export class SettingsApp {
|
|
|
313
270
|
this.#cycle(rows, selected, action === "next-value" ? 1 : -1);
|
|
314
271
|
return { consumed: true };
|
|
315
272
|
case "undo":
|
|
316
|
-
this.#undo();
|
|
273
|
+
this.#edits.undo();
|
|
317
274
|
return { consumed: true };
|
|
318
275
|
default:
|
|
319
276
|
return { consumed: false };
|
|
@@ -355,7 +312,7 @@ export class SettingsApp {
|
|
|
355
312
|
const value = menu.choices[overRow];
|
|
356
313
|
this.#closeMenu(menu);
|
|
357
314
|
if (value !== undefined)
|
|
358
|
-
this.#apply(menu.entry, value);
|
|
315
|
+
this.#edits.apply(menu.entry, value);
|
|
359
316
|
return { consumed: true };
|
|
360
317
|
}
|
|
361
318
|
if (event.kind === "wheel-up" || event.kind === "wheel-down") {
|
|
@@ -380,7 +337,14 @@ export class SettingsApp {
|
|
|
380
337
|
// cannot change its selection or act on the Settings list behind it.
|
|
381
338
|
return { consumed: true, render: false };
|
|
382
339
|
}
|
|
383
|
-
const rail = this.#
|
|
340
|
+
const rail = this.#rail.pointer(event, this.#scroll);
|
|
341
|
+
if (rail.scroll !== undefined)
|
|
342
|
+
this.#scroll = rail.scroll;
|
|
343
|
+
// Invariant: the rail is not a row: pointing at it lights nothing in the list.
|
|
344
|
+
if (rail.overRail) {
|
|
345
|
+
this.#hoverKey = null;
|
|
346
|
+
this.#hoverRegion = "label";
|
|
347
|
+
}
|
|
384
348
|
if (rail.owned)
|
|
385
349
|
return { consumed: true };
|
|
386
350
|
const row = this.#frameRows.find(candidate => candidate.screenRow === event.row - 1);
|
|
@@ -410,52 +374,6 @@ export class SettingsApp {
|
|
|
410
374
|
const changed = previousKey !== this.#hoverKey || previousRegion !== this.#hoverRegion || rail.changed;
|
|
411
375
|
return { consumed: event.kind !== "motion", render: changed };
|
|
412
376
|
}
|
|
413
|
-
// Rationale: the rail takes its share of a pointer report first: hover, a thumb drag, or a
|
|
414
|
-
// track page. Owned means the list must not see the report; changed means the rail looks different.
|
|
415
|
-
#railPointer(event) {
|
|
416
|
-
const frame = this.#railFrame;
|
|
417
|
-
const wasHovered = this.#rails.isHovered(RAIL_KEY);
|
|
418
|
-
if (frame === null) {
|
|
419
|
-
this.#rails.clear();
|
|
420
|
-
return { owned: false, changed: wasHovered };
|
|
421
|
-
}
|
|
422
|
-
const pointer = { column: event.column, row: event.row - 1 };
|
|
423
|
-
if (this.#rails.isDragging(RAIL_KEY)) {
|
|
424
|
-
// Invariant: a drag keeps the pointer wherever it goes until the button comes up.
|
|
425
|
-
if (event.kind === "release")
|
|
426
|
-
this.#rails.endDrag();
|
|
427
|
-
else {
|
|
428
|
-
const target = this.#rails.dragTo(frame.rail, frame.geometry, pointer);
|
|
429
|
-
if (target !== null)
|
|
430
|
-
this.#scroll = target;
|
|
431
|
-
}
|
|
432
|
-
return { owned: true, changed: true };
|
|
433
|
-
}
|
|
434
|
-
const over = this.#rails.notePointer([frame.rail], pointer) !== null;
|
|
435
|
-
if (!over)
|
|
436
|
-
return { owned: false, changed: wasHovered };
|
|
437
|
-
// Invariant: the rail is not a row: pointing at it lights nothing in the list.
|
|
438
|
-
this.#hoverKey = null;
|
|
439
|
-
this.#hoverRegion = "label";
|
|
440
|
-
if (event.kind === "press" && !this.#rails.beginDrag(frame.rail, frame.geometry, pointer)) {
|
|
441
|
-
this.#scroll = scrollForTrackPage(frame.geometry, pointer.row - frame.rail.rowStart, this.#scroll, frame.page);
|
|
442
|
-
}
|
|
443
|
-
return { owned: true, changed: true };
|
|
444
|
-
}
|
|
445
|
-
#noteScrollActivity(host, now) {
|
|
446
|
-
this.#activeUntil = Math.max(this.#activeUntil, now + SCROLL_LINGER_MS);
|
|
447
|
-
this.#clearActivityTimer();
|
|
448
|
-
this.#activityTimer = setTimeout(() => {
|
|
449
|
-
this.#activityTimer = undefined;
|
|
450
|
-
host.requestRender();
|
|
451
|
-
}, SCROLL_LINGER_REPAINT_MS);
|
|
452
|
-
this.#activityTimer.unref?.();
|
|
453
|
-
}
|
|
454
|
-
#clearActivityTimer() {
|
|
455
|
-
if (this.#activityTimer !== undefined)
|
|
456
|
-
clearTimeout(this.#activityTimer);
|
|
457
|
-
this.#activityTimer = undefined;
|
|
458
|
-
}
|
|
459
377
|
#openMenu(rows, selected, selectCurrent = false) {
|
|
460
378
|
const row = rows[selected];
|
|
461
379
|
if (row === undefined || row.kind !== "element")
|
|
@@ -465,7 +383,7 @@ export class SettingsApp {
|
|
|
465
383
|
this.#openStructured(entry);
|
|
466
384
|
return;
|
|
467
385
|
}
|
|
468
|
-
const shown = this.#
|
|
386
|
+
const shown = this.#edits.shown(entry);
|
|
469
387
|
// Rationale: a number is stepped, not picked from a list: it has its own two controls,
|
|
470
388
|
// and pointing at it is not a request for anything else.
|
|
471
389
|
if (typeof shown === "number")
|
|
@@ -522,7 +440,7 @@ export class SettingsApp {
|
|
|
522
440
|
// thing under the pointer, so it stops looking like it.
|
|
523
441
|
this.#hoverKey = null;
|
|
524
442
|
this.#hoverRegion = "label";
|
|
525
|
-
this.#
|
|
443
|
+
this.#rail.clear();
|
|
526
444
|
const currentDefault = typeof entry.rawValue === "string" ? entry.rawValue : null;
|
|
527
445
|
this.#structured = {
|
|
528
446
|
entry,
|
|
@@ -541,8 +459,14 @@ export class SettingsApp {
|
|
|
541
459
|
const open = this.#structured;
|
|
542
460
|
if (open === null)
|
|
543
461
|
return { consumed: false };
|
|
544
|
-
if (open.modelDialog !== null)
|
|
545
|
-
return
|
|
462
|
+
if (open.modelDialog !== null) {
|
|
463
|
+
return modelDialogKey(open, data, KEYS[data] ?? data, {
|
|
464
|
+
session: this.#session,
|
|
465
|
+
close: () => { this.#structured = null; },
|
|
466
|
+
reopen: reopened => { this.#structured = reopened; },
|
|
467
|
+
save: (edit, previous, forward) => { this.#saveStructured(edit, previous, forward); },
|
|
468
|
+
});
|
|
469
|
+
}
|
|
546
470
|
switch (SETTINGS_SHORTCUTS.resolve(KEYS[data] ?? data, DIALOG_SCOPE)) {
|
|
547
471
|
case "close":
|
|
548
472
|
this.#structured = null;
|
|
@@ -557,120 +481,12 @@ export class SettingsApp {
|
|
|
557
481
|
this.#toggleFlag(open.index);
|
|
558
482
|
return { consumed: true };
|
|
559
483
|
case "undo":
|
|
560
|
-
this.#undo();
|
|
484
|
+
this.#edits.undo();
|
|
561
485
|
return { consumed: true };
|
|
562
486
|
default:
|
|
563
487
|
return { consumed: true, render: false };
|
|
564
488
|
}
|
|
565
489
|
}
|
|
566
|
-
#modelDialogKey(open, data) {
|
|
567
|
-
const key = KEYS[data] ?? data;
|
|
568
|
-
if (open.modelDialog === "default") {
|
|
569
|
-
const flags = this.#filteredModelFlags(open);
|
|
570
|
-
const action = MODEL_SHORTCUTS.resolve(key, MODEL_SCOPE) ?? "edit-filter";
|
|
571
|
-
if (action === "close") {
|
|
572
|
-
this.#structured = null;
|
|
573
|
-
return { consumed: true };
|
|
574
|
-
}
|
|
575
|
-
if (action === "previous" || action === "next") {
|
|
576
|
-
open.index = Math.min(Math.max(0, flags.length - 1), Math.max(0, open.index + (action === "next" ? 1 : -1)));
|
|
577
|
-
return { consumed: true };
|
|
578
|
-
}
|
|
579
|
-
if (action === "select") {
|
|
580
|
-
const selected = flags[open.index];
|
|
581
|
-
if (selected === undefined)
|
|
582
|
-
return { consumed: true, render: false };
|
|
583
|
-
open.error = null;
|
|
584
|
-
this.#structured = null;
|
|
585
|
-
void this.#session.change(open.entry.backend, open.entry.id, selected.key).then(outcome => {
|
|
586
|
-
const failure = changeFailure(outcome);
|
|
587
|
-
if (failure !== null) {
|
|
588
|
-
open.error = `Could not save: ${failure}`;
|
|
589
|
-
this.#structured = open;
|
|
590
|
-
}
|
|
591
|
-
});
|
|
592
|
-
return { consumed: true };
|
|
593
|
-
}
|
|
594
|
-
if (open.filter === null)
|
|
595
|
-
return { consumed: true, render: false };
|
|
596
|
-
handleLineInputKey(open.filter, data);
|
|
597
|
-
open.index = 0;
|
|
598
|
-
return { consumed: true };
|
|
599
|
-
}
|
|
600
|
-
if (open.step === "model") {
|
|
601
|
-
const flags = this.#filteredModelFlags(open);
|
|
602
|
-
const action = MODEL_SHORTCUTS.resolve(key, MODEL_SCOPE) ?? "edit-filter";
|
|
603
|
-
if (action === "close") {
|
|
604
|
-
this.#structured = null;
|
|
605
|
-
return { consumed: true };
|
|
606
|
-
}
|
|
607
|
-
if (action === "previous" || action === "next") {
|
|
608
|
-
open.index = Math.min(Math.max(0, flags.length - 1), Math.max(0, open.index + (action === "next" ? 1 : -1)));
|
|
609
|
-
return { consumed: true };
|
|
610
|
-
}
|
|
611
|
-
if (action === "select") {
|
|
612
|
-
const selected = flags[open.index];
|
|
613
|
-
if (selected === undefined)
|
|
614
|
-
return { consumed: true, render: false };
|
|
615
|
-
open.modelIndex = open.index;
|
|
616
|
-
open.modelKey = selected.key;
|
|
617
|
-
open.step = "level";
|
|
618
|
-
const options = this.#modelLevelOptions(open, selected);
|
|
619
|
-
const current = structuredValue(open.entry, open.record)[selected.key];
|
|
620
|
-
open.index = Math.max(0, options.findIndex(option => option.value === current));
|
|
621
|
-
return { consumed: true };
|
|
622
|
-
}
|
|
623
|
-
const input = open.filter;
|
|
624
|
-
if (input === null)
|
|
625
|
-
return { consumed: true, render: false };
|
|
626
|
-
handleLineInputKey(input, data);
|
|
627
|
-
open.index = 0;
|
|
628
|
-
return { consumed: true };
|
|
629
|
-
}
|
|
630
|
-
const selected = open.entry.flags.find(flag => flag.key === open.modelKey);
|
|
631
|
-
const choices = selected === undefined ? [] : this.#modelLevelOptions(open, selected);
|
|
632
|
-
const action = MODEL_SHORTCUTS.resolve(key, MODEL_LEVEL_SCOPE);
|
|
633
|
-
if (action === "back") {
|
|
634
|
-
open.step = "model";
|
|
635
|
-
open.modelKey = null;
|
|
636
|
-
open.index = open.modelIndex;
|
|
637
|
-
return { consumed: true };
|
|
638
|
-
}
|
|
639
|
-
if (action === "previous" || action === "next") {
|
|
640
|
-
open.index = Math.min(Math.max(0, choices.length - 1), Math.max(0, open.index + (action === "next" ? 1 : -1)));
|
|
641
|
-
return { consumed: true };
|
|
642
|
-
}
|
|
643
|
-
if (action === "select") {
|
|
644
|
-
const choice = choices[open.index];
|
|
645
|
-
if (selected === undefined || choice === undefined)
|
|
646
|
-
return { consumed: true, render: false };
|
|
647
|
-
const previous = { ...open.record };
|
|
648
|
-
open.record[selected.key] = choice.value;
|
|
649
|
-
const forward = { ...open.record };
|
|
650
|
-
this.#saveStructured(open, previous, forward);
|
|
651
|
-
open.step = "model";
|
|
652
|
-
open.modelKey = null;
|
|
653
|
-
open.index = open.modelIndex;
|
|
654
|
-
return { consumed: true };
|
|
655
|
-
}
|
|
656
|
-
return { consumed: true, render: false };
|
|
657
|
-
}
|
|
658
|
-
#filteredModelFlags(open) {
|
|
659
|
-
const needle = open.filter?.value.trim().toLowerCase() ?? "";
|
|
660
|
-
return open.entry.flags.filter(flag => needle.length === 0
|
|
661
|
-
|| (flag.label ?? humanizeLabel(flag.key)).toLowerCase().includes(needle)
|
|
662
|
-
|| flag.description.toLowerCase().includes(needle)
|
|
663
|
-
|| flag.key.toLowerCase().includes(needle));
|
|
664
|
-
}
|
|
665
|
-
#modelLevelOptions(open, selected) {
|
|
666
|
-
const fallback = String(selected.fallback);
|
|
667
|
-
const supported = (selected.choices ?? [])
|
|
668
|
-
.filter(choice => choice !== fallback)
|
|
669
|
-
.map(choice => ({ value: choice, label: choice, description: thinkingLevelDescription(choice) }));
|
|
670
|
-
return structuredValue(open.entry, open.record)[selected.key] === undefined
|
|
671
|
-
? supported
|
|
672
|
-
: [...supported, { value: fallback, label: "(clear override)", description: "Revert to global default" }];
|
|
673
|
-
}
|
|
674
490
|
#toggleFlag(index) {
|
|
675
491
|
const open = this.#structured;
|
|
676
492
|
const flag = open?.flags[index];
|
|
@@ -689,14 +505,8 @@ export class SettingsApp {
|
|
|
689
505
|
this.#saveStructured(open, previous, forward);
|
|
690
506
|
}
|
|
691
507
|
#saveStructured(open, previous, forward) {
|
|
692
|
-
|
|
693
|
-
|
|
694
|
-
const failure = changeFailure(outcome);
|
|
695
|
-
if (failure === null) {
|
|
696
|
-
this.#recordUndo({ kind: "structured", sequence, entry: open.entry, previous, forward });
|
|
697
|
-
return;
|
|
698
|
-
}
|
|
699
|
-
// Concurrency: only roll back the dialog if no later press has moved the record on.
|
|
508
|
+
// Concurrency: only roll back the dialog if no later press has moved the record on.
|
|
509
|
+
this.#edits.saveStructured(open.entry, previous, forward, () => {
|
|
700
510
|
if (this.#structured === open && sameRecord(open.record, forward))
|
|
701
511
|
replaceRecord(open.record, previous);
|
|
702
512
|
});
|
|
@@ -708,7 +518,7 @@ export class SettingsApp {
|
|
|
708
518
|
const key = KEYS[data] ?? data;
|
|
709
519
|
if (SETTINGS_SHORTCUTS.resolve(key, SCOPE) === "undo") {
|
|
710
520
|
this.#closeMenu(menu);
|
|
711
|
-
this.#undo();
|
|
521
|
+
this.#edits.undo();
|
|
712
522
|
return { consumed: true };
|
|
713
523
|
}
|
|
714
524
|
if (key === "escape") {
|
|
@@ -725,7 +535,7 @@ export class SettingsApp {
|
|
|
725
535
|
const value = menu.choices[menu.index];
|
|
726
536
|
this.#closeMenu(menu);
|
|
727
537
|
if (value !== undefined)
|
|
728
|
-
this.#apply(menu.entry, value);
|
|
538
|
+
this.#edits.apply(menu.entry, value);
|
|
729
539
|
}
|
|
730
540
|
return { consumed: true };
|
|
731
541
|
}
|
|
@@ -785,13 +595,13 @@ export class SettingsApp {
|
|
|
785
595
|
const entry = row.value;
|
|
786
596
|
if (!entry.editable)
|
|
787
597
|
return;
|
|
788
|
-
const shown = this.#
|
|
598
|
+
const shown = this.#edits.shown(entry);
|
|
789
599
|
if (typeof shown === "number") {
|
|
790
600
|
// Rationale: at the end of the range there is nothing to say: the arrow already reads
|
|
791
601
|
// as unavailable, so a message would only repeat it.
|
|
792
602
|
const next = steppedValue(rangeOf(entry), shown, delta);
|
|
793
603
|
if (next !== null)
|
|
794
|
-
this.#apply(entry, next);
|
|
604
|
+
this.#edits.apply(entry, next);
|
|
795
605
|
return;
|
|
796
606
|
}
|
|
797
607
|
const choices = entry.choices;
|
|
@@ -802,82 +612,7 @@ export class SettingsApp {
|
|
|
802
612
|
? (delta > 0 ? 0 : choices.length - 1)
|
|
803
613
|
: (current + delta + choices.length) % choices.length];
|
|
804
614
|
if (next !== undefined)
|
|
805
|
-
this.#apply(entry, next);
|
|
806
|
-
}
|
|
807
|
-
#apply(entry, value) {
|
|
808
|
-
const key = `${entry.backend}:${entry.id}`;
|
|
809
|
-
const previous = this.#shownValue(entry);
|
|
810
|
-
const sequence = ++this.#editSequence;
|
|
811
|
-
// Invariant: shown immediately so the row never lags a keypress, and so the next press
|
|
812
|
-
// steps from here rather than from a value the source has not caught up to.
|
|
813
|
-
this.#pending.set(key, value);
|
|
814
|
-
void this.#session.change(entry.backend, entry.id, value).then(outcome => {
|
|
815
|
-
const failure = changeFailure(outcome);
|
|
816
|
-
if (failure !== null) {
|
|
817
|
-
if (this.#pending.get(key) === value)
|
|
818
|
-
this.#pending.delete(key);
|
|
819
|
-
return;
|
|
820
|
-
}
|
|
821
|
-
if (previous !== null && previous !== value)
|
|
822
|
-
this.#recordUndo({ kind: "scalar", sequence, entry, previous });
|
|
823
|
-
// Concurrency: a later press may have moved on; only the last request clears itself.
|
|
824
|
-
if (this.#pending.get(key) === value)
|
|
825
|
-
this.#pending.delete(key);
|
|
826
|
-
});
|
|
827
|
-
}
|
|
828
|
-
#shownValue(entry) {
|
|
829
|
-
return this.#pending.get(`${entry.backend}:${entry.id}`) ?? entry.value;
|
|
830
|
-
}
|
|
831
|
-
#recordUndo(record) {
|
|
832
|
-
if (this.#closed)
|
|
833
|
-
return;
|
|
834
|
-
const after = this.#undoHistory.findIndex(candidate => candidate.sequence > record.sequence);
|
|
835
|
-
if (after < 0)
|
|
836
|
-
this.#undoHistory.push(record);
|
|
837
|
-
else
|
|
838
|
-
this.#undoHistory.splice(after, 0, record);
|
|
839
|
-
}
|
|
840
|
-
#undo() {
|
|
841
|
-
this.#undoRequests++;
|
|
842
|
-
this.#drainUndo();
|
|
843
|
-
}
|
|
844
|
-
#drainUndo() {
|
|
845
|
-
if (this.#undoActive || this.#undoRequests === 0)
|
|
846
|
-
return;
|
|
847
|
-
const record = this.#undoHistory.pop();
|
|
848
|
-
if (record === undefined) {
|
|
849
|
-
this.#undoRequests = 0;
|
|
850
|
-
return;
|
|
851
|
-
}
|
|
852
|
-
this.#undoRequests--;
|
|
853
|
-
this.#undoActive = true;
|
|
854
|
-
if (record.kind === "scalar") {
|
|
855
|
-
const key = `${record.entry.backend}:${record.entry.id}`;
|
|
856
|
-
this.#pending.set(key, record.previous);
|
|
857
|
-
void this.#session.change(record.entry.backend, record.entry.id, record.previous).then(outcome => {
|
|
858
|
-
if (this.#pending.get(key) === record.previous)
|
|
859
|
-
this.#pending.delete(key);
|
|
860
|
-
this.#finishUndo(record, outcome);
|
|
861
|
-
});
|
|
862
|
-
return;
|
|
863
|
-
}
|
|
864
|
-
const open = this.#structured;
|
|
865
|
-
if (open !== null && sameEntry(open.entry, record.entry))
|
|
866
|
-
replaceRecord(open.record, record.previous);
|
|
867
|
-
void this.#session.changeStructured(record.entry.backend, record.entry.id, structuredValue(record.entry, record.previous)).then(outcome => {
|
|
868
|
-
const failure = changeFailure(outcome);
|
|
869
|
-
if (failure !== null && this.#structured === open && open !== null && sameRecord(open.record, record.previous)) {
|
|
870
|
-
replaceRecord(open.record, record.forward);
|
|
871
|
-
}
|
|
872
|
-
this.#finishUndo(record, outcome);
|
|
873
|
-
});
|
|
874
|
-
}
|
|
875
|
-
#finishUndo(record, outcome) {
|
|
876
|
-
const failure = changeFailure(outcome);
|
|
877
|
-
if (failure !== null)
|
|
878
|
-
this.#recordUndo(record);
|
|
879
|
-
this.#undoActive = false;
|
|
880
|
-
this.#drainUndo();
|
|
615
|
+
this.#edits.apply(entry, next);
|
|
881
616
|
}
|
|
882
617
|
#scrollbarSpeed() {
|
|
883
618
|
const value = this.#scrollSetting("scrollbarSpeed");
|
|
@@ -895,7 +630,7 @@ export class SettingsApp {
|
|
|
895
630
|
const entry = this.#session.sections()
|
|
896
631
|
.flatMap(section => section.entries)
|
|
897
632
|
.find(candidate => candidate.backend === "a1" && candidate.id === id);
|
|
898
|
-
return entry === undefined ? this.#session.value(id) : this.#
|
|
633
|
+
return entry === undefined ? this.#session.value(id) : this.#edits.shown(entry);
|
|
899
634
|
}
|
|
900
635
|
#jump(rows, target) {
|
|
901
636
|
this.#select(rows, target);
|
|
@@ -967,7 +702,7 @@ export class SettingsApp {
|
|
|
967
702
|
}
|
|
968
703
|
#viewRow(entry) {
|
|
969
704
|
const key = `${entry.backend}:${entry.id}`;
|
|
970
|
-
const shown = this.#
|
|
705
|
+
const shown = this.#edits.shown(entry);
|
|
971
706
|
const value = entry.structured || isDefaultModelEntry(entry)
|
|
972
707
|
? CONFIGURE
|
|
973
708
|
: shown === null
|
|
@@ -993,7 +728,7 @@ export class SettingsApp {
|
|
|
993
728
|
...(menu.entry.id === "accentColor" ? {
|
|
994
729
|
previews: menu.choices.map(choice => theme.accentPreview?.(String(choice), "■") ?? ""),
|
|
995
730
|
} : {}),
|
|
996
|
-
current: this.#
|
|
731
|
+
current: this.#edits.shown(menu.entry) === null ? null : displaySettingValue(menu.entry, this.#edits.shown(menu.entry)),
|
|
997
732
|
index: menu.index,
|
|
998
733
|
};
|
|
999
734
|
const frame = valueMenuFrame(state, {
|
|
@@ -1010,7 +745,7 @@ export class SettingsApp {
|
|
|
1010
745
|
}
|
|
1011
746
|
#dialogLines(open, width, height, theme) {
|
|
1012
747
|
if (open.modelDialog !== null)
|
|
1013
|
-
return
|
|
748
|
+
return modelDialogLines(open, width, height, theme);
|
|
1014
749
|
const rows = open.flags.map(key => {
|
|
1015
750
|
const declared = open.entry.flags.find(flag => flag.key === key);
|
|
1016
751
|
return {
|
|
@@ -1023,64 +758,6 @@ export class SettingsApp {
|
|
|
1023
758
|
const visible = dialogWindow(rows, open.index, configureDialogChoiceCapacity(height, false, configureDialogTextRows(rows[open.index]?.description ?? "", width)));
|
|
1024
759
|
return renderDialogPanel({ title: labelOf(open.entry), rows: visible.rows, index: visible.index, hint: SETTINGS_SHORTCUTS.hintEntries(DIALOG_SCOPE) }, width, theme);
|
|
1025
760
|
}
|
|
1026
|
-
#modelDialogLines(open, width, height, theme) {
|
|
1027
|
-
if (open.modelDialog === "default") {
|
|
1028
|
-
const flags = this.#filteredModelFlags(open);
|
|
1029
|
-
const current = typeof open.entry.rawValue === "string" ? open.entry.rawValue : null;
|
|
1030
|
-
const rows = flags.length === 0
|
|
1031
|
-
? [{ label: "No models found", value: "" }]
|
|
1032
|
-
: flags.map(flag => ({
|
|
1033
|
-
...modelLabelParts(flag.label ?? humanizeLabel(flag.key)),
|
|
1034
|
-
...(flag.key === current ? { successSuffix: "✓" } : {}),
|
|
1035
|
-
value: "",
|
|
1036
|
-
}));
|
|
1037
|
-
const description = open.error ?? "Select the model used for new sessions";
|
|
1038
|
-
const visible = dialogWindow(rows, open.index, configureDialogChoiceCapacity(height, true, configureDialogTextRows(description, width)));
|
|
1039
|
-
return renderSteppedDialogPanel({
|
|
1040
|
-
title: "Default Model", description, input: open.filter ?? new LineInput(""),
|
|
1041
|
-
rows: visible.rows, index: visible.index, hint: MODEL_SHORTCUTS.hintEntries(MODEL_SCOPE),
|
|
1042
|
-
}, width, theme);
|
|
1043
|
-
}
|
|
1044
|
-
if (open.step === "model") {
|
|
1045
|
-
const flags = this.#filteredModelFlags(open);
|
|
1046
|
-
const stored = structuredValue(open.entry, open.record);
|
|
1047
|
-
const allRows = flags.length === 0
|
|
1048
|
-
? [{ label: "No models found", value: "" }]
|
|
1049
|
-
: flags.map(flag => ({
|
|
1050
|
-
...modelLabelParts(flag.label ?? humanizeLabel(flag.key)),
|
|
1051
|
-
value: stored[flag.key] === undefined ? "" : String(stored[flag.key]),
|
|
1052
|
-
}));
|
|
1053
|
-
const description = "Select a model to configure";
|
|
1054
|
-
const visible = dialogWindow(allRows, open.index, configureDialogChoiceCapacity(height, true, configureDialogTextRows(description, width)));
|
|
1055
|
-
return renderSteppedDialogPanel({
|
|
1056
|
-
title: "Thinking Level",
|
|
1057
|
-
step: 1,
|
|
1058
|
-
steps: 2,
|
|
1059
|
-
description,
|
|
1060
|
-
...(open.filter === null ? {} : { input: open.filter }),
|
|
1061
|
-
rows: visible.rows,
|
|
1062
|
-
index: visible.index,
|
|
1063
|
-
hint: MODEL_SHORTCUTS.hintEntries(MODEL_SCOPE),
|
|
1064
|
-
}, width, theme);
|
|
1065
|
-
}
|
|
1066
|
-
const selected = open.entry.flags.find(flag => flag.key === open.modelKey);
|
|
1067
|
-
const current = selected === undefined ? undefined : structuredValue(open.entry, open.record)[selected.key];
|
|
1068
|
-
const allRows = (selected === undefined ? [] : this.#modelLevelOptions(open, selected)).map(choice => ({
|
|
1069
|
-
label: choice.value === current ? `✓ ${choice.label}` : choice.label,
|
|
1070
|
-
value: choice.description,
|
|
1071
|
-
}));
|
|
1072
|
-
const description = `Select default thinking level for ${selected?.label ?? open.modelKey ?? "model"}`;
|
|
1073
|
-
const visible = dialogWindow(allRows, open.index, configureDialogChoiceCapacity(height, false, configureDialogTextRows(description, width)));
|
|
1074
|
-
return renderSteppedDialogPanel({
|
|
1075
|
-
title: "Thinking Level",
|
|
1076
|
-
step: 2,
|
|
1077
|
-
steps: 2,
|
|
1078
|
-
description,
|
|
1079
|
-
rows: visible.rows,
|
|
1080
|
-
index: visible.index,
|
|
1081
|
-
hint: MODEL_SHORTCUTS.hintEntries(MODEL_LEVEL_SCOPE),
|
|
1082
|
-
}, width, theme);
|
|
1083
|
-
}
|
|
1084
761
|
#footerLines(width, theme) {
|
|
1085
762
|
// Rationale: standing guidance is more useful than transient feedback; failures still
|
|
1086
763
|
// roll back without displacing the Settings interaction contract.
|
|
@@ -1132,59 +809,6 @@ function orderDefaultModelBeforeThinking(entries, sectionId) {
|
|
|
1132
809
|
ordered.splice(thinking < 0 ? ordered.length : thinking, 0, defaultModel);
|
|
1133
810
|
return ordered;
|
|
1134
811
|
}
|
|
1135
|
-
function modelLabelParts(label) {
|
|
1136
|
-
const match = /^(.*?)(\s+\[[^\]]+\])$/u.exec(label);
|
|
1137
|
-
return match === null ? { label } : { label: match[1] ?? label, labelSuffix: match[2] ?? "" };
|
|
1138
|
-
}
|
|
1139
|
-
function dialogWindow(rows, index, maximum) {
|
|
1140
|
-
if (rows.length <= maximum)
|
|
1141
|
-
return { rows, index: Math.min(Math.max(0, rows.length - 1), Math.max(0, index)) };
|
|
1142
|
-
const start = Math.min(rows.length - maximum, Math.max(0, index - Math.floor(maximum / 2)));
|
|
1143
|
-
return { rows: rows.slice(start, start + maximum), index: index - start };
|
|
1144
|
-
}
|
|
1145
|
-
function thinkingLevelDescription(level) {
|
|
1146
|
-
switch (level) {
|
|
1147
|
-
case "default": return "global default";
|
|
1148
|
-
case "off": return "No reasoning";
|
|
1149
|
-
case "minimal": return "Very brief reasoning (~1k tokens)";
|
|
1150
|
-
case "low": return "Light reasoning (~2k tokens)";
|
|
1151
|
-
case "medium": return "Moderate reasoning (~8k tokens)";
|
|
1152
|
-
case "high": return "Deep reasoning (~16k tokens)";
|
|
1153
|
-
case "xhigh": return "Extra-high reasoning (~32k tokens)";
|
|
1154
|
-
case "max": return "Maximum reasoning";
|
|
1155
|
-
default: return "";
|
|
1156
|
-
}
|
|
1157
|
-
}
|
|
1158
|
-
function structuredValue(entry, record) {
|
|
1159
|
-
// Invariant: a choice part at its fallback is unset, so the engine's default applies.
|
|
1160
|
-
return Object.fromEntries(Object.entries(record).filter(([key, value]) => {
|
|
1161
|
-
const part = entry.flags.find(candidate => candidate.key === key);
|
|
1162
|
-
return part?.choices === undefined || value !== part.fallback;
|
|
1163
|
-
}));
|
|
1164
|
-
}
|
|
1165
|
-
function sameEntry(left, right) {
|
|
1166
|
-
return left.backend === right.backend && left.id === right.id;
|
|
1167
|
-
}
|
|
1168
|
-
function sameRecord(left, right) {
|
|
1169
|
-
const leftEntries = Object.entries(left);
|
|
1170
|
-
const rightEntries = Object.entries(right);
|
|
1171
|
-
return leftEntries.length === rightEntries.length
|
|
1172
|
-
&& leftEntries.every(([key, value]) => right[key] === value);
|
|
1173
|
-
}
|
|
1174
|
-
function replaceRecord(target, source) {
|
|
1175
|
-
for (const key of Object.keys(target))
|
|
1176
|
-
delete target[key];
|
|
1177
|
-
Object.assign(target, source);
|
|
1178
|
-
}
|
|
1179
|
-
function changeFailure(outcome) {
|
|
1180
|
-
if (outcome.failure !== null)
|
|
1181
|
-
return outcome.failure;
|
|
1182
|
-
if (outcome.status === "failed")
|
|
1183
|
-
return "the effect failed";
|
|
1184
|
-
if (outcome.status === "unavailable")
|
|
1185
|
-
return outcome.limitationReason ?? "the setting is unavailable";
|
|
1186
|
-
return outcome.limitationReason;
|
|
1187
|
-
}
|
|
1188
812
|
function isDefaultModelEntry(entry) {
|
|
1189
813
|
return entry.backend === "agent" && entry.id === "defaultModel";
|
|
1190
814
|
}
|