@pellux/goodvibes-tui 1.16.0 → 1.17.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 +95 -9
- package/README.md +1 -1
- package/docs/foundation-artifacts/operator-contract.json +1091 -271
- 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/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/conversation-line-cache.ts +3 -3
- package/src/core/conversation-rendering.ts +4 -4
- package/src/core/conversation.ts +2 -2
- package/src/core/long-task-notifier.ts +7 -7
- package/src/core/stream-event-wiring.ts +8 -6
- package/src/core/system-message-noise.ts +1 -1
- package/src/core/system-message-router.ts +6 -6
- package/src/core/turn-cancellation.ts +1 -1
- package/src/core/turn-event-wiring.ts +8 -8
- package/src/daemon/cli.ts +20 -5
- 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 +34 -9
- 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/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/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/provider-accounts-runtime.ts +71 -6
- package/src/input/commands/provider.ts +7 -5
- 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-runtime.ts +2 -2
- package/src/input/commands.ts +0 -2
- package/src/input/config-modal-types.ts +3 -3
- package/src/input/config-modal.ts +10 -11
- 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 +6 -6
- package/src/input/handler.ts +2 -2
- package/src/input/keybindings.ts +2 -2
- 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 +22 -21
- package/src/input/settings-modal-mutations.ts +12 -68
- package/src/input/settings-modal-types.ts +23 -16
- package/src/input/settings-modal.ts +74 -55
- package/src/main.ts +48 -48
- 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 +29 -10
- package/src/panels/builtin/session.ts +5 -5
- package/src/panels/builtin/shared.ts +4 -4
- package/src/panels/builtin-modals.ts +10 -10
- package/src/panels/builtin-panels.ts +1 -1
- package/src/panels/cost-tracker-panel.ts +124 -7
- package/src/panels/diff-panel.ts +5 -5
- package/src/panels/eval-registry.ts +2 -2
- package/src/panels/fleet-deep-link.ts +1 -1
- package/src/panels/fleet-panel-format.ts +44 -8
- package/src/panels/fleet-panel.ts +16 -16
- package/src/panels/fleet-read-model.ts +52 -13
- package/src/panels/fleet-steer.ts +2 -2
- package/src/panels/fleet-stop.ts +3 -3
- package/src/panels/fleet-tabs.ts +13 -14
- 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/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 +4 -4
- 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 +2 -2
- 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 +1 -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/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/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/onboarding/onboarding-wizard.ts +22 -8
- 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 +102 -24
- package/src/renderer/session-picker-modal.ts +2 -2
- package/src/renderer/settings-modal-helpers.ts +14 -5
- package/src/renderer/settings-modal.ts +127 -39
- package/src/renderer/shell-surface.ts +3 -0
- package/src/renderer/terminal-bg-probe.ts +1 -1
- package/src/renderer/theme.ts +3 -3
- package/src/renderer/tool-call.ts +1 -1
- package/src/renderer/tool-result-summary.ts +1 -1
- package/src/renderer/turn-injection.ts +7 -6
- package/src/renderer/ui-factory.ts +6 -1
- package/src/runtime/bootstrap-command-context.ts +4 -1
- package/src/runtime/bootstrap-command-parts.ts +6 -4
- package/src/runtime/bootstrap-core.ts +35 -35
- package/src/runtime/bootstrap-hook-bridge.ts +1 -1
- package/src/runtime/bootstrap-shell.ts +6 -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 +55 -0
- package/src/runtime/embedded-service-factories.ts +40 -0
- package/src/runtime/feature-settings.ts +147 -0
- package/src/runtime/index.ts +4 -21
- 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/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 +81 -82
- 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 +3 -1
- package/src/runtime/update-check.ts +15 -69
- package/src/runtime/workstream-services.ts +2 -2
- package/src/shell/blocking-input.ts +102 -6
- 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
|
@@ -3,6 +3,7 @@ import { beginOpenAICodexLogin, exchangeOpenAICodexCode } from '@pellux/goodvibe
|
|
|
3
3
|
import { summarizeError, openExternalUrl } from '@pellux/goodvibes-sdk/platform/utils';
|
|
4
4
|
import { getProviderIdFromModel } from '../config/provider-model.ts';
|
|
5
5
|
import { buildProviderAccountSnapshot } from '@/runtime/index.ts';
|
|
6
|
+
import { enrichProviderAccountsSnapshot } from '../runtime/onboarding/provider-key-capture.ts';
|
|
6
7
|
import { handleConnectExistingDaemonForHandler, handleMigrateLegacyDaemonServiceForHandler } from './handler-onboarding-daemon-adopt.ts';
|
|
7
8
|
import { detectLegacyUnit, resolveConfiguredServiceName } from '../runtime/legacy-daemon-migration.ts';
|
|
8
9
|
import { OnboardingWizardController, type OnboardingWizardAction, type OnboardingWizardApplyFeedback } from './onboarding/onboarding-wizard.ts';
|
|
@@ -376,12 +377,12 @@ export async function refreshOnboardingHydrationForHandler(handler: InputHandler
|
|
|
376
377
|
list: () => handler.uiServices.platform.surfaceRegistry.syncConfiguredSurfaces(),
|
|
377
378
|
},
|
|
378
379
|
providerAccounts: {
|
|
379
|
-
loadSnapshot: () => buildProviderAccountSnapshot({
|
|
380
|
+
loadSnapshot: async () => enrichProviderAccountsSnapshot(await buildProviderAccountSnapshot({
|
|
380
381
|
providerRegistry: handler.uiServices.providers.providerRegistry,
|
|
381
382
|
serviceRegistry: handler.uiServices.platform.serviceRegistry,
|
|
382
383
|
subscriptionManager: handler.uiServices.platform.subscriptionManager,
|
|
383
384
|
secretsManager: handler.uiServices.platform.secretsManager,
|
|
384
|
-
}),
|
|
385
|
+
}), handler.uiServices.providers.providerRegistry),
|
|
385
386
|
},
|
|
386
387
|
legacyDaemon: {
|
|
387
388
|
detect: () => ({ ...detectLegacyUnit({ homeDir: handler.uiServices.environment.homeDirectory }), trackedServiceName: resolveConfiguredServiceName(handler.uiServices.platform.configManager) }),
|
|
@@ -3,6 +3,7 @@ import type { InputToken } from '@pellux/goodvibes-sdk/platform/core';
|
|
|
3
3
|
import type { CommandContext } from './command-registry.ts';
|
|
4
4
|
import type { CapabilityFilter, CategoryFilter, ModelPickerModal } from './model-picker.ts';
|
|
5
5
|
import { MODEL_PICKER_CHROME_LINES } from '../renderer/model-picker-overlay.ts';
|
|
6
|
+
import { ensureProviderKeyThenSelect } from './provider-key-intake.ts';
|
|
6
7
|
import { resolveAndValidatePath } from '@pellux/goodvibes-sdk/platform/utils';
|
|
7
8
|
import { logger } from '@pellux/goodvibes-sdk/platform/utils';
|
|
8
9
|
import type { BlockActionId } from '../renderer/block-actions.ts';
|
|
@@ -66,15 +67,17 @@ export function handleModelPickerToken(state: ModelPickerRouteState, token: Inpu
|
|
|
66
67
|
} else {
|
|
67
68
|
const target = state.modelPicker.target;
|
|
68
69
|
const handled = state.onModelPickerCommit?.() ?? false;
|
|
69
|
-
if (!handled) {
|
|
70
|
-
state.commandContext?.completeModelSelection?.({
|
|
71
|
-
model: selected,
|
|
72
|
-
effort: currentEffort,
|
|
73
|
-
target,
|
|
74
|
-
});
|
|
75
|
-
}
|
|
76
70
|
state.modelPicker.close();
|
|
77
71
|
if (state.modalStack[state.modalStack.length - 1] === 'modelPicker') state.modalStack.pop();
|
|
72
|
+
const ctx = state.commandContext;
|
|
73
|
+
if (!handled && ctx) {
|
|
74
|
+
// Selecting an unconfigured provider captures its key inline
|
|
75
|
+
// (concealed prompt → secrets manager → live re-register) and
|
|
76
|
+
// only then completes the original selection.
|
|
77
|
+
ensureProviderKeyThenSelect(ctx, selected.provider, () => {
|
|
78
|
+
ctx.completeModelSelection?.({ model: selected, effort: currentEffort, target });
|
|
79
|
+
});
|
|
80
|
+
}
|
|
78
81
|
}
|
|
79
82
|
}
|
|
80
83
|
} else if (mode === 'provider') {
|
|
@@ -88,12 +91,16 @@ export function handleModelPickerToken(state: ModelPickerRouteState, token: Inpu
|
|
|
88
91
|
} else if (mode === 'effort') {
|
|
89
92
|
const model = state.modelPicker.pendingModel;
|
|
90
93
|
const effort = state.modelPicker.effortLevels[idx];
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
if (!handled) state.commandContext?.completeModelSelection?.({ model, effort, target: state.modelPicker.target });
|
|
94
|
-
}
|
|
94
|
+
const target = state.modelPicker.target;
|
|
95
|
+
const handled = model && effort ? (state.onModelPickerCommit?.() ?? false) : false;
|
|
95
96
|
state.modelPicker.close();
|
|
96
97
|
if (state.modalStack[state.modalStack.length - 1] === 'modelPicker') state.modalStack.pop();
|
|
98
|
+
const ctx = state.commandContext;
|
|
99
|
+
if (model && effort && !handled && ctx) {
|
|
100
|
+
ensureProviderKeyThenSelect(ctx, model.provider, () => {
|
|
101
|
+
ctx.completeModelSelection?.({ model, effort, target });
|
|
102
|
+
});
|
|
103
|
+
}
|
|
97
104
|
} else if (mode === 'embeddingProvider') {
|
|
98
105
|
const selectedProvider = state.modelPicker.embeddingProviders[idx];
|
|
99
106
|
if (selectedProvider) {
|
|
@@ -113,10 +120,16 @@ export function handleModelPickerToken(state: ModelPickerRouteState, token: Inpu
|
|
|
113
120
|
state.modelPicker.contextCapError = null;
|
|
114
121
|
const validCap = parsedCap !== null && parsedCap > 0 && parsedCap <= 10_000_000 ? parsedCap : null;
|
|
115
122
|
const effort = state.commandContext?.session.runtime.reasoningEffort ?? 'medium';
|
|
123
|
+
const target = state.modelPicker.target;
|
|
116
124
|
const handled = state.onModelPickerCommit?.() ?? false;
|
|
117
|
-
if (!handled) state.commandContext?.completeModelSelection?.({ model: capModel, effort, contextCap: validCap, target: state.modelPicker.target });
|
|
118
125
|
state.modelPicker.close();
|
|
119
126
|
if (state.modalStack[state.modalStack.length - 1] === 'modelPicker') state.modalStack.pop();
|
|
127
|
+
const ctx = state.commandContext;
|
|
128
|
+
if (!handled && ctx) {
|
|
129
|
+
ensureProviderKeyThenSelect(ctx, capModel.provider, () => {
|
|
130
|
+
ctx.completeModelSelection?.({ model: capModel, effort, contextCap: validCap, target });
|
|
131
|
+
});
|
|
132
|
+
}
|
|
120
133
|
}
|
|
121
134
|
} else {
|
|
122
135
|
state.modelPicker.close();
|
|
@@ -214,7 +227,7 @@ function cycleCapabilityFilter(modelPicker: ModelPickerModal): void {
|
|
|
214
227
|
modelPicker.setCapabilityFilter(cycle[(cur + 1) % cycle.length]!);
|
|
215
228
|
}
|
|
216
229
|
|
|
217
|
-
//
|
|
230
|
+
// e / retirement: the process-modal and live-tail-modal token routes
|
|
218
231
|
// were removed with those modals (F2 now opens Fleet, which subsumes the live
|
|
219
232
|
// process tree). ProcessModal/AgentDetailModal/LiveTailModal were structurally
|
|
220
233
|
// unreachable after the F2 repoint and were deleted.
|
|
@@ -84,7 +84,7 @@ export function handleGlobalShortcutToken(
|
|
|
84
84
|
// unclaimed key once panelFocused is true and reports it handled). The
|
|
85
85
|
// practical effect was that F2 could OPEN+focus the Fleet panel exactly
|
|
86
86
|
// once; every subsequent press while already focused vanished silently —
|
|
87
|
-
// "F2 pressed 4x never closed the panel" (
|
|
87
|
+
// "F2 pressed 4x never closed the panel" (evaluator finding). Routing
|
|
88
88
|
// it here, before handlePanelFocusToken ever sees the token, gives F2 the
|
|
89
89
|
// same toggle semantics as Ctrl+O below, matching how Ctrl+P/panel-picker
|
|
90
90
|
// was already reachable regardless of panelFocused.
|
|
@@ -139,7 +139,7 @@ export function handleGlobalShortcutToken(
|
|
|
139
139
|
// in-panel action (FleetPanel session-tab detach) before it closes the
|
|
140
140
|
// panel outright — see Panel.interceptPanelClose's doc comment.
|
|
141
141
|
if (active?.interceptPanelClose?.()) {
|
|
142
|
-
//
|
|
142
|
+
// fix: a consumed Ctrl+X (the Fleet panel's session-tab detach)
|
|
143
143
|
// used to leave panelFocused untouched, so focus stayed on the panel
|
|
144
144
|
// — the evaluator's "Ctrl+X detach landed focus in the panel and a
|
|
145
145
|
// typed question became nav keys". Detach is a leave-taking action:
|
|
@@ -203,7 +203,7 @@ export function handleGlobalShortcutToken(
|
|
|
203
203
|
// Alt+1..9: jump directly to the Nth workspace tab. Routed globally (like
|
|
204
204
|
// panel-tab-next/prev) so the jump works whether focus is on the prompt or
|
|
205
205
|
// the workspace; gated on visibility, matching cyclePanelTab semantics.
|
|
206
|
-
//
|
|
206
|
+
// a chord jump is "I'm going panel-driving" (focus rule 1a) — the
|
|
207
207
|
// jump now also grabs keyboard focus, matching F2/Ctrl+O/Ctrl+P, so j/k
|
|
208
208
|
// land in the newly-active tab immediately instead of the composer.
|
|
209
209
|
const pm = state.panelManager;
|
|
@@ -218,9 +218,9 @@ export function handleGlobalShortcutToken(
|
|
|
218
218
|
}
|
|
219
219
|
|
|
220
220
|
case 'panel-ops': {
|
|
221
|
-
// Ctrl+O: TOGGLE the Fleet panel (
|
|
221
|
+
// Ctrl+O: TOGGLE the Fleet panel (— same semantics as F2 above; see
|
|
222
222
|
// toggleFleetPanel's doc comment). The former Ops Control panel was
|
|
223
|
-
// retired to an 'ops-control' -> 'fleet' alias
|
|
223
|
+
// retired to an 'ops-control' -> 'fleet' alias; rather than route
|
|
224
224
|
// through the now-aliased openOpsPanel callback (which opens without
|
|
225
225
|
// transferring focus), this operates on 'fleet' directly.
|
|
226
226
|
toggleFleetPanel(state);
|
|
@@ -403,7 +403,7 @@ export function handleGlobalShortcutToken(
|
|
|
403
403
|
}
|
|
404
404
|
|
|
405
405
|
/**
|
|
406
|
-
* toggleFleetPanel — the shared F2 / Ctrl+O TOGGLE (
|
|
406
|
+
* toggleFleetPanel — the shared F2 / Ctrl+O TOGGLE (item 2): if the
|
|
407
407
|
* Fleet panel is open AND the panel workspace currently owns keyboard focus
|
|
408
408
|
* with Fleet as the active tab, the chord CLOSES it and returns focus to the
|
|
409
409
|
* composer; if Fleet is open but not the focused/active tab, the chord brings
|
package/src/input/handler.ts
CHANGED
|
@@ -194,7 +194,7 @@ export class InputHandler implements InputHandlerLike {
|
|
|
194
194
|
public blockActionsMenu = new BlockActionsMenu();
|
|
195
195
|
public settingsModal = new SettingsModal();
|
|
196
196
|
public configModal = new ConfigModal();
|
|
197
|
-
/**
|
|
197
|
+
/** item 5 — paste-flood guard state, mutated in place across tokens (never reallocated). */
|
|
198
198
|
private panelBurstGuard: PanelBurstGuardState = { timestamps: [], suspended: false, hintShown: false };
|
|
199
199
|
public mcpWorkspace = new McpWorkspace();
|
|
200
200
|
public onboardingWizard = new OnboardingWizardController();
|
|
@@ -277,7 +277,7 @@ export class InputHandler implements InputHandlerLike {
|
|
|
277
277
|
uiServices.providers.benchmarkStore,
|
|
278
278
|
uiServices.providers.providerRegistry,
|
|
279
279
|
);
|
|
280
|
-
//
|
|
280
|
+
// retirement: ProcessModal/LiveTailModal/AgentDetailModal were removed
|
|
281
281
|
// — F2 now opens the Fleet panel, which subsumes the live process tree.
|
|
282
282
|
this.bookmarkModal = new BookmarkModal(uiServices.shell.bookmarkManager);
|
|
283
283
|
this.sessionPickerModal = new SessionPickerModal(uiServices.sessions.sessionManager, uiServices.sessions.sessionBroker);
|
package/src/input/keybindings.ts
CHANGED
|
@@ -147,8 +147,8 @@ export const DEFAULT_KEYBINDINGS: Record<KeyAction, KeyCombo[]> = {
|
|
|
147
147
|
'panel-tab-8': [{ key: '8', alt: true }],
|
|
148
148
|
'panel-tab-9': [{ key: '9', alt: true }],
|
|
149
149
|
// Ctrl+O: TOGGLE the Fleet panel (open+focus / bring-to-front+focus / close
|
|
150
|
-
// — see toggleFleetPanel in handler-shortcuts.ts
|
|
151
|
-
// Control panel was retired to an 'ops-control' -> 'fleet' alias
|
|
150
|
+
// — see toggleFleetPanel in handler-shortcuts.ts). The former Ops
|
|
151
|
+
// Control panel was retired to an 'ops-control' -> 'fleet' alias; the
|
|
152
152
|
// binding is KEPT (repointed, not removed) so the Ctrl+O muscle memory still
|
|
153
153
|
// lands somewhere useful. Routed globally in handleGlobalShortcutToken.
|
|
154
154
|
'panel-ops': [{ key: 'o', ctrl: true }],
|
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
*/
|
|
16
16
|
|
|
17
17
|
import type { ConfigKey } from '../../config/index.ts';
|
|
18
|
-
import {
|
|
18
|
+
import { getFeatureSetting, isFeatureDefaultEnabled } from '../../runtime/feature-settings.ts';
|
|
19
19
|
import type {
|
|
20
20
|
OnboardingWizardControllerLike,
|
|
21
21
|
OnboardingWizardFieldDefinition,
|
|
@@ -94,12 +94,13 @@ export const FEATURE_ONBOARDING_SECTIONS: readonly FeatureSection[] = [
|
|
|
94
94
|
hint: 'When the exec sandbox leaves a command on ask, a model pass annotates the ask with stated reasons. Never converts allow to deny; never touches the frozen catastrophic block.',
|
|
95
95
|
subOptions: [
|
|
96
96
|
{
|
|
97
|
-
key: '
|
|
98
|
-
configKey: 'sandbox.
|
|
99
|
-
label: '
|
|
100
|
-
hint: '
|
|
101
|
-
valueType: '
|
|
102
|
-
|
|
97
|
+
key: 'mode',
|
|
98
|
+
configKey: 'sandbox.judgment' as ConfigKey,
|
|
99
|
+
label: 'Judgment mode',
|
|
100
|
+
hint: 'annotate (default) proposes a verdict with stated reasons and the human still decides; auto-approve additionally auto-approves looks-safe verdicts; off keeps plain asks.',
|
|
101
|
+
valueType: 'enum',
|
|
102
|
+
options: ['off', 'annotate', 'auto-approve'],
|
|
103
|
+
defaultValue: 'annotate',
|
|
103
104
|
},
|
|
104
105
|
],
|
|
105
106
|
},
|
|
@@ -283,23 +284,18 @@ export const FEATURE_ONBOARDING_SECTIONS: readonly FeatureSection[] = [
|
|
|
283
284
|
{
|
|
284
285
|
flagId: 'integration-delivery-slo',
|
|
285
286
|
label: 'Integration delivery SLO',
|
|
286
|
-
hint: 'Retry with backoff and a dead-letter queue for Slack/Discord/webhook delivery.
|
|
287
|
-
subOptions: [
|
|
288
|
-
{
|
|
289
|
-
key: 'slo',
|
|
290
|
-
configKey: 'integrations.delivery.sloEnforced' as ConfigKey,
|
|
291
|
-
label: 'Enforce delivery SLO',
|
|
292
|
-
hint: 'Yes logs dead-letter events at error level and surfaces them in diagnostics; No is warn-level only (default).',
|
|
293
|
-
valueType: 'boolean',
|
|
294
|
-
defaultValue: 'no',
|
|
295
|
-
},
|
|
296
|
-
],
|
|
287
|
+
hint: 'Retry with backoff and a dead-letter queue for Slack/Discord/webhook delivery, with dead-letter events surfaced in diagnostics. On by default; exposes /notify dlq and /notify replay. Retry bounds are tuned in /settings.',
|
|
297
288
|
},
|
|
298
289
|
{
|
|
299
290
|
flagId: 'adaptive-execution-planner',
|
|
300
291
|
label: 'Adaptive execution planner',
|
|
301
292
|
hint: 'Score single/cohort/background/remote strategies each turn and pick the best. Exposes /plan commands.',
|
|
302
293
|
},
|
|
294
|
+
{
|
|
295
|
+
flagId: 'daemon-auto-update',
|
|
296
|
+
label: 'Daemon auto-update',
|
|
297
|
+
hint: 'The daemon checks for a new release hourly, checksum-verifies it, swaps binaries only at a no-active-work moment, and keeps the previous binary for one-command rollback. On by default; update.auto turns it off and update.intervalMinutes tunes the cadence in /settings.',
|
|
298
|
+
},
|
|
303
299
|
{
|
|
304
300
|
flagId: 'relay-connect',
|
|
305
301
|
label: 'Outbound zero-knowledge relay',
|
|
@@ -355,10 +351,10 @@ export const FEATURE_ONBOARDING_SECTIONS: readonly FeatureSection[] = [
|
|
|
355
351
|
key: 'backend',
|
|
356
352
|
configKey: 'tools.overflowSpillBackend' as ConfigKey,
|
|
357
353
|
label: 'Spill backend',
|
|
358
|
-
hint: '
|
|
354
|
+
hint: 'ledger (default when this feature is on) or diagnostics; file is the baseline used while the feature is off.',
|
|
359
355
|
valueType: 'enum',
|
|
360
356
|
options: ['file', 'ledger', 'diagnostics'],
|
|
361
|
-
defaultValue: '
|
|
357
|
+
defaultValue: 'ledger',
|
|
362
358
|
},
|
|
363
359
|
],
|
|
364
360
|
},
|
|
@@ -398,9 +394,9 @@ export function featureSubOptionFieldId(flagId: string, key: string): string {
|
|
|
398
394
|
return `feature.${flagId}.${key}`;
|
|
399
395
|
}
|
|
400
396
|
|
|
401
|
-
/** Whether a
|
|
397
|
+
/** Whether a feature defaults to enabled (drives the toggle's default-checked state). */
|
|
402
398
|
export function isFeatureDefaultOn(flagId: string): boolean {
|
|
403
|
-
return
|
|
399
|
+
return isFeatureDefaultEnabled(flagId);
|
|
404
400
|
}
|
|
405
401
|
|
|
406
402
|
/** Every flag id reachable through the guided feature steps. */
|
|
@@ -498,10 +494,12 @@ export function buildFeatureUnitSteps(
|
|
|
498
494
|
|
|
499
495
|
/**
|
|
500
496
|
* Fold the guided feature selections into apply operations: for each unit, when
|
|
501
|
-
* the user's choice differs from the
|
|
502
|
-
* when the feature is enabled, write its implied config, prerequisite
|
|
503
|
-
* chosen sub-options.
|
|
504
|
-
*
|
|
497
|
+
* the user's choice differs from the feature's default, record the desired
|
|
498
|
+
* state; when the feature is enabled, write its implied config, prerequisite
|
|
499
|
+
* features, and chosen sub-options. Desired states are collected into
|
|
500
|
+
* `overrides` (flushed by the caller as plain domain-settings writes on each
|
|
501
|
+
* feature's enablement key, together with the surface capabilities); other
|
|
502
|
+
* config writes go straight to setConfig.
|
|
505
503
|
*/
|
|
506
504
|
export function applyFeatureUnitOperations(
|
|
507
505
|
controller: OnboardingWizardControllerLike,
|
|
@@ -521,15 +519,24 @@ export function applyFeatureUnitOperations(
|
|
|
521
519
|
for (const prerequisite of unit.requiresFlags ?? []) overrides.set(prerequisite, 'enabled');
|
|
522
520
|
for (const implied of unit.impliedConfig ?? []) setConfig(implied.key, implied.value);
|
|
523
521
|
|
|
522
|
+
const enablementKey = getFeatureSetting(unit.flagId)?.enablement.key;
|
|
524
523
|
for (const sub of unit.subOptions ?? []) {
|
|
525
524
|
const raw = controller.getStringFieldValue(featureSubOptionFieldId(unit.flagId, sub.key), sub.defaultValue);
|
|
525
|
+
let wrote = true;
|
|
526
526
|
if (sub.valueType === 'boolean') {
|
|
527
527
|
setConfig(sub.configKey, raw === 'yes');
|
|
528
528
|
} else if (sub.valueType === 'text') {
|
|
529
|
-
|
|
529
|
+
wrote = raw.length > 0;
|
|
530
|
+
if (wrote) setConfig(sub.configKey, raw);
|
|
530
531
|
} else {
|
|
531
532
|
setConfig(sub.configKey, raw);
|
|
532
533
|
}
|
|
534
|
+
// A sub-option that writes the unit's OWN enablement key (e.g. the
|
|
535
|
+
// provider-optimizer routing mode) is the authoritative enablement
|
|
536
|
+
// value — drop the pending override so the flush cannot clobber it.
|
|
537
|
+
if (wrote && enablementKey !== undefined && sub.configKey === enablementKey) {
|
|
538
|
+
overrides.delete(unit.flagId);
|
|
539
|
+
}
|
|
533
540
|
}
|
|
534
541
|
}
|
|
535
542
|
}
|
|
@@ -0,0 +1,112 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Provider-agnostic API-key fields for the onboarding provider step.
|
|
3
|
+
*
|
|
4
|
+
* Kept out of onboarding-wizard-steps.ts so the step file stays focused on step
|
|
5
|
+
* assembly. Both pieces read from the same registration-truth targets so the
|
|
6
|
+
* inventory line and the per-provider masked fields never disagree.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import type { ProviderKeyCaptureTarget, SubscriptionStatusTarget } from '../../runtime/onboarding/provider-key-capture.ts';
|
|
10
|
+
import { deriveSubscriptionStatusTargets, providerKeyFieldId, subscriptionStatusFieldId } from '../../runtime/onboarding/provider-key-capture.ts';
|
|
11
|
+
import type { OnboardingProviderAccountRecord } from '../../runtime/onboarding/types.ts';
|
|
12
|
+
import type {
|
|
13
|
+
OnboardingWizardMaskedFieldDefinition,
|
|
14
|
+
OnboardingWizardStatusFieldDefinition,
|
|
15
|
+
} from './onboarding-wizard-types.ts';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* Providers with a wired in-wizard subscription sign-in flow. This is DATA — the
|
|
19
|
+
* set of providers whose OAuth login the wizard can start/finish itself — not an
|
|
20
|
+
* assumption that any one vendor is the only subscription option.
|
|
21
|
+
*/
|
|
22
|
+
const SUBSCRIPTION_SIGN_IN_PROVIDER_IDS = new Set<string>(['openai']);
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* One subscription-status row per subscription-capable provider. The row's copy
|
|
26
|
+
* names the provider from data — never a vendor hardcoded in the field set — so
|
|
27
|
+
* the status surface tracks whatever subscription-capable providers the runtime
|
|
28
|
+
* reports, not a single assumed one.
|
|
29
|
+
*/
|
|
30
|
+
export function buildSubscriptionStatusFields(
|
|
31
|
+
targets: readonly SubscriptionStatusTarget[],
|
|
32
|
+
): OnboardingWizardStatusFieldDefinition[] {
|
|
33
|
+
return targets.map((target) => ({
|
|
34
|
+
kind: 'status',
|
|
35
|
+
id: subscriptionStatusFieldId(target.providerId),
|
|
36
|
+
label: `${target.providerId} subscription status`,
|
|
37
|
+
hint: target.active
|
|
38
|
+
? `A ${target.providerId} subscription session is already available.`
|
|
39
|
+
: target.pending
|
|
40
|
+
? `A ${target.providerId} subscription login is pending.`
|
|
41
|
+
: `No ${target.providerId} subscription session was found in the current runtime state.`,
|
|
42
|
+
defaultValue: target.active ? 'Active' : target.pending ? 'Pending' : 'Not detected',
|
|
43
|
+
}));
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/** The provider-agnostic subscription posture the provider step renders. */
|
|
47
|
+
export interface SubscriptionPosture {
|
|
48
|
+
readonly statusFields: OnboardingWizardStatusFieldDefinition[];
|
|
49
|
+
/** The provider whose in-wizard sign-in flow applies now, or null. */
|
|
50
|
+
readonly signInProviderId: string | null;
|
|
51
|
+
readonly signInPending: boolean;
|
|
52
|
+
readonly summaryLine: string;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Derive the subscription posture for the provider step: one status row per
|
|
57
|
+
* subscription-capable provider, plus which (if any) provider's in-wizard OAuth
|
|
58
|
+
* sign-in flow applies right now (a subscription-capable, sign-in-wired provider
|
|
59
|
+
* that is not already active).
|
|
60
|
+
*/
|
|
61
|
+
export function buildSubscriptionPosture(
|
|
62
|
+
activeProviderIds: readonly string[],
|
|
63
|
+
pendingProviderIds: readonly string[],
|
|
64
|
+
providers: readonly OnboardingProviderAccountRecord[] | undefined,
|
|
65
|
+
): SubscriptionPosture {
|
|
66
|
+
const targets = deriveSubscriptionStatusTargets(providers, activeProviderIds, pendingProviderIds);
|
|
67
|
+
const signIn = targets.find((target) => SUBSCRIPTION_SIGN_IN_PROVIDER_IDS.has(target.providerId) && !target.active);
|
|
68
|
+
const activeCount = targets.filter((target) => target.active).length;
|
|
69
|
+
const pendingCount = targets.filter((target) => target.pending).length;
|
|
70
|
+
return {
|
|
71
|
+
statusFields: buildSubscriptionStatusFields(targets),
|
|
72
|
+
signInProviderId: signIn?.providerId ?? null,
|
|
73
|
+
signInPending: signIn?.pending ?? false,
|
|
74
|
+
summaryLine: targets.length === 0
|
|
75
|
+
? 'Subscriptions: none detected'
|
|
76
|
+
: `Subscriptions: ${activeCount} active, ${pendingCount} pending across ${targets.length} provider(s)`,
|
|
77
|
+
};
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
/** The status line summarizing how many key-accepting providers are configured. */
|
|
81
|
+
export function buildProviderKeyInventoryField(
|
|
82
|
+
targets: readonly ProviderKeyCaptureTarget[],
|
|
83
|
+
): OnboardingWizardStatusFieldDefinition {
|
|
84
|
+
const configuredCount = targets.filter((target) => target.configured).length;
|
|
85
|
+
return {
|
|
86
|
+
kind: 'status',
|
|
87
|
+
id: 'providers.api-key-inventory',
|
|
88
|
+
label: 'Provider API keys',
|
|
89
|
+
hint: targets.length === 0
|
|
90
|
+
? 'No key-accepting providers are registered yet in the current runtime state.'
|
|
91
|
+
: `${targets.length} provider(s) accept an API key; ${configuredCount} already configured. Values stay masked.`,
|
|
92
|
+
defaultValue: targets.length === 0
|
|
93
|
+
? 'None detected'
|
|
94
|
+
: `${configuredCount}/${targets.length} configured`,
|
|
95
|
+
};
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
/** One masked field per key-accepting provider, keyed off registration truth. */
|
|
99
|
+
export function buildProviderKeyMaskedFields(
|
|
100
|
+
targets: readonly ProviderKeyCaptureTarget[],
|
|
101
|
+
): OnboardingWizardMaskedFieldDefinition[] {
|
|
102
|
+
return targets.map((target) => ({
|
|
103
|
+
kind: 'masked',
|
|
104
|
+
id: providerKeyFieldId(target.providerId),
|
|
105
|
+
label: `${target.providerId} API key`,
|
|
106
|
+
hint: target.configured
|
|
107
|
+
? `A key for ${target.providerId} is already stored. Leave blank to keep it; enter a new key to replace it through the secret manager.`
|
|
108
|
+
: `Optional: enter an API key for ${target.providerId} now. The value is stored through the secret manager, not in config.`,
|
|
109
|
+
placeholder: target.configured ? 'already configured' : 'paste key',
|
|
110
|
+
defaultValue: '',
|
|
111
|
+
}));
|
|
112
|
+
}
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import type { OnboardingAcknowledgementTarget, OnboardingApplyOperation, OnboardingApplyRequest } from '../../runtime/onboarding/index.ts';
|
|
2
2
|
import { formatProviderModel } from '../../config/provider-model.ts';
|
|
3
3
|
import { getServerSurfaceFeatureFlags } from '../../runtime/surface-feature-flags.ts';
|
|
4
|
+
import { featureEnablementWrite } from '../../runtime/feature-settings.ts';
|
|
4
5
|
import {
|
|
5
6
|
buildCloudflareApiTokenRef,
|
|
6
7
|
buildCloudflareOperationalTokenRef,
|
|
@@ -17,13 +18,9 @@ import {
|
|
|
17
18
|
} from './onboarding-wizard-external-surfaces.ts';
|
|
18
19
|
import { applyFeatureUnitOperations } from './onboarding-feature-units.ts';
|
|
19
20
|
import { buildGoodVibesSecretKey, buildGoodVibesSecretRef, isLoopbackAddress, isSecretReferenceValue } from './onboarding-wizard-helpers.ts';
|
|
21
|
+
import { deriveProviderKeyCaptureTargets, providerKeyFieldId } from '../../runtime/onboarding/provider-key-capture.ts';
|
|
20
22
|
import type { OnboardingWizardControllerLike } from './onboarding-wizard-types.ts';
|
|
21
23
|
|
|
22
|
-
/** SDK schema default for behavior.hitlMode (schema-domain-core DEFAULT_CONFIG). */
|
|
23
|
-
const HITL_MODE_SCHEMA_DEFAULT = 'balanced';
|
|
24
|
-
/** Feature flag that gates behavior.hitlMode preset application in ModeManager. */
|
|
25
|
-
const HITL_UX_MODES_FEATURE_FLAG = 'hitl-ux-modes';
|
|
26
|
-
|
|
27
24
|
export function buildOnboardingApplyRequest(controller: OnboardingWizardControllerLike): OnboardingApplyRequest {
|
|
28
25
|
const operations: OnboardingApplyOperation[] = [];
|
|
29
26
|
// Accumulates feature-flag state that onboarding selections require, so the
|
|
@@ -132,21 +129,21 @@ export function buildOnboardingApplyRequest(controller: OnboardingWizardControll
|
|
|
132
129
|
setConfig('provider.reasoningEffort', controller.getStringFieldValue('default-model.reasoning', controller.runtimeSnapshot?.providerRouting.primaryReasoningEffort ?? 'medium'));
|
|
133
130
|
const hitlMode = controller.getStringFieldValue('experience.hitl', controller.runtimeSnapshot?.runtimeDefaults.behavior.hitlMode ?? 'balanced');
|
|
134
131
|
setConfig('behavior.hitlMode', hitlMode);
|
|
135
|
-
// behavior.hitlMode
|
|
136
|
-
//
|
|
137
|
-
//
|
|
138
|
-
//
|
|
139
|
-
//
|
|
140
|
-
// SDK schema default is 'balanced' (schema-domain-core DEFAULT_CONFIG); a
|
|
141
|
-
// choice equal to the default is left to the flag's own default-off state.
|
|
142
|
-
if (hitlMode !== HITL_MODE_SCHEMA_DEFAULT) {
|
|
143
|
-
featureFlagOverrides.set(HITL_UX_MODES_FEATURE_FLAG, 'enabled');
|
|
144
|
-
}
|
|
132
|
+
// behavior.hitlMode IS the enablement key of the hitl-ux-modes capability
|
|
133
|
+
// (active for quiet/balanced/operator, off only at 'off'), so the write
|
|
134
|
+
// above already carries the enablement — no separate gating write exists,
|
|
135
|
+
// and adding one here would clobber a non-default choice with the stock
|
|
136
|
+
// mode when the batch flushes.
|
|
145
137
|
setConfig('behavior.guidanceMode', controller.getStringFieldValue('experience.guidance', controller.runtimeSnapshot?.runtimeDefaults.behavior.guidanceMode ?? 'minimal'));
|
|
146
138
|
setConfig('permissions.mode', controller.getStringFieldValue('experience.permissions', controller.runtimeSnapshot?.runtimeDefaults.permissionsMode ?? 'prompt'));
|
|
147
139
|
setConfig('storage.secretPolicy', controller.getStringFieldValue('external-services.secret-policy', controller.runtimeSnapshot?.runtimeDefaults.secretStoragePolicy ?? 'preferred_secure'));
|
|
148
140
|
|
|
149
|
-
|
|
141
|
+
// Provider-agnostic key capture: store each entered key under the provider's
|
|
142
|
+
// own declared secret key. Empty fields are skipped (setSecret no-ops), so
|
|
143
|
+
// a blank field keeps any existing key untouched.
|
|
144
|
+
for (const target of deriveProviderKeyCaptureTargets(controller.runtimeSnapshot?.providerAccounts?.providers)) {
|
|
145
|
+
setSecret(target.apiKeyEnvVar, controller.getStringFieldValue(providerKeyFieldId(target.providerId), ''));
|
|
146
|
+
}
|
|
150
147
|
|
|
151
148
|
if (shouldShowCloudflareStep(controller)) {
|
|
152
149
|
addCloudflareOperations(controller, operations, setSecret);
|
|
@@ -190,12 +187,13 @@ export function buildOnboardingApplyRequest(controller: OnboardingWizardControll
|
|
|
190
187
|
}
|
|
191
188
|
}
|
|
192
189
|
// Feature units from the guided feature steps (safety, memory & context,
|
|
193
|
-
// telemetry, automation, provider, advanced): enable/disable each
|
|
194
|
-
// user changed from its default and write its chosen sub-options.
|
|
190
|
+
// telemetry, automation, provider, advanced): enable/disable each feature
|
|
191
|
+
// the user changed from its default and write its chosen sub-options.
|
|
195
192
|
applyFeatureUnitOperations(controller, setConfig, featureFlagOverrides);
|
|
196
193
|
|
|
197
|
-
// Surface/server
|
|
198
|
-
// own — apply them last so they win over any feature-step
|
|
194
|
+
// Surface/server capabilities are authoritative for the network-exposing
|
|
195
|
+
// features they own — apply them last so they win over any feature-step
|
|
196
|
+
// override.
|
|
199
197
|
for (const surfaceFlag of getServerSurfaceFeatureFlags({
|
|
200
198
|
serverBacked: hasServers,
|
|
201
199
|
web: browserAccess,
|
|
@@ -203,8 +201,11 @@ export function buildOnboardingApplyRequest(controller: OnboardingWizardControll
|
|
|
203
201
|
})) {
|
|
204
202
|
featureFlagOverrides.set(surfaceFlag, 'enabled');
|
|
205
203
|
}
|
|
204
|
+
// Each selection lands as a plain domain-settings write on the feature's
|
|
205
|
+
// real enablement key (e.g. sandbox.enabled, controlPlane.gateway).
|
|
206
206
|
for (const flagId of [...featureFlagOverrides.keys()].sort((left, right) => left.localeCompare(right))) {
|
|
207
|
-
|
|
207
|
+
const write = featureEnablementWrite(flagId, featureFlagOverrides.get(flagId)! === 'enabled');
|
|
208
|
+
if (write) setConfig(write.key, write.value);
|
|
208
209
|
}
|
|
209
210
|
|
|
210
211
|
acknowledge('providers', 'providers.reviewed');
|
|
@@ -282,6 +282,23 @@ const SURFACE_OVERLAYS: readonly SurfaceOverlay[] = [
|
|
|
282
282
|
{ configKey: 'surfaces.mattermost.defaultChannelId', label: 'Mattermost default channel ID', hint: 'Fallback Mattermost channel for outbound messages.', placeholder: 'channel id' },
|
|
283
283
|
],
|
|
284
284
|
},
|
|
285
|
+
{
|
|
286
|
+
onboardingId: 'telephony',
|
|
287
|
+
sdkSurface: 'telephony',
|
|
288
|
+
label: 'Telephony surface',
|
|
289
|
+
hint: 'Enable SMS/voice notification delivery — direct Twilio, or a self-hosted bridge.',
|
|
290
|
+
fields: [
|
|
291
|
+
{ configKey: 'surfaces.telephony.provider', label: 'Telephony provider', hint: 'twilio for direct Twilio delivery, bridge for a self-hosted telephony bridge.', placeholder: 'twilio' },
|
|
292
|
+
{ configKey: 'surfaces.telephony.mode', label: 'Telephony mode', hint: 'sms, voice (call with spoken text), or bridge.', placeholder: 'sms' },
|
|
293
|
+
{ configKey: 'surfaces.telephony.accountSid', label: 'Twilio account SID', hint: 'Account SID for direct Twilio delivery.', placeholder: 'AC...' },
|
|
294
|
+
{ configKey: 'surfaces.telephony.authToken', label: 'Twilio auth token', hint: 'Auth token for direct Twilio delivery.', placeholder: 'auth token' },
|
|
295
|
+
{ configKey: 'surfaces.telephony.fromNumber', label: 'From number', hint: 'The E.164 number outbound SMS/calls originate from.', placeholder: '+15551234567' },
|
|
296
|
+
{ configKey: 'surfaces.telephony.defaultRecipient', label: 'Default recipient', hint: 'Fallback E.164 number for outbound delivery.', placeholder: '+15557654321' },
|
|
297
|
+
{ configKey: 'surfaces.telephony.bridgeUrl', label: 'Bridge URL', hint: 'Base URL of the self-hosted telephony bridge (bridge provider only).', placeholder: 'https://telephony-bridge.example.test' },
|
|
298
|
+
{ configKey: 'surfaces.telephony.token', label: 'Bridge token', hint: 'Token used to authenticate with the telephony bridge.', placeholder: 'bridge token' },
|
|
299
|
+
{ configKey: 'surfaces.telephony.webhookSecret', label: 'Webhook secret', hint: 'Secret used to verify inbound telephony webhooks.', placeholder: 'webhook secret' },
|
|
300
|
+
],
|
|
301
|
+
},
|
|
285
302
|
{
|
|
286
303
|
onboardingId: 'matrix',
|
|
287
304
|
sdkSurface: 'matrix',
|
|
@@ -106,7 +106,7 @@ export function pushLegacyDaemonMigrationFields(
|
|
|
106
106
|
fields.push({
|
|
107
107
|
kind: 'status',
|
|
108
108
|
id: 'network.migrate-legacy-daemon-detected',
|
|
109
|
-
label: '
|
|
109
|
+
label: 'Separate install-script daemon service detected',
|
|
110
110
|
// Follow-up: name the unit this host actually resolves (carried on the
|
|
111
111
|
// snapshot from `resolveConfiguredServiceName` at collection time) — the
|
|
112
112
|
// MANAGED_SERVICE_NAME fallback only covers snapshots built without it.
|
|
@@ -126,7 +126,7 @@ export function pushLegacyDaemonMigrationFields(
|
|
|
126
126
|
fields.push({
|
|
127
127
|
kind: 'action',
|
|
128
128
|
id: 'network.migrate-legacy-daemon',
|
|
129
|
-
label: confirmed ? 'Migrate
|
|
129
|
+
label: confirmed ? 'Migrate the install-script daemon service now' : 'Preview migration plan',
|
|
130
130
|
hint: confirmed
|
|
131
131
|
? 'Executes the migration now: new-up-then-old-down, never touching the legacy unit until the new one is verified healthy. Result prints to the feed below.'
|
|
132
132
|
: 'Prints the migration plan without changing anything. Check "Confirm migration execution" above to arm the real migration.',
|