@build-astron-co/nimbus 0.2.0 → 0.4.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/bin/nimbus +26 -10
- package/bin/nimbus.cmd +41 -0
- package/bin/nimbus.mjs +70 -0
- package/completions/nimbus.bash +38 -0
- package/completions/nimbus.fish +48 -0
- package/completions/nimbus.zsh +81 -0
- package/dist/src/agent/compaction-agent.js +215 -0
- package/dist/src/agent/context-manager.js +385 -0
- package/dist/src/agent/context.js +322 -0
- package/dist/src/agent/deploy-preview.js +395 -0
- package/dist/src/agent/expand-files.js +95 -0
- package/dist/src/agent/index.js +18 -0
- package/dist/src/agent/loop.js +1535 -0
- package/dist/src/agent/modes.js +347 -0
- package/dist/src/agent/permissions.js +396 -0
- package/dist/src/agent/subagents/base.js +67 -0
- package/dist/src/agent/subagents/cost.js +45 -0
- package/dist/src/agent/subagents/explore.js +36 -0
- package/dist/src/agent/subagents/general.js +41 -0
- package/dist/src/agent/subagents/index.js +88 -0
- package/dist/src/agent/subagents/infra.js +52 -0
- package/dist/src/agent/subagents/security.js +60 -0
- package/dist/src/agent/system-prompt.js +860 -0
- package/dist/src/app.js +152 -0
- package/dist/src/audit/activity-log.js +209 -0
- package/dist/src/audit/compliance-checker.js +419 -0
- package/dist/src/audit/cost-tracker.js +231 -0
- package/dist/src/audit/index.js +10 -0
- package/dist/src/audit/security-scanner.js +490 -0
- package/dist/src/auth/guard.js +64 -0
- package/dist/src/auth/index.js +19 -0
- package/dist/src/auth/keychain.js +79 -0
- package/dist/src/auth/oauth.js +389 -0
- package/dist/src/auth/providers.js +415 -0
- package/dist/src/auth/sso.js +87 -0
- package/dist/src/auth/store.js +424 -0
- package/dist/src/auth/types.js +5 -0
- package/dist/src/cli/index.js +8 -0
- package/dist/src/cli/init.js +1048 -0
- package/dist/src/cli/openapi-spec.js +346 -0
- package/dist/src/cli/run.js +505 -0
- package/dist/src/cli/serve-auth.js +56 -0
- package/dist/src/cli/serve.js +432 -0
- package/dist/src/cli/web.js +50 -0
- package/dist/src/cli.js +1574 -0
- package/dist/src/clients/core-engine-client.js +156 -0
- package/dist/src/clients/enterprise-client.js +246 -0
- package/dist/src/clients/generator-client.js +219 -0
- package/dist/src/clients/git-client.js +367 -0
- package/dist/src/clients/github-client.js +229 -0
- package/dist/src/clients/helm-client.js +299 -0
- package/dist/src/clients/index.js +18 -0
- package/dist/src/clients/k8s-client.js +270 -0
- package/dist/src/clients/llm-client.js +119 -0
- package/dist/src/clients/rest-client.js +104 -0
- package/dist/src/clients/service-discovery.js +35 -0
- package/dist/src/clients/terraform-client.js +302 -0
- package/dist/src/clients/tools-client.js +1227 -0
- package/dist/src/clients/ws-client.js +93 -0
- package/dist/src/commands/alias.js +91 -0
- package/dist/src/commands/analyze/index.js +313 -0
- package/dist/src/commands/apply/helm.js +375 -0
- package/dist/src/commands/apply/index.js +176 -0
- package/dist/src/commands/apply/k8s.js +350 -0
- package/dist/src/commands/apply/terraform.js +465 -0
- package/dist/src/commands/ask.js +137 -0
- package/dist/src/commands/audit/index.js +322 -0
- package/dist/src/commands/auth-cloud.js +345 -0
- package/dist/src/commands/auth-list.js +112 -0
- package/dist/src/commands/auth-profile.js +104 -0
- package/dist/src/commands/auth-refresh.js +161 -0
- package/dist/src/commands/auth-status.js +122 -0
- package/dist/src/commands/aws/ec2.js +402 -0
- package/dist/src/commands/aws/iam.js +304 -0
- package/dist/src/commands/aws/index.js +108 -0
- package/dist/src/commands/aws/lambda.js +317 -0
- package/dist/src/commands/aws/rds.js +345 -0
- package/dist/src/commands/aws/s3.js +346 -0
- package/dist/src/commands/aws/vpc.js +302 -0
- package/dist/src/commands/aws-discover.js +413 -0
- package/dist/src/commands/aws-terraform.js +618 -0
- package/dist/src/commands/azure/aks.js +305 -0
- package/dist/src/commands/azure/functions.js +200 -0
- package/dist/src/commands/azure/index.js +93 -0
- package/dist/src/commands/azure/storage.js +378 -0
- package/dist/src/commands/azure/vm.js +291 -0
- package/dist/src/commands/billing/index.js +224 -0
- package/dist/src/commands/chat.js +259 -0
- package/dist/src/commands/completions.js +255 -0
- package/dist/src/commands/config.js +291 -0
- package/dist/src/commands/cost/cloud-cost-estimator.js +211 -0
- package/dist/src/commands/cost/estimator.js +73 -0
- package/dist/src/commands/cost/index.js +625 -0
- package/dist/src/commands/cost/parsers/terraform.js +234 -0
- package/dist/src/commands/cost/parsers/types.js +4 -0
- package/dist/src/commands/cost/pricing/aws.js +501 -0
- package/dist/src/commands/cost/pricing/azure.js +462 -0
- package/dist/src/commands/cost/pricing/gcp.js +359 -0
- package/dist/src/commands/cost/pricing/index.js +24 -0
- package/dist/src/commands/demo.js +196 -0
- package/dist/src/commands/deploy.js +215 -0
- package/dist/src/commands/doctor.js +1291 -0
- package/dist/src/commands/drift/index.js +674 -0
- package/dist/src/commands/explain.js +235 -0
- package/dist/src/commands/export.js +120 -0
- package/dist/src/commands/feedback.js +319 -0
- package/dist/src/commands/fix.js +263 -0
- package/dist/src/commands/fs/index.js +338 -0
- package/dist/src/commands/gcp/compute.js +266 -0
- package/dist/src/commands/gcp/functions.js +221 -0
- package/dist/src/commands/gcp/gke.js +357 -0
- package/dist/src/commands/gcp/iam.js +295 -0
- package/dist/src/commands/gcp/index.js +105 -0
- package/dist/src/commands/gcp/storage.js +232 -0
- package/dist/src/commands/generate-helm.js +1026 -0
- package/dist/src/commands/generate-k8s.js +1263 -0
- package/dist/src/commands/generate-terraform.js +1058 -0
- package/dist/src/commands/gh/index.js +663 -0
- package/dist/src/commands/git/index.js +1208 -0
- package/dist/src/commands/helm/index.js +985 -0
- package/dist/src/commands/help.js +639 -0
- package/dist/src/commands/history.js +120 -0
- package/dist/src/commands/import.js +782 -0
- package/dist/src/commands/incident.js +144 -0
- package/dist/src/commands/index.js +109 -0
- package/dist/src/commands/init.js +955 -0
- package/dist/src/commands/k8s/index.js +979 -0
- package/dist/src/commands/login.js +588 -0
- package/dist/src/commands/logout.js +61 -0
- package/dist/src/commands/logs.js +160 -0
- package/dist/src/commands/onboarding.js +382 -0
- package/dist/src/commands/pipeline.js +153 -0
- package/dist/src/commands/plan/display.js +216 -0
- package/dist/src/commands/plan/index.js +525 -0
- package/dist/src/commands/plugin.js +325 -0
- package/dist/src/commands/preview.js +356 -0
- package/dist/src/commands/profile.js +297 -0
- package/dist/src/commands/questionnaire.js +1021 -0
- package/dist/src/commands/resume.js +35 -0
- package/dist/src/commands/rollback.js +259 -0
- package/dist/src/commands/rollout.js +74 -0
- package/dist/src/commands/runbook.js +307 -0
- package/dist/src/commands/schedule.js +202 -0
- package/dist/src/commands/status.js +213 -0
- package/dist/src/commands/team/index.js +309 -0
- package/dist/src/commands/team-context.js +200 -0
- package/dist/src/commands/template.js +204 -0
- package/dist/src/commands/tf/index.js +989 -0
- package/dist/src/commands/upgrade.js +515 -0
- package/dist/src/commands/usage/index.js +118 -0
- package/dist/src/commands/version.js +145 -0
- package/dist/src/commands/watch.js +127 -0
- package/dist/src/compat/index.js +2 -0
- package/dist/src/compat/runtime.js +10 -0
- package/dist/src/compat/sqlite.js +144 -0
- package/dist/src/config/index.js +6 -0
- package/dist/src/config/manager.js +469 -0
- package/dist/src/config/mode-store.js +57 -0
- package/dist/src/config/profiles.js +66 -0
- package/dist/src/config/safety-policy.js +251 -0
- package/dist/src/config/schema.js +107 -0
- package/dist/src/config/types.js +311 -0
- package/dist/src/config/workspace-state.js +38 -0
- package/dist/src/context/context-db.js +138 -0
- package/dist/src/demo/index.js +295 -0
- package/dist/src/demo/scenarios/full-journey.js +226 -0
- package/dist/src/demo/scenarios/getting-started.js +124 -0
- package/dist/src/demo/scenarios/helm-release.js +334 -0
- package/dist/src/demo/scenarios/k8s-deployment.js +190 -0
- package/dist/src/demo/scenarios/terraform-vpc.js +167 -0
- package/dist/src/demo/types.js +6 -0
- package/dist/src/engine/cost-estimator.js +334 -0
- package/dist/src/engine/diagram-generator.js +192 -0
- package/dist/src/engine/drift-detector.js +688 -0
- package/dist/src/engine/executor.js +832 -0
- package/dist/src/engine/index.js +39 -0
- package/dist/src/engine/orchestrator.js +436 -0
- package/dist/src/engine/planner.js +616 -0
- package/dist/src/engine/safety.js +609 -0
- package/dist/src/engine/verifier.js +664 -0
- package/dist/src/enterprise/audit.js +241 -0
- package/dist/src/enterprise/auth.js +189 -0
- package/dist/src/enterprise/billing.js +512 -0
- package/dist/src/enterprise/index.js +16 -0
- package/dist/src/enterprise/teams.js +315 -0
- package/dist/src/generator/best-practices.js +1375 -0
- package/dist/src/generator/helm.js +495 -0
- package/dist/src/generator/index.js +11 -0
- package/dist/src/generator/intent-parser.js +420 -0
- package/dist/src/generator/kubernetes.js +773 -0
- package/dist/src/generator/terraform.js +1472 -0
- package/dist/src/history/index.js +6 -0
- package/dist/src/history/manager.js +199 -0
- package/dist/src/history/types.js +6 -0
- package/dist/src/hooks/config.js +318 -0
- package/dist/src/hooks/engine.js +317 -0
- package/dist/src/hooks/index.js +2 -0
- package/dist/src/llm/auth-bridge.js +157 -0
- package/dist/src/llm/circuit-breaker.js +116 -0
- package/dist/src/llm/config-loader.js +172 -0
- package/dist/src/llm/cost-calculator.js +137 -0
- package/dist/src/llm/index.js +7 -0
- package/dist/src/llm/model-aliases.js +99 -0
- package/dist/src/llm/provider-registry.js +57 -0
- package/dist/src/llm/providers/anthropic.js +430 -0
- package/dist/src/llm/providers/bedrock.js +409 -0
- package/dist/src/llm/providers/google.js +344 -0
- package/dist/src/llm/providers/ollama.js +661 -0
- package/dist/src/llm/providers/openai-compatible.js +289 -0
- package/dist/src/llm/providers/openai.js +284 -0
- package/dist/src/llm/providers/openrouter.js +293 -0
- package/dist/src/llm/router.js +844 -0
- package/dist/src/llm/types.js +69 -0
- package/dist/src/lsp/client.js +239 -0
- package/dist/src/lsp/languages.js +95 -0
- package/dist/src/lsp/manager.js +243 -0
- package/dist/src/mcp/client.js +289 -0
- package/dist/src/mcp/index.js +5 -0
- package/dist/src/mcp/manager.js +113 -0
- package/dist/src/nimbus.js +212 -0
- package/dist/src/plugins/index.js +13 -0
- package/dist/src/plugins/loader.js +280 -0
- package/dist/src/plugins/manager.js +282 -0
- package/dist/src/plugins/types.js +23 -0
- package/dist/src/scanners/cicd-scanner.js +230 -0
- package/dist/src/scanners/cloud-scanner.js +415 -0
- package/dist/src/scanners/framework-scanner.js +430 -0
- package/dist/src/scanners/iac-scanner.js +350 -0
- package/dist/src/scanners/index.js +454 -0
- package/dist/src/scanners/language-scanner.js +258 -0
- package/dist/src/scanners/package-manager-scanner.js +252 -0
- package/dist/src/scanners/types.js +6 -0
- package/dist/src/sessions/manager.js +395 -0
- package/dist/src/sessions/types.js +4 -0
- package/dist/src/sharing/sync.js +238 -0
- package/dist/src/sharing/viewer.js +131 -0
- package/dist/src/snapshots/index.js +1 -0
- package/dist/src/snapshots/manager.js +432 -0
- package/dist/src/state/artifacts.js +94 -0
- package/dist/src/state/audit.js +73 -0
- package/dist/src/state/billing.js +126 -0
- package/dist/src/state/checkpoints.js +81 -0
- package/dist/src/state/config.js +58 -0
- package/dist/src/state/conversations.js +7 -0
- package/dist/src/state/credentials.js +96 -0
- package/dist/src/state/db.js +53 -0
- package/dist/src/state/index.js +23 -0
- package/dist/src/state/messages.js +76 -0
- package/dist/src/state/projects.js +92 -0
- package/dist/src/state/schema.js +233 -0
- package/dist/src/state/sessions.js +79 -0
- package/dist/src/state/teams.js +131 -0
- package/dist/src/telemetry.js +91 -0
- package/dist/src/tools/aws-ops.js +747 -0
- package/dist/src/tools/azure-ops.js +491 -0
- package/dist/src/tools/file-ops.js +451 -0
- package/dist/src/tools/gcp-ops.js +559 -0
- package/dist/src/tools/git-ops.js +557 -0
- package/dist/src/tools/github-ops.js +460 -0
- package/dist/src/tools/helm-ops.js +634 -0
- package/dist/src/tools/index.js +16 -0
- package/dist/src/tools/k8s-ops.js +579 -0
- package/dist/src/tools/schemas/converter.js +129 -0
- package/dist/src/tools/schemas/devops.js +3319 -0
- package/dist/src/tools/schemas/index.js +19 -0
- package/dist/src/tools/schemas/standard.js +966 -0
- package/dist/src/tools/schemas/types.js +409 -0
- package/dist/src/tools/spawn-exec.js +109 -0
- package/dist/src/tools/terraform-ops.js +627 -0
- package/dist/src/types/config.js +1 -0
- package/dist/src/types/drift.js +4 -0
- package/dist/src/types/enterprise.js +5 -0
- package/dist/src/types/index.js +14 -0
- package/dist/src/types/plan.js +1 -0
- package/dist/src/types/request.js +1 -0
- package/dist/src/types/response.js +1 -0
- package/dist/src/types/service.js +1 -0
- package/dist/src/ui/App.js +1672 -0
- package/dist/src/ui/DeployPreview.js +60 -0
- package/dist/src/ui/FileDiffModal.js +108 -0
- package/dist/src/ui/Header.js +46 -0
- package/dist/src/ui/HelpModal.js +9 -0
- package/dist/src/ui/InputBox.js +408 -0
- package/dist/src/ui/MessageList.js +795 -0
- package/dist/src/ui/PermissionPrompt.js +72 -0
- package/dist/src/ui/StatusBar.js +109 -0
- package/dist/src/ui/TerminalPane.js +31 -0
- package/dist/src/ui/ToolCallDisplay.js +303 -0
- package/dist/src/ui/TreePane.js +83 -0
- package/dist/src/ui/chat-ui.js +721 -0
- package/dist/src/ui/index.js +11 -0
- package/dist/src/ui/ink/index.js +1325 -0
- package/dist/src/ui/streaming.js +137 -0
- package/dist/src/ui/theme.js +78 -0
- package/dist/src/ui/types.js +7 -0
- package/dist/src/utils/analytics.js +61 -0
- package/dist/src/utils/cost-warning.js +25 -0
- package/dist/src/utils/env.js +42 -0
- package/dist/src/utils/errors.js +54 -0
- package/dist/src/utils/event-bus.js +22 -0
- package/dist/src/utils/index.js +16 -0
- package/dist/src/utils/logger.js +150 -0
- package/dist/src/utils/rate-limiter.js +90 -0
- package/dist/src/utils/service-auth.js +36 -0
- package/dist/src/utils/validation.js +39 -0
- package/dist/src/version.js +3 -0
- package/dist/src/watcher/index.js +192 -0
- package/dist/src/wizard/approval.js +275 -0
- package/dist/src/wizard/index.js +13 -0
- package/dist/src/wizard/prompts.js +273 -0
- package/dist/src/wizard/types.js +4 -0
- package/dist/src/wizard/ui.js +453 -0
- package/dist/src/wizard/wizard.js +227 -0
- package/package.json +31 -23
- package/src/__tests__/alias.test.ts +133 -0
- package/src/__tests__/app.test.ts +1 -1
- package/src/__tests__/audit.test.ts +1 -1
- package/src/__tests__/circuit-breaker.test.ts +1 -1
- package/src/__tests__/cli-run.test.ts +237 -1
- package/src/__tests__/compat-sqlite.test.ts +68 -0
- package/src/__tests__/context-manager.test.ts +131 -1
- package/src/__tests__/context.test.ts +1 -1
- package/src/__tests__/devops-terminal-gaps.test.ts +718 -0
- package/src/__tests__/doctor.test.ts +48 -0
- package/src/__tests__/enterprise.test.ts +1 -1
- package/src/__tests__/export.test.ts +236 -0
- package/src/__tests__/gap-11-18-20.test.ts +958 -0
- package/src/__tests__/generator.test.ts +1 -1
- package/src/__tests__/helm-streaming.test.ts +127 -0
- package/src/__tests__/hooks.test.ts +1 -1
- package/src/__tests__/incident.test.ts +179 -0
- package/src/__tests__/init.test.ts +55 -4
- package/src/__tests__/intent-parser.test.ts +1 -1
- package/src/__tests__/llm-router.test.ts +1 -1
- package/src/__tests__/logs.test.ts +107 -0
- package/src/__tests__/loop-errors.test.ts +244 -0
- package/src/__tests__/lsp.test.ts +1 -1
- package/src/__tests__/modes.test.ts +1 -1
- package/src/__tests__/perf-optimizations.test.ts +847 -0
- package/src/__tests__/permissions.test.ts +1 -1
- package/src/__tests__/pipeline.test.ts +50 -0
- package/src/__tests__/polish-phase3.test.ts +340 -0
- package/src/__tests__/profile.test.ts +237 -0
- package/src/__tests__/rollback.test.ts +83 -0
- package/src/__tests__/runbook.test.ts +219 -0
- package/src/__tests__/schedule.test.ts +206 -0
- package/src/__tests__/serve.test.ts +1 -1
- package/src/__tests__/sessions.test.ts +96 -1
- package/src/__tests__/sharing.test.ts +53 -1
- package/src/__tests__/snapshots.test.ts +1 -1
- package/src/__tests__/standalone-migration.test.ts +199 -0
- package/src/__tests__/state-db.test.ts +1 -1
- package/src/__tests__/status.test.ts +158 -0
- package/src/__tests__/stream-with-tools.test.ts +71 -25
- package/src/__tests__/subagents.test.ts +1 -1
- package/src/__tests__/system-prompt.test.ts +82 -3
- package/src/__tests__/terminal-gap-v2.test.ts +395 -0
- package/src/__tests__/terminal-parity.test.ts +393 -0
- package/src/__tests__/tf-apply.test.ts +187 -0
- package/src/__tests__/tool-converter.test.ts +1 -1
- package/src/__tests__/tool-schemas.test.ts +209 -4
- package/src/__tests__/tools.test.ts +4 -3
- package/src/__tests__/version-json.test.ts +184 -0
- package/src/__tests__/version.test.ts +1 -1
- package/src/__tests__/watch.test.ts +129 -0
- package/src/agent/compaction-agent.ts +40 -1
- package/src/agent/context-manager.ts +67 -3
- package/src/agent/deploy-preview.ts +62 -1
- package/src/agent/expand-files.ts +108 -0
- package/src/agent/loop.ts +1312 -31
- package/src/agent/permissions.ts +51 -4
- package/src/agent/system-prompt.ts +573 -19
- package/src/app.ts +58 -0
- package/src/audit/security-scanner.ts +45 -0
- package/src/auth/keychain.ts +82 -0
- package/src/auth/oauth.ts +15 -5
- package/src/cli/init.ts +378 -5
- package/src/cli/run.ts +407 -16
- package/src/cli/serve.ts +78 -1
- package/src/cli/web.ts +10 -6
- package/src/cli.ts +312 -1
- package/src/clients/service-discovery.ts +30 -25
- package/src/commands/alias.ts +100 -0
- package/src/commands/audit/index.ts +121 -2
- package/src/commands/auth-cloud.ts +113 -0
- package/src/commands/auth-refresh.ts +187 -0
- package/src/commands/aws-discover.ts +144 -251
- package/src/commands/aws-terraform.ts +68 -118
- package/src/commands/chat.ts +9 -3
- package/src/commands/completions.ts +268 -0
- package/src/commands/config.ts +26 -0
- package/src/commands/cost/index.ts +218 -2
- package/src/commands/deploy.ts +260 -0
- package/src/commands/doctor.ts +744 -152
- package/src/commands/drift/index.ts +371 -23
- package/src/commands/export.ts +146 -0
- package/src/commands/generate-k8s.ts +9 -61
- package/src/commands/generate-terraform.ts +191 -449
- package/src/commands/help.ts +212 -36
- package/src/commands/history.ts +8 -1
- package/src/commands/incident.ts +166 -0
- package/src/commands/init.ts +5 -0
- package/src/commands/login.ts +86 -1
- package/src/commands/logs.ts +167 -0
- package/src/commands/onboarding.ts +211 -34
- package/src/commands/pipeline.ts +186 -0
- package/src/commands/plugin.ts +398 -0
- package/src/commands/profile.ts +342 -0
- package/src/commands/questionnaire.ts +0 -98
- package/src/commands/resume.ts +26 -34
- package/src/commands/rollback.ts +315 -0
- package/src/commands/rollout.ts +88 -0
- package/src/commands/runbook.ts +346 -0
- package/src/commands/schedule.ts +236 -0
- package/src/commands/status.ts +252 -0
- package/src/commands/team-context.ts +220 -0
- package/src/commands/template.ts +58 -57
- package/src/commands/tf/index.ts +70 -11
- package/src/commands/upgrade.ts +57 -0
- package/src/commands/version.ts +54 -50
- package/src/commands/watch.ts +153 -0
- package/src/compat/runtime.ts +1 -1
- package/src/compat/sqlite.ts +75 -5
- package/src/config/mode-store.ts +62 -0
- package/src/config/profiles.ts +84 -0
- package/src/config/types.ts +83 -1
- package/src/config/workspace-state.ts +53 -0
- package/src/engine/cost-estimator.ts +52 -10
- package/src/engine/executor.ts +33 -2
- package/src/engine/planner.ts +68 -1
- package/src/generator/terraform.ts +8 -0
- package/src/history/manager.ts +2 -74
- package/src/hooks/engine.ts +5 -4
- package/src/llm/cost-calculator.ts +2 -2
- package/src/llm/providers/anthropic.ts +50 -21
- package/src/llm/router.ts +76 -7
- package/src/lsp/languages.ts +3 -0
- package/src/lsp/manager.ts +21 -5
- package/src/nimbus.ts +37 -18
- package/src/sessions/manager.ts +108 -1
- package/src/sharing/sync.ts +4 -0
- package/src/sharing/viewer.ts +66 -0
- package/src/tools/file-ops.ts +22 -0
- package/src/tools/schemas/devops.ts +3007 -117
- package/src/tools/schemas/standard.ts +5 -1
- package/src/tools/schemas/types.ts +31 -1
- package/src/tools/spawn-exec.ts +148 -0
- package/src/ui/App.tsx +1183 -66
- package/src/ui/DeployPreview.tsx +62 -57
- package/src/ui/FileDiffModal.tsx +162 -0
- package/src/ui/Header.tsx +87 -24
- package/src/ui/HelpModal.tsx +57 -0
- package/src/ui/InputBox.tsx +163 -10
- package/src/ui/MessageList.tsx +487 -40
- package/src/ui/PermissionPrompt.tsx +17 -5
- package/src/ui/StatusBar.tsx +122 -3
- package/src/ui/TerminalPane.tsx +84 -0
- package/src/ui/ToolCallDisplay.tsx +252 -18
- package/src/ui/TreePane.tsx +132 -0
- package/src/ui/chat-ui.ts +41 -44
- package/src/ui/ink/index.ts +771 -38
- package/src/ui/streaming.ts +1 -1
- package/src/ui/theme.ts +104 -0
- package/src/ui/types.ts +18 -0
- package/src/version.ts +1 -1
- package/src/watcher/index.ts +66 -15
- package/src/wizard/types.ts +1 -0
- package/src/wizard/ui.ts +1 -1
- package/tsconfig.json +2 -2
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logs Command — H1
|
|
3
|
+
*
|
|
4
|
+
* Shorthand for streaming Kubernetes pod logs directly.
|
|
5
|
+
*
|
|
6
|
+
* Usage:
|
|
7
|
+
* nimbus logs <pod> [-n namespace] [-f] [--previous] [--tail N] [--analyze]
|
|
8
|
+
*/
|
|
9
|
+
import { execFileSync, spawn } from 'node:child_process';
|
|
10
|
+
import { ui } from '../wizard/ui';
|
|
11
|
+
/**
|
|
12
|
+
* Build the kubectl logs argument array.
|
|
13
|
+
*/
|
|
14
|
+
function buildArgs(pod, options) {
|
|
15
|
+
const args = ['logs', pod];
|
|
16
|
+
if (options.namespace)
|
|
17
|
+
args.push('-n', options.namespace);
|
|
18
|
+
if (options.follow)
|
|
19
|
+
args.push('--follow');
|
|
20
|
+
if (options.previous)
|
|
21
|
+
args.push('--previous');
|
|
22
|
+
if (options.tail !== undefined)
|
|
23
|
+
args.push('--tail', String(options.tail));
|
|
24
|
+
if (options.container)
|
|
25
|
+
args.push('-c', options.container);
|
|
26
|
+
if (options.context)
|
|
27
|
+
args.push('--context', options.context);
|
|
28
|
+
return args;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Stream or fetch Kubernetes pod logs.
|
|
32
|
+
*/
|
|
33
|
+
export async function logsCommand(pod, options = {}) {
|
|
34
|
+
if (!pod) {
|
|
35
|
+
ui.error('Usage: nimbus logs <pod> [-n namespace] [-f] [--tail N]');
|
|
36
|
+
process.exit(1);
|
|
37
|
+
}
|
|
38
|
+
const args = buildArgs(pod, options);
|
|
39
|
+
// --analyze: capture output and pass to agent for analysis
|
|
40
|
+
if (options.analyze) {
|
|
41
|
+
if (!options.quiet) {
|
|
42
|
+
ui.startSpinner({ message: `Fetching logs for ${pod}...` });
|
|
43
|
+
}
|
|
44
|
+
try {
|
|
45
|
+
const output = execFileSync('kubectl', args, {
|
|
46
|
+
encoding: 'utf-8',
|
|
47
|
+
timeout: 30_000,
|
|
48
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
49
|
+
});
|
|
50
|
+
if (!options.quiet) {
|
|
51
|
+
ui.stopSpinnerSuccess('Logs fetched');
|
|
52
|
+
}
|
|
53
|
+
// Lazy-import agent loop to avoid circular deps at startup
|
|
54
|
+
const { runAgentLoop } = await import('../agent/loop');
|
|
55
|
+
const { getAppContext } = await import('../app');
|
|
56
|
+
const { defaultToolRegistry } = await import('../tools/schemas/types');
|
|
57
|
+
const { standardTools } = await import('../tools/schemas/standard');
|
|
58
|
+
const ctx = getAppContext();
|
|
59
|
+
if (!ctx) {
|
|
60
|
+
ui.error('App not initialized. Run `nimbus login` first.');
|
|
61
|
+
process.exit(1);
|
|
62
|
+
}
|
|
63
|
+
// Ensure tools are registered for the agent loop
|
|
64
|
+
if (defaultToolRegistry.size === 0) {
|
|
65
|
+
for (const tool of standardTools) {
|
|
66
|
+
try {
|
|
67
|
+
defaultToolRegistry.register(tool);
|
|
68
|
+
}
|
|
69
|
+
catch { /* skip duplicates */ }
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
if (!options.quiet) {
|
|
73
|
+
ui.info('Analyzing logs...');
|
|
74
|
+
}
|
|
75
|
+
await runAgentLoop(`Analyze these Kubernetes logs for pod "${pod}". Identify errors, anomalies, and crash patterns:\n\n${output}`, [], {
|
|
76
|
+
router: ctx.router,
|
|
77
|
+
toolRegistry: defaultToolRegistry,
|
|
78
|
+
mode: 'plan',
|
|
79
|
+
maxTurns: 5,
|
|
80
|
+
onText: text => { process.stdout.write(text); },
|
|
81
|
+
});
|
|
82
|
+
console.log('');
|
|
83
|
+
}
|
|
84
|
+
catch (error) {
|
|
85
|
+
if (!options.quiet) {
|
|
86
|
+
ui.stopSpinnerFail('Failed to fetch logs');
|
|
87
|
+
}
|
|
88
|
+
ui.error(error.message);
|
|
89
|
+
process.exit(1);
|
|
90
|
+
}
|
|
91
|
+
return;
|
|
92
|
+
}
|
|
93
|
+
// --follow: stream via spawn
|
|
94
|
+
if (options.follow) {
|
|
95
|
+
const child = spawn('kubectl', args, {
|
|
96
|
+
stdio: ['ignore', 'inherit', 'inherit'],
|
|
97
|
+
});
|
|
98
|
+
await new Promise((resolve, reject) => {
|
|
99
|
+
child.on('close', code => {
|
|
100
|
+
if (code !== 0)
|
|
101
|
+
reject(new Error(`kubectl logs exited with code ${code}`));
|
|
102
|
+
else
|
|
103
|
+
resolve();
|
|
104
|
+
});
|
|
105
|
+
child.on('error', reject);
|
|
106
|
+
});
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
// Non-follow: capture and print
|
|
110
|
+
try {
|
|
111
|
+
const output = execFileSync('kubectl', args, {
|
|
112
|
+
encoding: 'utf-8',
|
|
113
|
+
timeout: 60_000,
|
|
114
|
+
stdio: ['pipe', 'pipe', 'pipe'],
|
|
115
|
+
});
|
|
116
|
+
process.stdout.write(output);
|
|
117
|
+
}
|
|
118
|
+
catch (error) {
|
|
119
|
+
ui.error(`kubectl logs failed: ${error.message}`);
|
|
120
|
+
process.exit(1);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
/**
|
|
124
|
+
* Parse `nimbus logs <pod> [options]` arguments.
|
|
125
|
+
*/
|
|
126
|
+
export function parseLogsArgs(args) {
|
|
127
|
+
let pod = '';
|
|
128
|
+
const options = {};
|
|
129
|
+
for (let i = 0; i < args.length; i++) {
|
|
130
|
+
const arg = args[i];
|
|
131
|
+
if (arg === '-n' || arg === '--namespace') {
|
|
132
|
+
options.namespace = args[++i];
|
|
133
|
+
}
|
|
134
|
+
else if (arg === '-f' || arg === '--follow') {
|
|
135
|
+
options.follow = true;
|
|
136
|
+
}
|
|
137
|
+
else if (arg === '-p' || arg === '--previous') {
|
|
138
|
+
options.previous = true;
|
|
139
|
+
}
|
|
140
|
+
else if (arg === '--tail') {
|
|
141
|
+
options.tail = parseInt(args[++i] ?? '100', 10);
|
|
142
|
+
}
|
|
143
|
+
else if (arg === '--analyze') {
|
|
144
|
+
options.analyze = true;
|
|
145
|
+
}
|
|
146
|
+
else if (arg === '-c' || arg === '--container') {
|
|
147
|
+
options.container = args[++i];
|
|
148
|
+
}
|
|
149
|
+
else if (arg === '--context') {
|
|
150
|
+
options.context = args[++i];
|
|
151
|
+
}
|
|
152
|
+
else if (arg === '-q' || arg === '--quiet') {
|
|
153
|
+
options.quiet = true;
|
|
154
|
+
}
|
|
155
|
+
else if (!arg.startsWith('-') && !pod) {
|
|
156
|
+
pod = arg;
|
|
157
|
+
}
|
|
158
|
+
}
|
|
159
|
+
return { pod, options };
|
|
160
|
+
}
|
|
@@ -0,0 +1,382 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Onboarding Command
|
|
3
|
+
*
|
|
4
|
+
* First-run wizard that detects missing LLM credentials and guides
|
|
5
|
+
* the user through initial setup. Runs before full app init so it
|
|
6
|
+
* only depends on the auth store and wizard prompts.
|
|
7
|
+
*/
|
|
8
|
+
import { AuthStore } from '../auth/store';
|
|
9
|
+
import { PROVIDER_REGISTRY, getDefaultModel, validateProviderApiKey } from '../auth/providers';
|
|
10
|
+
import { ui } from '../wizard/ui';
|
|
11
|
+
import { select, input } from '../wizard/prompts';
|
|
12
|
+
/**
|
|
13
|
+
* Check whether onboarding is needed.
|
|
14
|
+
*
|
|
15
|
+
* Returns `true` if no LLM credentials are found in the auth store
|
|
16
|
+
* and no provider API key environment variables are set.
|
|
17
|
+
*/
|
|
18
|
+
export function needsOnboarding() {
|
|
19
|
+
const store = new AuthStore();
|
|
20
|
+
if (store.exists()) {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
const hasEnvKey = !!(process.env.ANTHROPIC_API_KEY ||
|
|
24
|
+
process.env.OPENAI_API_KEY ||
|
|
25
|
+
process.env.GOOGLE_API_KEY ||
|
|
26
|
+
process.env.OPENROUTER_API_KEY ||
|
|
27
|
+
process.env.GROQ_API_KEY ||
|
|
28
|
+
process.env.TOGETHER_API_KEY ||
|
|
29
|
+
process.env.DEEPSEEK_API_KEY ||
|
|
30
|
+
process.env.FIREWORKS_API_KEY ||
|
|
31
|
+
process.env.PERPLEXITY_API_KEY ||
|
|
32
|
+
process.env.AWS_ACCESS_KEY_ID);
|
|
33
|
+
return !hasEnvKey;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Run the first-run onboarding wizard.
|
|
37
|
+
*/
|
|
38
|
+
export async function onboardingCommand(options = {}) {
|
|
39
|
+
if (options.skip) {
|
|
40
|
+
return;
|
|
41
|
+
}
|
|
42
|
+
const store = new AuthStore();
|
|
43
|
+
// Double-check — if credentials exist, skip silently
|
|
44
|
+
if (store.exists()) {
|
|
45
|
+
return;
|
|
46
|
+
}
|
|
47
|
+
// Non-TTY detection: if stdin is not a TTY (piped input, CI, etc.),
|
|
48
|
+
// skip the interactive wizard and show setup instructions instead.
|
|
49
|
+
if (!process.stdin.isTTY) {
|
|
50
|
+
ui.newLine();
|
|
51
|
+
ui.info('No LLM provider configured. Set an API key via environment variable:');
|
|
52
|
+
ui.newLine();
|
|
53
|
+
ui.print(' export ANTHROPIC_API_KEY=sk-ant-...');
|
|
54
|
+
ui.print(' export OPENAI_API_KEY=sk-...');
|
|
55
|
+
ui.print(' export GOOGLE_API_KEY=...');
|
|
56
|
+
ui.print(' export OPENROUTER_API_KEY=sk-or-...');
|
|
57
|
+
ui.print(' export GROQ_API_KEY=gsk_...');
|
|
58
|
+
ui.print(' export DEEPSEEK_API_KEY=sk-...');
|
|
59
|
+
ui.newLine();
|
|
60
|
+
ui.info('Or run "nimbus login" in an interactive terminal.');
|
|
61
|
+
ui.newLine();
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
try {
|
|
65
|
+
// Welcome banner — DevOps-first identity
|
|
66
|
+
ui.newLine();
|
|
67
|
+
ui.box({
|
|
68
|
+
title: 'Welcome to Nimbus — AI-Powered DevOps Terminal',
|
|
69
|
+
content: [
|
|
70
|
+
'Plan, apply, and manage Terraform, Kubernetes, Helm,',
|
|
71
|
+
'AWS, GCP, and Azure using natural language.',
|
|
72
|
+
'',
|
|
73
|
+
"Let's get you set up. This takes about 30 seconds.",
|
|
74
|
+
'',
|
|
75
|
+
'After setup you can:',
|
|
76
|
+
' nimbus Open interactive DevOps terminal',
|
|
77
|
+
' nimbus run "tf plan --explain" Run agent non-interactively',
|
|
78
|
+
' nimbus status Live infra health dashboard',
|
|
79
|
+
],
|
|
80
|
+
style: 'rounded',
|
|
81
|
+
borderColor: 'cyan',
|
|
82
|
+
titleColor: 'brightCyan',
|
|
83
|
+
padding: 1,
|
|
84
|
+
});
|
|
85
|
+
ui.newLine();
|
|
86
|
+
// Gap 12: Show env var shortcut for power users before the wizard
|
|
87
|
+
ui.print(ui.dim('─────────────────────────────────────────────────────'));
|
|
88
|
+
ui.print(ui.dim(' Quick setup: export an API key and restart nimbus.'));
|
|
89
|
+
ui.print(ui.dim(' export ANTHROPIC_API_KEY=sk-ant-...'));
|
|
90
|
+
ui.print(ui.dim(' export OPENAI_API_KEY=sk-...'));
|
|
91
|
+
ui.print(ui.dim(' export GOOGLE_API_KEY=...'));
|
|
92
|
+
ui.print(ui.dim('─────────────────────────────────────────────────────'));
|
|
93
|
+
ui.newLine();
|
|
94
|
+
// Provider selection
|
|
95
|
+
const providerOptions = Object.values(PROVIDER_REGISTRY).map(p => ({
|
|
96
|
+
label: p.displayName,
|
|
97
|
+
value: p.name,
|
|
98
|
+
description: p.description,
|
|
99
|
+
}));
|
|
100
|
+
const provider = await select({
|
|
101
|
+
message: 'Which LLM provider would you like to use?',
|
|
102
|
+
options: providerOptions,
|
|
103
|
+
required: true,
|
|
104
|
+
});
|
|
105
|
+
if (!provider) {
|
|
106
|
+
ui.newLine();
|
|
107
|
+
ui.info('No provider selected. You can run "nimbus login" later to set up.');
|
|
108
|
+
ui.newLine();
|
|
109
|
+
return;
|
|
110
|
+
}
|
|
111
|
+
const providerInfo = PROVIDER_REGISTRY[provider];
|
|
112
|
+
// API key input (skip for Ollama)
|
|
113
|
+
let apiKey;
|
|
114
|
+
let baseUrl;
|
|
115
|
+
if (providerInfo.requiresApiKey) {
|
|
116
|
+
ui.newLine();
|
|
117
|
+
if (providerInfo.apiKeyUrl) {
|
|
118
|
+
ui.info(`Get your API key at: ${ui.color(providerInfo.apiKeyUrl, 'cyan')}`);
|
|
119
|
+
}
|
|
120
|
+
ui.newLine();
|
|
121
|
+
// Retry loop: re-prompt on invalid key (up to 3 attempts)
|
|
122
|
+
const MAX_ATTEMPTS = 3;
|
|
123
|
+
let attempt = 0;
|
|
124
|
+
let validated = false;
|
|
125
|
+
while (attempt < MAX_ATTEMPTS) {
|
|
126
|
+
attempt++;
|
|
127
|
+
apiKey = await input({
|
|
128
|
+
message: attempt === 1
|
|
129
|
+
? `Enter your ${providerInfo.displayName} API key`
|
|
130
|
+
: `Enter your ${providerInfo.displayName} API key (attempt ${attempt}/${MAX_ATTEMPTS})`,
|
|
131
|
+
});
|
|
132
|
+
if (!apiKey) {
|
|
133
|
+
ui.newLine();
|
|
134
|
+
ui.warning('No API key entered. You can run "nimbus login" later to set up.');
|
|
135
|
+
ui.newLine();
|
|
136
|
+
return;
|
|
137
|
+
}
|
|
138
|
+
// Validate credentials
|
|
139
|
+
ui.newLine();
|
|
140
|
+
ui.startSpinner({ message: `Validating ${providerInfo.displayName} credentials...` });
|
|
141
|
+
let validation;
|
|
142
|
+
try {
|
|
143
|
+
validation = await validateProviderApiKey(provider, apiKey, baseUrl);
|
|
144
|
+
}
|
|
145
|
+
catch (err) {
|
|
146
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
147
|
+
ui.stopSpinnerFail(`Validation error: ${msg}`);
|
|
148
|
+
if (attempt < MAX_ATTEMPTS) {
|
|
149
|
+
ui.warning('Please check your key and try again.');
|
|
150
|
+
ui.newLine();
|
|
151
|
+
continue;
|
|
152
|
+
}
|
|
153
|
+
ui.newLine();
|
|
154
|
+
ui.info('You can retry with "nimbus login" or set the API key via environment variable.');
|
|
155
|
+
ui.newLine();
|
|
156
|
+
return;
|
|
157
|
+
}
|
|
158
|
+
if (!validation.valid) {
|
|
159
|
+
ui.stopSpinnerFail(`Invalid key: ${validation.error}`);
|
|
160
|
+
if (attempt < MAX_ATTEMPTS) {
|
|
161
|
+
ui.warning('Please check your key and try again.');
|
|
162
|
+
ui.newLine();
|
|
163
|
+
continue;
|
|
164
|
+
}
|
|
165
|
+
ui.newLine();
|
|
166
|
+
ui.info('You can retry with "nimbus login" or set the API key via environment variable:');
|
|
167
|
+
if (providerInfo.envVarName) {
|
|
168
|
+
ui.info(` export ${providerInfo.envVarName}=your-key`);
|
|
169
|
+
}
|
|
170
|
+
ui.newLine();
|
|
171
|
+
return;
|
|
172
|
+
}
|
|
173
|
+
ui.stopSpinnerSuccess(`${providerInfo.displayName} credentials verified!`);
|
|
174
|
+
validated = true;
|
|
175
|
+
break;
|
|
176
|
+
}
|
|
177
|
+
if (!validated) {
|
|
178
|
+
return;
|
|
179
|
+
}
|
|
180
|
+
}
|
|
181
|
+
else if (providerInfo.supportsBaseUrl) {
|
|
182
|
+
// Ollama — ask for base URL
|
|
183
|
+
ui.newLine();
|
|
184
|
+
baseUrl = await input({
|
|
185
|
+
message: 'Ollama server URL',
|
|
186
|
+
defaultValue: providerInfo.defaultBaseUrl || 'http://localhost:11434',
|
|
187
|
+
});
|
|
188
|
+
}
|
|
189
|
+
// Detect live infra stack from current directory (Terraform, K8s, Helm, etc.)
|
|
190
|
+
let detectedInfraStack = [];
|
|
191
|
+
try {
|
|
192
|
+
const { existsSync, readdirSync } = await import('node:fs');
|
|
193
|
+
const cwd = process.cwd();
|
|
194
|
+
const files = readdirSync(cwd);
|
|
195
|
+
if (files.some(f => f.endsWith('.tf') || f === 'terraform'))
|
|
196
|
+
detectedInfraStack.push('terraform');
|
|
197
|
+
if (files.some(f => f === 'Chart.yaml' || f === 'helmfile.yaml'))
|
|
198
|
+
detectedInfraStack.push('helm');
|
|
199
|
+
if (files.some(f => f.endsWith('.yaml') || f.endsWith('.yml'))) {
|
|
200
|
+
// Check if any yaml looks like K8s
|
|
201
|
+
const yamls = files.filter(f => f.endsWith('.yaml') || f.endsWith('.yml')).slice(0, 5);
|
|
202
|
+
for (const y of yamls) {
|
|
203
|
+
try {
|
|
204
|
+
const txt = require('node:fs').readFileSync(require('node:path').join(cwd, y), 'utf-8');
|
|
205
|
+
if (txt.includes('apiVersion:') && txt.includes('kind:')) {
|
|
206
|
+
detectedInfraStack.push('kubernetes');
|
|
207
|
+
break;
|
|
208
|
+
}
|
|
209
|
+
}
|
|
210
|
+
catch { /* skip */ }
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
if (existsSync(require('node:path').join(cwd, 'docker-compose.yaml')) || existsSync(require('node:path').join(cwd, 'docker-compose.yml')) || existsSync(require('node:path').join(cwd, 'Dockerfile'))) {
|
|
214
|
+
detectedInfraStack.push('docker');
|
|
215
|
+
}
|
|
216
|
+
}
|
|
217
|
+
catch { /* non-critical */ }
|
|
218
|
+
if (detectedInfraStack.length > 0) {
|
|
219
|
+
ui.newLine();
|
|
220
|
+
ui.print(ui.color(`Detected infrastructure: ${detectedInfraStack.join(', ')}`, 'green'));
|
|
221
|
+
ui.print(ui.dim('Nimbus will use this context to give better DevOps assistance.'));
|
|
222
|
+
}
|
|
223
|
+
// C5: Cloud provider selection step
|
|
224
|
+
let primaryClouds = [];
|
|
225
|
+
try {
|
|
226
|
+
const cloudInput = await input({
|
|
227
|
+
message: 'Which cloud providers do you primarily use? (comma-separated: aws, gcp, azure, or none)',
|
|
228
|
+
defaultValue: 'none',
|
|
229
|
+
});
|
|
230
|
+
if (cloudInput && cloudInput.trim().toLowerCase() !== 'none') {
|
|
231
|
+
primaryClouds = cloudInput
|
|
232
|
+
.split(',')
|
|
233
|
+
.map((s) => s.trim().toLowerCase())
|
|
234
|
+
.filter((s) => ['aws', 'gcp', 'azure'].includes(s));
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
catch { /* non-critical — prompt may fail in non-interactive environments */ }
|
|
238
|
+
// Save credentials
|
|
239
|
+
const defaultModel = getDefaultModel(provider);
|
|
240
|
+
store.setProvider(provider, {
|
|
241
|
+
apiKey,
|
|
242
|
+
baseUrl,
|
|
243
|
+
model: defaultModel,
|
|
244
|
+
isDefault: true,
|
|
245
|
+
validatedAt: new Date().toISOString(),
|
|
246
|
+
});
|
|
247
|
+
// Create default config.yaml if it doesn't exist
|
|
248
|
+
try {
|
|
249
|
+
const { configManager } = await import('../config/manager');
|
|
250
|
+
if (!configManager.exists()) {
|
|
251
|
+
configManager.save();
|
|
252
|
+
}
|
|
253
|
+
}
|
|
254
|
+
catch {
|
|
255
|
+
/* non-critical */
|
|
256
|
+
}
|
|
257
|
+
// C5: Save primaryClouds to ~/.nimbus/config.json
|
|
258
|
+
if (primaryClouds.length > 0) {
|
|
259
|
+
try {
|
|
260
|
+
const { existsSync, readFileSync, writeFileSync, mkdirSync } = await import('node:fs');
|
|
261
|
+
const { join } = await import('node:path');
|
|
262
|
+
const { homedir } = await import('node:os');
|
|
263
|
+
const configJsonPath = join(homedir(), '.nimbus', 'config.json');
|
|
264
|
+
mkdirSync(join(homedir(), '.nimbus'), { recursive: true });
|
|
265
|
+
let configData = {};
|
|
266
|
+
if (existsSync(configJsonPath)) {
|
|
267
|
+
try {
|
|
268
|
+
configData = JSON.parse(readFileSync(configJsonPath, 'utf-8'));
|
|
269
|
+
}
|
|
270
|
+
catch { /* start fresh */ }
|
|
271
|
+
}
|
|
272
|
+
configData.primaryClouds = primaryClouds;
|
|
273
|
+
writeFileSync(configJsonPath, JSON.stringify(configData, null, 2), 'utf-8');
|
|
274
|
+
}
|
|
275
|
+
catch { /* non-critical */ }
|
|
276
|
+
}
|
|
277
|
+
// Success message
|
|
278
|
+
ui.newLine();
|
|
279
|
+
ui.box({
|
|
280
|
+
title: 'Setup Complete',
|
|
281
|
+
content: [
|
|
282
|
+
`Provider: ${providerInfo.displayName}`,
|
|
283
|
+
`Model: ${defaultModel}`,
|
|
284
|
+
'',
|
|
285
|
+
"You're ready to go! Starting interactive chat...",
|
|
286
|
+
],
|
|
287
|
+
style: 'rounded',
|
|
288
|
+
borderColor: 'green',
|
|
289
|
+
titleColor: 'brightGreen',
|
|
290
|
+
padding: 1,
|
|
291
|
+
});
|
|
292
|
+
// G3: DevOps context wizard — offer to run nimbus init after LLM setup
|
|
293
|
+
try {
|
|
294
|
+
const devopsSetup = await select({
|
|
295
|
+
message: 'Would you like to set up your DevOps context now? (recommended)',
|
|
296
|
+
options: [
|
|
297
|
+
{ label: 'Yes, detect my infrastructure', value: 'yes' },
|
|
298
|
+
{ label: 'No, I\'ll run nimbus init later', value: 'no' },
|
|
299
|
+
],
|
|
300
|
+
});
|
|
301
|
+
if (devopsSetup === 'yes') {
|
|
302
|
+
ui.newLine();
|
|
303
|
+
ui.startSpinner({ message: 'Detecting infrastructure context...' });
|
|
304
|
+
try {
|
|
305
|
+
const { runInit } = await import('../cli/init');
|
|
306
|
+
await runInit({ cwd: process.cwd(), quiet: false });
|
|
307
|
+
ui.stopSpinnerSuccess('NIMBUS.md generated — your infra context is ready');
|
|
308
|
+
}
|
|
309
|
+
catch (initErr) {
|
|
310
|
+
ui.stopSpinnerFail('Could not generate NIMBUS.md (run `nimbus init` manually)');
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
catch { /* non-critical — prompt may fail in non-interactive environments */ }
|
|
315
|
+
// GAP-4: Offer to install shell completions with clear success/failure feedback
|
|
316
|
+
try {
|
|
317
|
+
ui.newLine();
|
|
318
|
+
const installCompletions = await select({
|
|
319
|
+
message: 'Install shell completions for nimbus? (adds tab completion)',
|
|
320
|
+
options: [
|
|
321
|
+
{ label: 'Yes, install completions', value: 'yes' },
|
|
322
|
+
{ label: 'No, skip', value: 'no' },
|
|
323
|
+
],
|
|
324
|
+
});
|
|
325
|
+
if (installCompletions === 'yes') {
|
|
326
|
+
try {
|
|
327
|
+
const { completionsCommand } = await import('./completions');
|
|
328
|
+
await completionsCommand('install');
|
|
329
|
+
ui.success('Shell completions installed successfully!');
|
|
330
|
+
// Write marker file so nimbus can detect first-run tip
|
|
331
|
+
try {
|
|
332
|
+
const { mkdirSync, writeFileSync } = await import('node:fs');
|
|
333
|
+
const { join } = await import('node:path');
|
|
334
|
+
const { homedir } = await import('node:os');
|
|
335
|
+
mkdirSync(join(homedir(), '.nimbus'), { recursive: true });
|
|
336
|
+
writeFileSync(join(homedir(), '.nimbus', 'completions-installed'), '1', 'utf-8');
|
|
337
|
+
}
|
|
338
|
+
catch { /* non-critical */ }
|
|
339
|
+
}
|
|
340
|
+
catch (completionErr) {
|
|
341
|
+
const shell = process.env.SHELL ?? '';
|
|
342
|
+
ui.warning(`Could not auto-install completions: ${completionErr instanceof Error ? completionErr.message : String(completionErr)}`);
|
|
343
|
+
if (/zsh/.test(shell)) {
|
|
344
|
+
ui.print(ui.dim(' Manual install: nimbus completions install'));
|
|
345
|
+
ui.print(ui.dim(' Then add to ~/.zshrc: fpath=(~/.zsh/completions $fpath) && autoload -U compinit && compinit'));
|
|
346
|
+
}
|
|
347
|
+
else if (/bash/.test(shell)) {
|
|
348
|
+
ui.print(ui.dim(' Manual install: nimbus completions install'));
|
|
349
|
+
}
|
|
350
|
+
else {
|
|
351
|
+
ui.print(ui.dim(' Manual install: nimbus completions install'));
|
|
352
|
+
}
|
|
353
|
+
}
|
|
354
|
+
}
|
|
355
|
+
}
|
|
356
|
+
catch { /* non-critical — prompt may fail in non-interactive environments */ }
|
|
357
|
+
// C3/H1: Optional CI/CD and monitoring env vars
|
|
358
|
+
ui.newLine();
|
|
359
|
+
ui.print(ui.dim('Optional: Set these env vars for full DevOps integration:'));
|
|
360
|
+
ui.print(ui.dim(' GITLAB_TOKEN=<token> # GitLab CI pipeline access'));
|
|
361
|
+
ui.print(ui.dim(' CIRCLECI_TOKEN=<token> # CircleCI pipeline access'));
|
|
362
|
+
ui.print(ui.dim(' PROMETHEUS_URL=<url> # Prometheus metrics queries'));
|
|
363
|
+
ui.print(ui.dim(' GRAFANA_URL=<url> # Grafana dashboard access'));
|
|
364
|
+
ui.print(ui.dim(' GRAFANA_TOKEN=<token> # Grafana API token'));
|
|
365
|
+
ui.print(ui.dim(' DD_API_KEY=<key> # Datadog metrics/alerts'));
|
|
366
|
+
ui.print(ui.dim(' PD_API_KEY=<key> # PagerDuty incident management (Gap 5)'));
|
|
367
|
+
ui.print(ui.dim(' OPSGENIE_API_KEY=<key> # Opsgenie alert management (Gap 5)'));
|
|
368
|
+
ui.print(ui.dim(' BRAVE_API_KEY=<key> # Enhanced web search'));
|
|
369
|
+
ui.newLine();
|
|
370
|
+
}
|
|
371
|
+
catch (err) {
|
|
372
|
+
// Catch-all for prompt failures (stdin closed, terminal not supported, etc.)
|
|
373
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
374
|
+
ui.newLine();
|
|
375
|
+
ui.warning(`Onboarding wizard failed: ${msg}`);
|
|
376
|
+
ui.newLine();
|
|
377
|
+
ui.info('Set up manually with "nimbus login" or via environment variables:');
|
|
378
|
+
ui.print(' export ANTHROPIC_API_KEY=sk-ant-...');
|
|
379
|
+
ui.print(' export OPENAI_API_KEY=sk-...');
|
|
380
|
+
ui.newLine();
|
|
381
|
+
}
|
|
382
|
+
}
|