@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
package/src/cli/init.ts
CHANGED
|
@@ -68,6 +68,11 @@ export interface InitOptions {
|
|
|
68
68
|
force?: boolean;
|
|
69
69
|
/** Suppress all console output */
|
|
70
70
|
quiet?: boolean;
|
|
71
|
+
/**
|
|
72
|
+
* Merge mode (M2): append a ## Local Overrides section to an existing
|
|
73
|
+
* NIMBUS.md and create .nimbus/local.md instead of overwriting the file.
|
|
74
|
+
*/
|
|
75
|
+
merge?: boolean;
|
|
71
76
|
}
|
|
72
77
|
|
|
73
78
|
/** Value returned by {@link runInit} on success */
|
|
@@ -345,6 +350,167 @@ export function detectCloudProviders(dir: string): CloudProvider[] {
|
|
|
345
350
|
return Array.from(found);
|
|
346
351
|
}
|
|
347
352
|
|
|
353
|
+
/** Live infrastructure context gathered by querying actual CLI tools */
|
|
354
|
+
export interface InfraContext {
|
|
355
|
+
terraformWorkspace?: string;
|
|
356
|
+
terraformBackend?: string;
|
|
357
|
+
kubectlContext?: string;
|
|
358
|
+
kubectlClusters?: string[];
|
|
359
|
+
helmReleases?: string[];
|
|
360
|
+
awsAccount?: string;
|
|
361
|
+
awsRegion?: string;
|
|
362
|
+
/** G13: Named AWS profiles from ~/.aws/config (max 10) */
|
|
363
|
+
awsProfiles?: Array<{ profile: string; account?: string; region?: string }>;
|
|
364
|
+
gcpProject?: string;
|
|
365
|
+
/** G16: Number of Kubernetes namespaces in the current cluster */
|
|
366
|
+
k8sNamespaceCount?: number;
|
|
367
|
+
/** G16: Number of Kubernetes deployments across all namespaces */
|
|
368
|
+
k8sDeploymentCount?: number;
|
|
369
|
+
/** CI/CD pipeline system detected in the project directory (G9). */
|
|
370
|
+
cicdPipeline?: string;
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
/**
|
|
374
|
+
* Discover live infrastructure context by querying CLI tools.
|
|
375
|
+
* All queries are best-effort with short timeouts.
|
|
376
|
+
*/
|
|
377
|
+
export async function discoverInfraContext(dir: string): Promise<InfraContext> {
|
|
378
|
+
const { execFileSync } = await import('node:child_process');
|
|
379
|
+
const ctx: InfraContext = {};
|
|
380
|
+
|
|
381
|
+
// Terraform workspace (only if .terraform exists)
|
|
382
|
+
if (exists(path.join(dir, '.terraform'))) {
|
|
383
|
+
try {
|
|
384
|
+
ctx.terraformWorkspace = execFileSync('terraform', ['workspace', 'show'], {
|
|
385
|
+
cwd: dir, encoding: 'utf-8', timeout: 5000, stdio: ['pipe', 'pipe', 'pipe'],
|
|
386
|
+
}).trim();
|
|
387
|
+
} catch { /* ignore */ }
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
// kubectl context
|
|
391
|
+
try {
|
|
392
|
+
ctx.kubectlContext = execFileSync('kubectl', ['config', 'current-context'], {
|
|
393
|
+
encoding: 'utf-8', timeout: 3000, stdio: ['pipe', 'pipe', 'pipe'],
|
|
394
|
+
}).trim();
|
|
395
|
+
const clustersOut = execFileSync('kubectl', ['config', 'get-clusters'], {
|
|
396
|
+
encoding: 'utf-8', timeout: 3000, stdio: ['pipe', 'pipe', 'pipe'],
|
|
397
|
+
});
|
|
398
|
+
ctx.kubectlClusters = clustersOut.split('\n').slice(1).map(s => s.trim()).filter(Boolean);
|
|
399
|
+
} catch { /* ignore */ }
|
|
400
|
+
|
|
401
|
+
// Helm releases
|
|
402
|
+
try {
|
|
403
|
+
const helmOut = execFileSync('helm', ['list', '-A', '--output=json'], {
|
|
404
|
+
encoding: 'utf-8', timeout: 10000, stdio: ['pipe', 'pipe', 'pipe'],
|
|
405
|
+
});
|
|
406
|
+
const releases = JSON.parse(helmOut || '[]') as Array<{ name: string; namespace: string }>;
|
|
407
|
+
ctx.helmReleases = releases.map(r => `${r.name} (${r.namespace})`);
|
|
408
|
+
} catch { /* ignore */ }
|
|
409
|
+
|
|
410
|
+
// AWS account + region
|
|
411
|
+
try {
|
|
412
|
+
const awsIdOut = execFileSync('aws', ['sts', 'get-caller-identity', '--output=json'], {
|
|
413
|
+
encoding: 'utf-8', timeout: 8000, stdio: ['pipe', 'pipe', 'pipe'],
|
|
414
|
+
});
|
|
415
|
+
const awsId = JSON.parse(awsIdOut);
|
|
416
|
+
ctx.awsAccount = awsId.Account;
|
|
417
|
+
} catch { /* ignore */ }
|
|
418
|
+
|
|
419
|
+
try {
|
|
420
|
+
ctx.awsRegion = execFileSync('aws', ['configure', 'get', 'region'], {
|
|
421
|
+
encoding: 'utf-8', timeout: 3000, stdio: ['pipe', 'pipe', 'pipe'],
|
|
422
|
+
}).trim() || process.env.AWS_DEFAULT_REGION;
|
|
423
|
+
} catch {
|
|
424
|
+
ctx.awsRegion = process.env.AWS_DEFAULT_REGION;
|
|
425
|
+
}
|
|
426
|
+
|
|
427
|
+
// G13: Discover all AWS profiles from ~/.aws/config
|
|
428
|
+
try {
|
|
429
|
+
const { readFileSync } = await import('node:fs');
|
|
430
|
+
const { homedir } = await import('node:os');
|
|
431
|
+
const awsConfigPath = path.join(homedir(), '.aws', 'config');
|
|
432
|
+
if (exists(awsConfigPath)) {
|
|
433
|
+
const awsConfig = readFileSync(awsConfigPath, 'utf-8');
|
|
434
|
+
const profiles: Array<{ profile: string; account?: string; region?: string }> = [];
|
|
435
|
+
const profileRegex = /^\[(?:profile\s+)?(\S+)\]/gm;
|
|
436
|
+
let match;
|
|
437
|
+
while ((match = profileRegex.exec(awsConfig)) !== null) {
|
|
438
|
+
const profileName = match[1];
|
|
439
|
+
if (profileName === 'default') continue; // handled separately
|
|
440
|
+
// Extract region from the profile block
|
|
441
|
+
const blockStart = match.index + match[0].length;
|
|
442
|
+
const nextBlock = awsConfig.indexOf('\n[', blockStart);
|
|
443
|
+
const block = awsConfig.slice(blockStart, nextBlock === -1 ? undefined : nextBlock);
|
|
444
|
+
const regionMatch = block.match(/^\s*region\s*=\s*(.+)$/m);
|
|
445
|
+
profiles.push({ profile: profileName, region: regionMatch?.[1]?.trim() });
|
|
446
|
+
}
|
|
447
|
+
if (profiles.length > 0) ctx.awsProfiles = profiles.slice(0, 10); // max 10 profiles
|
|
448
|
+
}
|
|
449
|
+
} catch { /* ignore */ }
|
|
450
|
+
|
|
451
|
+
// GCP project
|
|
452
|
+
try {
|
|
453
|
+
const proj = execFileSync('gcloud', ['config', 'get-value', 'project'], {
|
|
454
|
+
encoding: 'utf-8', timeout: 3000, stdio: ['pipe', 'pipe', 'pipe'],
|
|
455
|
+
}).trim();
|
|
456
|
+
if (proj && proj !== '(unset)') ctx.gcpProject = proj;
|
|
457
|
+
} catch { /* ignore */ }
|
|
458
|
+
|
|
459
|
+
// G16: Count K8s namespaces and deployments
|
|
460
|
+
if (ctx.kubectlContext) {
|
|
461
|
+
try {
|
|
462
|
+
const nsOut = execFileSync('kubectl', ['get', 'namespaces', '--no-headers'], {
|
|
463
|
+
encoding: 'utf-8', timeout: 3000, stdio: ['pipe', 'pipe', 'pipe'],
|
|
464
|
+
});
|
|
465
|
+
const nsCount = nsOut.trim().split('\n').filter(Boolean).length;
|
|
466
|
+
ctx.k8sNamespaceCount = nsCount;
|
|
467
|
+
} catch { /* ignore */ }
|
|
468
|
+
try {
|
|
469
|
+
const deplOut = execFileSync('kubectl', ['get', 'deployments', '-A', '--no-headers'], {
|
|
470
|
+
encoding: 'utf-8', timeout: 3000, stdio: ['pipe', 'pipe', 'pipe'],
|
|
471
|
+
});
|
|
472
|
+
const deplCount = deplOut.trim().split('\n').filter(Boolean).length;
|
|
473
|
+
ctx.k8sDeploymentCount = deplCount;
|
|
474
|
+
} catch { /* ignore */ }
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
// CI/CD pipeline detection (G9)
|
|
478
|
+
const cicdFiles: Array<[string, string]> = [
|
|
479
|
+
['.github/workflows', 'GitHub Actions'],
|
|
480
|
+
['.gitlab-ci.yml', 'GitLab CI'],
|
|
481
|
+
['.circleci', 'CircleCI'],
|
|
482
|
+
['Jenkinsfile', 'Jenkins'],
|
|
483
|
+
['.buildkite', 'Buildkite'],
|
|
484
|
+
['azure-pipelines.yml', 'Azure Pipelines'],
|
|
485
|
+
];
|
|
486
|
+
for (const [file, name] of cicdFiles) {
|
|
487
|
+
if (exists(path.join(dir, file))) {
|
|
488
|
+
ctx.cicdPipeline = name;
|
|
489
|
+
break;
|
|
490
|
+
}
|
|
491
|
+
}
|
|
492
|
+
|
|
493
|
+
return ctx;
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
/**
|
|
497
|
+
* Format an InfraContext into a compact single-line summary for injection
|
|
498
|
+
* into agent messages (Gaps 7 & 10).
|
|
499
|
+
*/
|
|
500
|
+
export function formatInfraContext(ctx: InfraContext): string {
|
|
501
|
+
const parts: string[] = [];
|
|
502
|
+
if (ctx.terraformWorkspace) parts.push(`tf-workspace: ${ctx.terraformWorkspace}`);
|
|
503
|
+
if (ctx.kubectlContext) parts.push(`k8s-context: ${ctx.kubectlContext}`);
|
|
504
|
+
if (ctx.helmReleases && ctx.helmReleases.length > 0) {
|
|
505
|
+
parts.push(`helm-releases: ${ctx.helmReleases.slice(0, 3).join(', ')}${ctx.helmReleases.length > 3 ? ` +${ctx.helmReleases.length - 3} more` : ''}`);
|
|
506
|
+
}
|
|
507
|
+
if (ctx.awsAccount) parts.push(`aws-account: ${ctx.awsAccount}`);
|
|
508
|
+
if (ctx.awsRegion) parts.push(`aws-region: ${ctx.awsRegion}`);
|
|
509
|
+
if (ctx.gcpProject) parts.push(`gcp-project: ${ctx.gcpProject}`);
|
|
510
|
+
if (ctx.cicdPipeline) parts.push(`cicd: ${ctx.cicdPipeline}`);
|
|
511
|
+
return parts.length > 0 ? parts.join(' | ') : 'no infra context detected';
|
|
512
|
+
}
|
|
513
|
+
|
|
348
514
|
/**
|
|
349
515
|
* Detect which Node.js package manager is used in `dir`.
|
|
350
516
|
*
|
|
@@ -563,7 +729,7 @@ export function detectProject(dir: string): ProjectDetection {
|
|
|
563
729
|
* The generated markdown serves as both human-readable documentation
|
|
564
730
|
* and machine-readable project metadata for the Nimbus agent.
|
|
565
731
|
*/
|
|
566
|
-
export function generateNimbusMd(detection: ProjectDetection, _dir: string): string {
|
|
732
|
+
export function generateNimbusMd(detection: ProjectDetection, _dir: string, infraCtx?: InfraContext): string {
|
|
567
733
|
const lines: string[] = [];
|
|
568
734
|
|
|
569
735
|
// --- Header ---
|
|
@@ -597,6 +763,57 @@ export function generateNimbusMd(detection: ProjectDetection, _dir: string): str
|
|
|
597
763
|
if (detection.cloudProviders.length > 0) {
|
|
598
764
|
lines.push(`- **Cloud Providers:** ${detection.cloudProviders.join(', ')}`);
|
|
599
765
|
}
|
|
766
|
+
if (infraCtx) {
|
|
767
|
+
if (infraCtx.terraformWorkspace) {
|
|
768
|
+
lines.push(`- **Terraform Workspace:** ${infraCtx.terraformWorkspace}`);
|
|
769
|
+
}
|
|
770
|
+
if (infraCtx.kubectlContext) {
|
|
771
|
+
lines.push(`- **Kubernetes Context:** ${infraCtx.kubectlContext}`);
|
|
772
|
+
}
|
|
773
|
+
if (infraCtx.kubectlClusters && infraCtx.kubectlClusters.length > 0) {
|
|
774
|
+
lines.push(`- **Kubernetes Clusters:** ${infraCtx.kubectlClusters.join(', ')}`);
|
|
775
|
+
}
|
|
776
|
+
if (infraCtx.helmReleases && infraCtx.helmReleases.length > 0) {
|
|
777
|
+
lines.push(`- **Helm Releases:** ${infraCtx.helmReleases.slice(0, 5).join(', ')}${infraCtx.helmReleases.length > 5 ? ` (+${infraCtx.helmReleases.length - 5} more)` : ''}`);
|
|
778
|
+
}
|
|
779
|
+
if (infraCtx.awsAccount) {
|
|
780
|
+
lines.push(`- **AWS Account:** ${infraCtx.awsAccount}${infraCtx.awsRegion ? ` (${infraCtx.awsRegion})` : ''}`);
|
|
781
|
+
}
|
|
782
|
+
// G13: List named AWS profiles
|
|
783
|
+
if (infraCtx.awsProfiles && infraCtx.awsProfiles.length > 0) {
|
|
784
|
+
lines.push(`- **AWS Profiles:** ${infraCtx.awsProfiles.map(p => p.profile).join(', ')}`);
|
|
785
|
+
}
|
|
786
|
+
if (infraCtx.gcpProject) {
|
|
787
|
+
lines.push(`- **GCP Project:** ${infraCtx.gcpProject}`);
|
|
788
|
+
}
|
|
789
|
+
// G16: K8s namespace and deployment counts
|
|
790
|
+
if (infraCtx.k8sNamespaceCount !== undefined) {
|
|
791
|
+
lines.push(`- **K8s Namespaces:** ${infraCtx.k8sNamespaceCount}`);
|
|
792
|
+
}
|
|
793
|
+
if (infraCtx.k8sDeploymentCount !== undefined) {
|
|
794
|
+
lines.push(`- **K8s Deployments:** ${infraCtx.k8sDeploymentCount}`);
|
|
795
|
+
}
|
|
796
|
+
// G9: CI/CD pipeline
|
|
797
|
+
if (infraCtx.cicdPipeline) {
|
|
798
|
+
lines.push(`- **CI/CD:** ${infraCtx.cicdPipeline}`);
|
|
799
|
+
}
|
|
800
|
+
}
|
|
801
|
+
lines.push('');
|
|
802
|
+
}
|
|
803
|
+
|
|
804
|
+
// --- CI/CD (M4) ---
|
|
805
|
+
if (infraCtx?.cicdPipeline) {
|
|
806
|
+
lines.push('## CI/CD');
|
|
807
|
+
lines.push('');
|
|
808
|
+
const pipelineDir: Record<string, string> = {
|
|
809
|
+
'GitHub Actions': '.github/workflows/',
|
|
810
|
+
'GitLab CI': '.gitlab-ci.yml',
|
|
811
|
+
'CircleCI': '.circleci/',
|
|
812
|
+
'Jenkins': 'Jenkinsfile',
|
|
813
|
+
};
|
|
814
|
+
const pipelinePath = pipelineDir[infraCtx.cicdPipeline] ?? '';
|
|
815
|
+
lines.push(`Pipeline: ${infraCtx.cicdPipeline}${pipelinePath ? ` (${pipelinePath})` : ''}`);
|
|
816
|
+
lines.push('Convention: Always run `terraform plan` in CI before apply. Apply only on main branch merge.');
|
|
600
817
|
lines.push('');
|
|
601
818
|
}
|
|
602
819
|
|
|
@@ -613,6 +830,16 @@ export function generateNimbusMd(detection: ProjectDetection, _dir: string): str
|
|
|
613
830
|
lines.push('');
|
|
614
831
|
}
|
|
615
832
|
|
|
833
|
+
// --- Environments (GAP-22) ---
|
|
834
|
+
lines.push('## Environments');
|
|
835
|
+
lines.push('');
|
|
836
|
+
lines.push('| Name | Terraform Workspace | Kubernetes Context | Protected |');
|
|
837
|
+
lines.push('|------|--------------------|--------------------|-----------|');
|
|
838
|
+
lines.push('| dev | dev | | false |');
|
|
839
|
+
lines.push('| staging | staging | | false |');
|
|
840
|
+
lines.push('| prod | prod | | true |');
|
|
841
|
+
lines.push('');
|
|
842
|
+
|
|
616
843
|
// --- Safety Rules ---
|
|
617
844
|
lines.push('## Safety Rules');
|
|
618
845
|
lines.push('');
|
|
@@ -623,12 +850,52 @@ export function generateNimbusMd(detection: ProjectDetection, _dir: string): str
|
|
|
623
850
|
lines.push('- Never store secrets in source control');
|
|
624
851
|
lines.push('');
|
|
625
852
|
|
|
853
|
+
// --- Guardrails (G5): DevOps-specific rules when infra is detected ---
|
|
854
|
+
const hasInfra = detection.infraTypes.length > 0 || detection.cloudProviders.length > 0;
|
|
855
|
+
if (hasInfra) {
|
|
856
|
+
lines.push('## Guardrails');
|
|
857
|
+
lines.push('');
|
|
858
|
+
lines.push('- Never run `terraform destroy` without explicit confirmation');
|
|
859
|
+
lines.push('- Protected Kubernetes namespaces: `production`, `kube-system`, `monitoring`');
|
|
860
|
+
lines.push('- Always show terraform plan before apply');
|
|
861
|
+
lines.push('- Confirm target cloud account and region before resource creation');
|
|
862
|
+
lines.push('- Protected environments: any workspace/namespace containing `prod`, `prd`, `production`');
|
|
863
|
+
lines.push('');
|
|
864
|
+
}
|
|
865
|
+
|
|
866
|
+
// --- Forbidden placeholder (G5) ---
|
|
867
|
+
lines.push('## Forbidden');
|
|
868
|
+
lines.push('');
|
|
869
|
+
lines.push('<!-- List operations Nimbus must never perform in this project -->');
|
|
870
|
+
lines.push('<!-- Example: - Never destroy the production database -->');
|
|
871
|
+
lines.push('');
|
|
872
|
+
|
|
626
873
|
// --- Custom Instructions ---
|
|
627
874
|
lines.push('## Custom Instructions');
|
|
628
875
|
lines.push('');
|
|
629
876
|
lines.push('<!-- Add project-specific instructions for the Nimbus agent here -->');
|
|
630
877
|
lines.push('');
|
|
631
878
|
|
|
879
|
+
// --- G18: Runbooks ---
|
|
880
|
+
const runbookDirs = ['docs/runbooks', 'runbooks', '.github/runbooks', '.nimbus/runbooks'];
|
|
881
|
+
const foundRunbooks: string[] = [];
|
|
882
|
+
for (const dir of runbookDirs) {
|
|
883
|
+
const fullPath = path.join(_dir, dir);
|
|
884
|
+
if (fs.existsSync(fullPath)) {
|
|
885
|
+
try {
|
|
886
|
+
const files = fs.readdirSync(fullPath).filter(f => /\.(md|yaml|yml)$/.test(f));
|
|
887
|
+
foundRunbooks.push(...files.map(f => `- ${dir}/${f}`));
|
|
888
|
+
} catch { /* non-critical */ }
|
|
889
|
+
}
|
|
890
|
+
}
|
|
891
|
+
const runbookSection = foundRunbooks.length > 0
|
|
892
|
+
? foundRunbooks.join('\n') + '\n\nRefer to these runbooks for incident response and operational procedures.'
|
|
893
|
+
: '<!-- Add runbook references, e.g.:\n- docs/runbooks/cert-rotation.md -->';
|
|
894
|
+
lines.push('## Runbooks');
|
|
895
|
+
lines.push('');
|
|
896
|
+
lines.push(runbookSection);
|
|
897
|
+
lines.push('');
|
|
898
|
+
|
|
632
899
|
return lines.join('\n');
|
|
633
900
|
}
|
|
634
901
|
|
|
@@ -721,6 +988,7 @@ export async function runInit(options?: InitOptions): Promise<InitResult> {
|
|
|
721
988
|
const dir = path.resolve(options?.cwd ?? process.cwd());
|
|
722
989
|
const force = options?.force ?? false;
|
|
723
990
|
const quiet = options?.quiet ?? false;
|
|
991
|
+
const merge = options?.merge ?? false;
|
|
724
992
|
|
|
725
993
|
const log = (msg: string): void => {
|
|
726
994
|
if (!quiet) {
|
|
@@ -728,6 +996,31 @@ export async function runInit(options?: InitOptions): Promise<InitResult> {
|
|
|
728
996
|
}
|
|
729
997
|
};
|
|
730
998
|
|
|
999
|
+
// ---- M2: --merge mode — append Local Overrides section, don't overwrite ----
|
|
1000
|
+
const nimbusmdPathEarly = path.join(dir, 'NIMBUS.md');
|
|
1001
|
+
if (merge && exists(nimbusmdPathEarly)) {
|
|
1002
|
+
const content = fs.readFileSync(nimbusmdPathEarly, 'utf-8');
|
|
1003
|
+
const filesCreated: string[] = [];
|
|
1004
|
+
|
|
1005
|
+
if (!content.includes('## Local Overrides')) {
|
|
1006
|
+
fs.appendFileSync(nimbusmdPathEarly, '\n\n## Local Overrides\n\n<!-- Personal additions -->\n', 'utf-8');
|
|
1007
|
+
log(' Appended ## Local Overrides section to NIMBUS.md');
|
|
1008
|
+
} else {
|
|
1009
|
+
log(' NIMBUS.md already has a ## Local Overrides section');
|
|
1010
|
+
}
|
|
1011
|
+
|
|
1012
|
+
const localMdPath = path.join(dir, '.nimbus', 'local.md');
|
|
1013
|
+
if (!exists(localMdPath)) {
|
|
1014
|
+
fs.mkdirSync(path.join(dir, '.nimbus'), { recursive: true });
|
|
1015
|
+
fs.writeFileSync(localMdPath, '# Local Overrides\n\n<!-- Personal notes and overrides that are not committed -->\n', 'utf-8');
|
|
1016
|
+
log(' Created .nimbus/local.md for personal overrides');
|
|
1017
|
+
filesCreated.push(localMdPath);
|
|
1018
|
+
}
|
|
1019
|
+
|
|
1020
|
+
const detection = detectProject(dir);
|
|
1021
|
+
return { detection, filesCreated, nimbusmdPath: nimbusmdPathEarly };
|
|
1022
|
+
}
|
|
1023
|
+
|
|
731
1024
|
// ---- Step 1: Detect project characteristics ----
|
|
732
1025
|
log('Detecting project...');
|
|
733
1026
|
const detection = detectProject(dir);
|
|
@@ -746,10 +1039,62 @@ export async function runInit(options?: InitOptions): Promise<InitResult> {
|
|
|
746
1039
|
log(` Test framework: ${detection.testFramework}`);
|
|
747
1040
|
}
|
|
748
1041
|
|
|
749
|
-
// ---- Step 2: Check for existing NIMBUS.md ----
|
|
1042
|
+
// ---- Step 2: Check for existing NIMBUS.md and show diff (L8) ----
|
|
750
1043
|
const nimbusmdPath = path.join(dir, 'NIMBUS.md');
|
|
751
|
-
if (exists(nimbusmdPath) && !force) {
|
|
752
|
-
|
|
1044
|
+
if (exists(nimbusmdPath) && !force && !quiet) {
|
|
1045
|
+
// Generate the new content first for diffing
|
|
1046
|
+
const infraCtxForDiff = await discoverInfraContext(dir).catch(() => undefined);
|
|
1047
|
+
const newContent = generateNimbusMd(detection, dir, infraCtxForDiff);
|
|
1048
|
+
const existingContent = readText(nimbusmdPath);
|
|
1049
|
+
|
|
1050
|
+
if (newContent === existingContent) {
|
|
1051
|
+
log('NIMBUS.md is already up to date.');
|
|
1052
|
+
return { detection, filesCreated: [], nimbusmdPath };
|
|
1053
|
+
}
|
|
1054
|
+
|
|
1055
|
+
// Show line-level diff
|
|
1056
|
+
const oldLines = existingContent.split('\n');
|
|
1057
|
+
const newLines = newContent.split('\n');
|
|
1058
|
+
const diffLines: string[] = [];
|
|
1059
|
+
const maxLen = Math.max(oldLines.length, newLines.length);
|
|
1060
|
+
for (let idx = 0; idx < maxLen; idx++) {
|
|
1061
|
+
const o = oldLines[idx];
|
|
1062
|
+
const n = newLines[idx];
|
|
1063
|
+
if (o === undefined) diffLines.push(`+ ${n}`);
|
|
1064
|
+
else if (n === undefined) diffLines.push(`- ${o}`);
|
|
1065
|
+
else if (o !== n) { diffLines.push(`- ${o}`); diffLines.push(`+ ${n}`); }
|
|
1066
|
+
}
|
|
1067
|
+
|
|
1068
|
+
if (diffLines.length > 0) {
|
|
1069
|
+
log('\nNIMBUS.md changes:');
|
|
1070
|
+
for (const dl of diffLines.slice(0, 50)) {
|
|
1071
|
+
if (dl.startsWith('+')) log(` \x1b[32m${dl}\x1b[0m`);
|
|
1072
|
+
else if (dl.startsWith('-')) log(` \x1b[31m${dl}\x1b[0m`);
|
|
1073
|
+
else log(` ${dl}`);
|
|
1074
|
+
}
|
|
1075
|
+
if (diffLines.length > 50) log(` ... and ${diffLines.length - 50} more changes`);
|
|
1076
|
+
log('');
|
|
1077
|
+
log('Apply these changes? [y/N]');
|
|
1078
|
+
|
|
1079
|
+
// Synchronous readline for non-quiet mode
|
|
1080
|
+
const answer = await new Promise<string>(resolve => {
|
|
1081
|
+
const { createInterface } = require('readline') as typeof import('readline');
|
|
1082
|
+
const rl = createInterface({ input: process.stdin, output: process.stdout });
|
|
1083
|
+
rl.question('', (ans: string) => { rl.close(); resolve(ans.trim()); });
|
|
1084
|
+
});
|
|
1085
|
+
|
|
1086
|
+
if (answer.toLowerCase() !== 'y') {
|
|
1087
|
+
log('Aborted — NIMBUS.md not changed.');
|
|
1088
|
+
return { detection, filesCreated: [], nimbusmdPath };
|
|
1089
|
+
}
|
|
1090
|
+
|
|
1091
|
+
fs.writeFileSync(nimbusmdPath, newContent, 'utf-8');
|
|
1092
|
+
log(' Updated NIMBUS.md');
|
|
1093
|
+
return { detection, filesCreated: [nimbusmdPath], nimbusmdPath };
|
|
1094
|
+
}
|
|
1095
|
+
} else if (exists(nimbusmdPath) && !force) {
|
|
1096
|
+
// quiet mode — skip without prompting
|
|
1097
|
+
return { detection, filesCreated: [], nimbusmdPath };
|
|
753
1098
|
}
|
|
754
1099
|
|
|
755
1100
|
// ---- Step 3: Create .nimbus/ directory structure ----
|
|
@@ -827,7 +1172,25 @@ export async function runInit(options?: InitOptions): Promise<InitResult> {
|
|
|
827
1172
|
}
|
|
828
1173
|
|
|
829
1174
|
// ---- Step 7: Generate and write NIMBUS.md ----
|
|
830
|
-
|
|
1175
|
+
// L8: Monorepo detection — scan immediate subdirs for terraform roots
|
|
1176
|
+
let monorepoSection = '';
|
|
1177
|
+
try {
|
|
1178
|
+
const subdirs = fs.readdirSync(dir, { withFileTypes: true })
|
|
1179
|
+
.filter(e => e.isDirectory() && !e.name.startsWith('.') && !['node_modules', '.git'].includes(e.name))
|
|
1180
|
+
.map(e => e.name);
|
|
1181
|
+
const tfRoots: string[] = [];
|
|
1182
|
+
for (const sub of subdirs.slice(0, 20)) {
|
|
1183
|
+
const subPath = path.join(dir, sub);
|
|
1184
|
+
const hasTf = fs.readdirSync(subPath).some(f => f.endsWith('.tf'));
|
|
1185
|
+
if (hasTf) tfRoots.push(sub);
|
|
1186
|
+
}
|
|
1187
|
+
if (tfRoots.length > 1) {
|
|
1188
|
+
monorepoSection = `\n## Terraform Modules (Monorepo)\n\nThis is a monorepo with multiple Terraform roots:\n${tfRoots.map(r => `- \`./${r}/\``).join('\n')}\n\nTo target a specific root, \`cd\` into the directory or specify the path.\n`;
|
|
1189
|
+
log(` Detected ${tfRoots.length} Terraform roots (monorepo)`);
|
|
1190
|
+
}
|
|
1191
|
+
} catch { /* non-critical */ }
|
|
1192
|
+
|
|
1193
|
+
const nimbusmdContent = generateNimbusMd(detection, dir) + monorepoSection;
|
|
831
1194
|
fs.writeFileSync(nimbusmdPath, nimbusmdContent, 'utf-8');
|
|
832
1195
|
filesCreated.push(nimbusmdPath);
|
|
833
1196
|
log(' Created NIMBUS.md');
|
|
@@ -846,6 +1209,16 @@ export async function runInit(options?: InitOptions): Promise<InitResult> {
|
|
|
846
1209
|
log('Nimbus project initialized successfully.');
|
|
847
1210
|
log('Edit NIMBUS.md to customise agent behaviour.');
|
|
848
1211
|
|
|
1212
|
+
// M5: Print next steps after generating NIMBUS.md
|
|
1213
|
+
if (!quiet) {
|
|
1214
|
+
log('');
|
|
1215
|
+
log('\x1b[36mNext steps:\x1b[0m');
|
|
1216
|
+
log(' nimbus plan Preview infrastructure changes');
|
|
1217
|
+
log(' nimbus doctor Check your DevOps toolchain');
|
|
1218
|
+
log(' nimbus status Live infrastructure health dashboard');
|
|
1219
|
+
log(' nimbus Open the interactive DevOps agent');
|
|
1220
|
+
}
|
|
1221
|
+
|
|
849
1222
|
return {
|
|
850
1223
|
detection,
|
|
851
1224
|
filesCreated,
|