infra-kit 0.1.114 → 0.1.117

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 (204) hide show
  1. package/.eslintcache +1 -1
  2. package/.omc/state/agent-replay-1fcfe0ec-7567-41c3-9bfd-501e99e86819.jsonl +19 -0
  3. package/.omc/state/agent-replay-38382db5-3088-4b5a-aff7-2561a60827c7.jsonl +17 -0
  4. package/.omc/state/agent-replay-50c36be9-a3a2-42b9-9c85-5a06d3e22f6a.jsonl +5 -0
  5. package/.omc/state/agent-replay-8198b3e5-fad6-4ee0-9c59-ef773ad89af4.jsonl +1 -0
  6. package/.omc/state/agent-replay-8cd7652a-b8b5-49cf-9b1f-bee8e5972458.jsonl +3 -0
  7. package/.omc/state/agent-replay-9bea518f-a9ee-4d14-bb53-a936ebaf647c.jsonl +7 -0
  8. package/.omc/state/agent-replay-b52d89fb-0e24-4901-bc66-27e3c1697126.jsonl +2 -0
  9. package/.omc/state/agent-replay-f581a1ae-0ee4-48a3-96f3-ce31a0633bb0.jsonl +1 -0
  10. package/.omc/state/agent-replay-fe1057b4-9a25-4e8e-8c3f-3e11652ee697.jsonl +5 -0
  11. package/.omc/state/idle-notif-cooldown.json +1 -1
  12. package/.omc/state/sessions/1fcfe0ec-7567-41c3-9bfd-501e99e86819/last-tool-error-state.json +7 -0
  13. package/.omc/state/sessions/1fcfe0ec-7567-41c3-9bfd-501e99e86819/mission-state.json +109 -0
  14. package/.omc/state/sessions/1fcfe0ec-7567-41c3-9bfd-501e99e86819/pre-tool-advisory-throttle.json +42 -0
  15. package/.omc/state/sessions/1fcfe0ec-7567-41c3-9bfd-501e99e86819/ralph-state.json +13 -0
  16. package/.omc/state/sessions/1fcfe0ec-7567-41c3-9bfd-501e99e86819/skill-active-state.json +15 -0
  17. package/.omc/state/sessions/1fcfe0ec-7567-41c3-9bfd-501e99e86819/subagent-tracking-state.json +62 -0
  18. package/.omc/state/sessions/1fcfe0ec-7567-41c3-9bfd-501e99e86819/ultrawork-state.json +11 -0
  19. package/.omc/state/sessions/23d0ff82-17e5-428b-8743-38f7979bb6f3/last-tool-error-state.json +7 -0
  20. package/.omc/state/sessions/23d0ff82-17e5-428b-8743-38f7979bb6f3/pre-tool-advisory-throttle.json +18 -0
  21. package/.omc/state/sessions/38382db5-3088-4b5a-aff7-2561a60827c7/last-tool-error-state.json +7 -0
  22. package/.omc/state/sessions/38382db5-3088-4b5a-aff7-2561a60827c7/mission-state.json +145 -0
  23. package/.omc/state/sessions/38382db5-3088-4b5a-aff7-2561a60827c7/pre-tool-advisory-throttle.json +38 -0
  24. package/.omc/state/sessions/38382db5-3088-4b5a-aff7-2561a60827c7/ralplan-state.json +11 -0
  25. package/.omc/state/sessions/38382db5-3088-4b5a-aff7-2561a60827c7/subagent-tracking-state.json +98 -0
  26. package/.omc/state/sessions/41336850-028c-476b-be1a-2164e1e46cac/last-tool-error-state.json +7 -0
  27. package/.omc/state/sessions/41336850-028c-476b-be1a-2164e1e46cac/pre-tool-advisory-throttle.json +18 -0
  28. package/.omc/state/sessions/50c36be9-a3a2-42b9-9c85-5a06d3e22f6a/mission-state.json +61 -0
  29. package/.omc/state/sessions/50c36be9-a3a2-42b9-9c85-5a06d3e22f6a/pre-tool-advisory-throttle.json +22 -0
  30. package/.omc/state/sessions/50c36be9-a3a2-42b9-9c85-5a06d3e22f6a/skill-active-state.json +15 -0
  31. package/.omc/state/sessions/50c36be9-a3a2-42b9-9c85-5a06d3e22f6a/subagent-tracking-state.json +26 -0
  32. package/{src/lib/.omc/state/sessions/a60ac2ec-afbd-449f-a540-6df287392fc2 → .omc/state/sessions/8198b3e5-fad6-4ee0-9c59-ef773ad89af4}/pre-tool-advisory-throttle.json +3 -3
  33. package/.omc/state/sessions/8198b3e5-fad6-4ee0-9c59-ef773ad89af4/subagent-tracking-state.json +17 -0
  34. package/.omc/state/sessions/8cd7652a-b8b5-49cf-9b1f-bee8e5972458/pre-tool-advisory-throttle.json +18 -0
  35. package/.omc/state/sessions/8cd7652a-b8b5-49cf-9b1f-bee8e5972458/ralplan-state.json +11 -0
  36. package/.omc/state/sessions/8cd7652a-b8b5-49cf-9b1f-bee8e5972458/subagent-tracking-state.json +35 -0
  37. package/.omc/state/sessions/9bea518f-a9ee-4d14-bb53-a936ebaf647c/last-tool-error-state.json +7 -0
  38. package/.omc/state/sessions/9bea518f-a9ee-4d14-bb53-a936ebaf647c/mission-state.json +79 -0
  39. package/.omc/state/sessions/9bea518f-a9ee-4d14-bb53-a936ebaf647c/pre-tool-advisory-throttle.json +22 -0
  40. package/.omc/state/sessions/9bea518f-a9ee-4d14-bb53-a936ebaf647c/progress.txt +7 -0
  41. package/.omc/state/sessions/9bea518f-a9ee-4d14-bb53-a936ebaf647c/skill-active-state.json +15 -0
  42. package/.omc/state/sessions/9bea518f-a9ee-4d14-bb53-a936ebaf647c/subagent-tracking-state.json +26 -0
  43. package/.omc/state/sessions/b52d89fb-0e24-4901-bc66-27e3c1697126/pre-tool-advisory-throttle.json +14 -0
  44. package/.omc/state/sessions/b52d89fb-0e24-4901-bc66-27e3c1697126/subagent-tracking-state.json +17 -0
  45. package/.omc/state/sessions/c513ef38-cc3e-4a29-9c4c-1e0137245dd5/pre-tool-advisory-throttle.json +18 -0
  46. package/.omc/state/sessions/ed3e2cfb-a666-4bb1-bcc1-569d5d0b837a/pre-tool-advisory-throttle.json +18 -0
  47. package/.omc/state/sessions/f581a1ae-0ee4-48a3-96f3-ce31a0633bb0/pre-tool-advisory-throttle.json +18 -0
  48. package/.omc/state/sessions/f581a1ae-0ee4-48a3-96f3-ce31a0633bb0/subagent-tracking-state.json +17 -0
  49. package/.omc/state/sessions/fe1057b4-9a25-4e8e-8c3f-3e11652ee697/last-tool-error-state.json +7 -0
  50. package/.omc/state/sessions/fe1057b4-9a25-4e8e-8c3f-3e11652ee697/mission-state.json +61 -0
  51. package/.omc/state/sessions/fe1057b4-9a25-4e8e-8c3f-3e11652ee697/prd.json +22 -0
  52. package/.omc/state/sessions/fe1057b4-9a25-4e8e-8c3f-3e11652ee697/pre-tool-advisory-throttle.json +22 -0
  53. package/.omc/state/sessions/fe1057b4-9a25-4e8e-8c3f-3e11652ee697/progress.txt +22 -0
  54. package/.omc/state/sessions/fe1057b4-9a25-4e8e-8c3f-3e11652ee697/skill-active-state.json +15 -0
  55. package/.omc/state/sessions/fe1057b4-9a25-4e8e-8c3f-3e11652ee697/subagent-tracking-state.json +26 -0
  56. package/.turbo/turbo-build.log +3 -3
  57. package/.turbo/turbo-eslint-check.log +2 -0
  58. package/.turbo/turbo-test.log +90 -42
  59. package/dist/boot-K4QUAFSP.js +2 -0
  60. package/dist/boot-K4QUAFSP.js.map +7 -0
  61. package/dist/chunk-FEGOOVZE.js +166 -0
  62. package/dist/chunk-FEGOOVZE.js.map +7 -0
  63. package/dist/chunk-WA4BQRDC.js +2 -0
  64. package/dist/chunk-WA4BQRDC.js.map +7 -0
  65. package/dist/cli.js +11 -107
  66. package/dist/cli.js.map +4 -4
  67. package/dist/entry/index.d.ts +2 -0
  68. package/dist/index.js +1 -1
  69. package/dist/index.js.map +4 -4
  70. package/dist/lib/vendor/config-schema.d.ts +58 -0
  71. package/dist/mcp.js +1 -54
  72. package/dist/mcp.js.map +4 -4
  73. package/eslint.config.js +33 -1
  74. package/package.json +5 -1
  75. package/scripts/build.js +11 -1
  76. package/src/.omc/state/agent-replay-c513ef38-cc3e-4a29-9c4c-1e0137245dd5.jsonl +4 -0
  77. package/src/.omc/state/agent-replay-ed3e2cfb-a666-4bb1-bcc1-569d5d0b837a.jsonl +2 -0
  78. package/src/.omc/state/idle-notif-cooldown.json +1 -1
  79. package/src/.omc/state/sessions/c513ef38-cc3e-4a29-9c4c-1e0137245dd5/mission-state.json +79 -0
  80. package/src/.omc/state/sessions/c513ef38-cc3e-4a29-9c4c-1e0137245dd5/pre-tool-advisory-throttle.json +22 -0
  81. package/src/.omc/state/sessions/c513ef38-cc3e-4a29-9c4c-1e0137245dd5/subagent-tracking-state.json +26 -0
  82. package/src/.omc/state/sessions/ed3e2cfb-a666-4bb1-bcc1-569d5d0b837a/pre-tool-advisory-throttle.json +18 -0
  83. package/src/.omc/state/sessions/ed3e2cfb-a666-4bb1-bcc1-569d5d0b837a/ralph-state.json +13 -0
  84. package/src/.omc/state/sessions/ed3e2cfb-a666-4bb1-bcc1-569d5d0b837a/ultrawork-state.json +11 -0
  85. package/src/commands/config/.omc/state/sessions/41336850-028c-476b-be1a-2164e1e46cac/last-tool-error-state.json +7 -0
  86. package/src/commands/config/.omc/state/sessions/41336850-028c-476b-be1a-2164e1e46cac/pre-tool-advisory-throttle.json +18 -0
  87. package/src/commands/config/config.ts +7 -37
  88. package/src/commands/doctor/__tests__/agent-files.test.ts +8 -30
  89. package/src/commands/doctor/__tests__/check-legacy-user-global-config.test.ts +110 -0
  90. package/src/commands/doctor/doctor.ts +104 -44
  91. package/src/commands/env-autoload/env-autoload.ts +12 -0
  92. package/src/commands/env-autoload/index.ts +1 -0
  93. package/src/commands/env-clear/__tests__/env-clear.test.ts +27 -0
  94. package/src/commands/env-clear/env-clear.ts +22 -8
  95. package/src/commands/env-load/__tests__/env-load.test.ts +36 -1
  96. package/src/commands/env-load/env-load.ts +152 -35
  97. package/src/commands/env-load/index.ts +2 -1
  98. package/src/commands/env-status/__tests__/env-status.test.ts +78 -0
  99. package/src/commands/env-status/env-status.ts +19 -7
  100. package/src/commands/gh-release-deploy-all/gh-release-deploy-all.ts +45 -1
  101. package/src/commands/gh-release-deploy-selected/gh-release-deploy-selected.ts +46 -1
  102. package/src/commands/init/__tests__/agent-files.test.ts +145 -27
  103. package/src/commands/init/__tests__/migrate-config.test.ts +136 -5
  104. package/src/commands/init/__tests__/migrate-factory-config.test.ts +93 -0
  105. package/src/commands/init/__tests__/seed-user-global-config.test.ts +64 -0
  106. package/src/commands/init/__tests__/shell-body.test.ts +30 -0
  107. package/src/commands/init/agent-files.ts +65 -45
  108. package/src/commands/init/init.ts +140 -31
  109. package/src/commands/init/migrate-config.ts +160 -32
  110. package/src/commands/vendor-check/__tests__/runtime-isolation.test.ts +71 -0
  111. package/src/commands/vendor-check/__tests__/vendor-check.test.ts +87 -0
  112. package/src/commands/vendor-check/index.ts +1 -0
  113. package/src/commands/vendor-check/vendor-check.ts +127 -0
  114. package/src/commands/vendor-config/__tests__/vendor-config.test.ts +103 -0
  115. package/src/commands/vendor-config/index.ts +1 -0
  116. package/src/commands/vendor-config/vendor-config.ts +162 -0
  117. package/src/commands/vendor-diff/__tests__/vendor-diff.test.ts +74 -0
  118. package/src/commands/vendor-diff/index.ts +1 -0
  119. package/src/commands/vendor-diff/vendor-diff.ts +77 -0
  120. package/src/commands/vendor-manifest/index.ts +1 -0
  121. package/src/commands/vendor-manifest/vendor-manifest.ts +60 -0
  122. package/src/commands/vendor-sync/__tests__/vendor-write.test.ts +86 -0
  123. package/src/commands/vendor-sync/index.ts +1 -0
  124. package/src/commands/vendor-sync/vendor-sync.ts +90 -0
  125. package/src/commands/worktrees-add/worktrees-add.ts +1 -1
  126. package/src/commands/worktrees-reload/worktrees-reload.ts +6 -5
  127. package/src/commands/worktrees-remove/worktrees-remove.ts +10 -1
  128. package/src/commands/worktrees-sync/worktrees-sync.ts +9 -1
  129. package/src/entry/cli.ts +417 -210
  130. package/src/entry/index.ts +7 -1
  131. package/src/integrations/cmux/__tests__/open-workspace-with-layout.test.ts +127 -0
  132. package/src/integrations/cmux/close-workspace-by-title.ts +2 -2
  133. package/src/integrations/cmux/list-workspace-titles.ts +1 -1
  134. package/src/integrations/cmux/open-workspace-with-layout.ts +15 -4
  135. package/src/integrations/cursor/open-cursor-workspace.ts +6 -11
  136. package/src/integrations/doppler/__tests__/doppler-errors.test.ts +76 -0
  137. package/src/integrations/doppler/doppler-cli-auth.ts +12 -4
  138. package/src/integrations/doppler/doppler-errors.ts +88 -0
  139. package/src/integrations/doppler/doppler-project.ts +80 -0
  140. package/src/integrations/doppler/index.ts +3 -1
  141. package/src/integrations/gh/gh-cli-auth/gh-cli-auth.ts +9 -5
  142. package/src/integrations/gh/gh-release-prs/gh-release-prs.ts +16 -8
  143. package/src/integrations/ide/__tests__/ide-facade.test.ts +49 -10
  144. package/src/integrations/ide/open-ide-workspace.ts +6 -6
  145. package/src/integrations/ide/remove-ide-worktree-folders.ts +95 -30
  146. package/src/integrations/ide/types.ts +10 -1
  147. package/src/integrations/zed/__tests__/open-zed-workspace.test.ts +1 -17
  148. package/src/integrations/zed/__tests__/reuse-zed-workspace.test.ts +86 -0
  149. package/src/integrations/zed/index.ts +1 -0
  150. package/src/integrations/zed/open-zed-workspace.ts +4 -10
  151. package/src/integrations/zed/reuse-zed-workspace.ts +57 -0
  152. package/src/lib/command-catalog/__tests__/__snapshots__/command-catalog.test.ts.snap +212 -0
  153. package/src/lib/command-catalog/__tests__/command-catalog.test.ts +193 -0
  154. package/src/lib/command-catalog/command-catalog.ts +141 -0
  155. package/src/lib/command-catalog/index.ts +2 -0
  156. package/src/lib/command-echo/__tests__/command-echo.test.ts +127 -0
  157. package/src/lib/constants/constants.ts +13 -0
  158. package/src/lib/constants/index.ts +2 -0
  159. package/src/lib/env-autoload/__tests__/env-autoload.test.ts +288 -0
  160. package/src/lib/env-autoload/env-autoload.ts +294 -0
  161. package/src/lib/env-autoload/index.ts +9 -0
  162. package/src/lib/errors/operation-error.ts +1 -1
  163. package/src/lib/infra-kit-config/__tests__/env-autoload-schema.test.ts +71 -0
  164. package/src/lib/infra-kit-config/__tests__/infra-kit-config.test.ts +77 -6
  165. package/src/lib/infra-kit-config/index.ts +9 -1
  166. package/src/lib/infra-kit-config/infra-kit-config.ts +71 -11
  167. package/src/lib/json-output/__tests__/json-output.test.ts +139 -0
  168. package/src/lib/json-output/index.ts +1 -0
  169. package/src/lib/json-output/json-output.ts +47 -0
  170. package/src/lib/managed-block/managed-block.ts +4 -4
  171. package/src/lib/package-config/package-config.ts +1 -3
  172. package/src/lib/path-display/index.ts +1 -0
  173. package/src/lib/path-display/path-display.ts +42 -0
  174. package/src/lib/render/__tests__/render.test.ts +48 -0
  175. package/src/lib/render/index.ts +1 -0
  176. package/src/lib/render/render.ts +24 -0
  177. package/src/lib/vendor/__tests__/config-schema.test.ts +31 -0
  178. package/src/lib/vendor/__tests__/config.test.ts +63 -0
  179. package/src/lib/vendor/__tests__/factory-config.test.ts +92 -0
  180. package/src/lib/vendor/__tests__/vendor-lib.test.ts +158 -0
  181. package/src/lib/vendor/__tests__/zx-mock.ts +32 -0
  182. package/src/lib/vendor/config-schema.ts +78 -0
  183. package/src/lib/vendor/config.ts +58 -0
  184. package/src/lib/vendor/factory-config-schema.ts +35 -0
  185. package/src/lib/vendor/factory-config.ts +91 -0
  186. package/src/lib/vendor/hash.ts +16 -0
  187. package/src/lib/vendor/index.ts +23 -0
  188. package/src/lib/vendor/manifest.ts +151 -0
  189. package/src/lib/vendor/skip-sets.ts +48 -0
  190. package/src/lib/vendor/sync-ops.ts +290 -0
  191. package/src/lib/vendor/walk.ts +56 -0
  192. package/src/mcp/tools/index.ts +5 -42
  193. package/src/sanity.test.tsx +1 -0
  194. package/src/tui/__tests__/no-react-boundary.test.ts +51 -0
  195. package/src/tui/boot.tsx +45 -0
  196. package/src/tui/screens/__tests__/command-palette.test.tsx +136 -0
  197. package/src/tui/screens/command-palette.tsx +159 -0
  198. package/src/tui/types.ts +8 -0
  199. package/tsconfig.json +1 -0
  200. package/tsconfig.tsbuildinfo +1 -1
  201. package/vitest.config.ts +8 -0
  202. package/src/commands/worktrees-open/__tests__/open-cmux.test.ts +0 -96
  203. package/src/commands/worktrees-open/index.ts +0 -1
  204. package/src/commands/worktrees-open/worktrees-open.ts +0 -195
package/dist/cli.js.map CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "version": 3,
3
- "sources": ["../src/entry/cli.ts", "../src/commands/audit/audit.ts", "../src/lib/git-utils/git-utils.ts", "../src/lib/release-id/release-id.ts", "../src/lib/logger/index.ts", "../src/lib/package-config/package-config.ts", "../src/lib/package-config/package-config-schema.ts", "../src/lib/package-validator/fs-utils.ts", "../src/lib/package-validator/package-validator.ts", "../src/lib/package-validator/loader/config-loader.ts", "../src/lib/package-validator/loader/package-discovery.ts", "../src/lib/package-validator/checks/config-check.ts", "../src/lib/package-validator/checks/files-check.ts", "../src/lib/package-validator/checks/scripts-check.ts", "../src/lib/package-validator/checks/turbo-check.ts", "../src/types.ts", "../src/commands/config/config.ts", "../src/lib/infra-kit-config/infra-kit-config.ts", "../src/commands/doctor/doctor.ts", "../src/commands/init/agent-files.ts", "../src/lib/managed-block/managed-block.ts", "../package.json", "../src/commands/init/init.ts", "../src/commands/init/migrate-config.ts", "../src/commands/env-clear/env-clear.ts", "../src/lib/constants/constants.ts", "../src/commands/env-list/env-list.ts", "../src/integrations/doppler/doppler-project.ts", "../src/commands/env-load/env-load.ts", "../src/integrations/doppler/doppler-cli-auth.ts", "../src/lib/command-echo/command-echo.ts", "../src/commands/env-status/env-status.ts", "../src/commands/gh-merge-dev/gh-merge-dev.ts", "../src/integrations/gh/gh-cli-auth/gh-cli-auth.ts", "../src/integrations/gh/gh-release-prs/gh-release-prs.ts", "../src/lib/release-utils/release-utils.ts", "../src/integrations/jira/api.ts", "../src/lib/errors/operation-error.ts", "../src/lib/git-guard/git-guard.ts", "../src/commands/gh-release-deliver/gh-release-deliver.ts", "../src/lib/errors/format-zx-error.ts", "../src/lib/worktrees/remove-worktrees.ts", "../src/integrations/cmux/canonicalize-cmux-title.ts", "../src/integrations/cmux/close-workspace-by-title.ts", "../src/integrations/cmux/list-workspace-titles.ts", "../src/integrations/cmux/open-workspace-with-layout.ts", "../src/integrations/cmux/workspace-title.ts", "../src/commands/gh-release-deploy-all/gh-release-deploy-all.ts", "../src/commands/gh-release-deploy-selected/gh-release-deploy-selected.ts", "../src/commands/gh-release-list/gh-release-list.ts", "../src/commands/release-create/release-create.ts", "../src/lib/version-utils/load-existing-versions.ts", "../src/lib/version-utils/version-utils.ts", "../src/lib/version-utils/next-version.ts", "../src/commands/release-desc-edit/release-desc-edit.ts", "../src/commands/version/version.ts", "../src/commands/worktrees-add/worktrees-add.ts", "../src/integrations/cursor/add-folders-to-workspace.ts", "../src/integrations/cursor/launch-cursor.ts", "../src/integrations/cursor/reconcile-workspace-folders.ts", "../src/integrations/cursor/remove-folders-from-workspace.ts", "../src/integrations/cursor/resolve-workspace-path.ts", "../src/integrations/cursor/open-cursor-workspace.ts", "../src/integrations/zed/add-folders-to-zed-workspace.ts", "../src/integrations/zed/open-zed-workspace.ts", "../src/lib/assert-never/assert-never.ts", "../src/integrations/ide/add-ide-worktree-folders.ts", "../src/integrations/ide/open-ide-workspace.ts", "../src/integrations/ide/provider-label.ts", "../src/integrations/ide/remove-ide-worktree-folders.ts", "../src/integrations/ide/types.ts", "../src/commands/worktrees-list/worktrees-list.ts", "../src/commands/worktrees-open/worktrees-open.ts", "../src/commands/worktrees-reload/worktrees-reload.ts", "../src/commands/worktrees-remove/worktrees-remove.ts", "../src/commands/worktrees-sync/worktrees-sync.ts"],
4
- "sourcesContent": ["import select, { Separator } from '@inquirer/select'\nimport { Command } from 'commander'\nimport process from 'node:process'\n\nimport { audit } from 'src/commands/audit'\nimport { configEdit, configPath } from 'src/commands/config'\nimport { doctor } from 'src/commands/doctor'\nimport { envClear } from 'src/commands/env-clear'\nimport { envList } from 'src/commands/env-list'\nimport { envLoad } from 'src/commands/env-load'\nimport { envStatus } from 'src/commands/env-status'\nimport { ghMergeDev } from 'src/commands/gh-merge-dev'\nimport { ghReleaseDeliver } from 'src/commands/gh-release-deliver'\nimport { ghReleaseDeployAll } from 'src/commands/gh-release-deploy-all'\nimport { ghReleaseDeploySelected } from 'src/commands/gh-release-deploy-selected'\nimport { ghReleaseList } from 'src/commands/gh-release-list'\nimport { init } from 'src/commands/init'\nimport { releaseCreate } from 'src/commands/release-create'\nimport { releaseDescEdit } from 'src/commands/release-desc-edit'\nimport { version } from 'src/commands/version'\nimport { worktreesAdd } from 'src/commands/worktrees-add'\nimport { worktreesList } from 'src/commands/worktrees-list'\nimport { worktreesOpen } from 'src/commands/worktrees-open'\nimport { worktreesReload } from 'src/commands/worktrees-reload'\nimport { worktreesRemove } from 'src/commands/worktrees-remove'\nimport { worktreesSync } from 'src/commands/worktrees-sync'\nimport { IDE_MODES } from 'src/integrations/ide'\nimport type { IdeMode } from 'src/integrations/ide'\nimport { logger } from 'src/lib/logger'\nimport { parseReleaseSpec } from 'src/lib/version-utils'\nimport type { ReleaseInput } from 'src/lib/version-utils'\n\nconst program = new Command()\n\nconst collectReleaseSpec = (value: string, prev: string[]): string[] => {\n return [...prev, value]\n}\n\nconst normalizeIdeMode = (value: unknown, flagName: '--ide' | '--cursor'): IdeMode | undefined => {\n if (typeof value === 'undefined') {\n return undefined\n }\n\n if (value === true) {\n return 'workspace'\n }\n\n if (value === false) {\n return 'none'\n }\n\n if (typeof value === 'string' && (IDE_MODES as readonly string[]).includes(value)) {\n return value as IdeMode\n }\n\n throw new Error(`Invalid ${flagName} value \"${String(value)}\". Expected one of: ${IDE_MODES.join(', ')}.`)\n}\n\nconst runProgram = async (argv?: string[]): Promise<void> => {\n try {\n if (argv) {\n await program.parseAsync(argv)\n } else {\n await program.parseAsync()\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n\n logger.error(message)\n process.exit(1)\n }\n}\n\nprogram\n .command('merge-dev')\n .description('Merge dev branch into every release branch')\n .option('-a, --all', 'Select all active release branches')\n .option('-y, --yes', 'Skip confirmation prompt')\n .action(async (options) => {\n await ghMergeDev({ all: options.all, confirmedCommand: options.yes })\n })\n\nprogram\n .command('release-list')\n .description('List all release branches')\n .action(async () => {\n await ghReleaseList()\n })\n\nprogram\n .command('release-create')\n .description('Create one or more release branches (each entry can mix regular/hotfix and its own description)')\n .option(\n '-r, --release <spec>',\n 'Release spec \"<version|next|name>[:type[:description]]\" (repeatable). The token is a semver (\"1.2.5\"), the literal \"next\", or a kebab-case name (\"checkout-redesign\"). Type is regular|hotfix (default regular). Examples: \"1.2.5\", \"1.2.5:hotfix\", \"next:regular:Holiday backend\", \"checkout-redesign:regular:Q3 redesign\".',\n collectReleaseSpec,\n [],\n )\n .option('-y, --yes', 'Skip confirmation prompt')\n .action(async (options) => {\n const specs = options.release as string[]\n const inputs: ReleaseInput[] = specs.map(parseReleaseSpec)\n const releases = inputs.length > 0 ? inputs : undefined\n\n await releaseCreate({\n releases,\n confirmedCommand: options.yes,\n })\n })\n\nprogram\n .command('release-desc-edit')\n .description(\"Edit a release's description in Jira and in the matching GitHub PR body\")\n .option('-v, --version <version>', 'Release version (e.g. 1.2.5) or release name (e.g. checkout-redesign)')\n .option('-d, --description <description>', 'New description (use \"\" to clear)')\n .option('-y, --yes', 'Skip confirmation prompt')\n .action(async (options) => {\n await releaseDescEdit({\n version: options.version,\n description: options.description,\n confirmedCommand: options.yes,\n })\n })\n\nprogram\n .command('release-deploy-all')\n .description('Deploy any release branch to any environment')\n .option(\n '-v, --version <version>',\n 'Version (e.g. 1.2.5) or release name (e.g. checkout-redesign) to deploy; \"dev\" deploys from the dev branch',\n )\n .option('-e, --env <env>', 'Specify the environment to deploy to, e.g. dev')\n .option('--skip-terraform', 'Skip terraform deployment step')\n .action(async (options) => {\n await ghReleaseDeployAll({ version: options.version, env: options.env, skipTerraform: options.skipTerraform })\n })\n\nprogram\n .command('release-deploy-selected')\n .description('Deploy selected services from release branch to any environment')\n .option(\n '-v, --version <version>',\n 'Version (e.g. 1.2.5) or release name (e.g. checkout-redesign) to deploy; \"dev\" deploys from the dev branch',\n )\n .option('-e, --env <env>', 'Specify the environment to deploy to, e.g. dev')\n .option('-s, --services <services...>', 'Specify services to deploy, e.g. client-be client-fe')\n .option('--skip-terraform', 'Skip terraform deployment step')\n .action(async (options) => {\n await ghReleaseDeploySelected({\n version: options.version,\n env: options.env,\n services: options.services,\n skipTerraform: options.skipTerraform,\n })\n })\n\nprogram\n .command('release-deliver')\n .description('Release a new version to production')\n .option('-v, --version <version>', 'Version (e.g. 1.2.5) or release name (e.g. checkout-redesign) to deliver')\n .option('-y, --yes', 'Skip confirmation prompt')\n .action(async (options) => {\n await ghReleaseDeliver({ version: options.version, confirmedCommand: options.yes })\n })\n\nprogram\n .command('worktrees-sync')\n .description('Remove release worktrees whose PRs are no longer open')\n .option('-y, --yes', 'Skip confirmation prompt')\n .action(async (options) => {\n await worktreesSync({ confirmedCommand: options.yes })\n })\n\nprogram\n .command('worktrees-add')\n .description('Add git worktrees for release branches')\n .option('-y, --yes', 'Skip confirmation prompt')\n .option('-a, --all', 'Select all active release branches')\n .option('-v, --versions <versions>', 'Specify versions by comma, e.g. 1.2.5, 1.2.6')\n .option('-i, --ide [mode]', 'Editor mode for created worktrees: workspace (default) | none')\n .option('--no-ide', 'Skip the editor (alias for --ide none)')\n .option('-c, --cursor [mode]', 'Deprecated alias for --ide')\n .option('--no-cursor', 'Deprecated alias for --no-ide')\n .option('-g, --github-desktop', 'Open created worktrees in GitHub Desktop')\n .option('--no-github-desktop', 'Skip GitHub Desktop prompt')\n .option('-m, --cmux', 'Open created worktrees in cmux (3-pane layout)')\n .option('--no-cmux', 'Skip cmux prompt')\n .action(async (options) => {\n // `--ide` wins over the deprecated `--cursor` alias when both are provided.\n const ide = normalizeIdeMode(options.ide, '--ide') ?? normalizeIdeMode(options.cursor, '--cursor')\n\n await worktreesAdd({\n confirmedCommand: options.yes,\n all: options.all,\n versions: options.versions,\n ide,\n githubDesktop: options.githubDesktop,\n cmux: options.cmux,\n })\n })\n\nprogram\n .command('worktrees-list')\n .description('List all git worktrees with detailed information')\n .action(async () => {\n await worktreesList()\n })\n\nprogram\n .command('worktrees-remove')\n .description('Remove git worktrees for release branches')\n .option('-y, --yes', 'Skip confirmation prompt')\n .option('-a, --all', 'Select all active release branches')\n .option('-v, --versions <versions>', 'Specify versions by comma, e.g. 1.2.5, 1.2.6')\n .action(async (options) => {\n await worktreesRemove({ confirmedCommand: options.yes, all: options.all, versions: options.versions })\n })\n\nprogram\n .command('worktrees-open')\n .description('Open the configured editor (Cursor/Zed) + cmux for existing release worktrees (cold-start restore)')\n .action(async () => {\n await worktreesOpen()\n })\n\nprogram\n .command('worktrees-reload')\n .description('Close all cmux/editor worktree windows, then reopen the current release worktrees')\n .action(async () => {\n await worktreesReload()\n })\n\nconst configCmd = program.command('config').description('Manage infra-kit configuration files')\n\nconfigCmd\n .command('path')\n .description('Show the resolved config merge chain and file paths')\n .action(async () => {\n await configPath()\n })\n\nconfigCmd\n .command('edit')\n .description('Open the user-scope per-project override file in $EDITOR')\n .action(async () => {\n await configEdit()\n })\n\nprogram\n .command('audit')\n .description('Audit against infra-kit.config.ts rules (--all for every package, --root for the monorepo root)')\n .option('-a, --all', 'Audit every non-vendor workspace package')\n .option('-r, --root', 'Audit the monorepo root (turbo pipeline + root commands)')\n .action(async (options) => {\n const result = await audit({ all: options.all, root: options.root })\n\n if (!result.structuredContent.allPassed) {\n process.exitCode = 1\n }\n })\n\nprogram\n .command('doctor')\n .description('Check installation and authentication status of gh and doppler CLIs')\n .action(async () => {\n await doctor()\n })\n\nprogram\n .command('version')\n .description('Print the installed infra-kit CLI version')\n .action(async () => {\n await version()\n })\n\nprogram\n .command('env-status')\n .description('Show Doppler authentication status and detected project info')\n .action(async () => {\n await envStatus()\n })\n\nprogram\n .command('env-list')\n .description('List available Doppler configs for the detected project')\n .action(async () => {\n await envList()\n })\n\nprogram\n .command('init')\n .description('Inject shell integration into .zshrc and sync repo agent-instruction files')\n .action(async () => {\n await init()\n })\n\nprogram\n .command('env-load')\n .description('Load Doppler env vars for a config. Source the returned file path to apply.')\n .option('-c, --config <config>', 'Environment config name to load (e.g. dev, arthur)')\n .action(async (options) => {\n await envLoad({ config: options.config })\n })\n\nprogram\n .command('env-clear')\n .description('Clear loaded env vars. Source the returned file path to apply.')\n .action(async () => {\n await envClear()\n })\n\nif (process.argv.length <= 2) {\n const releaseCommands = [\n 'merge-dev',\n 'release-list',\n 'release-create',\n 'release-desc-edit',\n 'release-deploy-all',\n 'release-deploy-selected',\n 'release-deliver',\n ]\n const worktreeCommands = [\n 'worktrees-add',\n 'worktrees-list',\n 'worktrees-open',\n 'worktrees-reload',\n 'worktrees-remove',\n 'worktrees-sync',\n ]\n const envCommands = [\n 'audit',\n 'doctor',\n 'init',\n 'version',\n 'config',\n 'env-status',\n 'env-list',\n 'env-load',\n 'env-clear',\n ]\n\n const commandMap = new Map(\n program.commands.map((cmd) => {\n return [cmd.name(), cmd]\n }),\n )\n\n const allNames = [...releaseCommands, ...worktreeCommands, ...envCommands]\n const maxLen = Math.max(\n ...allNames.map((n) => {\n return n.length\n }),\n )\n\n const toChoices = (names: string[]) => {\n return names\n .filter((n) => {\n return commandMap.has(n)\n })\n .map((n) => {\n return {\n name: `${n.padEnd(maxLen)} ${commandMap.get(n)!.description()}`,\n value: n,\n }\n })\n }\n\n const selected = await select(\n {\n message: 'Select a command to run',\n choices: [\n new Separator(' '),\n new Separator('\u2014 Release Management \u2014'),\n ...toChoices(releaseCommands),\n new Separator(' '),\n new Separator('\u2014 Worktrees \u2014'),\n ...toChoices(worktreeCommands),\n new Separator(' '),\n new Separator('\u2014 Environment \u2014'),\n ...toChoices(envCommands),\n ],\n },\n { output: process.stderr },\n )\n\n await runProgram(['node', 'infra-kit', selected])\n} else {\n await runProgram()\n}\n", "import path from 'node:path'\nimport process from 'node:process'\nimport { z } from 'zod'\n\nimport { getProjectRoot } from 'src/lib/git-utils'\nimport { logger } from 'src/lib/logger'\nimport { ROOT_DEFAULT_RULES } from 'src/lib/package-config'\nimport type { ResolvedPackageRules } from 'src/lib/package-config'\nimport { discoverPackages, pathExists, validatePackage } from 'src/lib/package-validator'\nimport type { PackageValidationResult } from 'src/lib/package-validator'\nimport { defineMcpTool, textContent } from 'src/types'\n\n// TODO [DO]: extract `audit` into its own standalone CLI tool, decoupled from infra-kit.\n\ninterface AuditOptions {\n /** Audit every non-vendor workspace package instead of just the current one. */\n all?: boolean\n /** Audit the monorepo root (turbo pipeline + root commands) instead of a package. */\n root?: boolean\n /** Directory to resolve the current package from. Defaults to `process.cwd()`. */\n cwd?: string\n}\n\n/** A directory to audit plus the under-the-hood defaults that apply to it. */\ninterface AuditTarget {\n dir: string\n baseline?: Readonly<ResolvedPackageRules>\n}\n\n/**\n * Walk upward from `start` to the nearest directory containing a package.json.\n * Used so `infra-kit audit` (no `--all`) targets the package whose package.json\n * script invoked it, regardless of the exact working directory.\n *\n * @example\n * await findPackageRoot('/repo/packages/serverless-config/src')\n * // => '/repo/packages/serverless-config'\n */\nconst findPackageRoot = async (start: string): Promise<string> => {\n let current = path.resolve(start)\n\n while (current !== path.dirname(current)) {\n if (await pathExists(path.join(current, 'package.json'))) {\n return current\n }\n\n current = path.dirname(current)\n }\n\n if (await pathExists(path.join(current, 'package.json'))) {\n return current\n }\n\n throw new Error(`No package.json found in or above ${start}`)\n}\n\n/**\n * Resolve which directories to audit, and the baseline defaults each uses:\n * `root` \u2192 the monorepo root with {@link ROOT_DEFAULT_RULES}; `all` \u2192 every\n * discovered non-vendor package; otherwise the package walked up from cwd.\n */\nconst resolveTargets = async (options: AuditOptions): Promise<AuditTarget[]> => {\n if (options.root) {\n return [{ dir: await getProjectRoot(), baseline: ROOT_DEFAULT_RULES }]\n }\n\n if (options.all) {\n const dirs = await discoverPackages(await getProjectRoot())\n\n return dirs.map((dir) => {\n return { dir }\n })\n }\n\n return [{ dir: await findPackageRoot(options.cwd ?? process.cwd()) }]\n}\n\n/**\n * Print a package's audit result as doctor-style `[PASS]`/`[FAIL]` lines.\n */\nconst logResult = (result: PackageValidationResult): void => {\n const header = result.passed ? 'PASS' : 'FAIL'\n\n logger.info(`\\n${result.packageName} \u2014 ${header}`)\n\n for (const check of result.checks) {\n const icon = check.status === 'pass' ? '[PASS]' : '[FAIL]'\n\n logger.info(` ${icon} ${check.name}: ${check.message}`)\n }\n}\n\n/**\n * Audit the monorepo root (`root`), every non-vendor workspace package (`all`),\n * or the package resolved by walking up from the working directory (default \u2014\n * the shape used by a package's `\"check\": \"infra-kit audit\"` script). The\n * returned `structuredContent.allPassed` lets the CLI set a non-zero exit code so\n * the audit fails CI; this function never calls `process.exit` so the MCP tool\n * can reuse it.\n *\n * @example\n * // CLI inside packages/serverless-config: `infra-kit audit`\n * await audit() // audits the current package\n * await audit({ all: true }) // audits every non-vendor workspace package\n * await audit({ root: true }) // audits the monorepo root (turbo + root commands)\n */\nexport const audit = async (options: AuditOptions = {}) => {\n const targets = await resolveTargets(options)\n\n const results: PackageValidationResult[] = []\n\n for (const target of targets) {\n results.push(await validatePackage(target.dir, target.baseline))\n }\n\n for (const result of results) {\n logResult(result)\n }\n\n const allPassed = results.every((result) => {\n return result.passed\n })\n\n logger.info(`\\n${allPassed ? '\u2705 All valid' : '\u274C Audit failed'} (${results.length} checked)`)\n\n const structuredContent = {\n allPassed,\n packages: results.map((result) => {\n return {\n name: result.packageName,\n passed: result.passed,\n checks: result.checks,\n }\n }),\n }\n\n return {\n content: textContent(JSON.stringify(structuredContent, null, 2)),\n structuredContent,\n }\n}\n\nconst auditInputSchema = {\n all: z.boolean().optional().describe('Audit every non-vendor workspace package'),\n root: z.boolean().optional().describe('Audit the monorepo root (turbo pipeline + root commands)'),\n}\n\nconst auditOutputSchema = {\n allPassed: z.boolean().describe('Whether every audited package passed all checks'),\n packages: z\n .array(\n z.object({\n name: z.string(),\n passed: z.boolean(),\n checks: z.array(\n z.object({\n name: z.string(),\n status: z.enum(['pass', 'fail']),\n message: z.string(),\n }),\n ),\n }),\n )\n .describe('Per-package check results'),\n}\n\n// MCP Tool Registration\nexport const auditMcpTool = defineMcpTool({\n name: 'audit',\n description:\n 'Audit packages against infra-kit.config.ts rules (config present and valid, required scripts, required files, and turbo tasks for the root). Defaults to the current package; all=true audits every non-vendor workspace package; root=true audits the monorepo root.',\n inputSchema: auditInputSchema,\n outputSchema: auditOutputSchema,\n handler: (params) => {\n return audit({ all: params.all, root: params.root })\n },\n})\n", "import path from 'node:path'\nimport { $ } from 'zx'\n\nimport { isReleaseBranch } from 'src/lib/release-id'\n\n/**\n * Get current git worktrees\n *\n * @returns [release/v1.18.22, release/v1.18.23, release/v1.18.24] or [feature/mobile-app, feature/explore-page, feature/login-page]\n */\nexport const getCurrentWorktrees = async (type: 'release' | 'feature'): Promise<string[]> => {\n const worktreesOutput = await $`git worktree list`\n\n const worktreeLines = worktreesOutput.stdout.split('\\n').filter(Boolean)\n\n const worktreePredicateMap = {\n release: releaseWorktreePredicate,\n feature: featureWorktreePredicate,\n }\n\n return worktreeLines.map(worktreePredicateMap[type]).filter((branch) => {\n return branch !== null\n })\n}\n\n/**\n * Extract the branch name from a `git worktree list` output line.\n *\n * `git worktree list` formats each line as:\n * <path> <hash> [<branch>]\n *\n * Reads the branch from the trailing `[branch]` token so it works for the\n * main checkout too (whose path does not encode the branch name).\n */\nconst parseWorktreeBranch = (line: string): string | null => {\n const trimmed = line.trimEnd()\n\n if (!trimmed.endsWith(']')) return null\n\n const open = trimmed.lastIndexOf('[')\n\n if (open === -1) return null\n\n const branch = trimmed.slice(open + 1, -1)\n\n return branch.length > 0 ? branch : null\n}\n\n/**\n * Extract a release branch name from a `git worktree list` output line.\n *\n * Returns `null` for lines that are not release worktrees.\n *\n * @example\n * releaseWorktreePredicate('/path/to/release/v1.18.22 abc1234 [release/v1.18.22]')\n * // => 'release/v1.18.22'\n *\n * @example\n * releaseWorktreePredicate('/path/to/feature/login abc1234 [feature/login]')\n * // => null\n */\nconst releaseWorktreePredicate = (line: string): string | null => {\n const branch = parseWorktreeBranch(line)\n\n return isReleaseBranch(branch) ? branch : null\n}\n\n/**\n * Extract a feature branch name from a `git worktree list` output line.\n *\n * Returns `null` for lines that are not feature worktrees.\n *\n * @example\n * featureWorktreePredicate('/path/to/feature/login-page abc1234 [feature/login-page]')\n * // => 'feature/login-page'\n *\n * @example\n * featureWorktreePredicate('/path/to/release/v1.18.22 abc1234 [release/v1.18.22]')\n * // => null\n */\nconst featureWorktreePredicate = (line: string): string | null => {\n const branch = parseWorktreeBranch(line)\n\n return branch?.startsWith('feature/') ? branch : null\n}\n\n/**\n * Get the current project root directory\n */\nexport const getProjectRoot = async (): Promise<string> => {\n const result = await $`git rev-parse --show-toplevel`\n\n return result.stdout.trim()\n}\n\n/**\n * Get the current git branch name (e.g. `dev`, `main`, `release/v1.2.3`).\n */\nexport const getCurrentBranch = async (): Promise<string> => {\n const result = await $`git rev-parse --abbrev-ref HEAD`\n\n return result.stdout.trim()\n}\n\n/**\n * Whether the working tree has no staged, unstaged, or untracked changes.\n */\nexport const isWorkingTreeClean = async (): Promise<boolean> => {\n const result = await $`git status --porcelain`\n\n return result.stdout.trim().length === 0\n}\n\n/**\n * Whether the current checkout is a linked git worktree rather than the main\n * repository checkout.\n *\n * A linked worktree's git dir lives under `<main>/.git/worktrees/<name>`, so it\n * differs from the shared common dir; in the main checkout the two resolve to\n * the same path. Both are anchored to the toplevel so `--git-common-dir` (which\n * git may report relative to cwd) resolves consistently.\n */\nexport const isInsideLinkedWorktree = async (): Promise<boolean> => {\n const cwd = await getProjectRoot()\n\n const [gitDirResult, commonDirResult] = await Promise.all([\n $({ cwd })`git rev-parse --absolute-git-dir`,\n $({ cwd })`git rev-parse --git-common-dir`,\n ])\n\n const gitDir = gitDirResult.stdout.trim()\n const commonDir = path.resolve(cwd, commonDirResult.stdout.trim())\n\n return gitDir !== commonDir\n}\n\n/**\n * Get the current repository name (basename of the project root)\n */\nexport const getRepoName = async (): Promise<string> => {\n const projectRoot = await getProjectRoot()\n\n return path.basename(projectRoot)\n}\n\n/**\n * Delete a local branch if it exists and is not the current checkout.\n *\n * Idempotent: a no-op when the branch is absent (`git branch --list` prints\n * nothing). Uses force `-D` because a delivered release branch was\n * squash-merged \u2014 its tip is unreachable from the base, so `-d` would refuse\n * with \"not fully merged\". The delete itself still rejects if the branch is\n * checked out in another worktree; callers decide how to handle that.\n */\nexport const deleteLocalBranch = async (branch: string): Promise<void> => {\n const listed = await $`git branch --list ${branch}`\n\n if (listed.stdout.trim().length === 0) return\n\n if ((await getCurrentBranch()) === branch) return\n\n await $`git branch -D ${branch}`\n}\n\n/**\n * Delete a branch on the `origin` remote if it exists.\n *\n * Idempotent: a no-op when the branch is absent on the remote. Existence is\n * probed with `git ls-remote --heads` (empty stdout = absent) rather than\n * `--exit-code`, so a genuine network/auth failure rejects and propagates to\n * the caller instead of being silently misread as \"branch absent\".\n */\nexport const deleteRemoteBranch = async (branch: string): Promise<void> => {\n const refs = await $`git ls-remote --heads origin ${branch}`\n\n if (refs.stdout.trim().length === 0) return\n\n await $`git push origin --delete ${branch}`\n}\n", "/**\n * A release identity is either a semantic version or a free-form kebab-case\n * name. `raw` is the canonical token for the id: the no-`v` semver string for\n * versions (e.g. `1.2.3`) and the name itself for named releases.\n */\nexport type ReleaseId =\n | { kind: 'version'; semver: { major: number; minor: number; patch: number }; raw: string }\n | { kind: 'name'; name: string; raw: string }\n\n/** Matches a bare or `v`-prefixed semver token, e.g. `1.2.3` or `v1.2.3`. */\nconst VERSION_RE = /^v?(\\d+)\\.(\\d+)\\.(\\d+)$/\n\n/** Matches the semver core after the `v` in a `release/v\u2026` branch. */\nconst BRANCH_SEMVER_RE = /^(\\d+)\\.(\\d+)\\.(\\d+)$/\n\n/** Kebab-case: lowercase alphanumeric segments joined by single hyphens. */\nconst KEBAB_RE = /^[a-z0-9]+(?:-[a-z0-9]+)*$/\n\nconst RELEASE_BRANCH_PREFIX = 'release/'\nconst VERSION_BRANCH_PREFIX = 'release/v'\nconst REFS_HEADS_PREFIX = 'refs/heads/'\n\nconst NEXT_TOKEN = 'next'\nconst MAX_NAME_LENGTH = 50\n\n/**\n * Names that would collide with branch/release semantics or read as a special\n * token. Banned regardless of kebab-case validity.\n */\nconst RESERVED_NAMES: ReadonlySet<string> = new Set(['dev', 'main', 'next', 'hotfix', 'regular', 'release'])\n\n/** Thrown by {@link validateName} when a release name is not acceptable. */\nexport class InvalidReleaseNameError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'InvalidReleaseNameError'\n }\n}\n\n/** Thrown by {@link parseReleaseRef} when a release ref cannot be parsed. */\nexport class InvalidReleaseRefError extends Error {\n constructor(message: string) {\n super(message)\n this.name = 'InvalidReleaseRefError'\n }\n}\n\nconst stripRefsHeads = (input: string): string => {\n return input.startsWith(REFS_HEADS_PREFIX) ? input.slice(REFS_HEADS_PREFIX.length) : input\n}\n\nconst makeVersion = (major: number, minor: number, patch: number): ReleaseId => {\n return {\n kind: 'version',\n semver: { major, minor, patch },\n raw: `${major}.${minor}.${patch}`,\n }\n}\n\n/**\n * Validate a release name. Throws {@link InvalidReleaseNameError} with a\n * specific message unless the name is kebab-case, at most 50 characters, and\n * not a reserved word. Semver-looking tokens (e.g. `1.2.3`) are already\n * excluded by the kebab-case rule since they contain dots.\n */\nexport const validateName = (name: string): void => {\n if (name.length === 0) {\n throw new InvalidReleaseNameError('Release name is empty. Provide a kebab-case name like \"checkout-redesign\".')\n }\n\n if (name.length > MAX_NAME_LENGTH) {\n throw new InvalidReleaseNameError(\n `Release name \"${name}\" is ${name.length} characters; the maximum is ${MAX_NAME_LENGTH}.`,\n )\n }\n\n if (!KEBAB_RE.test(name)) {\n throw new InvalidReleaseNameError(\n `Release name \"${name}\" is not kebab-case. Use lowercase letters, digits, and single hyphens, e.g. \"checkout-redesign\".`,\n )\n }\n\n if (RESERVED_NAMES.has(name)) {\n throw new InvalidReleaseNameError(\n `Release name \"${name}\" is reserved. Reserved names: ${[...RESERVED_NAMES].join(', ')}.`,\n )\n }\n}\n\n/**\n * Lenient parse of a git branch name into a {@link ReleaseId}. Tolerates a\n * leading `refs/heads/`. Returns `null` for anything that is not a valid\n * `release/v<semver>` or `release/<name>` branch. Never throws.\n *\n * Precedence is version-first: `release/v<semver>` is a version, but if the\n * segment after `release/v` is not a valid semver (e.g. `release/vnext`), the\n * whole token after `release/` is treated as a candidate name instead.\n */\nexport const parseBranchName = (branch: string): ReleaseId | null => {\n const stripped = stripRefsHeads(branch.trim())\n\n if (!stripped.startsWith(RELEASE_BRANCH_PREFIX)) return null\n\n if (stripped.startsWith(VERSION_BRANCH_PREFIX)) {\n const semverPart = stripped.slice(VERSION_BRANCH_PREFIX.length)\n const match = BRANCH_SEMVER_RE.exec(semverPart)\n\n if (match) {\n return makeVersion(Number(match[1]), Number(match[2]), Number(match[3]))\n }\n }\n\n const namePart = stripped.slice(RELEASE_BRANCH_PREFIX.length)\n\n try {\n validateName(namePart)\n } catch {\n return null\n }\n\n return { kind: 'name', name: namePart, raw: namePart }\n}\n\n/**\n * Strict parse of a release ref into a {@link ReleaseId}. Throws\n * {@link InvalidReleaseRefError} on invalid input. Precedence (order matters):\n * 1. `release/\u2026` (or `refs/heads/release/\u2026`) \u2192 delegate to parseBranchName.\n * 2. semver token (`1.2.3` / `v1.2.3`) \u2192 version.\n * 3. `next` \u2192 throws; callers must resolve `next` to a concrete version\n * via computeNextVersion before calling this.\n * 4. otherwise \u2192 validateName, returning a named release.\n */\nexport const parseReleaseRef = (input: string): ReleaseId => {\n const trimmed = input.trim()\n const branchCandidate = stripRefsHeads(trimmed)\n\n if (branchCandidate.startsWith(RELEASE_BRANCH_PREFIX)) {\n const parsed = parseBranchName(trimmed)\n\n if (!parsed) {\n throw new InvalidReleaseRefError(\n `\"${input}\" looks like a release branch but is not a valid release/v<semver> or release/<name> ref.`,\n )\n }\n\n return parsed\n }\n\n const versionMatch = VERSION_RE.exec(trimmed)\n\n if (versionMatch) {\n return makeVersion(Number(versionMatch[1]), Number(versionMatch[2]), Number(versionMatch[3]))\n }\n\n if (trimmed.toLowerCase() === NEXT_TOKEN) {\n throw new InvalidReleaseRefError(\n 'The \"next\" token must be resolved to a concrete version (via computeNextVersion) before parsing a release ref.',\n )\n }\n\n try {\n validateName(trimmed)\n } catch (err) {\n const reason = err instanceof Error ? err.message : String(err)\n\n throw new InvalidReleaseRefError(`Cannot parse \"${input}\" as a release ref: ${reason}`)\n }\n\n return { kind: 'name', name: trimmed, raw: trimmed }\n}\n\n/** Render the branch name for a release id: `release/v1.2.3` | `release/<name>`. */\nexport const formatBranchName = (id: ReleaseId): string => {\n if (id.kind === 'version') return `${VERSION_BRANCH_PREFIX}${id.raw}`\n\n return `${RELEASE_BRANCH_PREFIX}${id.name}`\n}\n\n/**\n * Render a PR title: `Release v1.2.3` / `Hotfix v1.2.3` for versions,\n * `Release <name>` / `Hotfix <name>` for names.\n */\nexport const formatPrTitle = (id: ReleaseId, type: 'regular' | 'hotfix'): string => {\n const prefix = type === 'hotfix' ? 'Hotfix' : 'Release'\n\n if (id.kind === 'version') return `${prefix} v${id.raw}`\n\n return `${prefix} ${id.name}`\n}\n\n/** Render a release-candidate PR title: `Release v1.2.3 (RC)` | `Release <name> (RC)`. */\nexport const formatRcTitle = (id: ReleaseId): string => {\n if (id.kind === 'version') return `Release v${id.raw} (RC)`\n\n return `Release ${id.name} (RC)`\n}\n\n/** Render the Jira fix-version name: `v1.2.3` | `<name>`. */\nexport const formatJiraName = (id: ReleaseId): string => {\n if (id.kind === 'version') return `v${id.raw}`\n\n return id.name\n}\n\n/** Render a short human display label: `1.2.3` | `<name>`. */\nexport const displayLabel = (id: ReleaseId): string => {\n return id.raw\n}\n\n/** True iff `branch` is a valid release branch under either scheme. */\nexport const isReleaseBranch = (branch: string | null | undefined): boolean => {\n if (branch === null || branch === undefined) return false\n\n return parseBranchName(branch) !== null\n}\n\nconst toTime = (value: string | Date | undefined): number | null => {\n if (value === undefined) return null\n\n const time = value instanceof Date ? value.getTime() : new Date(value).getTime()\n\n return Number.isNaN(time) ? null : time\n}\n\n/**\n * Comparator for {@link ReleaseId} values (locked ordering):\n * - All versions sort before all names.\n * - Versions: semver ascending (major, then minor, then patch; numeric).\n * - Names: by date ascending when both dates are provided, otherwise\n * lexicographic by name. The result is stable and deterministic.\n */\nexport const compareReleaseIds = (\n a: ReleaseId,\n b: ReleaseId,\n dates?: { a?: string | Date; b?: string | Date },\n): number => {\n if (a.kind === 'version' && b.kind === 'version') {\n if (a.semver.major !== b.semver.major) return a.semver.major - b.semver.major\n if (a.semver.minor !== b.semver.minor) return a.semver.minor - b.semver.minor\n\n return a.semver.patch - b.semver.patch\n }\n\n if (a.kind === 'version') return -1\n if (b.kind === 'version') return 1\n\n const timeA = toTime(dates?.a)\n const timeB = toTime(dates?.b)\n\n if (timeA !== null && timeB !== null && timeA !== timeB) {\n return timeA - timeB\n }\n\n if (a.name < b.name) return -1\n if (a.name > b.name) return 1\n\n return 0\n}\n", "import process from 'node:process'\nimport pino from 'pino'\nimport pretty from 'pino-pretty'\n\n// eslint-disable-next-line sonarjs/publicly-writable-directories\nexport const LOG_FILE_PATH = '/tmp/mcp-infra-kit.log'\n\nexport const initLoggerMcp = () => {\n const logLevel = process.argv.includes('--debug') ? 'debug' : 'info'\n\n const logger = pino({ level: logLevel }, pino.destination({ dest: LOG_FILE_PATH }))\n\n logger.info(`Logger initialized with level: ${logLevel}. Logging to: ${LOG_FILE_PATH}`)\n\n return logger\n}\n\nexport const initLoggerCLI = () => {\n const logLevel = process.argv.includes('--debug') ? 'debug' : 'info'\n\n const ignoreFields = ['time', 'pid', 'hostname']\n\n if (logLevel === 'debug') {\n ignoreFields.push('level')\n }\n\n const logger = pino(\n { level: logLevel },\n pretty({\n destination: 2,\n ignore: ignoreFields.join(','),\n colorize: true,\n }),\n )\n\n return logger\n}\n\n// Singleton logger instance for CLI usage\nexport const logger = initLoggerCLI()\n", "/**\n * Validation rules for a single workspace package, declared in its\n * `infra-kit.config.js`. Every field is optional: a key left unset falls back to\n * the active baseline ({@link DEFAULT_RULES} for packages, {@link ROOT_DEFAULT_RULES}\n * for the monorepo root), and a key set replaces that default wholesale (per-key,\n * no array concatenation) so a package can opt out with an explicit empty array.\n *\n * Most packages need none of these \u2014 the standard rules live in the baseline, so\n * a typical config is just `defineConfig(() => ({}))`.\n *\n * @example\n * // infra-kit.config.js\n * import { defineConfig } from 'infra-kit'\n *\n * export default defineConfig(() => ({}))\n */\nexport interface InfraKitPackageConfig {\n /** Scripts that must be present in the package's package.json `scripts` map. */\n requiredScripts?: string[]\n /** Files (relative to the package root) that must exist on disk. */\n requiredFiles?: string[]\n /** Turborepo expectations \u2014 only meaningful where a turbo.json lives (the root). */\n turbo?: {\n /** Tasks that must be defined in turbo.json `tasks`. */\n requiredTasks?: string[]\n }\n}\n\n/**\n * Accepted shapes for a package config's default export \u2014 mirrors Vite's\n * `defineConfig` input: a plain object, a sync factory, or an async factory.\n */\nexport type InfraKitPackageConfigInput =\n | InfraKitPackageConfig\n | (() => InfraKitPackageConfig)\n | (() => Promise<InfraKitPackageConfig>)\n\n/**\n * Identity helper that gives `infra-kit.config.js` authors full type inference\n * and editor autocomplete without changing the value \u2014 exactly like Vite's\n * `defineConfig`. Resolution of the factory form happens in the loader, not here.\n *\n * @example\n * export default defineConfig(() => ({}))\n *\n * @example\n * export default defineConfig(() => ({ requiredScripts: [] }))\n */\nexport const defineConfig = (config: InfraKitPackageConfigInput): InfraKitPackageConfigInput => {\n return config\n}\n\n/** Fully-resolved rules with every defaultable field present. */\nexport interface ResolvedPackageRules {\n requiredScripts: string[]\n requiredFiles: string[]\n turboTasks: string[]\n}\n\n/**\n * Baseline rules for a standard TypeScript workspace package, applied to any key\n * a package leaves unset. These are the \"under the hood\" defaults so a conforming\n * package's config can stay empty; non-standard packages override the relevant key.\n */\nexport const DEFAULT_RULES: Readonly<ResolvedPackageRules> = {\n requiredScripts: ['build', 'ts-check', 'eslint-check', 'prettier-check', 'test'],\n requiredFiles: ['tsconfig.json', 'eslint.config.js', 'readme.md'],\n turboTasks: [],\n}\n\n/**\n * Baseline rules for the monorepo root (`infra-kit audit --root`). Checks the\n * root commands, the workspace/turbo files, and that the turbo pipeline defines\n * the expected tasks \u2014 so the root's own config can also stay empty.\n */\nexport const ROOT_DEFAULT_RULES: Readonly<ResolvedPackageRules> = {\n requiredScripts: ['build', 'dev', 'test', 'qa', 'check', 'fix'],\n requiredFiles: ['turbo.json', 'pnpm-workspace.yaml'],\n turboTasks: ['build', 'test', 'ts-check', 'eslint-check', 'prettier-check', 'check'],\n}\n\n/**\n * Merge a parsed package config over a baseline. Each key is replaced wholesale\n * when the package provides it, otherwise the baseline value is used.\n *\n * @example\n * resolvePackageConfig({ requiredScripts: [] })\n * // => { requiredScripts: [], requiredFiles: [...DEFAULT_RULES.requiredFiles], turboTasks: [] }\n */\nexport const resolvePackageConfig = (\n config: InfraKitPackageConfig,\n baseline: Readonly<ResolvedPackageRules> = DEFAULT_RULES,\n): ResolvedPackageRules => {\n return {\n requiredScripts: config.requiredScripts ?? [...baseline.requiredScripts],\n requiredFiles: config.requiredFiles ?? [...baseline.requiredFiles],\n turboTasks: config.turbo?.requiredTasks ?? [...baseline.turboTasks],\n }\n}\n", "import { z } from 'zod'\n\n/**\n * Schema for the resolved (post-factory) package config object. `strictObject`\n * rejects unknown keys so typos in `infra-kit.config.ts` surface as validation\n * errors instead of being silently ignored.\n *\n * Kept in its own module \u2014 separate from the public `defineConfig`/types entry \u2014\n * so the published `infra-kit` type surface stays free of a `zod` import.\n */\nexport const packageConfigSchema = z.strictObject({\n requiredScripts: z.array(z.string().min(1)).optional(),\n requiredFiles: z.array(z.string().min(1)).optional(),\n turbo: z\n .strictObject({\n requiredTasks: z.array(z.string().min(1)).optional(),\n })\n .optional(),\n})\n", "import fs from 'node:fs/promises'\n\n/**\n * Resolve whether a path is reachable, suppressing ENOENT into a boolean.\n *\n * @example\n * await pathExists('/etc/hosts') // => true\n * await pathExists('/nope') // => false\n */\nexport const pathExists = async (target: string): Promise<boolean> => {\n try {\n await fs.access(target)\n\n return true\n } catch {\n return false\n }\n}\n", "import path from 'node:path'\n\nimport { DEFAULT_RULES } from 'src/lib/package-config'\nimport type { ResolvedPackageRules } from 'src/lib/package-config'\n\nimport { checkConfig, checkFiles, checkScripts, checkTurbo } from './checks'\nimport { readPackageJson } from './loader'\nimport type { PackageCheck, PackageValidationResult } from './types'\n\n// Re-exported on the historical import path so consumers and tests that reach\n// for the loader through `package-validator` keep resolving after the split.\nexport { discoverPackages, loadPackageConfig } from './loader'\nexport type { PackageCheck, PackageValidationResult } from './types'\n\n/**\n * Validate a single directory against its `infra-kit.config.ts` rules: the config\n * must be present and valid, every required script must be declared, every\n * required file must exist, and (root only) every required turbo task must be\n * defined. When the config fails to load, only that check is reported (the rules\n * are unknown, so the rule-based checks are skipped). `baseline` selects which\n * under-the-hood defaults apply \u2014 package defaults or {@link ROOT_DEFAULT_RULES}.\n *\n * @example\n * const result = await validatePackage('/repo/packages/serverless-config')\n * // result.passed reflects the package's conformance; result.checks lists each check\n */\nexport const validatePackage = async (\n packageDir: string,\n baseline: Readonly<ResolvedPackageRules> = DEFAULT_RULES,\n): Promise<PackageValidationResult> => {\n const pkgJson = await readPackageJson(packageDir)\n const packageName = pkgJson.name ?? path.basename(packageDir)\n\n const { check: configCheck, rules } = await checkConfig(packageDir, baseline)\n const checks: PackageCheck[] = [configCheck]\n\n if (rules) {\n checks.push(...checkScripts(pkgJson.scripts ?? {}, rules.requiredScripts))\n checks.push(...(await checkFiles(packageDir, rules.requiredFiles)))\n checks.push(...(await checkTurbo(packageDir, rules.turboTasks)))\n }\n\n const passed = checks.every((check) => {\n return check.status === 'pass'\n })\n\n return { packageDir, packageName, checks, passed }\n}\n", "import fs from 'node:fs/promises'\nimport path from 'node:path'\nimport { pathToFileURL } from 'node:url'\nimport { z } from 'zod'\n\nimport { DEFAULT_RULES, packageConfigSchema, resolvePackageConfig } from 'src/lib/package-config'\nimport type { ResolvedPackageRules } from 'src/lib/package-config'\n\nimport { pathExists } from '../fs-utils'\n\n/** Per-package config filename every validated package must provide. */\nexport const PACKAGE_CONFIG_FILE = 'infra-kit.config.ts'\n\ninterface PackageJsonShape {\n name?: string\n scripts?: Record<string, string>\n}\n\n/**\n * Read and JSON-parse a package.json, returning an empty object when it is\n * missing or unreadable so callers can degrade into a clear \"missing\" check.\n */\nexport const readPackageJson = async (packageDir: string): Promise<PackageJsonShape> => {\n try {\n const raw = await fs.readFile(path.join(packageDir, 'package.json'), 'utf-8')\n\n return JSON.parse(raw) as PackageJsonShape\n } catch {\n return {}\n }\n}\n\n/**\n * Load, resolve, and validate a package's `infra-kit.config.ts`.\n *\n * Dynamic-imports the file (ESM), resolves the Vite-style factory or object\n * default export, validates the result against {@link packageConfigSchema}, and\n * merges it over the defaults. Throws a descriptive error when the file is\n * absent or the resolved config violates the schema.\n *\n * @example\n * await loadPackageConfig('/repo/packages/serverless-config')\n * // => { requiredScripts: [], requiredFiles: ['serverless.common.yml'], turboTasks: [] }\n */\nexport const loadPackageConfig = async (\n packageDir: string,\n baseline: Readonly<ResolvedPackageRules> = DEFAULT_RULES,\n): Promise<ResolvedPackageRules> => {\n const configPath = path.join(packageDir, PACKAGE_CONFIG_FILE)\n\n if (!(await pathExists(configPath))) {\n throw new Error(`${PACKAGE_CONFIG_FILE} not found at ${configPath}`)\n }\n\n // Cache-bust with the file mtime so repeated loads (long-running MCP server)\n // pick up edits without a process restart. `.ts` configs load via Node's\n // native type stripping (the repo requires Node >= 24).\n const stat = await fs.stat(configPath)\n const moduleUrl = `${pathToFileURL(configPath).href}?mtime=${Number(stat.mtimeMs)}`\n\n const imported = (await import(moduleUrl)) as { default?: unknown }\n const rawExport = imported.default\n\n if (rawExport === undefined) {\n throw new Error(`${PACKAGE_CONFIG_FILE} at ${configPath} has no default export`)\n }\n\n const resolvedExport = typeof rawExport === 'function' ? await (rawExport as () => unknown)() : rawExport\n\n const parsed = packageConfigSchema.safeParse(resolvedExport)\n\n if (!parsed.success) {\n throw new Error(`Invalid ${PACKAGE_CONFIG_FILE} at ${configPath}: ${z.prettifyError(parsed.error)}`)\n }\n\n return resolvePackageConfig(parsed.data, baseline)\n}\n", "import fs from 'node:fs/promises'\nimport path from 'node:path'\nimport yaml from 'yaml'\n\nimport { pathExists } from '../fs-utils'\n\nconst WORKSPACE_FILE = 'pnpm-workspace.yaml'\n\n/**\n * List the immediate child directories of `dir`, returning `[]` when the path\n * can't be read (e.g. the parent glob segment matched a non-existent dir).\n */\nconst listChildDirs = async (dir: string): Promise<string[]> => {\n const entries = await fs.readdir(dir, { withFileTypes: true }).catch(() => {\n return []\n })\n\n return entries\n .filter((entry) => {\n return entry.isDirectory()\n })\n .map((entry) => {\n return path.join(dir, entry.name)\n })\n}\n\n/**\n * Apply one glob segment to a set of directories: `*` fans out to every child\n * directory, a literal segment keeps the dirs where that child path exists.\n */\nconst expandSegment = async (dirs: string[], segment: string): Promise<string[]> => {\n const next: string[] = []\n\n for (const dir of dirs) {\n if (segment === '*') {\n next.push(...(await listChildDirs(dir)))\n\n continue\n }\n\n const candidate = path.join(dir, segment)\n\n if (await pathExists(candidate)) {\n next.push(candidate)\n }\n }\n\n return next\n}\n\n/**\n * Expand a single pnpm-workspace glob (only the `*` segment wildcard is\n * supported, which covers every pattern this monorepo uses) into directories.\n */\nconst expandGlob = async (projectRoot: string, pattern: string): Promise<string[]> => {\n let dirs = [projectRoot]\n\n for (const segment of pattern.split('/')) {\n dirs = await expandSegment(dirs, segment)\n }\n\n return dirs\n}\n\n/**\n * Discover validatable workspace packages from `pnpm-workspace.yaml`.\n *\n * Negation patterns (`!\u2026`) and everything under `vendor/` are excluded \u2014\n * vendor is mirrored from `starter-workspace` and is checksum-enforced by\n * `pnpm vendor:check`, so its configs are owned upstream, not here. Only\n * directories that actually contain a package.json are returned.\n *\n * @example\n * await discoverPackages('/repo')\n * // => ['/repo/apps/infra-kit/cli', '/repo/packages/serverless-config']\n */\nexport const discoverPackages = async (projectRoot: string): Promise<string[]> => {\n const raw = await fs.readFile(path.join(projectRoot, WORKSPACE_FILE), 'utf-8')\n const parsed = (yaml.parse(raw) ?? {}) as { packages?: string[] }\n\n const patterns = (parsed.packages ?? []).filter((pattern) => {\n return !pattern.startsWith('!') && !pattern.startsWith('vendor')\n })\n\n const found = new Set<string>()\n\n for (const pattern of patterns) {\n const dirs = await expandGlob(projectRoot, pattern)\n\n for (const dir of dirs) {\n if (await pathExists(path.join(dir, 'package.json'))) {\n found.add(dir)\n }\n }\n }\n\n return [...found].sort()\n}\n", "import { DEFAULT_RULES } from 'src/lib/package-config'\nimport type { ResolvedPackageRules } from 'src/lib/package-config'\n\nimport { PACKAGE_CONFIG_FILE, loadPackageConfig } from '../loader'\nimport type { PackageCheck } from '../types'\n\n/**\n * Build the \"config present and valid\" check, returning the resolved rules when\n * the load succeeds so the caller can run the rule-based checks against them.\n * When the config fails to load the rules are `null` and the caller skips the\n * rule-based checks (the expectations are unknown).\n */\nexport const checkConfig = async (\n packageDir: string,\n baseline: Readonly<ResolvedPackageRules> = DEFAULT_RULES,\n): Promise<{ check: PackageCheck; rules: ResolvedPackageRules | null }> => {\n try {\n const rules = await loadPackageConfig(packageDir, baseline)\n\n return {\n check: { name: PACKAGE_CONFIG_FILE, status: 'pass', message: 'present and valid' },\n rules,\n }\n } catch (err) {\n return {\n check: { name: PACKAGE_CONFIG_FILE, status: 'fail', message: (err as Error).message },\n rules: null,\n }\n }\n}\n", "import fs from 'node:fs/promises'\nimport path from 'node:path'\n\nimport type { PackageCheck } from '../types'\n\n/**\n * Check that every required file exists relative to the package root AND is a\n * regular file. A directory that happens to share the required name fails \u2014 a\n * required `readme.md` must be the file, not a folder.\n */\nexport const checkFiles = async (packageDir: string, requiredFiles: string[]): Promise<PackageCheck[]> => {\n return Promise.all(\n requiredFiles.map(async (file) => {\n const stat = await fs.stat(path.join(packageDir, file)).catch(() => {\n return null\n })\n\n if (!stat) {\n return { name: `file:${file}`, status: 'fail' as const, message: `missing file: ${file}` }\n }\n\n if (!stat.isFile()) {\n return { name: `file:${file}`, status: 'fail' as const, message: `not a file: ${file} (found a directory)` }\n }\n\n return { name: `file:${file}`, status: 'pass' as const, message: 'exists' }\n }),\n )\n}\n", "import type { PackageCheck } from '../types'\n\n/**\n * Check that every required script is present in the package.json `scripts` map\n * and carries a runnable command. A key declared with an empty or whitespace-only\n * value fails as well \u2014 an empty script silently no-ops in CI, so presence alone\n * is not enough.\n */\nexport const checkScripts = (scripts: Record<string, string>, requiredScripts: string[]): PackageCheck[] => {\n return requiredScripts.map((script) => {\n const value = scripts[script]\n\n if (typeof value !== 'string') {\n return { name: `script:${script}`, status: 'fail', message: `missing \"${script}\" in package.json scripts` }\n }\n\n if (value.trim().length === 0) {\n return { name: `script:${script}`, status: 'fail', message: `\"${script}\" is empty in package.json scripts` }\n }\n\n return { name: `script:${script}`, status: 'pass', message: 'defined' }\n })\n}\n", "import fs from 'node:fs/promises'\nimport path from 'node:path'\n\nimport type { PackageCheck } from '../types'\n\nconst TURBO_FILE = 'turbo.json'\n\n/**\n * Check that every required turbo task is defined in turbo.json `tasks`. A root\n * task may be keyed as either `name` or `//#name`, so both forms count as present.\n * Runs only when the resolved rules ask for turbo tasks (the monorepo root).\n *\n * Reports a single clear diagnostic when turbo.json is unreadable or carries no\n * `tasks` object, rather than emitting one identical \"missing task\" line per\n * required task.\n */\nexport const checkTurbo = async (packageDir: string, requiredTasks: string[]): Promise<PackageCheck[]> => {\n if (requiredTasks.length === 0) {\n return []\n }\n\n let parsed: { tasks?: Record<string, unknown> }\n\n try {\n const raw = await fs.readFile(path.join(packageDir, TURBO_FILE), 'utf-8')\n\n parsed = JSON.parse(raw) as { tasks?: Record<string, unknown> }\n } catch (err) {\n return [{ name: TURBO_FILE, status: 'fail', message: `cannot read/parse ${TURBO_FILE}: ${(err as Error).message}` }]\n }\n\n const tasks = parsed.tasks\n\n if (tasks === null || typeof tasks !== 'object') {\n return [{ name: TURBO_FILE, status: 'fail', message: `no \"tasks\" object defined in ${TURBO_FILE}` }]\n }\n\n return requiredTasks.map((task) => {\n const defined = task in tasks || `//#${task}` in tasks\n\n return {\n name: `turbo:${task}`,\n status: defined ? 'pass' : 'fail',\n message: defined ? 'defined' : `missing turbo task \"${task}\" in ${TURBO_FILE}`,\n }\n })\n}\n", "import type { z } from 'zod'\n\nexport interface ToolsExecutionResult<TStructured = Record<string, unknown>> {\n [x: string]: unknown\n content: {\n type: 'text'\n text: string\n }[]\n structuredContent?: TStructured\n}\n\nexport interface RequiredConfirmedOptionArg {\n confirmedCommand: boolean\n}\n\nexport interface McpTool<TIn extends z.ZodRawShape = z.ZodRawShape, TOut extends z.ZodRawShape = z.ZodRawShape> {\n name: string\n description: string\n inputSchema: TIn\n outputSchema: TOut\n handler: (\n params: z.infer<z.ZodObject<TIn>> & RequiredConfirmedOptionArg,\n ) => Promise<ToolsExecutionResult<z.infer<z.ZodObject<TOut>>>>\n}\n\n/**\n * Build the dual-channel content array shared by every MCP tool. Narrows the\n * literal `type: 'text'` so handlers can use inferred return types without TS\n * widening `type` to `string` \u2014 which would otherwise break assignability\n * against the MCP SDK's content union.\n *\n * @example\n * return {\n * content: textContent(JSON.stringify(structuredContent, null, 2)),\n * structuredContent,\n * }\n */\nexport const textContent = (text: string): ToolsExecutionResult['content'] => {\n return [{ type: 'text', text }]\n}\n\n/**\n * Factory that ties the handler's return type to the declared `outputSchema`\n * so `structuredContent` is checked against the schema at compile time. If a\n * handler accidentally drops or renames a field, TS errors at the registration\n * site rather than at runtime in an MCP client.\n *\n * @example\n * export const envLoadMcpTool = defineMcpTool({\n * name: 'env-load',\n * description: '...',\n * inputSchema: { config: z.string() },\n * outputSchema: {\n * filePath: z.string(),\n * variableCount: z.number(),\n * project: z.string(),\n * config: z.string(),\n * },\n * handler: envLoad,\n * })\n */\nexport const defineMcpTool = <TIn extends z.ZodRawShape, TOut extends z.ZodRawShape>(\n tool: McpTool<TIn, TOut>,\n): McpTool<TIn, TOut> => {\n return tool\n}\n", "import fs from 'node:fs/promises'\nimport os from 'node:os'\nimport path from 'node:path'\nimport process from 'node:process'\nimport { $ } from 'zx'\n\nimport { getInfraKitConfigPaths, resetInfraKitConfigCache } from 'src/lib/infra-kit-config'\nimport { logger } from 'src/lib/logger'\nimport type { ToolsExecutionResult } from 'src/types'\n\n/**\n * Resolve whether a file is reachable, suppressing ENOENT into a boolean.\n *\n * @example\n * await fileExists('/etc/hosts') // => true\n * await fileExists('/nope.txt') // => false\n */\nconst fileExists = async (filePath: string): Promise<boolean> => {\n try {\n await fs.access(filePath)\n\n return true\n } catch {\n return false\n }\n}\n\n/**\n * Replace the user's home prefix with `~` so logged paths stay short and\n * portable across machines. Leaves non-home paths untouched.\n *\n * @example\n * // os.homedir() === '/Users/arthur'\n * tildify('/Users/arthur/.infra-kit/config.json') // => '~/.infra-kit/config.json'\n * tildify('/etc/hosts') // => '/etc/hosts'\n */\nconst tildify = (filePath: string): string => {\n const home = os.homedir()\n\n return filePath.startsWith(home) ? `~${filePath.slice(home.length)}` : filePath\n}\n\n/**\n * Print the file paths that participate in the config merge chain along with\n * existence markers, so the user can see at a glance which override layers\n * are active.\n *\n * @example\n * // CLI: `infra-kit config path`\n * // INFO: Project name: api\n * // INFO: Config merge chain (later overrides earlier):\n * // INFO: [\u2713] project (committed) ~/projects/api/infra-kit.json\n * // INFO: [ ] user global ~/.infra-kit/config.json\n * // INFO: [\u2713] user project ~/.infra-kit/projects/api/infra-kit.json\n */\nexport const configPath = async (): Promise<ToolsExecutionResult> => {\n const paths = await getInfraKitConfigPaths()\n\n const rows: { label: string; path: string; exists: boolean }[] = await Promise.all(\n [\n { label: 'project (committed)', path: paths.main },\n { label: 'user global', path: paths.userGlobal },\n { label: 'user project', path: paths.userProject },\n ].map(async (row) => {\n return { ...row, exists: await fileExists(row.path) }\n }),\n )\n\n logger.info(`Project name: ${paths.projectName}\\n`)\n logger.info('Config merge chain (later overrides earlier):\\n')\n\n for (const row of rows) {\n const marker = row.exists ? ' [\u2713]' : ' [ ]'\n\n logger.info(`${marker} ${row.label.padEnd(22)} ${tildify(row.path)}`)\n }\n\n const structuredContent = {\n projectName: paths.projectName,\n layers: rows.map((r) => {\n return { label: r.label, path: r.path, exists: r.exists }\n }),\n }\n\n return {\n content: [{ type: 'text', text: JSON.stringify(structuredContent, null, 2) }],\n structuredContent,\n }\n}\n\n/**\n * Open the user-scope per-project override file in $EDITOR, creating the\n * parent directory and a stub file on first use. Resets the config cache\n * after the editor exits so subsequent reads pick up edits without a restart.\n *\n * @example\n * // CLI: `infra-kit config edit`\n * // first run \u2014 creates ~/.infra-kit/projects/api/infra-kit.json ({}) + a sibling\n * // infra-kit.example.jsonc reference, then $EDITOR opens the .json\n * // subsequent runs \u2014 opens the existing file as-is\n */\nexport const configEdit = async (): Promise<ToolsExecutionResult> => {\n const paths = await getInfraKitConfigPaths()\n const editor = process.env.EDITOR || process.env.VISUAL || 'vi'\n\n await fs.mkdir(path.dirname(paths.userProject), { recursive: true })\n\n if (!(await fileExists(paths.userProject))) {\n // JSON can't carry comments, so seed an empty-but-valid config and drop the\n // annotated guidance next to it in a non-loaded .example.jsonc the loader\n // never reads (it only globs the three exact `infra-kit.json` filenames).\n const examplePath = exampleSiblingPath(paths.userProject)\n\n await fs.writeFile(paths.userProject, '{}\\n', 'utf-8')\n await fs.writeFile(examplePath, buildUserProjectExample(paths.projectName), 'utf-8')\n\n logger.info(`Created ${tildify(paths.userProject)} \u2014 see ${tildify(examplePath)} for the annotated reference.`)\n }\n\n logger.info(`Opening ${tildify(paths.userProject)} in ${editor}`)\n\n await $({ stdio: 'inherit' })`${editor} ${paths.userProject}`\n\n resetInfraKitConfigCache()\n\n const structuredContent = { path: paths.userProject, editor }\n\n return {\n content: [{ type: 'text', text: JSON.stringify(structuredContent, null, 2) }],\n structuredContent,\n }\n}\n\n/**\n * Derive the non-loaded `.example.jsonc` sibling for a config path.\n *\n * @example\n * exampleSiblingPath('/u/.infra-kit/projects/api/infra-kit.json')\n * // => '/u/.infra-kit/projects/api/infra-kit.example.jsonc'\n */\nconst exampleSiblingPath = (jsonPath: string): string => {\n return jsonPath.replace(/\\.json$/, '.example.jsonc')\n}\n\n/**\n * Annotated JSONC reference for the user-scope per-project override layer.\n * Written alongside the real `{}` config so the guidance the old YAML stub\n * carried in comments survives the move to JSON.\n *\n * @example\n * buildUserProjectExample('api')\n * // => '// infra-kit user override for api \u2026\\n{ \u2026 }\\n'\n */\nconst buildUserProjectExample = (projectName: string): string => {\n return `// infra-kit user override for ${projectName} \u2014 ~/.infra-kit/projects/${projectName}/infra-kit.json\n//\n// Layer 3 (highest precedence) of the config merge chain. Shallow-merged on top\n// of <repo>/infra-kit.json and ~/.infra-kit/config.json \u2014 top-level keys\n// (environments, envManagement, ide, taskManager, worktrees) replace wholesale.\n//\n// This .example.jsonc is reference only \u2014 it is NOT loaded. Put real overrides\n// in the sibling infra-kit.json (strict JSON: no comments, double-quoted keys).\n{\n // \"worktrees\": { \"openInGithubDesktop\": false, \"openInCmux\": true }\n}\n`\n}\n", "import fs from 'node:fs/promises'\nimport os from 'node:os'\nimport path from 'node:path'\nimport { z } from 'zod'\n\nimport { getProjectRoot, getRepoName } from 'src/lib/git-utils'\n\nconst INFRA_KIT_CONFIG_FILE = 'infra-kit.json'\n\nconst USER_CONFIG_DIR_NAME = '.infra-kit'\nconst USER_GLOBAL_CONFIG_FILE = 'config.json'\nconst USER_PROJECTS_DIR = 'projects'\n\n// envManagement\nconst dopplerEnvManagementSchema = z.object({\n provider: z.literal('doppler'),\n config: z.object({\n name: z.string().min(1),\n }),\n})\n\nconst envManagementSchema = z.discriminatedUnion('provider', [dopplerEnvManagementSchema])\n\n// ide\n// There is one attach style: each worktree is added to the configured editor's\n// workspace and opened (no per-window mode). Cursor needs a `.code-workspace`\n// path to reconcile its `folders` array against.\nconst cursorIdeConfigSchema = z.object({\n workspaceConfigPath: z.string().min(1),\n})\n\nconst cursorIdeSchema = z.object({\n provider: z.literal('cursor'),\n config: cursorIdeConfigSchema,\n})\n\n// Zed has no portable workspace file (no `.code-workspace`) and no folder-remove\n// CLI: a multi-worktree workspace is realized by a single `zed <root> <wt...>`\n// invocation. So `config` carries no settings \u2014 there's no path to point at.\nconst zedIdeConfigSchema = z.object({})\n\nconst zedIdeSchema = z.object({\n provider: z.literal('zed'),\n config: zedIdeConfigSchema,\n})\n\nconst ideSchema = z.discriminatedUnion('provider', [cursorIdeSchema, zedIdeSchema])\n\n// `ide` accepts a single provider (back-compat) OR an array to drive multiple\n// editors at once (e.g. Cursor + Zed). Normalized to an array everywhere via\n// `resolveConfiguredIdes`. Uniqueness-by-provider is enforced at parse time by a\n// `.superRefine` on the full config schema (see below) \u2014 not here, so the message\n// survives `z.union` error aggregation.\nconst idesSchema = z.union([ideSchema, z.array(ideSchema).min(1)])\n\n// taskManager\nconst jiraTaskManagerSchema = z.object({\n provider: z.literal('jira'),\n config: z.object({\n baseUrl: z.string().url(),\n projectId: z.number().int().positive(),\n }),\n})\n\nconst taskManagerSchema = z.discriminatedUnion('provider', [jiraTaskManagerSchema])\n\n// worktrees prompt defaults\nconst worktreesConfigSchema = z.object({\n openInGithubDesktop: z.boolean().optional(),\n openInCmux: z.boolean().optional(),\n})\n\n// Base object shape, kept separate so `.partial()` (which only works on a plain\n// ZodObject, not the `.superRefine`-wrapped full schema) can derive the override\n// schema from it.\nconst infraKitConfigObject = z.object({\n environments: z.array(z.string().min(1)).min(1),\n envManagement: envManagementSchema,\n ide: idesSchema.optional(),\n taskManager: taskManagerSchema.optional(),\n worktrees: worktreesConfigSchema.optional(),\n})\n\n// Full schema = base object + a parse-time uniqueness check on the `ide` array.\n// This runs inside the *merged* `safeParse` in getInfraKitConfig, so it's the\n// gate for the final config. (The override layers use the `.partial()` form\n// below, which drops this object-level refinement \u2014 acceptable, the merged\n// parse is authoritative.)\nexport const infraKitConfigSchema = infraKitConfigObject.superRefine((cfg, ctx) => {\n if (!Array.isArray(cfg.ide)) return\n\n const seen = new Set<string>()\n\n for (const entry of cfg.ide) {\n if (seen.has(entry.provider)) {\n ctx.addIssue({\n code: 'custom',\n message: 'each IDE provider may appear at most once',\n path: ['ide'],\n })\n\n return\n }\n\n seen.add(entry.provider)\n }\n})\n\nexport const infraKitOverrideConfigSchema = infraKitConfigObject.partial()\n\nexport type InfraKitConfig = z.infer<typeof infraKitConfigSchema>\n\n/** A single resolved IDE entry (`{ provider, config }`). */\nexport type ConfiguredIde = z.infer<typeof ideSchema>\n\n/**\n * Normalize the `ide` config (single object, array, or unset) into a flat list.\n * Validation-free: assumes already-parsed input (uniqueness is enforced by the\n * schema). The one source of truth for \"which editors are configured.\"\n *\n * @example\n * resolveConfiguredIdes({ ide: { provider: 'cursor', config: {...} } }) // => [cursor]\n * resolveConfiguredIdes({ ide: [cursor, zed] }) // => [cursor, zed]\n * resolveConfiguredIdes({}) // => []\n */\nexport const resolveConfiguredIdes = (config: InfraKitConfig): ConfiguredIde[] => {\n const ide = config.ide\n\n if (!ide) return []\n\n return Array.isArray(ide) ? ide : [ide]\n}\n\nexport interface InfraKitConfigPaths {\n /** Committed project config (required). */\n main: string\n /** User-scope global overrides applied to every project. */\n userGlobal: string\n /** User-scope per-project overrides \u2014 `<userProjectsDir>/<projectName>/infra-kit.json`. */\n userProject: string\n /** Repo basename (`path.basename(projectRoot)`) used to namespace the user-project file. */\n projectName: string\n}\n\ninterface CacheEntry {\n mtimes: Record<keyof Omit<InfraKitConfigPaths, 'projectName'>, number | null>\n value: InfraKitConfig\n}\n\nlet cached: CacheEntry | null = null\n\n/**\n * Resolve every file path that participates in the config merge chain. Always\n * returns paths even for files that don't yet exist, so callers can use them\n * for \"where would my override go?\" prompts.\n *\n * @example\n * const paths = await getInfraKitConfigPaths()\n * // {\n * // main: '/Users/arthur/projects/api/infra-kit.json',\n * // userGlobal: '/Users/arthur/.infra-kit/config.json',\n * // userProject: '/Users/arthur/.infra-kit/projects/api/infra-kit.json',\n * // projectName: 'api',\n * // }\n */\nexport const getInfraKitConfigPaths = async (): Promise<InfraKitConfigPaths> => {\n const projectRoot = await getProjectRoot()\n const projectName = await getRepoName()\n const userConfigDir = path.join(os.homedir(), USER_CONFIG_DIR_NAME)\n\n return {\n main: path.join(projectRoot, INFRA_KIT_CONFIG_FILE),\n userGlobal: path.join(userConfigDir, USER_GLOBAL_CONFIG_FILE),\n userProject: path.join(userConfigDir, USER_PROJECTS_DIR, projectName, INFRA_KIT_CONFIG_FILE),\n projectName,\n }\n}\n\n/**\n * Read and validate `infra-kit.json`, with optional override layers shallow-merged\n * on top in this order (later wins):\n * 1. project `infra-kit.json` \u2014 committed source of truth\n * 2. `~/.infra-kit/config.json` \u2014 user-global defaults\n * 3. `~/.infra-kit/projects/<repo-name>/infra-kit.json` \u2014 user-scope per-project overrides\n *\n * Top-level keys (entire capability sections like `ide`, `envManagement`)\n * replace wholesale. Results are cached per file mtimes so the long-running\n * MCP server picks up edits without a restart.\n *\n * @example\n * // infra-kit.json: { \"environments\": [\"dev\"], \"envManagement\": { \"provider\": \"doppler\", \"config\": { \"name\": \"p\" } } }\n * // ~/.infra-kit/config.json: { \"ide\": { \"provider\": \"cursor\", \"config\": { \"workspaceConfigPath\": \"./ws.code-workspace\" } } }\n * const cfg = await getInfraKitConfig()\n * // => { environments: ['dev'], envManagement: {...}, ide: { provider: 'cursor', config: { workspaceConfigPath: './ws.code-workspace' } } }\n */\nexport const getInfraKitConfig = async (): Promise<InfraKitConfig> => {\n const paths = await getInfraKitConfigPaths()\n\n let mainStat: Awaited<ReturnType<typeof fs.stat>>\n\n try {\n mainStat = await fs.stat(paths.main)\n } catch {\n cached = null\n\n // Bridge the YAML\u2192JSON cutover: if a legacy infra-kit.yml is sitting where\n // the JSON config should be, point the user at the one-shot migration.\n const legacyYmlPath = paths.main.replace(/\\.json$/, '.yml')\n\n if (await statIfExists(legacyYmlPath)) {\n throw new Error(\n `infra-kit.json not found at ${paths.main}. A legacy infra-kit.yml exists \u2014 run \\`infra-kit init\\` to convert it.`,\n )\n }\n\n throw new Error(`infra-kit.json not found at ${paths.main}`)\n }\n\n const [userGlobalStat, userProjectStat] = await Promise.all([\n statIfExists(paths.userGlobal),\n statIfExists(paths.userProject),\n ])\n\n const mtimes = {\n main: Number(mainStat.mtimeMs),\n userGlobal: userGlobalStat ? Number(userGlobalStat.mtimeMs) : null,\n userProject: userProjectStat ? Number(userProjectStat.mtimeMs) : null,\n }\n\n if (cached && shallowEqual(cached.mtimes, mtimes)) {\n return cached.value\n }\n\n const layers: ConfigLayer[] = [\n { label: 'infra-kit.json', path: paths.main, required: true },\n { label: '~/.infra-kit/config.json', path: paths.userGlobal, required: false },\n {\n label: `~/.infra-kit/projects/${paths.projectName}/infra-kit.json`,\n path: paths.userProject,\n required: false,\n },\n ]\n\n let merged: Record<string, unknown> = {}\n\n for (const layer of layers) {\n const data = await loadLayer(layer)\n\n if (data === null) continue\n\n merged = { ...merged, ...data }\n }\n\n const finalResult = infraKitConfigSchema.safeParse(merged)\n\n if (!finalResult.success) {\n throw new Error(`Invalid merged infra-kit config: ${z.prettifyError(finalResult.error)}`)\n }\n\n cached = { mtimes, value: finalResult.data }\n\n return finalResult.data\n}\n\n/**\n * For tests \u2014 drops the in-memory cache so the next read hits disk.\n *\n * @example\n * resetInfraKitConfigCache()\n * await getInfraKitConfig() // re-reads files even if mtimes look unchanged\n */\nexport const resetInfraKitConfigCache = (): void => {\n cached = null\n}\n\n/**\n * `fs.stat` that returns `null` instead of throwing on ENOENT. Used so the\n * resolver can probe optional files in the merge chain without try/catch noise.\n *\n * @example\n * const stat = await statIfExists('/does/not/exist') // => null\n */\nconst statIfExists = async (filePath: string): Promise<Awaited<ReturnType<typeof fs.stat>> | null> => {\n try {\n return await fs.stat(filePath)\n } catch {\n return null\n }\n}\n\n/**\n * `fs.readFile` that returns `null` instead of throwing on ENOENT.\n *\n * @example\n * const raw = await readIfExists('/missing.json') // => null\n * const raw = await readIfExists('/exists.json') // => '{ \"environments\": [\"dev\"] }\\n'\n */\nconst readIfExists = async (filePath: string): Promise<string | null> => {\n try {\n return await fs.readFile(filePath, 'utf-8')\n } catch {\n return null\n }\n}\n\n/**\n * Reference-equality comparison of every key in two flat records. Used to\n * cheaply detect whether the cached mtime fingerprint still matches.\n *\n * @example\n * shallowEqual({ a: 1, b: 2 }, { a: 1, b: 2 }) // => true\n * shallowEqual({ a: 1 }, { a: 1, b: 2 }) // => false\n * shallowEqual({ a: 1 }, { a: 2 }) // => false\n */\nconst shallowEqual = <T extends Record<string, unknown>>(a: T, b: T): boolean => {\n const keys = Object.keys(a)\n\n if (keys.length !== Object.keys(b).length) return false\n\n return keys.every((k) => {\n return a[k] === b[k]\n })\n}\n\ninterface ConfigLayer {\n label: string\n path: string\n required: boolean\n}\n\n/**\n * Read a single layer of the merge chain: parse the JSON if the file exists\n * and validate it against the override schema. Returns `null` if an optional\n * layer is missing; throws if the layer is required, malformed, or invalid.\n * An empty/whitespace-only file is treated as `{}` (JSON.parse would throw).\n *\n * @example\n * await loadLayer({ label: '~/.infra-kit/config.json', path: '/missing.json', required: false })\n * // => null\n *\n * @example\n * // /home/me/.infra-kit/config.json: '{ \"ide\": { \"provider\": \"cursor\", \"config\": { \"workspaceConfigPath\": \"./ws.code-workspace\" } } }'\n * await loadLayer({ label: '~/.infra-kit/config.json', path: '/home/me/.infra-kit/config.json', required: false })\n * // => { ide: { provider: 'cursor', config: { workspaceConfigPath: './ws.code-workspace' } } }\n */\nconst loadLayer = async (layer: ConfigLayer): Promise<Record<string, unknown> | null> => {\n const raw = await readIfExists(layer.path)\n\n if (raw === null) {\n if (layer.required) {\n throw new Error(`${layer.label} not found at ${layer.path}`)\n }\n\n return null\n }\n\n let parsedRaw: unknown\n\n try {\n parsedRaw = raw.trim() === '' ? {} : JSON.parse(raw)\n } catch (err) {\n throw new Error(`Invalid JSON in ${layer.label} at ${layer.path}: ${(err as Error).message}`)\n }\n\n const result = infraKitOverrideConfigSchema.safeParse(parsedRaw)\n\n if (!result.success) {\n throw new Error(`Invalid ${layer.label} at ${layer.path}: ${z.prettifyError(result.error)}`)\n }\n\n return result.data as Record<string, unknown>\n}\n", "import fs from 'node:fs'\nimport os from 'node:os'\nimport path from 'node:path'\nimport { z } from 'zod'\nimport { $ } from 'zx'\n\nimport {\n AGENTS_IMPORT_END,\n AGENTS_IMPORT_START,\n AGENTS_MARKER_END,\n AGENTS_MARKER_START,\n} from 'src/commands/init/agent-files'\nimport { MARKER_END, MARKER_START, buildShellBlock } from 'src/commands/init/init'\nimport { getProjectRoot } from 'src/lib/git-utils/git-utils'\nimport {\n getInfraKitConfig,\n getInfraKitConfigPaths,\n resetInfraKitConfigCache,\n resolveConfiguredIdes,\n} from 'src/lib/infra-kit-config'\nimport { logger } from 'src/lib/logger'\nimport { hasManagedBlock } from 'src/lib/managed-block'\nimport { defineMcpTool, textContent } from 'src/types'\n\ninterface CheckResult {\n name: string\n status: 'pass' | 'fail'\n message: string\n}\n\nconst checkCommand = async (\n name: string,\n command: string[],\n successMsg: string,\n failMsg: string,\n): Promise<CheckResult> => {\n try {\n await $`${command}`\n\n return { name, status: 'pass', message: successMsg }\n } catch {\n return { name, status: 'fail', message: failMsg }\n }\n}\n\nconst checkZshrcInitialized = (): CheckResult => {\n const name = 'zshrc init block'\n const zshrcPath = path.join(os.homedir(), '.zshrc')\n\n if (!fs.existsSync(zshrcPath)) {\n return { name, status: 'fail', message: '~/.zshrc not found. Run: infra-kit init' }\n }\n\n const content = fs.readFileSync(zshrcPath, 'utf-8')\n const startIdx = content.indexOf(MARKER_START)\n const endIdx = content.indexOf(MARKER_END)\n\n if (startIdx === -1 || endIdx === -1 || endIdx < startIdx) {\n return {\n name,\n status: 'fail',\n message: 'infra-kit shell block missing from ~/.zshrc. Run: infra-kit init',\n }\n }\n\n const installedBlock = content.slice(startIdx, endIdx + MARKER_END.length).trim()\n const expectedBlock = buildShellBlock().trim()\n\n if (installedBlock !== expectedBlock) {\n return {\n name,\n status: 'fail',\n message: 'infra-kit shell block in ~/.zshrc is out of date. Run: infra-kit init',\n }\n }\n\n return { name, status: 'pass', message: 'infra-kit shell block in ~/.zshrc is up to date' }\n}\n\nconst checkPnpmWorkspaceVirtualStore = async (): Promise<CheckResult> => {\n const name = 'pnpm enableGlobalVirtualStore'\n\n try {\n const root = await getProjectRoot()\n const yamlPath = path.join(root, 'pnpm-workspace.yaml')\n\n if (!fs.existsSync(yamlPath)) {\n return { name, status: 'fail', message: `pnpm-workspace.yaml not found at ${yamlPath}` }\n }\n\n const content = fs.readFileSync(yamlPath, 'utf-8')\n // eslint-disable-next-line sonarjs/slow-regex\n const enabled = /^\\s*enableGlobalVirtualStore\\s*:\\s*true\\s*$/m.test(content)\n\n if (!enabled) {\n return {\n name,\n status: 'fail',\n message: 'enableGlobalVirtualStore: true is missing in pnpm-workspace.yaml',\n }\n }\n\n return { name, status: 'pass', message: 'enableGlobalVirtualStore: true is set' }\n } catch (err) {\n return {\n name,\n status: 'fail',\n message: `Failed to read pnpm-workspace.yaml: ${(err as Error).message}`,\n }\n }\n}\n\nconst checkInfraKitConfigValid = async (): Promise<CheckResult> => {\n const name = 'infra-kit config valid'\n\n try {\n resetInfraKitConfigCache()\n await getInfraKitConfig()\n\n return {\n name,\n status: 'pass',\n message: 'infra-kit.json is valid (user overrides applied if present)',\n }\n } catch (err) {\n return { name, status: 'fail', message: (err as Error).message }\n }\n}\n\n/**\n * Surface where this developer's user-scope override file would live and\n * whether it has been created. Always passes \u2014 informational only \u2014 so the\n * user knows the resolved project name and target path at a glance.\n *\n * @example\n * await checkUserOverridePath()\n * // {\n * // name: 'user override path',\n * // status: 'pass',\n * // message: '~/.infra-kit/projects/api/infra-kit.json (not yet created) \u2014 project: api',\n * // }\n */\nconst checkUserOverridePath = async (): Promise<CheckResult> => {\n const name = 'user override path'\n\n try {\n const paths = await getInfraKitConfigPaths()\n const home = os.homedir()\n const display = paths.userProject.startsWith(home) ? `~${paths.userProject.slice(home.length)}` : paths.userProject\n const exists = fs.existsSync(paths.userProject)\n const suffix = exists ? '(exists)' : '(not yet created)'\n\n return {\n name,\n status: 'pass',\n message: `${display} ${suffix} \u2014 project: ${paths.projectName}`,\n }\n } catch (err) {\n return { name, status: 'fail', message: (err as Error).message }\n }\n}\n\ninterface IdeProbe {\n ok: boolean\n label: string\n failMsg: string\n}\n\nconst IDE_PROBE_META: Record<'cursor' | 'zed', { command: string[]; label: string; failMsg: string }> = {\n cursor: {\n command: ['cursor', '--version'],\n label: 'Cursor',\n failMsg: 'Cursor is not installed. Install from: https://cursor.com/',\n },\n zed: {\n command: ['zed', '--version'],\n label: 'Zed',\n failMsg: 'Zed is not installed. Install from: https://zed.dev/',\n },\n}\n\nconst probeIde = async (provider: 'cursor' | 'zed'): Promise<IdeProbe> => {\n const meta = IDE_PROBE_META[provider]\n\n try {\n await $`${meta.command}`\n\n return { ok: true, label: meta.label, failMsg: meta.failMsg }\n } catch {\n return { ok: false, label: meta.label, failMsg: meta.failMsg }\n }\n}\n\n/**\n * Check that every editor configured under `ide` is installed. Reads the merged\n * infra-kit config and probes each matching binary (`cursor`/`zed`). Passes only\n * if all configured editors are present; fails listing any that are missing.\n * Informational pass when no IDE is configured or the config can't be read \u2014 an\n * unconfigured editor is a valid setup, and config validity is reported\n * separately by `checkInfraKitConfigValid`.\n */\nexport const checkIdeInstalled = async (): Promise<CheckResult> => {\n const name = 'ide installed'\n\n let providers: ('cursor' | 'zed')[]\n\n try {\n resetInfraKitConfigCache()\n const config = await getInfraKitConfig()\n\n providers = resolveConfiguredIdes(config).map((ide) => {\n return ide.provider\n })\n } catch {\n return { name, status: 'pass', message: 'Skipped \u2014 infra-kit config could not be read (see config check)' }\n }\n\n if (providers.length === 0) {\n return { name, status: 'pass', message: 'No IDE configured (ide unset)' }\n }\n\n const probes = await Promise.all(\n providers.map((provider) => {\n return probeIde(provider)\n }),\n )\n const missing = probes.filter((probe) => {\n return !probe.ok\n })\n\n if (missing.length === 0) {\n return {\n name,\n status: 'pass',\n message: `Installed: ${probes\n .map((probe) => {\n return probe.label\n })\n .join(', ')}`,\n }\n }\n\n return {\n name,\n status: 'fail',\n message: missing\n .map((probe) => {\n return probe.failMsg\n })\n .join('; '),\n }\n}\n\nconst RTK_REQUIRED_INDEXES = [1, 2, 3, 5, 7] as const\n\nconst checkRtkConfigured = async (): Promise<CheckResult> => {\n const name = 'rtk configured'\n\n try {\n const result = await $`rtk init --show`\n const statusLines = result.stdout\n .split('\\n')\n .map((l) => {\n return l.trim()\n })\n .filter((l) => {\n return l.startsWith('[ok]') || l.startsWith('[--]')\n })\n\n const failed: number[] = []\n\n for (const idx of RTK_REQUIRED_INDEXES) {\n const line = statusLines[idx - 1]\n\n if (!line || !line.startsWith('[ok]')) {\n failed.push(idx)\n }\n }\n\n if (failed.length > 0) {\n return {\n name,\n status: 'fail',\n message: `rtk setup incomplete (items ${failed.join(', ')} not [ok]). Run: rtk init -g --auto-patch`,\n }\n }\n\n return {\n name,\n status: 'pass',\n message: 'rtk hook, RTK.md, global CLAUDE.md, settings.json, and Cursor hook are configured',\n }\n } catch (err) {\n return {\n name,\n status: 'fail',\n message: `Failed to run 'rtk init --show': ${(err as Error).message}`,\n }\n }\n}\n\n/**\n * Check that the repo agent-instruction files managed by `infra-kit init` exist:\n * the `AGENTS.md` block, the `@AGENTS.md` import region in `CLAUDE.md`, and the\n * `.cursor/rules` block. Presence only. Repo-gated: returns no checks when run\n * outside an infra-kit repo so doctor never crashes there.\n */\nexport const checkAgentFiles = async (): Promise<CheckResult[]> => {\n let mainConfigPath: string\n\n try {\n mainConfigPath = (await getInfraKitConfigPaths()).main\n } catch {\n return []\n }\n\n if (!fs.existsSync(mainConfigPath)) return []\n\n const root = path.dirname(mainConfigPath)\n\n const blockPresent = (relPath: string, start: string, end: string): boolean => {\n const filePath = path.join(root, relPath)\n const content = fs.existsSync(filePath) ? fs.readFileSync(filePath, 'utf-8') : ''\n\n return hasManagedBlock(content, start, end)\n }\n\n const entries = [\n {\n name: 'AGENTS.md block',\n present: blockPresent('AGENTS.md', AGENTS_MARKER_START, AGENTS_MARKER_END),\n okMessage: 'AGENTS.md block present',\n missingMessage: 'infra-kit block missing from AGENTS.md. Run: infra-kit init',\n },\n {\n name: 'CLAUDE.md import',\n present: blockPresent('CLAUDE.md', AGENTS_IMPORT_START, AGENTS_IMPORT_END),\n okMessage: 'CLAUDE.md imports @AGENTS.md',\n missingMessage: '@AGENTS.md import block missing from CLAUDE.md. Run: infra-kit init',\n },\n {\n name: '.cursor/rules block',\n present: blockPresent(path.join('.cursor', 'rules', 'infra-kit.mdc'), AGENTS_MARKER_START, AGENTS_MARKER_END),\n okMessage: '.cursor/rules/infra-kit.mdc block present',\n missingMessage: '.cursor/rules/infra-kit.mdc block missing. Run: infra-kit init',\n },\n ]\n\n return entries.map((entry): CheckResult => {\n return {\n name: entry.name,\n status: entry.present ? 'pass' : 'fail',\n message: entry.present ? entry.okMessage : entry.missingMessage,\n }\n })\n}\n\n/**\n * Check installation and authentication status of gh, doppler, aws, and rtk CLIs\n */\nexport const doctor = async () => {\n const baseChecks: CheckResult[] = await Promise.all([\n checkCommand(\n 'gh installed',\n ['gh', '--version'],\n 'GitHub CLI is installed',\n 'GitHub CLI is not installed. Install from: https://cli.github.com/',\n ),\n checkCommand(\n 'gh authenticated',\n ['gh', 'auth', 'status'],\n 'GitHub CLI is authenticated',\n 'GitHub CLI is not authenticated. Run: gh auth login',\n ),\n checkCommand(\n 'doppler installed',\n ['doppler', '--version'],\n 'Doppler CLI is installed',\n 'Doppler CLI is not installed. Install from: https://docs.doppler.com/docs/install-cli',\n ),\n checkCommand(\n 'doppler authenticated',\n ['doppler', 'me'],\n 'Doppler CLI is authenticated',\n 'Doppler CLI is not authenticated. Run: doppler login',\n ),\n checkCommand(\n 'aws installed',\n ['aws', '--version'],\n 'AWS CLI is installed',\n 'AWS CLI is not installed. Install from: https://docs.aws.amazon.com/cli/latest/userguide/getting-started-install.html',\n ),\n // INFO: no need now, util the user does not load the env variables, the aws cli is not authenticated\n // checkCommand(\n // 'aws authenticated',\n // ['aws', 'sts', 'get-caller-identity'],\n // 'AWS CLI is authenticated',\n // 'AWS CLI is not authenticated. Run: aws configure (or aws sso login)',\n // ),\n checkCommand(\n 'rtk installed',\n ['rtk', '--version'],\n 'RTK is installed',\n 'RTK is not installed. Install from: https://github.com/rtk-ai/rtk',\n ),\n checkCommand(\n 'typescript-language-server installed',\n ['typescript-language-server', '--version'],\n 'typescript-language-server is installed',\n 'typescript-language-server is not installed. Install from: https://github.com/typescript-language-server/typescript-language-server#installing',\n ),\n checkRtkConfigured(),\n Promise.resolve(checkZshrcInitialized()),\n checkPnpmWorkspaceVirtualStore(),\n checkInfraKitConfigValid(),\n checkUserOverridePath(),\n checkIdeInstalled(),\n ])\n\n const checks: CheckResult[] = [...baseChecks, ...(await checkAgentFiles())]\n\n logger.info('Doctor check results:\\n')\n\n for (const check of checks) {\n const icon = check.status === 'pass' ? '[PASS]' : '[FAIL]'\n\n logger.info(` ${icon} ${check.name}: ${check.message}`)\n }\n\n const structuredContent = {\n checks: checks.map((c) => {\n return { name: c.name, status: c.status, message: c.message }\n }),\n allPassed: checks.every((c) => {\n return c.status === 'pass'\n }),\n }\n\n return {\n content: textContent(JSON.stringify(structuredContent, null, 2)),\n structuredContent,\n }\n}\n\n// MCP Tool Registration\nexport const doctorMcpTool = defineMcpTool({\n name: 'doctor',\n description: 'Check installation and authentication status of gh, doppler, aws, and rtk CLIs',\n inputSchema: {},\n outputSchema: {\n checks: z\n .array(\n z.object({\n name: z.string().describe('Name of the check'),\n status: z.enum(['pass', 'fail']).describe('Check result'),\n message: z.string().describe('Details about the check result'),\n }),\n )\n .describe('List of all check results'),\n allPassed: z.boolean().describe('Whether all checks passed'),\n },\n handler: doctor,\n})\n", "import fs from 'node:fs'\nimport path from 'node:path'\n\nimport { getInfraKitConfigPaths } from 'src/lib/infra-kit-config'\nimport { logger } from 'src/lib/logger'\nimport { hasManagedBlock, upsertManagedBlock } from 'src/lib/managed-block'\n\nimport packageJson from '../../../package.json' with { type: 'json' }\n\n/** Markers for the generated guidance block (HTML comments \u2014 invisible in rendered markdown). */\nexport const AGENTS_MARKER_START = '<!-- infra-kit:begin -->'\nexport const AGENTS_MARKER_END = '<!-- infra-kit:end -->'\n/** The version line lives on its own line (OMC `OMC:VERSION:` precedent) so the markers stay constant-matchable. */\nconst AGENTS_VERSION_PREFIX = '<!-- infra-kit:version '\n\n/** Separate marker pair for the small `@AGENTS.md` import region injected into CLAUDE.md. */\nexport const AGENTS_IMPORT_START = '<!-- infra-kit:import:begin -->'\nexport const AGENTS_IMPORT_END = '<!-- infra-kit:import:end -->'\n\nconst AGENTS_FILE = 'AGENTS.md'\nconst CLAUDE_FILE = 'CLAUDE.md'\nconst CURSOR_RULE_REL = path.join('.cursor', 'rules', 'infra-kit.mdc')\n\nconst CURSOR_FRONTMATTER = [\n '---',\n 'description: infra-kit CLI usage and conventions',\n 'alwaysApply: true',\n '---',\n '',\n].join('\\n')\n\nexport type WriteAction = 'created' | 'updated' | 'unchanged'\n\nexport interface AgentFileWrite {\n path: string\n action: WriteAction\n}\n\nexport interface WriteAgentFilesResult {\n /** True when run outside an infra-kit repo (no `infra-kit.json` at the git root). */\n skipped: boolean\n /** Repo root the files were written under, or null when skipped. */\n root: string | null\n written: AgentFileWrite[]\n}\n\n/** The version comment line, e.g. `<!-- infra-kit:version 0.1.105 -->`. */\nconst buildVersionLine = (version: string): string => {\n return `${AGENTS_VERSION_PREFIX}${version} -->`\n}\n\n/**\n * The generated guidance body (without the surrounding markers). Describes the\n * infra-kit CLI surface so any AI agent working in the repo learns it. Curated\n * from the real command set; the version line records which CLI version generated it.\n */\nconst buildAgentsBody = (version: string): string => {\n return [\n buildVersionLine(version),\n '',\n '# infra-kit',\n '',\n 'This repository uses the **infra-kit** CLI for environment, worktree, and release workflows.',\n 'This block is generated by `infra-kit init` \u2014 edit text *outside* the markers, never inside.',\n '',\n '## Commands (`ik` = `pnpm exec infra-kit`)',\n '',\n '- `ik env-load -c <config>` / `ik env-clear` / `ik env-status` \u2014 load, clear, or inspect Doppler env vars for a config (e.g. `dev`). Source the returned file to apply.',\n '- `ik worktrees-add` / `worktrees-list` / `worktrees-open` / `worktrees-remove` / `worktrees-sync` \u2014 manage release and feature git worktrees.',\n '- `ik release-create` / `release-list` / `release-deploy-all` / `release-deploy-selected` / `release-deliver` / `release-desc-edit` \u2014 release-branch and deploy flow.',\n '- `ik merge-dev` \u2014 merge the dev branch into every release branch.',\n '- `ik audit` \u2014 audit packages against `infra-kit.config.ts` rules.',\n '- `ik doctor` \u2014 check gh / doppler / aws / rtk install + auth and repo setup.',\n '- `ik init` \u2014 (re)install shell integration and regenerate these agent-instruction files.',\n '',\n '## Conventions',\n '',\n '- Tickets are prefixed by area: `[FE]` frontend, `[BE]` backend, `[DO]` DevOps/infra, `[APP]` mobile app, `[IDEA]` proposal, `[ROOT]` cross-cutting. Pick the single dominant area.',\n '- Environment variables are managed through Doppler via `ik env-load` \u2014 never commit secrets.',\n ].join('\\n')\n}\n\nconst assertNotSymlink = (filePath: string): void => {\n if (fs.existsSync(filePath) && fs.lstatSync(filePath).isSymbolicLink()) {\n throw new Error(`Refusing to write ${filePath} because the destination is a symlink`)\n }\n}\n\n/**\n * Write `nextContent` to `filePath` with OMC-style safety: refuse symlinks,\n * back up the prior file with a timestamp before overwriting, and skip the\n * write entirely when nothing changed (keeps re-runs churn-free).\n */\nconst writeManaged = (filePath: string, nextContent: string): WriteAction => {\n assertNotSymlink(filePath)\n\n const existed = fs.existsSync(filePath)\n const previous = existed ? fs.readFileSync(filePath, 'utf-8') : null\n\n if (previous === nextContent) return 'unchanged'\n\n if (existed) {\n const stamp = new Date().toISOString().replace(/[:.]/g, '-')\n\n fs.copyFileSync(filePath, `${filePath}.backup.${stamp}`)\n }\n\n fs.mkdirSync(path.dirname(filePath), { recursive: true })\n fs.writeFileSync(filePath, nextContent, 'utf-8')\n\n return existed ? 'updated' : 'created'\n}\n\nconst readOr = (filePath: string, fallback: string): string => {\n return fs.existsSync(filePath) ? fs.readFileSync(filePath, 'utf-8') : fallback\n}\n\nconst assertBlockPresent = (filePath: string, start: string, end: string): void => {\n const content = fs.readFileSync(filePath, 'utf-8')\n\n if (!hasManagedBlock(content, start, end)) {\n throw new Error(`Post-write validation failed: managed block missing from ${filePath}`)\n }\n}\n\n/**\n * Generate (or refresh) the repo agent-instruction files: the `AGENTS.md`\n * guidance block, a managed `@AGENTS.md` import region in `CLAUDE.md`\n * (preserving existing content), and a `.cursor/rules` rule file. Repo-gated:\n * a no-op outside an infra-kit repo. Idempotent and non-destructive.\n *\n * @example\n * await writeAgentFiles()\n * // INFO: Agent-instruction files synced (infra-kit 0.1.105)\n */\nexport const writeAgentFiles = async (): Promise<WriteAgentFilesResult> => {\n let mainConfigPath: string\n\n try {\n mainConfigPath = (await getInfraKitConfigPaths()).main\n } catch {\n logger.info('Skipped agent-instruction files \u2014 not inside an infra-kit repo')\n\n return { skipped: true, root: null, written: [] }\n }\n\n if (!fs.existsSync(mainConfigPath)) {\n logger.info('Skipped agent-instruction files \u2014 no infra-kit.json at the repo root')\n\n return { skipped: true, root: null, written: [] }\n }\n\n const root = path.dirname(mainConfigPath)\n const version = packageJson.version\n const body = buildAgentsBody(version)\n\n const agentsPath = path.join(root, AGENTS_FILE)\n const claudePath = path.join(root, CLAUDE_FILE)\n const cursorPath = path.join(root, CURSOR_RULE_REL)\n\n const agentsContent = upsertManagedBlock({\n content: readOr(agentsPath, ''),\n body,\n startMarker: AGENTS_MARKER_START,\n endMarker: AGENTS_MARKER_END,\n })\n\n const claudeContent = upsertManagedBlock({\n content: readOr(claudePath, ''),\n body: `@${AGENTS_FILE}`,\n startMarker: AGENTS_IMPORT_START,\n endMarker: AGENTS_IMPORT_END,\n })\n\n const cursorContent = upsertManagedBlock({\n content: readOr(cursorPath, CURSOR_FRONTMATTER),\n body,\n startMarker: AGENTS_MARKER_START,\n endMarker: AGENTS_MARKER_END,\n })\n\n const written: AgentFileWrite[] = [\n { path: agentsPath, action: writeManaged(agentsPath, agentsContent) },\n { path: claudePath, action: writeManaged(claudePath, claudeContent) },\n { path: cursorPath, action: writeManaged(cursorPath, cursorContent) },\n ]\n\n assertBlockPresent(agentsPath, AGENTS_MARKER_START, AGENTS_MARKER_END)\n assertBlockPresent(claudePath, AGENTS_IMPORT_START, AGENTS_IMPORT_END)\n assertBlockPresent(cursorPath, AGENTS_MARKER_START, AGENTS_MARKER_END)\n\n for (const file of written) {\n logger.info(` ${file.action.padEnd(9)} ${path.relative(root, file.path)}`)\n }\n\n logger.info(`Agent-instruction files synced (infra-kit ${version})`)\n\n return { skipped: false, root, written }\n}\n", "/**\n * Generic \"managed block\" helpers \u2014 a marker-delimited region a tool owns and\n * rewrites idempotently while never touching content outside the markers.\n *\n * This is the same mechanism `infra-kit init` already uses for the `~/.zshrc`\n * shell block (`# -- infra-kit:begin -- \u2026 # -- infra-kit:end --`), lifted here so\n * it can be reused for the repo agent-instruction files (`AGENTS.md`,\n * `CLAUDE.md` import region, `.cursor/rules`). It mirrors the design of OMC's\n * `<!-- OMC:START --> \u2026 <!-- OMC:END -->` CLAUDE.md installer.\n */\n\n/**\n * Where a freshly upserted block lands relative to existing content.\n *\n * - `replace-in-place`: if the block already exists, rewrite it where it sits\n * (surrounding text untouched, verbatim); if absent, append it at end-of-file.\n * - `append-end`: strip any existing block from wherever it is, then append the\n * fresh block at end-of-file (i.e. always relocate to the end). This preserves\n * the historical `~/.zshrc` behavior of `removeExistingBlock` + append.\n */\nexport type BlockPlacement = 'replace-in-place' | 'append-end'\n\nexport interface UpsertManagedBlockArgs {\n /** Existing file content (`''` for a new file). */\n content: string\n /** Inner body to place between the markers (WITHOUT the markers). */\n body: string\n startMarker: string\n endMarker: string\n /** Defaults to `replace-in-place`. */\n placement?: BlockPlacement\n}\n\n/**\n * Whether `content` contains a well-formed `start \u2026 end` block. A reversed pair\n * (end before start) is treated as absent \u2014 the same guard `doctor.ts` applies\n * to the zshrc block, ported here so corrupted markers never match.\n *\n * @example\n * hasManagedBlock('a<!--s-->x<!--e-->b', '<!--s-->', '<!--e-->') // => true\n * hasManagedBlock('<!--e--><!--s-->', '<!--s-->', '<!--e-->') // => false (reversed)\n */\nexport const hasManagedBlock = (content: string, startMarker: string, endMarker: string): boolean => {\n const startIdx = content.indexOf(startMarker)\n const endIdx = content.indexOf(endMarker)\n\n return startIdx !== -1 && endIdx !== -1 && endIdx >= startIdx\n}\n\n/**\n * Remove the first complete `start \u2026 end` block, preserving surrounding text.\n * Returns `null` when no well-formed block is present (no markers, or reversed),\n * so callers can fall through to legacy-format handling \u2014 this matches the\n * `string | null` contract of `init.ts`'s original `removeBetween`, with the\n * added reversed-marker guard.\n *\n * @example\n * removeManagedBlock('top\\n<!--s-->mid<!--e-->\\nbot', '<!--s-->', '<!--e-->')\n * // => 'top\\nbot'\n */\nexport const removeManagedBlock = (content: string, startMarker: string, endMarker: string): string | null => {\n const startIdx = content.indexOf(startMarker)\n const endIdx = content.indexOf(endMarker)\n\n if (startIdx === -1 || endIdx === -1 || endIdx < startIdx) return null\n\n // eslint-disable-next-line sonarjs/slow-regex\n const before = content.slice(0, startIdx).replace(/\\n+$/, '')\n const after = content.slice(endIdx + endMarker.length).replace(/^\\n+/, '')\n\n return before + (after ? `\\n${after}` : '')\n}\n\n/**\n * Read the version token that follows `versionPrefix` (e.g.\n * `'<!-- infra-kit:version '`). Returns the token up to the next whitespace or\n * `>`, or `null` if the prefix is absent. Mirrors OMC's `OMC:VERSION:` line.\n *\n * @example\n * extractVersion('<!-- infra-kit:version 0.1.105 -->', '<!-- infra-kit:version ')\n * // => '0.1.105'\n */\nexport const extractVersion = (content: string, versionPrefix: string): string | null => {\n const idx = content.indexOf(versionPrefix)\n\n if (idx === -1) return null\n\n const rest = content.slice(idx + versionPrefix.length)\n const match = rest.match(/^([^\\s>]+)/)\n\n return match ? match[1]! : null\n}\n\n/**\n * Compose a full block string: `start\\n{body}\\nend`. Kept identical in shape to\n * the historical `buildShellBlock()` output so doctor's exact-match comparison\n * stays valid.\n */\nexport const buildManagedBlock = (startMarker: string, body: string, endMarker: string): string => {\n return `${startMarker}\\n${body}\\n${endMarker}`\n}\n\n/**\n * Insert or update a managed block in `content`, preserving everything outside\n * the markers. Idempotent: re-running with the same body yields the same block\n * and never nests duplicates.\n *\n * @example\n * // fresh file\n * upsertManagedBlock({ content: '', body: 'hi', startMarker: '<!--s-->', endMarker: '<!--e-->' })\n * // => '<!--s-->\\nhi\\n<!--e-->\\n'\n *\n * @example\n * // existing block replaced in place, surrounding text kept\n * upsertManagedBlock({\n * content: 'top\\n<!--s-->\\nold\\n<!--e-->\\nbot',\n * body: 'new', startMarker: '<!--s-->', endMarker: '<!--e-->',\n * })\n * // => 'top\\n<!--s-->\\nnew\\n<!--e-->\\nbot'\n */\nexport const upsertManagedBlock = ({\n content,\n body,\n startMarker,\n endMarker,\n placement = 'replace-in-place',\n}: UpsertManagedBlockArgs): string => {\n const block = buildManagedBlock(startMarker, body, endMarker)\n const present = hasManagedBlock(content, startMarker, endMarker)\n\n if (placement === 'replace-in-place' && present) {\n const startIdx = content.indexOf(startMarker)\n const endIdx = content.indexOf(endMarker) + endMarker.length\n\n return content.slice(0, startIdx) + block + content.slice(endIdx)\n }\n\n // append-end, or replace-in-place with no existing block: drop any stale block\n // then append the fresh one at end-of-file.\n const stripped = present ? (removeManagedBlock(content, startMarker, endMarker) ?? content) : content\n // eslint-disable-next-line sonarjs/slow-regex\n const base = stripped.replace(/\\n+$/, '')\n\n return base.length > 0 ? `${base}\\n${block}\\n` : `${block}\\n`\n}\n", "{\n \"name\": \"infra-kit\",\n \"type\": \"module\",\n \"version\": \"0.1.114\",\n \"description\": \"infra-kit\",\n \"main\": \"dist/index.js\",\n \"module\": \"dist/index.js\",\n \"types\": \"dist/entry/index.d.ts\",\n \"exports\": {\n \".\": {\n \"types\": \"./dist/entry/index.d.ts\",\n \"import\": \"./dist/index.js\"\n }\n },\n \"bin\": {\n \"infra-kit\": \"dist/cli.js\"\n },\n \"engines\": {\n \"node\": \">=24.x\"\n },\n \"scripts\": {\n \"inspector\": \"npx @modelcontextprotocol/inspector node ./dist/mcp.js --debug\",\n \"build\": \"pnpm run clean-artifacts && node ./scripts/build.js\",\n \"check\": \"node ./dist/cli.js check\",\n \"clean-artifacts\": \"rm -rf dist\",\n \"clean-cache\": \"rm -rf node_modules/.cache .eslintcache tsconfig.tsbuildinfo .turbo .swc\",\n \"prettier-fix\": \"pnpm exec prettier **/* --write --no-error-on-unmatched-pattern --log-level silent --ignore-path ../../../.prettierignore\",\n \"prettier-check\": \"pnpm exec prettier **/* --check --no-error-on-unmatched-pattern --log-level silent --ignore-path ../../../.prettierignore\",\n \"eslint-check\": \"pnpm exec eslint --cache --quiet --report-unused-disable-directives ./src\",\n \"eslint-fix\": \"pnpm exec eslint --cache --quiet --report-unused-disable-directives ./src --fix\",\n \"ts-check\": \"tsc --noEmit\",\n \"test\": \"pnpm exec vitest run --reporter=minimal\",\n \"test-watch\": \"pnpm exec vitest --watch --silent passed-only\",\n \"test-ui\": \"pnpm exec vitest --ui --silent passed-only\",\n \"test-report\": \"pnpm exec vitest run --coverage --silent passed-only\",\n \"qa\": \"pnpm run prettier-check && pnpm run eslint-check && pnpm run ts-check && pnpm run test && echo \u2705 Success\",\n \"fix\": \"pnpm run prettier-fix && pnpm run eslint-fix && pnpm run qa\"\n },\n \"dependencies\": {\n \"@inquirer/checkbox\": \"^5.2.1\",\n \"@inquirer/confirm\": \"^6.1.1\",\n \"@inquirer/select\": \"^5.2.1\",\n \"@modelcontextprotocol/sdk\": \"^1.29.0\",\n \"commander\": \"^15.0.0\",\n \"pino\": \"^10.3.1\",\n \"pino-pretty\": \"^13.1.3\",\n \"yaml\": \"^2.9.0\",\n \"zod\": \"^4.4.3\",\n \"zx\": \"^8.8.5\"\n },\n \"devDependencies\": {\n \"@wl/eslint-config\": \"workspace:*\",\n \"@wl/vitest-config\": \"workspace:*\",\n \"esbuild\": \"^0.28.1\",\n \"typescript\": \"^6.0.3\"\n }\n}\n", "import fs from 'node:fs'\nimport os from 'node:os'\nimport path from 'node:path'\n\nimport { logger } from 'src/lib/logger'\nimport { removeManagedBlock, upsertManagedBlock } from 'src/lib/managed-block'\n\nimport { writeAgentFiles } from './agent-files'\nimport { migrateLegacyConfig, normalizeLegacyIdeStructures } from './migrate-config'\n\nexport const MARKER_START = '# -- infra-kit:begin --'\nexport const MARKER_END = '# -- infra-kit:end --'\n\nconst LEGACY_PAIRED: [start: string, end: string][] = [['# region infra-kit', '# endregion infra-kit']]\nconst LEGACY_SINGLE = '# infra-kit shell functions'\n\n// JSON can't carry comments, so the real config is an empty-but-valid object\u2026\nconst USER_GLOBAL_CONFIG_STUB = '{}\\n'\n\n// \u2026and the annotated guidance lives next to it in a non-loaded .example.jsonc\n// (the loader only reads the three exact `infra-kit.json` / `config.json` files).\nconst USER_GLOBAL_CONFIG_EXAMPLE = `// infra-kit user-global config \u2014 ~/.infra-kit/config.json\n//\n// Merge chain (later layers override earlier ones at top-level keys):\n// 1. <repo>/infra-kit.json \u2014 committed project config (required)\n// 2. ~/.infra-kit/config.json \u2014 user-global (the sibling of this file)\n// 3. ~/.infra-kit/projects/<repo-name>/infra-kit.json \u2014 user-scope per-project override\n//\n// Merge is shallow: setting a top-level key replaces that whole section from\n// layer 1. Arrays do not concatenate. Top-level keys recognized:\n// environments, envManagement, ide, taskManager, worktrees.\n//\n// This .example.jsonc is reference only \u2014 it is NOT loaded. Put real global\n// overrides in the sibling config.json (strict JSON: no comments, double-quoted\n// keys). Per-project tweaks belong in layer 3 \u2014 run \\`infra-kit config edit\\`.\n{\n // \"ide\": {\n // \"provider\": \"cursor\",\n // \"config\": { \"workspaceConfigPath\": \"/path/to/your.code-workspace\" }\n // },\n // // Or, for Zed (no workspace file \u2014 one window with all worktrees via \"zed <root> <wt...>\"):\n // \"ide\": { \"provider\": \"zed\", \"config\": {} },\n // // Or drive BOTH editors at once with an array (at most one entry per provider):\n // \"ide\": [\n // { \"provider\": \"cursor\", \"config\": { \"workspaceConfigPath\": \"/path/to/your.code-workspace\" } },\n // { \"provider\": \"zed\", \"config\": {} }\n // ],\n // \"worktrees\": { \"openInGithubDesktop\": false, \"openInCmux\": true }\n}\n`\n\n/**\n * Append infra-kit shell functions to .zshrc, migrate any legacy\n * `infra-kit.yml` config layers to JSON, normalize existing JSON configs from\n * the old IDE structure to the new one (strip the removed `ide.config.mode`),\n * and seed the user-global config at ~/.infra-kit/config.json on first run.\n * Idempotent: a subsequent run replaces the existing zshrc block in place, has\n * nothing left to migrate or normalize, and leaves the user-global config\n * untouched.\n *\n * @example\n * // CLI: `infra-kit init` (or via the `pnpm dx-init` alias)\n * // INFO: Added infra-kit shell functions to /Users/me/.zshrc\n * // INFO: Wrote user-global config to /Users/me/.infra-kit/config.json (see \u2026/config.example.jsonc \u2026)\n * // INFO: Run `source ~/.zshrc` or open a new terminal to activate.\n */\nexport const init = async (): Promise<void> => {\n const zshrcPath = path.join(os.homedir(), '.zshrc')\n\n // Strip any prior block (current or legacy markers) anywhere in the file, then\n // append a fresh block at end-of-file via the shared managed-block utility \u2014\n // the historical `removeExistingBlock` + append behavior, now centralized.\n const existing = fs.existsSync(zshrcPath) ? removeExistingBlock(fs.readFileSync(zshrcPath, 'utf-8')) : ''\n\n const updated = upsertManagedBlock({\n content: existing,\n body: buildShellBody(),\n startMarker: MARKER_START,\n endMarker: MARKER_END,\n placement: 'append-end',\n })\n\n fs.writeFileSync(zshrcPath, updated)\n\n logger.info(`Added infra-kit shell functions to ${zshrcPath}`)\n\n // Convert any legacy infra-kit.yml config layers to JSON before seeding, so a\n // migrated config.json is not re-seeded as an empty stub.\n await migrateLegacyConfig()\n\n // Migrate existing JSON configs from the old IDE structure to the new one\n // (strip the removed `ide.config.mode` field). No-op for already-clean configs.\n await normalizeLegacyIdeStructures()\n\n seedUserGlobalConfig()\n\n // Best-effort, non-fatal, repo-gated: keep the agent-instruction files in sync\n // with the CLI surface. A no-op outside an infra-kit repo.\n await writeAgentFiles()\n\n logger.info('Run `source ~/.zshrc` or open a new terminal to activate.')\n}\n\n/**\n * Create `~/.infra-kit/config.json` (empty `{}`) plus an annotated\n * `~/.infra-kit/config.example.jsonc` reference when absent. Skips silently if\n * the config already exists so user edits are preserved.\n *\n * @example\n * seedUserGlobalConfig()\n * // first call: writes ~/.infra-kit/config.json ({}) + config.example.jsonc\n * // later calls: leaves the config alone, logs that it is already present\n */\nconst seedUserGlobalConfig = (): void => {\n const userConfigDir = path.join(os.homedir(), '.infra-kit')\n const userConfigPath = path.join(userConfigDir, 'config.json')\n const userConfigExamplePath = path.join(userConfigDir, 'config.example.jsonc')\n\n if (fs.existsSync(userConfigPath)) {\n logger.info(`User-global config already present at ${userConfigPath}`)\n\n return\n }\n\n fs.mkdirSync(userConfigDir, { recursive: true })\n fs.writeFileSync(userConfigPath, USER_GLOBAL_CONFIG_STUB, 'utf-8')\n fs.writeFileSync(userConfigExamplePath, USER_GLOBAL_CONFIG_EXAMPLE, 'utf-8')\n\n logger.info(\n `Wrote user-global config to ${userConfigPath} (see ${userConfigExamplePath} for the annotated reference)`,\n )\n}\n\nconst isBlockLine = (line: string): boolean => {\n return (\n line.startsWith('#') ||\n line.startsWith('alias ') ||\n line.startsWith('env-load') ||\n line.startsWith('env-clear') ||\n line.startsWith('env-status') ||\n line.startsWith('if ') ||\n line.startsWith(' export INFRA_KIT_SESSION') ||\n line.startsWith('export _INFRA_KIT_') ||\n line.startsWith(': ${_INFRA_KIT_') ||\n line.startsWith('fi') ||\n line.startsWith('zmodload ') ||\n line.startsWith('autoload ') ||\n line.startsWith('add-zsh-hook ') ||\n line.startsWith('_infra_kit_autoload')\n )\n}\n\nconst removeExistingBlock = (content: string): string => {\n // 1. Current markers\n const result = removeManagedBlock(content, MARKER_START, MARKER_END)\n\n if (result !== null) return result\n\n // 2. Legacy paired markers (# region / # endregion)\n for (const [start, end] of LEGACY_PAIRED) {\n const legacyResult = removeManagedBlock(content, start, end)\n\n if (legacyResult !== null) return legacyResult\n }\n\n // 3. Oldest format: single marker + heuristic scan\n const legacyIdx = content.indexOf(LEGACY_SINGLE)\n\n if (legacyIdx === -1) return content\n\n // eslint-disable-next-line sonarjs/slow-regex\n const before = content.slice(0, legacyIdx).replace(/\\n+$/, '')\n const afterLines = content.slice(legacyIdx).split('\\n')\n\n let i = 0\n\n while (i < afterLines.length && isBlockLine(afterLines[i]!)) {\n i++\n }\n\n const remaining = afterLines.slice(i).join('\\n')\n\n return before + (remaining ? `\\n${remaining}` : '')\n}\n\n/**\n * The inner shell-function lines (no markers). Composed into the full marked\n * block by {@link buildShellBlock} and fed to `upsertManagedBlock` by `init()`.\n */\nexport const buildShellBody = (): string => {\n const runCmd = 'pnpm exec infra-kit'\n\n return [\n 'zmodload zsh/stat 2>/dev/null',\n 'zmodload zsh/datetime 2>/dev/null',\n // eslint-disable-next-line no-template-curly-in-string\n 'if [[ -z \"${INFRA_KIT_SESSION}\" ]]; then',\n ' export INFRA_KIT_SESSION=$(head -c 4 /dev/urandom | xxd -p)',\n 'fi',\n // eslint-disable-next-line no-template-curly-in-string\n ': ${_INFRA_KIT_LAST_LOAD_MTIME:=0}',\n // eslint-disable-next-line no-template-curly-in-string\n ': ${_INFRA_KIT_LAST_CLEAR_MTIME:=0}',\n // eslint-disable-next-line no-template-curly-in-string\n ': ${_INFRA_KIT_SHELL_STARTED:=${EPOCHSECONDS:-0}}',\n 'export _INFRA_KIT_LAST_LOAD_MTIME _INFRA_KIT_LAST_CLEAR_MTIME _INFRA_KIT_SHELL_STARTED',\n `env-load() { local f m; f=$(${runCmd} env-load \"$@\") || return; m=$(zstat +mtime -- \"$f\" 2>/dev/null || echo 0); _INFRA_KIT_LAST_LOAD_MTIME=$m; source \"$f\"; ${runCmd} env-status; }`,\n `env-clear() { local f m; f=$(${runCmd} env-clear) || return; m=$(zstat +mtime -- \"$f\" 2>/dev/null || echo 0); _INFRA_KIT_LAST_CLEAR_MTIME=$m; source \"$f\"; ${runCmd} env-status; }`,\n `env-status() { ${runCmd} env-status; }`,\n `alias ik='${runCmd}'`,\n '_infra_kit_autoload() {',\n ' [[ -z \"$INFRA_KIT_SESSION\" ]] && return',\n // eslint-disable-next-line no-template-curly-in-string\n ' local cache_root=\"${XDG_CACHE_HOME:-$HOME/.cache}/infra-kit\"',\n ' local dir=\"$cache_root/$INFRA_KIT_SESSION\"',\n ' local load_file=\"$dir/env-load.sh\"',\n ' local clear_file=\"$dir/env-clear.sh\"',\n ' local mtime',\n ' if [[ -f \"$load_file\" ]]; then',\n ' mtime=$(zstat +mtime -- \"$load_file\" 2>/dev/null || echo 0)',\n ' if (( mtime > _INFRA_KIT_LAST_LOAD_MTIME && mtime >= _INFRA_KIT_SHELL_STARTED )); then',\n ' source \"$load_file\"',\n ' _INFRA_KIT_LAST_LOAD_MTIME=$mtime',\n // eslint-disable-next-line no-template-curly-in-string\n ' print -u2 \"infra-kit: auto-loaded vars for ${INFRA_KIT_ENV_CONFIG:-?}\"',\n ' fi',\n ' fi',\n ' if [[ -f \"$clear_file\" ]]; then',\n ' mtime=$(zstat +mtime -- \"$clear_file\" 2>/dev/null || echo 0)',\n ' if (( mtime > _INFRA_KIT_LAST_CLEAR_MTIME && mtime >= _INFRA_KIT_SHELL_STARTED )); then',\n ' source \"$clear_file\"',\n ' _INFRA_KIT_LAST_CLEAR_MTIME=$mtime',\n ' print -u2 \"infra-kit: auto-cleared env\"',\n ' fi',\n ' fi',\n '}',\n 'autoload -Uz add-zsh-hook',\n 'if (( _INFRA_KIT_SHELL_STARTED > 0 )); then',\n ' add-zsh-hook precmd _infra_kit_autoload',\n 'fi',\n ].join('\\n')\n}\n\n/**\n * The full marker-delimited shell block (`MARKER_START \u2026 MARKER_END`). Kept as\n * a single composed string so `doctor`'s exact-match freshness check stays valid.\n */\nexport const buildShellBlock = (): string => {\n return `${MARKER_START}\\n${buildShellBody()}\\n${MARKER_END}`\n}\n", "import fs from 'node:fs/promises'\nimport os from 'node:os'\nimport path from 'node:path'\nimport yaml from 'yaml'\nimport { z } from 'zod'\n\nimport {\n getInfraKitConfigPaths,\n infraKitConfigSchema,\n infraKitOverrideConfigSchema,\n resetInfraKitConfigCache,\n} from 'src/lib/infra-kit-config'\nimport { logger } from 'src/lib/logger'\n\ninterface MigrateLayer {\n label: string\n /** Legacy YAML source path. */\n yml: string\n /** Target JSON path. */\n json: string\n /** Validates the parsed object before any write (main vs override schema). */\n schema: z.ZodType\n}\n\n/**\n * Replace the user's home prefix with `~` so logged paths stay short.\n *\n * @example\n * // os.homedir() === '/Users/arthur'\n * tildify('/Users/arthur/.infra-kit/config.yml') // => '~/.infra-kit/config.yml'\n */\nconst tildify = (filePath: string): string => {\n const home = os.homedir()\n\n return filePath.startsWith(home) ? `~${filePath.slice(home.length)}` : filePath\n}\n\n/**\n * `fs.access` reduced to a boolean, swallowing ENOENT.\n *\n * @example\n * await fileExists('/etc/hosts') // => true\n */\nconst fileExists = async (filePath: string): Promise<boolean> => {\n try {\n await fs.access(filePath)\n\n return true\n } catch {\n return false\n }\n}\n\n/**\n * Swap a resolved `.json` config path back to its legacy `.yml` sibling.\n *\n * @example\n * legacyYmlPath('/repo/infra-kit.json') // => '/repo/infra-kit.yml'\n */\nconst legacyYmlPath = (jsonPath: string): string => {\n return jsonPath.replace(/\\.json$/, '.yml')\n}\n\n/**\n * Convert any legacy `infra-kit.yml` config layers to `infra-kit.json` as part\n * of `infra-kit init`. Best-effort and non-fatal: each merge-chain layer\n * (project, user-global, user-project) is migrated independently, and a\n * conflict (both `.yml` and `.json` present) or an invalid `.yml` warns and\n * skips that layer rather than aborting init or touching the other layers.\n * Idempotent \u2014 already-JSON layers are left untouched.\n *\n * @example\n * await migrateLegacyConfig()\n * // INFO: \u2713 Migrated infra-kit.yml \u2192 infra-kit.json\n * // (no output when there is nothing legacy to convert)\n */\nexport const migrateLegacyConfig = async (): Promise<void> => {\n let paths: Awaited<ReturnType<typeof getInfraKitConfigPaths>>\n\n try {\n paths = await getInfraKitConfigPaths()\n } catch {\n // No resolvable project (e.g. init run outside a repo) \u2014 nothing to migrate.\n return\n }\n\n const layers: MigrateLayer[] = [\n { label: 'infra-kit.json', yml: legacyYmlPath(paths.main), json: paths.main, schema: infraKitConfigSchema },\n {\n label: '~/.infra-kit/config.json',\n yml: legacyYmlPath(paths.userGlobal),\n json: paths.userGlobal,\n schema: infraKitOverrideConfigSchema,\n },\n {\n label: `~/.infra-kit/projects/${paths.projectName}/infra-kit.json`,\n yml: legacyYmlPath(paths.userProject),\n json: paths.userProject,\n schema: infraKitOverrideConfigSchema,\n },\n ]\n\n let migrated = 0\n\n for (const layer of layers) {\n const [ymlExists, jsonExists] = await Promise.all([fileExists(layer.yml), fileExists(layer.json)])\n\n if (!ymlExists) continue\n\n if (jsonExists) {\n logger.info(\n `\u26A0 Skipped ${tildify(layer.yml)} \u2014 ${tildify(layer.json)} already exists (remove the stale .yml manually)`,\n )\n\n continue\n }\n\n // Keep per-layer migration non-fatal even for malformed YAML or I/O errors\n // (TOCTOU after the existence probe, EACCES, read-only FS): warn and skip\n // so one bad layer never aborts `init` or the other layers.\n try {\n const raw = await fs.readFile(layer.yml, 'utf-8')\n const parsed = (yaml.parse(raw) ?? {}) as unknown\n const result = layer.schema.safeParse(parsed)\n\n if (!result.success) {\n logger.info(`\u26A0 Skipped ${tildify(layer.yml)} \u2014 invalid config: ${z.prettifyError(result.error)}`)\n\n continue\n }\n\n await fs.mkdir(path.dirname(layer.json), { recursive: true })\n await fs.writeFile(layer.json, `${JSON.stringify(result.data, null, 2)}\\n`, 'utf-8')\n await fs.rm(layer.yml, { force: true })\n\n logger.info(`\u2713 Migrated ${tildify(layer.yml)} \u2192 ${tildify(layer.json)}`)\n migrated++\n } catch (err) {\n logger.info(`\u26A0 Skipped ${tildify(layer.yml)} \u2014 ${(err as Error).message}`)\n }\n }\n\n if (migrated > 0) {\n resetInfraKitConfigCache()\n }\n}\n\n/**\n * Surgically strip the removed `ide.config.mode` field from a parsed config\n * object (single-provider or array form). The windows-removal made `mode` a dead\n * key \u2014 the loader already ignores it, so this only matters for keeping the\n * on-disk file clean. Returns `changed: false` (and the input untouched) when\n * there is no `mode` to remove, so callers can skip rewriting clean files.\n *\n * Only `mode` is removed \u2014 every other key is preserved verbatim (no full-schema\n * re-validation), so a config that is otherwise invalid or carries forward-compat\n * keys is never altered beyond the dead field.\n */\nconst stripLegacyIdeMode = (parsed: Record<string, unknown>): { changed: boolean; result: Record<string, unknown> } => {\n const ide = parsed.ide\n\n if (ide === null || typeof ide !== 'object') {\n return { changed: false, result: parsed }\n }\n\n let changed = false\n\n const stripEntry = (entry: unknown): unknown => {\n if (entry === null || typeof entry !== 'object' || !('config' in entry)) {\n return entry\n }\n\n const config = (entry as { config: unknown }).config\n\n if (config === null || typeof config !== 'object' || !('mode' in config)) {\n return entry\n }\n\n changed = true\n\n const restConfig = Object.fromEntries(\n Object.entries(config as Record<string, unknown>).filter(([key]) => {\n return key !== 'mode'\n }),\n )\n\n return { ...(entry as Record<string, unknown>), config: restConfig }\n }\n\n const nextIde = Array.isArray(ide) ? ide.map(stripEntry) : stripEntry(ide)\n\n if (!changed) {\n return { changed: false, result: parsed }\n }\n\n return { changed: true, result: { ...parsed, ide: nextIde } }\n}\n\n/**\n * Normalize any existing `infra-kit.json` config layers (project, user-global,\n * user-project) from the old IDE structure to the new one by removing the\n * removed `ide.config.mode` field. Run by `infra-kit init` after the YAML\u2192JSON\n * migration. Best-effort and non-fatal per layer; only rewrites a file when its\n * `ide` config actually carries the dead key, so clean configs are left byte-for-\n * byte untouched (idempotent). Resets the config cache when anything changed.\n *\n * @example\n * await normalizeLegacyIdeStructures()\n * // \u2713 Normalized ide config in infra-kit.json (removed legacy \"mode\")\n * // (no output when no config carries a legacy \"mode\")\n */\nexport const normalizeLegacyIdeStructures = async (): Promise<void> => {\n let paths: Awaited<ReturnType<typeof getInfraKitConfigPaths>>\n\n try {\n paths = await getInfraKitConfigPaths()\n } catch {\n return\n }\n\n const jsonPaths = [paths.main, paths.userGlobal, paths.userProject]\n\n let normalized = 0\n\n for (const jsonPath of jsonPaths) {\n if (!(await fileExists(jsonPath))) continue\n\n try {\n const raw = await fs.readFile(jsonPath, 'utf-8')\n\n if (raw.trim() === '') continue\n\n const parsed = JSON.parse(raw) as Record<string, unknown>\n const { changed, result } = stripLegacyIdeMode(parsed)\n\n if (!changed) continue\n\n await fs.writeFile(jsonPath, `${JSON.stringify(result, null, 2)}\\n`, 'utf-8')\n\n logger.info(`\u2713 Normalized ide config in ${tildify(jsonPath)} (removed legacy \"mode\")`)\n normalized++\n } catch (err) {\n logger.info(`\u26A0 Skipped normalizing ${tildify(jsonPath)} \u2014 ${(err as Error).message}`)\n }\n }\n\n if (normalized > 0) {\n resetInfraKitConfigCache()\n }\n}\n", "import fs from 'node:fs'\nimport path from 'node:path'\nimport process from 'node:process'\nimport { z } from 'zod'\n\nimport {\n ENV_CLEAR_FILE,\n ENV_LOAD_FILE,\n INFRA_KIT_ENV_CONFIG_VAR,\n INFRA_KIT_ENV_LOADED_AT_VAR,\n INFRA_KIT_ENV_PROJECT_VAR,\n atomicWriteFileSync,\n getSessionCacheDir,\n parseVarNamesFromEnvFile,\n} from 'src/lib/constants'\nimport { defineMcpTool, textContent } from 'src/types'\n\n/**\n * Clear loaded env vars. Prints a file path to stdout that must be sourced to apply.\n * The env-clear shell alias does this automatically. Throws when no env is loaded\n * so CLI callers exit non-zero and MCP callers receive a structured tool error.\n */\nexport const envClear = async () => {\n const cacheDir = getSessionCacheDir()\n const envLoadPath = path.join(cacheDir, ENV_LOAD_FILE)\n\n if (!fs.existsSync(envLoadPath)) {\n throw new Error('No loaded environment found. Run `env-load` first.')\n }\n\n const varNames = parseVarNamesFromEnvFile(envLoadPath)\n\n const unsetLines = [\n ...varNames.map((v) => {\n return `unset ${v}`\n }),\n `unset ${INFRA_KIT_ENV_CONFIG_VAR}`,\n `unset ${INFRA_KIT_ENV_PROJECT_VAR}`,\n `unset ${INFRA_KIT_ENV_LOADED_AT_VAR}`,\n ]\n\n const clearFilePath = path.resolve(cacheDir, ENV_CLEAR_FILE)\n\n fs.mkdirSync(cacheDir, { recursive: true, mode: 0o700 })\n\n atomicWriteFileSync(clearFilePath, `${unsetLines.join('\\n')}\\n`, 0o600)\n\n // REQUIRED\n process.stdout.write(`${clearFilePath}\\n`)\n\n // Remove env load file so the next env-clear call correctly reports \"no env loaded\".\n fs.unlinkSync(envLoadPath)\n\n const structuredContent = {\n filePath: clearFilePath,\n variableCount: varNames.length,\n unsetStatements: unsetLines,\n }\n\n return {\n content: textContent(JSON.stringify(structuredContent, null, 2)),\n structuredContent,\n }\n}\n\n// MCP Tool Registration\nexport const envClearMcpTool = defineMcpTool({\n name: 'env-clear',\n description:\n 'Generate a shell script that unsets every env var previously loaded by env-load for this session, plus the infra-kit session metadata vars. Does NOT mutate the calling process. When `infra-kit init` has installed the zsh shell integration, the user\\'s terminal auto-sources the unset script on its next prompt (precmd hook) \u2014 so calling this via MCP will clear the vars in the shell that launched Claude Code automatically. Other callers must source \"<filePath>\" themselves or surface it to the user. Errors if no env is currently loaded.',\n inputSchema: {},\n outputSchema: {\n filePath: z.string().describe('Path to the file that must be sourced to apply'),\n variableCount: z.number().describe('Number of variables cleared'),\n unsetStatements: z.array(z.string()).describe('Unset statements generated'),\n },\n handler: envClear,\n})\n", "import fs from 'node:fs'\nimport os from 'node:os'\nimport path from 'node:path'\nimport process from 'node:process'\n\nexport const ENV_LOAD_FILE = 'env-load.sh'\nexport const ENV_CLEAR_FILE = 'env-clear.sh'\n\nexport const INFRA_KIT_SESSION_VAR = 'INFRA_KIT_SESSION'\nexport const INFRA_KIT_ENV_CONFIG_VAR = 'INFRA_KIT_ENV_CONFIG'\nexport const INFRA_KIT_ENV_PROJECT_VAR = 'INFRA_KIT_ENV_PROJECT'\nexport const INFRA_KIT_ENV_LOADED_AT_VAR = 'INFRA_KIT_ENV_LOADED_AT'\n\n/**\n * Matches a line of the form `KEY=...` where KEY is an env-var identifier\n * (letter or underscore, then word chars). Capture group 1 is the name. Shared\n * between env-load (validation, var counting) and parseVarNamesFromEnvFile.\n */\nexport const ENV_VAR_LINE_PATTERN = /^([A-Z_]\\w*)=/i\n\nexport const parseVarNamesFromEnvFile = (filePath: string): string[] => {\n if (!fs.existsSync(filePath)) return []\n\n const content = fs.readFileSync(filePath, 'utf-8')\n const names: string[] = []\n\n for (const line of content.split('\\n')) {\n const match = ENV_VAR_LINE_PATTERN.exec(line)\n\n if (match) {\n names.push(match[1]!)\n }\n }\n\n return names\n}\n\n/**\n * Root cache dir for infra-kit across all sessions. Resolved from\n * $XDG_CACHE_HOME when set, falling back to ~/.cache/infra-kit. Keep in sync\n * with the shell block emitted by `infra-kit init` (src/commands/init/init.ts).\n */\nexport const getCacheRoot = (): string => {\n const xdg = process.env.XDG_CACHE_HOME\n const base = xdg && xdg.length > 0 ? xdg : path.join(os.homedir(), '.cache')\n\n return path.join(base, 'infra-kit')\n}\n\nexport const getSessionCacheDir = (): string => {\n const session = process.env[INFRA_KIT_SESSION_VAR]\n\n if (!session) {\n throw new Error(`${INFRA_KIT_SESSION_VAR} is not set. Run \\`infra-kit init\\` then \\`source ~/.zshrc\\`.`)\n }\n\n return path.join(getCacheRoot(), session)\n}\n\n/**\n * Write content atomically: write to a pid-suffixed temp file in the same\n * directory, then rename. fs.renameSync is atomic on a single filesystem, so\n * concurrent writers can't produce a half-written secret file.\n */\nexport const atomicWriteFileSync = (filePath: string, content: string, mode: number): void => {\n const tmpPath = `${filePath}.tmp.${process.pid}`\n\n fs.writeFileSync(tmpPath, content, { mode })\n\n try {\n fs.renameSync(tmpPath, filePath)\n } catch (error) {\n fs.rmSync(tmpPath, { force: true })\n throw error\n }\n}\n\nexport const WORKTREES_DIR_SUFFIX = '-worktrees'\n// eslint-disable-next-line sonarjs/publicly-writable-directories\nexport const LOG_FILE_PATH = '/tmp/mcp-infra-kit.log'\n", "import { z } from 'zod'\n\nimport { getDopplerProject } from 'src/integrations/doppler/doppler-project'\nimport { getInfraKitConfig } from 'src/lib/infra-kit-config'\nimport { logger } from 'src/lib/logger'\nimport { defineMcpTool, textContent } from 'src/types'\n\n/**\n * List available Doppler configs for the detected project.\n *\n * Purely local: reads infra-kit.json and does not call Doppler. We intentionally\n * do not run validateDopplerCliAndAuth here \u2014 users listing envs often do so\n * before `doppler login`, and a spurious auth error would be misleading.\n */\nexport const envList = async () => {\n const project = await getDopplerProject()\n const { environments } = await getInfraKitConfig()\n\n logger.info(`Doppler project: ${project}\\n`)\n logger.info('Available configs:')\n\n for (const env of environments) {\n logger.info(` - ${env}`)\n }\n\n const structuredContent = {\n project,\n configs: environments,\n }\n\n return {\n content: textContent(JSON.stringify(structuredContent, null, 2)),\n structuredContent,\n }\n}\n\n// MCP Tool Registration\nexport const envListMcpTool = defineMcpTool({\n name: 'env-list',\n description:\n 'List the environments the project is configured to support. Returns the `environments` list declared in infra-kit.json at the project root (not a live fetch from Doppler) plus the Doppler project name resolved from the same file. Read-only.',\n inputSchema: {},\n outputSchema: {\n project: z.string().describe('Detected Doppler project name'),\n configs: z.array(z.string()).describe('Available environment configs'),\n },\n handler: envList,\n})\n", "import { getInfraKitConfig } from 'src/lib/infra-kit-config'\n\n/**\n * Resolve Doppler project name from infra-kit.json at the project root\n */\nexport const getDopplerProject = async (): Promise<string> => {\n const { envManagement } = await getInfraKitConfig()\n\n return envManagement.config.name\n}\n", "import select from '@inquirer/select'\nimport { Buffer } from 'node:buffer'\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport process from 'node:process'\nimport { z } from 'zod'\nimport { $ } from 'zx'\n\nimport { validateDopplerCliAndAuth } from 'src/integrations/doppler'\nimport { getDopplerProject } from 'src/integrations/doppler/doppler-project'\nimport { commandEcho } from 'src/lib/command-echo'\nimport {\n ENV_LOAD_FILE,\n ENV_VAR_LINE_PATTERN,\n INFRA_KIT_ENV_CONFIG_VAR,\n INFRA_KIT_ENV_LOADED_AT_VAR,\n INFRA_KIT_ENV_PROJECT_VAR,\n atomicWriteFileSync,\n getSessionCacheDir,\n} from 'src/lib/constants'\nimport { getInfraKitConfig } from 'src/lib/infra-kit-config'\nimport { defineMcpTool, textContent } from 'src/types'\n\ninterface EnvLoadArgs {\n config?: string\n}\n\n/**\n * Load environment variables from Doppler for the given config\n */\nexport const envLoad = async (args: EnvLoadArgs) => {\n await validateDopplerCliAndAuth()\n\n const { config } = args\n\n commandEcho.start('env-load')\n\n let selectedConfig = ''\n\n if (config) {\n selectedConfig = config\n } else {\n const { environments } = await getInfraKitConfig()\n\n commandEcho.setInteractive()\n selectedConfig = await select(\n {\n message: 'Select environment config',\n choices: environments.map((env) => {\n return { name: env, value: env }\n }),\n },\n // Render to stderr so the prompt is visible when stdout is captured via $() in the shell function.\n // Only env-load and env-clear use the $() stdout-capture shell pattern.\n { output: process.stderr },\n )\n }\n\n commandEcho.addOption('--config', selectedConfig)\n\n const project = await getDopplerProject()\n\n const envContent = await downloadDopplerSecrets(project, selectedConfig)\n\n assertValidEnvContent(envContent)\n\n // Build env file content in dotenv format\n const loadedAt = new Date().toISOString()\n const envFileLines = [\n 'set -a',\n envContent,\n `${INFRA_KIT_ENV_CONFIG_VAR}=${shellSingleQuote(selectedConfig)}`,\n `${INFRA_KIT_ENV_PROJECT_VAR}=${shellSingleQuote(project)}`,\n `${INFRA_KIT_ENV_LOADED_AT_VAR}=${shellSingleQuote(loadedAt)}`,\n 'set +a',\n ]\n\n const cacheDir = getSessionCacheDir()\n const envFilePath = path.resolve(cacheDir, ENV_LOAD_FILE)\n\n fs.mkdirSync(cacheDir, { recursive: true, mode: 0o700 })\n atomicWriteFileSync(envFilePath, `${envFileLines.join('\\n')}\\n`, 0o600)\n\n // REQUIRED\n process.stdout.write(`${envFilePath}\\n`)\n\n // Logs to stderr (pino \u2192 pretty-print), so it doesn't pollute the captured\n // file path that the shell wrapper reads from stdout.\n commandEcho.print()\n\n const varCount = countEnvVarLines(envContent)\n\n const structuredContent = {\n filePath: envFilePath,\n variableCount: varCount,\n project,\n config: selectedConfig,\n }\n\n return {\n content: textContent(JSON.stringify(structuredContent, null, 2)),\n structuredContent,\n }\n}\n\n/**\n * Cap the Doppler stdout we're willing to accept. A well-formed env bundle is\n * O(10 KB); megabytes would indicate a service regression or the wrong stream\n * being captured, and we don't want to write that to disk or source it.\n */\nexport const DOPPLER_MAX_OUTPUT_BYTES = 1024 * 1024\n\n/**\n * Hard upper bound for the Doppler subprocess. Well under zx's default so a\n * hung call surfaces quickly instead of blocking an interactive shell or an\n * MCP tool handler.\n */\nconst DOPPLER_DOWNLOAD_TIMEOUT_MS = 30_000\n\nconst downloadDopplerSecrets = async (project: string, config: string): Promise<string> => {\n const prevQuiet = $.quiet\n\n $.quiet = true\n try {\n const result =\n await $`doppler secrets download --no-file --format env --project ${project} --config ${config}`.timeout(\n DOPPLER_DOWNLOAD_TIMEOUT_MS,\n )\n\n assertDopplerOutputSize(result.stdout)\n\n return result.stdout.trim()\n } finally {\n $.quiet = prevQuiet\n }\n}\n\nexport const assertDopplerOutputSize = (stdout: string): void => {\n const bytes = Buffer.byteLength(stdout, 'utf-8')\n\n if (bytes > DOPPLER_MAX_OUTPUT_BYTES) {\n throw new Error(\n `doppler returned unexpectedly large output (${bytes} bytes > ${DOPPLER_MAX_OUTPUT_BYTES}) \u2014 refusing to write to disk`,\n )\n }\n}\n\nconst countEnvVarLines = (content: string): number => {\n return content.split('\\n').filter((line) => {\n return ENV_VAR_LINE_PATTERN.test(line)\n }).length\n}\n\nconst SHELL_DIRECTIVE_LINES = new Set(['set -a', 'set +a'])\n\nexport const shellSingleQuote = (value: string): string => {\n const escaped = value.replaceAll(\"'\", \"'\\\\''\")\n\n return `'${escaped}'`\n}\n\n/**\n * Guard against Doppler returning non-env output (auth warnings on stdout,\n * partial downloads, HTML error pages, etc.). Every non-blank, non-directive\n * line must match KEY=VALUE \u2014 skipping directives keeps future format tweaks\n * cheap without loosening the check.\n */\nexport const assertValidEnvContent = (content: string): void => {\n if (content.trim().length === 0) {\n throw new Error('doppler returned empty output for env-load')\n }\n\n for (const line of content.split('\\n')) {\n const trimmed = line.trim()\n\n if (trimmed.length === 0 || SHELL_DIRECTIVE_LINES.has(trimmed)) continue\n\n if (!ENV_VAR_LINE_PATTERN.test(trimmed)) {\n throw new Error(\n `doppler returned unexpected output for env-load (expected KEY=value lines, got: ${JSON.stringify(trimmed.slice(0, 80))})`,\n )\n }\n }\n}\n\n// MCP Tool Registration\nexport const envLoadMcpTool = defineMcpTool({\n name: 'env-load',\n description:\n 'Download the env vars for a Doppler config and write them to a temporary shell script. Does NOT mutate the calling process \u2014 returns the path to a script that must be sourced (\"source <filePath>\") for the vars to take effect. The infra-kit shell wrapper auto-sources; direct MCP callers must handle sourcing themselves or surface filePath to the user. \"config\" is required when invoked via MCP (the CLI interactive picker is unreachable without a TTY).',\n inputSchema: {\n config: z\n .string()\n .describe('Doppler config / environment name to load (e.g. \"dev\", \"arthur\", \"renana\"). Required for MCP calls.'),\n },\n outputSchema: {\n filePath: z.string().describe('Path to the file that must be sourced to apply variables'),\n variableCount: z.number().describe('Number of variables loaded'),\n project: z.string().describe('Doppler project name'),\n config: z.string().describe('Doppler config name'),\n },\n handler: envLoad,\n})\n", "import { $ } from 'zx'\n\n/**\n * Validate Doppler CLI installation and authentication status. Throws on failure\n * so callers (CLI entry, MCP tool handler) can translate to the right surface \u2014\n * CLI exits non-zero; MCP returns a structured tool error instead of tearing\n * down the server.\n */\nexport const validateDopplerCliAndAuth = async (): Promise<void> => {\n try {\n await $`doppler --version`\n } catch (error: unknown) {\n throw new Error('Doppler CLI is not installed. Install it from: https://docs.doppler.com/docs/install-cli', {\n cause: error,\n })\n }\n\n try {\n await $`doppler me`\n } catch (error: unknown) {\n throw new Error('Doppler CLI is not authenticated. Run: doppler login', { cause: error })\n }\n}\n", "import { logger } from 'src/lib/logger'\n\ninterface CommandOption {\n flag: string\n value: string | string[] | boolean\n}\n\nconst createCommandEcho = () => {\n let commandName = ''\n let options: CommandOption[] = []\n let isInteractive = false\n\n return {\n /**\n * Initialize command echo for a new command\n */\n start(name: string): void {\n commandName = name\n options = []\n isInteractive = false\n },\n\n /**\n * Mark that the command had interactive input (prompts)\n * Call this once when ANY prompt happens\n */\n setInteractive(): void {\n isInteractive = true\n },\n\n /**\n * Track an option selection\n * @param flag The CLI flag (e.g., \"--versions\")\n * @param value The selected value\n */\n addOption(flag: string, value: string | string[] | boolean): void {\n options.push({ flag, value })\n },\n\n /**\n * Print the equivalent CLI command if there was interactive input\n */\n print(): void {\n if (!isInteractive || options.length === 0) {\n return\n }\n\n const formattedOptions = options\n .map((opt) => {\n if (typeof opt.value === 'boolean') {\n return opt.value ? opt.flag : ''\n }\n\n if (Array.isArray(opt.value)) {\n return `${opt.flag} \"${opt.value.join(', ')}\"`\n }\n\n return `${opt.flag} \"${opt.value}\"`\n })\n .filter(Boolean)\n .join(' ')\n\n logger.info(`\uD83D\uDCDF Equivalent command: \\npnpm exec infra-kit ${commandName} ${formattedOptions}\\n`)\n },\n\n /**\n * Reset state (useful for testing)\n */\n reset(): void {\n commandName = ''\n options = []\n isInteractive = false\n },\n }\n}\n\n// Singleton instance (same pattern as logger)\nexport const commandEcho = createCommandEcho()\n", "import path from 'node:path'\nimport process from 'node:process'\nimport { z } from 'zod'\n\nimport { validateDopplerCliAndAuth } from 'src/integrations/doppler'\nimport {\n ENV_LOAD_FILE,\n INFRA_KIT_ENV_CONFIG_VAR,\n INFRA_KIT_ENV_LOADED_AT_VAR,\n INFRA_KIT_ENV_PROJECT_VAR,\n INFRA_KIT_SESSION_VAR,\n getSessionCacheDir,\n parseVarNamesFromEnvFile,\n} from 'src/lib/constants'\nimport { logger } from 'src/lib/logger'\nimport { defineMcpTool, textContent } from 'src/types'\n\n/**\n * Show Doppler authentication status and detected project info\n */\nexport const envStatus = async () => {\n await validateDopplerCliAndAuth()\n\n logger.info('Environment session status:')\n\n // Check session-loaded vars \u2014 getSessionCacheDir() throws if INFRA_KIT_SESSION is unset\n const cacheDir = getSessionCacheDir()\n\n const sessionId = process.env[INFRA_KIT_SESSION_VAR]!\n const envLoadPath = path.join(cacheDir, ENV_LOAD_FILE)\n\n let sessionLoadedCount = 0\n let sessionTotalCount = 0\n\n const sessionConfig = process.env[INFRA_KIT_ENV_CONFIG_VAR] ?? null\n const sessionProject = process.env[INFRA_KIT_ENV_PROJECT_VAR] ?? null\n const sessionLoadedAt = process.env[INFRA_KIT_ENV_LOADED_AT_VAR] ?? null\n\n if (sessionConfig) {\n const varNames = parseVarNamesFromEnvFile(envLoadPath)\n\n if (varNames.length > 0) {\n sessionTotalCount = varNames.length\n sessionLoadedCount = varNames.filter((v) => {\n return v in process.env\n }).length\n }\n\n const loadedAtDisplay = sessionLoadedAt?.replace(/\\.\\d{3}Z$/, '') ?? null\n\n logger.info(\n ` ${sessionConfig}: ${sessionLoadedCount} of ${sessionTotalCount} vars loaded (project: ${sessionProject}, loadedAt: ${loadedAtDisplay}, session: ${sessionId})\\n`,\n )\n\n if (sessionTotalCount > 0 && sessionLoadedCount < sessionTotalCount) {\n const missing = sessionTotalCount - sessionLoadedCount\n\n logger.warn(\n ` ${missing} cached var(s) are not present in the current process \u2014 env-load needs to be re-sourced, or vars were unset manually.`,\n )\n }\n } else {\n logger.info(` Session ${sessionId}: no env loaded\\n`)\n }\n\n const structuredContent = {\n sessionId,\n sessionLoadedCount,\n sessionTotalCount,\n sessionConfig,\n sessionProject,\n sessionLoadedAt,\n }\n\n return {\n content: textContent(JSON.stringify(structuredContent, null, 2)),\n structuredContent,\n }\n}\n\n// MCP Tool Registration\nexport const envStatusMcpTool = defineMcpTool({\n name: 'env-status',\n description:\n 'Report which Doppler project/config is currently loaded in the terminal session, when it was loaded, and how many variables are cached. Read-only \u2014 use env-load / env-clear to change the terminal session.',\n inputSchema: {},\n outputSchema: {\n sessionId: z.string().describe('Current terminal session ID'),\n sessionLoadedCount: z.number().describe('Number of cached vars active in the current session'),\n sessionTotalCount: z.number().describe('Total number of cached var names'),\n sessionConfig: z.string().nullable().describe('Doppler config name of the loaded session (environment name)'),\n sessionProject: z.string().nullable().describe('Doppler project name of the loaded session'),\n sessionLoadedAt: z.string().nullable().describe('ISO 8601 timestamp of when the env was loaded'),\n },\n handler: envStatus,\n})\n", "/* eslint-disable sonarjs/cognitive-complexity */\nimport checkbox from '@inquirer/checkbox'\nimport confirm from '@inquirer/confirm'\nimport process from 'node:process'\nimport { z } from 'zod'\nimport { $ } from 'zx'\n\nimport { getReleasePRsWithInfo } from 'src/integrations/gh'\nimport { commandEcho } from 'src/lib/command-echo'\nimport { OperationError } from 'src/lib/errors/operation-error'\nimport { assertManagementContext } from 'src/lib/git-guard'\nimport { logger } from 'src/lib/logger'\nimport { detectReleaseType, formatBranchChoices, getJiraDescriptions, releaseBranchLabels } from 'src/lib/release-utils'\nimport { defineMcpTool, textContent } from 'src/types'\nimport type { RequiredConfirmedOptionArg } from 'src/types'\n\ninterface GhMergeDevArgs extends RequiredConfirmedOptionArg {\n all?: boolean\n}\n\n/**\n * Merge dev into every release branch\n */\nexport const ghMergeDev = async (args: GhMergeDevArgs) => {\n const { all, confirmedCommand } = args\n\n commandEcho.start('merge-dev')\n\n await assertManagementContext({ operation: 'merge dev into release branches', requiredBranch: 'dev' })\n\n // Only merge dev into regular releases (not hotfixes, which target main)\n const allPRs = await getReleasePRsWithInfo()\n const releasePRsList = allPRs\n .filter((pr) => {\n return detectReleaseType(pr.title) === 'regular'\n })\n .map((pr) => {\n return pr.branch\n })\n\n if (releasePRsList.length === 0) {\n logger.info('\u2139\uFE0F No open release branches found')\n\n commandEcho.print()\n\n return {\n content: textContent(\n JSON.stringify({ successfulMerges: 0, failedMerges: 0, failedBranches: [], totalBranches: 0 }, null, 2),\n ),\n structuredContent: { successfulMerges: 0, failedMerges: 0, failedBranches: [], totalBranches: 0 },\n }\n }\n\n let selectedReleaseBranches: string[] = []\n\n if (all) {\n selectedReleaseBranches = releasePRsList\n } else {\n commandEcho.setInteractive()\n\n const descriptions = await getJiraDescriptions()\n\n selectedReleaseBranches = await checkbox({\n required: true,\n message: '\uD83C\uDF3F Select release branches',\n choices: formatBranchChoices({ branches: releasePRsList, descriptions }),\n })\n }\n\n // Track --all flag if all branches were selected (either via flag or interactively)\n const allSelected = selectedReleaseBranches.length === releasePRsList.length\n\n if (allSelected) {\n commandEcho.addOption('--all', true)\n } else {\n commandEcho.addOption('--versions', releaseBranchLabels(selectedReleaseBranches))\n }\n\n // Validate input\n // if (selectedReleaseBranches.length === 0) {\n // console.error('No branches provided. Exiting...')\n // process.exit(1)\n // }\n\n const answer = confirmedCommand\n ? true\n : await confirm({\n message: `Are you sure you want to merge dev into these branches: ${selectedReleaseBranches.join(', ')}?`,\n })\n\n if (!confirmedCommand) {\n commandEcho.setInteractive()\n }\n\n if (!answer) {\n logger.info('Operation cancelled. Exiting...')\n process.exit(0)\n }\n\n // Track --yes flag if confirmation was interactive (user confirmed)\n if (!confirmedCommand) {\n commandEcho.addOption('--yes', true)\n }\n\n $.quiet = true\n\n await $`git fetch origin`\n await $`git switch dev`\n await $`git pull origin dev`\n\n const failedBranches: string[] = []\n\n // Merge dev into each branch\n for (const branch of selectedReleaseBranches) {\n const success = await mergeDev(branch)\n\n if (!success) {\n failedBranches.push(branch)\n }\n }\n\n $.quiet = false\n\n if (failedBranches.length > 0) {\n logger.info(`\\n\u26A0\uFE0F ${failedBranches.length} branch(es) failed to merge automatically.\\n`)\n logger.info('\uD83D\uDCCB Manual merge script for failed branches:')\n for (const branch of failedBranches) {\n logger.info(\n `# Merge dev into ${branch} and resolve conflicts if any \\n\\ngit switch ${branch} && git pull origin ${branch} && git merge origin/dev\\ngit push origin ${branch} && git switch dev\\n`,\n )\n }\n logger.info(\n `\u2705 ${selectedReleaseBranches.length - failedBranches.length}/${selectedReleaseBranches.length} merges completed successfully.`,\n )\n } else {\n logger.info('\u2705 All merges completed successfully!\\n')\n }\n\n commandEcho.print()\n\n const structuredContent = {\n successfulMerges: selectedReleaseBranches.length - failedBranches.length,\n failedMerges: failedBranches.length,\n failedBranches,\n totalBranches: selectedReleaseBranches.length,\n }\n\n return {\n content: textContent(JSON.stringify(structuredContent, null, 2)),\n structuredContent,\n }\n}\n\nconst mergeDev = async (branch: string): Promise<boolean> => {\n try {\n await $`git switch ${branch}`\n\n await $`git pull origin ${branch}`\n\n await $`git merge origin/dev --no-edit`\n\n await $`git push origin ${branch}`\n\n await $`git switch dev`\n\n logger.info(`Successfully merged dev into ${branch}`)\n\n return true\n } catch (error: unknown) {\n const err = new OperationError(error, {\n operation: `merge dev into ${branch}`,\n remediation: \"resolve conflicts manually or rerun after 'git fetch origin'\",\n })\n\n logger.error({ error, branch, msg: err.message })\n\n await $`git reset --merge HEAD~1`\n\n return false\n }\n}\n\n// MCP Tool Registration\nexport const ghMergeDevMcpTool = defineMcpTool({\n name: 'gh-merge-dev',\n description:\n 'Merge origin/dev into every open regular (non-hotfix) release branch and push the result. Mutates local git state and the remote release branches. When invoked via MCP, pass all=true \u2014 the branch picker is unreachable without a TTY, and the confirmation prompt is auto-skipped for MCP calls, so the caller is responsible for gating. Irreversible once pushed.',\n inputSchema: {\n all: z\n .boolean()\n .optional()\n .describe(\n 'Target every open regular release branch. Must be true for MCP calls (the interactive picker is unavailable without a TTY).',\n ),\n },\n outputSchema: {\n successfulMerges: z.number().describe('Number of successful merges'),\n failedMerges: z.number().describe('Number of failed merges'),\n failedBranches: z.array(z.string()).describe('List of branches that failed to merge'),\n totalBranches: z.number().describe('Total number of branches processed'),\n },\n handler: ghMergeDev,\n})\n", "import process from 'node:process'\nimport { $ } from 'zx'\n\nimport { logger } from 'src/lib/logger'\n\n/**\n * Validate GitHub CLI installation and authentication status and throw an error if not valid\n */\nexport const validateGitHubCliAndAuth = async () => {\n try {\n await $`gh --version`\n } catch (error: unknown) {\n logger.error({ error }, 'Error: GitHub CLI (gh) is not installed.')\n logger.error('Please install it from: https://cli.github.com/')\n process.exit(1)\n }\n\n try {\n await $`gh auth status`\n } catch (error: unknown) {\n logger.error({ error }, 'Error: GitHub CLI (gh) is not authenticated.')\n logger.error('Please authenticate it from: https://cli.github.com/manual/gh_auth_login or type \"gh auth login\"')\n process.exit(1)\n }\n}\n", "import process from 'node:process'\nimport { $ } from 'zx'\n\nimport { logger } from 'src/lib/logger'\nimport { compareReleaseIds, formatBranchName, formatPrTitle, parseBranchName } from 'src/lib/release-id'\nimport type { ReleaseId } from 'src/lib/release-id'\nimport { getBaseBranch } from 'src/lib/release-utils'\nimport type { ReleaseType } from 'src/lib/release-utils'\n\ninterface ReleasePR {\n headRefName: string\n number: number\n state: string\n title: string\n baseRefName: string\n createdAt: string\n}\n\nexport interface ReleasePRInfo {\n branch: string\n title: string\n createdAt: string\n}\n\n/**\n * Sort release head refs in the locked deterministic order (versions block\n * first by semver ascending, then names by PR creation date). Head refs that\n * are not valid release branches (parseBranchName \u2192 null) are filtered out\n * rather than throwing or NaN-sorting, so a stray junk branch can never break\n * discovery. Carries each PR's createdAt for name ordering.\n */\nconst sortReleasePRs = (prs: ReleasePR[]): ReleasePR[] => {\n return prs\n .map((pr) => {\n return { pr, id: parseBranchName(pr.headRefName) }\n })\n .filter((entry): entry is { pr: ReleasePR; id: NonNullable<typeof entry.id> } => {\n return entry.id !== null\n })\n .sort((a, b) => {\n return compareReleaseIds(a.id, b.id, { a: a.pr.createdAt, b: b.pr.createdAt })\n })\n .map((entry) => {\n return entry.pr\n })\n}\n\n/**\n * Fetch all open release/hotfix PRs from GitHub.\n * Searches both dev (regular) and main (hotfix) base branches.\n * Returns deduplicated ReleasePR objects.\n */\nconst fetchAllReleasePRs = async (): Promise<ReleasePR[]> => {\n const releasePRs =\n await $`gh pr list --search \"Release in:title\" --base dev --json number,title,headRefName,state,baseRefName,createdAt`\n\n const hotfixPRs =\n await $`gh pr list --search \"Hotfix in:title\" --base main --json number,title,headRefName,state,baseRefName,createdAt`\n\n const all: ReleasePR[] = [...JSON.parse(releasePRs.stdout), ...JSON.parse(hotfixPRs.stdout)]\n\n // Deduplicate by headRefName\n const seen = new Set<string>()\n\n return all.filter((pr) => {\n if (seen.has(pr.headRefName)) return false\n\n seen.add(pr.headRefName)\n\n return true\n })\n}\n\n/**\n * Fetch open release PRs from GitHub with 'Release' or 'Hotfix' in the title.\n * Returns an array of headRefName strings in the locked deterministic order\n * (version branches first by semver ascending, then named branches by PR\n * creation date). Unparseable head refs are filtered out.\n *\n * @returns [release/v1.18.22, release/v1.18.23, release/checkout-redesign]\n */\nexport const getReleasePRs = async (): Promise<string[]> => {\n try {\n const prs = await fetchAllReleasePRs()\n\n if (prs.length === 0) {\n logger.error('\u274C No release PRs found. Check the project folder for the script. Exiting...')\n\n process.exit(1)\n }\n\n return sortReleasePRs(prs).map((pr) => {\n return pr.headRefName\n })\n } catch (error) {\n logger.error({ error }, '\u274C Error fetching release PRs')\n\n process.exit(1)\n }\n}\n\n/**\n * Fetch open release PRs with title info (for detecting release type).\n * Returns ReleasePRInfo objects in the locked deterministic order (version\n * branches first by semver ascending, then named branches by PR creation\n * date). Unparseable head refs are filtered out.\n */\nexport const getReleasePRsWithInfo = async (): Promise<ReleasePRInfo[]> => {\n try {\n const prs = await fetchAllReleasePRs()\n\n if (prs.length === 0) {\n logger.error('\u274C No release PRs found. Check the project folder for the script. Exiting...')\n process.exit(1)\n }\n\n return sortReleasePRs(prs).map((pr) => {\n return {\n branch: pr.headRefName,\n title: pr.title,\n createdAt: pr.createdAt,\n }\n })\n } catch (error) {\n logger.error({ error }, '\u274C Error fetching release PRs')\n process.exit(1)\n }\n}\n\ninterface UpdateReleasePRBodyArgs {\n branch: string\n body: string\n}\n\n/**\n * Update the body of an open release PR identified by its head branch.\n */\nexport const updateReleasePRBody = async (args: UpdateReleasePRBodyArgs): Promise<void> => {\n const { branch, body } = args\n\n try {\n $.quiet = true\n await $`gh pr edit ${branch} --body ${body}`\n $.quiet = false\n } catch (error: unknown) {\n logger.error({ error, branch }, `Error updating release PR body for ${branch}`)\n throw error\n }\n}\n\ninterface CreateReleaseBranchArgs {\n id: ReleaseId\n jiraVersionUrl: string\n type: ReleaseType\n description?: string\n}\n\n// Function to create a release branch\nexport const createReleaseBranch = async (\n args: CreateReleaseBranchArgs,\n): Promise<{ branchName: string; prUrl: string }> => {\n const { id, jiraVersionUrl, type, description } = args\n const prTitle = formatPrTitle(id, type)\n const baseBranch = getBaseBranch(type)\n\n const branchName = formatBranchName(id)\n\n const body = description && description.trim() !== '' ? `${jiraVersionUrl}\\n\\n${description}` : `${jiraVersionUrl} \\n`\n\n try {\n $.quiet = true\n\n await $`git switch ${baseBranch}`\n await $`git pull origin ${baseBranch}`\n await $`git checkout -b ${branchName}`\n await $`git push -u origin ${branchName}`\n await $`git commit --allow-empty-message --allow-empty --message ''`\n await $`git push origin ${branchName}`\n\n // Create PR and capture URL\n const prResult = await $`gh pr create --title ${prTitle} --body ${body} --base ${baseBranch} --head ${branchName}`\n\n const prLink = prResult.stdout.trim()\n\n await $`git switch ${baseBranch}`\n\n $.quiet = false\n\n return {\n branchName,\n prUrl: prLink,\n }\n } catch (error: unknown) {\n logger.error({ error, branchName }, `Error creating release branch ${branchName}`)\n\n throw error\n }\n}\n", "import { $ } from 'zx'\n\nimport { createReleaseBranch } from 'src/integrations/gh'\nimport { createJiraVersion, getProjectVersions, loadJiraConfigOptional } from 'src/integrations/jira'\nimport type { JiraConfig } from 'src/integrations/jira'\nimport { OperationError } from 'src/lib/errors/operation-error'\nimport { displayLabel, formatBranchName, formatJiraName, parseBranchName, parseReleaseRef } from 'src/lib/release-id'\nimport type { ReleaseId } from 'src/lib/release-id'\n\n/** Sentinel ref for deploying from the `dev` branch instead of a release branch. */\nexport const DEV_REF = 'dev'\n\nexport type ReleaseType = 'regular' | 'hotfix'\n\n/**\n * Get the base branch for a release type.\n * Regular releases branch from/to dev, hotfixes branch from/to main.\n */\nexport const getBaseBranch = (type: ReleaseType): string => {\n return type === 'hotfix' ? 'main' : 'dev'\n}\n\nexport interface ReleaseCreationResult {\n version: string\n type: ReleaseType\n branchName: string\n prUrl: string\n jiraVersionUrl: string\n}\n\n/**\n * Prepare git repository for release creation\n * Fetches latest changes, switches to base branch, and pulls latest\n */\nexport const prepareGitForRelease = async (type: ReleaseType = 'regular'): Promise<void> => {\n const baseBranch = getBaseBranch(type)\n\n $.quiet = true\n\n await $`git fetch origin`\n await $`git switch ${baseBranch}`\n await $`git pull origin ${baseBranch}`\n\n $.quiet = false\n}\n\ninterface CreateSingleReleaseArgs {\n id: ReleaseId\n jiraConfig: JiraConfig\n description?: string\n type?: ReleaseType\n}\n\n/**\n * Create a single release by creating both Jira version and GitHub release branch\n */\nexport const createSingleRelease = async (args: CreateSingleReleaseArgs): Promise<ReleaseCreationResult> => {\n const { id, jiraConfig, description, type = 'regular' } = args\n // 1. Create Jira version (mandatory). For versioned releases this is\n // \"v1.2.3\" (byte-identical to before); for named releases it is \"<name>\".\n const versionName = formatJiraName(id)\n\n const result = await createJiraVersion(\n {\n name: versionName,\n projectId: jiraConfig.projectId,\n description: description || '',\n released: false,\n archived: false,\n },\n jiraConfig,\n )\n\n // Construct user-friendly Jira URL using project key from API response\n const jiraVersionUrl = `${jiraConfig.baseUrl}/projects/${result.version!.projectId}/versions/${result.version!.id}/tab/release-report-all-issues`\n\n // 2. Create GitHub release branch\n const releaseInfo = await createReleaseBranch({ id, jiraVersionUrl, type, description })\n\n return {\n version: displayLabel(id),\n type,\n branchName: releaseInfo.branchName,\n prUrl: releaseInfo.prUrl,\n jiraVersionUrl,\n }\n}\n\n/**\n * Fetch Jira version descriptions mapped by version name (e.g., \"v1.2.5\" \u2192 \"Some description\")\n * Gracefully returns empty map if Jira is unavailable\n */\nexport const getJiraDescriptions = async (): Promise<Map<string, string>> => {\n const descriptions = new Map<string, string>()\n\n const jiraConfig = await loadJiraConfigOptional()\n\n if (!jiraConfig) return descriptions\n\n try {\n const versions = await getProjectVersions(jiraConfig)\n\n for (const version of versions) {\n if (version.description) {\n descriptions.set(version.name, version.description)\n }\n }\n } catch {\n // Jira fetch failed, continue without descriptions\n }\n\n return descriptions\n}\n\n/**\n * Format a version string with its release type tag, e.g. \"1.2.5 [regular]\"\n * When maxVersionLength is provided, pads the version for alignment.\n */\nexport const formatVersionLabel = (version: string, type: ReleaseType, maxVersionLength?: number): string => {\n const padding = maxVersionLength ? ' '.repeat(maxVersionLength - version.length + 3) : ' '\n const tag = `[${type}]`.padEnd(11)\n\n return `${version}${padding}${tag}`\n}\n\n/**\n * Detect release type from PR title.\n * PRs titled \"Hotfix v...\" are hotfix, everything else is regular.\n */\nexport const detectReleaseType = (title: string): ReleaseType => {\n return title.toLowerCase().startsWith('hotfix') ? 'hotfix' : 'regular'\n}\n\ninterface FormatBranchChoicesArgs {\n branches: string[]\n descriptions: Map<string, string>\n types?: Map<string, ReleaseType>\n}\n\ninterface ParsedBranchChoice {\n branch: string\n id: ReleaseId\n /** Human display label: `1.2.3` | `<name>`. */\n label: string\n}\n\n/**\n * Parse branches into release ids, dropping any that do not parse (lenient\n * discovery source). Exported for unit testing the version/name/junk split.\n */\nexport const parseBranchChoices = (branches: string[]): ParsedBranchChoice[] => {\n return branches.flatMap((branch) => {\n const id = parseBranchName(branch)\n\n if (!id) return []\n\n return [{ branch, id, label: displayLabel(id) }]\n })\n}\n\n/**\n * Resolve an operator-supplied release ref (version `1.2.3` / `v1.2.3` or name\n * `checkout-redesign`) to its branch name (`release/v1.2.3` | `release/<name>`).\n * Strict: surfaces a parse failure as an OperationError with remediation text.\n */\nexport const resolveReleaseBranch = (versionArg: string): string => {\n try {\n return formatBranchName(parseReleaseRef(versionArg))\n } catch (error) {\n throw new OperationError(error, {\n operation: `resolve release ref \"${versionArg}\"`,\n remediation: 'pass a version (e.g. \"1.2.5\") or a release name (e.g. \"checkout-redesign\")',\n })\n }\n}\n\n/**\n * Render the human display label for a release branch. Returns the `dev`\n * sentinel unchanged; otherwise derives `1.2.3` | `<name>` from the branch.\n * Falls back to the raw branch when it does not parse as a release id.\n */\nexport const releaseLabelFromBranch = (branch: string): string => {\n if (branch === DEV_REF) return DEV_REF\n\n const id = parseBranchName(branch)\n\n return id ? displayLabel(id) : branch\n}\n\n/**\n * Render human display labels for a list of release branches, dropping any\n * branch that does not parse as a release id (lenient discovery contract).\n */\nexport const releaseBranchLabels = (branches: string[]): string[] => {\n return branches.flatMap((branch) => {\n const id = parseBranchName(branch)\n\n return id ? [displayLabel(id)] : []\n })\n}\n\n/**\n * Format release branch names as checkbox choices with aligned type tags and Jira descriptions\n */\nexport const formatBranchChoices = (args: FormatBranchChoicesArgs): { name: string; value: string }[] => {\n const { branches, descriptions, types } = args\n\n const parsed = parseBranchChoices(branches)\n\n const maxLen = Math.max(\n 0,\n ...parsed.map((p) => {\n return p.label.length\n }),\n )\n\n return parsed.map(({ branch, id, label }) => {\n const type = types ? types.get(branch) || 'regular' : undefined\n // Jira-descriptions map is keyed by the Jira version NAME (`v1.2.3` | `<name>`).\n const desc = descriptions.get(formatJiraName(id))\n const padding = ' '.repeat(maxLen - label.length + 3)\n\n let name = type ? formatVersionLabel(label, type, maxLen) : label\n\n if (desc) {\n name = type ? `${name} ${desc}` : `${label}${padding}${desc}`\n }\n\n return { name, value: branch }\n })\n}\n", "import process from 'node:process'\n\nimport { logger } from 'src/lib/logger'\n\nimport type {\n CreateJiraVersionParams,\n CreateJiraVersionResult,\n DeliverJiraReleaseParams,\n DeliverJiraReleaseResult,\n JiraConfig,\n JiraVersion,\n UpdateJiraVersionParams,\n UpdateJiraVersionResult,\n} from './types.js'\n\n/**\n * Creates a new version in Jira using the REST API\n * @param params - Version creation parameters\n * @param config - Jira configuration (baseUrl, token, projectId)\n * @returns Result containing created version or error\n */\nexport const createJiraVersion = async (\n params: CreateJiraVersionParams,\n config: JiraConfig,\n): Promise<CreateJiraVersionResult> => {\n try {\n const { baseUrl, token, email, projectId } = config\n\n // Use current date if not provided\n // const releaseDate =\n // params.releaseDate || new Date().toISOString().split('T')[0] // 2025-12-06\n\n // Prepare request body\n const requestBody = {\n name: params.name,\n projectId: params.projectId || projectId,\n description: params.description || '',\n // releaseDate,\n released: params.released || false,\n archived: params.archived || false,\n }\n\n // logger.info(\n // { version: params.name, projectId: requestBody.projectId },\n // 'Creating Jira version',\n // )\n\n // Make API request\n const url = `${baseUrl}/rest/api/3/version`\n\n // Create Basic auth credentials\n const credentials = btoa(`${email}:${token}`)\n\n const response = await fetch(url, {\n method: 'POST',\n headers: {\n Accept: 'application/json',\n 'Content-Type': 'application/json',\n Authorization: `Basic ${credentials}`,\n },\n body: JSON.stringify(requestBody),\n })\n\n if (!response.ok) {\n const errorText = await response.text()\n\n logger.error(\n {\n status: response.status,\n statusText: response.statusText,\n error: errorText,\n },\n 'Failed to create Jira version',\n )\n\n throw new Error(`HTTP ${response.status}: ${response.statusText}`)\n }\n\n const version = (await response.json()) as JiraVersion\n\n // logger.info(\n // { versionId: version.id, versionName: version.name },\n // 'Successfully created Jira version',\n // )\n\n return {\n success: true,\n version,\n }\n } catch (error) {\n logger.error({ error }, 'Error creating Jira version')\n\n throw error\n }\n}\n\n/**\n * Gets all versions for a project from Jira\n * @param config - Jira configuration\n * @returns Array of JiraVersion objects\n */\nexport const getProjectVersions = async (config: JiraConfig): Promise<JiraVersion[]> => {\n try {\n const { baseUrl, token, email, projectId } = config\n\n const url = `${baseUrl}/rest/api/3/project/${projectId}/versions`\n const credentials = btoa(`${email}:${token}`)\n\n const response = await fetch(url, {\n method: 'GET',\n headers: {\n Accept: 'application/json',\n Authorization: `Basic ${credentials}`,\n },\n })\n\n if (!response.ok) {\n const errorText = await response.text()\n\n logger.error(\n {\n status: response.status,\n statusText: response.statusText,\n error: errorText,\n },\n 'Failed to get Jira project versions',\n )\n\n throw new Error(`HTTP ${response.status}: ${response.statusText}`)\n }\n\n const versions = (await response.json()) as JiraVersion[]\n\n return versions\n } catch (error) {\n logger.error({ error }, 'Error getting Jira project versions')\n\n throw error\n }\n}\n\n/**\n * Finds a Jira version by name in the project\n * @param versionName - Name of the version to find (e.g., \"v1.33.10\")\n * @param config - Jira configuration\n * @returns JiraVersion if found, null otherwise\n */\nexport const findVersionByName = async (versionName: string, config: JiraConfig): Promise<JiraVersion | null> => {\n try {\n const versions = await getProjectVersions(config)\n const version = versions.find((v) => {\n return v.name === versionName\n })\n\n return version || null\n } catch (error) {\n logger.error({ error, versionName }, 'Error finding Jira version by name')\n\n throw error\n }\n}\n\n/**\n * Updates an existing Jira version\n * @param params - Update parameters\n * @param config - Jira configuration\n * @returns Result containing updated version or error\n */\nexport const updateJiraVersion = async (\n params: UpdateJiraVersionParams,\n config: JiraConfig,\n): Promise<UpdateJiraVersionResult> => {\n try {\n const { baseUrl, token, email } = config\n\n // Only include fields the caller explicitly passed.\n const requestBody: Record<string, any> = {}\n\n if (params.released !== undefined) requestBody.released = params.released\n if (params.archived !== undefined) requestBody.archived = params.archived\n if (params.releaseDate !== undefined) requestBody.releaseDate = params.releaseDate\n if (params.description !== undefined) requestBody.description = params.description\n\n const url = `${baseUrl}/rest/api/3/version/${params.versionId}`\n const credentials = btoa(`${email}:${token}`)\n\n const response = await fetch(url, {\n method: 'PUT',\n headers: {\n Accept: 'application/json',\n 'Content-Type': 'application/json',\n Authorization: `Basic ${credentials}`,\n },\n body: JSON.stringify(requestBody),\n })\n\n if (!response.ok) {\n const errorText = await response.text()\n\n logger.error(\n {\n status: response.status,\n statusText: response.statusText,\n error: errorText,\n },\n 'Failed to update Jira version',\n )\n\n throw new Error(`HTTP ${response.status}: ${response.statusText}`)\n }\n\n const version = (await response.json()) as JiraVersion\n\n return {\n success: true,\n version,\n }\n } catch (error) {\n logger.error({ error }, 'Error updating Jira version')\n\n throw error\n }\n}\n\n/**\n * Delivers a Jira release by marking it as released with the current date\n * @param params - Parameters containing the version name\n * @param config - Jira configuration\n * @returns Result containing updated version\n * @throws Error if version not found or update fails\n */\nexport const deliverJiraRelease = async (\n params: DeliverJiraReleaseParams,\n config: JiraConfig,\n): Promise<DeliverJiraReleaseResult> => {\n try {\n const { versionName } = params\n\n // Find the version by name\n const version = await findVersionByName(versionName, config)\n\n if (!version) {\n logger.error({ versionName }, 'Jira version not found')\n throw new Error(`Version \"${versionName}\" not found in Jira project`)\n }\n\n // Update the version to mark it as released\n const result = await updateJiraVersion(\n {\n versionId: version.id,\n released: true,\n releaseDate: new Date().toISOString().split('T')[0], // Current date in YYYY-MM-DD format\n },\n config,\n )\n\n return result\n } catch (error) {\n logger.error({ error }, 'Error delivering Jira release')\n throw error\n }\n}\n\n/**\n * Loads Jira configuration from environment variables\n * @throws Error with detailed message if configuration is missing or invalid\n * @returns Promise<JiraConfig>\n */\nexport const loadJiraConfig = async (): Promise<JiraConfig> => {\n const baseUrl = process.env.JIRA_BASE_URL\n const token = process.env.JIRA_TOKEN || process.env.JIRA_API_TOKEN\n const projectIdStr = process.env.JIRA_PROJECT_ID\n const email = process.env.JIRA_EMAIL\n\n const missingVars: string[] = []\n\n if (!baseUrl) missingVars.push('JIRA_BASE_URL (e.g., https://your-domain.atlassian.net)')\n if (!token) missingVars.push('JIRA_TOKEN or JIRA_API_TOKEN (your Jira API token)')\n if (!projectIdStr) missingVars.push('JIRA_PROJECT_ID (numeric project ID)')\n if (!email) missingVars.push('JIRA_EMAIL (your Jira email address)')\n\n if (missingVars.length > 0) {\n const errorMessage = [\n 'Jira configuration is required but incomplete.',\n 'Please configure the following environment variables:',\n ...missingVars.map((v) => {\n return ` - ${v}`\n }),\n '',\n 'You can set these in your .env file or as environment variables.',\n ].join('\\n')\n\n throw new Error(errorMessage)\n }\n\n const projectId = Number.parseInt(projectIdStr!, 10)\n\n if (Number.isNaN(projectId)) {\n throw new TypeError(`Invalid JIRA_PROJECT_ID: \"${projectIdStr}\" must be a numeric value (e.g., 10001)`)\n }\n\n return {\n baseUrl: baseUrl!.replace(/\\/$/, ''), // Remove trailing slash\n token: token!,\n projectId,\n email: email!,\n }\n}\n\n/**\n * Attempts to load Jira configuration from environment variables\n * Returns null if configuration is missing or invalid (for optional Jira integration)\n * @returns Promise<JiraConfig | null>\n */\nexport const loadJiraConfigOptional = async (): Promise<JiraConfig | null> => {\n try {\n const config = await loadJiraConfig()\n\n return config\n } catch (error) {\n logger.warn({ error }, 'Jira configuration not available, skipping Jira integration')\n\n return null\n }\n}\n", "const STDERR_EXCERPT_MAX_BYTES = 200\n\nexport interface OperationErrorContext {\n operation: string\n remediation?: string\n stderrExcerpt?: string\n}\n\n/**\n * Duck-typed read of zx's `ProcessOutput.stderr` (and similar shapes) without\n * importing zx types just for an `instanceof` check.\n *\n * @example\n * extractStderr(new Error('x')) // undefined\n * extractStderr({ stderr: 'fatal: ...' }) // 'fatal: ...'\n * extractStderr({ stderr: '' }) // undefined (empty treated as missing)\n */\nconst extractStderr = (cause: unknown): string | undefined => {\n if (cause === null || typeof cause !== 'object') return undefined\n const stderr = (cause as { stderr?: unknown }).stderr\n\n return typeof stderr === 'string' && stderr.length > 0 ? stderr : undefined\n}\n\n/**\n * Compose the human-and-agent-readable message body for an `OperationError`:\n * `\"failed to <operation> [\u2014 stderr: <excerpt>] [\u2014 try: <remediation>]\"`.\n * `stderrExcerpt` overrides anything duck-typed off `cause`; both are trimmed\n * and capped at {@link STDERR_EXCERPT_MAX_BYTES} so a runaway subprocess can't\n * blow up the message.\n */\nconst buildMessage = (cause: unknown, ctx: OperationErrorContext): string => {\n const stderr = ctx.stderrExcerpt ?? extractStderr(cause)\n const parts = [`failed to ${ctx.operation}`]\n\n if (stderr) parts.push(`stderr: ${stderr.slice(0, STDERR_EXCERPT_MAX_BYTES).trim()}`)\n if (ctx.remediation) parts.push(`try: ${ctx.remediation}`)\n\n return parts.join(' \u2014 ')\n}\n\n/**\n * Error type for any handler-level failure that should surface to the caller\n * (CLI user or MCP-connected agent) with a remediation hint. Wraps an\n * underlying cause and renders a single-line, structured message so logs and\n * agent tool-result text stay scannable.\n *\n * Pattern modeled on the exemplary Doppler errors in\n * `src/integrations/doppler/doppler-cli-auth.ts`.\n *\n * @example\n * // wrap a zx subprocess failure\n * try {\n * await $`git worktree add ${path} ${branch}`\n * } catch (err) {\n * throw new OperationError(err, {\n * operation: `git worktree add for ${branch}`,\n * remediation: 'check the branch name and that the parent dir is writable',\n * })\n * }\n *\n * @example\n * // validation failure with no underlying cause\n * throw new OperationError(undefined, {\n * operation: 'launch deploy-all workflow',\n * remediation: `pass one of: ${environments.join(', ')}`,\n * stderrExcerpt: `invalid environment: ${selectedEnv}`,\n * })\n */\nexport class OperationError extends Error {\n readonly operation: string\n readonly remediation?: string\n\n constructor(cause: unknown, ctx: OperationErrorContext) {\n super(buildMessage(cause, ctx), { cause })\n this.name = 'OperationError'\n this.operation = ctx.operation\n this.remediation = ctx.remediation\n }\n}\n", "import { OperationError } from 'src/lib/errors/operation-error'\nimport { getCurrentBranch, isInsideLinkedWorktree, isWorkingTreeClean } from 'src/lib/git-utils'\n\nexport interface AssertManagementContextArgs {\n /** Operation name surfaced in the failure message, e.g. 'create release'. */\n operation: string\n /**\n * Canonical branch the command must run from (e.g. 'dev' / 'main'). Omit to\n * skip the branch check for commands that are branch-agnostic or self-switch.\n */\n requiredBranch?: string\n}\n\n/**\n * Guard release- and worktree-management commands so they run only from the\n * main repository checkout, with a clean working tree, and (where applicable)\n * on the canonical branch.\n *\n * Checks run most-structural-first \u2014 worktree, then branch, then clean \u2014 so the\n * operator fixes the most fundamental problem first. The worktree and clean-tree\n * checks always run; the branch check runs only when `requiredBranch` is set.\n * Throws {@link OperationError} on the first violation, which surfaces uniformly\n * to both CLI users and MCP-connected agents.\n */\nexport const assertManagementContext = async (args: AssertManagementContextArgs): Promise<void> => {\n const { operation, requiredBranch } = args\n\n if (await isInsideLinkedWorktree()) {\n throw new OperationError(undefined, {\n operation,\n remediation: 'run this from the main repository checkout, not a linked git worktree',\n stderrExcerpt: 'command run from inside a linked worktree',\n })\n }\n\n if (requiredBranch) {\n const currentBranch = await getCurrentBranch()\n\n if (currentBranch !== requiredBranch) {\n throw new OperationError(undefined, {\n operation,\n remediation: `switch to ${requiredBranch} first (git switch ${requiredBranch})`,\n stderrExcerpt: `current branch is \"${currentBranch}\", expected \"${requiredBranch}\"`,\n })\n }\n }\n\n if (!(await isWorkingTreeClean())) {\n throw new OperationError(undefined, {\n operation,\n remediation: 'commit or stash your changes, then retry',\n stderrExcerpt: 'working tree has uncommitted changes',\n })\n }\n}\n", "import confirm from '@inquirer/confirm'\nimport select from '@inquirer/select'\nimport process from 'node:process'\nimport { z } from 'zod'\nimport { $ } from 'zx'\n\nimport { getReleasePRsWithInfo } from 'src/integrations/gh'\nimport { deliverJiraRelease, loadJiraConfigOptional } from 'src/integrations/jira'\nimport { commandEcho } from 'src/lib/command-echo'\nimport { WORKTREES_DIR_SUFFIX } from 'src/lib/constants'\nimport { formatZxError } from 'src/lib/errors/format-zx-error'\nimport { OperationError } from 'src/lib/errors/operation-error'\nimport { assertManagementContext } from 'src/lib/git-guard'\nimport {\n deleteLocalBranch,\n deleteRemoteBranch,\n getCurrentWorktrees,\n getProjectRoot,\n getRepoName,\n} from 'src/lib/git-utils'\nimport { logger } from 'src/lib/logger'\nimport { displayLabel, formatJiraName, formatRcTitle, parseBranchName } from 'src/lib/release-id'\nimport type { ReleaseId } from 'src/lib/release-id'\nimport {\n detectReleaseType,\n formatBranchChoices,\n getJiraDescriptions,\n resolveReleaseBranch,\n} from 'src/lib/release-utils'\nimport type { ReleaseType } from 'src/lib/release-utils'\nimport { removeWorktrees } from 'src/lib/worktrees'\nimport { defineMcpTool, textContent } from 'src/types'\nimport type { RequiredConfirmedOptionArg } from 'src/types'\n\ninterface GhReleaseDeliverArgs extends RequiredConfirmedOptionArg {\n version: string\n}\n\ntype PRState = 'OPEN' | 'MERGED' | 'CLOSED'\n\ninterface PRStatus {\n number: number\n state: PRState\n title: string\n}\n\n/**\n * Wrap a delivery step so its failure logs structured zx fields and surfaces\n * an `OperationError` whose message names the actual step that failed \u2014\n * instead of the previous blanket \"merging release branch into dev\" message.\n */\nconst runStep = async <T>(operation: string, remediation: string, fn: () => Promise<T>): Promise<T> => {\n try {\n return await fn()\n } catch (error) {\n logger.error({ err: formatZxError(error) }, `\u274C Failed to ${operation}`)\n throw new OperationError(error, { operation, remediation })\n }\n}\n\n/**\n * Fetch the (most-recent) PR for the given head branch, across all states, so\n * we can resume a partially-completed delivery: a PR merged on a prior attempt\n * still appears here as `state: 'MERGED'`, letting the caller skip the merge.\n */\nconst fetchPRByHead = async (head: string): Promise<PRStatus | null> => {\n const result = await $`gh pr list --head ${head} --state all --json number,state,title --limit 1`\n const prs = JSON.parse(result.stdout) as PRStatus[]\n\n return prs[0] ?? null\n}\n\n/**\n * Find a MERGED RC PR (dev \u2192 main) whose title matches the given version, used\n * to detect that a prior delivery run already merged the RC and we should skip\n * the merge step on resume. Title-matched on purpose: an older MERGED RC PR\n * from a different release must not short-circuit this version's flow.\n */\nconst fetchMergedRcPRForVersion = async (id: ReleaseId): Promise<PRStatus | null> => {\n const expectedTitle = formatRcTitle(id)\n const result = await $`gh pr list --head dev --base main --state merged --json number,state,title --limit 20`\n const prs = JSON.parse(result.stdout) as PRStatus[]\n const match = prs.find((pr) => {\n return pr.title === expectedTitle\n })\n\n return match ?? null\n}\n\n/**\n * Find an open dev \u2192 main PR, if any. GitHub allows at most one open PR per\n * head/base pair, so an existing open PR here is the RC PR for this release \u2014\n * even if its title was set by a previous (failed) delivery run. Adopting it\n * is what makes the flow recoverable after a mid-run failure.\n */\nconst fetchOpenDevToMainPR = async (): Promise<PRStatus | null> => {\n const result = await $`gh pr list --head dev --base main --state open --json number,state,title --limit 5`\n const prs = JSON.parse(result.stdout) as PRStatus[]\n\n return prs[0] ?? null\n}\n\ninterface ResolvedTarget {\n selectedReleaseBranch: string\n releasePrTitle: string\n}\n\nconst resolveTargetFromVersion = async (version: string): Promise<ResolvedTarget> => {\n const selectedReleaseBranch = resolveReleaseBranch(version)\n const pr = await fetchPRByHead(selectedReleaseBranch)\n\n if (!pr) {\n logger.error(`\u274C No PR found for branch ${selectedReleaseBranch}.`)\n throw new OperationError(undefined, {\n operation: `deliver release ${selectedReleaseBranch}`,\n remediation: `confirm a PR exists ('gh pr list --head ${selectedReleaseBranch} --state all')`,\n })\n }\n\n return { selectedReleaseBranch, releasePrTitle: pr.title }\n}\n\nconst resolveTargetInteractively = async (): Promise<ResolvedTarget> => {\n const releasePRsInfo = await getReleasePRsWithInfo()\n\n const branches = releasePRsInfo.map((pr) => {\n return pr.branch\n })\n\n const releaseTypes = new Map<string, ReleaseType>(\n releasePRsInfo.map((pr) => {\n return [pr.branch, detectReleaseType(pr.title)]\n }),\n )\n\n commandEcho.setInteractive()\n\n const descriptions = await getJiraDescriptions()\n\n const selectedReleaseBranch = await select({\n message: '\uD83C\uDF3F Select release branch',\n choices: formatBranchChoices({ branches, descriptions, types: releaseTypes }),\n })\n\n const prInfo = releasePRsInfo.find((pr) => {\n return pr.branch === selectedReleaseBranch\n })\n\n if (!prInfo) {\n logger.error(`\u274C Release branch ${selectedReleaseBranch} not found in open PRs.`)\n throw new OperationError(undefined, {\n operation: `deliver release ${selectedReleaseBranch}`,\n remediation: `confirm an open PR exists for ${selectedReleaseBranch} ('gh pr list')`,\n })\n }\n\n return { selectedReleaseBranch, releasePrTitle: prInfo.title }\n}\n\n/**\n * `gh pr merge --delete-branch` also deletes the local branch, which fails if a\n * worktree has it checked out (the actual root cause of the \"Failed to merge\n * release PR\" surface error). Pre-remove any worktree for the release branch\n * so the local delete can succeed.\n */\nconst removeReleaseWorktreeIfPresent = async (releaseBranch: string): Promise<void> => {\n const worktreeBranches = await getCurrentWorktrees('release')\n\n if (!worktreeBranches.includes(releaseBranch)) return\n\n const [projectRoot, repoName] = await Promise.all([getProjectRoot(), getRepoName()])\n const worktreeDir = `${projectRoot}${WORKTREES_DIR_SUFFIX}`\n\n const removed = await removeWorktrees({ branches: [releaseBranch], worktreeDir, repoName })\n\n if (removed.length === 0) {\n throw new OperationError(undefined, {\n operation: `remove worktree for ${releaseBranch} before merge`,\n remediation: `run manually: git worktree remove ${worktreeDir}/${releaseBranch} (use --force if uncommitted changes)`,\n })\n }\n}\n\ninterface MergeReleasePRArgs {\n selectedReleaseBranch: string\n releaseType: ReleaseType\n}\n\nconst mergeReleasePR = async (args: MergeReleasePRArgs): Promise<void> => {\n const { selectedReleaseBranch, releaseType } = args\n\n const mergeTarget = releaseType === 'hotfix' ? 'main' : 'dev'\n\n const releasePr = await fetchPRByHead(selectedReleaseBranch)\n\n if (!releasePr) {\n throw new OperationError(undefined, {\n operation: `look up release PR for ${selectedReleaseBranch}`,\n remediation: `verify the PR exists in GitHub`,\n })\n }\n\n if (releasePr.state === 'MERGED') {\n logger.info(`\u2713 Release PR ${selectedReleaseBranch} already merged \u2014 skipping`)\n\n return\n }\n\n if (releasePr.state === 'CLOSED') {\n throw new OperationError(undefined, {\n operation: `merge release PR ${selectedReleaseBranch} into ${mergeTarget}`,\n remediation: `the PR is closed without merge; reopen it or create a new release`,\n })\n }\n\n await runStep(\n `merge release PR ${selectedReleaseBranch} into ${mergeTarget}`,\n `check 'gh pr view ${selectedReleaseBranch}' for mergeability and required reviews`,\n async () => {\n await $`gh pr merge ${selectedReleaseBranch} --squash --admin --delete-branch`\n },\n )\n}\n\nconst resolveRcPRNumber = async (id: ReleaseId): Promise<number> => {\n const selectedLabel = displayLabel(id)\n const expectedTitle = formatRcTitle(id)\n const existingOpen = await fetchOpenDevToMainPR()\n\n // Adopt any existing open dev\u2192main PR. GitHub permits only one open PR per\n // head/base pair, so a stale open RC PR (left behind by a prior failed run\n // \u2014 the single most common cause of \"Error merging release branch into\n // dev\") blocks `gh pr create`. Retitle it instead of fighting it.\n if (existingOpen) {\n const rcNumber = existingOpen.number\n\n if (existingOpen.title !== expectedTitle) {\n logger.info(\n `Adopting open dev \u2192 main PR #${rcNumber} (\"${existingOpen.title}\") and retitling for ${selectedLabel}`,\n )\n await runStep(\n `retitle dev \u2192 main PR #${rcNumber} to \"${expectedTitle}\"`,\n `update manually: gh pr edit ${rcNumber} --title \"${expectedTitle}\"`,\n async () => {\n await $`gh pr edit ${rcNumber} --title ${expectedTitle}`\n },\n )\n }\n\n return rcNumber\n }\n\n await runStep(\n `create RC PR (dev \u2192 main) for ${selectedLabel}`,\n `run 'gh pr create --base main --head dev' manually to surface the underlying error (e.g. no commits between dev and main)`,\n async () => {\n await $`gh pr create --base main --head dev --title ${expectedTitle} --body \"\"`\n },\n )\n\n const created = await fetchOpenDevToMainPR()\n\n if (!created) {\n throw new OperationError(undefined, {\n operation: `look up RC PR for ${selectedLabel}`,\n remediation: `verify the RC PR was created ('gh pr list --head dev --base main')`,\n })\n }\n\n return created.number\n}\n\nconst ensureRcPRMerged = async (id: ReleaseId): Promise<void> => {\n const selectedLabel = displayLabel(id)\n const alreadyMerged = await fetchMergedRcPRForVersion(id)\n\n if (alreadyMerged) {\n logger.info(`\u2713 RC PR for ${selectedLabel} already merged into main \u2014 skipping`)\n\n return\n }\n\n const rcNumber = await resolveRcPRNumber(id)\n\n await runStep(\n `merge RC PR #${rcNumber} (dev \u2192 main) for ${selectedLabel}`,\n `check 'gh pr view ${rcNumber}' for mergeability and required reviews`,\n async () => {\n await $`gh pr merge ${rcNumber} --squash --admin`\n },\n )\n}\n\nconst dispatchDeployWorkflow = async (): Promise<void> => {\n $.quiet = false\n\n await runStep(\n `dispatch deploy-all workflow on main`,\n `check 'gh workflow list' and that you have permission to dispatch deploy-all.yml`,\n async () => {\n await $`gh workflow run deploy-all.yml --ref main -f environment=prod`\n },\n )\n\n $.quiet = true\n}\n\nconst syncMainIntoDev = async (): Promise<void> => {\n await runStep(\n `sync main back into dev`,\n `run manually: git switch main && git pull && git switch dev && git pull && git merge main --no-edit && git push`,\n async () => {\n await $`git switch main && git pull && git switch dev && git pull && git merge main --no-edit && git push`\n },\n )\n}\n\n/**\n * Best-effort cleanup of the delivered release branch, locally and on `origin`.\n *\n * Idempotent backstop to `gh pr merge --delete-branch` (in `mergeReleasePR`):\n * that flag is skipped when the release PR was already merged on a prior\n * attempt, so an idempotent re-run would otherwise leave the branch behind.\n * Each delete is isolated \u2014 a failure (e.g. the branch checked out in a stray\n * worktree, or a remote hiccup) logs a warning naming the branch and never\n * aborts delivery, since the irreversible merge and deploy already happened.\n */\nconst removeDeliveredReleaseBranch = async (branch: string): Promise<void> => {\n try {\n await deleteLocalBranch(branch)\n } catch (error) {\n logger.warn({ err: formatZxError(error) }, `Failed to delete local branch ${branch} (non-blocking)`)\n }\n\n try {\n await deleteRemoteBranch(branch)\n } catch (error) {\n logger.warn({ err: formatZxError(error) }, `Failed to delete remote branch ${branch} (non-blocking)`)\n }\n}\n\nconst deliverJiraReleaseSafely = async (id: ReleaseId): Promise<void> => {\n const jiraConfig = await loadJiraConfigOptional()\n\n if (!jiraConfig) {\n logger.info('\uD83D\uDD14 Jira is not configured, skipping Jira release delivery')\n\n return\n }\n\n try {\n // Jira fix version name: `v1.2.3` | `<name>` \u2014 must match create-time formatJiraName.\n const versionName = formatJiraName(id)\n\n await deliverJiraRelease({ versionName }, jiraConfig)\n } catch (error) {\n logger.error({ err: formatZxError(error) }, 'Failed to deliver Jira release (non-blocking)')\n }\n}\n\n/**\n * Deliver a release branch to production. Each network/git step is run inside\n * `runStep` so the surfaced error names the failing operation and includes the\n * subprocess stderr. PR-merge steps are idempotent: if the release PR or RC PR\n * is already MERGED, the step is skipped, so re-running after a mid-flight\n * failure picks up where it stopped.\n */\nexport const ghReleaseDeliver = async (args: GhReleaseDeliverArgs) => {\n const { version, confirmedCommand } = args\n\n commandEcho.start('release-deliver')\n\n // Branch-agnostic (operates on release/RC PRs via gh and self-switches), so\n // only the worktree + clean-tree legs apply.\n await assertManagementContext({ operation: 'deliver release' })\n\n const { selectedReleaseBranch, releasePrTitle } = version\n ? await resolveTargetFromVersion(version)\n : await resolveTargetInteractively()\n\n // selectedReleaseBranch is always a release branch (operator ref strictly\n // parsed, or picked from discovery-filtered choices) so this cannot be null.\n const releaseId = parseBranchName(selectedReleaseBranch)\n\n if (!releaseId) {\n throw new OperationError(undefined, {\n operation: `deliver release ${selectedReleaseBranch}`,\n remediation: 'pass a version (e.g. \"1.2.5\") or a release name (e.g. \"checkout-redesign\")',\n })\n }\n\n const selectedVersion = displayLabel(releaseId)\n\n commandEcho.addOption('--version', selectedVersion)\n logger.info(`Delivering ${releaseId.kind === 'name' ? 'named release' : 'version'} ${selectedReleaseBranch}`)\n\n const releaseType: ReleaseType = detectReleaseType(releasePrTitle)\n\n const answer = confirmedCommand\n ? true\n : await confirm({\n message: `Are you sure you want to deliver version ${selectedReleaseBranch} to production?`,\n })\n\n if (!confirmedCommand) {\n commandEcho.setInteractive()\n }\n\n if (!answer) {\n logger.info('Operation cancelled. Exiting...')\n process.exit(0)\n }\n\n // Track --yes flag if confirmation was interactive (user confirmed)\n commandEcho.addOption('--yes', true)\n\n $.quiet = true\n\n await removeReleaseWorktreeIfPresent(selectedReleaseBranch)\n await mergeReleasePR({ selectedReleaseBranch, releaseType })\n\n if (releaseType !== 'hotfix') {\n await ensureRcPRMerged(releaseId)\n }\n\n await dispatchDeployWorkflow()\n await syncMainIntoDev()\n await removeDeliveredReleaseBranch(selectedReleaseBranch)\n\n $.quiet = false\n\n await deliverJiraReleaseSafely(releaseId)\n\n logger.info(`Successfully delivered ${selectedReleaseBranch} to production!`)\n\n commandEcho.print()\n\n const structuredContent = {\n releaseBranch: selectedReleaseBranch,\n version: selectedVersion,\n type: releaseType,\n success: true,\n }\n\n return {\n content: textContent(JSON.stringify(structuredContent, null, 2)),\n structuredContent,\n }\n}\n\n// MCP Tool Registration\nexport const ghReleaseDeliverMcpTool = defineMcpTool({\n name: 'gh-release-deliver',\n description:\n 'Deliver a release to production. For hotfixes: squash-merges the release branch to main and dispatches the deploy-all workflow. For regular releases: squash-merges to dev, opens an RC PR, merges dev into main, dispatches the deploy-all workflow, then syncs main back to dev. Also releases the matching Jira fix version if Jira is configured. Dispatches the deploy workflow fire-and-forget \u2014 the tool returns once the workflow is accepted by GitHub, not when the deployment finishes. PR-merge steps are idempotent: re-running after a partial failure skips PRs that are already merged. Irreversible production operation: the confirmation prompt is auto-skipped for MCP calls, so the caller is responsible for gating. \"version\" is required when invoked via MCP (the picker is unreachable without a TTY).',\n inputSchema: {\n version: z\n .string()\n .describe(\n 'Accepts a release version (e.g. \"1.2.5\") OR a release name (e.g. \"checkout-redesign\") to deliver to production. Required for MCP calls.',\n ),\n },\n outputSchema: {\n releaseBranch: z.string().describe('The release branch that was delivered'),\n version: z.string().describe('The version that was delivered'),\n type: z.enum(['regular', 'hotfix']).describe('Release type'),\n success: z.boolean().describe('Whether the delivery was successful'),\n },\n handler: ghReleaseDeliver,\n})\n", "const STDERR_EXCERPT_MAX_BYTES = 500\nconst STDOUT_EXCERPT_MAX_BYTES = 200\n\nexport interface ZxErrorFields {\n exitCode?: number | null\n stderr?: string\n stdout?: string\n message?: string\n name?: string\n}\n\nconst readTrimmedString = (value: unknown, max: number): string | undefined => {\n if (typeof value !== 'string' || value.length === 0) return undefined\n\n return value.slice(-max).trim()\n}\n\n/**\n * Extract loggable fields from an error for `logger.error({ err: formatZxError(e) }, ...)`.\n *\n * pino's default `err` serializer handles `Error` subclasses but renders zx's\n * `ProcessOutput` as `{}` because its informative fields (`stderr`, `stdout`,\n * `exitCode`) are non-enumerable / on the prototype. This helper duck-types\n * those fields so subprocess failures surface in logs instead of vanishing.\n */\nexport const formatZxError = (error: unknown): ZxErrorFields => {\n if (error === null || typeof error !== 'object') {\n return { message: String(error) }\n }\n\n const rec = error as Record<string, unknown>\n const fields: ZxErrorFields = {}\n\n if (error instanceof Error) {\n fields.name = error.name\n fields.message = error.message\n } else if (typeof rec.message === 'string') {\n fields.message = rec.message\n }\n\n const exitCode = rec.exitCode\n\n if (typeof exitCode === 'number' || exitCode === null) fields.exitCode = exitCode\n\n const stderr = readTrimmedString(rec.stderr, STDERR_EXCERPT_MAX_BYTES)\n\n if (stderr) fields.stderr = stderr\n\n const stdout = readTrimmedString(rec.stdout, STDOUT_EXCERPT_MAX_BYTES)\n\n if (stdout) fields.stdout = stdout\n\n return fields\n}\n", "import { $ } from 'zx'\n\nimport { buildCmuxWorkspaceTitle, closeCmuxWorkspaceByTitle } from 'src/integrations/cmux'\nimport { OperationError } from 'src/lib/errors/operation-error'\nimport { logger } from 'src/lib/logger'\n\ninterface RemoveWorktreesArgs {\n branches: string[]\n worktreeDir: string\n repoName: string\n pruneFolder?: boolean\n}\n\n/**\n * Close any cmux workspace for each branch and run `git worktree remove`,\n * returning the branches that were removed cleanly. Failures are logged but\n * never thrown, so a single bad worktree doesn't poison a batch removal.\n *\n * When `pruneFolder` is true and every branch was removed, also prune the\n * worktree metadata and delete the worktrees folder \u2014 used by the\n * `worktrees-remove` \"all\" path to leave the filesystem clean.\n */\nexport const removeWorktrees = async (args: RemoveWorktreesArgs): Promise<string[]> => {\n const { branches, worktreeDir, repoName, pruneFolder = false } = args\n\n const results = await Promise.allSettled(\n branches.map(async (branch) => {\n const worktreePath = `${worktreeDir}/${branch}`\n\n const title = buildCmuxWorkspaceTitle({ repoName, branch })\n\n await closeCmuxWorkspaceByTitle(title)\n\n await $`git worktree remove ${worktreePath}`\n\n return branch\n }),\n )\n\n const removed: string[] = []\n\n for (const [index, result] of results.entries()) {\n if (result.status === 'fulfilled') {\n removed.push(result.value)\n } else {\n const branch = branches[index]\n const err = new OperationError(result.reason, {\n operation: `remove worktree for ${branch}`,\n remediation: \"check 'git worktree list' for the path; uncommitted changes block removal\",\n })\n\n logger.error({ error: result.reason, msg: err.message })\n }\n }\n\n // `git worktree remove` only deletes the leaf worktree, leaving the group\n // folder (e.g. `release/`, `feature/`) behind. Remove it when it's now empty;\n // `rmdir` is a no-op when the folder still holds other worktrees.\n const groupDirs = new Set<string>()\n\n for (const branch of removed) {\n if (branch.includes('/')) {\n groupDirs.add(`${worktreeDir}/${branch.split('/')[0]}`)\n }\n }\n\n for (const groupDir of groupDirs) {\n await $`rmdir ${groupDir}`.nothrow()\n }\n\n if (pruneFolder && removed.length === branches.length) {\n await $`git worktree prune`\n await $`rm -rf ${worktreeDir}`\n\n logger.info(`\uD83D\uDDD1\uFE0F Removed worktree folder: ${worktreeDir}`)\n logger.info('')\n }\n\n return removed\n}\n", "/** Matches a `v`-prefixed semver token (e.g. `v1.48.0`) anchored on shape. */\nconst V_SEMVER_TOKEN_RE = /\\bv(\\d+\\.\\d+\\.\\d+)\\b/g\n\n/**\n * Canonicalizes a cmux workspace title into a stable dedup/close key.\n *\n * cmux workspace titles are human display strings built by\n * `buildCmuxWorkspaceTitle`, so the value stored when a workspace is created can\n * drift from the value rebuilt later \u2014 across whitespace and across CLI versions\n * (an older build titled version releases `v1.48.0`; the current build titles\n * them `1.48.0`). Keying dedup or close on the raw title silently creates\n * duplicate / unclosable workspaces whenever that drift occurs.\n *\n * Canonicalization collapses the known drift axes so both sides round-trip to an\n * equal key:\n * - trims and collapses internal whitespace to single spaces;\n * - normalizes a `v`-prefixed semver token to its bare form\n * (`v1.48.0` \u2192 `1.48.0`), anchored on semver shape so named releases that\n * merely start with `v` (e.g. `vega-redesign`) are left untouched.\n *\n * Non-release fallback titles (which may contain `/`, e.g. `feature/foo`) are\n * preserved as-is apart from whitespace normalization.\n *\n * @example\n * canonicalizeCmuxTitle('hulyo-monorepo v1.48.0') // => 'hulyo-monorepo 1.48.0'\n * canonicalizeCmuxTitle('hulyo-monorepo 1.48.0') // => 'hulyo-monorepo 1.48.0'\n * canonicalizeCmuxTitle('hulyo-monorepo vega-redesign') // => 'hulyo-monorepo vega-redesign'\n */\nexport const canonicalizeCmuxTitle = (raw: string): string => {\n return raw.trim().replace(/\\s+/g, ' ').replace(V_SEMVER_TOKEN_RE, '$1')\n}\n", "import { $ } from 'zx'\n\nimport { logger } from 'src/lib/logger'\n\nimport { canonicalizeCmuxTitle } from './canonicalize-cmux-title'\n\n/**\n * Best-effort close of the cmux workspace whose title matches `title` (compared\n * via {@link canonicalizeCmuxTitle}, so a drifted stored title still resolves).\n * Silently no-ops if cmux isn't running, the workspace isn't found, or close fails.\n */\nexport const closeCmuxWorkspaceByTitle = async (title: string): Promise<void> => {\n try {\n const listOutput = (await $`cmux list-workspaces`.quiet()).stdout\n\n const ref = findWorkspaceRefByTitle(listOutput, title)\n\n if (!ref) {\n return\n }\n\n await $`cmux close-workspace --workspace ${ref}`.quiet()\n } catch (error) {\n logger.debug({ error, title }, 'cmux: skipped closing workspace')\n }\n}\n\n/**\n * Parses `cmux list-workspaces` output and returns the workspace ref whose\n * title matches `title`, or undefined if no match. Both sides are compared via\n * {@link canonicalizeCmuxTitle} so a workspace stored under a drifted title\n * (whitespace, or an older CLI's `v`-prefixed semver) is still found \u2014 keeping\n * close symmetric with the dedup in `worktrees-open`.\n *\n * Each line looks like:\n * \" workspace:8 hulyo-monorepo 1.48.0\"\n * \"* workspace:6 obsidian-workspace [selected]\"\n */\nconst findWorkspaceRefByTitle = (output: string, title: string): string | undefined => {\n const target = canonicalizeCmuxTitle(title)\n\n for (const rawLine of output.split('\\n')) {\n // eslint-disable-next-line sonarjs/slow-regex, regexp/no-super-linear-backtracking\n const match = rawLine.match(/^[* ]\\s*(workspace:\\d+)\\s+(.+?)(?:\\s+\\[selected\\])?\\s*$/)\n\n if (!match) {\n continue\n }\n\n const ref = match[1]\n const lineTitle = match[2]?.trim() ?? ''\n\n if (canonicalizeCmuxTitle(lineTitle) === target) {\n return ref\n }\n }\n\n return undefined\n}\n", "import { $ } from 'zx'\n\nimport { logger } from 'src/lib/logger'\n\nimport { canonicalizeCmuxTitle } from './canonicalize-cmux-title'\n\n/**\n * Returns the set of **canonical** titles for all currently-open cmux\n * workspaces (see {@link canonicalizeCmuxTitle}). Keying on the canonical form\n * lets callers match a workspace even when its stored title drifted from the\n * title they rebuild (whitespace, or an older CLI's `v`-prefixed semver).\n * Returns an empty set if cmux isn't running, the call fails, or the output\n * can't be parsed \u2014 callers should treat \"empty\" as \"unknown, proceed as if\n * nothing is open\".\n *\n * Each line of `cmux list-workspaces` looks like:\n * \" workspace:8 hulyo-monorepo 1.48.0\"\n * \"* workspace:6 obsidian-workspace [selected]\"\n */\nexport const listCmuxWorkspaceTitles = async (): Promise<Set<string>> => {\n try {\n const output = (await $`cmux list-workspaces`.quiet()).stdout\n\n const titles = new Set<string>()\n\n for (const rawLine of output.split('\\n')) {\n // eslint-disable-next-line sonarjs/slow-regex, regexp/no-super-linear-backtracking\n const match = rawLine.match(/^[* ]\\s*workspace:\\d+\\s+(.+?)(?:\\s+\\[selected\\])?\\s*$/)\n\n if (!match) {\n continue\n }\n\n const title = match[1]?.trim()\n\n if (title) {\n titles.add(canonicalizeCmuxTitle(title))\n }\n }\n\n return titles\n } catch (error) {\n logger.debug({ error }, 'cmux: skipped listing workspace titles')\n\n return new Set()\n }\n}\n", "import { $ } from 'zx'\n\ninterface OpenCmuxWorkspaceArgs {\n cwd: string\n title?: string\n}\n\n/**\n * Opens a new cmux workspace rooted at `cwd` with three panes:\n * left-top (primary) | right (full-height)\n * left-bottom |\n * All panes inherit `cwd` from the workspace.\n */\nexport const openCmuxWorkspaceWithLayout = async (args: OpenCmuxWorkspaceArgs): Promise<void> => {\n const { cwd, title } = args\n\n const newWorkspaceOutput = (await $`cmux workspace create --cwd ${cwd}`).stdout\n\n const workspaceRef = parseWorkspaceRef(newWorkspaceOutput)\n\n const surfacesOutput = (await $`cmux list-pane-surfaces --workspace ${workspaceRef}`).stdout\n\n const leftTopRef = parseFirstSurfaceRef(surfacesOutput)\n\n await $`cmux new-split right --workspace ${workspaceRef} --surface ${leftTopRef}`\n await $`cmux new-split down --workspace ${workspaceRef} --surface ${leftTopRef}`\n\n if (title) {\n await $`cmux workspace rename --workspace ${workspaceRef} --title ${title}`\n }\n}\n\n/**\n * Extracts the first `surface:<id>` reference from the output of\n * `cmux list-pane-surfaces`. Used to locate the initial (primary) pane\n * surface so subsequent splits can be anchored relative to it.\n *\n * @example\n * const output = 'surface:12 (active)\\nsurface:13\\n'\n * parseFirstSurfaceRef(output) // => 'surface:12'\n */\nconst parseFirstSurfaceRef = (output: string): string => {\n const match = output.match(/surface:\\d+/)\n\n if (!match) {\n throw new Error('cmux: could not locate initial surface in list-pane-surfaces output')\n }\n\n return match[0]\n}\n\n/**\n * Extracts the `workspace:<id>` reference from the output of\n * `cmux workspace create`. The returned ref is used to target the newly\n * created workspace in follow-up `cmux` commands (splits, rename, etc.).\n *\n * @example\n * const output = 'created workspace:7\\n'\n * parseWorkspaceRef(output) // => 'workspace:7'\n */\nconst parseWorkspaceRef = (output: string): string => {\n const match = output.match(/workspace:\\d+/)\n\n if (!match) {\n throw new Error('cmux: could not locate workspace ref in workspace create output')\n }\n\n return match[0]\n}\n", "import { displayLabel, parseBranchName } from 'src/lib/release-id'\n\ninterface BuildCmuxWorkspaceTitleArgs {\n repoName: string\n branch: string\n}\n\n/**\n * Builds the cmux workspace title used by `worktrees-add` and looked up by\n * `worktrees-remove`. Release branches are rendered via their release-id\n * display label so the title reads e.g. `\"hulyo-monorepo 1.48.0\"` for\n * `\"release/v1.48.0\"` and `\"hulyo-monorepo checkout-redesign\"` for\n * `\"release/checkout-redesign\"`. Non-release branches (cmux titles them too)\n * fall back to the raw branch string.\n */\nexport const buildCmuxWorkspaceTitle = (args: BuildCmuxWorkspaceTitleArgs): string => {\n const { repoName, branch } = args\n\n const id = parseBranchName(branch)\n const label = id ? displayLabel(id) : branch\n\n return `${repoName} ${label}`\n}\n", "import select from '@inquirer/select'\nimport { z } from 'zod'\nimport { $ } from 'zx'\n\nimport { getReleasePRsWithInfo } from 'src/integrations/gh'\nimport { commandEcho } from 'src/lib/command-echo'\nimport { OperationError } from 'src/lib/errors/operation-error'\nimport { getInfraKitConfig } from 'src/lib/infra-kit-config'\nimport { logger } from 'src/lib/logger'\nimport {\n detectReleaseType,\n formatBranchChoices,\n getJiraDescriptions,\n releaseLabelFromBranch,\n resolveReleaseBranch,\n} from 'src/lib/release-utils'\nimport type { ReleaseType } from 'src/lib/release-utils'\nimport { defineMcpTool, textContent } from 'src/types'\n\ninterface GhReleaseDeployAllArgs {\n version: string\n env: string\n skipTerraform?: boolean\n}\n\n/**\n * Deploy a release branch to an environment\n */\nexport const ghReleaseDeployAll = async (args: GhReleaseDeployAllArgs) => {\n const { version, env, skipTerraform } = args\n\n commandEcho.start('release-deploy-all')\n\n let selectedReleaseBranch = '' // \"release/v1.8.0\" | \"release/checkout-redesign\" | \"dev\"\n\n if (version) {\n selectedReleaseBranch = version === 'dev' ? 'dev' : resolveReleaseBranch(version)\n } else {\n commandEcho.setInteractive()\n\n const releasePRsInfo = await getReleasePRsWithInfo()\n\n const branches = releasePRsInfo.map((pr) => {\n return pr.branch\n })\n\n const releaseTypes = new Map<string, ReleaseType>(\n releasePRsInfo.map((pr) => {\n return [pr.branch, detectReleaseType(pr.title)]\n }),\n )\n\n const descriptions = await getJiraDescriptions()\n\n selectedReleaseBranch = await select({\n message: '\uD83C\uDF3F Select release branch',\n choices: [{ name: 'dev', value: 'dev' }, ...formatBranchChoices({ branches, descriptions, types: releaseTypes })],\n })\n }\n\n const selectedVersion = releaseLabelFromBranch(selectedReleaseBranch)\n\n commandEcho.addOption('--version', selectedVersion)\n\n const { environments } = await getInfraKitConfig()\n\n let selectedEnv = ''\n\n if (env) {\n selectedEnv = env\n } else {\n commandEcho.setInteractive()\n\n selectedEnv = await select({\n message: '\uD83E\uDDEA Select environment',\n choices: environments.map((env) => {\n return {\n name: env,\n value: env,\n }\n }),\n })\n }\n\n commandEcho.addOption('--env', selectedEnv)\n\n if (!environments.includes(selectedEnv)) {\n throw new OperationError(undefined, {\n operation: 'launch deploy-all workflow',\n remediation: `pass one of: ${environments.join(', ')}`,\n stderrExcerpt: `invalid environment: ${selectedEnv}`,\n })\n }\n\n const shouldSkipTerraform = skipTerraform ?? false\n\n if (shouldSkipTerraform) {\n commandEcho.addOption('--skip-terraform', true)\n }\n\n try {\n $.quiet = true\n\n const skipTerraformFlag = shouldSkipTerraform ? ['-f', 'skip_terraform_deploy=true'] : []\n\n await $`gh workflow run deploy-all.yml --ref ${selectedReleaseBranch} -f environment=${selectedEnv} ${skipTerraformFlag}`\n\n $.quiet = false\n\n logger.info(\n `Successfully launched deploy-all workflow_dispatch for release branch: ${selectedReleaseBranch} and environment: ${selectedEnv}`,\n )\n\n commandEcho.print()\n\n const structuredContent = {\n releaseBranch: selectedReleaseBranch,\n version: selectedVersion,\n environment: selectedEnv,\n skipTerraformDeploy: shouldSkipTerraform,\n success: true,\n }\n\n return {\n content: textContent(JSON.stringify(structuredContent, null, 2)),\n structuredContent,\n }\n } catch (error: unknown) {\n logger.error({ error }, '\u274C Error launching workflow')\n throw new OperationError(error, {\n operation: 'launch deploy-all workflow',\n remediation: \"check 'gh workflow list' and that deploy-all.yml exists on the target ref\",\n })\n }\n}\n\n// MCP Tool Registration\nexport const ghReleaseDeployAllMcpTool = defineMcpTool({\n name: 'gh-release-deploy-all',\n description:\n 'Dispatch the deploy-all.yml GitHub Actions workflow to deploy every service from a release branch to the given environment. Fire-and-forget \u2014 returns once GitHub accepts the workflow_dispatch, NOT when the deployment finishes; watch the workflow run for completion status. Use gh-release-deploy-selected for a subset of services. Pass version=\"dev\" to deploy from the dev branch instead of a release branch. Both \"version\" and \"env\" are required when invoked via MCP (interactive pickers are unavailable without a TTY).',\n inputSchema: {\n version: z\n .string()\n .describe(\n 'Accepts a release version (e.g. \"1.2.5\") OR a release name (e.g. \"checkout-redesign\") \u2014 resolves to the release/vX.Y.Z or release/<name> branch. Pass \"dev\" to deploy from the dev branch instead. Required for MCP calls.',\n ),\n env: z\n .string()\n .describe(\n 'Target environment name \u2014 must match an env configured for the project (e.g. \"dev\", \"renana\", \"oriana\"). Required for MCP calls.',\n ),\n skipTerraform: z.boolean().optional().describe('Skip the terraform deployment stage.'),\n },\n outputSchema: {\n releaseBranch: z.string().describe('The release branch that was deployed'),\n version: z.string().describe('The version that was deployed'),\n environment: z.string().describe('The environment deployed to'),\n skipTerraformDeploy: z.boolean().describe('Whether terraform deployment was skipped'),\n success: z.boolean().describe('Whether the deployment was successful'),\n },\n handler: ghReleaseDeployAll,\n})\n", "import checkbox from '@inquirer/checkbox'\nimport select from '@inquirer/select'\nimport fs from 'node:fs/promises'\nimport { resolve } from 'node:path'\nimport yaml from 'yaml'\nimport { z } from 'zod'\nimport { $ } from 'zx'\n\nimport { getReleasePRsWithInfo } from 'src/integrations/gh'\nimport { commandEcho } from 'src/lib/command-echo'\nimport { OperationError } from 'src/lib/errors/operation-error'\nimport { getProjectRoot } from 'src/lib/git-utils'\nimport { getInfraKitConfig } from 'src/lib/infra-kit-config'\nimport { logger } from 'src/lib/logger'\nimport {\n detectReleaseType,\n formatBranchChoices,\n getJiraDescriptions,\n releaseLabelFromBranch,\n resolveReleaseBranch,\n} from 'src/lib/release-utils'\nimport type { ReleaseType } from 'src/lib/release-utils'\nimport { defineMcpTool, textContent } from 'src/types'\n\ninterface GhReleaseDeploySelectedArgs {\n version: string\n env: string\n services: string[]\n skipTerraform?: boolean\n}\n\n/**\n * Deploy selected services from a release branch to an environment\n */\n// eslint-disable-next-line sonarjs/cognitive-complexity\nexport const ghReleaseDeploySelected = async (args: GhReleaseDeploySelectedArgs) => {\n const { version, env, services, skipTerraform } = args\n\n commandEcho.start('release-deploy-selected')\n\n let selectedReleaseBranch = ''\n\n if (version) {\n selectedReleaseBranch = version === 'dev' ? 'dev' : resolveReleaseBranch(version)\n } else {\n commandEcho.setInteractive()\n\n const releasePRsInfo = await getReleasePRsWithInfo()\n\n const branches = releasePRsInfo.map((pr) => {\n return pr.branch\n })\n\n const releaseTypes = new Map<string, ReleaseType>(\n releasePRsInfo.map((pr) => {\n return [pr.branch, detectReleaseType(pr.title)]\n }),\n )\n\n const descriptions = await getJiraDescriptions()\n\n selectedReleaseBranch = await select({\n message: '\uD83C\uDF3F Select release branch',\n choices: [{ name: 'dev', value: 'dev' }, ...formatBranchChoices({ branches, descriptions, types: releaseTypes })],\n })\n }\n\n const selectedVersion = releaseLabelFromBranch(selectedReleaseBranch)\n\n commandEcho.addOption('--version', selectedVersion)\n\n const { environments } = await getInfraKitConfig()\n\n let selectedEnv = ''\n\n if (env) {\n selectedEnv = env\n } else {\n commandEcho.setInteractive()\n\n selectedEnv = await select({\n message: '\uD83E\uDDEA Select environment',\n choices: environments.map((env) => {\n return {\n name: env,\n value: env,\n }\n }),\n })\n }\n\n commandEcho.addOption('--env', selectedEnv)\n\n if (!environments.includes(selectedEnv)) {\n throw new OperationError(undefined, {\n operation: 'launch deploy-selected workflow',\n remediation: `pass one of: ${environments.join(', ')}`,\n stderrExcerpt: `invalid environment: ${selectedEnv}`,\n })\n }\n\n // Parse available services from workflow file\n const availableServices = await parseServicesFromWorkflow()\n\n if (availableServices.length === 0) {\n throw new OperationError(undefined, {\n operation: 'launch deploy-selected workflow',\n remediation: 'check .github/workflows/deploy-selected-services.yml for boolean service inputs',\n stderrExcerpt: 'no services found in workflow file',\n })\n }\n\n let selectedServices: string[] = []\n\n if (services && services.length > 0) {\n selectedServices = services\n } else {\n commandEcho.setInteractive()\n\n selectedServices = await checkbox({\n message: '\uD83D\uDE80 Select services to deploy (space to select, enter to confirm)',\n choices: availableServices.map((svc) => {\n return {\n name: svc,\n value: svc,\n }\n }),\n })\n }\n\n commandEcho.addOption('--services', selectedServices)\n\n if (selectedServices.length === 0) {\n throw new OperationError(undefined, {\n operation: 'launch deploy-selected workflow',\n remediation: `pass at least one service from: ${availableServices.join(', ')}`,\n stderrExcerpt: 'no services selected',\n })\n }\n\n // Validate all selected services\n const invalidServices = selectedServices.filter((svc) => {\n return !availableServices.includes(svc)\n })\n\n if (invalidServices.length > 0) {\n throw new OperationError(undefined, {\n operation: 'launch deploy-selected workflow',\n remediation: `pass services from: ${availableServices.join(', ')}`,\n stderrExcerpt: `invalid services: ${invalidServices.join(', ')}`,\n })\n }\n\n const shouldSkipTerraform = skipTerraform ?? false\n\n if (shouldSkipTerraform) {\n commandEcho.addOption('--skip-terraform', true)\n }\n\n try {\n $.quiet = true\n\n // Build the workflow command with boolean flags for each selected service\n const serviceFlags = selectedServices.flatMap((svc) => {\n return ['-f', `${svc}=true`]\n })\n const skipTerraformFlag = shouldSkipTerraform ? ['-f', 'skip_terraform_deploy=true'] : []\n\n await $`gh workflow run deploy-selected-services.yml --ref ${selectedReleaseBranch} -f environment=${selectedEnv} ${serviceFlags} ${skipTerraformFlag}`\n\n $.quiet = false\n\n logger.info(\n `Successfully launched deploy-selected-services workflow_dispatch for release branch: ${selectedReleaseBranch}, environment: ${selectedEnv}, services: ${selectedServices.join(', ')}`,\n )\n\n commandEcho.print()\n\n const structuredContent = {\n releaseBranch: selectedReleaseBranch,\n version: selectedVersion,\n environment: selectedEnv,\n services: selectedServices,\n skipTerraformDeploy: shouldSkipTerraform,\n success: true,\n }\n\n return {\n content: textContent(JSON.stringify(structuredContent, null, 2)),\n structuredContent,\n }\n } catch (error: unknown) {\n logger.error({ error }, '\u274C Error launching workflow')\n throw new OperationError(error, {\n operation: 'launch deploy-selected workflow',\n remediation: \"check 'gh workflow list' and that deploy-selected-services.yml exists on the target ref\",\n })\n }\n}\n\n/**\n * Parse available services from the workflow file\n * Services are defined as boolean inputs (excluding skip_terraform_deploy)\n */\nconst parseServicesFromWorkflow = async (): Promise<string[]> => {\n const projectRoot = await getProjectRoot()\n\n const workflowPath = resolve(projectRoot, '.github/workflows/deploy-selected-services.yml')\n\n const content = await fs.readFile(workflowPath, 'utf-8')\n const parsed = yaml.parse(content)\n\n const inputs = parsed.on.workflow_dispatch.inputs\n const services: string[] = []\n\n for (const [key, value] of Object.entries(inputs)) {\n // Filter for boolean type inputs, excluding non-service flags\n if ((value as { type: string }).type === 'boolean' && key !== 'skip_terraform_deploy') {\n services.push(key)\n }\n }\n\n return services\n}\n\n// MCP Tool Registration\nexport const ghReleaseDeploySelectedMcpTool = defineMcpTool({\n name: 'gh-release-deploy-selected',\n description:\n 'Dispatch the deploy-selected-services.yml GitHub Actions workflow to deploy a chosen subset of services from a release branch to the given environment. Fire-and-forget \u2014 returns once GitHub accepts the workflow_dispatch, NOT when the deployment finishes; watch the workflow run for completion status. Service names are validated against the boolean inputs declared in the workflow. Use gh-release-deploy-all for every service. \"version\", \"env\", and \"services\" are all required when invoked via MCP (interactive pickers are unavailable without a TTY).',\n inputSchema: {\n version: z\n .string()\n .describe(\n 'Accepts a release version (e.g. \"1.2.5\") OR a release name (e.g. \"checkout-redesign\") \u2014 resolves to the release/vX.Y.Z or release/<name> branch. Pass \"dev\" to deploy from the dev branch instead. Required for MCP calls.',\n ),\n env: z\n .string()\n .describe(\n 'Target environment name \u2014 must match an env configured for the project (e.g. \"dev\", \"renana\", \"oriana\"). Required for MCP calls.',\n ),\n services: z\n .array(z.string())\n .describe(\n 'Service names to deploy. Each must match a boolean input declared in .github/workflows/deploy-selected-services.yml (e.g. \"client-be\", \"client-fe\"). Required for MCP calls.',\n ),\n skipTerraform: z.boolean().optional().describe('Skip the terraform deployment stage.'),\n },\n outputSchema: {\n releaseBranch: z.string().describe('The release branch that was deployed'),\n version: z.string().describe('The version that was deployed'),\n environment: z.string().describe('The environment deployed to'),\n services: z.array(z.string()).describe('The services that were deployed'),\n skipTerraformDeploy: z.boolean().describe('Whether terraform deployment was skipped'),\n success: z.boolean().describe('Whether the deployment was successful'),\n },\n handler: ghReleaseDeploySelected,\n})\n", "import { z } from 'zod'\n\nimport { getReleasePRsWithInfo } from 'src/integrations/gh'\nimport { logger } from 'src/lib/logger'\nimport { displayLabel, formatJiraName, parseBranchName } from 'src/lib/release-id'\nimport { detectReleaseType, formatVersionLabel, getJiraDescriptions } from 'src/lib/release-utils'\nimport { defineMcpTool, textContent } from 'src/types'\n\n/**\n * List all open release branches\n */\nexport const ghReleaseList = async () => {\n const releasePRs = await getReleasePRsWithInfo()\n\n // Skip branches that do not parse as release ids (lenient discovery source).\n const releases = releasePRs.flatMap((pr) => {\n const id = parseBranchName(pr.branch)\n\n if (!id) return []\n\n return [\n {\n // Human display label: `1.2.3` | `<name>`.\n version: displayLabel(id),\n // Jira-descriptions map is keyed by the Jira version NAME (`v1.2.3` | `<name>`).\n jiraKey: formatJiraName(id),\n type: detectReleaseType(pr.title),\n },\n ]\n })\n\n const jiraDescriptions = await getJiraDescriptions()\n\n const maxVersionLength = Math.max(\n ...releases.map((r) => {\n return r.version.length\n }),\n )\n\n const formattedLines = releases.map((release) => {\n const label = formatVersionLabel(release.version, release.type, maxVersionLength)\n const description = jiraDescriptions.get(release.jiraKey)\n\n if (description) {\n return `${label} ${description}`\n }\n\n return label\n })\n\n logger.info('All release branches: \\n')\n logger.info(`\\n${formattedLines.join('\\n')}\\n`)\n\n const structuredContent = {\n releases: releases.map((release) => {\n return {\n version: release.version,\n type: release.type,\n description: jiraDescriptions.get(release.jiraKey) || null,\n }\n }),\n count: releases.length,\n }\n\n return {\n content: textContent(JSON.stringify(structuredContent, null, 2)),\n structuredContent,\n }\n}\n\n// MCP Tool Registration\nexport const ghReleaseListMcpTool = defineMcpTool({\n name: 'gh-release-list',\n description:\n 'List every open release PR with its version, type (regular / hotfix), and associated Jira fix-version description. Read-only; sourced from GitHub and Jira.',\n inputSchema: {},\n outputSchema: {\n releases: z\n .array(\n z.object({\n version: z.string().describe('Release version'),\n type: z.enum(['regular', 'hotfix']).describe('Release type'),\n description: z.string().nullable().describe('Jira version description'),\n }),\n )\n .describe('List of all release branches'),\n count: z.number().describe('Number of release branches'),\n },\n handler: ghReleaseList,\n})\n", "import confirm from '@inquirer/confirm'\nimport select from '@inquirer/select'\nimport process from 'node:process'\nimport { z } from 'zod'\nimport { question } from 'zx'\n\nimport { loadJiraConfig } from 'src/integrations/jira'\nimport { commandEcho } from 'src/lib/command-echo'\nimport { OperationError } from 'src/lib/errors/operation-error'\nimport { assertManagementContext } from 'src/lib/git-guard'\nimport { logger } from 'src/lib/logger'\nimport { InvalidReleaseNameError, displayLabel, validateName } from 'src/lib/release-id'\nimport { createSingleRelease, getBaseBranch, prepareGitForRelease } from 'src/lib/release-utils'\nimport type { ReleaseCreationResult, ReleaseType } from 'src/lib/release-utils'\nimport {\n NoPriorVersionsError,\n computeNextVersion,\n formatReleaseSpec,\n hasNextToken,\n loadExistingVersions,\n parseVersion,\n resolveReleaseEntries,\n} from 'src/lib/version-utils'\nimport type { ReleaseEntry, ReleaseInput, SemVer } from 'src/lib/version-utils'\nimport { defineMcpTool, textContent } from 'src/types'\nimport type { RequiredConfirmedOptionArg } from 'src/types'\n\ninterface ReleaseCreateArgs extends RequiredConfirmedOptionArg {\n releases?: ReleaseInput[]\n}\n\nconst VERSION_PROMPT_HINT = '\"1.2.5\" or \"next\"'\n\nconst trySuggestNext = (known: SemVer[], type: ReleaseType): string | null => {\n try {\n return computeNextVersion(known, type)\n } catch (err) {\n if (err instanceof NoPriorVersionsError) return null\n\n throw err\n }\n}\n\nconst resolveOrExit = (entries: ReleaseInput[], known: SemVer[]): ReleaseEntry[] => {\n try {\n return resolveReleaseEntries(entries, known)\n } catch (err) {\n if (err instanceof NoPriorVersionsError) {\n throw new OperationError(err, {\n operation: 'resolve release version',\n remediation: 'pass an explicit version (e.g. \"1.2.5\") instead of \"next\" when there are no prior versions',\n })\n }\n\n if (err instanceof InvalidReleaseNameError) {\n throw new OperationError(err, {\n operation: 'validate release name',\n remediation:\n 'use a kebab-case name like \"checkout-redesign\" (lowercase, digits, single hyphens, not a reserved word)',\n })\n }\n\n throw err\n }\n}\n\nconst promptForVersionInput = async (running: SemVer[], type: ReleaseType): Promise<string> => {\n const suggestion = trySuggestNext(running, type)\n const defaultHint = suggestion ? ` [${suggestion}]` : ''\n const versionAnswer = (await question(` Version (e.g. ${VERSION_PROMPT_HINT})${defaultHint}: `)).trim()\n const versionInput = versionAnswer === '' ? (suggestion ?? '') : versionAnswer\n\n if (versionInput === '') {\n logger.error('No version provided. Exiting...')\n process.exit(1)\n }\n\n return versionInput\n}\n\nconst promptForNameInput = async (): Promise<string> => {\n const name = (await question(' Name (kebab-case, e.g. \"checkout-redesign\"): ')).trim()\n\n if (name === '') {\n logger.error('No name provided. Exiting...')\n process.exit(1)\n }\n\n try {\n validateName(name)\n } catch (err) {\n const reason = err instanceof Error ? err.message : String(err)\n\n logger.error(`${reason} Exiting...`)\n process.exit(1)\n }\n\n return name\n}\n\nconst promptForReleasesInteractive = async (ensureKnown: () => Promise<SemVer[]>): Promise<ReleaseEntry[]> => {\n commandEcho.setInteractive()\n\n let baseKnown: SemVer[] | null = null\n const running: SemVer[] = []\n const ensureRunning = async (): Promise<SemVer[]> => {\n if (baseKnown === null) {\n baseKnown = await ensureKnown()\n running.push(...baseKnown)\n }\n\n return running\n }\n\n const entries: ReleaseEntry[] = []\n let addAnother = true\n\n while (addAnother) {\n const ordinal = entries.length + 1\n const kind = await select<'version' | 'name'>({\n message: `Release #${ordinal} \u2014 version or name?`,\n choices: [\n { name: 'version (semver / next)', value: 'version' },\n { name: 'name (free-form)', value: 'name' },\n ],\n default: 'version',\n })\n\n const type = await select<ReleaseType>({\n message: `Release #${ordinal} \u2014 select type:`,\n choices: [\n { name: 'regular', value: 'regular' },\n { name: 'hotfix', value: 'hotfix' },\n ],\n default: 'regular',\n })\n\n let resolved: ReleaseEntry\n\n if (kind === 'name') {\n const name = await promptForNameInput()\n\n resolved = resolveOrExit([{ name, type }], [])[0] as ReleaseEntry\n } else {\n // Versions may need prior versions for \"next\"; load lazily.\n const versionInput = await promptForVersionInput(await ensureRunning(), type)\n\n resolved = resolveOrExit([{ version: versionInput, type }], running)[0] as ReleaseEntry\n\n if (resolved.id.kind === 'version') {\n running.push(parseVersion(`v${resolved.id.raw}`))\n }\n }\n\n const description = (await question(' Description (optional, press Enter to skip): ')).trim()\n\n entries.push({ ...resolved, ...(description !== '' ? { description } : {}) })\n\n addAnother = await confirm({ message: 'Add another release?', default: false })\n }\n\n return entries\n}\n\nconst formatReleaseSummary = (entry: ReleaseEntry): string => {\n const label = entry.id.kind === 'version' ? `v${entry.id.raw}` : entry.id.name\n const parts = [label, entry.type]\n\n if (entry.description) parts.push(entry.description)\n\n return parts.join(' \u00B7 ')\n}\n\nconst echoReleases = (entries: ReleaseEntry[]): void => {\n // Every entry \u2014 versions, \"next\" (resolved to a concrete version), and named\n // releases alike \u2014 echoes through the single --release flag. formatReleaseSpec\n // produces a spec that parseReleaseSpec parses back into the same entry.\n for (const entry of entries) {\n commandEcho.addOption('--release', formatReleaseSpec(entry))\n }\n}\n\ninterface FailedRelease {\n version: string\n error: string\n}\n\nconst collectEntries = async (\n inputReleases: ReleaseInput[] | undefined,\n ensureKnown: () => Promise<SemVer[]>,\n): Promise<ReleaseEntry[]> => {\n if (inputReleases && inputReleases.length > 0) {\n const known = hasNextToken(inputReleases) ? await ensureKnown() : []\n const resolved = resolveOrExit(inputReleases, known)\n\n echoReleases(resolved)\n\n return resolved\n }\n\n const interactive = await promptForReleasesInteractive(ensureKnown)\n\n echoReleases(interactive)\n\n return interactive\n}\n\n/**\n * Reject a batch that mixes regular and hotfix releases. They branch off\n * different bases (dev vs main), so the batch has no single required branch for\n * the management guard \u2014 they must be created in separate invocations.\n * Exported for unit testing without running the side-effecting handler.\n */\nexport const assertHomogeneousReleaseType = (entries: ReleaseEntry[]): void => {\n const types = new Set(\n entries.map((entry) => {\n return entry.type\n }),\n )\n\n if (types.size > 1) {\n throw new OperationError(undefined, {\n operation: 'create release',\n remediation: 'create regular and hotfix releases in separate invocations',\n stderrExcerpt: 'mixed regular and hotfix releases in one batch are not supported',\n })\n }\n}\n\nconst confirmReleases = async (entries: ReleaseEntry[], confirmedCommand: boolean): Promise<void> => {\n const summary = entries.map(formatReleaseSummary).join('\\n - ')\n const answer = confirmedCommand\n ? true\n : await confirm({\n message: `Create the following ${entries.length} release(s)?\\n - ${summary}\\n`,\n })\n\n if (!confirmedCommand) {\n commandEcho.setInteractive()\n }\n\n if (!answer) {\n logger.info('Operation cancelled. Exiting...')\n process.exit(0)\n }\n\n commandEcho.addOption('--yes', true)\n}\n\ninterface ExecuteOneArgs {\n entry: ReleaseEntry\n jiraConfig: Awaited<ReturnType<typeof loadJiraConfig>>\n}\n\nconst executeOne = async (\n args: ExecuteOneArgs,\n): Promise<{ result?: ReleaseCreationResult; failure?: FailedRelease }> => {\n const { entry, jiraConfig } = args\n const label = displayLabel(entry.id)\n const prTitleLabel = entry.id.kind === 'version' ? `v${entry.id.raw}` : entry.id.name\n\n try {\n await prepareGitForRelease(entry.type)\n\n const result = await createSingleRelease({\n id: entry.id,\n jiraConfig,\n description: entry.description,\n type: entry.type,\n })\n\n logger.info(`\u2705 Successfully created release: ${prTitleLabel} (${entry.type})`)\n logger.info(`\uD83D\uDD17 GitHub PR: ${result.prUrl}`)\n logger.info(`\uD83D\uDD17 Jira Version: ${result.jiraVersionUrl}\\n`)\n\n return { result }\n } catch (error) {\n const err = new OperationError(error, {\n operation: `create release ${prTitleLabel} (${entry.type})`,\n remediation: 'verify the version or name is unique and the base branch is clean',\n })\n\n logger.error(`\u274C ${err.message}\\n`)\n\n return { failure: { version: label, error: err.message } }\n }\n}\n\nconst logFinalSummary = (total: number, successCount: number, failureCount: number): void => {\n if (successCount === total) {\n logger.info(`\u2705 All ${total} release branch(es) were created successfully.`)\n } else if (successCount > 0) {\n logger.warn(`\u26A0\uFE0F ${successCount} of ${total} release branches were created successfully.`)\n logger.warn(`\u274C ${failureCount} release(s) failed.`)\n } else {\n logger.error(`\u274C All ${total} release branch(es) failed to create.`)\n }\n}\n\n/**\n * Create one or more release branches. Each release carries its own type\n * (regular/hotfix) and optional Jira description. All entries in a single\n * invocation must share the same type \u2014 regular and hotfix releases branch off\n * different bases (dev vs main), so mixed batches are rejected and must be\n * created separately.\n */\nexport const releaseCreate = async (args: ReleaseCreateArgs) => {\n const { releases: inputReleases, confirmedCommand } = args\n\n commandEcho.start('release-create')\n\n const jiraConfig = await loadJiraConfig()\n\n let known: SemVer[] | null = null\n const ensureKnown = async (): Promise<SemVer[]> => {\n if (known === null) known = await loadExistingVersions()\n\n return known\n }\n\n const entries = await collectEntries(inputReleases, ensureKnown)\n\n if (entries.length === 0) {\n throw new OperationError(undefined, {\n operation: 'create release',\n remediation: 'pass at least one entry in \"releases\" (e.g. [{ version: \"1.2.5\", type: \"regular\" }])',\n stderrExcerpt: 'no releases provided',\n })\n }\n\n assertHomogeneousReleaseType(entries)\n\n await assertManagementContext({\n operation: 'create release',\n requiredBranch: getBaseBranch(entries[0]!.type),\n })\n\n await confirmReleases(entries, Boolean(confirmedCommand))\n\n const created: ReleaseCreationResult[] = []\n const failed: FailedRelease[] = []\n\n for (const entry of entries) {\n const { result, failure } = await executeOne({ entry, jiraConfig })\n\n if (result) created.push(result)\n if (failure) failed.push(failure)\n }\n\n logFinalSummary(entries.length, created.length, failed.length)\n\n commandEcho.print()\n\n const structuredContent = {\n createdBranches: created.map((r) => {\n return r.branchName\n }),\n successCount: created.length,\n failureCount: failed.length,\n releases: created,\n failedReleases: failed,\n }\n\n return {\n content: textContent(JSON.stringify(structuredContent, null, 2)),\n structuredContent,\n }\n}\n\n// MCP Tool Registration\nexport const releaseCreateMcpTool = defineMcpTool({\n name: 'release-create',\n description:\n 'Create one or more releases in a single call. Each entry in \"releases\" carries EITHER a \"version\" (semver or the literal token \"next\") OR a \"name\" (free-form kebab-case identifier) \u2014 exactly one is required and they are mutually exclusive. Each entry also has its own type (regular|hotfix, default regular) and optional description; all entries in one call must share the same type \u2014 mixed regular+hotfix batches are rejected (create them in separate invocations). For each release this tool switches to the appropriate base branch (dev for regular, main for hotfix), cuts the release branch (release/v<semver> for versions, release/<name> for names), opens a GitHub release PR, and creates the matching Jira fix version (v<semver> for versions, <name> for names). The literal token \"next\" auto-increments from the union of remote release branches and Jira fix versions (regular bumps minor + resets patch; hotfix bumps patch on the highest minor); multiple \"next\" tokens advance sequentially. Named releases never auto-bump and \"next\" is version-only. Must be run from the main repository checkout (not a linked worktree) on the matching base branch with a clean working tree. Confirmation is auto-skipped for MCP calls, so the caller is responsible for gating. Continues on per-release failure and reports successes/failures.',\n inputSchema: {\n releases: z\n .array(\n z\n .object({\n version: z\n .string()\n .optional()\n .describe(\n 'Version to create (e.g., \"1.2.5\") or the literal token \"next\" for auto-increment. Mutually exclusive with \"name\".',\n ),\n name: z\n .string()\n .optional()\n .describe(\n 'Free-form kebab-case release name (e.g., \"checkout-redesign\"). Mutually exclusive with \"version\". Named releases never auto-bump.',\n ),\n type: z\n .enum(['regular', 'hotfix'])\n .optional()\n .default('regular')\n .describe('Release type: \"regular\" (branches off dev) or \"hotfix\" (branches off main).'),\n description: z.string().optional().describe('Optional description for the Jira version.'),\n })\n .refine(\n (entry) => {\n return (entry.version === undefined) !== (entry.name === undefined)\n },\n {\n message: 'Each release entry must have exactly one of \"version\" or \"name\" (they are mutually exclusive).',\n },\n )\n .transform((entry): ReleaseInput => {\n return entry.name !== undefined\n ? { name: entry.name, type: entry.type, ...(entry.description ? { description: entry.description } : {}) }\n : {\n version: entry.version as string,\n type: entry.type,\n ...(entry.description ? { description: entry.description } : {}),\n }\n }),\n )\n .min(1)\n .describe(\n 'One or more releases to create. Each entry has exactly one of \"version\" or \"name\", plus its own type and optional description.',\n ),\n },\n outputSchema: {\n createdBranches: z.array(z.string()).describe('List of created release branch names'),\n successCount: z.number().describe('Number of releases created successfully'),\n failureCount: z.number().describe('Number of releases that failed'),\n releases: z\n .array(\n z.object({\n version: z.string().describe('Version number'),\n type: z.enum(['regular', 'hotfix']).describe('Release type'),\n branchName: z.string().describe('Release branch name'),\n prUrl: z.string().describe('GitHub PR URL'),\n jiraVersionUrl: z.string().describe('Jira version URL'),\n }),\n )\n .describe('Detailed information for each created release with URLs'),\n failedReleases: z\n .array(\n z.object({\n version: z.string().describe('Version number that failed'),\n error: z.string().describe('Error message'),\n }),\n )\n .describe('List of releases that failed with error messages'),\n },\n handler: releaseCreate,\n})\n", "import { $ } from 'zx'\n\nimport { getProjectVersions, loadJiraConfigOptional } from 'src/integrations/jira'\nimport { logger } from 'src/lib/logger'\nimport { parseBranchName } from 'src/lib/release-id'\n\nimport { collectKnownVersions } from './next-version'\nimport type { SemVer } from './next-version'\n\n/**\n * Extract version-branch tokens from raw `git ls-remote` stdout. Each line is\n * `<sha>\\t<ref>`; refs are routed through release-id's lenient\n * {@link parseBranchName} and only `kind: 'version'` ids are kept (named\n * `release/<name>` branches are irrelevant to `next`-bump math and are dropped).\n * Returns the no-`v` semver tokens (e.g. `1.2.3`) that\n * {@link collectKnownVersions} parses as versions. Pure \u2014 no I/O \u2014 so it is\n * unit-testable without the network.\n */\nexport const extractVersionBranches = (lsRemoteStdout: string): string[] => {\n return lsRemoteStdout\n .split('\\n')\n .map((line) => {\n const tab = line.indexOf('\\t')\n\n if (tab === -1) return null\n\n return parseBranchName(line.slice(tab + 1))\n })\n .filter((id): id is NonNullable<typeof id> => {\n return id !== null && id.kind === 'version'\n })\n .map((id) => {\n return id.raw\n })\n}\n\nconst parseRemoteRefs = async (): Promise<string[]> => {\n const previousQuiet = $.quiet\n\n try {\n $.quiet = true\n const result = await $`git ls-remote --heads origin 'release/v*'`\n\n return extractVersionBranches(result.stdout)\n } finally {\n $.quiet = previousQuiet\n }\n}\n\nconst fetchJiraVersionNames = async (): Promise<string[]> => {\n const config = await loadJiraConfigOptional()\n\n if (!config) return []\n\n const versions = await getProjectVersions(config)\n\n return versions.map((v) => {\n return v.name\n })\n}\n\n/**\n * Load known release versions from the union of:\n * - remote release branches (`release/v*` on origin)\n * - Jira fix versions (when configured)\n *\n * Each source is queried in parallel; if either fails, we log a warning\n * and continue with the other so a transient outage doesn't block release\n * creation.\n */\nexport const loadExistingVersions = async (): Promise<SemVer[]> => {\n const [branchesResult, jiraResult] = await Promise.allSettled([parseRemoteRefs(), fetchJiraVersionNames()])\n\n if (branchesResult.status === 'rejected') {\n logger.warn({ error: branchesResult.reason }, 'Failed to list remote release branches; continuing without them')\n }\n\n if (jiraResult.status === 'rejected') {\n logger.warn({ error: jiraResult.reason }, 'Failed to fetch Jira versions; continuing without them')\n }\n\n return collectKnownVersions({\n remoteBranches: branchesResult.status === 'fulfilled' ? branchesResult.value : [],\n jiraVersions: jiraResult.status === 'fulfilled' ? jiraResult.value : [],\n })\n}\n", "/**\n * Parse a `v<semver>` token into major, minor, patch numbers.\n *\n * SemVer-ONLY: this assumes a `v<semver>` token and will produce `NaN`s for\n * anything else. Callers that may see branch names or named releases\n * (`release/<name>`) MUST use the `release-id` module (`parseBranchName` /\n * `parseReleaseRef` + `compareReleaseIds`) instead. Only provably names-free\n * callers (the `collectKnownVersions` / `next`-bump math path) may use this.\n */\nexport const parseVersion = (versionStr: string): [number, number, number] => {\n return versionStr.slice(1).split('.').map(Number) as [number, number, number]\n}\n\n/**\n * Sort version strings in ascending order.\n * Note: Returns a new sorted array without mutating the original.\n *\n * SemVer-ONLY: relies on {@link parseVersion} and will NaN-sort named releases.\n * Name-aware callers MUST use `compareReleaseIds` from the `release-id` module.\n */\nexport const sortVersions = (versions: string[]): string[] => {\n return [...versions].sort((a, b) => {\n const [majA, minA, patchA] = parseVersion(a)\n const [majB, minB, patchB] = parseVersion(b)\n\n if (majA !== majB) return (majA ?? 0) - (majB ?? 0)\n if (minA !== minB) return (minA ?? 0) - (minB ?? 0)\n\n return (patchA ?? 0) - (patchB ?? 0)\n })\n}\n", "import { parseReleaseRef, validateName } from 'src/lib/release-id'\nimport type { ReleaseId } from 'src/lib/release-id'\nimport type { ReleaseType } from 'src/lib/release-utils'\n\nimport { parseVersion, sortVersions } from './version-utils'\n\nexport const NEXT_TOKEN = 'next'\n\nexport type SemVer = readonly [number, number, number]\n\nexport interface ExistingVersionsSources {\n remoteBranches?: string[]\n jiraVersions?: string[]\n}\n\nconst VERSION_RE = /^v?(\\d+)\\.(\\d+)\\.(\\d+)$/\n\nconst stripBranchPrefix = (raw: string): string => {\n return raw.replace(/^.*release\\//, '')\n}\n\nconst tryParse = (raw: string): SemVer | null => {\n const cleaned = stripBranchPrefix(raw.trim())\n const match = VERSION_RE.exec(cleaned)\n\n if (!match) return null\n\n return [Number(match[1]), Number(match[2]), Number(match[3])]\n}\n\nconst semverKey = (v: SemVer): string => {\n return `${v[0]}.${v[1]}.${v[2]}`\n}\n\nexport const collectKnownVersions = (sources: ExistingVersionsSources): SemVer[] => {\n const all = [...(sources.remoteBranches ?? []), ...(sources.jiraVersions ?? [])]\n const parsed: SemVer[] = []\n const seen = new Set<string>()\n\n for (const raw of all) {\n const v = tryParse(raw)\n\n if (!v) continue\n\n const key = semverKey(v)\n\n if (seen.has(key)) continue\n\n seen.add(key)\n parsed.push(v)\n }\n\n return sortVersions(\n parsed.map((v) => {\n return semverKey(v)\n }),\n ).map((s) => {\n return parseVersion(`v${s}`)\n })\n}\n\nexport class NoPriorVersionsError extends Error {\n constructor() {\n super('No prior release versions found from git or Jira. Specify the version explicitly.')\n this.name = 'NoPriorVersionsError'\n }\n}\n\n/**\n * Compute the next semantic version based on release type.\n * - regular: bump minor, reset patch to 0\n * - hotfix: bump patch on the highest minor (any patch)\n *\n * Returns the version without the leading \"v\" (e.g. \"1.64.0\").\n */\nexport const computeNextVersion = (known: SemVer[], type: ReleaseType): string => {\n if (known.length === 0) throw new NoPriorVersionsError()\n\n const max = known[known.length - 1] as SemVer\n\n if (type === 'hotfix') {\n const [major, minor] = max\n\n const highestPatchOnMinor = known.reduce((acc, v) => {\n if (v[0] === major && v[1] === minor) return Math.max(acc, v[2])\n\n return acc\n }, 0)\n\n return `${major}.${minor}.${highestPatchOnMinor + 1}`\n }\n\n const [major, minor] = max\n\n return `${major}.${minor + 1}.0`\n}\n\nconst isNextToken = (token: string): boolean => {\n return token.trim().toLowerCase() === NEXT_TOKEN\n}\n\n/**\n * A release spec is the parsed form of a versioned release request: a raw\n * version token (`\"1.2.5\"` or `\"next\"`) plus its type and optional\n * description. This is the unchanged output of {@link parseReleaseSpec} and the\n * versioned-input shape consumed by {@link resolveReleaseEntries}.\n */\nexport interface ReleaseSpec {\n version: string\n type: ReleaseType\n description?: string\n}\n\n/**\n * A named release request: a bare kebab-case name plus its type and optional\n * description. Named releases never auto-bump; `\"next\"` is version-only.\n */\nexport interface NamedReleaseInput {\n name: string\n type: ReleaseType\n description?: string\n}\n\n/** Either a versioned spec or a named release request. */\nexport type ReleaseInput = ReleaseSpec | NamedReleaseInput\n\n/**\n * A fully resolved release entry. The {@link ReleaseId} carries the concrete\n * identity (version or name) and is the single source for branch/PR/Jira\n * formatting via the `release-id` module.\n */\nexport interface ReleaseEntry {\n id: ReleaseId\n type: ReleaseType\n description?: string\n}\n\nconst isReleaseType = (value: string): value is ReleaseType => {\n return value === 'regular' || value === 'hotfix'\n}\n\nconst isNamedReleaseInput = (input: ReleaseInput): input is NamedReleaseInput => {\n return 'name' in input\n}\n\n/**\n * Parse a CLI release spec of the form `<token>[:type[:description]]` into a\n * {@link ReleaseInput}. The token determines the kind: a semver (`\"1.2.5\"`) or\n * the literal `\"next\"` yields a versioned {@link ReleaseSpec}; anything else is\n * treated as a named release ({@link NamedReleaseInput}) \u2014 the name is not\n * validated here, {@link resolveReleaseEntries} runs `validateName` later. Type\n * defaults to \"regular\". Description is everything after the second colon, so\n * colons inside descriptions are preserved.\n */\nexport const parseReleaseSpec = (raw: string): ReleaseInput => {\n const spec = raw.trim()\n\n if (spec === '') throw new Error('Release spec is empty')\n\n const firstColon = spec.indexOf(':')\n let token = spec\n let type: ReleaseType = 'regular'\n let description = ''\n\n if (firstColon !== -1) {\n token = spec.slice(0, firstColon).trim()\n const rest = spec.slice(firstColon + 1)\n const secondColon = rest.indexOf(':')\n const typeRaw = secondColon === -1 ? rest.trim() : rest.slice(0, secondColon).trim()\n\n description = secondColon === -1 ? '' : rest.slice(secondColon + 1).trim()\n const typeLower = typeRaw.toLowerCase()\n\n if (!isReleaseType(typeLower)) {\n throw new Error(`Invalid release type \"${typeRaw}\". Expected \"regular\" or \"hotfix\".`)\n }\n\n type = typeLower\n }\n\n // A semver token or the \"next\" token is a versioned release; everything else\n // is a named release. parseReleaseRef applies the same precedence downstream.\n // Note: tryParse strips a leading \"release/\" prefix, so \"release/1.2.3\" reads\n // as the version 1.2.3 (a real name can never contain a slash anyway).\n if (isNextToken(token) || tryParse(token) !== null) {\n const entry: ReleaseSpec = { version: token, type }\n\n if (description !== '') entry.description = description\n\n return entry\n }\n\n const entry: NamedReleaseInput = { name: token, type }\n\n if (description !== '') entry.description = description\n\n return entry\n}\n\n/**\n * Render a resolved {@link ReleaseEntry} as the canonical `--release` spec that\n * reproduces it \u2014 the inverse of {@link parseReleaseSpec} composed with\n * {@link resolveReleaseEntries}. The form is minimal: the bare token when the\n * release is `regular` with no description, `token:hotfix` for a hotfix with no\n * description, and `token:type:description` whenever a description is present\n * (the type segment is required to reach the description segment). The token is\n * the resolved {@link ReleaseId.raw} \u2014 a concrete semver for versions (so a\n * resolved `\"next\"` pins its computed version) or the name for named releases.\n */\nexport const formatReleaseSpec = (entry: ReleaseEntry): string => {\n const token = entry.id.raw\n\n if (entry.description !== undefined && entry.description !== '') {\n return `${token}:${entry.type}:${entry.description}`\n }\n\n if (entry.type === 'hotfix') return `${token}:hotfix`\n\n return token\n}\n\nconst withDescription = (base: { id: ReleaseId; type: ReleaseType }, description?: string): ReleaseEntry => {\n return description !== undefined && description !== '' ? { ...base, description } : base\n}\n\nconst resolveNamedInput = (input: NamedReleaseInput): ReleaseEntry => {\n const name = input.name.trim()\n\n // validateName throws InvalidReleaseNameError with a specific message.\n validateName(name)\n\n return withDescription({ id: { kind: 'name', name, raw: name }, type: input.type }, input.description)\n}\n\n/**\n * Resolve a list of release inputs into entries carrying a concrete\n * {@link ReleaseId}. Versioned inputs use the existing spec format: the\n * `\"next\"` token advances based on the running max so successive `\"next\"`\n * tokens produce sequential versions (even across mixed types), then the\n * concrete version is wrapped in a {@link ReleaseId}. Named inputs are\n * validated via `validateName` and never auto-bump.\n */\nexport const resolveReleaseEntries = (entries: ReleaseInput[], known: SemVer[]): ReleaseEntry[] => {\n const running: SemVer[] = [...known]\n\n return entries.map((entry) => {\n if (isNamedReleaseInput(entry)) {\n return resolveNamedInput(entry)\n }\n\n const trimmed = entry.version.trim()\n\n if (trimmed === '') {\n throw new Error('Release entry has an empty version')\n }\n\n if (isNextToken(trimmed)) {\n const next = computeNextVersion(running, entry.type)\n\n running.push(parseVersion(`v${next}`))\n\n return withDescription({ id: parseReleaseRef(next), type: entry.type }, entry.description)\n }\n\n const parsed = tryParse(trimmed)\n\n if (!parsed) {\n throw new Error(`Invalid version \"${trimmed}\". Expected semver like \"1.2.5\" or the token \"next\".`)\n }\n\n const explicit = `${parsed[0]}.${parsed[1]}.${parsed[2]}`\n\n running.push(parsed)\n\n return withDescription({ id: parseReleaseRef(explicit), type: entry.type }, entry.description)\n })\n}\n\nexport const hasNextToken = (entries: ReleaseInput[]): boolean => {\n return entries.some((e) => {\n return !isNamedReleaseInput(e) && isNextToken(e.version)\n })\n}\n", "import confirm from '@inquirer/confirm'\nimport select from '@inquirer/select'\nimport process from 'node:process'\nimport { z } from 'zod'\nimport { question } from 'zx'\n\nimport { getReleasePRsWithInfo, updateReleasePRBody } from 'src/integrations/gh'\nimport { findVersionByName, loadJiraConfig, updateJiraVersion } from 'src/integrations/jira'\nimport type { JiraConfig, JiraVersion } from 'src/integrations/jira'\nimport { commandEcho } from 'src/lib/command-echo'\nimport { OperationError } from 'src/lib/errors/operation-error'\nimport { logger } from 'src/lib/logger'\nimport { displayLabel, formatJiraName, parseBranchName } from 'src/lib/release-id'\nimport {\n detectReleaseType,\n formatBranchChoices,\n getJiraDescriptions,\n resolveReleaseBranch,\n} from 'src/lib/release-utils'\nimport type { ReleaseType } from 'src/lib/release-utils'\nimport { defineMcpTool, textContent } from 'src/types'\nimport type { RequiredConfirmedOptionArg } from 'src/types'\n\ninterface ReleaseDescEditArgs extends RequiredConfirmedOptionArg {\n version?: string\n description?: string\n}\n\nconst buildJiraVersionUrl = (jiraConfig: JiraConfig, version: JiraVersion): string => {\n return `${jiraConfig.baseUrl}/projects/${version.projectId}/versions/${version.id}/tab/release-report-all-issues`\n}\n\nconst buildPRBody = (jiraVersionUrl: string, description: string): string => {\n return description.trim() !== '' ? `${jiraVersionUrl}\\n\\n${description}` : `${jiraVersionUrl} \\n`\n}\n\nconst pickReleaseBranch = async (): Promise<{ branch: string; type: ReleaseType }> => {\n const releasePRsInfo = await getReleasePRsWithInfo()\n const branches = releasePRsInfo.map((pr) => {\n return pr.branch\n })\n const types = new Map<string, ReleaseType>(\n releasePRsInfo.map((pr) => {\n return [pr.branch, detectReleaseType(pr.title)]\n }),\n )\n const descriptions = await getJiraDescriptions()\n\n const branch = await select({\n message: '\uD83C\uDF3F Select release branch',\n choices: formatBranchChoices({ branches, descriptions, types }),\n })\n\n return { branch, type: types.get(branch) || 'regular' }\n}\n\nconst verifyReleasePRExists = async (selectedBranch: string): Promise<ReleaseType> => {\n const releasePRsInfo = await getReleasePRsWithInfo()\n const prInfo = releasePRsInfo.find((pr) => {\n return pr.branch === selectedBranch\n })\n\n if (!prInfo) {\n throw new OperationError(undefined, {\n operation: `edit description for ${selectedBranch}`,\n remediation: `confirm an open PR exists for ${selectedBranch} ('gh pr list')`,\n })\n }\n\n return detectReleaseType(prInfo.title)\n}\n\nconst promptDescription = async (current: string): Promise<string> => {\n const hint = current === '' ? '(no current description)' : `current: \"${current}\"`\n const answer = await question(` New description ${hint}\\n (press Enter to keep current): `)\n const trimmed = answer.replace(/\\n$/, '')\n\n return trimmed === '' ? current : trimmed\n}\n\n/**\n * Edit a release's description in Jira (fix version) and in the matching\n * GitHub release PR body. The PR body is rewritten canonically to\n * `<jiraVersionUrl>\\n\\n<description>` (matching `release-create`).\n */\nexport const releaseDescEdit = async (args: ReleaseDescEditArgs) => {\n const { version: versionArg, description: descriptionArg, confirmedCommand } = args\n\n commandEcho.start('release-desc-edit')\n\n const jiraConfig = await loadJiraConfig()\n\n let selectedBranch: string\n\n if (versionArg) {\n selectedBranch = resolveReleaseBranch(versionArg)\n await verifyReleasePRExists(selectedBranch)\n } else {\n commandEcho.setInteractive()\n const picked = await pickReleaseBranch()\n\n selectedBranch = picked.branch\n }\n\n // selectedBranch is always a release branch here (operator ref strictly parsed,\n // or picked from discovery-filtered choices), so parseBranchName cannot be null.\n const releaseId = parseBranchName(selectedBranch)\n\n if (!releaseId) {\n throw new OperationError(undefined, {\n operation: `edit description for ${selectedBranch}`,\n remediation: 'pass a version (e.g. \"1.2.5\") or a release name (e.g. \"checkout-redesign\")',\n })\n }\n\n const selectedVersion = displayLabel(releaseId)\n\n commandEcho.addOption('--version', selectedVersion)\n\n // Jira fix version is named by the Jira convention: `v1.2.3` | `<name>`.\n const versionName = formatJiraName(releaseId)\n const jiraVersion = await findVersionByName(versionName, jiraConfig)\n\n if (!jiraVersion) {\n throw new OperationError(undefined, {\n operation: `edit description for ${versionName}`,\n remediation: `create the Jira fix version \"${versionName}\" first or pick a different release`,\n })\n }\n\n const previousDescription = jiraVersion.description ?? ''\n\n let newDescription: string\n\n if (descriptionArg !== undefined) {\n newDescription = descriptionArg\n commandEcho.addOption('--description', newDescription)\n } else {\n commandEcho.setInteractive()\n newDescription = await promptDescription(previousDescription)\n }\n\n if (newDescription === previousDescription) {\n logger.info(`No change \u2014 description for ${versionName} is already: \"${previousDescription}\"`)\n commandEcho.print()\n\n const structuredContent = {\n version: selectedVersion,\n branch: selectedBranch,\n jiraVersionUrl: buildJiraVersionUrl(jiraConfig, jiraVersion),\n previousDescription,\n newDescription,\n changed: false,\n }\n\n return {\n content: textContent(JSON.stringify(structuredContent, null, 2)),\n structuredContent,\n }\n }\n\n const answer = confirmedCommand\n ? true\n : await confirm({\n message: `Update description for ${versionName}?\\n from: \"${previousDescription}\"\\n to: \"${newDescription}\"\\n`,\n })\n\n if (!confirmedCommand) {\n commandEcho.setInteractive()\n }\n\n if (!answer) {\n logger.info('Operation cancelled. Exiting...')\n process.exit(0)\n }\n\n commandEcho.addOption('--yes', true)\n\n await updateJiraVersion({ versionId: jiraVersion.id, description: newDescription }, jiraConfig)\n\n const jiraVersionUrl = buildJiraVersionUrl(jiraConfig, jiraVersion)\n const body = buildPRBody(jiraVersionUrl, newDescription)\n\n await updateReleasePRBody({ branch: selectedBranch, body })\n\n logger.info(`\u2705 Updated description for ${versionName}`)\n logger.info(`\uD83D\uDD17 Jira Version: ${jiraVersionUrl}`)\n logger.info(`\uD83D\uDD17 PR branch: ${selectedBranch}\\n`)\n\n commandEcho.print()\n\n const structuredContent = {\n version: selectedVersion,\n branch: selectedBranch,\n jiraVersionUrl,\n previousDescription,\n newDescription,\n changed: true,\n }\n\n return {\n content: textContent(JSON.stringify(structuredContent, null, 2)),\n structuredContent,\n }\n}\n\n// MCP Tool Registration\nexport const releaseDescEditMcpTool = defineMcpTool({\n name: 'release-desc-edit',\n description:\n \"Edit a release's description in Jira and in the matching GitHub release PR body. Accepts a release version or a release name: targets the Jira fix version named `v<version>` (versioned) or `<name>` (named) and the open PR on branch `release/v<version>` or `release/<name>`. The PR body is rewritten canonically to `<jiraVersionUrl>\\\\n\\\\n<description>` \u2014 any prior manual edits to the body are overwritten. Both `version` and `description` are required for MCP calls (the picker/prompt are unreachable without a TTY). Empty `description` clears the description on both sides. Confirmation is auto-skipped for MCP, so the caller is responsible for gating.\",\n inputSchema: {\n version: z\n .string()\n .describe('Accepts a release version (e.g. \"1.2.5\") OR a release name (e.g. \"checkout-redesign\").'),\n description: z.string().describe('New description. Empty string clears the description.'),\n },\n outputSchema: {\n version: z.string().describe('Release version'),\n branch: z.string().describe('Release branch name (e.g. \"release/v1.2.5\" or \"release/checkout-redesign\")'),\n jiraVersionUrl: z.string().describe('Jira fix version URL'),\n previousDescription: z.string().describe('The description before the update'),\n newDescription: z.string().describe('The description after the update'),\n changed: z.boolean().describe('Whether the description actually changed'),\n },\n handler: releaseDescEdit,\n})\n", "import { z } from 'zod'\n\nimport { logger } from 'src/lib/logger'\nimport { defineMcpTool, textContent } from 'src/types'\n\nimport packageJson from '../../../package.json' with { type: 'json' }\n\n/**\n * Print the infra-kit CLI version\n */\nexport const version = async () => {\n const cliVersion = packageJson.version\n\n logger.info(cliVersion)\n\n const structuredContent = { version: cliVersion }\n\n return {\n content: textContent(JSON.stringify(structuredContent, null, 2)),\n structuredContent,\n }\n}\n\n// MCP Tool Registration\nexport const versionMcpTool = defineMcpTool({\n name: 'version',\n description: 'Print the installed infra-kit CLI version',\n inputSchema: {},\n outputSchema: {\n version: z.string().describe('Installed infra-kit CLI version (from package.json)'),\n },\n handler: version,\n})\n", "/* eslint-disable sonarjs/cognitive-complexity */\nimport checkbox from '@inquirer/checkbox'\nimport confirm from '@inquirer/confirm'\nimport process from 'node:process'\nimport { z } from 'zod'\nimport { $ } from 'zx'\n\nimport {\n buildCmuxWorkspaceTitle,\n canonicalizeCmuxTitle,\n listCmuxWorkspaceTitles,\n openCmuxWorkspaceWithLayout,\n} from 'src/integrations/cmux'\nimport { getReleasePRsWithInfo } from 'src/integrations/gh'\nimport { IDE_MODES, addIdeWorktreeFolders } from 'src/integrations/ide'\nimport type { IdeMode } from 'src/integrations/ide'\nimport { commandEcho } from 'src/lib/command-echo'\nimport { WORKTREES_DIR_SUFFIX } from 'src/lib/constants'\nimport { OperationError } from 'src/lib/errors/operation-error'\nimport { assertManagementContext } from 'src/lib/git-guard'\nimport { getCurrentWorktrees, getProjectRoot, getRepoName } from 'src/lib/git-utils'\nimport { getInfraKitConfig, resolveConfiguredIdes } from 'src/lib/infra-kit-config'\nimport { logger } from 'src/lib/logger'\nimport { formatBranchName, isReleaseBranch, parseReleaseRef } from 'src/lib/release-id'\nimport { detectReleaseType, formatBranchChoices, getJiraDescriptions, releaseBranchLabels } from 'src/lib/release-utils'\nimport type { ReleaseType } from 'src/lib/release-utils'\nimport { defineMcpTool, textContent } from 'src/types'\nimport type { RequiredConfirmedOptionArg } from 'src/types'\n\n// Constants\nconst FEATURE_DIR = 'feature'\nconst RELEASE_DIR = 'release'\n\ninterface WorktreeManagementArgs extends RequiredConfirmedOptionArg {\n all?: boolean\n versions?: string\n ide?: IdeMode\n /** @deprecated Alias for `ide`, kept for back-compat. Ignored when `ide` is set. */\n cursor?: IdeMode\n githubDesktop?: boolean\n cmux?: boolean\n}\n\n/**\n * Manage git worktrees for release branches\n * Creates worktrees for active release branches and removes unused ones\n */\nexport const worktreesAdd = async (options: WorktreeManagementArgs) => {\n const { confirmedCommand, all, versions, githubDesktop, cmux } = options\n // `cursor` is the deprecated alias for `ide`; `ide` wins when both are present.\n const ide = options.ide ?? options.cursor\n\n commandEcho.start('worktrees-add')\n\n await assertManagementContext({ operation: 'create worktrees', requiredBranch: 'dev' })\n\n try {\n const currentWorktrees = await getCurrentWorktrees('release')\n const projectRoot = await getProjectRoot()\n\n const worktreeDir = `${projectRoot}${WORKTREES_DIR_SUFFIX}`\n\n await ensureWorktreeDirectory(`${worktreeDir}/${RELEASE_DIR}`)\n await ensureWorktreeDirectory(`${worktreeDir}/${FEATURE_DIR}`)\n\n let selectedReleaseBranches: string[] = []\n\n if (versions) {\n selectedReleaseBranches = versions.split(',').map((v) => {\n return formatBranchName(parseReleaseRef(v.trim()))\n })\n } else {\n const releasePRsInfo = await getReleasePRsWithInfo()\n\n const releasePRsList = releasePRsInfo.map((pr) => {\n return pr.branch\n })\n\n if (releasePRsList.length === 0) {\n logger.info('\u2139\uFE0F No open release branches found')\n\n commandEcho.print()\n\n return {\n content: textContent(JSON.stringify({ createdWorktrees: [], count: 0 }, null, 2)),\n structuredContent: { createdWorktrees: [], count: 0 },\n }\n }\n\n if (all) {\n selectedReleaseBranches = releasePRsList\n } else {\n commandEcho.setInteractive()\n\n const releaseTypes = new Map<string, ReleaseType>(\n releasePRsInfo.map((pr) => {\n return [pr.branch, detectReleaseType(pr.title)]\n }),\n )\n\n const descriptions = await getJiraDescriptions()\n\n selectedReleaseBranches = await checkbox({\n required: true,\n message: '\uD83C\uDF3F Select release branches',\n choices: formatBranchChoices({ branches: releasePRsList, descriptions, types: releaseTypes }),\n })\n }\n }\n\n // Track --all flag if all branches were selected (either via flag or interactively)\n if (all) {\n commandEcho.addOption('--all', true)\n } else {\n commandEcho.addOption('--versions', releaseBranchLabels(selectedReleaseBranches))\n }\n\n // Ask for confirmation\n const answer = confirmedCommand\n ? true\n : await confirm({\n message: 'Are you sure you want to proceed with these worktree changes?',\n })\n\n if (!confirmedCommand) {\n commandEcho.setInteractive()\n }\n\n if (!answer) {\n logger.info('Operation cancelled. Exiting...')\n process.exit(0)\n }\n\n // Track --yes flag if confirmation was interactive (user confirmed)\n if (!confirmedCommand) {\n commandEcho.addOption('--yes', true)\n }\n\n const config = await getInfraKitConfig()\n\n // One attach style: every configured editor gets the worktrees added to its\n // workspace. Per-run skip is `--ide none` / `--no-ide`; no editor configured\n // means there's nothing to open.\n const ideMode: IdeMode = ide ?? (resolveConfiguredIdes(config).length > 0 ? 'workspace' : 'none')\n\n commandEcho.addOption('--ide', ideMode)\n\n const openInGithubDesktop =\n githubDesktop ??\n config.worktrees?.openInGithubDesktop ??\n (await confirm({ message: 'Open created worktrees in GitHub Desktop?' }))\n\n if (typeof githubDesktop === 'undefined' && config.worktrees?.openInGithubDesktop === undefined) {\n commandEcho.setInteractive()\n }\n\n if (openInGithubDesktop) {\n commandEcho.addOption('--github-desktop', true)\n } else {\n commandEcho.addOption('--no-github-desktop', true)\n }\n\n const openInCmux =\n cmux ?? config.worktrees?.openInCmux ?? (await confirm({ message: 'Open created worktrees in cmux?' }))\n\n if (typeof cmux === 'undefined' && config.worktrees?.openInCmux === undefined) {\n commandEcho.setInteractive()\n }\n\n if (openInCmux) {\n commandEcho.addOption('--cmux', true)\n } else {\n commandEcho.addOption('--no-cmux', true)\n }\n\n const { branchesToCreate } = categorizeWorktrees({\n selectedReleaseBranches,\n currentWorktrees,\n })\n\n const createdWorktrees = await createWorktrees(branchesToCreate, worktreeDir)\n\n logResults(createdWorktrees)\n\n if (ideMode === 'workspace') {\n await addIdeWorktreeFolders({ projectRoot, worktreeDir, branches: createdWorktrees })\n }\n\n if (openInGithubDesktop) {\n for (const branch of createdWorktrees) {\n await $`github ${worktreeDir}/${branch}`\n await $`sleep 5`\n }\n }\n\n if (openInCmux) {\n const repoName = await getRepoName()\n const existingTitles = await listCmuxWorkspaceTitles()\n\n for (const branch of createdWorktrees) {\n const title = buildCmuxWorkspaceTitle({ repoName, branch })\n\n // Skip branches whose cmux workspace is already open (canonical match),\n // so re-running worktrees-add never duplicates an existing workspace.\n if (existingTitles.has(canonicalizeCmuxTitle(title))) {\n continue\n }\n\n await openCmuxWorkspaceWithLayout({\n cwd: `${worktreeDir}/${branch}`,\n title,\n })\n }\n }\n\n commandEcho.print()\n\n const structuredContent = {\n createdWorktrees,\n count: createdWorktrees.length,\n }\n\n return {\n content: textContent(JSON.stringify(structuredContent, null, 2)),\n structuredContent,\n }\n } catch (error) {\n logger.error({ error }, '\u274C Error managing worktrees')\n throw new OperationError(error, {\n operation: 'create worktrees',\n remediation: \"verify branches don't already exist as worktrees: 'git worktree list'\",\n })\n }\n}\n\n/**\n * Ensure the worktree directory exists\n */\nconst ensureWorktreeDirectory = async (worktreeDir: string): Promise<void> => {\n await $`mkdir -p ${worktreeDir}`\n}\n\ninterface CategorizeWorktreesArgs {\n selectedReleaseBranches: string[]\n currentWorktrees: string[]\n}\n\n/**\n * Categorize release worktrees into those that need to be created or removed\n */\nconst categorizeWorktrees = (args: CategorizeWorktreesArgs): { branchesToCreate: string[] } => {\n const { selectedReleaseBranches, currentWorktrees } = args\n\n const currentBranchNames = currentWorktrees.filter((branch) => {\n return isReleaseBranch(branch)\n })\n\n const branchesToCreate = selectedReleaseBranches.filter((branch) => {\n return !currentBranchNames.includes(branch)\n })\n\n return { branchesToCreate }\n}\n\n/**\n * Create worktrees for the specified branches\n */\nconst createWorktrees = async (branches: string[], worktreeDir: string): Promise<string[]> => {\n const results = await Promise.allSettled(\n branches.map(async (branch) => {\n const worktreePath = `${worktreeDir}/${branch}`\n\n await $`git worktree add ${worktreePath} ${branch}`\n await $({ cwd: worktreePath })`pnpm install`\n\n return branch\n }),\n )\n\n const created: string[] = []\n\n for (const [index, result] of results.entries()) {\n if (result.status === 'fulfilled') {\n created.push(result.value)\n } else {\n const branch = branches[index]\n const err = new OperationError(result.reason, {\n operation: `git worktree add for ${branch}`,\n remediation: 'check the branch name and that the parent dir is writable',\n })\n\n logger.error({ error: result.reason, msg: err.message })\n }\n }\n\n return created\n}\n\n/**\n * Log the results of worktree management\n */\nconst logResults = (created: string[]): void => {\n if (created.length > 0) {\n logger.info('\u2705 Created git worktrees:')\n for (const branch of created) {\n logger.info(branch)\n }\n logger.info('')\n } else {\n logger.info('\u2139\uFE0F No new git worktrees to create')\n }\n}\n\n// MCP Tool Registration\nexport const worktreesAddMcpTool = defineMcpTool({\n name: 'worktrees-add',\n description:\n 'Create local git worktrees for release branches under the worktrees directory and run \"pnpm install\" in each. Mutates the local filesystem. When invoked via MCP, pass either \"versions\" (comma-separated) or all=true \u2014 the branch picker and \"open in Cursor / GitHub Desktop / cmux\" follow-up prompts are unreachable without a TTY, and the CLI confirmation is auto-skipped for MCP calls.',\n inputSchema: {\n all: z\n .boolean()\n .optional()\n .describe(\n 'Add worktrees for every open release branch. Either \"all\" or \"versions\" must be provided for MCP calls (the interactive picker is unavailable without a TTY). Ignored if \"versions\" is provided.',\n ),\n versions: z\n .string()\n .optional()\n .describe(\n 'Comma-separated release versions or names to target (e.g. \"1.2.5, 1.2.6\" or \"checkout-redesign, 1.2.5\"). Either \"versions\" or all=true must be provided for MCP calls. Overrides \"all\" when set.',\n ),\n ide: z\n .enum(IDE_MODES)\n .optional()\n .describe(\n 'Editor open mode for created worktrees, applied to all configured editors (Cursor and/or Zed, per the \"ide\" config). \"workspace\" (the only attach style) adds each worktree to every configured editor workspace and opens it. \"none\" skips the editor. Resolution order: this flag \u2192 \"workspace\" when at least one \"ide\" is configured \u2192 \"none\" otherwise.',\n ),\n cursor: z\n .enum(IDE_MODES)\n .optional()\n .describe('Deprecated alias for \"ide\". Prefer \"ide\". Ignored when \"ide\" is provided.'),\n githubDesktop: z\n .boolean()\n .optional()\n .describe(\n 'Open each created worktree in GitHub Desktop. Resolution order: this flag \u2192 \"worktrees.openInGithubDesktop\" from infra-kit config \u2192 interactive prompt (CLI) / false (MCP, no TTY).',\n ),\n cmux: z\n .boolean()\n .optional()\n .describe(\n 'Open each created worktree in a new cmux workspace with a 3-pane layout (left-top, left-bottom, full-height right), all rooted at the worktree directory. Resolution order: this flag \u2192 \"worktrees.openInCmux\" from infra-kit config \u2192 interactive prompt (CLI) / false (MCP, no TTY).',\n ),\n },\n outputSchema: {\n createdWorktrees: z.array(z.string()).describe('List of created git worktree branches'),\n count: z.number().describe('Number of git worktrees created'),\n },\n handler: worktreesAdd,\n})\n", "import fs from 'node:fs/promises'\nimport path from 'node:path'\n\ninterface AddFoldersToCursorWorkspaceArgs {\n workspacePath: string\n folderPaths: string[]\n}\n\ninterface AddFoldersToCursorWorkspaceResult {\n added: string[]\n skipped: string[]\n}\n\ninterface WorkspaceFolderEntry {\n path: string\n name?: string\n}\n\ninterface WorkspaceFile {\n folders?: WorkspaceFolderEntry[]\n [key: string]: unknown\n}\n\n/**\n * Adds folders to a Cursor (`.code-workspace`) file's `folders` array, skipping\n * entries that already point to the same absolute path. Folder paths are written\n * as relative to the workspace file's directory to match Cursor's default style.\n */\nexport const addFoldersToCursorWorkspace = async (\n args: AddFoldersToCursorWorkspaceArgs,\n): Promise<AddFoldersToCursorWorkspaceResult> => {\n const { workspacePath, folderPaths } = args\n\n const workspaceDir = path.dirname(workspacePath)\n\n let raw: string\n\n try {\n raw = await fs.readFile(workspacePath, 'utf-8')\n } catch (error) {\n throw new Error(`Cursor workspace file not found at ${workspacePath}: ${(error as Error).message}`)\n }\n\n let parsed: WorkspaceFile\n\n try {\n parsed = JSON.parse(raw) as WorkspaceFile\n } catch (error) {\n throw new Error(\n `Failed to parse ${workspacePath} as JSON. Comments (JSONC) are not supported. ${(error as Error).message}`,\n )\n }\n\n const existingFolders = parsed.folders ?? []\n const existingAbsolutePaths = new Set(\n existingFolders.map((entry) => {\n return path.resolve(workspaceDir, entry.path)\n }),\n )\n\n const added: string[] = []\n const skipped: string[] = []\n\n for (const folderPath of folderPaths) {\n const absolutePath = path.resolve(folderPath)\n\n if (existingAbsolutePaths.has(absolutePath)) {\n skipped.push(folderPath)\n continue\n }\n\n const relativePath = path.relative(workspaceDir, absolutePath)\n\n existingFolders.push({ path: relativePath })\n existingAbsolutePaths.add(absolutePath)\n added.push(folderPath)\n }\n\n parsed.folders = existingFolders\n\n await fs.writeFile(workspacePath, `${JSON.stringify(parsed, null, 2)}\\n`, 'utf-8')\n\n return { added, skipped }\n}\n", "import { $ } from 'zx'\n\n/**\n * Spawns Cursor against a `.code-workspace` file (or any path). Centralised here\n * \u2014 rather than inlined at each call site \u2014 so the editor spawn lives inside the\n * cursor provider module and is covered by a single `vi.mock('src/integrations/cursor')`.\n * Keeping it out of the IDE-orchestration layer is what stops tests that mock the\n * provider (but not `zx`) from shelling out to a real editor.\n */\nexport const launchCursor = async (workspacePath: string): Promise<void> => {\n await $`cursor ${workspacePath}`\n}\n", "import fs from 'node:fs/promises'\nimport path from 'node:path'\n\nimport { addFoldersToCursorWorkspace } from './add-folders-to-workspace'\nimport { removeFoldersFromCursorWorkspace } from './remove-folders-from-workspace'\n\ninterface ReconcileCursorWorkspaceFoldersArgs {\n workspacePath: string\n worktreeDir: string\n currentBranches: string[]\n}\n\ninterface ReconcileCursorWorkspaceFoldersResult {\n added: string[]\n removed: string[]\n}\n\ninterface WorkspaceFolderEntry {\n path: string\n name?: string\n}\n\ninterface WorkspaceFile {\n folders?: WorkspaceFolderEntry[]\n [key: string]: unknown\n}\n\n/**\n * Reconciles the configured Cursor workspace's `folders` array against the\n * actual set of release worktrees on disk:\n * - Adds any worktree folders that aren't already listed.\n * - Removes entries whose absolute path lives under `${worktreeDir}/release/`\n * but no longer corresponds to a current branch (drift from manual\n * `git worktree remove`, deleted branches, etc.).\n *\n * Non-worktree folder entries are left untouched.\n */\nexport const reconcileCursorWorkspaceFolders = async (\n args: ReconcileCursorWorkspaceFoldersArgs,\n): Promise<ReconcileCursorWorkspaceFoldersResult> => {\n const { workspacePath, worktreeDir, currentBranches } = args\n\n const workspaceDir = path.dirname(workspacePath)\n const releaseRoot = path.resolve(`${worktreeDir}/release`)\n\n const raw = await fs.readFile(workspacePath, 'utf-8')\n const parsed = JSON.parse(raw) as WorkspaceFile\n\n const existingFolders = parsed.folders ?? []\n\n const desiredAbsolutePaths = new Set(\n currentBranches.map((branch) => {\n return path.resolve(`${worktreeDir}/${branch}`)\n }),\n )\n\n const danglingFolderPaths: string[] = []\n\n for (const entry of existingFolders) {\n const entryAbsolutePath = path.resolve(workspaceDir, entry.path)\n\n const isReleaseShaped = entryAbsolutePath === releaseRoot || entryAbsolutePath.startsWith(`${releaseRoot}/`)\n\n if (isReleaseShaped && !desiredAbsolutePaths.has(entryAbsolutePath)) {\n danglingFolderPaths.push(entryAbsolutePath)\n }\n }\n\n let removed: string[] = []\n\n if (danglingFolderPaths.length > 0) {\n const result = await removeFoldersFromCursorWorkspace({\n workspacePath,\n folderPaths: danglingFolderPaths,\n })\n\n removed = result.removed\n }\n\n const desiredFolderPaths = currentBranches.map((branch) => {\n return `${worktreeDir}/${branch}`\n })\n\n const { added } =\n desiredFolderPaths.length > 0\n ? await addFoldersToCursorWorkspace({ workspacePath, folderPaths: desiredFolderPaths })\n : { added: [] as string[] }\n\n return { added, removed }\n}\n", "import fs from 'node:fs/promises'\nimport path from 'node:path'\n\ninterface RemoveFoldersFromCursorWorkspaceArgs {\n workspacePath: string\n folderPaths: string[]\n}\n\ninterface RemoveFoldersFromCursorWorkspaceResult {\n removed: string[]\n notFound: string[]\n}\n\ninterface WorkspaceFolderEntry {\n path: string\n name?: string\n}\n\ninterface WorkspaceFile {\n folders?: WorkspaceFolderEntry[]\n [key: string]: unknown\n}\n\n/**\n * Removes folders from a Cursor (`.code-workspace`) file's `folders` array. Entries\n * are matched by resolved absolute path, so relative and absolute entries pointing\n * at the same folder are both removed.\n */\nexport const removeFoldersFromCursorWorkspace = async (\n args: RemoveFoldersFromCursorWorkspaceArgs,\n): Promise<RemoveFoldersFromCursorWorkspaceResult> => {\n const { workspacePath, folderPaths } = args\n\n const workspaceDir = path.dirname(workspacePath)\n\n let raw: string\n\n try {\n raw = await fs.readFile(workspacePath, 'utf-8')\n } catch (error) {\n throw new Error(`Cursor workspace file not found at ${workspacePath}: ${(error as Error).message}`)\n }\n\n let parsed: WorkspaceFile\n\n try {\n parsed = JSON.parse(raw) as WorkspaceFile\n } catch (error) {\n throw new Error(\n `Failed to parse ${workspacePath} as JSON. Comments (JSONC) are not supported. ${(error as Error).message}`,\n )\n }\n\n const existingFolders = parsed.folders ?? []\n const targetAbsolutePaths = new Set(\n folderPaths.map((folderPath) => {\n return path.resolve(folderPath)\n }),\n )\n\n const removedAbsolutePaths = new Set<string>()\n\n const filteredFolders = existingFolders.filter((entry) => {\n const entryAbsolutePath = path.resolve(workspaceDir, entry.path)\n\n if (targetAbsolutePaths.has(entryAbsolutePath)) {\n removedAbsolutePaths.add(entryAbsolutePath)\n\n return false\n }\n\n return true\n })\n\n parsed.folders = filteredFolders\n\n await fs.writeFile(workspacePath, `${JSON.stringify(parsed, null, 2)}\\n`, 'utf-8')\n\n const removed: string[] = []\n const notFound: string[] = []\n\n for (const folderPath of folderPaths) {\n const absolutePath = path.resolve(folderPath)\n\n if (removedAbsolutePaths.has(absolutePath)) {\n removed.push(folderPath)\n } else {\n notFound.push(folderPath)\n }\n }\n\n return { removed, notFound }\n}\n", "import path from 'node:path'\n\n/**\n * Resolves the configured Cursor workspace path against the project root.\n * Absolute paths are returned unchanged.\n */\nexport const resolveCursorWorkspacePath = (configValue: string, projectRoot: string): string => {\n if (path.isAbsolute(configValue)) {\n return configValue\n }\n\n return path.resolve(projectRoot, configValue)\n}\n", "import { logger } from 'src/lib/logger'\n\nimport { launchCursor } from './launch-cursor'\nimport { reconcileCursorWorkspaceFolders } from './reconcile-workspace-folders'\nimport { resolveCursorWorkspacePath } from './resolve-workspace-path'\n\ninterface OpenCursorWorkspaceArgs {\n projectRoot: string\n worktreeDir: string\n currentBranches: string[]\n /**\n * When true, skip the `cursor <workspace>` relaunch if there are no release\n * worktrees (folder reconcile still runs to strip dangling entries). Lets\n * `worktrees-reload` avoid popping an empty Cursor window while keeping the\n * cold-start `worktrees-open` behaviour (relaunch unconditionally) intact.\n */\n skipRelaunchWhenEmpty: boolean\n /**\n * The Cursor entry's config, selected by the facade from the (possibly\n * multi-IDE) infra-kit config. Passed in rather than re-read here so this\n * opener acts on the exact entry the caller chose \u2014 essential once `ide` can\n * be an array of providers.\n */\n cursorConfig: { workspaceConfigPath: string }\n}\n\ninterface OpenCursorWorkspaceOutcome {\n ran: boolean\n added: number\n removed: number\n}\n\n/**\n * Reconciles the configured Cursor `.code-workspace` `folders` array against the\n * set of release worktrees on disk, then launches Cursor against it. Shared by\n * `worktrees-open` (cold-start restore) and `worktrees-reload` (close + reopen).\n *\n * No-ops (returns `ran: false`) when the Cursor entry has no `workspaceConfigPath`.\n * All failures are swallowed into a warning \u2014 opening Cursor is best-effort.\n */\nexport const openCursorWorkspace = async (args: OpenCursorWorkspaceArgs): Promise<OpenCursorWorkspaceOutcome> => {\n const { projectRoot, worktreeDir, currentBranches, skipRelaunchWhenEmpty, cursorConfig } = args\n\n if (!cursorConfig.workspaceConfigPath) {\n logger.warn('\u26A0\uFE0F Skipping Cursor: workspaceConfigPath is not set.')\n\n return { ran: false, added: 0, removed: 0 }\n }\n\n const workspacePath = resolveCursorWorkspacePath(cursorConfig.workspaceConfigPath, projectRoot)\n\n try {\n const { added, removed } = await reconcileCursorWorkspaceFolders({\n workspacePath,\n worktreeDir,\n currentBranches,\n })\n\n if (!(skipRelaunchWhenEmpty && currentBranches.length === 0)) {\n await launchCursor(workspacePath)\n }\n\n return { ran: true, added: added.length, removed: removed.length }\n } catch (error) {\n logger.warn({ error }, `\u26A0\uFE0F Failed to reconcile/open Cursor workspace at ${workspacePath}`)\n\n return { ran: false, added: 0, removed: 0 }\n }\n}\n", "import { $ } from 'zx'\n\ninterface AddFoldersToZedWorkspaceArgs {\n folderPaths: string[]\n}\n\ninterface AddFoldersToZedWorkspaceResult {\n added: string[]\n}\n\n/**\n * Adds folders to Zed's current workspace via `zed --add <path>` per folder.\n * This is the only legitimate use of `--add` (it targets the most-recent\n * workspace, so it is reserved for the incremental add-only path right after\n * `worktrees-add` creates new worktrees \u2014 never for the full cold-start open).\n *\n * Zed has no folder-remove CLI and no skip-if-present concept, so every folder\n * is reported as added (no `skipped` set, unlike the Cursor `.code-workspace`).\n */\nexport const addFoldersToZedWorkspace = async (\n args: AddFoldersToZedWorkspaceArgs,\n): Promise<AddFoldersToZedWorkspaceResult> => {\n const { folderPaths } = args\n\n for (const folderPath of folderPaths) {\n await $`zed --add ${folderPath}`\n }\n\n return { added: folderPaths }\n}\n", "import { $ } from 'zx'\n\nimport { logger } from 'src/lib/logger'\n\ninterface OpenZedWorkspaceArgs {\n projectRoot: string\n worktreeDir: string\n currentBranches: string[]\n /**\n * When true, skip launching Zed if there are no release worktrees. Lets\n * `worktrees-reload` avoid popping a bare Zed window while keeping the\n * cold-start `worktrees-open` behaviour (launch unconditionally) intact.\n */\n skipRelaunchWhenEmpty: boolean\n}\n\ninterface OpenZedWorkspaceOutcome {\n ran: boolean\n added: number\n removed: number\n}\n\n/**\n * Opens a single Zed workspace containing the project root plus every release\n * worktree, via one `zed <root> <wt...>` invocation (Zed realizes a multi-folder\n * workspace from multiple path arguments). Shared by `worktrees-open` (cold-start\n * restore) and `worktrees-reload` (relaunch).\n *\n * Zed has no portable workspace file and no folder-remove CLI, so there is\n * nothing to reconcile: `added` is the number of worktrees opened and `removed`\n * is always 0. All failures are swallowed into a warning \u2014 opening Zed is\n * best-effort, mirroring the Cursor integration.\n */\nexport const openZedWorkspace = async (args: OpenZedWorkspaceArgs): Promise<OpenZedWorkspaceOutcome> => {\n const { projectRoot, worktreeDir, currentBranches, skipRelaunchWhenEmpty } = args\n\n if (skipRelaunchWhenEmpty && currentBranches.length === 0) {\n return { ran: false, added: 0, removed: 0 }\n }\n\n const paths = [\n projectRoot,\n ...currentBranches.map((branch) => {\n return `${worktreeDir}/${branch}`\n }),\n ]\n\n try {\n await $`zed ${paths}`\n\n return { ran: true, added: currentBranches.length, removed: 0 }\n } catch (error) {\n logger.warn({ error }, '\u26A0\uFE0F Failed to open Zed workspace')\n\n return { ran: false, added: 0, removed: 0 }\n }\n}\n", "/**\n * Exhaustiveness guard for discriminated unions. Place in the `default` branch of\n * a `switch` over a union: once every case is handled the argument narrows to\n * `never`, so adding a new variant later turns this into a compile error.\n *\n * @example\n * switch (provider) {\n * case 'cursor': return openCursor()\n * case 'zed': return openZed()\n * default: return assertNever(provider) // compile error if a provider is unhandled\n * }\n */\nexport const assertNever = (value: never): never => {\n throw new Error(`Unexpected value: ${JSON.stringify(value)}`)\n}\n", "import { addFoldersToCursorWorkspace, launchCursor, resolveCursorWorkspacePath } from 'src/integrations/cursor'\nimport { addFoldersToZedWorkspace } from 'src/integrations/zed'\nimport { assertNever } from 'src/lib/assert-never'\nimport { getInfraKitConfig, resolveConfiguredIdes } from 'src/lib/infra-kit-config'\nimport { logger } from 'src/lib/logger'\n\nimport type { AddIdeWorktreeFoldersOutcome } from './types'\n\ninterface AddIdeWorktreeFoldersArgs {\n projectRoot: string\n worktreeDir: string\n branches: string[]\n}\n\n/**\n * Workspace-mode add (used by `worktrees-add`): append the given worktree folders\n * to every configured editor's workspace and open it. Returns one outcome per\n * configured provider (empty array when no IDE is configured), iterating\n * sequentially.\n *\n * Cursor appends to the `.code-workspace` `folders` array (reporting `skipped`\n * for already-present entries) then runs `cursor <workspace>`. Zed has no\n * workspace file, so it `zed --add`s each folder (`skipped` is always 0).\n */\nexport const addIdeWorktreeFolders = async (\n args: AddIdeWorktreeFoldersArgs,\n): Promise<AddIdeWorktreeFoldersOutcome[]> => {\n const { projectRoot, worktreeDir, branches } = args\n\n const config = await getInfraKitConfig()\n const ides = resolveConfiguredIdes(config)\n\n const folderPaths = branches.map((branch) => {\n return `${worktreeDir}/${branch}`\n })\n\n const outcomes: AddIdeWorktreeFoldersOutcome[] = []\n\n for (const ide of ides) {\n switch (ide.provider) {\n case 'cursor': {\n if (!ide.config.workspaceConfigPath) {\n logger.warn('\u26A0\uFE0F Skipping Cursor: ide.config.workspaceConfigPath is not set in infra-kit config')\n\n outcomes.push({ ran: false, provider: 'cursor', added: 0, skipped: 0 })\n break\n }\n\n const workspacePath = resolveCursorWorkspacePath(ide.config.workspaceConfigPath, projectRoot)\n\n const { added, skipped } = await addFoldersToCursorWorkspace({ workspacePath, folderPaths })\n\n const skippedSuffix = skipped.length > 0 ? ` (${skipped.length} already present)` : ''\n\n logger.info(`\u2705 Added ${added.length} folder(s) to ${workspacePath}${skippedSuffix}`)\n\n await launchCursor(workspacePath)\n\n outcomes.push({ ran: true, provider: 'cursor', added: added.length, skipped: skipped.length })\n break\n }\n case 'zed': {\n const { added } = await addFoldersToZedWorkspace({ folderPaths })\n\n logger.info(`\u2705 Added ${added.length} folder(s) to Zed workspace`)\n\n outcomes.push({ ran: true, provider: 'zed', added: added.length, skipped: 0 })\n break\n }\n default: {\n assertNever(ide)\n }\n }\n }\n\n return outcomes\n}\n", "import { openCursorWorkspace } from 'src/integrations/cursor'\nimport { openZedWorkspace } from 'src/integrations/zed'\nimport { assertNever } from 'src/lib/assert-never'\nimport { getInfraKitConfig, resolveConfiguredIdes } from 'src/lib/infra-kit-config'\n\nimport type { OpenIdeWorkspaceOutcome } from './types'\n\ninterface OpenIdeWorkspaceArgs {\n projectRoot: string\n worktreeDir: string\n currentBranches: string[]\n skipRelaunchWhenEmpty: boolean\n}\n\n/**\n * Provider-agnostic entry point for the cold-start / reload open: for every\n * configured editor, reconciles (or, for Zed, simply assembles) the workspace\n * against the release worktrees on disk and launches it. Returns one outcome per\n * configured provider (empty array when no IDE is configured). Iterates\n * sequentially \u2014 `worktrees-reload` already wraps this call in an outer\n * `Promise.all` with cmux, so a `Promise.all` here would compound editor-spawn\n * concurrency. Best-effort \u2014 every provider swallows failures into a warning.\n */\nexport const openIdeWorkspace = async (args: OpenIdeWorkspaceArgs): Promise<OpenIdeWorkspaceOutcome[]> => {\n const config = await getInfraKitConfig()\n const ides = resolveConfiguredIdes(config)\n\n const outcomes: OpenIdeWorkspaceOutcome[] = []\n\n for (const ide of ides) {\n switch (ide.provider) {\n case 'cursor': {\n const outcome = await openCursorWorkspace({ ...args, cursorConfig: ide.config })\n\n outcomes.push({ ...outcome, provider: 'cursor' })\n break\n }\n case 'zed': {\n const outcome = await openZedWorkspace(args)\n\n outcomes.push({ ...outcome, provider: 'zed' })\n break\n }\n default: {\n assertNever(ide)\n }\n }\n }\n\n return outcomes\n}\n", "import { assertNever } from 'src/lib/assert-never'\n\nimport type { IdeProvider } from './types'\n\n/**\n * Human-facing display name for an IDE provider, used in log lines. Falls back to\n * a generic \"IDE\" when no provider is configured.\n */\nexport const ideProviderLabel = (provider: IdeProvider | undefined): string => {\n switch (provider) {\n case 'cursor': {\n return 'Cursor'\n }\n case 'zed': {\n return 'Zed'\n }\n case undefined: {\n return 'IDE'\n }\n default: {\n return assertNever(provider)\n }\n }\n}\n", "import { removeFoldersFromCursorWorkspace, resolveCursorWorkspacePath } from 'src/integrations/cursor'\nimport { assertNever } from 'src/lib/assert-never'\nimport { getInfraKitConfig, resolveConfiguredIdes } from 'src/lib/infra-kit-config'\nimport { logger } from 'src/lib/logger'\n\nimport type { RemoveIdeWorktreeFoldersOutcome } from './types'\n\ninterface RemoveIdeWorktreeFoldersArgs {\n projectRoot: string\n worktreeDir: string\n branches: string[]\n}\n\n/**\n * Strip removed worktrees from every configured editor's workspace (used by\n * `worktrees-remove` and `worktrees-sync`). Returns one outcome per configured\n * provider (empty array when no IDE is configured or no worktrees were removed),\n * iterating sequentially.\n *\n * Cursor edits the `.code-workspace` `folders` array. Zed has no folder-remove\n * CLI, so it is a structural no-op (`supported: false`) with an info-level\n * message \u2014 never a warning, because nothing failed.\n */\nexport const removeIdeWorktreeFolders = async (\n args: RemoveIdeWorktreeFoldersArgs,\n): Promise<RemoveIdeWorktreeFoldersOutcome[]> => {\n const { projectRoot, worktreeDir, branches } = args\n\n if (branches.length === 0) {\n return []\n }\n\n const config = await getInfraKitConfig()\n const ides = resolveConfiguredIdes(config)\n\n const folderPaths = branches.map((branch) => {\n return `${worktreeDir}/${branch}`\n })\n\n const outcomes: RemoveIdeWorktreeFoldersOutcome[] = []\n\n for (const ide of ides) {\n switch (ide.provider) {\n case 'cursor': {\n if (!ide.config.workspaceConfigPath) {\n outcomes.push({ provider: 'cursor', supported: true, removed: [] })\n break\n }\n\n const workspacePath = resolveCursorWorkspacePath(ide.config.workspaceConfigPath, projectRoot)\n\n try {\n const { removed } = await removeFoldersFromCursorWorkspace({ workspacePath, folderPaths })\n\n if (removed.length > 0) {\n logger.info(`\u2705 Removed ${removed.length} folder(s) from ${workspacePath}`)\n }\n\n outcomes.push({ provider: 'cursor', supported: true, removed })\n } catch (error) {\n logger.warn({ error }, `\u26A0\uFE0F Failed to update Cursor workspace at ${workspacePath}`)\n\n outcomes.push({ provider: 'cursor', supported: true, removed: [] })\n }\n break\n }\n case 'zed': {\n logger.info('\u2139\uFE0F Zed has no folder-remove CLI; close removed worktree folders in Zed manually if needed.')\n\n outcomes.push({ provider: 'zed', supported: false, removed: [] })\n break\n }\n default: {\n assertNever(ide)\n }\n }\n }\n\n return outcomes\n}\n", "export type IdeProvider = 'cursor' | 'zed'\n\n/**\n * CLI-level open modes for `worktrees-add` (`--ide`). `workspace` adds each\n * created worktree to the configured editor's workspace and opens it (the only\n * attach style); `none` means \"don't open any editor\".\n */\nexport const IDE_MODES = ['workspace', 'none'] as const\nexport type IdeMode = (typeof IDE_MODES)[number]\n\n// Each facade returns one outcome PER configured provider (an array), so every\n// outcome is tagged with its `provider`.\nexport interface OpenIdeWorkspaceOutcome {\n ran: boolean\n provider: IdeProvider\n added: number\n removed: number\n}\n\nexport interface AddIdeWorktreeFoldersOutcome {\n ran: boolean\n provider: IdeProvider\n added: number\n skipped: number\n}\n\nexport interface RemoveIdeWorktreeFoldersOutcome {\n provider: IdeProvider\n /** False when the configured provider has no folder-remove capability (Zed). */\n supported: boolean\n removed: string[]\n}\n", "import { z } from 'zod'\n\nimport { getReleasePRsWithInfo } from 'src/integrations/gh'\nimport { getCurrentWorktrees } from 'src/lib/git-utils'\nimport { logger } from 'src/lib/logger'\nimport { displayLabel, formatJiraName, parseBranchName } from 'src/lib/release-id'\nimport { detectReleaseType, formatVersionLabel, getJiraDescriptions } from 'src/lib/release-utils'\nimport type { ReleaseType } from 'src/lib/release-utils'\nimport { defineMcpTool, textContent } from 'src/types'\n\ninterface WorktreeInfo {\n version: string\n type: ReleaseType\n description: string | null\n}\n\n/**\n * List all release git worktrees with version, type, and Jira description\n */\nexport const worktreesList = async () => {\n const currentWorktrees = await getCurrentWorktrees('release')\n\n if (currentWorktrees.length === 0) {\n logger.info('\u2139\uFE0F No active worktrees found')\n\n return {\n content: textContent(JSON.stringify({ worktrees: [], count: 0 }, null, 2)),\n structuredContent: { worktrees: [], count: 0 },\n }\n }\n\n const [releasePRsInfo, jiraDescriptions] = await Promise.all([getReleasePRsWithInfo(), getJiraDescriptions()])\n\n const releaseTypes = new Map<string, ReleaseType>(\n releasePRsInfo.map((pr) => {\n return [pr.branch, detectReleaseType(pr.title)]\n }),\n )\n\n // Skip worktrees whose branch does not parse as a release id (lenient source).\n const worktrees: WorktreeInfo[] = currentWorktrees.flatMap((branch) => {\n const id = parseBranchName(branch)\n\n if (!id) return []\n\n // Human label `1.2.3` | `<name>`; Jira-descriptions map is keyed by the\n // Jira version NAME (`v1.2.3` | `<name>`) \u2014 same split as formatBranchChoices.\n const version = displayLabel(id)\n const type = releaseTypes.get(branch) || 'regular'\n const description = jiraDescriptions.get(formatJiraName(id)) || null\n\n return [{ version, type, description }]\n })\n\n // Log formatted output\n const maxVersionLength = Math.max(\n ...worktrees.map((w) => {\n return w.version.length\n }),\n )\n\n const formattedLines = worktrees.map((worktree) => {\n const label = formatVersionLabel(worktree.version, worktree.type, maxVersionLength)\n\n if (worktree.description) {\n return `${label} ${worktree.description}`\n }\n\n return label\n })\n\n logger.info('\uD83C\uDF3F Active worktrees:')\n logger.info(`\\n${formattedLines.join('\\n')}\\n`)\n\n const structuredContent = {\n worktrees,\n count: worktrees.length,\n }\n\n return {\n content: textContent(JSON.stringify(structuredContent, null, 2)),\n structuredContent,\n }\n}\n\n// MCP Tool Registration\nexport const worktreesListMcpTool = defineMcpTool({\n name: 'worktrees-list',\n description:\n 'List existing release-branch worktrees with version, release type (regular / hotfix), and Jira fix-version description. Read-only.',\n inputSchema: {},\n outputSchema: {\n worktrees: z\n .array(\n z.object({\n version: z.string().describe('Release version'),\n type: z.enum(['regular', 'hotfix']).describe('Release type'),\n description: z.string().nullable().describe('Jira version description'),\n }),\n )\n .describe('List of all worktrees with details'),\n count: z.number().describe('Number of worktrees'),\n },\n handler: worktreesList,\n})\n", "import { z } from 'zod'\n\nimport {\n buildCmuxWorkspaceTitle,\n canonicalizeCmuxTitle,\n listCmuxWorkspaceTitles,\n openCmuxWorkspaceWithLayout,\n} from 'src/integrations/cmux'\nimport { ideProviderLabel, openIdeWorkspace } from 'src/integrations/ide'\nimport type { IdeProvider } from 'src/integrations/ide'\nimport { commandEcho } from 'src/lib/command-echo'\nimport { WORKTREES_DIR_SUFFIX } from 'src/lib/constants'\nimport { OperationError } from 'src/lib/errors/operation-error'\nimport { getCurrentWorktrees, getProjectRoot, getRepoName } from 'src/lib/git-utils'\nimport { logger } from 'src/lib/logger'\nimport { defineMcpTool, textContent } from 'src/types'\n\ninterface WorktreesOpenResult {\n openedCmux: string[]\n skippedCmux: string[]\n ideProviders: IdeProvider[]\n ideFoldersAdded: number\n ideFoldersRemoved: number\n}\n\n/**\n * Cold-start restore command: reconciles the configured editor workspace against\n * the set of release worktrees on disk, opens the editor against it, and ensures\n * one cmux workspace exists per worktree. Idempotent and additive \u2014 never removes\n * worktrees, never recreates running cmux workspaces.\n */\nexport const worktreesOpen = async () => {\n commandEcho.start('worktrees-open')\n\n try {\n const projectRoot = await getProjectRoot()\n const worktreeDir = `${projectRoot}${WORKTREES_DIR_SUFFIX}`\n const currentBranches = await getCurrentWorktrees('release')\n\n const ideOutcomes = await openIdeWorkspace({\n projectRoot,\n worktreeDir,\n currentBranches,\n skipRelaunchWhenEmpty: false,\n })\n const cmuxOutcome = await openCmux({ worktreeDir, currentBranches })\n\n const result: WorktreesOpenResult = {\n openedCmux: cmuxOutcome.opened,\n skippedCmux: cmuxOutcome.skipped,\n ideProviders: ideOutcomes\n .filter((outcome) => {\n return outcome.ran\n })\n .map((outcome) => {\n return outcome.provider\n }),\n ideFoldersAdded: ideOutcomes.reduce((sum, outcome) => {\n return sum + outcome.added\n }, 0),\n ideFoldersRemoved: ideOutcomes.reduce((sum, outcome) => {\n return sum + outcome.removed\n }, 0),\n }\n\n logResults(result, {\n ideRan: ideOutcomes.some((outcome) => {\n return outcome.ran\n }),\n cmuxRan: cmuxOutcome.ran,\n })\n\n commandEcho.print()\n\n return {\n content: textContent(JSON.stringify(result, null, 2)),\n structuredContent: { ...result },\n }\n } catch (error) {\n logger.error({ error }, '\u274C Error opening worktrees')\n throw new OperationError(error, {\n operation: 'open worktrees',\n remediation: \"run 'worktrees-list' to confirm the branches exist\",\n })\n }\n}\n\ninterface OpenCmuxArgs {\n worktreeDir: string\n currentBranches: string[]\n}\n\ninterface OpenCmuxOutcome {\n ran: boolean\n opened: string[]\n skipped: string[]\n}\n\nexport const openCmux = async (args: OpenCmuxArgs): Promise<OpenCmuxOutcome> => {\n const { worktreeDir, currentBranches } = args\n\n if (currentBranches.length === 0) {\n return { ran: true, opened: [], skipped: [] }\n }\n\n const repoName = await getRepoName()\n const existingTitles = await listCmuxWorkspaceTitles()\n\n const opened: string[] = []\n const skipped: string[] = []\n\n for (const branch of currentBranches) {\n const title = buildCmuxWorkspaceTitle({ repoName, branch })\n\n // existingTitles holds canonical keys; match the built title the same way so\n // dedup survives whitespace / cross-CLI-version title drift (no duplicates).\n if (existingTitles.has(canonicalizeCmuxTitle(title))) {\n skipped.push(title)\n continue\n }\n\n try {\n await openCmuxWorkspaceWithLayout({ cwd: `${worktreeDir}/${branch}`, title })\n opened.push(title)\n } catch (error) {\n logger.warn({ error, title }, `\u26A0\uFE0F Failed to open cmux workspace for ${branch}`)\n }\n }\n\n return { ran: true, opened, skipped }\n}\n\ninterface LogResultsContext {\n ideRan: boolean\n cmuxRan: boolean\n}\n\nconst logResults = (result: WorktreesOpenResult, context: LogResultsContext): void => {\n if (context.ideRan) {\n const ideLabels = result.ideProviders\n .map((provider) => {\n return ideProviderLabel(provider)\n })\n .join(', ')\n\n if (result.ideFoldersAdded > 0) {\n logger.info(`\u2705 Added ${result.ideFoldersAdded} folder(s) to ${ideLabels} workspace(s)`)\n }\n\n if (result.ideFoldersRemoved > 0) {\n logger.info(`\uD83E\uDDF9 Removed ${result.ideFoldersRemoved} dangling folder(s) from ${ideLabels} workspace(s)`)\n }\n }\n\n if (result.openedCmux.length > 0) {\n logger.info('\u2705 Opened cmux workspaces:')\n for (const title of result.openedCmux) {\n logger.info(title)\n }\n }\n\n if (result.skippedCmux.length > 0) {\n logger.info(`\u2139\uFE0F Skipped ${result.skippedCmux.length} cmux workspace(s) already open`)\n }\n\n if (\n !context.ideRan &&\n result.openedCmux.length === 0 &&\n result.skippedCmux.length === 0 &&\n result.ideFoldersAdded === 0 &&\n result.ideFoldersRemoved === 0\n ) {\n logger.info('\u2139\uFE0F Nothing to open')\n }\n}\n\n// MCP Tool Registration\nexport const worktreesOpenMcpTool = defineMcpTool({\n name: 'worktrees-open',\n description:\n 'Open every configured editor (Cursor and/or Zed) against its workspace and ensure a cmux workspace exists for each existing release worktree. Idempotent and additive \u2014 never removes worktrees, never recreates running cmux workspaces. Use after a cold start (editor + cmux closed). For stale-worktree cleanup, use worktrees-sync.',\n inputSchema: {},\n outputSchema: {\n openedCmux: z.array(z.string()).describe('Titles of cmux workspaces opened during this run'),\n skippedCmux: z.array(z.string()).describe('Titles of cmux workspaces that were already open'),\n ideProviders: z\n .array(z.string())\n .describe('Configured IDE providers that were opened (cursor | zed); empty if none configured'),\n ideFoldersAdded: z.number().describe('Total worktree folders added across all configured editor workspaces'),\n ideFoldersRemoved: z\n .number()\n .describe('Total dangling worktree folders removed across all configured editor workspaces'),\n },\n handler: worktreesOpen,\n})\n", "import { z } from 'zod'\n\nimport {\n buildCmuxWorkspaceTitle,\n canonicalizeCmuxTitle,\n closeCmuxWorkspaceByTitle,\n listCmuxWorkspaceTitles,\n openCmuxWorkspaceWithLayout,\n} from 'src/integrations/cmux'\nimport { ideProviderLabel, openIdeWorkspace } from 'src/integrations/ide'\nimport type { IdeProvider } from 'src/integrations/ide'\nimport { commandEcho } from 'src/lib/command-echo'\nimport { WORKTREES_DIR_SUFFIX } from 'src/lib/constants'\nimport { OperationError } from 'src/lib/errors/operation-error'\nimport { getCurrentWorktrees, getProjectRoot, getRepoName } from 'src/lib/git-utils'\nimport { logger } from 'src/lib/logger'\nimport { defineMcpTool, textContent } from 'src/types'\n\ninterface WorktreesReloadResult {\n closedCmux: string[]\n openedCmux: string[]\n ideProviders: IdeProvider[]\n ideFoldersAdded: number\n ideFoldersRemoved: number\n}\n\n/**\n * Reload command: closes every open cmux workspace for the release worktrees on\n * disk, then reopens the full set \u2014 cmux workspaces are recreated fresh and the\n * configured editor workspace is reconciled and relaunched. Unlike the additive\n * `worktrees-open`, this is disruptive: it tears down live cmux windows first.\n *\n * The editor has no per-window close primitive, so its \"reload\" is a reconcile +\n * relaunch of the configured workspace. Safe to run from any branch\n * (non-destructive to git \u2014 only cmux/editor view state is touched).\n */\nexport const worktreesReload = async () => {\n commandEcho.start('worktrees-reload')\n\n try {\n const projectRoot = await getProjectRoot()\n const worktreeDir = `${projectRoot}${WORKTREES_DIR_SUFFIX}`\n const currentBranches = await getCurrentWorktrees('release')\n const repoName = await getRepoName()\n\n // Phase 1 \u2014 close (cmux only; Cursor has no per-window close).\n const closedCmux = await closeCmux({ currentBranches, repoName })\n\n // Phase 2 \u2014 reopen. cmux and Cursor are independent surfaces, so reopen them\n // concurrently to shrink the window where the just-closed cmux workspaces are gone.\n const [ideOutcomes, { opened: openedCmux }] = await Promise.all([\n openIdeWorkspace({ projectRoot, worktreeDir, currentBranches, skipRelaunchWhenEmpty: true }),\n reopenCmux({ worktreeDir, currentBranches, repoName }),\n ])\n\n const result: WorktreesReloadResult = {\n closedCmux,\n openedCmux,\n ideProviders: ideOutcomes\n .filter((outcome) => {\n return outcome.ran\n })\n .map((outcome) => {\n return outcome.provider\n }),\n ideFoldersAdded: ideOutcomes.reduce((sum, outcome) => {\n return sum + outcome.added\n }, 0),\n ideFoldersRemoved: ideOutcomes.reduce((sum, outcome) => {\n return sum + outcome.removed\n }, 0),\n }\n\n logResults(result, {\n ideRan: ideOutcomes.some((outcome) => {\n return outcome.ran\n }),\n })\n\n commandEcho.print()\n\n return {\n content: textContent(JSON.stringify(result, null, 2)),\n structuredContent: { ...result },\n }\n } catch (error) {\n logger.error({ error }, '\u274C Error reloading worktrees')\n throw new OperationError(error, {\n operation: 'reload worktrees',\n remediation: \"run 'worktrees-list' to confirm the branches exist\",\n })\n }\n}\n\ninterface CloseCmuxArgs {\n currentBranches: string[]\n repoName: string\n}\n\n/**\n * Close the cmux workspace for each release worktree that is currently open.\n * Snapshots `listCmuxWorkspaceTitles()` up front purely so the returned list\n * reflects which workspaces were actually open (the close itself is best-effort\n * and per-title). Returns the titles a close was attempted for.\n */\nexport const closeCmux = async (args: CloseCmuxArgs): Promise<string[]> => {\n const { currentBranches, repoName } = args\n\n if (currentBranches.length === 0) {\n return []\n }\n\n const openBefore = await listCmuxWorkspaceTitles()\n\n const closed: string[] = []\n\n for (const branch of currentBranches) {\n const title = buildCmuxWorkspaceTitle({ repoName, branch })\n\n // openBefore holds canonical keys; match the built title the same way so a\n // workspace stored under a drifted title (whitespace / old v-prefix) resolves.\n if (!openBefore.has(canonicalizeCmuxTitle(title))) {\n continue\n }\n\n await closeCmuxWorkspaceByTitle(title)\n closed.push(title)\n }\n\n return closed\n}\n\ninterface ReopenCmuxArgs {\n worktreeDir: string\n currentBranches: string[]\n repoName: string\n}\n\ninterface ReopenCmuxOutcome {\n opened: string[]\n}\n\n/**\n * Recreate a cmux workspace for every release worktree on disk. Force-opens each\n * branch (no dedup against the live workspace list): reload has just awaited the\n * close of these workspaces, so it favours liveness \u2014 guaranteeing every branch\n * ends up open \u2014 over the additive dedup that `worktrees-open` relies on.\n */\nexport const reopenCmux = async (args: ReopenCmuxArgs): Promise<ReopenCmuxOutcome> => {\n const { worktreeDir, currentBranches, repoName } = args\n\n const opened: string[] = []\n\n for (const branch of currentBranches) {\n const title = buildCmuxWorkspaceTitle({ repoName, branch })\n\n try {\n await openCmuxWorkspaceWithLayout({ cwd: `${worktreeDir}/${branch}`, title })\n opened.push(title)\n } catch (error) {\n logger.warn({ error, title }, `\u26A0\uFE0F Failed to reopen cmux workspace for ${branch}`)\n }\n }\n\n return { opened }\n}\n\ninterface LogResultsContext {\n ideRan: boolean\n}\n\nconst logResults = (result: WorktreesReloadResult, context: LogResultsContext): void => {\n if (result.closedCmux.length > 0) {\n logger.info(`\uD83E\uDDF9 Closed ${result.closedCmux.length} cmux workspace(s)`)\n }\n\n if (context.ideRan) {\n const ideLabels = result.ideProviders\n .map((provider) => {\n return ideProviderLabel(provider)\n })\n .join(', ')\n\n if (result.ideFoldersAdded > 0) {\n logger.info(`\u2705 Added ${result.ideFoldersAdded} folder(s) to ${ideLabels} workspace(s)`)\n }\n\n if (result.ideFoldersRemoved > 0) {\n logger.info(`\uD83E\uDDF9 Removed ${result.ideFoldersRemoved} dangling folder(s) from ${ideLabels} workspace(s)`)\n }\n }\n\n if (result.openedCmux.length > 0) {\n logger.info('\u2705 Reopened cmux workspaces:')\n for (const title of result.openedCmux) {\n logger.info(title)\n }\n }\n\n if (\n !context.ideRan &&\n result.closedCmux.length === 0 &&\n result.openedCmux.length === 0 &&\n result.ideFoldersAdded === 0 &&\n result.ideFoldersRemoved === 0\n ) {\n logger.info('\u2139\uFE0F Nothing to reload')\n }\n}\n\n// MCP Tool Registration\nexport const worktreesReloadMcpTool = defineMcpTool({\n name: 'worktrees-reload',\n description:\n 'Close all open cmux workspaces for the current release worktrees, then reopen the full set. Disruptive \u2014 closes live cmux windows (unlike the additive worktrees-open). Every configured editor (Cursor and/or Zed) is reconciled + relaunched (no per-window close). Safe to run from any branch. Use to refresh stale windows after restarting cmux/the editor.',\n inputSchema: {},\n outputSchema: {\n closedCmux: z.array(z.string()).describe('Titles of cmux workspaces a close was attempted for (best-effort)'),\n openedCmux: z.array(z.string()).describe('Titles of cmux workspaces reopened during this run'),\n ideProviders: z\n .array(z.string())\n .describe('Configured IDE providers that were reloaded (cursor | zed); empty if none configured'),\n ideFoldersAdded: z.number().describe('Total worktree folders added across all configured editor workspaces'),\n ideFoldersRemoved: z\n .number()\n .describe('Total dangling worktree folders removed across all configured editor workspaces'),\n },\n handler: worktreesReload,\n})\n", "import checkbox from '@inquirer/checkbox'\nimport confirm from '@inquirer/confirm'\nimport process from 'node:process'\nimport { z } from 'zod'\n\nimport { getReleasePRsWithInfo } from 'src/integrations/gh'\nimport { removeIdeWorktreeFolders } from 'src/integrations/ide'\nimport { commandEcho } from 'src/lib/command-echo'\nimport { WORKTREES_DIR_SUFFIX } from 'src/lib/constants'\nimport { OperationError } from 'src/lib/errors/operation-error'\nimport { assertManagementContext } from 'src/lib/git-guard'\nimport { getCurrentWorktrees, getProjectRoot, getRepoName } from 'src/lib/git-utils'\nimport { logger } from 'src/lib/logger'\nimport { formatBranchName, parseReleaseRef } from 'src/lib/release-id'\nimport { detectReleaseType, formatBranchChoices, getJiraDescriptions, releaseBranchLabels } from 'src/lib/release-utils'\nimport type { ReleaseType } from 'src/lib/release-utils'\nimport { removeWorktrees } from 'src/lib/worktrees'\nimport { defineMcpTool, textContent } from 'src/types'\nimport type { RequiredConfirmedOptionArg } from 'src/types'\n\n// Constants\ninterface WorktreeManagementArgs extends RequiredConfirmedOptionArg {\n all?: boolean\n versions?: string\n}\n\n/**\n * Manage git worktrees for release branches\n * Creates worktrees for active release branches and removes unused ones\n */\nexport const worktreesRemove = async (options: WorktreeManagementArgs) => {\n const { confirmedCommand, all, versions } = options\n\n commandEcho.start('worktrees-remove')\n\n await assertManagementContext({ operation: 'remove worktrees', requiredBranch: 'dev' })\n\n try {\n const currentWorktrees = await getCurrentWorktrees('release')\n\n if (currentWorktrees.length === 0) {\n logger.info('\u2139\uFE0F No active worktrees to remove')\n\n commandEcho.print()\n\n return {\n content: textContent(JSON.stringify({ removedWorktrees: [], count: 0 }, null, 2)),\n structuredContent: { removedWorktrees: [], count: 0 },\n }\n }\n\n const projectRoot = await getProjectRoot()\n\n const worktreeDir = `${projectRoot}${WORKTREES_DIR_SUFFIX}`\n\n let selectedReleaseBranches: string[] = []\n\n if (all) {\n selectedReleaseBranches = currentWorktrees\n } else if (versions) {\n selectedReleaseBranches = versions.split(',').map((v) => {\n return formatBranchName(parseReleaseRef(v.trim()))\n })\n } else {\n commandEcho.setInteractive()\n\n const [descriptions, prInfo] = await Promise.all([getJiraDescriptions(), getReleasePRsWithInfo()])\n\n const releaseTypes = new Map<string, ReleaseType>(\n prInfo.map((pr) => {\n return [pr.branch, detectReleaseType(pr.title)]\n }),\n )\n\n selectedReleaseBranches = await checkbox({\n required: true,\n message: '\uD83C\uDF3F Select release branches',\n choices: formatBranchChoices({ branches: currentWorktrees, descriptions, types: releaseTypes }),\n })\n }\n\n // Track --all flag if all branches were selected (either via flag or interactively)\n const allSelected = selectedReleaseBranches.length === currentWorktrees.length\n\n if (allSelected) {\n commandEcho.addOption('--all', true)\n } else {\n commandEcho.addOption('--versions', releaseBranchLabels(selectedReleaseBranches))\n }\n\n // Ask for confirmation\n const answer = confirmedCommand\n ? true\n : await confirm({\n message: 'Are you sure you want to proceed with these worktree changes?',\n })\n\n if (!confirmedCommand) {\n commandEcho.setInteractive()\n }\n\n if (!answer) {\n logger.info('Operation cancelled. Exiting...')\n process.exit(0)\n }\n\n // Track --yes flag if confirmation was interactive (user confirmed)\n if (!confirmedCommand) {\n commandEcho.addOption('--yes', true)\n }\n\n const repoName = await getRepoName()\n\n const removedWorktrees = await removeWorktrees({\n branches: selectedReleaseBranches,\n worktreeDir,\n repoName,\n pruneFolder: allSelected,\n })\n\n await removeIdeWorktreeFolders({ projectRoot, worktreeDir, branches: removedWorktrees })\n\n logResults(removedWorktrees)\n\n commandEcho.print()\n\n const structuredContent = {\n removedWorktrees,\n count: removedWorktrees.length,\n }\n\n return {\n content: textContent(JSON.stringify(structuredContent, null, 2)),\n structuredContent,\n }\n } catch (error) {\n logger.error({ error }, '\u274C Error managing worktrees')\n throw new OperationError(error, {\n operation: 'remove worktrees',\n remediation: \"check 'git worktree list' for the path; uncommitted changes block removal\",\n })\n }\n}\n\n/**\n * Log the results of worktree management\n */\nconst logResults = (removed: string[]): void => {\n if (removed.length > 0) {\n logger.info('\u274C Removed worktrees:')\n for (const branch of removed) {\n logger.info(branch)\n }\n logger.info('')\n } else {\n logger.info('\u2139\uFE0F No unused worktrees to remove')\n }\n}\n\n// MCP Tool Registration\nexport const worktreesRemoveMcpTool = defineMcpTool({\n name: 'worktrees-remove',\n description:\n 'Remove local git worktrees for release branches. When everything is removed, also runs \"git worktree prune\" and deletes the worktrees directory. When invoked via MCP, pass either \"versions\" (comma-separated) or all=true \u2014 the branch picker is unreachable without a TTY, and the CLI confirmation is auto-skipped for MCP calls, so the caller is responsible for gating.',\n inputSchema: {\n all: z\n .boolean()\n .optional()\n .describe(\n 'Remove every existing worktree. Either \"all\" or \"versions\" must be provided for MCP calls (the interactive picker is unavailable without a TTY). Ignored if \"versions\" is provided.',\n ),\n versions: z\n .string()\n .optional()\n .describe(\n 'Comma-separated release versions or names to target (e.g. \"1.2.5, 1.2.6\" or \"checkout-redesign, 1.2.5\"). Either \"versions\" or all=true must be provided for MCP calls. Overrides \"all\" when set.',\n ),\n },\n outputSchema: {\n removedWorktrees: z.array(z.string()).describe('List of removed git worktree branches'),\n count: z.number().describe('Number of git worktrees removed'),\n },\n handler: worktreesRemove,\n})\n", "import confirm from '@inquirer/confirm'\nimport process from 'node:process'\nimport { z } from 'zod'\nimport { $ } from 'zx'\n\nimport { buildCmuxWorkspaceTitle, closeCmuxWorkspaceByTitle } from 'src/integrations/cmux'\nimport { getReleasePRs } from 'src/integrations/gh'\nimport { removeIdeWorktreeFolders } from 'src/integrations/ide'\nimport { commandEcho } from 'src/lib/command-echo'\nimport { WORKTREES_DIR_SUFFIX } from 'src/lib/constants'\nimport { OperationError } from 'src/lib/errors/operation-error'\nimport { assertManagementContext } from 'src/lib/git-guard'\nimport { getCurrentWorktrees, getProjectRoot, getRepoName } from 'src/lib/git-utils'\nimport { logger } from 'src/lib/logger'\nimport { isReleaseBranch } from 'src/lib/release-id'\nimport { defineMcpTool, textContent } from 'src/types'\nimport type { RequiredConfirmedOptionArg } from 'src/types'\n\ninterface WorktreeSyncArgs extends RequiredConfirmedOptionArg {}\n\n/**\n * Manage git worktrees for release branches.\n *\n * Creates worktrees for active release branches and removes unused ones\n */\nexport const worktreesSync = async (options: WorktreeSyncArgs) => {\n const { confirmedCommand } = options\n\n commandEcho.start('worktrees-sync')\n\n await assertManagementContext({ operation: 'sync worktrees', requiredBranch: 'dev' })\n\n try {\n const currentWorktrees = await getCurrentWorktrees('release')\n const projectRoot = await getProjectRoot()\n\n const worktreeDir = `${projectRoot}${WORKTREES_DIR_SUFFIX}`\n\n const releasePRsList = await getReleasePRs()\n\n // Ask for confirmation\n const answer = confirmedCommand\n ? true\n : await confirm({\n message: 'Are you sure you want to proceed with these worktree changes?',\n })\n\n if (!confirmedCommand) {\n commandEcho.setInteractive()\n }\n\n if (!answer) {\n logger.info('Operation cancelled. Exiting...')\n process.exit(0)\n }\n\n // Track --yes flag if confirmation was interactive (user confirmed)\n if (!confirmedCommand) {\n commandEcho.addOption('--yes', true)\n }\n\n const { branchesToRemove } = categorizeWorktrees({\n releasePRsList,\n currentWorktrees,\n })\n\n const repoName = await getRepoName()\n\n const removedWorktrees = await removeWorktrees({\n branches: branchesToRemove,\n worktreeDir,\n repoName,\n })\n\n await removeIdeWorktreeFolders({ projectRoot, worktreeDir, branches: removedWorktrees })\n\n logResults(removedWorktrees)\n\n commandEcho.print()\n\n const structuredContent = {\n removedWorktrees,\n count: removedWorktrees.length,\n }\n\n return {\n content: textContent(JSON.stringify(structuredContent, null, 2)),\n structuredContent,\n }\n } catch (error) {\n logger.error({ error }, '\u274C Error managing worktrees')\n throw new OperationError(error, {\n operation: 'sync worktrees with remote',\n remediation: \"ensure 'gh auth status' is ok and you can reach origin\",\n })\n }\n}\n\ninterface CategorizeWorktreesArgs {\n releasePRsList: string[]\n currentWorktrees: string[]\n}\n\n/**\n * Categorize worktrees into those that need to be created or removed\n */\nconst categorizeWorktrees = (args: CategorizeWorktreesArgs): { branchesToRemove: string[] } => {\n const { releasePRsList, currentWorktrees } = args\n\n const currentBranchNames = currentWorktrees.filter((branch) => {\n return isReleaseBranch(branch)\n })\n\n const branchesToRemove = currentBranchNames.filter((branch) => {\n return !releasePRsList.includes(branch)\n })\n\n return { branchesToRemove }\n}\n\ninterface RemoveWorktreesArgs {\n branches: string[]\n worktreeDir: string\n repoName: string\n}\n\n/**\n * Remove worktrees for the specified branches and close their cmux workspaces\n */\nconst removeWorktrees = async (args: RemoveWorktreesArgs): Promise<string[]> => {\n const { branches, worktreeDir, repoName } = args\n\n const removed: string[] = []\n\n for (const branch of branches) {\n try {\n const worktreePath = `${worktreeDir}/${branch}`\n\n const title = buildCmuxWorkspaceTitle({ repoName, branch })\n\n await closeCmuxWorkspaceByTitle(title)\n\n await $`git worktree remove ${worktreePath}`\n removed.push(branch)\n } catch (error) {\n const err = new OperationError(error, {\n operation: `remove stale worktree for ${branch}`,\n remediation: 'inspect the worktree dir manually; rerun with the branch checked out elsewhere',\n })\n\n logger.error({ error, branch, msg: err.message })\n }\n }\n\n return removed\n}\n\n/**\n * Log the results of worktree management\n */\nconst logResults = (removed: string[]): void => {\n if (removed.length > 0) {\n logger.info('\u274C Removed worktrees:')\n for (const branch of removed) {\n logger.info(branch)\n }\n logger.info('')\n } else {\n logger.info('\u2139\uFE0F No unused worktrees to remove')\n }\n}\n\n// MCP Tool Registration\nexport const worktreesSyncMcpTool = defineMcpTool({\n name: 'worktrees-sync',\n description:\n 'Remove worktrees whose release PR is no longer open (stale cleanup). Only removes \u2014 never creates; use worktrees-add to create worktrees for new releases. The CLI confirmation is auto-skipped for MCP calls, so the caller is responsible for gating.',\n inputSchema: {},\n outputSchema: {\n removedWorktrees: z.array(z.string()).describe('List of removed worktree branches'),\n count: z.number().describe('Number of worktrees removed during sync'),\n },\n handler: worktreesSync,\n})\n"],
5
- "mappings": "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",
6
- "names": ["select", "Separator", "Command", "process", "path", "process", "z", "path", "$", "VERSION_RE", "BRANCH_SEMVER_RE", "KEBAB_RE", "RELEASE_BRANCH_PREFIX", "VERSION_BRANCH_PREFIX", "REFS_HEADS_PREFIX", "NEXT_TOKEN", "RESERVED_NAMES", "InvalidReleaseNameError", "message", "InvalidReleaseRefError", "stripRefsHeads", "input", "REFS_HEADS_PREFIX", "makeVersion", "major", "minor", "patch", "validateName", "name", "KEBAB_RE", "parseBranchName", "branch", "stripped", "RELEASE_BRANCH_PREFIX", "VERSION_BRANCH_PREFIX", "semverPart", "match", "BRANCH_SEMVER_RE", "namePart", "parseReleaseRef", "trimmed", "parsed", "versionMatch", "VERSION_RE", "NEXT_TOKEN", "err", "reason", "formatBranchName", "id", "formatPrTitle", "type", "prefix", "formatRcTitle", "formatJiraName", "displayLabel", "isReleaseBranch", "toTime", "value", "time", "compareReleaseIds", "a", "b", "dates", "timeA", "timeB", "getCurrentWorktrees", "type", "worktreeLines", "$", "worktreePredicateMap", "releaseWorktreePredicate", "featureWorktreePredicate", "branch", "parseWorktreeBranch", "line", "trimmed", "open", "isReleaseBranch", "getProjectRoot", "getCurrentBranch", "isWorkingTreeClean", "isInsideLinkedWorktree", "cwd", "gitDirResult", "commonDirResult", "gitDir", "commonDir", "path", "getRepoName", "projectRoot", "deleteLocalBranch", "deleteRemoteBranch", "process", "pino", "pretty", "initLoggerCLI", "logLevel", "process", "ignoreFields", "pino", "pretty", "logger", "DEFAULT_RULES", "ROOT_DEFAULT_RULES", "resolvePackageConfig", "config", "baseline", "z", "packageConfigSchema", "fs", "pathExists", "target", "path", "fs", "path", "pathToFileURL", "z", "PACKAGE_CONFIG_FILE", "readPackageJson", "packageDir", "raw", "fs", "path", "loadPackageConfig", "baseline", "DEFAULT_RULES", "configPath", "pathExists", "stat", "rawExport", "pathToFileURL", "resolvedExport", "parsed", "packageConfigSchema", "z", "resolvePackageConfig", "fs", "path", "yaml", "WORKSPACE_FILE", "listChildDirs", "dir", "fs", "entry", "path", "expandSegment", "dirs", "segment", "next", "candidate", "pathExists", "expandGlob", "projectRoot", "pattern", "discoverPackages", "raw", "patterns", "yaml", "found", "checkConfig", "packageDir", "baseline", "DEFAULT_RULES", "rules", "loadPackageConfig", "PACKAGE_CONFIG_FILE", "err", "fs", "path", "checkFiles", "packageDir", "requiredFiles", "file", "stat", "checkScripts", "scripts", "requiredScripts", "script", "value", "fs", "path", "TURBO_FILE", "checkTurbo", "packageDir", "requiredTasks", "parsed", "raw", "err", "tasks", "task", "defined", "validatePackage", "packageDir", "baseline", "DEFAULT_RULES", "pkgJson", "readPackageJson", "packageName", "path", "configCheck", "rules", "checkConfig", "checks", "checkScripts", "checkFiles", "checkTurbo", "passed", "check", "textContent", "text", "defineMcpTool", "tool", "findPackageRoot", "start", "current", "path", "pathExists", "resolveTargets", "options", "getProjectRoot", "ROOT_DEFAULT_RULES", "discoverPackages", "dir", "process", "logResult", "result", "header", "logger", "check", "icon", "audit", "targets", "results", "target", "validatePackage", "allPassed", "structuredContent", "textContent", "auditInputSchema", "z", "auditOutputSchema", "auditMcpTool", "defineMcpTool", "params", "fs", "os", "path", "process", "$", "fs", "os", "path", "z", "INFRA_KIT_CONFIG_FILE", "USER_CONFIG_DIR_NAME", "USER_GLOBAL_CONFIG_FILE", "USER_PROJECTS_DIR", "dopplerEnvManagementSchema", "z", "envManagementSchema", "cursorIdeConfigSchema", "cursorIdeSchema", "zedIdeConfigSchema", "zedIdeSchema", "ideSchema", "idesSchema", "jiraTaskManagerSchema", "taskManagerSchema", "worktreesConfigSchema", "infraKitConfigObject", "infraKitConfigSchema", "cfg", "ctx", "seen", "entry", "infraKitOverrideConfigSchema", "resolveConfiguredIdes", "config", "ide", "cached", "getInfraKitConfigPaths", "projectRoot", "getProjectRoot", "projectName", "getRepoName", "userConfigDir", "path", "os", "getInfraKitConfig", "paths", "mainStat", "fs", "legacyYmlPath", "statIfExists", "userGlobalStat", "userProjectStat", "mtimes", "shallowEqual", "layers", "merged", "layer", "data", "loadLayer", "finalResult", "resetInfraKitConfigCache", "filePath", "readIfExists", "a", "b", "keys", "k", "raw", "parsedRaw", "err", "result", "fileExists", "filePath", "fs", "tildify", "home", "os", "configPath", "paths", "getInfraKitConfigPaths", "rows", "row", "logger", "marker", "structuredContent", "r", "configEdit", "editor", "process", "path", "examplePath", "exampleSiblingPath", "buildUserProjectExample", "$", "resetInfraKitConfigCache", "jsonPath", "projectName", "fs", "os", "path", "z", "$", "fs", "path", "hasManagedBlock", "content", "startMarker", "endMarker", "startIdx", "endIdx", "removeManagedBlock", "before", "after", "buildManagedBlock", "startMarker", "body", "endMarker", "upsertManagedBlock", "content", "placement", "block", "present", "hasManagedBlock", "startIdx", "endIdx", "base", "removeManagedBlock", "package_default", "AGENTS_MARKER_START", "AGENTS_MARKER_END", "AGENTS_VERSION_PREFIX", "AGENTS_IMPORT_START", "AGENTS_IMPORT_END", "AGENTS_FILE", "CLAUDE_FILE", "CURSOR_RULE_REL", "path", "CURSOR_FRONTMATTER", "buildVersionLine", "version", "buildAgentsBody", "assertNotSymlink", "filePath", "fs", "writeManaged", "nextContent", "existed", "stamp", "readOr", "fallback", "assertBlockPresent", "start", "end", "content", "hasManagedBlock", "writeAgentFiles", "mainConfigPath", "getInfraKitConfigPaths", "logger", "root", "package_default", "body", "agentsPath", "claudePath", "cursorPath", "agentsContent", "upsertManagedBlock", "claudeContent", "cursorContent", "written", "file", "fs", "os", "path", "fs", "os", "path", "yaml", "z", "tildify", "filePath", "home", "os", "fileExists", "fs", "legacyYmlPath", "jsonPath", "migrateLegacyConfig", "paths", "getInfraKitConfigPaths", "layers", "infraKitConfigSchema", "infraKitOverrideConfigSchema", "migrated", "layer", "ymlExists", "jsonExists", "logger", "raw", "parsed", "yaml", "result", "z", "path", "err", "resetInfraKitConfigCache", "stripLegacyIdeMode", "ide", "changed", "stripEntry", "entry", "config", "restConfig", "key", "nextIde", "normalizeLegacyIdeStructures", "jsonPaths", "normalized", "MARKER_START", "MARKER_END", "LEGACY_PAIRED", "LEGACY_SINGLE", "USER_GLOBAL_CONFIG_STUB", "USER_GLOBAL_CONFIG_EXAMPLE", "init", "zshrcPath", "path", "os", "existing", "fs", "removeExistingBlock", "updated", "upsertManagedBlock", "buildShellBody", "logger", "migrateLegacyConfig", "normalizeLegacyIdeStructures", "seedUserGlobalConfig", "writeAgentFiles", "userConfigDir", "userConfigPath", "userConfigExamplePath", "isBlockLine", "line", "content", "result", "removeManagedBlock", "start", "end", "legacyResult", "legacyIdx", "before", "afterLines", "i", "remaining", "runCmd", "buildShellBlock", "checkCommand", "name", "command", "successMsg", "failMsg", "$", "checkZshrcInitialized", "zshrcPath", "path", "os", "fs", "content", "startIdx", "MARKER_START", "endIdx", "MARKER_END", "installedBlock", "expectedBlock", "buildShellBlock", "checkPnpmWorkspaceVirtualStore", "root", "getProjectRoot", "yamlPath", "err", "checkInfraKitConfigValid", "resetInfraKitConfigCache", "getInfraKitConfig", "checkUserOverridePath", "paths", "getInfraKitConfigPaths", "home", "display", "suffix", "IDE_PROBE_META", "probeIde", "provider", "meta", "checkIdeInstalled", "providers", "config", "resolveConfiguredIdes", "ide", "probes", "missing", "probe", "RTK_REQUIRED_INDEXES", "checkRtkConfigured", "statusLines", "l", "failed", "idx", "line", "checkAgentFiles", "mainConfigPath", "blockPresent", "relPath", "start", "end", "filePath", "hasManagedBlock", "AGENTS_MARKER_START", "AGENTS_MARKER_END", "AGENTS_IMPORT_START", "AGENTS_IMPORT_END", "entry", "doctor", "checks", "logger", "check", "icon", "structuredContent", "c", "textContent", "doctorMcpTool", "defineMcpTool", "z", "fs", "path", "process", "z", "fs", "os", "path", "process", "ENV_LOAD_FILE", "ENV_CLEAR_FILE", "INFRA_KIT_SESSION_VAR", "INFRA_KIT_ENV_CONFIG_VAR", "INFRA_KIT_ENV_PROJECT_VAR", "INFRA_KIT_ENV_LOADED_AT_VAR", "ENV_VAR_LINE_PATTERN", "parseVarNamesFromEnvFile", "filePath", "content", "names", "line", "match", "getCacheRoot", "xdg", "base", "getSessionCacheDir", "session", "atomicWriteFileSync", "mode", "tmpPath", "error", "WORKTREES_DIR_SUFFIX", "envClear", "cacheDir", "getSessionCacheDir", "envLoadPath", "path", "ENV_LOAD_FILE", "fs", "varNames", "parseVarNamesFromEnvFile", "unsetLines", "v", "INFRA_KIT_ENV_CONFIG_VAR", "INFRA_KIT_ENV_PROJECT_VAR", "INFRA_KIT_ENV_LOADED_AT_VAR", "clearFilePath", "ENV_CLEAR_FILE", "atomicWriteFileSync", "process", "structuredContent", "textContent", "envClearMcpTool", "defineMcpTool", "z", "z", "getDopplerProject", "envManagement", "getInfraKitConfig", "envList", "project", "getDopplerProject", "environments", "getInfraKitConfig", "logger", "env", "structuredContent", "textContent", "envListMcpTool", "defineMcpTool", "z", "select", "Buffer", "fs", "path", "process", "z", "$", "$", "validateDopplerCliAndAuth", "error", "createCommandEcho", "commandName", "options", "isInteractive", "name", "flag", "value", "formattedOptions", "opt", "logger", "commandEcho", "envLoad", "args", "validateDopplerCliAndAuth", "config", "commandEcho", "selectedConfig", "environments", "getInfraKitConfig", "select", "env", "process", "project", "getDopplerProject", "envContent", "downloadDopplerSecrets", "assertValidEnvContent", "loadedAt", "envFileLines", "INFRA_KIT_ENV_CONFIG_VAR", "shellSingleQuote", "INFRA_KIT_ENV_PROJECT_VAR", "INFRA_KIT_ENV_LOADED_AT_VAR", "cacheDir", "getSessionCacheDir", "envFilePath", "path", "ENV_LOAD_FILE", "fs", "atomicWriteFileSync", "varCount", "countEnvVarLines", "structuredContent", "textContent", "DOPPLER_MAX_OUTPUT_BYTES", "DOPPLER_DOWNLOAD_TIMEOUT_MS", "prevQuiet", "$", "result", "assertDopplerOutputSize", "stdout", "bytes", "Buffer", "content", "line", "ENV_VAR_LINE_PATTERN", "SHELL_DIRECTIVE_LINES", "value", "trimmed", "envLoadMcpTool", "defineMcpTool", "z", "path", "process", "z", "envStatus", "validateDopplerCliAndAuth", "logger", "cacheDir", "getSessionCacheDir", "sessionId", "process", "INFRA_KIT_SESSION_VAR", "envLoadPath", "path", "ENV_LOAD_FILE", "sessionLoadedCount", "sessionTotalCount", "sessionConfig", "INFRA_KIT_ENV_CONFIG_VAR", "sessionProject", "INFRA_KIT_ENV_PROJECT_VAR", "sessionLoadedAt", "INFRA_KIT_ENV_LOADED_AT_VAR", "varNames", "parseVarNamesFromEnvFile", "v", "loadedAtDisplay", "missing", "structuredContent", "textContent", "envStatusMcpTool", "defineMcpTool", "z", "checkbox", "confirm", "process", "z", "$", "$", "process", "$", "$", "process", "createJiraVersion", "params", "config", "baseUrl", "token", "email", "projectId", "requestBody", "url", "credentials", "response", "errorText", "logger", "error", "getProjectVersions", "findVersionByName", "versionName", "v", "updateJiraVersion", "deliverJiraRelease", "version", "loadJiraConfig", "process", "projectIdStr", "missingVars", "errorMessage", "loadJiraConfigOptional", "extractStderr", "cause", "stderr", "buildMessage", "ctx", "parts", "OperationError", "DEV_REF", "getBaseBranch", "type", "prepareGitForRelease", "baseBranch", "$", "createSingleRelease", "args", "id", "jiraConfig", "description", "versionName", "formatJiraName", "result", "createJiraVersion", "jiraVersionUrl", "releaseInfo", "createReleaseBranch", "displayLabel", "getJiraDescriptions", "descriptions", "loadJiraConfigOptional", "versions", "getProjectVersions", "version", "formatVersionLabel", "maxVersionLength", "padding", "tag", "detectReleaseType", "title", "parseBranchChoices", "branches", "branch", "parseBranchName", "resolveReleaseBranch", "versionArg", "formatBranchName", "parseReleaseRef", "error", "OperationError", "releaseLabelFromBranch", "releaseBranchLabels", "formatBranchChoices", "types", "parsed", "maxLen", "p", "label", "desc", "name", "sortReleasePRs", "prs", "pr", "parseBranchName", "entry", "a", "b", "compareReleaseIds", "fetchAllReleasePRs", "releasePRs", "$", "hotfixPRs", "all", "seen", "getReleasePRs", "logger", "process", "error", "getReleasePRsWithInfo", "updateReleasePRBody", "args", "branch", "body", "createReleaseBranch", "id", "jiraVersionUrl", "type", "description", "prTitle", "formatPrTitle", "baseBranch", "getBaseBranch", "branchName", "formatBranchName", "prLink", "assertManagementContext", "args", "operation", "requiredBranch", "isInsideLinkedWorktree", "OperationError", "currentBranch", "getCurrentBranch", "isWorkingTreeClean", "ghMergeDev", "args", "all", "confirmedCommand", "commandEcho", "assertManagementContext", "releasePRsList", "getReleasePRsWithInfo", "pr", "detectReleaseType", "logger", "textContent", "selectedReleaseBranches", "descriptions", "getJiraDescriptions", "checkbox", "formatBranchChoices", "releaseBranchLabels", "answer", "confirm", "process", "$", "failedBranches", "branch", "mergeDev", "structuredContent", "error", "err", "OperationError", "ghMergeDevMcpTool", "defineMcpTool", "z", "confirm", "select", "process", "z", "$", "readTrimmedString", "value", "max", "formatZxError", "error", "rec", "fields", "exitCode", "stderr", "stdout", "$", "V_SEMVER_TOKEN_RE", "canonicalizeCmuxTitle", "raw", "$", "closeCmuxWorkspaceByTitle", "title", "listOutput", "$", "ref", "findWorkspaceRefByTitle", "error", "logger", "output", "target", "canonicalizeCmuxTitle", "rawLine", "match", "lineTitle", "$", "listCmuxWorkspaceTitles", "output", "$", "titles", "rawLine", "match", "title", "canonicalizeCmuxTitle", "error", "logger", "$", "openCmuxWorkspaceWithLayout", "args", "cwd", "title", "newWorkspaceOutput", "workspaceRef", "parseWorkspaceRef", "surfacesOutput", "leftTopRef", "parseFirstSurfaceRef", "output", "match", "buildCmuxWorkspaceTitle", "args", "repoName", "branch", "id", "parseBranchName", "label", "displayLabel", "removeWorktrees", "args", "branches", "worktreeDir", "repoName", "pruneFolder", "results", "branch", "worktreePath", "title", "buildCmuxWorkspaceTitle", "closeCmuxWorkspaceByTitle", "$", "removed", "index", "result", "err", "OperationError", "logger", "groupDirs", "groupDir", "runStep", "operation", "remediation", "fn", "error", "logger", "formatZxError", "OperationError", "fetchPRByHead", "head", "result", "$", "fetchMergedRcPRForVersion", "id", "expectedTitle", "formatRcTitle", "pr", "fetchOpenDevToMainPR", "resolveTargetFromVersion", "version", "selectedReleaseBranch", "resolveReleaseBranch", "resolveTargetInteractively", "releasePRsInfo", "getReleasePRsWithInfo", "branches", "releaseTypes", "detectReleaseType", "commandEcho", "descriptions", "getJiraDescriptions", "select", "formatBranchChoices", "prInfo", "removeReleaseWorktreeIfPresent", "releaseBranch", "getCurrentWorktrees", "projectRoot", "repoName", "getProjectRoot", "getRepoName", "worktreeDir", "WORKTREES_DIR_SUFFIX", "removeWorktrees", "mergeReleasePR", "args", "releaseType", "mergeTarget", "releasePr", "resolveRcPRNumber", "selectedLabel", "displayLabel", "existingOpen", "rcNumber", "created", "ensureRcPRMerged", "dispatchDeployWorkflow", "syncMainIntoDev", "removeDeliveredReleaseBranch", "branch", "deleteLocalBranch", "deleteRemoteBranch", "deliverJiraReleaseSafely", "jiraConfig", "loadJiraConfigOptional", "versionName", "formatJiraName", "deliverJiraRelease", "ghReleaseDeliver", "confirmedCommand", "assertManagementContext", "releasePrTitle", "releaseId", "parseBranchName", "selectedVersion", "answer", "confirm", "process", "structuredContent", "textContent", "ghReleaseDeliverMcpTool", "defineMcpTool", "z", "select", "z", "$", "ghReleaseDeployAll", "args", "version", "env", "skipTerraform", "commandEcho", "selectedReleaseBranch", "resolveReleaseBranch", "releasePRsInfo", "getReleasePRsWithInfo", "branches", "pr", "releaseTypes", "detectReleaseType", "descriptions", "getJiraDescriptions", "select", "formatBranchChoices", "selectedVersion", "releaseLabelFromBranch", "environments", "getInfraKitConfig", "selectedEnv", "OperationError", "shouldSkipTerraform", "$", "logger", "structuredContent", "textContent", "error", "ghReleaseDeployAllMcpTool", "defineMcpTool", "z", "checkbox", "select", "fs", "resolve", "yaml", "z", "$", "ghReleaseDeploySelected", "args", "version", "env", "services", "skipTerraform", "commandEcho", "selectedReleaseBranch", "resolveReleaseBranch", "releasePRsInfo", "getReleasePRsWithInfo", "branches", "pr", "releaseTypes", "detectReleaseType", "descriptions", "getJiraDescriptions", "select", "formatBranchChoices", "selectedVersion", "releaseLabelFromBranch", "environments", "getInfraKitConfig", "selectedEnv", "OperationError", "availableServices", "parseServicesFromWorkflow", "selectedServices", "checkbox", "svc", "invalidServices", "shouldSkipTerraform", "$", "serviceFlags", "logger", "structuredContent", "textContent", "error", "projectRoot", "getProjectRoot", "workflowPath", "resolve", "content", "fs", "inputs", "yaml", "key", "value", "ghReleaseDeploySelectedMcpTool", "defineMcpTool", "z", "z", "ghReleaseList", "releases", "getReleasePRsWithInfo", "pr", "id", "parseBranchName", "displayLabel", "formatJiraName", "detectReleaseType", "jiraDescriptions", "getJiraDescriptions", "maxVersionLength", "r", "formattedLines", "release", "label", "formatVersionLabel", "description", "logger", "structuredContent", "textContent", "ghReleaseListMcpTool", "defineMcpTool", "z", "confirm", "select", "process", "z", "question", "$", "parseVersion", "versionStr", "sortVersions", "versions", "a", "b", "majA", "minA", "patchA", "majB", "minB", "patchB", "NEXT_TOKEN", "VERSION_RE", "stripBranchPrefix", "raw", "tryParse", "cleaned", "match", "semverKey", "v", "collectKnownVersions", "sources", "all", "parsed", "seen", "key", "sortVersions", "s", "parseVersion", "NoPriorVersionsError", "computeNextVersion", "known", "type", "max", "major", "minor", "highestPatchOnMinor", "acc", "isNextToken", "token", "isReleaseType", "value", "isNamedReleaseInput", "input", "parseReleaseSpec", "spec", "firstColon", "description", "rest", "secondColon", "typeRaw", "typeLower", "entry", "formatReleaseSpec", "withDescription", "base", "resolveNamedInput", "name", "validateName", "resolveReleaseEntries", "entries", "running", "trimmed", "next", "parseReleaseRef", "explicit", "hasNextToken", "e", "extractVersionBranches", "lsRemoteStdout", "line", "tab", "parseBranchName", "id", "parseRemoteRefs", "previousQuiet", "$", "result", "fetchJiraVersionNames", "config", "loadJiraConfigOptional", "getProjectVersions", "v", "loadExistingVersions", "branchesResult", "jiraResult", "logger", "collectKnownVersions", "VERSION_PROMPT_HINT", "trySuggestNext", "known", "type", "computeNextVersion", "err", "NoPriorVersionsError", "resolveOrExit", "entries", "resolveReleaseEntries", "OperationError", "InvalidReleaseNameError", "promptForVersionInput", "running", "suggestion", "defaultHint", "versionAnswer", "question", "versionInput", "logger", "process", "promptForNameInput", "name", "validateName", "reason", "promptForReleasesInteractive", "ensureKnown", "commandEcho", "baseKnown", "ensureRunning", "addAnother", "ordinal", "kind", "select", "resolved", "parseVersion", "description", "confirm", "formatReleaseSummary", "entry", "parts", "echoReleases", "formatReleaseSpec", "collectEntries", "inputReleases", "hasNextToken", "interactive", "assertHomogeneousReleaseType", "confirmReleases", "confirmedCommand", "summary", "answer", "executeOne", "args", "jiraConfig", "label", "displayLabel", "prTitleLabel", "prepareGitForRelease", "result", "createSingleRelease", "error", "logFinalSummary", "total", "successCount", "failureCount", "releaseCreate", "loadJiraConfig", "loadExistingVersions", "assertManagementContext", "getBaseBranch", "created", "failed", "failure", "structuredContent", "r", "textContent", "releaseCreateMcpTool", "defineMcpTool", "z", "confirm", "select", "process", "z", "question", "buildJiraVersionUrl", "jiraConfig", "version", "buildPRBody", "jiraVersionUrl", "description", "pickReleaseBranch", "releasePRsInfo", "getReleasePRsWithInfo", "branches", "pr", "types", "detectReleaseType", "descriptions", "getJiraDescriptions", "branch", "select", "formatBranchChoices", "verifyReleasePRExists", "selectedBranch", "prInfo", "OperationError", "promptDescription", "current", "hint", "trimmed", "question", "releaseDescEdit", "args", "versionArg", "descriptionArg", "confirmedCommand", "commandEcho", "loadJiraConfig", "resolveReleaseBranch", "releaseId", "parseBranchName", "selectedVersion", "displayLabel", "versionName", "formatJiraName", "jiraVersion", "findVersionByName", "previousDescription", "newDescription", "logger", "structuredContent", "textContent", "answer", "confirm", "process", "updateJiraVersion", "body", "updateReleasePRBody", "releaseDescEditMcpTool", "defineMcpTool", "z", "z", "version", "cliVersion", "package_default", "logger", "structuredContent", "textContent", "versionMcpTool", "defineMcpTool", "z", "checkbox", "confirm", "process", "z", "$", "fs", "path", "addFoldersToCursorWorkspace", "args", "workspacePath", "folderPaths", "workspaceDir", "raw", "error", "parsed", "existingFolders", "existingAbsolutePaths", "entry", "added", "skipped", "folderPath", "absolutePath", "relativePath", "$", "launchCursor", "workspacePath", "fs", "path", "fs", "path", "removeFoldersFromCursorWorkspace", "args", "workspacePath", "folderPaths", "workspaceDir", "raw", "error", "parsed", "existingFolders", "targetAbsolutePaths", "folderPath", "removedAbsolutePaths", "filteredFolders", "entry", "entryAbsolutePath", "removed", "notFound", "absolutePath", "reconcileCursorWorkspaceFolders", "args", "workspacePath", "worktreeDir", "currentBranches", "workspaceDir", "path", "releaseRoot", "raw", "fs", "existingFolders", "desiredAbsolutePaths", "branch", "danglingFolderPaths", "entry", "entryAbsolutePath", "removed", "removeFoldersFromCursorWorkspace", "desiredFolderPaths", "added", "addFoldersToCursorWorkspace", "path", "resolveCursorWorkspacePath", "configValue", "projectRoot", "openCursorWorkspace", "args", "projectRoot", "worktreeDir", "currentBranches", "skipRelaunchWhenEmpty", "cursorConfig", "logger", "workspacePath", "resolveCursorWorkspacePath", "added", "removed", "reconcileCursorWorkspaceFolders", "launchCursor", "error", "$", "addFoldersToZedWorkspace", "args", "folderPaths", "folderPath", "$", "openZedWorkspace", "args", "projectRoot", "worktreeDir", "currentBranches", "skipRelaunchWhenEmpty", "paths", "branch", "$", "error", "logger", "assertNever", "value", "addIdeWorktreeFolders", "args", "projectRoot", "worktreeDir", "branches", "config", "getInfraKitConfig", "ides", "resolveConfiguredIdes", "folderPaths", "branch", "outcomes", "ide", "logger", "workspacePath", "resolveCursorWorkspacePath", "added", "skipped", "addFoldersToCursorWorkspace", "skippedSuffix", "launchCursor", "addFoldersToZedWorkspace", "assertNever", "openIdeWorkspace", "args", "config", "getInfraKitConfig", "ides", "resolveConfiguredIdes", "outcomes", "ide", "outcome", "openCursorWorkspace", "openZedWorkspace", "assertNever", "ideProviderLabel", "provider", "assertNever", "removeIdeWorktreeFolders", "args", "projectRoot", "worktreeDir", "branches", "config", "getInfraKitConfig", "ides", "resolveConfiguredIdes", "folderPaths", "branch", "outcomes", "ide", "workspacePath", "resolveCursorWorkspacePath", "removed", "removeFoldersFromCursorWorkspace", "logger", "error", "assertNever", "IDE_MODES", "FEATURE_DIR", "RELEASE_DIR", "worktreesAdd", "options", "confirmedCommand", "all", "versions", "githubDesktop", "cmux", "ide", "commandEcho", "assertManagementContext", "currentWorktrees", "getCurrentWorktrees", "projectRoot", "getProjectRoot", "worktreeDir", "WORKTREES_DIR_SUFFIX", "ensureWorktreeDirectory", "selectedReleaseBranches", "v", "formatBranchName", "parseReleaseRef", "releasePRsInfo", "getReleasePRsWithInfo", "releasePRsList", "pr", "logger", "textContent", "releaseTypes", "detectReleaseType", "descriptions", "getJiraDescriptions", "checkbox", "formatBranchChoices", "releaseBranchLabels", "answer", "confirm", "process", "config", "getInfraKitConfig", "ideMode", "resolveConfiguredIdes", "openInGithubDesktop", "openInCmux", "branchesToCreate", "categorizeWorktrees", "createdWorktrees", "createWorktrees", "logResults", "addIdeWorktreeFolders", "branch", "$", "repoName", "getRepoName", "existingTitles", "listCmuxWorkspaceTitles", "title", "buildCmuxWorkspaceTitle", "canonicalizeCmuxTitle", "openCmuxWorkspaceWithLayout", "structuredContent", "error", "OperationError", "args", "currentBranchNames", "isReleaseBranch", "branches", "results", "worktreePath", "created", "index", "result", "err", "worktreesAddMcpTool", "defineMcpTool", "z", "IDE_MODES", "z", "worktreesList", "currentWorktrees", "getCurrentWorktrees", "logger", "textContent", "releasePRsInfo", "jiraDescriptions", "getReleasePRsWithInfo", "getJiraDescriptions", "releaseTypes", "pr", "detectReleaseType", "worktrees", "branch", "id", "parseBranchName", "version", "displayLabel", "type", "description", "formatJiraName", "maxVersionLength", "w", "formattedLines", "worktree", "label", "formatVersionLabel", "structuredContent", "worktreesListMcpTool", "defineMcpTool", "z", "z", "worktreesOpen", "commandEcho", "projectRoot", "getProjectRoot", "worktreeDir", "WORKTREES_DIR_SUFFIX", "currentBranches", "getCurrentWorktrees", "ideOutcomes", "openIdeWorkspace", "cmuxOutcome", "openCmux", "result", "outcome", "sum", "logResults", "textContent", "error", "logger", "OperationError", "args", "repoName", "getRepoName", "existingTitles", "listCmuxWorkspaceTitles", "opened", "skipped", "branch", "title", "buildCmuxWorkspaceTitle", "canonicalizeCmuxTitle", "openCmuxWorkspaceWithLayout", "context", "ideLabels", "provider", "ideProviderLabel", "worktreesOpenMcpTool", "defineMcpTool", "z", "z", "worktreesReload", "commandEcho", "projectRoot", "getProjectRoot", "worktreeDir", "WORKTREES_DIR_SUFFIX", "currentBranches", "getCurrentWorktrees", "repoName", "getRepoName", "closedCmux", "closeCmux", "ideOutcomes", "openedCmux", "openIdeWorkspace", "reopenCmux", "result", "outcome", "sum", "logResults", "textContent", "error", "logger", "OperationError", "args", "openBefore", "listCmuxWorkspaceTitles", "closed", "branch", "title", "buildCmuxWorkspaceTitle", "canonicalizeCmuxTitle", "closeCmuxWorkspaceByTitle", "opened", "openCmuxWorkspaceWithLayout", "context", "ideLabels", "provider", "ideProviderLabel", "worktreesReloadMcpTool", "defineMcpTool", "z", "checkbox", "confirm", "process", "z", "worktreesRemove", "options", "confirmedCommand", "all", "versions", "commandEcho", "assertManagementContext", "currentWorktrees", "getCurrentWorktrees", "logger", "textContent", "projectRoot", "getProjectRoot", "worktreeDir", "WORKTREES_DIR_SUFFIX", "selectedReleaseBranches", "formatBranchName", "parseReleaseRef", "descriptions", "prInfo", "getJiraDescriptions", "getReleasePRsWithInfo", "releaseTypes", "pr", "detectReleaseType", "checkbox", "formatBranchChoices", "allSelected", "releaseBranchLabels", "answer", "confirm", "process", "repoName", "getRepoName", "removedWorktrees", "removeWorktrees", "removeIdeWorktreeFolders", "logResults", "structuredContent", "error", "OperationError", "removed", "branch", "worktreesRemoveMcpTool", "defineMcpTool", "z", "confirm", "process", "z", "$", "worktreesSync", "options", "confirmedCommand", "commandEcho", "assertManagementContext", "currentWorktrees", "getCurrentWorktrees", "projectRoot", "getProjectRoot", "worktreeDir", "WORKTREES_DIR_SUFFIX", "releasePRsList", "getReleasePRs", "answer", "confirm", "logger", "process", "branchesToRemove", "categorizeWorktrees", "repoName", "getRepoName", "removedWorktrees", "removeWorktrees", "removeIdeWorktreeFolders", "logResults", "structuredContent", "textContent", "error", "OperationError", "args", "branch", "isReleaseBranch", "branches", "removed", "worktreePath", "title", "buildCmuxWorkspaceTitle", "closeCmuxWorkspaceByTitle", "$", "err", "worktreesSyncMcpTool", "defineMcpTool", "z", "program", "Command", "collectReleaseSpec", "value", "prev", "normalizeIdeMode", "flagName", "IDE_MODES", "runProgram", "argv", "error", "message", "logger", "process", "options", "ghMergeDev", "ghReleaseList", "inputs", "parseReleaseSpec", "releases", "releaseCreate", "releaseDescEdit", "ghReleaseDeployAll", "ghReleaseDeploySelected", "ghReleaseDeliver", "worktreesSync", "ide", "worktreesAdd", "worktreesList", "worktreesRemove", "worktreesOpen", "worktreesReload", "configCmd", "configPath", "configEdit", "audit", "doctor", "version", "envStatus", "envList", "init", "envLoad", "envClear", "releaseCommands", "worktreeCommands", "envCommands", "commandMap", "cmd", "allNames", "maxLen", "n", "toChoices", "names", "selected", "select", "Separator"]
3
+ "sources": ["../src/entry/cli.ts", "../src/commands/config/config.ts", "../src/lib/env-autoload/env-autoload.ts", "../src/commands/env-autoload/env-autoload.ts", "../src/commands/vendor-config/vendor-config.ts", "../src/lib/json-output/json-output.ts", "../src/lib/render/render.ts"],
4
+ "sourcesContent": ["import select, { Separator } from '@inquirer/select'\nimport { Command } from 'commander'\nimport process from 'node:process'\n\nimport { audit } from 'src/commands/audit'\nimport { configEdit, configPath } from 'src/commands/config'\nimport { doctor } from 'src/commands/doctor'\nimport { envAutoload } from 'src/commands/env-autoload'\nimport { envClear } from 'src/commands/env-clear'\nimport { envList } from 'src/commands/env-list'\nimport { envLoad } from 'src/commands/env-load'\nimport { envStatus } from 'src/commands/env-status'\nimport { ghMergeDev } from 'src/commands/gh-merge-dev'\nimport { ghReleaseDeliver } from 'src/commands/gh-release-deliver'\nimport { ghReleaseDeployAll } from 'src/commands/gh-release-deploy-all'\nimport { ghReleaseDeploySelected } from 'src/commands/gh-release-deploy-selected'\nimport { ghReleaseList } from 'src/commands/gh-release-list'\nimport { init } from 'src/commands/init'\nimport { releaseCreate } from 'src/commands/release-create'\nimport { releaseDescEdit } from 'src/commands/release-desc-edit'\nimport { vendorCheck } from 'src/commands/vendor-check'\nimport { vendorConfig } from 'src/commands/vendor-config'\nimport { vendorDiff } from 'src/commands/vendor-diff'\nimport { vendorManifest } from 'src/commands/vendor-manifest'\nimport { vendorSync } from 'src/commands/vendor-sync'\nimport { version } from 'src/commands/version'\nimport { worktreesAdd } from 'src/commands/worktrees-add'\nimport { worktreesList } from 'src/commands/worktrees-list'\nimport { worktreesReload } from 'src/commands/worktrees-reload'\nimport { worktreesRemove } from 'src/commands/worktrees-remove'\nimport { worktreesSync } from 'src/commands/worktrees-sync'\nimport { IDE_MODES } from 'src/integrations/ide'\nimport type { IdeMode } from 'src/integrations/ide'\nimport { getMenuGroupCommands } from 'src/lib/command-catalog'\nimport { runEnvAutoLoad } from 'src/lib/env-autoload'\nimport { addJsonOption, emit, jsonOutput } from 'src/lib/json-output'\nimport { logger } from 'src/lib/logger'\nimport { formatAlignedRows } from 'src/lib/render'\nimport { parseReleaseSpec } from 'src/lib/version-utils'\nimport type { ReleaseInput } from 'src/lib/version-utils'\n\nconst program = new Command()\n\nconst collectReleaseSpec = (value: string, prev: string[]): string[] => {\n return [...prev, value]\n}\n\n/** Parse a `--repos a,b,c` option into a target-name list (undefined = all). */\nconst parseRepos = (value: unknown): string[] | undefined => {\n return typeof value === 'string' ? value.split(',').filter(Boolean) : undefined\n}\n\nconst normalizeIdeMode = (value: unknown, flagName: '--ide' | '--cursor'): IdeMode | undefined => {\n if (typeof value === 'undefined') {\n return undefined\n }\n\n if (value === true) {\n return 'workspace'\n }\n\n if (value === false) {\n return 'none'\n }\n\n if (typeof value === 'string' && (IDE_MODES as readonly string[]).includes(value)) {\n return value as IdeMode\n }\n\n throw new Error(`Invalid ${flagName} value \"${String(value)}\". Expected one of: ${IDE_MODES.join(', ')}.`)\n}\n\nconst runProgram = async (argv?: string[]): Promise<void> => {\n try {\n if (argv) {\n await program.parseAsync(argv)\n } else {\n await program.parseAsync()\n }\n } catch (error) {\n const message = error instanceof Error ? error.message : String(error)\n\n logger.error(message)\n process.exit(1)\n }\n}\n\n// --- Deprecation support for flat command aliases (Phase 3 grouping) ---\n// Flat names (`release-create`, `worktrees-add`, `vendor-config`, ...) are kept\n// as working aliases of the grouped forms (`release create`, ...) for one\n// release cycle. They warn once when invoked directly, but stay silent when the\n// interactive no-arg menu drives them (the menu is a guided surface).\nconst invokedViaMenu = { value: false }\n\nconst deprecatedAlias = (cmd: Command, preferred: string): Command => {\n return cmd.hook('preAction', () => {\n if (!invokedViaMenu.value) {\n logger.warn(`\"${cmd.name()}\" is a deprecated alias; use \"${preferred}\" instead.`)\n }\n })\n}\n\n// --- Command configurators (one source of options + action, shared by the\n// grouped form and its flat alias so the two can never diverge) ---\nconst configureMergeDev = (cmd: Command): Command => {\n return cmd\n .description('Merge dev branch into every release branch')\n .option('-a, --all', 'Select all active release branches')\n .option('-y, --yes', 'Skip confirmation prompt')\n .action(async (options) => {\n emit(await ghMergeDev({ all: options.all, confirmedCommand: options.yes }))\n })\n}\n\nconst configureReleaseList = (cmd: Command): Command => {\n return cmd.description('List all release branches').action(async () => {\n emit(await ghReleaseList())\n })\n}\n\nconst configureReleaseCreate = (cmd: Command): Command => {\n return cmd\n .description('Create one or more release branches (each entry can mix regular/hotfix and its own description)')\n .option(\n '-r, --release <spec>',\n 'Release spec \"<version|next|name>[:type[:description]]\" (repeatable). The token is a semver (\"1.2.5\"), the literal \"next\", or a kebab-case name (\"checkout-redesign\"). Type is regular|hotfix (default regular). Examples: \"1.2.5\", \"1.2.5:hotfix\", \"next:regular:Holiday backend\", \"checkout-redesign:regular:Q3 redesign\".',\n collectReleaseSpec,\n [],\n )\n .option('-y, --yes', 'Skip confirmation prompt')\n .action(async (options) => {\n const specs = options.release as string[]\n const inputs: ReleaseInput[] = specs.map(parseReleaseSpec)\n const releases = inputs.length > 0 ? inputs : undefined\n\n emit(\n await releaseCreate({\n releases,\n confirmedCommand: options.yes,\n }),\n )\n })\n}\n\nconst configureReleaseDescEdit = (cmd: Command): Command => {\n return cmd\n .description(\"Edit a release's description in Jira and in the matching GitHub PR body\")\n .option('-v, --version <version>', 'Release version (e.g. 1.2.5) or release name (e.g. checkout-redesign)')\n .option('-d, --description <description>', 'New description (use \"\" to clear)')\n .option('-y, --yes', 'Skip confirmation prompt')\n .action(async (options) => {\n emit(\n await releaseDescEdit({\n version: options.version,\n description: options.description,\n confirmedCommand: options.yes,\n }),\n )\n })\n}\n\nconst configureReleaseDeployAll = (cmd: Command): Command => {\n return cmd\n .description('Deploy any release branch to any environment')\n .option(\n '-v, --version <version>',\n 'Version (e.g. 1.2.5) or release name (e.g. checkout-redesign) to deploy; \"dev\" deploys from the dev branch',\n )\n .option('-e, --env <env>', 'Specify the environment to deploy to, e.g. dev')\n .option('--skip-terraform', 'Skip terraform deployment step')\n .option('-y, --yes', 'Skip confirmation prompt')\n .action(async (options) => {\n emit(\n await ghReleaseDeployAll({\n version: options.version,\n env: options.env,\n skipTerraform: options.skipTerraform,\n confirmedCommand: options.yes,\n }),\n )\n })\n}\n\nconst configureReleaseDeploySelected = (cmd: Command): Command => {\n return cmd\n .description('Deploy selected services from release branch to any environment')\n .option(\n '-v, --version <version>',\n 'Version (e.g. 1.2.5) or release name (e.g. checkout-redesign) to deploy; \"dev\" deploys from the dev branch',\n )\n .option('-e, --env <env>', 'Specify the environment to deploy to, e.g. dev')\n .option('-s, --services <services...>', 'Specify services to deploy, e.g. client-be client-fe')\n .option('--skip-terraform', 'Skip terraform deployment step')\n .option('-y, --yes', 'Skip confirmation prompt')\n .action(async (options) => {\n emit(\n await ghReleaseDeploySelected({\n version: options.version,\n env: options.env,\n services: options.services,\n skipTerraform: options.skipTerraform,\n confirmedCommand: options.yes,\n }),\n )\n })\n}\n\nconst configureReleaseDeliver = (cmd: Command): Command => {\n return cmd\n .description('Release a new version to production')\n .option('-v, --version <version>', 'Version (e.g. 1.2.5) or release name (e.g. checkout-redesign) to deliver')\n .option('-y, --yes', 'Skip confirmation prompt')\n .action(async (options) => {\n emit(await ghReleaseDeliver({ version: options.version, confirmedCommand: options.yes }))\n })\n}\n\nconst configureWorktreesSync = (cmd: Command): Command => {\n return cmd\n .description('Remove release worktrees whose PRs are no longer open')\n .option('-y, --yes', 'Skip confirmation prompt')\n .action(async (options) => {\n emit(await worktreesSync({ confirmedCommand: options.yes }))\n })\n}\n\nconst configureWorktreesAdd = (cmd: Command): Command => {\n return cmd\n .description('Add git worktrees for release branches')\n .option('-y, --yes', 'Skip confirmation prompt')\n .option('-a, --all', 'Select all active release branches')\n .option('-v, --versions <versions>', 'Specify versions by comma, e.g. 1.2.5, 1.2.6')\n .option('-i, --ide [mode]', 'Editor mode for created worktrees: workspace (default) | none')\n .option('--no-ide', 'Skip the editor (alias for --ide none)')\n .option('-c, --cursor [mode]', 'Deprecated alias for --ide')\n .option('--no-cursor', 'Deprecated alias for --no-ide')\n .option('-g, --github-desktop', 'Open created worktrees in GitHub Desktop')\n .option('--no-github-desktop', 'Skip GitHub Desktop prompt')\n .option('-m, --cmux', 'Open created worktrees in cmux (3-pane layout)')\n .option('--no-cmux', 'Skip cmux prompt')\n .action(async (options) => {\n // `--ide` wins over the deprecated `--cursor` alias when both are provided.\n const ide = normalizeIdeMode(options.ide, '--ide') ?? normalizeIdeMode(options.cursor, '--cursor')\n\n emit(\n await worktreesAdd({\n confirmedCommand: options.yes,\n all: options.all,\n versions: options.versions,\n ide,\n githubDesktop: options.githubDesktop,\n cmux: options.cmux,\n }),\n )\n })\n}\n\nconst configureWorktreesList = (cmd: Command): Command => {\n return cmd.description('List all git worktrees with detailed information').action(async () => {\n emit(await worktreesList())\n })\n}\n\nconst configureWorktreesRemove = (cmd: Command): Command => {\n return cmd\n .description('Remove git worktrees for release branches')\n .option('-y, --yes', 'Skip confirmation prompt')\n .option('-a, --all', 'Select all active release branches')\n .option('-v, --versions <versions>', 'Specify versions by comma, e.g. 1.2.5, 1.2.6')\n .action(async (options) => {\n emit(await worktreesRemove({ confirmedCommand: options.yes, all: options.all, versions: options.versions }))\n })\n}\n\nconst configureWorktreesReload = (cmd: Command): Command => {\n return cmd\n .description(\n 'Close all cmux/editor worktree windows, then reopen the current release worktrees (also cold-start restore)',\n )\n .action(async () => {\n emit(await worktreesReload())\n })\n}\n\nconst configureVendorConfig = (cmd: Command): Command => {\n return cmd\n .description('Show the machine-local factory config (~/.infra-kit/vendor.json) or scaffold it with --init')\n .option('--init', 'Scaffold ~/.infra-kit/vendor.json (skips if it already exists)')\n .action(async (options) => {\n emit(await vendorConfig({ init: options.init }))\n })\n}\n\n// --- Grouped command surface (preferred form) ---\nconst releaseGroup = program.command('release').description('Release management commands')\n\nconfigureMergeDev(releaseGroup.command('merge-dev'))\nconfigureReleaseList(releaseGroup.command('list'))\nconfigureReleaseCreate(releaseGroup.command('create'))\nconfigureReleaseDescEdit(releaseGroup.command('desc-edit'))\nconfigureReleaseDeployAll(releaseGroup.command('deploy-all'))\nconfigureReleaseDeploySelected(releaseGroup.command('deploy-selected'))\nconfigureReleaseDeliver(releaseGroup.command('deliver'))\n\nconst worktreesGroup = program.command('worktrees').description('Git worktree management commands')\n\nconfigureWorktreesAdd(worktreesGroup.command('add'))\nconfigureWorktreesList(worktreesGroup.command('list'))\nconfigureWorktreesRemove(worktreesGroup.command('remove'))\nconfigureWorktreesSync(worktreesGroup.command('sync'))\nconfigureWorktreesReload(worktreesGroup.command('reload'))\n\n// --- Deprecated flat aliases (kept one release cycle; warn when used directly) ---\ndeprecatedAlias(configureMergeDev(program.command('merge-dev')), 'release merge-dev')\ndeprecatedAlias(configureReleaseList(program.command('release-list')), 'release list')\ndeprecatedAlias(configureReleaseCreate(program.command('release-create')), 'release create')\ndeprecatedAlias(configureReleaseDescEdit(program.command('release-desc-edit')), 'release desc-edit')\ndeprecatedAlias(configureReleaseDeployAll(program.command('release-deploy-all')), 'release deploy-all')\ndeprecatedAlias(configureReleaseDeploySelected(program.command('release-deploy-selected')), 'release deploy-selected')\ndeprecatedAlias(configureReleaseDeliver(program.command('release-deliver')), 'release deliver')\ndeprecatedAlias(configureWorktreesAdd(program.command('worktrees-add')), 'worktrees add')\ndeprecatedAlias(configureWorktreesList(program.command('worktrees-list')), 'worktrees list')\ndeprecatedAlias(configureWorktreesRemove(program.command('worktrees-remove')), 'worktrees remove')\ndeprecatedAlias(configureWorktreesSync(program.command('worktrees-sync')), 'worktrees sync')\ndeprecatedAlias(configureWorktreesReload(program.command('worktrees-reload')), 'worktrees reload')\n\nconst configCmd = program.command('config').description('Manage infra-kit configuration files')\n\nconfigCmd\n .command('path')\n .description('Show the resolved config merge chain and file paths')\n .action(async () => {\n emit(await configPath())\n })\n\nconfigCmd\n .command('edit')\n .description('Open the user-scope per-project override file in $EDITOR')\n .action(async () => {\n emit(await configEdit())\n })\n\nprogram\n .command('audit')\n .description('Audit against infra-kit.config.ts rules (--all for every package, --root for the monorepo root)')\n .option('-a, --all', 'Audit every non-vendor workspace package')\n .option('-r, --root', 'Audit the monorepo root (turbo pipeline + root commands)')\n .action(async (options) => {\n const result = await audit({ all: options.all, root: options.root })\n\n emit(result)\n\n if (!result.structuredContent.allPassed) {\n process.exitCode = 1\n }\n })\n\nconst vendorCmd = program.command('vendor').description('Verify and sync the mirrored vendor/ tree')\n\nvendorCmd\n .command('check')\n .description('Verify vendor/ matches vendor/.sync-manifest.json (self-contained; for any consumer repo)')\n .action(async () => {\n const result = await vendorCheck()\n\n emit(result)\n\n if (!result.structuredContent.ok) {\n process.exitCode = 1\n }\n })\n\nvendorCmd\n .command('sync')\n .description('Copy vendored files from the source repo into each target and regenerate manifests')\n .option('-y, --yes', 'Skip confirmation prompt')\n .option('-r, --repos <repos>', 'Restrict to comma-separated target repo names')\n .action(async (options) => {\n emit(await vendorSync({ confirmedCommand: options.yes, repos: parseRepos(options.repos) }))\n })\n\nvendorCmd\n .command('manifest')\n .description('Regenerate each target vendor/.sync-manifest.json + README from current content (no copy)')\n .option('-r, --repos <repos>', 'Restrict to comma-separated target repo names')\n .action(async (options) => {\n emit(await vendorManifest({ confirmedCommand: true, repos: parseRepos(options.repos) }))\n })\n\nvendorCmd\n .command('diff')\n .description('Source-aware drift check (rsync dry-run) of each target vendored subtree vs the source')\n .option('-r, --repos <repos>', 'Restrict to comma-separated target repo names')\n .action(async (options) => {\n const result = await vendorDiff({ repos: parseRepos(options.repos) })\n\n emit(result)\n\n if (!result.structuredContent.ok) {\n process.exitCode = 1\n }\n })\n\n// Grouped form (preferred); the flat `vendor-config` below is a deprecated alias.\nconfigureVendorConfig(vendorCmd.command('config'))\n\ndeprecatedAlias(configureVendorConfig(program.command('vendor-config')), 'vendor config')\n\nprogram\n .command('doctor')\n .description('Check installation and authentication status of gh and doppler CLIs')\n .action(async () => {\n emit(await doctor())\n })\n\nprogram\n .command('version')\n .description('Print the installed infra-kit CLI version')\n .action(async () => {\n emit(await version())\n })\n\nprogram\n .command('env-status')\n .description('Show which env is loaded in this session (local introspection; no Doppler call)')\n .action(async () => {\n emit(await envStatus())\n })\n\nprogram\n .command('env-list')\n .description('List available Doppler configs for the detected project')\n .action(async () => {\n emit(await envList())\n })\n\nprogram\n .command('init')\n .description('Inject shell integration into .zshrc and sync repo agent-instruction files')\n .action(async () => {\n emit(await init())\n })\n\nprogram\n .command('env-load')\n .description('Load Doppler env vars for a config. Source the returned file path to apply.')\n .option('-c, --config <config>', 'Environment config name to load (e.g. dev, arthur)')\n .action(async (options) => {\n emit(await envLoad({ config: options.config }))\n })\n\nprogram\n .command('env-clear')\n .description('Clear loaded env vars. Source the returned file path to apply.')\n .action(async () => {\n emit(await envClear())\n })\n\n// Internal: driven by the init shell-startup integration (backgrounded). Writes\n// env-load.sh when envAutoLoad is configured + eligible; the precmd hook sources\n// it. Hidden + no stdout output so it never pollutes the shell or the menu.\nprogram\n .command('env-autoload', { hidden: true })\n .description('Internal: prime env for the shell-startup auto-load trigger')\n .action(async () => {\n await envAutoload()\n })\n\n// Register `--json` on every command, then resolve the flag before each action\n// runs. In JSON mode we lower the logger to `warn` so the human-oriented info\n// lines stop cluttering stderr while errors still surface; the structured\n// payload is written to stdout by `emit`. No handler logic is affected.\nprogram.commands.forEach(addJsonOption)\n\n// Commands excluded from the cli-invocation auto-load trigger: the env-* family\n// (avoids recursion \u2014 `env-autoload`/`env-load` would re-enter), plus the\n// host-inspecting / meta commands where priming Doppler env would be surprising\n// (`init` bootstraps the shell block, `doctor` inspects auth, `version` prints a\n// string). `--help`/`--version`/the bare-arg menu don't fire preAction at all.\nconst isAutoLoadExcludedCommand = (name: string): boolean => {\n return name.startsWith('env-') || name === 'init' || name === 'doctor' || name === 'version'\n}\n\nprogram.hook('preAction', async (_thisCommand, actionCommand) => {\n // `optsWithGlobals` (not `opts`) so `--json` is seen on grouped subcommands:\n // for `release list --json` Commander binds the post-subcommand flag to the\n // parent `release` group, so the leaf's own `opts()` would not carry it.\n jsonOutput.enabled = Boolean(actionCommand.optsWithGlobals().json)\n\n if (jsonOutput.enabled) {\n logger.level = 'warn'\n }\n\n // cli-invocation auto-load: primes the shell env for SUBSEQUENT commands. The\n // current command does NOT see these vars \u2014 a child process can't mutate its\n // parent shell; the precmd hook sources the written file on the next prompt.\n // runEnvAutoLoad self-gates on config trigger and swallows transient failures,\n // so this is a no-op unless configured for cli-invocation and never blocks.\n if (!isAutoLoadExcludedCommand(actionCommand.name())) {\n await runEnvAutoLoad({ expectedTrigger: 'cli-invocation' })\n }\n})\n\nif (process.argv.length <= 2) {\n // Menu groups derive from the single command catalog (no hand-maintained\n // name arrays). Membership and order live in src/lib/command-catalog.\n const releaseCommands = getMenuGroupCommands('release')\n const worktreeCommands = getMenuGroupCommands('worktrees')\n const envCommands = getMenuGroupCommands('environment')\n\n const commandMap = new Map(\n program.commands.map((cmd) => {\n return [cmd.name(), cmd]\n }),\n )\n\n const groups = [\n { label: 'Release Management', names: releaseCommands },\n { label: 'Worktrees', names: worktreeCommands },\n { label: 'Environment', names: envCommands },\n ]\n\n // Flat {name, description, group} list shared by both the Ink palette and the\n // Inquirer fallback; descriptions come from Commander (single source).\n const paletteItems = groups.flatMap(({ label, names }) => {\n return names\n .filter((name) => {\n return commandMap.has(name)\n })\n .map((name) => {\n return { name, description: commandMap.get(name)!.description(), group: label }\n })\n })\n\n let selected: string | null\n\n // Interactive TTY \u2192 Ink command palette, loaded lazily via dynamic import so\n // React/Ink never touch the MCP / `--json` / non-TTY code paths. Otherwise fall\n // back to the Inquirer menu (scripts, pipes, CI).\n if (process.stdout.isTTY && process.stdin.isTTY) {\n const { runCommandPalette } = await import('src/tui/boot')\n\n selected = await runCommandPalette(paletteItems)\n } else {\n const alignedLabels = formatAlignedRows(\n paletteItems.map((item) => {\n return [item.name, item.description] as const\n }),\n )\n const labelByName = new Map<string, string>()\n\n paletteItems.forEach((item, index) => {\n labelByName.set(item.name, alignedLabels[index] ?? item.name)\n })\n\n const toChoices = (names: string[]) => {\n return names\n .filter((name) => {\n return commandMap.has(name)\n })\n .map((name) => {\n return {\n name: labelByName.get(name) ?? name,\n value: name,\n }\n })\n }\n\n selected = await select(\n {\n message: 'Select a command to run',\n choices: [\n new Separator(' '),\n new Separator('\u2014 Release Management \u2014'),\n ...toChoices(releaseCommands),\n new Separator(' '),\n new Separator('\u2014 Worktrees \u2014'),\n ...toChoices(worktreeCommands),\n new Separator(' '),\n new Separator('\u2014 Environment \u2014'),\n ...toChoices(envCommands),\n ],\n },\n { output: process.stderr },\n )\n }\n\n // The menu is a guided surface; don't nag about deprecated flat names here.\n if (selected) {\n invokedViaMenu.value = true\n\n await runProgram(['node', 'infra-kit', selected])\n }\n} else {\n await runProgram()\n}\n", "import fs from 'node:fs/promises'\nimport path from 'node:path'\nimport process from 'node:process'\nimport { $ } from 'zx'\n\nimport { getInfraKitConfigPaths, resetInfraKitConfigCache } from 'src/lib/infra-kit-config'\nimport { logger } from 'src/lib/logger'\nimport { fileExists, tildify } from 'src/lib/path-display'\nimport type { ToolsExecutionResult } from 'src/types'\n\n/**\n * Print the file paths that participate in the config merge chain along with\n * existence markers, so the user can see at a glance which override layers\n * are active.\n *\n * @example\n * // CLI: `infra-kit config path`\n * // INFO: Project name: api\n * // INFO: Config merge chain (later overrides earlier):\n * // INFO: [\u2713] project (committed) ~/projects/api/infra-kit.json\n * // INFO: [ ] user global ~/.infra-kit/infra-kit.json\n * // INFO: [\u2713] user project ~/.infra-kit/projects/api/infra-kit.json\n */\nexport const configPath = async (): Promise<ToolsExecutionResult> => {\n const paths = await getInfraKitConfigPaths()\n\n const rows: { label: string; path: string; exists: boolean }[] = await Promise.all(\n [\n { label: 'project (committed)', path: paths.main },\n { label: 'user global', path: paths.userGlobal },\n { label: 'user project', path: paths.userProject },\n ].map(async (row) => {\n return { ...row, exists: await fileExists(row.path) }\n }),\n )\n\n logger.info(`Project name: ${paths.projectName}\\n`)\n logger.info('Config merge chain (later overrides earlier):\\n')\n\n for (const row of rows) {\n const marker = row.exists ? ' [\u2713]' : ' [ ]'\n\n logger.info(`${marker} ${row.label.padEnd(22)} ${tildify(row.path)}`)\n }\n\n const structuredContent = {\n projectName: paths.projectName,\n layers: rows.map((r) => {\n return { label: r.label, path: r.path, exists: r.exists }\n }),\n }\n\n return {\n content: [{ type: 'text', text: JSON.stringify(structuredContent, null, 2) }],\n structuredContent,\n }\n}\n\n/**\n * Open the user-scope per-project override file in $EDITOR, creating the\n * parent directory and a stub file on first use. Resets the config cache\n * after the editor exits so subsequent reads pick up edits without a restart.\n *\n * @example\n * // CLI: `infra-kit config edit`\n * // first run \u2014 creates ~/.infra-kit/projects/api/infra-kit.json ({}) + a sibling\n * // infra-kit.example.jsonc reference, then $EDITOR opens the .json\n * // subsequent runs \u2014 opens the existing file as-is\n */\nexport const configEdit = async (): Promise<ToolsExecutionResult> => {\n const paths = await getInfraKitConfigPaths()\n const editor = process.env.EDITOR || process.env.VISUAL || 'vi'\n\n await fs.mkdir(path.dirname(paths.userProject), { recursive: true })\n\n if (!(await fileExists(paths.userProject))) {\n // JSON can't carry comments, so seed an empty-but-valid config and drop the\n // annotated guidance next to it in a non-loaded .example.jsonc the loader\n // never reads (it only globs the three exact `infra-kit.json` filenames).\n const examplePath = exampleSiblingPath(paths.userProject)\n\n await fs.writeFile(paths.userProject, '{}\\n', 'utf-8')\n await fs.writeFile(examplePath, buildUserProjectExample(paths.projectName), 'utf-8')\n\n logger.info(`Created ${tildify(paths.userProject)} \u2014 see ${tildify(examplePath)} for the annotated reference.`)\n }\n\n logger.info(`Opening ${tildify(paths.userProject)} in ${editor}`)\n\n await $({ stdio: 'inherit' })`${editor} ${paths.userProject}`\n\n resetInfraKitConfigCache()\n\n const structuredContent = { path: paths.userProject, editor }\n\n return {\n content: [{ type: 'text', text: JSON.stringify(structuredContent, null, 2) }],\n structuredContent,\n }\n}\n\n/**\n * Derive the non-loaded `.example.jsonc` sibling for a config path.\n *\n * @example\n * exampleSiblingPath('/u/.infra-kit/projects/api/infra-kit.json')\n * // => '/u/.infra-kit/projects/api/infra-kit.example.jsonc'\n */\nconst exampleSiblingPath = (jsonPath: string): string => {\n return jsonPath.replace(/\\.json$/, '.example.jsonc')\n}\n\n/**\n * Annotated JSONC reference for the user-scope per-project override layer.\n * Written alongside the real `{}` config so the guidance the old YAML stub\n * carried in comments survives the move to JSON.\n *\n * @example\n * buildUserProjectExample('api')\n * // => '// infra-kit user override for api \u2026\\n{ \u2026 }\\n'\n */\nconst buildUserProjectExample = (projectName: string): string => {\n return `// infra-kit user override for ${projectName} \u2014 ~/.infra-kit/projects/${projectName}/infra-kit.json\n//\n// Layer 3 (highest precedence) of the config merge chain. Shallow-merged on top\n// of <repo>/infra-kit.json and ~/.infra-kit/infra-kit.json \u2014 top-level keys\n// (environments, envManagement, ide, taskManager, worktrees, envAutoLoad) replace wholesale.\n//\n// This .example.jsonc is reference only \u2014 it is NOT loaded. Put real overrides\n// in the sibling infra-kit.json (strict JSON: no comments, double-quoted keys).\n{\n // \"worktrees\": { \"openInGithubDesktop\": false, \"openInCmux\": true, \"cmux\": { \"layout\": \"two-columns\" } },\n // // Auto-load Doppler env here. trigger (pick one): shell-startup | cli-invocation; config: an environment name.\n // \"envAutoLoad\": { \"trigger\": \"shell-startup\", \"config\": \"dev\" }\n}\n`\n}\n", "import fs from 'node:fs'\nimport path from 'node:path'\nimport process from 'node:process'\n\nimport { writeEnvLoadFile } from 'src/commands/env-load'\nimport {\n ENV_CLEAR_FILE,\n ENV_LOAD_FILE,\n INFRA_KIT_ENV_AUTOLOADED_VAR,\n INFRA_KIT_ENV_CLEARED_VAR,\n INFRA_KIT_ENV_CONFIG_VAR,\n INFRA_KIT_ENV_PROJECT_VAR,\n INFRA_KIT_SESSION_VAR,\n getSessionCacheDir,\n} from 'src/lib/constants'\nimport type { EnvAutoLoadConfig } from 'src/lib/infra-kit-config'\nimport { getInfraKitConfig } from 'src/lib/infra-kit-config'\nimport { logger } from 'src/lib/logger'\n\n/** Which moment a concrete callsite represents. Matches the config `trigger`. */\nexport type AutoLoadTrigger = EnvAutoLoadConfig['trigger']\n\n/** Per-session flag file that de-dups the auto-load warning (misconfig or failure). */\nconst WARN_SENTINEL_FILE = 'autoload-warn.flag'\n\n/** Per-session marker recording the last auto-load failure (mtime = when). */\nconst FAIL_SENTINEL_FILE = 'autoload-fail.flag'\n\n/**\n * After a failed auto-load, suppress retries for this long so a down/unauthenticated\n * Doppler isn't re-probed on every cli-invocation. A new shell starts a fresh\n * session cache dir, so this only throttles within one session.\n */\nconst FAIL_BACKOFF_MS = 30_000\n\n/** Resolved auto-load inputs: the chosen trigger + the env config and Doppler project to load. */\nexport interface ResolvedEnvAutoLoad {\n trigger: AutoLoadTrigger\n config: string\n project: string\n}\n\n/**\n * Read the resolved + validated env auto-load inputs, or `null` when auto-load\n * should not run. Returns `null` (never throws) when:\n * - we're not inside an infra-kit project (getInfraKitConfig throws), or config is unreadable;\n * - `envAutoLoad` is absent (feature off);\n * - `envAutoLoad.config` is not one of `environments` \u2014 warns once per session, then disables.\n *\n * Validation lives here (not in the schema) so a typo only disables this optional\n * feature instead of throwing inside the merged-config parse and breaking every command.\n * Resolves the Doppler project from the SAME config read (no second getInfraKitConfig),\n * so the skip path stays cheap.\n *\n * `canWarn` gates the misconfig warning: the shell-startup callsite runs backgrounded\n * with stderr discarded, so warning there is invisible AND would write the dedup flag,\n * poisoning the only channel (cli-invocation / interactive) that can actually surface\n * it. So shell-startup passes `false`; interactive callsites pass `true`.\n */\nexport const resolveEnvAutoLoad = async (canWarn = true): Promise<ResolvedEnvAutoLoad | null> => {\n let config\n\n try {\n config = await getInfraKitConfig()\n } catch {\n return null\n }\n\n const autoLoad = config.envAutoLoad\n\n if (!autoLoad) return null\n\n if (!config.environments.includes(autoLoad.config)) {\n if (canWarn) {\n warnOnce(\n `infra-kit: envAutoLoad.config \"${autoLoad.config}\" is not one of environments [${config.environments.join(\n ', ',\n )}] \u2014 env auto-load disabled.`,\n )\n }\n\n return null\n }\n\n return {\n trigger: autoLoad.trigger,\n config: autoLoad.config,\n project: config.envManagement.config.name,\n }\n}\n\n/** The env-var snapshot the freshness/suppression guards read. */\nexport interface AutoLoadEnvSnapshot {\n session?: string\n cleared?: string\n currentConfig?: string\n currentProject?: string\n autoLoadedMarker?: string\n}\n\nexport interface AutoLoadDecisionInput {\n /** The configured trigger. */\n trigger: AutoLoadTrigger\n /** Which trigger this callsite represents. */\n expectedTrigger: AutoLoadTrigger\n targetConfig: string\n targetProject: string\n env: AutoLoadEnvSnapshot\n}\n\nexport type AutoLoadDecision = 'load' | 'skip'\n\n/**\n * Pure decision: should this callsite (auto-)load env right now? Encodes the full\n * guard matrix so it is exhaustively unit-testable without Doppler or a shell:\n * - the configured trigger must match this callsite;\n * - a session must exist (the cache dir is session-scoped);\n * - an explicit clear suppresses auto-load (M2);\n * - a MANUAL load (config set, no auto marker) is never clobbered (C1);\n * - an auto-load already fresh for the same config AND project is a no-op\n * (project-aware so two same-named configs across different-repo worktrees\n * sharing one session don't leak each other's secrets).\n */\nexport const decideAutoLoad = (input: AutoLoadDecisionInput): AutoLoadDecision => {\n const { trigger, expectedTrigger, targetConfig, targetProject, env } = input\n\n if (trigger !== expectedTrigger) return 'skip'\n\n if (!env.session) return 'skip'\n\n if (env.cleared) return 'skip'\n\n // Manual load present (a config is loaded but it wasn't auto-loaded) \u2014 leave it.\n if (env.currentConfig && !env.autoLoadedMarker) return 'skip'\n\n // Our own auto-load already matches the target config+project \u2014 nothing to do.\n if (env.autoLoadedMarker && env.currentConfig === targetConfig && env.currentProject === targetProject) {\n return 'skip'\n }\n\n return 'load'\n}\n\nexport interface RunEnvAutoLoadArgs {\n expectedTrigger: AutoLoadTrigger\n}\n\n/**\n * Resolve config, evaluate the guards, and (if it should) produce env-load.sh with\n * the auto-load marker. Returns the written file path, or `null` when auto-load was\n * skipped or failed. NEVER throws. Transient failures (Doppler offline / not\n * authenticated / network) record a backoff marker so they aren't re-probed on every\n * command, and are surfaced once per session on the interactive (cli-invocation)\n * channel. No producer-side lock \u2014 a rare cold-shell double-fetch is tolerated (the\n * second write is atomic and idempotent).\n */\nexport const runEnvAutoLoad = async ({ expectedTrigger }: RunEnvAutoLoadArgs): Promise<string | null> => {\n // Only the cli-invocation / interactive callsite reaches a TTY; the shell-startup\n // spawn discards stderr, so warning there is invisible and would poison the dedup.\n const canWarn = expectedTrigger === 'cli-invocation'\n\n try {\n const resolved = await resolveEnvAutoLoad(canWarn)\n\n if (!resolved) return null\n\n const decision = decideAutoLoad({\n trigger: resolved.trigger,\n expectedTrigger,\n targetConfig: resolved.config,\n targetProject: resolved.project,\n env: readAutoLoadEnvSnapshot(),\n })\n\n if (decision === 'skip') return null\n\n // Disk-level clear signal: a clear that hasn't yet been sourced into this\n // process's env still suppresses auto-load (clear file newer than load file).\n if (isClearedOnDisk()) return null\n\n // Back off after a recent failure so a down/unauthenticated Doppler isn't\n // re-probed on every command in the same session.\n if (recentlyFailed()) return null\n\n const result = await writeEnvLoadFile({ config: resolved.config, autoLoaded: true })\n\n clearFailure()\n\n return result.filePath\n } catch (error) {\n const reason = (error as Error).message\n\n recordFailure()\n\n // Surface the failure once per session on the interactive channel; stay silent\n // (debug only) on the backgrounded shell-startup path.\n if (canWarn) {\n warnOnce(`infra-kit: env auto-load failed \u2014 ${reason} (will retry later)`)\n } else {\n logger.debug(`env auto-load skipped: ${reason}`)\n }\n\n return null\n }\n}\n\n/** Snapshot the env vars the guards depend on. */\nconst readAutoLoadEnvSnapshot = (): AutoLoadEnvSnapshot => {\n return {\n session: process.env[INFRA_KIT_SESSION_VAR],\n cleared: process.env[INFRA_KIT_ENV_CLEARED_VAR],\n currentConfig: process.env[INFRA_KIT_ENV_CONFIG_VAR],\n currentProject: process.env[INFRA_KIT_ENV_PROJECT_VAR],\n autoLoadedMarker: process.env[INFRA_KIT_ENV_AUTOLOADED_VAR],\n }\n}\n\n/**\n * True when a clear is pending on disk: an env-clear.sh exists and is at least as\n * new as env-load.sh (or no load file remains). Belt-and-suspenders next to the\n * INFRA_KIT_ENV_CLEARED env guard for the window before the shell sources the clear.\n */\nconst isClearedOnDisk = (): boolean => {\n try {\n const dir = getSessionCacheDir()\n const clearPath = path.join(dir, ENV_CLEAR_FILE)\n\n if (!fs.existsSync(clearPath)) return false\n\n const loadPath = path.join(dir, ENV_LOAD_FILE)\n\n if (!fs.existsSync(loadPath)) return true\n\n return fs.statSync(clearPath).mtimeMs >= fs.statSync(loadPath).mtimeMs\n } catch {\n return false\n }\n}\n\n/** True when an auto-load failed within the backoff window (suppress retries). */\nconst recentlyFailed = (): boolean => {\n try {\n const flagPath = path.join(getSessionCacheDir(), FAIL_SENTINEL_FILE)\n\n if (!fs.existsSync(flagPath)) return false\n\n return Date.now() - fs.statSync(flagPath).mtimeMs < FAIL_BACKOFF_MS\n } catch {\n return false\n }\n}\n\n/** Record an auto-load failure (refreshes the backoff window). */\nconst recordFailure = (): void => {\n try {\n const dir = getSessionCacheDir()\n\n fs.mkdirSync(dir, { recursive: true, mode: 0o700 })\n fs.writeFileSync(path.join(dir, FAIL_SENTINEL_FILE), '', { mode: 0o600 })\n } catch {\n // No session cache dir \u2014 nothing to back off against.\n }\n}\n\n/** Clear the failure marker after a successful load. */\nconst clearFailure = (): void => {\n try {\n fs.rmSync(path.join(getSessionCacheDir(), FAIL_SENTINEL_FILE), { force: true })\n } catch {\n // No session cache dir \u2014 nothing to clear.\n }\n}\n\n/**\n * Emit a warning at most once per shell session. Keyed on a flag file in the\n * session cache dir so a misconfigured `envAutoLoad.config` (or a repeated failure)\n * does not spam a warning on every cli-invocation. Falls back to a plain warn when\n * no session cache dir is available.\n */\nconst warnOnce = (message: string): void => {\n try {\n const dir = getSessionCacheDir()\n const flagPath = path.join(dir, WARN_SENTINEL_FILE)\n\n if (fs.existsSync(flagPath)) return\n\n fs.mkdirSync(dir, { recursive: true, mode: 0o700 })\n fs.writeFileSync(flagPath, '', { mode: 0o600 })\n } catch {\n // No session cache dir (e.g. INFRA_KIT_SESSION unset) \u2014 warn without de-dup.\n }\n\n logger.warn(message)\n}\n", "import { runEnvAutoLoad } from 'src/lib/env-autoload'\n\n/**\n * Internal command invoked (backgrounded) by the `infra-kit init` shell-startup\n * integration. Runs the 'shell-startup' trigger, writing env-load.sh when\n * envAutoLoad is configured for it + eligible; the shell precmd hook sources it on\n * a subsequent prompt. Intentionally writes NOTHING to stdout and never throws \u2014\n * auto-load must never disrupt shell startup.\n */\nexport const envAutoload = async (): Promise<void> => {\n await runEnvAutoLoad({ expectedTrigger: 'shell-startup' })\n}\n", "import fs from 'node:fs/promises'\nimport path from 'node:path'\nimport process from 'node:process'\nimport { pathToFileURL } from 'node:url'\n\nimport { getProjectRoot } from 'src/lib/git-utils'\nimport { logger } from 'src/lib/logger'\nimport { fileExists, tildify } from 'src/lib/path-display'\nimport { VENDOR_CONFIG_FILE } from 'src/lib/vendor/config-schema'\nimport { expandTilde, getFactoryConfigPath, loadFactoryConfig } from 'src/lib/vendor/factory-config'\n\ninterface VendorConfigOptions {\n /** Scaffold `~/.infra-kit/vendor.json` instead of printing the current one. */\n init?: boolean\n /** Source repo root used for legacy `targets` auto-seeding. Defaults to the git toplevel. */\n cwd?: string\n}\n\n/** Placeholder workspace dir written by `--init`; the user edits it to their layout. */\nconst PLACEHOLDER_WORKSPACE_DIR = '~/projects'\n\n/**\n * Surface or scaffold the machine-local factory config\n * (`~/.infra-kit/vendor.json`). CLI-only \u2014 NOT an MCP tool; returns nothing\n * and signals problems via `process.exitCode`.\n *\n * Without `--init`: prints the factory file path + existence, the resolved\n * `workspaceDir` + existence, and per-target reachability (`[\u2713]`/`[ ]`). Exits\n * non-zero if the file is missing, the workspace dir is missing, or any target\n * is unreachable, so it is usable as a doctor check.\n *\n * With `--init`: scaffolds the file (skipping if it already exists), seeding\n * `targets` from a legacy source `vendor.config.ts` when one is readable.\n */\nexport const vendorConfig = async (options: VendorConfigOptions = {}): Promise<void> => {\n if (options.init) {\n await initFactoryConfig(options.cwd)\n\n return\n }\n\n await printFactoryConfig()\n}\n\n/** Render the factory config chain with `[\u2713]`/`[ ]` reachability markers. */\nconst printFactoryConfig = async (): Promise<void> => {\n const factoryPath = getFactoryConfigPath()\n const exists = await fileExists(factoryPath)\n\n logger.info(`Factory config: ${tildify(factoryPath)} ${exists ? '[\u2713]' : '[ ]'}`)\n\n if (!exists) {\n logger.info('\\nNot found \u2014 run `infra-kit vendor-config --init` to scaffold it.')\n process.exitCode = 1\n\n return\n }\n\n const { workspaceDir, targets } = await loadFactoryConfig()\n const resolvedWorkspace = expandTilde(workspaceDir)\n const workspaceExists = await fileExists(resolvedWorkspace)\n\n logger.info(\n `workspaceDir: ${workspaceDir} (resolved: ${resolvedWorkspace}) ${workspaceExists ? '[\u2713 exists]' : '[ ] not found'}`,\n )\n logger.info('Targets:')\n\n let allReachable = workspaceExists\n\n for (const repo of targets) {\n const targetPath = path.join(resolvedWorkspace, repo)\n const reachable = await fileExists(targetPath)\n\n if (!reachable) {\n allReachable = false\n }\n\n const marker = reachable ? '[\u2713]' : '[ ]'\n const suffix = reachable ? '' : ' (not found \u2014 clone or remove)'\n\n logger.info(` ${marker} ${repo} ${tildify(targetPath)}${suffix}`)\n }\n\n if (!allReachable) {\n process.exitCode = 1\n }\n}\n\n/** Scaffold `~/.infra-kit/vendor.json`, skipping if it already exists. */\nconst initFactoryConfig = async (cwd?: string): Promise<void> => {\n const factoryPath = getFactoryConfigPath()\n\n if (await fileExists(factoryPath)) {\n logger.info(`Factory config already exists at ${tildify(factoryPath)} \u2014 leaving it untouched.`)\n\n return\n }\n\n const sourceRoot = cwd ?? (await getProjectRoot())\n const seededTargets = await readLegacyTargets(sourceRoot)\n\n await fs.mkdir(path.dirname(factoryPath), { recursive: true })\n await fs.writeFile(factoryPath, buildScaffold(seededTargets), 'utf-8')\n\n logger.info(`\u2713 Created ${tildify(factoryPath)}`)\n\n if (seededTargets.length > 0) {\n logger.info(` Seeded ${seededTargets.length} target(s) from the source ${VENDOR_CONFIG_FILE}.`)\n }\n\n logger.info(` Edit \\`workspaceDir\\` (placeholder: ${PLACEHOLDER_WORKSPACE_DIR}) to point at where your repos live.`)\n\n if (seededTargets.length === 0) {\n logger.info(' Add at least one repo name to `targets` before running vendor sync/manifest/diff.')\n }\n}\n\n/**\n * Best-effort read of a legacy `targets` array from the source repo's\n * `vendor.config.ts`. The current schema no longer accepts `targets`, so this\n * reads the raw default export directly (bypassing validation). Returns `[]` on\n * any failure \u2014 seeding is a convenience, never a hard requirement.\n */\nconst readLegacyTargets = async (sourceRoot: string): Promise<string[]> => {\n try {\n const configPath = path.join(sourceRoot, VENDOR_CONFIG_FILE)\n const stat = await fs.stat(configPath)\n const moduleUrl = `${pathToFileURL(configPath).href}?mtime=${Number(stat.mtimeMs)}`\n const imported = (await import(moduleUrl)) as { default?: unknown }\n const raw = imported.default\n const resolved = typeof raw === 'function' ? await (raw as () => unknown)() : raw\n\n if (resolved && typeof resolved === 'object' && 'targets' in resolved) {\n const targets = (resolved as { targets?: unknown }).targets\n\n if (\n Array.isArray(targets) &&\n targets.every((t) => {\n return typeof t === 'string'\n })\n ) {\n return targets as string[]\n }\n }\n } catch {\n // Absent or unreadable source config \u2014 fall through to an empty placeholder.\n }\n\n return []\n}\n\n/**\n * Render the scaffold file body as strict JSON (`vendor.json`). The factory config\n * is static JSON, loaded with `JSON.parse` \u2014 no comments, no executable code. When\n * `targets` is empty the stub writes `\"targets\": []`, which fails the schema's\n * `targets.min(1)` on load: this is intentional \u2014 `--init` produces an incomplete\n * stub the user must edit before running vendor sync/manifest/diff. The annotated\n * guidance lives in the sibling `vendor.example.jsonc` (seeded by `infra-kit init`).\n */\nconst buildScaffold = (targets: string[]): string => {\n return `${JSON.stringify({ workspaceDir: PLACEHOLDER_WORKSPACE_DIR, targets }, null, 2)}\\n`\n}\n", "import type { Command } from 'commander'\nimport process from 'node:process'\n\n/**\n * `--json` output mode for the CLI. This is a presentation concern only: every\n * command handler already returns a `structuredContent` payload (the same one\n * the MCP surface consumes). Human/log output goes to stderr (see lib/logger),\n * so writing the structured payload to stdout never collides with it.\n */\n\nexport interface CommandResult {\n structuredContent?: unknown\n}\n\n/** Mutable holder (object so `prefer-const` holds while the flag toggles per run). */\nexport const jsonOutput = { enabled: false }\n\n/**\n * In `--json` mode, write a command result's `structuredContent` to stdout as\n * pretty JSON and return the result unchanged. Outside `--json` mode it is a\n * no-op pass-through. The writer is injectable for testing.\n */\nexport const emit = <T extends CommandResult | void>(\n result: T,\n write: (text: string) => void = (text) => {\n process.stdout.write(text)\n },\n): T => {\n if (jsonOutput.enabled && result && result.structuredContent != null) {\n write(`${JSON.stringify(result.structuredContent, null, 2)}\\n`)\n }\n\n return result\n}\n\n/** Register `--json` on a command and every nested subcommand (idempotent). */\nexport const addJsonOption = (cmd: Command): void => {\n const alreadyHasJson = cmd.options.some((option) => {\n return option.long === '--json'\n })\n\n if (!alreadyHasJson) {\n cmd.option('--json', 'Output the structured result as JSON on stdout (human logs stay on stderr)')\n }\n\n cmd.commands.forEach(addJsonOption)\n}\n", "/**\n * Small shared rendering helpers for aligned terminal output. These replace\n * the ad-hoc \"compute the max width, then padEnd each row\" pattern that the\n * interactive menu (and similar list views) hand-rolled. Pure string helpers \u2014\n * no I/O, no color \u2014 so they are trivially testable and reusable.\n */\n\n/**\n * Align a list of two-column rows: pad every left cell to the widest left cell,\n * then join the two cells with `gap`. Returns one rendered line per row.\n *\n * @example\n * formatAlignedRows([['a', 'x'], ['bbb', 'y']])\n * // ['a x', 'bbb y'] (left padded to width 3, default 2-space gap)\n */\nexport const formatAlignedRows = (rows: ReadonlyArray<readonly [string, string]>, gap = ' '): string[] => {\n const width = rows.reduce((max, [left]) => {\n return Math.max(max, left.length)\n }, 0)\n\n return rows.map(([left, right]) => {\n return `${left.padEnd(width)}${gap}${right}`\n })\n}\n"],
5
+ "mappings": "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",
6
+ "names": ["select", "Separator", "Command", "process", "fs", "path", "process", "$", "configPath", "paths", "getInfraKitConfigPaths", "rows", "row", "fileExists", "logger", "marker", "tildify", "structuredContent", "configEdit", "editor", "process", "fs", "path", "examplePath", "exampleSiblingPath", "buildUserProjectExample", "$", "resetInfraKitConfigCache", "jsonPath", "projectName", "fs", "path", "process", "WARN_SENTINEL_FILE", "FAIL_SENTINEL_FILE", "FAIL_BACKOFF_MS", "resolveEnvAutoLoad", "canWarn", "config", "getInfraKitConfig", "autoLoad", "warnOnce", "decideAutoLoad", "input", "trigger", "expectedTrigger", "targetConfig", "targetProject", "env", "runEnvAutoLoad", "resolved", "readAutoLoadEnvSnapshot", "isClearedOnDisk", "recentlyFailed", "result", "writeEnvLoadFile", "clearFailure", "error", "reason", "recordFailure", "logger", "process", "INFRA_KIT_SESSION_VAR", "INFRA_KIT_ENV_CLEARED_VAR", "INFRA_KIT_ENV_CONFIG_VAR", "INFRA_KIT_ENV_PROJECT_VAR", "INFRA_KIT_ENV_AUTOLOADED_VAR", "dir", "getSessionCacheDir", "clearPath", "path", "ENV_CLEAR_FILE", "fs", "loadPath", "ENV_LOAD_FILE", "flagPath", "message", "envAutoload", "runEnvAutoLoad", "fs", "path", "process", "pathToFileURL", "PLACEHOLDER_WORKSPACE_DIR", "vendorConfig", "options", "initFactoryConfig", "printFactoryConfig", "factoryPath", "getFactoryConfigPath", "exists", "fileExists", "logger", "tildify", "process", "workspaceDir", "targets", "loadFactoryConfig", "resolvedWorkspace", "expandTilde", "workspaceExists", "allReachable", "repo", "targetPath", "path", "reachable", "marker", "suffix", "cwd", "sourceRoot", "getProjectRoot", "seededTargets", "readLegacyTargets", "fs", "buildScaffold", "VENDOR_CONFIG_FILE", "configPath", "stat", "raw", "pathToFileURL", "resolved", "t", "process", "jsonOutput", "emit", "result", "write", "text", "addJsonOption", "cmd", "option", "formatAlignedRows", "rows", "gap", "width", "max", "left", "right", "program", "Command", "collectReleaseSpec", "value", "prev", "parseRepos", "normalizeIdeMode", "flagName", "IDE_MODES", "runProgram", "argv", "error", "message", "logger", "process", "invokedViaMenu", "deprecatedAlias", "cmd", "preferred", "configureMergeDev", "options", "emit", "ghMergeDev", "configureReleaseList", "ghReleaseList", "configureReleaseCreate", "inputs", "parseReleaseSpec", "releases", "releaseCreate", "configureReleaseDescEdit", "releaseDescEdit", "configureReleaseDeployAll", "ghReleaseDeployAll", "configureReleaseDeploySelected", "ghReleaseDeploySelected", "configureReleaseDeliver", "ghReleaseDeliver", "configureWorktreesSync", "worktreesSync", "configureWorktreesAdd", "ide", "worktreesAdd", "configureWorktreesList", "worktreesList", "configureWorktreesRemove", "worktreesRemove", "configureWorktreesReload", "worktreesReload", "configureVendorConfig", "vendorConfig", "releaseGroup", "worktreesGroup", "configCmd", "configPath", "configEdit", "result", "audit", "vendorCmd", "vendorCheck", "vendorSync", "vendorManifest", "vendorDiff", "doctor", "version", "envStatus", "envList", "init", "envLoad", "envClear", "envAutoload", "addJsonOption", "isAutoLoadExcludedCommand", "name", "_thisCommand", "actionCommand", "jsonOutput", "runEnvAutoLoad", "releaseCommands", "getMenuGroupCommands", "worktreeCommands", "envCommands", "commandMap", "paletteItems", "label", "names", "selected", "runCommandPalette", "alignedLabels", "formatAlignedRows", "item", "labelByName", "index", "toChoices", "select", "Separator"]
7
7
  }