@pellux/goodvibes-agent 0.1.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/.goodvibes/GOODVIBES.md +35 -0
- package/.goodvibes/agents/reviewer.md +48 -0
- package/.goodvibes/skills/add-provider/SKILL.md +199 -0
- package/CHANGELOG.md +25 -0
- package/README.md +74 -0
- package/bin/goodvibes-agent.ts +2 -0
- package/docs/README.md +23 -0
- package/docs/deployment-and-services.md +57 -0
- package/docs/getting-started.md +53 -0
- package/docs/release-and-publishing.md +46 -0
- package/package.json +134 -0
- package/scripts/check-bun.sh +20 -0
- package/src/audio/player.ts +156 -0
- package/src/audio/spoken-turn-controller.ts +203 -0
- package/src/audio/spoken-turn-model-routing.ts +117 -0
- package/src/audio/spoken-turn-wiring.ts +44 -0
- package/src/audio/text-chunker.ts +110 -0
- package/src/cli/bundle-command.ts +227 -0
- package/src/cli/completion.ts +90 -0
- package/src/cli/config-overrides.ts +159 -0
- package/src/cli/endpoints.ts +63 -0
- package/src/cli/entrypoint.ts +172 -0
- package/src/cli/help.ts +299 -0
- package/src/cli/index.ts +11 -0
- package/src/cli/management-commands.ts +426 -0
- package/src/cli/management.ts +744 -0
- package/src/cli/network-posture.ts +46 -0
- package/src/cli/package-verification.ts +123 -0
- package/src/cli/parser.ts +369 -0
- package/src/cli/provider-auth-routes.ts +22 -0
- package/src/cli/provider-classification.ts +107 -0
- package/src/cli/redaction.ts +105 -0
- package/src/cli/service-command.ts +26 -0
- package/src/cli/service-posture.ts +482 -0
- package/src/cli/status.ts +383 -0
- package/src/cli/surface-command.ts +247 -0
- package/src/cli/tui-startup.ts +32 -0
- package/src/cli/types.ts +69 -0
- package/src/cli-flags.ts +21 -0
- package/src/config/goodvibes-home-audit.ts +465 -0
- package/src/config/index.ts +57 -0
- package/src/config/provider-model.ts +23 -0
- package/src/config/secret-config.ts +119 -0
- package/src/config/secrets.ts +71 -0
- package/src/config/surface.ts +1 -0
- package/src/core/composer-state.ts +61 -0
- package/src/core/conversation-rendering.ts +359 -0
- package/src/core/conversation.ts +551 -0
- package/src/core/history.ts +45 -0
- package/src/core/orchestrator.ts +7 -0
- package/src/core/system-message-router.ts +171 -0
- package/src/daemon/cli.ts +55 -0
- package/src/daemon/safe-serve.ts +61 -0
- package/src/input/agent-workspace.ts +428 -0
- package/src/input/autocomplete.ts +96 -0
- package/src/input/bookmark-modal.ts +115 -0
- package/src/input/command-args-hint.ts +36 -0
- package/src/input/command-registry.ts +329 -0
- package/src/input/commands/agent-externalized-tui.ts +73 -0
- package/src/input/commands/agent-workspace-runtime.ts +17 -0
- package/src/input/commands/branch-runtime.ts +72 -0
- package/src/input/commands/cloudflare-runtime.ts +370 -0
- package/src/input/commands/config.ts +18 -0
- package/src/input/commands/control-room-runtime.ts +255 -0
- package/src/input/commands/conversation-runtime.ts +207 -0
- package/src/input/commands/discovery-runtime.ts +52 -0
- package/src/input/commands/eval.ts +204 -0
- package/src/input/commands/experience-runtime.ts +278 -0
- package/src/input/commands/guidance-runtime.ts +106 -0
- package/src/input/commands/health-runtime.ts +434 -0
- package/src/input/commands/hooks-runtime.ts +148 -0
- package/src/input/commands/incident-runtime.ts +95 -0
- package/src/input/commands/integration-runtime.ts +394 -0
- package/src/input/commands/intelligence-runtime.ts +223 -0
- package/src/input/commands/knowledge.ts +531 -0
- package/src/input/commands/local-auth-runtime.ts +105 -0
- package/src/input/commands/local-provider-runtime.ts +170 -0
- package/src/input/commands/local-runtime.ts +392 -0
- package/src/input/commands/local-setup-review.ts +199 -0
- package/src/input/commands/local-setup-transfer.ts +135 -0
- package/src/input/commands/local-setup.ts +282 -0
- package/src/input/commands/managed-runtime.ts +209 -0
- package/src/input/commands/marketplace-runtime.ts +290 -0
- package/src/input/commands/mcp-runtime.ts +432 -0
- package/src/input/commands/memory-product-runtime.ts +111 -0
- package/src/input/commands/memory.ts +151 -0
- package/src/input/commands/notify-runtime.ts +83 -0
- package/src/input/commands/onboarding-runtime.ts +14 -0
- package/src/input/commands/operator-panel-runtime.ts +146 -0
- package/src/input/commands/operator-runtime.ts +392 -0
- package/src/input/commands/planning-runtime.ts +205 -0
- package/src/input/commands/platform-access-runtime.ts +422 -0
- package/src/input/commands/platform-services-runtime.ts +246 -0
- package/src/input/commands/policy-dispatch.ts +339 -0
- package/src/input/commands/policy.ts +17 -0
- package/src/input/commands/product-runtime.ts +351 -0
- package/src/input/commands/profile-sync-runtime.ts +99 -0
- package/src/input/commands/provider-accounts-runtime.ts +113 -0
- package/src/input/commands/provider.ts +363 -0
- package/src/input/commands/qrcode-runtime.ts +20 -0
- package/src/input/commands/quit-shared.ts +162 -0
- package/src/input/commands/recall-bundle.ts +132 -0
- package/src/input/commands/recall-capture.ts +152 -0
- package/src/input/commands/recall-query.ts +229 -0
- package/src/input/commands/recall-review.ts +98 -0
- package/src/input/commands/recall-shared.ts +22 -0
- package/src/input/commands/remote-runtime-pool.ts +106 -0
- package/src/input/commands/remote-runtime-setup.ts +199 -0
- package/src/input/commands/remote-runtime.ts +431 -0
- package/src/input/commands/replay-runtime.ts +18 -0
- package/src/input/commands/runtime-services.ts +291 -0
- package/src/input/commands/schedule-runtime.ts +91 -0
- package/src/input/commands/services-runtime.ts +209 -0
- package/src/input/commands/session-content.ts +408 -0
- package/src/input/commands/session-workflow.ts +464 -0
- package/src/input/commands/session.ts +375 -0
- package/src/input/commands/settings-sync-runtime.ts +174 -0
- package/src/input/commands/share-runtime.ts +119 -0
- package/src/input/commands/shell-core.ts +307 -0
- package/src/input/commands/skills-runtime.ts +221 -0
- package/src/input/commands/subscription-runtime.ts +434 -0
- package/src/input/commands/tasks-runtime.ts +230 -0
- package/src/input/commands/teamwork-runtime.ts +339 -0
- package/src/input/commands/teleport-runtime.ts +57 -0
- package/src/input/commands/tts-runtime.ts +29 -0
- package/src/input/commands/work-plan-runtime.ts +169 -0
- package/src/input/commands.ts +131 -0
- package/src/input/feed-context-factory.ts +254 -0
- package/src/input/file-picker.ts +192 -0
- package/src/input/handler-command-route.ts +180 -0
- package/src/input/handler-content-actions.ts +497 -0
- package/src/input/handler-feed-routes.ts +648 -0
- package/src/input/handler-feed.ts +452 -0
- package/src/input/handler-interactions.ts +281 -0
- package/src/input/handler-modal-routes.ts +418 -0
- package/src/input/handler-modal-stack.ts +263 -0
- package/src/input/handler-modal-token-routes.ts +329 -0
- package/src/input/handler-onboarding-cloudflare.ts +391 -0
- package/src/input/handler-onboarding.ts +620 -0
- package/src/input/handler-picker-routes.ts +472 -0
- package/src/input/handler-prompt-buffer.ts +320 -0
- package/src/input/handler-shortcuts.ts +213 -0
- package/src/input/handler-ui-state.ts +372 -0
- package/src/input/handler.ts +729 -0
- package/src/input/input-history.ts +297 -0
- package/src/input/keybindings.ts +292 -0
- package/src/input/mcp-workspace.ts +554 -0
- package/src/input/model-picker-provider-filter.ts +28 -0
- package/src/input/model-picker-types.ts +137 -0
- package/src/input/model-picker.ts +797 -0
- package/src/input/onboarding/handler-onboarding-routes.ts +125 -0
- package/src/input/onboarding/onboarding-runtime-status.ts +87 -0
- package/src/input/onboarding/onboarding-wizard-apply.ts +277 -0
- package/src/input/onboarding/onboarding-wizard-cloudflare-step.ts +494 -0
- package/src/input/onboarding/onboarding-wizard-cloudflare.ts +204 -0
- package/src/input/onboarding/onboarding-wizard-constants.ts +158 -0
- package/src/input/onboarding/onboarding-wizard-external-surface-extra-specs.ts +130 -0
- package/src/input/onboarding/onboarding-wizard-external-surfaces.ts +762 -0
- package/src/input/onboarding/onboarding-wizard-helpers.ts +167 -0
- package/src/input/onboarding/onboarding-wizard-rules.ts +256 -0
- package/src/input/onboarding/onboarding-wizard-state.ts +365 -0
- package/src/input/onboarding/onboarding-wizard-steps.ts +798 -0
- package/src/input/onboarding/onboarding-wizard-types.ts +195 -0
- package/src/input/onboarding/onboarding-wizard.ts +711 -0
- package/src/input/panel-integration-actions.ts +78 -0
- package/src/input/profile-picker-modal.ts +222 -0
- package/src/input/search.ts +100 -0
- package/src/input/selection-modal.ts +163 -0
- package/src/input/selection.ts +135 -0
- package/src/input/session-picker-modal.ts +136 -0
- package/src/input/settings-modal-behavior.ts +37 -0
- package/src/input/settings-modal-secrets.ts +41 -0
- package/src/input/settings-modal-subscriptions.ts +95 -0
- package/src/input/settings-modal-types.ts +91 -0
- package/src/input/settings-modal.ts +793 -0
- package/src/input/submission-intent.ts +17 -0
- package/src/input/submission-router.ts +59 -0
- package/src/input/tts-settings-actions.ts +100 -0
- package/src/main.ts +792 -0
- package/src/mcp/runtime-reload.ts +81 -0
- package/src/panels/agent-inspector-panel.ts +521 -0
- package/src/panels/agent-inspector-shared.ts +94 -0
- package/src/panels/agent-logs-panel.ts +559 -0
- package/src/panels/agent-logs-shared.ts +129 -0
- package/src/panels/approval-panel.ts +150 -0
- package/src/panels/automation-control-panel.ts +212 -0
- package/src/panels/base-panel.ts +254 -0
- package/src/panels/builtin/agent.ts +117 -0
- package/src/panels/builtin/development.ts +31 -0
- package/src/panels/builtin/knowledge.ts +26 -0
- package/src/panels/builtin/operations.ts +349 -0
- package/src/panels/builtin/session.ts +129 -0
- package/src/panels/builtin/shared.ts +274 -0
- package/src/panels/builtin-panels.ts +23 -0
- package/src/panels/cockpit-panel.ts +183 -0
- package/src/panels/communication-panel.ts +153 -0
- package/src/panels/confirm-state.ts +61 -0
- package/src/panels/context-visualizer-panel.ts +204 -0
- package/src/panels/control-plane-panel.ts +211 -0
- package/src/panels/cost-tracker-panel.ts +444 -0
- package/src/panels/debug-panel.ts +432 -0
- package/src/panels/diff-panel.ts +520 -0
- package/src/panels/docs-panel.ts +283 -0
- package/src/panels/eval-panel.ts +399 -0
- package/src/panels/file-explorer-panel.ts +584 -0
- package/src/panels/file-preview-panel.ts +434 -0
- package/src/panels/forensics-panel.ts +364 -0
- package/src/panels/git-panel.ts +638 -0
- package/src/panels/hooks-panel.ts +239 -0
- package/src/panels/incident-review-panel.ts +197 -0
- package/src/panels/index.ts +46 -0
- package/src/panels/intelligence-panel.ts +176 -0
- package/src/panels/knowledge-panel.ts +345 -0
- package/src/panels/local-auth-panel.ts +130 -0
- package/src/panels/marketplace-panel.ts +212 -0
- package/src/panels/memory-panel.ts +225 -0
- package/src/panels/ops-control-panel.ts +150 -0
- package/src/panels/ops-strategy-panel.ts +235 -0
- package/src/panels/orchestration-panel.ts +273 -0
- package/src/panels/panel-list-panel.ts +509 -0
- package/src/panels/panel-manager.ts +570 -0
- package/src/panels/panel-picker.ts +106 -0
- package/src/panels/plan-dashboard-panel.ts +274 -0
- package/src/panels/plugins-panel.ts +178 -0
- package/src/panels/policy-panel.ts +308 -0
- package/src/panels/polish.ts +717 -0
- package/src/panels/project-planning-panel.ts +711 -0
- package/src/panels/provider-account-snapshot.ts +259 -0
- package/src/panels/provider-accounts-panel.ts +218 -0
- package/src/panels/provider-health-domains.ts +215 -0
- package/src/panels/provider-health-panel.ts +727 -0
- package/src/panels/provider-health-tracker.ts +115 -0
- package/src/panels/provider-stats-panel.ts +366 -0
- package/src/panels/qr-panel.ts +182 -0
- package/src/panels/remote-panel.ts +449 -0
- package/src/panels/routes-panel.ts +178 -0
- package/src/panels/sandbox-panel.ts +283 -0
- package/src/panels/schedule-panel.ts +329 -0
- package/src/panels/scrollable-list-panel.ts +491 -0
- package/src/panels/search-focus.ts +32 -0
- package/src/panels/security-panel.ts +295 -0
- package/src/panels/services-panel.ts +231 -0
- package/src/panels/session-browser-panel.ts +400 -0
- package/src/panels/session-maintenance.ts +125 -0
- package/src/panels/settings-sync-panel.ts +120 -0
- package/src/panels/skills-panel.ts +431 -0
- package/src/panels/subscription-panel.ts +263 -0
- package/src/panels/symbol-outline-panel.ts +486 -0
- package/src/panels/system-messages-panel.ts +230 -0
- package/src/panels/tasks-panel.ts +399 -0
- package/src/panels/thinking-panel.ts +304 -0
- package/src/panels/token-budget-panel.ts +475 -0
- package/src/panels/tool-inspector-panel.ts +429 -0
- package/src/panels/types.ts +54 -0
- package/src/panels/watchers-panel.ts +193 -0
- package/src/panels/work-plan-panel.ts +175 -0
- package/src/panels/worktree-panel.ts +182 -0
- package/src/panels/wrfc-panel.ts +609 -0
- package/src/permissions/prompt.ts +165 -0
- package/src/planning/project-planning-coordinator.ts +543 -0
- package/src/plugins/loader.ts +15 -0
- package/src/renderer/agent-detail-modal.ts +331 -0
- package/src/renderer/agent-workspace.ts +238 -0
- package/src/renderer/ansi-sanitize.ts +76 -0
- package/src/renderer/autocomplete-overlay.ts +154 -0
- package/src/renderer/block-actions.ts +76 -0
- package/src/renderer/bookmark-modal.ts +101 -0
- package/src/renderer/bottom-bar.ts +58 -0
- package/src/renderer/buffer.ts +113 -0
- package/src/renderer/code-block.ts +373 -0
- package/src/renderer/compositor.ts +283 -0
- package/src/renderer/context-inspector.ts +219 -0
- package/src/renderer/conversation-layout.ts +67 -0
- package/src/renderer/conversation-overlays.ts +140 -0
- package/src/renderer/conversation-surface.ts +260 -0
- package/src/renderer/diff-view.ts +132 -0
- package/src/renderer/diff.ts +130 -0
- package/src/renderer/file-picker-overlay.ts +101 -0
- package/src/renderer/file-tree.ts +153 -0
- package/src/renderer/fullscreen-primitives.ts +130 -0
- package/src/renderer/fullscreen-workspace.ts +199 -0
- package/src/renderer/git-status.ts +89 -0
- package/src/renderer/help-overlay.ts +267 -0
- package/src/renderer/history-search-overlay.ts +73 -0
- package/src/renderer/layout-engine.ts +97 -0
- package/src/renderer/layout.ts +32 -0
- package/src/renderer/live-tail-modal.ts +156 -0
- package/src/renderer/markdown.ts +635 -0
- package/src/renderer/mcp-workspace.ts +237 -0
- package/src/renderer/modal-factory.ts +467 -0
- package/src/renderer/modal-utils.ts +24 -0
- package/src/renderer/model-picker-overlay.ts +473 -0
- package/src/renderer/model-workspace.ts +488 -0
- package/src/renderer/onboarding/onboarding-wizard.ts +615 -0
- package/src/renderer/overlay-box.ts +146 -0
- package/src/renderer/overlay-viewport.ts +104 -0
- package/src/renderer/panel-composite.ts +158 -0
- package/src/renderer/panel-picker-overlay.ts +202 -0
- package/src/renderer/panel-tab-bar.ts +69 -0
- package/src/renderer/panel-workspace-bar.ts +42 -0
- package/src/renderer/process-indicator.ts +96 -0
- package/src/renderer/process-modal.ts +656 -0
- package/src/renderer/process-summary.ts +67 -0
- package/src/renderer/profile-picker-modal.ts +129 -0
- package/src/renderer/progress.ts +98 -0
- package/src/renderer/qr-renderer.ts +120 -0
- package/src/renderer/search-overlay.ts +54 -0
- package/src/renderer/selection-modal-overlay.ts +214 -0
- package/src/renderer/semantic-diff.ts +369 -0
- package/src/renderer/session-picker-modal.ts +127 -0
- package/src/renderer/settings-modal-helpers.ts +193 -0
- package/src/renderer/settings-modal.ts +537 -0
- package/src/renderer/shell-surface.ts +88 -0
- package/src/renderer/status-glyphs.ts +21 -0
- package/src/renderer/status-token.ts +67 -0
- package/src/renderer/surface-layout.ts +101 -0
- package/src/renderer/syntax-highlighter.ts +542 -0
- package/src/renderer/system-message.ts +83 -0
- package/src/renderer/tab-strip.ts +108 -0
- package/src/renderer/text-layout.ts +31 -0
- package/src/renderer/thinking.ts +17 -0
- package/src/renderer/tool-call.ts +234 -0
- package/src/renderer/ui-factory.ts +524 -0
- package/src/renderer/ui-primitives.ts +96 -0
- package/src/runtime/bootstrap-command-context.ts +278 -0
- package/src/runtime/bootstrap-command-parts.ts +386 -0
- package/src/runtime/bootstrap-core.ts +540 -0
- package/src/runtime/bootstrap-hook-bridge.ts +112 -0
- package/src/runtime/bootstrap-shell.ts +283 -0
- package/src/runtime/bootstrap.ts +575 -0
- package/src/runtime/cloudflare-control-plane.ts +349 -0
- package/src/runtime/context.ts +142 -0
- package/src/runtime/diagnostics/panels/index.ts +24 -0
- package/src/runtime/diagnostics/panels/ops.ts +156 -0
- package/src/runtime/diagnostics/panels/panel-resources.ts +118 -0
- package/src/runtime/diagnostics/panels/policy.ts +177 -0
- package/src/runtime/index.ts +662 -0
- package/src/runtime/onboarding/apply.ts +642 -0
- package/src/runtime/onboarding/derivation.ts +534 -0
- package/src/runtime/onboarding/index.ts +7 -0
- package/src/runtime/onboarding/markers.ts +148 -0
- package/src/runtime/onboarding/snapshot.ts +406 -0
- package/src/runtime/onboarding/state.ts +141 -0
- package/src/runtime/onboarding/types.ts +404 -0
- package/src/runtime/onboarding/verify.ts +171 -0
- package/src/runtime/operator-token-cleanup.ts +27 -0
- package/src/runtime/perf/panel-contracts.ts +32 -0
- package/src/runtime/perf/panel-health-monitor.ts +18 -0
- package/src/runtime/sandbox-public-gaps.ts +358 -0
- package/src/runtime/services.ts +670 -0
- package/src/runtime/store/domains/domain-read-matrix.ts +15 -0
- package/src/runtime/store/domains/index.ts +222 -0
- package/src/runtime/store/domains/panels.ts +117 -0
- package/src/runtime/store/domains/ui-perf.ts +103 -0
- package/src/runtime/store/index.ts +305 -0
- package/src/runtime/store/selectors/index.ts +359 -0
- package/src/runtime/store/state.ts +145 -0
- package/src/runtime/surface-feature-flags.ts +65 -0
- package/src/runtime/terminal-output-guard.ts +228 -0
- package/src/runtime/ui/index.ts +39 -0
- package/src/runtime/ui/model-picker/data-provider.ts +182 -0
- package/src/runtime/ui/model-picker/health-enrichment.ts +228 -0
- package/src/runtime/ui/model-picker/index.ts +59 -0
- package/src/runtime/ui/model-picker/types.ts +149 -0
- package/src/runtime/ui/provider-health/data-provider.ts +244 -0
- package/src/runtime/ui/provider-health/fallback-visualizer.ts +71 -0
- package/src/runtime/ui/provider-health/index.ts +46 -0
- package/src/runtime/ui/provider-health/types.ts +146 -0
- package/src/runtime/ui-events.ts +1 -0
- package/src/runtime/ui-read-model-helpers.ts +1 -0
- package/src/runtime/ui-read-models-observability-maintenance.ts +1 -0
- package/src/runtime/ui-read-models-observability-options.ts +1 -0
- package/src/runtime/ui-read-models-observability-remote.ts +1 -0
- package/src/runtime/ui-read-models-observability-security.ts +1 -0
- package/src/runtime/ui-read-models-observability-system.ts +1 -0
- package/src/runtime/ui-read-models-observability.ts +1 -0
- package/src/runtime/ui-read-models.ts +61 -0
- package/src/runtime/ui-service-queries.ts +1 -0
- package/src/runtime/ui-services.ts +190 -0
- package/src/scripts/process-messages.ts +42 -0
- package/src/shell/blocking-input.ts +98 -0
- package/src/shell/service-settings-sync.ts +273 -0
- package/src/shell/ui-openers.ts +352 -0
- package/src/tools/index.ts +1 -0
- package/src/tools/wrfc-agent-guard.ts +49 -0
- package/src/types/grid.ts +48 -0
- package/src/types/sql-js.d.ts +15 -0
- package/src/utils/clipboard.ts +22 -0
- package/src/utils/splash-lines.ts +46 -0
- package/src/utils/terminal-width.ts +185 -0
- package/src/verification/live-verifier.ts +430 -0
- package/src/verification/verification-ledger.ts +242 -0
- package/src/version.ts +17 -0
- package/src/widget/index.ts +2 -0
- package/src/widget/types.ts +9 -0
- package/src/widget/widget.ts +8 -0
- package/src/work-plans/work-plan-store.ts +374 -0
- package/tsconfig.json +18 -0
|
@@ -0,0 +1,798 @@
|
|
|
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 { shouldShowCloudflareStep } from './onboarding-wizard-cloudflare.ts';
|
|
3
|
+
import { buildCloudflareStep } from './onboarding-wizard-cloudflare-step.ts';
|
|
4
|
+
import {
|
|
5
|
+
EXTERNAL_SURFACE_SPECS,
|
|
6
|
+
getExternalSurfaceAutoStartDefaultValue,
|
|
7
|
+
getExternalSurfaceAutoStartFieldId,
|
|
8
|
+
isExternalSurfaceSelectedByDefault,
|
|
9
|
+
type ExternalSurfaceSpec,
|
|
10
|
+
} from './onboarding-wizard-external-surfaces.ts';
|
|
11
|
+
import { countSelected, modelSelectionLabel, normalizeText } from './onboarding-wizard-helpers.ts';
|
|
12
|
+
import type { OnboardingWizardController } from './onboarding-wizard.ts';
|
|
13
|
+
import type { OnboardingWizardAcknowledgementFieldDefinition, OnboardingWizardActionFieldDefinition, OnboardingWizardChecklistFieldDefinition, OnboardingWizardExternalSurfaceStepId, OnboardingWizardFieldDefinition, OnboardingWizardModelPickerFieldDefinition, OnboardingWizardRadioFieldDefinition, OnboardingWizardRadioOption, OnboardingWizardStepDefinition } from './onboarding-wizard-types.ts';
|
|
14
|
+
|
|
15
|
+
export function buildOnboardingWizardSteps(controller: OnboardingWizardController): readonly OnboardingWizardStepDefinition[] {
|
|
16
|
+
if (controller.hydrationPending || controller.hydrationError !== null) return [buildLoadingStep(controller)];
|
|
17
|
+
|
|
18
|
+
const capabilities = controller.getCapabilitySelectionState();
|
|
19
|
+
const hasServers = capabilities.some((item) => item.id !== 'local-tui-only' && item.selected);
|
|
20
|
+
const wantsExternalServices = capabilities.some((item) => item.id === 'external-integrations' && item.selected);
|
|
21
|
+
const steps: OnboardingWizardStepDefinition[] = [
|
|
22
|
+
buildCapabilitiesStep(controller),
|
|
23
|
+
];
|
|
24
|
+
if (hasServers) {
|
|
25
|
+
steps.push(buildNetworkStep(controller));
|
|
26
|
+
}
|
|
27
|
+
if (hasServers || controller.hasExistingAccessState()) {
|
|
28
|
+
steps.push(buildAccessStep(controller));
|
|
29
|
+
}
|
|
30
|
+
if (wantsExternalServices) {
|
|
31
|
+
steps.push(buildExternalServicesStep(controller));
|
|
32
|
+
for (const surface of getSelectedExternalSurfaceSpecs(controller)) {
|
|
33
|
+
steps.push(buildExternalSurfaceStep(controller, surface));
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
if (shouldShowCloudflareStep(controller)) {
|
|
37
|
+
steps.push(buildCloudflareStep(controller));
|
|
38
|
+
}
|
|
39
|
+
steps.push(buildProviderAccessStep(controller));
|
|
40
|
+
steps.push(buildDefaultModelStep(controller));
|
|
41
|
+
steps.push(buildExperienceStep(controller));
|
|
42
|
+
steps.push(buildReviewStep(controller));
|
|
43
|
+
return steps.map(addApplyAndContinueAction);
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
function buildApplyAndContinueAction(step: OnboardingWizardStepDefinition): OnboardingWizardActionFieldDefinition {
|
|
47
|
+
return {
|
|
48
|
+
kind: 'action',
|
|
49
|
+
id: `${step.id}.apply-and-continue`,
|
|
50
|
+
action: 'apply-and-continue',
|
|
51
|
+
label: 'Apply & Continue To Next Section',
|
|
52
|
+
hint: 'Save the current wizard selections in this onboarding session and move to the next section. Settings are persisted on the final Review apply.',
|
|
53
|
+
defaultValue: 'Apply & next',
|
|
54
|
+
spacerBeforeRows: 2,
|
|
55
|
+
};
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
function addApplyAndContinueAction(step: OnboardingWizardStepDefinition): OnboardingWizardStepDefinition {
|
|
59
|
+
if (step.id === 'loading' || step.id === 'review') return step;
|
|
60
|
+
return {
|
|
61
|
+
...step,
|
|
62
|
+
fields: [
|
|
63
|
+
...step.fields,
|
|
64
|
+
buildApplyAndContinueAction(step),
|
|
65
|
+
],
|
|
66
|
+
};
|
|
67
|
+
}
|
|
68
|
+
|
|
69
|
+
export function buildLoadingStep(controller: OnboardingWizardController): OnboardingWizardStepDefinition {
|
|
70
|
+
const failed = controller.hydrationError !== null;
|
|
71
|
+
return {
|
|
72
|
+
id: 'loading',
|
|
73
|
+
title: failed ? 'Current settings unavailable' : 'Loading current settings',
|
|
74
|
+
shortLabel: 'Loading',
|
|
75
|
+
description: failed
|
|
76
|
+
? 'The wizard is locked because current runtime settings could not be collected. Close and reopen onboarding after fixing the reported issue.'
|
|
77
|
+
: 'Collecting the current daemon, listener, provider, subscription, auth, and surface settings before the wizard becomes editable.',
|
|
78
|
+
summaryTitle: failed ? 'Preload failed' : 'Preload required',
|
|
79
|
+
summaryLines: [
|
|
80
|
+
failed
|
|
81
|
+
? 'Editable fields remain locked to avoid applying defaults over existing configuration.'
|
|
82
|
+
: 'Editable fields are locked until runtime settings are loaded.',
|
|
83
|
+
failed
|
|
84
|
+
? controller.hydrationError ?? 'Unknown snapshot failure.'
|
|
85
|
+
: 'This prevents the wizard from applying defaults over existing configuration.',
|
|
86
|
+
],
|
|
87
|
+
fields: [
|
|
88
|
+
{
|
|
89
|
+
kind: 'status',
|
|
90
|
+
id: 'loading.runtime-snapshot',
|
|
91
|
+
label: failed ? 'Runtime settings snapshot failed' : 'Runtime settings snapshot',
|
|
92
|
+
hint: failed
|
|
93
|
+
? controller.hydrationError ?? 'The runtime snapshot did not complete.'
|
|
94
|
+
: 'Waiting for the current GoodVibes configuration and account state.',
|
|
95
|
+
defaultValue: failed ? 'Locked' : 'Loading',
|
|
96
|
+
},
|
|
97
|
+
],
|
|
98
|
+
};
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
export function buildCapabilitiesStep(controller: OnboardingWizardController): OnboardingWizardStepDefinition {
|
|
102
|
+
const capabilities = controller.getCapabilitySelectionState();
|
|
103
|
+
const selectedCount = countSelected(capabilities);
|
|
104
|
+
const fields: OnboardingWizardFieldDefinition[] = [
|
|
105
|
+
...capabilities.map((capability) => ({
|
|
106
|
+
kind: 'checklist' as const,
|
|
107
|
+
id: `capabilities.${capability.id}`,
|
|
108
|
+
capabilityId: capability.id,
|
|
109
|
+
label: capability.label,
|
|
110
|
+
hint: capability.detail,
|
|
111
|
+
defaultValue: capability.selected,
|
|
112
|
+
})),
|
|
113
|
+
{
|
|
114
|
+
kind: 'action',
|
|
115
|
+
id: 'capabilities.select-all',
|
|
116
|
+
action: 'select-all-capabilities',
|
|
117
|
+
label: 'Review external-daemon capabilities',
|
|
118
|
+
hint: 'Review browser, LAN, webhooks/events, and external app surfaces without letting Agent own daemon lifecycle.',
|
|
119
|
+
defaultValue: 'Action',
|
|
120
|
+
},
|
|
121
|
+
{
|
|
122
|
+
kind: 'action',
|
|
123
|
+
id: 'capabilities.clear',
|
|
124
|
+
action: 'clear-capabilities',
|
|
125
|
+
label: 'Keep Agent local-only',
|
|
126
|
+
hint: 'Clear external-daemon capabilities and keep Agent work in this terminal conversation.',
|
|
127
|
+
defaultValue: 'Action',
|
|
128
|
+
},
|
|
129
|
+
];
|
|
130
|
+
|
|
131
|
+
return {
|
|
132
|
+
id: 'capabilities',
|
|
133
|
+
title: 'Choose GoodVibes capabilities',
|
|
134
|
+
shortLabel: 'Capabilities',
|
|
135
|
+
description: 'Choose what Agent should prepare locally. Daemon-backed capabilities are reviewed as external dependencies; Agent does not enable service mode or autostart.',
|
|
136
|
+
summaryTitle: 'Selected capabilities',
|
|
137
|
+
summaryLines: [
|
|
138
|
+
`${selectedCount}/${capabilities.length} option(s) selected`,
|
|
139
|
+
`Mode: ${controller.mode === 'edit' ? 'edit existing shell state' : controller.mode === 'reopen' ? 'reopen review flow' : 'new setup'}`,
|
|
140
|
+
controller.runtimeSnapshot?.collectionIssues.length
|
|
141
|
+
? `${controller.runtimeSnapshot.collectionIssues.length} runtime collection issue(s)`
|
|
142
|
+
: 'Runtime snapshot collected cleanly',
|
|
143
|
+
],
|
|
144
|
+
fields,
|
|
145
|
+
};
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
export function buildProvidersStep(controller: OnboardingWizardController): OnboardingWizardStepDefinition {
|
|
149
|
+
const providerAck = controller.runtimeDerived.reopenEditAcknowledgements.providers;
|
|
150
|
+
const activeSubscriptions = controller.runtimeSnapshot?.subscriptions.active ?? [];
|
|
151
|
+
const pendingSubscriptions = controller.runtimeSnapshot?.subscriptions.pending ?? [];
|
|
152
|
+
const openAiActive = activeSubscriptions.some((subscription) => subscription.provider === 'openai');
|
|
153
|
+
const openAiPending = pendingSubscriptions.some((subscription) => subscription.provider === 'openai');
|
|
154
|
+
const providerSecretCount = controller.runtimeSnapshot?.secrets.records.filter((record) => record.key.endsWith('_API_KEY') || record.key.endsWith('_TOKEN')).length ?? 0;
|
|
155
|
+
const openAiApiKeyConfigured = controller.runtimeSnapshot?.secrets.records.some((record) => record.key === 'OPENAI_API_KEY') ?? false;
|
|
156
|
+
const providerReviewField: OnboardingWizardAcknowledgementFieldDefinition = {
|
|
157
|
+
kind: 'acknowledgement',
|
|
158
|
+
id: 'providers.reviewed',
|
|
159
|
+
label: 'Confirm provider access review',
|
|
160
|
+
hint: providerAck.detail,
|
|
161
|
+
defaultValue: providerAck.accepted,
|
|
162
|
+
required: controller.mode !== 'new' && providerAck.required,
|
|
163
|
+
reason: providerAck.reason,
|
|
164
|
+
target: 'providers',
|
|
165
|
+
};
|
|
166
|
+
|
|
167
|
+
const fields: OnboardingWizardFieldDefinition[] = [
|
|
168
|
+
{
|
|
169
|
+
kind: 'status',
|
|
170
|
+
id: 'providers.openai-subscription',
|
|
171
|
+
label: 'OpenAI subscription status',
|
|
172
|
+
hint: openAiActive
|
|
173
|
+
? 'An OpenAI subscription session is already available.'
|
|
174
|
+
: openAiPending
|
|
175
|
+
? 'An OpenAI subscription login is pending.'
|
|
176
|
+
: 'No OpenAI subscription session was found in the current runtime state.',
|
|
177
|
+
defaultValue: openAiActive ? 'Active' : openAiPending ? 'Pending' : 'Not detected',
|
|
178
|
+
},
|
|
179
|
+
{
|
|
180
|
+
kind: 'status',
|
|
181
|
+
id: 'providers.api-key-inventory',
|
|
182
|
+
label: 'Provider API key inventory',
|
|
183
|
+
hint: providerSecretCount > 0
|
|
184
|
+
? `${providerSecretCount} provider credential reference(s) were found. Values stay masked.`
|
|
185
|
+
: 'No provider API key references were detected in the current runtime state.',
|
|
186
|
+
defaultValue: providerSecretCount > 0 ? `${providerSecretCount} configured` : 'None detected',
|
|
187
|
+
},
|
|
188
|
+
{
|
|
189
|
+
kind: 'masked',
|
|
190
|
+
id: 'providers.openai-api-key',
|
|
191
|
+
label: 'OpenAI API key',
|
|
192
|
+
hint: openAiApiKeyConfigured
|
|
193
|
+
? 'An OpenAI API key is already stored. Leave blank to keep it; enter a new key to replace it through the secret manager.'
|
|
194
|
+
: 'Optional: enter an OpenAI API key now. The value is stored through the secret manager, not in config.',
|
|
195
|
+
placeholder: openAiApiKeyConfigured ? 'already configured' : 'sk-...',
|
|
196
|
+
defaultValue: '',
|
|
197
|
+
},
|
|
198
|
+
...(openAiActive ? [] : [
|
|
199
|
+
{
|
|
200
|
+
kind: 'action' as const,
|
|
201
|
+
id: 'providers.openai-subscription-start',
|
|
202
|
+
action: 'start-openai-subscription' as const,
|
|
203
|
+
label: openAiPending ? 'Restart OpenAI subscription sign-in' : 'Start OpenAI subscription sign-in',
|
|
204
|
+
hint: 'Opens the OpenAI sign-in flow from the wizard and records pending login state here.',
|
|
205
|
+
defaultValue: openAiPending ? 'Restart' : 'Start',
|
|
206
|
+
},
|
|
207
|
+
...(openAiPending ? [
|
|
208
|
+
{
|
|
209
|
+
kind: 'text' as const,
|
|
210
|
+
id: 'providers.openai-authorization-url',
|
|
211
|
+
label: 'OpenAI authorization URL',
|
|
212
|
+
hint: 'If the browser did not open, use this URL to continue sign-in without leaving the wizard.',
|
|
213
|
+
placeholder: 'authorization URL appears after start',
|
|
214
|
+
defaultValue: '',
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
kind: 'text' as const,
|
|
218
|
+
id: 'providers.openai-callback-code',
|
|
219
|
+
label: 'OpenAI callback code or URL',
|
|
220
|
+
hint: 'Paste the callback code or redirected URL after completing browser sign-in.',
|
|
221
|
+
placeholder: 'code or callback URL',
|
|
222
|
+
defaultValue: '',
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
kind: 'action' as const,
|
|
226
|
+
id: 'providers.openai-subscription-finish',
|
|
227
|
+
action: 'finish-openai-subscription' as const,
|
|
228
|
+
label: 'Finish OpenAI subscription sign-in',
|
|
229
|
+
hint: 'Completes the pending OpenAI subscription login using the code above.',
|
|
230
|
+
defaultValue: 'Finish',
|
|
231
|
+
},
|
|
232
|
+
] : []),
|
|
233
|
+
]),
|
|
234
|
+
providerReviewField,
|
|
235
|
+
];
|
|
236
|
+
|
|
237
|
+
return {
|
|
238
|
+
id: 'provider-access',
|
|
239
|
+
title: 'AI provider access',
|
|
240
|
+
shortLabel: 'Providers',
|
|
241
|
+
description: 'Review subscription posture and optionally add an OpenAI API key directly through the wizard.',
|
|
242
|
+
summaryTitle: 'Provider access summary',
|
|
243
|
+
summaryLines: [
|
|
244
|
+
`OpenAI subscription: ${openAiActive ? 'active' : openAiPending ? 'pending' : 'not detected'}`,
|
|
245
|
+
`OpenAI API key: ${openAiApiKeyConfigured ? 'configured' : 'not detected'}`,
|
|
246
|
+
`Provider credential references: ${providerSecretCount}`,
|
|
247
|
+
`Review: ${controller.getFieldValueLabel(providerReviewField)}`,
|
|
248
|
+
],
|
|
249
|
+
fields,
|
|
250
|
+
};
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
export function buildProviderAccessStep(controller: OnboardingWizardController): OnboardingWizardStepDefinition {
|
|
254
|
+
return buildProvidersStep(controller);
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
export function buildDefaultModelStep(controller: OnboardingWizardController): OnboardingWizardStepDefinition {
|
|
258
|
+
const routing = controller.runtimeSnapshot?.providerRouting;
|
|
259
|
+
const primarySelectionField: OnboardingWizardModelPickerFieldDefinition = {
|
|
260
|
+
kind: 'modelPicker',
|
|
261
|
+
id: 'default-model.primary-model',
|
|
262
|
+
label: 'Default provider + model',
|
|
263
|
+
hint: 'Open the nested model picker for the shell’s main routing target.',
|
|
264
|
+
target: 'main',
|
|
265
|
+
defaultSelection: {
|
|
266
|
+
providerId: normalizeText(routing?.primaryProviderId),
|
|
267
|
+
modelId: normalizeText(routing?.primaryModelId),
|
|
268
|
+
enabled: true,
|
|
269
|
+
},
|
|
270
|
+
};
|
|
271
|
+
const reasoningField: OnboardingWizardRadioFieldDefinition = {
|
|
272
|
+
kind: 'radio',
|
|
273
|
+
id: 'default-model.reasoning',
|
|
274
|
+
label: 'Reasoning effort',
|
|
275
|
+
hint: 'Use the shell reasoning default that matches the current provider routing.',
|
|
276
|
+
options: REASONING_OPTIONS,
|
|
277
|
+
defaultValue: normalizeText(routing?.primaryReasoningEffort) || 'medium',
|
|
278
|
+
};
|
|
279
|
+
|
|
280
|
+
return {
|
|
281
|
+
id: 'default-model',
|
|
282
|
+
title: 'Default model',
|
|
283
|
+
shortLabel: 'Model',
|
|
284
|
+
description: 'Choose the default model routing the shell should use after onboarding.',
|
|
285
|
+
summaryTitle: 'Default model summary',
|
|
286
|
+
summaryLines: [
|
|
287
|
+
`Main: ${modelSelectionLabel(controller.modelSelectionState.get('main') ?? primarySelectionField.defaultSelection)}`,
|
|
288
|
+
`Reasoning: ${controller.getFieldValueLabel(reasoningField)}`,
|
|
289
|
+
],
|
|
290
|
+
fields: [
|
|
291
|
+
primarySelectionField,
|
|
292
|
+
reasoningField,
|
|
293
|
+
],
|
|
294
|
+
};
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
export function buildExternalServicesStep(controller: OnboardingWizardController): OnboardingWizardStepDefinition {
|
|
298
|
+
const selectedCount = EXTERNAL_SURFACE_SPECS
|
|
299
|
+
.filter((surface) => controller.getBooleanFieldValue(
|
|
300
|
+
surface.enabledFieldId,
|
|
301
|
+
isExternalSurfaceSelectedByDefault(surface, controller.runtimeSnapshot),
|
|
302
|
+
))
|
|
303
|
+
.length;
|
|
304
|
+
const fields: OnboardingWizardFieldDefinition[] = [];
|
|
305
|
+
|
|
306
|
+
for (const surface of EXTERNAL_SURFACE_SPECS) {
|
|
307
|
+
fields.push({
|
|
308
|
+
kind: 'checklist',
|
|
309
|
+
id: surface.enabledFieldId,
|
|
310
|
+
label: surface.label,
|
|
311
|
+
hint: `${surface.hint} Selecting this opens a dedicated setup screen; auto-start is chosen on that screen.`,
|
|
312
|
+
defaultValue: isExternalSurfaceSelectedByDefault(surface, controller.runtimeSnapshot),
|
|
313
|
+
});
|
|
314
|
+
}
|
|
315
|
+
|
|
316
|
+
fields.push(
|
|
317
|
+
{
|
|
318
|
+
kind: 'action',
|
|
319
|
+
id: 'external-services.select-all',
|
|
320
|
+
action: 'select-all-external-surfaces',
|
|
321
|
+
label: 'Select all external surfaces',
|
|
322
|
+
hint: 'Show setup screens for every supported external surface. Auto-start stays controlled per surface.',
|
|
323
|
+
defaultValue: 'Action',
|
|
324
|
+
},
|
|
325
|
+
{
|
|
326
|
+
kind: 'action',
|
|
327
|
+
id: 'external-services.clear',
|
|
328
|
+
action: 'clear-external-surfaces',
|
|
329
|
+
label: 'Clear all external surfaces',
|
|
330
|
+
hint: 'Hide all external surface setup screens. The HTTP listener can still be enabled separately by webhook/event capabilities.',
|
|
331
|
+
defaultValue: 'Action',
|
|
332
|
+
},
|
|
333
|
+
{
|
|
334
|
+
kind: 'radio',
|
|
335
|
+
id: 'external-services.secret-policy',
|
|
336
|
+
label: 'Secret storage policy',
|
|
337
|
+
hint: 'Choose how selected surface secrets should be stored. Secret values are never shown in the wizard.',
|
|
338
|
+
options: SECRET_POLICY_OPTIONS,
|
|
339
|
+
defaultValue: controller.runtimeSnapshot?.runtimeDefaults.secretStoragePolicy ?? 'preferred_secure',
|
|
340
|
+
},
|
|
341
|
+
);
|
|
342
|
+
|
|
343
|
+
return {
|
|
344
|
+
id: 'external-services',
|
|
345
|
+
title: 'Choose external surfaces',
|
|
346
|
+
shortLabel: 'Services',
|
|
347
|
+
description: 'Select the apps and integration surfaces GoodVibes should prepare. Each selected surface gets its own setup screen and its own auto-start choice.',
|
|
348
|
+
summaryTitle: 'External surfaces',
|
|
349
|
+
summaryLines: [
|
|
350
|
+
`${selectedCount} external surface(s) selected for setup`,
|
|
351
|
+
`Secret policy: ${controller.getStringFieldValue('external-services.secret-policy', controller.runtimeSnapshot?.runtimeDefaults.secretStoragePolicy ?? 'preferred_secure')}`,
|
|
352
|
+
selectedCount > 0 ? 'Selected surfaces appear as separate setup screens.' : 'No external surfaces selected.',
|
|
353
|
+
],
|
|
354
|
+
fields,
|
|
355
|
+
};
|
|
356
|
+
}
|
|
357
|
+
|
|
358
|
+
function getSelectedExternalSurfaceSpecs(controller: OnboardingWizardController): readonly ExternalSurfaceSpec[] {
|
|
359
|
+
return EXTERNAL_SURFACE_SPECS.filter((surface) => (
|
|
360
|
+
controller.getBooleanFieldValue(
|
|
361
|
+
surface.enabledFieldId,
|
|
362
|
+
isExternalSurfaceSelectedByDefault(surface, controller.runtimeSnapshot),
|
|
363
|
+
)
|
|
364
|
+
));
|
|
365
|
+
}
|
|
366
|
+
|
|
367
|
+
const SURFACE_AUTO_START_OPTIONS: readonly OnboardingWizardRadioOption[] = [
|
|
368
|
+
{
|
|
369
|
+
id: 'yes',
|
|
370
|
+
label: 'Yes',
|
|
371
|
+
hint: 'Save the surface as enabled; the external daemon/service owner controls actual startup.',
|
|
372
|
+
},
|
|
373
|
+
{
|
|
374
|
+
id: 'no',
|
|
375
|
+
label: 'No',
|
|
376
|
+
hint: 'Save these settings but leave the surface idle until it is enabled from Settings > Surfaces.',
|
|
377
|
+
},
|
|
378
|
+
];
|
|
379
|
+
|
|
380
|
+
function buildExternalSurfaceStep(
|
|
381
|
+
controller: OnboardingWizardController,
|
|
382
|
+
surface: ExternalSurfaceSpec,
|
|
383
|
+
): OnboardingWizardStepDefinition {
|
|
384
|
+
let setupCount = 0;
|
|
385
|
+
let setupCompleteCount = 0;
|
|
386
|
+
const autoStartFieldId = getExternalSurfaceAutoStartFieldId(surface);
|
|
387
|
+
const autoStartDefault = getExternalSurfaceAutoStartDefaultValue(surface, controller.runtimeSnapshot);
|
|
388
|
+
const autoStartValue = controller.getStringFieldValue(autoStartFieldId, autoStartDefault);
|
|
389
|
+
const setupFields = surface.fields.map((setupField): OnboardingWizardFieldDefinition => {
|
|
390
|
+
const suggested = controller.isRequiredExternalSetupField(setupField.id);
|
|
391
|
+
if (suggested) {
|
|
392
|
+
setupCount += 1;
|
|
393
|
+
if (normalizeText(setupField.defaultValue(controller.runtimeSnapshot)).length > 0
|
|
394
|
+
|| normalizeText(controller.getStringFieldValue(setupField.id, '')).length > 0) {
|
|
395
|
+
setupCompleteCount += 1;
|
|
396
|
+
}
|
|
397
|
+
}
|
|
398
|
+
|
|
399
|
+
const hint = suggested
|
|
400
|
+
? `${setupField.hint} Recommended because ${surface.label} is selected, but it will not block saving.`
|
|
401
|
+
: setupField.hint;
|
|
402
|
+
|
|
403
|
+
if (setupField.kind === 'radio') {
|
|
404
|
+
return {
|
|
405
|
+
kind: 'radio',
|
|
406
|
+
id: setupField.id,
|
|
407
|
+
label: setupField.label,
|
|
408
|
+
hint,
|
|
409
|
+
options: setupField.options ?? [],
|
|
410
|
+
defaultValue: setupField.defaultValue(controller.runtimeSnapshot),
|
|
411
|
+
};
|
|
412
|
+
}
|
|
413
|
+
|
|
414
|
+
return {
|
|
415
|
+
kind: setupField.kind,
|
|
416
|
+
id: setupField.id,
|
|
417
|
+
label: setupField.label,
|
|
418
|
+
hint,
|
|
419
|
+
placeholder: setupField.placeholder,
|
|
420
|
+
defaultValue: setupField.defaultValue(controller.runtimeSnapshot),
|
|
421
|
+
};
|
|
422
|
+
});
|
|
423
|
+
const ntfyTopicSummary = surface.id === 'ntfy'
|
|
424
|
+
? [
|
|
425
|
+
`Chat topic: ${controller.getStringFieldValue('external-services.ntfy.chat-topic', 'goodvibes-chat')}`,
|
|
426
|
+
`Agent topic: ${controller.getStringFieldValue('external-services.ntfy.agent-topic', 'goodvibes-agent')}`,
|
|
427
|
+
`Daemon-only remote topic: ${controller.getStringFieldValue('external-services.ntfy.remote-topic', 'goodvibes-ntfy')}`,
|
|
428
|
+
]
|
|
429
|
+
: [];
|
|
430
|
+
const title = `${surface.label.replace(/ surface$/i, '')} setup`;
|
|
431
|
+
const setupSummary = setupCount === 0
|
|
432
|
+
? 'Suggested setup: none'
|
|
433
|
+
: `Suggested setup entered: ${setupCompleteCount}/${setupCount}`;
|
|
434
|
+
|
|
435
|
+
return {
|
|
436
|
+
id: `external-surface:${surface.id}` as OnboardingWizardExternalSurfaceStepId,
|
|
437
|
+
title,
|
|
438
|
+
shortLabel: surface.label.replace(/ surface$/i, ''),
|
|
439
|
+
description: `Configure ${surface.label}. Settings are saved either way; Agent does not start or own the background service.`,
|
|
440
|
+
summaryTitle: `${surface.label} setup`,
|
|
441
|
+
summaryLines: [
|
|
442
|
+
`External activation requested: ${autoStartValue === 'yes' ? 'yes' : 'no'}`,
|
|
443
|
+
...ntfyTopicSummary,
|
|
444
|
+
setupSummary,
|
|
445
|
+
`Secret policy: ${controller.getStringFieldValue('external-services.secret-policy', controller.runtimeSnapshot?.runtimeDefaults.secretStoragePolicy ?? 'preferred_secure')}`,
|
|
446
|
+
autoStartValue === 'yes'
|
|
447
|
+
? 'Agent will save the requested enabled state, but daemon lifecycle remains external.'
|
|
448
|
+
: 'Enable it later from Settings > Surfaces after the external daemon is ready.',
|
|
449
|
+
],
|
|
450
|
+
fields: [
|
|
451
|
+
{
|
|
452
|
+
kind: 'radio',
|
|
453
|
+
id: autoStartFieldId,
|
|
454
|
+
label: 'Request external activation',
|
|
455
|
+
hint: `Yes saves ${surface.enabledConfigKey}. No saves setup values but keeps the surface off until Settings > Surfaces enables it.`,
|
|
456
|
+
options: SURFACE_AUTO_START_OPTIONS,
|
|
457
|
+
defaultValue: autoStartDefault,
|
|
458
|
+
},
|
|
459
|
+
...setupFields,
|
|
460
|
+
],
|
|
461
|
+
};
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
export function buildAccessStep(controller: OnboardingWizardController): OnboardingWizardStepDefinition {
|
|
465
|
+
const step = buildAccountsStep(controller);
|
|
466
|
+
return {
|
|
467
|
+
...step,
|
|
468
|
+
id: 'access',
|
|
469
|
+
title: 'Access and accounts',
|
|
470
|
+
shortLabel: 'Access',
|
|
471
|
+
};
|
|
472
|
+
}
|
|
473
|
+
|
|
474
|
+
export function buildExperienceStep(controller: OnboardingWizardController): OnboardingWizardStepDefinition {
|
|
475
|
+
return {
|
|
476
|
+
id: 'experience',
|
|
477
|
+
title: 'Shell experience',
|
|
478
|
+
shortLabel: 'Experience',
|
|
479
|
+
description: 'Tune review noise, guidance, and permission posture for day-to-day use.',
|
|
480
|
+
summaryTitle: 'Experience posture',
|
|
481
|
+
summaryLines: [
|
|
482
|
+
`Human-in-the-Loop (HITL): ${controller.getStringFieldValue('experience.hitl', controller.runtimeSnapshot?.runtimeDefaults.behavior.hitlMode ?? 'balanced')}`,
|
|
483
|
+
`Guidance: ${controller.getStringFieldValue('experience.guidance', controller.runtimeSnapshot?.runtimeDefaults.behavior.guidanceMode ?? 'minimal')}`,
|
|
484
|
+
`Permissions: ${controller.getStringFieldValue('experience.permissions', controller.runtimeSnapshot?.runtimeDefaults.permissionsMode ?? 'prompt')}`,
|
|
485
|
+
],
|
|
486
|
+
fields: [
|
|
487
|
+
{
|
|
488
|
+
kind: 'radio',
|
|
489
|
+
id: 'experience.hitl',
|
|
490
|
+
label: 'Human-in-the-Loop (HITL) mode',
|
|
491
|
+
hint: 'Choose how much operational activity should be surfaced.',
|
|
492
|
+
options: HITL_MODE_OPTIONS,
|
|
493
|
+
defaultValue: controller.runtimeSnapshot?.runtimeDefaults.behavior.hitlMode ?? 'balanced',
|
|
494
|
+
},
|
|
495
|
+
{
|
|
496
|
+
kind: 'radio',
|
|
497
|
+
id: 'experience.guidance',
|
|
498
|
+
label: 'Guidance verbosity',
|
|
499
|
+
hint: 'Choose how much explanation the shell should provide.',
|
|
500
|
+
options: GUIDANCE_MODE_OPTIONS,
|
|
501
|
+
defaultValue: controller.runtimeSnapshot?.runtimeDefaults.behavior.guidanceMode ?? 'minimal',
|
|
502
|
+
},
|
|
503
|
+
{
|
|
504
|
+
kind: 'radio',
|
|
505
|
+
id: 'experience.permissions',
|
|
506
|
+
label: 'Permission posture',
|
|
507
|
+
hint: 'Choose how aggressively the shell should ask before powerful actions.',
|
|
508
|
+
options: PERMISSION_MODE_OPTIONS,
|
|
509
|
+
defaultValue: controller.runtimeSnapshot?.runtimeDefaults.permissionsMode ?? 'prompt',
|
|
510
|
+
},
|
|
511
|
+
],
|
|
512
|
+
};
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
export function buildNetworkStep(controller: OnboardingWizardController): OnboardingWizardStepDefinition {
|
|
516
|
+
const bindSettings = controller.runtimeSnapshot?.bindSettings;
|
|
517
|
+
const browserEnabled = controller.shouldEnableBrowserSurface();
|
|
518
|
+
const listenerEnabled = controller.shouldExposeHttpListenerNetworkFields();
|
|
519
|
+
const listenerWillApply = controller.shouldEnableHttpListener();
|
|
520
|
+
const controlPlaneRemote = controller.shouldExposeControlPlaneNetwork();
|
|
521
|
+
const networkEnabled = {
|
|
522
|
+
controlPlane: controlPlaneRemote,
|
|
523
|
+
httpListener: listenerEnabled,
|
|
524
|
+
web: browserEnabled,
|
|
525
|
+
};
|
|
526
|
+
const mode = controller.getStringFieldValue('network.mode', controller.runtimeDerived.step1_5NetworkMode);
|
|
527
|
+
const custom = mode === 'custom';
|
|
528
|
+
const fields: OnboardingWizardFieldDefinition[] = [
|
|
529
|
+
{
|
|
530
|
+
kind: 'radio',
|
|
531
|
+
id: 'network.mode',
|
|
532
|
+
label: 'Network mode',
|
|
533
|
+
hint: 'Choose Local Network for the default LAN setup, or Custom to set IP addresses and ports.',
|
|
534
|
+
options: NETWORK_MODE_OPTIONS,
|
|
535
|
+
defaultValue: controller.runtimeDerived.step1_5NetworkMode,
|
|
536
|
+
},
|
|
537
|
+
];
|
|
538
|
+
|
|
539
|
+
if (custom) {
|
|
540
|
+
const sharedIpField: OnboardingWizardChecklistFieldDefinition = {
|
|
541
|
+
kind: 'checklist',
|
|
542
|
+
id: 'network.shared-ip',
|
|
543
|
+
label: 'Use the same IP address for all services',
|
|
544
|
+
hint: 'When included, browser, GoodVibes service, and webhook listener network bindings share one IP address.',
|
|
545
|
+
defaultValue: controller.getSharedIpDefault(networkEnabled),
|
|
546
|
+
};
|
|
547
|
+
const sharedIp = controller.getBooleanFieldValue(sharedIpField.id, sharedIpField.defaultValue);
|
|
548
|
+
fields.push(sharedIpField);
|
|
549
|
+
if (sharedIp) {
|
|
550
|
+
fields.push({
|
|
551
|
+
kind: 'text',
|
|
552
|
+
id: 'network.shared-ip-address',
|
|
553
|
+
label: 'Shared IP address',
|
|
554
|
+
hint: 'IP address used by each enabled service.',
|
|
555
|
+
placeholder: '0.0.0.0',
|
|
556
|
+
defaultValue: controller.getSharedIpHostDefault(networkEnabled),
|
|
557
|
+
});
|
|
558
|
+
}
|
|
559
|
+
|
|
560
|
+
if (controlPlaneRemote) {
|
|
561
|
+
fields.push({
|
|
562
|
+
kind: 'text',
|
|
563
|
+
id: 'network.service-port',
|
|
564
|
+
label: 'GoodVibes service port',
|
|
565
|
+
hint: 'Port for the background service and control plane.',
|
|
566
|
+
placeholder: '3421',
|
|
567
|
+
defaultValue: String(bindSettings?.controlPlane.port ?? 3421),
|
|
568
|
+
});
|
|
569
|
+
if (!sharedIp) {
|
|
570
|
+
fields.push({
|
|
571
|
+
kind: 'text',
|
|
572
|
+
id: 'network.service-ip',
|
|
573
|
+
label: 'GoodVibes service IP address',
|
|
574
|
+
hint: 'IP address for the background service and control plane.',
|
|
575
|
+
placeholder: '0.0.0.0',
|
|
576
|
+
defaultValue: normalizeText(bindSettings?.controlPlane.host) || '0.0.0.0',
|
|
577
|
+
});
|
|
578
|
+
}
|
|
579
|
+
}
|
|
580
|
+
|
|
581
|
+
if (browserEnabled) {
|
|
582
|
+
fields.push({
|
|
583
|
+
kind: 'text',
|
|
584
|
+
id: 'network.browser-port',
|
|
585
|
+
label: 'Browser surface port',
|
|
586
|
+
hint: 'Port for browser access to GoodVibes.',
|
|
587
|
+
placeholder: '3423',
|
|
588
|
+
defaultValue: String(bindSettings?.web.port ?? 3423),
|
|
589
|
+
});
|
|
590
|
+
if (!sharedIp) {
|
|
591
|
+
fields.push({
|
|
592
|
+
kind: 'text',
|
|
593
|
+
id: 'network.browser-ip',
|
|
594
|
+
label: 'Browser surface IP address',
|
|
595
|
+
hint: 'IP address for browser access.',
|
|
596
|
+
placeholder: '0.0.0.0',
|
|
597
|
+
defaultValue: normalizeText(bindSettings?.web.host) || '0.0.0.0',
|
|
598
|
+
});
|
|
599
|
+
}
|
|
600
|
+
}
|
|
601
|
+
|
|
602
|
+
if (listenerEnabled) {
|
|
603
|
+
fields.push({
|
|
604
|
+
kind: 'text',
|
|
605
|
+
id: 'network.webhook-port',
|
|
606
|
+
label: 'HTTP listener port',
|
|
607
|
+
hint: 'Port for incoming webhooks and events.',
|
|
608
|
+
placeholder: '3422',
|
|
609
|
+
defaultValue: String(bindSettings?.httpListener.port ?? 3422),
|
|
610
|
+
});
|
|
611
|
+
if (!sharedIp) {
|
|
612
|
+
fields.push({
|
|
613
|
+
kind: 'text',
|
|
614
|
+
id: 'network.webhook-ip',
|
|
615
|
+
label: 'HTTP listener IP address',
|
|
616
|
+
hint: 'IP address for incoming webhooks and events.',
|
|
617
|
+
placeholder: '0.0.0.0',
|
|
618
|
+
defaultValue: normalizeText(bindSettings?.httpListener.host) || '0.0.0.0',
|
|
619
|
+
});
|
|
620
|
+
}
|
|
621
|
+
}
|
|
622
|
+
}
|
|
623
|
+
|
|
624
|
+
return {
|
|
625
|
+
id: 'network',
|
|
626
|
+
title: 'Network setup',
|
|
627
|
+
shortLabel: 'Network',
|
|
628
|
+
description: 'Choose the LAN default or customize IP addresses and ports for the enabled browser, service, and listener surfaces.',
|
|
629
|
+
summaryTitle: 'Bind posture',
|
|
630
|
+
summaryLines: [
|
|
631
|
+
`Mode: ${custom ? 'custom' : 'local network default'}`,
|
|
632
|
+
`Browser surface: ${browserEnabled ? 'enabled' : 'not selected'}`,
|
|
633
|
+
`HTTP listener: ${listenerWillApply ? 'enabled' : listenerEnabled ? 'available for selected external apps' : 'not selected'}`,
|
|
634
|
+
],
|
|
635
|
+
fields,
|
|
636
|
+
};
|
|
637
|
+
}
|
|
638
|
+
|
|
639
|
+
export function buildAccountsStep(controller: OnboardingWizardController): OnboardingWizardStepDefinition {
|
|
640
|
+
const subscriptionsAck = controller.runtimeDerived.reopenEditAcknowledgements.subscriptions;
|
|
641
|
+
const authAck = controller.runtimeDerived.reopenEditAcknowledgements.auth;
|
|
642
|
+
const auth = controller.runtimeSnapshot?.auth.snapshot;
|
|
643
|
+
const needsAuthBootstrap = controller.requiresAuthBootstrap();
|
|
644
|
+
const needsExistingAuthAcknowledgement = controller.hasServerCapabilitiesSelected()
|
|
645
|
+
&& !needsAuthBootstrap
|
|
646
|
+
&& controller.hasLocalAuthUser();
|
|
647
|
+
const fields: OnboardingWizardFieldDefinition[] = [];
|
|
648
|
+
const defaultAdminUsername = controller.getDefaultAdminUsername();
|
|
649
|
+
|
|
650
|
+
fields.push(
|
|
651
|
+
{
|
|
652
|
+
kind: 'text',
|
|
653
|
+
id: 'accounts.admin-username',
|
|
654
|
+
label: 'Local auth admin username',
|
|
655
|
+
hint: needsAuthBootstrap
|
|
656
|
+
? 'Required before any background service, browser surface, or listener is exposed.'
|
|
657
|
+
: 'Optional. Enter an existing admin username to rotate its password, or a new username to create another admin.',
|
|
658
|
+
placeholder: defaultAdminUsername,
|
|
659
|
+
defaultValue: defaultAdminUsername,
|
|
660
|
+
required: needsAuthBootstrap,
|
|
661
|
+
},
|
|
662
|
+
{
|
|
663
|
+
kind: 'masked',
|
|
664
|
+
id: 'accounts.admin-password',
|
|
665
|
+
label: 'Local auth admin password',
|
|
666
|
+
hint: needsAuthBootstrap
|
|
667
|
+
? controller.hasBootstrapCredentialPresent()
|
|
668
|
+
? 'Creates or updates the named local admin, removes the bootstrap credential file, and retires the bootstrap admin when it is a different user.'
|
|
669
|
+
: 'Creates the first local admin user and an initial session before LAN/server settings are applied.'
|
|
670
|
+
: 'Optional. Leave blank to keep existing local auth unchanged; enter a password to create or rotate the named admin user.',
|
|
671
|
+
placeholder: needsAuthBootstrap ? 'password required' : 'leave blank to keep unchanged',
|
|
672
|
+
defaultValue: '',
|
|
673
|
+
required: needsAuthBootstrap,
|
|
674
|
+
},
|
|
675
|
+
);
|
|
676
|
+
|
|
677
|
+
fields.push(
|
|
678
|
+
{
|
|
679
|
+
kind: 'acknowledgement',
|
|
680
|
+
id: 'accounts.subscriptions',
|
|
681
|
+
label: 'Confirm stored subscription state',
|
|
682
|
+
hint: subscriptionsAck.detail,
|
|
683
|
+
defaultValue: subscriptionsAck.accepted,
|
|
684
|
+
required: controller.mode !== 'new' && subscriptionsAck.required,
|
|
685
|
+
reason: subscriptionsAck.reason,
|
|
686
|
+
target: 'subscriptions',
|
|
687
|
+
},
|
|
688
|
+
{
|
|
689
|
+
kind: 'acknowledgement',
|
|
690
|
+
id: 'accounts.auth',
|
|
691
|
+
label: 'Confirm local auth posture',
|
|
692
|
+
hint: authAck.detail,
|
|
693
|
+
defaultValue: authAck.accepted,
|
|
694
|
+
required: needsExistingAuthAcknowledgement || (controller.mode !== 'new' && authAck.required),
|
|
695
|
+
reason: authAck.reason,
|
|
696
|
+
target: 'auth',
|
|
697
|
+
},
|
|
698
|
+
{
|
|
699
|
+
kind: 'status',
|
|
700
|
+
id: 'accounts.bootstrap',
|
|
701
|
+
label: 'Local auth readiness',
|
|
702
|
+
hint: needsAuthBootstrap
|
|
703
|
+
? 'The wizard will create local auth before applying network-accessible settings.'
|
|
704
|
+
: controller.hasAdminAuthUser()
|
|
705
|
+
? 'An existing local auth admin user was detected and will be kept.'
|
|
706
|
+
: controller.hasLocalAuthUser()
|
|
707
|
+
? 'Existing local auth users were detected and will be kept.'
|
|
708
|
+
: 'No server-backed capability is selected, so local auth is not required.',
|
|
709
|
+
defaultValue: needsAuthBootstrap
|
|
710
|
+
? controller.hasBootstrapCredentialPresent() ? 'Bootstrap replacement required' : 'Local admin required'
|
|
711
|
+
: controller.hasAdminAuthUser() ? 'Admin detected' : controller.hasLocalAuthUser() ? 'Local auth detected' : 'Not required',
|
|
712
|
+
},
|
|
713
|
+
{
|
|
714
|
+
kind: 'status',
|
|
715
|
+
id: 'accounts.user-store',
|
|
716
|
+
label: 'Local auth store path',
|
|
717
|
+
hint: 'Carry the current auth store location into edit/review mode.',
|
|
718
|
+
defaultValue: normalizeText(auth?.userStorePath) || 'No local auth store path',
|
|
719
|
+
},
|
|
720
|
+
);
|
|
721
|
+
|
|
722
|
+
return {
|
|
723
|
+
id: 'access',
|
|
724
|
+
title: 'Subscriptions and auth review',
|
|
725
|
+
shortLabel: 'Accounts',
|
|
726
|
+
description: needsAuthBootstrap
|
|
727
|
+
? 'Create wizard-owned local auth before any LAN, browser, service, or listener settings are applied.'
|
|
728
|
+
: 'Review existing subscription and local auth state. Existing local auth is kept unless you change it elsewhere.',
|
|
729
|
+
summaryTitle: 'Stored account state',
|
|
730
|
+
summaryLines: [
|
|
731
|
+
`Subscriptions: ${controller.runtimeSnapshot?.subscriptions.active.length ?? 0} active / ${controller.runtimeSnapshot?.subscriptions.pending.length ?? 0} pending`,
|
|
732
|
+
`Auth: ${auth?.userCount ?? 0} users / ${auth?.sessionCount ?? 0} sessions`,
|
|
733
|
+
needsAuthBootstrap
|
|
734
|
+
? controller.hasBootstrapCredentialPresent()
|
|
735
|
+
? 'Bootstrap credentials will be replaced before network settings are applied'
|
|
736
|
+
: 'Local admin will be created before network settings are applied'
|
|
737
|
+
: controller.hasLocalAuthUser() ? 'Existing local auth will be kept' : 'Local auth is not required for this setup',
|
|
738
|
+
],
|
|
739
|
+
fields,
|
|
740
|
+
};
|
|
741
|
+
}
|
|
742
|
+
|
|
743
|
+
export function buildReviewStep(controller: OnboardingWizardController): OnboardingWizardStepDefinition {
|
|
744
|
+
const feedback = controller.applyFeedback;
|
|
745
|
+
const feedbackFields: OnboardingWizardFieldDefinition[] = feedback
|
|
746
|
+
? [
|
|
747
|
+
{
|
|
748
|
+
kind: 'status',
|
|
749
|
+
id: 'review.feedback',
|
|
750
|
+
label: feedback.title,
|
|
751
|
+
hint: feedback.summary,
|
|
752
|
+
defaultValue: feedback.severity === 'error' ? 'Needs attention' : feedback.severity === 'warning' ? 'Warning' : 'Info',
|
|
753
|
+
},
|
|
754
|
+
...feedback.messages.slice(0, 8).map((message, index): OnboardingWizardFieldDefinition => ({
|
|
755
|
+
kind: 'status',
|
|
756
|
+
id: `review.feedback.${index}`,
|
|
757
|
+
label: message,
|
|
758
|
+
hint: message,
|
|
759
|
+
defaultValue: feedback.severity === 'error' ? 'Error' : feedback.severity === 'warning' ? 'Warning' : 'Info',
|
|
760
|
+
})),
|
|
761
|
+
]
|
|
762
|
+
: [];
|
|
763
|
+
const unsavedLabel = controller.dirtyStepCount === 1
|
|
764
|
+
? '1 screen has unapplied changes'
|
|
765
|
+
: `${controller.dirtyStepCount} screens have unapplied changes`;
|
|
766
|
+
|
|
767
|
+
return {
|
|
768
|
+
id: 'review',
|
|
769
|
+
title: 'Review and apply',
|
|
770
|
+
shortLabel: 'Review',
|
|
771
|
+
description: 'Review the selected settings and apply them directly from the wizard.',
|
|
772
|
+
summaryTitle: 'Review posture',
|
|
773
|
+
summaryLines: [
|
|
774
|
+
unsavedLabel,
|
|
775
|
+
`${controller.buildApplyRequest().operations.length} settings change(s) ready to apply`,
|
|
776
|
+
feedback ? `Last apply: ${feedback.title}` : 'No apply errors reported',
|
|
777
|
+
controller.isEditingTextField() ? `Editing: ${controller.editingFieldId}` : 'Ready to apply',
|
|
778
|
+
],
|
|
779
|
+
fields: [
|
|
780
|
+
...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
|
+
{
|
|
789
|
+
kind: 'action',
|
|
790
|
+
id: 'review.apply',
|
|
791
|
+
action: 'apply',
|
|
792
|
+
label: 'Apply settings and verify',
|
|
793
|
+
hint: 'Persist the wizard settings and verify the resulting runtime state. The global onboarding check was already recorded when the wizard opened.',
|
|
794
|
+
defaultValue: 'Ready',
|
|
795
|
+
},
|
|
796
|
+
],
|
|
797
|
+
};
|
|
798
|
+
}
|