@shepai/cli 1.69.0 → 1.70.1

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 (136) hide show
  1. package/dist/packages/core/src/application/use-cases/tools/list-tools.use-case.d.ts +1 -1
  2. package/dist/packages/core/src/application/use-cases/tools/list-tools.use-case.d.ts.map +1 -1
  3. package/dist/packages/core/src/infrastructure/services/deployment/deployment-logger.d.ts +7 -0
  4. package/dist/packages/core/src/infrastructure/services/deployment/deployment-logger.d.ts.map +1 -0
  5. package/dist/packages/core/src/infrastructure/services/deployment/deployment-logger.js +17 -0
  6. package/dist/packages/core/src/infrastructure/services/deployment/deployment.service.d.ts.map +1 -1
  7. package/dist/packages/core/src/infrastructure/services/deployment/deployment.service.js +60 -7
  8. package/dist/packages/core/src/infrastructure/services/deployment/detect-dev-script.d.ts.map +1 -1
  9. package/dist/packages/core/src/infrastructure/services/deployment/detect-dev-script.js +13 -6
  10. package/dist/packages/core/src/infrastructure/services/tool-installer/tool-installer.service.d.ts +2 -1
  11. package/dist/packages/core/src/infrastructure/services/tool-installer/tool-installer.service.d.ts.map +1 -1
  12. package/dist/packages/core/src/infrastructure/services/tool-installer/tool-installer.service.js +17 -2
  13. package/dist/packages/core/src/infrastructure/services/tool-installer/tool-metadata.d.ts +1 -1
  14. package/dist/packages/core/src/infrastructure/services/tool-installer/tool-metadata.d.ts.map +1 -1
  15. package/dist/packages/core/src/infrastructure/services/tool-installer/tools/CLAUDE.md +45 -18
  16. package/dist/packages/core/src/infrastructure/services/tool-installer/tools/alacritty.json +18 -0
  17. package/dist/packages/core/src/infrastructure/services/tool-installer/tools/iterm2.json +17 -0
  18. package/dist/packages/core/src/infrastructure/services/tool-installer/tools/kitty.json +18 -0
  19. package/dist/packages/core/src/infrastructure/services/tool-installer/tools/tmux.json +27 -0
  20. package/dist/packages/core/src/infrastructure/services/tool-installer/tools/warp.json +17 -0
  21. package/dist/src/presentation/web/app/actions/deploy-feature.d.ts.map +1 -1
  22. package/dist/src/presentation/web/app/actions/deploy-feature.js +11 -0
  23. package/dist/src/presentation/web/app/actions/deploy-repository.d.ts.map +1 -1
  24. package/dist/src/presentation/web/app/actions/deploy-repository.js +8 -0
  25. package/dist/src/presentation/web/components/features/tools/tool-card.d.ts.map +1 -1
  26. package/dist/src/presentation/web/components/features/tools/tool-card.js +1 -0
  27. package/dist/src/presentation/web/components/features/tools/tools-page-client.d.ts.map +1 -1
  28. package/dist/src/presentation/web/components/features/tools/tools-page-client.js +2 -1
  29. package/dist/src/presentation/web/hooks/use-deploy-action.d.ts.map +1 -1
  30. package/dist/src/presentation/web/hooks/use-deploy-action.js +36 -5
  31. package/dist/tsconfig.build.tsbuildinfo +1 -1
  32. package/package.json +1 -1
  33. package/web/.next/BUILD_ID +1 -1
  34. package/web/.next/build-manifest.json +2 -2
  35. package/web/.next/cache/.previewinfo +1 -1
  36. package/web/.next/cache/.rscinfo +1 -1
  37. package/web/.next/cache/.tsbuildinfo +1 -1
  38. package/web/.next/cache/config.json +3 -3
  39. package/web/.next/fallback-build-manifest.json +2 -2
  40. package/web/.next/prerender-manifest.json +3 -3
  41. package/web/.next/required-server-files.js +1 -1
  42. package/web/.next/required-server-files.json +1 -1
  43. package/web/.next/server/app/_global-error.html +2 -2
  44. package/web/.next/server/app/_global-error.rsc +1 -1
  45. package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  46. package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  47. package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  48. package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  49. package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  50. package/web/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  51. package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  52. package/web/.next/server/app/page/server-reference-manifest.json +18 -18
  53. package/web/.next/server/app/page_client-reference-manifest.js +1 -1
  54. package/web/.next/server/app/skills/page/server-reference-manifest.json +5 -5
  55. package/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  56. package/web/.next/server/app/tools/page/server-reference-manifest.json +1 -1
  57. package/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
  58. package/web/.next/server/app/version/page/server-reference-manifest.json +1 -1
  59. package/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
  60. package/web/.next/server/chunks/[root-of-the-server]__09413611._.js.map +1 -1
  61. package/web/.next/server/chunks/ssr/[root-of-the-server]__08ba9bd3._.js +1 -1
  62. package/web/.next/server/chunks/ssr/[root-of-the-server]__08ba9bd3._.js.map +1 -1
  63. package/web/.next/server/chunks/ssr/[root-of-the-server]__249c74f6._.js +1 -1
  64. package/web/.next/server/chunks/ssr/[root-of-the-server]__551fb7e1._.js +1 -1
  65. package/web/.next/server/chunks/ssr/[root-of-the-server]__551fb7e1._.js.map +1 -1
  66. package/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js +1 -1
  67. package/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js.map +1 -1
  68. package/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js +1 -1
  69. package/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js.map +1 -1
  70. package/web/.next/server/chunks/ssr/[root-of-the-server]__9add7c3a._.js +2 -2
  71. package/web/.next/server/chunks/ssr/[root-of-the-server]__9add7c3a._.js.map +1 -1
  72. package/web/.next/server/chunks/ssr/[root-of-the-server]__e41b5eec._.js +2 -2
  73. package/web/.next/server/chunks/ssr/[root-of-the-server]__e41b5eec._.js.map +1 -1
  74. package/web/.next/server/chunks/ssr/_49bf495c._.js +1 -1
  75. package/web/.next/server/chunks/ssr/_49bf495c._.js.map +1 -1
  76. package/web/.next/server/chunks/ssr/_68b5e0de._.js +1 -1
  77. package/web/.next/server/chunks/ssr/_68b5e0de._.js.map +1 -1
  78. package/web/.next/server/chunks/ssr/_690ea95f._.js +1 -1
  79. package/web/.next/server/chunks/ssr/_690ea95f._.js.map +1 -1
  80. package/web/.next/server/chunks/ssr/_725584e5._.js +1 -1
  81. package/web/.next/server/chunks/ssr/_725584e5._.js.map +1 -1
  82. package/web/.next/server/pages/500.html +2 -2
  83. package/web/.next/server/server-reference-manifest.js +1 -1
  84. package/web/.next/server/server-reference-manifest.json +19 -19
  85. package/web/.next/standalone/src/presentation/web/.next/BUILD_ID +1 -1
  86. package/web/.next/standalone/src/presentation/web/.next/build-manifest.json +2 -2
  87. package/web/.next/standalone/src/presentation/web/.next/prerender-manifest.json +3 -3
  88. package/web/.next/standalone/src/presentation/web/.next/required-server-files.json +1 -1
  89. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.html +2 -2
  90. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.rsc +1 -1
  91. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  92. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  93. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  94. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  95. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  96. package/web/.next/standalone/src/presentation/web/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  97. package/web/.next/standalone/src/presentation/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  98. package/web/.next/standalone/src/presentation/web/.next/server/app/page/server-reference-manifest.json +18 -18
  99. package/web/.next/standalone/src/presentation/web/.next/server/app/page_client-reference-manifest.js +1 -1
  100. package/web/.next/standalone/src/presentation/web/.next/server/app/skills/page/server-reference-manifest.json +5 -5
  101. package/web/.next/standalone/src/presentation/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  102. package/web/.next/standalone/src/presentation/web/.next/server/app/tools/page/server-reference-manifest.json +1 -1
  103. package/web/.next/standalone/src/presentation/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
  104. package/web/.next/standalone/src/presentation/web/.next/server/app/version/page/server-reference-manifest.json +1 -1
  105. package/web/.next/standalone/src/presentation/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
  106. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__08ba9bd3._.js +1 -1
  107. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__249c74f6._.js +1 -1
  108. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__551fb7e1._.js +1 -1
  109. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js +1 -1
  110. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js +1 -1
  111. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__9add7c3a._.js +2 -2
  112. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__e41b5eec._.js +2 -2
  113. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_49bf495c._.js +1 -1
  114. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_68b5e0de._.js +1 -1
  115. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_690ea95f._.js +1 -1
  116. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/_725584e5._.js +1 -1
  117. package/web/.next/standalone/src/presentation/web/.next/server/pages/500.html +2 -2
  118. package/web/.next/standalone/src/presentation/web/.next/server/server-reference-manifest.js +1 -1
  119. package/web/.next/standalone/src/presentation/web/.next/server/server-reference-manifest.json +19 -19
  120. package/web/.next/standalone/src/presentation/web/app/actions/deploy-feature.ts +16 -0
  121. package/web/.next/standalone/src/presentation/web/app/actions/deploy-repository.ts +10 -0
  122. package/web/.next/standalone/src/presentation/web/components/features/tools/tool-card.tsx +1 -0
  123. package/web/.next/standalone/src/presentation/web/components/features/tools/tools-page-client.tsx +5 -1
  124. package/web/.next/standalone/src/presentation/web/hooks/use-deploy-action.ts +45 -5
  125. package/web/.next/standalone/src/presentation/web/server.js +1 -1
  126. package/web/.next/static/chunks/16e380b8dd9d11bc.js +1 -0
  127. package/web/.next/static/chunks/{5bc5d426870feb7e.js → 1ed0df845a1625f6.js} +1 -1
  128. package/web/.next/static/chunks/{2da52289a4a8f9e2.js → 24e1d97cab8bad6d.js} +1 -1
  129. package/web/.next/static/chunks/{491ae2bbae40857c.js → 505c6a9e4c5d0808.js} +1 -1
  130. package/web/.next/static/chunks/{5ef9d8b7401f2f1f.js → 9db5c06001f3e664.js} +2 -2
  131. package/web/.next/trace +1 -1
  132. package/web/.next/trace-build +1 -1
  133. package/web/.next/static/chunks/faf8ad4c823884d7.js +0 -1
  134. /package/web/.next/static/{7ktIn83yR3rYLLF00uLSx → 8xZoRkWykApYNlvamCGUe}/_buildManifest.js +0 -0
  135. /package/web/.next/static/{7ktIn83yR3rYLLF00uLSx → 8xZoRkWykApYNlvamCGUe}/_clientMiddlewareManifest.json +0 -0
  136. /package/web/.next/static/{7ktIn83yR3rYLLF00uLSx → 8xZoRkWykApYNlvamCGUe}/_ssgManifest.js +0 -0
