@pellux/goodvibes-tui 1.16.1 → 1.18.0
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/CHANGELOG.md +138 -9
- package/README.md +1 -1
- package/docs/foundation-artifacts/operator-contract.json +5490 -1806
- package/package.json +7 -7
- package/src/cli/completions/generate.ts +5 -4
- package/src/cli/config-overrides.ts +51 -11
- package/src/cli/doctor.ts +4 -5
- package/src/cli/entrypoint.ts +13 -8
- package/src/cli/help.ts +7 -6
- package/src/cli/launch-auto-update.ts +214 -0
- package/src/cli/management-commands.ts +82 -15
- package/src/cli/management.ts +0 -2
- package/src/cli/parser.ts +5 -0
- package/src/cli/status.ts +13 -0
- package/src/cli/surface-command.ts +5 -5
- package/src/cli/tui-startup.ts +60 -97
- package/src/cli/types.ts +2 -0
- package/src/config/index.ts +1 -1
- package/src/config/tui-extension-settings.ts +33 -0
- package/src/core/composer-state.ts +1 -1
- package/src/core/consolidation-receipt.ts +41 -0
- package/src/core/conversation-line-cache.ts +3 -3
- package/src/core/conversation-rendering.ts +18 -9
- package/src/core/conversation.ts +2 -2
- package/src/core/long-task-notifier.ts +7 -7
- package/src/core/memory-provenance.ts +67 -0
- package/src/core/pairing-devices.ts +49 -0
- package/src/core/pairing-handoff.ts +101 -0
- package/src/core/pairing-offers.ts +83 -0
- package/src/core/pairing-origin.ts +78 -0
- package/src/core/pairing-tailscale-gateway.ts +56 -0
- package/src/core/power-chip-source.ts +91 -0
- package/src/core/power-status.ts +95 -0
- package/src/core/stable-host.ts +171 -0
- package/src/core/stream-event-wiring.ts +29 -6
- package/src/core/system-message-noise.ts +1 -1
- package/src/core/system-message-router.ts +6 -6
- package/src/core/turn-budget-outcome.ts +60 -0
- package/src/core/turn-cancellation.ts +40 -1
- package/src/core/turn-event-wiring.ts +14 -8
- package/src/daemon/cli.ts +64 -58
- package/src/daemon/lifecycle.ts +41 -0
- package/src/daemon/service-commands.ts +5 -5
- package/src/export/cost-utils.ts +128 -6
- package/src/input/autocomplete.ts +2 -2
- package/src/input/command-registry.ts +55 -9
- package/src/input/commands/acp-runtime.ts +72 -0
- package/src/input/commands/ci-runtime.ts +5 -1
- package/src/input/commands/codebase-runtime.ts +6 -6
- package/src/input/commands/cost-runtime.ts +1 -1
- package/src/input/commands/devices-runtime.ts +109 -0
- package/src/input/commands/git-runtime.ts +28 -4
- package/src/input/commands/graph-runtime.ts +45 -0
- package/src/input/commands/health-runtime.ts +2 -2
- package/src/input/commands/intelligence-runtime.ts +1 -1
- package/src/input/commands/local-auth-runtime.ts +1 -1
- package/src/input/commands/local-provider-runtime.ts +49 -10
- package/src/input/commands/local-runtime.ts +53 -5
- package/src/input/commands/memory.ts +2 -2
- package/src/input/commands/operator-panel-runtime.ts +5 -5
- package/src/input/commands/operator-rpc.ts +32 -11
- package/src/input/commands/permissions-provenance.ts +1 -1
- package/src/input/commands/permissions-runtime.ts +99 -8
- package/src/input/commands/planning-runtime.ts +3 -3
- package/src/input/commands/platform-sandbox-runtime.ts +1 -1
- package/src/input/commands/power-runtime.ts +56 -0
- package/src/input/commands/provider-accounts-runtime.ts +71 -6
- package/src/input/commands/provider.ts +7 -5
- package/src/input/commands/qrcode-runtime.ts +14 -19
- package/src/input/commands/queue-runtime.ts +70 -0
- package/src/input/commands/recall-files-git.ts +13 -51
- package/src/input/commands/recall-files.ts +8 -11
- package/src/input/commands/recall-review.ts +2 -2
- package/src/input/commands/relay-runtime.ts +1 -1
- package/src/input/commands/remote-runtime.ts +1 -1
- package/src/input/commands/runtime-services.ts +4 -4
- package/src/input/commands/schedule-runtime.ts +14 -7
- package/src/input/commands/services-runtime.ts +1 -1
- package/src/input/commands/session-workflow.ts +2 -2
- package/src/input/commands/settings-sync-runtime.ts +2 -2
- package/src/input/commands/share-runtime.ts +1 -1
- package/src/input/commands/shell-core.ts +46 -68
- package/src/input/commands/subscription-runtime.ts +1 -1
- package/src/input/commands/update-runtime.ts +153 -96
- package/src/input/commands/work-plan-runtime.ts +1 -1
- package/src/input/commands/workstream-attempts.ts +6 -1
- package/src/input/commands/workstream-runtime.ts +46 -27
- package/src/input/commands/worktree-runtime.ts +35 -8
- package/src/input/commands.ts +10 -2
- package/src/input/config-modal-types.ts +14 -3
- package/src/input/config-modal.ts +75 -13
- package/src/input/feature-unit-layout.ts +93 -82
- package/src/input/feed-context-factory.ts +2 -2
- package/src/input/handler-command-route.ts +2 -2
- package/src/input/handler-content-actions.ts +1 -1
- package/src/input/handler-feed-routes.ts +7 -7
- package/src/input/handler-feed.ts +4 -4
- package/src/input/handler-interactions.ts +3 -2
- package/src/input/handler-modal-routes.ts +12 -4
- package/src/input/handler-modal-token-routes.ts +1 -1
- package/src/input/handler-onboarding-daemon-adopt.ts +2 -2
- package/src/input/handler-onboarding.ts +3 -2
- package/src/input/handler-picker-routes.ts +26 -13
- package/src/input/handler-shortcuts.ts +29 -6
- package/src/input/handler.ts +2 -2
- package/src/input/keybindings.ts +21 -3
- package/src/input/onboarding/onboarding-feature-units.ts +34 -27
- package/src/input/onboarding/onboarding-provider-key-fields.ts +112 -0
- package/src/input/onboarding/onboarding-wizard-apply.ts +22 -21
- package/src/input/onboarding/onboarding-wizard-external-surfaces.ts +17 -0
- package/src/input/onboarding/onboarding-wizard-network-adopt.ts +2 -2
- package/src/input/onboarding/onboarding-wizard-steps.ts +30 -42
- package/src/input/panel-integration-actions.ts +2 -2
- package/src/input/panel-mouse-geometry.ts +1 -1
- package/src/input/panel-paste-flood-guard.ts +1 -1
- package/src/input/provider-key-intake.ts +167 -0
- package/src/input/sandbox-exec-config.ts +2 -2
- package/src/input/selection-modal.ts +1 -1
- package/src/input/settings-modal-activation.ts +5 -0
- package/src/input/settings-modal-adjustment.ts +4 -31
- package/src/input/settings-modal-data.ts +52 -57
- package/src/input/settings-modal-mutations.ts +12 -68
- package/src/input/settings-modal-types.ts +27 -17
- package/src/input/settings-modal.ts +74 -55
- package/src/main.ts +90 -90
- package/src/panels/agent-inspector-shared.ts +4 -4
- package/src/panels/base-panel.ts +2 -2
- package/src/panels/builtin/agent.ts +4 -4
- package/src/panels/builtin/development.ts +4 -4
- package/src/panels/builtin/knowledge.ts +1 -1
- package/src/panels/builtin/operations.ts +83 -11
- package/src/panels/builtin/session.ts +5 -5
- package/src/panels/builtin/shared.ts +16 -4
- package/src/panels/builtin-modals.ts +59 -42
- package/src/panels/builtin-panels.ts +1 -1
- package/src/panels/cost-tracker-panel.ts +124 -7
- package/src/panels/diff-panel.ts +39 -6
- package/src/panels/eval-registry.ts +2 -2
- package/src/panels/fleet-acts.ts +446 -0
- package/src/panels/fleet-deep-link.ts +1 -1
- package/src/panels/fleet-gateway.ts +117 -0
- package/src/panels/fleet-observed-render.ts +128 -0
- package/src/panels/fleet-panel-format.ts +163 -11
- package/src/panels/fleet-panel-worktree-detail.ts +14 -0
- package/src/panels/fleet-panel.ts +73 -57
- package/src/panels/fleet-read-model.ts +84 -14
- package/src/panels/fleet-spawn.ts +266 -0
- package/src/panels/fleet-steer.ts +2 -2
- package/src/panels/fleet-stop.ts +41 -5
- package/src/panels/fleet-tabs.ts +15 -16
- package/src/panels/fleet-transcript.ts +5 -5
- package/src/panels/git-panel.ts +2 -2
- package/src/panels/index.ts +4 -1
- package/src/panels/local-auth-panel.ts +1 -1
- package/src/panels/memory-consolidation-gateway.ts +94 -0
- package/src/panels/modals/devices-modal.ts +161 -0
- package/src/panels/modals/hooks-modal.ts +1 -1
- package/src/panels/modals/keybindings-modal.ts +2 -2
- package/src/panels/modals/knowledge-modal.ts +1 -1
- package/src/panels/modals/marketplace-modal.ts +4 -4
- package/src/panels/modals/memory-modal.ts +153 -9
- package/src/panels/modals/modal-surface-helpers.ts +1 -1
- package/src/panels/modals/modal-theme.ts +1 -1
- package/src/panels/modals/pairing-modal.ts +198 -68
- package/src/panels/modals/planning-modal.ts +2 -2
- package/src/panels/modals/plugins-modal.ts +1 -1
- package/src/panels/modals/policy-modal.ts +1 -1
- package/src/panels/modals/security-modal.ts +7 -1
- package/src/panels/modals/skills-modal.ts +1 -1
- package/src/panels/modals/work-plan-modal.ts +3 -3
- package/src/panels/notifications-feed.ts +127 -0
- package/src/panels/notifications-panel.ts +160 -0
- package/src/panels/panel-manager.ts +9 -9
- package/src/panels/plugins-panel.ts +4 -4
- package/src/panels/project-planning-answer-actions.ts +1 -1
- package/src/panels/provider-health-routes.ts +2 -2
- package/src/panels/skills-panel.ts +4 -5
- package/src/panels/token-budget-panel.ts +11 -3
- package/src/panels/types.ts +5 -5
- package/src/panels/workstream-graph-render.ts +123 -0
- package/src/permissions/broker-approval-card.ts +201 -0
- package/src/permissions/hunk-selection.ts +28 -4
- package/src/permissions/prompt.ts +244 -29
- package/src/renderer/autocomplete-overlay.ts +107 -54
- package/src/renderer/code-block.ts +2 -2
- package/src/renderer/compaction-history-modal.ts +1 -1
- package/src/renderer/compaction-preview.ts +1 -1
- package/src/renderer/compaction-quality.ts +1 -1
- package/src/renderer/composer-fragments.ts +69 -0
- package/src/renderer/compositor.ts +2 -2
- package/src/renderer/config-modal.ts +1 -1
- package/src/renderer/conversation-overlays.ts +1 -1
- package/src/renderer/footer-tips.ts +3 -3
- package/src/renderer/hint-grammar.ts +1 -1
- package/src/renderer/modal-factory.ts +1 -1
- package/src/renderer/model-picker-overlay.ts +1 -1
- package/src/renderer/model-workspace.ts +7 -2
- package/src/renderer/panel-composite.ts +2 -2
- package/src/renderer/panel-workspace-bar.ts +1 -1
- package/src/renderer/process-indicator.ts +1 -1
- package/src/renderer/selection-modal-overlay.ts +1 -1
- package/src/renderer/session-picker-modal.ts +2 -2
- package/src/renderer/settings-modal-helpers.ts +23 -5
- package/src/renderer/settings-modal.ts +129 -39
- package/src/renderer/shell-surface.ts +6 -0
- package/src/renderer/terminal-bg-probe.ts +1 -1
- package/src/renderer/theme.ts +3 -3
- package/src/renderer/tool-call.ts +13 -7
- package/src/renderer/tool-result-summary.ts +1 -1
- package/src/renderer/turn-injection.ts +7 -6
- package/src/renderer/ui-factory.ts +38 -1
- package/src/runtime/bootstrap-command-context.ts +7 -2
- package/src/runtime/bootstrap-command-parts.ts +9 -5
- package/src/runtime/bootstrap-core.ts +41 -41
- package/src/runtime/bootstrap-hook-bridge.ts +1 -1
- package/src/runtime/bootstrap-shell.ts +13 -5
- package/src/runtime/bootstrap.ts +34 -32
- package/src/runtime/channel-composition.ts +46 -0
- package/src/runtime/code-index-services.ts +3 -4
- package/src/runtime/daemon-attach-notices.ts +120 -0
- package/src/runtime/durability-services.ts +90 -0
- package/src/runtime/embedded-service-factories.ts +40 -0
- package/src/runtime/feature-settings.ts +147 -0
- package/src/runtime/fleet-services.ts +41 -0
- package/src/runtime/idle-power-services.ts +85 -0
- package/src/runtime/index.ts +6 -21
- package/src/runtime/interaction-seams.ts +109 -0
- package/src/runtime/legacy-daemon-migration.ts +29 -19
- package/src/runtime/memory-fold.ts +1 -1
- package/src/runtime/notification-dispatch.ts +110 -0
- package/src/runtime/onboarding/apply.ts +3 -29
- package/src/runtime/onboarding/fast-path.ts +39 -6
- package/src/runtime/onboarding/provider-key-capture.ts +126 -0
- package/src/runtime/onboarding/snapshot.ts +0 -1
- package/src/runtime/onboarding/types.ts +9 -3
- package/src/runtime/power-keepawake-remote.ts +75 -0
- package/src/runtime/process-lifecycle.ts +3 -1
- package/src/runtime/provider-fallback.ts +55 -0
- package/src/runtime/provider-optimizer-wiring.ts +55 -0
- package/src/runtime/release-artifacts.ts +19 -103
- package/src/runtime/resume-notice.ts +1 -1
- package/src/runtime/services.ts +113 -113
- package/src/runtime/session-continuity-hints.ts +38 -0
- package/src/runtime/surface-feature-flags.ts +40 -9
- package/src/runtime/terminal-output-guard.ts +2 -2
- package/src/runtime/trust/workspace-registration.ts +10 -2
- package/src/runtime/trust/workspace-trust.ts +58 -31
- package/src/runtime/ui-services.ts +6 -1
- package/src/runtime/update-check.ts +15 -69
- package/src/runtime/workstream-services.ts +2 -2
- package/src/shell/blocking-input.ts +108 -132
- package/src/shell/recovery-input-helpers.ts +53 -166
- package/src/shell/ui-openers.ts +38 -6
- package/src/utils/format-duration.ts +1 -1
- package/src/verification/verification-ledger.ts +21 -4
- package/src/version.ts +1 -1
- package/src/input/commands/flags-runtime.ts +0 -328
|
@@ -25,6 +25,7 @@ import {
|
|
|
25
25
|
} from './worktree-setup-config.ts';
|
|
26
26
|
import { BUDGET_ALERT_USD_CONFIG_KEY, BUDGET_ALERT_USD_DEFAULT, readBudgetAlertUsd } from '../export/cost-utils.ts';
|
|
27
27
|
import { MEMORY_PROJECTION_DIR_CONFIG_KEY, buildMemoryProjectionDirSyntheticEntry } from './commands/recall-files-config.ts';
|
|
28
|
+
import { MEMORY_SHOW_PROVENANCE_CONFIG_KEY, buildMemoryProvenanceSyntheticEntry } from '../core/memory-provenance.ts';
|
|
28
29
|
import {
|
|
29
30
|
injectSandboxExecSyntheticEntries,
|
|
30
31
|
isSandboxExecListConfigKey,
|
|
@@ -52,16 +53,15 @@ import {
|
|
|
52
53
|
} from './settings-modal-types.ts';
|
|
53
54
|
import { enrichRelaySettingDescriptions } from './relay-settings-descriptions.ts';
|
|
54
55
|
import { applyFeatureUnitLayout } from './feature-unit-layout.ts';
|
|
56
|
+
import { FEATURE_SETTINGS_BY_ID } from '../runtime/feature-settings.ts';
|
|
55
57
|
|
|
56
58
|
// ---------------------------------------------------------------------------
|
|
57
59
|
// deepEqual — structural equality for isDefault comparisons
|
|
58
60
|
// ---------------------------------------------------------------------------
|
|
59
61
|
|
|
60
62
|
/**
|
|
61
|
-
* Structural equality
|
|
62
|
-
*
|
|
63
|
-
* circular references or non-plain prototypes — config defaults
|
|
64
|
-
* are always JSON-safe primitives, arrays, or plain objects.
|
|
63
|
+
* Structural equality for setting-default comparisons: scalars, arrays, and
|
|
64
|
+
* plain objects (config defaults are always JSON-safe; no circular refs).
|
|
65
65
|
*/
|
|
66
66
|
export function deepEqual(a: unknown, b: unknown): boolean {
|
|
67
67
|
if (a === b) return true;
|
|
@@ -98,9 +98,8 @@ export function buildSettingGroups(
|
|
|
98
98
|
featureFlagManager?: FeatureFlagManager | null,
|
|
99
99
|
): Map<SettingsCategory, SettingEntry[]> {
|
|
100
100
|
const groups = new Map<SettingsCategory, SettingEntry[]>();
|
|
101
|
-
// Every category starts empty
|
|
102
|
-
//
|
|
103
|
-
// namespaces) and is filled from CONFIG_SCHEMA below.
|
|
101
|
+
// Every category starts empty and is filled from CONFIG_SCHEMA below; the
|
|
102
|
+
// feature-unit layout pass then folds each capability's rows into one unit.
|
|
104
103
|
for (const cat of SETTINGS_CATEGORIES) groups.set(cat, []);
|
|
105
104
|
|
|
106
105
|
for (const setting of CONFIG_SCHEMA) {
|
|
@@ -122,11 +121,11 @@ export function buildSettingGroups(
|
|
|
122
121
|
if ((rawCat === 'controlPlane' || rawCat === 'httpListener' || rawCat === 'web') && groups.has('network')) {
|
|
123
122
|
groups.get('network')!.push(entry);
|
|
124
123
|
}
|
|
124
|
+
// fleet.maxSize (was orchestration.maxActiveAgents) surfaces under orchestration.
|
|
125
|
+
if (rawCat === 'fleet' && groups.has('orchestration')) groups.get('orchestration')!.push(entry);
|
|
125
126
|
}
|
|
126
127
|
|
|
127
|
-
//
|
|
128
|
-
// key stored under the existing `display` section (see theme-mode-config.ts for why
|
|
129
|
-
// not `appearance`), same rationale as the other synthetic settings below.
|
|
128
|
+
// Synthetic display.themeMode enum (auto|dark|light) — TUI-local, see theme-mode-config.ts.
|
|
130
129
|
const displayEntries = groups.get('display');
|
|
131
130
|
if (displayEntries && !displayEntries.some((e) => e.setting.key === (THEME_MODE_CONFIG_KEY as ConfigKey))) {
|
|
132
131
|
displayEntries.push(buildThemeModeSyntheticEntry(configManager));
|
|
@@ -153,26 +152,19 @@ export function buildSettingGroups(
|
|
|
153
152
|
}
|
|
154
153
|
}
|
|
155
154
|
|
|
156
|
-
//
|
|
157
|
-
// tts.speed is not yet a ConfigKey in the SDK schema (pending SDK addition).
|
|
158
|
-
// The entry is surfaced here with an honest description caveat so users can
|
|
159
|
-
// see and understand the setting before the SDK schema catches up.
|
|
155
|
+
// Synthetic tts.speed (not yet an SDK ConfigKey) — surfaced with an honest caveat.
|
|
160
156
|
if (ttsEntries && !ttsEntries.some((e) => e.setting.key === ('tts.speed' as ConfigKey))) {
|
|
161
157
|
ttsEntries.push(buildTtsSpeedSyntheticEntry(configManager));
|
|
162
158
|
}
|
|
163
159
|
|
|
164
|
-
//
|
|
165
|
-
// category. This key is TUI-local (not in the SDK ConfigKey union) and
|
|
166
|
-
// controls the long-task push notification threshold.
|
|
160
|
+
// Synthetic behavior.notifyAfterSeconds (TUI-local): long-task push threshold.
|
|
167
161
|
const behaviorEntries = groups.get('behavior');
|
|
168
162
|
if (behaviorEntries && !behaviorEntries.some((e) => e.setting.key === ('behavior.notifyAfterSeconds' as ConfigKey))) {
|
|
169
163
|
behaviorEntries.push(buildNotifyAfterSecondsSyntheticEntry(configManager));
|
|
170
164
|
}
|
|
171
165
|
|
|
172
|
-
//
|
|
173
|
-
//
|
|
174
|
-
// previously left it with no schema-driven inspection surface at all: it
|
|
175
|
-
// never appeared in /config, and /settings-sync show rejects any key not
|
|
166
|
+
// Synthetic behavior.budgetAlertUsd (TUI-local): no schema surface previously,
|
|
167
|
+
// never in /config; /settings-sync show rejects any key not
|
|
176
168
|
// in CONFIG_KEYS. The Cost panel's 'b' key and /cost budget <usd> remain
|
|
177
169
|
// the primary way to change it; this entry makes the current effective
|
|
178
170
|
// value (and whether it's still the "no budget configured" default)
|
|
@@ -181,7 +173,7 @@ export function buildSettingGroups(
|
|
|
181
173
|
behaviorEntries.push(buildBudgetAlertUsdSyntheticEntry(configManager));
|
|
182
174
|
}
|
|
183
175
|
|
|
184
|
-
// Inject the
|
|
176
|
+
// Inject the alert-class toggles + master focus gate. TUI-local
|
|
185
177
|
// synthetic settings, same rationale as notifyAfterSeconds above.
|
|
186
178
|
if (behaviorEntries) {
|
|
187
179
|
for (const entry of buildNotifyAlertSyntheticEntries(configManager)) {
|
|
@@ -214,6 +206,12 @@ export function buildSettingGroups(
|
|
|
214
206
|
storageEntries.push(buildMemoryProjectionDirSyntheticEntry(configManager));
|
|
215
207
|
}
|
|
216
208
|
|
|
209
|
+
// Synthetic memory.showProvenance (TUI-local, default OFF — see memory-provenance.ts).
|
|
210
|
+
const memoryEntries = groups.get('memory');
|
|
211
|
+
if (memoryEntries && !memoryEntries.some((e) => e.setting.key === (MEMORY_SHOW_PROVENANCE_CONFIG_KEY as ConfigKey))) {
|
|
212
|
+
memoryEntries.push(buildMemoryProvenanceSyntheticEntry(configManager) as unknown as SettingEntry);
|
|
213
|
+
}
|
|
214
|
+
|
|
217
215
|
// Inject the worktree.setup.commands / worktree.setup.carryOverGlobs
|
|
218
216
|
// synthetic entries into the orchestration category (worktree isolation is
|
|
219
217
|
// an orchestration-engine concern — see WorkstreamIsolation 'worktree').
|
|
@@ -240,11 +238,10 @@ export function buildSettingGroups(
|
|
|
240
238
|
// the SDK's own descriptions don't carry (see relay-settings-descriptions.ts).
|
|
241
239
|
enrichRelaySettingDescriptions(groups);
|
|
242
240
|
|
|
243
|
-
// Feature-unit presentation:
|
|
244
|
-
// keys it tunes)
|
|
245
|
-
//
|
|
246
|
-
//
|
|
247
|
-
// flagless test path.
|
|
241
|
+
// Feature-unit presentation: each capability becomes ONE unit (its real
|
|
242
|
+
// enablement row + the settings keys it tunes) in its settings domain,
|
|
243
|
+
// sourced from FEATURE_SETTINGS. Runs AFTER synthetic injection so
|
|
244
|
+
// non-feature-owned rows stay orphans; skipped on the featureless path.
|
|
248
245
|
if (featureFlagManager) applyFeatureUnitLayout(groups, buildFlagEntries(featureFlagManager));
|
|
249
246
|
|
|
250
247
|
// learning.consolidation.* is a real SDK config domain now, so its keys arrive
|
|
@@ -301,7 +298,7 @@ export function buildTtsSpeedSyntheticEntry(configManager: Pick<ConfigManager, '
|
|
|
301
298
|
}
|
|
302
299
|
|
|
303
300
|
// ---------------------------------------------------------------------------
|
|
304
|
-
// display.themeMode synthetic setting (
|
|
301
|
+
// display.themeMode synthetic setting (light theme)
|
|
305
302
|
// ---------------------------------------------------------------------------
|
|
306
303
|
|
|
307
304
|
/**
|
|
@@ -415,11 +412,11 @@ export function buildBudgetAlertUsdSyntheticEntry(configManager: Pick<ConfigMana
|
|
|
415
412
|
}
|
|
416
413
|
|
|
417
414
|
// ---------------------------------------------------------------------------
|
|
418
|
-
//
|
|
415
|
+
// alert-class synthetic settings — behavior.notifyOn* + notifyOnlyWhenUnfocused
|
|
419
416
|
// ---------------------------------------------------------------------------
|
|
420
417
|
|
|
421
418
|
/**
|
|
422
|
-
* The five
|
|
419
|
+
* The five alert-gating booleans, all TUI-local (not yet in the SDK
|
|
423
420
|
* ConfigKey union), all defaulting to on. Read/written generically by
|
|
424
421
|
* core/alert-gating.ts (readBooleanConfig) and the per-alert-class modules
|
|
425
422
|
* (budget-breach-notifier.ts, approval-alert.ts, turn-event-wiring.ts,
|
|
@@ -475,7 +472,7 @@ export function buildNotifyAlertSyntheticEntries(configManager: Pick<ConfigManag
|
|
|
475
472
|
/**
|
|
476
473
|
* The OSC 9 in-terminal desktop-notification toggles + the audible bell.
|
|
477
474
|
* TUI-local synthetic booleans (not in the SDK ConfigKey union), each carrying
|
|
478
|
-
* its OWN default (unlike the always-on
|
|
475
|
+
* its OWN default (unlike the always-on alert toggles above): approval-wait
|
|
479
476
|
* on, turn-end/agent-blocked off, bell off. Read generically by
|
|
480
477
|
* core/terminal-notifier.ts (readBooleanConfig); this is only the
|
|
481
478
|
* settings-modal-visible surface. These are independent of the master
|
|
@@ -537,9 +534,13 @@ export function buildCodeIndexEnabledSyntheticEntry(configManager: Pick<ConfigMa
|
|
|
537
534
|
|
|
538
535
|
export function buildFlagEntries(featureFlagManager: FeatureFlagManager | null): FlagEntry[] {
|
|
539
536
|
if (!featureFlagManager) return [];
|
|
540
|
-
|
|
541
|
-
|
|
542
|
-
|
|
537
|
+
const entries: FlagEntry[] = [];
|
|
538
|
+
for (const { flag, state, persistedState, pendingRestart } of featureFlagManager.getAll().values()) {
|
|
539
|
+
const feature = FEATURE_SETTINGS_BY_ID.get(flag.id);
|
|
540
|
+
if (!feature) continue; // gate with no settings surface (registry/binding drift is SDK test-guarded)
|
|
541
|
+
entries.push({ feature, flag, state, persistedState, pendingRestart });
|
|
542
|
+
}
|
|
543
|
+
return entries;
|
|
543
544
|
}
|
|
544
545
|
|
|
545
546
|
// ---------------------------------------------------------------------------
|
|
@@ -606,44 +607,34 @@ export function refreshEntryValues(
|
|
|
606
607
|
): void {
|
|
607
608
|
for (const entries of groups.values()) {
|
|
608
609
|
for (const entry of entries) {
|
|
609
|
-
//
|
|
610
|
-
// registers the 'worktree' section in DEFAULT_CONFIG, so a plain
|
|
611
|
-
// configManager.get returns the empty default rather than throwing; the
|
|
612
|
-
// helper's guard (belt-and-suspenders for an older SDK) keeps this
|
|
613
|
-
// refresh from crashing for EVERY setting change if the section is ever
|
|
614
|
-
// absent (see worktree-setup-config.ts).
|
|
610
|
+
// worktree.setup.* read through a defensive array-normalizing helper (see worktree-setup-config.ts).
|
|
615
611
|
if (isWorktreeSetupListConfigKey(entry.setting.key)) {
|
|
616
612
|
entry.currentValue = readWorktreeSetupList(configManager, entry.setting.key);
|
|
617
613
|
entry.isDefault = (entry.currentValue as string[]).length === 0;
|
|
618
614
|
continue;
|
|
619
615
|
}
|
|
620
|
-
// sandbox
|
|
621
|
-
// DEFAULT_CONFIG section (has been since before this repack, backing the
|
|
622
|
-
// VM/REPL isolation settings), so a plain get() would not throw — but an
|
|
623
|
-
// unset leaf still reads back as `undefined`, not `[]`, so this still needs
|
|
624
|
-
// the same array-normalizing read as the worktree keys above (see
|
|
625
|
-
// sandbox-exec-config.ts).
|
|
616
|
+
// sandbox.* list leaves normalize an unset undefined to [] (see sandbox-exec-config.ts).
|
|
626
617
|
if (isSandboxExecListConfigKey(entry.setting.key)) {
|
|
627
618
|
entry.currentValue = readSandboxExecList(configManager, entry.setting.key);
|
|
628
619
|
entry.isDefault = (entry.currentValue as string[]).length === 0;
|
|
629
620
|
continue;
|
|
630
621
|
}
|
|
631
|
-
// permissions.execEnvScrubAllowlist: same normalizing
|
|
632
|
-
// 'permissions' is a real section but this leaf is TUI-local (see
|
|
633
|
-
// exec-env-scrub-config.ts).
|
|
622
|
+
// permissions.execEnvScrubAllowlist: same array-normalizing read (see exec-env-scrub-config.ts).
|
|
634
623
|
if (isExecEnvScrubAllowlistConfigKey(entry.setting.key)) {
|
|
635
624
|
entry.currentValue = readExecEnvScrubAllowlist(configManager);
|
|
636
625
|
entry.isDefault = (entry.currentValue as string[]).length === 0;
|
|
637
626
|
continue;
|
|
638
627
|
}
|
|
639
|
-
// '
|
|
640
|
-
// so learning.consolidation.* keys read through the plain path below like any
|
|
641
|
-
// other schema-driven setting — no special case needed anymore.
|
|
642
|
-
// Same trap still applies here: 'memory' has no DEFAULT_CONFIG entry.
|
|
628
|
+
// 'memory' has no DEFAULT_CONFIG entry — its synthetic leaves read defensively below.
|
|
643
629
|
if (entry.setting.key === MEMORY_PROJECTION_DIR_CONFIG_KEY) {
|
|
644
630
|
const refreshed = buildMemoryProjectionDirSyntheticEntry(configManager);
|
|
645
|
-
entry.currentValue = refreshed.currentValue;
|
|
646
|
-
|
|
631
|
+
entry.currentValue = refreshed.currentValue; entry.isDefault = refreshed.isDefault;
|
|
632
|
+
continue;
|
|
633
|
+
}
|
|
634
|
+
// memory.showProvenance: same 'memory'-has-no-DEFAULT_CONFIG trap — read defensively.
|
|
635
|
+
if (entry.setting.key === (MEMORY_SHOW_PROVENANCE_CONFIG_KEY as ConfigKey)) {
|
|
636
|
+
const refreshed = buildMemoryProvenanceSyntheticEntry(configManager);
|
|
637
|
+
entry.currentValue = refreshed.currentValue; entry.isDefault = refreshed.isDefault;
|
|
647
638
|
continue;
|
|
648
639
|
}
|
|
649
640
|
const raw = configManager.get(entry.setting.key as ConfigKey);
|
|
@@ -676,8 +667,12 @@ export function updateEntryForKey(
|
|
|
676
667
|
if (entry) {
|
|
677
668
|
if (key === MEMORY_PROJECTION_DIR_CONFIG_KEY) {
|
|
678
669
|
const refreshed = buildMemoryProjectionDirSyntheticEntry(configManager);
|
|
679
|
-
entry.currentValue = refreshed.currentValue;
|
|
680
|
-
|
|
670
|
+
entry.currentValue = refreshed.currentValue; entry.isDefault = refreshed.isDefault;
|
|
671
|
+
continue;
|
|
672
|
+
}
|
|
673
|
+
if (key === (MEMORY_SHOW_PROVENANCE_CONFIG_KEY as ConfigKey)) {
|
|
674
|
+
const refreshed = buildMemoryProvenanceSyntheticEntry(configManager);
|
|
675
|
+
entry.currentValue = refreshed.currentValue; entry.isDefault = refreshed.isDefault;
|
|
681
676
|
continue;
|
|
682
677
|
}
|
|
683
678
|
if (isSandboxExecListConfigKey(key)) {
|
|
@@ -1,17 +1,18 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* settings-modal-mutations — pure mutation helpers for SettingsModal.
|
|
3
3
|
*
|
|
4
|
-
* These functions encapsulate the side-effectful write operations
|
|
5
|
-
*
|
|
6
|
-
*
|
|
7
|
-
*
|
|
4
|
+
* These functions encapsulate the side-effectful write operations. Every
|
|
5
|
+
* write — feature-unit headers included — is a plain domain-settings config
|
|
6
|
+
* write; the SDK's settings bridge keeps the runtime gate manager in sync
|
|
7
|
+
* (flipping runtime-toggleable gates live and recording honest
|
|
8
|
+
* pending-restart markers for startup-gated ones). Each function takes its
|
|
9
|
+
* dependencies as explicit arguments rather than accessing class-level state.
|
|
8
10
|
*/
|
|
9
11
|
|
|
10
|
-
import type { ConfigKey
|
|
12
|
+
import type { ConfigKey } from '@pellux/goodvibes-sdk/platform/config';
|
|
11
13
|
import type { ConfigManager } from '@pellux/goodvibes-sdk/platform/config';
|
|
12
14
|
import { logger, summarizeError } from '@pellux/goodvibes-sdk/platform/utils';
|
|
13
15
|
import type { FeatureFlagManager } from '@/runtime/index.ts';
|
|
14
|
-
import type { FeatureFlag, FlagState } from '@/runtime/index.ts';
|
|
15
16
|
import type { FlagEntry, SettingEntry } from './settings-modal-types.ts';
|
|
16
17
|
import { deepEqual } from './settings-modal-data.ts';
|
|
17
18
|
|
|
@@ -83,10 +84,12 @@ export function applySettingValue({
|
|
|
83
84
|
};
|
|
84
85
|
}
|
|
85
86
|
|
|
86
|
-
// Update
|
|
87
|
+
// Update every entry carrying this key: cross-listed rows (the network
|
|
88
|
+
// combined view) and feature-unit headers that share one enablement key
|
|
89
|
+
// (e.g. both compaction features read behavior.compactionStrategy).
|
|
87
90
|
for (const entries of groups.values()) {
|
|
88
|
-
const entry
|
|
89
|
-
|
|
91
|
+
for (const entry of entries) {
|
|
92
|
+
if (entry.setting.key !== key) continue;
|
|
90
93
|
entry.currentValue = configManager.get(key);
|
|
91
94
|
entry.isDefault = deepEqual(entry.currentValue, entry.setting.default);
|
|
92
95
|
}
|
|
@@ -112,65 +115,6 @@ export function applySettingValue({
|
|
|
112
115
|
return { restartDomain, effectMessage, changed: previousValue !== value };
|
|
113
116
|
}
|
|
114
117
|
|
|
115
|
-
// ---------------------------------------------------------------------------
|
|
116
|
-
// persistFlagState — write a flag override to config
|
|
117
|
-
// ---------------------------------------------------------------------------
|
|
118
|
-
|
|
119
|
-
export function persistFlagState(
|
|
120
|
-
configManager: ConfigManager,
|
|
121
|
-
flagId: string,
|
|
122
|
-
newState: FlagState,
|
|
123
|
-
defaultState: FlagState,
|
|
124
|
-
): void {
|
|
125
|
-
if (newState === 'killed') return; // never persist killed state
|
|
126
|
-
|
|
127
|
-
try {
|
|
128
|
-
if (newState === defaultState) {
|
|
129
|
-
// Back at the default: the override must be REMOVED, not merged.
|
|
130
|
-
// getCategory clones and mergeCategory only sets keys, so the old
|
|
131
|
-
// delete-then-merge approach left the stale override on disk and the
|
|
132
|
-
// flag silently reloaded in the overridden state on the next start.
|
|
133
|
-
configManager.removeCategoryKey('featureFlags', flagId);
|
|
134
|
-
} else {
|
|
135
|
-
configManager.mergeCategory('featureFlags', { [flagId]: newState } as Record<string, PersistedFlagState>);
|
|
136
|
-
}
|
|
137
|
-
} catch (e) {
|
|
138
|
-
logger.error('SettingsModal: failed to persist flag state', { flagId, error: summarizeError(e) });
|
|
139
|
-
}
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
// ---------------------------------------------------------------------------
|
|
143
|
-
// applyFlagState — toggle a feature flag (runtime + persist)
|
|
144
|
-
// ---------------------------------------------------------------------------
|
|
145
|
-
|
|
146
|
-
export function applyFlagState(
|
|
147
|
-
flagEntry: FlagEntry,
|
|
148
|
-
newState: FlagState,
|
|
149
|
-
featureFlagManager: FeatureFlagManager,
|
|
150
|
-
configManager: ConfigManager,
|
|
151
|
-
): void {
|
|
152
|
-
const flag: FeatureFlag = flagEntry.flag;
|
|
153
|
-
|
|
154
|
-
try {
|
|
155
|
-
// Persist first so the on-disk override is the source of truth, then apply
|
|
156
|
-
// the same value to the live manager through applyConfigState. That single
|
|
157
|
-
// call keeps both paths consistent with the SDK's config→flag bridge:
|
|
158
|
-
// - runtime-toggleable flags apply immediately (firing flag subscribers
|
|
159
|
-
// exactly as a direct enable()/disable() would), and
|
|
160
|
-
// - startup-gated flags are NOT faked live — the effective state is left
|
|
161
|
-
// untouched and a pending-restart marker is recorded instead.
|
|
162
|
-
persistFlagState(configManager, flag.id, newState, flag.defaultState as FlagState);
|
|
163
|
-
featureFlagManager.applyConfigState(flag.id, newState);
|
|
164
|
-
} catch (e) {
|
|
165
|
-
logger.error('SettingsModal: failed to toggle feature flag', { flag: flag.id, error: summarizeError(e) });
|
|
166
|
-
}
|
|
167
|
-
|
|
168
|
-
// Reflect the manager's real state, never the requested target: for a
|
|
169
|
-
// startup-gated flag `state` stays at the unchanged effective value and
|
|
170
|
-
// `pendingRestart` reports that a restart is needed for `persistedState`.
|
|
171
|
-
syncFlagEntryFromManager(flagEntry, featureFlagManager);
|
|
172
|
-
}
|
|
173
|
-
|
|
174
118
|
/**
|
|
175
119
|
* Refresh a FlagEntry's live/persisted/pending fields from the manager's
|
|
176
120
|
* authoritative snapshot so the settings UI never displays a guessed state.
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
import type { ConfigSetting } from '@pellux/goodvibes-sdk/platform/config';
|
|
2
2
|
import type { ProviderAuthFreshness, ProviderAuthRoute } from '@/runtime/index.ts';
|
|
3
|
-
import type { FeatureFlag, FlagState } from '@/runtime/index.ts';
|
|
3
|
+
import type { FeatureFlag, FeatureSetting, FlagState } from '@/runtime/index.ts';
|
|
4
4
|
|
|
5
5
|
export type SettingsCategory =
|
|
6
6
|
| 'display'
|
|
7
7
|
| 'ui'
|
|
8
8
|
| 'provider'
|
|
9
|
+
| 'pricing'
|
|
9
10
|
| 'subscriptions'
|
|
10
11
|
| 'behavior'
|
|
11
12
|
| 'storage'
|
|
@@ -17,6 +18,7 @@ export type SettingsCategory =
|
|
|
17
18
|
| 'tools'
|
|
18
19
|
| 'helper'
|
|
19
20
|
| 'tts'
|
|
21
|
+
| 'voice'
|
|
20
22
|
| 'service'
|
|
21
23
|
| 'daemon'
|
|
22
24
|
| 'controlPlane'
|
|
@@ -43,8 +45,10 @@ export type SettingsCategory =
|
|
|
43
45
|
| 'integrations'
|
|
44
46
|
| 'policy'
|
|
45
47
|
| 'notifications'
|
|
46
|
-
| 'flags'
|
|
47
48
|
| 'release'
|
|
49
|
+
| 'update'
|
|
50
|
+
| 'power'
|
|
51
|
+
| 'memory'
|
|
48
52
|
| 'danger';
|
|
49
53
|
|
|
50
54
|
export type SettingsFocusPane = 'categories' | 'settings';
|
|
@@ -54,12 +58,12 @@ export const SETTINGS_CATEGORY_GROUPS: ReadonlyArray<{
|
|
|
54
58
|
readonly categories: readonly SettingsCategory[];
|
|
55
59
|
}> = [
|
|
56
60
|
{ label: 'Interface', categories: ['display', 'ui', 'behavior', 'notifications', 'permissions', 'policy', 'security'] },
|
|
57
|
-
{ label: 'AI Routing', categories: ['provider', 'subscriptions', 'helper', 'tools', 'tts'] },
|
|
61
|
+
{ label: 'AI Routing', categories: ['provider', 'pricing', 'subscriptions', 'helper', 'tools', 'tts', 'voice'] },
|
|
58
62
|
{ label: 'Service & Network', categories: ['service', 'daemon', 'network', 'controlPlane', 'httpListener', 'web', 'relay'] },
|
|
59
63
|
{ label: 'Surfaces & Cloud', categories: ['surfaces', 'integrations', 'mcp', 'cloudflare'] },
|
|
60
64
|
{ label: 'Automation', categories: ['batch', 'automation', 'checkin', 'watchers', 'orchestration', 'planner', 'wrfc'] },
|
|
61
|
-
{ label: 'Runtime & Data', categories: ['storage', 'atRest', 'sandbox', 'fetch', 'agents', 'runtime', 'cache', 'telemetry', 'diagnostics', 'learning'] },
|
|
62
|
-
{ label: 'Advanced', categories: ['
|
|
65
|
+
{ label: 'Runtime & Data', categories: ['storage', 'atRest', 'sandbox', 'fetch', 'agents', 'runtime', 'power', 'memory', 'cache', 'telemetry', 'diagnostics', 'learning'] },
|
|
66
|
+
{ label: 'Advanced', categories: ['release', 'update', 'danger'] },
|
|
63
67
|
];
|
|
64
68
|
|
|
65
69
|
export const SETTINGS_CATEGORIES: SettingsCategory[] = SETTINGS_CATEGORY_GROUPS.flatMap(group => group.categories);
|
|
@@ -74,34 +78,40 @@ export interface SettingEntry {
|
|
|
74
78
|
sourceLabel?: string;
|
|
75
79
|
lockReason?: string;
|
|
76
80
|
/**
|
|
77
|
-
* Present when this row is a feature-unit
|
|
78
|
-
* rendered as one unit with
|
|
79
|
-
*
|
|
80
|
-
*
|
|
81
|
+
* Present when this row is a feature-unit header (a platform capability
|
|
82
|
+
* rendered as one unit with the settings that tune it beneath). The row IS
|
|
83
|
+
* the real config row for the feature's enablement key — boolean headers
|
|
84
|
+
* toggle and enum headers cycle their mode choices through the ordinary
|
|
85
|
+
* settings write path (a plain config write; the settings bridge keeps the
|
|
86
|
+
* runtime gate in sync).
|
|
81
87
|
*/
|
|
82
88
|
flag?: FlagEntry;
|
|
83
89
|
/**
|
|
84
|
-
* Present when this row is a
|
|
85
|
-
* id of the owning
|
|
86
|
-
* marks the row as claimed so it does not double-list as an
|
|
90
|
+
* Present when this row is a settings sub-option OWNED by a feature unit —
|
|
91
|
+
* the id of the owning feature. Drives the indented rendering beneath its
|
|
92
|
+
* header and marks the row as claimed so it does not double-list as an
|
|
93
|
+
* orphan.
|
|
87
94
|
*/
|
|
88
95
|
ownerFlagId?: string;
|
|
89
96
|
}
|
|
90
97
|
|
|
91
98
|
export interface FlagEntry {
|
|
99
|
+
/** The per-feature settings metadata (domain, enablement shape, settings keys, real description). */
|
|
100
|
+
feature: FeatureSetting;
|
|
101
|
+
/** The internal gate declaration (kill state/reason live here). */
|
|
92
102
|
flag: FeatureFlag;
|
|
93
103
|
/** Live effective state as the runtime currently sees it. */
|
|
94
104
|
state: FlagState;
|
|
95
105
|
/**
|
|
96
106
|
* Last known config-layer (persisted) value. Equals `state` unless a
|
|
97
|
-
* startup-gated
|
|
98
|
-
* will take effect on the next launch.
|
|
107
|
+
* startup-gated feature was changed this session — then it holds the value
|
|
108
|
+
* that will take effect on the next launch.
|
|
99
109
|
*/
|
|
100
110
|
persistedState: FlagState;
|
|
101
111
|
/**
|
|
102
|
-
* True when a startup-gated
|
|
103
|
-
* state, i.e. a restart is required before the change takes
|
|
104
|
-
* from FeatureFlagManager.getAll(), never guessed.
|
|
112
|
+
* True when a startup-gated feature's persisted value differs from its
|
|
113
|
+
* effective state, i.e. a restart is required before the change takes
|
|
114
|
+
* effect. Sourced from FeatureFlagManager.getAll(), never guessed.
|
|
105
115
|
*/
|
|
106
116
|
pendingRestart: boolean;
|
|
107
117
|
}
|