@build-astron-co/nimbus 0.2.0 → 0.4.0

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 (469) hide show
  1. package/bin/nimbus +26 -10
  2. package/bin/nimbus.cmd +41 -0
  3. package/bin/nimbus.mjs +70 -0
  4. package/completions/nimbus.bash +38 -0
  5. package/completions/nimbus.fish +48 -0
  6. package/completions/nimbus.zsh +81 -0
  7. package/dist/src/agent/compaction-agent.js +215 -0
  8. package/dist/src/agent/context-manager.js +385 -0
  9. package/dist/src/agent/context.js +322 -0
  10. package/dist/src/agent/deploy-preview.js +395 -0
  11. package/dist/src/agent/expand-files.js +95 -0
  12. package/dist/src/agent/index.js +18 -0
  13. package/dist/src/agent/loop.js +1535 -0
  14. package/dist/src/agent/modes.js +347 -0
  15. package/dist/src/agent/permissions.js +396 -0
  16. package/dist/src/agent/subagents/base.js +67 -0
  17. package/dist/src/agent/subagents/cost.js +45 -0
  18. package/dist/src/agent/subagents/explore.js +36 -0
  19. package/dist/src/agent/subagents/general.js +41 -0
  20. package/dist/src/agent/subagents/index.js +88 -0
  21. package/dist/src/agent/subagents/infra.js +52 -0
  22. package/dist/src/agent/subagents/security.js +60 -0
  23. package/dist/src/agent/system-prompt.js +860 -0
  24. package/dist/src/app.js +152 -0
  25. package/dist/src/audit/activity-log.js +209 -0
  26. package/dist/src/audit/compliance-checker.js +419 -0
  27. package/dist/src/audit/cost-tracker.js +231 -0
  28. package/dist/src/audit/index.js +10 -0
  29. package/dist/src/audit/security-scanner.js +490 -0
  30. package/dist/src/auth/guard.js +64 -0
  31. package/dist/src/auth/index.js +19 -0
  32. package/dist/src/auth/keychain.js +79 -0
  33. package/dist/src/auth/oauth.js +389 -0
  34. package/dist/src/auth/providers.js +415 -0
  35. package/dist/src/auth/sso.js +87 -0
  36. package/dist/src/auth/store.js +424 -0
  37. package/dist/src/auth/types.js +5 -0
  38. package/dist/src/cli/index.js +8 -0
  39. package/dist/src/cli/init.js +1048 -0
  40. package/dist/src/cli/openapi-spec.js +346 -0
  41. package/dist/src/cli/run.js +505 -0
  42. package/dist/src/cli/serve-auth.js +56 -0
  43. package/dist/src/cli/serve.js +432 -0
  44. package/dist/src/cli/web.js +50 -0
  45. package/dist/src/cli.js +1574 -0
  46. package/dist/src/clients/core-engine-client.js +156 -0
  47. package/dist/src/clients/enterprise-client.js +246 -0
  48. package/dist/src/clients/generator-client.js +219 -0
  49. package/dist/src/clients/git-client.js +367 -0
  50. package/dist/src/clients/github-client.js +229 -0
  51. package/dist/src/clients/helm-client.js +299 -0
  52. package/dist/src/clients/index.js +18 -0
  53. package/dist/src/clients/k8s-client.js +270 -0
  54. package/dist/src/clients/llm-client.js +119 -0
  55. package/dist/src/clients/rest-client.js +104 -0
  56. package/dist/src/clients/service-discovery.js +35 -0
  57. package/dist/src/clients/terraform-client.js +302 -0
  58. package/dist/src/clients/tools-client.js +1227 -0
  59. package/dist/src/clients/ws-client.js +93 -0
  60. package/dist/src/commands/alias.js +91 -0
  61. package/dist/src/commands/analyze/index.js +313 -0
  62. package/dist/src/commands/apply/helm.js +375 -0
  63. package/dist/src/commands/apply/index.js +176 -0
  64. package/dist/src/commands/apply/k8s.js +350 -0
  65. package/dist/src/commands/apply/terraform.js +465 -0
  66. package/dist/src/commands/ask.js +137 -0
  67. package/dist/src/commands/audit/index.js +322 -0
  68. package/dist/src/commands/auth-cloud.js +345 -0
  69. package/dist/src/commands/auth-list.js +112 -0
  70. package/dist/src/commands/auth-profile.js +104 -0
  71. package/dist/src/commands/auth-refresh.js +161 -0
  72. package/dist/src/commands/auth-status.js +122 -0
  73. package/dist/src/commands/aws/ec2.js +402 -0
  74. package/dist/src/commands/aws/iam.js +304 -0
  75. package/dist/src/commands/aws/index.js +108 -0
  76. package/dist/src/commands/aws/lambda.js +317 -0
  77. package/dist/src/commands/aws/rds.js +345 -0
  78. package/dist/src/commands/aws/s3.js +346 -0
  79. package/dist/src/commands/aws/vpc.js +302 -0
  80. package/dist/src/commands/aws-discover.js +413 -0
  81. package/dist/src/commands/aws-terraform.js +618 -0
  82. package/dist/src/commands/azure/aks.js +305 -0
  83. package/dist/src/commands/azure/functions.js +200 -0
  84. package/dist/src/commands/azure/index.js +93 -0
  85. package/dist/src/commands/azure/storage.js +378 -0
  86. package/dist/src/commands/azure/vm.js +291 -0
  87. package/dist/src/commands/billing/index.js +224 -0
  88. package/dist/src/commands/chat.js +259 -0
  89. package/dist/src/commands/completions.js +255 -0
  90. package/dist/src/commands/config.js +291 -0
  91. package/dist/src/commands/cost/cloud-cost-estimator.js +211 -0
  92. package/dist/src/commands/cost/estimator.js +73 -0
  93. package/dist/src/commands/cost/index.js +625 -0
  94. package/dist/src/commands/cost/parsers/terraform.js +234 -0
  95. package/dist/src/commands/cost/parsers/types.js +4 -0
  96. package/dist/src/commands/cost/pricing/aws.js +501 -0
  97. package/dist/src/commands/cost/pricing/azure.js +462 -0
  98. package/dist/src/commands/cost/pricing/gcp.js +359 -0
  99. package/dist/src/commands/cost/pricing/index.js +24 -0
  100. package/dist/src/commands/demo.js +196 -0
  101. package/dist/src/commands/deploy.js +215 -0
  102. package/dist/src/commands/doctor.js +1291 -0
  103. package/dist/src/commands/drift/index.js +674 -0
  104. package/dist/src/commands/explain.js +235 -0
  105. package/dist/src/commands/export.js +120 -0
  106. package/dist/src/commands/feedback.js +319 -0
  107. package/dist/src/commands/fix.js +263 -0
  108. package/dist/src/commands/fs/index.js +338 -0
  109. package/dist/src/commands/gcp/compute.js +266 -0
  110. package/dist/src/commands/gcp/functions.js +221 -0
  111. package/dist/src/commands/gcp/gke.js +357 -0
  112. package/dist/src/commands/gcp/iam.js +295 -0
  113. package/dist/src/commands/gcp/index.js +105 -0
  114. package/dist/src/commands/gcp/storage.js +232 -0
  115. package/dist/src/commands/generate-helm.js +1026 -0
  116. package/dist/src/commands/generate-k8s.js +1263 -0
  117. package/dist/src/commands/generate-terraform.js +1058 -0
  118. package/dist/src/commands/gh/index.js +663 -0
  119. package/dist/src/commands/git/index.js +1208 -0
  120. package/dist/src/commands/helm/index.js +985 -0
  121. package/dist/src/commands/help.js +639 -0
  122. package/dist/src/commands/history.js +120 -0
  123. package/dist/src/commands/import.js +782 -0
  124. package/dist/src/commands/incident.js +144 -0
  125. package/dist/src/commands/index.js +109 -0
  126. package/dist/src/commands/init.js +955 -0
  127. package/dist/src/commands/k8s/index.js +979 -0
  128. package/dist/src/commands/login.js +588 -0
  129. package/dist/src/commands/logout.js +61 -0
  130. package/dist/src/commands/logs.js +160 -0
  131. package/dist/src/commands/onboarding.js +382 -0
  132. package/dist/src/commands/pipeline.js +153 -0
  133. package/dist/src/commands/plan/display.js +216 -0
  134. package/dist/src/commands/plan/index.js +525 -0
  135. package/dist/src/commands/plugin.js +325 -0
  136. package/dist/src/commands/preview.js +356 -0
  137. package/dist/src/commands/profile.js +297 -0
  138. package/dist/src/commands/questionnaire.js +1021 -0
  139. package/dist/src/commands/resume.js +35 -0
  140. package/dist/src/commands/rollback.js +259 -0
  141. package/dist/src/commands/rollout.js +74 -0
  142. package/dist/src/commands/runbook.js +307 -0
  143. package/dist/src/commands/schedule.js +202 -0
  144. package/dist/src/commands/status.js +213 -0
  145. package/dist/src/commands/team/index.js +309 -0
  146. package/dist/src/commands/team-context.js +200 -0
  147. package/dist/src/commands/template.js +204 -0
  148. package/dist/src/commands/tf/index.js +989 -0
  149. package/dist/src/commands/upgrade.js +515 -0
  150. package/dist/src/commands/usage/index.js +118 -0
  151. package/dist/src/commands/version.js +145 -0
  152. package/dist/src/commands/watch.js +127 -0
  153. package/dist/src/compat/index.js +2 -0
  154. package/dist/src/compat/runtime.js +10 -0
  155. package/dist/src/compat/sqlite.js +144 -0
  156. package/dist/src/config/index.js +6 -0
  157. package/dist/src/config/manager.js +469 -0
  158. package/dist/src/config/mode-store.js +57 -0
  159. package/dist/src/config/profiles.js +66 -0
  160. package/dist/src/config/safety-policy.js +251 -0
  161. package/dist/src/config/schema.js +107 -0
  162. package/dist/src/config/types.js +311 -0
  163. package/dist/src/config/workspace-state.js +38 -0
  164. package/dist/src/context/context-db.js +138 -0
  165. package/dist/src/demo/index.js +295 -0
  166. package/dist/src/demo/scenarios/full-journey.js +226 -0
  167. package/dist/src/demo/scenarios/getting-started.js +124 -0
  168. package/dist/src/demo/scenarios/helm-release.js +334 -0
  169. package/dist/src/demo/scenarios/k8s-deployment.js +190 -0
  170. package/dist/src/demo/scenarios/terraform-vpc.js +167 -0
  171. package/dist/src/demo/types.js +6 -0
  172. package/dist/src/engine/cost-estimator.js +334 -0
  173. package/dist/src/engine/diagram-generator.js +192 -0
  174. package/dist/src/engine/drift-detector.js +688 -0
  175. package/dist/src/engine/executor.js +832 -0
  176. package/dist/src/engine/index.js +39 -0
  177. package/dist/src/engine/orchestrator.js +436 -0
  178. package/dist/src/engine/planner.js +616 -0
  179. package/dist/src/engine/safety.js +609 -0
  180. package/dist/src/engine/verifier.js +664 -0
  181. package/dist/src/enterprise/audit.js +241 -0
  182. package/dist/src/enterprise/auth.js +189 -0
  183. package/dist/src/enterprise/billing.js +512 -0
  184. package/dist/src/enterprise/index.js +16 -0
  185. package/dist/src/enterprise/teams.js +315 -0
  186. package/dist/src/generator/best-practices.js +1375 -0
  187. package/dist/src/generator/helm.js +495 -0
  188. package/dist/src/generator/index.js +11 -0
  189. package/dist/src/generator/intent-parser.js +420 -0
  190. package/dist/src/generator/kubernetes.js +773 -0
  191. package/dist/src/generator/terraform.js +1472 -0
  192. package/dist/src/history/index.js +6 -0
  193. package/dist/src/history/manager.js +199 -0
  194. package/dist/src/history/types.js +6 -0
  195. package/dist/src/hooks/config.js +318 -0
  196. package/dist/src/hooks/engine.js +317 -0
  197. package/dist/src/hooks/index.js +2 -0
  198. package/dist/src/llm/auth-bridge.js +157 -0
  199. package/dist/src/llm/circuit-breaker.js +116 -0
  200. package/dist/src/llm/config-loader.js +172 -0
  201. package/dist/src/llm/cost-calculator.js +137 -0
  202. package/dist/src/llm/index.js +7 -0
  203. package/dist/src/llm/model-aliases.js +99 -0
  204. package/dist/src/llm/provider-registry.js +57 -0
  205. package/dist/src/llm/providers/anthropic.js +430 -0
  206. package/dist/src/llm/providers/bedrock.js +409 -0
  207. package/dist/src/llm/providers/google.js +344 -0
  208. package/dist/src/llm/providers/ollama.js +661 -0
  209. package/dist/src/llm/providers/openai-compatible.js +289 -0
  210. package/dist/src/llm/providers/openai.js +284 -0
  211. package/dist/src/llm/providers/openrouter.js +293 -0
  212. package/dist/src/llm/router.js +844 -0
  213. package/dist/src/llm/types.js +69 -0
  214. package/dist/src/lsp/client.js +239 -0
  215. package/dist/src/lsp/languages.js +95 -0
  216. package/dist/src/lsp/manager.js +243 -0
  217. package/dist/src/mcp/client.js +289 -0
  218. package/dist/src/mcp/index.js +5 -0
  219. package/dist/src/mcp/manager.js +113 -0
  220. package/dist/src/nimbus.js +212 -0
  221. package/dist/src/plugins/index.js +13 -0
  222. package/dist/src/plugins/loader.js +280 -0
  223. package/dist/src/plugins/manager.js +282 -0
  224. package/dist/src/plugins/types.js +23 -0
  225. package/dist/src/scanners/cicd-scanner.js +230 -0
  226. package/dist/src/scanners/cloud-scanner.js +415 -0
  227. package/dist/src/scanners/framework-scanner.js +430 -0
  228. package/dist/src/scanners/iac-scanner.js +350 -0
  229. package/dist/src/scanners/index.js +454 -0
  230. package/dist/src/scanners/language-scanner.js +258 -0
  231. package/dist/src/scanners/package-manager-scanner.js +252 -0
  232. package/dist/src/scanners/types.js +6 -0
  233. package/dist/src/sessions/manager.js +395 -0
  234. package/dist/src/sessions/types.js +4 -0
  235. package/dist/src/sharing/sync.js +238 -0
  236. package/dist/src/sharing/viewer.js +131 -0
  237. package/dist/src/snapshots/index.js +1 -0
  238. package/dist/src/snapshots/manager.js +432 -0
  239. package/dist/src/state/artifacts.js +94 -0
  240. package/dist/src/state/audit.js +73 -0
  241. package/dist/src/state/billing.js +126 -0
  242. package/dist/src/state/checkpoints.js +81 -0
  243. package/dist/src/state/config.js +58 -0
  244. package/dist/src/state/conversations.js +7 -0
  245. package/dist/src/state/credentials.js +96 -0
  246. package/dist/src/state/db.js +53 -0
  247. package/dist/src/state/index.js +23 -0
  248. package/dist/src/state/messages.js +76 -0
  249. package/dist/src/state/projects.js +92 -0
  250. package/dist/src/state/schema.js +233 -0
  251. package/dist/src/state/sessions.js +79 -0
  252. package/dist/src/state/teams.js +131 -0
  253. package/dist/src/telemetry.js +91 -0
  254. package/dist/src/tools/aws-ops.js +747 -0
  255. package/dist/src/tools/azure-ops.js +491 -0
  256. package/dist/src/tools/file-ops.js +451 -0
  257. package/dist/src/tools/gcp-ops.js +559 -0
  258. package/dist/src/tools/git-ops.js +557 -0
  259. package/dist/src/tools/github-ops.js +460 -0
  260. package/dist/src/tools/helm-ops.js +634 -0
  261. package/dist/src/tools/index.js +16 -0
  262. package/dist/src/tools/k8s-ops.js +579 -0
  263. package/dist/src/tools/schemas/converter.js +129 -0
  264. package/dist/src/tools/schemas/devops.js +3319 -0
  265. package/dist/src/tools/schemas/index.js +19 -0
  266. package/dist/src/tools/schemas/standard.js +966 -0
  267. package/dist/src/tools/schemas/types.js +409 -0
  268. package/dist/src/tools/spawn-exec.js +109 -0
  269. package/dist/src/tools/terraform-ops.js +627 -0
  270. package/dist/src/types/config.js +1 -0
  271. package/dist/src/types/drift.js +4 -0
  272. package/dist/src/types/enterprise.js +5 -0
  273. package/dist/src/types/index.js +14 -0
  274. package/dist/src/types/plan.js +1 -0
  275. package/dist/src/types/request.js +1 -0
  276. package/dist/src/types/response.js +1 -0
  277. package/dist/src/types/service.js +1 -0
  278. package/dist/src/ui/App.js +1672 -0
  279. package/dist/src/ui/DeployPreview.js +60 -0
  280. package/dist/src/ui/FileDiffModal.js +108 -0
  281. package/dist/src/ui/Header.js +46 -0
  282. package/dist/src/ui/HelpModal.js +9 -0
  283. package/dist/src/ui/InputBox.js +408 -0
  284. package/dist/src/ui/MessageList.js +795 -0
  285. package/dist/src/ui/PermissionPrompt.js +72 -0
  286. package/dist/src/ui/StatusBar.js +109 -0
  287. package/dist/src/ui/TerminalPane.js +31 -0
  288. package/dist/src/ui/ToolCallDisplay.js +303 -0
  289. package/dist/src/ui/TreePane.js +83 -0
  290. package/dist/src/ui/chat-ui.js +721 -0
  291. package/dist/src/ui/index.js +11 -0
  292. package/dist/src/ui/ink/index.js +1325 -0
  293. package/dist/src/ui/streaming.js +137 -0
  294. package/dist/src/ui/theme.js +78 -0
  295. package/dist/src/ui/types.js +7 -0
  296. package/dist/src/utils/analytics.js +61 -0
  297. package/dist/src/utils/cost-warning.js +25 -0
  298. package/dist/src/utils/env.js +42 -0
  299. package/dist/src/utils/errors.js +54 -0
  300. package/dist/src/utils/event-bus.js +22 -0
  301. package/dist/src/utils/index.js +16 -0
  302. package/dist/src/utils/logger.js +150 -0
  303. package/dist/src/utils/rate-limiter.js +90 -0
  304. package/dist/src/utils/service-auth.js +36 -0
  305. package/dist/src/utils/validation.js +39 -0
  306. package/dist/src/version.js +3 -0
  307. package/dist/src/watcher/index.js +192 -0
  308. package/dist/src/wizard/approval.js +275 -0
  309. package/dist/src/wizard/index.js +13 -0
  310. package/dist/src/wizard/prompts.js +273 -0
  311. package/dist/src/wizard/types.js +4 -0
  312. package/dist/src/wizard/ui.js +453 -0
  313. package/dist/src/wizard/wizard.js +227 -0
  314. package/package.json +31 -23
  315. package/src/__tests__/alias.test.ts +133 -0
  316. package/src/__tests__/app.test.ts +1 -1
  317. package/src/__tests__/audit.test.ts +1 -1
  318. package/src/__tests__/circuit-breaker.test.ts +1 -1
  319. package/src/__tests__/cli-run.test.ts +237 -1
  320. package/src/__tests__/compat-sqlite.test.ts +68 -0
  321. package/src/__tests__/context-manager.test.ts +131 -1
  322. package/src/__tests__/context.test.ts +1 -1
  323. package/src/__tests__/devops-terminal-gaps.test.ts +718 -0
  324. package/src/__tests__/doctor.test.ts +48 -0
  325. package/src/__tests__/enterprise.test.ts +1 -1
  326. package/src/__tests__/export.test.ts +236 -0
  327. package/src/__tests__/gap-11-18-20.test.ts +958 -0
  328. package/src/__tests__/generator.test.ts +1 -1
  329. package/src/__tests__/helm-streaming.test.ts +127 -0
  330. package/src/__tests__/hooks.test.ts +1 -1
  331. package/src/__tests__/incident.test.ts +179 -0
  332. package/src/__tests__/init.test.ts +55 -4
  333. package/src/__tests__/intent-parser.test.ts +1 -1
  334. package/src/__tests__/llm-router.test.ts +1 -1
  335. package/src/__tests__/logs.test.ts +107 -0
  336. package/src/__tests__/loop-errors.test.ts +244 -0
  337. package/src/__tests__/lsp.test.ts +1 -1
  338. package/src/__tests__/modes.test.ts +1 -1
  339. package/src/__tests__/perf-optimizations.test.ts +847 -0
  340. package/src/__tests__/permissions.test.ts +1 -1
  341. package/src/__tests__/pipeline.test.ts +50 -0
  342. package/src/__tests__/polish-phase3.test.ts +340 -0
  343. package/src/__tests__/profile.test.ts +237 -0
  344. package/src/__tests__/rollback.test.ts +83 -0
  345. package/src/__tests__/runbook.test.ts +219 -0
  346. package/src/__tests__/schedule.test.ts +206 -0
  347. package/src/__tests__/serve.test.ts +1 -1
  348. package/src/__tests__/sessions.test.ts +96 -1
  349. package/src/__tests__/sharing.test.ts +53 -1
  350. package/src/__tests__/snapshots.test.ts +1 -1
  351. package/src/__tests__/standalone-migration.test.ts +199 -0
  352. package/src/__tests__/state-db.test.ts +1 -1
  353. package/src/__tests__/status.test.ts +158 -0
  354. package/src/__tests__/stream-with-tools.test.ts +71 -25
  355. package/src/__tests__/subagents.test.ts +1 -1
  356. package/src/__tests__/system-prompt.test.ts +82 -3
  357. package/src/__tests__/terminal-gap-v2.test.ts +395 -0
  358. package/src/__tests__/terminal-parity.test.ts +393 -0
  359. package/src/__tests__/tf-apply.test.ts +187 -0
  360. package/src/__tests__/tool-converter.test.ts +1 -1
  361. package/src/__tests__/tool-schemas.test.ts +209 -4
  362. package/src/__tests__/tools.test.ts +4 -3
  363. package/src/__tests__/version-json.test.ts +184 -0
  364. package/src/__tests__/version.test.ts +1 -1
  365. package/src/__tests__/watch.test.ts +129 -0
  366. package/src/agent/compaction-agent.ts +40 -1
  367. package/src/agent/context-manager.ts +67 -3
  368. package/src/agent/deploy-preview.ts +62 -1
  369. package/src/agent/expand-files.ts +108 -0
  370. package/src/agent/loop.ts +1312 -31
  371. package/src/agent/permissions.ts +51 -4
  372. package/src/agent/system-prompt.ts +573 -19
  373. package/src/app.ts +58 -0
  374. package/src/audit/security-scanner.ts +45 -0
  375. package/src/auth/keychain.ts +82 -0
  376. package/src/auth/oauth.ts +15 -5
  377. package/src/cli/init.ts +378 -5
  378. package/src/cli/run.ts +407 -16
  379. package/src/cli/serve.ts +78 -1
  380. package/src/cli/web.ts +10 -6
  381. package/src/cli.ts +312 -1
  382. package/src/clients/service-discovery.ts +30 -25
  383. package/src/commands/alias.ts +100 -0
  384. package/src/commands/audit/index.ts +121 -2
  385. package/src/commands/auth-cloud.ts +113 -0
  386. package/src/commands/auth-refresh.ts +187 -0
  387. package/src/commands/aws-discover.ts +144 -251
  388. package/src/commands/aws-terraform.ts +68 -118
  389. package/src/commands/chat.ts +9 -3
  390. package/src/commands/completions.ts +268 -0
  391. package/src/commands/config.ts +26 -0
  392. package/src/commands/cost/index.ts +218 -2
  393. package/src/commands/deploy.ts +260 -0
  394. package/src/commands/doctor.ts +744 -152
  395. package/src/commands/drift/index.ts +371 -23
  396. package/src/commands/export.ts +146 -0
  397. package/src/commands/generate-k8s.ts +9 -61
  398. package/src/commands/generate-terraform.ts +191 -449
  399. package/src/commands/help.ts +212 -36
  400. package/src/commands/history.ts +8 -1
  401. package/src/commands/incident.ts +166 -0
  402. package/src/commands/init.ts +5 -0
  403. package/src/commands/login.ts +86 -1
  404. package/src/commands/logs.ts +167 -0
  405. package/src/commands/onboarding.ts +211 -34
  406. package/src/commands/pipeline.ts +186 -0
  407. package/src/commands/plugin.ts +398 -0
  408. package/src/commands/profile.ts +342 -0
  409. package/src/commands/questionnaire.ts +0 -98
  410. package/src/commands/resume.ts +26 -34
  411. package/src/commands/rollback.ts +315 -0
  412. package/src/commands/rollout.ts +88 -0
  413. package/src/commands/runbook.ts +346 -0
  414. package/src/commands/schedule.ts +236 -0
  415. package/src/commands/status.ts +252 -0
  416. package/src/commands/team-context.ts +220 -0
  417. package/src/commands/template.ts +58 -57
  418. package/src/commands/tf/index.ts +70 -11
  419. package/src/commands/upgrade.ts +57 -0
  420. package/src/commands/version.ts +54 -50
  421. package/src/commands/watch.ts +153 -0
  422. package/src/compat/runtime.ts +1 -1
  423. package/src/compat/sqlite.ts +75 -5
  424. package/src/config/mode-store.ts +62 -0
  425. package/src/config/profiles.ts +84 -0
  426. package/src/config/types.ts +83 -1
  427. package/src/config/workspace-state.ts +53 -0
  428. package/src/engine/cost-estimator.ts +52 -10
  429. package/src/engine/executor.ts +33 -2
  430. package/src/engine/planner.ts +68 -1
  431. package/src/generator/terraform.ts +8 -0
  432. package/src/history/manager.ts +2 -74
  433. package/src/hooks/engine.ts +5 -4
  434. package/src/llm/cost-calculator.ts +2 -2
  435. package/src/llm/providers/anthropic.ts +50 -21
  436. package/src/llm/router.ts +76 -7
  437. package/src/lsp/languages.ts +3 -0
  438. package/src/lsp/manager.ts +21 -5
  439. package/src/nimbus.ts +37 -18
  440. package/src/sessions/manager.ts +108 -1
  441. package/src/sharing/sync.ts +4 -0
  442. package/src/sharing/viewer.ts +66 -0
  443. package/src/tools/file-ops.ts +22 -0
  444. package/src/tools/schemas/devops.ts +3007 -117
  445. package/src/tools/schemas/standard.ts +5 -1
  446. package/src/tools/schemas/types.ts +31 -1
  447. package/src/tools/spawn-exec.ts +148 -0
  448. package/src/ui/App.tsx +1183 -66
  449. package/src/ui/DeployPreview.tsx +62 -57
  450. package/src/ui/FileDiffModal.tsx +162 -0
  451. package/src/ui/Header.tsx +87 -24
  452. package/src/ui/HelpModal.tsx +57 -0
  453. package/src/ui/InputBox.tsx +163 -10
  454. package/src/ui/MessageList.tsx +487 -40
  455. package/src/ui/PermissionPrompt.tsx +17 -5
  456. package/src/ui/StatusBar.tsx +122 -3
  457. package/src/ui/TerminalPane.tsx +84 -0
  458. package/src/ui/ToolCallDisplay.tsx +252 -18
  459. package/src/ui/TreePane.tsx +132 -0
  460. package/src/ui/chat-ui.ts +41 -44
  461. package/src/ui/ink/index.ts +771 -38
  462. package/src/ui/streaming.ts +1 -1
  463. package/src/ui/theme.ts +104 -0
  464. package/src/ui/types.ts +18 -0
  465. package/src/version.ts +1 -1
  466. package/src/watcher/index.ts +66 -15
  467. package/src/wizard/types.ts +1 -0
  468. package/src/wizard/ui.ts +1 -1
  469. package/tsconfig.json +2 -2
