@pellux/goodvibes-tui 0.19.27 → 0.19.29
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 +11 -0
- package/README.md +3 -1
- package/docs/foundation-artifacts/operator-contract.json +1 -1
- package/package.json +2 -2
- package/src/cli/bundle-command.ts +3 -2
- package/src/cli/entrypoint.ts +2 -2
- package/src/cli/help.ts +1 -1
- package/src/cli/status.ts +9 -9
- package/src/cli/surface-command.ts +46 -11
- package/src/cli/tui-startup.ts +4 -4
- package/src/daemon/cli.ts +7 -0
- package/src/input/handler-interactions.ts +14 -1
- package/src/input/handler-onboarding.ts +161 -118
- package/src/input/handler.ts +1 -1
- package/src/input/onboarding/handler-onboarding-routes.ts +35 -15
- package/src/input/onboarding/onboarding-wizard-apply.ts +35 -25
- package/src/input/onboarding/onboarding-wizard-constants.ts +4 -5
- package/src/input/onboarding/onboarding-wizard-external-surfaces.ts +93 -5
- package/src/input/onboarding/onboarding-wizard-helpers.ts +2 -3
- package/src/input/onboarding/onboarding-wizard-rules.ts +40 -8
- package/src/input/onboarding/onboarding-wizard-state.ts +19 -8
- package/src/input/onboarding/onboarding-wizard-steps.ts +226 -93
- package/src/input/onboarding/onboarding-wizard-types.ts +15 -0
- package/src/input/onboarding/onboarding-wizard.ts +123 -6
- package/src/input/settings-modal-types.ts +2 -1
- package/src/input/settings-modal.ts +4 -0
- package/src/main.ts +35 -27
- package/src/renderer/compositor.ts +3 -3
- package/src/renderer/onboarding/onboarding-wizard.ts +141 -57
- package/src/renderer/settings-modal-helpers.ts +9 -0
- package/src/renderer/settings-modal.ts +3 -0
- package/src/runtime/bootstrap.ts +15 -0
- package/src/runtime/onboarding/apply.ts +45 -90
- package/src/runtime/onboarding/derivation.ts +7 -7
- package/src/runtime/onboarding/markers.ts +41 -55
- package/src/runtime/onboarding/snapshot.ts +1 -0
- package/src/runtime/onboarding/state.ts +6 -6
- package/src/runtime/onboarding/types.ts +24 -27
- package/src/runtime/onboarding/verify.ts +3 -65
- package/src/runtime/surface-feature-flags.ts +67 -0
- package/src/version.ts +1 -1
|
@@ -1,8 +1,14 @@
|
|
|
1
1
|
import { NETWORK_MODE_OPTIONS, REASONING_OPTIONS, HITL_MODE_OPTIONS, GUIDANCE_MODE_OPTIONS, PERMISSION_MODE_OPTIONS, SECRET_POLICY_OPTIONS } from './onboarding-wizard-constants.ts';
|
|
2
|
-
import {
|
|
2
|
+
import {
|
|
3
|
+
EXTERNAL_SURFACE_SPECS,
|
|
4
|
+
getExternalSurfaceAutoStartDefaultValue,
|
|
5
|
+
getExternalSurfaceAutoStartFieldId,
|
|
6
|
+
isExternalSurfaceSelectedByDefault,
|
|
7
|
+
type ExternalSurfaceSpec,
|
|
8
|
+
} from './onboarding-wizard-external-surfaces.ts';
|
|
3
9
|
import { countSelected, modelSelectionLabel, normalizeText } from './onboarding-wizard-helpers.ts';
|
|
4
10
|
import type { OnboardingWizardController } from './onboarding-wizard.ts';
|
|
5
|
-
import type { OnboardingWizardAcknowledgementFieldDefinition, OnboardingWizardChecklistFieldDefinition, OnboardingWizardFieldDefinition, OnboardingWizardModelPickerFieldDefinition, OnboardingWizardRadioFieldDefinition, OnboardingWizardStepDefinition } from './onboarding-wizard-types.ts';
|
|
11
|
+
import type { OnboardingWizardAcknowledgementFieldDefinition, OnboardingWizardChecklistFieldDefinition, OnboardingWizardExternalSurfaceStepId, OnboardingWizardFieldDefinition, OnboardingWizardModelPickerFieldDefinition, OnboardingWizardRadioFieldDefinition, OnboardingWizardRadioOption, OnboardingWizardStepDefinition } from './onboarding-wizard-types.ts';
|
|
6
12
|
|
|
7
13
|
export function buildOnboardingWizardSteps(controller: OnboardingWizardController): readonly OnboardingWizardStepDefinition[] {
|
|
8
14
|
if (controller.hydrationPending || controller.hydrationError !== null) return [buildLoadingStep(controller)];
|
|
@@ -24,6 +30,9 @@ export function buildOnboardingWizardSteps(controller: OnboardingWizardControlle
|
|
|
24
30
|
|
|
25
31
|
if (wantsExternalServices) {
|
|
26
32
|
steps.push(buildExternalServicesStep(controller));
|
|
33
|
+
for (const surface of getSelectedExternalSurfaceSpecs(controller)) {
|
|
34
|
+
steps.push(buildExternalSurfaceStep(controller, surface));
|
|
35
|
+
}
|
|
27
36
|
}
|
|
28
37
|
|
|
29
38
|
steps.push(buildProviderAccessStep(controller));
|
|
@@ -83,7 +92,7 @@ export function buildCapabilitiesStep(controller: OnboardingWizardController): O
|
|
|
83
92
|
id: 'capabilities.select-all',
|
|
84
93
|
action: 'select-all-capabilities',
|
|
85
94
|
label: 'Select all server-backed capabilities',
|
|
86
|
-
hint: 'Enable browser access,
|
|
95
|
+
hint: 'Enable browser access, LAN reachability, webhooks/events, and external app surfaces. Local TUI Only is turned off.',
|
|
87
96
|
defaultValue: 'Action',
|
|
88
97
|
},
|
|
89
98
|
{
|
|
@@ -98,9 +107,9 @@ export function buildCapabilitiesStep(controller: OnboardingWizardController): O
|
|
|
98
107
|
|
|
99
108
|
return {
|
|
100
109
|
id: 'capabilities',
|
|
101
|
-
title: '
|
|
110
|
+
title: 'Choose GoodVibes capabilities',
|
|
102
111
|
shortLabel: 'Capabilities',
|
|
103
|
-
description: 'Choose
|
|
112
|
+
description: 'Choose what GoodVibes should be able to do. Local TUI Only avoids servers; any other choice enables service mode and autostart.',
|
|
104
113
|
summaryTitle: 'Selected capabilities',
|
|
105
114
|
summaryLines: [
|
|
106
115
|
`${selectedCount}/${capabilities.length} option(s) selected`,
|
|
@@ -263,68 +272,169 @@ export function buildDefaultModelStep(controller: OnboardingWizardController): O
|
|
|
263
272
|
}
|
|
264
273
|
|
|
265
274
|
export function buildExternalServicesStep(controller: OnboardingWizardController): OnboardingWizardStepDefinition {
|
|
266
|
-
const
|
|
267
|
-
.filter((surface) => controller.getBooleanFieldValue(
|
|
275
|
+
const selectedCount = EXTERNAL_SURFACE_SPECS
|
|
276
|
+
.filter((surface) => controller.getBooleanFieldValue(
|
|
277
|
+
surface.enabledFieldId,
|
|
278
|
+
isExternalSurfaceSelectedByDefault(surface, controller.runtimeSnapshot),
|
|
279
|
+
))
|
|
268
280
|
.length;
|
|
269
281
|
const fields: OnboardingWizardFieldDefinition[] = [];
|
|
270
282
|
|
|
271
283
|
for (const surface of EXTERNAL_SURFACE_SPECS) {
|
|
272
|
-
const enabled = controller.getBooleanFieldValue(surface.enabledFieldId, surface.defaultEnabled(controller.runtimeSnapshot));
|
|
273
284
|
fields.push({
|
|
274
285
|
kind: 'checklist',
|
|
275
286
|
id: surface.enabledFieldId,
|
|
276
287
|
label: surface.label,
|
|
277
|
-
hint: surface.hint
|
|
278
|
-
defaultValue: surface
|
|
288
|
+
hint: `${surface.hint} Selecting this opens a dedicated setup screen; auto-start is chosen on that screen.`,
|
|
289
|
+
defaultValue: isExternalSurfaceSelectedByDefault(surface, controller.runtimeSnapshot),
|
|
279
290
|
});
|
|
291
|
+
}
|
|
280
292
|
|
|
281
|
-
|
|
282
|
-
|
|
283
|
-
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
292
|
-
|
|
293
|
+
fields.push(
|
|
294
|
+
{
|
|
295
|
+
kind: 'action',
|
|
296
|
+
id: 'external-services.select-all',
|
|
297
|
+
action: 'select-all-external-surfaces',
|
|
298
|
+
label: 'Select all external surfaces',
|
|
299
|
+
hint: 'Show setup screens for every supported external surface. Auto-start stays controlled per surface.',
|
|
300
|
+
defaultValue: 'Action',
|
|
301
|
+
},
|
|
302
|
+
{
|
|
303
|
+
kind: 'action',
|
|
304
|
+
id: 'external-services.clear',
|
|
305
|
+
action: 'clear-external-surfaces',
|
|
306
|
+
label: 'Clear all external surfaces',
|
|
307
|
+
hint: 'Hide all external surface setup screens. The HTTP listener can still be enabled separately by webhook/event capabilities.',
|
|
308
|
+
defaultValue: 'Action',
|
|
309
|
+
},
|
|
310
|
+
{
|
|
311
|
+
kind: 'radio',
|
|
312
|
+
id: 'external-services.secret-policy',
|
|
313
|
+
label: 'Secret storage policy',
|
|
314
|
+
hint: 'Choose how selected surface secrets should be stored. Secret values are never shown in the wizard.',
|
|
315
|
+
options: SECRET_POLICY_OPTIONS,
|
|
316
|
+
defaultValue: controller.runtimeSnapshot?.runtimeDefaults.secretStoragePolicy ?? 'preferred_secure',
|
|
317
|
+
},
|
|
318
|
+
);
|
|
319
|
+
|
|
320
|
+
return {
|
|
321
|
+
id: 'external-services',
|
|
322
|
+
title: 'Choose external surfaces',
|
|
323
|
+
shortLabel: 'Services',
|
|
324
|
+
description: 'Select the apps and integration surfaces GoodVibes should prepare. Each selected surface gets its own setup screen and its own auto-start choice.',
|
|
325
|
+
summaryTitle: 'External surfaces',
|
|
326
|
+
summaryLines: [
|
|
327
|
+
`${selectedCount} external surface(s) selected for setup`,
|
|
328
|
+
`Secret policy: ${controller.getStringFieldValue('external-services.secret-policy', controller.runtimeSnapshot?.runtimeDefaults.secretStoragePolicy ?? 'preferred_secure')}`,
|
|
329
|
+
selectedCount > 0 ? 'Selected surfaces appear as separate setup screens.' : 'No external surfaces selected.',
|
|
330
|
+
],
|
|
331
|
+
fields,
|
|
332
|
+
};
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
function getSelectedExternalSurfaceSpecs(controller: OnboardingWizardController): readonly ExternalSurfaceSpec[] {
|
|
336
|
+
return EXTERNAL_SURFACE_SPECS.filter((surface) => (
|
|
337
|
+
controller.getBooleanFieldValue(
|
|
338
|
+
surface.enabledFieldId,
|
|
339
|
+
isExternalSurfaceSelectedByDefault(surface, controller.runtimeSnapshot),
|
|
340
|
+
)
|
|
341
|
+
));
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
const SURFACE_AUTO_START_OPTIONS: readonly OnboardingWizardRadioOption[] = [
|
|
345
|
+
{
|
|
346
|
+
id: 'yes',
|
|
347
|
+
label: 'Yes',
|
|
348
|
+
hint: 'Start this surface automatically when the GoodVibes service starts.',
|
|
349
|
+
},
|
|
350
|
+
{
|
|
351
|
+
id: 'no',
|
|
352
|
+
label: 'No',
|
|
353
|
+
hint: 'Save these settings but leave the surface idle until it is enabled from Settings > Surfaces.',
|
|
354
|
+
},
|
|
355
|
+
];
|
|
356
|
+
|
|
357
|
+
function buildExternalSurfaceStep(
|
|
358
|
+
controller: OnboardingWizardController,
|
|
359
|
+
surface: ExternalSurfaceSpec,
|
|
360
|
+
): OnboardingWizardStepDefinition {
|
|
361
|
+
let setupCount = 0;
|
|
362
|
+
let setupCompleteCount = 0;
|
|
363
|
+
const autoStartFieldId = getExternalSurfaceAutoStartFieldId(surface);
|
|
364
|
+
const autoStartDefault = getExternalSurfaceAutoStartDefaultValue(surface, controller.runtimeSnapshot);
|
|
365
|
+
const autoStartValue = controller.getStringFieldValue(autoStartFieldId, autoStartDefault);
|
|
366
|
+
const setupFields = surface.fields.map((setupField): OnboardingWizardFieldDefinition => {
|
|
367
|
+
const suggested = controller.isRequiredExternalSetupField(setupField.id);
|
|
368
|
+
if (suggested) {
|
|
369
|
+
setupCount += 1;
|
|
370
|
+
if (normalizeText(setupField.defaultValue(controller.runtimeSnapshot)).length > 0
|
|
371
|
+
|| normalizeText(controller.getStringFieldValue(setupField.id, '')).length > 0) {
|
|
372
|
+
setupCompleteCount += 1;
|
|
293
373
|
}
|
|
374
|
+
}
|
|
294
375
|
|
|
295
|
-
|
|
296
|
-
|
|
376
|
+
const hint = suggested
|
|
377
|
+
? `${setupField.hint} Recommended because ${surface.label} is selected, but it will not block saving.`
|
|
378
|
+
: setupField.hint;
|
|
379
|
+
|
|
380
|
+
if (setupField.kind === 'radio') {
|
|
381
|
+
return {
|
|
382
|
+
kind: 'radio',
|
|
297
383
|
id: setupField.id,
|
|
298
384
|
label: setupField.label,
|
|
299
|
-
hint
|
|
300
|
-
|
|
385
|
+
hint,
|
|
386
|
+
options: setupField.options ?? [],
|
|
301
387
|
defaultValue: setupField.defaultValue(controller.runtimeSnapshot),
|
|
302
|
-
|
|
303
|
-
});
|
|
388
|
+
};
|
|
304
389
|
}
|
|
305
|
-
}
|
|
306
390
|
|
|
307
|
-
|
|
308
|
-
|
|
309
|
-
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
313
|
-
|
|
391
|
+
return {
|
|
392
|
+
kind: setupField.kind,
|
|
393
|
+
id: setupField.id,
|
|
394
|
+
label: setupField.label,
|
|
395
|
+
hint,
|
|
396
|
+
placeholder: setupField.placeholder,
|
|
397
|
+
defaultValue: setupField.defaultValue(controller.runtimeSnapshot),
|
|
398
|
+
};
|
|
314
399
|
});
|
|
400
|
+
const ntfyTopicSummary = surface.id === 'ntfy'
|
|
401
|
+
? [
|
|
402
|
+
`Chat topic: ${controller.getStringFieldValue('external-services.ntfy.chat-topic', 'goodvibes-chat')}`,
|
|
403
|
+
`Agent topic: ${controller.getStringFieldValue('external-services.ntfy.agent-topic', 'goodvibes-agent')}`,
|
|
404
|
+
`Daemon-only remote topic: ${controller.getStringFieldValue('external-services.ntfy.remote-topic', 'goodvibes-ntfy')}`,
|
|
405
|
+
]
|
|
406
|
+
: [];
|
|
407
|
+
const title = `${surface.label.replace(/ surface$/i, '')} setup`;
|
|
408
|
+
const setupSummary = setupCount === 0
|
|
409
|
+
? 'Suggested setup: none'
|
|
410
|
+
: `Suggested setup entered: ${setupCompleteCount}/${setupCount}`;
|
|
315
411
|
|
|
316
412
|
return {
|
|
317
|
-
id:
|
|
318
|
-
title
|
|
319
|
-
shortLabel: '
|
|
320
|
-
description:
|
|
321
|
-
summaryTitle:
|
|
413
|
+
id: `external-surface:${surface.id}` as OnboardingWizardExternalSurfaceStepId,
|
|
414
|
+
title,
|
|
415
|
+
shortLabel: surface.label.replace(/ surface$/i, ''),
|
|
416
|
+
description: `Configure ${surface.label}. Settings are saved either way; auto-start controls whether this surface starts with the background service.`,
|
|
417
|
+
summaryTitle: `${surface.label} setup`,
|
|
322
418
|
summaryLines: [
|
|
323
|
-
|
|
419
|
+
`Auto-start: ${autoStartValue === 'yes' ? 'yes' : 'no'}`,
|
|
420
|
+
...ntfyTopicSummary,
|
|
421
|
+
setupSummary,
|
|
324
422
|
`Secret policy: ${controller.getStringFieldValue('external-services.secret-policy', controller.runtimeSnapshot?.runtimeDefaults.secretStoragePolicy ?? 'preferred_secure')}`,
|
|
325
|
-
|
|
423
|
+
autoStartValue === 'yes'
|
|
424
|
+
? 'The surface will be enabled after apply.'
|
|
425
|
+
: 'Start it later from Settings > Surfaces by turning Enabled on.',
|
|
426
|
+
],
|
|
427
|
+
fields: [
|
|
428
|
+
{
|
|
429
|
+
kind: 'radio',
|
|
430
|
+
id: autoStartFieldId,
|
|
431
|
+
label: 'Auto-start this surface',
|
|
432
|
+
hint: `Yes turns on ${surface.enabledConfigKey}. No saves setup values but keeps the surface off until Settings > Surfaces enables it.`,
|
|
433
|
+
options: SURFACE_AUTO_START_OPTIONS,
|
|
434
|
+
defaultValue: autoStartDefault,
|
|
435
|
+
},
|
|
436
|
+
...setupFields,
|
|
326
437
|
],
|
|
327
|
-
fields,
|
|
328
438
|
};
|
|
329
439
|
}
|
|
330
440
|
|
|
@@ -510,34 +620,36 @@ export function buildAccountsStep(controller: OnboardingWizardController): Onboa
|
|
|
510
620
|
const needsAuthBootstrap = controller.requiresAuthBootstrap();
|
|
511
621
|
const needsExistingAuthAcknowledgement = controller.hasServerCapabilitiesSelected()
|
|
512
622
|
&& !needsAuthBootstrap
|
|
513
|
-
&& controller.
|
|
623
|
+
&& controller.hasLocalAuthUser();
|
|
514
624
|
const fields: OnboardingWizardFieldDefinition[] = [];
|
|
625
|
+
const defaultAdminUsername = controller.getDefaultAdminUsername();
|
|
515
626
|
|
|
516
|
-
|
|
517
|
-
|
|
518
|
-
|
|
519
|
-
|
|
520
|
-
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
531
|
-
|
|
532
|
-
|
|
533
|
-
|
|
534
|
-
|
|
535
|
-
|
|
536
|
-
|
|
537
|
-
|
|
538
|
-
|
|
539
|
-
|
|
540
|
-
|
|
627
|
+
fields.push(
|
|
628
|
+
{
|
|
629
|
+
kind: 'text',
|
|
630
|
+
id: 'accounts.admin-username',
|
|
631
|
+
label: 'Local auth admin username',
|
|
632
|
+
hint: needsAuthBootstrap
|
|
633
|
+
? 'Required before any background service, browser surface, or listener is exposed.'
|
|
634
|
+
: 'Optional. Enter an existing admin username to rotate its password, or a new username to create another admin.',
|
|
635
|
+
placeholder: defaultAdminUsername,
|
|
636
|
+
defaultValue: defaultAdminUsername,
|
|
637
|
+
required: needsAuthBootstrap,
|
|
638
|
+
},
|
|
639
|
+
{
|
|
640
|
+
kind: 'masked',
|
|
641
|
+
id: 'accounts.admin-password',
|
|
642
|
+
label: 'Local auth admin password',
|
|
643
|
+
hint: needsAuthBootstrap
|
|
644
|
+
? controller.hasBootstrapCredentialPresent()
|
|
645
|
+
? 'Creates or updates the named local admin, removes the bootstrap credential file, and retires the bootstrap admin when it is a different user.'
|
|
646
|
+
: 'Creates the first local admin user and an initial session before LAN/server settings are applied.'
|
|
647
|
+
: 'Optional. Leave blank to keep existing local auth unchanged; enter a password to create or rotate the named admin user.',
|
|
648
|
+
placeholder: needsAuthBootstrap ? 'password required' : 'leave blank to keep unchanged',
|
|
649
|
+
defaultValue: '',
|
|
650
|
+
required: needsAuthBootstrap,
|
|
651
|
+
},
|
|
652
|
+
);
|
|
541
653
|
|
|
542
654
|
fields.push(
|
|
543
655
|
{
|
|
@@ -563,13 +675,17 @@ export function buildAccountsStep(controller: OnboardingWizardController): Onboa
|
|
|
563
675
|
{
|
|
564
676
|
kind: 'status',
|
|
565
677
|
id: 'accounts.bootstrap',
|
|
566
|
-
label: '
|
|
678
|
+
label: 'Local auth readiness',
|
|
567
679
|
hint: needsAuthBootstrap
|
|
568
680
|
? 'The wizard will create local auth before applying network-accessible settings.'
|
|
569
|
-
:
|
|
681
|
+
: controller.hasAdminAuthUser()
|
|
682
|
+
? 'An existing local auth admin user was detected and will be kept.'
|
|
683
|
+
: controller.hasLocalAuthUser()
|
|
684
|
+
? 'Existing local auth users were detected and will be kept.'
|
|
685
|
+
: 'No server-backed capability is selected, so local auth is not required.',
|
|
570
686
|
defaultValue: needsAuthBootstrap
|
|
571
687
|
? controller.hasBootstrapCredentialPresent() ? 'Bootstrap replacement required' : 'Local admin required'
|
|
572
|
-
:
|
|
688
|
+
: controller.hasAdminAuthUser() ? 'Admin detected' : controller.hasLocalAuthUser() ? 'Local auth detected' : 'Not required',
|
|
573
689
|
},
|
|
574
690
|
{
|
|
575
691
|
kind: 'status',
|
|
@@ -586,7 +702,7 @@ export function buildAccountsStep(controller: OnboardingWizardController): Onboa
|
|
|
586
702
|
shortLabel: 'Accounts',
|
|
587
703
|
description: needsAuthBootstrap
|
|
588
704
|
? 'Create wizard-owned local auth before any LAN, browser, service, or listener settings are applied.'
|
|
589
|
-
: '
|
|
705
|
+
: 'Review existing subscription and local auth state. Existing local auth is kept unless you change it elsewhere.',
|
|
590
706
|
summaryTitle: 'Stored account state',
|
|
591
707
|
summaryLines: [
|
|
592
708
|
`Subscriptions: ${controller.runtimeSnapshot?.subscriptions.active.length ?? 0} active / ${controller.runtimeSnapshot?.subscriptions.pending.length ?? 0} pending`,
|
|
@@ -595,46 +711,63 @@ export function buildAccountsStep(controller: OnboardingWizardController): Onboa
|
|
|
595
711
|
? controller.hasBootstrapCredentialPresent()
|
|
596
712
|
? 'Bootstrap credentials will be replaced before network settings are applied'
|
|
597
713
|
: 'Local admin will be created before network settings are applied'
|
|
598
|
-
:
|
|
714
|
+
: controller.hasLocalAuthUser() ? 'Existing local auth will be kept' : 'Local auth is not required for this setup',
|
|
599
715
|
],
|
|
600
716
|
fields,
|
|
601
717
|
};
|
|
602
718
|
}
|
|
603
719
|
|
|
604
720
|
export function buildReviewStep(controller: OnboardingWizardController): OnboardingWizardStepDefinition {
|
|
721
|
+
const feedback = controller.applyFeedback;
|
|
722
|
+
const feedbackFields: OnboardingWizardFieldDefinition[] = feedback
|
|
723
|
+
? [
|
|
724
|
+
{
|
|
725
|
+
kind: 'status',
|
|
726
|
+
id: 'review.feedback',
|
|
727
|
+
label: feedback.title,
|
|
728
|
+
hint: feedback.summary,
|
|
729
|
+
defaultValue: feedback.severity === 'error' ? 'Needs attention' : feedback.severity === 'warning' ? 'Warning' : 'Info',
|
|
730
|
+
},
|
|
731
|
+
...feedback.messages.slice(0, 8).map((message, index): OnboardingWizardFieldDefinition => ({
|
|
732
|
+
kind: 'status',
|
|
733
|
+
id: `review.feedback.${index}`,
|
|
734
|
+
label: message,
|
|
735
|
+
hint: message,
|
|
736
|
+
defaultValue: feedback.severity === 'error' ? 'Error' : feedback.severity === 'warning' ? 'Warning' : 'Info',
|
|
737
|
+
})),
|
|
738
|
+
]
|
|
739
|
+
: [];
|
|
740
|
+
const unsavedLabel = controller.dirtyStepCount === 1
|
|
741
|
+
? '1 screen has unapplied changes'
|
|
742
|
+
: `${controller.dirtyStepCount} screens have unapplied changes`;
|
|
743
|
+
|
|
605
744
|
return {
|
|
606
745
|
id: 'review',
|
|
607
|
-
title: 'Review and
|
|
746
|
+
title: 'Review and apply',
|
|
608
747
|
shortLabel: 'Review',
|
|
609
748
|
description: 'Review the selected settings and apply them directly from the wizard.',
|
|
610
749
|
summaryTitle: 'Review posture',
|
|
611
750
|
summaryLines: [
|
|
612
|
-
|
|
613
|
-
`${controller.buildApplyRequest().operations.length}
|
|
614
|
-
`
|
|
615
|
-
controller.isEditingTextField() ? `Editing: ${controller.editingFieldId}` : 'Ready
|
|
751
|
+
unsavedLabel,
|
|
752
|
+
`${controller.buildApplyRequest().operations.length} settings change(s) ready to apply`,
|
|
753
|
+
feedback ? `Last apply: ${feedback.title}` : 'No apply errors reported',
|
|
754
|
+
controller.isEditingTextField() ? `Editing: ${controller.editingFieldId}` : 'Ready to apply',
|
|
616
755
|
],
|
|
617
756
|
fields: [
|
|
757
|
+
...feedbackFields,
|
|
618
758
|
{
|
|
619
|
-
kind: '
|
|
620
|
-
id: 'review.
|
|
621
|
-
label: '
|
|
622
|
-
hint: '
|
|
623
|
-
defaultValue:
|
|
624
|
-
},
|
|
625
|
-
{
|
|
626
|
-
kind: 'checklist',
|
|
627
|
-
id: 'review.user-marker',
|
|
628
|
-
label: 'Write user completion marker',
|
|
629
|
-
hint: 'User scope keeps the shell-level completion marker available outside this workspace.',
|
|
630
|
-
defaultValue: controller.defaultReviewUserMarker(),
|
|
759
|
+
kind: 'status',
|
|
760
|
+
id: 'review.global-marker',
|
|
761
|
+
label: 'Global onboarding check',
|
|
762
|
+
hint: 'Opening this wizard marks onboarding as shown for this user account, so new projects do not reopen it automatically.',
|
|
763
|
+
defaultValue: 'Already marked as shown',
|
|
631
764
|
},
|
|
632
765
|
{
|
|
633
766
|
kind: 'action',
|
|
634
767
|
id: 'review.apply',
|
|
635
768
|
action: 'apply',
|
|
636
769
|
label: 'Apply settings and verify',
|
|
637
|
-
hint: 'Persist the wizard settings
|
|
770
|
+
hint: 'Persist the wizard settings and verify the resulting runtime state. The global onboarding check was already recorded when the wizard opened.',
|
|
638
771
|
defaultValue: 'Ready',
|
|
639
772
|
},
|
|
640
773
|
],
|
|
@@ -16,12 +16,15 @@ import type { ConfigKey } from '../../config/index.ts';
|
|
|
16
16
|
|
|
17
17
|
export type OnboardingWizardMode = OnboardingMode;
|
|
18
18
|
|
|
19
|
+
export type OnboardingWizardExternalSurfaceStepId = `external-surface:${string}`;
|
|
20
|
+
|
|
19
21
|
export type OnboardingWizardStepId =
|
|
20
22
|
| 'loading'
|
|
21
23
|
| 'capabilities'
|
|
22
24
|
| 'network'
|
|
23
25
|
| 'access'
|
|
24
26
|
| 'external-services'
|
|
27
|
+
| OnboardingWizardExternalSurfaceStepId
|
|
25
28
|
| 'provider-access'
|
|
26
29
|
| 'default-model'
|
|
27
30
|
| 'experience'
|
|
@@ -41,9 +44,20 @@ export type OnboardingWizardAction =
|
|
|
41
44
|
| 'apply'
|
|
42
45
|
| 'select-all-capabilities'
|
|
43
46
|
| 'clear-capabilities'
|
|
47
|
+
| 'select-all-external-surfaces'
|
|
48
|
+
| 'clear-external-surfaces'
|
|
44
49
|
| 'start-openai-subscription'
|
|
45
50
|
| 'finish-openai-subscription';
|
|
46
51
|
|
|
52
|
+
export type OnboardingWizardApplyFeedbackSeverity = 'info' | 'warning' | 'error';
|
|
53
|
+
|
|
54
|
+
export interface OnboardingWizardApplyFeedback {
|
|
55
|
+
readonly severity: OnboardingWizardApplyFeedbackSeverity;
|
|
56
|
+
readonly title: string;
|
|
57
|
+
readonly summary: string;
|
|
58
|
+
readonly messages: readonly string[];
|
|
59
|
+
}
|
|
60
|
+
|
|
47
61
|
export interface OnboardingWizardRadioOption {
|
|
48
62
|
readonly id: string;
|
|
49
63
|
readonly label: string;
|
|
@@ -159,6 +173,7 @@ export interface OnboardingWizardSnapshot {
|
|
|
159
173
|
readonly editBuffer: string;
|
|
160
174
|
readonly hydrationPending: boolean;
|
|
161
175
|
readonly hydrationError: string | null;
|
|
176
|
+
readonly applyFeedback: OnboardingWizardApplyFeedback | null;
|
|
162
177
|
readonly hydration: OnboardingWizardRuntimeHydration;
|
|
163
178
|
}
|
|
164
179
|
|