@shepai/cli 1.28.0 → 1.29.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 (165) hide show
  1. package/dist/packages/core/src/infrastructure/di/container.d.ts +6 -0
  2. package/dist/packages/core/src/infrastructure/di/container.d.ts.map +1 -1
  3. package/dist/packages/core/src/infrastructure/di/container.js +24 -0
  4. package/dist/packages/core/src/infrastructure/index.d.ts +1 -1
  5. package/dist/packages/core/src/infrastructure/index.d.ts.map +1 -1
  6. package/dist/packages/core/src/infrastructure/index.js +1 -1
  7. package/dist/packages/core/src/infrastructure/services/filesystem/shep-directory.service.d.ts +12 -21
  8. package/dist/packages/core/src/infrastructure/services/filesystem/shep-directory.service.d.ts.map +1 -1
  9. package/dist/packages/core/src/infrastructure/services/filesystem/shep-directory.service.js +27 -31
  10. package/dist/packages/core/src/infrastructure/services/git/worktree.service.js +2 -2
  11. package/dist/packages/core/src/infrastructure/services/ide-launchers/compute-worktree-path.d.ts.map +1 -1
  12. package/dist/packages/core/src/infrastructure/services/ide-launchers/compute-worktree-path.js +2 -3
  13. package/dist/packages/core/src/infrastructure/services/settings.service.d.ts +1 -2
  14. package/dist/packages/core/src/infrastructure/services/settings.service.d.ts.map +1 -1
  15. package/dist/packages/core/src/infrastructure/services/settings.service.js +1 -2
  16. package/dist/src/presentation/cli/commands/feat/new.command.js +2 -2
  17. package/dist/src/presentation/cli/commands/settings/init.command.d.ts.map +1 -1
  18. package/dist/src/presentation/cli/commands/settings/init.command.js +13 -0
  19. package/dist/src/presentation/cli/index.js +2 -6
  20. package/dist/src/presentation/web/app/api/features/[id]/route.d.ts +11 -0
  21. package/dist/src/presentation/web/app/api/features/[id]/route.d.ts.map +1 -0
  22. package/dist/src/presentation/web/app/api/features/[id]/route.js +17 -0
  23. package/dist/src/presentation/web/app/api/features/create/route.d.ts +1 -1
  24. package/dist/src/presentation/web/app/api/features/create/route.d.ts.map +1 -1
  25. package/dist/src/presentation/web/app/api/features/create/route.js +3 -2
  26. package/dist/src/presentation/web/app/page.d.ts +1 -1
  27. package/dist/src/presentation/web/app/page.d.ts.map +1 -1
  28. package/dist/src/presentation/web/app/page.js +6 -4
  29. package/dist/src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.d.ts +1 -1
  30. package/dist/src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.d.ts.map +1 -1
  31. package/dist/src/presentation/web/components/common/feature-drawer/feature-drawer.d.ts +3 -1
  32. package/dist/src/presentation/web/components/common/feature-drawer/feature-drawer.d.ts.map +1 -1
  33. package/dist/src/presentation/web/components/common/feature-drawer/feature-drawer.js +4 -3
  34. package/dist/src/presentation/web/components/common/feature-drawer/feature-drawer.stories.d.ts +6 -0
  35. package/dist/src/presentation/web/components/common/feature-drawer/feature-drawer.stories.d.ts.map +1 -1
  36. package/dist/src/presentation/web/components/common/feature-drawer/feature-drawer.stories.js +22 -0
  37. package/dist/src/presentation/web/components/features/control-center/control-center-inner.d.ts.map +1 -1
  38. package/dist/src/presentation/web/components/features/control-center/control-center-inner.js +2 -2
  39. package/dist/src/presentation/web/components/features/control-center/use-control-center-state.d.ts +3 -1
  40. package/dist/src/presentation/web/components/features/control-center/use-control-center-state.d.ts.map +1 -1
  41. package/dist/src/presentation/web/components/features/control-center/use-control-center-state.js +27 -0
  42. package/dist/src/presentation/web/components/ui/alert-dialog.d.ts +19 -0
  43. package/dist/src/presentation/web/components/ui/alert-dialog.d.ts.map +1 -0
  44. package/dist/src/presentation/web/components/ui/alert-dialog.js +42 -0
  45. package/dist/src/presentation/web/components/ui/alert-dialog.stories.d.ts +9 -0
  46. package/dist/src/presentation/web/components/ui/alert-dialog.stories.d.ts.map +1 -0
  47. package/dist/src/presentation/web/components/ui/alert-dialog.stories.js +21 -0
  48. package/dist/src/presentation/web/dev-server.d.ts +1 -2
  49. package/dist/src/presentation/web/dev-server.d.ts.map +1 -1
  50. package/dist/src/presentation/web/dev-server.js +3 -5
  51. package/dist/src/presentation/web/instrumentation.d.ts +13 -0
  52. package/dist/src/presentation/web/instrumentation.d.ts.map +1 -0
  53. package/dist/src/presentation/web/instrumentation.js +14 -0
  54. package/dist/src/presentation/web/lib/server-container.d.ts +21 -0
  55. package/dist/src/presentation/web/lib/server-container.d.ts.map +1 -0
  56. package/dist/src/presentation/web/lib/server-container.js +26 -0
  57. package/dist/src/presentation/web/next.config.d.ts.map +1 -1
  58. package/dist/src/presentation/web/next.config.js +2 -0
  59. package/dist/tsconfig.build.tsbuildinfo +1 -1
  60. package/package.json +1 -1
  61. package/web/.next/BUILD_ID +1 -1
  62. package/web/.next/app-path-routes-manifest.json +1 -0
  63. package/web/.next/build-manifest.json +2 -2
  64. package/web/.next/cache/.previewinfo +1 -1
  65. package/web/.next/cache/.rscinfo +1 -1
  66. package/web/.next/cache/.tsbuildinfo +1 -1
  67. package/web/.next/cache/config.json +3 -3
  68. package/web/.next/fallback-build-manifest.json +2 -2
  69. package/web/.next/prerender-manifest.json +3 -3
  70. package/web/.next/required-server-files.js +8 -2
  71. package/web/.next/required-server-files.json +8 -2
  72. package/web/.next/routes-manifest.json +10 -1
  73. package/web/.next/server/app/_global-error.html +2 -2
  74. package/web/.next/server/app/_global-error.rsc +1 -1
  75. package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  76. package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  77. package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  78. package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  79. package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +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/features/[id]/route/app-paths-manifest.json +3 -0
  90. package/web/.next/server/app/api/features/[id]/route/build-manifest.json +11 -0
  91. package/web/.next/server/app/api/features/[id]/route/server-reference-manifest.json +4 -0
  92. package/web/.next/server/app/api/features/[id]/route.js +7 -0
  93. package/web/.next/server/app/api/features/[id]/route.js.map +5 -0
  94. package/web/.next/server/app/api/features/[id]/route.js.nft.json +1 -0
  95. package/web/.next/server/app/api/features/[id]/route_client-reference-manifest.js +2 -0
  96. package/web/.next/server/app/api/features/create/route.js +1 -1
  97. package/web/.next/server/app/api/features/create/route.js.nft.json +1 -1
  98. package/web/.next/server/app/api/ide/open/route.js +1 -1
  99. package/web/.next/server/app/api/ide/open/route.js.nft.json +1 -1
  100. package/web/.next/server/app/api/shell/open/route.js +1 -1
  101. package/web/.next/server/app/api/shell/open/route.js.nft.json +1 -1
  102. package/web/.next/server/app/page_client-reference-manifest.js +1 -1
  103. package/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
  104. package/web/.next/server/app/version.html +2 -2
  105. package/web/.next/server/app/version.rsc +2 -2
  106. package/web/.next/server/app/version.segments/_full.segment.rsc +2 -2
  107. package/web/.next/server/app/version.segments/_head.segment.rsc +1 -1
  108. package/web/.next/server/app/version.segments/_index.segment.rsc +2 -2
  109. package/web/.next/server/app/version.segments/_tree.segment.rsc +2 -2
  110. package/web/.next/server/app/version.segments/version/__PAGE__.segment.rsc +1 -1
  111. package/web/.next/server/app/version.segments/version.segment.rsc +1 -1
  112. package/web/.next/server/app-paths-manifest.json +1 -0
  113. package/web/.next/server/chunks/744ca_web__next-internal_server_app_api_features_[id]_route_actions_03b9a4b5.js +3 -0
  114. package/web/.next/server/chunks/744ca_web__next-internal_server_app_api_features_[id]_route_actions_03b9a4b5.js.map +1 -0
  115. package/web/.next/server/chunks/[root-of-the-server]__0af905fe._.js +3 -0
  116. package/web/.next/server/chunks/[root-of-the-server]__0af905fe._.js.map +1 -0
  117. package/web/.next/server/chunks/[root-of-the-server]__3d63a020._.js +8 -0
  118. package/web/.next/server/chunks/[root-of-the-server]__3d63a020._.js.map +1 -0
  119. package/web/.next/server/chunks/[root-of-the-server]__72567d8d._.js +3 -0
  120. package/web/.next/server/chunks/[root-of-the-server]__72567d8d._.js.map +1 -0
  121. package/web/.next/server/chunks/[root-of-the-server]__acfd2769._.js +3 -0
  122. package/web/.next/server/chunks/[root-of-the-server]__acfd2769._.js.map +1 -0
  123. package/web/.next/server/chunks/src_presentation_web_instrumentation_ts_2b921ecb._.js +3 -0
  124. package/web/.next/server/chunks/src_presentation_web_instrumentation_ts_2b921ecb._.js.map +1 -0
  125. package/web/.next/server/chunks/ssr/[root-of-the-server]__f12b60be._.js +1 -1
  126. package/web/.next/server/chunks/ssr/_09afa42a._.js +8 -2
  127. package/web/.next/server/chunks/ssr/_09afa42a._.js.map +1 -1
  128. package/web/.next/server/chunks/ssr/src_presentation_web_ed0934e5._.js +1 -1
  129. package/web/.next/server/chunks/ssr/src_presentation_web_ed0934e5._.js.map +1 -1
  130. package/web/.next/server/edge/chunks/403f9_next_dist_esm_build_templates_edge-wrapper_f6192dd5.js.map +1 -0
  131. package/web/.next/server/edge/chunks/_5e9af917._.js +3 -0
  132. package/web/.next/server/edge/chunks/_5e9af917._.js.map +1 -0
  133. package/web/.next/server/edge/chunks/b35d5_next_dist_esm_build_templates_edge-wrapper_f6192dd5.js +6 -0
  134. package/web/.next/server/instrumentation/middleware-manifest.json +12 -0
  135. package/web/.next/server/instrumentation.js +4 -0
  136. package/web/.next/server/instrumentation.js.map +5 -0
  137. package/web/.next/server/instrumentation.js.nft.json +1 -0
  138. package/web/.next/server/pages/404.html +2 -2
  139. package/web/.next/server/pages/500.html +2 -2
  140. package/web/.next/server/server-reference-manifest.js +1 -1
  141. package/web/.next/server/server-reference-manifest.json +1 -1
  142. package/web/.next/static/chunks/{28c05929f2636c01.js → daacb9d30e4fc428.js} +9 -3
  143. package/web/.next/static/chunks/fd816afd85fd9a19.css +2 -0
  144. package/web/.next/trace +1 -1
  145. package/web/.next/trace-build +1 -1
  146. package/web/.next/types/link.d.ts +2 -1
  147. package/web/.next/types/routes.d.ts +2 -1
  148. package/web/.next/types/validator.ts +9 -0
  149. package/web/package.json +1 -0
  150. package/dist/packages/core/src/infrastructure/di/populate-use-cases-bridge.d.ts +0 -20
  151. package/dist/packages/core/src/infrastructure/di/populate-use-cases-bridge.d.ts.map +0 -1
  152. package/dist/packages/core/src/infrastructure/di/populate-use-cases-bridge.js +0 -29
  153. package/dist/packages/core/src/infrastructure/di/use-cases-bridge.d.ts +0 -42
  154. package/dist/packages/core/src/infrastructure/di/use-cases-bridge.d.ts.map +0 -1
  155. package/dist/packages/core/src/infrastructure/di/use-cases-bridge.js +0 -88
  156. package/web/.next/server/chunks/[root-of-the-server]__4e987cf3._.js +0 -8
  157. package/web/.next/server/chunks/[root-of-the-server]__4e987cf3._.js.map +0 -1
  158. package/web/.next/server/chunks/[root-of-the-server]__61349adc._.js +0 -3
  159. package/web/.next/server/chunks/[root-of-the-server]__61349adc._.js.map +0 -1
  160. package/web/.next/server/chunks/[root-of-the-server]__aa2074ca._.js +0 -3
  161. package/web/.next/server/chunks/[root-of-the-server]__aa2074ca._.js.map +0 -1
  162. package/web/.next/static/chunks/a7273c84449394e0.css +0 -2
  163. /package/web/.next/static/{wymVMk3X_cTuoYKeS0Gbf → xfxn0ObmVPrJQ_jxVxePe}/_buildManifest.js +0 -0
  164. /package/web/.next/static/{wymVMk3X_cTuoYKeS0Gbf → xfxn0ObmVPrJQ_jxVxePe}/_clientMiddlewareManifest.json +0 -0
  165. /package/web/.next/static/{wymVMk3X_cTuoYKeS0Gbf → xfxn0ObmVPrJQ_jxVxePe}/_ssgManifest.js +0 -0
