@shepai/cli 1.134.1 → 1.135.0-pr430.5b0b699

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 (182) hide show
  1. package/apis/json-schema/FeatureFlags.yaml +1 -1
  2. package/dist/packages/core/src/application/use-cases/features/create/create-feature-from-remote.use-case.d.ts +82 -0
  3. package/dist/packages/core/src/application/use-cases/features/create/create-feature-from-remote.use-case.d.ts.map +1 -0
  4. package/dist/packages/core/src/application/use-cases/features/create/create-feature-from-remote.use-case.js +96 -0
  5. package/dist/packages/core/src/domain/factories/settings-defaults.factory.js +1 -1
  6. package/dist/packages/core/src/infrastructure/di/container.d.ts.map +1 -1
  7. package/dist/packages/core/src/infrastructure/di/container.js +5 -0
  8. package/dist/packages/core/src/infrastructure/services/git/git-pr.service.d.ts.map +1 -1
  9. package/dist/packages/core/src/infrastructure/services/git/git-pr.service.js +9 -1
  10. package/dist/src/presentation/cli/commands/feat/new.command.d.ts +1 -0
  11. package/dist/src/presentation/cli/commands/feat/new.command.d.ts.map +1 -1
  12. package/dist/src/presentation/cli/commands/feat/new.command.js +88 -7
  13. package/dist/src/presentation/web/app/actions/create-feature-from-remote.d.ts +29 -0
  14. package/dist/src/presentation/web/app/actions/create-feature-from-remote.d.ts.map +1 -0
  15. package/dist/src/presentation/web/app/actions/create-feature-from-remote.js +72 -0
  16. package/dist/src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.d.ts.map +1 -1
  17. package/dist/src/presentation/web/components/common/feature-create-drawer/feature-create-drawer.js +18 -4
  18. package/dist/src/presentation/web/components/common/feature-create-drawer/repository-combobox.stories.d.ts +6 -0
  19. package/dist/src/presentation/web/components/common/feature-create-drawer/repository-combobox.stories.d.ts.map +1 -1
  20. package/dist/src/presentation/web/components/common/feature-create-drawer/repository-combobox.stories.js +35 -2
  21. package/dist/src/presentation/web/lib/feature-flags.js +1 -1
  22. package/dist/tsconfig.build.tsbuildinfo +1 -1
  23. package/package.json +1 -1
  24. package/web/.next/BUILD_ID +1 -1
  25. package/web/.next/build-manifest.json +2 -2
  26. package/web/.next/fallback-build-manifest.json +2 -2
  27. package/web/.next/prerender-manifest.json +3 -3
  28. package/web/.next/required-server-files.js +3 -3
  29. package/web/.next/required-server-files.json +3 -3
  30. package/web/.next/server/app/(dashboard)/@drawer/adopt/page/server-reference-manifest.json +24 -24
  31. package/web/.next/server/app/(dashboard)/@drawer/adopt/page.js.nft.json +1 -1
  32. package/web/.next/server/app/(dashboard)/@drawer/adopt/page_client-reference-manifest.js +1 -1
  33. package/web/.next/server/app/(dashboard)/@drawer/create/page/server-reference-manifest.json +24 -24
  34. package/web/.next/server/app/(dashboard)/@drawer/create/page.js.nft.json +1 -1
  35. package/web/.next/server/app/(dashboard)/@drawer/create/page_client-reference-manifest.js +1 -1
  36. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page/server-reference-manifest.json +30 -30
  37. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page.js.nft.json +1 -1
  38. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page_client-reference-manifest.js +1 -1
  39. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page/server-reference-manifest.json +30 -30
  40. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js.nft.json +1 -1
  41. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page_client-reference-manifest.js +1 -1
  42. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page/server-reference-manifest.json +22 -22
  43. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js.nft.json +1 -1
  44. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  45. package/web/.next/server/app/(dashboard)/create/page/server-reference-manifest.json +24 -24
  46. package/web/.next/server/app/(dashboard)/create/page.js.nft.json +1 -1
  47. package/web/.next/server/app/(dashboard)/create/page_client-reference-manifest.js +1 -1
  48. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page/server-reference-manifest.json +30 -30
  49. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page.js.nft.json +1 -1
  50. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page_client-reference-manifest.js +1 -1
  51. package/web/.next/server/app/(dashboard)/feature/[featureId]/page/server-reference-manifest.json +30 -30
  52. package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js.nft.json +1 -1
  53. package/web/.next/server/app/(dashboard)/feature/[featureId]/page_client-reference-manifest.js +1 -1
  54. package/web/.next/server/app/(dashboard)/page/server-reference-manifest.json +22 -22
  55. package/web/.next/server/app/(dashboard)/page.js.nft.json +1 -1
  56. package/web/.next/server/app/(dashboard)/page_client-reference-manifest.js +1 -1
  57. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page/server-reference-manifest.json +22 -22
  58. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js.nft.json +1 -1
  59. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  60. package/web/.next/server/app/_global-error.html +2 -2
  61. package/web/.next/server/app/_global-error.rsc +1 -1
  62. package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  63. package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  64. package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  65. package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  66. package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  67. package/web/.next/server/app/_not-found/page/server-reference-manifest.json +3 -3
  68. package/web/.next/server/app/_not-found/page.js.nft.json +1 -1
  69. package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  70. package/web/.next/server/app/api/attachments/preview/route.js.nft.json +1 -1
  71. package/web/.next/server/app/api/evidence/route.js.nft.json +1 -1
  72. package/web/.next/server/app/api/graph-data/route.js.nft.json +1 -1
  73. package/web/.next/server/app/settings/page/server-reference-manifest.json +8 -8
  74. package/web/.next/server/app/settings/page.js.nft.json +1 -1
  75. package/web/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  76. package/web/.next/server/app/skills/page/server-reference-manifest.json +8 -8
  77. package/web/.next/server/app/skills/page.js.nft.json +1 -1
  78. package/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  79. package/web/.next/server/app/tools/page/server-reference-manifest.json +8 -8
  80. package/web/.next/server/app/tools/page.js.nft.json +1 -1
  81. package/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
  82. package/web/.next/server/app/version/page/server-reference-manifest.json +3 -3
  83. package/web/.next/server/app/version/page.js.nft.json +1 -1
  84. package/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
  85. package/web/.next/server/chunks/[root-of-the-server]__a402b567._.js +1 -1
  86. package/web/.next/server/chunks/ssr/744ca_web__next-internal_server_app_(dashboard)_@drawer_adopt_page_actions_4e741df2.js +1 -1
  87. package/web/.next/server/chunks/ssr/744ca_web__next-internal_server_app_(dashboard)_@drawer_adopt_page_actions_4e741df2.js.map +1 -1
  88. package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js +1 -1
  89. package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js.map +1 -1
  90. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_026fdffa.js +1 -1
  91. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_026fdffa.js.map +1 -1
  92. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_8b91e197.js +1 -1
  93. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_8b91e197.js.map +1 -1
  94. package/web/.next/server/chunks/ssr/[root-of-the-server]__2c791c42._.js +2 -2
  95. package/web/.next/server/chunks/ssr/[root-of-the-server]__357d99f9._.js +1 -1
  96. package/web/.next/server/chunks/ssr/[root-of-the-server]__3ef34e4c._.js +1 -1
  97. package/web/.next/server/chunks/ssr/[root-of-the-server]__43f51aa6._.js +1 -1
  98. package/web/.next/server/chunks/ssr/[root-of-the-server]__43f51aa6._.js.map +1 -1
  99. package/web/.next/server/chunks/ssr/[root-of-the-server]__6bb00d90._.js +2 -2
  100. package/web/.next/server/chunks/ssr/[root-of-the-server]__6bb00d90._.js.map +1 -1
  101. package/web/.next/server/chunks/ssr/[root-of-the-server]__755cfe02._.js +1 -1
  102. package/web/.next/server/chunks/ssr/[root-of-the-server]__755cfe02._.js.map +1 -1
  103. package/web/.next/server/chunks/ssr/[root-of-the-server]__815546bd._.js +1 -1
  104. package/web/.next/server/chunks/ssr/[root-of-the-server]__815546bd._.js.map +1 -1
  105. package/web/.next/server/chunks/ssr/[root-of-the-server]__8fae3a20._.js +3 -0
  106. package/web/.next/server/chunks/ssr/[root-of-the-server]__8fae3a20._.js.map +1 -0
  107. package/web/.next/server/chunks/ssr/[root-of-the-server]__96670392._.js +2 -2
  108. package/web/.next/server/chunks/ssr/[root-of-the-server]__a628fb91._.js +1 -1
  109. package/web/.next/server/chunks/ssr/[root-of-the-server]__a628fb91._.js.map +1 -1
  110. package/web/.next/server/chunks/ssr/[root-of-the-server]__bfba58e6._.js +1 -1
  111. package/web/.next/server/chunks/ssr/[root-of-the-server]__bfba58e6._.js.map +1 -1
  112. package/web/.next/server/chunks/ssr/[root-of-the-server]__c3ab8422._.js +1 -1
  113. package/web/.next/server/chunks/ssr/[root-of-the-server]__c3ab8422._.js.map +1 -1
  114. package/web/.next/server/chunks/ssr/_02ec1aea._.js +1 -1
  115. package/web/.next/server/chunks/ssr/_02ec1aea._.js.map +1 -1
  116. package/web/.next/server/chunks/ssr/_2e03c237._.js +3 -0
  117. package/web/.next/server/chunks/ssr/_2e03c237._.js.map +1 -0
  118. package/web/.next/server/chunks/ssr/_7acd7690._.js +9 -0
  119. package/web/.next/server/chunks/ssr/_7acd7690._.js.map +1 -0
  120. package/web/.next/server/chunks/ssr/_7dca1882._.js +1 -1
  121. package/web/.next/server/chunks/ssr/_7dca1882._.js.map +1 -1
  122. package/web/.next/server/chunks/ssr/{_a72b7c58._.js → _93a801f1._.js} +2 -2
  123. package/web/.next/server/chunks/ssr/{_a72b7c58._.js.map → _93a801f1._.js.map} +1 -1
  124. package/web/.next/server/chunks/ssr/_a37f5f18._.js +1 -1
  125. package/web/.next/server/chunks/ssr/_a37f5f18._.js.map +1 -1
  126. package/web/.next/server/chunks/ssr/_a9f57758._.js +1 -1
  127. package/web/.next/server/chunks/ssr/_a9f57758._.js.map +1 -1
  128. package/web/.next/server/chunks/ssr/{_2245e9a2._.js → _d1c40d87._.js} +2 -2
  129. package/web/.next/server/chunks/ssr/{_2245e9a2._.js.map → _d1c40d87._.js.map} +1 -1
  130. package/web/.next/server/chunks/ssr/_d8575088._.js +1 -1
  131. package/web/.next/server/chunks/ssr/_d8575088._.js.map +1 -1
  132. package/web/.next/server/chunks/ssr/_f39a1adb._.js +1 -1
  133. package/web/.next/server/chunks/ssr/_f39a1adb._.js.map +1 -1
  134. package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js +1 -1
  135. package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js.map +1 -1
  136. package/web/.next/server/chunks/ssr/src_presentation_web_7daab21a._.js +3 -0
  137. package/web/.next/server/chunks/ssr/{src_presentation_web_2deef0bb._.js.map → src_presentation_web_7daab21a._.js.map} +1 -1
  138. package/web/.next/server/chunks/ssr/src_presentation_web_8e7fe0d1._.js +2 -2
  139. package/web/.next/server/chunks/ssr/src_presentation_web_8e7fe0d1._.js.map +1 -1
  140. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_ca051134.js +1 -1
  141. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_ca051134.js.map +1 -1
  142. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_1b176e3c.js +1 -1
  143. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_1b176e3c.js.map +1 -1
  144. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_bd9f0dda.js +1 -1
  145. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_bd9f0dda.js.map +1 -1
  146. package/web/.next/server/chunks/ssr/src_presentation_web_b9023017._.js +2 -2
  147. package/web/.next/server/chunks/ssr/src_presentation_web_b9023017._.js.map +1 -1
  148. package/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js +1 -1
  149. package/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js.map +1 -1
  150. package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js +1 -1
  151. package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js.map +1 -1
  152. package/web/.next/server/pages/500.html +2 -2
  153. package/web/.next/server/server-reference-manifest.js +1 -1
  154. package/web/.next/server/server-reference-manifest.json +38 -38
  155. package/web/.next/static/chunks/{0d402c720e467362.js → 49f9ce1e2953f293.js} +1 -1
  156. package/web/.next/static/chunks/{7bf6864106b4a492.js → 6c628cd7f8e54b37.js} +1 -1
  157. package/web/.next/static/chunks/9d55dd03daac8bb2.js +3 -0
  158. package/web/.next/static/chunks/9e35dfeb65fbb0ff.js +2 -0
  159. package/web/.next/static/chunks/a20470eee309dc12.js +1 -0
  160. package/web/.next/static/chunks/abbc9bc0ecff7cac.js +1 -0
  161. package/web/.next/static/chunks/{3a7297918dbc91a3.js → c0bc54eda21bbcf1.js} +1 -1
  162. package/web/.next/static/chunks/{f6a3616c124c7477.js → c99297cbb9c20255.js} +2 -2
  163. package/web/.next/static/chunks/cc54a5316b728fd9.js +1 -0
  164. package/web/.next/static/chunks/e95018ef71b4083d.js +11 -0
  165. package/web/.next/static/chunks/{57b2b14dd532178a.js → eb8bb6289b905648.js} +1 -1
  166. package/web/.next/static/chunks/ebe7f939b642b667.js +1 -0
  167. package/web/.next/static/chunks/{6873d45035d5a770.js → ecbbae4d5e4cfab2.js} +1 -1
  168. package/web/.next/server/chunks/ssr/[root-of-the-server]__7894f27f._.js +0 -3
  169. package/web/.next/server/chunks/ssr/[root-of-the-server]__7894f27f._.js.map +0 -1
  170. package/web/.next/server/chunks/ssr/_01046927._.js +0 -9
  171. package/web/.next/server/chunks/ssr/_01046927._.js.map +0 -1
  172. package/web/.next/server/chunks/ssr/src_presentation_web_2deef0bb._.js +0 -3
  173. package/web/.next/static/chunks/0881a378255faa56.js +0 -1
  174. package/web/.next/static/chunks/0b7fe2ac4f078f54.js +0 -13
  175. package/web/.next/static/chunks/1198e6430b3d8d60.js +0 -1
  176. package/web/.next/static/chunks/295eda9920677a58.js +0 -2
  177. package/web/.next/static/chunks/3ca48946f52422b7.js +0 -1
  178. package/web/.next/static/chunks/78fcc26559384102.js +0 -1
  179. package/web/.next/static/chunks/b5a6eb27a1639a39.js +0 -1
  180. /package/web/.next/static/{OjdBKBsY7_vAITPyXhtKr → 5_A91ycYn-g6phGM-k_v-}/_buildManifest.js +0 -0
  181. /package/web/.next/static/{OjdBKBsY7_vAITPyXhtKr → 5_A91ycYn-g6phGM-k_v-}/_clientMiddlewareManifest.json +0 -0
  182. /package/web/.next/static/{OjdBKBsY7_vAITPyXhtKr → 5_A91ycYn-g6phGM-k_v-}/_ssgManifest.js +0 -0
