@build-astron-co/nimbus 0.4.2 → 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.
Files changed (430) hide show
  1. package/dist/src/agent/compaction-agent.js +24 -12
  2. package/dist/src/agent/context-manager.js +2 -1
  3. package/dist/src/agent/expand-files.js +2 -1
  4. package/dist/src/agent/loop.js +71 -33
  5. package/dist/src/agent/permissions.js +4 -2
  6. package/dist/src/agent/system-prompt.js +34 -17
  7. package/dist/src/app.js +1 -1
  8. package/dist/src/auth/keychain.js +8 -4
  9. package/dist/src/auth/store.js +70 -107
  10. package/dist/src/cli/init.js +35 -19
  11. package/dist/src/cli/run.js +18 -10
  12. package/dist/src/cli/serve.js +4 -2
  13. package/dist/src/cli.js +52 -11
  14. package/dist/src/commands/alias.js +5 -3
  15. package/dist/src/commands/audit/index.js +2 -1
  16. package/dist/src/commands/aws-terraform.js +36 -18
  17. package/dist/src/commands/completions.js +1 -1
  18. package/dist/src/commands/config.js +3 -2
  19. package/dist/src/commands/connect-github.js +92 -0
  20. package/dist/src/commands/cost/index.js +3 -2
  21. package/dist/src/commands/deploy.js +15 -10
  22. package/dist/src/commands/doctor.js +6 -3
  23. package/dist/src/commands/drift/index.js +2 -1
  24. package/dist/src/commands/export.js +5 -3
  25. package/dist/src/commands/generate-terraform.js +110 -2
  26. package/dist/src/commands/import.js +3 -3
  27. package/dist/src/commands/incident.js +10 -5
  28. package/dist/src/commands/login.js +8 -93
  29. package/dist/src/commands/logs.js +16 -8
  30. package/dist/src/commands/onboarding.js +6 -4
  31. package/dist/src/commands/pipeline.js +6 -3
  32. package/dist/src/commands/plugin.js +3 -2
  33. package/dist/src/commands/profile.js +27 -14
  34. package/dist/src/commands/questionnaire.js +1 -1
  35. package/dist/src/commands/rollback.js +3 -2
  36. package/dist/src/commands/rollout.js +5 -3
  37. package/dist/src/commands/runbook.js +17 -10
  38. package/dist/src/commands/schedule.js +10 -5
  39. package/dist/src/commands/status.js +2 -1
  40. package/dist/src/commands/team-context.js +12 -7
  41. package/dist/src/commands/template.js +1 -1
  42. package/dist/src/commands/tf/index.js +6 -3
  43. package/dist/src/commands/version.js +6 -3
  44. package/dist/src/commands/watch.js +6 -3
  45. package/dist/src/compat/sqlite.js +5 -3
  46. package/dist/src/config/mode-store.js +2 -1
  47. package/dist/src/config/profiles.js +4 -2
  48. package/dist/src/config/types.js +2 -1
  49. package/dist/src/engine/executor.js +8 -4
  50. package/dist/src/engine/planner.js +9 -5
  51. package/dist/src/llm/providers/anthropic.js +6 -3
  52. package/dist/src/llm/providers/ollama.js +1 -1
  53. package/dist/src/llm/router.js +22 -7
  54. package/dist/src/sessions/manager.js +6 -3
  55. package/dist/src/sharing/viewer.js +2 -1
  56. package/dist/src/tools/file-ops.js +1 -2
  57. package/dist/src/tools/schemas/devops.js +197 -108
  58. package/dist/src/tools/schemas/standard.js +1 -1
  59. package/dist/src/ui/App.js +25 -13
  60. package/dist/src/ui/FileDiffModal.js +22 -11
  61. package/dist/src/ui/HelpModal.js +2 -1
  62. package/dist/src/ui/InputBox.js +6 -3
  63. package/dist/src/ui/MessageList.js +40 -20
  64. package/dist/src/ui/TerminalPane.js +2 -1
  65. package/dist/src/ui/ToolCallDisplay.js +12 -6
  66. package/dist/src/ui/TreePane.js +2 -1
  67. package/dist/src/ui/ink/index.js +37 -21
  68. package/dist/src/watcher/index.js +8 -4
  69. package/package.json +3 -5
  70. package/src/__tests__/alias.test.ts +0 -133
  71. package/src/__tests__/app.test.ts +0 -76
  72. package/src/__tests__/audit.test.ts +0 -877
  73. package/src/__tests__/circuit-breaker.test.ts +0 -116
  74. package/src/__tests__/cli-run.test.ts +0 -351
  75. package/src/__tests__/compat-sqlite.test.ts +0 -68
  76. package/src/__tests__/context-manager.test.ts +0 -632
  77. package/src/__tests__/context.test.ts +0 -242
  78. package/src/__tests__/devops-terminal-gaps.test.ts +0 -718
  79. package/src/__tests__/doctor.test.ts +0 -48
  80. package/src/__tests__/enterprise.test.ts +0 -401
  81. package/src/__tests__/export.test.ts +0 -236
  82. package/src/__tests__/gap-11-18-20.test.ts +0 -958
  83. package/src/__tests__/generator.test.ts +0 -433
  84. package/src/__tests__/helm-streaming.test.ts +0 -127
  85. package/src/__tests__/hooks.test.ts +0 -582
  86. package/src/__tests__/incident.test.ts +0 -179
  87. package/src/__tests__/init.test.ts +0 -487
  88. package/src/__tests__/intent-parser.test.ts +0 -229
  89. package/src/__tests__/llm-router.test.ts +0 -209
  90. package/src/__tests__/logs.test.ts +0 -107
  91. package/src/__tests__/loop-errors.test.ts +0 -244
  92. package/src/__tests__/lsp.test.ts +0 -293
  93. package/src/__tests__/modes.test.ts +0 -336
  94. package/src/__tests__/perf-optimizations.test.ts +0 -847
  95. package/src/__tests__/permissions.test.ts +0 -338
  96. package/src/__tests__/pipeline.test.ts +0 -50
  97. package/src/__tests__/polish-phase3.test.ts +0 -340
  98. package/src/__tests__/profile.test.ts +0 -237
  99. package/src/__tests__/rollback.test.ts +0 -83
  100. package/src/__tests__/runbook.test.ts +0 -219
  101. package/src/__tests__/schedule.test.ts +0 -206
  102. package/src/__tests__/serve.test.ts +0 -275
  103. package/src/__tests__/sessions.test.ts +0 -322
  104. package/src/__tests__/sharing.test.ts +0 -340
  105. package/src/__tests__/snapshots.test.ts +0 -581
  106. package/src/__tests__/standalone-migration.test.ts +0 -199
  107. package/src/__tests__/state-db.test.ts +0 -334
  108. package/src/__tests__/status.test.ts +0 -158
  109. package/src/__tests__/stream-with-tools.test.ts +0 -778
  110. package/src/__tests__/subagents.test.ts +0 -176
  111. package/src/__tests__/system-prompt.test.ts +0 -248
  112. package/src/__tests__/terminal-gap-v2.test.ts +0 -395
  113. package/src/__tests__/terminal-parity.test.ts +0 -393
  114. package/src/__tests__/tf-apply.test.ts +0 -187
  115. package/src/__tests__/tool-converter.test.ts +0 -256
  116. package/src/__tests__/tool-schemas.test.ts +0 -602
  117. package/src/__tests__/tools.test.ts +0 -144
  118. package/src/__tests__/version-json.test.ts +0 -184
  119. package/src/__tests__/version.test.ts +0 -49
  120. package/src/__tests__/watch.test.ts +0 -129
  121. package/src/agent/compaction-agent.ts +0 -266
  122. package/src/agent/context-manager.ts +0 -499
  123. package/src/agent/context.ts +0 -427
  124. package/src/agent/deploy-preview.ts +0 -487
  125. package/src/agent/expand-files.ts +0 -108
  126. package/src/agent/index.ts +0 -68
  127. package/src/agent/loop.ts +0 -1998
  128. package/src/agent/modes.ts +0 -429
  129. package/src/agent/permissions.ts +0 -513
  130. package/src/agent/subagents/base.ts +0 -116
  131. package/src/agent/subagents/cost.ts +0 -51
  132. package/src/agent/subagents/explore.ts +0 -42
  133. package/src/agent/subagents/general.ts +0 -54
  134. package/src/agent/subagents/index.ts +0 -102
  135. package/src/agent/subagents/infra.ts +0 -59
  136. package/src/agent/subagents/security.ts +0 -69
  137. package/src/agent/system-prompt.ts +0 -990
  138. package/src/app.ts +0 -180
  139. package/src/audit/activity-log.ts +0 -290
  140. package/src/audit/compliance-checker.ts +0 -540
  141. package/src/audit/cost-tracker.ts +0 -318
  142. package/src/audit/index.ts +0 -23
  143. package/src/audit/security-scanner.ts +0 -641
  144. package/src/auth/guard.ts +0 -75
  145. package/src/auth/index.ts +0 -56
  146. package/src/auth/keychain.ts +0 -82
  147. package/src/auth/oauth.ts +0 -465
  148. package/src/auth/providers.ts +0 -470
  149. package/src/auth/sso.ts +0 -113
  150. package/src/auth/store.ts +0 -505
  151. package/src/auth/types.ts +0 -187
  152. package/src/build.ts +0 -141
  153. package/src/cli/index.ts +0 -16
  154. package/src/cli/init.ts +0 -1227
  155. package/src/cli/openapi-spec.ts +0 -356
  156. package/src/cli/run.ts +0 -628
  157. package/src/cli/serve-auth.ts +0 -80
  158. package/src/cli/serve.ts +0 -539
  159. package/src/cli/web.ts +0 -71
  160. package/src/cli.ts +0 -1728
  161. package/src/clients/core-engine-client.ts +0 -227
  162. package/src/clients/enterprise-client.ts +0 -334
  163. package/src/clients/generator-client.ts +0 -351
  164. package/src/clients/git-client.ts +0 -627
  165. package/src/clients/github-client.ts +0 -410
  166. package/src/clients/helm-client.ts +0 -504
  167. package/src/clients/index.ts +0 -80
  168. package/src/clients/k8s-client.ts +0 -497
  169. package/src/clients/llm-client.ts +0 -161
  170. package/src/clients/rest-client.ts +0 -130
  171. package/src/clients/service-discovery.ts +0 -38
  172. package/src/clients/terraform-client.ts +0 -482
  173. package/src/clients/tools-client.ts +0 -1843
  174. package/src/clients/ws-client.ts +0 -115
  175. package/src/commands/alias.ts +0 -100
  176. package/src/commands/analyze/index.ts +0 -352
  177. package/src/commands/apply/helm.ts +0 -473
  178. package/src/commands/apply/index.ts +0 -213
  179. package/src/commands/apply/k8s.ts +0 -454
  180. package/src/commands/apply/terraform.ts +0 -582
  181. package/src/commands/ask.ts +0 -167
  182. package/src/commands/audit/index.ts +0 -357
  183. package/src/commands/auth-cloud.ts +0 -407
  184. package/src/commands/auth-list.ts +0 -134
  185. package/src/commands/auth-profile.ts +0 -121
  186. package/src/commands/auth-refresh.ts +0 -187
  187. package/src/commands/auth-status.ts +0 -141
  188. package/src/commands/aws/ec2.ts +0 -501
  189. package/src/commands/aws/iam.ts +0 -397
  190. package/src/commands/aws/index.ts +0 -133
  191. package/src/commands/aws/lambda.ts +0 -396
  192. package/src/commands/aws/rds.ts +0 -439
  193. package/src/commands/aws/s3.ts +0 -439
  194. package/src/commands/aws/vpc.ts +0 -393
  195. package/src/commands/aws-discover.ts +0 -542
  196. package/src/commands/aws-terraform.ts +0 -755
  197. package/src/commands/azure/aks.ts +0 -376
  198. package/src/commands/azure/functions.ts +0 -253
  199. package/src/commands/azure/index.ts +0 -116
  200. package/src/commands/azure/storage.ts +0 -478
  201. package/src/commands/azure/vm.ts +0 -355
  202. package/src/commands/billing/index.ts +0 -256
  203. package/src/commands/chat.ts +0 -320
  204. package/src/commands/completions.ts +0 -268
  205. package/src/commands/config.ts +0 -372
  206. package/src/commands/cost/cloud-cost-estimator.ts +0 -266
  207. package/src/commands/cost/estimator.ts +0 -79
  208. package/src/commands/cost/index.ts +0 -810
  209. package/src/commands/cost/parsers/terraform.ts +0 -273
  210. package/src/commands/cost/parsers/types.ts +0 -25
  211. package/src/commands/cost/pricing/aws.ts +0 -544
  212. package/src/commands/cost/pricing/azure.ts +0 -499
  213. package/src/commands/cost/pricing/gcp.ts +0 -396
  214. package/src/commands/cost/pricing/index.ts +0 -40
  215. package/src/commands/demo.ts +0 -250
  216. package/src/commands/deploy.ts +0 -260
  217. package/src/commands/doctor.ts +0 -1386
  218. package/src/commands/drift/index.ts +0 -787
  219. package/src/commands/explain.ts +0 -277
  220. package/src/commands/export.ts +0 -146
  221. package/src/commands/feedback.ts +0 -389
  222. package/src/commands/fix.ts +0 -324
  223. package/src/commands/fs/index.ts +0 -402
  224. package/src/commands/gcp/compute.ts +0 -325
  225. package/src/commands/gcp/functions.ts +0 -271
  226. package/src/commands/gcp/gke.ts +0 -438
  227. package/src/commands/gcp/iam.ts +0 -344
  228. package/src/commands/gcp/index.ts +0 -129
  229. package/src/commands/gcp/storage.ts +0 -284
  230. package/src/commands/generate-helm.ts +0 -1249
  231. package/src/commands/generate-k8s.ts +0 -1508
  232. package/src/commands/generate-terraform.ts +0 -1202
  233. package/src/commands/gh/index.ts +0 -863
  234. package/src/commands/git/index.ts +0 -1343
  235. package/src/commands/helm/index.ts +0 -1126
  236. package/src/commands/help.ts +0 -715
  237. package/src/commands/history.ts +0 -149
  238. package/src/commands/import.ts +0 -868
  239. package/src/commands/incident.ts +0 -166
  240. package/src/commands/index.ts +0 -367
  241. package/src/commands/init.ts +0 -1051
  242. package/src/commands/k8s/index.ts +0 -1137
  243. package/src/commands/login.ts +0 -716
  244. package/src/commands/logout.ts +0 -83
  245. package/src/commands/logs.ts +0 -167
  246. package/src/commands/onboarding.ts +0 -405
  247. package/src/commands/pipeline.ts +0 -186
  248. package/src/commands/plan/display.ts +0 -279
  249. package/src/commands/plan/index.ts +0 -599
  250. package/src/commands/plugin.ts +0 -398
  251. package/src/commands/preview.ts +0 -452
  252. package/src/commands/profile.ts +0 -342
  253. package/src/commands/questionnaire.ts +0 -1172
  254. package/src/commands/resume.ts +0 -47
  255. package/src/commands/rollback.ts +0 -315
  256. package/src/commands/rollout.ts +0 -88
  257. package/src/commands/runbook.ts +0 -346
  258. package/src/commands/schedule.ts +0 -236
  259. package/src/commands/status.ts +0 -252
  260. package/src/commands/team/index.ts +0 -346
  261. package/src/commands/team-context.ts +0 -220
  262. package/src/commands/template.ts +0 -233
  263. package/src/commands/tf/index.ts +0 -1093
  264. package/src/commands/upgrade.ts +0 -609
  265. package/src/commands/usage/index.ts +0 -134
  266. package/src/commands/version.ts +0 -174
  267. package/src/commands/watch.ts +0 -153
  268. package/src/compat/index.ts +0 -2
  269. package/src/compat/runtime.ts +0 -12
  270. package/src/compat/sqlite.ts +0 -177
  271. package/src/config/index.ts +0 -17
  272. package/src/config/manager.ts +0 -530
  273. package/src/config/mode-store.ts +0 -62
  274. package/src/config/profiles.ts +0 -84
  275. package/src/config/safety-policy.ts +0 -358
  276. package/src/config/schema.ts +0 -125
  277. package/src/config/types.ts +0 -609
  278. package/src/config/workspace-state.ts +0 -53
  279. package/src/context/context-db.ts +0 -199
  280. package/src/demo/index.ts +0 -349
  281. package/src/demo/scenarios/full-journey.ts +0 -229
  282. package/src/demo/scenarios/getting-started.ts +0 -127
  283. package/src/demo/scenarios/helm-release.ts +0 -341
  284. package/src/demo/scenarios/k8s-deployment.ts +0 -194
  285. package/src/demo/scenarios/terraform-vpc.ts +0 -170
  286. package/src/demo/types.ts +0 -92
  287. package/src/engine/cost-estimator.ts +0 -480
  288. package/src/engine/diagram-generator.ts +0 -256
  289. package/src/engine/drift-detector.ts +0 -902
  290. package/src/engine/executor.ts +0 -1066
  291. package/src/engine/index.ts +0 -76
  292. package/src/engine/orchestrator.ts +0 -636
  293. package/src/engine/planner.ts +0 -787
  294. package/src/engine/safety.ts +0 -743
  295. package/src/engine/verifier.ts +0 -770
  296. package/src/enterprise/audit.ts +0 -348
  297. package/src/enterprise/auth.ts +0 -270
  298. package/src/enterprise/billing.ts +0 -822
  299. package/src/enterprise/index.ts +0 -17
  300. package/src/enterprise/teams.ts +0 -443
  301. package/src/generator/best-practices.ts +0 -1608
  302. package/src/generator/helm.ts +0 -630
  303. package/src/generator/index.ts +0 -37
  304. package/src/generator/intent-parser.ts +0 -514
  305. package/src/generator/kubernetes.ts +0 -976
  306. package/src/generator/terraform.ts +0 -1875
  307. package/src/history/index.ts +0 -8
  308. package/src/history/manager.ts +0 -250
  309. package/src/history/types.ts +0 -34
  310. package/src/hooks/config.ts +0 -432
  311. package/src/hooks/engine.ts +0 -392
  312. package/src/hooks/index.ts +0 -4
  313. package/src/llm/auth-bridge.ts +0 -198
  314. package/src/llm/circuit-breaker.ts +0 -140
  315. package/src/llm/config-loader.ts +0 -201
  316. package/src/llm/cost-calculator.ts +0 -171
  317. package/src/llm/index.ts +0 -8
  318. package/src/llm/model-aliases.ts +0 -115
  319. package/src/llm/provider-registry.ts +0 -63
  320. package/src/llm/providers/anthropic.ts +0 -462
  321. package/src/llm/providers/bedrock.ts +0 -477
  322. package/src/llm/providers/google.ts +0 -405
  323. package/src/llm/providers/ollama.ts +0 -767
  324. package/src/llm/providers/openai-compatible.ts +0 -340
  325. package/src/llm/providers/openai.ts +0 -328
  326. package/src/llm/providers/openrouter.ts +0 -338
  327. package/src/llm/router.ts +0 -1104
  328. package/src/llm/types.ts +0 -232
  329. package/src/lsp/client.ts +0 -298
  330. package/src/lsp/languages.ts +0 -119
  331. package/src/lsp/manager.ts +0 -294
  332. package/src/mcp/client.ts +0 -402
  333. package/src/mcp/index.ts +0 -5
  334. package/src/mcp/manager.ts +0 -133
  335. package/src/nimbus.ts +0 -234
  336. package/src/plugins/index.ts +0 -27
  337. package/src/plugins/loader.ts +0 -334
  338. package/src/plugins/manager.ts +0 -376
  339. package/src/plugins/types.ts +0 -284
  340. package/src/scanners/cicd-scanner.ts +0 -258
  341. package/src/scanners/cloud-scanner.ts +0 -466
  342. package/src/scanners/framework-scanner.ts +0 -469
  343. package/src/scanners/iac-scanner.ts +0 -388
  344. package/src/scanners/index.ts +0 -539
  345. package/src/scanners/language-scanner.ts +0 -276
  346. package/src/scanners/package-manager-scanner.ts +0 -277
  347. package/src/scanners/types.ts +0 -172
  348. package/src/sessions/manager.ts +0 -472
  349. package/src/sessions/types.ts +0 -44
  350. package/src/sharing/sync.ts +0 -300
  351. package/src/sharing/viewer.ts +0 -163
  352. package/src/snapshots/index.ts +0 -2
  353. package/src/snapshots/manager.ts +0 -530
  354. package/src/state/artifacts.ts +0 -147
  355. package/src/state/audit.ts +0 -137
  356. package/src/state/billing.ts +0 -240
  357. package/src/state/checkpoints.ts +0 -117
  358. package/src/state/config.ts +0 -67
  359. package/src/state/conversations.ts +0 -14
  360. package/src/state/credentials.ts +0 -154
  361. package/src/state/db.ts +0 -58
  362. package/src/state/index.ts +0 -26
  363. package/src/state/messages.ts +0 -115
  364. package/src/state/projects.ts +0 -123
  365. package/src/state/schema.ts +0 -236
  366. package/src/state/sessions.ts +0 -147
  367. package/src/state/teams.ts +0 -200
  368. package/src/telemetry.ts +0 -108
  369. package/src/tools/aws-ops.ts +0 -952
  370. package/src/tools/azure-ops.ts +0 -579
  371. package/src/tools/file-ops.ts +0 -615
  372. package/src/tools/gcp-ops.ts +0 -625
  373. package/src/tools/git-ops.ts +0 -773
  374. package/src/tools/github-ops.ts +0 -799
  375. package/src/tools/helm-ops.ts +0 -943
  376. package/src/tools/index.ts +0 -17
  377. package/src/tools/k8s-ops.ts +0 -819
  378. package/src/tools/schemas/converter.ts +0 -184
  379. package/src/tools/schemas/devops.ts +0 -3502
  380. package/src/tools/schemas/index.ts +0 -73
  381. package/src/tools/schemas/standard.ts +0 -1148
  382. package/src/tools/schemas/types.ts +0 -735
  383. package/src/tools/spawn-exec.ts +0 -148
  384. package/src/tools/terraform-ops.ts +0 -862
  385. package/src/types/ambient.d.ts +0 -193
  386. package/src/types/config.ts +0 -83
  387. package/src/types/drift.ts +0 -116
  388. package/src/types/enterprise.ts +0 -335
  389. package/src/types/index.ts +0 -20
  390. package/src/types/plan.ts +0 -44
  391. package/src/types/request.ts +0 -65
  392. package/src/types/response.ts +0 -54
  393. package/src/types/service.ts +0 -51
  394. package/src/ui/App.tsx +0 -2114
  395. package/src/ui/DeployPreview.tsx +0 -174
  396. package/src/ui/FileDiffModal.tsx +0 -162
  397. package/src/ui/Header.tsx +0 -131
  398. package/src/ui/HelpModal.tsx +0 -57
  399. package/src/ui/InputBox.tsx +0 -503
  400. package/src/ui/MessageList.tsx +0 -1032
  401. package/src/ui/PermissionPrompt.tsx +0 -163
  402. package/src/ui/StatusBar.tsx +0 -277
  403. package/src/ui/TerminalPane.tsx +0 -84
  404. package/src/ui/ToolCallDisplay.tsx +0 -643
  405. package/src/ui/TreePane.tsx +0 -132
  406. package/src/ui/chat-ui.ts +0 -850
  407. package/src/ui/index.ts +0 -33
  408. package/src/ui/ink/index.ts +0 -1444
  409. package/src/ui/streaming.ts +0 -176
  410. package/src/ui/theme.ts +0 -104
  411. package/src/ui/types.ts +0 -75
  412. package/src/utils/analytics.ts +0 -72
  413. package/src/utils/cost-warning.ts +0 -27
  414. package/src/utils/env.ts +0 -46
  415. package/src/utils/errors.ts +0 -69
  416. package/src/utils/event-bus.ts +0 -38
  417. package/src/utils/index.ts +0 -24
  418. package/src/utils/logger.ts +0 -171
  419. package/src/utils/rate-limiter.ts +0 -121
  420. package/src/utils/service-auth.ts +0 -49
  421. package/src/utils/validation.ts +0 -53
  422. package/src/version.ts +0 -4
  423. package/src/watcher/index.ts +0 -214
  424. package/src/wizard/approval.ts +0 -383
  425. package/src/wizard/index.ts +0 -25
  426. package/src/wizard/prompts.ts +0 -338
  427. package/src/wizard/types.ts +0 -172
  428. package/src/wizard/ui.ts +0 -556
  429. package/src/wizard/wizard.ts +0 -304
  430. package/tsconfig.json +0 -24
