@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
package/package.json CHANGED
@@ -1,14 +1,16 @@
1
1
  {
2
2
  "name": "@build-astron-co/nimbus",
3
- "version": "0.2.0",
4
- "description": "AI-Powered Cloud Engineering Agent",
5
- "main": "src/nimbus.ts",
3
+ "version": "0.4.0",
4
+ "description": "AI-Powered DevOps Engineering Agent",
5
+ "main": "dist/src/nimbus.js",
6
6
  "bin": {
7
- "nimbus": "bin/nimbus"
7
+ "nimbus": "bin/nimbus.mjs"
8
8
  },
9
9
  "files": [
10
10
  "bin/",
11
11
  "src/",
12
+ "dist/",
13
+ "completions/",
12
14
  "package.json",
13
15
  "tsconfig.json"
14
16
  ],
@@ -16,34 +18,39 @@
16
18
  "access": "public"
17
19
  },
18
20
  "scripts": {
19
- "test": "bun test src/__tests__/",
20
- "test:coverage": "bun test src/__tests__/ --coverage --coverage-reporter=lcov --coverage-reporter=text --coverage-threshold=80",
21
- "test:watch": "bun test src/__tests__/ --watch",
21
+ "test": "vitest run src/__tests__/",
22
+ "test:coverage": "vitest run src/__tests__/ --coverage",
23
+ "test:watch": "vitest src/__tests__/ --watch",
22
24
  "lint": "eslint . --ext .ts,.tsx",
23
25
  "lint:fix": "eslint . --ext .ts,.tsx --fix",
24
26
  "format": "prettier --write .",
25
27
  "format:check": "prettier --check .",
26
- "type-check": "bun tsc --noEmit",
27
- "build": "bun src/build.ts",
28
+ "type-check": "tsc --noEmit",
29
+ "build": "./scripts/build-binary.sh",
28
30
  "build:binary": "./scripts/build-binary.sh",
29
31
  "build:binary:all": "./scripts/build-binary.sh all",
30
- "nimbus": "bun src/nimbus.ts",
31
- "precommit": "bun run lint && bun run format:check && bun run type-check"
32
+ "nimbus": "node --loader ./node_modules/tsx/dist/esm/index.mjs src/nimbus.ts",
33
+ "build:npm": "tsc --project tsconfig.build.json",
34
+ "prepare": "npm run build:npm",
35
+ "prepack": "tsc --project tsconfig.build.json",
36
+ "precommit": "npm run lint && npm run format:check && npm run type-check",
37
+ "postinstall": "node -e \"process.stdout.write('\\n Nimbus installed! Next steps:\\n 1. Run: nimbus login (configure your LLM provider)\\n 2. Run: nimbus doctor (check your DevOps toolchain)\\n 3. Run: nimbus completions install (enable tab completion)\\n 4. Run: nimbus (start the DevOps agent)\\n\\n')\""
32
38
  },
33
39
  "devDependencies": {
34
40
  "@types/better-sqlite3": "^7.6.0",
35
- "@types/bun": "latest",
36
41
  "@types/js-yaml": "^4.0.9",
42
+ "@types/node": "^20.0.0",
37
43
  "@types/react": "^19.2.14",
38
- "@typescript-eslint/eslint-plugin": "^6.21.0",
39
- "@typescript-eslint/parser": "^6.21.0",
44
+ "@typescript-eslint/eslint-plugin": "^8.56.1",
45
+ "@typescript-eslint/parser": "^8.56.1",
46
+ "@vitest/coverage-v8": "^3.2.4",
40
47
  "eslint": "^8.57.0",
41
48
  "prettier": "^3.2.5",
42
- "typescript": "^5.3.3"
49
+ "typescript": "^5.3.3",
50
+ "vitest": "^3.2.4"
43
51
  },
44
52
  "engines": {
45
- "node": ">=18.0.0",
46
- "bun": ">=1.0.0"
53
+ "node": ">=18.0.0"
47
54
  },