@@ -16,7 +16,7 @@ properties:
16
16
  description: Enable debug UI elements and verbose client-side logging
17
17
  githubImport:
18
18
  type: boolean
19
- default: false
19
+ default: true
20
20
  description: Enable GitHub repository import in the web UI
21
21
  adoptBranch:
22
22
  type: boolean
@@ -0,0 +1,82 @@
1
+ /**
2
+ * Create Feature From Remote Use Case
3
+ *
4
+ * Composite use case that orchestrates importing a GitHub repository via
5
+ * ImportGitHubRepositoryUseCase and then creating a feature via
6
+ * CreateFeatureUseCase. Provides both a single execute() method (for CLI)
7
+ * and two-phase createRecord() + initializeAndSpawn() (for Web UI).
8
+ */
9
+ import type { Feature } from '../../../../domain/generated/output.js';
10
+ import type { CloneOptions } from '../../../ports/output/services/github-repository-service.interface.js';
11
+ import type { ApprovalGates, Attachment } from '../../../../domain/generated/output.js';
12
+ import { ImportGitHubRepositoryUseCase } from '../../repositories/import-github-repository.use-case.js';
13
+ import { CreateFeatureUseCase } from './create-feature.use-case.js';
14
+ import type { CreateFeatureResult, CreateRecordResult } from './types.js';
15
+ export interface CreateFeatureFromRemoteInput {
16
+ /** GitHub URL or shorthand (e.g. "owner/repo", HTTPS, SSH) */
17
+ remoteUrl: string;
18
+ /** Override clone destination directory */
19
+ cloneDest?: string;
20
+ /** Default base directory for clones (from settings) */
21
+ defaultCloneDir?: string;
22
+ /** Options for the clone subprocess (e.g. progress callback) */
23
+ cloneOptions?: CloneOptions;
24
+ /** Description of the feature to create */
25
+ userInput: string;
26
+ /** Approval gate settings */
27
+ approvalGates?: ApprovalGates;
28
+ /** Push branch to remote after creation */
29
+ push?: boolean;
30
+ /** Open a PR after creation */
31
+ openPr?: boolean;
32
+ /** Optional ID of the parent feature */
33
+ parentId?: string;
34
+ /** Pre-supplied name (skips AI metadata extraction for name) */
35
+ name?: string;
36
+ /** Pre-supplied description (skips AI metadata extraction for description) */
37
+ description?: string;
38
+ /** When true, skip SDLC phases and implement directly */
39
+ fast?: boolean;
40
+ /** When true, create feature in Pending state */
41
+ pending?: boolean;
42
+ /** Optional agent type override */
43
+ agentType?: string;
44
+ /** Optional model identifier forwarded to the agent executor */
45
+ model?: string;
46
+ /** Attachment records to persist with the feature */
47
+ attachments?: Attachment[];
48
+ /** Session ID for committing pending uploads (web UI flow) */
49
+ sessionId?: string;
50
+ /** Absolute file paths to attach (CLI --attach flow) */
51
+ attachmentPaths?: string[];
52
+ }
53
+ export declare class CreateFeatureFromRemoteUseCase {
54
+ private readonly importGitHubRepo;
55
+ private readonly createFeature;
56
+ constructor(importGitHubRepo: ImportGitHubRepositoryUseCase, createFeature: CreateFeatureUseCase);
57
+ /**
58
+ * Full execution: imports the repository (or finds existing), then creates
59
+ * the feature with all SDLC initialization. Used by the CLI.
60
+ */
61
+ execute(input: CreateFeatureFromRemoteInput): Promise<CreateFeatureResult>;
62
+ /**
63
+ * Phase 1 (fast): Imports the repository, then creates the feature + agent
64
+ * run records in DB. Returns immediately with a real feature ID.
65
+ * Used by the Web UI for optimistic rendering.
66
+ */
67
+ createRecord(input: CreateFeatureFromRemoteInput): Promise<CreateRecordResult>;
68
+ /**
69
+ * Phase 2 (slow): AI metadata generation, git worktree, spec init, agent spawn.
70
+ * Delegates directly to CreateFeatureUseCase since import is already complete.
71
+ */
72
+ initializeAndSpawn(feature: Feature, input: CreateFeatureFromRemoteInput, shouldSpawn: boolean): Promise<{
73
+ warning?: string;
74
+ updatedFeature: Feature;
75
+ }>;
76
+ /**
77
+ * Maps CreateFeatureFromRemoteInput to CreateFeatureInput by injecting
78
+ * the repositoryPath derived from the import result.
79
+ */
80
+ private toCreateFeatureInput;
81
+ }
82
+ //# sourceMappingURL=create-feature-from-remote.use-case.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-feature-from-remote.use-case.d.ts","sourceRoot":"","sources":["../../../../../../../../packages/core/src/application/use-cases/features/create/create-feature-from-remote.use-case.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAGH,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,wCAAwC,CAAC;AACtE,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,uEAAuE,CAAC;AAC1G,OAAO,KAAK,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,wCAAwC,CAAC;AACxF,OAAO,EAAE,6BAA6B,EAAE,MAAM,yDAAyD,CAAC;AACxG,OAAO,EAAE,oBAAoB,EAAE,MAAM,8BAA8B,CAAC;AACpE,OAAO,KAAK,EAAsB,mBAAmB,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAC;AAE9F,MAAM,WAAW,4BAA4B;IAC3C,8DAA8D;IAC9D,SAAS,EAAE,MAAM,CAAC;IAClB,2CAA2C;IAC3C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wDAAwD;IACxD,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gEAAgE;IAChE,YAAY,CAAC,EAAE,YAAY,CAAC;IAE5B,2CAA2C;IAC3C,SAAS,EAAE,MAAM,CAAC;IAClB,6BAA6B;IAC7B,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,2CAA2C;IAC3C,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,+BAA+B;IAC/B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,wCAAwC;IACxC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,gEAAgE;IAChE,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,8EAA8E;IAC9E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,yDAAyD;IACzD,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,iDAAiD;IACjD,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,mCAAmC;IACnC,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,gEAAgE;IAChE,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,qDAAqD;IACrD,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC;IAC3B,8DAA8D;IAC9D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,wDAAwD;IACxD,eAAe,CAAC,EAAE,MAAM,EAAE,CAAC;CAC5B;AAED,qBACa,8BAA8B;IAGvC,OAAO,CAAC,QAAQ,CAAC,gBAAgB;IAEjC,OAAO,CAAC,QAAQ,CAAC,aAAa;gBAFb,gBAAgB,EAAE,6BAA6B,EAE/C,aAAa,EAAE,oBAAoB;IAGtD;;;OAGG;IACG,OAAO,CAAC,KAAK,EAAE,4BAA4B,GAAG,OAAO,CAAC,mBAAmB,CAAC;IAWhF;;;;OAIG;IACG,YAAY,CAAC,KAAK,EAAE,4BAA4B,GAAG,OAAO,CAAC,kBAAkB,CAAC;IAWpF;;;OAGG;IACG,kBAAkB,CACtB,OAAO,EAAE,OAAO,EAChB,KAAK,EAAE,4BAA4B,EACnC,WAAW,EAAE,OAAO,GACnB,OAAO,CAAC;QAAE,OAAO,CAAC,EAAE,MAAM,CAAC;QAAC,cAAc,EAAE,OAAO,CAAA;KAAE,CAAC;IAQzD;;;OAGG;IACH,OAAO,CAAC,oBAAoB;CAsB7B"}
@@ -0,0 +1,96 @@
1
+ /**
2
+ * Create Feature From Remote Use Case
3
+ *
4
+ * Composite use case that orchestrates importing a GitHub repository via
5
+ * ImportGitHubRepositoryUseCase and then creating a feature via
6
+ * CreateFeatureUseCase. Provides both a single execute() method (for CLI)
7
+ * and two-phase createRecord() + initializeAndSpawn() (for Web UI).
8
+ */
9
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
10
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
11
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
12
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
13
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
14
+ };
15
+ var __metadata = (this && this.__metadata) || function (k, v) {
16
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
17
+ };
18
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
19
+ return function (target, key) { decorator(target, key, paramIndex); }
20
+ };
21
+ import { injectable, inject } from 'tsyringe';
22
+ import { ImportGitHubRepositoryUseCase } from '../../repositories/import-github-repository.use-case.js';
23
+ import { CreateFeatureUseCase } from './create-feature.use-case.js';
24
+ let CreateFeatureFromRemoteUseCase = class CreateFeatureFromRemoteUseCase {
25
+ importGitHubRepo;
26
+ createFeature;
27
+ constructor(importGitHubRepo, createFeature) {
28
+ this.importGitHubRepo = importGitHubRepo;
29
+ this.createFeature = createFeature;
30
+ }
31
+ /**
32
+ * Full execution: imports the repository (or finds existing), then creates
33
+ * the feature with all SDLC initialization. Used by the CLI.
34
+ */
35
+ async execute(input) {
36
+ const repository = await this.importGitHubRepo.execute({
37
+ url: input.remoteUrl,
38
+ dest: input.cloneDest,
39
+ defaultCloneDir: input.defaultCloneDir,
40
+ cloneOptions: input.cloneOptions,
41
+ });
42
+ return this.createFeature.execute(this.toCreateFeatureInput(input, repository.path));
43
+ }
44
+ /**
45
+ * Phase 1 (fast): Imports the repository, then creates the feature + agent
46
+ * run records in DB. Returns immediately with a real feature ID.
47
+ * Used by the Web UI for optimistic rendering.
48
+ */
49
+ async createRecord(input) {
50
+ const repository = await this.importGitHubRepo.execute({
51
+ url: input.remoteUrl,
52
+ dest: input.cloneDest,
53
+ defaultCloneDir: input.defaultCloneDir,
54
+ cloneOptions: input.cloneOptions,
55
+ });
56
+ return this.createFeature.createRecord(this.toCreateFeatureInput(input, repository.path));
57
+ }
58
+ /**
59
+ * Phase 2 (slow): AI metadata generation, git worktree, spec init, agent spawn.
60
+ * Delegates directly to CreateFeatureUseCase since import is already complete.
61
+ */
62
+ async initializeAndSpawn(feature, input, shouldSpawn) {
63
+ return this.createFeature.initializeAndSpawn(feature, this.toCreateFeatureInput(input, feature.repositoryPath), shouldSpawn);
64
+ }
65
+ /**
66
+ * Maps CreateFeatureFromRemoteInput to CreateFeatureInput by injecting
67
+ * the repositoryPath derived from the import result.
68
+ */
69
+ toCreateFeatureInput(input, repositoryPath) {
70
+ return {
71
+ userInput: input.userInput,
72
+ repositoryPath,
73
+ approvalGates: input.approvalGates,
74
+ push: input.push,
75
+ openPr: input.openPr,
76
+ parentId: input.parentId,
77
+ name: input.name,
78
+ description: input.description,
79
+ fast: input.fast,
80
+ pending: input.pending,
81
+ agentType: input.agentType,
82
+ model: input.model,
83
+ attachments: input.attachments,
84
+ sessionId: input.sessionId,
85
+ attachmentPaths: input.attachmentPaths,
86
+ };
87
+ }
88
+ };
89
+ CreateFeatureFromRemoteUseCase = __decorate([
90
+ injectable(),
91
+ __param(0, inject(ImportGitHubRepositoryUseCase)),
92
+ __param(1, inject(CreateFeatureUseCase)),
93
+ __metadata("design:paramtypes", [ImportGitHubRepositoryUseCase,
94
+ CreateFeatureUseCase])
95
+ ], CreateFeatureFromRemoteUseCase);
96
+ export { CreateFeatureFromRemoteUseCase };
@@ -123,7 +123,7 @@ export function createDefaultSettings() {
123
123
  skills: false,
124
124
  envDeploy: true,
125
125
  debug: false,
126
- githubImport: false,
126
+ githubImport: true,
127
127
  adoptBranch: false,
128
128
  reactFileManager: false,
129
129
  };