@@ -13,7 +13,7 @@ export interface ToolItem {
13
13
  name: string;
14
14
  summary: string;
15
15
  description: string;
16
- tags: ('ide' | 'cli-agent' | 'vcs')[];
16
+ tags: ('ide' | 'cli-agent' | 'vcs' | 'terminal')[];
17
17
  iconUrl: string | undefined;
18
18
  autoInstall: boolean;
19
19
  required: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"list-tools.use-case.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/application/use-cases/tools/list-tools.use-case.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qCAAqC,CAAC;AAClF,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sCAAsC,CAAC;AAGlF,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,CAAC,KAAK,GAAG,WAAW,GAAG,KAAK,CAAC,EAAE,CAAC;IACtC,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,WAAW,EAAE,OAAO,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;IAClB,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,gBAAgB,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,MAAM,EAAE,sBAAsB,CAAC;CAChC;AAED,MAAM,MAAM,eAAe,GAAG,QAAQ,EAAE,CAAC;AAWzC,qBACa,gBAAgB;IAGzB,OAAO,CAAC,QAAQ,CAAC,oBAAoB;gBAApB,oBAAoB,EAAE,qBAAqB;IAGxD,OAAO,IAAI,OAAO,CAAC,eAAe,CAAC;CAgC1C"}
1
+ {"version":3,"file":"list-tools.use-case.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/application/use-cases/tools/list-tools.use-case.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,qCAAqC,CAAC;AAClF,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sCAAsC,CAAC;AAGlF,MAAM,WAAW,QAAQ;IACvB,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;IACpB,IAAI,EAAE,CAAC,KAAK,GAAG,WAAW,GAAG,KAAK,GAAG,UAAU,CAAC,EAAE,CAAC;IACnD,OAAO,EAAE,MAAM,GAAG,SAAS,CAAC;IAC5B,WAAW,EAAE,OAAO,CAAC;IACrB,QAAQ,EAAE,OAAO,CAAC;IAClB,aAAa,EAAE,MAAM,GAAG,SAAS,CAAC;IAClC,gBAAgB,EAAE,MAAM,CAAC;IACzB,cAAc,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,MAAM,EAAE,sBAAsB,CAAC;CAChC;AAED,MAAM,MAAM,eAAe,GAAG,QAAQ,EAAE,CAAC;AAWzC,qBACa,gBAAgB;IAGzB,OAAO,CAAC,QAAQ,CAAC,oBAAoB;gBAApB,oBAAoB,EAAE,qBAAqB;IAGxD,OAAO,IAAI,OAAO,CAAC,eAAe,CAAC;CAgC1C"}
@@ -0,0 +1,7 @@
1
+ export declare function createDeploymentLogger(prefix: string): {
2
+ info: (...args: unknown[]) => void;
3
+ debug: (...args: unknown[]) => void;
4
+ warn: (...args: unknown[]) => void;
5
+ error: (...args: unknown[]) => void;
6
+ };
7
+ //# sourceMappingURL=deployment-logger.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"deployment-logger.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/deployment/deployment-logger.ts"],"names":[],"mappings":"AAWA,wBAAgB,sBAAsB,CAAC,MAAM,EAAE,MAAM;oBAIvB,OAAO,EAAE;qBACR,OAAO,EAAE;oBACpB,OAAO,EAAE;qBACR,OAAO,EAAE;EAE7B"}
@@ -0,0 +1,17 @@
1
+ /* eslint-disable no-console */
2
+ /**
3
+ * Debug-gated logger for deployment services.
4
+ *
5
+ * - `info` and `debug` only emit when `process.env.DEBUG` is set.
6
+ * - `warn` and `error` always emit (they indicate real problems).
7
+ */
8
+ const noop = () => undefined;
9
+ export function createDeploymentLogger(prefix) {
10
+ const isDebug = !!process.env.DEBUG;
11
+ return {
12
+ info: isDebug ? (...args) => console.info(prefix, ...args) : noop,
13
+ debug: isDebug ? (...args) => console.debug(prefix, ...args) : noop,
14
+ warn: (...args) => console.warn(prefix, ...args),
15
+ error: (...args) => console.error(prefix, ...args),
16
+ };
17
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"deployment.service.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/deployment/deployment.service.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,KAAK,EAAqB,MAAM,oBAAoB,CAAC;AAE9D,OAAO,KAAK,EACV,kBAAkB,EAClB,gBAAgB,EACjB,MAAM,qEAAqE,CAAC;AAC7E,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAgBzD,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,OAAO,KAAK,CAAC;IACpB,eAAe,EAAE,OAAO,eAAe,CAAC;IACxC,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,MAAM,KAAK,IAAI,CAAC;IAC7D,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;CACnC;AAgBD,qBAAa,iBAAkB,YAAW,kBAAkB;IAC1D,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAsC;IAClE,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAwB;gBAEjC,IAAI,GAAE,OAAO,CAAC,qBAAqB,CAAM;IAIrD;;;OAGG;IACH,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI;IAmDjD;;;OAGG;IACH,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI;IAMpD;;OAEG;IACG,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA6B3C;;OAEG;IACH,OAAO,IAAI,IAAI;IAMf;;OAEG;IACH,OAAO,CAAC,WAAW;IAQnB;;OAEG;IACH,OAAO,CAAC,oBAAoB;IA0B5B;;OAEG;YACW,aAAa;IAW3B;;OAEG;IACH,OAAO,CAAC,WAAW;CASpB"}
1
+ {"version":3,"file":"deployment.service.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/deployment/deployment.service.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,KAAK,EAAqB,MAAM,oBAAoB,CAAC;AAE9D,OAAO,KAAK,EACV,kBAAkB,EAClB,gBAAgB,EACjB,MAAM,qEAAqE,CAAC;AAC7E,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAkBzD,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,OAAO,KAAK,CAAC;IACpB,eAAe,EAAE,OAAO,eAAe,CAAC;IACxC,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,MAAM,KAAK,IAAI,CAAC;IAC7D,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;CACnC;AAgBD,qBAAa,iBAAkB,YAAW,kBAAkB;IAC1D,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAsC;IAClE,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAwB;gBAEjC,IAAI,GAAE,OAAO,CAAC,qBAAqB,CAAM;IAIrD;;;OAGG;IACH,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,GAAG,IAAI;IA8EjD;;;OAGG;IACH,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI;IAYpD;;OAEG;IACG,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAuC3C;;OAEG;IACH,OAAO,IAAI,IAAI;IAMf;;OAEG;IACH,OAAO,CAAC,WAAW;IAQnB;;OAEG;IACH,OAAO,CAAC,oBAAoB;IAoD5B;;OAEG;YACW,aAAa;IAW3B;;OAEG;IACH,OAAO,CAAC,WAAW;CASpB"}
@@ -9,7 +9,9 @@
9
9
  import { spawn } from 'node:child_process';