48
55
  "dependencies": {
49
56
  "@anthropic-ai/sdk": "^0.78.0",
@@ -61,20 +68,21 @@
61
68
  "openai": "^6.22.0",
62
69
  "react": "^19.2.4",
63
70
  "simple-git": "^3.32.1",
64
- "better-sqlite3": "^11.0.0",
65
71
  "tsx": "^4.7.0",
66
72
  "zod": "^4.3.6"
67
73
  },
68
74
  "optionalDependencies": {
69
- "@azure/identity": "^4.0.0",
75
+ "better-sqlite3": "^11.0.0",
76
+ "sql.js": "^1.12.0",
70
77
  "@azure/arm-compute": "^22.0.0",
71
- "@azure/arm-storage": "^18.0.0",
72
78
  "@azure/arm-containerservice": "^21.0.0",
73
79
  "@azure/arm-network": "^33.0.0",
74
- "google-auth-library": "^9.0.0",
80
+ "@azure/arm-storage": "^18.0.0",
81
+ "@azure/identity": "^4.0.0",
75
82
  "@google-cloud/compute": "^4.0.0",
76
- "@google-cloud/storage": "^7.0.0",
77
83
  "@google-cloud/container": "^5.0.0",
78
- "@octokit/rest": "^21.0.0"
84
+ "@google-cloud/storage": "^7.0.0",
85
+ "@octokit/rest": "^21.0.0",
86
+ "google-auth-library": "^9.0.0"
79
87
  }
80
88
  }