@@ -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;AAyHrC;;;;;;GAMG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,OAAO,SAAS,CAAC,CAmVrE;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,OAAO,CAEhD;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;AA0HrC;;;;;;GAMG;AACH,wBAAsB,mBAAmB,IAAI,OAAO,CAAC,OAAO,SAAS,CAAC,CAuVrE;AAED;;;GAGG;AACH,wBAAgB,sBAAsB,IAAI,OAAO,CAEhD;AAED;;;GAGG;AACH,OAAO,EAAE,SAAS,EAAE,CAAC"}
@@ -59,6 +59,7 @@ import { ApproveAgentRunUseCase } from '../../application/use-cases/agents/appro
59
59
  import { RejectAgentRunUseCase } from '../../application/use-cases/agents/reject-agent-run.use-case.js';
60
60
  import { ReviewFeatureUseCase } from '../../application/use-cases/agents/review-feature.use-case.js';
61
61
  import { CreateFeatureUseCase } from '../../application/use-cases/features/create/create-feature.use-case.js';
62
+ import { CreateFeatureFromRemoteUseCase } from '../../application/use-cases/features/create/create-feature-from-remote.use-case.js';
62
63
  import { MetadataGenerator } from '../../application/use-cases/features/create/metadata-generator.js';
63
64
  import { SlugResolver } from '../../application/use-cases/features/create/slug-resolver.js';
