@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
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* tests run entirely in-memory and complete in milliseconds.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import { describe, it, expect } from '
|
|
12
|
+
import { describe, it, expect } from 'vitest';
|
|
13
13
|
import { TerraformProjectGenerator, type TerraformProjectConfig } from '../generator/terraform';
|
|
14
14
|
import {
|
|
15
15
|
KubernetesGenerator,
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Helm Streaming Tests — G10
|
|
3
|
+
*
|
|
4
|
+
* Verifies that:
|
|
5
|
+
* 1. devops.ts defines the HELM_STREAMING_ACTIONS set with the correct members
|
|
6
|
+
* 2. spawnExec is imported (not execAsync) for streaming actions
|
|
7
|
+
* 3. The helmTool.execute() calls spawnExec for upgrade/install actions
|
|
8
|
+
*
|
|
9
|
+
* The functional test mocks both spawnExec and the execAsync (helm repo update)
|
|
10
|
+
* by mocking 'node:child_process' at the top level.
|
|
11
|
+
*/
|
|
12
|
+
|
|
13
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
14
|
+
import { readFileSync } from 'node:fs';
|
|
15
|
+
import { join } from 'node:path';
|
|
16
|
+
|
|
17
|
+
const DEVOPS_SRC = readFileSync(join(__dirname, '..', 'tools', 'schemas', 'devops.ts'), 'utf-8');
|
|
18
|
+
|
|
19
|
+
// ---------------------------------------------------------------------------
|
|
20
|
+
// Top-level mocks — must be hoisted by vitest before imports
|
|
21
|
+
// ---------------------------------------------------------------------------
|
|
22
|
+
|
|
23
|
+
// Mock spawnExec so streaming helm actions don't attempt real shell calls
|
|
24
|
+
vi.mock('../tools/spawn-exec', () => ({
|
|
25
|
+
spawnExec: vi.fn().mockResolvedValue({ stdout: 'Release deployed successfully', stderr: '', exitCode: 0 }),
|
|
26
|
+
}));
|
|
27
|
+
|
|
28
|
+
// Mock node:child_process exec so execAsync('helm repo update') doesn't fail
|
|
29
|
+
vi.mock('node:child_process', async () => {
|
|
30
|
+
const actual = await vi.importActual<typeof import('node:child_process')>('node:child_process');
|
|
31
|
+
return {
|
|
32
|
+
...actual,
|
|
33
|
+
exec: vi.fn((cmd: string, opts: unknown, cb?: (err: null, result: { stdout: string; stderr: string }) => void) => {
|
|
34
|
+
// Handle promisify(exec) — callback style
|
|
35
|
+
const callback = typeof opts === 'function' ? opts : cb;
|
|
36
|
+
if (typeof callback === 'function') {
|
|
37
|
+
(callback as (err: null, result: { stdout: string; stderr: string }) => void)(null, { stdout: '', stderr: '' });
|
|
38
|
+
}
|
|
39
|
+
return { on: vi.fn(), stdout: { on: vi.fn() }, stderr: { on: vi.fn() } };
|
|
40
|
+
}),
|
|
41
|
+
};
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
// ---------------------------------------------------------------------------
|
|
45
|
+
// Source-level assertions (G10)
|
|
46
|
+
// ---------------------------------------------------------------------------
|
|
47
|
+
|
|
48
|
+
describe('HELM_STREAMING_ACTIONS constant in devops.ts (G10)', () => {
|
|
49
|
+
it('devops.ts defines HELM_STREAMING_ACTIONS', () => {
|
|
50
|
+
expect(DEVOPS_SRC).toContain('HELM_STREAMING_ACTIONS');
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
it('HELM_STREAMING_ACTIONS includes install', () => {
|
|
54
|
+
const setDefMatch = DEVOPS_SRC.match(/HELM_STREAMING_ACTIONS\s*=\s*new Set\(\[([^\]]+)\]\)/);
|
|
55
|
+
expect(setDefMatch).not.toBeNull();
|
|
56
|
+
expect(setDefMatch![1]).toContain('install');
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
it('HELM_STREAMING_ACTIONS includes upgrade', () => {
|
|
60
|
+
const setDefMatch = DEVOPS_SRC.match(/HELM_STREAMING_ACTIONS\s*=\s*new Set\(\[([^\]]+)\]\)/);
|
|
61
|
+
expect(setDefMatch).not.toBeNull();
|
|
62
|
+
expect(setDefMatch![1]).toContain('upgrade');
|
|
63
|
+
});
|
|
64
|
+
|
|
65
|
+
it('HELM_STREAMING_ACTIONS includes rollback', () => {
|
|
66
|
+
const setDefMatch = DEVOPS_SRC.match(/HELM_STREAMING_ACTIONS\s*=\s*new Set\(\[([^\]]+)\]\)/);
|
|
67
|
+
expect(setDefMatch).not.toBeNull();
|
|
68
|
+
expect(setDefMatch![1]).toContain('rollback');
|
|
69
|
+
});
|
|
70
|
+
|
|
71
|
+
it('HELM_STREAMING_ACTIONS includes uninstall', () => {
|
|
72
|
+
const setDefMatch = DEVOPS_SRC.match(/HELM_STREAMING_ACTIONS\s*=\s*new Set\(\[([^\]]+)\]\)/);
|
|
73
|
+
expect(setDefMatch).not.toBeNull();
|
|
74
|
+
expect(setDefMatch![1]).toContain('uninstall');
|
|
75
|
+
});
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
describe('spawnExec is imported in devops.ts (G10)', () => {
|
|
79
|
+
it('devops.ts imports spawnExec from spawn-exec', () => {
|
|
80
|
+
expect(DEVOPS_SRC).toContain("import { spawnExec } from '../spawn-exec'");
|
|
81
|
+
});
|
|
82
|
+
|
|
83
|
+
it('devops.ts uses spawnExec for helm streaming actions (not only execAsync)', () => {
|
|
84
|
+
expect(DEVOPS_SRC).toContain('await spawnExec(command');
|
|
85
|
+
});
|
|
86
|
+
|
|
87
|
+
it('helm streaming block checks HELM_STREAMING_ACTIONS.has(input.action)', () => {
|
|
88
|
+
expect(DEVOPS_SRC).toContain('HELM_STREAMING_ACTIONS.has(input.action)');
|
|
89
|
+
});
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
// ---------------------------------------------------------------------------
|
|
93
|
+
// Functional test: spawnExec mock for streaming action
|
|
94
|
+
// ---------------------------------------------------------------------------
|
|
95
|
+
|
|
96
|
+
describe('helmTool routes to spawnExec for streaming actions (G10)', () => {
|
|
97
|
+
afterEach(() => {
|
|
98
|
+
vi.clearAllMocks();
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
it('calls spawnExec for upgrade action and returns success', async () => {
|
|
102
|
+
const { spawnExec } = await import('../tools/spawn-exec');
|
|
103
|
+
const { helmTool } = await import('../tools/schemas/devops');
|
|
104
|
+
|
|
105
|
+
const result = await helmTool.execute(
|
|
106
|
+
{ action: 'upgrade', release: 'myapp', chart: 'stable/nginx', namespace: 'default' },
|
|
107
|
+
undefined,
|
|
108
|
+
);
|
|
109
|
+
|
|
110
|
+
expect(spawnExec).toHaveBeenCalled();
|
|
111
|
+
expect(result.isError).toBe(false);
|
|
112
|
+
expect(result.output).toContain('deployed successfully');
|
|
113
|
+
});
|
|
114
|
+
|
|
115
|
+
it('calls spawnExec for install action and returns success', async () => {
|
|
116
|
+
const { spawnExec } = await import('../tools/spawn-exec');
|
|
117
|
+
const { helmTool } = await import('../tools/schemas/devops');
|
|
118
|
+
|
|
119
|
+
const result = await helmTool.execute(
|
|
120
|
+
{ action: 'install', release: 'myapp', chart: 'bitnami/nginx' },
|
|
121
|
+
undefined,
|
|
122
|
+
);
|
|
123
|
+
|
|
124
|
+
expect(spawnExec).toHaveBeenCalled();
|
|
125
|
+
expect(result.isError).toBe(false);
|
|
126
|
+
});
|
|
127
|
+
});
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* with real hook scripts and hooks.yaml configuration files.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import { describe, test, expect, beforeEach, afterEach } from '
|
|
12
|
+
import { describe, test, expect, beforeEach, afterEach } from 'vitest';
|
|
13
13
|
import * as fs from 'node:fs';
|
|
14
14
|
import * as path from 'node:path';
|
|
15
15
|
import * as os from 'node:os';
|
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Incident Command Tests — G14
|
|
3
|
+
*
|
|
4
|
+
* Tests parseIncidentInput (internal logic), PD_API_TOKEN guard,
|
|
5
|
+
* detectServiceName logic, and overall incidentCommand integration.
|
|
6
|
+
*
|
|
7
|
+
* Because parseIncidentInput and detectServiceName are not exported,
|
|
8
|
+
* we test via inline reproductions of the same logic and source-level
|
|
9
|
+
* assertions.
|
|
10
|
+
*/
|
|
11
|
+
|
|
12
|
+
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
|
|
13
|
+
import { readFileSync } from 'node:fs';
|
|
14
|
+
import { join } from 'node:path';
|
|
15
|
+
|
|
16
|
+
const INCIDENT_SRC = readFileSync(join(__dirname, '..', 'commands', 'incident.ts'), 'utf-8');
|
|
17
|
+
|
|
18
|
+
// ---------------------------------------------------------------------------
|
|
19
|
+
// Source-level assertions
|
|
20
|
+
// ---------------------------------------------------------------------------
|
|
21
|
+
|
|
22
|
+
describe('incident.ts source structure (G14)', () => {
|
|
23
|
+
it('defines parseIncidentInput function', () => {
|
|
24
|
+
expect(INCIDENT_SRC).toContain('function parseIncidentInput');
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
it('detects PagerDuty URLs via pagerduty.com regex', () => {
|
|
28
|
+
expect(INCIDENT_SRC).toContain('pagerduty\\.com');
|
|
29
|
+
});
|
|
30
|
+
|
|
31
|
+
it('detects Opsgenie URLs via opsgenie.com regex', () => {
|
|
32
|
+
expect(INCIDENT_SRC).toContain('opsgenie\\.com');
|
|
33
|
+
});
|
|
34
|
+
|
|
35
|
+
it('reads PD_API_TOKEN from process.env before fetch', () => {
|
|
36
|
+
expect(INCIDENT_SRC).toContain('PD_API_TOKEN');
|
|
37
|
+
});
|
|
38
|
+
|
|
39
|
+
it('defines detectServiceName function', () => {
|
|
40
|
+
expect(INCIDENT_SRC).toContain('function detectServiceName');
|
|
41
|
+
});
|
|
42
|
+
|
|
43
|
+
it('exports incidentCommand', () => {
|
|
44
|
+
expect(INCIDENT_SRC).toContain('export async function incidentCommand');
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
it('fetchPagerDutyDetails returns null immediately when no token is set', () => {
|
|
48
|
+
// Verify the guard is present in source
|
|
49
|
+
expect(INCIDENT_SRC).toContain('if (!token) return null');
|
|
50
|
+
});
|
|
51
|
+
});
|
|
52
|
+
|
|
53
|
+
// ---------------------------------------------------------------------------
|
|
54
|
+
// Inline reproduction of parseIncidentInput to unit-test logic (G14)
|
|
55
|
+
// ---------------------------------------------------------------------------
|
|
56
|
+
|
|
57
|
+
type AlertSource = 'pagerduty' | 'opsgenie' | 'plain';
|
|
58
|
+
interface ParsedIncident { source: AlertSource; id: string; rawInput: string; }
|
|
59
|
+
|
|
60
|
+
function parseIncidentInput(input: string): ParsedIncident {
|
|
61
|
+
if (/pagerduty\.com/i.test(input)) {
|
|
62
|
+
const match = input.match(/incidents?\/(P[A-Z0-9]+)/i);
|
|
63
|
+
return { source: 'pagerduty', id: match?.[1] ?? input, rawInput: input };
|
|
64
|
+
}
|
|
65
|
+
if (/opsgenie\.com/i.test(input) || /app\.opsgenie\.com/i.test(input)) {
|
|
66
|
+
const match = input.match(/alert\/([a-f0-9-]{36})/i);
|
|
67
|
+
return { source: 'opsgenie', id: match?.[1] ?? input, rawInput: input };
|
|
68
|
+
}
|
|
69
|
+
return { source: 'plain', id: input, rawInput: input };
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
describe('parseIncidentInput logic (G14)', () => {
|
|
73
|
+
it('returns source=pagerduty for a PagerDuty URL', () => {
|
|
74
|
+
const result = parseIncidentInput('https://acme.pagerduty.com/incidents/PABC123');
|
|
75
|
+
expect(result.source).toBe('pagerduty');
|
|
76
|
+
expect(result.id).toBe('PABC123');
|
|
77
|
+
});
|
|
78
|
+
|
|
79
|
+
it('returns source=opsgenie for an Opsgenie URL', () => {
|
|
80
|
+
const uuid = 'a1b2c3d4-e5f6-7890-abcd-ef1234567890';
|
|
81
|
+
const result = parseIncidentInput(`https://app.opsgenie.com/alert/${uuid}`);
|
|
82
|
+
expect(result.source).toBe('opsgenie');
|
|
83
|
+
expect(result.id).toBe(uuid);
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
it('returns source=plain for plain text', () => {
|
|
87
|
+
const result = parseIncidentInput('high CPU on api-service pod');
|
|
88
|
+
expect(result.source).toBe('plain');
|
|
89
|
+
expect(result.id).toBe('high CPU on api-service pod');
|
|
90
|
+
});
|
|
91
|
+
});
|
|
92
|
+
|
|
93
|
+
// ---------------------------------------------------------------------------
|
|
94
|
+
// Inline reproduction of detectServiceName to unit-test logic (G14)
|
|
95
|
+
// ---------------------------------------------------------------------------
|
|
96
|
+
|
|
97
|
+
function detectServiceName(incident: ParsedIncident): string | null {
|
|
98
|
+
const match = incident.rawInput.match(/\b([\w-]+(?:service|worker|api|pod|deploy(?:ment)?|ingress|controller)[\w-]*)\b/i);
|
|
99
|
+
return match?.[1] ?? null;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
describe('detectServiceName logic (G14)', () => {
|
|
103
|
+
it('detects service name from plain text containing "service"', () => {
|
|
104
|
+
const incident = parseIncidentInput('high CPU on payment-service pod');
|
|
105
|
+
const name = detectServiceName(incident);
|
|
106
|
+
expect(name).not.toBeNull();
|
|
107
|
+
expect(name).toContain('service');
|
|
108
|
+
});
|
|
109
|
+
|
|
110
|
+
it('detects API service names', () => {
|
|
111
|
+
const incident = parseIncidentInput('error rate spike in user-api deployment');
|
|
112
|
+
const name = detectServiceName(incident);
|
|
113
|
+
expect(name).not.toBeNull();
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
it('returns null for an opaque string with no recognizable service pattern', () => {
|
|
117
|
+
const incident = parseIncidentInput('PABC123');
|
|
118
|
+
const name = detectServiceName(incident);
|
|
119
|
+
expect(name).toBeNull();
|
|
120
|
+
});
|
|
121
|
+
});
|
|
122
|
+
|
|
123
|
+
// ---------------------------------------------------------------------------
|
|
124
|
+
// PD_API_TOKEN guard: fetchPagerDutyDetails skips when token absent
|
|
125
|
+
// ---------------------------------------------------------------------------
|
|
126
|
+
|
|
127
|
+
describe('PD_API_TOKEN guard (G14)', () => {
|
|
128
|
+
beforeEach(() => {
|
|
129
|
+
vi.resetModules();
|
|
130
|
+
delete process.env.PD_API_TOKEN;
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
afterEach(() => {
|
|
134
|
+
vi.restoreAllMocks();
|
|
135
|
+
delete process.env.PD_API_TOKEN;
|
|
136
|
+
vi.resetModules();
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
it('incidentCommand with plain text does not throw when chatCommand is mocked', async () => {
|
|
140
|
+
// Mock chatCommand so the test doesn't start the full TUI
|
|
141
|
+
vi.doMock('../commands/chat', () => ({
|
|
142
|
+
chatCommand: vi.fn().mockResolvedValue(undefined),
|
|
143
|
+
}));
|
|
144
|
+
|
|
145
|
+
// Also mock child_process to prevent any real shell calls
|
|
146
|
+
vi.doMock('node:child_process', async () => {
|
|
147
|
+
const actual = await vi.importActual<typeof import('node:child_process')>('node:child_process');
|
|
148
|
+
return {
|
|
149
|
+
...actual,
|
|
150
|
+
execSync: vi.fn(() => ''),
|
|
151
|
+
};
|
|
152
|
+
});
|
|
153
|
+
|
|
154
|
+
const { incidentCommand } = await import('../commands/incident');
|
|
155
|
+
// Plain text input — should not throw, PD fetch is not triggered
|
|
156
|
+
await expect(incidentCommand('high CPU on api-service', {})).resolves.not.toThrow();
|
|
157
|
+
});
|
|
158
|
+
|
|
159
|
+
it('incidentCommand with PagerDuty URL and no token skips PD API call', async () => {
|
|
160
|
+
vi.doMock('../commands/chat', () => ({
|
|
161
|
+
chatCommand: vi.fn().mockResolvedValue(undefined),
|
|
162
|
+
}));
|
|
163
|
+
|
|
164
|
+
// Prevent real helm/kubectl shell calls
|
|
165
|
+
vi.doMock('node:child_process', async () => {
|
|
166
|
+
const actual = await vi.importActual<typeof import('node:child_process')>('node:child_process');
|
|
167
|
+
return {
|
|
168
|
+
...actual,
|
|
169
|
+
execSync: vi.fn(() => ''),
|
|
170
|
+
};
|
|
171
|
+
});
|
|
172
|
+
|
|
173
|
+
const { incidentCommand } = await import('../commands/incident');
|
|
174
|
+
// PD_API_TOKEN is not set, so the PD API fetch should be skipped
|
|
175
|
+
await expect(
|
|
176
|
+
incidentCommand('https://acme.pagerduty.com/incidents/PABC123', {})
|
|
177
|
+
).resolves.not.toThrow();
|
|
178
|
+
});
|
|
179
|
+
});
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* exercises the detection and init functions, and cleans up afterward.
|
|
6
6
|
*/
|
|
7
7
|
|
|
8
|
-
import { describe, test, expect, beforeEach, afterEach } from '
|
|
8
|
+
import { describe, test, expect, beforeEach, afterEach } from 'vitest';
|
|
9
9
|
import * as fs from 'node:fs';
|
|
10
10
|
import * as path from 'node:path';
|
|
11
11
|
import * as os from 'node:os';
|
|
@@ -333,6 +333,55 @@ describe('generateNimbusMd()', () => {
|
|
|
333
333
|
|
|
334
334
|
expect(md).toContain('**Package Manager:** bun');
|
|
335
335
|
});
|
|
336
|
+
|
|
337
|
+
test('G5: includes Guardrails section when infra is detected', () => {
|
|
338
|
+
const md = generateNimbusMd(
|
|
339
|
+
{
|
|
340
|
+
projectName: 'infra-app',
|
|
341
|
+
projectType: 'typescript',
|
|
342
|
+
infraTypes: ['terraform', 'kubernetes'],
|
|
343
|
+
cloudProviders: ['aws'],
|
|
344
|
+
hasGit: true,
|
|
345
|
+
},
|
|
346
|
+
'/tmp/infra-app'
|
|
347
|
+
);
|
|
348
|
+
|
|
349
|
+
expect(md).toContain('## Guardrails');
|
|
350
|
+
expect(md).toContain('Never run `terraform destroy`');
|
|
351
|
+
expect(md).toContain('Protected Kubernetes namespaces');
|
|
352
|
+
expect(md).toContain('Always show terraform plan before apply');
|
|
353
|
+
});
|
|
354
|
+
|
|
355
|
+
test('G5: omits Guardrails section when no infra detected', () => {
|
|
356
|
+
const md = generateNimbusMd(
|
|
357
|
+
{
|
|
358
|
+
projectName: 'pure-code',
|
|
359
|
+
projectType: 'typescript',
|
|
360
|
+
infraTypes: [],
|
|
361
|
+
cloudProviders: [],
|
|
362
|
+
hasGit: false,
|
|
363
|
+
},
|
|
364
|
+
'/tmp/pure-code'
|
|
365
|
+
);
|
|
366
|
+
|
|
367
|
+
expect(md).not.toContain('## Guardrails');
|
|
368
|
+
});
|
|
369
|
+
|
|
370
|
+
test('G5: always includes Forbidden placeholder section', () => {
|
|
371
|
+
const md = generateNimbusMd(
|
|
372
|
+
{
|
|
373
|
+
projectName: 'any-app',
|
|
374
|
+
projectType: 'typescript',
|
|
375
|
+
infraTypes: [],
|
|
376
|
+
cloudProviders: [],
|
|
377
|
+
hasGit: false,
|
|
378
|
+
},
|
|
379
|
+
'/tmp/any-app'
|
|
380
|
+
);
|
|
381
|
+
|
|
382
|
+
expect(md).toContain('## Forbidden');
|
|
383
|
+
expect(md).toContain('<!-- List operations Nimbus must never perform');
|
|
384
|
+
});
|
|
336
385
|
});
|
|
337
386
|
|
|
338
387
|
// ============================================================================
|
|
@@ -386,13 +435,15 @@ describe('runInit()', () => {
|
|
|
386
435
|
expect(content).toContain('type: typescript');
|
|
387
436
|
});
|
|
388
437
|
|
|
389
|
-
test('
|
|
438
|
+
test('skips if NIMBUS.md exists without --force (quiet mode)', async () => {
|
|
390
439
|
// First init
|
|
391
440
|
await runInit({ cwd: tmpDir, quiet: true });
|
|
392
441
|
expect(fs.existsSync(path.join(tmpDir, 'NIMBUS.md'))).toBe(true);
|
|
393
442
|
|
|
394
|
-
// Second init should
|
|
395
|
-
await
|
|
443
|
+
// Second init in quiet mode should skip without throwing
|
|
444
|
+
const result = await runInit({ cwd: tmpDir, quiet: true });
|
|
445
|
+
expect(result.filesCreated).toHaveLength(0);
|
|
446
|
+
expect(result.nimbusmdPath).toBe(path.join(tmpDir, 'NIMBUS.md'));
|
|
396
447
|
});
|
|
397
448
|
|
|
398
449
|
test('overwrites with --force', async () => {
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* intentionally excluded from unit tests.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import { describe, it, expect } from '
|
|
10
|
+
import { describe, it, expect } from 'vitest';
|
|
11
11
|
import { IntentParser, type ConversationalIntent } from '../generator/intent-parser';
|
|
12
12
|
|
|
13
13
|
// Helper: create a parser in pure-heuristic mode (no router)
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
* (no I/O, no network) and execute synchronously.
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
-
import { describe, it, expect } from '
|
|
12
|
+
import { describe, it, expect } from 'vitest';
|
|
13
13
|
import { resolveModelAlias, getAliases } from '../llm/model-aliases';
|
|
14
14
|
import { detectProvider } from '../llm/provider-registry';
|
|
15
15
|
import { calculateCost, getPricingData, type CostResult } from '../llm/cost-calculator';
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Logs Command Tests — H1
|
|
3
|
+
*
|
|
4
|
+
* Validates argument building for the logsCommand helper.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { describe, test, it, expect } from 'vitest';
|
|
8
|
+
import { parseLogsArgs } from '../commands/logs';
|
|
9
|
+
|
|
10
|
+
describe('parseLogsArgs (H1)', () => {
|
|
11
|
+
test('parses pod name as first positional', () => {
|
|
12
|
+
const { pod, options } = parseLogsArgs(['my-pod']);
|
|
13
|
+
expect(pod).toBe('my-pod');
|
|
14
|
+
expect(options).toEqual({});
|
|
15
|
+
});
|
|
16
|
+
|
|
17
|
+
test('parses -n namespace', () => {
|
|
18
|
+
const { pod, options } = parseLogsArgs(['my-pod', '-n', 'kube-system']);
|
|
19
|
+
expect(pod).toBe('my-pod');
|
|
20
|
+
expect(options.namespace).toBe('kube-system');
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
test('parses --namespace', () => {
|
|
24
|
+
const { options } = parseLogsArgs(['pod', '--namespace', 'production']);
|
|
25
|
+
expect(options.namespace).toBe('production');
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
test('parses -f / --follow', () => {
|
|
29
|
+
const { options: o1 } = parseLogsArgs(['pod', '-f']);
|
|
30
|
+
expect(o1.follow).toBe(true);
|
|
31
|
+
|
|
32
|
+
const { options: o2 } = parseLogsArgs(['pod', '--follow']);
|
|
33
|
+
expect(o2.follow).toBe(true);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
test('parses -p / --previous', () => {
|
|
37
|
+
const { options: o1 } = parseLogsArgs(['pod', '-p']);
|
|
38
|
+
expect(o1.previous).toBe(true);
|
|
39
|
+
|
|
40
|
+
const { options: o2 } = parseLogsArgs(['pod', '--previous']);
|
|
41
|
+
expect(o2.previous).toBe(true);
|
|
42
|
+
});
|
|
43
|
+
|
|
44
|
+
test('parses --tail N', () => {
|
|
45
|
+
const { options } = parseLogsArgs(['pod', '--tail', '100']);
|
|
46
|
+
expect(options.tail).toBe(100);
|
|
47
|
+
});
|
|
48
|
+
|
|
49
|
+
test('parses --analyze', () => {
|
|
50
|
+
const { options } = parseLogsArgs(['pod', '--analyze']);
|
|
51
|
+
expect(options.analyze).toBe(true);
|
|
52
|
+
});
|
|
53
|
+
|
|
54
|
+
test('parses -c container', () => {
|
|
55
|
+
const { options } = parseLogsArgs(['pod', '-c', 'sidecar']);
|
|
56
|
+
expect(options.container).toBe('sidecar');
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
test('parses --context', () => {
|
|
60
|
+
const { options } = parseLogsArgs(['pod', '--context', 'prod-cluster']);
|
|
61
|
+
expect(options.context).toBe('prod-cluster');
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
test('parses combined flags', () => {
|
|
65
|
+
const { pod, options } = parseLogsArgs([
|
|
66
|
+
'app-pod',
|
|
67
|
+
'-n', 'default',
|
|
68
|
+
'-f',
|
|
69
|
+
'--tail', '50',
|
|
70
|
+
'-c', 'app',
|
|
71
|
+
]);
|
|
72
|
+
expect(pod).toBe('app-pod');
|
|
73
|
+
expect(options.namespace).toBe('default');
|
|
74
|
+
expect(options.follow).toBe(true);
|
|
75
|
+
expect(options.tail).toBe(50);
|
|
76
|
+
expect(options.container).toBe('app');
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
|
|
80
|
+
// ---------------------------------------------------------------------------
|
|
81
|
+
// C1: logsTool follow mode (streaming)
|
|
82
|
+
// ---------------------------------------------------------------------------
|
|
83
|
+
|
|
84
|
+
describe('logsTool follow field (C1)', () => {
|
|
85
|
+
it('logsSchema has follow field', async () => {
|
|
86
|
+
const { readFileSync } = await import('node:fs');
|
|
87
|
+
const { join } = await import('node:path');
|
|
88
|
+
const src = readFileSync(join(process.cwd(), 'src/tools/schemas/devops.ts'), 'utf-8');
|
|
89
|
+
expect(src).toContain('follow: z.boolean()');
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
it('logsTool execute signature accepts ctx', async () => {
|
|
93
|
+
const { readFileSync } = await import('node:fs');
|
|
94
|
+
const { join } = await import('node:path');
|
|
95
|
+
const src = readFileSync(join(process.cwd(), 'src/tools/schemas/devops.ts'), 'utf-8');
|
|
96
|
+
// Check that logsTool execute accepts ctx parameter
|
|
97
|
+
expect(src).toMatch(/logsTool.*execute.*raw.*ctx\?/s);
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
it('follow mode uses spawnExec for kubernetes provider', async () => {
|
|
101
|
+
const { readFileSync } = await import('node:fs');
|
|
102
|
+
const { join } = await import('node:path');
|
|
103
|
+
const src = readFileSync(join(process.cwd(), 'src/tools/schemas/devops.ts'), 'utf-8');
|
|
104
|
+
// Verify the follow mode path calls spawnExec
|
|
105
|
+
expect(src).toContain('input.follow && ctx?.onProgress');
|
|
106
|
+
});
|
|
107
|
+
});
|