@shepai/cli 1.25.0 → 1.26.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (163) hide show
  1. package/dist/packages/core/src/infrastructure/services/ide-launchers/antigravity.launcher.d.ts.map +1 -1
  2. package/dist/packages/core/src/infrastructure/services/ide-launchers/compute-worktree-path.d.ts +17 -0
  3. package/dist/packages/core/src/infrastructure/services/ide-launchers/compute-worktree-path.d.ts.map +1 -0
  4. package/dist/packages/core/src/infrastructure/services/ide-launchers/compute-worktree-path.js +24 -0
  5. package/dist/packages/core/src/infrastructure/services/ide-launchers/cursor.launcher.d.ts.map +1 -1
  6. package/dist/packages/core/src/infrastructure/services/ide-launchers/ide-launcher.interface.d.ts.map +1 -1
  7. package/dist/packages/core/src/infrastructure/services/ide-launchers/ide-launcher.registry.d.ts.map +1 -1
  8. package/dist/packages/core/src/infrastructure/services/ide-launchers/launch-ide.d.ts +30 -0
  9. package/dist/packages/core/src/infrastructure/services/ide-launchers/launch-ide.d.ts.map +1 -0
  10. package/dist/packages/core/src/infrastructure/services/ide-launchers/launch-ide.js +41 -0
  11. package/dist/packages/core/src/infrastructure/services/ide-launchers/vscode.launcher.d.ts.map +1 -1
  12. package/dist/packages/core/src/infrastructure/services/ide-launchers/windsurf.launcher.d.ts.map +1 -1
  13. package/dist/packages/core/src/infrastructure/services/ide-launchers/zed.launcher.d.ts.map +1 -1
  14. package/dist/packages/core/src/infrastructure/services/settings.service.d.ts +3 -1
  15. package/dist/packages/core/src/infrastructure/services/settings.service.d.ts.map +1 -1
  16. package/dist/packages/core/src/infrastructure/services/settings.service.js +27 -12
  17. package/dist/src/presentation/cli/commands/agent/show.command.d.ts.map +1 -1
  18. package/dist/src/presentation/cli/commands/agent/show.command.js +1 -8
  19. package/dist/src/presentation/cli/commands/feat/show.command.d.ts.map +1 -1
  20. package/dist/src/presentation/cli/commands/feat/show.command.js +1 -8
  21. package/dist/src/presentation/cli/commands/ide-open.command.d.ts.map +1 -1
  22. package/dist/src/presentation/cli/commands/ide-open.command.js +11 -21
  23. package/dist/src/presentation/web/app/api/ide/open/route.d.ts +9 -0
  24. package/dist/src/presentation/web/app/api/ide/open/route.d.ts.map +1 -0
  25. package/dist/src/presentation/web/app/api/ide/open/route.js +29 -0
  26. package/dist/src/presentation/web/app/api/shell/open/route.d.ts +9 -0
  27. package/dist/src/presentation/web/app/api/shell/open/route.d.ts.map +1 -0
  28. package/dist/src/presentation/web/app/api/shell/open/route.js +51 -0
  29. package/dist/src/presentation/web/app/api/validate-toolbar-input.d.ts +17 -0
  30. package/dist/src/presentation/web/app/api/validate-toolbar-input.d.ts.map +1 -0
  31. package/dist/src/presentation/web/app/api/validate-toolbar-input.js +25 -0
  32. package/dist/src/presentation/web/app/page.d.ts.map +1 -1
  33. package/dist/src/presentation/web/app/page.js +2 -0
  34. package/dist/src/presentation/web/components/common/feature-drawer/feature-drawer.d.ts.map +1 -1
  35. package/dist/src/presentation/web/components/common/feature-drawer/feature-drawer.js +11 -2
  36. package/dist/src/presentation/web/components/common/feature-drawer/feature-drawer.stories.d.ts +8 -0
  37. package/dist/src/presentation/web/components/common/feature-drawer/feature-drawer.stories.d.ts.map +1 -1
  38. package/dist/src/presentation/web/components/common/feature-drawer/feature-drawer.stories.js +31 -0
  39. package/dist/src/presentation/web/components/common/feature-drawer/use-feature-actions.d.ts +14 -0
  40. package/dist/src/presentation/web/components/common/feature-drawer/use-feature-actions.d.ts.map +1 -0
  41. package/dist/src/presentation/web/components/common/feature-drawer/use-feature-actions.js +58 -0
  42. package/dist/src/presentation/web/components/common/feature-node/feature-node-state-config.d.ts +4 -0
  43. package/dist/src/presentation/web/components/common/feature-node/feature-node-state-config.d.ts.map +1 -1
  44. package/dist/src/presentation/web/components/common/feature-node/feature-node.stories.d.ts.map +1 -1
  45. package/dist/src/presentation/web/components/common/feature-node/feature-node.stories.js +18 -0
  46. package/dist/src/presentation/web/components/common/index.d.ts +1 -0
  47. package/dist/src/presentation/web/components/common/index.d.ts.map +1 -1
  48. package/dist/src/presentation/web/components/common/index.js +1 -0
  49. package/dist/src/presentation/web/components/features/control-center/control-center.stories.d.ts.map +1 -1
  50. package/dist/src/presentation/web/components/features/control-center/control-center.stories.js +16 -0
  51. package/dist/src/presentation/web/components/features/control-center/use-control-center-state.d.ts.map +1 -1
  52. package/dist/src/presentation/web/components/features/control-center/use-control-center-state.js +2 -0
  53. package/dist/src/presentation/web/components/features/features-canvas/features-canvas.stories.d.ts.map +1 -1
  54. package/dist/src/presentation/web/components/features/features-canvas/features-canvas.stories.js +44 -0
  55. package/dist/tsconfig.build.tsbuildinfo +1 -1
  56. package/package.json +1 -1
  57. package/web/.next/BUILD_ID +1 -1
  58. package/web/.next/app-path-routes-manifest.json +2 -0
  59. package/web/.next/build-manifest.json +2 -2
  60. package/web/.next/cache/.previewinfo +1 -1
  61. package/web/.next/cache/.rscinfo +1 -1
  62. package/web/.next/cache/.tsbuildinfo +1 -1
  63. package/web/.next/cache/config.json +3 -3
  64. package/web/.next/fallback-build-manifest.json +2 -2
  65. package/web/.next/prerender-manifest.json +3 -3
  66. package/web/.next/required-server-files.js +1 -1
  67. package/web/.next/required-server-files.json +1 -1
  68. package/web/.next/routes-manifest.json +12 -0
  69. package/web/.next/server/app/_global-error/page.js +1 -1
  70. package/web/.next/server/app/_global-error/page.js.nft.json +1 -1
  71. package/web/.next/server/app/_global-error.html +2 -2
  72. package/web/.next/server/app/_global-error.rsc +1 -1
  73. package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  74. package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  75. package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  76. package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  77. package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  78. package/web/.next/server/app/_not-found/page.js +1 -1
  79. package/web/.next/server/app/_not-found/page.js.nft.json +1 -1
  80. package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  81. package/web/.next/server/app/_not-found.html +2 -2
  82. package/web/.next/server/app/_not-found.rsc +2 -2
  83. package/web/.next/server/app/_not-found.segments/_full.segment.rsc +2 -2
  84. package/web/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  85. package/web/.next/server/app/_not-found.segments/_index.segment.rsc +2 -2
  86. package/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  87. package/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  88. package/web/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
  89. package/web/.next/server/app/api/dialog/pick-files/route.js +1 -1
  90. package/web/.next/server/app/api/dialog/pick-files/route.js.nft.json +1 -1
  91. package/web/.next/server/app/api/dialog/pick-folder/route.js +1 -1
  92. package/web/.next/server/app/api/dialog/pick-folder/route.js.nft.json +1 -1
  93. package/web/.next/server/app/api/features/create/route.js +1 -1
  94. package/web/.next/server/app/api/features/create/route.js.nft.json +1 -1
  95. package/web/.next/server/app/api/ide/open/route/app-paths-manifest.json +3 -0
  96. package/web/.next/server/app/api/ide/open/route/build-manifest.json +11 -0
  97. package/web/.next/server/app/api/ide/open/route/server-reference-manifest.json +4 -0
  98. package/web/.next/server/app/api/ide/open/route.js +6 -0
  99. package/web/.next/server/app/api/ide/open/route.js.map +5 -0
  100. package/web/.next/server/app/api/ide/open/route.js.nft.json +1 -0
  101. package/web/.next/server/app/api/ide/open/route_client-reference-manifest.js +2 -0
  102. package/web/.next/server/app/api/shell/open/route/app-paths-manifest.json +3 -0
  103. package/web/.next/server/app/api/shell/open/route/build-manifest.json +11 -0
  104. package/web/.next/server/app/api/shell/open/route/server-reference-manifest.json +4 -0
  105. package/web/.next/server/app/api/shell/open/route.js +6 -0
  106. package/web/.next/server/app/api/shell/open/route.js.map +5 -0
  107. package/web/.next/server/app/api/shell/open/route.js.nft.json +1 -0
  108. package/web/.next/server/app/api/shell/open/route_client-reference-manifest.js +2 -0
  109. package/web/.next/server/app/page.js +1 -1
  110. package/web/.next/server/app/page.js.nft.json +1 -1
  111. package/web/.next/server/app/page_client-reference-manifest.js +1 -1
  112. package/web/.next/server/app/version/page.js +1 -1
  113. package/web/.next/server/app/version/page.js.nft.json +1 -1
  114. package/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
  115. package/web/.next/server/app/version.html +2 -2
  116. package/web/.next/server/app/version.rsc +2 -2
  117. package/web/.next/server/app/version.segments/_full.segment.rsc +2 -2
  118. package/web/.next/server/app/version.segments/_head.segment.rsc +1 -1
  119. package/web/.next/server/app/version.segments/_index.segment.rsc +2 -2
  120. package/web/.next/server/app/version.segments/_tree.segment.rsc +2 -2
  121. package/web/.next/server/app/version.segments/version/__PAGE__.segment.rsc +1 -1
  122. package/web/.next/server/app/version.segments/version.segment.rsc +1 -1
  123. package/web/.next/server/app-paths-manifest.json +2 -0
  124. package/web/.next/server/chunks/744ca_web__next-internal_server_app_api_shell_open_route_actions_814dc5b6.js +3 -0
  125. package/web/.next/server/chunks/744ca_web__next-internal_server_app_api_shell_open_route_actions_814dc5b6.js.map +1 -0
  126. package/web/.next/server/chunks/{[root-of-the-server]__ec87d735._.js → [root-of-the-server]__1913013c._.js} +2 -2
  127. package/web/.next/server/chunks/[root-of-the-server]__56ac1509._.js +3 -0
  128. package/web/.next/server/chunks/[root-of-the-server]__56ac1509._.js.map +1 -0
  129. package/web/.next/server/chunks/[root-of-the-server]__602cce1b._.js +3 -0
  130. package/web/.next/server/chunks/[root-of-the-server]__602cce1b._.js.map +1 -0
  131. package/web/.next/server/chunks/{[root-of-the-server]__a6bf88cc._.js → [root-of-the-server]__bb4fc5b5._.js} +2 -2
  132. package/web/.next/server/chunks/{[root-of-the-server]__4e987cf3._.js → [root-of-the-server]__eaa478b7._.js} +2 -2
  133. package/web/.next/server/chunks/b1a17_presentation_web__next-internal_server_app_api_ide_open_route_actions_9fe6e1cd.js +3 -0
  134. package/web/.next/server/chunks/b1a17_presentation_web__next-internal_server_app_api_ide_open_route_actions_9fe6e1cd.js.map +1 -0
  135. package/web/.next/server/chunks/ssr/[root-of-the-server]__97377864._.js +3 -0
  136. package/web/.next/server/chunks/ssr/[root-of-the-server]__f12b60be._.js +1 -1
  137. package/web/.next/server/chunks/ssr/[root-of-the-server]__f285e474._.js +3 -0
  138. package/web/.next/server/chunks/ssr/_09afa42a._.js +1 -1
  139. package/web/.next/server/chunks/ssr/_09afa42a._.js.map +1 -1
  140. package/web/.next/server/chunks/ssr/src_presentation_web_ed0934e5._.js +1 -1
  141. package/web/.next/server/chunks/ssr/src_presentation_web_ed0934e5._.js.map +1 -1
  142. package/web/.next/server/pages/404.html +2 -2
  143. package/web/.next/server/pages/500.html +2 -2
  144. package/web/.next/server/server-reference-manifest.js +1 -1
  145. package/web/.next/server/server-reference-manifest.json +1 -1
  146. package/web/.next/static/chunks/86ff2b6444e06e88.css +2 -0
  147. package/web/.next/static/chunks/{1c236dcc303f3033.js → c2854b6c6d0ca1f3.js} +2 -2
  148. package/web/.next/trace +1 -1
  149. package/web/.next/trace-build +1 -1
  150. package/web/.next/types/link.d.ts +2 -0
  151. package/web/.next/types/routes.d.ts +3 -1
  152. package/web/.next/types/validator.ts +18 -0
  153. package/web/.next/server/chunks/ssr/[root-of-the-server]__757c7912._.js +0 -3
  154. package/web/.next/server/chunks/ssr/[root-of-the-server]__dbd220d2._.js +0 -3
  155. package/web/.next/static/chunks/74748b4d725c5c74.css +0 -2
  156. /package/web/.next/server/chunks/{[root-of-the-server]__ec87d735._.js.map → [root-of-the-server]__1913013c._.js.map} +0 -0
  157. /package/web/.next/server/chunks/{[root-of-the-server]__a6bf88cc._.js.map → [root-of-the-server]__bb4fc5b5._.js.map} +0 -0
  158. /package/web/.next/server/chunks/{[root-of-the-server]__4e987cf3._.js.map → [root-of-the-server]__eaa478b7._.js.map} +0 -0
  159. /package/web/.next/server/chunks/ssr/{[root-of-the-server]__757c7912._.js.map → [root-of-the-server]__97377864._.js.map} +0 -0
  160. /package/web/.next/server/chunks/ssr/{[root-of-the-server]__dbd220d2._.js.map → [root-of-the-server]__f285e474._.js.map} +0 -0
  161. /package/web/.next/static/{-dFLqLT3RMg1ueqbAhsJk → _6j6GS-S6zPiASj5tsxJ8}/_buildManifest.js +0 -0
  162. /package/web/.next/static/{-dFLqLT3RMg1ueqbAhsJk → _6j6GS-S6zPiASj5tsxJ8}/_clientMiddlewareManifest.json +0 -0
  163. /package/web/.next/static/{-dFLqLT3RMg1ueqbAhsJk → _6j6GS-S6zPiASj5tsxJ8}/_ssgManifest.js +0 -0