10
10
  import { DeploymentState } from '../../../domain/generated/output.js';
11
11
  import { detectDevScript } from './detect-dev-script.js';
12
+ import { createDeploymentLogger } from './deployment-logger.js';
12
13
  import { parsePort } from './parse-port.js';
14
+ const log = createDeploymentLogger('[DeploymentService]');
13
15
  const POLL_INTERVAL_MS = 200;
14
16
  const MAX_WAIT_MS = 5000;
15
17
  const defaultDeps = {
@@ -37,20 +39,24 @@ export class DeploymentService {
37
39
  * If a deployment already exists for this target, it is stopped first.
38
40
  */
39
41
  start(targetId, targetPath) {
42
+ log.info(`start() called — targetId="${targetId}", targetPath="${targetPath}"`);
40
43
  // Stop any existing deployment for this target
41
44
  const existing = this.deployments.get(targetId);
42
45
  if (existing) {
46
+ log.info(`Stopping existing deployment for "${targetId}" (pid=${existing.pid})`);
43
47
  this.killProcess(existing);
44
48
  this.deployments.delete(targetId);
45
49
  }
46
50
  // Detect the dev script
47
51
  const detection = this.deps.detectDevScript(targetPath);
48
52
  if (!detection.success) {
53
+ log.error(`Dev script detection failed: ${detection.error}`);
49
54
  throw new Error(detection.error);
50
55
  }
51
56
  // Build spawn args based on package manager
52
- const { packageManager, scriptName } = detection;
57
+ const { packageManager, scriptName, command } = detection;
53
58
  const args = packageManager === 'npm' ? ['run', scriptName] : [scriptName];
59
+ log.info(`Spawning dev server: command="${command}", packageManager="${packageManager}", scriptName="${scriptName}", cwd="${targetPath}"`);
54
60
  const child = this.deps.spawn(packageManager, args, {
55
61
  shell: true,
56
62
  cwd: targetPath,
@@ -58,8 +64,10 @@ export class DeploymentService {
58
64
  stdio: ['ignore', 'pipe', 'pipe'],
59
65
  });
60
66
  if (!child.pid) {
67
+ log.error('spawn() returned no PID — process failed to start');
61
68
  throw new Error('Failed to spawn dev server: no PID returned');
62
69
  }
70
+ log.info(`Process spawned — pid=${child.pid}`);
63
71
  const entry = {
64
72
  pid: child.pid,
65
73
  child: child,
@@ -73,8 +81,19 @@ export class DeploymentService {
73
81
  // Attach stdout/stderr listeners for port detection
74
82
  this.attachOutputListener(entry, 'stdout');
75
83
  this.attachOutputListener(entry, 'stderr');
84
+ // Handle spawn errors (command not found, permission denied, etc.)
85
+ child.on('error', (err) => {
86
+ log.error(`Child process error for "${targetId}" (pid=${entry.pid}): ${err.message}`);
87
+ entry.state = DeploymentState.Stopped;
88
+ this.deployments.delete(targetId);
89
+ });
76
90
  // Clean up on process exit
77
- child.on('exit', () => {
91
+ child.on('exit', (code, signal) => {
92
+ const wasBooting = entry.state === DeploymentState.Booting;
93
+ log.info(`Process exited for "${targetId}" (pid=${entry.pid}) — code=${code}, signal=${signal}, wasBooting=${wasBooting}`);
94
+ if (wasBooting) {
95
+ log.warn('Process exited while still in Booting state — dev server likely crashed on startup. Check stderr output above.');
96
+ }
78
97
  this.deployments.delete(targetId);
79
98
  });
80
99
  }
@@ -84,8 +103,11 @@ export class DeploymentService {
84
103
  */
85
104
  getStatus(targetId) {
86
105
  const entry = this.deployments.get(targetId);
87
- if (!entry)
106
+ if (!entry) {
107
+ log.debug(`getStatus("${targetId}") — no deployment found`);
88
108
  return null;
109
+ }
110
+ log.debug(`getStatus("${targetId}") — state=${entry.state}, url=${entry.url}, pid=${entry.pid}`);
89
111
  return { state: entry.state, url: entry.url };
90
112
  }
91
113
  /**
@@ -93,20 +115,24 @@ export class DeploymentService {
93
115
  */
94
116
  async stop(targetId) {
95
117
  const entry = this.deployments.get(targetId);
96
- if (!entry)
118
+ if (!entry) {
119
+ log.info(`stop("${targetId}") — no deployment found, nothing to stop`);
97
120
  return;
121
+ }
122
+ log.info(`stop("${targetId}") — sending SIGTERM to process group (pid=${entry.pid})`);
98
123
  // Send SIGTERM to process group
99
124
  try {
100
125
  this.deps.kill(-entry.pid, 'SIGTERM');
101
126
  }
102
127
  catch {
103
- // Process may already be dead
128
+ log.info(`stop("${targetId}") process already dead on SIGTERM`);
104
129
  this.deployments.delete(targetId);
105
130
  return;
106
131
  }
107
132
  // Wait for the process to exit
108
133
  const died = await this.pollUntilDead(entry.pid, MAX_WAIT_MS, POLL_INTERVAL_MS);
109
134
  if (!died) {
135
+ log.warn(`stop("${targetId}") — process did not exit after ${MAX_WAIT_MS}ms, escalating to SIGKILL`);
110
136
  // Escalate to SIGKILL
111
137
  try {
112
138
  this.deps.kill(-entry.pid, 'SIGKILL');
@@ -115,6 +141,9 @@ export class DeploymentService {
115
141
  // Process may have exited between check and kill
116
142
  }
117
143
  }
144
+ else {
145
+ log.info(`stop("${targetId}") — process exited gracefully`);
146
+ }
118
147
  // Wait for the exit event to clean up the map
119
148
  await this.waitForExit(entry.child);
120
149
  }
@@ -143,26 +172,50 @@ export class DeploymentService {
143
172
  attachOutputListener(entry, stream) {
144
173
  const bufferKey = stream === 'stdout' ? 'stdoutBuffer' : 'stderrBuffer';
145
174
  const childStream = entry.child[stream];
146
- if (!childStream)
175
+ if (!childStream) {
176
+ log.warn(`[${entry.targetId}] No ${stream} stream available — cannot attach listener`);
147
177
  return;
178
+ }
148
179
  childStream.on('data', (chunk) => {
180
+ const text = chunk.toString();
149
181
  // Append chunk to buffer
150
- entry[bufferKey] += chunk.toString();
182
+ entry[bufferKey] += text;
151
183
  // Process complete lines
152
184
  const lines = entry[bufferKey].split('\n');
153
185
  // Keep the last element (incomplete line) in the buffer
154
186
  entry[bufferKey] = lines.pop() ?? '';
155
187
  for (const line of lines) {
188
+ if (!line.trim())
189
+ continue;
190
+ log.debug(`[${entry.targetId}] ${stream}: ${line}`);
156
191
  if (entry.state !== DeploymentState.Booting)
157
192
  break;
158
193
  const url = parsePort(line);
159
194
  if (url) {
195
+ log.info(`[${entry.targetId}] Port detected — url="${url}" (from ${stream})`);
160
196
  entry.state = DeploymentState.Ready;
161
197
  entry.url = url;
162
198
  break;
163
199
  }
164
200
  }
165
201
  });
202
+ childStream.on('end', () => {
203
+ // Flush remaining buffer content
204
+ const remaining = entry[bufferKey].trim();
205
+ if (remaining) {
206
+ log.debug(`[${entry.targetId}] ${stream} (flush): ${remaining}`);
207
+ if (entry.state === DeploymentState.Booting) {
208
+ const url = parsePort(remaining);
209
+ if (url) {
210
+ log.info(`[${entry.targetId}] Port detected in flushed buffer — url="${url}"`);
211
+ entry.state = DeploymentState.Ready;
212
+ entry.url = url;
213
+ }
214
+ }
215
+ entry[bufferKey] = '';
216
+ }
217
+ log.debug(`[${entry.targetId}] ${stream} stream ended`);
218
+ });
166
219
  }
167
220
  /**
168
221
  * Poll until a process is dead or timeout expires.
@@ -1 +1 @@
1
- {"version":3,"file":"detect-dev-script.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/deployment/detect-dev-script.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAeH,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,IAAI,CAAC;IACd,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,KAAK,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,MAAM,qBAAqB,GAAG,sBAAsB,GAAG,oBAAoB,CAAC;AAElF;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,qBAAqB,CA4BtE"}
1
+ {"version":3,"file":"detect-dev-script.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/deployment/detect-dev-script.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAgBH,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,IAAI,CAAC;IACd,cAAc,EAAE,MAAM,CAAC;IACvB,UAAU,EAAE,MAAM,CAAC;IACnB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,KAAK,CAAC;IACf,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,MAAM,qBAAqB,GAAG,sBAAsB,GAAG,oBAAoB,CAAC;AAIlF;;;;;GAKG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,GAAG,qBAAqB,CAuCtE"}
@@ -7,6 +7,7 @@
7
7
  */
8
8
  import { readFileSync, existsSync } from 'node:fs';
9
9
  import { join } from 'node:path';
10
+ import { createDeploymentLogger } from './deployment-logger.js';
10
11
  /** Script names to search for, in priority order */
11
12
  const SCRIPT_PRIORITY = ['dev', 'start', 'serve'];
12
13
  /** Lockfile-to-package-manager mapping, checked in order */
@@ -15,6 +16,7 @@ const LOCKFILE_MANAGERS = [
15
16
  { lockfile: 'yarn.lock', manager: 'yarn' },
16
17
  { lockfile: 'package-lock.json', manager: 'npm' },
17
18
  ];
19
+ const log = createDeploymentLogger('[detectDevScript]');
18
20
  /**
19
21
  * Detect the dev script and package manager for a project directory.
20
22
  *
@@ -22,28 +24,33 @@ const LOCKFILE_MANAGERS = [
22
24
  * @returns Detection result with command info, or an error
23
25
  */
24
26
  export function detectDevScript(dirPath) {
27
+ log.info(`scanning dirPath="${dirPath}"`);
25
28
  // Read and parse package.json
26
29
  let packageJson;
27
30
  try {
28
31
  const raw = readFileSync(join(dirPath, 'package.json'), 'utf-8');
29
32
  packageJson = JSON.parse(raw);
30
33
  }
31
- catch {
32
- return { success: false, error: `No package.json found in ${dirPath}` };
34
+ catch (err) {
35
+ const msg = `No package.json found in ${dirPath}`;
36
+ log.error(msg, err);
37
+ return { success: false, error: msg };
33
38
  }
34
39
  // Find the first matching script in priority order
35
40
  const scripts = packageJson.scripts ?? {};
41
+ const availableScripts = Object.keys(scripts);
42
+ log.info(`available scripts: [${availableScripts.join(', ')}], looking for: [${SCRIPT_PRIORITY.join(', ')}]`);
36
43
  const scriptName = SCRIPT_PRIORITY.find((name) => name in scripts);
37
44
  if (!scriptName) {
38
- return {
39
- success: false,
40
- error: `No dev script found in package.json. Expected one of: ${SCRIPT_PRIORITY.join(', ')}`,
41
- };
45
+ const msg = `No dev script found in package.json. Expected one of: ${SCRIPT_PRIORITY.join(', ')}`;
46
+ log.warn(msg);
47
+ return { success: false, error: msg };
42
48
  }
43
49
  // Detect package manager from lockfile
44
50
  const packageManager = detectPackageManager(dirPath);
45
51
  // Build the command — pnpm/yarn use `<pm> <script>`, npm uses `npm run <script>`
46
52
  const command = packageManager === 'npm' ? `npm run ${scriptName}` : `${packageManager} ${scriptName}`;
53
+ log.info(`detected — packageManager="${packageManager}", scriptName="${scriptName}", command="${command}"`);
47
54
  return { success: true, packageManager, scriptName, command };
48
55
  }
49
56
  /**
@@ -15,7 +15,8 @@ import type { IToolInstallerService } from '../../../application/ports/output/se
15
15
  import type { ToolInstallationStatus, ToolInstallCommand } from '../../../domain/generated/output.js';
16
16
  export declare class ToolInstallerServiceImpl implements IToolInstallerService {
17
17
  /**
18
- * Check if a tool binary is available on the system (PATH check)
18
+ * Check if a tool binary is available on the system (PATH check,
19
+ * with verifyCommand fallback for GUI apps).
19
20
  */
20
21
  checkAvailability(toolName: string): Promise<ToolInstallationStatus>;
21
22
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"tool-installer.service.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/tool-installer/tool-installer.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sEAAsE,CAAC;AAClH,OAAO,KAAK,EACV,sBAAsB,EACtB,kBAAkB,EAEnB,MAAM,qCAAqC,CAAC;AA6C7C,qBACa,wBAAyB,YAAW,qBAAqB;IACpE;;OAEG;IACG,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,sBAAsB,CAAC;IA4B1E;;;OAGG;IACH,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI;IAqB9D;;;OAGG;IACG,cAAc,CAClB,QAAQ,EAAE,MAAM,EAChB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAChC,OAAO,CAAC,sBAAsB,CAAC;IAuElC;;OAEG;IACH,OAAO,CAAC,6BAA6B;CA4BtC"}
1
+ {"version":3,"file":"tool-installer.service.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/tool-installer/tool-installer.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAKH,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,sEAAsE,CAAC;AAClH,OAAO,KAAK,EACV,sBAAsB,EACtB,kBAAkB,EAEnB,MAAM,qCAAqC,CAAC;AAsD7C,qBACa,wBAAyB,YAAW,qBAAqB;IACpE;;;OAGG;IACG,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,sBAAsB,CAAC;IAoC1E;;;OAGG;IACH,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,kBAAkB,GAAG,IAAI;IAqB9D;;;OAGG;IACG,cAAc,CAClB,QAAQ,EAAE,MAAM,EAChB,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,GAChC,OAAO,CAAC,sBAAsB,CAAC;IAuElC;;OAEG;IACH,OAAO,CAAC,6BAA6B;CA4BtC"}
@@ -18,7 +18,7 @@ var __decorate = (this && this.__decorate) || function (decorators, target, key,
18
18
  return c > 3 && r && Object.defineProperty(target, key, r), r;
19
19
  };
20
20
  import { injectable } from 'tsyringe';
21
- import { execFile, spawn } from 'node:child_process';
21
+ import { exec, execFile, spawn } from 'node:child_process';
22
22
  import { platform } from 'node:os';
23
23
  import { createAvailableStatus, createMissingStatus, createErrorStatus, } from '../../../domain/value-objects/tool-installation-status.js';
24
24
  import { TOOL_METADATA } from './tool-metadata.js';
@@ -55,9 +55,17 @@ const checkBinaryExists = (binary) => {
55
55
  });
56
56
  });
57
57
  };
58
+ /**
59
+ * Run a shell command and resolve true when it exits 0, false otherwise.
60
+ * Used as a fallback for GUI apps whose binary isn't in PATH (e.g. Warp, iTerm2).
61
+ */
62
+ const runVerifyCommand = (command) => new Promise((resolve) => {
63
+ exec(command, (err) => resolve(!err));
64
+ });
58
65
  let ToolInstallerServiceImpl = class ToolInstallerServiceImpl {
59
66
  /**
60
- * Check if a tool binary is available on the system (PATH check)
67
+ * Check if a tool binary is available on the system (PATH check,
68
+ * with verifyCommand fallback for GUI apps).
61
69
  */
62
70
  async checkAvailability(toolName) {
63
71
  const metadata = TOOL_METADATA[toolName];
@@ -69,6 +77,13 @@ let ToolInstallerServiceImpl = class ToolInstallerServiceImpl {
69
77
  if (result.found) {
70
78
  return createAvailableStatus(toolName);
71
79
  }
80
+ // Binary not in PATH — try verifyCommand as fallback (handles GUI .app bundles)
81
+ if (result.notInPath && metadata.verifyCommand) {
82
+ const verified = await runVerifyCommand(metadata.verifyCommand);
83
+ if (verified) {
84
+ return createAvailableStatus(toolName);
85
+ }
86
+ }
72
87
  if (result.notInPath) {
73
88
  const suggestions = this.createInstallationSuggestions(metadata);
74
89
  return createMissingStatus(toolName, suggestions);
@@ -15,7 +15,7 @@ export interface ToolMetadata {
15
15
  /** Detailed description */
16
16
  description: string;
17
17
  /** Tool tags for grouping in listings. A tool can belong to multiple categories. */
18
- tags: ('ide' | 'cli-agent' | 'vcs')[];
18
+ tags: ('ide' | 'cli-agent' | 'vcs' | 'terminal')[];
19
19
  /** URL to the tool's icon/logo image */
20
20
  iconUrl?: string;
21
21
  /** Binary name to check with 'which' command (string or per-platform map) */
@@ -1 +1 @@
1
- {"version":3,"file":"tool-metadata.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/tool-installer/tool-metadata.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,MAAM,WAAW,YAAY;IAC3B,kCAAkC;IAClC,IAAI,EAAE,MAAM,CAAC;IAEb,6BAA6B;IAC7B,OAAO,EAAE,MAAM,CAAC;IAEhB,2BAA2B;IAC3B,WAAW,EAAE,MAAM,CAAC;IAEpB,oFAAoF;IACpF,IAAI,EAAE,CAAC,KAAK,GAAG,WAAW,GAAG,KAAK,CAAC,EAAE,CAAC;IAEtC,wCAAwC;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,6EAA6E;IAC7E,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAExC,6CAA6C;IAC7C,cAAc,EAAE,MAAM,CAAC;IAEvB,wFAAwF;IACxF,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEjC,2CAA2C;IAC3C,OAAO,EAAE,MAAM,CAAC;IAEhB,iCAAiC;IACjC,gBAAgB,EAAE,MAAM,CAAC;IAEzB,8DAA8D;IAC9D,aAAa,EAAE,MAAM,CAAC;IAEtB,uEAAuE;IACvE,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB,kFAAkF;IAClF,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;yGAEqG;IACrG,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEhD;;iGAE6F;IAC7F,YAAY,CAAC,EAAE;QACb,KAAK,CAAC,EAAE,OAAO,CAAC;QAChB,KAAK,CAAC,EAAE,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAC;QACtC,QAAQ,CAAC,EAAE,OAAO,CAAC;KACpB,CAAC;IAEF;;;;wEAIoE;IACpE,eAAe,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACnD;AA8CD,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAsB,CAAC;AAE9E;;;;GAIG;AACH,wBAAgB,aAAa,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC,EAAE,CAExD"}
1
+ {"version":3,"file":"tool-metadata.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/tool-installer/tool-metadata.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAMH,MAAM,WAAW,YAAY;IAC3B,kCAAkC;IAClC,IAAI,EAAE,MAAM,CAAC;IAEb,6BAA6B;IAC7B,OAAO,EAAE,MAAM,CAAC;IAEhB,2BAA2B;IAC3B,WAAW,EAAE,MAAM,CAAC;IAEpB,oFAAoF;IACpF,IAAI,EAAE,CAAC,KAAK,GAAG,WAAW,GAAG,KAAK,GAAG,UAAU,CAAC,EAAE,CAAC;IAEnD,wCAAwC;IACxC,OAAO,CAAC,EAAE,MAAM,CAAC;IAEjB,6EAA6E;IAC7E,MAAM,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAExC,6CAA6C;IAC7C,cAAc,EAAE,MAAM,CAAC;IAEvB,wFAAwF;IACxF,QAAQ,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEjC,2CAA2C;IAC3C,OAAO,EAAE,MAAM,CAAC;IAEhB,iCAAiC;IACjC,gBAAgB,EAAE,MAAM,CAAC;IAEzB,8DAA8D;IAC9D,aAAa,EAAE,MAAM,CAAC;IAEtB,uEAAuE;IACvE,WAAW,CAAC,EAAE,OAAO,CAAC;IAEtB,kFAAkF;IAClF,QAAQ,CAAC,EAAE,OAAO,CAAC;IAEnB;;yGAEqG;IACrG,aAAa,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IAEhD;;iGAE6F;IAC7F,YAAY,CAAC,EAAE;QACb,KAAK,CAAC,EAAE,OAAO,CAAC;QAChB,KAAK,CAAC,EAAE,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAC;QACtC,QAAQ,CAAC,EAAE,OAAO,CAAC;KACpB,CAAC;IAEF;;;;wEAIoE;IACpE,eAAe,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CACnD;AA8CD,eAAO,MAAM,aAAa,EAAE,MAAM,CAAC,MAAM,EAAE,YAAY,CAAsB,CAAC;AAE9E;;;;GAIG;AACH,wBAAgB,aAAa,IAAI,CAAC,MAAM,EAAE,YAAY,CAAC,EAAE,CAExD"}
@@ -5,24 +5,24 @@ Files are loaded dynamically by `tool-metadata.ts` — the filename (minus `.jso
5
5
 
6
6
  ## Schema
7
7
 
8
- | Field | Type | Required | Description |
9
- | ------------------ | --------------------------------- | -------- | ------------------------------------------------------------------------ |
10
- | `name` | `string` | Yes | Human-readable display name |
11
- | `summary` | `string` | Yes | One-line description |
12
- | `description` | `string` | Yes | Detailed description |
13
- | `tags` | `("ide"\|"cli-agent"\|"vcs")[]` | Yes | Categories for filtering in UI and CLI |
14
- | `iconUrl` | `string` | No | URL to SVG/PNG icon (use cdn.simpleicons.org when possible) |
15
- | `binary` | `string \| Record<string,string>` | Yes | Binary name for `which` check. Per-platform map if differs |
16
- | `packageManager` | `string` | Yes | Install method label (apt, brew, curl, manual, download) |
17
- | `commands` | `Record<string,string>` | Yes | Platform-keyed install commands (`linux`, `darwin`) |
18
- | `timeout` | `number` | Yes | Install timeout in ms (typically 300000) |
19
- | `documentationUrl` | `string` | Yes | Official docs URL |
20
- | `verifyCommand` | `string` | Yes | Command to verify installation (e.g. `git --version`) |
21
- | `autoInstall` | `boolean` | No | `true` (default) = run commands automatically. `false` = manual download |
22
- | `required` | `boolean` | No | `true` = tool is required for platform to function |
23
- | `openDirectory` | `string \| Record<string,string>` | No | Command to open a directory. Use `{dir}` placeholder |
24
- | `spawnOptions` | `object` | No | Override spawn behavior (see below) |
25
- | `terminalCommand` | `string \| Record<string,string>` | No | Command to open tool in a **new terminal window** from web UI |
8
+ | Field | Type | Required | Description |
9
+ | ------------------ | ------------------------------------------- | -------- | ------------------------------------------------------------------------ |
10
+ | `name` | `string` | Yes | Human-readable display name |
11
+ | `summary` | `string` | Yes | One-line description |
12
+ | `description` | `string` | Yes | Detailed description |
13
+ | `tags` | `("ide"\|"cli-agent"\|"vcs"\|"terminal")[]` | Yes | Categories for filtering in UI and CLI |
14
+ | `iconUrl` | `string` | No | URL to SVG/PNG icon (use cdn.simpleicons.org when possible) |
15
+ | `binary` | `string \| Record<string,string>` | Yes | Binary name for `which` check. Per-platform map if differs |
16
+ | `packageManager` | `string` | Yes | Install method label (apt, brew, curl, manual, download) |
17
+ | `commands` | `Record<string,string>` | Yes | Platform-keyed install commands (`linux`, `darwin`) |
18
+ | `timeout` | `number` | Yes | Install timeout in ms (typically 300000) |
19
+ | `documentationUrl` | `string` | Yes | Official docs URL |
20
+ | `verifyCommand` | `string` | Yes | Command to verify installation (e.g. `git --version`) |
21
+ | `autoInstall` | `boolean` | No | `true` (default) = run commands automatically. `false` = manual download |
22
+ | `required` | `boolean` | No | `true` = tool is required for platform to function |
23
+ | `openDirectory` | `string \| Record<string,string>` | No | Command to open a directory. Use `{dir}` placeholder |
24
+ | `spawnOptions` | `object` | No | Override spawn behavior (see below) |
25
+ | `terminalCommand` | `string \| Record<string,string>` | No | Command to open tool in a **new terminal window** from web UI |
26
26
 
27
27
  ## Spawn Options
28
28
 
@@ -59,5 +59,32 @@ The launcher auto-detects TTY: CLI launch uses `openDirectory`, web launch uses
59
59
  | `ide` | GUI code editor | VS Code, Cursor, Zed |
60
60
  | `cli-agent` | Terminal-based AI coding agent | Claude Code, Cursor CLI |
61
61
  | `vcs` | Version control tool | Git, GitHub CLI |
62
+ | `terminal` | Terminal emulator/multiplexer | tmux, Kitty, Alacritty |
62
63
 
63
64
  Tools can have multiple tags. A tool appears in all matching filter tabs in the UI.
65
+
66
+ ### Terminal Tools
67
+
68
+ Terminal tools use the `terminal` tag. GUI terminals (Kitty, Alacritty) use `brew install --cask` on macOS.
69
+ CLI tools like tmux use `brew install` (formula). Terminals with `--working-directory` flags can include
70
+ `openDirectory` for launch support. tmux requires `spawnOptions` with `shell: true` and `stdio: "inherit"`
71
+ since it runs inside the current terminal session.
72
+
73
+ Example (tmux):
74
+
75
+ ```json
76
+ {
77
+ "name": "tmux",
78
+ "summary": "Terminal multiplexer for session management",
79
+ "tags": ["terminal"],
80
+ "binary": "tmux",
81
+ "packageManager": "brew",
82
+ "commands": { "darwin": "brew install tmux", "linux": "apt install -y tmux" },
83
+ "timeout": 300000,
84
+ "documentationUrl": "https://github.com/tmux/tmux/wiki",
85
+ "verifyCommand": "tmux -V",
86
+ "autoInstall": true,
87
+ "openDirectory": "tmux new-session -c {dir}",
88
+ "spawnOptions": { "shell": true, "stdio": "inherit", "detached": false }
89
+ }
90
+ ```
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "Alacritty",
3
+ "summary": "GPU-accelerated terminal emulator",
4
+ "description": "Alacritty is a modern, GPU-accelerated terminal emulator focused on simplicity and performance. Cross-platform (macOS and Linux). On older Linux distributions, you may need to add a PPA before installing via apt.",
5
+ "tags": ["terminal"],
6
+ "iconUrl": "https://cdn.simpleicons.org/alacritty",
7
+ "binary": "alacritty",
8
+ "packageManager": "brew",
9
+ "commands": {
10
+ "darwin": "brew install --cask alacritty",
11
+ "linux": "apt install -y alacritty"
12
+ },
13
+ "timeout": 300000,
14
+ "documentationUrl": "https://alacritty.org/",
15
+ "verifyCommand": "alacritty --version",
16
+ "autoInstall": false,
17
+ "openDirectory": "alacritty --working-directory {dir}"
18
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "iTerm2",
3
+ "summary": "macOS terminal replacement",
4
+ "description": "iTerm2 is a feature-rich replacement for the default macOS Terminal.app with split panes, search, autocomplete, and extensive customization. macOS only. Verified by checking for the iTerm.app bundle in /Applications.",
5
+ "tags": ["terminal"],
6
+ "iconUrl": "https://cdn.simpleicons.org/iterm2",
7
+ "binary": "iterm2",
8
+ "packageManager": "brew",
9
+ "commands": {
10
+ "darwin": "brew install --cask iterm2"
11
+ },
12
+ "timeout": 300000,
13
+ "documentationUrl": "https://iterm2.com/documentation.html",
14
+ "verifyCommand": "test -d /Applications/iTerm.app",
15
+ "autoInstall": false,
16
+ "openDirectory": "open -a iTerm {dir}"
17
+ }
@@ -0,0 +1,18 @@
1
+ {
2
+ "name": "Kitty",
3
+ "summary": "Fast, GPU-based terminal emulator",
4
+ "description": "Kitty is a fast, feature-rich, GPU-based terminal emulator with advanced graphics support, extensibility via kittens, and modern rendering. Cross-platform (macOS and Linux).",
5
+ "tags": ["terminal"],
6
+ "iconUrl": "https://raw.githubusercontent.com/kovidgoyal/kitty/master/logo/kitty.svg",
7
+ "binary": "kitty",
8
+ "packageManager": "brew",
9
+ "commands": {
10
+ "darwin": "brew install --cask kitty",
11
+ "linux": "apt install -y kitty"
12
+ },
13
+ "timeout": 300000,
14
+ "documentationUrl": "https://sw.kovidgoyal.net/kitty/",
15
+ "verifyCommand": "kitty --version",
16
+ "autoInstall": false,
17
+ "openDirectory": "kitty --working-directory {dir}"
18
+ }
@@ -0,0 +1,27 @@
1
+ {
2
+ "name": "tmux",
3
+ "summary": "Terminal multiplexer for session management",
4
+ "description": "tmux is a terminal multiplexer that lets you create, manage, and switch between multiple terminal sessions. Ideal for remote development, persistent sessions, and multi-pane workflows. Cross-platform (macOS and Linux).",
5
+ "tags": ["terminal"],
6
+ "iconUrl": "https://cdn.simpleicons.org/tmux",
7
+ "binary": "tmux",
8
+ "packageManager": "brew",
9
+ "commands": {
10
+ "darwin": "brew install tmux",
11
+ "linux": "apt install -y tmux"
12
+ },
13
+ "timeout": 300000,
14
+ "documentationUrl": "https://github.com/tmux/tmux/wiki",
15
+ "verifyCommand": "tmux -V",
16
+ "autoInstall": true,
17
+ "openDirectory": "tmux new-session -c {dir}",
18
+ "terminalCommand": {
19
+ "darwin": "osascript -e 'tell application \"Terminal\" to do script \"tmux new-session -c {dir}\"' -e 'tell application \"Terminal\" to activate'",
20
+ "linux": "x-terminal-emulator -e tmux new-session -c {dir}"
21
+ },
22
+ "spawnOptions": {
23
+ "shell": true,
24
+ "stdio": "inherit",
25
+ "detached": false
26
+ }
27
+ }
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "Warp",
3
+ "summary": "Modern terminal with AI features",
4
+ "description": "Warp is a modern terminal with AI-powered features, intelligent command suggestions, and a collaborative workflow. macOS only — Linux users can install manually via AppImage from https://www.warp.dev/.",
5
+ "tags": ["terminal"],
6
+ "iconUrl": "https://cdn.simpleicons.org/warp",
7
+ "binary": "warp",
8
+ "packageManager": "brew",
9
+ "commands": {
10
+ "darwin": "brew install --cask warp"
11
+ },
12
+ "timeout": 300000,
13
+ "documentationUrl": "https://docs.warp.dev/",
14
+ "verifyCommand": "test -d /Applications/Warp.app",
15
+ "autoInstall": false,
16
+ "openDirectory": "open -a Warp {dir}"
17
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"deploy-feature.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/web/app/actions/deploy-feature.ts"],"names":[],"mappings":"AAOA,OAAO,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AAEvE,wBAAsB,aAAa,CACjC,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,eAAe,CAAA;CAAE,CAAC,CA2BxE"}
1
+ {"version":3,"file":"deploy-feature.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/web/app/actions/deploy-feature.ts"],"names":[],"mappings":"AAQA,OAAO,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AAIvE,wBAAsB,aAAa,CACjC,SAAS,EAAE,MAAM,GAChB,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,eAAe,CAAA;CAAE,CAAC,CAwCxE"}
@@ -1,28 +1,39 @@
1
1
  'use server';
2
2
  import { existsSync } from 'node:fs';
3
3
  import { resolve } from '../../lib/server-container.js';
4
+ import { createDeploymentLogger } from '../../../../../packages/core/src/infrastructure/services/deployment/deployment-logger.js';
4
5
  import { computeWorktreePath } from '../../../../../packages/core/src/infrastructure/services/ide-launchers/compute-worktree-path.js';
5
6
  import { DeploymentState } from '../../../../../packages/core/src/domain/generated/output.js';
7
+ const log = createDeploymentLogger('[deployFeature]');
6
8
  export async function deployFeature(featureId) {
9
+ log.info(`called — featureId="${featureId}"`);
7
10
  if (!featureId?.trim()) {
11
+ log.warn('rejected — featureId is empty');
8
12
  return { success: false, error: 'featureId is required' };
9
13
  }
10
14
  try {
11
15
  const featureRepo = resolve('IFeatureRepository');
12
16
  const feature = await featureRepo.findById(featureId);
13
17
  if (!feature) {
18
+ log.warn(`feature not found in repository: "${featureId}"`);
14
19
  return { success: false, error: `Feature not found: ${featureId}` };
15
20
  }
21
+ log.info(`feature found — repositoryPath="${feature.repositoryPath}", branch="${feature.branch}"`);
16
22
  const worktreePath = computeWorktreePath(feature.repositoryPath, feature.branch);
23
+ log.info(`computed worktreePath="${worktreePath}"`);
17
24
  if (!existsSync(worktreePath)) {
25
+ log.warn(`worktree path does not exist on disk: "${worktreePath}"`);
18
26
  return { success: false, error: `Worktree path does not exist: ${worktreePath}` };
19
27
  }
28
+ log.info('worktree path exists, calling deploymentService.start()');
20
29
  const deploymentService = resolve('IDeploymentService');
21
30
  deploymentService.start(featureId, worktreePath);
31
+ log.info('start() returned successfully — state=Booting');
22
32
  return { success: true, state: DeploymentState.Booting };
23
33
  }
24
34
  catch (error) {
25
35
  const message = error instanceof Error ? error.message : 'Failed to deploy feature';
36
+ log.error(`error: ${message}`, error);
26
37
  return { success: false, error: message };
27
38
  }
28
39
  }
@@ -1 +1 @@
1
- {"version":3,"file":"deploy-repository.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/web/app/actions/deploy-repository.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AAEvE,wBAAsB,gBAAgB,CACpC,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,eAAe,CAAA;CAAE,CAAC,CAkBxE"}
1
+ {"version":3,"file":"deploy-repository.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/web/app/actions/deploy-repository.ts"],"names":[],"mappings":"AAMA,OAAO,EAAE,eAAe,EAAE,MAAM,sCAAsC,CAAC;AAIvE,wBAAsB,gBAAgB,CACpC,cAAc,EAAE,MAAM,GACrB,OAAO,CAAC;IAAE,OAAO,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAC;IAAC,KAAK,CAAC,EAAE,eAAe,CAAA;CAAE,CAAC,CAyBxE"}