64
65
  import { ListFeaturesUseCase } from '../../application/use-cases/features/list-features.use-case.js';
@@ -280,6 +281,7 @@ export async function initializeContainer() {
280
281
  container.registerSingleton(MetadataGenerator);
281
282
  container.registerSingleton(SlugResolver);
282
283
  container.registerSingleton(CreateFeatureUseCase);
284
+ container.registerSingleton(CreateFeatureFromRemoteUseCase);
283
285
  container.registerSingleton(ListFeaturesUseCase);
284
286
  container.registerSingleton(ShowFeatureUseCase);
285
287
  container.registerSingleton(DeleteFeatureUseCase);
@@ -323,6 +325,9 @@ export async function initializeContainer() {
323
325
  container.register('CreateFeatureUseCase', {
324
326
  useFactory: (c) => c.resolve(CreateFeatureUseCase),
325
327
  });
328
+ container.register('CreateFeatureFromRemoteUseCase', {
329
+ useFactory: (c) => c.resolve(CreateFeatureFromRemoteUseCase),
330
+ });
326
331
  container.register('ListFeaturesUseCase', {
327
332
  useFactory: (c) => c.resolve(ListFeaturesUseCase),
328
333
  });
@@ -1 +1 @@
1
- {"version":3,"file":"git-pr.service.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/git/git-pr.service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"git-pr.service.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/git/git-pr.service.ts"],"names":[],"mappings":"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"}
@@ -322,7 +322,15 @@ let GitPrService = class GitPrService {
322
322
  const runId = String(runs[0].databaseId);
323
323
  runUrl = runs[0].url;
324
324
  const interval = intervalSeconds ?? 30;
325
- const args = ['run', 'watch', runId, '--exit-status', '--interval', String(interval)];
325
+ const args = [
326
+ 'run',
327
+ 'watch',
328
+ runId,
329
+ '--exit-status',
330
+ '--compact',
331
+ '--interval',
332
+ String(interval),
333
+ ];
326
334
  const { stdout } = await this.execFile('gh', args, {
327
335
  cwd,
328
336
  ...(timeoutMs ? { timeout: timeoutMs } : {}),
@@ -8,6 +8,7 @@
8
8
  * @example
9
9
  * $ shep feat new "Add user authentication"
10
10
  * $ shep feat new "Add login page" --repo /path/to/project
11
+ * $ shep feat new "Add dark mode" --remote owner/repo
11
12
  */
12
13
  import { Command } from 'commander';
13
14
  /**
@@ -1 +1 @@
1
- {"version":3,"file":"new.command.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/cli/commands/feat/new.command.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA6DpC;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAmJ1C"}
1
+ {"version":3,"file":"new.command.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/cli/commands/feat/new.command.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAEH,OAAO,EAAE,OAAO,EAAU,MAAM,WAAW,CAAC;AAoE5C;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAiP1C"}
@@ -8,15 +8,18 @@
8
8
  * @example
9
9
  * $ shep feat new "Add user authentication"
10
10
  * $ shep feat new "Add login page" --repo /path/to/project
11
+ * $ shep feat new "Add dark mode" --remote owner/repo
11
12
  */
12
- import { Command } from 'commander';
13
+ import { Command, Option } from 'commander';
13
14
  import { createHash } from 'node:crypto';
14
15
  import { existsSync } from 'node:fs';
15
16
  import { join, resolve } from 'node:path';
16
17
  import { container } from '../../../../../packages/core/src/infrastructure/di/container.js';
17
18
  import { CreateFeatureUseCase } from '../../../../../packages/core/src/application/use-cases/features/create/create-feature.use-case.js';
19
+ import { CreateFeatureFromRemoteUseCase } from '../../../../../packages/core/src/application/use-cases/features/create/create-feature-from-remote.use-case.js';
18
20
  import { SdlcLifecycle } from '../../../../../packages/core/src/domain/generated/output.js';
19
- import { colors, messages, spinner } from '../../ui/index.js';
21
+ import { GitHubAuthError, GitHubCloneError, GitHubUrlParseError, } from '../../../../../packages/core/src/application/ports/output/services/github-repository-service.interface.js';
22
+ import { colors, messages, symbols, spinner } from '../../ui/index.js';
20
23
  import { getShepHomeDir } from '../../../../../packages/core/src/infrastructure/services/filesystem/shep-directory.service.js';
21
24
  import { getSettings, hasSettings } from '../../../../../packages/core/src/infrastructure/services/settings.service.js';
22
25
  import { CheckOnboardingStatusUseCase } from '../../../../../packages/core/src/application/use-cases/settings/check-onboarding-status.use-case.js';
@@ -47,6 +50,7 @@ export function createNewCommand() {
47
50
  .description('Create a new feature')
48
51
  .argument('<description>', 'Feature description')
49
52
  .option('-r, --repo <path>', 'Repository path (defaults to current directory)')
53
+ .addOption(new Option('--remote <url>', 'GitHub URL or owner/repo shorthand to clone and create feature on').conflicts('repo'))
50
54
  .option('--push', 'Push branch to remote after implementation')
51
55
  .option('--pr', 'Open PR on implementation complete (implies --push)')
52
56
  .option('--no-pr', 'Do not open PR on implementation complete')
@@ -68,8 +72,6 @@ export function createNewCommand() {
68
72
  await onboardingWizard();
69
73
  }
70
74
  }
71
- const useCase = container.resolve(CreateFeatureUseCase);
72
- const repoPath = options.repo ?? process.cwd();
73
75
  // Resolve openPr from CLI flags or settings defaults
74
76
  const defaults = getWorkflowDefaults();
75
77
  const openPr = options.pr ?? defaults.openPr;
@@ -107,9 +109,9 @@ export function createNewCommand() {
107
109
  attachmentPaths.push(resolved);
108
110
  }
109
111
  }
110
- const result = await spinner('Thinking', () => useCase.execute({
112
+ // Common input fields shared between local and remote paths
113
+ const commonInput = {
111
114
  userInput: description,
112
- repositoryPath: repoPath,
113
115
  approvalGates,
114
116
  push,
115
117
  openPr,
@@ -118,8 +120,70 @@ export function createNewCommand() {
118
120
  ...(options.fast && { fast: true }),
119
121
  ...(options.model !== undefined && { model: options.model }),
120
122
  ...(attachmentPaths.length > 0 && { attachmentPaths }),
121
- }));
123
+ };
124
+ let result;
125
+ if (options.remote) {
126
+ // Remote flow: import GitHub repo then create feature
127
+ const remoteUseCase = container.resolve(CreateFeatureFromRemoteUseCase);
128
+ // Read defaultCloneDir from settings
129
+ const settings = getSettings();
130
+ const defaultCloneDir = settings.environment?.defaultCloneDirectory;
131
+ // Dynamic spinner with clone progress updates
132
+ const frames = symbols.spinner;
133
+ let frameIdx = 0;
134
+ let spinnerLabel = 'Cloning repository';
135
+ let maxLabelLen = spinnerLabel.length;
136
+ const writeSpinner = () => {
137
+ const frame = frames[frameIdx % frames.length];
138
+ process.stderr.write(`\r${colors.muted(`${frame} ${spinnerLabel}...`)}`);
139
+ frameIdx++;
140
+ };
141
+ writeSpinner();
142
+ const spinnerInterval = setInterval(writeSpinner, 80);
143
+ const clearSpinner = () => {
144
+ clearInterval(spinnerInterval);
145
+ process.stderr.write(`\r${' '.repeat(maxLabelLen + 6)}\r`);
146
+ };
147
+ try {
148
+ result = await remoteUseCase.execute({
149
+ ...commonInput,
150
+ remoteUrl: options.remote,
151
+ ...(defaultCloneDir !== undefined && { defaultCloneDir }),
152
+ cloneOptions: {
153
+ onProgress: (data) => {
154
+ // Parse clone progress from gh CLI stderr
155
+ const progressMatch = data.match(/(?:Cloning|Receiving objects|Resolving deltas|Updating files)[^]*?(?:\d+%|\.{3})/);
156
+ if (progressMatch) {
157
+ // Sanitize: take the first meaningful line, trim whitespace
158
+ const line = progressMatch[0].split('\n')[0].trim();
159
+ if (line.length > 0) {
160
+ spinnerLabel = line;
161
+ if (spinnerLabel.length > maxLabelLen) {
162
+ maxLabelLen = spinnerLabel.length;
163
+ }
164
+ }
165
+ }
166
+ },
167
+ },
168
+ });
169
+ clearSpinner();
170
+ }
171
+ catch (error) {
172
+ clearSpinner();
173
+ throw error;
174
+ }
175
+ }
176
+ else {
177
+ // Local flow: use existing repository
178
+ const useCase = container.resolve(CreateFeatureUseCase);
179
+ const repoPath = options.repo ?? process.cwd();
180
+ result = await spinner('Thinking', () => useCase.execute({
181
+ ...commonInput,
182
+ repositoryPath: repoPath,
183
+ }));
184
+ }
122
185
  const { feature, warning } = result;
186
+ const repoPath = options.remote ? feature.repositoryPath : (options.repo ?? process.cwd());
123
187
  const repoHash = createHash('sha256').update(repoPath).digest('hex').slice(0, 16);
124
188
  const wtSlug = feature.branch.replace(/\//g, '-');
125
189
  const worktreePath = join(getShepHomeDir(), 'repos', repoHash, 'wt', wtSlug);
@@ -166,6 +230,23 @@ export function createNewCommand() {
166
230
  messages.newline();
167
231
  }
168
232
  catch (error) {
233
+ // Handle GitHub-specific errors with actionable messages
234
+ if (error instanceof GitHubAuthError) {
235
+ messages.error('GitHub CLI is not authenticated. Run `gh auth login` to sign in.');
236
+ process.exitCode = 1;
237
+ return;
238
+ }
239
+ if (error instanceof GitHubUrlParseError) {
240
+ messages.error(`Invalid GitHub URL: ${error.message}`);
241
+ messages.info('Supported formats: https://github.com/owner/repo, git@github.com:owner/repo.git, or owner/repo');
242
+ process.exitCode = 1;
243
+ return;
244
+ }
245
+ if (error instanceof GitHubCloneError) {
246
+ messages.error(`Clone failed: ${error.message}`);
247
+ process.exitCode = 1;
248
+ return;
249
+ }
169
250
  const err = error instanceof Error ? error : new Error(String(error));
170
251
  messages.error('Failed to create feature', err);
171
252
  process.exitCode = 1;
@@ -0,0 +1,29 @@
1
+ import type { Feature } from '../../../../../packages/core/src/domain/generated/output.js';
2
+ interface Attachment {
3
+ path: string;
4
+ name: string;
5
+ }
6
+ interface CreateFeatureFromRemoteInput {
7
+ remoteUrl: string;
8
+ description: string;
9
+ attachments?: Attachment[];
10
+ sessionId?: string;
11
+ approvalGates?: {
12
+ allowPrd: boolean;
13
+ allowPlan: boolean;
14
+ allowMerge?: boolean;
15
+ };
16
+ push?: boolean;
17
+ openPr?: boolean;
18
+ parentId?: string;
19
+ fast?: boolean;
20
+ pending?: boolean;
21
+ agentType?: string;
22
+ model?: string;
23
+ }
24
+ export declare function createFeatureFromRemote(input: CreateFeatureFromRemoteInput): Promise<{
25
+ feature?: Feature;
26
+ error?: string;
27
+ }>;
28
+ export {};
29
+ //# sourceMappingURL=create-feature-from-remote.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"create-feature-from-remote.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/web/app/actions/create-feature-from-remote.ts"],"names":[],"mappings":"AAIA,OAAO,KAAK,EAAE,OAAO,EAAE,MAAM,sCAAsC,CAAC;AAQpE,UAAU,UAAU;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAQD,UAAU,4BAA4B;IACpC,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,CAAC,EAAE,UAAU,EAAE,CAAC;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,aAAa,CAAC,EAAE;QACd,QAAQ,EAAE,OAAO,CAAC;QAClB,SAAS,EAAE,OAAO,CAAC;QACnB,UAAU,CAAC,EAAE,OAAO,CAAC;KACtB,CAAC;IACF,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,KAAK,CAAC,EAAE,MAAM,CAAC;CAChB;AAED,wBAAsB,uBAAuB,CAC3C,KAAK,EAAE,4BAA4B,GAClC,OAAO,CAAC;IAAE,OAAO,CAAC,EAAE,OAAO,CAAC;IAAC,KAAK,CAAC,EAAE,MAAM,CAAA;CAAE,CAAC,CA0FhD"}
@@ -0,0 +1,72 @@
1
+ 'use server';
2
+ import { resolve } from '../../lib/server-container.js';
3
+ import { GitHubAuthError, GitHubUrlParseError, GitHubCloneError, } from '../../../../../packages/core/src/application/ports/output/services/github-repository-service.interface.js';
4
+ import { composeUserInput } from './compose-user-input.js';
5
+ export async function createFeatureFromRemote(input) {
6
+ const { remoteUrl, description, attachments, sessionId, approvalGates, push, openPr, parentId, fast, pending, agentType, model, } = input;
7
+ if (!remoteUrl?.trim()) {
8
+ return { error: 'GitHub URL is required' };
9
+ }
10
+ if (!description?.trim()) {
11
+ return { error: 'description is required' };
12
+ }
13
+ const userInput = composeUserInput(description, attachments);
14
+ const gates = {
15
+ allowPrd: approvalGates?.allowPrd ?? false,
16
+ allowPlan: approvalGates?.allowPlan ?? false,
17
+ allowMerge: approvalGates?.allowMerge ?? false,
18
+ };
19
+ try {
20
+ const useCase = resolve('CreateFeatureFromRemoteUseCase');
21
+ // Phase 1 (fast): import repo + create DB record — returns immediately
22
+ const { feature, shouldSpawn } = await useCase.createRecord({
23
+ remoteUrl,
24
+ userInput,
25
+ approvalGates: gates,
26
+ push: push ?? false,
27
+ openPr: openPr ?? false,
28
+ ...(parentId ? { parentId } : {}),
29
+ description,
30
+ ...(fast ? { fast } : {}),
31
+ ...(pending ? { pending } : {}),
32
+ ...(agentType ? { agentType } : {}),
33
+ ...(model ? { model } : {}),
34
+ });
35
+ // Phase 2 (background): metadata generation, worktree, spec, agent spawn
36
+ // Fire-and-forget — the UI gets the real feature ID immediately
37
+ useCase
38
+ .initializeAndSpawn(feature, {
39
+ remoteUrl,
40
+ userInput,
41
+ approvalGates: gates,
42
+ push: push ?? false,
43
+ openPr: openPr ?? false,
44
+ ...(parentId ? { parentId } : {}),
45
+ ...(fast ? { fast } : {}),
46
+ ...(pending ? { pending } : {}),
47
+ ...(agentType ? { agentType } : {}),
48
+ ...(model ? { model } : {}),
49
+ ...(sessionId ? { sessionId } : {}),
50
+ }, shouldSpawn)
51
+ .catch((err) => {
52
+ // eslint-disable-next-line no-console
53
+ console.error('[createFeatureFromRemote] initializeAndSpawn failed:', err);
54
+ });
55
+ return { feature };
56
+ }
57
+ catch (error) {
58
+ if (error instanceof GitHubAuthError) {
59
+ return {
60
+ error: 'GitHub CLI is not authenticated. Run `gh auth login` to sign in.',
61
+ };
62
+ }
63
+ if (error instanceof GitHubUrlParseError) {
64
+ return { error: `Invalid GitHub URL: ${error.message}` };
65
+ }
66
+ if (error instanceof GitHubCloneError) {
67
+ return { error: `Clone failed: ${error.message}` };
68
+ }
69
+ const message = error instanceof Error ? error.message : 'Failed to create feature from remote';
70
+ return { error: message };
71
+ }
72
+ }
@@ -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":"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"}
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":"AA2BA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qCAAqC,CAAC;AAW5E,YAAY,EAAE,cAAc,EAAE,MAAM,0DAA0D,CAAC;AAE/F,uFAAuF;AACvF,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,EAAE,MAAM,CAAC;IACjB,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED,0DAA0D;AAC1D,MAAM,WAAW,mBAAmB;IAClC,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;CACd;AAED,iEAAiE;AACjE,MAAM,WAAW,gBAAgB;IAC/B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,oBAAoB;IACnC,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE,cAAc,EAAE,CAAC;IAC9B,cAAc,EAAE,MAAM,CAAC;IACvB,aAAa,EAAE;QACb,QAAQ,EAAE,OAAO,CAAC;QAClB,SAAS,EAAE,OAAO,CAAC;QACnB,UAAU,EAAE,OAAO,CAAC;KACrB,CAAC;IACF,IAAI,EAAE,OAAO,CAAC;IACd,MAAM,EAAE,OAAO,CAAC;IAChB,cAAc,EAAE,OAAO,CAAC;IACxB,cAAc,EAAE,OAAO,CAAC;IACxB,cAAc,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0EAA0E;IAC1E,IAAI,EAAE,OAAO,CAAC;IACd,yEAAyE;IACzE,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,wDAAwD;IACxD,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,mDAAmD;IACnD,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AA+ED,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,OAAO,CAAC;IACd,OAAO,EAAE,MAAM,IAAI,CAAC;IACpB,QAAQ,EAAE,CAAC,IAAI,EAAE,oBAAoB,KAAK,IAAI,CAAC;IAC/C,cAAc,EAAE,MAAM,CAAC;IACvB,YAAY,CAAC,EAAE,OAAO,CAAC;IACvB,gBAAgB,CAAC,EAAE,gBAAgB,CAAC;IACpC,qEAAqE;IACrE,QAAQ,CAAC,EAAE,mBAAmB,EAAE,CAAC;IACjC,+EAA+E;IAC/E,YAAY,CAAC,EAAE,gBAAgB,EAAE,CAAC;IAClC,kGAAkG;IAClG,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,8CAA8C;IAC9C,gBAAgB,CAAC,EAAE,MAAM,CAAC;IAC1B,yCAAyC;IACzC,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,oEAAoE;IACpE,kBAAkB,CAAC,EAAE,MAAM,CAAC;CAC7B;AAED,wBAAgB,mBAAmB,CAAC,EAClC,IAAI,EACJ,OAAO,EACP,QAAQ,EACR,cAAc,EACd,YAAoB,EACpB,gBAAgB,EAChB,QAAQ,EACR,YAAY,EACZ,eAAe,EACf,gBAAgB,EAChB,YAAY,EACZ,kBAAkB,GACnB,EAAE,wBAAwB,2CAwzB1B;AAmJD,MAAM,WAAW,uBAAuB;IACtC,YAAY,EAAE,gBAAgB,EAAE,CAAC;IACjC,KAAK,EAAE,MAAM,GAAG,SAAS,CAAC;IAC1B,QAAQ,EAAE,CAAC,IAAI,EAAE,MAAM,GAAG,SAAS,KAAK,IAAI,CAAC;IAC7C,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,gBAAgB,KAAK,IAAI,CAAC;IACnD,QAAQ,CAAC,EAAE,OAAO,CAAC;CACpB;AAED,wBAAgB,kBAAkB,CAAC,EACjC,YAAY,EACZ,KAAK,EACL,QAAQ,EACR,eAAe,EACf,QAAQ,GACT,EAAE,uBAAuB,2CAkPzB"}
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
  import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
3
3
  import { useState, useCallback, useEffect, useRef } from 'react';
4
- import { PaperclipIcon, ChevronsUpDown, CheckIcon, Zap, Clock, FolderPlus, Loader2, } from 'lucide-react';
4
+ import { PaperclipIcon, ChevronsUpDown, CheckIcon, Zap, Clock, FolderPlus, Loader2, Github, } from 'lucide-react';
5
5
  import { cn } from '../../../lib/utils.js';
6
6
  import { useSoundAction } from '../../../hooks/use-sound-action.js';
7
7
  import { BaseDrawer } from '../../common/base-drawer/index.js';
@@ -22,6 +22,7 @@ import { pickFolder } from '../../common/add-repository-button/pick-folder.js';
22
22
  import { ReactFileManagerDialog } from '../../common/react-file-manager-dialog/index.js';
23
23
  import { useFeatureFlags } from '../../../hooks/feature-flags-context.js';
24
24
  import { addRepository } from '../../../app/actions/add-repository.js';
25
+ import { GitHubImportDialog } from '../../common/github-import-dialog/index.js';
25
26
  import { pickFiles } from './pick-files.js';
26
27
  const MAX_FILE_SIZE = 10 * 1024 * 1024; // 10 MB
27
28
  const ALLOWED_EXTENSIONS = new Set([
@@ -495,8 +496,9 @@ export function RepositoryCombobox({ repositories, value, onChange, onAddReposit
495
496
  const [isAdding, setIsAdding] = useState(false);
496
497
  const [addError, setAddError] = useState(null);
497
498
  const [showReactPicker, setShowReactPicker] = useState(false);
499
+ const [showGitHubImport, setShowGitHubImport] = useState(false);
498
500
  const inputRef = useRef(null);
499
- const { reactFileManager: useReactFileManager } = useFeatureFlags();
501
+ const { reactFileManager: useReactFileManager, githubImport } = useFeatureFlags();
500
502
  const selectedRepo = repositories.find((r) => r.path === value);
501
503
  const filtered = query.trim()
502
504
  ? repositories.filter((r) => r.name.toLowerCase().includes(query.toLowerCase()) ||
@@ -551,6 +553,18 @@ export function RepositoryCombobox({ repositories, value, onChange, onAddReposit
551
553
  setIsAdding(false);
552
554
  }
553
555
  }, [isAdding, useReactFileManager, addRepoFromPath]);
556
+ const handleGitHubImportComplete = useCallback((repository) => {
557
+ const newRepo = {
558
+ id: repository.id,
559
+ name: repository.name,
560
+ path: repository.path,
561
+ };
562
+ onAddRepository?.(newRepo);
563
+ onChange(newRepo.path);
564
+ setOpen(false);
565
+ setQuery('');
566
+ setShowGitHubImport(false);
567
+ }, [onAddRepository, onChange]);
554
568
  const handleReactPickerSelect = useCallback(async (path) => {
555
569
  setShowReactPicker(false);
556
570
  if (!path)
@@ -575,8 +589,8 @@ export function RepositoryCombobox({ repositories, value, onChange, onAddReposit
575
589
  setQuery('');
576
590
  }
577
591
  }, [open]);
578
- return (_jsxs(_Fragment, { children: [_jsxs(Popover, { open: open, onOpenChange: setOpen, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs("button", { type: "button", role: "combobox", "aria-expanded": open, "aria-label": "Repository", disabled: disabled, "data-testid": "repository-combobox", className: cn('border-input bg-background ring-offset-background focus:ring-ring flex h-9 w-full items-center justify-between rounded-md border px-3 py-2 text-sm focus:ring-2 focus:ring-offset-2 focus:outline-none disabled:cursor-not-allowed disabled:opacity-50', !selectedRepo && 'text-muted-foreground'), children: [_jsx("span", { className: "truncate", children: selectedRepo ? selectedRepo.name : 'Select repository...' }), _jsx(ChevronsUpDown, { className: "ml-2 h-4 w-4 shrink-0 opacity-50" })] }) }), _jsx(PopoverContent, { className: "w-80 p-0", align: "start", "data-testid": "repository-combobox-content", children: _jsxs("div", { className: "flex flex-col", children: [_jsx("div", { className: "border-b p-2", children: _jsx(Input, { ref: inputRef, placeholder: "Search repositories...", value: query, onChange: (e) => setQuery(e.target.value), className: "h-8 border-0 p-0 text-sm shadow-none focus-visible:ring-0", "data-testid": "repository-search" }) }), _jsx("div", { className: "max-h-48 overflow-y-auto py-1", role: "listbox", "aria-label": "Repositories", children: filtered.length === 0 ? (_jsx("p", { className: "text-muted-foreground px-3 py-2 text-sm", "data-testid": "repository-empty", children: "No repositories found." })) : (filtered.map((r) => (_jsxs("button", { type: "button", role: "option", "aria-selected": value === r.path, onClick: () => handleSelect(r.path), className: cn('hover:bg-accent hover:text-accent-foreground flex w-full items-center gap-2 px-3 py-2 text-sm', value === r.path && 'bg-accent/50'), "data-testid": `repository-option-${r.id}`, children: [_jsx(CheckIcon, { className: cn('h-4 w-4 shrink-0', value !== r.path && 'invisible') }), _jsxs("span", { className: "flex flex-col items-start truncate", children: [_jsx("span", { className: "truncate", children: r.name }), _jsx("span", { className: "text-muted-foreground truncate text-xs", children: r.path })] })] }, r.id)))) }), _jsx(Separator, {}), _jsxs("button", { type: "button", onClick: handleAddRepository, disabled: isAdding, className: "hover:bg-accent hover:text-accent-foreground flex w-full items-center gap-2 px-3 py-2 text-sm", "data-testid": "add-repository-item", children: [isAdding ? (_jsx(Loader2, { className: "h-4 w-4 shrink-0 animate-spin" })) : (_jsx(FolderPlus, { className: "h-4 w-4 shrink-0" })), _jsx("span", { children: "Add new repository..." })] }), addError ? (_jsx("p", { className: "px-3 pb-2 text-xs text-red-500", "data-testid": "add-repository-error", children: addError })) : null] }) })] }), _jsx(ReactFileManagerDialog, { open: showReactPicker, onOpenChange: (isOpen) => {
592
+ return (_jsxs(_Fragment, { children: [_jsxs(Popover, { open: open, onOpenChange: setOpen, children: [_jsx(PopoverTrigger, { asChild: true, children: _jsxs("button", { type: "button", role: "combobox", "aria-expanded": open, "aria-label": "Repository", disabled: disabled, "data-testid": "repository-combobox", className: cn('border-input bg-background ring-offset-background focus:ring-ring flex h-9 w-full items-center justify-between rounded-md border px-3 py-2 text-sm focus:ring-2 focus:ring-offset-2 focus:outline-none disabled:cursor-not-allowed disabled:opacity-50', !selectedRepo && 'text-muted-foreground'), children: [_jsx("span", { className: "truncate", children: selectedRepo ? selectedRepo.name : 'Select repository...' }), _jsx(ChevronsUpDown, { className: "ml-2 h-4 w-4 shrink-0 opacity-50" })] }) }), _jsx(PopoverContent, { className: "w-80 p-0", align: "start", "data-testid": "repository-combobox-content", children: _jsxs("div", { className: "flex flex-col", children: [_jsx("div", { className: "border-b p-2", children: _jsx(Input, { ref: inputRef, placeholder: "Search repositories...", value: query, onChange: (e) => setQuery(e.target.value), className: "h-8 border-0 p-0 text-sm shadow-none focus-visible:ring-0", "data-testid": "repository-search" }) }), _jsx("div", { className: "max-h-48 overflow-y-auto py-1", role: "listbox", "aria-label": "Repositories", children: filtered.length === 0 ? (_jsx("p", { className: "text-muted-foreground px-3 py-2 text-sm", "data-testid": "repository-empty", children: "No repositories found." })) : (filtered.map((r) => (_jsxs("button", { type: "button", role: "option", "aria-selected": value === r.path, onClick: () => handleSelect(r.path), className: cn('hover:bg-accent hover:text-accent-foreground flex w-full items-center gap-2 px-3 py-2 text-sm', value === r.path && 'bg-accent/50'), "data-testid": `repository-option-${r.id}`, children: [_jsx(CheckIcon, { className: cn('h-4 w-4 shrink-0', value !== r.path && 'invisible') }), _jsxs("span", { className: "flex flex-col items-start truncate", children: [_jsx("span", { className: "truncate", children: r.name }), _jsx("span", { className: "text-muted-foreground truncate text-xs", children: r.path })] })] }, r.id)))) }), _jsx(Separator, {}), githubImport ? (_jsxs("button", { type: "button", onClick: () => setShowGitHubImport(true), className: "hover:bg-accent hover:text-accent-foreground flex w-full items-center gap-2 px-3 py-2 text-sm", "data-testid": "import-github-item", children: [_jsx(Github, { className: "h-4 w-4 shrink-0" }), _jsx("span", { children: "Import from GitHub..." })] })) : null, _jsxs("button", { type: "button", onClick: handleAddRepository, disabled: isAdding, className: "hover:bg-accent hover:text-accent-foreground flex w-full items-center gap-2 px-3 py-2 text-sm", "data-testid": "add-repository-item", children: [isAdding ? (_jsx(Loader2, { className: "h-4 w-4 shrink-0 animate-spin" })) : (_jsx(FolderPlus, { className: "h-4 w-4 shrink-0" })), _jsx("span", { children: "Add new repository..." })] }), addError ? (_jsx("p", { className: "px-3 pb-2 text-xs text-red-500", "data-testid": "add-repository-error", children: addError })) : null] }) })] }), _jsx(ReactFileManagerDialog, { open: showReactPicker, onOpenChange: (isOpen) => {
579
593
  if (!isOpen)
580
594
  setShowReactPicker(false);
581
- }, onSelect: handleReactPickerSelect })] }));
595
+ }, onSelect: handleReactPickerSelect }), _jsx(GitHubImportDialog, { open: showGitHubImport, onOpenChange: setShowGitHubImport, onImportComplete: handleGitHubImportComplete })] }));
582
596
  }
@@ -11,4 +11,10 @@ export declare const EmptyList: Story;
11
11
  export declare const PreSelected: Story;
12
12
  /** Disabled state — combobox trigger button is non-interactive. */
13
13
  export declare const Disabled: Story;
14
+ /** GitHub import enabled — "Import from GitHub..." button visible in dropdown. */
15
+ export declare const WithGitHubImport: Story;
16
+ /** GitHub import disabled — "Import from GitHub..." button hidden. */
17
+ export declare const WithGitHubImportDisabled: Story;
18
+ /** Empty list with GitHub import — shows import option alongside add repository. */
19
+ export declare const EmptyWithGitHubImport: Story;
14
20
  //# sourceMappingURL=repository-combobox.stories.d.ts.map