@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,663 @@
1
+ /**
2
+ * GitHub CLI Commands
3
+ *
4
+ * CLI commands for interacting with GitHub via the GitHub Tools Service
5
+ */
6
+ import { spawn } from 'node:child_process';
7
+ import { githubClient } from '../../clients/github-client';
8
+ import { ui } from '../../wizard/ui';
9
+ /**
10
+ * Parse owner/repo from git remote or arguments
11
+ */
12
+ async function getOwnerRepo(options) {
13
+ if (options.owner && options.repo) {
14
+ return { owner: options.owner, repo: options.repo };
15
+ }
16
+ // Try to get from git remote
17
+ try {
18
+ const output = await new Promise((resolve, reject) => {
19
+ const proc = spawn('git', ['remote', 'get-url', 'origin'], {
20
+ stdio: ['ignore', 'pipe', 'pipe'],
21
+ });
22
+ let out = '';
23
+ proc.stdout?.on('data', (data) => {
24
+ out += data.toString();
25
+ });
26
+ proc.on('close', () => resolve(out));
27
+ proc.on('error', reject);
28
+ });
29
+ const match = output.match(/github\.com[:/]([^/]+)\/([^/.]+)/);
30
+ if (match) {
31
+ return { owner: match[1], repo: match[2] };
32
+ }
33
+ }
34
+ catch {
35
+ // Ignore git errors
36
+ }
37
+ ui.error('Could not determine repository. Use --owner and --repo options.');
38
+ return null;
39
+ }
40
+ /**
41
+ * Format a date for display
42
+ */
43
+ function formatDate(dateStr) {
44
+ const date = new Date(dateStr);
45
+ return date.toLocaleDateString('en-US', {
46
+ month: 'short',
47
+ day: 'numeric',
48
+ year: 'numeric',
49
+ });
50
+ }
51
+ /**
52
+ * List pull requests
53
+ */
54
+ export async function ghPrListCommand(options = {}) {
55
+ const ownerRepo = await getOwnerRepo(options);
56
+ if (!ownerRepo) {
57
+ return;
58
+ }
59
+ ui.startSpinner({ message: 'Fetching pull requests...' });
60
+ const result = await githubClient.listPRs(ownerRepo.owner, ownerRepo.repo, {
61
+ state: options.state || 'open',
62
+ perPage: options.limit || 10,
63
+ });
64
+ if (!result.success || !result.data) {
65
+ ui.stopSpinnerFail('Failed to fetch pull requests');
66
+ ui.error(result.error || 'Failed to fetch pull requests');
67
+ return;
68
+ }
69
+ ui.stopSpinnerSuccess('Fetched pull requests');
70
+ if (options.json) {
71
+ console.log(JSON.stringify(result.data, null, 2));
72
+ return;
73
+ }
74
+ if (result.data.length === 0) {
75
+ ui.info('No pull requests found');
76
+ return;
77
+ }
78
+ ui.header(`Pull Requests - ${ownerRepo.owner}/${ownerRepo.repo}`);
79
+ ui.table({
80
+ columns: [
81
+ { key: 'number', header: '#' },
82
+ { key: 'title', header: 'Title' },
83
+ { key: 'author', header: 'Author' },
84
+ { key: 'state', header: 'State' },
85
+ { key: 'updated', header: 'Updated' },
86
+ ],
87
+ data: result.data.map(pr => ({
88
+ number: `#${pr.number}`,
89
+ title: pr.title.substring(0, 50) + (pr.title.length > 50 ? '...' : ''),
90
+ author: pr.user.login,
91
+ state: pr.draft
92
+ ? ui.color('draft', 'gray')
93
+ : pr.state === 'open'
94
+ ? ui.color('open', 'green')
95
+ : ui.color('closed', 'red'),
96
+ updated: formatDate(pr.updated_at),
97
+ })),
98
+ });
99
+ }
100
+ /**
101
+ * View a single pull request
102
+ */
103
+ export async function ghPrViewCommand(options) {
104
+ const ownerRepo = await getOwnerRepo(options);
105
+ if (!ownerRepo) {
106
+ return;
107
+ }
108
+ ui.startSpinner({ message: `Fetching PR #${options.prNumber}...` });
109
+ const result = await githubClient.getPR(ownerRepo.owner, ownerRepo.repo, options.prNumber);
110
+ if (!result.success || !result.data) {
111
+ ui.stopSpinnerFail('Failed to fetch pull request');
112
+ ui.error(result.error || 'Failed to fetch pull request');
113
+ return;
114
+ }
115
+ ui.stopSpinnerSuccess('Fetched pull request');
116
+ const pr = result.data;
117
+ if (options.json) {
118
+ console.log(JSON.stringify(pr, null, 2));
119
+ return;
120
+ }
121
+ ui.header(`PR #${pr.number}: ${pr.title}`);
122
+ ui.newLine();
123
+ ui.info(`Author: ${pr.user.login}`);
124
+ ui.info(`State: ${pr.state}${pr.draft ? ' (draft)' : ''}`);
125
+ ui.info(`Branch: ${pr.head.ref} → ${pr.base.ref}`);
126
+ ui.info(`Created: ${formatDate(pr.created_at)}`);
127
+ ui.info(`Updated: ${formatDate(pr.updated_at)}`);
128
+ if (pr.labels.length > 0) {
129
+ ui.info(`Labels: ${pr.labels.map(l => l.name).join(', ')}`);
130
+ }
131
+ if (pr.body) {
132
+ ui.newLine();
133
+ ui.box({ title: 'Description', content: pr.body });
134
+ }
135
+ }
136
+ /**
137
+ * Create a pull request
138
+ */
139
+ export async function ghPrCreateCommand(options) {
140
+ const ownerRepo = await getOwnerRepo(options);
141
+ if (!ownerRepo) {
142
+ return;
143
+ }
144
+ // Get current branch if head not specified
145
+ let head = options.head;
146
+ if (!head) {
147
+ try {
148
+ const branchOutput = await new Promise((resolve, reject) => {
149
+ const proc = spawn('git', ['branch', '--show-current'], {
150
+ stdio: ['ignore', 'pipe', 'pipe'],
151
+ });
152
+ let out = '';
153
+ proc.stdout?.on('data', (data) => {
154
+ out += data.toString();
155
+ });
156
+ proc.on('close', () => resolve(out));
157
+ proc.on('error', reject);
158
+ });
159
+ head = branchOutput.trim();
160
+ }
161
+ catch {
162
+ ui.error('Could not determine current branch. Use --head option.');
163
+ return;
164
+ }
165
+ }
166
+ ui.startSpinner({ message: 'Creating pull request...' });
167
+ const result = await githubClient.createPR(ownerRepo.owner, ownerRepo.repo, {
168
+ title: options.title,
169
+ head,
170
+ base: options.base || 'main',
171
+ body: options.body,
172
+ draft: options.draft,
173
+ });
174
+ if (!result.success || !result.data) {
175
+ ui.stopSpinnerFail('Failed to create pull request');
176
+ ui.error(result.error || 'Failed to create pull request');
177
+ return;
178
+ }
179
+ ui.stopSpinnerSuccess('Created pull request');
180
+ ui.success(`Created PR #${result.data.number}: ${result.data.title}`);
181
+ }
182
+ /**
183
+ * Merge a pull request
184
+ */
185
+ export async function ghPrMergeCommand(options) {
186
+ const ownerRepo = await getOwnerRepo(options);
187
+ if (!ownerRepo) {
188
+ return;
189
+ }
190
+ ui.startSpinner({ message: `Merging PR #${options.prNumber}...` });
191
+ const result = await githubClient.mergePR(ownerRepo.owner, ownerRepo.repo, options.prNumber, {
192
+ mergeMethod: options.method,
193
+ commitTitle: options.commitTitle,
194
+ });
195
+ if (!result.success || !result.data) {
196
+ ui.stopSpinnerFail('Failed to merge pull request');
197
+ ui.error(result.error || 'Failed to merge pull request');
198
+ return;
199
+ }
200
+ ui.stopSpinnerSuccess('Merged pull request');
201
+ ui.success(result.data.message);
202
+ }
203
+ /**
204
+ * Review a pull request
205
+ */
206
+ export async function ghPrReviewCommand(options) {
207
+ const ownerRepo = await getOwnerRepo(options);
208
+ if (!ownerRepo) {
209
+ return;
210
+ }
211
+ ui.startSpinner({ message: `Reviewing PR #${options.prNumber}...` });
212
+ const result = await githubClient.createPRReview(ownerRepo.owner, ownerRepo.repo, options.prNumber, options.event, options.body);
213
+ if (!result.success || !result.data) {
214
+ ui.stopSpinnerFail('Failed to review pull request');
215
+ ui.error(result.error || 'Failed to review pull request');
216
+ return;
217
+ }
218
+ ui.stopSpinnerSuccess('Review submitted');
219
+ ui.success(`Review submitted on PR #${options.prNumber}: ${options.event}`);
220
+ }
221
+ /**
222
+ * List issues
223
+ */
224
+ export async function ghIssueListCommand(options = {}) {
225
+ const ownerRepo = await getOwnerRepo(options);
226
+ if (!ownerRepo) {
227
+ return;
228
+ }
229
+ ui.startSpinner({ message: 'Fetching issues...' });
230
+ const result = await githubClient.listIssues(ownerRepo.owner, ownerRepo.repo, {
231
+ state: options.state || 'open',
232
+ perPage: options.limit || 10,
233
+ });
234
+ if (!result.success || !result.data) {
235
+ ui.stopSpinnerFail('Failed to fetch issues');
236
+ ui.error(result.error || 'Failed to fetch issues');
237
+ return;
238
+ }
239
+ ui.stopSpinnerSuccess('Fetched issues');
240
+ if (options.json) {
241
+ console.log(JSON.stringify(result.data, null, 2));
242
+ return;
243
+ }
244
+ if (result.data.length === 0) {
245
+ ui.info('No issues found');
246
+ return;
247
+ }
248
+ ui.header(`Issues - ${ownerRepo.owner}/${ownerRepo.repo}`);
249
+ ui.table({
250
+ columns: [
251
+ { key: 'number', header: '#' },
252
+ { key: 'title', header: 'Title' },
253
+ { key: 'author', header: 'Author' },
254
+ { key: 'state', header: 'State' },
255
+ { key: 'comments', header: 'Comments' },
256
+ { key: 'updated', header: 'Updated' },
257
+ ],
258
+ data: result.data.map(issue => ({
259
+ number: `#${issue.number}`,
260
+ title: issue.title.substring(0, 40) + (issue.title.length > 40 ? '...' : ''),
261
+ author: issue.user.login,
262
+ state: issue.state === 'open' ? ui.color('open', 'green') : ui.color('closed', 'red'),
263
+ comments: String(issue.comments),
264
+ updated: formatDate(issue.updated_at),
265
+ })),
266
+ });
267
+ }
268
+ /**
269
+ * View a single issue
270
+ */
271
+ export async function ghIssueViewCommand(options) {
272
+ const ownerRepo = await getOwnerRepo(options);
273
+ if (!ownerRepo) {
274
+ return;
275
+ }
276
+ ui.startSpinner({ message: `Fetching issue #${options.issueNumber}...` });
277
+ const result = await githubClient.getIssue(ownerRepo.owner, ownerRepo.repo, options.issueNumber);
278
+ if (!result.success || !result.data) {
279
+ ui.stopSpinnerFail('Failed to fetch issue');
280
+ ui.error(result.error || 'Failed to fetch issue');
281
+ return;
282
+ }
283
+ ui.stopSpinnerSuccess('Fetched issue');
284
+ const issue = result.data;
285
+ if (options.json) {
286
+ console.log(JSON.stringify(issue, null, 2));
287
+ return;
288
+ }
289
+ ui.header(`Issue #${issue.number}: ${issue.title}`);
290
+ ui.newLine();
291
+ ui.info(`Author: ${issue.user.login}`);
292
+ ui.info(`State: ${issue.state}`);
293
+ ui.info(`Comments: ${issue.comments}`);
294
+ ui.info(`Created: ${formatDate(issue.created_at)}`);
295
+ ui.info(`Updated: ${formatDate(issue.updated_at)}`);
296
+ if (issue.labels.length > 0) {
297
+ ui.info(`Labels: ${issue.labels.map(l => l.name).join(', ')}`);
298
+ }
299
+ if (issue.body) {
300
+ ui.newLine();
301
+ ui.box({ title: 'Description', content: issue.body });
302
+ }
303
+ }
304
+ /**
305
+ * Create an issue
306
+ */
307
+ export async function ghIssueCreateCommand(options) {
308
+ const ownerRepo = await getOwnerRepo(options);
309
+ if (!ownerRepo) {
310
+ return;
311
+ }
312
+ ui.startSpinner({ message: 'Creating issue...' });
313
+ const result = await githubClient.createIssue(ownerRepo.owner, ownerRepo.repo, {
314
+ title: options.title,
315
+ body: options.body,
316
+ labels: options.labels,
317
+ assignees: options.assignees,
318
+ });
319
+ if (!result.success || !result.data) {
320
+ ui.stopSpinnerFail('Failed to create issue');
321
+ ui.error(result.error || 'Failed to create issue');
322
+ return;
323
+ }
324
+ ui.stopSpinnerSuccess('Created issue');
325
+ ui.success(`Created issue #${result.data.number}: ${result.data.title}`);
326
+ }
327
+ /**
328
+ * Close an issue
329
+ */
330
+ export async function ghIssueCloseCommand(options) {
331
+ const ownerRepo = await getOwnerRepo(options);
332
+ if (!ownerRepo) {
333
+ return;
334
+ }
335
+ ui.startSpinner({ message: `Closing issue #${options.issueNumber}...` });
336
+ const result = await githubClient.closeIssue(ownerRepo.owner, ownerRepo.repo, options.issueNumber);
337
+ if (!result.success || !result.data) {
338
+ ui.stopSpinnerFail('Failed to close issue');
339
+ ui.error(result.error || 'Failed to close issue');
340
+ return;
341
+ }
342
+ ui.stopSpinnerSuccess('Closed issue');
343
+ ui.success(`Closed issue #${options.issueNumber}`);
344
+ }
345
+ /**
346
+ * Add a comment to an issue
347
+ */
348
+ export async function ghIssueCommentCommand(options) {
349
+ const ownerRepo = await getOwnerRepo(options);
350
+ if (!ownerRepo) {
351
+ return;
352
+ }
353
+ ui.startSpinner({ message: 'Adding comment...' });
354
+ const result = await githubClient.addComment(ownerRepo.owner, ownerRepo.repo, options.issueNumber, options.body);
355
+ if (!result.success || !result.data) {
356
+ ui.stopSpinnerFail('Failed to add comment');
357
+ ui.error(result.error || 'Failed to add comment');
358
+ return;
359
+ }
360
+ ui.stopSpinnerSuccess('Added comment');
361
+ ui.success('Comment added');
362
+ }
363
+ /**
364
+ * Get repository info
365
+ */
366
+ export async function ghRepoInfoCommand(options = {}) {
367
+ const ownerRepo = await getOwnerRepo(options);
368
+ if (!ownerRepo) {
369
+ return;
370
+ }
371
+ ui.startSpinner({ message: 'Fetching repository info...' });
372
+ const result = await githubClient.getRepo(ownerRepo.owner, ownerRepo.repo);
373
+ if (!result.success || !result.data) {
374
+ ui.stopSpinnerFail('Failed to fetch repository info');
375
+ ui.error(result.error || 'Failed to fetch repository info');
376
+ return;
377
+ }
378
+ ui.stopSpinnerSuccess('Fetched repository info');
379
+ const repo = result.data;
380
+ if (options.json) {
381
+ console.log(JSON.stringify(repo, null, 2));
382
+ return;
383
+ }
384
+ ui.header(repo.full_name);
385
+ ui.newLine();
386
+ if (repo.description) {
387
+ ui.info(repo.description);
388
+ ui.newLine();
389
+ }
390
+ ui.info(`Visibility: ${repo.private ? 'Private' : 'Public'}`);
391
+ ui.info(`Default Branch: ${repo.default_branch}`);
392
+ if (repo.language) {
393
+ ui.info(`Language: ${repo.language}`);
394
+ }
395
+ ui.info(`Stars: ${repo.stargazers_count}`);
396
+ ui.info(`Forks: ${repo.forks_count}`);
397
+ ui.info(`Open Issues: ${repo.open_issues_count}`);
398
+ }
399
+ /**
400
+ * List repository branches
401
+ */
402
+ export async function ghRepoBranchesCommand(options = {}) {
403
+ const ownerRepo = await getOwnerRepo(options);
404
+ if (!ownerRepo) {
405
+ return;
406
+ }
407
+ ui.startSpinner({ message: 'Fetching branches...' });
408
+ const result = await githubClient.listBranches(ownerRepo.owner, ownerRepo.repo, {
409
+ perPage: options.limit || 20,
410
+ });
411
+ if (!result.success || !result.data) {
412
+ ui.stopSpinnerFail('Failed to fetch branches');
413
+ ui.error(result.error || 'Failed to fetch branches');
414
+ return;
415
+ }
416
+ ui.stopSpinnerSuccess('Fetched branches');
417
+ if (options.json) {
418
+ console.log(JSON.stringify(result.data, null, 2));
419
+ return;
420
+ }
421
+ if (result.data.length === 0) {
422
+ ui.info('No branches found');
423
+ return;
424
+ }
425
+ ui.header(`Branches - ${ownerRepo.owner}/${ownerRepo.repo}`);
426
+ ui.table({
427
+ columns: [
428
+ { key: 'name', header: 'Name' },
429
+ { key: 'sha', header: 'SHA' },
430
+ { key: 'protected', header: 'Protected' },
431
+ ],
432
+ data: result.data.map(branch => ({
433
+ name: branch.name,
434
+ sha: branch.commit.sha.substring(0, 7),
435
+ protected: branch.protected ? ui.color('yes', 'yellow') : 'no',
436
+ })),
437
+ });
438
+ }
439
+ // ==========================================
440
+ // Main Router
441
+ // ==========================================
442
+ /**
443
+ * Main gh command router
444
+ */
445
+ export async function ghCommand(subcommand, args) {
446
+ // Parse common options
447
+ const options = {};
448
+ const cleanArgs = [];
449
+ for (let i = 0; i < args.length; i++) {
450
+ const arg = args[i];
451
+ if (arg === '--owner' && args[i + 1]) {
452
+ options.owner = args[++i];
453
+ }
454
+ else if (arg === '--repo' && args[i + 1]) {
455
+ options.repo = args[++i];
456
+ }
457
+ else if (arg === '--json') {
458
+ options.json = true;
459
+ }
460
+ else {
461
+ cleanArgs.push(arg);
462
+ }
463
+ }
464
+ // PR commands
465
+ if (subcommand === 'pr') {
466
+ const prSubcommand = cleanArgs[0];
467
+ if (prSubcommand === 'list' || !prSubcommand) {
468
+ const prOptions = { ...options };
469
+ for (let i = 1; i < cleanArgs.length; i++) {
470
+ if (cleanArgs[i] === '--state' && cleanArgs[i + 1]) {
471
+ prOptions.state = cleanArgs[++i];
472
+ }
473
+ else if ((cleanArgs[i] === '--limit' || cleanArgs[i] === '-n') && cleanArgs[i + 1]) {
474
+ prOptions.limit = parseInt(cleanArgs[++i], 10);
475
+ }
476
+ }
477
+ await ghPrListCommand(prOptions);
478
+ return;
479
+ }
480
+ if (prSubcommand === 'view') {
481
+ const prNumber = parseInt(cleanArgs[1], 10);
482
+ if (isNaN(prNumber)) {
483
+ ui.error('Usage: nimbus gh pr view <number>');
484
+ return;
485
+ }
486
+ await ghPrViewCommand({ ...options, prNumber });
487
+ return;
488
+ }
489
+ if (prSubcommand === 'create') {
490
+ const prOptions = { ...options, title: '' };
491
+ for (let i = 1; i < cleanArgs.length; i++) {
492
+ if ((cleanArgs[i] === '--title' || cleanArgs[i] === '-t') && cleanArgs[i + 1]) {
493
+ prOptions.title = cleanArgs[++i];
494
+ }
495
+ else if ((cleanArgs[i] === '--body' || cleanArgs[i] === '-b') && cleanArgs[i + 1]) {
496
+ prOptions.body = cleanArgs[++i];
497
+ }
498
+ else if (cleanArgs[i] === '--head' && cleanArgs[i + 1]) {
499
+ prOptions.head = cleanArgs[++i];
500
+ }
501
+ else if (cleanArgs[i] === '--base' && cleanArgs[i + 1]) {
502
+ prOptions.base = cleanArgs[++i];
503
+ }
504
+ else if (cleanArgs[i] === '--draft') {
505
+ prOptions.draft = true;
506
+ }
507
+ }
508
+ if (!prOptions.title) {
509
+ ui.error('Usage: nimbus gh pr create --title "PR Title" [--body "Description"] [--draft]');
510
+ return;
511
+ }
512
+ await ghPrCreateCommand(prOptions);
513
+ return;
514
+ }
515
+ if (prSubcommand === 'merge') {
516
+ const prNumber = parseInt(cleanArgs[1], 10);
517
+ if (isNaN(prNumber)) {
518
+ ui.error('Usage: nimbus gh pr merge <number> [--method squash|merge|rebase]');
519
+ return;
520
+ }
521
+ const mergeOptions = { ...options, prNumber };
522
+ for (let i = 2; i < cleanArgs.length; i++) {
523
+ if (cleanArgs[i] === '--method' && cleanArgs[i + 1]) {
524
+ mergeOptions.method = cleanArgs[++i];
525
+ }
526
+ }
527
+ await ghPrMergeCommand(mergeOptions);
528
+ return;
529
+ }
530
+ if (prSubcommand === 'review') {
531
+ const prNumber = parseInt(cleanArgs[1], 10);
532
+ if (isNaN(prNumber)) {
533
+ ui.error('Usage: nimbus gh pr review <number> --event APPROVE|REQUEST_CHANGES|COMMENT [--body "..."]');
534
+ return;
535
+ }
536
+ const reviewOptions = { ...options, prNumber, event: 'COMMENT' };
537
+ for (let i = 2; i < cleanArgs.length; i++) {
538
+ if (cleanArgs[i] === '--event' && cleanArgs[i + 1]) {
539
+ reviewOptions.event = cleanArgs[++i];
540
+ }
541
+ else if ((cleanArgs[i] === '--body' || cleanArgs[i] === '-b') && cleanArgs[i + 1]) {
542
+ reviewOptions.body = cleanArgs[++i];
543
+ }
544
+ }
545
+ await ghPrReviewCommand(reviewOptions);
546
+ return;
547
+ }
548
+ ui.error(`Unknown pr subcommand: ${prSubcommand}`);
549
+ return;
550
+ }
551
+ // Issue commands
552
+ if (subcommand === 'issue') {
553
+ const issueSubcommand = cleanArgs[0];
554
+ if (issueSubcommand === 'list' || !issueSubcommand) {
555
+ const issueOptions = { ...options };
556
+ for (let i = 1; i < cleanArgs.length; i++) {
557
+ if (cleanArgs[i] === '--state' && cleanArgs[i + 1]) {
558
+ issueOptions.state = cleanArgs[++i];
559
+ }
560
+ else if ((cleanArgs[i] === '--limit' || cleanArgs[i] === '-n') && cleanArgs[i + 1]) {
561
+ issueOptions.limit = parseInt(cleanArgs[++i], 10);
562
+ }
563
+ }
564
+ await ghIssueListCommand(issueOptions);
565
+ return;
566
+ }
567
+ if (issueSubcommand === 'view') {
568
+ const issueNumber = parseInt(cleanArgs[1], 10);
569
+ if (isNaN(issueNumber)) {
570
+ ui.error('Usage: nimbus gh issue view <number>');
571
+ return;
572
+ }
573
+ await ghIssueViewCommand({ ...options, issueNumber });
574
+ return;
575
+ }
576
+ if (issueSubcommand === 'create') {
577
+ const issueOptions = { ...options, title: '' };
578
+ for (let i = 1; i < cleanArgs.length; i++) {
579
+ if ((cleanArgs[i] === '--title' || cleanArgs[i] === '-t') && cleanArgs[i + 1]) {
580
+ issueOptions.title = cleanArgs[++i];
581
+ }
582
+ else if ((cleanArgs[i] === '--body' || cleanArgs[i] === '-b') && cleanArgs[i + 1]) {
583
+ issueOptions.body = cleanArgs[++i];
584
+ }
585
+ else if (cleanArgs[i] === '--label' && cleanArgs[i + 1]) {
586
+ issueOptions.labels = issueOptions.labels || [];
587
+ issueOptions.labels.push(cleanArgs[++i]);
588
+ }
589
+ else if (cleanArgs[i] === '--assignee' && cleanArgs[i + 1]) {
590
+ issueOptions.assignees = issueOptions.assignees || [];
591
+ issueOptions.assignees.push(cleanArgs[++i]);
592
+ }
593
+ }
594
+ if (!issueOptions.title) {
595
+ ui.error('Usage: nimbus gh issue create --title "Issue Title" [--body "Description"]');
596
+ return;
597
+ }
598
+ await ghIssueCreateCommand(issueOptions);
599
+ return;
600
+ }
601
+ if (issueSubcommand === 'close') {
602
+ const issueNumber = parseInt(cleanArgs[1], 10);
603
+ if (isNaN(issueNumber)) {
604
+ ui.error('Usage: nimbus gh issue close <number>');
605
+ return;
606
+ }
607
+ await ghIssueCloseCommand({ ...options, issueNumber });
608
+ return;
609
+ }
610
+ if (issueSubcommand === 'comment') {
611
+ const issueNumber = parseInt(cleanArgs[1], 10);
612
+ let body = '';
613
+ for (let i = 2; i < cleanArgs.length; i++) {
614
+ if ((cleanArgs[i] === '--body' || cleanArgs[i] === '-b') && cleanArgs[i + 1]) {
615
+ body = cleanArgs[++i];
616
+ }
617
+ }
618
+ if (isNaN(issueNumber) || !body) {
619
+ ui.error('Usage: nimbus gh issue comment <number> --body "Comment text"');
620
+ return;
621
+ }
622
+ await ghIssueCommentCommand({ ...options, issueNumber, body });
623
+ return;
624
+ }
625
+ ui.error(`Unknown issue subcommand: ${issueSubcommand}`);
626
+ return;
627
+ }
628
+ // Repo commands
629
+ if (subcommand === 'repo') {
630
+ const repoSubcommand = cleanArgs[0];
631
+ if (repoSubcommand === 'info' || !repoSubcommand) {
632
+ await ghRepoInfoCommand(options);
633
+ return;
634
+ }
635
+ if (repoSubcommand === 'branches') {
636
+ const branchOptions = { ...options };
637
+ for (let i = 1; i < cleanArgs.length; i++) {
638
+ if ((cleanArgs[i] === '--limit' || cleanArgs[i] === '-n') && cleanArgs[i + 1]) {
639
+ branchOptions.limit = parseInt(cleanArgs[++i], 10);
640
+ }
641
+ }
642
+ await ghRepoBranchesCommand(branchOptions);
643
+ return;
644
+ }
645
+ ui.error(`Unknown repo subcommand: ${repoSubcommand}`);
646
+ return;
647
+ }
648
+ ui.error(`Unknown gh subcommand: ${subcommand}`);
649
+ console.log('');
650
+ console.log('Available subcommands:');
651
+ console.log(' pr list - List pull requests');
652
+ console.log(' pr view <number> - View a pull request');
653
+ console.log(' pr create - Create a pull request');
654
+ console.log(' pr merge <number> - Merge a pull request');
655
+ console.log(' pr review <number> - Review a pull request');
656
+ console.log(' issue list - List issues');
657
+ console.log(' issue view <number> - View an issue');
658
+ console.log(' issue create - Create an issue');
659
+ console.log(' issue close <number> - Close an issue');
660
+ console.log(' issue comment <n> - Add a comment');
661
+ console.log(' repo info - Show repository info');
662
+ console.log(' repo branches - List branches');
663
+ }