@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
@@ -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