@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
|
@@ -4,11 +4,39 @@ import { STEP_ORDER } from './onboarding-wizard-constants.ts';
|
|
|
4
4
|
import { buildOnboardingApplyRequest } from './onboarding-wizard-apply.ts';
|
|
5
5
|
import { buildOnboardingWizardSteps } from './onboarding-wizard-steps.ts';
|
|
6
6
|
import { buildDefaultDerivedState, clamp, cloneSelection, getRuntimeDerivedState, maskValue, modelSelectionLabel, normalizeText } from './onboarding-wizard-helpers.ts';
|
|
7
|
-
import {
|
|
7
|
+
import {
|
|
8
|
+
clearExternalSurfaces as clearExternalSurfacesForController,
|
|
9
|
+
getBooleanFieldValue as getBooleanFieldValueForController,
|
|
10
|
+
getDefaultAdminUsername as getDefaultAdminUsernameForController,
|
|
11
|
+
getNumberFieldValue as getNumberFieldValueForController,
|
|
12
|
+
getPortFieldValue as getPortFieldValueForController,
|
|
13
|
+
getSelectedSecretMedium as getSelectedSecretMediumForController,
|
|
14
|
+
getSharedIpDefault as getSharedIpDefaultForController,
|
|
15
|
+
getSharedIpHostDefault as getSharedIpHostDefaultForController,
|
|
16
|
+
getStringFieldValue as getStringFieldValueForController,
|
|
17
|
+
hasAdminAuthUser as hasAdminAuthUserForController,
|
|
18
|
+
hasBootstrapCredentialPresent as hasBootstrapCredentialPresentForController,
|
|
19
|
+
hasLocalAuthUser as hasLocalAuthUserForController,
|
|
20
|
+
hasSelectedInboundExternalSurface as hasSelectedInboundExternalSurfaceForController,
|
|
21
|
+
hasServerCapabilitiesSelected as hasServerCapabilitiesSelectedForController,
|
|
22
|
+
isCapabilitySelected as isCapabilitySelectedForController,
|
|
23
|
+
isRequiredExternalSetupField as isRequiredExternalSetupFieldForController,
|
|
24
|
+
parseIntegerFieldValue as parseIntegerFieldValueForController,
|
|
25
|
+
requiresAuthBootstrap as requiresAuthBootstrapForController,
|
|
26
|
+
selectAllExternalSurfaces as selectAllExternalSurfacesForController,
|
|
27
|
+
selectAllServerCapabilities as selectAllServerCapabilitiesForController,
|
|
28
|
+
selectLocalTuiOnly as selectLocalTuiOnlyForController,
|
|
29
|
+
setCapabilityValue as setCapabilityValueForController,
|
|
30
|
+
shouldEnableBrowserSurface as shouldEnableBrowserSurfaceForController,
|
|
31
|
+
shouldEnableHttpListener as shouldEnableHttpListenerForController,
|
|
32
|
+
shouldExposeControlPlaneNetwork as shouldExposeControlPlaneNetworkForController,
|
|
33
|
+
shouldExposeHttpListenerNetworkFields as shouldExposeHttpListenerNetworkFieldsForController,
|
|
34
|
+
toggleCapability as toggleCapabilityForController,
|
|
35
|
+
} from './onboarding-wizard-rules.ts';
|
|
8
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';
|
|
9
|
-
import type { MutableModelSelectionMap, OnboardingWizardAction, OnboardingWizardFieldDefinition, OnboardingWizardFieldWindow, OnboardingWizardMode, OnboardingWizardModelSelection, OnboardingWizardRuntimeHydration, OnboardingWizardSnapshot, OnboardingWizardStepDefinition, OnboardingWizardStepId } from './onboarding-wizard-types.ts';
|
|
37
|
+
import type { MutableModelSelectionMap, OnboardingWizardAction, OnboardingWizardApplyFeedback, OnboardingWizardFieldDefinition, OnboardingWizardFieldWindow, OnboardingWizardMode, OnboardingWizardModelSelection, OnboardingWizardRuntimeHydration, OnboardingWizardSnapshot, OnboardingWizardStepDefinition, OnboardingWizardStepId } from './onboarding-wizard-types.ts';
|
|
10
38
|
|
|
11
|
-
export type { OnboardingWizardAcknowledgementFieldDefinition, OnboardingWizardAction, OnboardingWizardActionFieldDefinition, OnboardingWizardChecklistFieldDefinition, OnboardingWizardFieldDefinition, OnboardingWizardFieldKind, OnboardingWizardFieldWindow, OnboardingWizardMaskedFieldDefinition, OnboardingWizardMode, OnboardingWizardModelPickerFieldDefinition, OnboardingWizardModelSelection, OnboardingWizardRadioFieldDefinition, OnboardingWizardRadioOption, OnboardingWizardRuntimeHydration, OnboardingWizardSnapshot, OnboardingWizardStatusFieldDefinition, OnboardingWizardStepDefinition, OnboardingWizardStepId, OnboardingWizardTextFieldDefinition } from './onboarding-wizard-types.ts';
|
|
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';
|
|
12
40
|
export { getOnboardingWizardBodyRows, getOnboardingWizardVisibleFieldCount } from './onboarding-wizard-helpers.ts';
|
|
13
41
|
|
|
14
42
|
export class OnboardingWizardController {
|
|
@@ -30,6 +58,7 @@ export class OnboardingWizardController {
|
|
|
30
58
|
public editingFieldId: string | null = null;
|
|
31
59
|
public editBuffer = '';
|
|
32
60
|
public hydrationError: string | null = null;
|
|
61
|
+
public applyFeedback: OnboardingWizardApplyFeedback | null = null;
|
|
33
62
|
|
|
34
63
|
public readonly baselineToggleState = new Map<string, boolean>();
|
|
35
64
|
public readonly baselineRadioState = new Map<string, string>();
|
|
@@ -40,7 +69,9 @@ export class OnboardingWizardController {
|
|
|
40
69
|
public runtimeDerived: OnboardingStepDerivationState = buildDefaultDerivedState();
|
|
41
70
|
|
|
42
71
|
public get steps(): readonly OnboardingWizardStepDefinition[] {
|
|
43
|
-
|
|
72
|
+
const steps = buildOnboardingWizardSteps(this);
|
|
73
|
+
this.ensureNavigationStateLength(steps.length);
|
|
74
|
+
return steps;
|
|
44
75
|
}
|
|
45
76
|
|
|
46
77
|
public get currentStep(): OnboardingWizardStepDefinition {
|
|
@@ -59,6 +90,11 @@ export class OnboardingWizardController {
|
|
|
59
90
|
this.resetValuesFromCurrentDefinitions();
|
|
60
91
|
}
|
|
61
92
|
|
|
93
|
+
private ensureNavigationStateLength(stepCount: number): void {
|
|
94
|
+
while (this.scrollOffsets.length < stepCount) this.scrollOffsets.push(0);
|
|
95
|
+
while (this.selectedFieldIndices.length < stepCount) this.selectedFieldIndices.push(0);
|
|
96
|
+
}
|
|
97
|
+
|
|
62
98
|
public open(mode: OnboardingWizardMode = 'new'): void {
|
|
63
99
|
this.mode = mode;
|
|
64
100
|
this.active = true;
|
|
@@ -67,6 +103,7 @@ export class OnboardingWizardController {
|
|
|
67
103
|
this.stepIndex = 0;
|
|
68
104
|
this.pendingModelPickerTarget = null;
|
|
69
105
|
this.pendingAction = null;
|
|
106
|
+
this.applyFeedback = null;
|
|
70
107
|
this.editingFieldId = null;
|
|
71
108
|
this.editBuffer = '';
|
|
72
109
|
this.scrollOffsets.fill(0);
|
|
@@ -80,6 +117,7 @@ export class OnboardingWizardController {
|
|
|
80
117
|
this.hydrationError = null;
|
|
81
118
|
this.pendingModelPickerTarget = null;
|
|
82
119
|
this.pendingAction = null;
|
|
120
|
+
this.applyFeedback = null;
|
|
83
121
|
this.cancelEdit();
|
|
84
122
|
}
|
|
85
123
|
|
|
@@ -143,6 +181,7 @@ export class OnboardingWizardController {
|
|
|
143
181
|
editBuffer: this.editBuffer,
|
|
144
182
|
hydrationPending: this.hydrationPending,
|
|
145
183
|
hydrationError: this.hydrationError,
|
|
184
|
+
applyFeedback: this.applyFeedback,
|
|
146
185
|
hydration: this.captureHydratedState(),
|
|
147
186
|
};
|
|
148
187
|
}
|
|
@@ -156,10 +195,13 @@ export class OnboardingWizardController {
|
|
|
156
195
|
this.stepIndex = clamp(snapshot.stepIndex, 0, Math.max(0, this.steps.length - 1));
|
|
157
196
|
this.pendingModelPickerTarget = snapshot.pendingModelPickerTarget;
|
|
158
197
|
this.pendingAction = snapshot.pendingAction;
|
|
198
|
+
this.applyFeedback = snapshot.applyFeedback;
|
|
159
199
|
this.dirtyStepIds.clear();
|
|
160
200
|
for (const stepId of snapshot.dirtyStepIds) this.dirtyStepIds.add(stepId);
|
|
161
201
|
|
|
162
|
-
|
|
202
|
+
const navigationLength = Math.max(this.steps.length, snapshot.scrollOffsets.length, this.scrollOffsets.length);
|
|
203
|
+
this.ensureNavigationStateLength(navigationLength);
|
|
204
|
+
for (let index = 0; index < navigationLength; index += 1) {
|
|
163
205
|
this.scrollOffsets[index] = snapshot.scrollOffsets[index] ?? 0;
|
|
164
206
|
this.selectedFieldIndices[index] = snapshot.selectedFieldIndices[index] ?? 0;
|
|
165
207
|
}
|
|
@@ -186,6 +228,7 @@ export class OnboardingWizardController {
|
|
|
186
228
|
public beginRuntimeHydration(): void {
|
|
187
229
|
this.hydrationPending = true;
|
|
188
230
|
this.hydrationError = null;
|
|
231
|
+
this.applyFeedback = null;
|
|
189
232
|
this.stepIndex = 0;
|
|
190
233
|
this.pendingModelPickerTarget = null;
|
|
191
234
|
this.pendingAction = null;
|
|
@@ -195,6 +238,7 @@ export class OnboardingWizardController {
|
|
|
195
238
|
public finishRuntimeHydration(): void {
|
|
196
239
|
this.hydrationPending = false;
|
|
197
240
|
this.hydrationError = null;
|
|
241
|
+
this.applyFeedback = null;
|
|
198
242
|
this.stepIndex = clamp(this.stepIndex, 0, Math.max(0, this.steps.length - 1));
|
|
199
243
|
this.reconcileStepCursor(this.stepIndex);
|
|
200
244
|
}
|
|
@@ -202,6 +246,12 @@ export class OnboardingWizardController {
|
|
|
202
246
|
public failRuntimeHydration(message: string): void {
|
|
203
247
|
this.hydrationPending = false;
|
|
204
248
|
this.hydrationError = message;
|
|
249
|
+
this.applyFeedback = {
|
|
250
|
+
severity: 'error',
|
|
251
|
+
title: 'Current settings could not load',
|
|
252
|
+
summary: message,
|
|
253
|
+
messages: [message],
|
|
254
|
+
};
|
|
205
255
|
this.stepIndex = 0;
|
|
206
256
|
this.pendingModelPickerTarget = null;
|
|
207
257
|
this.pendingAction = null;
|
|
@@ -307,6 +357,14 @@ export class OnboardingWizardController {
|
|
|
307
357
|
this.pendingAction = null;
|
|
308
358
|
}
|
|
309
359
|
|
|
360
|
+
public setApplyFeedback(feedback: OnboardingWizardApplyFeedback): void {
|
|
361
|
+
this.applyFeedback = feedback;
|
|
362
|
+
}
|
|
363
|
+
|
|
364
|
+
public clearApplyFeedback(): void {
|
|
365
|
+
this.applyFeedback = null;
|
|
366
|
+
}
|
|
367
|
+
|
|
310
368
|
public consumePendingAction(): OnboardingWizardAction | null {
|
|
311
369
|
const action = this.pendingAction;
|
|
312
370
|
this.pendingAction = null;
|
|
@@ -323,6 +381,7 @@ export class OnboardingWizardController {
|
|
|
323
381
|
this.toggleCapability(field.capabilityId);
|
|
324
382
|
this.pendingModelPickerTarget = null;
|
|
325
383
|
this.pendingAction = null;
|
|
384
|
+
this.applyFeedback = null;
|
|
326
385
|
this.recalculateDirtyState();
|
|
327
386
|
return;
|
|
328
387
|
}
|
|
@@ -332,6 +391,7 @@ export class OnboardingWizardController {
|
|
|
332
391
|
this.toggleState.set(field.id, !current);
|
|
333
392
|
this.pendingModelPickerTarget = null;
|
|
334
393
|
this.pendingAction = null;
|
|
394
|
+
this.applyFeedback = null;
|
|
335
395
|
this.recalculateDirtyState();
|
|
336
396
|
return;
|
|
337
397
|
}
|
|
@@ -345,6 +405,7 @@ export class OnboardingWizardController {
|
|
|
345
405
|
this.radioState.set(field.id, next.id);
|
|
346
406
|
this.pendingModelPickerTarget = null;
|
|
347
407
|
this.pendingAction = null;
|
|
408
|
+
this.applyFeedback = null;
|
|
348
409
|
this.recalculateDirtyState();
|
|
349
410
|
return;
|
|
350
411
|
}
|
|
@@ -360,6 +421,7 @@ export class OnboardingWizardController {
|
|
|
360
421
|
this.selectAllServerCapabilities();
|
|
361
422
|
this.pendingAction = null;
|
|
362
423
|
this.pendingModelPickerTarget = null;
|
|
424
|
+
this.applyFeedback = null;
|
|
363
425
|
this.recalculateDirtyState();
|
|
364
426
|
return;
|
|
365
427
|
}
|
|
@@ -368,6 +430,25 @@ export class OnboardingWizardController {
|
|
|
368
430
|
this.selectLocalTuiOnly();
|
|
369
431
|
this.pendingAction = null;
|
|
370
432
|
this.pendingModelPickerTarget = null;
|
|
433
|
+
this.applyFeedback = null;
|
|
434
|
+
this.recalculateDirtyState();
|
|
435
|
+
return;
|
|
436
|
+
}
|
|
437
|
+
|
|
438
|
+
if (field.action === 'select-all-external-surfaces') {
|
|
439
|
+
this.selectAllExternalSurfaces();
|
|
440
|
+
this.pendingAction = null;
|
|
441
|
+
this.pendingModelPickerTarget = null;
|
|
442
|
+
this.applyFeedback = null;
|
|
443
|
+
this.recalculateDirtyState();
|
|
444
|
+
return;
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
if (field.action === 'clear-external-surfaces') {
|
|
448
|
+
this.clearExternalSurfaces();
|
|
449
|
+
this.pendingAction = null;
|
|
450
|
+
this.pendingModelPickerTarget = null;
|
|
451
|
+
this.applyFeedback = null;
|
|
371
452
|
this.recalculateDirtyState();
|
|
372
453
|
return;
|
|
373
454
|
}
|
|
@@ -380,6 +461,7 @@ export class OnboardingWizardController {
|
|
|
380
461
|
this.pendingModelPickerTarget = field.target;
|
|
381
462
|
this.pendingAction = null;
|
|
382
463
|
this.touchedActionFields.add(field.id);
|
|
464
|
+
this.applyFeedback = null;
|
|
383
465
|
}
|
|
384
466
|
|
|
385
467
|
public beginEdit(fieldId: string): void {
|
|
@@ -391,12 +473,21 @@ export class OnboardingWizardController {
|
|
|
391
473
|
this.editBuffer = this.textState.get(field.id) ?? field.defaultValue;
|
|
392
474
|
}
|
|
393
475
|
|
|
476
|
+
public beginSelectedTextInput(initialText: string): boolean {
|
|
477
|
+
const field = this.getSelectedField();
|
|
478
|
+
if (!field || (field.kind !== 'text' && field.kind !== 'masked')) return false;
|
|
479
|
+
this.beginEdit(field.id);
|
|
480
|
+
this.editBuffer = initialText;
|
|
481
|
+
return true;
|
|
482
|
+
}
|
|
483
|
+
|
|
394
484
|
public commitEdit(): void {
|
|
395
485
|
const fieldId = this.editingFieldId;
|
|
396
486
|
if (fieldId === null) return;
|
|
397
487
|
const field = this.getFieldById(fieldId);
|
|
398
488
|
if (field && (field.kind === 'text' || field.kind === 'masked')) {
|
|
399
489
|
this.textState.set(fieldId, this.editBuffer);
|
|
490
|
+
this.applyFeedback = null;
|
|
400
491
|
this.recalculateDirtyState();
|
|
401
492
|
}
|
|
402
493
|
this.editingFieldId = null;
|
|
@@ -418,6 +509,21 @@ export class OnboardingWizardController {
|
|
|
418
509
|
this.editBuffer = this.editBuffer.slice(0, -1);
|
|
419
510
|
}
|
|
420
511
|
|
|
512
|
+
public clearEditingValue(): void {
|
|
513
|
+
if (this.editingFieldId === null) return;
|
|
514
|
+
this.editBuffer = '';
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
public clearSelectedTextField(): boolean {
|
|
518
|
+
const field = this.getSelectedField();
|
|
519
|
+
if (!field || (field.kind !== 'text' && field.kind !== 'masked')) return false;
|
|
520
|
+
this.textState.set(field.id, '');
|
|
521
|
+
if (this.editingFieldId === field.id) this.editBuffer = '';
|
|
522
|
+
this.applyFeedback = null;
|
|
523
|
+
this.recalculateDirtyState();
|
|
524
|
+
return true;
|
|
525
|
+
}
|
|
526
|
+
|
|
421
527
|
public setFieldValue(fieldId: string, value: boolean | string): void {
|
|
422
528
|
const field = this.getFieldById(fieldId);
|
|
423
529
|
if (!field) return;
|
|
@@ -426,6 +532,7 @@ export class OnboardingWizardController {
|
|
|
426
532
|
if (typeof value === 'boolean') {
|
|
427
533
|
if (field.kind === 'checklist' && field.capabilityId) this.setCapabilityValue(field.capabilityId, value);
|
|
428
534
|
else this.toggleState.set(fieldId, value);
|
|
535
|
+
this.applyFeedback = null;
|
|
429
536
|
this.recalculateDirtyState();
|
|
430
537
|
}
|
|
431
538
|
return;
|
|
@@ -434,6 +541,7 @@ export class OnboardingWizardController {
|
|
|
434
541
|
if (field.kind === 'radio') {
|
|
435
542
|
if (typeof value === 'string' && field.options.some((option) => option.id === value)) {
|
|
436
543
|
this.radioState.set(fieldId, value);
|
|
544
|
+
this.applyFeedback = null;
|
|
437
545
|
this.recalculateDirtyState();
|
|
438
546
|
}
|
|
439
547
|
return;
|
|
@@ -443,6 +551,7 @@ export class OnboardingWizardController {
|
|
|
443
551
|
if (typeof value === 'string') {
|
|
444
552
|
this.textState.set(fieldId, value);
|
|
445
553
|
if (this.editingFieldId === fieldId) this.editBuffer = value;
|
|
554
|
+
this.applyFeedback = null;
|
|
446
555
|
this.recalculateDirtyState();
|
|
447
556
|
}
|
|
448
557
|
}
|
|
@@ -498,11 +607,15 @@ export class OnboardingWizardController {
|
|
|
498
607
|
|
|
499
608
|
if (field.kind === 'text') {
|
|
500
609
|
const value = normalizeText(this.getFieldValue(field) as string);
|
|
610
|
+
if (value.length === 0 && field.required === true) return 'Missing';
|
|
611
|
+
if (value.length === 0 && this.isRequiredExternalSetupField(field.id)) return 'Not set';
|
|
501
612
|
return value.length > 0 ? value : field.placeholder;
|
|
502
613
|
}
|
|
503
614
|
|
|
504
615
|
if (field.kind === 'masked') {
|
|
505
616
|
const value = normalizeText(this.getFieldValue(field) as string);
|
|
617
|
+
if (value.length === 0 && field.required === true) return 'Missing';
|
|
618
|
+
if (value.length === 0 && this.isRequiredExternalSetupField(field.id)) return 'Not set';
|
|
506
619
|
return value.length > 0 ? maskValue(value) : field.placeholder;
|
|
507
620
|
}
|
|
508
621
|
|
|
@@ -521,6 +634,7 @@ export class OnboardingWizardController {
|
|
|
521
634
|
enabled: selection.enabled ?? true,
|
|
522
635
|
});
|
|
523
636
|
this.pendingModelPickerTarget = null;
|
|
637
|
+
this.applyFeedback = null;
|
|
524
638
|
this.recalculateDirtyState();
|
|
525
639
|
}
|
|
526
640
|
|
|
@@ -538,6 +652,7 @@ export class OnboardingWizardController {
|
|
|
538
652
|
this.baselineModelSelectionState.clear();
|
|
539
653
|
for (const [key, value] of this.modelSelectionState) this.baselineModelSelectionState.set(key, cloneSelection(value));
|
|
540
654
|
this.dirtyStepIds.clear();
|
|
655
|
+
this.applyFeedback = null;
|
|
541
656
|
}
|
|
542
657
|
|
|
543
658
|
public getSharedIpDefault(enabled: { readonly controlPlane: boolean; readonly httpListener: boolean; readonly web: boolean }): boolean {
|
|
@@ -548,10 +663,11 @@ export class OnboardingWizardController {
|
|
|
548
663
|
return getSharedIpHostDefaultForController(this, enabled);
|
|
549
664
|
}
|
|
550
665
|
|
|
551
|
-
public defaultReviewUserMarker(): boolean { return defaultReviewUserMarkerForController(this); }
|
|
552
666
|
public toggleCapability(capabilityId: OnboardingStep1CapabilityId): void { toggleCapabilityForController(this, capabilityId); }
|
|
553
667
|
public selectAllServerCapabilities(): void { selectAllServerCapabilitiesForController(this); }
|
|
554
668
|
public selectLocalTuiOnly(): void { selectLocalTuiOnlyForController(this); }
|
|
669
|
+
public selectAllExternalSurfaces(): void { selectAllExternalSurfacesForController(this); }
|
|
670
|
+
public clearExternalSurfaces(): void { clearExternalSurfacesForController(this); }
|
|
555
671
|
public setCapabilityValue(capabilityId: OnboardingStep1CapabilityId, selected: boolean): void { setCapabilityValueForController(this, capabilityId, selected); }
|
|
556
672
|
public isCapabilitySelected(capabilityId: OnboardingStep1CapabilityId): boolean { return isCapabilitySelectedForController(this, capabilityId); }
|
|
557
673
|
public hasServerCapabilitiesSelected(): boolean { return hasServerCapabilitiesSelectedForController(this); }
|
|
@@ -564,6 +680,7 @@ export class OnboardingWizardController {
|
|
|
564
680
|
public shouldExposeControlPlaneNetwork(): boolean { return shouldExposeControlPlaneNetworkForController(this); }
|
|
565
681
|
public requiresAuthBootstrap(): boolean { return requiresAuthBootstrapForController(this); }
|
|
566
682
|
public hasAdminAuthUser(): boolean { return hasAdminAuthUserForController(this); }
|
|
683
|
+
public hasLocalAuthUser(): boolean { return hasLocalAuthUserForController(this); }
|
|
567
684
|
public hasBootstrapCredentialPresent(): boolean { return hasBootstrapCredentialPresentForController(this); }
|
|
568
685
|
public getDefaultAdminUsername(): string { return getDefaultAdminUsernameForController(this); }
|
|
569
686
|
public getBooleanFieldValue(fieldId: string, fallback: boolean): boolean { return getBooleanFieldValueForController(this, fieldId, fallback); }
|
|
@@ -2,7 +2,7 @@ import type { ConfigSetting } from '@pellux/goodvibes-sdk/platform/config/schema
|
|
|
2
2
|
import type { ProviderAuthFreshness, ProviderAuthRoute } from '@pellux/goodvibes-sdk/platform/runtime/provider-accounts/registry';
|
|
3
3
|
import type { FeatureFlag, FlagState } from '@pellux/goodvibes-sdk/platform/runtime/feature-flags/types';
|
|
4
4
|
|
|
5
|
-
export type SettingsCategory = 'display' | 'ui' | 'provider' | 'subscriptions' | 'behavior' | 'storage' | 'permissions' | 'mcp' | 'sandbox' | 'danger' | 'tools' | 'flags' | 'network';
|
|
5
|
+
export type SettingsCategory = 'display' | 'ui' | 'provider' | 'subscriptions' | 'behavior' | 'storage' | 'permissions' | 'mcp' | 'sandbox' | 'surfaces' | 'danger' | 'tools' | 'flags' | 'network';
|
|
6
6
|
|
|
7
7
|
export const SETTINGS_CATEGORIES: SettingsCategory[] = [
|
|
8
8
|
'display',
|
|
@@ -14,6 +14,7 @@ export const SETTINGS_CATEGORIES: SettingsCategory[] = [
|
|
|
14
14
|
'permissions',
|
|
15
15
|
'mcp',
|
|
16
16
|
'sandbox',
|
|
17
|
+
'surfaces',
|
|
17
18
|
'danger',
|
|
18
19
|
'tools',
|
|
19
20
|
'flags',
|
|
@@ -519,6 +519,8 @@ export class SettingsModal {
|
|
|
519
519
|
cat = 'tools';
|
|
520
520
|
} else if (rawCat === 'controlPlane' || rawCat === 'httpListener' || rawCat === 'web') {
|
|
521
521
|
cat = 'network';
|
|
522
|
+
} else if (rawCat === 'surfaces') {
|
|
523
|
+
cat = 'surfaces';
|
|
522
524
|
} else {
|
|
523
525
|
cat = rawCat as SettingsCategory;
|
|
524
526
|
}
|
|
@@ -746,6 +748,8 @@ export class SettingsModal {
|
|
|
746
748
|
if (isRestartKey && previousValue !== value) {
|
|
747
749
|
this.lastSaveTriggeredRestart = 'web';
|
|
748
750
|
}
|
|
751
|
+
} else if (rawCat === 'surfaces') {
|
|
752
|
+
cat = 'surfaces';
|
|
749
753
|
} else {
|
|
750
754
|
cat = rawCat as SettingsCategory;
|
|
751
755
|
}
|
package/src/main.ts
CHANGED
|
@@ -177,6 +177,7 @@ async function main() {
|
|
|
177
177
|
};
|
|
178
178
|
|
|
179
179
|
const getViewportHeight = (): number => {
|
|
180
|
+
if (input.onboardingWizard.active) return stdout.rows || 24;
|
|
180
181
|
const promptLines: number = input.getVisiblePromptLineCount(getPromptContentWidth());
|
|
181
182
|
const currentModel = providerRegistry.getCurrentModel();
|
|
182
183
|
return (stdout.rows || 24) - 2 - estimateShellFooterHeight(promptLines, currentModel.contextWindow);
|
|
@@ -258,7 +259,8 @@ async function main() {
|
|
|
258
259
|
stdout.removeListener('resize', resizeHandler);
|
|
259
260
|
process.removeListener('SIGINT', sigintHandler);
|
|
260
261
|
process.removeListener('unhandledRejection', unhandledRejectionHandler);
|
|
261
|
-
|
|
262
|
+
const exitScreen = cli.flags.noAltScreen ? CLEAR_SCREEN : CLEAR_SCREEN + ALT_SCREEN_EXIT;
|
|
263
|
+
stdout.write(PASTE_DISABLE + KEYBOARD_EXT_DISABLE + MOUSE_DISABLE + CURSOR_SHOW + exitScreen);
|
|
262
264
|
stdin.setRawMode(false);
|
|
263
265
|
process.exit(0);
|
|
264
266
|
};
|
|
@@ -550,19 +552,23 @@ async function main() {
|
|
|
550
552
|
composerPendingRisk: composerState.pendingRisk,
|
|
551
553
|
}).lines;
|
|
552
554
|
|
|
555
|
+
const onboardingOwnsScreen = input.onboardingWizard.active;
|
|
556
|
+
const shellHeaderLines = onboardingOwnsScreen ? [] : headerLines;
|
|
557
|
+
const shellFooterLines = onboardingOwnsScreen ? [] : footerLines;
|
|
558
|
+
const panelWidth = !onboardingOwnsScreen && panelManager.isVisible() && panelManager.getAllOpen().length > 0
|
|
559
|
+
? panelManager.getRightWidth(width)
|
|
560
|
+
: 0;
|
|
553
561
|
const shellLayout = createShellLayout({
|
|
554
562
|
width,
|
|
555
563
|
height,
|
|
556
|
-
headerHeight:
|
|
557
|
-
footerHeight:
|
|
558
|
-
panelWidth
|
|
559
|
-
? panelManager.getRightWidth(width)
|
|
560
|
-
: 0,
|
|
564
|
+
headerHeight: shellHeaderLines.length,
|
|
565
|
+
footerHeight: shellFooterLines.length,
|
|
566
|
+
panelWidth,
|
|
561
567
|
});
|
|
562
568
|
const vHeight = shellLayout.body.height;
|
|
563
569
|
const conversationWidth = shellLayout.conversation.width;
|
|
564
570
|
activeConversationWidth = conversationWidth;
|
|
565
|
-
const hasPanelWorkspace = panelManager.isVisible() && panelManager.getAllOpen().length > 0;
|
|
571
|
+
const hasPanelWorkspace = !onboardingOwnsScreen && panelManager.isVisible() && panelManager.getAllOpen().length > 0;
|
|
566
572
|
conversation.setSplashSuppressed(hasPanelWorkspace);
|
|
567
573
|
|
|
568
574
|
// Flush pending renders after updating the width provider and splash posture
|
|
@@ -626,27 +632,29 @@ async function main() {
|
|
|
626
632
|
});
|
|
627
633
|
|
|
628
634
|
// Panel composite data
|
|
629
|
-
const panelComposite =
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
+
const panelComposite = onboardingOwnsScreen
|
|
636
|
+
? { panelData: undefined, panelWidth: 0 }
|
|
637
|
+
: buildPanelCompositeData(
|
|
638
|
+
panelManager,
|
|
639
|
+
input,
|
|
640
|
+
shellLayout.panel?.width ?? 0,
|
|
641
|
+
shellLayout.panel?.height ?? vHeight,
|
|
642
|
+
);
|
|
635
643
|
|
|
636
644
|
compositor.composite({
|
|
637
645
|
width, height,
|
|
638
|
-
header:
|
|
646
|
+
header: shellHeaderLines,
|
|
639
647
|
viewport,
|
|
640
|
-
footer:
|
|
641
|
-
selection: {
|
|
648
|
+
footer: shellFooterLines,
|
|
649
|
+
selection: onboardingOwnsScreen ? undefined : {
|
|
642
650
|
isCellSelected: (col, row) => selection.isCellSelected(col, row),
|
|
643
651
|
scrollTop,
|
|
644
652
|
lineCount: conversation.history.getLineCount(),
|
|
645
653
|
},
|
|
646
|
-
search: input.searchManager.active ? {
|
|
654
|
+
search: !onboardingOwnsScreen && input.searchManager.active ? {
|
|
647
655
|
manager: input.searchManager,
|
|
648
656
|
scrollTop,
|
|
649
|
-
viewportStartY:
|
|
657
|
+
viewportStartY: shellHeaderLines.length,
|
|
650
658
|
} : undefined,
|
|
651
659
|
panel: panelComposite.panelData,
|
|
652
660
|
panelWidth: panelComposite.panelWidth,
|
|
@@ -674,15 +682,6 @@ async function main() {
|
|
|
674
682
|
render,
|
|
675
683
|
});
|
|
676
684
|
|
|
677
|
-
applyInitialTuiCliState({
|
|
678
|
-
cli,
|
|
679
|
-
input,
|
|
680
|
-
commandRegistry,
|
|
681
|
-
commandContext,
|
|
682
|
-
shellPaths: ctx.services.shellPaths,
|
|
683
|
-
render,
|
|
684
|
-
});
|
|
685
|
-
|
|
686
685
|
// --- Streaming speed + tool preview wiring ---
|
|
687
686
|
const refreshGit = () => gitStatusProvider.refresh().then((info) => { lastGitInfoRef.value = info; render(); }).catch(() => { /* non-fatal */ });
|
|
688
687
|
// Refresh git status after each turn completes or after tool results arrive
|
|
@@ -728,6 +727,15 @@ async function main() {
|
|
|
728
727
|
stdin.setEncoding('utf8');
|
|
729
728
|
stdout.write((cli.flags.noAltScreen ? '' : ALT_SCREEN_ENTER) + CLEAR_SCREEN + CURSOR_HIDE + MOUSE_ENABLE + KEYBOARD_EXT_ENABLE + PASTE_ENABLE);
|
|
730
729
|
|
|
730
|
+
applyInitialTuiCliState({
|
|
731
|
+
cli,
|
|
732
|
+
input,
|
|
733
|
+
commandRegistry,
|
|
734
|
+
commandContext,
|
|
735
|
+
shellPaths: ctx.services.shellPaths,
|
|
736
|
+
render,
|
|
737
|
+
});
|
|
738
|
+
|
|
731
739
|
stdin.on('data', (data: string) => {
|
|
732
740
|
const blocking = handleBlockingShellInput({
|
|
733
741
|
data,
|
|
@@ -86,11 +86,11 @@ export class Compositor {
|
|
|
86
86
|
const leftWidth = hasPanel ? Math.max(1, width - panelWidth - 1) : width;
|
|
87
87
|
const sepX = hasPanel ? leftWidth : -1;
|
|
88
88
|
|
|
89
|
-
// 1. Draw Header
|
|
89
|
+
// 1. Draw Header — always full width
|
|
90
90
|
header.forEach((line, i) => newBuffer.blitLine(i, line));
|
|
91
91
|
|
|
92
|
-
// 2. Draw Viewport
|
|
93
|
-
const viewportStartY =
|
|
92
|
+
// 2. Draw Viewport directly after the supplied header.
|
|
93
|
+
const viewportStartY = header.length;
|
|
94
94
|
const vHeight = Math.max(0, height - header.length - footer.length);
|
|
95
95
|
|
|
96
96
|
// Calculate the offset for bottom-anchored short history
|