@@ -15,10 +15,16 @@ import { container } from 'tsyringe';
15
15
  /**
16
16
  * Initialize the DI container with all dependencies.
17
17
  * Must be called before resolving any dependencies.
18
+ * Safe to call multiple times — returns existing container if already initialized.
18
19
  *
19
20
  * @returns Configured container instance
20
21
  */
21
22
  export declare function initializeContainer(): Promise<typeof container>;
23
+ /**
24
+ * Check whether the DI container has been initialized.
25
+ * Useful for diagnostics and conditional initialization in instrumentation.ts.
26
+ */
27
+ export declare function isContainerInitialized(): boolean;
22
28
  /**
23
29
  * Get the configured container instance.
24
30
  * Container must be initialized first via initializeContainer().
@@ -1 +1 @@
1
- {"version":3,"file":"container.d.ts","sourceRoot":"","sources":["../../../../../../packages/core/src/infrastructure/di/container.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,kBAAkB,CAAC;AAC1B,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAiFrC;;;;;GAKG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,OAAO,SAAS,CAAC,CAsJrE;AAED;;;GAGG;AACH,OAAO,EAAE,SAAS,EAAE,CAAC"}
1
+ {"version":3,"file":"container.d.ts","sourceRoot":"","sources":["../../../../../../packages/core/src/infrastructure/di/container.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,kBAAkB,CAAC;AAC1B,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAC;AAmFrC;;;;;;GAMG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,OAAO,SAAS,CAAC,CAuKrE;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,OAAO,CAEhD;AAED;;;GAGG;AACH,OAAO,EAAE,SAAS,EAAE,CAAC"}
@@ -60,13 +60,18 @@ import { InstallToolUseCase } from '../../application/use-cases/tools/install-to
60
60
  // Database connection
61
61
  import { getSQLiteConnection } from '../persistence/sqlite/connection.js';
62
62
  import { runSQLiteMigrations } from '../persistence/sqlite/migrations.js';
63
+ let _initialized = false;
63
64
  /**
64
65
  * Initialize the DI container with all dependencies.
65
66
  * Must be called before resolving any dependencies.
67
+ * Safe to call multiple times — returns existing container if already initialized.
66
68
  *
67
69
  * @returns Configured container instance
68
70
  */