@@ -80,18 +80,24 @@ export async function runCompaction(messages, contextManager, options) {
80
80
  if (options.infraContext) {
81
81
  const ic = options.infraContext;
82
82
  const infraLines = [];
83
- if (ic.terraformWorkspace)
83
+ if (ic.terraformWorkspace) {
84
84
  infraLines.push(`- Terraform workspace: ${ic.terraformWorkspace}`);
85
- if (ic.kubectlContext)
85
+ }
86
+ if (ic.kubectlContext) {
86
87
  infraLines.push(`- kubectl context: ${ic.kubectlContext}`);
87
- if (ic.awsProfile)
88
+ }
89
+ if (ic.awsProfile) {
88
90
  infraLines.push(`- AWS profile: ${ic.awsProfile}`);
89
- if (ic.awsRegion)
91
+ }
92
+ if (ic.awsRegion) {
90
93
  infraLines.push(`- AWS region: ${ic.awsRegion}`);
91
- if (ic.gcpProject)
94
+ }
95
+ if (ic.gcpProject) {
92
96
  infraLines.push(`- GCP project: ${ic.gcpProject}`);
93
- if (ic.azureSubscription)
97
+ }
98
+ if (ic.azureSubscription) {
94
99
  infraLines.push(`- Azure subscription: ${ic.azureSubscription}`);
100
+ }
95
101
  if (infraLines.length > 0) {
96
102
  userPrompt += `\n\n## ALWAYS PRESERVE IN SUMMARY (do not omit):\n${infraLines.join('\n')}`;
97
103
  }
@@ -119,18 +125,24 @@ export async function runCompaction(messages, contextManager, options) {
119
125
  if (options.infraContext) {
120
126
  const ic = options.infraContext;
121
127
  const infraLines = [];
122
- if (ic.terraformWorkspace)
128
+ if (ic.terraformWorkspace) {
123
129
  infraLines.push(`- Terraform workspace: ${ic.terraformWorkspace}`);
124
- if (ic.kubectlContext)
130
+ }
131
+ if (ic.kubectlContext) {
125
132
  infraLines.push(`- kubectl context: ${ic.kubectlContext}`);
126
- if (ic.awsProfile)
133
+ }
134
+ if (ic.awsProfile) {
127
135
  infraLines.push(`- AWS profile: ${ic.awsProfile}`);
128
- if (ic.awsRegion)
136
+ }
137
+ if (ic.awsRegion) {
129
138
  infraLines.push(`- AWS region: ${ic.awsRegion}`);
130
- if (ic.gcpProject)
139
+ }
140
+ if (ic.gcpProject) {
131
141
  infraLines.push(`- GCP project: ${ic.gcpProject}`);
132
- if (ic.azureSubscription)
142
+ }
143
+ if (ic.azureSubscription) {
133
144
  infraLines.push(`- Azure subscription: ${ic.azureSubscription}`);
145
+ }
134
146
  if (infraLines.length > 0) {
135
147
  finalSummary = `## Infrastructure Context\n${infraLines.join('\n')}\n\n${summary}`;
136
148
  }
@@ -188,8 +188,9 @@ export class ContextManager {
188
188
  const tcIds = msg.toolCalls?.map(tc => tc.id).join(',') ?? '';
189
189
  const key = `${msg.role}:${contentLen}:${tcCount}:${tcIds}`;
190
190
  const cached = this._tokenCache.get(key);
191
- if (cached !== undefined)
191
+ if (cached !== undefined) {
192
192
  return cached;
193
+ }
193
194
  const val = estimateMessageTokens(msg);
194
195
  this._tokenCache.set(key, val);
195
196
  return val;
@@ -24,8 +24,9 @@ const SENSITIVE_FILE_RE = /(\.env|\.pem|\.key|\.p12|\.pfx|id_rsa|id_ed25519|cred
24
24
  */
25
25
  export function expandFileReferences(text, cwd = process.cwd()) {
26
26
  const fileRefs = text.match(/@([\w./_-]+)/g);
27
- if (!fileRefs)
27
+ if (!fileRefs) {
28
28
  return text;
29
+ }
29
30
  let expanded = text;
30
31
  // G22: Handle @workspace special token — concatenate all .tf files
31
32
  if (expanded.includes('@workspace')) {
@@ -27,6 +27,7 @@ import { maskSecrets } from '../audit/security-scanner';
27
27
  import { classifyTaskComplexity, routeModel } from '../llm/router';
28
28
  import { mkdirSync as _cpMkdirSync, writeFileSync as _cpWriteFileSync } from 'node:fs';
29
29
  import { homedir as _cpHomedir } from 'node:os';
30
+ import { authStore } from '../auth/store';
30
31
  // ---------------------------------------------------------------------------
31
32
  // C2: Infra state checkpoint helper
32
33
  // ---------------------------------------------------------------------------
@@ -58,7 +59,7 @@ function writeInfraCheckpoint(tool, action, input) {
58
59
  cwd: process.cwd(),
59
60
  workdir: input.workdir ?? undefined,
60
61
  };
61
- const fileName = timestamp.replace(/[:.]/g, '-') + '.json';
62
+ const fileName = `${timestamp.replace(/[:.]/g, '-')}.json`;
62
63
  _cpWriteFileSync(join(checkpointsDir, fileName), JSON.stringify(checkpoint, null, 2), 'utf-8');
63
64
  }
64
65
  catch { /* non-critical */ }
@@ -274,11 +275,13 @@ function isRetryableStreamError(err) {
274
275
  const e = err;
275
276
  const status = (typeof e.status === 'number' ? e.status : undefined) ??
276
277
  (typeof e.statusCode === 'number' ? e.statusCode : undefined);
277
- if (status === 429 || (status !== undefined && status >= 500 && status < 600))
278
+ if (status === 429 || (status !== undefined && status >= 500 && status < 600)) {
278
279
  return true;
280
+ }
279
281
  const msg = typeof e.message === 'string' ? e.message : '';
280
- if (/rate.?limit|429|too many requests|overloaded|503/i.test(msg))
282
+ if (/rate.?limit|429|too many requests|overloaded|503/i.test(msg)) {
281
283
  return true;
284
+ }
282
285
  }
283
286
  return false;
284
287
  }
@@ -319,12 +322,15 @@ function extractCostHintFromToolOutput(toolName, input, output) {
319
322
  const changed = Number(m[2]);
320
323
  const destroyed = Number(m[3]);
321
324
  const parts = [];
322
- if (added > 0)
325
+ if (added > 0) {
323
326
  parts.push(`+${added} resources created`);
324
- if (changed > 0)
327
+ }
328
+ if (changed > 0) {
325
329
  parts.push(`${changed} updated`);
326
- if (destroyed > 0)
330
+ }
331
+ if (destroyed > 0) {
327
332
  parts.push(`${destroyed} destroyed`);
333
+ }
328
334
  return parts.length > 0
329
335
  ? `${parts.join(', ')} — run "nimbus cost" for monthly cost estimate`
330
336
  : null;
@@ -352,11 +358,13 @@ function trackAndPersistError(toolName, errorHint, cwd) {
352
358
  const { existsSync, readFileSync, writeFileSync, appendFileSync } = require('node:fs');
353
359
  const { join } = require('node:path');
354
360
  const nimbusPath = join(cwd, 'NIMBUS.md');
355
- if (!existsSync(nimbusPath))
361
+ if (!existsSync(nimbusPath)) {
356
362
  return;
363
+ }
357
364
  const existing = readFileSync(nimbusPath, 'utf-8');
358
- if (existing.includes(errorHint.slice(0, 40)))
359
- return; // already recorded
365
+ if (existing.includes(errorHint.slice(0, 40))) {
366
+ return;
367
+ } // already recorded
360
368
  const entry = `- ${toolName}: ${errorHint}\n`;
361
369
  if (existing.includes('## Observed Issues')) {
362
370
  writeFileSync(nimbusPath, existing.replace('## Observed Issues\n', `## Observed Issues\n${entry}`));
@@ -394,8 +402,9 @@ function cacheTerraformPlan(workdir, output) {
394
402
  /** Retrieve a cached terraform plan for a workdir, or null if expired/missing. */
395
403
  function getCachedTerraformPlan(workdir) {
396
404
  const entry = terraformPlanCache.get(workdir);
397
- if (!entry)
405
+ if (!entry) {
398
406
  return null;
407
+ }
399
408
  if (Date.now() - entry.timestamp > PLAN_CACHE_TTL_MS) {
400
409
  terraformPlanCache.delete(workdir);
401
410
  return null;
@@ -561,6 +570,8 @@ export async function runAgentLoop(userMessage, history, options) {
561
570
  // A1: Retry on transient errors (rate-limit / 5xx) with exponential backoff
562
571
  const MAX_STREAM_RETRIES = 2;
563
572
  let streamAttempt = 0;
573
+ // Flag to prevent infinite 401-retry loops (attempt re-init only once per turn)
574
+ let _401RecoveryAttempted = false;
564
575
  while (true) {
565
576
  // A2: Silence timeout — abort if no chunk arrives (G21: configurable)
566
577
  const STREAM_SILENCE_MS = options.streamSilenceTimeoutMs ?? 60_000;
@@ -611,13 +622,30 @@ export async function runAgentLoop(userMessage, history, options) {
611
622
  responseUsage = { promptTokens: 0, completionTokens: 0, totalTokens: 0 };
612
623
  continue;
613
624
  }
614
- // G24: Graceful network error message instead of raw Node.js error
625
+ // 401 auto-recovery: reinitialize providers in case credentials were just updated
615
626
  const streamErrObj = streamErr;
627
+ const is401 = streamErrObj?.status === 401 || streamErrObj?.statusCode === 401
628
+ || /401|Invalid API Key|Unauthorized|authentication_error/i.test(streamErrObj?.message ?? '');
629
+ if (is401 && !_401RecoveryAttempted) {
630
+ _401RecoveryAttempted = true;
631
+ try {
632
+ authStore.reload();
633
+ router.reinitializeProviders();
634
+ }
635
+ catch { /* non-critical */ }
636
+ // Reset partial accumulation and retry once
637
+ responseContent = '';
638
+ responseToolCalls = undefined;
639
+ responseUsage = { promptTokens: 0, completionTokens: 0, totalTokens: 0 };
640
+ continue;
641
+ }
642
+ // G24: Graceful network error message instead of raw Node.js error
616
643
  const isNetworkError = /ECONNREFUSED|ETIMEDOUT|ENOTFOUND|fetch failed|network/i.test(streamErrObj?.message ?? '');
617
644
  if (isNetworkError) {
618
645
  const netMsg = '\n[!!] Network unreachable — cannot reach the LLM API.\nCheck your internet connection and API key validity, then try again.\n';
619
- if (onText)
646
+ if (onText) {
620
647
  onText(netMsg);
648
+ }
621
649
  // Re-throw a specially-marked error so the outer turn catch block can handle it
622
650
  const netErr = new Error(netMsg);
623
651
  netErr._nimbusNetworkError = true;
@@ -651,8 +679,9 @@ export async function runAgentLoop(userMessage, history, options) {
651
679
  // G16: Cost budget enforcement — stop if cumulative cost exceeds the limit
652
680
  if (options.costBudgetUSD !== undefined && totalCost >= options.costBudgetUSD) {
653
681
  const budgetMsg = `\n\n[!!] Cost budget of $${options.costBudgetUSD.toFixed(2)} reached (used: $${totalCost.toFixed(3)}). Stopping to prevent overspend.\n`;
654
- if (onText)
682
+ if (onText) {
655
683
  onText(budgetMsg);
684
+ }
656
685
  messages.push({ role: 'assistant', content: budgetMsg });
657
686
  break;
658
687
  }
@@ -747,7 +776,7 @@ export async function runAgentLoop(userMessage, history, options) {
747
776
  if (destructiveWarning) {
748
777
  messages.push({
749
778
  role: 'tool',
750
- toolCallId: toolCall.id + '-guard',
779
+ toolCallId: `${toolCall.id}-guard`,
751
780
  name: toolCall.function.name,
752
781
  content: `[SAFETY] ${destructiveWarning}`,
753
782
  });
@@ -798,11 +827,11 @@ export async function runAgentLoop(userMessage, history, options) {
798
827
  }
799
828
  const refreshMsg = [
800
829
  '[!!] Credential expired. Run: nimbus auth-refresh',
801
- '[Nimbus] Credential error detected on tool: ' + toolCall.function.name,
830
+ `[Nimbus] Credential error detected on tool: ${toolCall.function.name}`,
802
831
  'Run "nimbus auth-refresh" to refresh cloud credentials, then retry.',
803
832
  ].join('\n');
804
- toolContent += '\n\n' + refreshMsg;
805
- result.output += '\n\n' + refreshMsg;
833
+ toolContent += `\n\n${refreshMsg}`;
834
+ result.output += `\n\n${refreshMsg}`;
806
835
  }
807
836
  }
808
837
  else if (DEVOPS_TOOL_NAMES.has(toolCall.function.name)) {
@@ -884,7 +913,7 @@ export async function runAgentLoop(userMessage, history, options) {
884
913
  cwd: options.cwd ?? process.cwd(),
885
914
  timestamp: new Date().toISOString(),
886
915
  });
887
- appendFileSync(join(auditDir, 'audit.jsonl'), event + '\n', 'utf-8');
916
+ appendFileSync(join(auditDir, 'audit.jsonl'), `${event}\n`, 'utf-8');
888
917
  }
889
918
  catch { /* audit logging is non-critical */ }
890
919
  }
@@ -927,8 +956,9 @@ export async function runAgentLoop(userMessage, history, options) {
927
956
  const batchFiles = buildFileDiffBatchFromPlan({ changes });
928
957
  for (const file of batchFiles) {
929
958
  const decision = await options.requestFileDiff(file.filePath, file.toolName ?? 'terraform', file.diff ?? '');
930
- if (decision === 'reject-all')
959
+ if (decision === 'reject-all') {
931
960
  break;
961
+ }
932
962
  }
933
963
  }
934
964
  }
@@ -1016,13 +1046,13 @@ export async function runAgentLoop(userMessage, history, options) {
1016
1046
  const outFile = join(outDir, `${Date.now()}-${toolCall.function.name}.log`);
1017
1047
  _writeFileSync(outFile, toolContent, 'utf-8');
1018
1048
  toolContent = omitted > 0
1019
- ? `${head}${tail ? '\n\n... [' + omitted + ' lines omitted — full output saved to ' + outFile + '] ...\n\n' + tail : '\n\n... [full output saved to ' + outFile + ']'}`
1020
- : `${head}${tail ? '\n\n' + tail : ''}`;
1049
+ ? `${head}${tail ? `\n\n... [${omitted} lines omitted — full output saved to ${outFile}] ...\n\n${tail}` : `\n\n... [full output saved to ${outFile}]`}`
1050
+ : `${head}${tail ? `\n\n${tail}` : ''}`;
1021
1051
  }
1022
1052
  catch {
1023
1053
  toolContent = omitted > 0
1024
- ? `${head}${tail ? '\n\n... [' + omitted + ' lines omitted — output too large for context] ...\n\n' + tail : '\n\n... [' + omitted + ' lines omitted]'}`
1025
- : `${head}${tail ? '\n\n' + tail : ''}`;
1054
+ ? `${head}${tail ? `\n\n... [${omitted} lines omitted — output too large for context] ...\n\n${tail}` : `\n\n... [${omitted} lines omitted]`}`
1055
+ : `${head}${tail ? `\n\n${tail}` : ''}`;
1026
1056
  }
1027
1057
  }
1028
1058
  messages.push({
@@ -1112,14 +1142,17 @@ export async function runAgentLoop(userMessage, history, options) {
1112
1142
  const kubectl = allToolCalls.filter(c => c.name === 'kubectl');
1113
1143
  const helm = allToolCalls.filter(c => c.name === 'helm');
1114
1144
  const summaryLines = ['---', '**Session Summary**'];
1115
- if (terraform.length)
1145
+ if (terraform.length) {
1116
1146
  summaryLines.push(`• Terraform: ${terraform.map(c => String(c.input.action ?? '')).join(', ')}`);
1117
- if (kubectl.length)
1147
+ }
1148
+ if (kubectl.length) {
1118
1149
  summaryLines.push(`• Kubectl: ${kubectl.map(c => String(c.input.action ?? '')).join(', ')}`);
1119
- if (helm.length)
1150
+ }
1151
+ if (helm.length) {
1120
1152
  summaryLines.push(`• Helm: ${helm.map(c => String(c.input.action ?? '')).join(', ')}`);
1153
+ }
1121
1154
  if (summaryLines.length > 2) {
1122
- options.onText('\n\n' + summaryLines.join('\n'));
1155
+ options.onText(`\n\n${summaryLines.join('\n')}`);
1123
1156
  }
1124
1157
  }
1125
1158
  }
@@ -1178,8 +1211,9 @@ async function computeProposedDiff(toolName, args) {
1178
1211
  try {
1179
1212
  const { readFile } = await import('node:fs/promises');
1180
1213
  const path = args.path;
1181
- if (!path)
1214
+ if (!path) {
1182
1215
  return null;
1216
+ }
1183
1217
  const currentContent = await readFile(path, 'utf-8').catch(() => '');
1184
1218
  let proposed = currentContent;
1185
1219
  if (toolName === 'edit_file') {
@@ -1196,8 +1230,9 @@ async function computeProposedDiff(toolName, args) {
1196
1230
  else if (toolName === 'write_file') {
1197
1231
  proposed = args.content;
1198
1232
  }
1199
- if (proposed === currentContent)
1200
- return null; // no change
1233
+ if (proposed === currentContent) {
1234
+ return null;
1235
+ } // no change
1201
1236
  return generateUnifiedDiff(path, currentContent, proposed);
1202
1237
  }
1203
1238
  catch {
@@ -1328,8 +1363,9 @@ async function executeToolCall(toolCall, registry, onStart, onEnd, checkPermissi
1328
1363
  error: undefined,
1329
1364
  isError: false,
1330
1365
  };
1331
- if (onEnd)
1366
+ if (onEnd) {
1332
1367
  onEnd(callInfo, rejResult);
1368
+ }
1333
1369
  return rejResult;
1334
1370
  }
1335
1371
  const diff = await computeProposedDiff(toolName, parsedArgs);
@@ -1342,8 +1378,9 @@ async function executeToolCall(toolCall, registry, onStart, onEnd, checkPermissi
1342
1378
  error: undefined,
1343
1379
  isError: false,
1344
1380
  };
1345
- if (onEnd)
1381
+ if (onEnd) {
1346
1382
  onEnd(callInfo, rejResult);
1383
+ }
1347
1384
  return rejResult;
1348
1385
  }
1349
1386
  if (decision === 'reject-all') {
@@ -1355,8 +1392,9 @@ async function executeToolCall(toolCall, registry, onStart, onEnd, checkPermissi
1355
1392
  error: undefined,
1356
1393
  isError: false,
1357
1394
  };
1358
- if (onEnd)
1395
+ if (onEnd) {
1359
1396
  onEnd(callInfo, rejResult);
1397
+ }
1360
1398
  return rejResult;
1361
1399
  }
1362
1400
  if (decision === 'apply-all' && skipRemainingDiffPrompts) {
@@ -131,8 +131,9 @@ export function checkPermission(tool, input, sessionState, config, autoApprove /
131
131
  ) {
132
132
  // H2: When running in CI / --auto-approve / --non-interactive mode,
133
133
  // bypass all tier logic and immediately allow the tool call.
134
- if (autoApprove)
134
+ if (autoApprove) {
135
135
  return 'allow';
136
+ }
136
137
  // 1. Check user overrides first
137
138
  if (config?.toolOverrides?.[tool.name]) {
138
139
  const overrideTier = config.toolOverrides[tool.name];
@@ -362,8 +363,9 @@ function checkHelmPermission(input, _sessionState) {
362
363
  * @returns `'block'` if forbidden, `null` otherwise.
363
364
  */
364
365
  export function checkForbiddenPatterns(toolName, input, forbiddenRules) {
365
- if (forbiddenRules.length === 0)
366
+ if (forbiddenRules.length === 0) {
366
367
  return null;
368
+ }
367
369
  const inputStr = JSON.stringify(input ?? {}).toLowerCase();
368
370
  const toolLower = toolName.toLowerCase();
369
371
  for (const rule of forbiddenRules) {
@@ -100,19 +100,24 @@ export function buildSystemPrompt(options) {
100
100
  if (options.infraContext) {
101
101
  const ic = options.infraContext;
102
102
  const lines = ['## Current Infrastructure Context'];
103
- if (ic.terraformWorkspace)
103
+ if (ic.terraformWorkspace) {
104
104
  lines.push(`- Terraform workspace: ${ic.terraformWorkspace}`);
105
- if (ic.kubectlContext)
105
+ }
106
+ if (ic.kubectlContext) {
106
107
  lines.push(`- kubectl context: ${ic.kubectlContext}`);
108
+ }
107
109
  if (ic.helmReleases && ic.helmReleases.length > 0) {
108
110
  lines.push(`- Active Helm releases: ${ic.helmReleases.slice(0, 5).join(', ')}`);
109
111
  }
110
- if (ic.awsAccount)
112
+ if (ic.awsAccount) {
111
113
  lines.push(`- AWS account: ${ic.awsAccount}`);
112
- if (ic.awsRegion)
114
+ }
115
+ if (ic.awsRegion) {
113
116
  lines.push(`- AWS region: ${ic.awsRegion}`);
114
- if (ic.gcpProject)
117
+ }
118
+ if (ic.gcpProject) {
115
119
  lines.push(`- GCP project: ${ic.gcpProject}`);
120
+ }
116
121
  parts.push(lines.join('\n'));
117
122
  // H3: Inject known resource inventory for better tool call accuracy.
118
123
  // Lists exact names for contexts, releases, workspaces, and cloud accounts
@@ -478,11 +483,13 @@ export function getPrunedHeuristics(mode) {
478
483
  .filter(line => {
479
484
  const l = line.toLowerCase();
480
485
  // Remove deploy-specific execution requirements (plan mode cannot apply)
481
- if (l.includes('in deploy mode:') || l.includes('deploy_preview before'))
486
+ if (l.includes('in deploy mode:') || l.includes('deploy_preview before')) {
482
487
  return false;
488
+ }
483
489
  // Remove tool selection items for deploy-only tools
484
- if (l.includes('use drift_detect') || l.includes('use cost_estimate'))
490
+ if (l.includes('use drift_detect') || l.includes('use cost_estimate')) {
485
491
  return false;
492
+ }
486
493
  return true;
487
494
  })
488
495
  .join('\n');
@@ -493,8 +500,9 @@ export function getPrunedHeuristics(mode) {
493
500
  .filter(line => {
494
501
  const l = line.toLowerCase();
495
502
  // Remove plan-mode-only readonly enforcement lines
496
- if (l.includes('in plan mode:') || l.includes('never apply, apply'))
503
+ if (l.includes('in plan mode:') || l.includes('never apply, apply')) {
497
504
  return false;
505
+ }
498
506
  return true;
499
507
  })
500
508
  .join('\n');
@@ -666,11 +674,13 @@ export function extractForbiddenRules(nimbusContent) {
666
674
  }
667
675
  if (inForbidden) {
668
676
  // Stop at any new ## section
669
- if (/^##\s/.test(trimmed))
677
+ if (/^##\s/.test(trimmed)) {
670
678
  break;
679
+ }
671
680
  // Skip blank lines and HTML comments
672
- if (!trimmed || trimmed.startsWith('<!--'))
681
+ if (!trimmed || trimmed.startsWith('<!--')) {
673
682
  continue;
683
+ }
674
684
  // Collect bullet items
675
685
  if (trimmed.startsWith('-') || trimmed.startsWith('*')) {
676
686
  const rule = trimmed.replace(/^[-*]\s*/, '').trim();
@@ -781,8 +791,9 @@ function buildEnvironmentContext(cwd) {
781
791
  // Kubernetes context
782
792
  try {
783
793
  const ctx = execSync('kubectl config current-context', { timeout: 2000, encoding: 'utf-8' }).trim();
784
- if (ctx)
794
+ if (ctx) {
785
795
  parts.push(`- Kubernetes context: ${ctx}`);
796
+ }
786
797
  }
787
798
  catch { /* ignore */ }
788
799
  // Terraform workspace (only if .terraform dir exists)
@@ -791,8 +802,9 @@ function buildEnvironmentContext(cwd) {
791
802
  const ws = execSync('terraform workspace show', {
792
803
  cwd: effectiveCwd, timeout: 5000, encoding: 'utf-8',
793
804
  }).trim();
794
- if (ws)
805
+ if (ws) {
795
806
  parts.push(`- Terraform workspace: ${ws}`);
807
+ }
796
808
  }
797
809
  catch { /* ignore */ }
798
810
  }
@@ -808,12 +820,14 @@ function buildEnvironmentContext(cwd) {
808
820
  catch { /* ignore */ }
809
821
  try {
810
822
  const region = execSync('aws configure get region', { timeout: 2000, encoding: 'utf-8' }).trim();
811
- if (region)
823
+ if (region) {
812
824
  parts.push(`- AWS region: ${region}`);
825
+ }
813
826
  }
814
827
  catch {
815
- if (process.env.AWS_DEFAULT_REGION)
828
+ if (process.env.AWS_DEFAULT_REGION) {
816
829
  parts.push(`- AWS region: ${process.env.AWS_DEFAULT_REGION}`);
830
+ }
817
831
  }
818
832
  }
819
833
  // GCP project (only if gcloud available)
@@ -821,8 +835,9 @@ function buildEnvironmentContext(cwd) {
821
835
  const proj = execSync('gcloud config get-value project 2>/dev/null', {
822
836
  timeout: 3000, encoding: 'utf-8',
823
837
  }).trim();
824
- if (proj && proj !== '(unset)')
838
+ if (proj && proj !== '(unset)') {
825
839
  parts.push(`- GCP project: ${proj}`);
840
+ }
826
841
  }
827
842
  catch { /* ignore */ }
828
843
  return parts.join('\n');
@@ -840,13 +855,15 @@ function buildEnvironmentContext(cwd) {
840
855
  function buildPrimaryCloudSection() {
841
856
  try {
842
857
  const configPath = path.join(homedir(), '.nimbus', 'config.json');
843
- if (!fs.existsSync(configPath))
858
+ if (!fs.existsSync(configPath)) {
844
859
  return null;
860
+ }
845
861
  const raw = fs.readFileSync(configPath, 'utf-8');
846
862
  const config = JSON.parse(raw);
847
863
  const clouds = config.primaryClouds;
848
- if (!Array.isArray(clouds) || clouds.length === 0)
864
+ if (!Array.isArray(clouds) || clouds.length === 0) {
849
865
  return null;
866
+ }
850
867
  const cloudNames = clouds.map(c => c.toUpperCase()).join(', ');
851
868
  return [
852
869
  '# Primary Cloud Providers',
package/dist/src/app.js CHANGED
@@ -41,7 +41,7 @@ export async function initApp() {
41
41
  '',
42
42
  '\x1b[2mRun `nimbus doctor` for detailed diagnosis.\x1b[0m',
43
43
  ];
44
- process.stderr.write(lines.join('\n') + '\n');
44
+ process.stderr.write(`${lines.join('\n')}\n`);
45
45
  process.exit(1);
46
46
  }
47
47
  startupWarnings = issues.warnings;
@@ -13,8 +13,9 @@ const SERVICE = 'nimbus-ai';
13
13
  /** Lazy-loaded keytar module. null = checked and unavailable. */
14
14
  let keytarModule = undefined; // undefined = not yet checked
15
15
  async function loadKeytar() {
16
- if (keytarModule !== undefined)
16
+ if (keytarModule !== undefined) {
17
17
  return keytarModule;
18
+ }
18
19
  try {
19
20
  // Dynamic import — keytar is an optional peer dependency
20
21
  // eslint-disable-next-line @typescript-eslint/no-var-requires
@@ -38,8 +39,9 @@ export async function isKeychainAvailable() {
38
39
  */
39
40
  export async function keychainGet(account) {
40
41
  const kt = await loadKeytar();
41
- if (!kt)
42
+ if (!kt) {
42
43
  return null;
44
+ }
43
45
  try {
44
46
  return await kt.getPassword(SERVICE, account);
45
47
  }
@@ -53,8 +55,9 @@ export async function keychainGet(account) {
53
55
  */
54
56
  export async function keychainSet(account, secret) {
55
57
  const kt = await loadKeytar();
56
- if (!kt)
58
+ if (!kt) {
57
59
  return;
60
+ }
58
61
  try {
59
62
  await kt.setPassword(SERVICE, account, secret);
60
63
  }
@@ -68,8 +71,9 @@ export async function keychainSet(account, secret) {
68
71
  */
69
72
  export async function keychainDelete(account) {
70
73
  const kt = await loadKeytar();
71
- if (!kt)
74
+ if (!kt) {
72
75
  return;
76
+ }
73
77
  try {
74
78
  await kt.deletePassword(SERVICE, account);
75
79
  }