@pellux/goodvibes-tui 0.20.3 → 0.22.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 +50 -0
- package/README.md +23 -2
- package/docs/foundation-artifacts/operator-contract.json +78 -1
- package/package.json +4 -2
- package/src/audio/spoken-turn-controller.ts +31 -1
- package/src/audio/spoken-turn-wiring.ts +26 -4
- package/src/cli/bundle-command.ts +1 -1
- package/src/cli/completions/generate.ts +658 -0
- package/src/cli/config-overrides.ts +68 -0
- package/src/cli/entrypoint.ts +6 -0
- package/src/cli/help.ts +4 -2
- package/src/cli/management-commands.ts +1 -1
- package/src/cli/management.ts +1 -8
- package/src/cli/parser.ts +31 -18
- package/src/cli/service-command.ts +1 -1
- package/src/cli/surface-command.ts +1 -1
- package/src/cli/tui-startup.ts +72 -10
- package/src/cli/types.ts +14 -3
- package/src/cli-flags.ts +1 -0
- package/src/config/atomic-write.ts +70 -0
- package/src/config/goodvibes-home-audit.ts +2 -0
- package/src/config/read-versioned.ts +115 -0
- package/src/core/context-auto-compact.ts +77 -0
- package/src/core/conversation-rendering.ts +49 -15
- package/src/core/conversation.ts +101 -16
- package/src/core/format-user-error.ts +192 -0
- package/src/core/stream-event-wiring.ts +144 -0
- package/src/core/stream-stall-watchdog.ts +103 -0
- package/src/core/system-message-router.ts +5 -1
- package/src/core/turn-event-wiring.ts +124 -0
- package/src/daemon/cli.ts +5 -0
- package/src/export/cost-utils.ts +71 -0
- package/src/export/gist-uploader.ts +136 -0
- package/src/input/command-registry.ts +32 -1
- package/src/input/commands/control-room-runtime.ts +10 -10
- package/src/input/commands/experience-runtime.ts +5 -4
- package/src/input/commands/knowledge.ts +1 -1
- package/src/input/commands/local-auth-runtime.ts +27 -5
- package/src/input/commands/local-setup.ts +4 -6
- package/src/input/commands/memory-product-runtime.ts +8 -6
- package/src/input/commands/operator-panel-runtime.ts +1 -1
- package/src/input/commands/operator-runtime.ts +3 -10
- package/src/input/commands/{integration-runtime.ts → plugin-runtime.ts} +1 -1
- package/src/input/commands/provider.ts +57 -3
- package/src/input/commands/recall-review.ts +26 -2
- package/src/input/commands/services-runtime.ts +2 -2
- package/src/input/commands/session-workflow.ts +8 -16
- package/src/input/commands/session.ts +70 -20
- package/src/input/commands/share-runtime.ts +99 -12
- package/src/input/commands/tts-runtime.ts +30 -4
- package/src/input/commands.ts +2 -4
- package/src/input/delete-key-policy.ts +46 -0
- package/src/input/feed-context-factory.ts +2 -0
- package/src/input/handler-feed.ts +3 -0
- package/src/input/handler-interactions.ts +2 -15
- package/src/input/handler-modal-routes.ts +128 -12
- package/src/input/handler-modal-token-routes.ts +22 -5
- package/src/input/handler-onboarding-cloudflare.ts +1 -1
- package/src/input/handler-onboarding.ts +73 -69
- package/src/input/handler-types.ts +163 -0
- package/src/input/handler.ts +6 -2
- package/src/input/input-history.ts +76 -6
- package/src/input/model-picker-filter.ts +265 -0
- package/src/input/model-picker-items.ts +208 -0
- package/src/input/model-picker.ts +92 -325
- package/src/input/onboarding/handler-onboarding-routes.ts +7 -2
- package/src/input/onboarding/onboarding-verification-helpers.ts +76 -0
- package/src/input/onboarding/onboarding-wizard-apply.ts +14 -4
- package/src/input/onboarding/onboarding-wizard-cloudflare-step.ts +16 -2
- package/src/input/onboarding/onboarding-wizard-cloudflare.ts +8 -8
- package/src/input/onboarding/onboarding-wizard-external-surface-extra-specs.ts +1 -1
- package/src/input/onboarding/onboarding-wizard-external-surfaces.ts +2 -29
- package/src/input/onboarding/onboarding-wizard-rules.ts +28 -28
- package/src/input/onboarding/onboarding-wizard-state.ts +20 -20
- package/src/input/onboarding/onboarding-wizard-steps.ts +24 -25
- package/src/input/onboarding/onboarding-wizard-types.ts +145 -3
- package/src/input/onboarding/onboarding-wizard-validation.ts +77 -0
- package/src/input/onboarding/onboarding-wizard.ts +3 -3
- package/src/input/settings-modal-behavior.ts +5 -0
- package/src/input/settings-modal-data.ts +378 -0
- package/src/input/settings-modal-mutations.ts +157 -0
- package/src/input/settings-modal-reset.ts +154 -0
- package/src/input/settings-modal.ts +236 -232
- package/src/main.ts +93 -85
- package/src/panels/agent-inspector-panel.ts +120 -18
- package/src/panels/agent-inspector-shared.ts +29 -0
- package/src/panels/builtin/agent.ts +4 -1
- package/src/panels/builtin/development.ts +5 -1
- package/src/panels/builtin/knowledge.ts +14 -13
- package/src/panels/builtin/operations.ts +22 -1
- package/src/panels/builtin/shared.ts +7 -0
- package/src/panels/cockpit-panel.ts +123 -3
- package/src/panels/cockpit-read-model.ts +232 -0
- package/src/panels/confirm-state.ts +27 -12
- package/src/panels/cost-tracker-panel.ts +23 -67
- package/src/panels/eval-panel.ts +10 -9
- package/src/panels/index.ts +1 -1
- package/src/panels/knowledge-graph-panel.ts +84 -0
- package/src/panels/local-auth-panel.ts +124 -4
- package/src/panels/memory-panel.ts +370 -40
- package/src/panels/project-planning-panel.ts +42 -4
- package/src/panels/search-focus.ts +11 -5
- package/src/panels/session-maintenance.ts +66 -15
- package/src/panels/subscription-panel.ts +33 -25
- package/src/panels/types.ts +28 -1
- package/src/panels/wrfc-panel.ts +224 -41
- package/src/renderer/agent-detail-modal.ts +118 -13
- package/src/renderer/code-block.ts +10 -2
- package/src/renderer/compositor.ts +18 -4
- package/src/renderer/context-inspector.ts +1 -5
- package/src/renderer/context-status-hint.ts +54 -0
- package/src/renderer/diff.ts +94 -21
- package/src/renderer/markdown.ts +29 -13
- package/src/renderer/settings-modal-helpers.ts +1 -1
- package/src/renderer/settings-modal.ts +90 -10
- package/src/renderer/shell-surface.ts +10 -0
- package/src/renderer/syntax-highlighter.ts +10 -3
- package/src/renderer/term-caps.ts +318 -0
- package/src/renderer/theme.ts +158 -0
- package/src/renderer/tool-call.ts +12 -2
- package/src/renderer/ui-factory.ts +50 -6
- package/src/runtime/bootstrap-command-context.ts +1 -0
- package/src/runtime/bootstrap-command-parts.ts +18 -0
- package/src/runtime/bootstrap-core.ts +145 -13
- package/src/runtime/bootstrap-shell.ts +11 -0
- package/src/runtime/bootstrap.ts +9 -0
- package/src/runtime/onboarding/apply.ts +4 -6
- package/src/runtime/onboarding/index.ts +1 -0
- package/src/runtime/onboarding/markers.ts +42 -49
- package/src/runtime/onboarding/progress.ts +148 -0
- package/src/runtime/onboarding/state.ts +133 -55
- package/src/runtime/onboarding/types.ts +20 -0
- package/src/runtime/services.ts +27 -1
- package/src/runtime/wrfc-persistence.ts +237 -0
- package/src/shell/blocking-input.ts +20 -5
- package/src/tools/wrfc-agent-guard.ts +64 -3
- package/src/utils/format-elapsed.ts +30 -0
- package/src/utils/terminal-width.ts +45 -0
- package/src/version.ts +1 -1
- package/src/work-plans/work-plan-store.ts +4 -6
- package/src/panels/knowledge-panel.ts +0 -345
- package/src/planning/project-planning-coordinator.ts +0 -543
|
@@ -9,10 +9,10 @@ import {
|
|
|
9
9
|
type ExternalSurfaceSpec,
|
|
10
10
|
} from './onboarding-wizard-external-surfaces.ts';
|
|
11
11
|
import { countSelected, modelSelectionLabel, normalizeText } from './onboarding-wizard-helpers.ts';
|
|
12
|
-
import type {
|
|
12
|
+
import type { OnboardingWizardControllerLike } from './onboarding-wizard-types.ts';
|
|
13
13
|
import type { OnboardingWizardAcknowledgementFieldDefinition, OnboardingWizardActionFieldDefinition, OnboardingWizardChecklistFieldDefinition, OnboardingWizardExternalSurfaceStepId, OnboardingWizardFieldDefinition, OnboardingWizardModelPickerFieldDefinition, OnboardingWizardRadioFieldDefinition, OnboardingWizardRadioOption, OnboardingWizardStepDefinition } from './onboarding-wizard-types.ts';
|
|
14
14
|
|
|
15
|
-
export function buildOnboardingWizardSteps(controller:
|
|
15
|
+
export function buildOnboardingWizardSteps(controller: OnboardingWizardControllerLike): readonly OnboardingWizardStepDefinition[] {
|
|
16
16
|
if (controller.hydrationPending || controller.hydrationError !== null) return [buildLoadingStep(controller)];
|
|
17
17
|
|
|
18
18
|
const capabilities = controller.getCapabilitySelectionState();
|
|
@@ -48,8 +48,8 @@ function buildApplyAndContinueAction(step: OnboardingWizardStepDefinition): Onbo
|
|
|
48
48
|
kind: 'action',
|
|
49
49
|
id: `${step.id}.apply-and-continue`,
|
|
50
50
|
action: 'apply-and-continue',
|
|
51
|
-
label: '
|
|
52
|
-
hint: '
|
|
51
|
+
label: 'Next section',
|
|
52
|
+
hint: 'Selections are kept in this wizard session and persisted on the final Review apply.',
|
|
53
53
|
defaultValue: 'Apply & next',
|
|
54
54
|
spacerBeforeRows: 2,
|
|
55
55
|
};
|
|
@@ -66,7 +66,7 @@ function addApplyAndContinueAction(step: OnboardingWizardStepDefinition): Onboar
|
|
|
66
66
|
};
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
export function buildLoadingStep(controller:
|
|
69
|
+
export function buildLoadingStep(controller: OnboardingWizardControllerLike): OnboardingWizardStepDefinition {
|
|
70
70
|
const failed = controller.hydrationError !== null;
|
|
71
71
|
return {
|
|
72
72
|
id: 'loading',
|
|
@@ -98,7 +98,7 @@ export function buildLoadingStep(controller: OnboardingWizardController): Onboar
|
|
|
98
98
|
};
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
-
export function buildCapabilitiesStep(controller:
|
|
101
|
+
export function buildCapabilitiesStep(controller: OnboardingWizardControllerLike): OnboardingWizardStepDefinition {
|
|
102
102
|
const capabilities = controller.getCapabilitySelectionState();
|
|
103
103
|
const selectedCount = countSelected(capabilities);
|
|
104
104
|
const fields: OnboardingWizardFieldDefinition[] = [
|
|
@@ -145,7 +145,7 @@ export function buildCapabilitiesStep(controller: OnboardingWizardController): O
|
|
|
145
145
|
};
|
|
146
146
|
}
|
|
147
147
|
|
|
148
|
-
export function buildProvidersStep(controller:
|
|
148
|
+
export function buildProvidersStep(controller: OnboardingWizardControllerLike): OnboardingWizardStepDefinition {
|
|
149
149
|
const providerAck = controller.runtimeDerived.reopenEditAcknowledgements.providers;
|
|
150
150
|
const activeSubscriptions = controller.runtimeSnapshot?.subscriptions.active ?? [];
|
|
151
151
|
const pendingSubscriptions = controller.runtimeSnapshot?.subscriptions.pending ?? [];
|
|
@@ -250,11 +250,11 @@ export function buildProvidersStep(controller: OnboardingWizardController): Onbo
|
|
|
250
250
|
};
|
|
251
251
|
}
|
|
252
252
|
|
|
253
|
-
export function buildProviderAccessStep(controller:
|
|
253
|
+
export function buildProviderAccessStep(controller: OnboardingWizardControllerLike): OnboardingWizardStepDefinition {
|
|
254
254
|
return buildProvidersStep(controller);
|
|
255
255
|
}
|
|
256
256
|
|
|
257
|
-
export function buildDefaultModelStep(controller:
|
|
257
|
+
export function buildDefaultModelStep(controller: OnboardingWizardControllerLike): OnboardingWizardStepDefinition {
|
|
258
258
|
const routing = controller.runtimeSnapshot?.providerRouting;
|
|
259
259
|
const primarySelectionField: OnboardingWizardModelPickerFieldDefinition = {
|
|
260
260
|
kind: 'modelPicker',
|
|
@@ -294,7 +294,7 @@ export function buildDefaultModelStep(controller: OnboardingWizardController): O
|
|
|
294
294
|
};
|
|
295
295
|
}
|
|
296
296
|
|
|
297
|
-
export function buildExternalServicesStep(controller:
|
|
297
|
+
export function buildExternalServicesStep(controller: OnboardingWizardControllerLike): OnboardingWizardStepDefinition {
|
|
298
298
|
const selectedCount = EXTERNAL_SURFACE_SPECS
|
|
299
299
|
.filter((surface) => controller.getBooleanFieldValue(
|
|
300
300
|
surface.enabledFieldId,
|
|
@@ -355,7 +355,7 @@ export function buildExternalServicesStep(controller: OnboardingWizardController
|
|
|
355
355
|
};
|
|
356
356
|
}
|
|
357
357
|
|
|
358
|
-
function getSelectedExternalSurfaceSpecs(controller:
|
|
358
|
+
function getSelectedExternalSurfaceSpecs(controller: OnboardingWizardControllerLike): readonly ExternalSurfaceSpec[] {
|
|
359
359
|
return EXTERNAL_SURFACE_SPECS.filter((surface) => (
|
|
360
360
|
controller.getBooleanFieldValue(
|
|
361
361
|
surface.enabledFieldId,
|
|
@@ -378,7 +378,7 @@ const SURFACE_AUTO_START_OPTIONS: readonly OnboardingWizardRadioOption[] = [
|
|
|
378
378
|
];
|
|
379
379
|
|
|
380
380
|
function buildExternalSurfaceStep(
|
|
381
|
-
controller:
|
|
381
|
+
controller: OnboardingWizardControllerLike,
|
|
382
382
|
surface: ExternalSurfaceSpec,
|
|
383
383
|
): OnboardingWizardStepDefinition {
|
|
384
384
|
let setupCount = 0;
|
|
@@ -461,7 +461,7 @@ function buildExternalSurfaceStep(
|
|
|
461
461
|
};
|
|
462
462
|
}
|
|
463
463
|
|
|
464
|
-
export function buildAccessStep(controller:
|
|
464
|
+
export function buildAccessStep(controller: OnboardingWizardControllerLike): OnboardingWizardStepDefinition {
|
|
465
465
|
const step = buildAccountsStep(controller);
|
|
466
466
|
return {
|
|
467
467
|
...step,
|
|
@@ -471,7 +471,7 @@ export function buildAccessStep(controller: OnboardingWizardController): Onboard
|
|
|
471
471
|
};
|
|
472
472
|
}
|
|
473
473
|
|
|
474
|
-
export function buildExperienceStep(controller:
|
|
474
|
+
export function buildExperienceStep(controller: OnboardingWizardControllerLike): OnboardingWizardStepDefinition {
|
|
475
475
|
return {
|
|
476
476
|
id: 'experience',
|
|
477
477
|
title: 'Shell experience',
|
|
@@ -512,7 +512,7 @@ export function buildExperienceStep(controller: OnboardingWizardController): Onb
|
|
|
512
512
|
};
|
|
513
513
|
}
|
|
514
514
|
|
|
515
|
-
export function buildNetworkStep(controller:
|
|
515
|
+
export function buildNetworkStep(controller: OnboardingWizardControllerLike): OnboardingWizardStepDefinition {
|
|
516
516
|
const bindSettings = controller.runtimeSnapshot?.bindSettings;
|
|
517
517
|
const browserEnabled = controller.shouldEnableBrowserSurface();
|
|
518
518
|
const listenerEnabled = controller.shouldExposeHttpListenerNetworkFields();
|
|
@@ -621,6 +621,12 @@ export function buildNetworkStep(controller: OnboardingWizardController): Onboar
|
|
|
621
621
|
}
|
|
622
622
|
}
|
|
623
623
|
|
|
624
|
+
if (controlPlaneRemote || listenerEnabled || browserEnabled) { // TLS warn + CORS notice.
|
|
625
|
+
const cpOff = controlPlaneRemote && String(controller.runtimeSnapshot?.config.controlPlane?.tls?.mode ?? 'off') === 'off';
|
|
626
|
+
const hlOff = listenerEnabled && String(controller.runtimeSnapshot?.config.httpListener?.tls?.mode ?? 'off') === 'off';
|
|
627
|
+
if (cpOff || hlOff) { const a = [cpOff ? 'control plane' : '', hlOff ? 'HTTP listener' : ''].filter(Boolean).join(' and '); fields.push({ kind: 'status', id: 'network.tls-warn', label: `TLS off — ${a} transmits plaintext`, defaultValue: 'Warning', hint: `The ${a} is network-reachable but TLS is off. Traffic travels in plaintext. Enable TLS or use a terminating reverse proxy.` }); }
|
|
628
|
+
if (listenerEnabled) { fields.push({ kind: 'status', id: 'network.cors-note', label: 'CORS must be configured manually', defaultValue: 'Info', hint: 'httpListener.enforceCors and httpListener.allowedOrigins are not in ConfigKey union (SDK handoff Item 5). Edit ~/.goodvibes/tui/settings.json to set them, then restart the daemon.' }); }
|
|
629
|
+
}
|
|
624
630
|
return {
|
|
625
631
|
id: 'network',
|
|
626
632
|
title: 'Network setup',
|
|
@@ -636,7 +642,7 @@ export function buildNetworkStep(controller: OnboardingWizardController): Onboar
|
|
|
636
642
|
};
|
|
637
643
|
}
|
|
638
644
|
|
|
639
|
-
export function buildAccountsStep(controller:
|
|
645
|
+
export function buildAccountsStep(controller: OnboardingWizardControllerLike): OnboardingWizardStepDefinition {
|
|
640
646
|
const subscriptionsAck = controller.runtimeDerived.reopenEditAcknowledgements.subscriptions;
|
|
641
647
|
const authAck = controller.runtimeDerived.reopenEditAcknowledgements.auth;
|
|
642
648
|
const auth = controller.runtimeSnapshot?.auth.snapshot;
|
|
@@ -740,7 +746,7 @@ export function buildAccountsStep(controller: OnboardingWizardController): Onboa
|
|
|
740
746
|
};
|
|
741
747
|
}
|
|
742
748
|
|
|
743
|
-
export function buildReviewStep(controller:
|
|
749
|
+
export function buildReviewStep(controller: OnboardingWizardControllerLike): OnboardingWizardStepDefinition {
|
|
744
750
|
const feedback = controller.applyFeedback;
|
|
745
751
|
const feedbackFields: OnboardingWizardFieldDefinition[] = feedback
|
|
746
752
|
? [
|
|
@@ -778,19 +784,12 @@ export function buildReviewStep(controller: OnboardingWizardController): Onboard
|
|
|
778
784
|
],
|
|
779
785
|
fields: [
|
|
780
786
|
...feedbackFields,
|
|
781
|
-
{
|
|
782
|
-
kind: 'status',
|
|
783
|
-
id: 'review.global-marker',
|
|
784
|
-
label: 'Global onboarding check',
|
|
785
|
-
hint: 'Opening this wizard marks onboarding as shown for this user account, so new projects do not reopen it automatically.',
|
|
786
|
-
defaultValue: 'Already marked as shown',
|
|
787
|
-
},
|
|
788
787
|
{
|
|
789
788
|
kind: 'action',
|
|
790
789
|
id: 'review.apply',
|
|
791
790
|
action: 'apply',
|
|
792
791
|
label: 'Apply settings and verify',
|
|
793
|
-
hint: 'Persist the wizard settings and verify the resulting runtime state. The global onboarding check
|
|
792
|
+
hint: 'Persist the wizard settings and verify the resulting runtime state. The global onboarding check marker is recorded when apply succeeds.',
|
|
794
793
|
defaultValue: 'Ready',
|
|
795
794
|
},
|
|
796
795
|
],
|
|
@@ -1,10 +1,7 @@
|
|
|
1
|
-
import { isIP } from 'node:net';
|
|
2
1
|
import type { ModelPickerTarget } from '../model-picker.ts';
|
|
3
2
|
import {
|
|
4
|
-
deriveOnboardingStepState,
|
|
5
3
|
type OnboardingAcknowledgementReason,
|
|
6
4
|
type OnboardingAcknowledgementTarget,
|
|
7
|
-
type OnboardingApplyOperation,
|
|
8
5
|
type OnboardingApplyRequest,
|
|
9
6
|
type OnboardingMode,
|
|
10
7
|
type OnboardingSnapshotState,
|
|
@@ -193,3 +190,148 @@ export interface OnboardingWizardRuntimeHydration {
|
|
|
193
190
|
}
|
|
194
191
|
|
|
195
192
|
export type MutableModelSelectionMap = Map<ModelPickerTarget, OnboardingWizardModelSelection>;
|
|
193
|
+
|
|
194
|
+
// ---------------------------------------------------------------------------
|
|
195
|
+
// External surface types (moved here to break the surfaces ↔ extra-specs cycle)
|
|
196
|
+
// ---------------------------------------------------------------------------
|
|
197
|
+
|
|
198
|
+
export interface ExternalSurfaceSetupFieldSpec {
|
|
199
|
+
readonly id: string;
|
|
200
|
+
readonly configKey: ConfigKey;
|
|
201
|
+
readonly kind: 'text' | 'masked' | 'radio';
|
|
202
|
+
readonly valueType?: 'string' | 'number';
|
|
203
|
+
readonly label: string;
|
|
204
|
+
readonly hint: string;
|
|
205
|
+
readonly placeholder: string;
|
|
206
|
+
readonly options?: readonly OnboardingWizardRadioOption[];
|
|
207
|
+
readonly defaultNumber?: number;
|
|
208
|
+
readonly min?: number;
|
|
209
|
+
readonly max?: number;
|
|
210
|
+
readonly defaultValue: (snapshot: OnboardingSnapshotState | null) => string;
|
|
211
|
+
}
|
|
212
|
+
|
|
213
|
+
export interface ExternalSurfaceSpec {
|
|
214
|
+
readonly id: string;
|
|
215
|
+
readonly enabledFieldId: string;
|
|
216
|
+
readonly enabledConfigKey: ConfigKey;
|
|
217
|
+
readonly label: string;
|
|
218
|
+
readonly hint: string;
|
|
219
|
+
/**
|
|
220
|
+
* Existing SDK config key. In onboarding this maps to the per-surface
|
|
221
|
+
* auto-start choice, not to whether setup fields are shown.
|
|
222
|
+
*/
|
|
223
|
+
readonly defaultEnabled: (snapshot: OnboardingSnapshotState | null) => boolean;
|
|
224
|
+
readonly fields: readonly ExternalSurfaceSetupFieldSpec[];
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
// ---------------------------------------------------------------------------
|
|
228
|
+
// Controller interface (moved here to break the wizard ↔ satellites cycle)
|
|
229
|
+
// ---------------------------------------------------------------------------
|
|
230
|
+
|
|
231
|
+
/**
|
|
232
|
+
* Public interface of OnboardingWizardController. Satellite modules
|
|
233
|
+
* (apply, steps, rules, state, cloudflare, cloudflare-step) receive the
|
|
234
|
+
* controller through this interface so they do not need to import from
|
|
235
|
+
* onboarding-wizard.ts and the circular dependency is broken.
|
|
236
|
+
*/
|
|
237
|
+
export interface OnboardingWizardControllerLike {
|
|
238
|
+
// State fields
|
|
239
|
+
active: boolean;
|
|
240
|
+
mode: OnboardingWizardMode;
|
|
241
|
+
stepIndex: number;
|
|
242
|
+
hydrationPending: boolean;
|
|
243
|
+
hydrationError: string | null;
|
|
244
|
+
pendingModelPickerTarget: ModelPickerTarget | null;
|
|
245
|
+
pendingAction: OnboardingWizardAction | null;
|
|
246
|
+
editingFieldId: string | null;
|
|
247
|
+
editBuffer: string;
|
|
248
|
+
applyFeedback: OnboardingWizardApplyFeedback | null;
|
|
249
|
+
|
|
250
|
+
readonly scrollOffsets: number[];
|
|
251
|
+
readonly selectedFieldIndices: number[];
|
|
252
|
+
readonly dirtyStepIds: Set<OnboardingWizardStepId>;
|
|
253
|
+
readonly toggleState: Map<string, boolean>;
|
|
254
|
+
readonly touchedActionFields: Set<string>;
|
|
255
|
+
readonly radioState: Map<string, string>;
|
|
256
|
+
readonly textState: Map<string, string>;
|
|
257
|
+
readonly modelSelectionState: MutableModelSelectionMap;
|
|
258
|
+
|
|
259
|
+
readonly baselineToggleState: Map<string, boolean>;
|
|
260
|
+
readonly baselineRadioState: Map<string, string>;
|
|
261
|
+
readonly baselineTextState: Map<string, string>;
|
|
262
|
+
readonly baselineModelSelectionState: MutableModelSelectionMap;
|
|
263
|
+
|
|
264
|
+
runtimeSnapshot: OnboardingSnapshotState | null;
|
|
265
|
+
runtimeDerived: OnboardingStepDerivationState;
|
|
266
|
+
|
|
267
|
+
// Computed
|
|
268
|
+
readonly steps: readonly OnboardingWizardStepDefinition[];
|
|
269
|
+
readonly currentStep: OnboardingWizardStepDefinition;
|
|
270
|
+
readonly dirty: boolean;
|
|
271
|
+
readonly dirtyStepCount: number;
|
|
272
|
+
|
|
273
|
+
// Field value accessors
|
|
274
|
+
getFieldValue(field: OnboardingWizardFieldDefinition): boolean | string | OnboardingWizardModelSelection;
|
|
275
|
+
getFieldById(fieldId: string): OnboardingWizardFieldDefinition | null;
|
|
276
|
+
getStringFieldValue(fieldId: string, fallback: string): string;
|
|
277
|
+
getBooleanFieldValue(fieldId: string, fallback: boolean): boolean;
|
|
278
|
+
parseIntegerFieldValue(fieldId: string, fallback: number): number | null;
|
|
279
|
+
getPortFieldValue(fieldId: string, fallback: number): number;
|
|
280
|
+
getNumberFieldValue(fieldId: string, fallback: number, min?: number, max?: number): number;
|
|
281
|
+
|
|
282
|
+
// Capability / rules accessors
|
|
283
|
+
isCapabilitySelected(capabilityId: OnboardingStep1CapabilityId): boolean;
|
|
284
|
+
hasServerCapabilitiesSelected(): boolean;
|
|
285
|
+
shouldEnableBrowserSurface(): boolean;
|
|
286
|
+
hasSelectedInboundExternalSurface(): boolean;
|
|
287
|
+
isRequiredExternalSetupField(fieldId: string): boolean;
|
|
288
|
+
getSelectedSecretMedium(): 'secure' | 'plaintext';
|
|
289
|
+
shouldEnableHttpListener(): boolean;
|
|
290
|
+
shouldExposeHttpListenerNetworkFields(): boolean;
|
|
291
|
+
shouldExposeControlPlaneNetwork(): boolean;
|
|
292
|
+
requiresAuthBootstrap(): boolean;
|
|
293
|
+
hasAdminAuthUser(): boolean;
|
|
294
|
+
hasLocalAuthUser(): boolean;
|
|
295
|
+
hasBootstrapCredentialPresent(): boolean;
|
|
296
|
+
getDefaultAdminUsername(): string;
|
|
297
|
+
getSharedIpDefault(enabled: { readonly controlPlane: boolean; readonly httpListener: boolean; readonly web: boolean }): boolean;
|
|
298
|
+
getSharedIpHostDefault(enabled: { readonly controlPlane: boolean; readonly httpListener: boolean; readonly web: boolean }): string;
|
|
299
|
+
|
|
300
|
+
// Capability mutations
|
|
301
|
+
toggleCapability(capabilityId: OnboardingStep1CapabilityId): void;
|
|
302
|
+
selectAllServerCapabilities(): void;
|
|
303
|
+
selectLocalTuiOnly(): void;
|
|
304
|
+
selectAllExternalSurfaces(): void;
|
|
305
|
+
clearExternalSurfaces(): void;
|
|
306
|
+
setCapabilityValue(capabilityId: OnboardingStep1CapabilityId, selected: boolean): void;
|
|
307
|
+
getCurrentCapabilities(): readonly OnboardingStep1CapabilityItem[];
|
|
308
|
+
getCapabilitySelectionState(): readonly OnboardingStep1CapabilityItem[];
|
|
309
|
+
|
|
310
|
+
// State operations
|
|
311
|
+
recalculateDirtyState(): void;
|
|
312
|
+
reconcileStateWithCurrentDefinitions(): void;
|
|
313
|
+
reconcileStepCursor(stepIndex: number): void;
|
|
314
|
+
resetValuesFromCurrentDefinitions(): void;
|
|
315
|
+
ensureSelectionVisible(visibleFields: number): void;
|
|
316
|
+
isFieldDirty(fieldId: string): boolean;
|
|
317
|
+
isFieldDirtyByDefinition(field: OnboardingWizardFieldDefinition): boolean;
|
|
318
|
+
isFieldSatisfied(field: OnboardingWizardFieldDefinition): boolean;
|
|
319
|
+
isStepDirty(stepIndex: number): boolean;
|
|
320
|
+
hasExistingAccessState(): boolean;
|
|
321
|
+
getBlockingFieldLabels(): readonly string[];
|
|
322
|
+
getFieldValidationError(step: OnboardingWizardStepDefinition, field: OnboardingWizardFieldDefinition): string | null;
|
|
323
|
+
getToggleFieldCount(stepIndex: number): number;
|
|
324
|
+
getCompletedToggleCount(stepIndex: number): number;
|
|
325
|
+
getStepFieldCount(stepIndex: number): number;
|
|
326
|
+
getCompletedFieldCount(stepIndex: number): number;
|
|
327
|
+
|
|
328
|
+
// Additional operations used by steps/apply
|
|
329
|
+
buildApplyRequest(): OnboardingApplyRequest;
|
|
330
|
+
isEditingTextField(): boolean;
|
|
331
|
+
getTextFieldValue(fieldId: string, fallback?: string): string;
|
|
332
|
+
getFieldValueLabel(field: OnboardingWizardFieldDefinition): string;
|
|
333
|
+
getSelectedFieldIndex(): number;
|
|
334
|
+
getSelectedField(): OnboardingWizardFieldDefinition | null;
|
|
335
|
+
getFieldWindow(visibleFields: number): OnboardingWizardFieldWindow;
|
|
336
|
+
}
|
|
337
|
+
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { normalizeText } from './onboarding-wizard-helpers.ts';
|
|
2
|
+
import type { OnboardingWizardControllerLike } from './onboarding-wizard-types.ts';
|
|
3
|
+
import type { OnboardingWizardFieldDefinition, OnboardingWizardStepDefinition } from './onboarding-wizard-types.ts';
|
|
4
|
+
|
|
5
|
+
export interface WizardStepValidationResult {
|
|
6
|
+
/** Human-readable error strings for each violating field. */
|
|
7
|
+
readonly errors: readonly string[];
|
|
8
|
+
/** ID of the first field that has an error, or null when all pass. */
|
|
9
|
+
readonly firstOffendingFieldId: string | null;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Validate all fields on a single wizard step, checking:
|
|
14
|
+
* - required text / masked fields that are empty
|
|
15
|
+
* - required acknowledgement fields that are unchecked
|
|
16
|
+
* - any general field-level validation errors (via getFieldValidationError)
|
|
17
|
+
*
|
|
18
|
+
* Returns per-field error messages and the first offending field id so the
|
|
19
|
+
* caller can block navigation and jump focus to the first problem.
|
|
20
|
+
*/
|
|
21
|
+
export function getStepValidationErrors(
|
|
22
|
+
controller: OnboardingWizardControllerLike,
|
|
23
|
+
step: OnboardingWizardStepDefinition,
|
|
24
|
+
): WizardStepValidationResult {
|
|
25
|
+
const errors: string[] = [];
|
|
26
|
+
let firstOffendingFieldId: string | null = null;
|
|
27
|
+
|
|
28
|
+
for (const field of step.fields) {
|
|
29
|
+
const error = getFieldError(controller, step, field);
|
|
30
|
+
if (error !== null) {
|
|
31
|
+
errors.push(error);
|
|
32
|
+
if (firstOffendingFieldId === null) firstOffendingFieldId = field.id;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
return { errors, firstOffendingFieldId };
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function getFieldError(
|
|
40
|
+
controller: OnboardingWizardControllerLike,
|
|
41
|
+
step: OnboardingWizardStepDefinition,
|
|
42
|
+
field: OnboardingWizardFieldDefinition,
|
|
43
|
+
): string | null {
|
|
44
|
+
// Required acknowledgement not checked
|
|
45
|
+
if (field.kind === 'acknowledgement' && field.required) {
|
|
46
|
+
if (!controller.isFieldSatisfied(field)) {
|
|
47
|
+
return `${step.shortLabel}: ${field.label} must be acknowledged before continuing.`;
|
|
48
|
+
}
|
|
49
|
+
return null;
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// Required text / masked field that is empty
|
|
53
|
+
if ((field.kind === 'text' || field.kind === 'masked') && field.required === true) {
|
|
54
|
+
const value = normalizeText(controller.getFieldValue(field) as string);
|
|
55
|
+
if (value.length === 0) {
|
|
56
|
+
return `${step.shortLabel}: ${field.label} is required.`;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
// Delegate all other field-level validation (format errors, port range, etc.)
|
|
61
|
+
return controller.getFieldValidationError(step, field);
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Focus the first offending field on the current step by mutating the
|
|
66
|
+
* controller's selectedFieldIndices. The renderer will pick up the change on
|
|
67
|
+
* the next paint cycle.
|
|
68
|
+
*/
|
|
69
|
+
export function focusFirstOffendingField(
|
|
70
|
+
controller: OnboardingWizardControllerLike,
|
|
71
|
+
fieldId: string,
|
|
72
|
+
): void {
|
|
73
|
+
const fields = controller.currentStep.fields;
|
|
74
|
+
const index = fields.findIndex((f) => f.id === fieldId);
|
|
75
|
+
if (index < 0) return;
|
|
76
|
+
controller.selectedFieldIndices[controller.stepIndex] = index;
|
|
77
|
+
}
|
|
@@ -34,12 +34,12 @@ import {
|
|
|
34
34
|
toggleCapability as toggleCapabilityForController,
|
|
35
35
|
} from './onboarding-wizard-rules.ts';
|
|
36
36
|
import { ensureSelectionVisible as ensureSelectionVisibleForController, getBlockingFieldLabels as getBlockingFieldLabelsForController, getCapabilitySelectionState as getCapabilitySelectionStateForController, getCompletedFieldCount as getCompletedFieldCountForController, getCompletedToggleCount as getCompletedToggleCountForController, getCurrentCapabilities as getCurrentCapabilitiesForController, getFieldById as getFieldByIdForController, getFieldValidationError as getFieldValidationErrorForController, getStepFieldCount as getStepFieldCountForController, getToggleFieldCount as getToggleFieldCountForController, hasExistingAccessState as hasExistingAccessStateForController, isFieldDirty as isFieldDirtyForController, isFieldDirtyByDefinition as isFieldDirtyByDefinitionForController, isFieldSatisfied as isFieldSatisfiedForController, isStepDirty as isStepDirtyForController, recalculateDirtyState as recalculateDirtyStateForController, reconcileStateWithCurrentDefinitions as reconcileStateWithCurrentDefinitionsForController, reconcileStepCursor as reconcileStepCursorForController, resetValuesFromCurrentDefinitions as resetValuesFromCurrentDefinitionsForController } from './onboarding-wizard-state.ts';
|
|
37
|
-
import type { MutableModelSelectionMap, OnboardingWizardAction, OnboardingWizardApplyFeedback, OnboardingWizardFieldDefinition, OnboardingWizardFieldWindow, OnboardingWizardMode, OnboardingWizardModelSelection, OnboardingWizardRuntimeHydration, OnboardingWizardSnapshot, OnboardingWizardStepDefinition, OnboardingWizardStepId } from './onboarding-wizard-types.ts';
|
|
37
|
+
import type { OnboardingWizardControllerLike, MutableModelSelectionMap, OnboardingWizardAction, OnboardingWizardApplyFeedback, OnboardingWizardFieldDefinition, OnboardingWizardFieldWindow, OnboardingWizardMode, OnboardingWizardModelSelection, OnboardingWizardRuntimeHydration, OnboardingWizardSnapshot, OnboardingWizardStepDefinition, OnboardingWizardStepId } from './onboarding-wizard-types.ts';
|
|
38
38
|
|
|
39
|
-
export type { OnboardingWizardAcknowledgementFieldDefinition, OnboardingWizardAction, OnboardingWizardActionFieldDefinition, OnboardingWizardApplyFeedback, OnboardingWizardApplyFeedbackSeverity, OnboardingWizardChecklistFieldDefinition, OnboardingWizardExternalSurfaceStepId, OnboardingWizardFieldDefinition, OnboardingWizardFieldKind, OnboardingWizardFieldWindow, OnboardingWizardMaskedFieldDefinition, OnboardingWizardMode, OnboardingWizardModelPickerFieldDefinition, OnboardingWizardModelSelection, OnboardingWizardRadioFieldDefinition, OnboardingWizardRadioOption, OnboardingWizardRuntimeHydration, OnboardingWizardSnapshot, OnboardingWizardStatusFieldDefinition, OnboardingWizardStepDefinition, OnboardingWizardStepId, OnboardingWizardTextFieldDefinition } from './onboarding-wizard-types.ts';
|
|
39
|
+
export type { OnboardingWizardControllerLike, OnboardingWizardAcknowledgementFieldDefinition, OnboardingWizardAction, OnboardingWizardActionFieldDefinition, OnboardingWizardApplyFeedback, OnboardingWizardApplyFeedbackSeverity, OnboardingWizardChecklistFieldDefinition, OnboardingWizardExternalSurfaceStepId, OnboardingWizardFieldDefinition, OnboardingWizardFieldKind, OnboardingWizardFieldWindow, OnboardingWizardMaskedFieldDefinition, OnboardingWizardMode, OnboardingWizardModelPickerFieldDefinition, OnboardingWizardModelSelection, OnboardingWizardRadioFieldDefinition, OnboardingWizardRadioOption, OnboardingWizardRuntimeHydration, OnboardingWizardSnapshot, OnboardingWizardStatusFieldDefinition, OnboardingWizardStepDefinition, OnboardingWizardStepId, OnboardingWizardTextFieldDefinition } from './onboarding-wizard-types.ts';
|
|
40
40
|
export { getOnboardingWizardBodyRows, getOnboardingWizardVisibleFieldCount } from './onboarding-wizard-helpers.ts';
|
|
41
41
|
|
|
42
|
-
export class OnboardingWizardController {
|
|
42
|
+
export class OnboardingWizardController implements OnboardingWizardControllerLike {
|
|
43
43
|
public active = false;
|
|
44
44
|
public mode: OnboardingWizardMode = 'new';
|
|
45
45
|
public stepIndex = 0;
|
|
@@ -33,5 +33,10 @@ export function getNumericAdjustmentMeta(setting: ConfigSetting): {
|
|
|
33
33
|
if (setting.key === 'wrfc.scoreThreshold') {
|
|
34
34
|
return { step: 0.1, min: 0, max: 10, precision: 1 };
|
|
35
35
|
}
|
|
36
|
+
if ((setting.key as string) === 'tts.speed') {
|
|
37
|
+
// Speed multiplier: 0.1 increments, min 0.1, no hard max (provider-defined).
|
|
38
|
+
// tts.speed is not yet a ConfigKey in the SDK schema; cast required.
|
|
39
|
+
return { step: 0.1, min: 0.1, precision: 1 };
|
|
40
|
+
}
|
|
36
41
|
return { step: 1, precision: 0 };
|
|
37
42
|
}
|