@@ -0,0 +1,860 @@
1
+ /**
2
+ * System Prompt Builder for the Nimbus Agentic Loop
3
+ *
4
+ * Generates the complete system prompt that is injected as the first message
5
+ * in every LLM conversation. The prompt tells the model who it is, what mode
6
+ * it is operating in, which tools are available, and how to behave.
7
+ *
8
+ * The prompt is assembled from several composable sections:
9
+ *
10
+ * 1. **Base identity** -- who Nimbus is and its core behavioral rules.
11
+ * 2. **Mode instructions** -- what the current {@link AgentMode} allows.
12
+ * 3. **Tool-use guidelines** -- general best practices for tool invocation.
13
+ * 4. **Available tools** -- a summarized list built from {@link ToolDefinition}s.
14
+ * 5. **NIMBUS.md** -- optional per-project or per-user custom instructions.
15
+ * 6. **Subagent instructions** -- constraints when running as a spawned subagent.
16
+ * 7. **Environment context** -- working directory, platform, date, git status.
17
+ *
18
+ * @module agent/system-prompt
19
+ */
20
+ import * as fs from 'node:fs';
21
+ import * as path from 'node:path';
22
+ import { homedir } from 'node:os';
23
+ import { execSync } from 'node:child_process';
24
+ /**
25
+ * Ordered list of all agent modes from least permissive to most permissive.
26
+ * Useful for comparison and escalation logic.
27
+ */
28
+ export const AGENT_MODES = ['plan', 'build', 'deploy'];
29
+ // ---------------------------------------------------------------------------
30
+ // Public API
31
+ // ---------------------------------------------------------------------------
32
+ /**
33
+ * Build the complete system prompt for the agentic loop.
34
+ *
35
+ * The returned string is intended to be used as the `system` message (or
36
+ * first `user`/`system` message, depending on the LLM provider) in a
37
+ * conversation with the model.
38
+ *
39
+ * @param options - Configuration that controls prompt assembly.
40
+ * @returns The fully assembled system prompt string.
41
+ *
42
+ * @example
43
+ * ```ts
44
+ * import { buildSystemPrompt } from './system-prompt';
45
+ *
46
+ * const prompt = buildSystemPrompt({
47
+ * mode: 'build',
48
+ * tools: registry.getAll(),
49
+ * cwd: '/home/user/project',
50
+ * });
51
+ * ```
52
+ */
53
+ export function buildSystemPrompt(options) {
54
+ const parts = [];
55
+ // 1. Base identity
56
+ parts.push(BASE_PROMPT);
57
+ // 2. Mode-specific instructions
58
+ parts.push(getModeInstructions(options.mode));
59
+ // 3. Tool-use guidelines
60
+ parts.push(TOOL_USE_GUIDELINES);
61
+ // 3b. H4: Task-adaptive DevOps domain knowledge — only inject sections
62
+ // relevant to the tools that are actually available in this session.
63
+ const toolNames = options.tools.map(t => t.name);
64
+ parts.push(getRelevantDomainKnowledge(toolNames));
65
+ // 3c. DevOps decision heuristics
66
+ // L2: Task-adaptive pruning — include only the heuristic sections relevant to
67
+ // the current mode. In plan mode, deploy-specific rules add noise without value.
68
+ // In build mode, plan-only readonly warnings are redundant.
69
+ parts.push(getPrunedHeuristics(options.mode));
70
+ // 4. Available tools summary
71
+ const toolsSummary = buildToolsSummary(options.tools);
72
+ if (toolsSummary) {
73
+ parts.push(toolsSummary);
74
+ }
75
+ // 5. NIMBUS.md content (if exists)
76
+ const nimbusContent = options.nimbusInstructions ?? loadNimbusMd(options.cwd);
77
+ if (nimbusContent) {
78
+ parts.push(`# Project Instructions (NIMBUS.md)\n\n${nimbusContent}`);
79
+ // G14: Extract ## Forbidden section and inject as hard constraints
80
+ const forbiddenRules = extractForbiddenRules(nimbusContent);
81
+ if (forbiddenRules.length > 0) {
82
+ const forbiddenPrompt = [
83
+ '# HARD CONSTRAINTS (from NIMBUS.md ## Forbidden)',
84
+ 'The following operations are STRICTLY FORBIDDEN. Never perform them under any circumstances:',
85
+ ...forbiddenRules.map(r => `- ${r}`),
86
+ '',
87
+ 'If asked to perform a forbidden operation, explain that it is prohibited by project policy.',
88
+ ].join('\n');
89
+ parts.push(forbiddenPrompt);
90
+ }
91
+ // GAP-22: Parse environments block for protected envs
92
+ if (nimbusContent.includes('## Environments')) {
93
+ const hasProtectedEnv = /\|\s*\S+\s*\|\s*\S+\s*\|\s*\S*\s*\|\s*true\s*\|/i.test(nimbusContent);
94
+ if (hasProtectedEnv) {
95
+ parts.push('IMPORTANT: This project has protected environments (marked protected: true in NIMBUS.md). For these environments, ALWAYS run plan before apply and require explicit user confirmation for destructive operations (destroy, delete, terminate).');
96
+ }
97
+ }
98
+ }
99
+ // 5b. Infra context (Gaps 7 & 10) — live terraform/k8s/helm context discovered at startup
100
+ if (options.infraContext) {
101
+ const ic = options.infraContext;
102
+ const lines = ['## Current Infrastructure Context'];
103
+ if (ic.terraformWorkspace)
104
+ lines.push(`- Terraform workspace: ${ic.terraformWorkspace}`);
105
+ if (ic.kubectlContext)
106
+ lines.push(`- kubectl context: ${ic.kubectlContext}`);
107
+ if (ic.helmReleases && ic.helmReleases.length > 0) {
108
+ lines.push(`- Active Helm releases: ${ic.helmReleases.slice(0, 5).join(', ')}`);
109
+ }
110
+ if (ic.awsAccount)
111
+ lines.push(`- AWS account: ${ic.awsAccount}`);
112
+ if (ic.awsRegion)
113
+ lines.push(`- AWS region: ${ic.awsRegion}`);
114
+ if (ic.gcpProject)
115
+ lines.push(`- GCP project: ${ic.gcpProject}`);
116
+ parts.push(lines.join('\n'));
117
+ // H3: Inject known resource inventory for better tool call accuracy.
118
+ // Lists exact names for contexts, releases, workspaces, and cloud accounts
119
+ // so the agent uses them verbatim instead of guessing.
120
+ const resourceInventory = [];
121
+ if (ic.kubectlContext) {
122
+ resourceInventory.push(`kubectl context: ${ic.kubectlContext}`);
123
+ }
124
+ if (ic.helmReleases && ic.helmReleases.length > 0) {
125
+ resourceInventory.push(`Helm releases: ${ic.helmReleases.join(', ')}`);
126
+ }
127
+ if (ic.terraformWorkspace) {
128
+ resourceInventory.push(`Terraform workspace: ${ic.terraformWorkspace}`);
129
+ }
130
+ if (ic.awsAccount) {
131
+ resourceInventory.push(`AWS account: ${ic.awsAccount} (${ic.awsRegion ?? 'unknown region'})`);
132
+ }
133
+ // C6: Inject awsRegion standalone so LLM passes correct region to tool calls
134
+ if (ic.awsRegion) {
135
+ resourceInventory.push(`AWS default region: ${ic.awsRegion} (pass region param to target others)`);
136
+ }
137
+ if (ic.gcpProject) {
138
+ resourceInventory.push(`GCP project: ${ic.gcpProject}`);
139
+ }
140
+ if (resourceInventory.length > 0) {
141
+ parts.push(`## Known Infrastructure Resources\nUse these exact names when calling tools:\n${resourceInventory.map(r => `- ${r}`).join('\n')}`);
142
+ }
143
+ }
144
+ // 6. Subagent instructions (if applicable)
145
+ if (options.activeSubagent) {
146
+ parts.push(getSubagentInstructions(options.activeSubagent));
147
+ }
148
+ // 7. Environment context
149
+ parts.push(buildEnvironmentContext(options.cwd));
150
+ // C5: Primary cloud providers section (from ~/.nimbus/config.json)
151
+ const primaryCloudsSection = buildPrimaryCloudSection();
152
+ if (primaryCloudsSection) {
153
+ parts.push(primaryCloudsSection);
154
+ }
155
+ // M1: Dry-run mode — append hard constraint at the end so it takes priority
156
+ if (options.dryRun) {
157
+ parts.push('# DRY-RUN MODE — ACTIVE\n\n' +
158
+ 'DRY-RUN MODE: Do not execute any mutating operations. ' +
159
+ 'List exactly what you would do step by step.\n\n' +
160
+ 'You MUST NOT:\n' +
161
+ '- Apply, create, update, or delete any infrastructure\n' +
162
+ '- Run terraform apply, kubectl apply, helm install/upgrade/uninstall\n' +
163
+ '- Write or modify files\n' +
164
+ '- Execute any destructive bash commands\n\n' +
165
+ 'Instead, describe precisely what each step would do and why.');
166
+ }
167
+ return parts.join('\n\n---\n\n');
168
+ }
169
+ // ---------------------------------------------------------------------------
170
+ // Prompt Fragments
171
+ // ---------------------------------------------------------------------------
172
+ /**
173
+ * Core identity and behavioral rules that apply regardless of mode.
174
+ * @internal
175
+ */
176
+ const BASE_PROMPT = `You are Nimbus, an autonomous DevOps operator. Your job is to keep
177
+ infrastructure healthy, deployments flowing, and production stable — through direct action.
178
+
179
+ Your PRIMARY instinct is to RUN commands and query live state first:
180
+ - When something is broken: run \`kubectl describe\`, \`terraform plan\`, \`aws logs\` BEFORE reading files
181
+ - When asked about infrastructure state: query it (\`kubectl get pods -A\`, \`terraform state list\`)
182
+ - When asked to deploy: validate → plan → show plan → confirm → apply
183
+ - Edit IaC files only as a follow-up once diagnostics reveal what must change
184
+
185
+ Your domain is DevOps: Terraform, Kubernetes, Helm, AWS, GCP, Azure, CI/CD, Docker, secrets management.
186
+
187
+ Key operational rules:
188
+ - Run diagnostics and infrastructure commands FIRST — do not start by reading files
189
+ - Always show a plan/preview and get confirmation before destructive operations
190
+ - Always run validation (terraform validate, kubectl --dry-run) before apply
191
+ - Be namespace-aware for Kubernetes; always pass \`-n <namespace>\` explicitly
192
+ - Explain what you are doing and why at each step
193
+ - If a tool call fails, classify the error and try a corrective approach before giving up
194
+ - Make precise, targeted edits to IaC files — never rewrite entire configurations
195
+
196
+ You are specialized exclusively for DevOps, infrastructure, and cloud operations. If asked to help with tasks unrelated to DevOps (e.g., building a UI, writing business logic, general algorithms unrelated to infrastructure), respond: "I'm specialized for DevOps and infrastructure. For general software development, try a general-purpose coding agent. Is there an infrastructure or deployment aspect I can help with?"`;
197
+ /**
198
+ * General best-practice guidelines for tool invocation that are included in
199
+ * every prompt regardless of mode.
200
+ * @internal
201
+ */
202
+ const TOOL_USE_GUIDELINES = `# Tool-Use Guidelines
203
+
204
+ - Use the most specific tool available. Prefer \`read_file\` over \`bash cat\`, \`glob\` over \`bash find\`, \`grep\` over \`bash grep\`.
205
+ - For file edits, use \`edit_file\` for single replacements and \`multi_edit\` for multiple replacements in the same file.
206
+ - Use \`write_file\` only for creating new files or complete rewrites.
207
+ - When running bash commands, prefer specific commands over broad ones. Avoid \`rm -rf\` or other destructive patterns.
208
+ - For infrastructure operations, always run validation (terraform validate, kubectl --dry-run) before apply.
209
+ - Use \`deploy_preview\` before any destructive infrastructure change.
210
+ - Use the \`task\` tool to spawn subagents for parallel or specialized work.
211
+ - When using \`terraform\`, always run \`terraform init\` before \`plan\` or \`apply\` if not already initialized.
212
+ - For Kubernetes operations, be namespace-aware. Default to the current namespace context.
213
+ - Never read or search inside generated/dependency directories: \`node_modules/\`, \`dist/\`, \`build/\`, \`__pycache__/\`, \`.terraform/\`, \`.git/\`, \`coverage/\`, \`.next/\`, \`vendor/\`. These are never relevant to editing source code and will waste context window.
214
+ - Respect \`.gitignore\` patterns — do not read files that would be gitignored unless the user explicitly asks for them.`;
215
+ // ---------------------------------------------------------------------------
216
+ // H4: Task-Adaptive DevOps Domain Knowledge
217
+ //
218
+ // The domain knowledge is split into named sections. buildSystemPrompt uses
219
+ // getRelevantDomainKnowledge() to include only the sections that are relevant
220
+ // to the tools available in the current session, keeping the prompt concise.
221
+ // ---------------------------------------------------------------------------
222
+ /**
223
+ * Per-domain knowledge sections keyed by domain name.
224
+ * @internal
225
+ */
226
+ const DOMAIN_SECTIONS = {
227
+ general: `## General DevOps Principles
228
+ - Infrastructure drift: plan outputs starting with \`~\` = modify, \`-\` = destroy, \`+\` = create
229
+ - Zero-downtime deploys: rolling updates, blue/green, canary with traffic splitting
230
+ - Secret management: never hardcode secrets; use SSM Parameter Store, Secrets Manager, Vault, or sealed-secrets
231
+ - Observability: logs → \`kubectl logs\`, metrics → \`kubectl top\`, traces → service mesh
232
+ - Cost optimization: right-size instances, use spot/preemptible for stateless workloads
233
+
234
+ ## Docker Best Practices
235
+ - Always use multi-stage builds to minimize image size; pin base image tags (avoid \`latest\`)
236
+ - Build: \`docker build -t myapp:v1.0 -f Dockerfile .\`
237
+ - Compose: \`docker compose up -d\` starts detached; \`docker compose down\` removes containers
238
+ - Check daemon: \`docker info\`; if not running → \`colima start\` (macOS) or \`sudo systemctl start docker\`
239
+ - Common errors:
240
+ - \`cannot connect to the Docker daemon\` → start Docker Desktop or run \`colima start\`
241
+ - \`manifest not found\` → verify image name/tag; check registry login (\`docker login\`)
242
+ - \`no space left on device\` → run \`docker system prune -f\` to reclaim space
243
+ - \`permission denied\` on socket → add user to docker group or use \`sudo\`
244
+
245
+ ## Incident Management (PagerDuty & Opsgenie)
246
+ - PagerDuty: requires \`PD_API_KEY\` env var; list incidents with action=incidents, acknowledge with action=ack, resolve with action=resolve
247
+ - Opsgenie: requires \`OPSGENIE_API_KEY\` env var; list alerts with action=alerts, acknowledge with action=ack, close with action=resolve
248
+ - On-call schedule: use action=on-call with provider=pagerduty or provider=opsgenie to see who is currently on call
249
+ - Incident response workflow: acknowledge first (stops escalation) → investigate → resolve
250
+ - Common errors:
251
+ - \`401 Unauthorized\` → verify API key is correct and not expired
252
+ - \`403 Forbidden\` → check API key permissions (needs read+write for ack/resolve)
253
+ - \`404 Not Found\` → verify incident/alert ID is correct (use list first)
254
+
255
+ ## Web Search for DevOps
256
+ - Use \`web_search\` to look up error codes, provider limits, API endpoints, pricing
257
+ - Set \`BRAVE_API_KEY\` env var for higher-quality search results via Brave Search API`,
258
+ terraform: `## Terraform Best Practices
259
+ - Always run \`terraform validate\` → \`terraform plan\` → \`terraform apply\` in sequence
260
+ - Use \`terraform plan -out=tfplan\` to save plan files; apply with \`terraform apply tfplan\`
261
+ - For state inspection: \`terraform state list\`, \`terraform state show <resource>\`
262
+ - Remote state: prefer S3+DynamoDB (AWS), GCS (GCP), Azure Blob. Never commit \`.tfstate\` files
263
+ - Workspaces: \`terraform workspace new <env>\`, \`terraform workspace select <env>\`
264
+ - Module structure: \`main.tf\`, \`variables.tf\`, \`outputs.tf\`, \`versions.tf\`
265
+ - Lock files (\`.terraform.lock.hcl\`) MUST be committed to version control
266
+ - Use \`count\` or \`for_each\` for resource iteration; avoid \`count\` for ordered resources
267
+ - \`depends_on\` is a last resort — prefer implicit dependencies via references
268
+
269
+ ## Error Diagnosis — Terraform
270
+ - \`Error: The provider "hashicorp/aws" requires Terraform >= X\` → run \`terraform init -upgrade\`
271
+ - \`Error: configuring Terraform AWS Provider: no valid credentials\` → check AWS credentials, run \`aws configure\`
272
+ - \`Error: creating EC2 Instance: VcpuLimitExceeded\` → request quota increase in AWS Console`,
273
+ kubernetes: `## Kubernetes Operations
274
+ - Check cluster health first: \`kubectl get nodes\`, \`kubectl get pods -A\`
275
+ - Namespace-aware commands: always pass \`-n <namespace>\` or use \`--all-namespaces\`
276
+ - Deployment rollouts: \`kubectl rollout status deploy/<name>\`, \`kubectl rollout history deploy/<name>\`
277
+ - Rollback: \`kubectl rollout undo deploy/<name>\`, or \`kubectl rollout undo deploy/<name> --to-revision=N\`
278
+ - Resource sizing: check \`kubectl top pods\`, \`kubectl top nodes\` before scaling
279
+ - Debug pods: \`kubectl exec -it <pod> -- /bin/sh\`, \`kubectl logs <pod> --previous\` for crashloops
280
+ - Dry-run before apply: \`kubectl apply --dry-run=client -f manifest.yaml\`
281
+ - Labels and selectors: always verify selectors match pod templates in Deployments
282
+
283
+ ## Error Diagnosis — Kubernetes
284
+ - \`OOMKilled\` → increase memory limit in pod spec; check \`kubectl describe pod\`
285
+ - \`CrashLoopBackOff\` → \`kubectl logs <pod> --previous\`; check readiness/liveness probes
286
+ - \`ImagePullBackOff\` → verify image name/tag, check registry credentials (imagePullSecret)
287
+ - \`Pending\` pods → \`kubectl describe pod\` for events; common: insufficient resources, no matching node`,
288
+ helm: `## Helm Operations
289
+ - Repo management: \`helm repo add <name> <url>\`, \`helm repo update\` before install/upgrade
290
+ - Template debugging: \`helm template <release> <chart> -f values.yaml\` before install
291
+ - Diff before upgrade: \`helm diff upgrade <release> <chart>\` (requires helm-diff plugin)
292
+ - Override values: \`-f values.yaml\` for files, \`--set key=value\` for single values
293
+ - Release history: \`helm history <release> -n <namespace>\`
294
+ - Rollback: \`helm rollback <release> <revision> -n <namespace>\`
295
+
296
+ ## Helm Secrets (SOPS) Best Practices
297
+ - Install: \`helm plugin install https://github.com/jkroepke/helm-secrets\`
298
+ - Encrypt: \`helm secrets enc values.yaml\` (requires SOPS config \`.sops.yaml\`)
299
+ - Decrypt: \`helm secrets dec values.yaml.enc\`
300
+ - View without decrypt: \`helm secrets view values.yaml.enc\`
301
+ - Install with secrets: \`helm secrets install release chart -f values.yaml.enc\`
302
+ - Common errors:
303
+ - \`plugin not found\` → run \`helm plugin list | grep secrets\` to verify install
304
+ - \`sops: not found\` → install sops: \`brew install sops\``,
305
+ aws: `## AWS Patterns
306
+ - IAM: prefer roles over long-lived credentials; use instance profiles, IRSA, workload identity
307
+ - Networking: VPC → subnets → security groups → route tables; know public vs private subnets
308
+ - EKS: use IRSA for pod-level AWS API access; node groups vs Fargate tradeoffs
309
+ - S3 versioning + lifecycle policies for state files; enable MFA delete for sensitive buckets
310
+ - Common debug: \`aws sts get-caller-identity\`, \`aws configure list\`, \`aws --debug <cmd>\``,
311
+ secrets: `## Secrets Management Best Practices
312
+ - Never log or display raw secret values — always redact in output
313
+ - Rotation patterns: automate rotation with Lambda (AWS) or Cloud Functions (GCP)
314
+ - Kubernetes secrets: prefer external-secrets-operator or Vault Agent Injector over native k8s secrets
315
+ - SOPS (Secrets OPerationS): encrypt secrets files committed to Git using \`sops --encrypt file.yaml\`
316
+ - External Secrets Operator: syncs secrets from Vault/AWS/GCP into k8s Secrets automatically
317
+ - Vault: use \`vault kv get -format=json <path>\` and never expose SecretString in logs
318
+ - Common errors:
319
+ - \`permission denied\` on Vault → check policy: \`vault policy read <policy-name>\`
320
+ - \`secret not found\` → verify path and namespace: \`vault kv list <mount>\``,
321
+ cicd: `## CI/CD Pipeline Best Practices
322
+ - GitHub Actions: workflow files live in \`.github/workflows/\`; use \`gh workflow run\` to trigger
323
+ - GitLab CI: \`.gitlab-ci.yml\` at repo root; \`glab ci run\` triggers pipelines
324
+ - CircleCI: \`.circleci/config.yml\`; use project slugs (gh/org/repo)
325
+ - Always check branch protection rules before triggering on main/production
326
+ - Common errors:
327
+ - \`workflow not found\` → check filename in \`.github/workflows/\` and branch name
328
+ - \`rate limited\` → wait 60s and retry; check API rate limit headers
329
+ - \`token expired\` → refresh token or check service account permissions`,
330
+ monitoring: `## Monitoring & Observability Best Practices
331
+ - Prometheus: use \`rate()\` for counters, \`histogram_quantile()\` for latencies; query via HTTP API
332
+ - CloudWatch: structured queries with CloudWatch Insights for efficient log searching
333
+ - Grafana: use \`$GRAFANA_URL\` env var + Bearer token for API access
334
+ - Datadog: requires both \`DD_API_KEY\` and \`DD_APP_KEY\` for query API
335
+ - Alert on: error rate, latency p99, saturation (CPU/memory), traffic (requests/sec)
336
+ - SLO pattern: \`1 - (error_rate / total_rate)\` over 30-day rolling window`,
337
+ gitops: `## GitOps Best Practices (ArgoCD & Flux)
338
+ - ArgoCD: \`argocd app sync\` triggers reconciliation; \`argocd app diff\` shows pending changes
339
+ - Flux: \`flux reconcile kustomization flux-system\` forces immediate reconciliation
340
+ - Always check health before sync: \`argocd app get <app>\` shows health.status
341
+ - Rollback strategy: ArgoCD → \`argocd app rollback <app> <revision>\`; Flux → revert Git commit
342
+ - Common errors:
343
+ - \`app not found\` → check \`ARGOCD_SERVER\` env var and login token
344
+ - \`ComparisonError\` → validate manifests with \`kubectl apply --dry-run=client\``,
345
+ };
346
+ /**
347
+ * Return the DevOps domain knowledge sections that are relevant to the given
348
+ * set of tool names.
349
+ *
350
+ * The general section is always included. Domain-specific sections (terraform,
351
+ * kubernetes, helm, aws, secrets, cicd, monitoring, gitops) are only added when
352
+ * at least one tool in `toolNames` maps to that domain.
353
+ *
354
+ * This keeps the system prompt lean for sessions that only use a small subset
355
+ * of the DevOps toolchain.
356
+ *
357
+ * @param toolNames - The names of the tools available in the current session.
358
+ * @returns A markdown string containing only the relevant knowledge sections.
359
+ */
360
+ export function getRelevantDomainKnowledge(toolNames) {
361
+ const sections = [`# DevOps Domain Knowledge\n\n${DOMAIN_SECTIONS.general}`];
362
+ if (toolNames.some(t => t.includes('terraform') || t === 'drift_detect')) {
363
+ sections.push(DOMAIN_SECTIONS.terraform);
364
+ }
365
+ if (toolNames.some(t => t.includes('kubectl') || t === 'k8s_rbac' || t === 'k8s')) {
366
+ sections.push(DOMAIN_SECTIONS.kubernetes);
367
+ }
368
+ if (toolNames.some(t => t.includes('helm'))) {
369
+ sections.push(DOMAIN_SECTIONS.helm);
370
+ }
371
+ if (toolNames.some(t => t.includes('aws') || t.includes('cloud'))) {
372
+ sections.push(DOMAIN_SECTIONS.aws);
373
+ }
374
+ if (toolNames.some(t => t.includes('secret') || t.includes('vault'))) {
375
+ sections.push(DOMAIN_SECTIONS.secrets);
376
+ }
377
+ if (toolNames.some(t => t.includes('cicd') || t.includes('pipeline') || t.includes('github'))) {
378
+ sections.push(DOMAIN_SECTIONS.cicd);
379
+ }
380
+ if (toolNames.some(t => t.includes('monitor') || t.includes('logs') || t.includes('metric'))) {
381
+ sections.push(DOMAIN_SECTIONS.monitoring);
382
+ }
383
+ if (toolNames.some(t => t.includes('gitops') || t.includes('argocd') || t.includes('flux'))) {
384
+ sections.push(DOMAIN_SECTIONS.gitops);
385
+ }
386
+ return sections.join('\n\n');
387
+ }
388
+ /**
389
+ * The full concatenated DevOps domain knowledge (all sections).
390
+ *
391
+ * Kept for backward-compatibility. New call sites should prefer
392
+ * {@link getRelevantDomainKnowledge} with a tool list so only the relevant
393
+ * sections are included in the prompt.
394
+ *
395
+ * @deprecated Use {@link getRelevantDomainKnowledge} instead.
396
+ * @internal
397
+ */
398
+ export const DEVOPS_DOMAIN_KNOWLEDGE = [
399
+ `# DevOps Domain Knowledge\n\n${DOMAIN_SECTIONS.general}`,
400
+ DOMAIN_SECTIONS.terraform,
401
+ DOMAIN_SECTIONS.kubernetes,
402
+ DOMAIN_SECTIONS.helm,
403
+ DOMAIN_SECTIONS.aws,
404
+ DOMAIN_SECTIONS.secrets,
405
+ DOMAIN_SECTIONS.cicd,
406
+ DOMAIN_SECTIONS.monitoring,
407
+ DOMAIN_SECTIONS.gitops,
408
+ ].join('\n\n');
409
+ // ---------------------------------------------------------------------------
410
+ // DevOps Decision Heuristics
411
+ // ---------------------------------------------------------------------------
412
+ /**
413
+ * Explicit decision rules injected into every prompt to prevent common mistakes.
414
+ * @internal
415
+ */
416
+ const DEVOPS_HEURISTICS = `# DevOps Decision Heuristics
417
+
418
+ ## Terraform Workflow Rules
419
+ - ALWAYS follow: init → validate → plan → review → apply. NEVER apply without a prior plan.
420
+ - NEVER use terraform apply if you haven't seen the plan output in this session.
421
+ - state-rm and force-unlock require EXPLICIT user confirmation — always ask before running.
422
+ - For multi-environment: check active workspace (\`terraform workspace show\`) before any operation.
423
+ - Tag every resource you create with \`managed_by = "nimbus"\` in Terraform resources.
424
+ - Prefer \`terraform output -json\` over parsing state files directly.
425
+
426
+ ## Kubernetes Rules
427
+ - ALWAYS include \`-n <namespace>\` or \`--all-namespaces\`. Never assume default namespace.
428
+ - When debugging: check LOGS first, then events (\`kubectl describe\`), then resource state.
429
+ - NEVER delete a pod directly unless debugging — prefer \`kubectl rollout restart deploy/<name>\`.
430
+ - Cordon/drain before node maintenance: \`kubectl cordon\` then \`kubectl drain --ignore-daemonsets\`.
431
+ - Add label \`app.kubernetes.io/managed-by: nimbus\` to K8s resources you create.
432
+
433
+ ## Helm Rules
434
+ - ALWAYS run \`helm lint\` before install or upgrade.
435
+ - ALWAYS get current values before upgrading: \`helm get values <release> -n <ns>\`.
436
+ - Use \`--atomic\` on upgrades to auto-rollback on failure.
437
+ - Check \`helm history\` before rollback to pick the correct revision.
438
+
439
+ ## General DevOps Rules
440
+ - Prefer read/inspect operations before any write/mutate operations.
441
+ - In PLAN mode: NEVER apply, apply, delete, or mutate any resource.
442
+ - In DEPLOY mode: ALWAYS show deploy_preview before destructive operations (destroy/delete/state-rm).
443
+ - Use \`env\` field on terraform/kubectl/helm tools to pass \`AWS_PROFILE\`, \`KUBECONFIG\`, \`TF_WORKSPACE\`.
444
+ - Prefer dedicated cloud tools (\`aws\`, \`gcloud\`, \`az\`) over \`bash\` for cloud operations.
445
+
446
+ ## Tool Selection Priority
447
+ 1. Use terraform/kubectl/helm tools for IaC operations (not bash).
448
+ 2. Use cloud_discover to find resources before operating on them.
449
+ 3. Use drift_detect to check actual vs desired state.
450
+ 4. Use cost_estimate to understand financial impact before applying.
451
+ 5. Fall back to bash only when no dedicated tool covers the operation.`;
452
+ // ---------------------------------------------------------------------------
453
+ // L2: Mode-Pruned Heuristics
454
+ // ---------------------------------------------------------------------------
455
+ /**
456
+ * Return the DevOps decision heuristics pruned to only include sections
457
+ * relevant to the current mode. This prevents prompt bloat in restricted
458
+ * modes where deploy-specific or plan-specific rules are irrelevant.
459
+ *
460
+ * - plan mode: omit deploy-related execution rules (they cannot be triggered)
461
+ * - build mode: omit plan-only readonly reminders (build mode can write files)
462
+ * - deploy mode: include everything
463
+ *
464
+ * @param mode - The current agent mode.
465
+ * @returns A pruned markdown heuristics string.
466
+ */
467
+ export function getPrunedHeuristics(mode) {
468
+ if (mode === 'deploy') {
469
+ // Deploy mode: include the complete heuristics — no pruning needed.
470
+ return DEVOPS_HEURISTICS;
471
+ }
472
+ // Split into lines and filter based on mode.
473
+ const lines = DEVOPS_HEURISTICS.split('\n');
474
+ if (mode === 'plan') {
475
+ // Plan mode: skip lines that reference apply/deploy operations that are
476
+ // blocked anyway. This saves ~10-15 tokens without losing useful context.
477
+ return lines
478
+ .filter(line => {
479
+ const l = line.toLowerCase();
480
+ // Remove deploy-specific execution requirements (plan mode cannot apply)
481
+ if (l.includes('in deploy mode:') || l.includes('deploy_preview before'))
482
+ return false;
483
+ // Remove tool selection items for deploy-only tools
484
+ if (l.includes('use drift_detect') || l.includes('use cost_estimate'))
485
+ return false;
486
+ return true;
487
+ })
488
+ .join('\n');
489
+ }
490
+ if (mode === 'build') {
491
+ // Build mode: skip plan-only readonly reminders that contradict build mode.
492
+ return lines
493
+ .filter(line => {
494
+ const l = line.toLowerCase();
495
+ // Remove plan-mode-only readonly enforcement lines
496
+ if (l.includes('in plan mode:') || l.includes('never apply, apply'))
497
+ return false;
498
+ return true;
499
+ })
500
+ .join('\n');
501
+ }
502
+ return DEVOPS_HEURISTICS;
503
+ }
504
+ // ---------------------------------------------------------------------------
505
+ // Mode Instructions
506
+ // ---------------------------------------------------------------------------
507
+ /**
508
+ * Return the mode-specific instruction block for the given {@link AgentMode}.
509
+ *
510
+ * Each mode defines an explicit allow-list and deny-list so the model
511
+ * understands the boundaries of what it can do.
512
+ *
513
+ * @param mode - The active agent mode.
514
+ * @returns A markdown section describing the mode's rules.
515
+ * @internal
516
+ */
517
+ function getModeInstructions(mode) {
518
+ switch (mode) {
519
+ case 'plan':
520
+ return `# Mode: PLAN
521
+
522
+ You are in Plan mode. Your role is to analyze, explore, and propose — NOT to modify.
523
+
524
+ Allowed actions:
525
+ - Read files, search configurations, list directories
526
+ - Analyze infrastructure configurations (Terraform, Kubernetes, Helm, CI/CD)
527
+ - Estimate costs and detect drift
528
+ - Use terraform_plan_analyze to inspect plan files
529
+ - Use kubectl_context to list cluster contexts (read-only)
530
+ - Propose changes and create task lists
531
+ - Fetch web content for research
532
+
533
+ NOT allowed:
534
+ - Editing or creating files
535
+ - Running bash commands that modify state
536
+ - Executing terraform apply, kubectl apply, helm install
537
+ - Making any state-changing operations
538
+
539
+ WORKSPACE AWARENESS: Start by checking the active Terraform workspace and kubectl context. Report the current workspace/context before making any proposals so the user knows what environment you're analyzing.
540
+
541
+ Focus on understanding the infrastructure and environment, then propose a clear, specific action plan.`;
542
+ case 'build':
543
+ return `# Mode: BUILD
544
+
545
+ You are in Build mode. You can read, edit, create files, and run non-destructive commands.
546
+
547
+ Allowed actions:
548
+ - All Plan mode actions
549
+ - Edit infrastructure configurations, generate IaC, fix scripts and automation code
550
+ - Edit and create files (Terraform, Kubernetes manifests, Helm charts, CI/CD configs)
551
+ - Run terraform validate, terraform fmt, terraform plan
552
+ - Run kubectl get, kubectl describe, kubectl diff
553
+ - Run linters, formatters, and validation commands
554
+
555
+ NOT allowed:
556
+ - terraform apply, terraform destroy
557
+ - kubectl apply, kubectl delete
558
+ - helm install, helm upgrade, helm uninstall
559
+ - Any infrastructure-mutating operations
560
+
561
+ Focus on generating, editing, and validating infrastructure configurations before deploying.`;
562
+ case 'deploy':
563
+ return `# Mode: DEPLOY
564
+
565
+ You are in Deploy mode. You have full access to all tools including infrastructure mutations.
566
+
567
+ Allowed actions:
568
+ - All Build mode actions
569
+ - terraform apply, terraform destroy
570
+ - kubectl apply, kubectl delete
571
+ - helm install, helm upgrade, helm uninstall
572
+ - Cloud resource mutations
573
+
574
+ REQUIRED:
575
+ - Always run deploy_preview before any destructive operation
576
+ - Show the user what will change before executing
577
+ - Wait for explicit approval on destructive changes
578
+ - Be WORKSPACE-AWARE: before applying, confirm the active Terraform workspace and kubectl context match the intended environment. State this explicitly: "Applying to workspace: X in cluster: Y"
579
+ - For multi-environment setups, use terraform_plan_analyze to confirm the scope before terraform apply
580
+
581
+ Focus on safe, verified deployments with minimal blast radius.`;
582
+ }
583
+ }
584
+ // ---------------------------------------------------------------------------
585
+ // Tools Summary
586
+ // ---------------------------------------------------------------------------
587
+ /**
588
+ * Build a markdown summary of the available tools from their definitions.
589
+ *
590
+ * Returns an empty string when the tool list is empty so callers can
591
+ * conditionally include the section.
592
+ *
593
+ * @param tools - The tool definitions to summarize.
594
+ * @returns A markdown section listing each tool, or `''` if none.
595
+ * @internal
596
+ */
597
+ function buildToolsSummary(tools) {
598
+ if (tools.length === 0) {
599
+ return '';
600
+ }
601
+ const lines = tools.map(t => `- **${t.name}**: ${t.description}`);
602
+ return `# Available Tools (${tools.length})\n\n${lines.join('\n')}`;
603
+ }
604
+ // ---------------------------------------------------------------------------
605
+ // NIMBUS.md Loader
606
+ // ---------------------------------------------------------------------------
607
+ /**
608
+ * Search paths for `NIMBUS.md` files, in priority order.
609
+ * @internal
610
+ */
611
+ function getNimbusMdSearchPaths(cwd) {
612
+ return [
613
+ cwd ? path.join(cwd, 'NIMBUS.md') : null,
614
+ cwd ? path.join(cwd, '.nimbus', 'NIMBUS.md') : null,
615
+ path.join(homedir(), '.nimbus', 'NIMBUS.md'),
616
+ ].filter(Boolean);
617
+ }
618
+ /**
619
+ * Load `NIMBUS.md` from the project directory or the user's home directory.
620
+ *
621
+ * The search order is:
622
+ * 1. `<cwd>/NIMBUS.md`
623
+ * 2. `<cwd>/.nimbus/NIMBUS.md`
624
+ * 3. `~/.nimbus/NIMBUS.md`
625
+ *
626
+ * Returns `null` if no file is found or if all candidates are inaccessible.
627
+ *
628
+ * @param cwd - The working directory to search from. Defaults to `undefined`
629
+ * (skips cwd-relative paths).
630
+ * @returns The file contents as a string, or `null`.
631
+ */
632
+ export function loadNimbusMd(cwd) {
633
+ const searchPaths = getNimbusMdSearchPaths(cwd);
634
+ for (const p of searchPaths) {
635
+ try {
636
+ if (fs.existsSync(p)) {
637
+ return fs.readFileSync(p, 'utf-8');
638
+ }
639
+ }
640
+ catch {
641
+ // Skip inaccessible files silently
642
+ }
643
+ }
644
+ return null;
645
+ }
646
+ // ---------------------------------------------------------------------------
647
+ // G14: Forbidden rules extraction
648
+ // ---------------------------------------------------------------------------
649
+ /**
650
+ * Extract bullet items from the `## Forbidden` section of a NIMBUS.md string.
651
+ * Returns an array of rule strings (without the leading `-` or `*`).
652
+ *
653
+ * @param nimbusContent - The full content of a NIMBUS.md file.
654
+ * @returns Array of forbidden rule strings, empty if section not found or empty.
655
+ */
656
+ export function extractForbiddenRules(nimbusContent) {
657
+ // Find the ## Forbidden section and extract lines until the next ## heading or end of string
658
+ const lines = nimbusContent.split('\n');
659
+ let inForbidden = false;
660
+ const rules = [];
661
+ for (const line of lines) {
662
+ const trimmed = line.trim();
663
+ if (/^##\s+Forbidden\s*$/.test(trimmed)) {
664
+ inForbidden = true;
665
+ continue;
666
+ }
667
+ if (inForbidden) {
668
+ // Stop at any new ## section
669
+ if (/^##\s/.test(trimmed))
670
+ break;
671
+ // Skip blank lines and HTML comments
672
+ if (!trimmed || trimmed.startsWith('<!--'))
673
+ continue;
674
+ // Collect bullet items
675
+ if (trimmed.startsWith('-') || trimmed.startsWith('*')) {
676
+ const rule = trimmed.replace(/^[-*]\s*/, '').trim();
677
+ if (rule && !rule.startsWith('<!--')) {
678
+ rules.push(rule);
679
+ }
680
+ }
681
+ }
682
+ }
683
+ return rules;
684
+ }
685
+ // ---------------------------------------------------------------------------
686
+ // Subagent Instructions
687
+ // ---------------------------------------------------------------------------
688
+ /**
689
+ * Return the instruction block appended when the agent is running as a
690
+ * spawned subagent.
691
+ *
692
+ * Subagents are constrained to prevent recursive spawning and to keep
693
+ * execution focused on a single task.
694
+ *
695
+ * @param agentName - The name of the active subagent.
696
+ * @returns A markdown section with subagent-specific rules.
697
+ * @internal
698
+ */
699
+ function getSubagentInstructions(agentName) {
700
+ return `# Subagent Mode: ${agentName}
701
+
702
+ You are running as a subagent spawned by the primary Nimbus agent. Your task is specific and focused.
703
+ - Complete the requested task and return a clear, concise result
704
+ - Do NOT spawn further subagents (no nesting)
705
+ - Stay focused on the assigned task — do not explore tangentially
706
+ - Return your findings as structured, actionable information`;
707
+ }
708
+ // ---------------------------------------------------------------------------
709
+ // Environment Context
710
+ // ---------------------------------------------------------------------------
711
+ /**
712
+ * Build a short environment-context block that gives the model awareness of
713
+ * the runtime environment (working directory, platform, date, git status).
714
+ *
715
+ * @param cwd - The working directory. Defaults to `process.cwd()`.
716
+ * @returns A markdown section with environment metadata.
717
+ * @internal
718
+ */
719
+ function buildEnvironmentContext(cwd) {
720
+ const effectiveCwd = cwd ?? process.cwd();
721
+ const parts = [
722
+ '# Environment',
723
+ `- Working directory: ${effectiveCwd}`,
724
+ `- Platform: ${process.platform}`,
725
+ `- Date: ${new Date().toISOString().split('T')[0]}`,
726
+ ];
727
+ // Check for git repo and gather context
728
+ const gitDir = path.join(effectiveCwd, '.git');
729
+ if (fs.existsSync(gitDir)) {
730
+ parts.push('- Git repository: yes');
731
+ const execOpts = {
732
+ cwd: effectiveCwd,
733
+ timeout: 1000,
734
+ encoding: 'utf-8',
735
+ stdio: ['pipe', 'pipe', 'pipe'],
736
+ };
737
+ try {
738
+ const branch = execSync('git rev-parse --abbrev-ref HEAD', execOpts).trim();
739
+ parts.push(`- Git branch: ${branch}`);
740
+ }
741
+ catch {
742
+ /* ignore */
743
+ }
744
+ try {
745
+ const log = execSync('git log --oneline -5 2>/dev/null', execOpts).trim();
746
+ if (log) {
747
+ parts.push(`- Recent commits:\n${log
748
+ .split('\n')
749
+ .map((l) => ` ${l}`)
750
+ .join('\n')}`);
751
+ }
752
+ }
753
+ catch {
754
+ /* ignore */
755
+ }
756
+ try {
757
+ const staged = execSync('git diff --cached --stat 2>/dev/null', execOpts).trim();
758
+ if (staged) {
759
+ parts.push(`- Staged changes:\n${staged
760
+ .split('\n')
761
+ .map((l) => ` ${l}`)
762
+ .join('\n')}`);
763
+ }
764
+ }
765
+ catch {
766
+ /* ignore */
767
+ }
768
+ try {
769
+ const unstaged = execSync('git diff --stat 2>/dev/null', execOpts).trim();
770
+ if (unstaged) {
771
+ parts.push(`- Unstaged changes:\n${unstaged
772
+ .split('\n')
773
+ .map((l) => ` ${l}`)
774
+ .join('\n')}`);
775
+ }
776
+ }
777
+ catch {
778
+ /* ignore */
779
+ }
780
+ }
781
+ // Kubernetes context
782
+ try {
783
+ const ctx = execSync('kubectl config current-context', { timeout: 2000, encoding: 'utf-8' }).trim();
784
+ if (ctx)
785
+ parts.push(`- Kubernetes context: ${ctx}`);
786
+ }
787
+ catch { /* ignore */ }
788
+ // Terraform workspace (only if .terraform dir exists)
789
+ if (fs.existsSync(path.join(effectiveCwd, '.terraform'))) {
790
+ try {
791
+ const ws = execSync('terraform workspace show', {
792
+ cwd: effectiveCwd, timeout: 5000, encoding: 'utf-8',
793
+ }).trim();
794
+ if (ws)
795
+ parts.push(`- Terraform workspace: ${ws}`);
796
+ }
797
+ catch { /* ignore */ }
798
+ }
799
+ // AWS identity (only if credentials are configured)
800
+ if (process.env.AWS_ACCESS_KEY_ID || process.env.AWS_PROFILE || fs.existsSync(path.join(homedir(), '.aws', 'credentials'))) {
801
+ try {
802
+ const identity = execSync('aws sts get-caller-identity --output json', {
803
+ timeout: 5000, encoding: 'utf-8',
804
+ }).trim();
805
+ const parsed = JSON.parse(identity);
806
+ parts.push(`- AWS account: ${parsed.Account}`);
807
+ }
808
+ catch { /* ignore */ }
809
+ try {
810
+ const region = execSync('aws configure get region', { timeout: 2000, encoding: 'utf-8' }).trim();
811
+ if (region)
812
+ parts.push(`- AWS region: ${region}`);
813
+ }
814
+ catch {
815
+ if (process.env.AWS_DEFAULT_REGION)
816
+ parts.push(`- AWS region: ${process.env.AWS_DEFAULT_REGION}`);
817
+ }
818
+ }
819
+ // GCP project (only if gcloud available)
820
+ try {
821
+ const proj = execSync('gcloud config get-value project 2>/dev/null', {
822
+ timeout: 3000, encoding: 'utf-8',
823
+ }).trim();
824
+ if (proj && proj !== '(unset)')
825
+ parts.push(`- GCP project: ${proj}`);
826
+ }
827
+ catch { /* ignore */ }
828
+ return parts.join('\n');
829
+ }
830
+ // ---------------------------------------------------------------------------
831
+ // C5: Primary Cloud Section
832
+ // ---------------------------------------------------------------------------
833
+ /**
834
+ * Read the primaryClouds field from ~/.nimbus/config.json and build a section
835
+ * that focuses the agent on those cloud providers.
836
+ *
837
+ * @returns A markdown section string, or `null` if not configured.
838
+ * @internal
839
+ */
840
+ function buildPrimaryCloudSection() {
841
+ try {
842
+ const configPath = path.join(homedir(), '.nimbus', 'config.json');
843
+ if (!fs.existsSync(configPath))
844
+ return null;
845
+ const raw = fs.readFileSync(configPath, 'utf-8');
846
+ const config = JSON.parse(raw);
847
+ const clouds = config.primaryClouds;
848
+ if (!Array.isArray(clouds) || clouds.length === 0)
849
+ return null;
850
+ const cloudNames = clouds.map(c => c.toUpperCase()).join(', ');
851
+ return [
852
+ '# Primary Cloud Providers',
853
+ `Primary cloud providers: ${cloudNames}`,
854
+ `Focus on ${cloudNames} patterns and best practices in your responses.`,
855
+ ].join('\n');
856
+ }
857
+ catch {
858
+ return null;
859
+ }
860
+ }