@shepai/cli 1.23.2 → 1.25.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/packages/core/src/application/use-cases/features/create/metadata-generator.d.ts.map +1 -1
- package/dist/packages/core/src/application/use-cases/features/create/metadata-generator.js +3 -0
- package/dist/packages/core/src/infrastructure/di/populate-use-cases-bridge.d.ts +20 -0
- package/dist/packages/core/src/infrastructure/di/populate-use-cases-bridge.d.ts.map +1 -0
- package/dist/packages/core/src/infrastructure/di/populate-use-cases-bridge.js +29 -0
- package/dist/packages/core/src/infrastructure/di/use-cases-bridge.d.ts +42 -0
- package/dist/packages/core/src/infrastructure/di/use-cases-bridge.d.ts.map +1 -0
- package/dist/packages/core/src/infrastructure/di/use-cases-bridge.js +88 -0
- package/dist/packages/core/src/infrastructure/services/git/worktree.service.d.ts +2 -0
- package/dist/packages/core/src/infrastructure/services/git/worktree.service.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/git/worktree.service.js +12 -1
- package/dist/src/presentation/cli/commands/upgrade.command.d.ts +17 -0
- package/dist/src/presentation/cli/commands/upgrade.command.d.ts.map +1 -0
- package/dist/src/presentation/cli/commands/upgrade.command.js +115 -0
- package/dist/src/presentation/cli/index.d.ts +1 -0
- package/dist/src/presentation/cli/index.d.ts.map +1 -1
- package/dist/src/presentation/cli/index.js +9 -8
- package/dist/src/presentation/web/app/api/features/create/route.d.ts +5 -0
- package/dist/src/presentation/web/app/api/features/create/route.d.ts.map +1 -0
- package/dist/src/presentation/web/app/api/features/create/route.js +32 -0
- package/dist/src/presentation/web/app/layout.d.ts.map +1 -1
- package/dist/src/presentation/web/app/layout.js +2 -1
- package/dist/src/presentation/web/app/page.d.ts +2 -0
- package/dist/src/presentation/web/app/page.d.ts.map +1 -1
- package/dist/src/presentation/web/app/page.js +20 -11
- package/dist/src/presentation/web/components/features/control-center/control-center-inner.d.ts.map +1 -1
- package/dist/src/presentation/web/components/features/control-center/control-center-inner.js +2 -2
- package/dist/src/presentation/web/components/features/control-center/use-control-center-state.d.ts +1 -0
- package/dist/src/presentation/web/components/features/control-center/use-control-center-state.d.ts.map +1 -1
- package/dist/src/presentation/web/components/features/control-center/use-control-center-state.js +45 -9
- package/dist/src/presentation/web/dev-server.js +19 -10
- package/dist/src/presentation/web/next.config.d.ts.map +1 -1
- package/dist/src/presentation/web/next.config.js +0 -4
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +3 -3
- package/web/.next/BUILD_ID +1 -1
- package/web/.next/app-path-routes-manifest.json +1 -0
- package/web/.next/build-manifest.json +2 -2
- package/web/.next/cache/.previewinfo +1 -1
- package/web/.next/cache/.rscinfo +1 -1
- package/web/.next/cache/.tsbuildinfo +1 -1
- package/web/.next/cache/config.json +3 -3
- package/web/.next/fallback-build-manifest.json +2 -2
- package/web/.next/prerender-manifest.json +3 -27
- package/web/.next/required-server-files.js +1 -4
- package/web/.next/required-server-files.json +1 -4
- package/web/.next/routes-manifest.json +6 -0
- package/web/.next/server/app/_global-error.html +2 -2
- package/web/.next/server/app/_global-error.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/web/.next/server/app/_not-found/page.js +1 -1
- package/web/.next/server/app/_not-found/page.js.nft.json +1 -1
- package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/_not-found.html +2 -2
- package/web/.next/server/app/_not-found.rsc +14 -13
- package/web/.next/server/app/_not-found.segments/_full.segment.rsc +14 -13
- package/web/.next/server/app/_not-found.segments/_head.segment.rsc +3 -3
- package/web/.next/server/app/_not-found.segments/_index.segment.rsc +6 -5
- package/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +2 -2
- package/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +3 -3
- package/web/.next/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/web/.next/server/app/api/dialog/pick-files/route.js +2 -2
- package/web/.next/server/app/api/dialog/pick-files/route.js.nft.json +1 -1
- package/web/.next/server/app/api/dialog/pick-folder/route.js +2 -2
- package/web/.next/server/app/api/dialog/pick-folder/route.js.nft.json +1 -1
- package/web/.next/server/app/api/features/create/route/app-paths-manifest.json +3 -0
- package/web/.next/server/app/api/features/create/route/build-manifest.json +11 -0
- package/web/.next/server/app/api/features/create/route/server-reference-manifest.json +4 -0
- package/web/.next/server/app/api/features/create/route.js +6 -0
- package/web/.next/server/app/api/features/create/route.js.map +5 -0
- package/web/.next/server/app/api/features/create/route.js.nft.json +1 -0
- package/web/.next/server/app/api/features/create/route_client-reference-manifest.js +2 -0
- package/web/.next/server/app/page.js +3 -3
- package/web/.next/server/app/page.js.nft.json +1 -1
- package/web/.next/server/app/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/version/page.js +1 -1
- package/web/.next/server/app/version/page.js.nft.json +1 -1
- package/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/version.html +2 -2
- package/web/.next/server/app/version.rsc +13 -12
- package/web/.next/server/app/version.segments/_full.segment.rsc +13 -12
- package/web/.next/server/app/version.segments/_head.segment.rsc +1 -1
- package/web/.next/server/app/version.segments/_index.segment.rsc +4 -3
- package/web/.next/server/app/version.segments/_tree.segment.rsc +2 -2
- package/web/.next/server/app/version.segments/version/__PAGE__.segment.rsc +2 -2
- package/web/.next/server/app/version.segments/version.segment.rsc +1 -1
- package/web/.next/server/app-paths-manifest.json +1 -0
- package/web/.next/server/chunks/744ca_web__next-internal_server_app_api_features_create_route_actions_de49a114.js +3 -0
- package/web/.next/server/chunks/[root-of-the-server]__4e987cf3._.js +8 -0
- package/web/.next/server/chunks/[root-of-the-server]__4e987cf3._.js.map +1 -0
- package/web/.next/server/chunks/{[root-of-the-server]__22cabd43._.js → [root-of-the-server]__a6bf88cc._.js} +3 -3
- package/web/.next/server/chunks/{[root-of-the-server]__22cabd43._.js.map → [root-of-the-server]__a6bf88cc._.js.map} +1 -1
- package/web/.next/server/chunks/{[root-of-the-server]__00833626._.js → [root-of-the-server]__ba6c5641._.js} +2 -2
- package/web/.next/server/chunks/{[root-of-the-server]__00833626._.js.map → [root-of-the-server]__ba6c5641._.js.map} +1 -1
- package/web/.next/server/chunks/[root-of-the-server]__ec87d735._.js +3 -0
- package/web/.next/server/chunks/{[root-of-the-server]__95785ac7._.js.map → [root-of-the-server]__ec87d735._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/{[root-of-the-server]__71515c64._.js → [root-of-the-server]__80e5bed2._.js} +2 -2
- package/web/.next/server/chunks/ssr/[root-of-the-server]__80e5bed2._.js.map +1 -0
- package/web/.next/server/chunks/ssr/[root-of-the-server]__a21ef212._.js +3 -0
- package/web/.next/server/chunks/ssr/[root-of-the-server]__a21ef212._.js.map +1 -0
- package/web/.next/server/chunks/ssr/[root-of-the-server]__f12b60be._.js +1 -1
- package/web/.next/server/chunks/ssr/_09afa42a._.js +1 -1
- package/web/.next/server/chunks/ssr/_09afa42a._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_1c3962d7._.js +10 -0
- package/web/.next/server/chunks/ssr/_1c3962d7._.js.map +1 -0
- package/web/.next/server/chunks/ssr/src_presentation_web_67178b88._.js +13 -0
- package/web/.next/server/chunks/ssr/src_presentation_web_67178b88._.js.map +1 -0
- package/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js +3 -0
- package/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js.map +1 -0
- package/web/.next/server/chunks/ssr/src_presentation_web_ed0934e5._.js +3 -0
- package/web/.next/server/chunks/ssr/src_presentation_web_ed0934e5._.js.map +1 -0
- package/web/.next/server/pages/404.html +2 -2
- package/web/.next/server/pages/500.html +2 -2
- package/web/.next/server/server-reference-manifest.js +1 -1
- package/web/.next/server/server-reference-manifest.json +1 -1
- package/web/.next/static/chunks/{f6b5484377f4e78e.js → 1c236dcc303f3033.js} +1 -1
- package/web/.next/static/chunks/74748b4d725c5c74.css +2 -0
- package/web/.next/static/chunks/78ef4acb26e4d6ea.js +1 -0
- package/web/.next/static/chunks/79009d1ca0d944d2.js +5 -0
- package/web/.next/trace +1 -1
- package/web/.next/trace-build +1 -1
- package/web/.next/types/link.d.ts +1 -0
- package/web/.next/types/routes.d.ts +2 -1
- package/web/.next/types/validator.ts +9 -0
- package/web/next.config.mjs +1 -1
- package/dist/src/presentation/web/lib/features.d.ts +0 -30
- package/dist/src/presentation/web/lib/features.d.ts.map +0 -1
- package/dist/src/presentation/web/lib/features.js +0 -50
- package/dist/src/presentation/web/lib/use-cases.d.ts +0 -29
- package/dist/src/presentation/web/lib/use-cases.d.ts.map +0 -1
- package/dist/src/presentation/web/lib/use-cases.js +0 -46
- package/web/.next/server/app/index.html +0 -11
- package/web/.next/server/app/index.meta +0 -14
- package/web/.next/server/app/index.rsc +0 -16
- package/web/.next/server/app/index.segments/__PAGE__.segment.rsc +0 -6
- package/web/.next/server/app/index.segments/_full.segment.rsc +0 -16
- package/web/.next/server/app/index.segments/_head.segment.rsc +0 -5
- package/web/.next/server/app/index.segments/_index.segment.rsc +0 -6
- package/web/.next/server/app/index.segments/_tree.segment.rsc +0 -2
- package/web/.next/server/chunks/[root-of-the-server]__95785ac7._.js +0 -3
- package/web/.next/server/chunks/ssr/[root-of-the-server]__7c64f85c._.js +0 -3
- package/web/.next/server/chunks/ssr/[root-of-the-server]__7c64f85c._.js.map +0 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__8507ac68._.js +0 -3
- package/web/.next/server/chunks/ssr/[root-of-the-server]__8507ac68._.js.map +0 -1
- package/web/.next/server/chunks/ssr/_1f9347c8._.js +0 -7
- package/web/.next/server/chunks/ssr/_1f9347c8._.js.map +0 -1
- package/web/.next/server/chunks/ssr/_a0c04017._.js +0 -6
- package/web/.next/server/chunks/ssr/_a0c04017._.js.map +0 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_372075f9._.js +0 -13
- package/web/.next/server/chunks/ssr/src_presentation_web_372075f9._.js.map +0 -1
- package/web/.next/static/chunks/66a2ada783ebc0d4.css +0 -2
- package/web/.next/static/chunks/8bc34062bc0f4ddc.js +0 -1
- package/web/.next/static/chunks/f5099c5888ef9a74.js +0 -5
- /package/web/.next/server/chunks/{ssr/[root-of-the-server]__71515c64._.js.map → 744ca_web__next-internal_server_app_api_features_create_route_actions_de49a114.js.map} +0 -0
- /package/web/.next/static/{3Y7OJekbogJm47SonWxv7 → -dFLqLT3RMg1ueqbAhsJk}/_buildManifest.js +0 -0
- /package/web/.next/static/{3Y7OJekbogJm47SonWxv7 → -dFLqLT3RMg1ueqbAhsJk}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{3Y7OJekbogJm47SonWxv7 → -dFLqLT3RMg1ueqbAhsJk}/_ssgManifest.js +0 -0
package/dist/packages/core/src/application/use-cases/features/create/metadata-generator.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"metadata-generator.d.ts","sourceRoot":"","sources":["../../../../../../../../packages/core/src/application/use-cases/features/create/metadata-generator.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,mEAAmE,CAAC;AAChH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAKlD,qBACa,iBAAiB;IAG1B,OAAO,CAAC,QAAQ,CAAC,gBAAgB;gBAAhB,gBAAgB,EAAE,sBAAsB;IAG3D;;;OAGG;IACG,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"metadata-generator.d.ts","sourceRoot":"","sources":["../../../../../../../../packages/core/src/application/use-cases/features/create/metadata-generator.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,mEAAmE,CAAC;AAChH,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,YAAY,CAAC;AAKlD,qBACa,iBAAiB;IAG1B,OAAO,CAAC,QAAQ,CAAC,gBAAgB;gBAAhB,gBAAgB,EAAE,sBAAsB;IAG3D;;;OAGG;IACG,gBAAgB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,eAAe,CAAC;IA4CnE;;OAEG;IACH,OAAO,CAAC,cAAc;IAgBtB;;;OAGG;IACH,OAAO,CAAC,MAAM;CAgBf"}
|
|
@@ -53,6 +53,9 @@ JSON only, no markdown fences.`;
|
|
|
53
53
|
silent: true,
|
|
54
54
|
});
|
|
55
55
|
const cleaned = this.stripCodeFence(result.result);
|
|
56
|
+
if (!cleaned) {
|
|
57
|
+
throw new Error('AI returned empty response for metadata generation');
|
|
58
|
+
}
|
|
56
59
|
const parsed = JSON.parse(cleaned);
|
|
57
60
|
if (!parsed.slug || !parsed.name || !parsed.description) {
|
|
58
61
|
throw new Error('Missing required fields in AI response');
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Use Cases Bridge — Writer
|
|
3
|
+
*
|
|
4
|
+
* Resolves use cases from the DI container and places them on globalThis
|
|
5
|
+
* so the Next.js web layer can access them without importing DI infrastructure.
|
|
6
|
+
* Called by CLI bootstrap and dev-server after initializeContainer() completes.
|
|
7
|
+
*
|
|
8
|
+
* This file imports tsyringe and decorated use case classes — only import it
|
|
9
|
+
* from Node.js entry points, never from the Next.js web layer (Turbopack
|
|
10
|
+
* cannot bundle native addons or decorator metadata).
|
|
11
|
+
*
|
|
12
|
+
* @see use-cases-bridge.ts for the reader side (web-safe).
|
|
13
|
+
*/
|
|
14
|
+
import type { DependencyContainer } from 'tsyringe';
|
|
15
|
+
/**
|
|
16
|
+
* Populate the globalThis bridge with resolved use cases from the DI container.
|
|
17
|
+
* Must be called after `initializeContainer()` completes.
|
|
18
|
+
*/
|
|
19
|
+
export declare function populateUseCasesBridge(c: DependencyContainer): void;
|
|
20
|
+
//# sourceMappingURL=populate-use-cases-bridge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"populate-use-cases-bridge.d.ts","sourceRoot":"","sources":["../../../../../../packages/core/src/infrastructure/di/populate-use-cases-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAMpD;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,EAAE,mBAAmB,GAAG,IAAI,CAQnE"}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Use Cases Bridge — Writer
|
|
3
|
+
*
|
|
4
|
+
* Resolves use cases from the DI container and places them on globalThis
|
|
5
|
+
* so the Next.js web layer can access them without importing DI infrastructure.
|
|
6
|
+
* Called by CLI bootstrap and dev-server after initializeContainer() completes.
|
|
7
|
+
*
|
|
8
|
+
* This file imports tsyringe and decorated use case classes — only import it
|
|
9
|
+
* from Node.js entry points, never from the Next.js web layer (Turbopack
|
|
10
|
+
* cannot bundle native addons or decorator metadata).
|
|
11
|
+
*
|
|
12
|
+
* @see use-cases-bridge.ts for the reader side (web-safe).
|
|
13
|
+
*/
|
|
14
|
+
import { ListFeaturesUseCase } from '../../application/use-cases/features/list-features.use-case.js';
|
|
15
|
+
import { CreateFeatureUseCase } from '../../application/use-cases/features/create/create-feature.use-case.js';
|
|
16
|
+
import { SHEP_USE_CASES_KEY } from './use-cases-bridge.js';
|
|
17
|
+
/**
|
|
18
|
+
* Populate the globalThis bridge with resolved use cases from the DI container.
|
|
19
|
+
* Must be called after `initializeContainer()` completes.
|
|
20
|
+
*/
|
|
21
|
+
export function populateUseCasesBridge(c) {
|
|
22
|
+
const bridge = {
|
|
23
|
+
listFeatures: c.resolve(ListFeaturesUseCase),
|
|
24
|
+
agentRunRepo: c.resolve('IAgentRunRepository'),
|
|
25
|
+
createFeature: c.resolve(CreateFeatureUseCase),
|
|
26
|
+
};
|
|
27
|
+
globalThis[SHEP_USE_CASES_KEY] = bridge;
|
|
28
|
+
process[SHEP_USE_CASES_KEY] = bridge;
|
|
29
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Use Cases Bridge — Reader
|
|
3
|
+
*
|
|
4
|
+
* Why does this exist?
|
|
5
|
+
* Use cases (e.g. ListFeaturesUseCase) are DI-managed classes that depend on
|
|
6
|
+
* injected repositories, which in turn need a live SQLite connection. The web
|
|
7
|
+
* layer (Next.js / Turbopack) cannot run the DI container because it would
|
|
8
|
+
* pull in tsyringe, reflect-metadata, and better-sqlite3 (native C++ addon) —
|
|
9
|
+
* none of which Turbopack can bundle.
|
|
10
|
+
*
|
|
11
|
+
* How it works:
|
|
12
|
+
* 1. CLI bootstrap runs initializeContainer() and resolves fully-wired use cases.
|
|
13
|
+
* 2. The writer (populate-use-cases-bridge.ts) places those instances on globalThis.
|
|
14
|
+
* 3. This reader retrieves them — no DI, no native modules, no decorators.
|
|
15
|
+
*
|
|
16
|
+
* This file is safe to import from the Next.js web layer.
|
|
17
|
+
*/
|
|
18
|
+
import type { Feature, AgentRun } from '../../domain/generated/output.js';
|
|
19
|
+
import type { FeatureListFilters } from '../../application/ports/output/repositories/feature-repository.interface.js';
|
|
20
|
+
import type { CreateFeatureInput, CreateFeatureResult } from '../../application/use-cases/features/create/types.js';
|
|
21
|
+
export type { FeatureListFilters, CreateFeatureInput, CreateFeatureResult };
|
|
22
|
+
/** The globalThis key shared between writer and reader. */
|
|
23
|
+
export declare const SHEP_USE_CASES_KEY = "__shepUseCases";
|
|
24
|
+
/**
|
|
25
|
+
* List all features for the control center.
|
|
26
|
+
* Returns an empty array if the DI bridge is not initialized
|
|
27
|
+
* (e.g. during static builds or when running outside the CLI process).
|
|
28
|
+
*/
|
|
29
|
+
export declare function getFeatures(filters?: FeatureListFilters): Promise<Feature[]>;
|
|
30
|
+
/**
|
|
31
|
+
* Find an agent run by ID.
|
|
32
|
+
* Returns null if the DI bridge is not initialized or the run is not found.
|
|
33
|
+
*/
|
|
34
|
+
export declare function getAgentRun(id: string): Promise<AgentRun | null>;
|
|
35
|
+
/**
|
|
36
|
+
* Create a new feature via the DI-managed use case.
|
|
37
|
+
* Unlike getFeatures/getAgentRun, this function propagates errors so callers
|
|
38
|
+
* (API routes) can return proper HTTP error responses and surface messages to the user.
|
|
39
|
+
* Throws if the bridge is not initialized or the use case fails.
|
|
40
|
+
*/
|
|
41
|
+
export declare function createFeature(input: CreateFeatureInput): Promise<CreateFeatureResult>;
|
|
42
|
+
//# sourceMappingURL=use-cases-bridge.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"use-cases-bridge.d.ts","sourceRoot":"","sources":["../../../../../../packages/core/src/infrastructure/di/use-cases-bridge.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,kCAAkC,CAAC;AAC1E,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,6EAA6E,CAAC;AACtH,OAAO,KAAK,EACV,kBAAkB,EAClB,mBAAmB,EACpB,MAAM,sDAAsD,CAAC;AAE9D,YAAY,EAAE,kBAAkB,EAAE,kBAAkB,EAAE,mBAAmB,EAAE,CAAC;AAE5E,2DAA2D;AAC3D,eAAO,MAAM,kBAAkB,mBAAmB,CAAC;AAqCnD;;;;GAIG;AACH,wBAAsB,WAAW,CAAC,OAAO,CAAC,EAAE,kBAAkB,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAWlF;AAED;;;GAGG;AACH,wBAAsB,WAAW,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,CAStE;AAED;;;;;GAKG;AACH,wBAAsB,aAAa,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAO3F"}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Use Cases Bridge — Reader
|
|
3
|
+
*
|
|
4
|
+
* Why does this exist?
|
|
5
|
+
* Use cases (e.g. ListFeaturesUseCase) are DI-managed classes that depend on
|
|
6
|
+
* injected repositories, which in turn need a live SQLite connection. The web
|
|
7
|
+
* layer (Next.js / Turbopack) cannot run the DI container because it would
|
|
8
|
+
* pull in tsyringe, reflect-metadata, and better-sqlite3 (native C++ addon) —
|
|
9
|
+
* none of which Turbopack can bundle.
|
|
10
|
+
*
|
|
11
|
+
* How it works:
|
|
12
|
+
* 1. CLI bootstrap runs initializeContainer() and resolves fully-wired use cases.
|
|
13
|
+
* 2. The writer (populate-use-cases-bridge.ts) places those instances on globalThis.
|
|
14
|
+
* 3. This reader retrieves them — no DI, no native modules, no decorators.
|
|
15
|
+
*
|
|
16
|
+
* This file is safe to import from the Next.js web layer.
|
|
17
|
+
*/
|
|
18
|
+
/** The globalThis key shared between writer and reader. */
|
|
19
|
+
export const SHEP_USE_CASES_KEY = '__shepUseCases';
|
|
20
|
+
function isShepUseCases(value) {
|
|
21
|
+
if (!value || typeof value !== 'object')
|
|
22
|
+
return false;
|
|
23
|
+
const maybe = value;
|
|
24
|
+
const listFeatures = maybe.listFeatures;
|
|
25
|
+
const agentRunRepo = maybe.agentRunRepo;
|
|
26
|
+
const createFeature = maybe.createFeature;
|
|
27
|
+
return (!!listFeatures &&
|
|
28
|
+
typeof listFeatures.execute === 'function' &&
|
|
29
|
+
!!agentRunRepo &&
|
|
30
|
+
typeof agentRunRepo.findById === 'function' &&
|
|
31
|
+
!!createFeature &&
|
|
32
|
+
typeof createFeature.execute === 'function');
|
|
33
|
+
}
|
|
34
|
+
function getUseCases() {
|
|
35
|
+
const globalBridge = globalThis[SHEP_USE_CASES_KEY];
|
|
36
|
+
if (isShepUseCases(globalBridge))
|
|
37
|
+
return globalBridge;
|
|
38
|
+
const processBridge = process[SHEP_USE_CASES_KEY];
|
|
39
|
+
if (isShepUseCases(processBridge))
|
|
40
|
+
return processBridge;
|
|
41
|
+
return undefined;
|
|
42
|
+
}
|
|
43
|
+
/**
|
|
44
|
+
* List all features for the control center.
|
|
45
|
+
* Returns an empty array if the DI bridge is not initialized
|
|
46
|
+
* (e.g. during static builds or when running outside the CLI process).
|
|
47
|
+
*/
|
|
48
|
+
export async function getFeatures(filters) {
|
|
49
|
+
const useCases = getUseCases();
|
|
50
|
+
if (!useCases?.listFeatures)
|
|
51
|
+
return [];
|
|
52
|
+
try {
|
|
53
|
+
return await useCases.listFeatures.execute(filters);
|
|
54
|
+
}
|
|
55
|
+
catch (error) {
|
|
56
|
+
// eslint-disable-next-line no-console
|
|
57
|
+
console.error('Failed to load features:', error);
|
|
58
|
+
return [];
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Find an agent run by ID.
|
|
63
|
+
* Returns null if the DI bridge is not initialized or the run is not found.
|
|
64
|
+
*/
|
|
65
|
+
export async function getAgentRun(id) {
|
|
66
|
+
const useCases = getUseCases();
|
|
67
|
+
if (!useCases?.agentRunRepo)
|
|
68
|
+
return null;
|
|
69
|
+
try {
|
|
70
|
+
return await useCases.agentRunRepo.findById(id);
|
|
71
|
+
}
|
|
72
|
+
catch {
|
|
73
|
+
return null;
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Create a new feature via the DI-managed use case.
|
|
78
|
+
* Unlike getFeatures/getAgentRun, this function propagates errors so callers
|
|
79
|
+
* (API routes) can return proper HTTP error responses and surface messages to the user.
|
|
80
|
+
* Throws if the bridge is not initialized or the use case fails.
|
|
81
|
+
*/
|
|
82
|
+
export async function createFeature(input) {
|
|
83
|
+
const useCases = getUseCases();
|
|
84
|
+
if (!useCases?.createFeature) {
|
|
85
|
+
throw new Error('Use-cases bridge is not initialized. Ensure the CLI process is running.');
|
|
86
|
+
}
|
|
87
|
+
return useCases.createFeature.execute(input);
|
|
88
|
+
}
|
|
@@ -24,5 +24,7 @@ export declare class WorktreeService implements IWorktreeService {
|
|
|
24
24
|
getWorktreePath(repoPath: string, branch: string): string;
|
|
25
25
|
private parseWorktreeOutput;
|
|
26
26
|
private parseGitError;
|
|
27
|
+
private arePathsEquivalent;
|
|
28
|
+
private normalizeWorktreePath;
|
|
27
29
|
}
|
|
28
30
|
//# sourceMappingURL=worktree.service.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"worktree.service.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/git/worktree.service.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,OAAO,KAAK,EACV,gBAAgB,EAChB,YAAY,EACb,MAAM,0EAA0E,CAAC;AAOlF;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,CACzB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,CAAC,EAAE,MAAM,KACb,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAEjD,qBACa,eAAgB,YAAW,gBAAgB;IAClB,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBAAR,QAAQ,EAAE,YAAY;IAErE,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAqBrF,MAAM,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ3C,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAO/C,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAKhE,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM;IAMzD,OAAO,CAAC,mBAAmB;IA2B3B,OAAO,CAAC,aAAa;
|
|
1
|
+
{"version":3,"file":"worktree.service.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/git/worktree.service.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAKH,OAAO,KAAK,EACV,gBAAgB,EAChB,YAAY,EACb,MAAM,0EAA0E,CAAC;AAOlF;;;GAGG;AACH,MAAM,MAAM,YAAY,GAAG,CACzB,IAAI,EAAE,MAAM,EACZ,IAAI,EAAE,MAAM,EAAE,EACd,OAAO,CAAC,EAAE,MAAM,KACb,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC;AAEjD,qBACa,eAAgB,YAAW,gBAAgB;IAClB,OAAO,CAAC,QAAQ,CAAC,QAAQ;gBAAR,QAAQ,EAAE,YAAY;IAErE,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAqBrF,MAAM,CAAC,YAAY,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ3C,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,EAAE,CAAC;IAO/C,MAAM,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAKhE,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,MAAM;IAMzD,OAAO,CAAC,mBAAmB;IA2B3B,OAAO,CAAC,aAAa;IAgCrB,OAAO,CAAC,kBAAkB;IAI1B,OAAO,CAAC,qBAAqB;CAU9B"}
|
|
@@ -38,7 +38,7 @@ let WorktreeService = class WorktreeService {
|
|
|
38
38
|
}
|
|
39
39
|
// Get info about the created worktree
|
|
40
40
|
const worktrees = await this.list(repoPath);
|
|
41
|
-
const created = worktrees.find((w) => w.path
|
|
41
|
+
const created = worktrees.find((w) => this.arePathsEquivalent(w.path, worktreePath));
|
|
42
42
|
if (!created) {
|
|
43
43
|
throw new WorktreeError('Worktree created but not found in list', WorktreeErrorCode.GIT_ERROR);
|
|
44
44
|
}
|
|
@@ -103,6 +103,17 @@ let WorktreeService = class WorktreeService {
|
|
|
103
103
|
}
|
|
104
104
|
return new WorktreeError(message, WorktreeErrorCode.GIT_ERROR, error instanceof Error ? error : undefined);
|
|
105
105
|
}
|
|
106
|
+
arePathsEquivalent(a, b) {
|
|
107
|
+
return this.normalizeWorktreePath(a) === this.normalizeWorktreePath(b);
|
|
108
|
+
}
|
|
109
|
+
normalizeWorktreePath(input) {
|
|
110
|
+
const normalized = path.normalize(input).replace(/\/+$/, '');
|
|
111
|
+
// On macOS, git can report /private/var/... while callers use /var/...
|
|
112
|
+
if (process.platform === 'darwin' && normalized.startsWith('/private/var/')) {
|
|
113
|
+
return normalized.slice('/private'.length);
|
|
114
|
+
}
|
|
115
|
+
return normalized;
|
|
116
|
+
}
|
|
106
117
|
};
|
|
107
118
|
WorktreeService = __decorate([
|
|
108
119
|
injectable(),
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Upgrade Command
|
|
3
|
+
*
|
|
4
|
+
* Self-upgrades Shep CLI to the latest published version.
|
|
5
|
+
* Checks current vs latest version before running npm install.
|
|
6
|
+
*
|
|
7
|
+
* Usage: shep upgrade
|
|
8
|
+
*/
|
|
9
|
+
import { Command } from 'commander';
|
|
10
|
+
import { spawn as defaultSpawn } from 'node:child_process';
|
|
11
|
+
type SpawnFn = typeof defaultSpawn;
|
|
12
|
+
/**
|
|
13
|
+
* Create the upgrade command
|
|
14
|
+
*/
|
|
15
|
+
export declare function createUpgradeCommand(spawnFn?: SpawnFn): Command;
|
|
16
|
+
export {};
|
|
17
|
+
//# sourceMappingURL=upgrade.command.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"upgrade.command.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/cli/commands/upgrade.command.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,KAAK,IAAI,YAAY,EAAqB,MAAM,oBAAoB,CAAC;AAK9E,KAAK,OAAO,GAAG,OAAO,YAAY,CAAC;AAyEnC;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,GAAE,OAAsB,GAAG,OAAO,CAuC7E"}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Upgrade Command
|
|
3
|
+
*
|
|
4
|
+
* Self-upgrades Shep CLI to the latest published version.
|
|
5
|
+
* Checks current vs latest version before running npm install.
|
|
6
|
+
*
|
|
7
|
+
* Usage: shep upgrade
|
|
8
|
+
*/
|
|
9
|
+
import { Command } from 'commander';
|
|
10
|
+
import { spawn as defaultSpawn } from 'node:child_process';
|
|
11
|
+
import { container } from '../../../../packages/core/src/infrastructure/di/container.js';
|
|
12
|
+
import { messages } from '../ui/index.js';
|
|
13
|
+
const VERSION_CHECK_TIMEOUT_MS = 10_000;
|
|
14
|
+
/**
|
|
15
|
+
* Get the latest published version of @shepai/cli from npm registry.
|
|
16
|
+
* Returns null if the check fails (fail-open).
|
|
17
|
+
*/
|
|
18
|
+
function getLatestVersion(spawnFn) {
|
|
19
|
+
return new Promise((resolve) => {
|
|
20
|
+
let output = '';
|
|
21
|
+
let settled = false;
|
|
22
|
+
const child = spawnFn('npm', ['view', '@shepai/cli', 'version'], {
|
|
23
|
+
stdio: ['ignore', 'pipe', 'pipe'],
|
|
24
|
+
});
|
|
25
|
+
const timeout = setTimeout(() => {
|
|
26
|
+
if (!settled) {
|
|
27
|
+
settled = true;
|
|
28
|
+
child.kill();
|
|
29
|
+
messages.warning('Could not complete version check (timed out)');
|
|
30
|
+
resolve(null);
|
|
31
|
+
}
|
|
32
|
+
}, VERSION_CHECK_TIMEOUT_MS);
|
|
33
|
+
child.stdout?.on('data', (data) => {
|
|
34
|
+
output += data.toString();
|
|
35
|
+
});
|
|
36
|
+
child.on('close', (code) => {
|
|
37
|
+
if (!settled) {
|
|
38
|
+
settled = true;
|
|
39
|
+
clearTimeout(timeout);
|
|
40
|
+
if (code === 0 && output.trim()) {
|
|
41
|
+
resolve(output.trim());
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
resolve(null);
|
|
45
|
+
}
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
child.on('error', () => {
|
|
49
|
+
if (!settled) {
|
|
50
|
+
settled = true;
|
|
51
|
+
clearTimeout(timeout);
|
|
52
|
+
messages.warning('Could not complete version check');
|
|
53
|
+
resolve(null);
|
|
54
|
+
}
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
/**
|
|
59
|
+
* Run npm i -g @shepai/cli@latest with inherited stdio.
|
|
60
|
+
* Returns the exit code, or rejects on spawn error.
|
|
61
|
+
*/
|
|
62
|
+
function runNpmInstall(spawnFn) {
|
|
63
|
+
return new Promise((resolve, reject) => {
|
|
64
|
+
const child = spawnFn('npm', ['i', '-g', '@shepai/cli@latest'], {
|
|
65
|
+
stdio: 'inherit',
|
|
66
|
+
});
|
|
67
|
+
child.on('close', (code) => {
|
|
68
|
+
resolve(code ?? 1);
|
|
69
|
+
});
|
|
70
|
+
child.on('error', (err) => {
|
|
71
|
+
reject(err);
|
|
72
|
+
});
|
|
73
|
+
});
|
|
74
|
+
}
|
|
75
|
+
/**
|
|
76
|
+
* Create the upgrade command
|
|
77
|
+
*/
|
|
78
|
+
export function createUpgradeCommand(spawnFn = defaultSpawn) {
|
|
79
|
+
return new Command('upgrade')
|
|
80
|
+
.description('Upgrade Shep CLI to the latest version')
|
|
81
|
+
.action(async () => {
|
|
82
|
+
try {
|
|
83
|
+
const versionService = container.resolve('IVersionService');
|
|
84
|
+
const { version: currentVersion } = versionService.getVersion();
|
|
85
|
+
// 1. Check latest version (fail-open with timeout)
|
|
86
|
+
const latestVersion = await getLatestVersion(spawnFn);
|
|
87
|
+
// 2. Compare — exit early if up to date
|
|
88
|
+
if (latestVersion && latestVersion === currentVersion) {
|
|
89
|
+
messages.success(`Already up to date (v${currentVersion})`);
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
// 3. Show what we're doing
|
|
93
|
+
if (latestVersion) {
|
|
94
|
+
messages.info(`Upgrading from v${currentVersion} to v${latestVersion}`);
|
|
95
|
+
}
|
|
96
|
+
else {
|
|
97
|
+
messages.info(`Upgrading from v${currentVersion} to latest`);
|
|
98
|
+
}
|
|
99
|
+
// 4. Run npm i -g @shepai/cli@latest with inherited stdio
|
|
100
|
+
const exitCode = await runNpmInstall(spawnFn);
|
|
101
|
+
if (exitCode === 0) {
|
|
102
|
+
messages.success('Shep CLI upgraded successfully');
|
|
103
|
+
}
|
|
104
|
+
else {
|
|
105
|
+
messages.error('Upgrade failed');
|
|
106
|
+
process.exitCode = 1;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
catch (error) {
|
|
110
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
111
|
+
messages.error('Upgrade failed', err);
|
|
112
|
+
process.exitCode = 1;
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
}
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
* shep agent Manage and view agent runs
|
|
16
16
|
* shep feat Manage features through the SDLC lifecycle
|
|
17
17
|
* shep settings Configure Shep settings
|
|
18
|
+
* shep upgrade Upgrade Shep CLI to the latest version
|
|
18
19
|
* shep --version Display version number only
|
|
19
20
|
*
|
|
20
21
|
* Global Options:
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/presentation/cli/index.ts"],"names":[],"mappings":";AAEA
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../src/presentation/cli/index.ts"],"names":[],"mappings":";AAEA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAGH,OAAO,kBAAkB,CAAC"}
|
|
@@ -15,6 +15,7 @@
|
|
|
15
15
|
* shep agent Manage and view agent runs
|
|
16
16
|
* shep feat Manage features through the SDLC lifecycle
|
|
17
17
|
* shep settings Configure Shep settings
|
|
18
|
+
* shep upgrade Upgrade Shep CLI to the latest version
|
|
18
19
|
* shep --version Display version number only
|
|
19
20
|
*
|
|
20
21
|
* Global Options:
|
|
@@ -32,12 +33,13 @@ import { createAgentCommand } from './commands/agent/index.js';
|
|
|
32
33
|
import { createFeatCommand } from './commands/feat/index.js';
|
|
33
34
|
import { createIdeOpenCommand } from './commands/ide-open.command.js';
|
|
34
35
|
import { createInstallCommand } from './commands/install.command.js';
|
|
36
|
+
import { createUpgradeCommand } from './commands/upgrade.command.js';
|
|
35
37
|
import { messages } from './ui/index.js';
|
|
36
38
|
// DI container and settings
|
|
37
39
|
import { initializeContainer, container } from '../../../packages/core/src/infrastructure/di/container.js';
|
|
38
40
|
import { InitializeSettingsUseCase } from '../../../packages/core/src/application/use-cases/settings/initialize-settings.use-case.js';
|
|
39
|
-
import { ListFeaturesUseCase } from '../../../packages/core/src/application/use-cases/features/list-features.use-case.js';
|
|
40
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';
|
|
41
43
|
/**
|
|
42
44
|
* Bootstrap function - initializes all dependencies before CLI starts.
|
|
43
45
|
* Performs async initialization (database, settings) before parsing commands.
|
|
@@ -64,13 +66,11 @@ async function bootstrap() {
|
|
|
64
66
|
messages.error('Failed to initialize settings', err);
|
|
65
67
|
throw error;
|
|
66
68
|
}
|
|
67
|
-
//
|
|
68
|
-
// The Next.js web
|
|
69
|
-
//
|
|
70
|
-
globalThis
|
|
71
|
-
|
|
72
|
-
agentRunRepo: container.resolve('IAgentRunRepository'),
|
|
73
|
-
};
|
|
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
74
|
// Step 3: Set up Commander CLI
|
|
75
75
|
const versionService = container.resolve('IVersionService');
|
|
76
76
|
const { version, description } = versionService.getVersion();
|
|
@@ -90,6 +90,7 @@ async function bootstrap() {
|
|
|
90
90
|
program.addCommand(createFeatCommand());
|
|
91
91
|
program.addCommand(createIdeOpenCommand());
|
|
92
92
|
program.addCommand(createInstallCommand());
|
|
93
|
+
program.addCommand(createUpgradeCommand());
|
|
93
94
|
// Parse arguments (parseAsync needed for async command actions like init)
|
|
94
95
|
await program.parseAsync();
|
|
95
96
|
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
export declare function POST(request: Request): Promise<NextResponse<{
|
|
3
|
+
error: string;
|
|
4
|
+
}> | NextResponse<import("../../../../../../../packages/core/src/infrastructure/di/use-cases-bridge.js").CreateFeatureResult>>;
|
|
5
|
+
//# sourceMappingURL=route.d.ts.map
|
|
@@ -0,0 +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;AA2B3C,wBAAsB,IAAI,CAAC,OAAO,EAAE,OAAO;;kGA0B1C"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { NextResponse } from 'next/server';
|
|
2
|
+
import { createFeature } from '../../../../../../../packages/core/src/infrastructure/di/use-cases-bridge.js';
|
|
3
|
+
function composeUserInput(name, description, attachments) {
|
|
4
|
+
let userInput = `Feature: ${name}`;
|
|
5
|
+
if (description) {
|
|
6
|
+
userInput += `\n\n${description}`;
|
|
7
|
+
}
|
|
8
|
+
if (attachments && attachments.length > 0) {
|
|
9
|
+
const paths = attachments.map((a) => `- ${a.path}`).join('\n');
|
|
10
|
+
userInput += `\n\nAttached files:\n${paths}`;
|
|
11
|
+
}
|
|
12
|
+
return userInput;
|
|
13
|
+
}
|
|
14
|
+
export async function POST(request) {
|
|
15
|
+
const body = await request.json();
|
|
16
|
+
const { name, description, repositoryPath, attachments } = body;
|
|
17
|
+
if (!name?.trim()) {
|
|
18
|
+
return NextResponse.json({ error: 'name is required' }, { status: 400 });
|
|
19
|
+
}
|
|
20
|
+
if (!repositoryPath?.trim()) {
|
|
21
|
+
return NextResponse.json({ error: 'repositoryPath is required' }, { status: 400 });
|
|
22
|
+
}
|
|
23
|
+
const userInput = composeUserInput(name, description, attachments);
|
|
24
|
+
try {
|
|
25
|
+
const result = await createFeature({ userInput, repositoryPath });
|
|
26
|
+
return NextResponse.json(result);
|
|
27
|
+
}
|
|
28
|
+
catch (error) {
|
|
29
|
+
const message = error instanceof Error ? error.message : 'Failed to create feature';
|
|
30
|
+
return NextResponse.json({ error: message }, { status: 500 });
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/web/app/layout.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,6BAA6B,CAAC;AACrC,OAAO,eAAe,CAAC;
|
|
1
|
+
{"version":3,"file":"layout.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/web/app/layout.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,MAAM,CAAC;AACrC,OAAO,6BAA6B,CAAC;AACrC,OAAO,eAAe,CAAC;AAIvB,eAAO,MAAM,QAAQ,EAAE,QAItB,CAAC;AAEF,MAAM,CAAC,OAAO,UAAU,UAAU,CAAC,EACjC,QAAQ,GACT,EAAE,QAAQ,CAAC;IACV,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B,CAAC,2CA0BD"}
|
|
@@ -2,6 +2,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
2
2
|
import '@xyflow/react/dist/base.css';
|
|
3
3
|
import './globals.css';
|
|
4
4
|
import { AppShell } from '../components/layouts/app-shell/index.js';
|
|
5
|
+
import { Toaster } from '../components/ui/sonner.js';
|
|
5
6
|
export const metadata = {
|
|
6
7
|
title: 'Shep AI',
|
|
7
8
|
description: 'Autonomous AI Native SDLC Platform - Automate the development cycle from idea to deploy',
|
|
@@ -19,5 +20,5 @@ export default function RootLayout({ children, }) {
|
|
|
19
20
|
} catch (e) {}
|
|
20
21
|
})();
|
|
21
22
|
`,
|
|
22
|
-
} }) }),
|
|
23
|
+
} }) }), _jsxs("body", { className: "min-h-screen antialiased", children: [_jsx(AppShell, { children: children }), _jsx(Toaster, {})] })] }));
|
|
23
24
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"page.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/web/app/page.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"page.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/web/app/page.tsx"],"names":[],"mappings":"AAQA,6EAA6E;AAC7E,eAAO,MAAM,OAAO,kBAAkB,CAAC;AAqBvC,wBAA8B,QAAQ,qDAoFrC"}
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
2
|
import { ControlCenter } from '../components/features/control-center/index.js';
|
|
3
|
-
import { getFeatures } from '
|
|
3
|
+
import { getAgentRun, getFeatures } from '../../../../packages/core/src/infrastructure/di/use-cases-bridge.js';
|
|
4
4
|
import { deriveState } from './derive-state.js';
|
|
5
5
|
import { layoutWithDagre } from '../lib/layout-with-dagre.js';
|
|
6
|
+
/** Force request-time rendering so the globalThis DI bridge is available. */
|
|
7
|
+
export const dynamic = 'force-dynamic';
|
|
6
8
|
/** Map domain SdlcLifecycle enum values to UI FeatureLifecyclePhase (1:1). */
|
|
7
9
|
const lifecycleMap = {
|
|
8
10
|
Requirements: 'requirements',
|
|
@@ -22,14 +24,23 @@ const nodeToLifecyclePhase = {
|
|
|
22
24
|
};
|
|
23
25
|
export default async function HomePage() {
|
|
24
26
|
const features = await getFeatures();
|
|
27
|
+
const featuresWithRuns = await Promise.all(features.map(async (feature) => {
|
|
28
|
+
const run = feature.agentRunId ? await getAgentRun(feature.agentRunId) : null;
|
|
29
|
+
return {
|
|
30
|
+
feature,
|
|
31
|
+
agentStatus: run?.status,
|
|
32
|
+
agentError: run?.error,
|
|
33
|
+
agentResult: run?.result,
|
|
34
|
+
};
|
|
35
|
+
}));
|
|
25
36
|
// Group features by repository path
|
|
26
37
|
const featuresByRepo = {};
|
|
27
|
-
|
|
28
|
-
const repoKey =
|
|
38
|
+
featuresWithRuns.forEach((entry) => {
|
|
39
|
+
const repoKey = entry.feature.repositoryPath;
|
|
29
40
|
if (!featuresByRepo[repoKey]) {
|
|
30
41
|
featuresByRepo[repoKey] = [];
|
|
31
42
|
}
|
|
32
|
-
featuresByRepo[repoKey].push(
|
|
43
|
+
featuresByRepo[repoKey].push(entry);
|
|
33
44
|
});
|
|
34
45
|
const nodes = [];
|
|
35
46
|
const edges = [];
|
|
@@ -42,11 +53,9 @@ export default async function HomePage() {
|
|
|
42
53
|
position: { x: 0, y: 0 },
|
|
43
54
|
data: { name: repoName },
|
|
44
55
|
});
|
|
45
|
-
repoFeatures.forEach((feature) => {
|
|
46
|
-
const agentNode =
|
|
47
|
-
|
|
48
|
-
: undefined;
|
|
49
|
-
const lifecycle = feature.agentStatus === 'completed'
|
|
56
|
+
repoFeatures.forEach(({ feature, agentStatus, agentError, agentResult }) => {
|
|
57
|
+
const agentNode = agentResult?.startsWith('node:') ? agentResult.slice(5) : undefined;
|
|
58
|
+
const lifecycle = agentStatus === 'completed'
|
|
50
59
|
? 'maintain'
|
|
51
60
|
: ((agentNode ? nodeToLifecyclePhase[agentNode] : undefined) ??
|
|
52
61
|
lifecycleMap[feature.lifecycle] ??
|
|
@@ -56,8 +65,8 @@ export default async function HomePage() {
|
|
|
56
65
|
description: feature.description ?? feature.slug,
|
|
57
66
|
featureId: feature.id,
|
|
58
67
|
lifecycle,
|
|
59
|
-
...deriveState(lifecycle,
|
|
60
|
-
...(
|
|
68
|
+
...deriveState(lifecycle, agentStatus),
|
|
69
|
+
...(agentError && { errorMessage: agentError }),
|
|
61
70
|
};
|
|
62
71
|
const featureNodeId = `feat-${feature.id}`;
|
|
63
72
|
nodes.push({
|
package/dist/src/presentation/web/components/features/control-center/control-center-inner.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"control-center-inner.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/control-center/control-center-inner.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAE1C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAK5E,UAAU,uBAAuB;IAC/B,YAAY,EAAE,cAAc,EAAE,CAAC;IAC/B,YAAY,EAAE,IAAI,EAAE,CAAC;CACtB;AAED,wBAAgB,kBAAkB,CAAC,EAAE,YAAY,EAAE,YAAY,EAAE,EAAE,uBAAuB,
|
|
1
|
+
{"version":3,"file":"control-center-inner.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/features/control-center/control-center-inner.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAE1C,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAK5E,UAAU,uBAAuB;IAC/B,YAAY,EAAE,cAAc,EAAE,CAAC;IAC/B,YAAY,EAAE,IAAI,EAAE,CAAC;CACtB;AAED,wBAAgB,kBAAkB,CAAC,EAAE,YAAY,EAAE,YAAY,EAAE,EAAE,uBAAuB,2CAkDzF"}
|
package/dist/src/presentation/web/components/features/control-center/control-center-inner.js
CHANGED
|
@@ -6,12 +6,12 @@ import { FeatureDrawer, FeatureCreateDrawer } from '../../common/index.js';
|
|
|
6
6
|
import { ControlCenterEmptyState } from './control-center-empty-state.js';
|
|
7
7
|
import { useControlCenterState } from './use-control-center-state.js';
|
|
8
8
|
export function ControlCenterInner({ initialNodes, initialEdges }) {
|
|
9
|
-
const { nodes, edges, selectedNode, isCreateDrawerOpen, onNodesChange, handleConnect, handleAddFeature, handleAddFeatureToRepo, handleAddFeatureToFeature, handleAddRepository, handleNodeClick, clearSelection, handleCreateFeatureSubmit, closeCreateDrawer, } = useControlCenterState(initialNodes, initialEdges);
|
|
9
|
+
const { nodes, edges, selectedNode, isCreateDrawerOpen, isSubmitting, onNodesChange, handleConnect, handleAddFeature, handleAddFeatureToRepo, handleAddFeatureToFeature, handleAddRepository, handleNodeClick, clearSelection, handleCreateFeatureSubmit, closeCreateDrawer, } = useControlCenterState(initialNodes, initialEdges);
|
|
10
10
|
// Listen for global "open create drawer" events from the sidebar
|
|
11
11
|
useEffect(() => {
|
|
12
12
|
const handler = () => handleAddFeature();
|
|
13
13
|
window.addEventListener('shep:open-create-drawer', handler);
|
|
14
14
|
return () => window.removeEventListener('shep:open-create-drawer', handler);
|
|
15
15
|
}, [handleAddFeature]);
|
|
16
|
-
return (_jsxs(_Fragment, { children: [_jsx(FeaturesCanvas, { nodes: nodes, edges: edges, onNodesChange: onNodesChange, onConnect: handleConnect, onAddFeature: handleAddFeature, onNodeAction: handleAddFeatureToFeature, onNodeClick: handleNodeClick, onPaneClick: clearSelection, onRepositoryAdd: handleAddFeatureToRepo, onRepositorySelect: handleAddRepository, emptyState: _jsx(ControlCenterEmptyState, { onRepositorySelect: handleAddRepository }) }), _jsx(FeatureDrawer, { selectedNode: selectedNode, onClose: clearSelection }), _jsx(FeatureCreateDrawer, { open: isCreateDrawerOpen, onClose: closeCreateDrawer, onSubmit: handleCreateFeatureSubmit })] }));
|
|
16
|
+
return (_jsxs(_Fragment, { children: [_jsx(FeaturesCanvas, { nodes: nodes, edges: edges, onNodesChange: onNodesChange, onConnect: handleConnect, onAddFeature: handleAddFeature, onNodeAction: handleAddFeatureToFeature, onNodeClick: handleNodeClick, onPaneClick: clearSelection, onRepositoryAdd: handleAddFeatureToRepo, onRepositorySelect: handleAddRepository, emptyState: _jsx(ControlCenterEmptyState, { onRepositorySelect: handleAddRepository }) }), _jsx(FeatureDrawer, { selectedNode: selectedNode, onClose: clearSelection }), _jsx(FeatureCreateDrawer, { open: isCreateDrawerOpen, onClose: closeCreateDrawer, onSubmit: handleCreateFeatureSubmit, isSubmitting: isSubmitting })] }));
|
|
17
17
|
}
|
package/dist/src/presentation/web/components/features/control-center/use-control-center-state.d.ts
CHANGED
|
@@ -8,6 +8,7 @@ export interface ControlCenterState {
|
|
|
8
8
|
edges: Edge[];
|
|
9
9
|
selectedNode: FeatureNodeData | null;
|
|
10
10
|
isCreateDrawerOpen: boolean;
|
|
11
|
+
isSubmitting: boolean;
|
|
11
12
|
onNodesChange: (changes: NodeChange<CanvasNodeType>[]) => void;
|
|
12
13
|
handleConnect: (connection: Connection) => void;
|
|
13
14
|
clearSelection: () => void;
|