@@ -0,0 +1,133 @@
1
+ /**
2
+ * Alias Command Tests — L2
3
+ *
4
+ * Tests resolveAlias expansion and alias file management.
5
+ */
6
+
7
+ import { describe, test, expect, beforeEach, afterEach, vi } from 'vitest';
8
+ import * as fs from 'node:fs';
9
+ import * as path from 'node:path';
10
+ import * as os from 'node:os';
11
+
12
+ // Patch homedir so aliases are stored in a temp dir during tests
13
+ let tmpDir: string;
14
+
15
+ vi.mock('node:os', async () => {
16
+ const actual = await vi.importActual<typeof os>('node:os');
17
+ return {
18
+ ...actual,
19
+ homedir: () => tmpDir ?? actual.homedir(),
20
+ };
21
+ });
22
+
23
+ // Re-import after mock is set up (dynamic to pick up the homedir mock)
24
+ async function getAliasModule() {
25
+ // Force re-import so homedir mock is active
26
+ return await import('../commands/alias');
27
+ }
28
+
29
+ describe('resolveAlias (L2)', () => {
30
+ beforeEach(() => {
31
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'nimbus-alias-test-'));
32
+ // Clear module cache so homedir mock takes effect
33
+ vi.resetModules();
34
+ });
35
+
36
+ afterEach(() => {
37
+ fs.rmSync(tmpDir, { recursive: true, force: true });
38
+ vi.resetModules();
39
+ });
40
+
41
+ test('returns args unchanged when no alias exists', async () => {
42
+ const { resolveAlias } = await getAliasModule();
43
+ expect(resolveAlias(['run', '--help'])).toEqual(['run', '--help']);
44
+ });
45
+
46
+ test('returns empty array for empty input', async () => {
47
+ const { resolveAlias } = await getAliasModule();
48
+ expect(resolveAlias([])).toEqual([]);
49
+ });
50
+
51
+ test('expands a defined alias', async () => {
52
+ // Write alias file manually
53
+ const nimbusDir = path.join(tmpDir, '.nimbus');
54
+ fs.mkdirSync(nimbusDir, { recursive: true });
55
+ fs.writeFileSync(
56
+ path.join(nimbusDir, 'aliases.json'),
57
+ JSON.stringify({ deploy: 'run --auto-approve "deploy staging"' }),
58
+ 'utf-8'
59
+ );
60
+
61
+ const { resolveAlias } = await getAliasModule();
62
+ const result = resolveAlias(['deploy']);
63
+ expect(result[0]).toBe('run');
64
+ expect(result).toContain('--auto-approve');
65
+ });
66
+
67
+ test('appends remaining args after expanding alias', async () => {
68
+ const nimbusDir = path.join(tmpDir, '.nimbus');
69
+ fs.mkdirSync(nimbusDir, { recursive: true });
70
+ fs.writeFileSync(
71
+ path.join(nimbusDir, 'aliases.json'),
72
+ JSON.stringify({ tf: 'run "terraform plan"' }),
73
+ 'utf-8'
74
+ );
75
+
76
+ const { resolveAlias } = await getAliasModule();
77
+ const result = resolveAlias(['tf', '--verbose']);
78
+ expect(result[result.length - 1]).toBe('--verbose');
79
+ });
80
+ });
81
+
82
+ describe('aliasCommand list/add/remove (L2)', () => {
83
+ beforeEach(() => {
84
+ tmpDir = fs.mkdtempSync(path.join(os.tmpdir(), 'nimbus-alias-cmd-test-'));
85
+ vi.resetModules();
86
+ });
87
+
88
+ afterEach(() => {
89
+ fs.rmSync(tmpDir, { recursive: true, force: true });
90
+ vi.resetModules();
91
+ });
92
+
93
+ test('list shows "no aliases" when file is absent', async () => {
94
+ const { aliasCommand } = await getAliasModule();
95
+ const logs: string[] = [];
96
+ vi.spyOn(console, 'log').mockImplementation((...args) => logs.push(args.join(' ')));
97
+ // Should not throw even if file doesn't exist
98
+ await expect(aliasCommand('list', [])).resolves.not.toThrow();
99
+ vi.restoreAllMocks();
100
+ });
101
+
102
+ test('set writes alias to file', async () => {
103
+ const { aliasCommand } = await getAliasModule();
104
+ vi.spyOn(process.stdout, 'write').mockImplementation(() => true);
105
+ vi.spyOn(console, 'log').mockImplementation(() => {});
106
+
107
+ await aliasCommand('myalias=run "do something"', []);
108
+
109
+ const aliasFile = path.join(tmpDir, '.nimbus', 'aliases.json');
110
+ const data = JSON.parse(fs.readFileSync(aliasFile, 'utf-8')) as Record<string, string>;
111
+ expect(data['myalias']).toBe('run "do something"');
112
+ vi.restoreAllMocks();
113
+ });
114
+
115
+ test('remove deletes alias from file', async () => {
116
+ const nimbusDir = path.join(tmpDir, '.nimbus');
117
+ fs.mkdirSync(nimbusDir, { recursive: true });
118
+ fs.writeFileSync(
119
+ path.join(nimbusDir, 'aliases.json'),
120
+ JSON.stringify({ myalias: 'run stuff' }),
121
+ 'utf-8'
122
+ );
123
+
124
+ const { aliasCommand } = await getAliasModule();
125
+ vi.spyOn(console, 'log').mockImplementation(() => {});
126
+
127
+ await aliasCommand('remove', ['myalias']);
128
+
129
+ const data = JSON.parse(fs.readFileSync(path.join(nimbusDir, 'aliases.json'), 'utf-8')) as Record<string, string>;
130
+ expect(data['myalias']).toBeUndefined();
131
+ vi.restoreAllMocks();
132
+ });
133
+ });
@@ -8,7 +8,7 @@
8
8
  * - shutdownApp() is idempotent (safe to call when already shut down)
9
9
  */
10
10
 
11
- import { describe, it, expect, afterEach } from 'bun:test';
11
+ import { describe, it, expect, afterEach } from 'vitest';
12
12
  import { initApp, shutdownApp, getAppContext } from '../app';
13
13
 