69
71
  export async function initializeContainer() {
72
+ if (_initialized) {
73
+ return container;
74
+ }
70
75
  // Get database connection
71
76
  const db = await getSQLiteConnection();
72
77
  // Run migrations
@@ -192,8 +197,27 @@ export async function initializeContainer() {
192
197
  container.registerSingleton(ResumeFeatureUseCase);
193
198
  container.registerSingleton(ValidateToolAvailabilityUseCase);
194
199
  container.registerSingleton(InstallToolUseCase);
200
+ // String-token aliases for web routes (Turbopack can't resolve .js→.ts
201
+ // imports inside @shepai/core, so routes use string tokens instead of class refs)
202
+ container.register('CreateFeatureUseCase', {
203
+ useFactory: (c) => c.resolve(CreateFeatureUseCase),
204
+ });
205
+ container.register('ListFeaturesUseCase', {
206
+ useFactory: (c) => c.resolve(ListFeaturesUseCase),
207
+ });
208
+ container.register('DeleteFeatureUseCase', {
209
+ useFactory: (c) => c.resolve(DeleteFeatureUseCase),
210
+ });
211
+ _initialized = true;
195
212
  return container;
196
213
  }
214
+ /**
215
+ * Check whether the DI container has been initialized.
216
+ * Useful for diagnostics and conditional initialization in instrumentation.ts.
217
+ */
218
+ export function isContainerInitialized() {
219
+ return _initialized;
220
+ }
197
221
  /**
198
222
  * Get the configured container instance.
199
223
  * Container must be initialized first via initializeContainer().
@@ -3,6 +3,6 @@
3
3
  *
4
4
  * Exports DI container, repositories, and services.
5
5
  */
6
- export { initializeContainer, container } from './di/container.js';
6
+ export { initializeContainer, isContainerInitialized, container } from './di/container.js';
7
7
  export { getSettings, initializeSettings } from './services/settings.service.js';
8
8
  //# sourceMappingURL=index.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../packages/core/src/infrastructure/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,mBAAmB,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAGnE,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../packages/core/src/infrastructure/index.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAGH,OAAO,EAAE,mBAAmB,EAAE,sBAAsB,EAAE,SAAS,EAAE,MAAM,mBAAmB,CAAC;AAG3F,OAAO,EAAE,WAAW,EAAE,kBAAkB,EAAE,MAAM,gCAAgC,CAAC"}
@@ -4,6 +4,6 @@
4
4
  * Exports DI container, repositories, and services.
5
5
  */
6
6
  // DI container
7
- export { initializeContainer, container } from './di/container.js';
7
+ export { initializeContainer, isContainerInitialized, container } from './di/container.js';
8
8
  // Settings service
9
9
  export { getSettings, initializeSettings } from './services/settings.service.js';
@@ -3,19 +3,24 @@
3
3
  *
4
4
  * Manages the ~/.shep/ directory for global settings and data storage.
5
5
  * Ensures directory exists with correct permissions before database operations.
6
+ *
7
+ * Supports SHEP_HOME env var for test isolation (overrides default ~/.shep/).
6
8
  */
7
9
  /**
8
- * The root directory for Shep AI CLI data.
9
- * Located at ~/.shep/ in the user's home directory.
10
+ * Gets the path to the Shep home directory.
11
+ * Uses SHEP_HOME env var if set, otherwise ~/.shep/
12
+ *
13
+ * @returns Path to shep home directory
10
14
  */
11
- export declare const SHEP_HOME_DIR: string;
15
+ export declare function getShepHomeDir(): string;
12
16
  /**
13
- * The path to the SQLite database file.
14
- * Located at ~/.shep/data
17
+ * Gets the path to the SQLite database file.
18
+ *
19
+ * @returns Path to the database file
15
20
  */
16
- export declare const SHEP_DB_PATH: string;
21
+ export declare function getShepDbPath(): string;
17
22
  /**
18
- * Ensures the ~/.shep/ directory exists with correct permissions.
23
+ * Ensures the shep home directory exists with correct permissions.
19
24
  * Creates the directory if it doesn't exist.
20
25
  * Safe to call multiple times (idempotent).
21
26
  *
@@ -24,18 +29,4 @@ export declare const SHEP_DB_PATH: string;
24
29
  * @throws Error if directory cannot be created (permissions, disk space, etc.)
25
30
  */
26
31
  export declare function ensureShepDirectory(): Promise<void>;
27
- /**
28
- * Gets the path to the Shep home directory.
29
- * Does not create the directory.
30
- *
31
- * @returns Path to ~/.shep/
32
- */
33
- export declare function getShepHomeDir(): string;
34
- /**
35
- * Gets the path to the SQLite database file.
36
- * Does not create the file or directory.
37
- *
38
- * @returns Path to ~/.shep/data
39
- */
40
- export declare function getShepDbPath(): string;
41
32
  //# sourceMappingURL=shep-directory.service.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"shep-directory.service.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/filesystem/shep-directory.service.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAOH;;;GAGG;AACH,eAAO,MAAM,aAAa,QAA2B,CAAC;AAEtD;;;GAGG;AACH,eAAO,MAAM,YAAY,QAA8B,CAAC;AAExD;;;;;;;;GAQG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,CAkBzD;AAED;;;;;GAKG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED;;;;;GAKG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAEtC"}
1
+ {"version":3,"file":"shep-directory.service.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/filesystem/shep-directory.service.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAeH;;;;;GAKG;AACH,wBAAgB,cAAc,IAAI,MAAM,CAEvC;AAED;;;;GAIG;AACH,wBAAgB,aAAa,IAAI,MAAM,CAEtC;AAED;;;;;;;;GAQG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,IAAI,CAAC,CAiBzD"}
@@ -3,23 +3,39 @@
3
3
  *
4
4
  * Manages the ~/.shep/ directory for global settings and data storage.
5
5
  * Ensures directory exists with correct permissions before database operations.
6
+ *
7
+ * Supports SHEP_HOME env var for test isolation (overrides default ~/.shep/).
6
8
  */
7
9
  import { mkdir } from 'node:fs/promises';
8
10
  import { homedir } from 'node:os';
9
11
  import { join } from 'node:path';
10
12
  import { existsSync } from 'node:fs';
11
13
  /**
12
- * The root directory for Shep AI CLI data.
13
- * Located at ~/.shep/ in the user's home directory.
14
+ * Resolves the Shep home directory.
15
+ * Respects SHEP_HOME env var for test isolation, falls back to ~/.shep/
16
+ */
17
+ function resolveShepHomeDir() {
18
+ return process.env.SHEP_HOME ?? join(homedir(), '.shep');
19
+ }
20
+ /**
21
+ * Gets the path to the Shep home directory.
22
+ * Uses SHEP_HOME env var if set, otherwise ~/.shep/
23
+ *
24
+ * @returns Path to shep home directory
14
25
  */
15
- export const SHEP_HOME_DIR = join(homedir(), '.shep');
26
+ export function getShepHomeDir() {
27
+ return resolveShepHomeDir();
28
+ }
16
29
  /**
17
- * The path to the SQLite database file.
18
- * Located at ~/.shep/data
30
+ * Gets the path to the SQLite database file.
31
+ *
32
+ * @returns Path to the database file
19
33
  */
20
- export const SHEP_DB_PATH = join(SHEP_HOME_DIR, 'data');
34
+ export function getShepDbPath() {
35
+ return join(resolveShepHomeDir(), 'data');
36
+ }
21
37
  /**
22
- * Ensures the ~/.shep/ directory exists with correct permissions.
38
+ * Ensures the shep home directory exists with correct permissions.
23
39
  * Creates the directory if it doesn't exist.
24
40
  * Safe to call multiple times (idempotent).
25
41
  *
@@ -28,37 +44,17 @@ export const SHEP_DB_PATH = join(SHEP_HOME_DIR, 'data');
28
44
  * @throws Error if directory cannot be created (permissions, disk space, etc.)
29
45
  */
30
46
  export async function ensureShepDirectory() {
31
- // Check if directory already exists
32
- if (existsSync(SHEP_HOME_DIR)) {
47
+ const shepDir = resolveShepHomeDir();
48
+ if (existsSync(shepDir)) {
33
49
  return;
34
50
  }
35
51
  try {
36
- // Create directory with 700 permissions (owner read/write/execute only)
37
- await mkdir(SHEP_HOME_DIR, {
52
+ await mkdir(shepDir, {
38
53
  recursive: true,
39
54
  mode: 0o700,
40
55
  });
41
56
  }
42
57
  catch (error) {
43
- // Provide helpful error message
44
- throw new Error(`Failed to create Shep directory at ${SHEP_HOME_DIR}: ${error instanceof Error ? error.message : String(error)}`);
58
+ throw new Error(`Failed to create Shep directory at ${shepDir}: ${error instanceof Error ? error.message : String(error)}`);
45
59
  }
46
60
  }
47
- /**
48
- * Gets the path to the Shep home directory.
49
- * Does not create the directory.
50
- *
51
- * @returns Path to ~/.shep/
52
- */
53
- export function getShepHomeDir() {
54
- return SHEP_HOME_DIR;
55
- }
56
- /**
57
- * Gets the path to the SQLite database file.
58
- * Does not create the file or directory.
59
- *
60
- * @returns Path to ~/.shep/data
61
- */
62
- export function getShepDbPath() {
63
- return SHEP_DB_PATH;
64
- }
@@ -21,7 +21,7 @@ import { createHash } from 'node:crypto';
21
21
  import path from 'node:path';
22
22
  import { injectable, inject } from 'tsyringe';
23
23
  import { WorktreeError, WorktreeErrorCode, } from '../../../application/ports/output/services/worktree-service.interface.js';
24
- import { SHEP_HOME_DIR } from '../filesystem/shep-directory.service.js';
24
+ import { getShepHomeDir } from '../filesystem/shep-directory.service.js';
25
25
  let WorktreeService = class WorktreeService {
26
26
  execFile;
27
27
  constructor(execFile) {
@@ -65,7 +65,7 @@ let WorktreeService = class WorktreeService {
65
65
  getWorktreePath(repoPath, branch) {
66
66
  const repoHash = createHash('sha256').update(repoPath).digest('hex').slice(0, 16);
67
67
  const slug = branch.replace(/\//g, '-');
68
- return path.join(SHEP_HOME_DIR, 'repos', repoHash, 'wt', slug);
68
+ return path.join(getShepHomeDir(), 'repos', repoHash, 'wt', slug);
69
69
  }
70
70
  parseWorktreeOutput(output) {
71
71
  if (!output.trim())
@@ -1 +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"}
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;AAMH;;;;;;GAMG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM,CAI5E"}
@@ -7,9 +7,8 @@
7
7
  * Path format: ~/.shep/repos/<sha256-hash-prefix>/wt/<branch-slug>
8
8
  */
9
9
  import { createHash } from 'node:crypto';
10
- import { homedir } from 'node:os';
11
10
  import { join } from 'node:path';
12
- const SHEP_HOME_DIR = join(homedir(), '.shep');
11
+ import { getShepHomeDir } from '../filesystem/shep-directory.service.js';
13
12
  /**
14
13
  * Compute the worktree path for a given repository and branch.
15
14
  *
@@ -20,5 +19,5 @@ const SHEP_HOME_DIR = join(homedir(), '.shep');
20
19
  export function computeWorktreePath(repoPath, branch) {
21
20
  const repoHash = createHash('sha256').update(repoPath).digest('hex').slice(0, 16);
22
21
  const slug = branch.replace(/\//g, '-');
23
- return join(SHEP_HOME_DIR, 'repos', repoHash, 'wt', slug);
22
+ return join(getShepHomeDir(), 'repos', repoHash, 'wt', slug);
24
23
  }
@@ -3,8 +3,7 @@
3
3
  *
4
4
  * Provides global access to application settings within the CLI.
5
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
+ * module re-evaluations in Next.js API routes.
8
7
  *
9
8
  * Usage:
10
9
  * ```typescript
@@ -1 +1 @@
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"}
1
+ {"version":3,"file":"settings.service.d.ts","sourceRoot":"","sources":["../../../../../../packages/core/src/infrastructure/services/settings.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;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"}
@@ -3,8 +3,7 @@
3
3
  *
4
4
  * Provides global access to application settings within the CLI.
5
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
+ * module re-evaluations in Next.js API routes.
8
7
  *
9
8
  * Usage:
10
9
  * ```typescript
@@ -15,7 +15,7 @@ import { join } from 'node:path';
15
15
  import { container } from '../../../../../packages/core/src/infrastructure/di/container.js';
16
16
  import { CreateFeatureUseCase } from '../../../../../packages/core/src/application/use-cases/features/create/create-feature.use-case.js';
17
17
  import { colors, messages, spinner } from '../../ui/index.js';
18
- import { SHEP_HOME_DIR } from '../../../../../packages/core/src/infrastructure/services/filesystem/shep-directory.service.js';
18
+ import { getShepHomeDir } from '../../../../../packages/core/src/infrastructure/services/filesystem/shep-directory.service.js';
19
19
  /**
20
20
  * Create the feat new command
21
21
  */
@@ -48,7 +48,7 @@ export function createNewCommand() {
48
48
  const { feature, warning } = result;
49
49
  const repoHash = createHash('sha256').update(repoPath).digest('hex').slice(0, 16);
50
50
  const wtSlug = feature.branch.replace(/\//g, '-');
51
- const worktreePath = join(SHEP_HOME_DIR, 'repos', repoHash, 'wt', wtSlug);
51
+ const worktreePath = join(getShepHomeDir(), 'repos', repoHash, 'wt', wtSlug);
52
52
  messages.newline();
53
53
  if (warning) {
54
54
  messages.warning(warning);
@@ -1 +1 @@
1
- {"version":3,"file":"init.command.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/cli/commands/settings/init.command.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAiCpC;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,CAoC3C"}
1
+ {"version":3,"file":"init.command.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/cli/commands/settings/init.command.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAmCpC;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,CAkD3C"}
@@ -11,6 +11,7 @@ import { Command } from 'commander';
11
11
  import { createInterface } from 'node:readline';
12
12
  import { createDefaultSettings } from '../../../../../packages/core/src/domain/factories/settings-defaults.factory.js';
13
13
  import { resetSettings, initializeSettings } from '../../../../../packages/core/src/infrastructure/services/settings.service.js';
14
+ import { container } from '../../../../../packages/core/src/infrastructure/di/container.js';
14
15
  import { messages } from '../../ui/index.js';
15
16
  /**
16
17
  * Prompt user for yes/no confirmation.
@@ -57,7 +58,19 @@ Examples:
57
58
  return;
58
59
  }
59
60
  }
61
+ const repo = container.resolve('ISettingsRepository');
62
+ const existing = await repo.load();
60
63
  const newSettings = createDefaultSettings();
64
+ if (existing) {
65
+ // Preserve the existing record's identity, reset everything else
66
+ const resetSettings_db = {
67
+ ...newSettings,
68
+ id: existing.id,
69
+ createdAt: existing.createdAt,
70
+ };
71
+ await repo.update(resetSettings_db);
72
+ }
73
+ // Update in-memory singleton
61
74
  resetSettings();
62
75
  initializeSettings(newSettings);
63
76
  messages.success('Settings initialized to defaults.');
@@ -39,7 +39,6 @@ import { messages } from './ui/index.js';
39
39
  import { initializeContainer, container } from '../../../packages/core/src/infrastructure/di/container.js';
40
40
  import { InitializeSettingsUseCase } from '../../../packages/core/src/application/use-cases/settings/initialize-settings.use-case.js';
41
41
  import { initializeSettings } from '../../../packages/core/src/infrastructure/services/settings.service.js';
42
- import { populateUseCasesBridge } from '../../../packages/core/src/infrastructure/di/populate-use-cases-bridge.js';
43
42
  /**
44
43
  * Bootstrap function - initializes all dependencies before CLI starts.
45
44
  * Performs async initialization (database, settings) before parsing commands.
@@ -49,6 +48,8 @@ async function bootstrap() {
49
48
  // Step 1: Initialize DI container (database + migrations)
50
49
  try {
51
50
  await initializeContainer();
51
+ // Expose the DI container on globalThis for the web UI's server-side code
52
+ globalThis.__shepContainer = container;
52
53
  }
53
54
  catch (error) {
54
55
  const err = error instanceof Error ? error : new Error(String(error));
@@ -66,11 +67,6 @@ async function bootstrap() {
66
67
  messages.error('Failed to initialize settings', err);
67
68
  throw error;
68
69
  }
69
- // Expose resolved use cases on globalThis for the web layer.
70
- // The Next.js web UI (Turbopack) cannot import @shepai/core at runtime
71
- // (ESM .js extensions, native C++ addons, tsyringe decorators), so the
72
- // CLI places live instances on globalThis and the web reads them back.
73
- populateUseCasesBridge(container);
74
70
  // Step 3: Set up Commander CLI
75
71
  const versionService = container.resolve('IVersionService');
76
72
  const { version, description } = versionService.getVersion();
@@ -0,0 +1,11 @@
1
+ import { NextResponse } from 'next/server';
2
+ export declare function DELETE(_request: Request, { params }: {
3
+ params: Promise<{
4
+ id: string;
5
+ }>;
6
+ }): Promise<NextResponse<{
7
+ error: string;
8
+ }> | NextResponse<{
9
+ feature: import("../../../../../../../packages/core/src/domain/index.js").Feature;
10
+ }>>;
11
+ //# sourceMappingURL=route.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../../../../src/presentation/web/app/api/features/[id]/route.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAI3C,wBAAsB,MAAM,CAAC,QAAQ,EAAE,OAAO,EAAE,EAAE,MAAM,EAAE,EAAE;IAAE,MAAM,EAAE,OAAO,CAAC;QAAE,EAAE,EAAE,MAAM,CAAA;KAAE,CAAC,CAAA;CAAE;;;;IAe9F"}
@@ -0,0 +1,17 @@
1
+ import { NextResponse } from 'next/server';
2
+ import { resolve } from '../../../../lib/server-container.js';
3
+ export async function DELETE(_request, { params }) {
4
+ const { id } = await params;
5
+ if (!id?.trim()) {
6
+ return NextResponse.json({ error: 'id is required' }, { status: 400 });
7
+ }
8
+ try {
9
+ const deleteFeature = resolve('DeleteFeatureUseCase');
10
+ const feature = await deleteFeature.execute(id);
11
+ return NextResponse.json({ feature });
12
+ }
13
+ catch (error) {
14
+ const message = error instanceof Error ? error.message : 'Failed to delete feature';
15
+ return NextResponse.json({ error: message }, { status: 500 });
16
+ }
17
+ }
@@ -1,5 +1,5 @@
1
1
  import { NextResponse } from 'next/server';
2
2
  export declare function POST(request: Request): Promise<NextResponse<{
3
3
  error: string;
4
- }> | NextResponse<import("../../../../../../../packages/core/src/infrastructure/di/use-cases-bridge.js").CreateFeatureResult>>;
4
+ }> | NextResponse<import("../../../../../../../packages/core/src/application/use-cases/features/create/types.js").CreateFeatureResult>>;
5
5
  //# sourceMappingURL=route.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../../../../src/presentation/web/app/api/features/create/route.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAqD3C,wBAAsB,IAAI,CAAC,OAAO,EAAE,OAAO;;kGAyC1C"}
1
+ {"version":3,"file":"route.d.ts","sourceRoot":"","sources":["../../../../../../../../src/presentation/web/app/api/features/create/route.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAsD3C,wBAAsB,IAAI,CAAC,OAAO,EAAE,OAAO;;2GA0C1C"}
@@ -1,5 +1,5 @@
1
1
  import { NextResponse } from 'next/server';
2
- import { createFeature } from '../../../../../../../packages/core/src/infrastructure/di/use-cases-bridge.js';
2
+ import { resolve } from '../../../../lib/server-container.js';
3
3
  function isValidApprovalGates(value) {
4
4
  if (typeof value !== 'object' || value === null || Array.isArray(value))
5
5
  return false;
@@ -48,7 +48,8 @@ export async function POST(request) {
48
48
  ? normalizeApprovalGates(approvalGates)
49
49
  : defaultGates;
50
50
  try {
51
- const result = await createFeature({ userInput, repositoryPath, approvalGates: gates });
51
+ const createFeature = resolve('CreateFeatureUseCase');
52
+ const result = await createFeature.execute({ userInput, repositoryPath, approvalGates: gates });
52
53
  return NextResponse.json(result);
53
54
  }
54
55
  catch (error) {
@@ -1,4 +1,4 @@
1
- /** Force request-time rendering so the globalThis DI bridge is available. */
1
+ /** Force request-time rendering so the DI container is available. */
2
2
  export declare const dynamic = "force-dynamic";
3
3
  export default function HomePage(): Promise<import("react/jsx-runtime").JSX.Element>;
4
4
  //# sourceMappingURL=page.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"page.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/web/app/page.tsx"],"names":[],"mappings":"AAWA,6EAA6E;AAC7E,eAAO,MAAM,OAAO,kBAAkB,CAAC;AAqBvC,wBAA8B,QAAQ,qDAmFrC"}
1
+ {"version":3,"file":"page.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/web/app/page.tsx"],"names":[],"mappings":"AAaA,qEAAqE;AACrE,eAAO,MAAM,OAAO,kBAAkB,CAAC;AAqBvC,wBAA8B,QAAQ,qDAqFrC"}
@@ -1,9 +1,9 @@
1
1
  import { jsx as _jsx } from "react/jsx-runtime";
2
2
  import { ControlCenter } from '../components/features/control-center/index.js';
3
- import { getAgentRun, getFeatures } from '../../../../packages/core/src/infrastructure/di/use-cases-bridge.js';
3
+ import { resolve } from '../lib/server-container.js';
4
4
  import { deriveNodeState, deriveProgress, } from '../components/common/feature-node/derive-feature-state.js';
5
5
  import { layoutWithDagre } from '../lib/layout-with-dagre.js';
6
- /** Force request-time rendering so the globalThis DI bridge is available. */
6
+ /** Force request-time rendering so the DI container is available. */
7
7
  export const dynamic = 'force-dynamic';
8
8
  /** Map domain SdlcLifecycle enum values to UI FeatureLifecyclePhase (1:1). */
9
9
  const lifecycleMap = {
@@ -23,9 +23,11 @@ const nodeToLifecyclePhase = {
23
23
  implement: 'implementation',
24
24
  };
25
25
  export default async function HomePage() {
26
- const features = await getFeatures();
26
+ const listFeatures = resolve('ListFeaturesUseCase');
27
+ const agentRunRepo = resolve('IAgentRunRepository');
28
+ const features = await listFeatures.execute();
27
29
  const featuresWithRuns = await Promise.all(features.map(async (feature) => {
28
- const run = feature.agentRunId ? await getAgentRun(feature.agentRunId) : null;
30
+ const run = feature.agentRunId ? await agentRunRepo.findById(feature.agentRunId) : null;
29
31
  return { feature, run };
30
32
  }));
31
33
  // Group features by repository path
@@ -1,4 +1,4 @@
1
- import type { CreateFeatureInput } from '../../../../../../packages/core/src/infrastructure/di/use-cases-bridge.js';
1
+ import type { CreateFeatureInput } from '../../../../../../packages/core/src/application/use-cases/features/create/types.js';
2
2
  export type { FileAttachment } from '../../../../../../packages/core/src/infrastructure/services/file-dialog.service.js';
3
3
  export interface FeatureCreateDrawerProps {
4
4
  open: boolean;
@@ -1 +1 @@
1
- {"version":3,"file":"feature-create-drawer.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.tsx"],"names":[],"mappings":"AA8BA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iDAAiD,CAAC;AAG1F,YAAY,EAAE,cAAc,EAAE,MAAM,0DAA0D,CAAC;AAiC/F,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,EAAE,CAAC,IAAI,EAAE,kBAAkB,KAAK,IAAI,CAAC;IAC7C,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,wBAAgB,mBAAmB,CAAC,EAClC,IAAI,EACJ,OAAO,EACP,QAAQ,EACR,cAAc,EACd,YAAoB,GACrB,EAAE,wBAAwB,2CA6L1B"}
1
+ {"version":3,"file":"feature-create-drawer.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.tsx"],"names":[],"mappings":"AA8BA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,0DAA0D,CAAC;AAGnG,YAAY,EAAE,cAAc,EAAE,MAAM,0DAA0D,CAAC;AAiC/F,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,EAAE,CAAC,IAAI,EAAE,kBAAkB,KAAK,IAAI,CAAC;IAC7C,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,OAAO,CAAC;CACxB;AAED,wBAAgB,mBAAmB,CAAC,EAClC,IAAI,EACJ,OAAO,EACP,QAAQ,EACR,cAAc,EACd,YAAoB,GACrB,EAAE,wBAAwB,2CA6L1B"}
@@ -2,6 +2,8 @@ import type { FeatureNodeData } from '../../common/feature-node/index.js';
2
2
  export interface FeatureDrawerProps {
3
3
  selectedNode: FeatureNodeData | null;
4
4
  onClose: () => void;
5
+ onDelete?: (featureId: string) => void;
6
+ isDeleting?: boolean;
5
7
  }
6
- export declare function FeatureDrawer({ selectedNode, onClose }: FeatureDrawerProps): import("react/jsx-runtime").JSX.Element;
8
+ export declare function FeatureDrawer({ selectedNode, onClose, onDelete, isDeleting, }: FeatureDrawerProps): import("react/jsx-runtime").JSX.Element;
7
9
  //# sourceMappingURL=feature-drawer.d.ts.map
@@ -1 +1 @@
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
+ {"version":3,"file":"feature-drawer.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-drawer/feature-drawer.tsx"],"names":[],"mappings":"AA0BA,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;IACpB,QAAQ,CAAC,EAAE,CAAC,SAAS,EAAE,MAAM,KAAK,IAAI,CAAC;IACvC,UAAU,CAAC,EAAE,OAAO,CAAC;CACtB;AAED,wBAAgB,aAAa,CAAC,EAC5B,YAAY,EACZ,OAAO,EACP,QAAQ,EACR,UAAkB,GACnB,EAAE,kBAAkB,2CAyHpB"}
@@ -1,18 +1,19 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
- import { XIcon, Code2, Terminal, Loader2, CircleAlert } from 'lucide-react';
3
+ import { XIcon, Code2, Terminal, Loader2, CircleAlert, Trash2 } from 'lucide-react';
4
4
  import { cn } from '../../../lib/utils.js';
5
5
  import { Drawer, DrawerContent, DrawerHeader, DrawerTitle, DrawerDescription, } from '../../ui/drawer.js';
6
6
  import { Button } from '../../ui/button.js';
7
7
  import { Separator } from '../../ui/separator.js';
8
8
  import { CometSpinner } from '../../ui/comet-spinner.js';
9
+ import { AlertDialog, AlertDialogAction, AlertDialogCancel, AlertDialogContent, AlertDialogDescription, AlertDialogFooter, AlertDialogHeader, AlertDialogTitle, AlertDialogTrigger, } from '../../ui/alert-dialog.js';
9
10
  import { featureNodeStateConfig, lifecycleDisplayLabels } from '../../common/feature-node/index.js';
10
11
  import { useFeatureActions } from './use-feature-actions.js';
11
- export function FeatureDrawer({ selectedNode, onClose }) {
12
+ export function FeatureDrawer({ selectedNode, onClose, onDelete, isDeleting = false, }) {
12
13
  return (_jsx(Drawer, { direction: "right", modal: false, open: selectedNode !== null, onOpenChange: (open) => {
13
14
  if (!open)
14
15
  onClose();
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 }) }));
16
+ }, 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 }), onDelete ? (_jsxs(_Fragment, { children: [_jsx(Separator, {}), _jsx("div", { "data-testid": "feature-drawer-delete", className: "p-4", children: _jsxs(AlertDialog, { children: [_jsx(AlertDialogTrigger, { asChild: true, children: _jsxs(Button, { variant: "destructive", className: "w-full", disabled: isDeleting, children: [_jsx(Trash2, { className: "mr-2 h-4 w-4" }), "Delete feature"] }) }), _jsxs(AlertDialogContent, { children: [_jsxs(AlertDialogHeader, { children: [_jsx(AlertDialogTitle, { children: "Delete feature?" }), _jsxs(AlertDialogDescription, { children: ["This will permanently delete ", _jsx("strong", { children: selectedNode.name }), " (", selectedNode.featureId, "). This action cannot be undone.", selectedNode.state === 'running' ? (_jsx(_Fragment, { children: " This feature has a running agent that will be stopped." })) : null] })] }), _jsxs(AlertDialogFooter, { children: [_jsx(AlertDialogCancel, { disabled: isDeleting, children: "Cancel" }), _jsx(AlertDialogAction, { variant: "destructive", disabled: isDeleting, onClick: () => onDelete(selectedNode.featureId), children: isDeleting ? (_jsxs(_Fragment, { children: [_jsx(Loader2, { className: "mr-2 h-4 w-4 animate-spin" }), "Deleting\u2026"] })) : ('Delete') })] })] })] }) })] })) : null] })) : null }) }));
16
17
  }
