@build-astron-co/nimbus 0.4.1 → 0.4.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +268 -89
- package/README.md +26 -567
- package/dist/src/agent/compaction-agent.js +24 -12
- package/dist/src/agent/context-manager.js +2 -1
- package/dist/src/agent/expand-files.js +2 -1
- package/dist/src/agent/loop.js +71 -33
- package/dist/src/agent/permissions.js +4 -2
- package/dist/src/agent/system-prompt.js +34 -17
- package/dist/src/app.js +1 -1
- package/dist/src/auth/keychain.js +8 -4
- package/dist/src/auth/store.js +70 -107
- package/dist/src/cli/init.js +35 -19
- package/dist/src/cli/run.js +18 -10
- package/dist/src/cli/serve.js +4 -2
- package/dist/src/cli.js +52 -11
- package/dist/src/commands/alias.js +5 -3
- package/dist/src/commands/audit/index.js +2 -1
- package/dist/src/commands/aws-terraform.js +36 -18
- package/dist/src/commands/completions.js +1 -1
- package/dist/src/commands/config.js +3 -2
- package/dist/src/commands/connect-github.js +92 -0
- package/dist/src/commands/cost/index.js +3 -2
- package/dist/src/commands/deploy.js +15 -10
- package/dist/src/commands/doctor.js +9 -6
- package/dist/src/commands/drift/index.js +2 -1
- package/dist/src/commands/export.js +5 -3
- package/dist/src/commands/generate-terraform.js +110 -2
- package/dist/src/commands/import.js +3 -3
- package/dist/src/commands/incident.js +10 -5
- package/dist/src/commands/login.js +8 -93
- package/dist/src/commands/logs.js +16 -8
- package/dist/src/commands/onboarding.js +6 -4
- package/dist/src/commands/pipeline.js +6 -3
- package/dist/src/commands/plugin.js +3 -2
- package/dist/src/commands/profile.js +27 -14
- package/dist/src/commands/questionnaire.js +1 -1
- package/dist/src/commands/rollback.js +3 -2
- package/dist/src/commands/rollout.js +5 -3
- package/dist/src/commands/runbook.js +17 -10
- package/dist/src/commands/schedule.js +10 -5
- package/dist/src/commands/status.js +2 -1
- package/dist/src/commands/team-context.js +12 -7
- package/dist/src/commands/template.js +1 -1
- package/dist/src/commands/tf/index.js +6 -3
- package/dist/src/commands/upgrade.js +5 -3
- package/dist/src/commands/version.js +6 -3
- package/dist/src/commands/watch.js +6 -3
- package/dist/src/compat/sqlite.js +5 -3
- package/dist/src/config/mode-store.js +2 -1
- package/dist/src/config/profiles.js +4 -2
- package/dist/src/config/types.js +2 -1
- package/dist/src/engine/executor.js +8 -4
- package/dist/src/engine/planner.js +9 -5
- package/dist/src/llm/providers/anthropic.js +6 -3
- package/dist/src/llm/providers/ollama.js +1 -1
- package/dist/src/llm/router.js +22 -7
- package/dist/src/nimbus.js +1 -0
- package/dist/src/sessions/manager.js +6 -3
- package/dist/src/sharing/viewer.js +2 -1
- package/dist/src/tools/file-ops.js +1 -2
- package/dist/src/tools/schemas/devops.js +197 -108
- package/dist/src/tools/schemas/standard.js +1 -1
- package/dist/src/ui/App.js +25 -13
- package/dist/src/ui/FileDiffModal.js +22 -11
- package/dist/src/ui/HelpModal.js +2 -1
- package/dist/src/ui/InputBox.js +6 -3
- package/dist/src/ui/MessageList.js +40 -20
- package/dist/src/ui/TerminalPane.js +2 -1
- package/dist/src/ui/ToolCallDisplay.js +12 -6
- package/dist/src/ui/TreePane.js +2 -1
- package/dist/src/ui/ink/index.js +37 -21
- package/dist/src/version.js +1 -1
- package/dist/src/watcher/index.js +8 -4
- package/package.json +3 -5
- package/src/__tests__/alias.test.ts +0 -133
- package/src/__tests__/app.test.ts +0 -76
- package/src/__tests__/audit.test.ts +0 -877
- package/src/__tests__/circuit-breaker.test.ts +0 -116
- package/src/__tests__/cli-run.test.ts +0 -351
- package/src/__tests__/compat-sqlite.test.ts +0 -68
- package/src/__tests__/context-manager.test.ts +0 -632
- package/src/__tests__/context.test.ts +0 -242
- package/src/__tests__/devops-terminal-gaps.test.ts +0 -718
- package/src/__tests__/doctor.test.ts +0 -48
- package/src/__tests__/enterprise.test.ts +0 -401
- package/src/__tests__/export.test.ts +0 -236
- package/src/__tests__/gap-11-18-20.test.ts +0 -958
- package/src/__tests__/generator.test.ts +0 -433
- package/src/__tests__/helm-streaming.test.ts +0 -127
- package/src/__tests__/hooks.test.ts +0 -582
- package/src/__tests__/incident.test.ts +0 -179
- package/src/__tests__/init.test.ts +0 -487
- package/src/__tests__/intent-parser.test.ts +0 -229
- package/src/__tests__/llm-router.test.ts +0 -209
- package/src/__tests__/logs.test.ts +0 -107
- package/src/__tests__/loop-errors.test.ts +0 -244
- package/src/__tests__/lsp.test.ts +0 -293
- package/src/__tests__/modes.test.ts +0 -336
- package/src/__tests__/perf-optimizations.test.ts +0 -847
- package/src/__tests__/permissions.test.ts +0 -338
- package/src/__tests__/pipeline.test.ts +0 -50
- package/src/__tests__/polish-phase3.test.ts +0 -340
- package/src/__tests__/profile.test.ts +0 -237
- package/src/__tests__/rollback.test.ts +0 -83
- package/src/__tests__/runbook.test.ts +0 -219
- package/src/__tests__/schedule.test.ts +0 -206
- package/src/__tests__/serve.test.ts +0 -275
- package/src/__tests__/sessions.test.ts +0 -322
- package/src/__tests__/sharing.test.ts +0 -340
- package/src/__tests__/snapshots.test.ts +0 -581
- package/src/__tests__/standalone-migration.test.ts +0 -199
- package/src/__tests__/state-db.test.ts +0 -334
- package/src/__tests__/status.test.ts +0 -158
- package/src/__tests__/stream-with-tools.test.ts +0 -778
- package/src/__tests__/subagents.test.ts +0 -176
- package/src/__tests__/system-prompt.test.ts +0 -248
- package/src/__tests__/terminal-gap-v2.test.ts +0 -395
- package/src/__tests__/terminal-parity.test.ts +0 -393
- package/src/__tests__/tf-apply.test.ts +0 -187
- package/src/__tests__/tool-converter.test.ts +0 -256
- package/src/__tests__/tool-schemas.test.ts +0 -602
- package/src/__tests__/tools.test.ts +0 -144
- package/src/__tests__/version-json.test.ts +0 -184
- package/src/__tests__/version.test.ts +0 -49
- package/src/__tests__/watch.test.ts +0 -129
- package/src/agent/compaction-agent.ts +0 -266
- package/src/agent/context-manager.ts +0 -499
- package/src/agent/context.ts +0 -427
- package/src/agent/deploy-preview.ts +0 -487
- package/src/agent/expand-files.ts +0 -108
- package/src/agent/index.ts +0 -68
- package/src/agent/loop.ts +0 -1998
- package/src/agent/modes.ts +0 -429
- package/src/agent/permissions.ts +0 -513
- package/src/agent/subagents/base.ts +0 -116
- package/src/agent/subagents/cost.ts +0 -51
- package/src/agent/subagents/explore.ts +0 -42
- package/src/agent/subagents/general.ts +0 -54
- package/src/agent/subagents/index.ts +0 -102
- package/src/agent/subagents/infra.ts +0 -59
- package/src/agent/subagents/security.ts +0 -69
- package/src/agent/system-prompt.ts +0 -990
- package/src/app.ts +0 -180
- package/src/audit/activity-log.ts +0 -290
- package/src/audit/compliance-checker.ts +0 -540
- package/src/audit/cost-tracker.ts +0 -318
- package/src/audit/index.ts +0 -23
- package/src/audit/security-scanner.ts +0 -641
- package/src/auth/guard.ts +0 -75
- package/src/auth/index.ts +0 -56
- package/src/auth/keychain.ts +0 -82
- package/src/auth/oauth.ts +0 -465
- package/src/auth/providers.ts +0 -470
- package/src/auth/sso.ts +0 -113
- package/src/auth/store.ts +0 -505
- package/src/auth/types.ts +0 -187
- package/src/build.ts +0 -141
- package/src/cli/index.ts +0 -16
- package/src/cli/init.ts +0 -1227
- package/src/cli/openapi-spec.ts +0 -356
- package/src/cli/run.ts +0 -628
- package/src/cli/serve-auth.ts +0 -80
- package/src/cli/serve.ts +0 -539
- package/src/cli/web.ts +0 -71
- package/src/cli.ts +0 -1728
- package/src/clients/core-engine-client.ts +0 -227
- package/src/clients/enterprise-client.ts +0 -334
- package/src/clients/generator-client.ts +0 -351
- package/src/clients/git-client.ts +0 -627
- package/src/clients/github-client.ts +0 -410
- package/src/clients/helm-client.ts +0 -504
- package/src/clients/index.ts +0 -80
- package/src/clients/k8s-client.ts +0 -497
- package/src/clients/llm-client.ts +0 -161
- package/src/clients/rest-client.ts +0 -130
- package/src/clients/service-discovery.ts +0 -38
- package/src/clients/terraform-client.ts +0 -482
- package/src/clients/tools-client.ts +0 -1843
- package/src/clients/ws-client.ts +0 -115
- package/src/commands/alias.ts +0 -100
- package/src/commands/analyze/index.ts +0 -352
- package/src/commands/apply/helm.ts +0 -473
- package/src/commands/apply/index.ts +0 -213
- package/src/commands/apply/k8s.ts +0 -454
- package/src/commands/apply/terraform.ts +0 -582
- package/src/commands/ask.ts +0 -167
- package/src/commands/audit/index.ts +0 -357
- package/src/commands/auth-cloud.ts +0 -407
- package/src/commands/auth-list.ts +0 -134
- package/src/commands/auth-profile.ts +0 -121
- package/src/commands/auth-refresh.ts +0 -187
- package/src/commands/auth-status.ts +0 -141
- package/src/commands/aws/ec2.ts +0 -501
- package/src/commands/aws/iam.ts +0 -397
- package/src/commands/aws/index.ts +0 -133
- package/src/commands/aws/lambda.ts +0 -396
- package/src/commands/aws/rds.ts +0 -439
- package/src/commands/aws/s3.ts +0 -439
- package/src/commands/aws/vpc.ts +0 -393
- package/src/commands/aws-discover.ts +0 -542
- package/src/commands/aws-terraform.ts +0 -755
- package/src/commands/azure/aks.ts +0 -376
- package/src/commands/azure/functions.ts +0 -253
- package/src/commands/azure/index.ts +0 -116
- package/src/commands/azure/storage.ts +0 -478
- package/src/commands/azure/vm.ts +0 -355
- package/src/commands/billing/index.ts +0 -256
- package/src/commands/chat.ts +0 -320
- package/src/commands/completions.ts +0 -268
- package/src/commands/config.ts +0 -372
- package/src/commands/cost/cloud-cost-estimator.ts +0 -266
- package/src/commands/cost/estimator.ts +0 -79
- package/src/commands/cost/index.ts +0 -810
- package/src/commands/cost/parsers/terraform.ts +0 -273
- package/src/commands/cost/parsers/types.ts +0 -25
- package/src/commands/cost/pricing/aws.ts +0 -544
- package/src/commands/cost/pricing/azure.ts +0 -499
- package/src/commands/cost/pricing/gcp.ts +0 -396
- package/src/commands/cost/pricing/index.ts +0 -40
- package/src/commands/demo.ts +0 -250
- package/src/commands/deploy.ts +0 -260
- package/src/commands/doctor.ts +0 -1386
- package/src/commands/drift/index.ts +0 -787
- package/src/commands/explain.ts +0 -277
- package/src/commands/export.ts +0 -146
- package/src/commands/feedback.ts +0 -389
- package/src/commands/fix.ts +0 -324
- package/src/commands/fs/index.ts +0 -402
- package/src/commands/gcp/compute.ts +0 -325
- package/src/commands/gcp/functions.ts +0 -271
- package/src/commands/gcp/gke.ts +0 -438
- package/src/commands/gcp/iam.ts +0 -344
- package/src/commands/gcp/index.ts +0 -129
- package/src/commands/gcp/storage.ts +0 -284
- package/src/commands/generate-helm.ts +0 -1249
- package/src/commands/generate-k8s.ts +0 -1508
- package/src/commands/generate-terraform.ts +0 -1202
- package/src/commands/gh/index.ts +0 -863
- package/src/commands/git/index.ts +0 -1343
- package/src/commands/helm/index.ts +0 -1126
- package/src/commands/help.ts +0 -715
- package/src/commands/history.ts +0 -149
- package/src/commands/import.ts +0 -868
- package/src/commands/incident.ts +0 -166
- package/src/commands/index.ts +0 -367
- package/src/commands/init.ts +0 -1051
- package/src/commands/k8s/index.ts +0 -1137
- package/src/commands/login.ts +0 -716
- package/src/commands/logout.ts +0 -83
- package/src/commands/logs.ts +0 -167
- package/src/commands/onboarding.ts +0 -405
- package/src/commands/pipeline.ts +0 -186
- package/src/commands/plan/display.ts +0 -279
- package/src/commands/plan/index.ts +0 -599
- package/src/commands/plugin.ts +0 -398
- package/src/commands/preview.ts +0 -452
- package/src/commands/profile.ts +0 -342
- package/src/commands/questionnaire.ts +0 -1172
- package/src/commands/resume.ts +0 -47
- package/src/commands/rollback.ts +0 -315
- package/src/commands/rollout.ts +0 -88
- package/src/commands/runbook.ts +0 -346
- package/src/commands/schedule.ts +0 -236
- package/src/commands/status.ts +0 -252
- package/src/commands/team/index.ts +0 -346
- package/src/commands/team-context.ts +0 -220
- package/src/commands/template.ts +0 -233
- package/src/commands/tf/index.ts +0 -1093
- package/src/commands/upgrade.ts +0 -607
- package/src/commands/usage/index.ts +0 -134
- package/src/commands/version.ts +0 -174
- package/src/commands/watch.ts +0 -153
- package/src/compat/index.ts +0 -2
- package/src/compat/runtime.ts +0 -12
- package/src/compat/sqlite.ts +0 -177
- package/src/config/index.ts +0 -17
- package/src/config/manager.ts +0 -530
- package/src/config/mode-store.ts +0 -62
- package/src/config/profiles.ts +0 -84
- package/src/config/safety-policy.ts +0 -358
- package/src/config/schema.ts +0 -125
- package/src/config/types.ts +0 -609
- package/src/config/workspace-state.ts +0 -53
- package/src/context/context-db.ts +0 -199
- package/src/demo/index.ts +0 -349
- package/src/demo/scenarios/full-journey.ts +0 -229
- package/src/demo/scenarios/getting-started.ts +0 -127
- package/src/demo/scenarios/helm-release.ts +0 -341
- package/src/demo/scenarios/k8s-deployment.ts +0 -194
- package/src/demo/scenarios/terraform-vpc.ts +0 -170
- package/src/demo/types.ts +0 -92
- package/src/engine/cost-estimator.ts +0 -480
- package/src/engine/diagram-generator.ts +0 -256
- package/src/engine/drift-detector.ts +0 -902
- package/src/engine/executor.ts +0 -1066
- package/src/engine/index.ts +0 -76
- package/src/engine/orchestrator.ts +0 -636
- package/src/engine/planner.ts +0 -787
- package/src/engine/safety.ts +0 -743
- package/src/engine/verifier.ts +0 -770
- package/src/enterprise/audit.ts +0 -348
- package/src/enterprise/auth.ts +0 -270
- package/src/enterprise/billing.ts +0 -822
- package/src/enterprise/index.ts +0 -17
- package/src/enterprise/teams.ts +0 -443
- package/src/generator/best-practices.ts +0 -1608
- package/src/generator/helm.ts +0 -630
- package/src/generator/index.ts +0 -37
- package/src/generator/intent-parser.ts +0 -514
- package/src/generator/kubernetes.ts +0 -976
- package/src/generator/terraform.ts +0 -1875
- package/src/history/index.ts +0 -8
- package/src/history/manager.ts +0 -250
- package/src/history/types.ts +0 -34
- package/src/hooks/config.ts +0 -432
- package/src/hooks/engine.ts +0 -392
- package/src/hooks/index.ts +0 -4
- package/src/llm/auth-bridge.ts +0 -198
- package/src/llm/circuit-breaker.ts +0 -140
- package/src/llm/config-loader.ts +0 -201
- package/src/llm/cost-calculator.ts +0 -171
- package/src/llm/index.ts +0 -8
- package/src/llm/model-aliases.ts +0 -115
- package/src/llm/provider-registry.ts +0 -63
- package/src/llm/providers/anthropic.ts +0 -462
- package/src/llm/providers/bedrock.ts +0 -477
- package/src/llm/providers/google.ts +0 -405
- package/src/llm/providers/ollama.ts +0 -767
- package/src/llm/providers/openai-compatible.ts +0 -340
- package/src/llm/providers/openai.ts +0 -328
- package/src/llm/providers/openrouter.ts +0 -338
- package/src/llm/router.ts +0 -1104
- package/src/llm/types.ts +0 -232
- package/src/lsp/client.ts +0 -298
- package/src/lsp/languages.ts +0 -119
- package/src/lsp/manager.ts +0 -294
- package/src/mcp/client.ts +0 -402
- package/src/mcp/index.ts +0 -5
- package/src/mcp/manager.ts +0 -133
- package/src/nimbus.ts +0 -233
- package/src/plugins/index.ts +0 -27
- package/src/plugins/loader.ts +0 -334
- package/src/plugins/manager.ts +0 -376
- package/src/plugins/types.ts +0 -284
- package/src/scanners/cicd-scanner.ts +0 -258
- package/src/scanners/cloud-scanner.ts +0 -466
- package/src/scanners/framework-scanner.ts +0 -469
- package/src/scanners/iac-scanner.ts +0 -388
- package/src/scanners/index.ts +0 -539
- package/src/scanners/language-scanner.ts +0 -276
- package/src/scanners/package-manager-scanner.ts +0 -277
- package/src/scanners/types.ts +0 -172
- package/src/sessions/manager.ts +0 -472
- package/src/sessions/types.ts +0 -44
- package/src/sharing/sync.ts +0 -300
- package/src/sharing/viewer.ts +0 -163
- package/src/snapshots/index.ts +0 -2
- package/src/snapshots/manager.ts +0 -530
- package/src/state/artifacts.ts +0 -147
- package/src/state/audit.ts +0 -137
- package/src/state/billing.ts +0 -240
- package/src/state/checkpoints.ts +0 -117
- package/src/state/config.ts +0 -67
- package/src/state/conversations.ts +0 -14
- package/src/state/credentials.ts +0 -154
- package/src/state/db.ts +0 -58
- package/src/state/index.ts +0 -26
- package/src/state/messages.ts +0 -115
- package/src/state/projects.ts +0 -123
- package/src/state/schema.ts +0 -236
- package/src/state/sessions.ts +0 -147
- package/src/state/teams.ts +0 -200
- package/src/telemetry.ts +0 -108
- package/src/tools/aws-ops.ts +0 -952
- package/src/tools/azure-ops.ts +0 -579
- package/src/tools/file-ops.ts +0 -615
- package/src/tools/gcp-ops.ts +0 -625
- package/src/tools/git-ops.ts +0 -773
- package/src/tools/github-ops.ts +0 -799
- package/src/tools/helm-ops.ts +0 -943
- package/src/tools/index.ts +0 -17
- package/src/tools/k8s-ops.ts +0 -819
- package/src/tools/schemas/converter.ts +0 -184
- package/src/tools/schemas/devops.ts +0 -3502
- package/src/tools/schemas/index.ts +0 -73
- package/src/tools/schemas/standard.ts +0 -1148
- package/src/tools/schemas/types.ts +0 -735
- package/src/tools/spawn-exec.ts +0 -148
- package/src/tools/terraform-ops.ts +0 -862
- package/src/types/ambient.d.ts +0 -193
- package/src/types/config.ts +0 -83
- package/src/types/drift.ts +0 -116
- package/src/types/enterprise.ts +0 -335
- package/src/types/index.ts +0 -20
- package/src/types/plan.ts +0 -44
- package/src/types/request.ts +0 -65
- package/src/types/response.ts +0 -54
- package/src/types/service.ts +0 -51
- package/src/ui/App.tsx +0 -2114
- package/src/ui/DeployPreview.tsx +0 -174
- package/src/ui/FileDiffModal.tsx +0 -162
- package/src/ui/Header.tsx +0 -131
- package/src/ui/HelpModal.tsx +0 -57
- package/src/ui/InputBox.tsx +0 -503
- package/src/ui/MessageList.tsx +0 -1032
- package/src/ui/PermissionPrompt.tsx +0 -163
- package/src/ui/StatusBar.tsx +0 -277
- package/src/ui/TerminalPane.tsx +0 -84
- package/src/ui/ToolCallDisplay.tsx +0 -643
- package/src/ui/TreePane.tsx +0 -132
- package/src/ui/chat-ui.ts +0 -850
- package/src/ui/index.ts +0 -33
- package/src/ui/ink/index.ts +0 -1444
- package/src/ui/streaming.ts +0 -176
- package/src/ui/theme.ts +0 -104
- package/src/ui/types.ts +0 -75
- package/src/utils/analytics.ts +0 -72
- package/src/utils/cost-warning.ts +0 -27
- package/src/utils/env.ts +0 -46
- package/src/utils/errors.ts +0 -69
- package/src/utils/event-bus.ts +0 -38
- package/src/utils/index.ts +0 -24
- package/src/utils/logger.ts +0 -171
- package/src/utils/rate-limiter.ts +0 -121
- package/src/utils/service-auth.ts +0 -49
- package/src/utils/validation.ts +0 -53
- package/src/version.ts +0 -4
- package/src/watcher/index.ts +0 -214
- package/src/wizard/approval.ts +0 -383
- package/src/wizard/index.ts +0 -25
- package/src/wizard/prompts.ts +0 -338
- package/src/wizard/types.ts +0 -172
- package/src/wizard/ui.ts +0 -556
- package/src/wizard/wizard.ts +0 -304
- package/tsconfig.json +0 -24
|
@@ -1,199 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Standalone Migration Tests
|
|
3
|
-
*
|
|
4
|
-
* Source-level checks verifying that microservice-dependent commands
|
|
5
|
-
* (RestClient, CoreEngineClient, localhost:300X) have been replaced
|
|
6
|
-
* with standalone CLI/SQLite/generator implementations.
|
|
7
|
-
*
|
|
8
|
-
* These are intentionally static — no runtime startup needed.
|
|
9
|
-
*/
|
|
10
|
-
|
|
11
|
-
import { readFileSync } from 'node:fs';
|
|
12
|
-
import { join } from 'node:path';
|
|
13
|
-
import { describe, it, expect } from 'vitest';
|
|
14
|
-
|
|
15
|
-
const ROOT = join(__dirname, '..', '..');
|
|
16
|
-
|
|
17
|
-
function src(relativePath: string): string {
|
|
18
|
-
return readFileSync(join(ROOT, relativePath), 'utf8');
|
|
19
|
-
}
|
|
20
|
-
|
|
21
|
-
// ---------------------------------------------------------------------------
|
|
22
|
-
// C1 — generate-terraform: standalone
|
|
23
|
-
// ---------------------------------------------------------------------------
|
|
24
|
-
describe('C1 — generate-terraform standalone', () => {
|
|
25
|
-
it('has no new RestClient call', () => {
|
|
26
|
-
expect(src('src/commands/generate-terraform.ts')).not.toContain('new RestClient');
|
|
27
|
-
});
|
|
28
|
-
it('imports generateTerraformProject from generator', () => {
|
|
29
|
-
expect(src('src/commands/generate-terraform.ts')).toContain('generateTerraformProject');
|
|
30
|
-
});
|
|
31
|
-
it('has no localhost:300 reference', () => {
|
|
32
|
-
expect(src('src/commands/generate-terraform.ts')).not.toMatch(/localhost:300\d/);
|
|
33
|
-
});
|
|
34
|
-
});
|
|
35
|
-
|
|
36
|
-
// ---------------------------------------------------------------------------
|
|
37
|
-
// C2 — generate-k8s: standalone
|
|
38
|
-
// ---------------------------------------------------------------------------
|
|
39
|
-
describe('C2 — generate-k8s standalone', () => {
|
|
40
|
-
it('has no new RestClient call', () => {
|
|
41
|
-
expect(src('src/commands/generate-k8s.ts')).not.toContain('new RestClient');
|
|
42
|
-
});
|
|
43
|
-
it('uses generateManifestsLocally or kubernetes generator', () => {
|
|
44
|
-
expect(src('src/commands/generate-k8s.ts')).toMatch(/generateManifestsLocally|generateK8sManifests|K8sGeneratorConfig/);
|
|
45
|
-
});
|
|
46
|
-
it('has no localhost:300 reference', () => {
|
|
47
|
-
expect(src('src/commands/generate-k8s.ts')).not.toMatch(/localhost:300\d/);
|
|
48
|
-
});
|
|
49
|
-
});
|
|
50
|
-
|
|
51
|
-
// ---------------------------------------------------------------------------
|
|
52
|
-
// C3 — aws-discover: standalone
|
|
53
|
-
// ---------------------------------------------------------------------------
|
|
54
|
-
describe('C3 — aws-discover standalone', () => {
|
|
55
|
-
it('has no new RestClient call', () => {
|
|
56
|
-
expect(src('src/commands/aws-discover.ts')).not.toContain('new RestClient');
|
|
57
|
-
});
|
|
58
|
-
it('uses aws configure or execFile for profiles', () => {
|
|
59
|
-
expect(src('src/commands/aws-discover.ts')).toMatch(/configure|execFile|execFileSync|cliGetAwsProfiles/);
|
|
60
|
-
});
|
|
61
|
-
it('has no localhost:300 reference', () => {
|
|
62
|
-
expect(src('src/commands/aws-discover.ts')).not.toMatch(/localhost:300\d/);
|
|
63
|
-
});
|
|
64
|
-
});
|
|
65
|
-
|
|
66
|
-
// ---------------------------------------------------------------------------
|
|
67
|
-
// C4 — aws-terraform: standalone
|
|
68
|
-
// ---------------------------------------------------------------------------
|
|
69
|
-
describe('C4 — aws-terraform standalone', () => {
|
|
70
|
-
it('has no new RestClient call', () => {
|
|
71
|
-
expect(src('src/commands/aws-terraform.ts')).not.toContain('new RestClient');
|
|
72
|
-
});
|
|
73
|
-
it('imports generateTerraformProject from generator', () => {
|
|
74
|
-
expect(src('src/commands/aws-terraform.ts')).toContain('generateTerraformProject');
|
|
75
|
-
});
|
|
76
|
-
it('has no localhost:300 reference', () => {
|
|
77
|
-
expect(src('src/commands/aws-terraform.ts')).not.toMatch(/localhost:300\d/);
|
|
78
|
-
});
|
|
79
|
-
});
|
|
80
|
-
|
|
81
|
-
// ---------------------------------------------------------------------------
|
|
82
|
-
// C5 — resume: standalone
|
|
83
|
-
// ---------------------------------------------------------------------------
|
|
84
|
-
describe('C5 — resume command standalone', () => {
|
|
85
|
-
it('has no CoreEngineClient import', () => {
|
|
86
|
-
expect(src('src/commands/resume.ts')).not.toContain('CoreEngineClient');
|
|
87
|
-
});
|
|
88
|
-
it('references chatCommand or getDb for session lookup', () => {
|
|
89
|
-
expect(src('src/commands/resume.ts')).toMatch(/chatCommand|getDb|SessionManager/);
|
|
90
|
-
});
|
|
91
|
-
it('has no localhost:300 reference', () => {
|
|
92
|
-
expect(src('src/commands/resume.ts')).not.toMatch(/localhost:300\d/);
|
|
93
|
-
});
|
|
94
|
-
});
|
|
95
|
-
|
|
96
|
-
// ---------------------------------------------------------------------------
|
|
97
|
-
// C6 — version: DevOps CLI tools (not localhost services)
|
|
98
|
-
// ---------------------------------------------------------------------------
|
|
99
|
-
describe('C6 — version command DevOps tools', () => {
|
|
100
|
-
it('has no localhost:300 references in fetchComponentVersions', () => {
|
|
101
|
-
expect(src('src/commands/version.ts')).not.toMatch(/localhost:300\d/);
|
|
102
|
-
});
|
|
103
|
-
it('includes terraform version check', () => {
|
|
104
|
-
expect(src('src/commands/version.ts')).toContain('terraform');
|
|
105
|
-
});
|
|
106
|
-
it('includes kubectl version check', () => {
|
|
107
|
-
expect(src('src/commands/version.ts')).toContain('kubectl');
|
|
108
|
-
});
|
|
109
|
-
it('includes helm version check', () => {
|
|
110
|
-
expect(src('src/commands/version.ts')).toContain('helm');
|
|
111
|
-
});
|
|
112
|
-
it('shows [+] / [-] icon format', () => {
|
|
113
|
-
expect(src('src/commands/version.ts')).toMatch(/\[\+\]|\[-\]/);
|
|
114
|
-
});
|
|
115
|
-
});
|
|
116
|
-
|
|
117
|
-
// ---------------------------------------------------------------------------
|
|
118
|
-
// C7 — drift: no CoreEngineClient
|
|
119
|
-
// ---------------------------------------------------------------------------
|
|
120
|
-
describe('C7 — drift no CoreEngineClient', () => {
|
|
121
|
-
it('drift/index.ts has no CoreEngineClient import', () => {
|
|
122
|
-
const content = src('src/commands/drift/index.ts');
|
|
123
|
-
// Must not have an import statement (comments are fine)
|
|
124
|
-
expect(content).not.toMatch(/^import.*CoreEngineClient/m);
|
|
125
|
-
});
|
|
126
|
-
it('drift/index.ts uses execFileSync or execFile for terraform', () => {
|
|
127
|
-
expect(src('src/commands/drift/index.ts')).toMatch(/execFileSync|execFile|spawnExec/);
|
|
128
|
-
});
|
|
129
|
-
});
|
|
130
|
-
|
|
131
|
-
// ---------------------------------------------------------------------------
|
|
132
|
-
// C8 — dead client code deleted/stubbed
|
|
133
|
-
// ---------------------------------------------------------------------------
|
|
134
|
-
describe('C8 — dead client code', () => {
|
|
135
|
-
it('service-discovery.ts is either deleted or a stub without ghost URLs', () => {
|
|
136
|
-
try {
|
|
137
|
-
const content = src('src/clients/service-discovery.ts');
|
|
138
|
-
// If it exists, it must not contain the old ghost localhost service URLs
|
|
139
|
-
expect(content).not.toContain('localhost:3001');
|
|
140
|
-
expect(content).not.toContain('localhost:3003');
|
|
141
|
-
expect(content).not.toContain('localhost:3009');
|
|
142
|
-
} catch {
|
|
143
|
-
// File deleted — that's fine
|
|
144
|
-
}
|
|
145
|
-
});
|
|
146
|
-
});
|
|
147
|
-
|
|
148
|
-
// ---------------------------------------------------------------------------
|
|
149
|
-
// H1 — Emoji removed, replaced with ASCII icons
|
|
150
|
-
// ---------------------------------------------------------------------------
|
|
151
|
-
describe('H1 — emoji removed from UI', () => {
|
|
152
|
-
it('TreePane.tsx has no folder emoji', () => {
|
|
153
|
-
expect(src('src/ui/TreePane.tsx')).not.toContain('\u{1F4C1}'); // 📁
|
|
154
|
-
});
|
|
155
|
-
it('TreePane.tsx uses [/] for directories', () => {
|
|
156
|
-
expect(src('src/ui/TreePane.tsx')).toContain('[/]');
|
|
157
|
-
});
|
|
158
|
-
it('TerminalPane.tsx has no right-pointing triangle', () => {
|
|
159
|
-
expect(src('src/ui/TerminalPane.tsx')).not.toContain('\u25B6'); // ▶
|
|
160
|
-
});
|
|
161
|
-
it('TerminalPane.tsx uses [>] icon', () => {
|
|
162
|
-
expect(src('src/ui/TerminalPane.tsx')).toContain('[>]');
|
|
163
|
-
});
|
|
164
|
-
it('StatusBar.tsx has no Greek capital delta (Δ)', () => {
|
|
165
|
-
expect(src('src/ui/StatusBar.tsx')).not.toContain('\u0394'); // Δ
|
|
166
|
-
});
|
|
167
|
-
it('StatusBar.tsx uses delta: text', () => {
|
|
168
|
-
expect(src('src/ui/StatusBar.tsx')).toContain('delta:');
|
|
169
|
-
});
|
|
170
|
-
});
|
|
171
|
-
|
|
172
|
-
// ---------------------------------------------------------------------------
|
|
173
|
-
// M1 — Secret redaction in spawn-exec
|
|
174
|
-
// ---------------------------------------------------------------------------
|
|
175
|
-
describe('M1 — secret redaction in spawn-exec', () => {
|
|
176
|
-
it('spawn-exec.ts has SECRET_PATTERNS constant', () => {
|
|
177
|
-
expect(src('src/tools/spawn-exec.ts')).toContain('SECRET_PATTERNS');
|
|
178
|
-
});
|
|
179
|
-
it('spawn-exec.ts has redactSecrets function', () => {
|
|
180
|
-
expect(src('src/tools/spawn-exec.ts')).toContain('redactSecrets');
|
|
181
|
-
});
|
|
182
|
-
it('spawn-exec.ts redacts AKIA keys', () => {
|
|
183
|
-
expect(src('src/tools/spawn-exec.ts')).toContain('AKIA');
|
|
184
|
-
});
|
|
185
|
-
it('spawn-exec.ts redacts Bearer tokens', () => {
|
|
186
|
-
expect(src('src/tools/spawn-exec.ts')).toContain('Bearer');
|
|
187
|
-
});
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
// ---------------------------------------------------------------------------
|
|
191
|
-
// M2 — Doctor shows inline versions
|
|
192
|
-
// ---------------------------------------------------------------------------
|
|
193
|
-
describe('M2 — doctor inline versions', () => {
|
|
194
|
-
it('doctor.ts references version in available tools output', () => {
|
|
195
|
-
// The available list should include t.version or similar version string
|
|
196
|
-
const content = src('src/commands/doctor.ts');
|
|
197
|
-
expect(content).toMatch(/t\.version|tool\.version|\.version\b/);
|
|
198
|
-
});
|
|
199
|
-
});
|
|
@@ -1,334 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for the SQLite state layer:
|
|
3
|
-
* - src/state/db.ts – getTestDb, closeDb
|
|
4
|
-
* - src/state/sessions.ts – saveOperation, getOperation, listOperations, listOperationsByType
|
|
5
|
-
* - src/state/messages.ts – saveConversation, getConversation, listConversations, deleteConversation
|
|
6
|
-
* - src/state/config.ts – setConfig, getConfig, getAllConfig
|
|
7
|
-
* - src/state/artifacts.ts – saveArtifact, getArtifact, listArtifacts, deleteArtifact
|
|
8
|
-
*
|
|
9
|
-
* Every test uses getTestDb() (in-memory SQLite) so the real ~/.nimbus/nimbus.db
|
|
10
|
-
* is never touched, and tests are fully isolated and fast.
|
|
11
|
-
*/
|
|
12
|
-
|
|
13
|
-
import { describe, it, expect, beforeEach } from 'vitest';
|
|
14
|
-
import type { Database } from '../compat/sqlite';
|
|
15
|
-
import { getTestDb } from '../state/db';
|
|
16
|
-
import {
|
|
17
|
-
saveOperation,
|
|
18
|
-
getOperation,
|
|
19
|
-
listOperations,
|
|
20
|
-
listOperationsByType,
|
|
21
|
-
type SaveOperationInput,
|
|
22
|
-
} from '../state/sessions';
|
|
23
|
-
import {
|
|
24
|
-
saveConversation,
|
|
25
|
-
getConversation,
|
|
26
|
-
listConversations,
|
|
27
|
-
deleteConversation,
|
|
28
|
-
} from '../state/messages';
|
|
29
|
-
import { setConfig, getConfig, getAllConfig } from '../state/config';
|
|
30
|
-
import { saveArtifact, getArtifact, listArtifacts, deleteArtifact } from '../state/artifacts';
|
|
31
|
-
|
|
32
|
-
// ---------------------------------------------------------------------------
|
|
33
|
-
// Helpers
|
|
34
|
-
// ---------------------------------------------------------------------------
|
|
35
|
-
|
|
36
|
-
/** Fresh in-memory database for every test block. */
|
|
37
|
-
let db: Database;
|
|
38
|
-
|
|
39
|
-
beforeEach(() => {
|
|
40
|
-
db = getTestDb();
|
|
41
|
-
});
|
|
42
|
-
|
|
43
|
-
// ---------------------------------------------------------------------------
|
|
44
|
-
// Sessions (operations)
|
|
45
|
-
// ---------------------------------------------------------------------------
|
|
46
|
-
|
|
47
|
-
describe('operations CRUD', () => {
|
|
48
|
-
it('saves and retrieves an operation by id', () => {
|
|
49
|
-
const op: SaveOperationInput = {
|
|
50
|
-
id: 'op-001',
|
|
51
|
-
timestamp: new Date('2025-01-01T00:00:00Z'),
|
|
52
|
-
type: 'generate',
|
|
53
|
-
command: 'nimbus generate vpc',
|
|
54
|
-
status: 'success',
|
|
55
|
-
};
|
|
56
|
-
|
|
57
|
-
saveOperation(op, db);
|
|
58
|
-
const record = getOperation('op-001', db);
|
|
59
|
-
|
|
60
|
-
expect(record).not.toBeNull();
|
|
61
|
-
expect(record!.id).toBe('op-001');
|
|
62
|
-
expect(record!.type).toBe('generate');
|
|
63
|
-
expect(record!.command).toBe('nimbus generate vpc');
|
|
64
|
-
expect(record!.status).toBe('success');
|
|
65
|
-
});
|
|
66
|
-
|
|
67
|
-
it('returns null for a non-existent operation id', () => {
|
|
68
|
-
const record = getOperation('does-not-exist', db);
|
|
69
|
-
expect(record).toBeNull();
|
|
70
|
-
});
|
|
71
|
-
|
|
72
|
-
it('saves optional fields and retrieves them correctly', () => {
|
|
73
|
-
const op: SaveOperationInput = {
|
|
74
|
-
id: 'op-002',
|
|
75
|
-
timestamp: new Date('2025-01-02T00:00:00Z'),
|
|
76
|
-
type: 'chat',
|
|
77
|
-
command: 'nimbus ask',
|
|
78
|
-
status: 'success',
|
|
79
|
-
input: 'create a vpc',
|
|
80
|
-
output: 'Generated terraform files',
|
|
81
|
-
durationMs: 1234,
|
|
82
|
-
model: 'claude-sonnet-4-20250514',
|
|
83
|
-
tokensUsed: 500,
|
|
84
|
-
costUsd: 0.0015,
|
|
85
|
-
metadata: { env: 'test' },
|
|
86
|
-
};
|
|
87
|
-
|
|
88
|
-
saveOperation(op, db);
|
|
89
|
-
const record = getOperation('op-002', db);
|
|
90
|
-
|
|
91
|
-
expect(record!.input).toBe('create a vpc');
|
|
92
|
-
expect(record!.output).toBe('Generated terraform files');
|
|
93
|
-
expect(record!.durationMs).toBe(1234);
|
|
94
|
-
expect(record!.model).toBe('claude-sonnet-4-20250514');
|
|
95
|
-
expect(record!.tokensUsed).toBe(500);
|
|
96
|
-
expect(record!.costUsd).toBeCloseTo(0.0015, 6);
|
|
97
|
-
expect(record!.metadata).toEqual({ env: 'test' });
|
|
98
|
-
});
|
|
99
|
-
|
|
100
|
-
it('listOperations returns all saved operations ordered by timestamp desc', () => {
|
|
101
|
-
saveOperation(
|
|
102
|
-
{
|
|
103
|
-
id: 'op-a',
|
|
104
|
-
timestamp: new Date('2025-01-01'),
|
|
105
|
-
type: 'generate',
|
|
106
|
-
command: 'cmd1',
|
|
107
|
-
status: 'success',
|
|
108
|
-
},
|
|
109
|
-
db
|
|
110
|
-
);
|
|
111
|
-
saveOperation(
|
|
112
|
-
{
|
|
113
|
-
id: 'op-b',
|
|
114
|
-
timestamp: new Date('2025-01-03'),
|
|
115
|
-
type: 'generate',
|
|
116
|
-
command: 'cmd2',
|
|
117
|
-
status: 'success',
|
|
118
|
-
},
|
|
119
|
-
db
|
|
120
|
-
);
|
|
121
|
-
saveOperation(
|
|
122
|
-
{
|
|
123
|
-
id: 'op-c',
|
|
124
|
-
timestamp: new Date('2025-01-02'),
|
|
125
|
-
type: 'generate',
|
|
126
|
-
command: 'cmd3',
|
|
127
|
-
status: 'success',
|
|
128
|
-
},
|
|
129
|
-
db
|
|
130
|
-
);
|
|
131
|
-
|
|
132
|
-
const ops = listOperations(10, 0, db);
|
|
133
|
-
expect(ops.length).toBe(3);
|
|
134
|
-
// Most recent first
|
|
135
|
-
expect(ops[0].id).toBe('op-b');
|
|
136
|
-
expect(ops[2].id).toBe('op-a');
|
|
137
|
-
});
|
|
138
|
-
|
|
139
|
-
it('listOperationsByType filters correctly', () => {
|
|
140
|
-
saveOperation(
|
|
141
|
-
{ id: 'op-gen', timestamp: new Date(), type: 'generate', command: 'g', status: 'success' },
|
|
142
|
-
db
|
|
143
|
-
);
|
|
144
|
-
saveOperation(
|
|
145
|
-
{ id: 'op-chat', timestamp: new Date(), type: 'chat', command: 'c', status: 'success' },
|
|
146
|
-
db
|
|
147
|
-
);
|
|
148
|
-
|
|
149
|
-
const generated = listOperationsByType('generate', 10, 0, db);
|
|
150
|
-
const chats = listOperationsByType('chat', 10, 0, db);
|
|
151
|
-
|
|
152
|
-
expect(generated.every(o => o.type === 'generate')).toBe(true);
|
|
153
|
-
expect(chats.every(o => o.type === 'chat')).toBe(true);
|
|
154
|
-
});
|
|
155
|
-
});
|
|
156
|
-
|
|
157
|
-
// ---------------------------------------------------------------------------
|
|
158
|
-
// Conversations (messages)
|
|
159
|
-
// ---------------------------------------------------------------------------
|
|
160
|
-
|
|
161
|
-
describe('conversations CRUD', () => {
|
|
162
|
-
it('saves and retrieves a conversation by id', () => {
|
|
163
|
-
const msgs = [{ role: 'user', content: 'hello' }];
|
|
164
|
-
saveConversation('conv-001', 'My Chat', msgs, 'claude-sonnet-4-20250514', undefined, db);
|
|
165
|
-
|
|
166
|
-
const record = getConversation('conv-001', db);
|
|
167
|
-
expect(record).not.toBeNull();
|
|
168
|
-
expect(record!.id).toBe('conv-001');
|
|
169
|
-
expect(record!.title).toBe('My Chat');
|
|
170
|
-
expect(record!.model).toBe('claude-sonnet-4-20250514');
|
|
171
|
-
expect(record!.messages).toEqual(msgs);
|
|
172
|
-
});
|
|
173
|
-
|
|
174
|
-
it('returns null for a non-existent conversation id', () => {
|
|
175
|
-
expect(getConversation('no-such-id', db)).toBeNull();
|
|
176
|
-
});
|
|
177
|
-
|
|
178
|
-
it('upserts an existing conversation on duplicate id', () => {
|
|
179
|
-
const msgs1 = [{ role: 'user', content: 'first' }];
|
|
180
|
-
const msgs2 = [{ role: 'user', content: 'updated' }];
|
|
181
|
-
|
|
182
|
-
saveConversation('conv-002', 'Original', msgs1, undefined, undefined, db);
|
|
183
|
-
saveConversation('conv-002', 'Updated Title', msgs2, undefined, undefined, db);
|
|
184
|
-
|
|
185
|
-
const record = getConversation('conv-002', db);
|
|
186
|
-
expect(record!.title).toBe('Updated Title');
|
|
187
|
-
expect(record!.messages).toEqual(msgs2);
|
|
188
|
-
});
|
|
189
|
-
|
|
190
|
-
it('listConversations returns all saved conversations ordered by updated_at desc', () => {
|
|
191
|
-
saveConversation('c1', 'Chat 1', [], undefined, undefined, db);
|
|
192
|
-
saveConversation('c2', 'Chat 2', [], undefined, undefined, db);
|
|
193
|
-
saveConversation('c3', 'Chat 3', [], undefined, undefined, db);
|
|
194
|
-
|
|
195
|
-
const list = listConversations(10, 0, db);
|
|
196
|
-
expect(list.length).toBe(3);
|
|
197
|
-
});
|
|
198
|
-
|
|
199
|
-
it('deleteConversation removes the record', () => {
|
|
200
|
-
saveConversation('conv-del', 'To Delete', [], undefined, undefined, db);
|
|
201
|
-
deleteConversation('conv-del', db);
|
|
202
|
-
expect(getConversation('conv-del', db)).toBeNull();
|
|
203
|
-
});
|
|
204
|
-
|
|
205
|
-
it('saves metadata and retrieves it correctly', () => {
|
|
206
|
-
const meta = { source: 'cli', version: 2 };
|
|
207
|
-
saveConversation('conv-meta', 'Meta Chat', [], undefined, meta, db);
|
|
208
|
-
const record = getConversation('conv-meta', db);
|
|
209
|
-
expect(record!.metadata).toEqual(meta);
|
|
210
|
-
});
|
|
211
|
-
});
|
|
212
|
-
|
|
213
|
-
// ---------------------------------------------------------------------------
|
|
214
|
-
// Config key-value store
|
|
215
|
-
// ---------------------------------------------------------------------------
|
|
216
|
-
|
|
217
|
-
describe('config store', () => {
|
|
218
|
-
it('sets and retrieves a string value', () => {
|
|
219
|
-
setConfig('theme', 'dark', db);
|
|
220
|
-
expect(getConfig('theme', db)).toBe('dark');
|
|
221
|
-
});
|
|
222
|
-
|
|
223
|
-
it('returns null for a non-existent key', () => {
|
|
224
|
-
expect(getConfig('no-such-key', db)).toBeNull();
|
|
225
|
-
});
|
|
226
|
-
|
|
227
|
-
it('overwrites an existing key (REPLACE semantics)', () => {
|
|
228
|
-
setConfig('count', 1, db);
|
|
229
|
-
setConfig('count', 99, db);
|
|
230
|
-
expect(getConfig('count', db)).toBe(99);
|
|
231
|
-
});
|
|
232
|
-
|
|
233
|
-
it('sets and retrieves a complex object value', () => {
|
|
234
|
-
const value = { llm: { provider: 'anthropic', model: 'sonnet' } };
|
|
235
|
-
setConfig('llm-config', value, db);
|
|
236
|
-
expect(getConfig('llm-config', db)).toEqual(value);
|
|
237
|
-
});
|
|
238
|
-
|
|
239
|
-
it('getAllConfig returns all stored entries', () => {
|
|
240
|
-
setConfig('key-a', 'alpha', db);
|
|
241
|
-
setConfig('key-b', 42, db);
|
|
242
|
-
|
|
243
|
-
const all = getAllConfig(db);
|
|
244
|
-
expect(all['key-a']).toBe('alpha');
|
|
245
|
-
expect(all['key-b']).toBe(42);
|
|
246
|
-
});
|
|
247
|
-
|
|
248
|
-
it('getAllConfig returns an empty object when no config exists', () => {
|
|
249
|
-
const all = getAllConfig(db);
|
|
250
|
-
expect(typeof all).toBe('object');
|
|
251
|
-
});
|
|
252
|
-
});
|
|
253
|
-
|
|
254
|
-
// ---------------------------------------------------------------------------
|
|
255
|
-
// Artifacts
|
|
256
|
-
// ---------------------------------------------------------------------------
|
|
257
|
-
|
|
258
|
-
describe('artifacts CRUD', () => {
|
|
259
|
-
it('saves and retrieves an artifact by id', () => {
|
|
260
|
-
saveArtifact(
|
|
261
|
-
'art-001',
|
|
262
|
-
null,
|
|
263
|
-
'main.tf',
|
|
264
|
-
'terraform',
|
|
265
|
-
'resource "aws_vpc" "main" {}',
|
|
266
|
-
'hcl',
|
|
267
|
-
undefined,
|
|
268
|
-
db
|
|
269
|
-
);
|
|
270
|
-
|
|
271
|
-
const record = getArtifact('art-001', db);
|
|
272
|
-
expect(record).not.toBeNull();
|
|
273
|
-
expect(record!.id).toBe('art-001');
|
|
274
|
-
expect(record!.name).toBe('main.tf');
|
|
275
|
-
expect(record!.type).toBe('terraform');
|
|
276
|
-
expect(record!.content).toBe('resource "aws_vpc" "main" {}');
|
|
277
|
-
expect(record!.language).toBe('hcl');
|
|
278
|
-
});
|
|
279
|
-
|
|
280
|
-
it('returns null for a non-existent artifact id', () => {
|
|
281
|
-
expect(getArtifact('ghost', db)).toBeNull();
|
|
282
|
-
});
|
|
283
|
-
|
|
284
|
-
it('upserts on duplicate artifact id', () => {
|
|
285
|
-
saveArtifact('art-002', null, 'file.tf', 'terraform', 'original', undefined, undefined, db);
|
|
286
|
-
saveArtifact(
|
|
287
|
-
'art-002',
|
|
288
|
-
null,
|
|
289
|
-
'file.tf',
|
|
290
|
-
'terraform',
|
|
291
|
-
'updated content',
|
|
292
|
-
undefined,
|
|
293
|
-
undefined,
|
|
294
|
-
db
|
|
295
|
-
);
|
|
296
|
-
|
|
297
|
-
const record = getArtifact('art-002', db);
|
|
298
|
-
expect(record!.content).toBe('updated content');
|
|
299
|
-
});
|
|
300
|
-
|
|
301
|
-
it('listArtifacts with type filter returns only matching records', () => {
|
|
302
|
-
saveArtifact('art-tf', null, 'a.tf', 'terraform', '', undefined, undefined, db);
|
|
303
|
-
saveArtifact('art-k8s', null, 'b.yaml', 'kubernetes', '', undefined, undefined, db);
|
|
304
|
-
|
|
305
|
-
const tfArtifacts = listArtifacts('terraform', undefined, 10, 0, db);
|
|
306
|
-
expect(tfArtifacts.every(a => a.type === 'terraform')).toBe(true);
|
|
307
|
-
|
|
308
|
-
const k8sArtifacts = listArtifacts('kubernetes', undefined, 10, 0, db);
|
|
309
|
-
expect(k8sArtifacts.every(a => a.type === 'kubernetes')).toBe(true);
|
|
310
|
-
});
|
|
311
|
-
|
|
312
|
-
it('listArtifacts with conversationId filter returns only matching records', () => {
|
|
313
|
-
saveArtifact('art-c1a', 'conv-A', 'x.tf', 'terraform', '', undefined, undefined, db);
|
|
314
|
-
saveArtifact('art-c1b', 'conv-A', 'y.tf', 'terraform', '', undefined, undefined, db);
|
|
315
|
-
saveArtifact('art-c2', 'conv-B', 'z.tf', 'terraform', '', undefined, undefined, db);
|
|
316
|
-
|
|
317
|
-
const forConvA = listArtifacts(undefined, 'conv-A', 10, 0, db);
|
|
318
|
-
expect(forConvA.length).toBe(2);
|
|
319
|
-
expect(forConvA.every(a => a.conversationId === 'conv-A')).toBe(true);
|
|
320
|
-
});
|
|
321
|
-
|
|
322
|
-
it('deleteArtifact removes the record', () => {
|
|
323
|
-
saveArtifact('art-del', null, 'del.tf', 'terraform', 'x', undefined, undefined, db);
|
|
324
|
-
deleteArtifact('art-del', db);
|
|
325
|
-
expect(getArtifact('art-del', db)).toBeNull();
|
|
326
|
-
});
|
|
327
|
-
|
|
328
|
-
it('saves and retrieves artifact metadata', () => {
|
|
329
|
-
const meta = { generated_by: 'nimbus', version: 1 };
|
|
330
|
-
saveArtifact('art-meta', null, 'meta.tf', 'terraform', '', undefined, meta, db);
|
|
331
|
-
const record = getArtifact('art-meta', db);
|
|
332
|
-
expect(record!.metadata).toEqual(meta);
|
|
333
|
-
});
|
|
334
|
-
});
|
|
@@ -1,158 +0,0 @@
|
|
|
1
|
-
/**
|
|
2
|
-
* Tests for the nimbus status command (G18).
|
|
3
|
-
*
|
|
4
|
-
* The statusCommand runs concurrent CLI checks. We test the module structure
|
|
5
|
-
* and basic argument parsing rather than the actual CLI calls to avoid
|
|
6
|
-
* platform dependencies.
|
|
7
|
-
*/
|
|
8
|
-
|
|
9
|
-
import { describe, test, expect } from 'vitest';
|
|
10
|
-
import { statusCommand, type StatusOptions } from '../commands/status';
|
|
11
|
-
|
|
12
|
-
describe('statusCommand (G18)', () => {
|
|
13
|
-
test('exports statusCommand function', () => {
|
|
14
|
-
expect(typeof statusCommand).toBe('function');
|
|
15
|
-
});
|
|
16
|
-
|
|
17
|
-
test('StatusOptions accepts json flag', () => {
|
|
18
|
-
const opts: StatusOptions = { json: true };
|
|
19
|
-
expect(opts.json).toBe(true);
|
|
20
|
-
});
|
|
21
|
-
|
|
22
|
-
test('StatusOptions json defaults to undefined', () => {
|
|
23
|
-
const opts: StatusOptions = {};
|
|
24
|
-
expect(opts.json).toBeUndefined();
|
|
25
|
-
});
|
|
26
|
-
|
|
27
|
-
test('statusCommand resolves without throwing when CLIs are unavailable', async () => {
|
|
28
|
-
// Mock console.log to suppress output in test
|
|
29
|
-
const original = console.log;
|
|
30
|
-
const logs: string[] = [];
|
|
31
|
-
console.log = (msg: string) => logs.push(msg);
|
|
32
|
-
|
|
33
|
-
try {
|
|
34
|
-
// Should not throw even if kubectl/terraform/aws/gcloud are not installed
|
|
35
|
-
// (the command catches errors gracefully)
|
|
36
|
-
await expect(statusCommand({ json: true })).resolves.toBeUndefined();
|
|
37
|
-
} finally {
|
|
38
|
-
console.log = original;
|
|
39
|
-
}
|
|
40
|
-
});
|
|
41
|
-
|
|
42
|
-
test('statusCommand with json option outputs valid JSON', async () => {
|
|
43
|
-
const original = console.log;
|
|
44
|
-
let jsonOutput = '';
|
|
45
|
-
console.log = (msg: string) => { jsonOutput = msg; };
|
|
46
|
-
|
|
47
|
-
try {
|
|
48
|
-
await statusCommand({ json: true });
|
|
49
|
-
// Should produce valid JSON
|
|
50
|
-
const parsed = JSON.parse(jsonOutput);
|
|
51
|
-
expect(parsed).toBeTypeOf('object');
|
|
52
|
-
// Should have an errors array
|
|
53
|
-
expect(Array.isArray(parsed.errors)).toBe(true);
|
|
54
|
-
} finally {
|
|
55
|
-
console.log = original;
|
|
56
|
-
}
|
|
57
|
-
});
|
|
58
|
-
});
|
|
59
|
-
|
|
60
|
-
describe('statusCommand C2 enhancements', () => {
|
|
61
|
-
test('JSON output includes model field with default fallback', async () => {
|
|
62
|
-
const original = console.log;
|
|
63
|
-
let jsonOutput = '';
|
|
64
|
-
console.log = (msg: string) => { jsonOutput = msg; };
|
|
65
|
-
|
|
66
|
-
try {
|
|
67
|
-
await statusCommand({ json: true });
|
|
68
|
-
const parsed = JSON.parse(jsonOutput) as Record<string, unknown>;
|
|
69
|
-
// model should be set (either from config.json or default 'claude-sonnet-4-6')
|
|
70
|
-
expect(typeof parsed.model).toBe('string');
|
|
71
|
-
expect((parsed.model as string).length).toBeGreaterThan(0);
|
|
72
|
-
} finally {
|
|
73
|
-
console.log = original;
|
|
74
|
-
}
|
|
75
|
-
});
|
|
76
|
-
|
|
77
|
-
test('JSON output includes provider field with default fallback', async () => {
|
|
78
|
-
const original = console.log;
|
|
79
|
-
let jsonOutput = '';
|
|
80
|
-
console.log = (msg: string) => { jsonOutput = msg; };
|
|
81
|
-
|
|
82
|
-
try {
|
|
83
|
-
await statusCommand({ json: true });
|
|
84
|
-
const parsed = JSON.parse(jsonOutput) as Record<string, unknown>;
|
|
85
|
-
// provider should be set (either from config.json or default 'anthropic')
|
|
86
|
-
expect(typeof parsed.provider).toBe('string');
|
|
87
|
-
expect((parsed.provider as string).length).toBeGreaterThan(0);
|
|
88
|
-
} finally {
|
|
89
|
-
console.log = original;
|
|
90
|
-
}
|
|
91
|
-
});
|
|
92
|
-
|
|
93
|
-
test('JSON output includes nimbusMdFound field', async () => {
|
|
94
|
-
const original = console.log;
|
|
95
|
-
let jsonOutput = '';
|
|
96
|
-
console.log = (msg: string) => { jsonOutput = msg; };
|
|
97
|
-
|
|
98
|
-
try {
|
|
99
|
-
await statusCommand({ json: true });
|
|
100
|
-
const parsed = JSON.parse(jsonOutput) as Record<string, unknown>;
|
|
101
|
-
// nimbusMdFound should be a boolean (true or undefined/false)
|
|
102
|
-
expect(
|
|
103
|
-
parsed.nimbusMdFound === undefined || typeof parsed.nimbusMdFound === 'boolean'
|
|
104
|
-
).toBe(true);
|
|
105
|
-
} finally {
|
|
106
|
-
console.log = original;
|
|
107
|
-
}
|
|
108
|
-
});
|
|
109
|
-
|
|
110
|
-
test('JSON output includes sessionCount field', async () => {
|
|
111
|
-
const original = console.log;
|
|
112
|
-
let jsonOutput = '';
|
|
113
|
-
console.log = (msg: string) => { jsonOutput = msg; };
|
|
114
|
-
|
|
115
|
-
try {
|
|
116
|
-
await statusCommand({ json: true });
|
|
117
|
-
const parsed = JSON.parse(jsonOutput) as Record<string, unknown>;
|
|
118
|
-
// sessionCount should be a number or 'N/A'
|
|
119
|
-
expect(
|
|
120
|
-
typeof parsed.sessionCount === 'number' || parsed.sessionCount === 'N/A'
|
|
121
|
-
).toBe(true);
|
|
122
|
-
} finally {
|
|
123
|
-
console.log = original;
|
|
124
|
-
}
|
|
125
|
-
});
|
|
126
|
-
|
|
127
|
-
test('default model is claude-sonnet-4-6 when config.json is absent', async () => {
|
|
128
|
-
const original = console.log;
|
|
129
|
-
let jsonOutput = '';
|
|
130
|
-
console.log = (msg: string) => { jsonOutput = msg; };
|
|
131
|
-
|
|
132
|
-
// We can test this by verifying the model is never empty
|
|
133
|
-
try {
|
|
134
|
-
await statusCommand({ json: true });
|
|
135
|
-
const parsed = JSON.parse(jsonOutput) as Record<string, unknown>;
|
|
136
|
-
// Model should be a non-empty string
|
|
137
|
-
expect(typeof parsed.model).toBe('string');
|
|
138
|
-
expect((parsed.model as string).length).toBeGreaterThan(0);
|
|
139
|
-
} finally {
|
|
140
|
-
console.log = original;
|
|
141
|
-
}
|
|
142
|
-
});
|
|
143
|
-
|
|
144
|
-
test('default provider is anthropic when config.json is absent', async () => {
|
|
145
|
-
const original = console.log;
|
|
146
|
-
let jsonOutput = '';
|
|
147
|
-
console.log = (msg: string) => { jsonOutput = msg; };
|
|
148
|
-
|
|
149
|
-
try {
|
|
150
|
-
await statusCommand({ json: true });
|
|
151
|
-
const parsed = JSON.parse(jsonOutput) as Record<string, unknown>;
|
|
152
|
-
expect(typeof parsed.provider).toBe('string');
|
|
153
|
-
expect((parsed.provider as string).length).toBeGreaterThan(0);
|
|
154
|
-
} finally {
|
|
155
|
-
console.log = original;
|
|
156
|
-
}
|
|
157
|
-
});
|
|
158
|
-
});
|