@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
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
*/
|
|
8
8
|
import { logger } from '../utils';
|
|
9
9
|
import { createWizard, ui, select, confirm, input, } from '../wizard';
|
|
10
|
-
import { authStore, AuthStore, getProviderInfo, getProviderNames, getDefaultModel, validateProviderApiKey,
|
|
10
|
+
import { authStore, AuthStore, getProviderInfo, getProviderNames, getDefaultModel, validateProviderApiKey, } from '../auth';
|
|
11
11
|
/**
|
|
12
12
|
* Run the login command
|
|
13
13
|
*/
|
|
@@ -54,27 +54,20 @@ function createWizardSteps() {
|
|
|
54
54
|
title: 'Welcome',
|
|
55
55
|
execute: welcomeStep,
|
|
56
56
|
},
|
|
57
|
-
// Step 2:
|
|
58
|
-
{
|
|
59
|
-
id: 'github-identity',
|
|
60
|
-
title: 'GitHub Identity',
|
|
61
|
-
execute: githubIdentityStep,
|
|
62
|
-
canSkip: true,
|
|
63
|
-
},
|
|
64
|
-
// Step 3: LLM Provider Configuration Loop
|
|
57
|
+
// Step 2: LLM Provider Configuration Loop
|
|
65
58
|
{
|
|
66
59
|
id: 'providers-loop',
|
|
67
60
|
title: 'LLM Provider Configuration',
|
|
68
61
|
execute: providersLoopStep,
|
|
69
62
|
},
|
|
70
|
-
// Step
|
|
63
|
+
// Step 3: Set Default Provider
|
|
71
64
|
{
|
|
72
65
|
id: 'set-default',
|
|
73
66
|
title: 'Set Default Provider',
|
|
74
67
|
execute: setDefaultStep,
|
|
75
68
|
condition: ctx => ctx.configuredProviders.length > 1,
|
|
76
69
|
},
|
|
77
|
-
// Step
|
|
70
|
+
// Step 4: Complete
|
|
78
71
|
{
|
|
79
72
|
id: 'complete',
|
|
80
73
|
title: 'Setup Complete',
|
|
@@ -126,87 +119,7 @@ async function welcomeStep(_ctx) {
|
|
|
126
119
|
return { success: true };
|
|
127
120
|
}
|
|
128
121
|
/**
|
|
129
|
-
* Step 2:
|
|
130
|
-
*/
|
|
131
|
-
async function githubIdentityStep(_ctx) {
|
|
132
|
-
ui.section('GitHub Identity (Optional)');
|
|
133
|
-
// Check if already authenticated
|
|
134
|
-
const existingIdentity = authStore.getIdentity();
|
|
135
|
-
if (existingIdentity) {
|
|
136
|
-
ui.info(`Currently signed in as: ${existingIdentity.username}`);
|
|
137
|
-
const useExisting = await confirm({
|
|
138
|
-
message: 'Keep existing GitHub identity?',
|
|
139
|
-
defaultValue: true,
|
|
140
|
-
});
|
|
141
|
-
if (useExisting) {
|
|
142
|
-
return { success: true, data: { githubIdentity: existingIdentity } };
|
|
143
|
-
}
|
|
144
|
-
}
|
|
145
|
-
// Ask if they want to sign in with GitHub
|
|
146
|
-
const shouldSignIn = await confirm({
|
|
147
|
-
message: 'Sign in with GitHub?',
|
|
148
|
-
defaultValue: true,
|
|
149
|
-
});
|
|
150
|
-
if (!shouldSignIn) {
|
|
151
|
-
ui.info('Skipping GitHub sign-in');
|
|
152
|
-
return { success: true, data: { skipGitHub: true } };
|
|
153
|
-
}
|
|
154
|
-
// GitHub Device Flow
|
|
155
|
-
ui.newLine();
|
|
156
|
-
ui.info('Starting GitHub Device Flow authentication...');
|
|
157
|
-
ui.newLine();
|
|
158
|
-
try {
|
|
159
|
-
const deviceFlow = new GitHubDeviceFlow();
|
|
160
|
-
// Request device code
|
|
161
|
-
ui.startSpinner({ message: 'Requesting authorization code...' });
|
|
162
|
-
const deviceCode = await deviceFlow.requestDeviceCode();
|
|
163
|
-
ui.stopSpinnerSuccess('Authorization code received');
|
|
164
|
-
// Display code for user
|
|
165
|
-
ui.newLine();
|
|
166
|
-
ui.box({
|
|
167
|
-
title: 'GitHub Authorization',
|
|
168
|
-
content: [
|
|
169
|
-
`Open ${deviceCode.verification_uri} in your browser`,
|
|
170
|
-
'and enter this code:',
|
|
171
|
-
'',
|
|
172
|
-
` ${deviceCode.user_code}`,
|
|
173
|
-
'',
|
|
174
|
-
'Waiting for authorization...',
|
|
175
|
-
],
|
|
176
|
-
style: 'rounded',
|
|
177
|
-
borderColor: 'yellow',
|
|
178
|
-
padding: 1,
|
|
179
|
-
});
|
|
180
|
-
ui.newLine();
|
|
181
|
-
// Poll for authorization
|
|
182
|
-
ui.startSpinner({ message: 'Waiting for authorization...' });
|
|
183
|
-
const accessToken = await deviceFlow.waitForAuthorization(() => {
|
|
184
|
-
// This callback is called on each poll
|
|
185
|
-
});
|
|
186
|
-
ui.stopSpinnerSuccess('Authorization successful');
|
|
187
|
-
// Fetch user profile
|
|
188
|
-
ui.startSpinner({ message: 'Fetching user profile...' });
|
|
189
|
-
const identity = await completeGitHubAuth(accessToken);
|
|
190
|
-
ui.stopSpinnerSuccess(`Signed in as ${identity.username}${identity.name ? ` (${identity.name})` : ''}`);
|
|
191
|
-
// Save identity
|
|
192
|
-
authStore.setIdentity(identity);
|
|
193
|
-
return { success: true, data: { githubIdentity: identity } };
|
|
194
|
-
}
|
|
195
|
-
catch (error) {
|
|
196
|
-
const message = error instanceof Error ? error.message : 'Unknown error';
|
|
197
|
-
ui.stopSpinnerFail(`GitHub authentication failed: ${message}`);
|
|
198
|
-
const skipGitHub = await confirm({
|
|
199
|
-
message: 'Continue without GitHub sign-in?',
|
|
200
|
-
defaultValue: true,
|
|
201
|
-
});
|
|
202
|
-
if (skipGitHub) {
|
|
203
|
-
return { success: true, data: { skipGitHub: true } };
|
|
204
|
-
}
|
|
205
|
-
return { success: false, error: message };
|
|
206
|
-
}
|
|
207
|
-
}
|
|
208
|
-
/**
|
|
209
|
-
* Step 3: LLM Provider Configuration Loop
|
|
122
|
+
* Step 2 (now Step 2): LLM Provider Configuration Loop
|
|
210
123
|
*/
|
|
211
124
|
async function providersLoopStep(_ctx) {
|
|
212
125
|
ui.section('LLM Provider Configuration');
|
|
@@ -438,6 +351,9 @@ async function completeStep(ctx) {
|
|
|
438
351
|
// Next steps
|
|
439
352
|
content.push('Run `nimbus generate terraform` to get started!');
|
|
440
353
|
content.push('');
|
|
354
|
+
content.push('To link your GitHub identity (optional):');
|
|
355
|
+
content.push(' run nimbus connect github');
|
|
356
|
+
content.push('');
|
|
441
357
|
ui.box({
|
|
442
358
|
title: '✓ Setup Complete',
|
|
443
359
|
content,
|
|
@@ -500,7 +416,6 @@ async function runNonInteractive(options) {
|
|
|
500
416
|
*/
|
|
501
417
|
export async function loginCloudCommand(provider) {
|
|
502
418
|
const { execFileSync } = await import('node:child_process');
|
|
503
|
-
const { existsSync } = await import('node:fs');
|
|
504
419
|
const { execSync } = await import('node:child_process');
|
|
505
420
|
const checkInPath = (cmd) => {
|
|
506
421
|
try {
|
|
@@ -13,18 +13,24 @@ import { ui } from '../wizard/ui';
|
|
|
13
13
|
*/
|
|
14
14
|
function buildArgs(pod, options) {
|
|
15
15
|
const args = ['logs', pod];
|
|
16
|
-
if (options.namespace)
|
|
16
|
+
if (options.namespace) {
|
|
17
17
|
args.push('-n', options.namespace);
|
|
18
|
-
|
|
18
|
+
}
|
|
19
|
+
if (options.follow) {
|
|
19
20
|
args.push('--follow');
|
|
20
|
-
|
|
21
|
+
}
|
|
22
|
+
if (options.previous) {
|
|
21
23
|
args.push('--previous');
|
|
22
|
-
|
|
24
|
+
}
|
|
25
|
+
if (options.tail !== undefined) {
|
|
23
26
|
args.push('--tail', String(options.tail));
|
|
24
|
-
|
|
27
|
+
}
|
|
28
|
+
if (options.container) {
|
|
25
29
|
args.push('-c', options.container);
|
|
26
|
-
|
|
30
|
+
}
|
|
31
|
+
if (options.context) {
|
|
27
32
|
args.push('--context', options.context);
|
|
33
|
+
}
|
|
28
34
|
return args;
|
|
29
35
|
}
|
|
30
36
|
/**
|
|
@@ -97,10 +103,12 @@ export async function logsCommand(pod, options = {}) {
|
|
|
97
103
|
});
|
|
98
104
|
await new Promise((resolve, reject) => {
|
|
99
105
|
child.on('close', code => {
|
|
100
|
-
if (code !== 0)
|
|
106
|
+
if (code !== 0) {
|
|
101
107
|
reject(new Error(`kubectl logs exited with code ${code}`));
|
|
102
|
-
|
|
108
|
+
}
|
|
109
|
+
else {
|
|
103
110
|
resolve();
|
|
111
|
+
}
|
|
104
112
|
});
|
|
105
113
|
child.on('error', reject);
|
|
106
114
|
});
|
|
@@ -187,15 +187,17 @@ export async function onboardingCommand(options = {}) {
|
|
|
187
187
|
});
|
|
188
188
|
}
|
|
189
189
|
// Detect live infra stack from current directory (Terraform, K8s, Helm, etc.)
|
|
190
|
-
|
|
190
|
+
const detectedInfraStack = [];
|
|
191
191
|
try {
|
|
192
192
|
const { existsSync, readdirSync } = await import('node:fs');
|
|
193
193
|
const cwd = process.cwd();
|
|
194
194
|
const files = readdirSync(cwd);
|
|
195
|
-
if (files.some(f => f.endsWith('.tf') || f === 'terraform'))
|
|
195
|
+
if (files.some(f => f.endsWith('.tf') || f === 'terraform')) {
|
|
196
196
|
detectedInfraStack.push('terraform');
|
|
197
|
-
|
|
197
|
+
}
|
|
198
|
+
if (files.some(f => f === 'Chart.yaml' || f === 'helmfile.yaml')) {
|
|
198
199
|
detectedInfraStack.push('helm');
|
|
200
|
+
}
|
|
199
201
|
if (files.some(f => f.endsWith('.yaml') || f.endsWith('.yml'))) {
|
|
200
202
|
// Check if any yaml looks like K8s
|
|
201
203
|
const yamls = files.filter(f => f.endsWith('.yaml') || f.endsWith('.yml')).slice(0, 5);
|
|
@@ -306,7 +308,7 @@ export async function onboardingCommand(options = {}) {
|
|
|
306
308
|
await runInit({ cwd: process.cwd(), quiet: false });
|
|
307
309
|
ui.stopSpinnerSuccess('NIMBUS.md generated — your infra context is ready');
|
|
308
310
|
}
|
|
309
|
-
catch (
|
|
311
|
+
catch (_initErr) {
|
|
310
312
|
ui.stopSpinnerFail('Could not generate NIMBUS.md (run `nimbus init` manually)');
|
|
311
313
|
}
|
|
312
314
|
}
|
|
@@ -15,12 +15,15 @@ import { ui } from '../wizard/ui';
|
|
|
15
15
|
* Auto-detect the CI/CD provider by scanning the cwd for config files.
|
|
16
16
|
*/
|
|
17
17
|
export function detectProvider(cwd = process.cwd()) {
|
|
18
|
-
if (fs.existsSync(path.join(cwd, '.github', 'workflows')))
|
|
18
|
+
if (fs.existsSync(path.join(cwd, '.github', 'workflows'))) {
|
|
19
19
|
return 'github';
|
|
20
|
-
|
|
20
|
+
}
|
|
21
|
+
if (fs.existsSync(path.join(cwd, '.gitlab-ci.yml'))) {
|
|
21
22
|
return 'gitlab';
|
|
22
|
-
|
|
23
|
+
}
|
|
24
|
+
if (fs.existsSync(path.join(cwd, '.circleci', 'config.yml'))) {
|
|
23
25
|
return 'circleci';
|
|
26
|
+
}
|
|
24
27
|
return null;
|
|
25
28
|
}
|
|
26
29
|
function fetchGitHubRuns(limit, runId) {
|
|
@@ -157,7 +157,7 @@ export async function mcpCommand(subcommand, args) {
|
|
|
157
157
|
// stdio: spawn briefly and send a tools/list JSON-RPC message
|
|
158
158
|
ui.startSpinner({ message: `Testing MCP server "${name}" (stdio)...` });
|
|
159
159
|
try {
|
|
160
|
-
const testPayload = JSON.stringify({ jsonrpc: '2.0', id: 1, method: 'tools/list', params: {} })
|
|
160
|
+
const testPayload = `${JSON.stringify({ jsonrpc: '2.0', id: 1, method: 'tools/list', params: {} })}\n`;
|
|
161
161
|
const result = execFileSync(server.command, server.args ?? [], {
|
|
162
162
|
input: testPayload,
|
|
163
163
|
encoding: 'utf-8',
|
|
@@ -210,8 +210,9 @@ export async function pluginCommand(subcommand, args) {
|
|
|
210
210
|
ui.header('Installed Plugins');
|
|
211
211
|
for (const p of registry.plugins) {
|
|
212
212
|
ui.print(` ${ui.color(p.name, 'cyan')} — ${p.description ?? p.command}`);
|
|
213
|
-
if (p.args)
|
|
213
|
+
if (p.args) {
|
|
214
214
|
ui.print(` args: ${p.args.join(' ')}`);
|
|
215
|
+
}
|
|
215
216
|
}
|
|
216
217
|
break;
|
|
217
218
|
}
|
|
@@ -44,8 +44,9 @@ export function saveProfiles(profiles) {
|
|
|
44
44
|
/** Get the name of the currently active profile (if any). */
|
|
45
45
|
export function getCurrentProfileName() {
|
|
46
46
|
// Check env var first
|
|
47
|
-
if (process.env.NIMBUS_PROFILE)
|
|
47
|
+
if (process.env.NIMBUS_PROFILE) {
|
|
48
48
|
return process.env.NIMBUS_PROFILE;
|
|
49
|
+
}
|
|
49
50
|
try {
|
|
50
51
|
if (fs.existsSync(CURRENT_PROFILE_PATH)) {
|
|
51
52
|
return fs.readFileSync(CURRENT_PROFILE_PATH, 'utf-8').trim() || null;
|
|
@@ -79,18 +80,24 @@ async function listProfiles() {
|
|
|
79
80
|
const profile = profiles[name];
|
|
80
81
|
const marker = name === current ? ui.color('* ', 'green') : ' ';
|
|
81
82
|
ui.print(`${marker}${name}`);
|
|
82
|
-
if (profile.awsProfile)
|
|
83
|
+
if (profile.awsProfile) {
|
|
83
84
|
ui.print(` AWS profile: ${profile.awsProfile}`);
|
|
84
|
-
|
|
85
|
+
}
|
|
86
|
+
if (profile.tfWorkspace) {
|
|
85
87
|
ui.print(` TF workspace: ${profile.tfWorkspace}`);
|
|
86
|
-
|
|
88
|
+
}
|
|
89
|
+
if (profile.kubectlContext) {
|
|
87
90
|
ui.print(` kubectl context: ${profile.kubectlContext}`);
|
|
88
|
-
|
|
91
|
+
}
|
|
92
|
+
if (profile.gcpProject) {
|
|
89
93
|
ui.print(` GCP project: ${profile.gcpProject}`);
|
|
90
|
-
|
|
94
|
+
}
|
|
95
|
+
if (profile.azureSubscription) {
|
|
91
96
|
ui.print(` Azure subscription: ${profile.azureSubscription}`);
|
|
92
|
-
|
|
97
|
+
}
|
|
98
|
+
if (profile.k8sNamespace) {
|
|
93
99
|
ui.print(` K8s namespace: ${profile.k8sNamespace}`);
|
|
100
|
+
}
|
|
94
101
|
}
|
|
95
102
|
if (current) {
|
|
96
103
|
ui.newLine();
|
|
@@ -118,22 +125,28 @@ async function createProfile(name) {
|
|
|
118
125
|
const azureSubscription = await inputPrompt({ message: 'Azure subscription ID', defaultValue: '' });
|
|
119
126
|
const k8sNamespace = await inputPrompt({ message: 'Default K8s namespace', defaultValue: '' });
|
|
120
127
|
const profile = {};
|
|
121
|
-
if (awsProfile)
|
|
128
|
+
if (awsProfile) {
|
|
122
129
|
profile.awsProfile = awsProfile;
|
|
123
|
-
|
|
130
|
+
}
|
|
131
|
+
if (tfWorkspace) {
|
|
124
132
|
profile.tfWorkspace = tfWorkspace;
|
|
125
|
-
|
|
133
|
+
}
|
|
134
|
+
if (kubectlContext) {
|
|
126
135
|
profile.kubectlContext = kubectlContext;
|
|
127
|
-
|
|
136
|
+
}
|
|
137
|
+
if (gcpProject) {
|
|
128
138
|
profile.gcpProject = gcpProject;
|
|
129
|
-
|
|
139
|
+
}
|
|
140
|
+
if (azureSubscription) {
|
|
130
141
|
profile.azureSubscription = azureSubscription;
|
|
131
|
-
|
|
142
|
+
}
|
|
143
|
+
if (k8sNamespace) {
|
|
132
144
|
profile.k8sNamespace = k8sNamespace;
|
|
145
|
+
}
|
|
133
146
|
profiles[name] = profile;
|
|
134
147
|
saveProfiles(profiles);
|
|
135
148
|
ui.print(`${ui.color('✓', 'green')} Profile "${name}" created.`);
|
|
136
|
-
ui.dim(
|
|
149
|
+
ui.dim(`Activate it with: nimbus profile set ${name}`);
|
|
137
150
|
}
|
|
138
151
|
async function setProfile(name) {
|
|
139
152
|
if (!name) {
|
|
@@ -190,8 +190,9 @@ async function rollbackTerraformState(dir, run) {
|
|
|
190
190
|
ui.print(` ${line}`);
|
|
191
191
|
}
|
|
192
192
|
const total = stateList.split('\n').length;
|
|
193
|
-
if (total > 20)
|
|
193
|
+
if (total > 20) {
|
|
194
194
|
ui.dim(` ... and ${total - 20} more`);
|
|
195
|
+
}
|
|
195
196
|
ui.newLine();
|
|
196
197
|
}
|
|
197
198
|
// Rollback guidance specific to state
|
|
@@ -199,7 +200,7 @@ async function rollbackTerraformState(dir, run) {
|
|
|
199
200
|
title: `Terraform State Rollback — workspace: ${currentWorkspace}`,
|
|
200
201
|
content: [
|
|
201
202
|
'',
|
|
202
|
-
|
|
203
|
+
`To roll back Terraform state in workspace "${currentWorkspace}":`,
|
|
203
204
|
'',
|
|
204
205
|
'1. Pull current state:',
|
|
205
206
|
' terraform state pull > state-backup.tfstate',
|
|
@@ -39,8 +39,9 @@ export async function rolloutCommand(options) {
|
|
|
39
39
|
const combined = [result.stdout, result.stderr].filter(Boolean).join('\n');
|
|
40
40
|
if (result.exitCode !== 0) {
|
|
41
41
|
console.error(`\nRollout failed (exit code ${result.exitCode}):`);
|
|
42
|
-
if (combined)
|
|
42
|
+
if (combined) {
|
|
43
43
|
console.error(combined);
|
|
44
|
+
}
|
|
44
45
|
process.exitCode = 1;
|
|
45
46
|
}
|
|
46
47
|
else {
|
|
@@ -62,8 +63,9 @@ export async function rolloutCommand(options) {
|
|
|
62
63
|
*/
|
|
63
64
|
export function parseTimeoutToMs(timeout) {
|
|
64
65
|
const match = timeout.match(/^(\d+)(s|m|h)$/);
|
|
65
|
-
if (!match)
|
|
66
|
-
return 300_000;
|
|
66
|
+
if (!match) {
|
|
67
|
+
return 300_000;
|
|
68
|
+
} // default 5 min
|
|
67
69
|
const value = parseInt(match[1]);
|
|
68
70
|
switch (match[2]) {
|
|
69
71
|
case 's': return value * 1000;
|
|
@@ -36,8 +36,9 @@ const RUNBOOK_DIRS = [
|
|
|
36
36
|
function findRunbooks() {
|
|
37
37
|
const results = [];
|
|
38
38
|
for (const dir of RUNBOOK_DIRS) {
|
|
39
|
-
if (!existsSync(dir))
|
|
39
|
+
if (!existsSync(dir)) {
|
|
40
40
|
continue;
|
|
41
|
+
}
|
|
41
42
|
try {
|
|
42
43
|
const files = readdirSync(dir).filter(f => /\.(yaml|yml)$/.test(f));
|
|
43
44
|
for (const file of files) {
|
|
@@ -74,8 +75,9 @@ function parseRunbookYaml(content) {
|
|
|
74
75
|
};
|
|
75
76
|
for (const raw of lines) {
|
|
76
77
|
const line = raw.trimEnd();
|
|
77
|
-
if (line.startsWith('#') || !line.trim())
|
|
78
|
+
if (line.startsWith('#') || !line.trim()) {
|
|
78
79
|
continue;
|
|
80
|
+
}
|
|
79
81
|
if (line.startsWith('name:') && !inSteps) {
|
|
80
82
|
def.name = line.slice(5).trim().replace(/^['"]|['"]$/g, '');
|
|
81
83
|
}
|
|
@@ -110,8 +112,9 @@ function parseRunbookYaml(content) {
|
|
|
110
112
|
else if (currentStep && /^\s+(name|run|action):/.test(line)) {
|
|
111
113
|
// Structured field continuation inside a step block
|
|
112
114
|
const val = line.replace(/^\s+(name|run|action):\s*/, '').replace(/^['"]|['"]$/g, '');
|
|
113
|
-
if (!currentStep.text)
|
|
115
|
+
if (!currentStep.text) {
|
|
114
116
|
currentStep.text = val;
|
|
117
|
+
}
|
|
115
118
|
}
|
|
116
119
|
else if (currentStep && /^\s+if:/.test(line)) {
|
|
117
120
|
const val = line.replace(/^\s+if:\s*/, '').replace(/^['"]|['"]$/g, '');
|
|
@@ -139,10 +142,12 @@ function buildRunbookPrompt(def) {
|
|
|
139
142
|
const parts = [
|
|
140
143
|
`# Runbook: ${def.name}`,
|
|
141
144
|
];
|
|
142
|
-
if (def.description)
|
|
145
|
+
if (def.description) {
|
|
143
146
|
parts.push(`\n${def.description}`);
|
|
144
|
-
|
|
147
|
+
}
|
|
148
|
+
if (def.context) {
|
|
145
149
|
parts.push(`\nContext/profile: ${def.context}`);
|
|
150
|
+
}
|
|
146
151
|
parts.push('\n## Steps to execute in order:');
|
|
147
152
|
def.steps.forEach((step, i) => {
|
|
148
153
|
// GAP-24: In step parsing loop
|
|
@@ -155,7 +160,7 @@ function buildRunbookPrompt(def) {
|
|
|
155
160
|
}
|
|
156
161
|
if (requireApproval) {
|
|
157
162
|
stepText += `\n [REQUIRES APPROVAL: State this step's plan and wait for explicit user approval before executing]`;
|
|
158
|
-
stepText = `IMPORTANT: Before executing this step, explicitly state what you are about to do and wait for the user to say "approve" or "yes" before proceeding.\n
|
|
163
|
+
stepText = `IMPORTANT: Before executing this step, explicitly state what you are about to do and wait for the user to say "approve" or "yes" before proceeding.\n${stepText}`;
|
|
159
164
|
}
|
|
160
165
|
parts.push(stepText);
|
|
161
166
|
});
|
|
@@ -208,8 +213,9 @@ async function runbookRun(name, options) {
|
|
|
208
213
|
const def = parseRunbookYaml(readFileSync(match.path, 'utf-8'));
|
|
209
214
|
const prompt = buildRunbookPrompt(def);
|
|
210
215
|
console.log(`Executing runbook: ${def.name}`);
|
|
211
|
-
if (def.description)
|
|
216
|
+
if (def.description) {
|
|
212
217
|
console.log(`Description: ${def.description}`);
|
|
218
|
+
}
|
|
213
219
|
console.log(`Steps: ${def.steps.length}`);
|
|
214
220
|
console.log('');
|
|
215
221
|
if (!options.auto) {
|
|
@@ -247,8 +253,9 @@ async function runbookCreate(name) {
|
|
|
247
253
|
let stepNum = 1;
|
|
248
254
|
while (true) {
|
|
249
255
|
const step = await question(`Step ${stepNum}: `);
|
|
250
|
-
if (!step.trim())
|
|
256
|
+
if (!step.trim()) {
|
|
251
257
|
break;
|
|
258
|
+
}
|
|
252
259
|
steps.push(step.trim());
|
|
253
260
|
stepNum++;
|
|
254
261
|
}
|
|
@@ -257,13 +264,13 @@ async function runbookCreate(name) {
|
|
|
257
264
|
console.error('Runbook must have at least one step.');
|
|
258
265
|
process.exit(1);
|
|
259
266
|
}
|
|
260
|
-
const yaml = [
|
|
267
|
+
const yaml = `${[
|
|
261
268
|
`name: ${name}`,
|
|
262
269
|
`description: ${description}`,
|
|
263
270
|
context ? `context: ${context}` : '# context: prod',
|
|
264
271
|
'steps:',
|
|
265
272
|
...steps.map(s => ` - ${s}`),
|
|
266
|
-
].join('\n')
|
|
273
|
+
].join('\n')}\n`;
|
|
267
274
|
writeFileSync(targetPath, yaml, 'utf-8');
|
|
268
275
|
console.log(`\nRunbook saved to: ${targetPath}`);
|
|
269
276
|
console.log(`Run with: nimbus runbook run ${name}`);
|
|
@@ -19,8 +19,9 @@ import { randomBytes } from 'node:crypto';
|
|
|
19
19
|
// ---------------------------------------------------------------------------
|
|
20
20
|
const SCHEDULE_FILE = join(homedir(), '.nimbus', 'schedules.json');
|
|
21
21
|
function loadSchedules() {
|
|
22
|
-
if (!existsSync(SCHEDULE_FILE))
|
|
22
|
+
if (!existsSync(SCHEDULE_FILE)) {
|
|
23
23
|
return [];
|
|
24
|
+
}
|
|
24
25
|
try {
|
|
25
26
|
return JSON.parse(readFileSync(SCHEDULE_FILE, 'utf-8'));
|
|
26
27
|
}
|
|
@@ -37,8 +38,9 @@ function saveSchedules(schedules) {
|
|
|
37
38
|
// ---------------------------------------------------------------------------
|
|
38
39
|
function isValidCron(cron) {
|
|
39
40
|
const parts = cron.trim().split(/\s+/);
|
|
40
|
-
if (parts.length !== 5)
|
|
41
|
+
if (parts.length !== 5) {
|
|
41
42
|
return false;
|
|
43
|
+
}
|
|
42
44
|
const validPart = /^(\*|\d+(-\d+)?(\/\d+)?)(,(\*|\d+(-\d+)?(\/\d+)?))*$/;
|
|
43
45
|
return parts.every(p => validPart.test(p));
|
|
44
46
|
}
|
|
@@ -47,17 +49,20 @@ function isValidCron(cron) {
|
|
|
47
49
|
*/
|
|
48
50
|
function describeNextRun(cron) {
|
|
49
51
|
const [min, hour, dom, month, dow] = cron.split(/\s+/);
|
|
50
|
-
if (hour === '*' && min === '0')
|
|
52
|
+
if (hour === '*' && min === '0') {
|
|
51
53
|
return 'every hour at :00';
|
|
54
|
+
}
|
|
52
55
|
if (dom === '*' && month === '*' && dow === '*') {
|
|
53
|
-
if (hour !== '*' && min !== '*')
|
|
56
|
+
if (hour !== '*' && min !== '*') {
|
|
54
57
|
return `daily at ${hour}:${min.padStart(2, '0')}`;
|
|
58
|
+
}
|
|
55
59
|
}
|
|
56
60
|
if (dow !== '*') {
|
|
57
61
|
const days = ['Sun', 'Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat'];
|
|
58
62
|
const dayName = days[parseInt(dow, 10)];
|
|
59
|
-
if (dayName && hour !== '*')
|
|
63
|
+
if (dayName && hour !== '*') {
|
|
60
64
|
return `weekly on ${dayName} at ${hour}:${(min ?? '0').padStart(2, '0')}`;
|
|
65
|
+
}
|
|
61
66
|
}
|
|
62
67
|
return `cron: ${cron}`;
|
|
63
68
|
}
|
|
@@ -54,8 +54,9 @@ export async function statusCommand(options = {}) {
|
|
|
54
54
|
info.awsAccount = identity.Account;
|
|
55
55
|
// Try to get region separately
|
|
56
56
|
const region = run('aws', ['configure', 'get', 'region']);
|
|
57
|
-
if (region)
|
|
57
|
+
if (region) {
|
|
58
58
|
info.awsRegion = region;
|
|
59
|
+
}
|
|
59
60
|
}
|
|
60
61
|
catch {
|
|
61
62
|
// Could not parse AWS identity
|
|
@@ -18,8 +18,9 @@ const NIMBUS_MD_PATHS = [
|
|
|
18
18
|
];
|
|
19
19
|
function findLocalNimbusMd() {
|
|
20
20
|
for (const p of NIMBUS_MD_PATHS) {
|
|
21
|
-
if (fs.existsSync(p))
|
|
21
|
+
if (fs.existsSync(p)) {
|
|
22
22
|
return p;
|
|
23
|
+
}
|
|
23
24
|
}
|
|
24
25
|
return null;
|
|
25
26
|
}
|
|
@@ -71,9 +72,10 @@ function mergeSections(localContent, teamContent) {
|
|
|
71
72
|
const heading = s.match(/^(#{1,3} .+)$/m)?.[1]?.trim();
|
|
72
73
|
return heading && !localHeadings.has(heading);
|
|
73
74
|
});
|
|
74
|
-
if (newSections.length === 0)
|
|
75
|
+
if (newSections.length === 0) {
|
|
75
76
|
return localContent;
|
|
76
|
-
|
|
77
|
+
}
|
|
78
|
+
const merged = `${localContent.trimEnd()}\n\n${newSections.join('\n').trimStart()}`;
|
|
77
79
|
return merged;
|
|
78
80
|
}
|
|
79
81
|
export async function teamContextCommand(subcommand, args) {
|
|
@@ -183,15 +185,18 @@ export async function teamContextCommand(subcommand, args) {
|
|
|
183
185
|
*/
|
|
184
186
|
export async function fetchRemoteNimbusMd() {
|
|
185
187
|
const url = process.env.NIMBUS_INSTRUCTIONS_URL;
|
|
186
|
-
if (!url)
|
|
188
|
+
if (!url) {
|
|
187
189
|
return null;
|
|
190
|
+
}
|
|
188
191
|
const localPath = findLocalNimbusMd();
|
|
189
|
-
if (localPath)
|
|
190
|
-
return null;
|
|
192
|
+
if (localPath) {
|
|
193
|
+
return null;
|
|
194
|
+
} // local file takes priority
|
|
191
195
|
try {
|
|
192
196
|
const response = await fetch(url, { signal: AbortSignal.timeout(10_000) });
|
|
193
|
-
if (!response.ok)
|
|
197
|
+
if (!response.ok) {
|
|
194
198
|
return null;
|
|
199
|
+
}
|
|
195
200
|
return await response.text();
|
|
196
201
|
}
|
|
197
202
|
catch {
|
|
@@ -55,7 +55,7 @@ async function templateGetCommand(id, _options = {}) {
|
|
|
55
55
|
const db = getDb();
|
|
56
56
|
const template = db
|
|
57
57
|
.prepare('SELECT * FROM templates WHERE id LIKE ?')
|
|
58
|
-
.get(id
|
|
58
|
+
.get(`${id}%`);
|
|
59
59
|
if (template) {
|
|
60
60
|
ui.stopSpinnerSuccess('Template retrieved');
|
|
61
61
|
ui.print(` ${ui.color('Name:', 'cyan')} ${template.name || '-'}`);
|
|
@@ -123,8 +123,9 @@ export async function tfApplyCommand(options = {}) {
|
|
|
123
123
|
});
|
|
124
124
|
if (!planResult.success) {
|
|
125
125
|
ui.stopSpinnerFail('Terraform plan failed');
|
|
126
|
-
if (planResult.error)
|
|
126
|
+
if (planResult.error) {
|
|
127
127
|
ui.error(planResult.error);
|
|
128
|
+
}
|
|
128
129
|
return;
|
|
129
130
|
}
|
|
130
131
|
if (!planResult.hasChanges) {
|
|
@@ -155,8 +156,9 @@ export async function tfApplyCommand(options = {}) {
|
|
|
155
156
|
}
|
|
156
157
|
else {
|
|
157
158
|
ui.stopSpinnerFail('Terraform apply failed');
|
|
158
|
-
if (applyResult.error)
|
|
159
|
+
if (applyResult.error) {
|
|
159
160
|
ui.error(applyResult.error);
|
|
161
|
+
}
|
|
160
162
|
}
|
|
161
163
|
return;
|
|
162
164
|
}
|
|
@@ -176,8 +178,9 @@ export async function tfApplyCommand(options = {}) {
|
|
|
176
178
|
}
|
|
177
179
|
else {
|
|
178
180
|
ui.stopSpinnerFail('Terraform apply failed');
|
|
179
|
-
if (result.error)
|
|
181
|
+
if (result.error) {
|
|
180
182
|
ui.error(result.error);
|
|
183
|
+
}
|
|
181
184
|
}
|
|
182
185
|
}
|
|
183
186
|
catch (error) {
|
|
@@ -265,9 +265,11 @@ async function upgradeViaHomebrew(spinner) {
|
|
|
265
265
|
await runShellCommand(`brew upgrade ${HOMEBREW_TAP} 2>&1`);
|
|
266
266
|
}
|
|
267
267
|
catch {
|
|
268
|
-
// If the tap formula isn't found,
|
|
269
|
-
|
|
270
|
-
|
|
268
|
+
// If the tap formula isn't found, tap it first then retry.
|
|
269
|
+
// Never fall back to bare `brew upgrade nimbus` — Homebrew core has an
|
|
270
|
+
// unrelated deprecated cask with the same name.
|
|
271
|
+
spinner.update('Adding tap and retrying...');
|
|
272
|
+
await runShellCommand(`brew tap the-ai-project-co/tap && brew upgrade ${HOMEBREW_TAP} 2>&1`);
|
|
271
273
|
}
|
|
272
274
|
}
|
|
273
275
|
/**
|