@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.
Files changed (435) hide show
  1. package/CHANGELOG.md +268 -89
  2. package/README.md +26 -567
  3. package/dist/src/agent/compaction-agent.js +24 -12
  4. package/dist/src/agent/context-manager.js +2 -1
  5. package/dist/src/agent/expand-files.js +2 -1
  6. package/dist/src/agent/loop.js +71 -33
  7. package/dist/src/agent/permissions.js +4 -2
  8. package/dist/src/agent/system-prompt.js +34 -17
  9. package/dist/src/app.js +1 -1
  10. package/dist/src/auth/keychain.js +8 -4
  11. package/dist/src/auth/store.js +70 -107
  12. package/dist/src/cli/init.js +35 -19
  13. package/dist/src/cli/run.js +18 -10
  14. package/dist/src/cli/serve.js +4 -2
  15. package/dist/src/cli.js +52 -11
  16. package/dist/src/commands/alias.js +5 -3
  17. package/dist/src/commands/audit/index.js +2 -1
  18. package/dist/src/commands/aws-terraform.js +36 -18
  19. package/dist/src/commands/completions.js +1 -1
  20. package/dist/src/commands/config.js +3 -2
  21. package/dist/src/commands/connect-github.js +92 -0
  22. package/dist/src/commands/cost/index.js +3 -2
  23. package/dist/src/commands/deploy.js +15 -10
  24. package/dist/src/commands/doctor.js +9 -6
  25. package/dist/src/commands/drift/index.js +2 -1
  26. package/dist/src/commands/export.js +5 -3
  27. package/dist/src/commands/generate-terraform.js +110 -2
  28. package/dist/src/commands/import.js +3 -3
  29. package/dist/src/commands/incident.js +10 -5
  30. package/dist/src/commands/login.js +8 -93
  31. package/dist/src/commands/logs.js +16 -8
  32. package/dist/src/commands/onboarding.js +6 -4
  33. package/dist/src/commands/pipeline.js +6 -3
  34. package/dist/src/commands/plugin.js +3 -2
  35. package/dist/src/commands/profile.js +27 -14
  36. package/dist/src/commands/questionnaire.js +1 -1
  37. package/dist/src/commands/rollback.js +3 -2
  38. package/dist/src/commands/rollout.js +5 -3
  39. package/dist/src/commands/runbook.js +17 -10
  40. package/dist/src/commands/schedule.js +10 -5
  41. package/dist/src/commands/status.js +2 -1
  42. package/dist/src/commands/team-context.js +12 -7
  43. package/dist/src/commands/template.js +1 -1
  44. package/dist/src/commands/tf/index.js +6 -3
  45. package/dist/src/commands/upgrade.js +5 -3
  46. package/dist/src/commands/version.js +6 -3
  47. package/dist/src/commands/watch.js +6 -3
  48. package/dist/src/compat/sqlite.js +5 -3
  49. package/dist/src/config/mode-store.js +2 -1
  50. package/dist/src/config/profiles.js +4 -2
  51. package/dist/src/config/types.js +2 -1
  52. package/dist/src/engine/executor.js +8 -4
  53. package/dist/src/engine/planner.js +9 -5
  54. package/dist/src/llm/providers/anthropic.js +6 -3
  55. package/dist/src/llm/providers/ollama.js +1 -1
  56. package/dist/src/llm/router.js +22 -7
  57. package/dist/src/nimbus.js +1 -0
  58. package/dist/src/sessions/manager.js +6 -3
  59. package/dist/src/sharing/viewer.js +2 -1
  60. package/dist/src/tools/file-ops.js +1 -2
  61. package/dist/src/tools/schemas/devops.js +197 -108
  62. package/dist/src/tools/schemas/standard.js +1 -1
  63. package/dist/src/ui/App.js +25 -13
  64. package/dist/src/ui/FileDiffModal.js +22 -11
  65. package/dist/src/ui/HelpModal.js +2 -1
  66. package/dist/src/ui/InputBox.js +6 -3
  67. package/dist/src/ui/MessageList.js +40 -20
  68. package/dist/src/ui/TerminalPane.js +2 -1
  69. package/dist/src/ui/ToolCallDisplay.js +12 -6
  70. package/dist/src/ui/TreePane.js +2 -1
  71. package/dist/src/ui/ink/index.js +37 -21
  72. package/dist/src/version.js +1 -1
  73. package/dist/src/watcher/index.js +8 -4
  74. package/package.json +3 -5
  75. package/src/__tests__/alias.test.ts +0 -133
  76. package/src/__tests__/app.test.ts +0 -76
  77. package/src/__tests__/audit.test.ts +0 -877
  78. package/src/__tests__/circuit-breaker.test.ts +0 -116
  79. package/src/__tests__/cli-run.test.ts +0 -351
  80. package/src/__tests__/compat-sqlite.test.ts +0 -68
  81. package/src/__tests__/context-manager.test.ts +0 -632
  82. package/src/__tests__/context.test.ts +0 -242
  83. package/src/__tests__/devops-terminal-gaps.test.ts +0 -718
  84. package/src/__tests__/doctor.test.ts +0 -48
  85. package/src/__tests__/enterprise.test.ts +0 -401
  86. package/src/__tests__/export.test.ts +0 -236
  87. package/src/__tests__/gap-11-18-20.test.ts +0 -958
  88. package/src/__tests__/generator.test.ts +0 -433
  89. package/src/__tests__/helm-streaming.test.ts +0 -127
  90. package/src/__tests__/hooks.test.ts +0 -582
  91. package/src/__tests__/incident.test.ts +0 -179
  92. package/src/__tests__/init.test.ts +0 -487
  93. package/src/__tests__/intent-parser.test.ts +0 -229
  94. package/src/__tests__/llm-router.test.ts +0 -209
  95. package/src/__tests__/logs.test.ts +0 -107
  96. package/src/__tests__/loop-errors.test.ts +0 -244
  97. package/src/__tests__/lsp.test.ts +0 -293
  98. package/src/__tests__/modes.test.ts +0 -336
  99. package/src/__tests__/perf-optimizations.test.ts +0 -847
  100. package/src/__tests__/permissions.test.ts +0 -338
  101. package/src/__tests__/pipeline.test.ts +0 -50
  102. package/src/__tests__/polish-phase3.test.ts +0 -340
  103. package/src/__tests__/profile.test.ts +0 -237
  104. package/src/__tests__/rollback.test.ts +0 -83
  105. package/src/__tests__/runbook.test.ts +0 -219
  106. package/src/__tests__/schedule.test.ts +0 -206
  107. package/src/__tests__/serve.test.ts +0 -275
  108. package/src/__tests__/sessions.test.ts +0 -322
  109. package/src/__tests__/sharing.test.ts +0 -340
  110. package/src/__tests__/snapshots.test.ts +0 -581
  111. package/src/__tests__/standalone-migration.test.ts +0 -199
  112. package/src/__tests__/state-db.test.ts +0 -334
  113. package/src/__tests__/status.test.ts +0 -158
  114. package/src/__tests__/stream-with-tools.test.ts +0 -778
  115. package/src/__tests__/subagents.test.ts +0 -176
  116. package/src/__tests__/system-prompt.test.ts +0 -248
  117. package/src/__tests__/terminal-gap-v2.test.ts +0 -395
  118. package/src/__tests__/terminal-parity.test.ts +0 -393
  119. package/src/__tests__/tf-apply.test.ts +0 -187
  120. package/src/__tests__/tool-converter.test.ts +0 -256
  121. package/src/__tests__/tool-schemas.test.ts +0 -602
  122. package/src/__tests__/tools.test.ts +0 -144
  123. package/src/__tests__/version-json.test.ts +0 -184
  124. package/src/__tests__/version.test.ts +0 -49
  125. package/src/__tests__/watch.test.ts +0 -129
  126. package/src/agent/compaction-agent.ts +0 -266
  127. package/src/agent/context-manager.ts +0 -499
  128. package/src/agent/context.ts +0 -427
  129. package/src/agent/deploy-preview.ts +0 -487
  130. package/src/agent/expand-files.ts +0 -108
  131. package/src/agent/index.ts +0 -68
  132. package/src/agent/loop.ts +0 -1998
  133. package/src/agent/modes.ts +0 -429
  134. package/src/agent/permissions.ts +0 -513
  135. package/src/agent/subagents/base.ts +0 -116
  136. package/src/agent/subagents/cost.ts +0 -51
  137. package/src/agent/subagents/explore.ts +0 -42
  138. package/src/agent/subagents/general.ts +0 -54
  139. package/src/agent/subagents/index.ts +0 -102
  140. package/src/agent/subagents/infra.ts +0 -59
  141. package/src/agent/subagents/security.ts +0 -69
  142. package/src/agent/system-prompt.ts +0 -990
  143. package/src/app.ts +0 -180
  144. package/src/audit/activity-log.ts +0 -290
  145. package/src/audit/compliance-checker.ts +0 -540
  146. package/src/audit/cost-tracker.ts +0 -318
  147. package/src/audit/index.ts +0 -23
  148. package/src/audit/security-scanner.ts +0 -641
  149. package/src/auth/guard.ts +0 -75
  150. package/src/auth/index.ts +0 -56
  151. package/src/auth/keychain.ts +0 -82
  152. package/src/auth/oauth.ts +0 -465
  153. package/src/auth/providers.ts +0 -470
  154. package/src/auth/sso.ts +0 -113
  155. package/src/auth/store.ts +0 -505
  156. package/src/auth/types.ts +0 -187
  157. package/src/build.ts +0 -141
  158. package/src/cli/index.ts +0 -16
  159. package/src/cli/init.ts +0 -1227
  160. package/src/cli/openapi-spec.ts +0 -356
  161. package/src/cli/run.ts +0 -628
  162. package/src/cli/serve-auth.ts +0 -80
  163. package/src/cli/serve.ts +0 -539
  164. package/src/cli/web.ts +0 -71
  165. package/src/cli.ts +0 -1728
  166. package/src/clients/core-engine-client.ts +0 -227
  167. package/src/clients/enterprise-client.ts +0 -334
  168. package/src/clients/generator-client.ts +0 -351
  169. package/src/clients/git-client.ts +0 -627
  170. package/src/clients/github-client.ts +0 -410
  171. package/src/clients/helm-client.ts +0 -504
  172. package/src/clients/index.ts +0 -80
  173. package/src/clients/k8s-client.ts +0 -497
  174. package/src/clients/llm-client.ts +0 -161
  175. package/src/clients/rest-client.ts +0 -130
  176. package/src/clients/service-discovery.ts +0 -38
  177. package/src/clients/terraform-client.ts +0 -482
  178. package/src/clients/tools-client.ts +0 -1843
  179. package/src/clients/ws-client.ts +0 -115
  180. package/src/commands/alias.ts +0 -100
  181. package/src/commands/analyze/index.ts +0 -352
  182. package/src/commands/apply/helm.ts +0 -473
  183. package/src/commands/apply/index.ts +0 -213
  184. package/src/commands/apply/k8s.ts +0 -454
  185. package/src/commands/apply/terraform.ts +0 -582
  186. package/src/commands/ask.ts +0 -167
  187. package/src/commands/audit/index.ts +0 -357
  188. package/src/commands/auth-cloud.ts +0 -407
  189. package/src/commands/auth-list.ts +0 -134
  190. package/src/commands/auth-profile.ts +0 -121
  191. package/src/commands/auth-refresh.ts +0 -187
  192. package/src/commands/auth-status.ts +0 -141
  193. package/src/commands/aws/ec2.ts +0 -501
  194. package/src/commands/aws/iam.ts +0 -397
  195. package/src/commands/aws/index.ts +0 -133
  196. package/src/commands/aws/lambda.ts +0 -396
  197. package/src/commands/aws/rds.ts +0 -439
  198. package/src/commands/aws/s3.ts +0 -439
  199. package/src/commands/aws/vpc.ts +0 -393
  200. package/src/commands/aws-discover.ts +0 -542
  201. package/src/commands/aws-terraform.ts +0 -755
  202. package/src/commands/azure/aks.ts +0 -376
  203. package/src/commands/azure/functions.ts +0 -253
  204. package/src/commands/azure/index.ts +0 -116
  205. package/src/commands/azure/storage.ts +0 -478
  206. package/src/commands/azure/vm.ts +0 -355
  207. package/src/commands/billing/index.ts +0 -256
  208. package/src/commands/chat.ts +0 -320
  209. package/src/commands/completions.ts +0 -268
  210. package/src/commands/config.ts +0 -372
  211. package/src/commands/cost/cloud-cost-estimator.ts +0 -266
  212. package/src/commands/cost/estimator.ts +0 -79
  213. package/src/commands/cost/index.ts +0 -810
  214. package/src/commands/cost/parsers/terraform.ts +0 -273
  215. package/src/commands/cost/parsers/types.ts +0 -25
  216. package/src/commands/cost/pricing/aws.ts +0 -544
  217. package/src/commands/cost/pricing/azure.ts +0 -499
  218. package/src/commands/cost/pricing/gcp.ts +0 -396
  219. package/src/commands/cost/pricing/index.ts +0 -40
  220. package/src/commands/demo.ts +0 -250
  221. package/src/commands/deploy.ts +0 -260
  222. package/src/commands/doctor.ts +0 -1386
  223. package/src/commands/drift/index.ts +0 -787
  224. package/src/commands/explain.ts +0 -277
  225. package/src/commands/export.ts +0 -146
  226. package/src/commands/feedback.ts +0 -389
  227. package/src/commands/fix.ts +0 -324
  228. package/src/commands/fs/index.ts +0 -402
  229. package/src/commands/gcp/compute.ts +0 -325
  230. package/src/commands/gcp/functions.ts +0 -271
  231. package/src/commands/gcp/gke.ts +0 -438
  232. package/src/commands/gcp/iam.ts +0 -344
  233. package/src/commands/gcp/index.ts +0 -129
  234. package/src/commands/gcp/storage.ts +0 -284
  235. package/src/commands/generate-helm.ts +0 -1249
  236. package/src/commands/generate-k8s.ts +0 -1508
  237. package/src/commands/generate-terraform.ts +0 -1202
  238. package/src/commands/gh/index.ts +0 -863
  239. package/src/commands/git/index.ts +0 -1343
  240. package/src/commands/helm/index.ts +0 -1126
  241. package/src/commands/help.ts +0 -715
  242. package/src/commands/history.ts +0 -149
  243. package/src/commands/import.ts +0 -868
  244. package/src/commands/incident.ts +0 -166
  245. package/src/commands/index.ts +0 -367
  246. package/src/commands/init.ts +0 -1051
  247. package/src/commands/k8s/index.ts +0 -1137
  248. package/src/commands/login.ts +0 -716
  249. package/src/commands/logout.ts +0 -83
  250. package/src/commands/logs.ts +0 -167
  251. package/src/commands/onboarding.ts +0 -405
  252. package/src/commands/pipeline.ts +0 -186
  253. package/src/commands/plan/display.ts +0 -279
  254. package/src/commands/plan/index.ts +0 -599
  255. package/src/commands/plugin.ts +0 -398
  256. package/src/commands/preview.ts +0 -452
  257. package/src/commands/profile.ts +0 -342
  258. package/src/commands/questionnaire.ts +0 -1172
  259. package/src/commands/resume.ts +0 -47
  260. package/src/commands/rollback.ts +0 -315
  261. package/src/commands/rollout.ts +0 -88
  262. package/src/commands/runbook.ts +0 -346
  263. package/src/commands/schedule.ts +0 -236
  264. package/src/commands/status.ts +0 -252
  265. package/src/commands/team/index.ts +0 -346
  266. package/src/commands/team-context.ts +0 -220
  267. package/src/commands/template.ts +0 -233
  268. package/src/commands/tf/index.ts +0 -1093
  269. package/src/commands/upgrade.ts +0 -607
  270. package/src/commands/usage/index.ts +0 -134
  271. package/src/commands/version.ts +0 -174
  272. package/src/commands/watch.ts +0 -153
  273. package/src/compat/index.ts +0 -2
  274. package/src/compat/runtime.ts +0 -12
  275. package/src/compat/sqlite.ts +0 -177
  276. package/src/config/index.ts +0 -17
  277. package/src/config/manager.ts +0 -530
  278. package/src/config/mode-store.ts +0 -62
  279. package/src/config/profiles.ts +0 -84
  280. package/src/config/safety-policy.ts +0 -358
  281. package/src/config/schema.ts +0 -125
  282. package/src/config/types.ts +0 -609
  283. package/src/config/workspace-state.ts +0 -53
  284. package/src/context/context-db.ts +0 -199
  285. package/src/demo/index.ts +0 -349
  286. package/src/demo/scenarios/full-journey.ts +0 -229
  287. package/src/demo/scenarios/getting-started.ts +0 -127
  288. package/src/demo/scenarios/helm-release.ts +0 -341
  289. package/src/demo/scenarios/k8s-deployment.ts +0 -194
  290. package/src/demo/scenarios/terraform-vpc.ts +0 -170
  291. package/src/demo/types.ts +0 -92
  292. package/src/engine/cost-estimator.ts +0 -480
  293. package/src/engine/diagram-generator.ts +0 -256
  294. package/src/engine/drift-detector.ts +0 -902
  295. package/src/engine/executor.ts +0 -1066
  296. package/src/engine/index.ts +0 -76
  297. package/src/engine/orchestrator.ts +0 -636
  298. package/src/engine/planner.ts +0 -787
  299. package/src/engine/safety.ts +0 -743
  300. package/src/engine/verifier.ts +0 -770
  301. package/src/enterprise/audit.ts +0 -348
  302. package/src/enterprise/auth.ts +0 -270
  303. package/src/enterprise/billing.ts +0 -822
  304. package/src/enterprise/index.ts +0 -17
  305. package/src/enterprise/teams.ts +0 -443
  306. package/src/generator/best-practices.ts +0 -1608
  307. package/src/generator/helm.ts +0 -630
  308. package/src/generator/index.ts +0 -37
  309. package/src/generator/intent-parser.ts +0 -514
  310. package/src/generator/kubernetes.ts +0 -976
  311. package/src/generator/terraform.ts +0 -1875
  312. package/src/history/index.ts +0 -8
  313. package/src/history/manager.ts +0 -250
  314. package/src/history/types.ts +0 -34
  315. package/src/hooks/config.ts +0 -432
  316. package/src/hooks/engine.ts +0 -392
  317. package/src/hooks/index.ts +0 -4
  318. package/src/llm/auth-bridge.ts +0 -198
  319. package/src/llm/circuit-breaker.ts +0 -140
  320. package/src/llm/config-loader.ts +0 -201
  321. package/src/llm/cost-calculator.ts +0 -171
  322. package/src/llm/index.ts +0 -8
  323. package/src/llm/model-aliases.ts +0 -115
  324. package/src/llm/provider-registry.ts +0 -63
  325. package/src/llm/providers/anthropic.ts +0 -462
  326. package/src/llm/providers/bedrock.ts +0 -477
  327. package/src/llm/providers/google.ts +0 -405
  328. package/src/llm/providers/ollama.ts +0 -767
  329. package/src/llm/providers/openai-compatible.ts +0 -340
  330. package/src/llm/providers/openai.ts +0 -328
  331. package/src/llm/providers/openrouter.ts +0 -338
  332. package/src/llm/router.ts +0 -1104
  333. package/src/llm/types.ts +0 -232
  334. package/src/lsp/client.ts +0 -298
  335. package/src/lsp/languages.ts +0 -119
  336. package/src/lsp/manager.ts +0 -294
  337. package/src/mcp/client.ts +0 -402
  338. package/src/mcp/index.ts +0 -5
  339. package/src/mcp/manager.ts +0 -133
  340. package/src/nimbus.ts +0 -233
  341. package/src/plugins/index.ts +0 -27
  342. package/src/plugins/loader.ts +0 -334
  343. package/src/plugins/manager.ts +0 -376
  344. package/src/plugins/types.ts +0 -284
  345. package/src/scanners/cicd-scanner.ts +0 -258
  346. package/src/scanners/cloud-scanner.ts +0 -466
  347. package/src/scanners/framework-scanner.ts +0 -469
  348. package/src/scanners/iac-scanner.ts +0 -388
  349. package/src/scanners/index.ts +0 -539
  350. package/src/scanners/language-scanner.ts +0 -276
  351. package/src/scanners/package-manager-scanner.ts +0 -277
  352. package/src/scanners/types.ts +0 -172
  353. package/src/sessions/manager.ts +0 -472
  354. package/src/sessions/types.ts +0 -44
  355. package/src/sharing/sync.ts +0 -300
  356. package/src/sharing/viewer.ts +0 -163
  357. package/src/snapshots/index.ts +0 -2
  358. package/src/snapshots/manager.ts +0 -530
  359. package/src/state/artifacts.ts +0 -147
  360. package/src/state/audit.ts +0 -137
  361. package/src/state/billing.ts +0 -240
  362. package/src/state/checkpoints.ts +0 -117
  363. package/src/state/config.ts +0 -67
  364. package/src/state/conversations.ts +0 -14
  365. package/src/state/credentials.ts +0 -154
  366. package/src/state/db.ts +0 -58
  367. package/src/state/index.ts +0 -26
  368. package/src/state/messages.ts +0 -115
  369. package/src/state/projects.ts +0 -123
  370. package/src/state/schema.ts +0 -236
  371. package/src/state/sessions.ts +0 -147
  372. package/src/state/teams.ts +0 -200
  373. package/src/telemetry.ts +0 -108
  374. package/src/tools/aws-ops.ts +0 -952
  375. package/src/tools/azure-ops.ts +0 -579
  376. package/src/tools/file-ops.ts +0 -615
  377. package/src/tools/gcp-ops.ts +0 -625
  378. package/src/tools/git-ops.ts +0 -773
  379. package/src/tools/github-ops.ts +0 -799
  380. package/src/tools/helm-ops.ts +0 -943
  381. package/src/tools/index.ts +0 -17
  382. package/src/tools/k8s-ops.ts +0 -819
  383. package/src/tools/schemas/converter.ts +0 -184
  384. package/src/tools/schemas/devops.ts +0 -3502
  385. package/src/tools/schemas/index.ts +0 -73
  386. package/src/tools/schemas/standard.ts +0 -1148
  387. package/src/tools/schemas/types.ts +0 -735
  388. package/src/tools/spawn-exec.ts +0 -148
  389. package/src/tools/terraform-ops.ts +0 -862
  390. package/src/types/ambient.d.ts +0 -193
  391. package/src/types/config.ts +0 -83
  392. package/src/types/drift.ts +0 -116
  393. package/src/types/enterprise.ts +0 -335
  394. package/src/types/index.ts +0 -20
  395. package/src/types/plan.ts +0 -44
  396. package/src/types/request.ts +0 -65
  397. package/src/types/response.ts +0 -54
  398. package/src/types/service.ts +0 -51
  399. package/src/ui/App.tsx +0 -2114
  400. package/src/ui/DeployPreview.tsx +0 -174
  401. package/src/ui/FileDiffModal.tsx +0 -162
  402. package/src/ui/Header.tsx +0 -131
  403. package/src/ui/HelpModal.tsx +0 -57
  404. package/src/ui/InputBox.tsx +0 -503
  405. package/src/ui/MessageList.tsx +0 -1032
  406. package/src/ui/PermissionPrompt.tsx +0 -163
  407. package/src/ui/StatusBar.tsx +0 -277
  408. package/src/ui/TerminalPane.tsx +0 -84
  409. package/src/ui/ToolCallDisplay.tsx +0 -643
  410. package/src/ui/TreePane.tsx +0 -132
  411. package/src/ui/chat-ui.ts +0 -850
  412. package/src/ui/index.ts +0 -33
  413. package/src/ui/ink/index.ts +0 -1444
  414. package/src/ui/streaming.ts +0 -176
  415. package/src/ui/theme.ts +0 -104
  416. package/src/ui/types.ts +0 -75
  417. package/src/utils/analytics.ts +0 -72
  418. package/src/utils/cost-warning.ts +0 -27
  419. package/src/utils/env.ts +0 -46
  420. package/src/utils/errors.ts +0 -69
  421. package/src/utils/event-bus.ts +0 -38
  422. package/src/utils/index.ts +0 -24
  423. package/src/utils/logger.ts +0 -171
  424. package/src/utils/rate-limiter.ts +0 -121
  425. package/src/utils/service-auth.ts +0 -49
  426. package/src/utils/validation.ts +0 -53
  427. package/src/version.ts +0 -4
  428. package/src/watcher/index.ts +0 -214
  429. package/src/wizard/approval.ts +0 -383
  430. package/src/wizard/index.ts +0 -25
  431. package/src/wizard/prompts.ts +0 -338
  432. package/src/wizard/types.ts +0 -172
  433. package/src/wizard/ui.ts +0 -556
  434. package/src/wizard/wizard.ts +0 -304
  435. package/tsconfig.json +0 -24