14
14
  describe('app lifecycle', () => {
@@ -6,7 +6,7 @@
6
6
  * - Activity Log
7
7
  */
8
8
 
9
- import { describe, test, expect, beforeEach, afterEach } from 'bun:test';
9
+ import { describe, test, expect, beforeEach, afterEach } from 'vitest';
10
10
  import * as fs from 'node:fs';
11
11
  import * as path from 'node:path';
12
12
  import * as os from 'node:os';
@@ -1,4 +1,4 @@
1
- import { describe, expect, test, beforeEach } from 'bun:test';
1
+ import { describe, expect, test, beforeEach } from 'vitest';
2
2
  import { ProviderCircuitBreaker } from '../llm/circuit-breaker';
3
3
 
4
4
  describe('ProviderCircuitBreaker', () => {
@@ -5,7 +5,7 @@
5
5
  * structured RunOptions for the non-interactive nimbus run command.
6
6
  */
7
7
 
8
- import { describe, test, expect } from 'bun:test';
8
+ import { describe, test, it, expect } from 'vitest';
9
9
  import { parseRunArgs } from '../cli/run';
10
10
 
11
11
  // ===========================================================================
@@ -29,6 +29,12 @@ describe('parseRunArgs', () => {
29
29
  expect(result.format).toBe('json');
30
30
  });
31
31
 
32
+ test('parses --format table (H4)', () => {
33
+ const result = parseRunArgs(['--format', 'table', 'my prompt']);
34
+ expect(result.format).toBe('table');
35
+ expect(result.prompt).toBe('my prompt');
36
+ });
37
+
32
38
  test('parses --auto-approve', () => {
33
39
  const result = parseRunArgs(['--auto-approve', 'do', 'stuff']);
34
40
  expect(result.autoApprove).toBe(true);
@@ -112,4 +118,234 @@ describe('parseRunArgs', () => {
112
118
  expect(result.model).toBe('openai/gpt-4');
113
119
  expect(result.prompt).toBe('deploy everything');
114
120
  });
121
+
122
+ // G13: --timeout flag
123
+ test('G13: parses --timeout <seconds> into milliseconds', () => {
124
+ const result = parseRunArgs(['--timeout', '30', 'my prompt']);
125
+ expect(result.timeout).toBe(30000);
126
+ expect(result.prompt).toBe('my prompt');
127
+ });
128
+
129
+ test('G13: timeout defaults to undefined when not specified', () => {
130
+ const result = parseRunArgs(['my prompt']);
131
+ expect(result.timeout).toBeUndefined();
132
+ });
133
+
134
+ test('G13: parses --timeout 0 as 0 ms', () => {
135
+ const result = parseRunArgs(['--timeout', '0', 'prompt']);
136
+ expect(result.timeout).toBe(0);
137
+ });
138
+
139
+ // G15: --raw-tool-output flag
140
+ test('G15: parses --raw-tool-output flag', () => {
141
+ const result = parseRunArgs(['--raw-tool-output', 'show pod status']);
142
+ expect(result.rawToolOutput).toBe(true);
143
+ expect(result.prompt).toBe('show pod status');
144
+ });
145
+
146
+ test('G15: rawToolOutput defaults to false', () => {
147
+ const result = parseRunArgs(['prompt']);
148
+ expect(result.rawToolOutput).toBe(false);
149
+ });
150
+
151
+ test('G13 + G15: combines timeout and raw-tool-output with other flags', () => {
152
+ const result = parseRunArgs([
153
+ '--timeout', '60',
154
+ '--raw-tool-output',
155
+ '--auto-approve',
156
+ 'list all pods',
157
+ ]);
158
+ expect(result.timeout).toBe(60000);
159
+ expect(result.rawToolOutput).toBe(true);
160
+ expect(result.autoApprove).toBe(true);
161
+ expect(result.prompt).toBe('list all pods');
162
+ });
163
+
164
+ // H3: CI/CD flags
165
+ test('H3: parses --exit-code-on-error flag', () => {
166
+ const result = parseRunArgs(['--exit-code-on-error', 'run tests']);
167
+ expect(result.exitOnError).toBe(true);
168
+ expect(result.prompt).toBe('run tests');
169
+ });
170
+
171
+ test('C5: exitOnError defaults to true (POSIX convention)', () => {
172
+ const result = parseRunArgs(['prompt']);
173
+ expect(result.exitOnError).toBe(true);
174
+ });
175
+
176
+ test('C5: --no-exit-on-error disables exitOnError', () => {
177
+ const result = parseRunArgs(['--no-exit-on-error', 'prompt']);
178
+ expect(result.exitOnError).toBe(false);
179
+ });
180
+
181
+ test('H3: parses --context <kubectl-context>', () => {
182
+ const result = parseRunArgs(['--context', 'prod-cluster', 'deploy app']);
183
+ expect(result.context).toBe('prod-cluster');
184
+ expect(result.prompt).toBe('deploy app');
185
+ });
186
+
187
+ test('H3: context defaults to undefined', () => {
188
+ const result = parseRunArgs(['prompt']);
189
+ expect(result.context).toBeUndefined();
190
+ });
191
+
192
+ test('H3: parses --workspace <tf-workspace>', () => {
193
+ const result = parseRunArgs(['--workspace', 'production', 'run plan']);
194
+ expect(result.workspace).toBe('production');
195
+ expect(result.prompt).toBe('run plan');
196
+ });
197
+
198
+ test('H3: workspace defaults to undefined', () => {
199
+ const result = parseRunArgs(['prompt']);
200
+ expect(result.workspace).toBeUndefined();
201
+ });
202
+
203
+ test('H3: parses --namespace <k8s-namespace>', () => {
204
+ const result = parseRunArgs(['--namespace', 'prod', 'list pods']);
205
+ expect(result.namespace).toBe('prod');
206
+ expect(result.prompt).toBe('list pods');
207
+ });
208
+
209
+ test('H3: parses -n as short form for --namespace', () => {
210
+ const result = parseRunArgs(['-n', 'kube-system', 'get pods']);
211
+ expect(result.namespace).toBe('kube-system');
212
+ expect(result.prompt).toBe('get pods');
213
+ });
214
+
215
+ test('H3: namespace defaults to undefined', () => {
216
+ const result = parseRunArgs(['prompt']);
217
+ expect(result.namespace).toBeUndefined();
218
+ });
219
+
220
+ test('H3: parses --notify <url>', () => {
221
+ const result = parseRunArgs(['--notify', 'https://hooks.example.com/notify', 'do work']);
222
+ expect(result.notify).toBe('https://hooks.example.com/notify');
223
+ expect(result.prompt).toBe('do work');
224
+ });
225
+
226
+ test('H3: parses --notify-slack <url>', () => {
227
+ const result = parseRunArgs(['--notify-slack', 'https://hooks.slack.com/T123/B456', 'deploy']);
228
+ expect(result.notifySlack).toBe('https://hooks.slack.com/T123/B456');
229
+ expect(result.prompt).toBe('deploy');
230
+ });
231
+
232
+ test('H3: all CI/CD flags combined', () => {
233
+ const result = parseRunArgs([
234
+ '--exit-code-on-error',
235
+ '--context', 'staging-cluster',
236
+ '--workspace', 'staging',
237
+ '--namespace', 'staging',
238
+ '--notify', 'https://example.com/webhook',
239
+ '--notify-slack', 'https://hooks.slack.com/abc',
240
+ 'run deployment',
241
+ ]);
242
+ expect(result.exitOnError).toBe(true);
243
+ expect(result.context).toBe('staging-cluster');
244
+ expect(result.workspace).toBe('staging');
245
+ expect(result.namespace).toBe('staging');
246
+ expect(result.notify).toBe('https://example.com/webhook');
247
+ expect(result.notifySlack).toBe('https://hooks.slack.com/abc');
248
+ expect(result.prompt).toBe('run deployment');
249
+ });
250
+
251
+ test('H3: --context sets KUBECTL_CONTEXT env var when executeRun processes it', () => {
252
+ // Test that parseRunArgs properly captures context for env injection
253
+ const result = parseRunArgs(['--context', 'my-context', 'test prompt']);
254
+ expect(result.context).toBe('my-context');
255
+ // The env var injection happens in executeRun; we test parseRunArgs captures it correctly
256
+ });
257
+ });
258
+
259
+ // ---------------------------------------------------------------------------
260
+ // L2: planSummary in JSON output
261
+ // ---------------------------------------------------------------------------
262
+
263
+ describe('planSummary in RunJsonOutput (L2)', () => {
264
+ it('RunJsonOutput interface has planSummary field', async () => {
265
+ const { readFileSync } = await import('node:fs');
266
+ const { join } = await import('node:path');
267
+ const src = readFileSync(join(process.cwd(), 'src/cli/run.ts'), 'utf-8');
268
+ expect(src).toContain('planSummary');
269
+ });
270
+
271
+ it('planSummary regex matches terraform plan output', () => {
272
+ const planOutput = 'Plan: 3 to add, 1 to change, 0 to destroy.';
273
+ const planLine = planOutput.match(/Plan:\s*(\d+)\s*to add,\s*(\d+)\s*to change,\s*(\d+)\s*to destroy/i);
274
+ expect(planLine).not.toBeNull();
275
+ expect(parseInt(planLine![1])).toBe(3);
276
+ expect(parseInt(planLine![2])).toBe(1);
277
+ expect(parseInt(planLine![3])).toBe(0);
278
+ });
279
+
280
+ it('planSummary regex works with large numbers', () => {
281
+ const planOutput = 'Plan: 150 to add, 42 to change, 7 to destroy.';
282
+ const planLine = planOutput.match(/Plan:\s*(\d+)\s*to add,\s*(\d+)\s*to change,\s*(\d+)\s*to destroy/i);
283
+ expect(planLine).not.toBeNull();
284
+ expect(parseInt(planLine![1])).toBe(150);
285
+ expect(parseInt(planLine![2])).toBe(42);
286
+ expect(parseInt(planLine![3])).toBe(7);
287
+ });
288
+ });
289
+
290
+ // ===========================================================================
291
+ // C2: No staleness check in bin/nimbus.mjs
292
+ // ===========================================================================
293
+
294
+ describe('C2 — bin/nimbus.mjs startup optimizations', () => {
295
+ it('bin/nimbus.mjs does not import statSync', async () => {
296
+ const { readFileSync } = await import('node:fs');
297
+ const { join } = await import('node:path');
298
+ const src = readFileSync(join(process.cwd(), 'bin/nimbus.mjs'), 'utf-8');
299
+ expect(src).not.toContain('statSync');
300
+ });
301
+
302
+ it('bin/nimbus.mjs uses simple existsSync check for dist entry', async () => {
303
+ const { readFileSync } = await import('node:fs');
304
+ const { join } = await import('node:path');
305
+ const src = readFileSync(join(process.cwd(), 'bin/nimbus.mjs'), 'utf-8');
306
+ expect(src).toContain('existsSync(DIST_ENTRY)');
307
+ });
308
+ });
309
+
310
+ // ===========================================================================
311
+ // H5: nimbus whoami wiring
312
+ // ===========================================================================
313
+
314
+ describe('H5 — nimbus whoami command', () => {
315
+ it('cli.ts contains whoami handler', async () => {
316
+ const { readFileSync } = await import('node:fs');
317
+ const { join } = await import('node:path');
318
+ const src = readFileSync(join(process.cwd(), 'src/cli.ts'), 'utf-8');
319
+ expect(src).toContain("command === 'whoami'");
320
+ });
321
+
322
+ it('cli.ts whoami calls authStatusCommand', async () => {
323
+ const { readFileSync } = await import('node:fs');
324
+ const { join } = await import('node:path');
325
+ const src = readFileSync(join(process.cwd(), 'src/cli.ts'), 'utf-8');
326
+ // whoami section should call authStatusCommand
327
+ const whoamiIdx = src.indexOf("command === 'whoami'");
328
+ const authStatusIdx = src.indexOf('authStatusCommand({})', whoamiIdx);
329
+ expect(authStatusIdx).toBeGreaterThan(whoamiIdx);
330
+ });
331
+ });
332
+
333
+ // ===========================================================================
334
+ // M1: nimbus diff top-level alias
335
+ // ===========================================================================
336
+
337
+ describe('M1 — nimbus diff alias', () => {
338
+ it('cli.ts contains diff command handler', async () => {
339
+ const { readFileSync } = await import('node:fs');
340
+ const { join } = await import('node:path');
341
+ const src = readFileSync(join(process.cwd(), 'src/cli.ts'), 'utf-8');
342
+ expect(src).toContain("command === 'diff'");
343
+ });
344
+
345
+ it('cli.ts diff calls fsCommand with "diff" subcommand', async () => {
346
+ const { readFileSync } = await import('node:fs');
347
+ const { join } = await import('node:path');
348
+ const src = readFileSync(join(process.cwd(), 'src/cli.ts'), 'utf-8');
349
+ expect(src).toContain("fsCommand('diff', args.slice(1))");
350
+ });
115
351
  });
@@ -0,0 +1,68 @@
1
+ /**
2
+ * SQLite Compat Layer Tests — G1
3
+ *
4
+ * Validates that the sqlite compat module:
5
+ * - Has proper fallback entries in package.json optionalDependencies
6
+ * - Contains sql.js fallback code
7
+ * - Contains the in-memory warning text
8
+ */
9
+
10
+ import { describe, it, expect } from 'vitest';
11
+ import { readFileSync } from 'node:fs';
12
+ import { join } from 'node:path';
13
+
14
+ const ROOT = join(__dirname, '..', '..');
15
+
16
+ describe('package.json SQLite compat configuration (G1)', () => {
17
+ const pkg = JSON.parse(readFileSync(join(ROOT, 'package.json'), 'utf-8')) as {
18
+ scripts?: Record<string, string>;
19
+ optionalDependencies?: Record<string, string>;
20
+ dependencies?: Record<string, string>;
21
+ };
22
+
23
+ it('has better-sqlite3 in optionalDependencies', () => {
24
+ expect(pkg.optionalDependencies).toBeDefined();
25
+ expect(Object.keys(pkg.optionalDependencies!)).toContain('better-sqlite3');
26
+ });
27
+
28
+ it('has sql.js in optionalDependencies', () => {
29
+ expect(pkg.optionalDependencies).toBeDefined();
30
+ expect(Object.keys(pkg.optionalDependencies!)).toContain('sql.js');
31
+ });
32
+
33
+ it('has a prepack script defined', () => {
34
+ expect(pkg.scripts).toBeDefined();
35
+ expect(pkg.scripts!['prepack']).toBeDefined();
36
+ expect(typeof pkg.scripts!['prepack']).toBe('string');
37
+ });
38
+ });
39
+
40
+ describe('src/compat/sqlite.ts fallback implementation (G1)', () => {
41
+ const sqliteSrc = readFileSync(join(ROOT, 'src', 'compat', 'sqlite.ts'), 'utf-8');
42
+
43
+ it('contains the sql.js fallback require call', () => {
44
+ expect(sqliteSrc).toContain('sql.js');
45
+ });
46
+
47
+ it('contains the in-memory warning text', () => {
48
+ expect(sqliteSrc).toContain('in-memory');
49
+ });
50
+
51
+ it('contains the better-sqlite3 require call', () => {
52
+ expect(sqliteSrc).toContain('better-sqlite3');
53
+ });
54
+
55
+ it('defines a SqlJsDatabase class for the fallback path', () => {
56
+ expect(sqliteSrc).toContain('SqlJsDatabase');
57
+ });
58
+
59
+ it('exports exec, prepare, and close methods in SqlJsDatabase', () => {
60
+ expect(sqliteSrc).toContain('exec(sql');
61
+ expect(sqliteSrc).toContain('prepare(sql');
62
+ expect(sqliteSrc).toContain('close()');
63
+ });
64
+
65
+ it('contains install hint for better-sqlite3', () => {
66
+ expect(sqliteSrc).toContain('npm install better-sqlite3');
67
+ });
68
+ });