@@ -1 +1 @@
1
- {"version":3,"file":"antigravity.launcher.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/ide-launchers/antigravity.launcher.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,qCAAqC,CAAC;AACjE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAE5D,qBAAa,mBAAoB,YAAW,WAAW;IACrD,QAAQ,CAAC,IAAI,iBAAiB;IAC9B,QAAQ,CAAC,QAAQ,0BAA0B;IAC3C,QAAQ,CAAC,MAAM,iBAAiB;IAE1B,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQzC,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC;CAOnC"}
1
+ {"version":3,"file":"antigravity.launcher.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/ide-launchers/antigravity.launcher.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAC;AAC9D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAE5D,qBAAa,mBAAoB,YAAW,WAAW;IACrD,QAAQ,CAAC,IAAI,iBAAiB;IAC9B,QAAQ,CAAC,QAAQ,0BAA0B;IAC3C,QAAQ,CAAC,MAAM,iBAAiB;IAE1B,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQzC,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC;CAOnC"}
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Compute Worktree Path
3
+ *
4
+ * Pure utility that computes the filesystem path for a feature's git worktree
5
+ * given a repository path and branch name.
6
+ *
7
+ * Path format: ~/.shep/repos/<sha256-hash-prefix>/wt/<branch-slug>
8
+ */
9
+ /**
10
+ * Compute the worktree path for a given repository and branch.
11
+ *
12
+ * @param repoPath - Absolute path to the repository
13
+ * @param branch - Git branch name (slashes are replaced with hyphens)
14
+ * @returns Absolute path to the worktree directory under ~/.shep/repos/
15
+ */
16
+ export declare function computeWorktreePath(repoPath: string, branch: string): string;
17
+ //# sourceMappingURL=compute-worktree-path.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"compute-worktree-path.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/ide-launchers/compute-worktree-path.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAQH;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAI5E"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Compute Worktree Path
3
+ *
4
+ * Pure utility that computes the filesystem path for a feature's git worktree
5
+ * given a repository path and branch name.
6
+ *
7
+ * Path format: ~/.shep/repos/<sha256-hash-prefix>/wt/<branch-slug>
8
+ */
9
+ import { createHash } from 'node:crypto';
10
+ import { homedir } from 'node:os';
11
+ import { join } from 'node:path';
12
+ const SHEP_HOME_DIR = join(homedir(), '.shep');
13
+ /**
14
+ * Compute the worktree path for a given repository and branch.
15
+ *
16
+ * @param repoPath - Absolute path to the repository
17
+ * @param branch - Git branch name (slashes are replaced with hyphens)
18
+ * @returns Absolute path to the worktree directory under ~/.shep/repos/
19
+ */
20
+ export function computeWorktreePath(repoPath, branch) {
21
+ const repoHash = createHash('sha256').update(repoPath).digest('hex').slice(0, 16);
22
+ const slug = branch.replace(/\//g, '-');
23
+ return join(SHEP_HOME_DIR, 'repos', repoHash, 'wt', slug);
24
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"cursor.launcher.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/ide-launchers/cursor.launcher.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,qCAAqC,CAAC;AACjE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAE5D,qBAAa,cAAe,YAAW,WAAW;IAChD,QAAQ,CAAC,IAAI,YAAY;IACzB,QAAQ,CAAC,QAAQ,qBAAqB;IACtC,QAAQ,CAAC,MAAM,YAAY;IAErB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQzC,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC;CAOnC"}
1
+ {"version":3,"file":"cursor.launcher.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/ide-launchers/cursor.launcher.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAC;AAC9D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAE5D,qBAAa,cAAe,YAAW,WAAW;IAChD,QAAQ,CAAC,IAAI,YAAY;IACzB,QAAQ,CAAC,QAAQ,qBAAqB;IACtC,QAAQ,CAAC,MAAM,YAAY;IAErB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQzC,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC;CAOnC"}
@@ -1 +1 @@
1
- {"version":3,"file":"ide-launcher.interface.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/ide-launchers/ide-launcher.interface.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qCAAqC,CAAC;AAEtE,MAAM,WAAW,WAAW;IAC1B,wDAAwD;IACxD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,4DAA4D;IAC5D,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC;IAE9B,2DAA2D;IAC3D,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAExB;;;;;;OAMG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEpC;;;;OAIG;IACH,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;CACpC"}
1
+ {"version":3,"file":"ide-launcher.interface.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/ide-launchers/ide-launcher.interface.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAC;AAEnE,MAAM,WAAW,WAAW;IAC1B,wDAAwD;IACxD,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC;IAEtB,4DAA4D;IAC5D,QAAQ,CAAC,QAAQ,EAAE,UAAU,CAAC;IAE9B,2DAA2D;IAC3D,QAAQ,CAAC,MAAM,EAAE,MAAM,CAAC;IAExB;;;;;;OAMG;IACH,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;IAEpC;;;;OAIG;IACH,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC,CAAC;CACpC"}
@@ -1 +1 @@
1
- {"version":3,"file":"ide-launcher.registry.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/ide-launchers/ide-launcher.registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qCAAqC,CAAC;AACtE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,6BAA6B,CAAC;AAO/D;;;;GAIG;AACH,wBAAgB,sBAAsB,IAAI,GAAG,CAAC,UAAU,EAAE,WAAW,CAAC,CAcrE"}
1
+ {"version":3,"file":"ide-launcher.registry.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/ide-launchers/ide-launcher.registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAC;AACnE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAO5D;;;;GAIG;AACH,wBAAgB,sBAAsB,IAAI,GAAG,CAAC,UAAU,EAAE,WAAW,CAAC,CAcrE"}
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Shared IDE launch logic used by both CLI and Web presentation layers.
3
+ *
4
+ * Returns a discriminated union so callers can map errors to their own format
5
+ * (CLI messages vs HTTP status codes).
6
+ */
7
+ import type { EditorType } from '../../../domain/generated/output.js';
8
+ export interface LaunchIdeInput {
9
+ /** Which editor to launch. */
10
+ editorId: EditorType;
11
+ /** Absolute path to the repository root. */
12
+ repositoryPath: string;
13
+ /** Git branch name. */
14
+ branch: string;
15
+ /** Whether to verify binary availability before launching. Default: false. */
16
+ checkAvailability?: boolean;
17
+ }
18
+ export interface LaunchIdeSuccess {
19
+ ok: true;
20
+ editorName: string;
21
+ worktreePath: string;
22
+ }
23
+ export interface LaunchIdeFailed {
24
+ ok: false;
25
+ code: 'unknown_editor' | 'editor_unavailable' | 'launch_failed';
26
+ message: string;
27
+ }
28
+ export type LaunchIdeResult = LaunchIdeSuccess | LaunchIdeFailed;
29
+ export declare function launchIde(input: LaunchIdeInput): Promise<LaunchIdeResult>;
30
+ //# sourceMappingURL=launch-ide.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"launch-ide.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/ide-launchers/launch-ide.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAC;AAInE,MAAM,WAAW,cAAc;IAC7B,8BAA8B;IAC9B,QAAQ,EAAE,UAAU,CAAC;IACrB,4CAA4C;IAC5C,cAAc,EAAE,MAAM,CAAC;IACvB,uBAAuB;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,8EAA8E;IAC9E,iBAAiB,CAAC,EAAE,OAAO,CAAC;CAC7B;AAED,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,IAAI,CAAC;IACT,UAAU,EAAE,MAAM,CAAC;IACnB,YAAY,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,eAAe;IAC9B,EAAE,EAAE,KAAK,CAAC;IACV,IAAI,EAAE,gBAAgB,GAAG,oBAAoB,GAAG,eAAe,CAAC;IAChE,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,MAAM,eAAe,GAAG,gBAAgB,GAAG,eAAe,CAAC;AAEjE,wBAAsB,SAAS,CAAC,KAAK,EAAE,cAAc,GAAG,OAAO,CAAC,eAAe,CAAC,CAkC/E"}
@@ -0,0 +1,41 @@
1
+ /**
2
+ * Shared IDE launch logic used by both CLI and Web presentation layers.
3
+ *
4
+ * Returns a discriminated union so callers can map errors to their own format
5
+ * (CLI messages vs HTTP status codes).
6
+ */
7
+ import { createLauncherRegistry } from './ide-launcher.registry.js';
8
+ import { computeWorktreePath } from './compute-worktree-path.js';
9
+ export async function launchIde(input) {
10
+ const registry = createLauncherRegistry();
11
+ const launcher = registry.get(input.editorId);
12
+ if (!launcher) {
13
+ return {
14
+ ok: false,
15
+ code: 'unknown_editor',
16
+ message: `No launcher found for editor: ${input.editorId}. Supported: ${[...registry.keys()].join(', ')}`,
17
+ };
18
+ }
19
+ if (input.checkAvailability) {
20
+ const available = await launcher.checkAvailable();
21
+ if (!available) {
22
+ return {
23
+ ok: false,
24
+ code: 'editor_unavailable',
25
+ message: `${launcher.name} is not available — ensure "${launcher.binary}" is installed and on your PATH`,
26
+ };
27
+ }
28
+ }
29
+ try {
30
+ const worktreePath = computeWorktreePath(input.repositoryPath, input.branch);
31
+ await launcher.launch(worktreePath);
32
+ return { ok: true, editorName: launcher.name, worktreePath };
33
+ }
34
+ catch (error) {
35
+ return {
36
+ ok: false,
37
+ code: 'launch_failed',
38
+ message: error instanceof Error ? error.message : 'Failed to launch IDE',
39
+ };
40
+ }
41
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"vscode.launcher.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/ide-launchers/vscode.launcher.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,qCAAqC,CAAC;AACjE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAE5D,qBAAa,cAAe,YAAW,WAAW;IAChD,QAAQ,CAAC,IAAI,aAAa;IAC1B,QAAQ,CAAC,QAAQ,qBAAqB;IACtC,QAAQ,CAAC,MAAM,UAAU;IAEnB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQzC,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC;CAOnC"}
1
+ {"version":3,"file":"vscode.launcher.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/ide-launchers/vscode.launcher.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAC;AAC9D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAE5D,qBAAa,cAAe,YAAW,WAAW;IAChD,QAAQ,CAAC,IAAI,aAAa;IAC1B,QAAQ,CAAC,QAAQ,qBAAqB;IACtC,QAAQ,CAAC,MAAM,UAAU;IAEnB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQzC,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC;CAOnC"}
@@ -1 +1 @@
1
- {"version":3,"file":"windsurf.launcher.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/ide-launchers/windsurf.launcher.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,qCAAqC,CAAC;AACjE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAE5D,qBAAa,gBAAiB,YAAW,WAAW;IAClD,QAAQ,CAAC,IAAI,cAAc;IAC3B,QAAQ,CAAC,QAAQ,uBAAuB;IACxC,QAAQ,CAAC,MAAM,cAAc;IAEvB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQzC,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC;CAOnC"}
1
+ {"version":3,"file":"windsurf.launcher.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/ide-launchers/windsurf.launcher.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAC;AAC9D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAE5D,qBAAa,gBAAiB,YAAW,WAAW;IAClD,QAAQ,CAAC,IAAI,cAAc;IAC3B,QAAQ,CAAC,QAAQ,uBAAuB;IACxC,QAAQ,CAAC,MAAM,cAAc;IAEvB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQzC,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC;CAOnC"}
@@ -1 +1 @@
1
- {"version":3,"file":"zed.launcher.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/ide-launchers/zed.launcher.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,qCAAqC,CAAC;AACjE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAE5D,qBAAa,WAAY,YAAW,WAAW;IAC7C,QAAQ,CAAC,IAAI,SAAS;IACtB,QAAQ,CAAC,QAAQ,kBAAkB;IACnC,QAAQ,CAAC,MAAM,SAAS;IAElB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQzC,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC;CAOnC"}
1
+ {"version":3,"file":"zed.launcher.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/ide-launchers/zed.launcher.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,UAAU,EAAE,MAAM,kCAAkC,CAAC;AAC9D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,0BAA0B,CAAC;AAE5D,qBAAa,WAAY,YAAW,WAAW;IAC7C,QAAQ,CAAC,IAAI,SAAS;IACtB,QAAQ,CAAC,QAAQ,kBAAkB;IACnC,QAAQ,CAAC,MAAM,SAAS;IAElB,MAAM,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQzC,cAAc,IAAI,OAAO,CAAC,OAAO,CAAC;CAOnC"}
@@ -2,7 +2,9 @@
2
2
  * Settings Service
3
3
  *
4
4
  * Provides global access to application settings within the CLI.
5
- * Implements singleton pattern for consistent settings access.
5
+ * Uses globalThis/process storage so the singleton survives Turbopack
6
+ * module re-evaluations in Next.js API routes (same pattern as the
7
+ * use-cases bridge in di/use-cases-bridge.ts).
6
8
  *
7
9
  * Usage:
8
10
  * ```typescript
@@ -1 +1 @@
1
- {"version":3,"file":"settings.service.d.ts","sourceRoot":"","sources":["../../../../../../packages/core/src/infrastructure/services/settings.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kCAAkC,CAAC;AAQjE;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAM3D;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,IAAI,QAAQ,CAMtC;AAED;;;;GAIG;AACH,wBAAgB,WAAW,IAAI,OAAO,CAErC;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,IAAI,IAAI,CAEpC"}
1
+ {"version":3,"file":"settings.service.d.ts","sourceRoot":"","sources":["../../../../../../packages/core/src/infrastructure/services/settings.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,kCAAkC,CAAC;AAsBjE;;;;;;GAMG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI,CAM3D;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,WAAW,IAAI,QAAQ,CAOtC;AAED;;;;GAIG;AACH,wBAAgB,WAAW,IAAI,OAAO,CAErC;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,IAAI,IAAI,CAEpC"}
@@ -2,7 +2,9 @@
2
2
  * Settings Service
3
3
  *
4
4
  * Provides global access to application settings within the CLI.
5
- * Implements singleton pattern for consistent settings access.
5
+ * Uses globalThis/process storage so the singleton survives Turbopack
6
+ * module re-evaluations in Next.js API routes (same pattern as the
7
+ * use-cases bridge in di/use-cases-bridge.ts).
6
8
  *
7
9
  * Usage:
8
10
  * ```typescript
@@ -12,11 +14,23 @@
12
14
  * console.log(settings.models.analyze); // 'claude-opus-4'
13
15
  * ```
14
16
  */
15
- /**
16
- * Singleton settings instance.
17
- * Set during CLI initialization, accessed throughout application lifecycle.
18
- */
19
- let settingsInstance = null;
17
+ /** The globalThis / process key for the settings singleton. */
18
+ const SHEP_SETTINGS_KEY = '__shepSettings';
19
+ /** Read the settings instance from globalThis, falling back to process. */
20
+ function readSettings() {
21
+ const fromGlobal = globalThis[SHEP_SETTINGS_KEY];
22
+ if (fromGlobal != null)
23
+ return fromGlobal;
24
+ const fromProcess = process[SHEP_SETTINGS_KEY];
25
+ if (fromProcess != null)
26
+ return fromProcess;
27
+ return null;
28
+ }
29
+ /** Write the settings instance to both globalThis and process. */
30
+ function writeSettings(value) {
31
+ globalThis[SHEP_SETTINGS_KEY] = value;
32
+ process[SHEP_SETTINGS_KEY] = value;
33
+ }
20
34
  /**
21
35
  * Initialize the settings service with loaded settings.
22
36
  * Must be called once during CLI bootstrap.
@@ -25,10 +39,10 @@ let settingsInstance = null;
25
39
  * @throws Error if settings are already initialized
26
40
  */
27
41
  export function initializeSettings(settings) {
28
- if (settingsInstance !== null) {
42
+ if (readSettings() !== null) {
29
43
  throw new Error('Settings already initialized. Cannot re-initialize.');
30
44
  }
31
- settingsInstance = settings;
45
+ writeSettings(settings);
32
46
  }
33
47
  /**
34
48
  * Get the current application settings.
@@ -43,10 +57,11 @@ export function initializeSettings(settings) {
43
57
  * ```
44
58
  */
45
59
  export function getSettings() {
46
- if (settingsInstance === null) {
60
+ const instance = readSettings();
61
+ if (instance === null) {
47
62
  throw new Error('Settings not initialized. Call initializeSettings() during CLI bootstrap.');
48
63
  }
49
- return settingsInstance;
64
+ return instance;
50
65
  }
51
66
  /**
52
67
  * Check if settings have been initialized.
@@ -54,7 +69,7 @@ export function getSettings() {
54
69
  * @returns True if settings are initialized, false otherwise
55
70
  */
56
71
  export function hasSettings() {
57
- return settingsInstance !== null;
72
+ return readSettings() !== null;
58
73
  }
59
74
  /**
60
75
  * Reset settings instance (for testing purposes only).
@@ -63,5 +78,5 @@ export function hasSettings() {
63
78
  * @internal
64
79
  */
65
80
  export function resetSettings() {
66
- settingsInstance = null;
81
+ writeSettings(null);
67
82
  }
@@ -1 +1 @@
1
- {"version":3,"file":"show.command.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/cli/commands/agent/show.command.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAyBpC,wBAAgB,iBAAiB,IAAI,OAAO,CAoG3C"}
1
+ {"version":3,"file":"show.command.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/cli/commands/agent/show.command.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAiBpC,wBAAgB,iBAAiB,IAAI,OAAO,CAoG3C"}
@@ -8,17 +8,10 @@
8
8
  * shep agent show <id>
9
9
  */
10
10
  import { Command } from 'commander';
11
- import { createHash } from 'node:crypto';
12
- import { join } from 'node:path';
13
11
  import { colors, messages, symbols, renderDetailView } from '../../ui/index.js';
14
12
  import { resolveAgentRun } from './resolve-run.js';
15
13
  import { container } from '../../../../../packages/core/src/infrastructure/di/container.js';
16
- import { SHEP_HOME_DIR } from '../../../../../packages/core/src/infrastructure/services/filesystem/shep-directory.service.js';
17
- function computeWorktreePath(repoPath, branch) {
18
- const repoHash = createHash('sha256').update(repoPath).digest('hex').slice(0, 16);
19
- const slug = branch.replace(/\//g, '-');
20
- return join(SHEP_HOME_DIR, 'repos', repoHash, 'wt', slug);
21
- }
14
+ import { computeWorktreePath } from '../../../../../packages/core/src/infrastructure/services/ide-launchers/compute-worktree-path.js';
22
15
  function isProcessAlive(pid) {
23
16
  try {
24
17
  process.kill(pid, 0);
@@ -1 +1 @@
1
- {"version":3,"file":"show.command.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/cli/commands/feat/show.command.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAuEpC,wBAAgB,iBAAiB,IAAI,OAAO,CA4I3C"}
1
+ {"version":3,"file":"show.command.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/cli/commands/feat/show.command.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA+DpC,wBAAgB,iBAAiB,IAAI,OAAO,CA4I3C"}
@@ -7,17 +7,10 @@
7
7
  * Usage: shep feat show <id>
8
8
  */
9
9
  import { Command } from 'commander';
10
- import { createHash } from 'node:crypto';
11
- import { join } from 'node:path';
12
10
  import { container } from '../../../../../packages/core/src/infrastructure/di/container.js';
13
11
  import { ShowFeatureUseCase } from '../../../../../packages/core/src/application/use-cases/features/show-feature.use-case.js';
14
12
  import { colors, symbols, messages, renderDetailView } from '../../ui/index.js';
15
- import { SHEP_HOME_DIR } from '../../../../../packages/core/src/infrastructure/services/filesystem/shep-directory.service.js';
16
- function computeWorktreePath(repoPath, branch) {
17
- const repoHash = createHash('sha256').update(repoPath).digest('hex').slice(0, 16);
18
- const slug = branch.replace(/\//g, '-');
19
- return join(SHEP_HOME_DIR, 'repos', repoHash, 'wt', slug);
20
- }
13
+ import { computeWorktreePath } from '../../../../../packages/core/src/infrastructure/services/ide-launchers/compute-worktree-path.js';
21
14
  /** Map graph node names to human-readable phase labels (active). */
22
15
  const NODE_TO_PHASE = {
23
16
  analyze: 'Analyzing',
@@ -1 +1 @@
1
- {"version":3,"file":"ide-open.command.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/cli/commands/ide-open.command.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA+CpC,wBAAgB,oBAAoB,IAAI,OAAO,CAwC9C"}
1
+ {"version":3,"file":"ide-open.command.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/cli/commands/ide-open.command.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAsCpC,wBAAgB,oBAAoB,IAAI,OAAO,CAkC9C"}
@@ -6,20 +6,12 @@
6
6
  * Usage: shep ide <feat-id> [--vscode|--cursor|--windsurf|--zed|--antigravity]
7
7
  */
8
8
  import { Command } from 'commander';
9
- import { createHash } from 'node:crypto';
10
- import { join } from 'node:path';
11
9
  import { EditorType } from '../../../../packages/core/src/domain/generated/output.js';
12
10
  import { container } from '../../../../packages/core/src/infrastructure/di/container.js';
13
11
  import { ShowFeatureUseCase } from '../../../../packages/core/src/application/use-cases/features/show-feature.use-case.js';
14
12
  import { getSettings } from '../../../../packages/core/src/infrastructure/services/settings.service.js';
15
- import { createLauncherRegistry } from '../../../../packages/core/src/infrastructure/services/ide-launchers/ide-launcher.registry.js';
16
- import { SHEP_HOME_DIR } from '../../../../packages/core/src/infrastructure/services/filesystem/shep-directory.service.js';
13
+ import { launchIde } from '../../../../packages/core/src/infrastructure/services/ide-launchers/launch-ide.js';
17
14
  import { messages } from '../ui/index.js';
18
- function computeWorktreePath(repoPath, branch) {
19
- const repoHash = createHash('sha256').update(repoPath).digest('hex').slice(0, 16);
20
- const slug = branch.replace(/\//g, '-');
21
- return join(SHEP_HOME_DIR, 'repos', repoHash, 'wt', slug);
22
- }
23
15
  /** IDE flag names mapped to their EditorType values. */
24
16
  const IDE_FLAG_MAP = {
25
17
  vscode: EditorType.VsCode,
@@ -51,22 +43,20 @@ export function createIdeOpenCommand() {
51
43
  .option('--antigravity', 'Open in Antigravity')
52
44
  .action(async (featId, options) => {
53
45
  try {
54
- // Resolve the editor
55
46
  const editorId = resolveEditorId(options);
56
- const registry = createLauncherRegistry();
57
- const launcher = registry.get(editorId);
58
- if (!launcher) {
59
- messages.error(`Unknown editor "${editorId}". Supported: ${[...registry.keys()].join(', ')}`, new Error(`Unknown editor: ${editorId}`));
47
+ const useCase = container.resolve(ShowFeatureUseCase);
48
+ const feature = await useCase.execute(featId);
49
+ const result = await launchIde({
50
+ editorId,
51
+ repositoryPath: feature.repositoryPath,
52
+ branch: feature.branch,
53
+ });
54
+ if (!result.ok) {
55
+ messages.error(result.message, new Error(result.message));
60
56
  process.exitCode = 1;
61
57
  return;
62
58
  }
63
- // Resolve the feature
64
- const useCase = container.resolve(ShowFeatureUseCase);
65
- const feature = await useCase.execute(featId);
66
- // Compute worktree path and launch
67
- const worktreePath = computeWorktreePath(feature.repositoryPath, feature.branch);
68
- await launcher.launch(worktreePath);
69
- messages.success(`Opened ${launcher.name} at ${worktreePath}`);
59
+ messages.success(`Opened ${result.editorName} at ${result.worktreePath}`);
70
60
  }
71
61
  catch (error) {
72
62
  const err = error instanceof Error ? error : new Error(String(error));
@@ -0,0 +1,9 @@
1
+ import { NextResponse } from 'next/server';
2
+ export declare function POST(request: Request): Promise<NextResponse<{
3
+ error: string;
4
+ }> | NextResponse<{
5
+ success: boolean;
6
+ editor: string;
7
+ path: string;
8
+ }>>;
9
+ //# sourceMappingURL=route.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../../../../src/presentation/web/app/api/ide/open/route.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAK3C,wBAAsB,IAAI,CAAC,OAAO,EAAE,OAAO;;;;;;IA8B1C"}
@@ -0,0 +1,29 @@
1
+ import { NextResponse } from 'next/server';
2
+ import { getSettings } from '../../../../../../../packages/core/src/infrastructure/services/settings.service.js';
3
+ import { launchIde } from '../../../../../../../packages/core/src/infrastructure/services/ide-launchers/launch-ide.js';
4
+ import { validateToolbarInput } from '../../validate-toolbar-input.js';
5
+ export async function POST(request) {
6
+ const body = await request.json();
7
+ const validation = validateToolbarInput(body);
8
+ if ('error' in validation) {
9
+ return NextResponse.json({ error: validation.error }, { status: validation.status });
10
+ }
11
+ const { repositoryPath, branch } = validation;
12
+ const settings = getSettings();
13
+ const editor = settings.environment.defaultEditor;
14
+ const result = await launchIde({
15
+ editorId: editor,
16
+ repositoryPath,
17
+ branch,
18
+ checkAvailability: true,
19
+ });
20
+ if (!result.ok) {
21
+ const status = result.code === 'launch_failed' ? 500 : 404;
22
+ return NextResponse.json({ error: result.message }, { status });
23
+ }
24
+ return NextResponse.json({
25
+ success: true,
26
+ editor: result.editorName,
27
+ path: result.worktreePath,
28
+ });
29
+ }
@@ -0,0 +1,9 @@
1
+ import { NextResponse } from 'next/server';
2
+ export declare function POST(request: Request): Promise<NextResponse<{
3
+ error: string;
4
+ }> | NextResponse<{
5
+ success: boolean;
6
+ path: string;
7
+ shell: string;
8
+ }>>;
9
+ //# sourceMappingURL=route.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../../../../src/presentation/web/app/api/shell/open/route.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAO3C,wBAAsB,IAAI,CAAC,OAAO,EAAE,OAAO;;;;;;IAsD1C"}
@@ -0,0 +1,51 @@
1
+ import { NextResponse } from 'next/server';
2
+ import { existsSync } from 'node:fs';
3
+ import { spawn } from 'node:child_process';
4
+ import { getSettings } from '../../../../../../../packages/core/src/infrastructure/services/settings.service.js';
5
+ import { computeWorktreePath } from '../../../../../../../packages/core/src/infrastructure/services/ide-launchers/compute-worktree-path.js';
6
+ import { validateToolbarInput } from '../../validate-toolbar-input.js';
7
+ export async function POST(request) {
8
+ const body = await request.json();
9
+ const validation = validateToolbarInput(body);
10
+ if ('error' in validation) {
11
+ return NextResponse.json({ error: validation.error }, { status: validation.status });
12
+ }
13
+ const { repositoryPath, branch } = validation;
14
+ try {
15
+ const settings = getSettings();
16
+ const shell = settings.environment.shellPreference;
17
+ const worktreePath = computeWorktreePath(repositoryPath, branch);
18
+ if (!existsSync(worktreePath)) {
19
+ return NextResponse.json({ error: `Worktree path does not exist: ${worktreePath}` }, { status: 404 });
20
+ }
21
+ const platform = process.platform;
22
+ if (platform === 'darwin') {
23
+ const child = spawn('open', ['-a', 'Terminal', worktreePath], {
24
+ detached: true,
25
+ stdio: 'ignore',
26
+ });
27
+ child.unref();
28
+ }
29
+ else if (platform === 'linux') {
30
+ const child = spawn('x-terminal-emulator', [`--working-directory=${worktreePath}`], {
31
+ detached: true,
32
+ stdio: 'ignore',
33
+ });
34
+ child.unref();
35
+ }
36
+ else {
37
+ return NextResponse.json({
38
+ error: `Unsupported platform: ${platform}. Shell launch is supported on macOS and Linux only.`,
39
+ }, { status: 501 });
40
+ }
41
+ return NextResponse.json({
42
+ success: true,
43
+ path: worktreePath,
44
+ shell,
45
+ });
46
+ }
47
+ catch (error) {
48
+ const message = error instanceof Error ? error.message : 'Failed to open shell';
49
+ return NextResponse.json({ error: message }, { status: 500 });
50
+ }
51
+ }
@@ -0,0 +1,17 @@
1
+ /**
2
+ * Shared input validation for feature toolbar API routes.
3
+ *
4
+ * Validates that repositoryPath is a non-empty absolute path and branch is a
5
+ * non-empty string without path traversal sequences or null bytes.
6
+ */
7
+ interface ValidInput {
8
+ repositoryPath: string;
9
+ branch: string;
10
+ }
11
+ interface ValidationError {
12
+ error: string;
13
+ status: number;
14
+ }
15
+ export declare function validateToolbarInput(body: Record<string, unknown>): ValidInput | ValidationError;
16
+ export {};
17
+ //# sourceMappingURL=validate-toolbar-input.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"validate-toolbar-input.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/web/app/api/validate-toolbar-input.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,UAAU,UAAU;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;CAChB;AACD,UAAU,eAAe;IACvB,KAAK,EAAE,MAAM,CAAC;IACd,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,wBAAgB,oBAAoB,CAAC,IAAI,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,UAAU,GAAG,eAAe,CAwBhG"}
@@ -0,0 +1,25 @@
1
+ /**
2
+ * Shared input validation for feature toolbar API routes.
3
+ *
4
+ * Validates that repositoryPath is a non-empty absolute path and branch is a
5
+ * non-empty string without path traversal sequences or null bytes.
6
+ */
7
+ export function validateToolbarInput(body) {
8
+ const { repositoryPath, branch } = body;
9
+ if (typeof repositoryPath !== 'string' || repositoryPath.length === 0) {
10
+ return { error: 'repositoryPath is required and must be a non-empty string', status: 400 };
11
+ }
12
+ if (!repositoryPath.startsWith('/')) {
13
+ return { error: 'repositoryPath must be an absolute path (starting with /)', status: 400 };
14
+ }
15
+ if (typeof branch !== 'string' || branch.length === 0) {
16
+ return { error: 'branch is required and must be a non-empty string', status: 400 };
17
+ }
18
+ if (branch.includes('..')) {
19
+ return { error: 'branch must not contain path traversal sequences (..)', status: 400 };
20
+ }
21
+ if (branch.includes('\0')) {
22
+ return { error: 'branch must not contain null bytes', status: 400 };
23
+ }
24
+ return { repositoryPath, branch };
25
+ }
@@ -1 +1 @@
1
- {"version":3,"file":"page.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/web/app/page.tsx"],"names":[],"mappings":"AAQA,6EAA6E;AAC7E,eAAO,MAAM,OAAO,kBAAkB,CAAC;AAqBvC,wBAA8B,QAAQ,qDAoFrC"}
1
+ {"version":3,"file":"page.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/web/app/page.tsx"],"names":[],"mappings":"AAQA,6EAA6E;AAC7E,eAAO,MAAM,OAAO,kBAAkB,CAAC;AAqBvC,wBAA8B,QAAQ,qDAsFrC"}
@@ -65,6 +65,8 @@ export default async function HomePage() {
65
65
  description: feature.description ?? feature.slug,
66
66
  featureId: feature.id,
67
67
  lifecycle,
68
+ repositoryPath: feature.repositoryPath,
69
+ branch: feature.branch,
68
70
  ...deriveState(lifecycle, agentStatus),
69
71
  ...(agentError && { errorMessage: agentError }),
70
72
  };
@@ -1 +1 @@
1
- {"version":3,"file":"feature-drawer.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-drawer/feature-drawer.tsx"],"names":[],"mappings":"AAcA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAExE,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,eAAe,GAAG,IAAI,CAAC;IACrC,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,wBAAgB,aAAa,CAAC,EAAE,YAAY,EAAE,OAAO,EAAE,EAAE,kBAAkB,2CAmE1E"}
1
+ {"version":3,"file":"feature-drawer.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-drawer/feature-drawer.tsx"],"names":[],"mappings":"AAeA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,kCAAkC,CAAC;AAGxE,MAAM,WAAW,kBAAkB;IACjC,YAAY,EAAE,eAAe,GAAG,IAAI,CAAC;IACrC,OAAO,EAAE,MAAM,IAAI,CAAC;CACrB;AAED,wBAAgB,aAAa,CAAC,EAAE,YAAY,EAAE,OAAO,EAAE,EAAE,kBAAkB,2CA2E1E"}
@@ -1,16 +1,18 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
- import { XIcon } from 'lucide-react';
3
+ import { XIcon, Code2, Terminal, Loader2, CircleAlert } from 'lucide-react';
4
4
  import { cn } from '../../../lib/utils.js';
5
5
  import { Drawer, DrawerContent, DrawerHeader, DrawerTitle, DrawerDescription, } from '../../ui/drawer.js';
6
+ import { Button } from '../../ui/button.js';
6
7
  import { Separator } from '../../ui/separator.js';
7
8
  import { CometSpinner } from '../../ui/comet-spinner.js';
8
9
  import { featureNodeStateConfig, lifecycleDisplayLabels } from '../../common/feature-node/index.js';
10
+ import { useFeatureActions } from './use-feature-actions.js';
9
11
  export function FeatureDrawer({ selectedNode, onClose }) {
10
12
  return (_jsx(Drawer, { direction: "right", modal: false, open: selectedNode !== null, onOpenChange: (open) => {
11
13
  if (!open)
12
14
  onClose();
13
- }, children: _jsx(DrawerContent, { direction: "right", className: "w-96", showCloseButton: false, children: selectedNode ? (_jsxs(_Fragment, { children: [_jsx("button", { type: "button", "aria-label": "Close", onClick: onClose, className: "ring-offset-background focus:ring-ring absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden", children: _jsx(XIcon, { className: "size-4" }) }), _jsxs(DrawerHeader, { "data-testid": "feature-drawer-header", children: [_jsx(DrawerTitle, { children: selectedNode.name }), _jsx(DrawerDescription, { children: selectedNode.featureId })] }), _jsx(Separator, {}), _jsxs("div", { "data-testid": "feature-drawer-status", className: "flex flex-col gap-3 p-4", children: [_jsx("div", { className: "text-muted-foreground text-xs font-semibold tracking-wider", children: lifecycleDisplayLabels[selectedNode.lifecycle] }), _jsx(StateBadge, { data: selectedNode }), selectedNode.progress > 0 ? (_jsxs("div", { "data-testid": "feature-drawer-progress", className: "flex flex-col gap-1", children: [_jsxs("div", { className: "text-muted-foreground flex items-center justify-between text-xs", children: [_jsx("span", { children: "Progress" }), _jsxs("span", { children: [selectedNode.progress, "%"] })] }), _jsx("div", { className: "bg-muted h-2 w-full overflow-hidden rounded-full", children: _jsx("div", { className: cn('h-full rounded-full transition-all', featureNodeStateConfig[selectedNode.state].progressClass), style: { width: `${selectedNode.progress}%` } }) })] })) : null] }), _jsx(Separator, {}), _jsx(DetailsSection, { data: selectedNode })] })) : null }) }));
15
+ }, children: _jsx(DrawerContent, { direction: "right", className: "w-96", showCloseButton: false, children: selectedNode ? (_jsxs(_Fragment, { children: [_jsx("button", { type: "button", "aria-label": "Close", onClick: onClose, className: "ring-offset-background focus:ring-ring absolute top-4 right-4 rounded-xs opacity-70 transition-opacity hover:opacity-100 focus:ring-2 focus:ring-offset-2 focus:outline-hidden", children: _jsx(XIcon, { className: "size-4" }) }), _jsxs(DrawerHeader, { "data-testid": "feature-drawer-header", children: [_jsx(DrawerTitle, { children: selectedNode.name }), _jsx(DrawerDescription, { children: selectedNode.featureId })] }), selectedNode.repositoryPath && selectedNode.branch ? (_jsx(DrawerActions, { repositoryPath: selectedNode.repositoryPath, branch: selectedNode.branch })) : null, _jsx(Separator, {}), _jsxs("div", { "data-testid": "feature-drawer-status", className: "flex flex-col gap-3 p-4", children: [_jsx("div", { className: "text-muted-foreground text-xs font-semibold tracking-wider", children: lifecycleDisplayLabels[selectedNode.lifecycle] }), _jsx(StateBadge, { data: selectedNode }), selectedNode.progress > 0 ? (_jsxs("div", { "data-testid": "feature-drawer-progress", className: "flex flex-col gap-1", children: [_jsxs("div", { className: "text-muted-foreground flex items-center justify-between text-xs", children: [_jsx("span", { children: "Progress" }), _jsxs("span", { children: [selectedNode.progress, "%"] })] }), _jsx("div", { className: "bg-muted h-2 w-full overflow-hidden rounded-full", children: _jsx("div", { className: cn('h-full rounded-full transition-all', featureNodeStateConfig[selectedNode.state].progressClass), style: { width: `${selectedNode.progress}%` } }) })] })) : null] }), _jsx(Separator, {}), _jsx(DetailsSection, { data: selectedNode })] })) : null }) }));
14
16
  }
15
17
  function StateBadge({ data }) {
16
18
  const config = featureNodeStateConfig[data.state];
@@ -26,3 +28,10 @@ function DetailsSection({ data }) {
26
28
  function DetailRow({ label, value }) {
27
29
  return (_jsxs("div", { className: "flex flex-col gap-0.5", children: [_jsx("span", { className: "text-muted-foreground text-xs font-medium", children: label }), _jsx("span", { className: "text-sm", children: value })] }));
28
30
  }
31
+ function DrawerActions({ repositoryPath, branch }) {
32
+ const { openInIde, openInShell, ideLoading, shellLoading, ideError, shellError } = useFeatureActions({ repositoryPath, branch });
33
+ return (_jsxs("div", { className: "flex gap-2 px-4 pb-3", children: [_jsx(DrawerActionButton, { label: "Open in IDE", onClick: openInIde, loading: ideLoading, error: !!ideError, icon: Code2 }), _jsx(DrawerActionButton, { label: "Open in Shell", onClick: openInShell, loading: shellLoading, error: !!shellError, icon: Terminal })] }));
34
+ }
35
+ function DrawerActionButton({ label, onClick, loading, error, icon: Icon, }) {
36
+ return (_jsxs(Button, { variant: "outline", size: "sm", "aria-label": label, disabled: loading, onClick: onClick, className: cn('gap-1.5', error && 'text-destructive hover:text-destructive'), children: [loading ? (_jsx(Loader2, { className: "size-4 animate-spin" })) : error ? (_jsx(CircleAlert, { className: "size-4" })) : (_jsx(Icon, { className: "size-4" })), label] }));
37
+ }
@@ -16,4 +16,12 @@ export declare const AllFields: Story;
16
16
  export declare const AllStates: Story;
17
17
  /** Cycle through all 6 lifecycle phases via buttons. */
18
18
  export declare const AllLifecycles: Story;
19
+ /** No repositoryPath — action buttons are hidden. */
20
+ export declare const NoRepositoryPath: Story;
21
+ /**
22
+ * Action buttons visible — click "Open in IDE" or "Open in Shell" to see
23
+ * loading spinner (while API call is in flight) followed by error state
24
+ * (API routes are not available in Storybook).
25
+ */
26
+ export declare const WithActionButtons: Story;
19
27
  //# sourceMappingURL=feature-drawer.stories.d.ts.map