@@ -707,7 +707,7 @@ export const todoReadTool = {
707
707
  });
708
708
  return ok(lines.join('\n'));
709
709
  }
710
- catch (error) {
710
+ catch (_error) {
711
711
  // Fallback to original placeholder behavior on DB failure.
712
712
  return ok('No tasks yet.');
713
713
  }
@@ -142,18 +142,21 @@ export function App({ initialSession, onMessage, onAbort, onCompact, onContext,
142
142
  addMessage: (msg) => {
143
143
  setMessages(prev => [...prev, msg]);
144
144
  // C1: Keep pinned to bottom when scroll is locked
145
- if (scrollLockedRef.current)
145
+ if (scrollLockedRef.current) {
146
146
  setScrollOffset(0);
147
+ }
147
148
  },
148
149
  updateMessage: (id, content) => {
149
- if (content)
150
+ if (content) {
150
151
  setCurrentTurnHasOutput(true);
152
+ }
151
153
  setMessages(prev => prev.map(m => (m.id === id ? { ...m, content } : m)));
152
154
  },
153
155
  updateSession: (patch) => setSession(prev => ({ ...prev, ...patch })),
154
156
  setToolCalls: (toolCalls) => {
155
- if (toolCalls.length > 0)
157
+ if (toolCalls.length > 0) {
156
158
  setCurrentTurnHasOutput(true);
159
+ }
157
160
  setActiveToolCalls(toolCalls);
158
161
  // M3: Auto-show terminal pane when long-running DevOps tools start
159
162
  const LONG_RUNNING_TOOL_PATTERNS = [
@@ -975,15 +978,18 @@ export function App({ initialSession, onMessage, onAbort, onCompact, onContext,
975
978
  const watcher = new FileWatcher(process.cwd());
976
979
  watcher.start();
977
980
  watcher.on('change', (filePath) => {
978
- if (ac.signal.aborted)
981
+ if (ac.signal.aborted) {
979
982
  return;
983
+ }
980
984
  const ext = pattern.replace('**/', '').replace(/\*/g, '');
981
- if (ext && !filePath.includes(ext))
985
+ if (ext && !filePath.includes(ext)) {
982
986
  return;
987
+ }
983
988
  const prompt = `File changed: ${filePath}. Analyze the change and report any issues or drift.`;
984
989
  sysMsg(`[watch] Change detected: ${filePath}`);
985
- if (!isProcessing)
990
+ if (!isProcessing) {
986
991
  handleSubmit(prompt);
992
+ }
987
993
  });
988
994
  ac.signal.addEventListener('abort', () => watcher.stop());
989
995
  }
@@ -1062,8 +1068,9 @@ export function App({ initialSession, onMessage, onAbort, onCompact, onContext,
1062
1068
  setIsProcessing(true);
1063
1069
  setCurrentTurnHasOutput(false);
1064
1070
  setProcessingStartTime(Date.now());
1065
- if (onMessage)
1071
+ if (onMessage) {
1066
1072
  onMessage('List all available Kubernetes contexts and show the current one.');
1073
+ }
1067
1074
  }
1068
1075
  return;
1069
1076
  }
@@ -1132,8 +1139,9 @@ export function App({ initialSession, onMessage, onAbort, onCompact, onContext,
1132
1139
  setIsProcessing(true);
1133
1140
  setCurrentTurnHasOutput(false);
1134
1141
  setProcessingStartTime(Date.now());
1135
- if (onMessage)
1142
+ if (onMessage) {
1136
1143
  onMessage('List all Terraform workspaces and show the current one.');
1144
+ }
1137
1145
  }
1138
1146
  return;
1139
1147
  }
@@ -1526,8 +1534,9 @@ export function App({ initialSession, onMessage, onAbort, onCompact, onContext,
1526
1534
  if (key.downArrow || input === 'j') {
1527
1535
  setScrollOffset(prev => {
1528
1536
  const next = Math.max(0, prev - 1);
1529
- if (next === 0)
1537
+ if (next === 0) {
1530
1538
  setScrollLocked(true);
1539
+ }
1531
1540
  return next;
1532
1541
  });
1533
1542
  return;
@@ -1542,8 +1551,9 @@ export function App({ initialSession, onMessage, onAbort, onCompact, onContext,
1542
1551
  if (key.pageDown || input === 'f' || input === ' ') {
1543
1552
  setScrollOffset(prev => {
1544
1553
  const next = Math.max(0, prev - 10);
1545
- if (next === 0)
1554
+ if (next === 0) {
1546
1555
  setScrollLocked(true);
1556
+ }
1547
1557
  return next;
1548
1558
  });
1549
1559
  return;
@@ -1593,13 +1603,15 @@ export function App({ initialSession, onMessage, onAbort, onCompact, onContext,
1593
1603
  }, { isActive: !isProcessing && !permissionRequest && !deployPreview && !fileDiffRequest && !showHelp });
1594
1604
  /* -- H3: Deploy mode confirmation input handler ----------------------- */
1595
1605
  useInput((input, key) => {
1596
- if (!pendingDeployConfirm)
1606
+ if (!pendingDeployConfirm) {
1597
1607
  return;
1608
+ }
1598
1609
  if (input === 'y' || input === 'Y') {
1599
1610
  setPendingDeployConfirm(false);
1600
1611
  setSession(prev => ({ ...prev, mode: 'deploy' }));
1601
- if (onModeChange)
1612
+ if (onModeChange) {
1602
1613
  onModeChange('deploy');
1614
+ }
1603
1615
  try {
1604
1616
  const { saveModeForCwd } = require('../config/mode-store');
1605
1617
  saveModeForCwd(process.cwd(), 'deploy');
@@ -1643,7 +1655,7 @@ export function App({ initialSession, onMessage, onAbort, onCompact, onContext,
1643
1655
  return (_jsxs(Box, { flexDirection: "column", width: "100%", height: "100%", children: [showApiKeySetup && (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", padding: 1, marginBottom: 1, children: [_jsx(Text, { bold: true, color: "yellow", children: "Welcome to Nimbus! No API key configured." }), _jsx(Text, { dimColor: true, children: "Set ANTHROPIC_API_KEY environment variable, or run: nimbus login" }), _jsx(Text, { dimColor: true, children: "Press Enter to continue without API key (limited functionality)" }), _jsx(Text, { dimColor: true, children: "This banner will dismiss in 8 seconds or on your first message." })] })), _jsx(Header, { session: session }), _jsxs(Box, { flexDirection: "row", flexGrow: 1, children: [_jsx(Box, { flexDirection: "column", flexGrow: 1, children: _jsx(MessageList, { messages: messages, mode: session.mode, scrollOffset: scrollOffset, searchQuery: searchQuery || undefined, columns: columns }) }), (showTerminalPane || terminalPaneAuto) && (_jsx(TerminalPane, { toolCalls: completedToolCalls, maxLines: 20 })), showTreePane && (_jsx(TreePane, { cwd: process.cwd(), onSelectFile: fp => {
1644
1656
  // GAP-21: inject @filepath directly into InputBox via prefill state
1645
1657
  const cwd = process.cwd();
1646
- const rel = fp.startsWith(cwd + '/') ? fp.slice(cwd.length + 1) : fp;
1658
+ const rel = fp.startsWith(`${cwd}/`) ? fp.slice(cwd.length + 1) : fp;
1647
1659
  setInputPrefill(`@${rel} `);
1648
1660
  } }))] }), isProcessing && !currentTurnHasOutput && (_jsxs(Box, { paddingX: 1, paddingY: 0, children: [_jsx(Text, { color: "cyan", children: _jsx(Spinner, { type: "dots" }) }), _jsxs(Text, { color: "cyan", dimColor: true, children: [' ', "Thinking..."] })] })), visibleToolCalls.length > 0 && (_jsx(ToolCallDisplay, { toolCalls: visibleToolCalls, expanded: isProcessing })), permissionRequest && (_jsx(PermissionPrompt, { toolName: permissionRequest.tool, toolInput: permissionRequest.input, riskLevel: permissionRequest.riskLevel, onDecide: handlePermission })), pendingDeployConfirm && (_jsxs(Box, { flexDirection: "column", borderStyle: "double", borderColor: "red", paddingX: 2, paddingY: 1, children: [_jsx(Text, { bold: true, color: "red", children: "!! Switch to DEPLOY mode?" }), _jsx(Text, { children: " " }), _jsx(Text, { children: "DEPLOY mode enables destructive operations:" }), _jsx(Text, { dimColor: true, children: " terraform apply/destroy, kubectl delete, helm uninstall" }), _jsx(Text, { children: " " }), _jsxs(Text, { children: ["Press ", _jsx(Text, { bold: true, color: "green", children: "y" }), " to confirm | ", _jsx(Text, { bold: true, color: "red", children: "n" }), " or Esc to cancel"] })] })), deployPreview && _jsx(DeployPreview, { preview: deployPreview, onDecide: handleDeployDecision }), fileDiffRequest && (_jsx(FileDiffModal, { request: {
1649
1661
  ...fileDiffRequest,
@@ -70,22 +70,30 @@ export function FileDiffModal({ request }) {
70
70
  const total = diffLines.length;
71
71
  const maxOffset = Math.max(0, total - VISIBLE_LINES);
72
72
  useInput((input, key) => {
73
- if (input === 'a')
73
+ if (input === 'a') {
74
74
  request.onDecide('apply');
75
- if (input === 'r')
75
+ }
76
+ if (input === 'r') {
76
77
  request.onDecide('reject');
77
- if (input === 'A')
78
+ }
79
+ if (input === 'A') {
78
80
  request.onDecide('apply-all');
79
- if (input === 'R')
81
+ }
82
+ if (input === 'R') {
80
83
  request.onDecide('reject-all');
81
- if (key.upArrow)
84
+ }
85
+ if (key.upArrow) {
82
86
  setScrollOffset(o => Math.max(0, o - 1));
83
- if (key.downArrow)
87
+ }
88
+ if (key.downArrow) {
84
89
  setScrollOffset(o => Math.min(maxOffset, o + 1));
85
- if (key.pageUp)
90
+ }
91
+ if (key.pageUp) {
86
92
  setScrollOffset(o => Math.max(0, o - VISIBLE_LINES));
87
- if (key.pageDown)
93
+ }
94
+ if (key.pageDown) {
88
95
  setScrollOffset(o => Math.min(maxOffset, o + VISIBLE_LINES));
96
+ }
89
97
  });
90
98
  const endLine = Math.min(scrollOffset + VISIBLE_LINES, total);
91
99
  const displayLines = diffLines.slice(scrollOffset, endLine);
@@ -97,12 +105,15 @@ export function FileDiffModal({ request }) {
97
105
  : '';
98
106
  return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "yellow", paddingX: 1, children: [_jsxs(Text, { bold: true, color: "yellow", children: [request.toolName, progress, ": ", request.filePath, scrollIndicator] }), _jsx(Box, { flexDirection: "column", marginY: 1, children: displayLines.map((line, i) => {
99
107
  let color;
100
- if (line.startsWith('+') && !line.startsWith('+++'))
108
+ if (line.startsWith('+') && !line.startsWith('+++')) {
101
109
  color = 'green';
102
- else if (line.startsWith('-') && !line.startsWith('---'))
110
+ }
111
+ else if (line.startsWith('-') && !line.startsWith('---')) {
103
112
  color = 'red';
104
- else if (line.startsWith('@@'))
113
+ }
114
+ else if (line.startsWith('@@')) {
105
115
  color = 'cyan';
116
+ }
106
117
  return (_jsx(Text, { color: color, dimColor: !color, children: line }, i));
107
118
  }) }), _jsx(Text, { dimColor: true, children: " [a] Apply [r] Reject [A] Apply all [R] Reject all [\u2191/\u2193] Scroll [PgUp/PgDn] Page" })] }));
108
119
  }
@@ -2,8 +2,9 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
2
  import { Box, Text, useInput } from 'ink';
3
3
  export function HelpModal({ onClose }) {
4
4
  useInput((input, key) => {
5
- if (key.escape || input === 'q' || input === '?')
5
+ if (key.escape || input === 'q' || input === '?') {
6
6
  onClose();
7
+ }
7
8
  });
8
9
  return (_jsxs(Box, { flexDirection: "column", borderStyle: "round", borderColor: "cyan", padding: 1, marginY: 1, children: [_jsx(Text, { bold: true, color: "cyan", children: " Nimbus DevOps Agent \u2014 Help " }), _jsx(Text, { children: " " }), _jsx(Text, { bold: true, children: "Slash Commands:" }), _jsx(Text, { children: " /help Show this help" }), _jsx(Text, { children: " /mode plan Switch to plan mode (read-only tools)" }), _jsx(Text, { children: " /mode build Switch to build mode (file + infra tools)" }), _jsx(Text, { children: " /mode deploy Switch to deploy mode (all tools + previews)" }), _jsx(Text, { children: " /clear Clear conversation history" }), _jsx(Text, { children: " /compact Compress context to free tokens" }), _jsx(Text, { children: " /context Show context window usage" }), _jsx(Text, { children: " /cost Show token usage and cost" }), _jsx(Text, { children: " /diff Show unstaged git diff" }), _jsx(Text, { children: " /init Regenerate NIMBUS.md project context" }), _jsx(Text, { children: " /model [name] Show or switch the active model" }), _jsx(Text, { children: " /models List all available provider models" }), _jsx(Text, { children: " /undo Undo last file change (snapshot)" }), _jsx(Text, { children: " /redo Redo last undone change" }), _jsx(Text, { children: " /sessions List active sessions" }), _jsx(Text, { children: " /new [name] Create a new session" }), _jsxs(Text, { children: [" /switch ", '<id>', " Switch to a different session"] }), _jsx(Text, { children: " " }), _jsx(Text, { bold: true, children: "DevOps Tools Available:" }), _jsx(Text, { children: " terraform, kubectl, helm, cloud_discover, cost_estimate," }), _jsx(Text, { children: " drift_detect, deploy_preview, git, task (subagent)" }), _jsx(Text, { children: " " }), _jsx(Text, { bold: true, children: "Keyboard Shortcuts:" }), _jsx(Text, { children: " ? Open this help panel" }), _jsx(Text, { children: " Tab Cycle mode (plan \u2192 build \u2192 deploy)" }), _jsx(Text, { children: " Ctrl+R Search input history" }), _jsx(Text, { children: " Ctrl+C Interrupt or exit" }), _jsx(Text, { children: " Esc / q / ? Close this help" }), _jsx(Text, { children: " " }), _jsx(Text, { dimColor: true, children: "Press Esc, q, or ? to close" })] }));
9
10
  }
@@ -27,12 +27,14 @@ const HISTORY_FILE = join(homedir(), '.nimbus', 'input-history.json');
27
27
  /** Load persisted input history from disk (returns [] on any error). */
28
28
  function loadHistory() {
29
29
  try {
30
- if (!existsSync(HISTORY_FILE))
30
+ if (!existsSync(HISTORY_FILE)) {
31
31
  return [];
32
+ }
32
33
  const raw = readFileSync(HISTORY_FILE, 'utf-8');
33
34
  const parsed = JSON.parse(raw);
34
- if (Array.isArray(parsed))
35
+ if (Array.isArray(parsed)) {
35
36
  return parsed.slice(-MAX_HISTORY);
37
+ }
36
38
  }
37
39
  catch { /* ignore */ }
38
40
  return [];
@@ -41,8 +43,9 @@ function loadHistory() {
41
43
  function saveHistory(entries) {
42
44
  try {
43
45
  const dir = join(homedir(), '.nimbus');
44
- if (!existsSync(dir))
46
+ if (!existsSync(dir)) {
45
47
  mkdirSync(dir, { recursive: true });
48
+ }
46
49
  writeFileSync(HISTORY_FILE, JSON.stringify(entries.slice(-MAX_HISTORY)), 'utf-8');
47
50
  }
48
51
  catch { /* non-critical */ }
@@ -42,14 +42,16 @@ export const _parseContentCache = new Map();
42
42
  const _PARSE_CACHE_MAX = 200;
43
43
  function parseContent(raw) {
44
44
  const cached = _parseContentCache.get(raw);
45
- if (cached !== undefined)
45
+ if (cached !== undefined) {
46
46
  return cached;
47
+ }
47
48
  const result = _parseContentRaw(raw);
48
49
  if (_parseContentCache.size >= _PARSE_CACHE_MAX) {
49
50
  // FIFO eviction: delete the oldest entry
50
51
  const firstKey = _parseContentCache.keys().next().value;
51
- if (firstKey !== undefined)
52
+ if (firstKey !== undefined) {
52
53
  _parseContentCache.delete(firstKey);
54
+ }
53
55
  }
54
56
  _parseContentCache.set(raw, result);
55
57
  return result;
@@ -306,8 +308,9 @@ function tokenizeYamlLine(line) {
306
308
  const keyMatch = line.match(/^(\s*)([\w\-./]+)(\s*:\s*)(.*)/);
307
309
  if (keyMatch) {
308
310
  const [, indent, key, colon, value] = keyMatch;
309
- if (indent)
311
+ if (indent) {
310
312
  tokens.push({ type: 'plain', text: indent });
313
+ }
311
314
  tokens.push({ type: 'type', text: key });
312
315
  tokens.push({ type: 'plain', text: colon });
313
316
  if (value) {
@@ -328,8 +331,9 @@ function tokenizeYamlLine(line) {
328
331
  const dashIdx = line.indexOf('-');
329
332
  tokens.push({ type: 'plain', text: line.slice(0, dashIdx + 1) });
330
333
  const rest = line.slice(dashIdx + 1);
331
- if (rest.trim())
334
+ if (rest.trim()) {
332
335
  tokens.push({ type: 'string', text: rest });
336
+ }
333
337
  return tokens;
334
338
  }
335
339
  return [{ type: 'plain', text: line }];
@@ -343,8 +347,9 @@ function tokenizeJsonLine(line) {
343
347
  if (line[i] === '"') {
344
348
  let j = i + 1;
345
349
  while (j < line.length && line[j] !== '"') {
346
- if (line[j] === '\\')
350
+ if (line[j] === '\\') {
347
351
  j++;
352
+ }
348
353
  j++;
349
354
  }
350
355
  j = Math.min(j + 1, line.length);
@@ -363,8 +368,9 @@ function tokenizeJsonLine(line) {
363
368
  // Numbers
364
369
  if (/[0-9\-]/.test(line[i]) && (i === 0 || /[\s,\[{:]/.test(line[i - 1]))) {
365
370
  let j = i;
366
- while (j < line.length && /[0-9.\-eE+]/.test(line[j]))
371
+ while (j < line.length && /[0-9.\-eE+]/.test(line[j])) {
367
372
  j++;
373
+ }
368
374
  tokens.push({ type: 'number', text: line.slice(i, j) });
369
375
  i = j;
370
376
  continue;
@@ -372,8 +378,9 @@ function tokenizeJsonLine(line) {
372
378
  // Keywords: true, false, null
373
379
  if (/[a-z]/.test(line[i])) {
374
380
  let j = i;
375
- while (j < line.length && /[a-z]/.test(line[j]))
381
+ while (j < line.length && /[a-z]/.test(line[j])) {
376
382
  j++;
383
+ }
377
384
  const word = line.slice(i, j);
378
385
  if (word === 'true' || word === 'false' || word === 'null') {
379
386
  tokens.push({ type: 'type', text: word });
@@ -399,11 +406,13 @@ function tokenizeDockerfileLine(line) {
399
406
  if (instrMatch && DOCKERFILE_INSTRUCTIONS.has(instrMatch[1])) {
400
407
  const tokens = [];
401
408
  const leadingSpaces = line.length - line.trimStart().length;
402
- if (leadingSpaces > 0)
409
+ if (leadingSpaces > 0) {
403
410
  tokens.push({ type: 'plain', text: line.slice(0, leadingSpaces) });
411
+ }
404
412
  tokens.push({ type: 'keyword', text: instrMatch[1] });
405
- if (instrMatch[2])
413
+ if (instrMatch[2]) {
406
414
  tokens.push({ type: 'plain', text: instrMatch[2] });
415
+ }
407
416
  return tokens;
408
417
  }
409
418
  return [{ type: 'plain', text: line }];
@@ -423,13 +432,15 @@ function tokenizeBashLine(line, keywords) {
423
432
  let j = i + 1;
424
433
  if (line[j] === '{') {
425
434
  j++;
426
- while (j < line.length && line[j] !== '}')
435
+ while (j < line.length && line[j] !== '}') {
427
436
  j++;
437
+ }
428
438
  j = Math.min(j + 1, line.length);
429
439
  }
430
440
  else {
431
- while (j < line.length && /[a-zA-Z0-9_]/.test(line[j]))
441
+ while (j < line.length && /[a-zA-Z0-9_]/.test(line[j])) {
432
442
  j++;
443
+ }
433
444
  }
434
445
  tokens.push({ type: 'number', text: line.slice(i, j) });
435
446
  i = j;
@@ -440,8 +451,9 @@ function tokenizeBashLine(line, keywords) {
440
451
  const quote = line[i];
441
452
  let j = i + 1;
442
453
  while (j < line.length && line[j] !== quote) {
443
- if (line[j] === '\\')
454
+ if (line[j] === '\\') {
444
455
  j++;
456
+ }
445
457
  j++;
446
458
  }
447
459
  j = Math.min(j + 1, line.length);
@@ -452,8 +464,9 @@ function tokenizeBashLine(line, keywords) {
452
464
  // Flags (words starting with -)
453
465
  if (line[i] === '-' && i > 0 && /\s/.test(line[i - 1])) {
454
466
  let j = i;
455
- while (j < line.length && !/\s/.test(line[j]))
467
+ while (j < line.length && !/\s/.test(line[j])) {
456
468
  j++;
469
+ }
457
470
  tokens.push({ type: 'comment', text: line.slice(i, j) });
458
471
  i = j;
459
472
  continue;
@@ -461,8 +474,9 @@ function tokenizeBashLine(line, keywords) {
461
474
  // Words / keywords
462
475
  if (/[a-zA-Z_]/.test(line[i])) {
463
476
  let j = i;
464
- while (j < line.length && /[a-zA-Z0-9_]/.test(line[j]))
477
+ while (j < line.length && /[a-zA-Z0-9_]/.test(line[j])) {
465
478
  j++;
479
+ }
466
480
  const word = line.slice(i, j);
467
481
  if (keywords.has(word)) {
468
482
  tokens.push({ type: 'keyword', text: word });
@@ -485,14 +499,18 @@ function tokenizeLine(line, keywords, types, language) {
485
499
  // Language-specific fast paths
486
500
  if (language) {
487
501
  const lang = language.toLowerCase();
488
- if (lang === 'yaml' || lang === 'yml')
502
+ if (lang === 'yaml' || lang === 'yml') {
489
503
  return tokenizeYamlLine(line);
490
- if (lang === 'json')
504
+ }
505
+ if (lang === 'json') {
491
506
  return tokenizeJsonLine(line);
492
- if (lang === 'dockerfile' || lang === 'docker')
507
+ }
508
+ if (lang === 'dockerfile' || lang === 'docker') {
493
509
  return tokenizeDockerfileLine(line);
494
- if (lang === 'bash' || lang === 'sh' || lang === 'shell' || lang === 'zsh')
510
+ }
511
+ if (lang === 'bash' || lang === 'sh' || lang === 'shell' || lang === 'zsh') {
495
512
  return tokenizeBashLine(line, keywords);
513
+ }
496
514
  }
497
515
  // Generic tokenizer below
498
516
  /* falls through */
@@ -669,8 +687,9 @@ function MessageBody({ content }) {
669
687
  * Returns a React node with matching portions highlighted.
670
688
  */
671
689
  function highlightText(text, query) {
672
- if (!query || !text.toLowerCase().includes(query.toLowerCase()))
690
+ if (!query || !text.toLowerCase().includes(query.toLowerCase())) {
673
691
  return text;
692
+ }
674
693
  const escaped = query.replace(/[.*+?^${}()|[\]\\]/g, '\\$&');
675
694
  const parts = text.split(new RegExp(`(${escaped})`, 'gi'));
676
695
  return (_jsx(_Fragment, { children: parts.map((p, i) => p.toLowerCase() === query.toLowerCase() ? (_jsx(Text, { color: "yellow", bold: true, children: p }, i)) : (_jsx(Text, { children: p }, i))) }));
@@ -682,8 +701,9 @@ function highlightText(text, query) {
682
701
  */
683
702
  function parseSubagentTag(content) {
684
703
  const match = content.match(/^\[subagent:(\w+)\]/);
685
- if (match)
704
+ if (match) {
686
705
  return match[1];
706
+ }
687
707
  return null;
688
708
  }
689
709
  /**
@@ -16,8 +16,9 @@ export function TerminalPane({ toolCalls, maxLines = 20 }) {
16
16
  }
17
17
  continue;
18
18
  }
19
- if (tc.status !== 'completed' && tc.status !== 'failed')
19
+ if (tc.status !== 'completed' && tc.status !== 'failed') {
20
20
  continue;
21
+ }
21
22
  const output = tc.result?.output ?? '';
22
23
  const isError = tc.result?.isError ?? false;
23
24
  const lines = output.split('\n').filter(l => l.length > 0);
@@ -34,8 +34,9 @@ const LONG_RUNNING_TOOLS = new Set([
34
34
  function StatusBadge({ status, startTime }) {
35
35
  const [elapsed, setElapsed] = useState(0);
36
36
  useEffect(() => {
37
- if (status !== 'running' || !startTime)
37
+ if (status !== 'running' || !startTime) {
38
38
  return;
39
+ }
39
40
  const initial = Math.floor((Date.now() - startTime) / 1000);
40
41
  setElapsed(initial);
41
42
  const id = setInterval(() => {
@@ -200,8 +201,9 @@ function DockerBuildBody({ input, result, streamingOutput, }) {
200
201
  if (result && !result.isError) {
201
202
  return (_jsx(Box, { flexDirection: "column", marginTop: 1, children: result.output.split('\n').slice(0, 20).map((line, i) => (_jsx(Text, { dimColor: true, children: line }, i))) }));
202
203
  }
203
- if (result?.isError)
204
+ if (result?.isError) {
204
205
  return _jsx(Text, { color: "red", children: result.output });
206
+ }
205
207
  return null;
206
208
  }
207
209
  // Parse step progress from streaming output or result
@@ -272,18 +274,22 @@ function ToolCallBox({ toolCall, expanded }) {
272
274
  const windowSize = isTerraformOrKubectl ? 60 : 40;
273
275
  const visibleLines = allLines.slice(-windowSize);
274
276
  // Pad to minimum 4 lines so the live area is always visible
275
- while (visibleLines.length < 4)
277
+ while (visibleLines.length < 4) {
276
278
  visibleLines.push('');
279
+ }
277
280
  const hiddenCount = Math.max(0, allLines.length - windowSize);
278
281
  return (_jsxs(_Fragment, { children: [hiddenCount > 0 && (_jsxs(Text, { dimColor: true, children: ["... ", hiddenCount, " earlier lines"] })), visibleLines.map((line, i) => {
279
282
  // M2: Color terraform/kubectl streaming output lines
280
283
  let lineColor;
281
- if (line.match(/^\s*\+/) || line.includes('will be created') || line.includes(' created'))
284
+ if (line.match(/^\s*\+/) || line.includes('will be created') || line.includes(' created')) {
282
285
  lineColor = 'green';
283
- else if (line.match(/^\s*-/) || line.includes('will be destroyed') || line.includes(' destroyed'))
286
+ }
287
+ else if (line.match(/^\s*-/) || line.includes('will be destroyed') || line.includes(' destroyed')) {
284
288
  lineColor = 'red';
285
- else if (line.match(/^\s*~/) || line.includes('will be updated') || line.includes(' modified'))
289
+ }
290
+ else if (line.match(/^\s*~/) || line.includes('will be updated') || line.includes(' modified')) {
286
291
  lineColor = 'yellow';
292
+ }
287
293
  return _jsx(Text, { color: lineColor ?? 'gray', dimColor: !lineColor, children: line }, i);
288
294
  })] }));
289
295
  })()] })), _jsx(Box, { marginTop: 1, children: renderBody() })] }));
@@ -10,8 +10,9 @@ import { Box, Text, useInput } from 'ink';
10
10
  import * as fs from 'node:fs';
11
11
  import * as path from 'node:path';
12
12
  function buildTree(dir, depth, maxDepth) {
13
- if (depth > maxDepth)
13
+ if (depth > maxDepth) {
14
14
  return [];
15
+ }
15
16
  try {
16
17
  const entries = fs.readdirSync(dir, { withFileTypes: true });
17
18
  return entries
@@ -129,10 +129,11 @@ export async function startInkChat(options = {}) {
129
129
  // NIMBUS.md live reload (M10): watch for changes to NIMBUS.md mid-session
130
130
  // M5: Also notify on DevOps file changes (debounced 30s per file)
131
131
  const devopsChangeDebounce = new Map();
132
- watcher.on('change', (changedPath) => {
133
- if (changedPath.endsWith('NIMBUS.md')) {
132
+ watcher.on('change', (event) => {
133
+ const filePath = event.path;
134
+ if (filePath.endsWith('NIMBUS.md')) {
134
135
  try {
135
- nimbusInstructions = readFileSync(changedPath, 'utf-8');
136
+ nimbusInstructions = readFileSync(filePath, 'utf-8');
136
137
  addMessage({
137
138
  id: crypto.randomUUID(),
138
139
  role: 'system',
@@ -145,15 +146,15 @@ export async function startInkChat(options = {}) {
145
146
  }
146
147
  }
147
148
  // M5: Notify on DevOps file changes (debounced 30s per file)
148
- const filePath = typeof changedPath === 'string' ? changedPath : changedPath?.path ?? '';
149
149
  const isDevOps = /\.(tf|yaml|yml)$|Dockerfile|docker-compose/i.test(filePath);
150
150
  if (isDevOps) {
151
151
  const existing = devopsChangeDebounce.get(filePath);
152
- if (existing)
152
+ if (existing) {
153
153
  clearTimeout(existing);
154
+ }
154
155
  const timer = setTimeout(() => {
155
156
  devopsChangeDebounce.delete(filePath);
156
- const relPath = filePath.replace(process.cwd() + '/', '');
157
+ const relPath = filePath.replace(`${process.cwd()}/`, '');
157
158
  const hint = relPath.endsWith('.tf') ? '/plan' : relPath.includes('yaml') ? '/plan' : '/init';
158
159
  addMessage({
159
160
  id: crypto.randomUUID(),
@@ -383,8 +384,9 @@ export async function startInkChat(options = {}) {
383
384
  * Covers terraform/kubectl/helm plus destructive bash cloud CLI commands.
384
385
  */
385
386
  function requiresDeployPreview(toolName, toolInput) {
386
- if (['terraform', 'kubectl', 'helm'].includes(toolName))
387
+ if (['terraform', 'kubectl', 'helm'].includes(toolName)) {
387
388
  return true;
389
+ }
388
390
  if (toolName === 'docker') {
389
391
  const action = String(toolInput.action ?? '');
390
392
  return ['build', 'push', 'stop', 'compose-up', 'compose-down', 'rm', 'prune'].includes(action);
@@ -447,12 +449,14 @@ export async function startInkChat(options = {}) {
447
449
  function parseToolTimeouts(nimbusMd) {
448
450
  const result = {};
449
451
  const match = nimbusMd.match(/##\s+Tool Timeouts\s*\n([\s\S]*?)(?=##|$)/);
450
- if (!match)
452
+ if (!match) {
451
453
  return result;
454
+ }
452
455
  for (const line of match[1].split('\n')) {
453
456
  const m = line.match(/^\s*([a-z_]+)\s*:\s*(\d+)\s*$/);
454
- if (m)
457
+ if (m) {
455
458
  result[m[1]] = parseInt(m[2], 10);
459
+ }
456
460
  }
457
461
  return result;
458
462
  }
@@ -476,8 +480,9 @@ export async function startInkChat(options = {}) {
476
480
  if (userMessageCount === 1 && sessionManager && sessionId) {
477
481
  try {
478
482
  const semanticName = text.slice(0, 40).replace(/[^a-z0-9]+/gi, '-').toLowerCase().replace(/^-+|-+$/g, '');
479
- if (semanticName)
483
+ if (semanticName) {
480
484
  sessionManager.rename(sessionId, semanticName);
485
+ }
481
486
  }
482
487
  catch { /* non-critical */ }
483
488
  }
@@ -839,16 +844,18 @@ export async function startInkChat(options = {}) {
839
844
  const full = spawnSync('git', ['diff'], { encoding: 'utf-8', cwd: process.cwd() });
840
845
  const statOut = stat.stdout?.trim() ?? '';
841
846
  const fullOut = full.stdout?.trim() ?? '';
842
- if (!statOut && !fullOut)
847
+ if (!statOut && !fullOut) {
843
848
  return 'No unstaged changes.';
849
+ }
844
850
  return [statOut, fullOut].filter(Boolean).join('\n\n');
845
851
  };
846
852
  /**
847
853
  * Handle /cost command — show per-turn cost breakdown.
848
854
  */
849
855
  const onCost = () => {
850
- if (turnCostLog.length === 0)
856
+ if (turnCostLog.length === 0) {
851
857
  return 'No turns yet.';
858
+ }
852
859
  const rows = turnCostLog.map(t => ` Turn ${t.turn} ${t.tokens.toLocaleString()} tokens $${t.costUSD.toFixed(4)}`);
853
860
  const total = turnCostLog.reduce((s, t) => s + t.costUSD, 0);
854
861
  const totalTok = turnCostLog.reduce((s, t) => s + t.tokens, 0);
@@ -1089,26 +1096,35 @@ export async function startInkChat(options = {}) {
1089
1096
  }
1090
1097
  // GAP-17: context-aware suggestions based on detected infrastructure
1091
1098
  const suggestions = [];
1092
- if (currentInfraContext?.terraformWorkspace)
1099
+ if (currentInfraContext?.terraformWorkspace) {
1093
1100
  suggestions.push(`"check for drift in workspace ${currentInfraContext.terraformWorkspace}"`);
1094
- if (currentInfraContext?.kubectlContext)
1101
+ }
1102
+ if (currentInfraContext?.kubectlContext) {
1095
1103
  suggestions.push(`"show all pods in ${currentInfraContext.kubectlContext}"`);
1096
- if (currentInfraContext?.awsAccount)
1104
+ }
1105
+ if (currentInfraContext?.awsAccount) {
1097
1106
  suggestions.push(`"show AWS costs for this month"`);
1098
- if ((currentInfraContext?.helmReleases?.length ?? 0) > 0)
1107
+ }
1108
+ if ((currentInfraContext?.helmReleases?.length ?? 0) > 0) {
1099
1109
  suggestions.push(`"show helm release history for ${currentInfraContext.helmReleases[0]}"`);
1110
+ }
1100
1111
  // H5: Build one-line infra hint for cold start
1101
1112
  const infraHintParts = [];
1102
- if (currentInfraContext?.terraformWorkspace)
1113
+ if (currentInfraContext?.terraformWorkspace) {
1103
1114
  infraHintParts.push(`tf:${currentInfraContext.terraformWorkspace}`);
1104
- if (currentInfraContext?.kubectlContext)
1115
+ }
1116
+ if (currentInfraContext?.kubectlContext) {
1105
1117
  infraHintParts.push(`k8s:${currentInfraContext.kubectlContext}`);
1106
- if (currentInfraContext?.awsAccount)
1118
+ }
1119
+ if (currentInfraContext?.awsAccount) {
1107
1120
  infraHintParts.push(`aws:${currentInfraContext.awsAccount}`);
1108
- if (currentInfraContext?.gcpProject)
1121
+ }
1122
+ if (currentInfraContext?.gcpProject) {
1109
1123
  infraHintParts.push(`gcp:${currentInfraContext.gcpProject}`);
1110
- if ((currentInfraContext?.helmReleases?.length ?? 0) > 0)
1124
+ }
1125
+ if ((currentInfraContext?.helmReleases?.length ?? 0) > 0) {
1111
1126
  infraHintParts.push(`${currentInfraContext.helmReleases.length} helm release${currentInfraContext.helmReleases.length > 1 ? 's' : ''}`);
1127
+ }
1112
1128
  const infraHintLine = infraHintParts.length > 0 ? `Infra detected: ${infraHintParts.join(' | ')}` : '';
1113
1129
  // G24: DevOps-specific quick-start examples
1114
1130
  // M3: When no NIMBUS.md, show concrete DevOps prompt examples to reduce blank-prompt friction
@@ -1,3 +1,3 @@
1
- export const VERSION = '0.4.1';
1
+ export const VERSION = '0.4.2';
2
2
  const _RAW_BUILD_DATE = '__BUILD_DATE__';
3
3
  export const BUILD_DATE = _RAW_BUILD_DATE.startsWith('__') ? 'dev' : _RAW_BUILD_DATE;