17
18
  function StateBadge({ data }) {
18
19
  const config = featureNodeStateConfig[data.state];
@@ -24,4 +24,10 @@ export declare const NoRepositoryPath: Story;
24
24
  * (API routes are not available in Storybook).
25
25
  */
26
26
  export declare const WithActionButtons: Story;
27
+ /** FeatureDrawer with a delete button in the footer. */
28
+ export declare const WithDeleteButton: Story;
29
+ /** FeatureDrawer showing the delete button in loading/disabled state. */
30
+ export declare const DeletingState: Story;
31
+ /** FeatureDrawer with a running agent showing the running-agent warning in the AlertDialog. */
32
+ export declare const DeleteRunningAgent: Story;
27
33
  //# sourceMappingURL=feature-drawer.stories.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"feature-drawer.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-drawer/feature-drawer.stories.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAKjD,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,aAAa,CAOpC,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,aAAa,CAAC,CAAC;AAgG5C,eAAO,MAAM,OAAO,EAAE,KAErB,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,KAE5B,CAAC;AAEF,eAAO,MAAM,IAAI,EAAE,KAElB,CAAC;AAEF,eAAO,MAAM,OAAO,EAAE,KAErB,CAAC;AAEF,eAAO,MAAM,KAAK,EAAE,KAEnB,CAAC;AAMF,wEAAwE;AACxE,eAAO,MAAM,WAAW,EAAE,KAEzB,CAAC;AAEF,qFAAqF;AACrF,eAAO,MAAM,SAAS,EAAE,KAqBvB,CAAC;AAuDF,0DAA0D;AAC1D,eAAO,MAAM,SAAS,EAAE,KAEvB,CAAC;AA6CF,wDAAwD;AACxD,eAAO,MAAM,aAAa,EAAE,KAE3B,CAAC;AAMF,qDAAqD;AACrD,eAAO,MAAM,gBAAgB,EAAE,KAO9B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,EAAE,KAE/B,CAAC"}
1
+ {"version":3,"file":"feature-drawer.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-drawer/feature-drawer.stories.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAKjD,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,aAAa,CAOpC,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,aAAa,CAAC,CAAC;AAgG5C,eAAO,MAAM,OAAO,EAAE,KAErB,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,KAE5B,CAAC;AAEF,eAAO,MAAM,IAAI,EAAE,KAElB,CAAC;AAEF,eAAO,MAAM,OAAO,EAAE,KAErB,CAAC;AAEF,eAAO,MAAM,KAAK,EAAE,KAEnB,CAAC;AAMF,wEAAwE;AACxE,eAAO,MAAM,WAAW,EAAE,KAEzB,CAAC;AAEF,qFAAqF;AACrF,eAAO,MAAM,SAAS,EAAE,KAqBvB,CAAC;AAuDF,0DAA0D;AAC1D,eAAO,MAAM,SAAS,EAAE,KAEvB,CAAC;AA6CF,wDAAwD;AACxD,eAAO,MAAM,aAAa,EAAE,KAE3B,CAAC;AAMF,qDAAqD;AACrD,eAAO,MAAM,gBAAgB,EAAE,KAO9B,CAAC;AAEF;;;;GAIG;AACH,eAAO,MAAM,iBAAiB,EAAE,KAE/B,CAAC;AAoCF,wDAAwD;AACxD,eAAO,MAAM,gBAAgB,EAAE,KAE9B,CAAC;AAEF,yEAAyE;AACzE,eAAO,MAAM,aAAa,EAAE,KAE3B,CAAC;AAEF,+FAA+F;AAC/F,eAAO,MAAM,kBAAkB,EAAE,KAEhC,CAAC"}
@@ -196,3 +196,25 @@ export const NoRepositoryPath = {
196
196
  export const WithActionButtons = {
197
197
  render: () => _jsx(DrawerTrigger, { data: runningData, label: "Open With Actions" }),
198
198
  };
199
+ /* ---------------------------------------------------------------------------
200
+ * Delete stories
201
+ * ------------------------------------------------------------------------- */
202
+ function noop() {
203
+ // intentional no-op for stories
204
+ }
205
+ function DrawerTriggerWithDelete({ data, label, isDeleting = false, }) {
206
+ const [selected, setSelected] = useState(null);
207
+ return (_jsxs("div", { className: "flex h-screen items-start p-4", children: [_jsx(Button, { variant: "outline", onClick: () => setSelected(data), children: label }), _jsx(FeatureDrawer, { selectedNode: selected, onClose: () => setSelected(null), onDelete: noop, isDeleting: isDeleting })] }));
208
+ }
209
+ /** FeatureDrawer with a delete button in the footer. */
210
+ export const WithDeleteButton = {
211
+ render: () => _jsx(DrawerTriggerWithDelete, { data: doneData, label: "Open With Delete" }),
212
+ };
213
+ /** FeatureDrawer showing the delete button in loading/disabled state. */
214
+ export const DeletingState = {
215
+ render: () => _jsx(DrawerTriggerWithDelete, { data: doneData, label: "Open Deleting State", isDeleting: true }),
216
+ };
217
+ /** FeatureDrawer with a running agent showing the running-agent warning in the AlertDialog. */
218
+ export const DeleteRunningAgent = {
219
+ render: () => _jsx(DrawerTriggerWithDelete, { data: runningData, label: "Open Running Agent Delete" }),
220
+ };