@shepai/cli 1.129.0-pr413.57e1c33 → 1.129.1-pr408.36c273f
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/repositories/add-repository.use-case.d.ts.map +1 -1
- package/dist/packages/core/src/application/use-cases/repositories/add-repository.use-case.js +5 -2
- package/dist/packages/core/src/infrastructure/repositories/sqlite-repository.repository.js +2 -2
- package/dist/packages/core/src/infrastructure/services/agents/common/agent-validator.service.js +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/common/executors/cursor-executor.service.d.ts +5 -5
- package/dist/packages/core/src/infrastructure/services/agents/common/executors/cursor-executor.service.js +8 -8
- package/dist/packages/core/src/infrastructure/services/deployment/deployment.service.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/deployment/deployment.service.js +6 -20
- package/dist/src/presentation/web/app/(dashboard)/get-graph-data.d.ts +8 -0
- package/dist/src/presentation/web/app/(dashboard)/get-graph-data.d.ts.map +1 -1
- package/dist/src/presentation/web/app/(dashboard)/get-graph-data.js +75 -22
- package/dist/src/presentation/web/app/actions/check-agent-auth.js +1 -1
- package/dist/src/presentation/web/app/build-graph-nodes.d.ts +2 -0
- package/dist/src/presentation/web/app/build-graph-nodes.d.ts.map +1 -1
- package/dist/src/presentation/web/app/build-graph-nodes.js +2 -0
- package/dist/src/presentation/web/components/common/feature-node/feature-node.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/feature-node/feature-node.js +3 -3
- package/dist/src/presentation/web/components/common/prd-questionnaire/prd-questionnaire.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/prd-questionnaire/prd-questionnaire.js +1 -1
- package/dist/src/presentation/web/components/common/prd-questionnaire/prd-questionnaire.stories.d.ts +6 -0
- package/dist/src/presentation/web/components/common/prd-questionnaire/prd-questionnaire.stories.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/prd-questionnaire/prd-questionnaire.stories.js +96 -1
- package/dist/src/presentation/web/components/common/product-decisions-summary/product-decisions-summary.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/product-decisions-summary/product-decisions-summary.js +1 -1
- package/dist/src/presentation/web/components/common/repository-node/repository-node-config.d.ts +2 -0
- package/dist/src/presentation/web/components/common/repository-node/repository-node-config.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/repository-node/repository-node.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/repository-node/repository-node.js +7 -3
- package/dist/src/presentation/web/components/common/repository-node/repository-node.stories.d.ts +2 -0
- package/dist/src/presentation/web/components/common/repository-node/repository-node.stories.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/repository-node/repository-node.stories.js +14 -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 +1 -0
- package/dist/src/presentation/web/lib/derive-graph.d.ts.map +1 -1
- package/dist/src/presentation/web/lib/derive-graph.js +5 -2
- package/dist/src/presentation/web/lib/layout-with-dagre.js +2 -2
- package/dist/tsconfig.build.tsbuildinfo +1 -1
- package/package.json +1 -1
- package/web/.next/BUILD_ID +1 -1
- package/web/.next/build-manifest.json +2 -2
- package/web/.next/fallback-build-manifest.json +2 -2
- package/web/.next/prerender-manifest.json +3 -3
- package/web/.next/required-server-files.js +2 -2
- package/web/.next/required-server-files.json +2 -2
- package/web/.next/server/app/(dashboard)/@drawer/adopt/page/server-reference-manifest.json +24 -24
- package/web/.next/server/app/(dashboard)/@drawer/adopt/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/adopt/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/create/page/server-reference-manifest.json +24 -24
- package/web/.next/server/app/(dashboard)/@drawer/create/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/create/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page/server-reference-manifest.json +30 -30
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page/server-reference-manifest.json +30 -30
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page/server-reference-manifest.json +22 -22
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/create/page/server-reference-manifest.json +24 -24
- package/web/.next/server/app/(dashboard)/create/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/create/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page/server-reference-manifest.json +30 -30
- package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/feature/[featureId]/page/server-reference-manifest.json +30 -30
- package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/feature/[featureId]/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/page/server-reference-manifest.json +22 -22
- package/web/.next/server/app/(dashboard)/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page/server-reference-manifest.json +22 -22
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js.nft.json +1 -1
- package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
- 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/server-reference-manifest.json +3 -3
- package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/settings/page/server-reference-manifest.json +8 -8
- package/web/.next/server/app/settings/page.js.nft.json +1 -1
- package/web/.next/server/app/settings/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/skills/page/server-reference-manifest.json +8 -8
- package/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/tools/page/server-reference-manifest.json +8 -8
- package/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
- package/web/.next/server/app/version/page/server-reference-manifest.json +3 -3
- package/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
- package/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_370c43b1.js +1 -1
- package/web/.next/server/chunks/403f9_next_dist_esm_build_templates_app-route_370c43b1.js.map +1 -1
- package/web/.next/server/chunks/[root-of-the-server]__a402b567._.js +1 -1
- package/web/.next/server/chunks/ssr/744ca_web__next-internal_server_app_(dashboard)_@drawer_adopt_page_actions_4e741df2.js +1 -1
- package/web/.next/server/chunks/ssr/744ca_web__next-internal_server_app_(dashboard)_@drawer_adopt_page_actions_4e741df2.js.map +1 -1
- package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js +1 -1
- package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js.map +1 -1
- package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_026fdffa.js +1 -1
- package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_026fdffa.js.map +1 -1
- package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_8b91e197.js +1 -1
- package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_8b91e197.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__0e842eba._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__0e842eba._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__2f886f77._.js +2 -2
- package/web/.next/server/chunks/ssr/[root-of-the-server]__357d99f9._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__43f51aa6._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__43f51aa6._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__60684242._.js +2 -2
- package/web/.next/server/chunks/ssr/[root-of-the-server]__6bb00d90._.js +2 -2
- package/web/.next/server/chunks/ssr/[root-of-the-server]__6bb00d90._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__755cfe02._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__755cfe02._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__815546bd._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__815546bd._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__a628fb91._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__a628fb91._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__bfba58e6._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__bfba58e6._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__c3ab8422._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__c3ab8422._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__f4a463ee._.js +2 -2
- package/web/.next/server/chunks/ssr/[root-of-the-server]__f4a463ee._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_02ec1aea._.js +1 -1
- package/web/.next/server/chunks/ssr/_02ec1aea._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_7dca1882._.js +1 -1
- package/web/.next/server/chunks/ssr/_7dca1882._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_a9f57758._.js +1 -1
- package/web/.next/server/chunks/ssr/{_4c579535._.js → _c577275e._.js} +2 -2
- package/web/.next/server/chunks/ssr/{_4c579535._.js.map → _c577275e._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/_d8575088._.js +1 -1
- package/web/.next/server/chunks/ssr/_d8575088._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_f39a1adb._.js +1 -1
- package/web/.next/server/chunks/ssr/_f39a1adb._.js.map +1 -1
- package/web/.next/server/chunks/ssr/{_ea5daaaf._.js → _fab5571d._.js} +2 -2
- package/web/.next/server/chunks/ssr/{_ea5daaaf._.js.map → _fab5571d._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js +1 -1
- package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_8e7fe0d1._.js +2 -2
- package/web/.next/server/chunks/ssr/src_presentation_web_8e7fe0d1._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_ca051134.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_ca051134.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_1b176e3c.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_1b176e3c.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_bd9f0dda.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_bd9f0dda.js.map +1 -1
- package/web/.next/server/chunks/ssr/{src_presentation_web_8401cef2._.js → src_presentation_web_a64706b8._.js} +2 -2
- package/web/.next/server/chunks/ssr/{src_presentation_web_8401cef2._.js.map → src_presentation_web_a64706b8._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_b9023017._.js +2 -2
- package/web/.next/server/chunks/ssr/src_presentation_web_b9023017._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_ca99d62d._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_ca99d62d._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js.map +1 -1
- 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 +38 -38
- package/web/.next/static/chunks/153699224addc51e.js +2 -0
- package/web/.next/static/chunks/{2c0f72e13873aa11.js → 4ee771feb075f293.js} +1 -1
- package/web/.next/static/chunks/{e46b2039c3259c91.js → 5b223ee4211e9f97.js} +1 -1
- package/web/.next/static/chunks/{f0f36e5435461097.js → 622d45c8fcd8c71a.js} +1 -1
- package/web/.next/static/chunks/{36544f2ce44008e9.js → 6515a36a0fa239b1.js} +1 -1
- package/web/.next/static/chunks/{5ee76a706c272a48.js → 6eb57a04da8dd9ec.js} +1 -1
- package/web/.next/static/chunks/{963c38281082498c.js → 718a86f43c105bf6.js} +1 -1
- package/web/.next/static/chunks/{b4211828df7f8b84.js → 96e8f2ffe7c7dc0e.js} +1 -1
- package/web/.next/static/chunks/{4fa84a327da62d41.js → c0f289d181410faf.js} +1 -1
- package/web/.next/static/chunks/{e9b5b99f78a82ff2.js → c134a4de481e7510.js} +1 -1
- package/web/.next/static/chunks/{e6b6017a4788e869.js → d1bf55cbdce4ca71.js} +1 -1
- package/web/.next/static/chunks/da484d44874006a2.css +1 -0
- package/web/.next/static/chunks/{8435f506faaeab86.js → e23741487ff1c417.js} +1 -1
- package/web/.next/static/chunks/98dfbecc5ee30ce1.css +0 -1
- package/web/.next/static/chunks/fbe09387689edb43.js +0 -2
- /package/web/.next/static/{2FNRt2NFwO7rgcja0AV1h → jGtdRopyVmCvF4SZRRryd}/_buildManifest.js +0 -0
- /package/web/.next/static/{2FNRt2NFwO7rgcja0AV1h → jGtdRopyVmCvF4SZRRryd}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{2FNRt2NFwO7rgcja0AV1h → jGtdRopyVmCvF4SZRRryd}/_ssgManifest.js +0 -0
package/dist/packages/core/src/application/use-cases/repositories/add-repository.use-case.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"add-repository.use-case.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/application/use-cases/repositories/add-repository.use-case.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qCAAqC,CAAC;AACtE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,oEAAoE,CAAC;AAEhH,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAcD,qBACa,oBAAoB;IAG7B,OAAO,CAAC,QAAQ,CAAC,cAAc;gBAAd,cAAc,EAAE,qBAAqB;IAGlD,OAAO,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,UAAU,CAAC;
|
|
1
|
+
{"version":3,"file":"add-repository.use-case.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/application/use-cases/repositories/add-repository.use-case.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAIH,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,qCAAqC,CAAC;AACtE,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,oEAAoE,CAAC;AAEhH,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,MAAM,CAAC;IACb,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAcD,qBACa,oBAAoB;IAG7B,OAAO,CAAC,QAAQ,CAAC,cAAc;gBAAd,cAAc,EAAE,qBAAqB;IAGlD,OAAO,CAAC,KAAK,EAAE,kBAAkB,GAAG,OAAO,CAAC,UAAU,CAAC;CAiC9D"}
|
package/dist/packages/core/src/application/use-cases/repositories/add-repository.use-case.js
CHANGED
|
@@ -41,11 +41,14 @@ let AddRepositoryUseCase = class AddRepositoryUseCase {
|
|
|
41
41
|
if (existing) {
|
|
42
42
|
return existing;
|
|
43
43
|
}
|
|
44
|
-
// Check for soft-deleted repository — restore it instead of creating a duplicate
|
|
44
|
+
// Check for soft-deleted repository — restore it instead of creating a duplicate.
|
|
45
|
+
// Reset createdAt so the restored repo sorts as "newest" on the canvas
|
|
46
|
+
// (otherwise the old createdAt would place it above repos added later).
|
|
45
47
|
const deleted = await this.repositoryRepo.findByPathIncludingDeleted(normalizedPath);
|
|
46
48
|
if (deleted) {
|
|
49
|
+
const now = new Date();
|
|
47
50
|
await this.repositoryRepo.restore(deleted.id);
|
|
48
|
-
return { ...deleted, deletedAt: undefined, updatedAt:
|
|
51
|
+
return { ...deleted, deletedAt: undefined, createdAt: now, updatedAt: now };
|
|
49
52
|
}
|
|
50
53
|
const now = new Date();
|
|
51
54
|
const name = input.name ?? normalizedPath.split('/').pop() ?? normalizedPath;
|
|
@@ -94,8 +94,8 @@ let SQLiteRepositoryRepository = SQLiteRepositoryRepository_1 = class SQLiteRepo
|
|
|
94
94
|
}
|
|
95
95
|
async restore(id) {
|
|
96
96
|
const now = Date.now();
|
|
97
|
-
const stmt = this.db.prepare('UPDATE repositories SET deleted_at = NULL, updated_at = ? WHERE id = ?');
|
|
98
|
-
stmt.run(now, id);
|
|
97
|
+
const stmt = this.db.prepare('UPDATE repositories SET deleted_at = NULL, created_at = ?, updated_at = ? WHERE id = ?');
|
|
98
|
+
stmt.run(now, now, id);
|
|
99
99
|
}
|
|
100
100
|
static normalizeRemoteUrl(url) {
|
|
101
101
|
return url.replace(/\.git$/, '').toLowerCase();
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Cursor Executor Service
|
|
3
3
|
*
|
|
4
4
|
* Infrastructure implementation of IAgentExecutor for the Cursor agent.
|
|
5
|
-
* Executes prompts via the `
|
|
5
|
+
* Executes prompts via the `agent` CLI subprocess with JSON and stream-json
|
|
6
6
|
* output formats.
|
|
7
7
|
*
|
|
8
8
|
* Uses constructor dependency injection for the spawn function
|
|
@@ -13,7 +13,7 @@ import type { IAgentExecutor, AgentExecutionOptions, AgentExecutionResult, Agent
|
|
|
13
13
|
import type { SpawnFunction } from '../types.js';
|
|
14
14
|
/**
|
|
15
15
|
* Executor service for Cursor agent.
|
|
16
|
-
* Uses subprocess spawning to interact with the `
|
|
16
|
+
* Uses subprocess spawning to interact with the `agent` CLI.
|
|
17
17
|
*/
|
|
18
18
|
export declare class CursorExecutorService implements IAgentExecutor {
|
|
19
19
|
private readonly spawn;
|
|
@@ -35,13 +35,13 @@ export declare class CursorExecutorService implements IAgentExecutor {
|
|
|
35
35
|
/**
|
|
36
36
|
* Spawn the agent process, handling Windows specially via PowerShell.
|
|
37
37
|
*
|
|
38
|
-
* On Windows, cursor CLI ships as `
|
|
38
|
+
* On Windows, cursor CLI ships as `agent.cmd` which requires `shell: true`,
|
|
39
39
|
* but cmd.exe mangles long `-p` arguments (8191-char limit + special chars).
|
|
40
|
-
* Solution: write prompt to a temp file, invoke
|
|
40
|
+
* Solution: write prompt to a temp file, invoke agent via PowerShell which
|
|
41
41
|
* reads the file and passes the content as `-p`. PowerShell handles long
|
|
42
42
|
* strings natively (32K limit) and doesn't mangle arguments.
|
|
43
43
|
*
|
|
44
|
-
* On Linux/macOS, spawn `
|
|
44
|
+
* On Linux/macOS, spawn `agent` directly — no shell needed.
|
|
45
45
|
*/
|
|
46
46
|
private spawnAgent;
|
|
47
47
|
private parseStreamLine;
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Cursor Executor Service
|
|
3
3
|
*
|
|
4
4
|
* Infrastructure implementation of IAgentExecutor for the Cursor agent.
|
|
5
|
-
* Executes prompts via the `
|
|
5
|
+
* Executes prompts via the `agent` CLI subprocess with JSON and stream-json
|
|
6
6
|
* output formats.
|
|
7
7
|
*
|
|
8
8
|
* Uses constructor dependency injection for the spawn function
|
|
@@ -32,7 +32,7 @@ function toCursorModelName(model) {
|
|
|
32
32
|
const SUPPORTED_FEATURES = new Set(['session-resume', 'streaming']);
|
|
33
33
|
/**
|
|
34
34
|
* Executor service for Cursor agent.
|
|
35
|
-
* Uses subprocess spawning to interact with the `
|
|
35
|
+
* Uses subprocess spawning to interact with the `agent` CLI.
|
|
36
36
|
*/
|
|
37
37
|
export class CursorExecutorService {
|
|
38
38
|
spawn;
|
|
@@ -312,13 +312,13 @@ export class CursorExecutorService {
|
|
|
312
312
|
/**
|
|
313
313
|
* Spawn the agent process, handling Windows specially via PowerShell.
|
|
314
314
|
*
|
|
315
|
-
* On Windows, cursor CLI ships as `
|
|
315
|
+
* On Windows, cursor CLI ships as `agent.cmd` which requires `shell: true`,
|
|
316
316
|
* but cmd.exe mangles long `-p` arguments (8191-char limit + special chars).
|
|
317
|
-
* Solution: write prompt to a temp file, invoke
|
|
317
|
+
* Solution: write prompt to a temp file, invoke agent via PowerShell which
|
|
318
318
|
* reads the file and passes the content as `-p`. PowerShell handles long
|
|
319
319
|
* strings natively (32K limit) and doesn't mangle arguments.
|
|
320
320
|
*
|
|
321
|
-
* On Linux/macOS, spawn `
|
|
321
|
+
* On Linux/macOS, spawn `agent` directly — no shell needed.
|
|
322
322
|
*/
|
|
323
323
|
spawnAgent(prompt, args, options) {
|
|
324
324
|
const { CLAUDECODE: _, ...cleanEnv } = process.env;
|
|
@@ -330,7 +330,7 @@ export class CursorExecutorService {
|
|
|
330
330
|
// Build the agent args WITHOUT -p and the prompt (they go via temp file)
|
|
331
331
|
const agentFlags = args.filter((a) => a !== '-p' && a !== prompt).join(' ');
|
|
332
332
|
const safePath = tmpFile.replace(/'/g, "''");
|
|
333
|
-
const psCmd = `$p = Get-Content -Raw '${safePath}'; &
|
|
333
|
+
const psCmd = `$p = Get-Content -Raw '${safePath}'; & agent ${agentFlags} -p $p`;
|
|
334
334
|
this.log(`Windows PowerShell mode: wrote ${prompt.length} chars to ${tmpFile}`);
|
|
335
335
|
this.log(`PS command: ${psCmd.replace(prompt, `<${prompt.length} chars>`)}`);
|
|
336
336
|
const proc = this.spawn('powershell.exe', ['-NoProfile', '-NonInteractive', '-Command', psCmd], {
|
|
@@ -351,9 +351,9 @@ export class CursorExecutorService {
|
|
|
351
351
|
};
|
|
352
352
|
if (cwd)
|
|
353
353
|
spawnOpts.cwd = cwd;
|
|
354
|
-
this.log(`Spawning:
|
|
354
|
+
this.log(`Spawning: agent ${args.map((a) => (a.length > 80 ? `${a.slice(0, 77)}...` : a)).join(' ')}`);
|
|
355
355
|
this.log(`Spawn cwd: ${cwd ?? '(inherited)'}`);
|
|
356
|
-
const proc = this.spawn('
|
|
356
|
+
const proc = this.spawn('agent', args, spawnOpts);
|
|
357
357
|
this.log(`Subprocess PID: ${proc.pid ?? 'undefined (spawn may have failed)'}`);
|
|
358
358
|
if (proc.stdin)
|
|
359
359
|
proc.stdin.end();
|
package/dist/packages/core/src/infrastructure/services/deployment/deployment.service.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"deployment.service.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/deployment/deployment.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,KAAK,
|
|
1
|
+
{"version":3,"file":"deployment.service.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/infrastructure/services/deployment/deployment.service.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,KAAK,EAAqB,MAAM,oBAAoB,CAAC;AAE9D,OAAO,KAAK,QAAQ,MAAM,gBAAgB,CAAC;AAO3C,OAAO,KAAK,EACV,kBAAkB,EAClB,gBAAgB,EAChB,QAAQ,EACT,MAAM,qEAAqE,CAAC;AAC7E,OAAO,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAgCzD,MAAM,WAAW,qBAAqB;IACpC,KAAK,EAAE,OAAO,KAAK,CAAC;IACpB,eAAe,EAAE,OAAO,eAAe,CAAC;IACxC,IAAI,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,GAAG,MAAM,KAAK,IAAI,CAAC;IAC7D,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC;CACnC;AA6BD,qBAAa,iBAAkB,YAAW,kBAAkB;IAC1D,OAAO,CAAC,QAAQ,CAAC,WAAW,CAAsC;IAClE,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAwB;IAC7C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAsB;IAC9C,OAAO,CAAC,EAAE,CAAkC;gBAEhC,IAAI,GAAE,OAAO,CAAC,qBAAqB,CAAM;IAIrD;;OAEG;IACH,WAAW,CAAC,EAAE,EAAE,QAAQ,CAAC,QAAQ,GAAG,IAAI;IAIxC;;;OAGG;IACH,UAAU,IAAI,IAAI;IA4ClB;;;OAGG;IACH,KAAK,CAAC,QAAQ,EAAE,MAAM,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,SAAe,GAAG,IAAI;IAqF5E;;;;OAIG;IACH,SAAS,CAAC,QAAQ,EAAE,MAAM,GAAG,gBAAgB,GAAG,IAAI;IA4CpD;;OAEG;IACG,IAAI,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IA0D3C;;OAEG;IACH,OAAO,IAAI,IAAI;IAef;;OAEG;IACH,OAAO,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,EAAE,GAAG,IAAI;IAM5C;;OAEG;IACH,EAAE,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,GAAG,IAAI;IAI1D;;OAEG;IACH,GAAG,CAAC,KAAK,EAAE,KAAK,EAAE,OAAO,EAAE,CAAC,KAAK,EAAE,QAAQ,KAAK,IAAI,GAAG,IAAI;IAM3D,OAAO,CAAC,QAAQ;IAuBhB,OAAO,CAAC,aAAa;IAWrB,OAAO,CAAC,QAAQ;IAShB,OAAO,CAAC,MAAM;IAed,OAAO,CAAC,WAAW;IAQnB;;;OAGG;IACH,OAAO,CAAC,oBAAoB;YA4Dd,aAAa;IAW3B,OAAO,CAAC,WAAW;CASpB"}
|
|
@@ -9,17 +9,18 @@
|
|
|
9
9
|
* On startup, call `recoverAll()` to reconcile the DB with actual
|
|
10
10
|
* process state (clean up dead PIDs, re-adopt live ones).
|
|
11
11
|
*/
|
|
12
|
-
import { spawn
|
|
12
|
+
import { spawn } from 'node:child_process';
|
|
13
13
|
import { EventEmitter } from 'node:events';
|
|
14
|
-
//
|
|
15
|
-
//
|
|
16
|
-
//
|
|
14
|
+
// NOTE: We intentionally do NOT use tree-kill here. tree-kill traverses
|
|
15
|
+
// /proc to find child processes which can accidentally kill parent processes
|
|
16
|
+
// (including the Shep web UI). Instead, we use process.kill(-pid) to send
|
|
17
|
+
// signals to the process GROUP (since we spawn with detached: true, the
|
|
18
|
+
// child gets its own process group via setsid()).
|
|
17
19
|
import { DeploymentState } from '../../../domain/generated/output.js';
|
|
18
20
|
import { detectDevScript } from './detect-dev-script.js';
|
|
19
21
|
import { createDeploymentLogger } from './deployment-logger.js';
|
|
20
22
|
import { parsePort } from './parse-port.js';
|
|
21
23
|
import { LogRingBuffer } from './log-ring-buffer.js';
|
|
22
|
-
import { IS_WINDOWS } from '../../platform.js';
|
|
23
24
|
const log = createDeploymentLogger('[DeploymentService]');
|
|
24
25
|
const POLL_INTERVAL_MS = 200;
|
|
25
26
|
const MAX_WAIT_MS = 5000;
|
|
@@ -27,20 +28,6 @@ const defaultDeps = {
|
|
|
27
28
|
spawn,
|
|
28
29
|
detectDevScript,
|
|
29
30
|
kill: (pid, signal) => {
|
|
30
|
-
if (IS_WINDOWS) {
|
|
31
|
-
// On Windows, negative PIDs are not supported. Use taskkill /T to
|
|
32
|
-
// kill the entire process tree (shell + child dev server).
|
|
33
|
-
try {
|
|
34
|
-
execFileSync('taskkill', ['/F', '/T', '/PID', String(pid)], {
|
|
35
|
-
stdio: 'ignore',
|
|
36
|
-
windowsHide: true,
|
|
37
|
-
});
|
|
38
|
-
}
|
|
39
|
-
catch {
|
|
40
|
-
// Process already dead
|
|
41
|
-
}
|
|
42
|
-
return;
|
|
43
|
-
}
|
|
44
31
|
try {
|
|
45
32
|
// Kill the entire process group (negative PID) — safe because
|
|
46
33
|
// detached: true puts the child in its own group via setsid().
|
|
@@ -153,7 +140,6 @@ export class DeploymentService {
|
|
|
153
140
|
cwd: targetPath,
|
|
154
141
|
detached: true,
|
|
155
142
|
stdio: ['ignore', 'pipe', 'pipe'],
|
|
156
|
-
...(IS_WINDOWS ? { windowsHide: true } : {}),
|
|
157
143
|
});
|
|
158
144
|
if (!child.pid) {
|
|
159
145
|
log.error('spawn() returned no PID — process failed to start');
|
|
@@ -6,6 +6,14 @@ export interface RepoGitInfo {
|
|
|
6
6
|
committer: string;
|
|
7
7
|
behindCount: number | null;
|
|
8
8
|
}
|
|
9
|
+
export type GitInfoResult = {
|
|
10
|
+
status: 'loading';
|
|
11
|
+
} | {
|
|
12
|
+
status: 'ready';
|
|
13
|
+
data: RepoGitInfo;
|
|
14
|
+
} | {
|
|
15
|
+
status: 'not-a-repo';
|
|
16
|
+
};
|
|
9
17
|
export declare function getGraphData(): Promise<{
|
|
10
18
|
nodes: CanvasNodeType[];
|
|
11
19
|
edges: Edge[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"get-graph-data.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/web/app/(dashboard)/get-graph-data.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAE5E,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAI1C,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;
|
|
1
|
+
{"version":3,"file":"get-graph-data.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/web/app/(dashboard)/get-graph-data.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAE5E,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAI1C,MAAM,WAAW,WAAW;IAC1B,MAAM,EAAE,MAAM,CAAC;IACf,aAAa,EAAE,MAAM,CAAC;IACtB,SAAS,EAAE,MAAM,CAAC;IAClB,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAwFD,MAAM,MAAM,aAAa,GACrB;IAAE,MAAM,EAAE,SAAS,CAAA;CAAE,GACrB;IAAE,MAAM,EAAE,OAAO,CAAC;IAAC,IAAI,EAAE,WAAW,CAAA;CAAE,GACtC;IAAE,MAAM,EAAE,YAAY,CAAA;CAAE,CAAC;AA6B7B,wBAAsB,YAAY,IAAI,OAAO,CAAC;IAAE,KAAK,EAAE,cAAc,EAAE,CAAC;IAAC,KAAK,EAAE,IAAI,EAAE,CAAA;CAAE,CAAC,CA6DxF"}
|
|
@@ -6,6 +6,11 @@ import { getSettings } from '../../../../../packages/core/src/infrastructure/ser
|
|
|
6
6
|
import { layoutWithDagre, CANVAS_LAYOUT_DEFAULTS } from '../../lib/layout-with-dagre.js';
|
|
7
7
|
import { buildGraphNodes } from '../build-graph-nodes.js';
|
|
8
8
|
const execFileAsync = promisify(execFileCb);
|
|
9
|
+
// Cache git info per repo — refreshed every GIT_INFO_TTL_MS via background-style check.
|
|
10
|
+
// getGraphData() always reads from cache (zero git calls), and only spawns git
|
|
11
|
+
// processes when the cache entry is older than the TTL.
|
|
12
|
+
const GIT_INFO_TTL_MS = 30_000;
|
|
13
|
+
const gitInfoCache = new Map();
|
|
9
14
|
async function gitCommand(cwd, args) {
|
|
10
15
|
try {
|
|
11
16
|
const opts = IS_WINDOWS ? { cwd, windowsHide: true } : { cwd };
|
|
@@ -16,22 +21,38 @@ async function gitCommand(cwd, args) {
|
|
|
16
21
|
return null;
|
|
17
22
|
}
|
|
18
23
|
}
|
|
19
|
-
|
|
24
|
+
const FIELD_SEP = '\x1f'; // ASCII Unit Separator — safe in git output and child_process
|
|
25
|
+
/** Refresh git info for a single repo (spawns git processes). */
|
|
26
|
+
async function refreshRepoGitInfo(repo) {
|
|
20
27
|
try {
|
|
21
|
-
const
|
|
28
|
+
const headSha = await gitCommand(repo.path, ['rev-parse', 'HEAD']);
|
|
29
|
+
if (!headSha) {
|
|
30
|
+
// Not a git repo (or bare/broken) — cache this so the UI can show it
|
|
31
|
+
gitInfoCache.set(repo.path, { kind: 'not-a-repo', checkedAt: Date.now() });
|
|
32
|
+
return;
|
|
33
|
+
}
|
|
34
|
+
const cached = gitInfoCache.get(repo.path);
|
|
35
|
+
if (cached?.kind === 'repo' && cached.sha === headSha) {
|
|
36
|
+
// HEAD unchanged — just bump checkedAt
|
|
37
|
+
cached.checkedAt = Date.now();
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
// HEAD changed — fetch branch + subject & author in parallel
|
|
41
|
+
const [currentBranch, logLine] = await Promise.all([
|
|
22
42
|
gitCommand(repo.path, ['symbolic-ref', '--short', 'HEAD']),
|
|
23
|
-
gitCommand(repo.path, ['log', '-1',
|
|
24
|
-
gitCommand(repo.path, ['log', '-1', '--format=%an']),
|
|
43
|
+
gitCommand(repo.path, ['log', '-1', `--format=%s${FIELD_SEP}%an`]),
|
|
25
44
|
]);
|
|
26
45
|
if (!currentBranch)
|
|
27
|
-
return
|
|
28
|
-
|
|
46
|
+
return;
|
|
47
|
+
const [commitMessage, committer] = (logLine ?? '').split(FIELD_SEP);
|
|
48
|
+
// Behind count
|
|
29
49
|
let behindCount = null;
|
|
30
|
-
const
|
|
50
|
+
const defaultBranchRef = await gitCommand(repo.path, [
|
|
31
51
|
'symbolic-ref',
|
|
32
52
|
'--short',
|
|
33
53
|
'refs/remotes/origin/HEAD',
|
|
34
|
-
])
|
|
54
|
+
]);
|
|
55
|
+
const defaultBranch = defaultBranchRef?.replace('origin/', '') ?? null;
|
|
35
56
|
if (defaultBranch && currentBranch !== defaultBranch) {
|
|
36
57
|
const behind = await gitCommand(repo.path, [
|
|
37
58
|
'rev-list',
|
|
@@ -42,32 +63,63 @@ async function fetchRepoGitInfo(repo) {
|
|
|
42
63
|
if (isNaN(behindCount))
|
|
43
64
|
behindCount = null;
|
|
44
65
|
}
|
|
45
|
-
else
|
|
66
|
+
else {
|
|
46
67
|
behindCount = 0;
|
|
47
68
|
}
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
69
|
+
gitInfoCache.set(repo.path, {
|
|
70
|
+
kind: 'repo',
|
|
71
|
+
sha: headSha,
|
|
72
|
+
checkedAt: Date.now(),
|
|
73
|
+
data: {
|
|
74
|
+
branch: currentBranch,
|
|
75
|
+
commitMessage: commitMessage ?? 'unknown',
|
|
76
|
+
committer: committer ?? 'unknown',
|
|
77
|
+
behindCount,
|
|
78
|
+
},
|
|
79
|
+
});
|
|
54
80
|
}
|
|
55
81
|
catch {
|
|
56
|
-
|
|
82
|
+
// ignore — stale cache is better than no data
|
|
57
83
|
}
|
|
58
84
|
}
|
|
85
|
+
/**
|
|
86
|
+
* Return cached git info for a repo. If the cache is stale (> TTL),
|
|
87
|
+
* kick off a fire-and-forget refresh so the NEXT call gets fresh data.
|
|
88
|
+
* Never blocks getGraphData() with git subprocess calls.
|
|
89
|
+
*/
|
|
90
|
+
function getRepoGitInfo(repo) {
|
|
91
|
+
const cached = gitInfoCache.get(repo.path);
|
|
92
|
+
const now = Date.now();
|
|
93
|
+
if (!cached) {
|
|
94
|
+
// First time — trigger async refresh, return loading for this call
|
|
95
|
+
void refreshRepoGitInfo(repo);
|
|
96
|
+
return { status: 'loading' };
|
|
97
|
+
}
|
|
98
|
+
if (now - cached.checkedAt >= GIT_INFO_TTL_MS) {
|
|
99
|
+
// Stale — trigger async refresh, return current data immediately
|
|
100
|
+
void refreshRepoGitInfo(repo);
|
|
101
|
+
}
|
|
102
|
+
if (cached.kind === 'not-a-repo') {
|
|
103
|
+
return { status: 'not-a-repo' };
|
|
104
|
+
}
|
|
105
|
+
return { status: 'ready', data: cached.data };
|
|
106
|
+
}
|
|
59
107
|
export async function getGraphData() {
|
|
60
108
|
const listFeatures = resolve('ListFeaturesUseCase');
|
|
61
109
|
const listRepos = resolve('ListRepositoriesUseCase');
|
|
62
110
|
const agentRunRepo = resolve('IAgentRunRepository');
|
|
63
111
|
const [features, repositories] = await Promise.all([listFeatures.execute(), listRepos.execute()]);
|
|
64
|
-
//
|
|
112
|
+
// Read git info from cache (zero git calls). Stale entries trigger
|
|
113
|
+
// a fire-and-forget background refresh for the next poll cycle.
|
|
65
114
|
const repoGitInfoMap = new Map();
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
115
|
+
const repoGitStatusMap = new Map();
|
|
116
|
+
for (const repo of repositories) {
|
|
117
|
+
const result = getRepoGitInfo(repo);
|
|
118
|
+
repoGitStatusMap.set(repo.path, result.status);
|
|
119
|
+
if (result.status === 'ready') {
|
|
120
|
+
repoGitInfoMap.set(repo.path, result.data);
|
|
121
|
+
}
|
|
122
|
+
}
|
|
71
123
|
// PR/CI status is kept fresh by PrSyncWatcher (30s background poll).
|
|
72
124
|
// No live GitHub calls here — use cached DB values for fast response.
|
|
73
125
|
const featuresWithRuns = await Promise.all(features.map(async (feature) => {
|
|
@@ -80,6 +132,7 @@ export async function getGraphData() {
|
|
|
80
132
|
commitEvidence: workflow.commitEvidence,
|
|
81
133
|
ciWatchEnabled: workflow.ciWatchEnabled,
|
|
82
134
|
repoGitInfo: repoGitInfoMap,
|
|
135
|
+
repoGitStatus: repoGitStatusMap,
|
|
83
136
|
});
|
|
84
137
|
// Enrich feature nodes with deployment status
|
|
85
138
|
let deploymentService = null;
|
|
@@ -27,6 +27,8 @@ export interface BuildGraphNodesOptions {
|
|
|
27
27
|
committer: string;
|
|
28
28
|
behindCount: number | null;
|
|
29
29
|
}>;
|
|
30
|
+
/** Git info resolution status keyed by repository path */
|
|
31
|
+
repoGitStatus?: Map<string, 'loading' | 'ready' | 'not-a-repo'>;
|
|
30
32
|
}
|
|
31
33
|
export declare function buildGraphNodes(repositories: Repository[], featuresWithRuns: FeatureWithRun[], options?: BuildGraphNodesOptions): {
|
|
32
34
|
nodes: CanvasNodeType[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"build-graph-nodes.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/web/app/build-graph-nodes.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,sCAAsC,CAAC;AAS1F,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAC5E,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAU1C,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,QAAQ,GAAG,IAAI,CAAC;CACtB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,sBAAsB;IACrC,uEAAuE;IACvE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,6EAA6E;IAC7E,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,qEAAqE;IACrE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,0FAA0F;IAC1F,WAAW,CAAC,EAAE,GAAG,CACf,MAAM,EACN;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CACzF,CAAC;
|
|
1
|
+
{"version":3,"file":"build-graph-nodes.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/web/app/build-graph-nodes.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAE,MAAM,sCAAsC,CAAC;AAS1F,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAC5E,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,eAAe,CAAC;AAU1C,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,QAAQ,GAAG,IAAI,CAAC;CACtB;AAED;;;;;;;GAOG;AACH,MAAM,WAAW,sBAAsB;IACrC,uEAAuE;IACvE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,6EAA6E;IAC7E,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,qEAAqE;IACrE,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,0FAA0F;IAC1F,WAAW,CAAC,EAAE,GAAG,CACf,MAAM,EACN;QAAE,MAAM,EAAE,MAAM,CAAC;QAAC,aAAa,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,WAAW,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,CACzF,CAAC;IACF,0DAA0D;IAC1D,aAAa,CAAC,EAAE,GAAG,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,GAAG,YAAY,CAAC,CAAC;CACjE;AAED,wBAAgB,eAAe,CAC7B,YAAY,EAAE,UAAU,EAAE,EAC1B,gBAAgB,EAAE,cAAc,EAAE,EAClC,OAAO,CAAC,EAAE,sBAAsB,GAC/B;IAAE,KAAK,EAAE,cAAc,EAAE,CAAC;IAAC,KAAK,EAAE,IAAI,EAAE,CAAA;CAAE,CAoG5C"}
|
|
@@ -32,6 +32,7 @@ export function buildGraphNodes(repositories, featuresWithRuns, options) {
|
|
|
32
32
|
coveredPaths.add(normalizedRepoPath);
|
|
33
33
|
const repoNodeId = `repo-${repo.id}`;
|
|
34
34
|
const gitInfo = options?.repoGitInfo?.get(repo.path);
|
|
35
|
+
const gitInfoStatus = options?.repoGitStatus?.get(repo.path) ?? 'loading';
|
|
35
36
|
nodes.push({
|
|
36
37
|
id: repoNodeId,
|
|
37
38
|
type: 'repositoryNode',
|
|
@@ -41,6 +42,7 @@ export function buildGraphNodes(repositories, featuresWithRuns, options) {
|
|
|
41
42
|
repositoryPath: normalizedRepoPath,
|
|
42
43
|
id: repo.id,
|
|
43
44
|
createdAt: repo.createdAt instanceof Date ? repo.createdAt.getTime() : Number(repo.createdAt),
|
|
45
|
+
gitInfoStatus,
|
|
44
46
|
...(gitInfo && {
|
|
45
47
|
branch: gitInfo.branch,
|
|
46
48
|
commitMessage: gitInfo.commitMessage,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feature-node.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-node/feature-node.tsx"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AA6DnE,wBAAgB,WAAW,CAAC,EAC1B,IAAI,EACJ,QAAQ,GACT,EAAE;IACD,IAAI,EAAE,eAAe,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,
|
|
1
|
+
{"version":3,"file":"feature-node.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-node/feature-node.tsx"],"names":[],"mappings":"AAyBA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,6BAA6B,CAAC;AA6DnE,wBAAgB,WAAW,CAAC,EAC1B,IAAI,EACJ,QAAQ,GACT,EAAE;IACD,IAAI,EAAE,eAAe,CAAC;IACtB,QAAQ,CAAC,EAAE,OAAO,CAAC;IACnB,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;CACxB,2CAqWA"}
|
|
@@ -70,7 +70,7 @@ export function FeatureNode({ data, selected, }) {
|
|
|
70
70
|
const config = featureNodeStateConfig[data.state];
|
|
71
71
|
const Icon = config.icon;
|
|
72
72
|
const [confirmOpen, setConfirmOpen] = useState(false);
|
|
73
|
-
return (_jsxs("div", { className: "animate-in fade-in group relative duration-300", children: [data.showHandles ? (_jsx(Handle, { type: "target", position: Position.Left, isConnectable: false, className: "opacity-0!" })) : null, data.onDelete && data.featureId && data.state !== 'deleting' ? (_jsxs(_Fragment, { children: [_jsx("div", { className: "absolute top-1/2 -left-10 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100", onPointerDown: (e) => e.stopPropagation(), children: _jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { "aria-label": "Delete feature", "data-testid": "feature-node-delete-button", onClick: (e) => {
|
|
73
|
+
return (_jsxs("div", { className: "animate-in fade-in group relative duration-300", children: [data.showHandles ? (_jsx(Handle, { type: "target", position: Position.Left, isConnectable: false, className: "opacity-0!", style: { top: 70 } })) : null, data.onDelete && data.featureId && data.state !== 'deleting' ? (_jsxs(_Fragment, { children: [_jsx("div", { className: "absolute top-1/2 -left-10 -translate-y-1/2 opacity-0 transition-opacity group-hover:opacity-100", onPointerDown: (e) => e.stopPropagation(), children: _jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("button", { "aria-label": "Delete feature", "data-testid": "feature-node-delete-button", onClick: (e) => {
|
|
74
74
|
e.stopPropagation();
|
|
75
75
|
setConfirmOpen(true);
|
|
76
76
|
}, className: "bg-card text-muted-foreground hover:border-destructive hover:text-destructive flex h-7 w-7 cursor-pointer items-center justify-center rounded-full border shadow-sm transition-colors", children: _jsx(Trash2, { className: "h-3.5 w-3.5" }) }) }), _jsx(TooltipContent, { children: "Delete feature" })] }) }) }), _jsx(DeleteFeatureDialog, { open: confirmOpen, onOpenChange: setConfirmOpen, onConfirm: (cleanup, cascadeDelete, closePr) => {
|
|
@@ -109,8 +109,8 @@ export function FeatureNode({ data, selected, }) {
|
|
|
109
109
|
}, className: "nodrag flex shrink-0 cursor-pointer items-center gap-1 rounded-full bg-red-100 px-2.5 py-1 text-[11px] font-medium text-red-700 transition-colors hover:bg-red-200", children: [_jsx(RotateCcw, { className: "h-3 w-3" }), "Retry"] })) : null, data.state === 'pending' && data.onStart ? (_jsxs("button", { type: "button", "aria-label": "Start feature", "data-testid": "feature-node-start-button", onClick: (e) => {
|
|
110
110
|
e.stopPropagation();
|
|
111
111
|
data.onStart(data.featureId);
|
|
112
|
-
}, className: "nodrag flex shrink-0 cursor-pointer items-center gap-1 rounded-full bg-slate-100 px-2.5 py-1 text-[11px] font-medium text-slate-700 transition-colors hover:bg-slate-200", children: [_jsx(Play, { className: "h-3 w-3" }), "Start"] })) : null] })] })) })] }), data.onAction && data.state !== 'deleting' ? (_jsx(Handle, { type: "source", position: Position.Right, className: "h-0! w-0! border-0! bg-transparent!", children: _jsx("button", { type: "button", "aria-label": "Add", "data-testid": "feature-node-action-button", onClick: (e) => {
|
|
112
|
+
}, className: "nodrag flex shrink-0 cursor-pointer items-center gap-1 rounded-full bg-slate-100 px-2.5 py-1 text-[11px] font-medium text-slate-700 transition-colors hover:bg-slate-200", children: [_jsx(Play, { className: "h-3 w-3" }), "Start"] })) : null] })] })) })] }), data.onAction && data.state !== 'deleting' ? (_jsx(Handle, { type: "source", position: Position.Right, className: "h-0! w-0! border-0! bg-transparent!", style: { top: 70 }, children: _jsx("button", { type: "button", "aria-label": "Add", "data-testid": "feature-node-action-button", onClick: (e) => {
|
|
113
113
|
e.stopPropagation();
|
|
114
114
|
data.onAction?.();
|
|
115
|
-
}, className: "nodrag absolute top-1/2 left-1/2 flex h-6 w-6 -translate-x-1/2 -translate-y-1/2 cursor-pointer items-center justify-center rounded-full bg-blue-500 text-white opacity-0 shadow-md transition-opacity group-hover:opacity-100 hover:bg-blue-600", children: _jsx(Plus, { className: "h-3.5 w-3.5" }) }) })) : data.showHandles ? (_jsx(Handle, { type: "source", position: Position.Right, isConnectable: false, className: "opacity-0!" })) : null] }));
|
|
115
|
+
}, className: "nodrag absolute top-1/2 left-1/2 flex h-6 w-6 -translate-x-1/2 -translate-y-1/2 cursor-pointer items-center justify-center rounded-full bg-blue-500 text-white opacity-0 shadow-md transition-opacity group-hover:opacity-100 hover:bg-blue-600", children: _jsx(Plus, { className: "h-3.5 w-3.5" }) }) })) : data.showHandles ? (_jsx(Handle, { type: "source", position: Position.Right, isConnectable: false, className: "opacity-0!", style: { top: 70 } })) : null] }));
|
|
116
116
|
}
|
package/dist/src/presentation/web/components/common/prd-questionnaire/prd-questionnaire.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prd-questionnaire.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/prd-questionnaire/prd-questionnaire.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAExE,wBAAgB,gBAAgB,CAAC,EAC/B,IAAI,EACJ,UAAU,EACV,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,YAAoB,EACpB,WAAmB,EACnB,UAAkB,EAClB,SAAS,EACT,iBAAiB,GAClB,EAAE,qBAAqB,
|
|
1
|
+
{"version":3,"file":"prd-questionnaire.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/prd-questionnaire/prd-questionnaire.tsx"],"names":[],"mappings":"AASA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,4BAA4B,CAAC;AAExE,wBAAgB,gBAAgB,CAAC,EAC/B,IAAI,EACJ,UAAU,EACV,QAAQ,EACR,SAAS,EACT,QAAQ,EACR,YAAoB,EACpB,WAAmB,EACnB,UAAkB,EAClB,SAAS,EACT,iBAAiB,GAClB,EAAE,qBAAqB,kDAuLvB"}
|
|
@@ -33,7 +33,7 @@ export function PrdQuestionnaire({ data, selections, onSelect, onApprove, onReje
|
|
|
33
33
|
} }, q.id))) })] }), _jsx("div", { className: "space-y-2", children: currentQuestion.options.map((opt, optIdx) => {
|
|
34
34
|
const selected = selections[currentQuestion.id] === opt.id;
|
|
35
35
|
const letter = String.fromCharCode(65 + optIdx);
|
|
36
|
-
return (_jsx("button", { type: "button", className: cn('border-border w-full rounded-md border px-3 py-3 text-left text-xs transition-all', 'hover:border-primary/70 hover:bg-primary/5 group', selected && 'border-primary bg-primary/5', opt.isNew && 'animate-option-highlight'), disabled: isProcessing, onClick: () => handleSelect(currentQuestion.id, opt.id), children: _jsxs("div", { className: "flex items-start gap-2", children: [_jsxs("span", { className: "text-muted-foreground mt-0.5 font-mono text-xs", children: [letter, "."] }), _jsxs("div", { className: "flex-1", children: [
|
|
36
|
+
return (_jsx("button", { type: "button", className: cn('border-border w-full overflow-hidden rounded-md border px-3 py-3 text-left text-xs transition-all', 'hover:border-primary/70 hover:bg-primary/5 group', selected && 'border-primary bg-primary/5', opt.isNew && 'animate-option-highlight'), disabled: isProcessing, onClick: () => handleSelect(currentQuestion.id, opt.id), children: _jsxs("div", { className: "flex items-start gap-2", children: [_jsxs("span", { className: "text-muted-foreground mt-0.5 font-mono text-xs", children: [letter, "."] }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("div", { className: "text-foreground mb-0.5 text-xs font-semibold wrap-break-word", children: opt.label }), _jsx("div", { className: "text-muted-foreground text-xs leading-snug", children: opt.rationale })] }), opt.recommended || opt.isNew ? (_jsx("div", { className: "shrink-0 pt-0.5", children: opt.recommended ? (_jsx(Badge, { className: "px-1.5 py-0 text-[10px] whitespace-nowrap", children: "AI Recommended" })) : (_jsx(Badge, { className: "border-transparent bg-emerald-600 px-1.5 py-0 text-[10px] whitespace-nowrap text-white hover:bg-emerald-600/80", children: "New" })) })) : null] }) }, opt.id));
|
|
37
37
|
}) })] }), _jsxs("div", { className: "flex items-center justify-between pt-2", children: [_jsxs(Button, { type: "button", variant: "ghost", size: "sm", disabled: isFirstStep || isProcessing, onClick: () => {
|
|
38
38
|
navigateSound.play();
|
|
39
39
|
setCurrentStep((s) => s - 1);
|
package/dist/src/presentation/web/components/common/prd-questionnaire/prd-questionnaire.stories.d.ts
CHANGED
|
@@ -17,4 +17,10 @@ export declare const MinimalData: Story;
|
|
|
17
17
|
export declare const WithRejectButton: Story;
|
|
18
18
|
/** Rejecting state — reject button disabled with spinner while reject action is in flight. */
|
|
19
19
|
export declare const RejectingState: Story;
|
|
20
|
+
/** Real-world LLM provider question — reproduces exact label text from the reported bug. Badge must stay on one line. */
|
|
21
|
+
export declare const LlmProviderQuestion: Story;
|
|
22
|
+
/** Pathological overflow — label with no natural word break (repeating token). Verifies button does not overflow panel. */
|
|
23
|
+
export declare const RepeatingLabelOverflow: Story;
|
|
24
|
+
/** Long labels — verifies that AI Recommended badge stays on one line even with very long option labels. Uses 640px width to match real panel width. */
|
|
25
|
+
export declare const LongLabels: Story;
|
|
20
26
|
//# sourceMappingURL=prd-questionnaire.stories.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"prd-questionnaire.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/prd-questionnaire/prd-questionnaire.stories.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAiKvD,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,gBAAgB,CAkBvC,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAU/C,sJAAsJ;AACtJ,eAAO,MAAM,OAAO,EAAE,KAErB,CAAC;AAEF,2EAA2E;AAC3E,eAAO,MAAM,cAAc,EAAE,KAW5B,CAAC;AAEF,uEAAuE;AACvE,eAAO,MAAM,WAAW,EAAE,KAczB,CAAC;AAEF,0EAA0E;AAC1E,eAAO,MAAM,QAAQ,EAAE,KAStB,CAAC;AAEF,uDAAuD;AACvD,eAAO,MAAM,WAAW,EAAE,KA8BzB,CAAC;AAaF,4DAA4D;AAC5D,eAAO,MAAM,gBAAgB,EAAE,KAQ9B,CAAC;AAEF,8FAA8F;AAC9F,eAAO,MAAM,cAAc,EAAE,KAO5B,CAAC"}
|
|
1
|
+
{"version":3,"file":"prd-questionnaire.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/prd-questionnaire/prd-questionnaire.stories.tsx"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAiKvD,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,gBAAgB,CAkBvC,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAU/C,sJAAsJ;AACtJ,eAAO,MAAM,OAAO,EAAE,KAErB,CAAC;AAEF,2EAA2E;AAC3E,eAAO,MAAM,cAAc,EAAE,KAW5B,CAAC;AAEF,uEAAuE;AACvE,eAAO,MAAM,WAAW,EAAE,KAczB,CAAC;AAEF,0EAA0E;AAC1E,eAAO,MAAM,QAAQ,EAAE,KAStB,CAAC;AAEF,uDAAuD;AACvD,eAAO,MAAM,WAAW,EAAE,KA8BzB,CAAC;AAaF,4DAA4D;AAC5D,eAAO,MAAM,gBAAgB,EAAE,KAQ9B,CAAC;AAEF,8FAA8F;AAC9F,eAAO,MAAM,cAAc,EAAE,KAO5B,CAAC;AAEF,yHAAyH;AACzH,eAAO,MAAM,mBAAmB,EAAE,KAuCjC,CAAC;AAEF,2HAA2H;AAC3H,eAAO,MAAM,sBAAsB,EAAE,KAiCpC,CAAC;AAEF,wJAAwJ;AACxJ,eAAO,MAAM,UAAU,EAAE,KAyCxB,CAAC"}
|
package/dist/src/presentation/web/components/common/prd-questionnaire/prd-questionnaire.stories.js
CHANGED
|
@@ -154,7 +154,7 @@ const meta = {
|
|
|
154
154
|
onApprove: { action: 'onApprove' },
|
|
155
155
|
},
|
|
156
156
|
decorators: [
|
|
157
|
-
(Story) => (_jsx("div", { style: { height: '600px', width: '
|
|
157
|
+
(Story) => (_jsx("div", { style: { height: '600px', width: '760px', border: '1px solid var(--color-border)' }, children: _jsx(Story, {}) })),
|
|
158
158
|
],
|
|
159
159
|
};
|
|
160
160
|
export default meta;
|
|
@@ -248,3 +248,98 @@ export const RejectingState = {
|
|
|
248
248
|
isRejecting: true,
|
|
249
249
|
},
|
|
250
250
|
};
|
|
251
|
+
/** Real-world LLM provider question — reproduces exact label text from the reported bug. Badge must stay on one line. */
|
|
252
|
+
export const LlmProviderQuestion = {
|
|
253
|
+
render: () => (_jsx(InteractiveQuestionnaire, { data: {
|
|
254
|
+
question: 'Review Feature Requirements',
|
|
255
|
+
context: 'Testing badge nowrap with real-world LLM provider labels.',
|
|
256
|
+
questions: [
|
|
257
|
+
{
|
|
258
|
+
id: 'llm-provider',
|
|
259
|
+
question: 'Which LLM provider should be the primary AI engine?',
|
|
260
|
+
type: 'select',
|
|
261
|
+
options: [
|
|
262
|
+
{
|
|
263
|
+
id: 'claude-primary',
|
|
264
|
+
label: 'Claude (Anthropic) as primary for all AI tasks including vision/OCR, OpenAI as fallback LLM',
|
|
265
|
+
rationale: 'Claude is used as the primary engine for all AI tasks: structured reasoning, signal interpretation, opportunity scoring, AND vision/OCR for flyer image extraction.',
|
|
266
|
+
recommended: true,
|
|
267
|
+
},
|
|
268
|
+
{
|
|
269
|
+
id: 'split',
|
|
270
|
+
label: 'Claude (Anthropic) for reasoning, OpenAI Vision for OCR',
|
|
271
|
+
rationale: 'Split responsibilities: Claude for text reasoning tasks, OpenAI Vision API specifically for OCR/image analysis.',
|
|
272
|
+
},
|
|
273
|
+
{
|
|
274
|
+
id: 'single',
|
|
275
|
+
label: 'Single provider only (Claude OR OpenAI for everything)',
|
|
276
|
+
rationale: 'Simplifies implementation — one SDK, one billing relationship, one prompt format.',
|
|
277
|
+
},
|
|
278
|
+
],
|
|
279
|
+
},
|
|
280
|
+
],
|
|
281
|
+
finalAction: mockFinalAction,
|
|
282
|
+
} })),
|
|
283
|
+
};
|
|
284
|
+
/** Pathological overflow — label with no natural word break (repeating token). Verifies button does not overflow panel. */
|
|
285
|
+
export const RepeatingLabelOverflow = {
|
|
286
|
+
render: () => (_jsx(InteractiveQuestionnaire, { data: {
|
|
287
|
+
question: 'Where should the dark-mode preference be persisted?',
|
|
288
|
+
context: 'Testing overflow containment with no-break label text.',
|
|
289
|
+
questions: [
|
|
290
|
+
{
|
|
291
|
+
id: 'storage',
|
|
292
|
+
question: 'Where should the dark-mode preference be persisted?',
|
|
293
|
+
type: 'select',
|
|
294
|
+
options: [
|
|
295
|
+
{
|
|
296
|
+
id: 'localstorage',
|
|
297
|
+
label: 'localStorage only localStorage only localStorage only localStorage only localStorage only localStorage only',
|
|
298
|
+
rationale: 'Store the theme preference in localStorage. Zero backend changes, instant read on page load, and no need for API round-trips.',
|
|
299
|
+
recommended: true,
|
|
300
|
+
},
|
|
301
|
+
{
|
|
302
|
+
id: 'sqlite',
|
|
303
|
+
label: 'SQLite settings via backend API',
|
|
304
|
+
rationale: 'Persist the preference in the Shep SQLite settings store alongside other settings. Syncs across devices but requires API changes and a settings migration — out of scope for this feature.',
|
|
305
|
+
},
|
|
306
|
+
],
|
|
307
|
+
},
|
|
308
|
+
],
|
|
309
|
+
finalAction: mockFinalAction,
|
|
310
|
+
} })),
|
|
311
|
+
};
|
|
312
|
+
/** Long labels — verifies that AI Recommended badge stays on one line even with very long option labels. Uses 640px width to match real panel width. */
|
|
313
|
+
export const LongLabels = {
|
|
314
|
+
render: () => (_jsx(InteractiveQuestionnaire, { data: {
|
|
315
|
+
question: 'Review Feature Requirements',
|
|
316
|
+
context: 'Testing badge nowrap behavior with long option labels.',
|
|
317
|
+
questions: [
|
|
318
|
+
{
|
|
319
|
+
id: 'long-label',
|
|
320
|
+
question: 'Which deployment strategy should we use for the distributed microservices architecture?',
|
|
321
|
+
type: 'select',
|
|
322
|
+
options: [
|
|
323
|
+
{
|
|
324
|
+
id: 'opt-long-1',
|
|
325
|
+
label: 'Blue-Green Deployment with Automated Canary Analysis and Progressive Rollout',
|
|
326
|
+
rationale: 'Minimizes downtime and risk by running two identical production environments',
|
|
327
|
+
recommended: true,
|
|
328
|
+
},
|
|
329
|
+
{
|
|
330
|
+
id: 'opt-long-2',
|
|
331
|
+
label: 'Rolling Update with Health Check Verification and Automatic Rollback on Failure',
|
|
332
|
+
rationale: 'Gradually replaces instances with zero-downtime deployment',
|
|
333
|
+
},
|
|
334
|
+
{
|
|
335
|
+
id: 'opt-long-3',
|
|
336
|
+
label: 'Feature Flags with Percentage-Based Gradual Rollout to Target User Segments',
|
|
337
|
+
rationale: 'Enables targeted rollout and instant rollback via configuration',
|
|
338
|
+
isNew: true,
|
|
339
|
+
},
|
|
340
|
+
],
|
|
341
|
+
},
|
|
342
|
+
],
|
|
343
|
+
finalAction: mockFinalAction,
|
|
344
|
+
} })),
|
|
345
|
+
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"product-decisions-summary.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/product-decisions-summary/product-decisions-summary.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,4BAA4B,EAE7B,MAAM,oCAAoC,CAAC;
|
|
1
|
+
{"version":3,"file":"product-decisions-summary.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/product-decisions-summary/product-decisions-summary.tsx"],"names":[],"mappings":"AAIA,OAAO,KAAK,EACV,4BAA4B,EAE7B,MAAM,oCAAoC,CAAC;AA6B5C,wBAAgB,uBAAuB,CAAC,EAAE,IAAI,EAAE,EAAE,4BAA4B,kDAmB7E"}
|
|
@@ -3,7 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import { ClipboardList } from 'lucide-react';
|
|
4
4
|
import { Badge } from '../../ui/badge.js';
|
|
5
5
|
function ProductDecisionCard({ item, index }) {
|
|
6
|
-
return (_jsx("div", { className: "border-border rounded-lg border", children: _jsx("div", { className: "space-y-2 px-4 py-3", children: _jsxs("div", { className: "flex items-start gap-2.5", children: [_jsx("span", { className: "bg-primary text-primary-foreground flex h-6 w-6 shrink-0 items-center justify-center rounded-full text-xs font-bold", children: index + 1 }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("h3", { className: "text-foreground text-sm leading-tight font-semibold", children: item.question }), _jsxs("div", { className: "mt-1 flex items-center gap-2", children: [_jsx("p", { className: "text-muted-foreground text-xs", children: item.selectedOption }), item.wasRecommended ? (_jsx(Badge, { className: "px-1.5 py-0 text-[10px]", children: "AI Recommended" })) : null] })] })] }) }) }));
|
|
6
|
+
return (_jsx("div", { className: "border-border rounded-lg border", children: _jsx("div", { className: "space-y-2 px-4 py-3", children: _jsxs("div", { className: "flex items-start gap-2.5", children: [_jsx("span", { className: "bg-primary text-primary-foreground flex h-6 w-6 shrink-0 items-center justify-center rounded-full text-xs font-bold", children: index + 1 }), _jsxs("div", { className: "min-w-0 flex-1", children: [_jsx("h3", { className: "text-foreground text-sm leading-tight font-semibold", children: item.question }), _jsxs("div", { className: "mt-1 flex items-center gap-2", children: [_jsx("p", { className: "text-muted-foreground min-w-0 truncate text-xs", children: item.selectedOption }), item.wasRecommended ? (_jsx(Badge, { className: "shrink-0 px-1.5 py-0 text-[10px] whitespace-nowrap", children: "AI Recommended" })) : null] })] })] }) }) }));
|
|
7
7
|
}
|
|
8
8
|
export function ProductDecisionsSummary({ data }) {
|
|
9
9
|
const { questions } = data;
|