@shepai/cli 1.149.1 → 1.150.0-pr471.902d313
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/infrastructure/services/agents/feature-agent/nodes/evidence.node.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/evidence.node.js +2 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/fast-implement.node.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/fast-implement.node.js +11 -42
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/implement.node.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/implement.node.js +2 -3
- package/dist/src/presentation/web/components/common/control-center-drawer/feature-drawer-client.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/control-center-drawer/feature-drawer-client.js +29 -2
- package/dist/src/presentation/web/components/common/feature-drawer/use-feature-actions.d.ts +3 -0
- package/dist/src/presentation/web/components/common/feature-drawer/use-feature-actions.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/feature-drawer/use-feature-actions.js +32 -1
- package/dist/src/presentation/web/components/common/open-action-menu/open-action-menu.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/open-action-menu/open-action-menu.js +3 -3
- package/dist/src/presentation/web/components/common/open-action-menu/open-action-menu.stories.d.ts.map +1 -1
- package/dist/src/presentation/web/components/common/open-action-menu/open-action-menu.stories.js +3 -0
- 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 +18 -0
- 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 +3 -3
- package/web/.next/required-server-files.json +3 -3
- package/web/.next/server/app/(dashboard)/@drawer/adopt/page/server-reference-manifest.json +28 -28
- 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 +28 -28
- 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 +36 -36
- 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 +36 -36
- 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 +26 -26
- 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 +28 -28
- 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 +36 -36
- 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 +36 -36
- 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 +26 -26
- 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 +26 -26
- 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/[root-of-the-server]__a402b567._.js +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/[root-of-the-server]__2138fa7e._.js +2 -2
- package/web/.next/server/chunks/ssr/[root-of-the-server]__29580090._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__29580090._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__357d99f9._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__3ef34e4c._.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]__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]__aad040c0._.js +3 -3
- package/web/.next/server/chunks/ssr/[root-of-the-server]__aad040c0._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__c094882b._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__c094882b._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__d48c5b11._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__d48c5b11._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__dac5dbf1._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__dac5dbf1._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__fae8b355._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__fae8b355._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_05c23ad9._.js +1 -1
- package/web/.next/server/chunks/ssr/_05c23ad9._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_0c5f56e3._.js +2 -2
- package/web/.next/server/chunks/ssr/_0c5f56e3._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_16eb4fec._.js +1 -1
- package/web/.next/server/chunks/ssr/_16eb4fec._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_1b719e7f._.js +1 -1
- package/web/.next/server/chunks/ssr/_1b719e7f._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_37e8548b._.js +1 -1
- package/web/.next/server/chunks/ssr/_37e8548b._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_55d763e2._.js +1 -1
- package/web/.next/server/chunks/ssr/_55d763e2._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_6256a985._.js +1 -1
- package/web/.next/server/chunks/ssr/_6256a985._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_64bdfc6f._.js +2 -2
- package/web/.next/server/chunks/ssr/_64bdfc6f._.js.map +1 -1
- package/web/.next/server/chunks/ssr/_8fcc39d4._.js +1 -1
- package/web/.next/server/chunks/ssr/_9c5afe42._.js +3 -0
- package/web/.next/server/chunks/ssr/{_ee80b25c._.js.map → _9c5afe42._.js.map} +1 -1
- package/web/.next/server/chunks/ssr/_b71645b4._.js +1 -1
- package/web/.next/server/chunks/ssr/_b71645b4._.js.map +1 -1
- package/web/.next/server/chunks/ssr/{_2b873e3b._.js → _d6e950e9._.js} +2 -2
- package/web/.next/server/chunks/ssr/_d6e950e9._.js.map +1 -0
- 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/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_91545e86._.js → src_presentation_web_4821386e._.js} +2 -2
- package/web/.next/server/chunks/ssr/{src_presentation_web_91545e86._.js.map → src_presentation_web_4821386e._.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_app_actions_open-ide_ts_baaca5d5._.js +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 +44 -44
- package/web/.next/static/chunks/{932fdc72f19fba16.js → 29592ee94d1dfe16.js} +1 -1
- package/web/.next/static/chunks/2a69ae46f2d670d7.js +5 -0
- package/web/.next/static/chunks/{e23f0c8da44fe4ca.js → 49a66916caf0ada7.js} +1 -1
- package/web/.next/static/chunks/{42a1e8928c2a8b1e.js → 531213d3d708207f.js} +1 -1
- package/web/.next/static/chunks/6165454dbc7b6804.js +1 -0
- package/web/.next/static/chunks/{70917246e2079de0.js → 6e3377bb4787e6cb.js} +1 -1
- package/web/.next/static/chunks/{9522b3e38757bf73.js → 7ac8a1e723543fde.js} +1 -1
- package/web/.next/static/chunks/{ee210d2383098e91.js → 92c95676375f0e58.js} +2 -2
- package/web/.next/static/chunks/{213bc4d2c2c7885a.js → a624c0b71dd16424.js} +1 -1
- package/web/.next/static/chunks/{6b7b66ce14353296.js → c509c047eeefe599.js} +1 -1
- package/web/.next/static/chunks/{fbf933fea8dd21f4.js → cad7da3eb163aad3.js} +1 -1
- package/web/.next/static/chunks/{d3e9784c18cc85e9.js → ec9b83aaa577d5d8.js} +1 -1
- package/web/.next/server/chunks/ssr/_2b873e3b._.js.map +0 -1
- package/web/.next/server/chunks/ssr/_ee80b25c._.js +0 -3
- package/web/.next/static/chunks/c8c503403d49f600.js +0 -1
- package/web/.next/static/chunks/faf6b0ec1cf9125c.js +0 -5
- /package/web/.next/static/{0-b0NgavBiu5Fo1rzdeX2 → Wet2q3jRm5z9R1HGr5e3e}/_buildManifest.js +0 -0
- /package/web/.next/static/{0-b0NgavBiu5Fo1rzdeX2 → Wet2q3jRm5z9R1HGr5e3e}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{0-b0NgavBiu5Fo1rzdeX2 → Wet2q3jRm5z9R1HGr5e3e}/_ssgManifest.js +0 -0
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"evidence.node.d.ts","sourceRoot":"","sources":["../../../../../../../../../packages/core/src/infrastructure/services/agents/feature-agent/nodes/evidence.node.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+DAA+D,CAAC;AAEpG,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAqDrD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,cAAc,IAG3C,OAAO,iBAAiB,KAAG,OAAO,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,
|
|
1
|
+
{"version":3,"file":"evidence.node.d.ts","sourceRoot":"","sources":["../../../../../../../../../packages/core/src/infrastructure/services/agents/feature-agent/nodes/evidence.node.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;GAqBG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+DAA+D,CAAC;AAEpG,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAqDrD;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,cAAc,IAG3C,OAAO,iBAAiB,KAAG,OAAO,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAqJ7E"}
|
package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/evidence.node.js
CHANGED
|
@@ -82,8 +82,9 @@ export function createEvidenceNode(executor) {
|
|
|
82
82
|
};
|
|
83
83
|
}
|
|
84
84
|
// --- Configuration ---
|
|
85
|
+
// Use feature-level state for commitEvidence; fall back to global for retries config
|
|
86
|
+
const commitEvidence = state.commitEvidence;
|
|
85
87
|
const settings = hasSettings() ? getSettings() : undefined;
|
|
86
|
-
const commitEvidence = settings?.workflow.commitEvidence ?? false;
|
|
87
88
|
const maxRetries = settings?.workflow.evidenceRetries ?? DEFAULT_MAX_RETRIES;
|
|
88
89
|
const options = buildExecutorOptions(state);
|
|
89
90
|
const tasks = parseTasks(state.specDir);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"fast-implement.node.d.ts","sourceRoot":"","sources":["../../../../../../../../../packages/core/src/infrastructure/services/agents/feature-agent/nodes/fast-implement.node.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+DAA+D,CAAC;
|
|
1
|
+
{"version":3,"file":"fast-implement.node.d.ts","sourceRoot":"","sources":["../../../../../../../../../packages/core/src/infrastructure/services/agents/feature-agent/nodes/fast-implement.node.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAIH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+DAA+D,CAAC;AACpG,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAcrD;;;;;GAKG;AACH,wBAAgB,uBAAuB,CAAC,QAAQ,EAAE,cAAc,IAGhD,OAAO,iBAAiB,KAAG,OAAO,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,CA6F7E"}
|
|
@@ -11,14 +11,12 @@
|
|
|
11
11
|
*/
|
|
12
12
|
import { execSync } from 'node:child_process';
|
|
13
13
|
import { isGraphBubbleUp } from '@langchain/langgraph';
|
|
14
|
-
import { createNodeLogger, buildExecutorOptions, retryExecute, getCompletedPhases, markPhaseComplete,
|
|
14
|
+
import { createNodeLogger, buildExecutorOptions, retryExecute, getCompletedPhases, markPhaseComplete, } from './node-helpers.js';
|
|
15
15
|
import { reportNodeStart } from '../heartbeat.js';
|
|
16
16
|
import { recordPhaseStart, recordPhaseEnd } from '../phase-timing-context.js';
|
|
17
17
|
import { updateNodeLifecycle } from '../lifecycle-context.js';
|
|
18
18
|
import { buildFastImplementPrompt } from './prompts/fast-implement.prompt.js';
|
|
19
|
-
import {
|
|
20
|
-
import { parseEvidenceRecords } from './evidence-output-parser.js';
|
|
21
|
-
import { hasSettings, getSettings } from '../../../settings.service.js';
|
|
19
|
+
import { createEvidenceNode } from './evidence.node.js';
|
|
22
20
|
/**
|
|
23
21
|
* Factory that creates the fast-implement node function.
|
|
24
22
|
*
|
|
@@ -62,11 +60,15 @@ export function createFastImplementNode(executor) {
|
|
|
62
60
|
if (!hasWorktreeChanges(cwd) && !hasNewCommits(cwd)) {
|
|
63
61
|
throw new Error('[fast-implement] Agent produced no file changes — it may have entered plan mode or asked questions instead of implementing. Retrying.');
|
|
64
62
|
}
|
|
65
|
-
// --- Evidence sub-agent: capture proof of completion (
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
63
|
+
// --- Evidence sub-agent: capture proof of completion (feature-gated) ---
|
|
64
|
+
let evidence = [];
|
|
65
|
+
if (state.enableEvidence) {
|
|
66
|
+
const evidenceNode = createEvidenceNode(executor);
|
|
67
|
+
const evidenceResult = await evidenceNode(state);
|
|
68
|
+
evidence = evidenceResult.evidence ?? [];
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
log.info('Evidence collection disabled — skipping');
|
|
70
72
|
}
|
|
71
73
|
await recordPhaseEnd(timingId, durationMs, {
|
|
72
74
|
inputTokens: result.usage?.inputTokens,
|
|
@@ -106,39 +108,6 @@ export function createFastImplementNode(executor) {
|
|
|
106
108
|
}
|
|
107
109
|
};
|
|
108
110
|
}
|
|
109
|
-
/**
|
|
110
|
-
* Sub-agent call to collect evidence after fast implementation completes.
|
|
111
|
-
* Graceful degradation: returns empty array on any failure so evidence
|
|
112
|
-
* collection never blocks the workflow.
|
|
113
|
-
*/
|
|
114
|
-
async function collectEvidence(executor, state, log) {
|
|
115
|
-
try {
|
|
116
|
-
log.info('Collecting evidence (sub-agent)');
|
|
117
|
-
const commitEvidence = hasSettings() && getSettings().workflow.commitEvidence;
|
|
118
|
-
const prompt = buildEvidencePrompt(state, { commitEvidence });
|
|
119
|
-
const options = buildExecutorOptions(state);
|
|
120
|
-
const result = await retryExecute(executor, prompt, options, { logger: log });
|
|
121
|
-
try {
|
|
122
|
-
const evidence = parseEvidenceRecords(result.result);
|
|
123
|
-
log.info(`Parsed ${evidence.length} evidence record(s)`);
|
|
124
|
-
saveEvidenceManifest(state, evidence, log);
|
|
125
|
-
return evidence;
|
|
126
|
-
}
|
|
127
|
-
catch (parseErr) {
|
|
128
|
-
const msg = parseErr instanceof Error ? parseErr.message : String(parseErr);
|
|
129
|
-
log.error(`Warning: evidence parsing failed: ${msg} — continuing with empty evidence`);
|
|
130
|
-
return [];
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
catch (err) {
|
|
134
|
-
// Re-throw LangGraph control-flow exceptions
|
|
135
|
-
if (isGraphBubbleUp(err))
|
|
136
|
-
throw err;
|
|
137
|
-
const msg = err instanceof Error ? err.message : String(err);
|
|
138
|
-
log.error(`Evidence collection failed: ${msg} — continuing without evidence`);
|
|
139
|
-
return [];
|
|
140
|
-
}
|
|
141
|
-
}
|
|
142
111
|
/**
|
|
143
112
|
* Check whether the worktree has any uncommitted changes (new, modified, or deleted files).
|
|
144
113
|
* Uses `git status --porcelain` which outputs one line per changed file, or empty if clean.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"implement.node.d.ts","sourceRoot":"","sources":["../../../../../../../../../packages/core/src/infrastructure/services/agents/feature-agent/nodes/implement.node.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+DAA+D,CAAC;AACpG,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;
|
|
1
|
+
{"version":3,"file":"implement.node.d.ts","sourceRoot":"","sources":["../../../../../../../../../packages/core/src/infrastructure/services/agents/feature-agent/nodes/implement.node.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+DAA+D,CAAC;AACpG,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AAoErD,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,cAAc,IAG5C,OAAO,iBAAiB,KAAG,OAAO,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAiQ7E"}
|
package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/implement.node.js
CHANGED
|
@@ -16,7 +16,6 @@ import { recordPhaseStart, recordPhaseEnd, recordApprovalWaitStart, updatePhaseP
|
|
|
16
16
|
import { updateNodeLifecycle } from '../lifecycle-context.js';
|
|
17
17
|
import { buildImplementPhasePrompt, } from './prompts/implement.prompt.js';
|
|
18
18
|
import { createEvidenceNode } from './evidence.node.js';
|
|
19
|
-
import { hasSettings, getSettings } from '../../../settings.service.js';
|
|
20
19
|
/**
|
|
21
20
|
* Update feature.yaml with current implementation progress.
|
|
22
21
|
* Silently no-ops if the file is missing or unparseable.
|
|
@@ -190,8 +189,8 @@ export function createImplementNode(executor) {
|
|
|
190
189
|
log.info(`All phases complete — ${completedTasks}/${totalTasks} tasks (${elapsed}s)`);
|
|
191
190
|
updateFeatureProgress(state.specDir, totalTasks, totalTasks, 'implementation-complete', null, log);
|
|
192
191
|
messages.push(`[implement] Complete: ${totalTasks} tasks across ${totalPhases} phases (${elapsed}s)`);
|
|
193
|
-
// --- Evidence sub-agent: capture proof of completion (
|
|
194
|
-
const evidenceEnabled =
|
|
192
|
+
// --- Evidence sub-agent: capture proof of completion (feature-gated) ---
|
|
193
|
+
const evidenceEnabled = state.enableEvidence;
|
|
195
194
|
let evidenceResult = {};
|
|
196
195
|
if (evidenceEnabled) {
|
|
197
196
|
const evidenceNode = createEvidenceNode(executor);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"feature-drawer-client.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/control-center-drawer/feature-drawer-client.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"feature-drawer-client.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/control-center-drawer/feature-drawer-client.tsx"],"names":[],"mappings":"AAkDA,OAAO,KAAK,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AAK/D,MAAM,WAAW,wBAAwB;IACvC,IAAI,EAAE,UAAU,CAAC;IACjB,8FAA8F;IAC9F,MAAM,CAAC,EAAE,aAAa,CAAC;CACxB;AAED,wBAAgB,mBAAmB,CAAC,EAAE,IAAI,EAAE,WAAW,EAAE,MAAM,EAAE,EAAE,wBAAwB,2CAsuB1F"}
|
package/dist/src/presentation/web/components/common/control-center-drawer/feature-drawer-client.js
CHANGED
|
@@ -3,7 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
3
3
|
import { useState, useCallback, useEffect, useRef } from 'react';
|
|
4
4
|
import { useRouter, usePathname } from 'next/navigation';
|
|
5
5
|
import { toast } from 'sonner';
|
|
6
|
-
import { Loader2, Trash2, Play, Square, Copy, Check, Code2, ExternalLink } from 'lucide-react';
|
|
6
|
+
import { Loader2, Trash2, Play, Square, Copy, Check, Code2, ExternalLink, Archive, ArchiveRestore, } from 'lucide-react';
|
|
7
7
|
import { approveFeature } from '../../../app/actions/approve-feature.js';
|
|
8
8
|
import { resumeFeature } from '../../../app/actions/resume-feature.js';
|
|
9
9
|
import { startFeature } from '../../../app/actions/start-feature.js';
|
|
@@ -106,6 +106,19 @@ export function FeatureDrawerClient({ view: initialView, urlTab }) {
|
|
|
106
106
|
// ── Delete state ───────────────────────────────────────────────────────
|
|
107
107
|
const [isDeleting, setIsDeleting] = useState(false);
|
|
108
108
|
const [deleteDialogOpen, setDeleteDialogOpen] = useState(false);
|
|
109
|
+
// ── Archive state ─────────────────────────────────────────────────────
|
|
110
|
+
const [isArchiving, setIsArchiving] = useState(false);
|
|
111
|
+
// Reset archive loading spinner when the feature state or feature ID
|
|
112
|
+
// changes (e.g. state flips to 'archived' / 'done' after the server
|
|
113
|
+
// action, or the user navigates to a different feature drawer).
|
|
114
|
+
const archiveResetKey = `${featureNode?.featureId}:${featureNode?.state}`;
|
|
115
|
+
const prevArchiveResetKeyRef = useRef(archiveResetKey);
|
|
116
|
+
useEffect(() => {
|
|
117
|
+
if (archiveResetKey !== prevArchiveResetKeyRef.current) {
|
|
118
|
+
prevArchiveResetKeyRef.current = archiveResetKey;
|
|
119
|
+
setIsArchiving(false);
|
|
120
|
+
}
|
|
121
|
+
}, [archiveResetKey]);
|
|
109
122
|
// ── Shared reject state ────────────────────────────────────────────────
|
|
110
123
|
const [isRejecting, setIsRejecting] = useState(false);
|
|
111
124
|
const isRejectingRef = useRef(false);
|
|
@@ -290,6 +303,20 @@ export function FeatureDrawerClient({ view: initialView, urlTab }) {
|
|
|
290
303
|
}));
|
|
291
304
|
router.push('/');
|
|
292
305
|
}, [router]);
|
|
306
|
+
const handleArchive = useCallback((featureId) => {
|
|
307
|
+
setIsArchiving(true);
|
|
308
|
+
window.dispatchEvent(new CustomEvent('shep:feature-archive-requested', {
|
|
309
|
+
detail: { featureId },
|
|
310
|
+
}));
|
|
311
|
+
router.push('/');
|
|
312
|
+
}, [router]);
|
|
313
|
+
const handleUnarchive = useCallback((featureId) => {
|
|
314
|
+
setIsArchiving(true);
|
|
315
|
+
window.dispatchEvent(new CustomEvent('shep:feature-unarchive-requested', {
|
|
316
|
+
detail: { featureId },
|
|
317
|
+
}));
|
|
318
|
+
router.push('/');
|
|
319
|
+
}, [router]);
|
|
293
320
|
const handleRetry = useCallback(async (featureId) => {
|
|
294
321
|
const result = await resumeFeature(featureId);
|
|
295
322
|
if (result.error) {
|
|
@@ -376,7 +403,7 @@ export function FeatureDrawerClient({ view: initialView, urlTab }) {
|
|
|
376
403
|
const repoName = featureNode.repositoryName ??
|
|
377
404
|
featureNode.repositoryPath.split('/').filter(Boolean).at(-1) ??
|
|
378
405
|
'';
|
|
379
|
-
header = (_jsxs(_Fragment, { children: [_jsxs("div", { "data-testid": "feature-drawer-header", children: [_jsx(DrawerTitle, { children: featureNode.name }), repoName ? (_jsxs("div", { className: "flex items-center gap-1.5 pt-0.5", children: [_jsx(Code2, { className: "text-muted-foreground size-3.5 shrink-0" }), featureNode.remoteUrl ? (_jsxs("a", { href: featureNode.remoteUrl, target: "_blank", rel: "noopener noreferrer", className: "text-muted-foreground hover:text-foreground inline-flex items-center gap-1 text-xs transition-colors", "data-testid": "feature-drawer-repo-link", children: [repoName, _jsx(ExternalLink, { className: "size-3" })] })) : (_jsx("span", { className: "text-muted-foreground text-xs", children: repoName }))] })) : null, _jsx(DrawerDescription, { className: "sr-only", children: featureNode.name })] }), featureActionsInput ? (_jsxs("div", { className: "flex items-center gap-2 pt-2", "data-testid": "feature-drawer-actions", children: [_jsx(OpenActionMenu, { actions: featureActions, repositoryPath: featureActionsInput.repositoryPath, worktreePath: featureActionsInput.worktreePath, showSpecs: !!featureActionsInput.specPath }), featureFlags.envDeploy && featureDeployTarget ? (_jsxs(_Fragment, { children: [_jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("span", { children: _jsx(ActionButton, { label: isFeatureDeployActive ? 'Stop Dev Server' : 'Start Dev Server', onClick: isFeatureDeployActive ? deployAction.stop : deployAction.deploy, loading: deployAction.deployLoading || deployAction.stopLoading, error: !!deployAction.deployError, icon: isFeatureDeployActive ? Square : Play, iconOnly: true, variant: "outline", size: "icon-sm" }) }) }), _jsx(TooltipContent, { children: isFeatureDeployActive ? 'Stop Dev Server' : 'Start Dev Server' })] }) }), isFeatureDeployActive ? (_jsx(DeploymentStatusBadge, { status: deployAction.status, url: deployAction.url, targetId: featureDeployTarget?.targetId })) : null] })) : null, _jsxs("div", { className: "ml-auto flex items-center gap-1.5", children: [_jsx("code", { className: "bg-muted text-muted-foreground rounded px-1.5 py-0.5 font-mono text-xs", children: shortId }), _jsx("button", { type: "button", onClick: handleCopyId, className: "text-muted-foreground hover:text-foreground inline-flex items-center rounded p-0.5 transition-colors", "aria-label": "Copy feature ID", "data-testid": "feature-drawer-copy-id", children: idCopied ? (_jsx(Check, { className: "size-3.5 text-green-600" })) : (_jsx(Copy, { className: "size-3.5" })) })] }), featureNode.featureId ? (_jsxs(_Fragment, { children: [_jsx(Button, { variant: "ghost", size: "icon-sm", "aria-label": "Delete feature", disabled: isDeleting, className: "text-muted-foreground hover:text-destructive", "data-testid": "feature-drawer-delete", onClick: () => setDeleteDialogOpen(true), children: isDeleting ? (_jsx(Loader2, { className: "size-4 animate-spin" })) : (_jsx(Trash2, { className: "size-4" })) }), _jsx(DeleteFeatureDialog, { open: deleteDialogOpen, onOpenChange: setDeleteDialogOpen, onConfirm: (cleanup, cascadeDelete, closePr) => handleDelete(featureNode.featureId, cleanup, cascadeDelete, closePr), isDeleting: isDeleting, featureName: featureNode.name, featureId: featureNode.featureId, hasChildren: featureNode.hasChildren, hasOpenPr: !!featureNode.pr && featureNode.pr.status === 'Open' })] })) : null] })) : null] }));
|
|
406
|
+
header = (_jsxs(_Fragment, { children: [_jsxs("div", { "data-testid": "feature-drawer-header", children: [_jsx(DrawerTitle, { children: featureNode.name }), repoName ? (_jsxs("div", { className: "flex items-center gap-1.5 pt-0.5", children: [_jsx(Code2, { className: "text-muted-foreground size-3.5 shrink-0" }), featureNode.remoteUrl ? (_jsxs("a", { href: featureNode.remoteUrl, target: "_blank", rel: "noopener noreferrer", className: "text-muted-foreground hover:text-foreground inline-flex items-center gap-1 text-xs transition-colors", "data-testid": "feature-drawer-repo-link", children: [repoName, _jsx(ExternalLink, { className: "size-3" })] })) : (_jsx("span", { className: "text-muted-foreground text-xs", children: repoName }))] })) : null, _jsx(DrawerDescription, { className: "sr-only", children: featureNode.name })] }), featureActionsInput ? (_jsxs("div", { className: "flex items-center gap-2 pt-2", "data-testid": "feature-drawer-actions", children: [featureNode?.state !== 'done' ? (_jsx(OpenActionMenu, { actions: featureActions, repositoryPath: featureActionsInput.repositoryPath, worktreePath: featureActionsInput.worktreePath, showSpecs: !!featureActionsInput.specPath })) : null, featureNode?.state !== 'done' && featureFlags.envDeploy && featureDeployTarget ? (_jsxs(_Fragment, { children: [_jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx("span", { children: _jsx(ActionButton, { label: isFeatureDeployActive ? 'Stop Dev Server' : 'Start Dev Server', onClick: isFeatureDeployActive ? deployAction.stop : deployAction.deploy, loading: deployAction.deployLoading || deployAction.stopLoading, error: !!deployAction.deployError, icon: isFeatureDeployActive ? Square : Play, iconOnly: true, variant: "outline", size: "icon-sm" }) }) }), _jsx(TooltipContent, { children: isFeatureDeployActive ? 'Stop Dev Server' : 'Start Dev Server' })] }) }), isFeatureDeployActive ? (_jsx(DeploymentStatusBadge, { status: deployAction.status, url: deployAction.url, targetId: featureDeployTarget?.targetId })) : null] })) : null, _jsxs("div", { className: "ml-auto flex items-center gap-1.5", children: [_jsx("code", { className: "bg-muted text-muted-foreground rounded px-1.5 py-0.5 font-mono text-xs", children: shortId }), _jsx("button", { type: "button", onClick: handleCopyId, className: "text-muted-foreground hover:text-foreground inline-flex items-center rounded p-0.5 transition-colors", "aria-label": "Copy feature ID", "data-testid": "feature-drawer-copy-id", children: idCopied ? (_jsx(Check, { className: "size-3.5 text-green-600" })) : (_jsx(Copy, { className: "size-3.5" })) })] }), featureNode.featureId ? (_jsxs(_Fragment, { children: [featureNode.state === 'archived' ? (_jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(Button, { variant: "ghost", size: "icon-sm", "aria-label": "Unarchive feature", disabled: isArchiving, className: "text-muted-foreground hover:text-primary", "data-testid": "feature-drawer-unarchive", onClick: () => handleUnarchive(featureNode.featureId), children: isArchiving ? (_jsx(Loader2, { className: "size-4 animate-spin" })) : (_jsx(ArchiveRestore, { className: "size-4" })) }) }), _jsx(TooltipContent, { children: "Unarchive feature" })] }) })) : featureNode.state !== 'deleting' ? (_jsx(TooltipProvider, { children: _jsxs(Tooltip, { children: [_jsx(TooltipTrigger, { asChild: true, children: _jsx(Button, { variant: "ghost", size: "icon-sm", "aria-label": "Archive feature", disabled: isArchiving, className: "text-muted-foreground hover:text-foreground", "data-testid": "feature-drawer-archive", onClick: () => handleArchive(featureNode.featureId), children: isArchiving ? (_jsx(Loader2, { className: "size-4 animate-spin" })) : (_jsx(Archive, { className: "size-4" })) }) }), _jsx(TooltipContent, { children: "Archive feature" })] }) })) : null, _jsx(Button, { variant: "ghost", size: "icon-sm", "aria-label": "Delete feature", disabled: isDeleting, className: "text-muted-foreground hover:text-destructive", "data-testid": "feature-drawer-delete", onClick: () => setDeleteDialogOpen(true), children: isDeleting ? (_jsx(Loader2, { className: "size-4 animate-spin" })) : (_jsx(Trash2, { className: "size-4" })) }), _jsx(DeleteFeatureDialog, { open: deleteDialogOpen, onOpenChange: setDeleteDialogOpen, onConfirm: (cleanup, cascadeDelete, closePr) => handleDelete(featureNode.featureId, cleanup, cascadeDelete, closePr), isDeleting: isDeleting, featureName: featureNode.name, featureId: featureNode.featureId, hasChildren: featureNode.hasChildren, hasOpenPr: !!featureNode.pr && featureNode.pr.status === 'Open' })] })) : null] })) : null] }));
|
|
380
407
|
}
|
|
381
408
|
// ── Body ──────────────────────────────────────────────────────────────
|
|
382
409
|
let body = null;
|
|
@@ -8,14 +8,17 @@ export interface FeatureActionsInput {
|
|
|
8
8
|
export interface FeatureActionsState {
|
|
9
9
|
openInIde: () => Promise<void>;
|
|
10
10
|
openInShell: () => Promise<void>;
|
|
11
|
+
openFolder: () => Promise<void>;
|
|
11
12
|
openSpecsFolder: () => Promise<void>;
|
|
12
13
|
rebaseOnMain: () => Promise<void>;
|
|
13
14
|
ideLoading: boolean;
|
|
14
15
|
shellLoading: boolean;
|
|
16
|
+
folderLoading: boolean;
|
|
15
17
|
specsLoading: boolean;
|
|
16
18
|
rebaseLoading: boolean;
|
|
17
19
|
ideError: string | null;
|
|
18
20
|
shellError: string | null;
|
|
21
|
+
folderError: string | null;
|
|
19
22
|
specsError: string | null;
|
|
20
23
|
rebaseError: string | null;
|
|
21
24
|
}
|
package/dist/src/presentation/web/components/common/feature-drawer/use-feature-actions.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-feature-actions.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-drawer/use-feature-actions.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,WAAW,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,eAAe,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,YAAY,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC,UAAU,EAAE,OAAO,CAAC;IACpB,YAAY,EAAE,OAAO,CAAC;IACtB,YAAY,EAAE,OAAO,CAAC;IACtB,aAAa,EAAE,OAAO,CAAC;IACvB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAID,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,mBAAmB,GAAG,IAAI,GAAG,mBAAmB,
|
|
1
|
+
{"version":3,"file":"use-feature-actions.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/feature-drawer/use-feature-actions.ts"],"names":[],"mappings":"AAQA,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,MAAM,EAAE,MAAM,CAAC;IACf,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,QAAQ,CAAC,EAAE,MAAM,CAAC;CACnB;AAED,MAAM,WAAW,mBAAmB;IAClC,SAAS,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAC/B,WAAW,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACjC,UAAU,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAChC,eAAe,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,YAAY,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IAClC,UAAU,EAAE,OAAO,CAAC;IACpB,YAAY,EAAE,OAAO,CAAC;IACtB,aAAa,EAAE,OAAO,CAAC;IACvB,YAAY,EAAE,OAAO,CAAC;IACtB,aAAa,EAAE,OAAO,CAAC;IACvB,QAAQ,EAAE,MAAM,GAAG,IAAI,CAAC;IACxB,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;IAC3B,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,WAAW,EAAE,MAAM,GAAG,IAAI,CAAC;CAC5B;AAID,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,mBAAmB,GAAG,IAAI,GAAG,mBAAmB,CA6KxF"}
|
|
@@ -8,20 +8,23 @@ const ERROR_CLEAR_DELAY = 5000;
|
|
|
8
8
|
export function useFeatureActions(input) {
|
|
9
9
|
const [ideLoading, setIdeLoading] = useState(false);
|
|
10
10
|
const [shellLoading, setShellLoading] = useState(false);
|
|
11
|
+
const [folderLoading, setFolderLoading] = useState(false);
|
|
11
12
|
const [specsLoading, setSpecsLoading] = useState(false);
|
|
12
13
|
const [rebaseLoading, setRebaseLoading] = useState(false);
|
|
13
14
|
const [ideError, setIdeError] = useState(null);
|
|
14
15
|
const [shellError, setShellError] = useState(null);
|
|
16
|
+
const [folderError, setFolderError] = useState(null);
|
|
15
17
|
const [specsError, setSpecsError] = useState(null);
|
|
16
18
|
const [rebaseError, setRebaseError] = useState(null);
|
|
17
19
|
const ideTimerRef = useRef(null);
|
|
18
20
|
const shellTimerRef = useRef(null);
|
|
21
|
+
const folderTimerRef = useRef(null);
|
|
19
22
|
const specsTimerRef = useRef(null);
|
|
20
23
|
const rebaseTimerRef = useRef(null);
|
|
21
24
|
// Clear timers on unmount — read .current inside cleanup so we get the
|
|
22
25
|
// actual timer value at teardown time, not the always-null value at mount.
|
|
23
26
|
useEffect(() => {
|
|
24
|
-
const refs = [ideTimerRef, shellTimerRef, specsTimerRef, rebaseTimerRef];
|
|
27
|
+
const refs = [ideTimerRef, shellTimerRef, folderTimerRef, specsTimerRef, rebaseTimerRef];
|
|
25
28
|
return () => {
|
|
26
29
|
for (const ref of refs) {
|
|
27
30
|
if (ref.current)
|
|
@@ -59,6 +62,31 @@ export function useFeatureActions(input) {
|
|
|
59
62
|
}, [input]);
|
|
60
63
|
const handleOpenIde = useCallback(() => performAction(openIde, setIdeLoading, setIdeError, ideTimerRef, ideLoading), [performAction, ideLoading]);
|
|
61
64
|
const handleOpenShell = useCallback(() => performAction(openShell, setShellLoading, setShellError, shellTimerRef, shellLoading), [performAction, shellLoading]);
|
|
65
|
+
const handleOpenFolder = useCallback(async () => {
|
|
66
|
+
if (!input || folderLoading)
|
|
67
|
+
return;
|
|
68
|
+
if (folderTimerRef.current)
|
|
69
|
+
clearTimeout(folderTimerRef.current);
|
|
70
|
+
setFolderLoading(true);
|
|
71
|
+
setFolderError(null);
|
|
72
|
+
try {
|
|
73
|
+
const folderPath = input.worktreePath ?? input.repositoryPath;
|
|
74
|
+
const result = await openFolder(folderPath);
|
|
75
|
+
if (!result.success) {
|
|
76
|
+
const errorMessage = result.error ?? 'An unexpected error occurred';
|
|
77
|
+
setFolderError(errorMessage);
|
|
78
|
+
folderTimerRef.current = setTimeout(() => setFolderError(null), ERROR_CLEAR_DELAY);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
catch (err) {
|
|
82
|
+
const errorMessage = err instanceof Error ? err.message : 'An unexpected error occurred';
|
|
83
|
+
setFolderError(errorMessage);
|
|
84
|
+
folderTimerRef.current = setTimeout(() => setFolderError(null), ERROR_CLEAR_DELAY);
|
|
85
|
+
}
|
|
86
|
+
finally {
|
|
87
|
+
setFolderLoading(false);
|
|
88
|
+
}
|
|
89
|
+
}, [input, folderLoading]);
|
|
62
90
|
const handleOpenSpecsFolder = useCallback(async () => {
|
|
63
91
|
if (!input?.specPath || specsLoading)
|
|
64
92
|
return;
|
|
@@ -110,14 +138,17 @@ export function useFeatureActions(input) {
|
|
|
110
138
|
return {
|
|
111
139
|
openInIde: handleOpenIde,
|
|
112
140
|
openInShell: handleOpenShell,
|
|
141
|
+
openFolder: handleOpenFolder,
|
|
113
142
|
openSpecsFolder: handleOpenSpecsFolder,
|
|
114
143
|
rebaseOnMain: handleRebaseOnMain,
|
|
115
144
|
ideLoading,
|
|
116
145
|
shellLoading,
|
|
146
|
+
folderLoading,
|
|
117
147
|
specsLoading,
|
|
118
148
|
rebaseLoading,
|
|
119
149
|
ideError,
|
|
120
150
|
shellError,
|
|
151
|
+
folderError,
|
|
121
152
|
specsError,
|
|
122
153
|
rebaseError,
|
|
123
154
|
};
|
package/dist/src/presentation/web/components/common/open-action-menu/open-action-menu.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"open-action-menu.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/open-action-menu/open-action-menu.tsx"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAIpD,wBAAgB,cAAc,CAAC,EAC7B,OAAO,EACP,cAAc,EACd,YAAY,EACZ,SAAS,GACV,EAAE,mBAAmB,
|
|
1
|
+
{"version":3,"file":"open-action-menu.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/open-action-menu/open-action-menu.tsx"],"names":[],"mappings":"AAsBA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,UAAU,CAAC;AAIpD,wBAAgB,cAAc,CAAC,EAC7B,OAAO,EACP,cAAc,EACd,YAAY,EACZ,SAAS,GACV,EAAE,mBAAmB,2CAqGrB"}
|
|
@@ -12,7 +12,7 @@ export function OpenActionMenu({ actions, repositoryPath, worktreePath, showSpec
|
|
|
12
12
|
setCopied(true);
|
|
13
13
|
setTimeout(() => setCopied(false), COPY_FEEDBACK_DELAY);
|
|
14
14
|
};
|
|
15
|
-
const anyLoading = actions.ideLoading || actions.shellLoading || actions.specsLoading;
|
|
16
|
-
const anyError = actions.ideError ?? actions.shellError ?? actions.specsError;
|
|
17
|
-
return (_jsxs(DropdownMenu, { modal: false, children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsxs(Button, { variant: "outline", size: "sm", className: "gap-1.5", disabled: anyLoading, children: [anyLoading ? (_jsx(Loader2, { className: "size-4 animate-spin" })) : anyError ? (_jsx(CircleAlert, { className: "text-destructive size-4" })) : (_jsx(FolderOpen, { className: "size-4" })), "Open", _jsx(ChevronDown, { className: "size-3 opacity-60" })] }) }), _jsxs(DropdownMenuContent, { align: "start", className: "w-48", children: [_jsx(DropdownMenuLabel, { children: "Open in" }), _jsxs(DropdownMenuItem, { onClick: actions.openInIde, disabled: actions.ideLoading, className: "gap-2", children: [actions.ideLoading ? (_jsx(Loader2, { className: "size-4 animate-spin" })) : actions.ideError ? (_jsx(CircleAlert, { className: "text-destructive size-4" })) : (_jsx(Code2, { className: "size-4" })), "IDE"] }), _jsxs(DropdownMenuItem, { onClick: actions.openInShell, disabled: actions.shellLoading, className: "gap-2", children: [actions.shellLoading ? (_jsx(Loader2, { className: "size-4 animate-spin" })) : actions.shellError ? (_jsx(CircleAlert, { className: "text-destructive size-4" })) : (_jsx(Terminal, { className: "size-4" })), "Terminal"] }), _jsxs(DropdownMenuItem, { onClick: actions.openSpecsFolder, disabled: actions.specsLoading || !showSpecs, className: "gap-2", children: [actions.specsLoading ? (_jsx(Loader2, { className: "size-4 animate-spin" })) : actions.specsError ? (_jsx(CircleAlert, { className: "text-destructive size-4" })) : (_jsx(FolderOpen, { className: "size-4" })), "Specs Folder"] }), _jsx(DropdownMenuSeparator, {}), _jsxs(DropdownMenuItem, { onClick: handleCopyPath, className: "gap-2", children: [copied ? _jsx(Check, { className: "size-4 text-green-600" }) : _jsx(Copy, { className: "size-4" }), copied ? 'Copied!' : 'Copy path'] })] })] }));
|
|
15
|
+
const anyLoading = actions.ideLoading || actions.shellLoading || actions.folderLoading || actions.specsLoading;
|
|
16
|
+
const anyError = actions.ideError ?? actions.shellError ?? actions.folderError ?? actions.specsError;
|
|
17
|
+
return (_jsxs(DropdownMenu, { modal: false, children: [_jsx(DropdownMenuTrigger, { asChild: true, children: _jsxs(Button, { variant: "outline", size: "sm", className: "gap-1.5", disabled: anyLoading, children: [anyLoading ? (_jsx(Loader2, { className: "size-4 animate-spin" })) : anyError ? (_jsx(CircleAlert, { className: "text-destructive size-4" })) : (_jsx(FolderOpen, { className: "size-4" })), "Open", _jsx(ChevronDown, { className: "size-3 opacity-60" })] }) }), _jsxs(DropdownMenuContent, { align: "start", className: "w-48", children: [_jsx(DropdownMenuLabel, { children: "Open in" }), _jsxs(DropdownMenuItem, { onClick: actions.openInIde, disabled: actions.ideLoading, className: "gap-2", children: [actions.ideLoading ? (_jsx(Loader2, { className: "size-4 animate-spin" })) : actions.ideError ? (_jsx(CircleAlert, { className: "text-destructive size-4" })) : (_jsx(Code2, { className: "size-4" })), "IDE"] }), _jsxs(DropdownMenuItem, { onClick: actions.openInShell, disabled: actions.shellLoading, className: "gap-2", children: [actions.shellLoading ? (_jsx(Loader2, { className: "size-4 animate-spin" })) : actions.shellError ? (_jsx(CircleAlert, { className: "text-destructive size-4" })) : (_jsx(Terminal, { className: "size-4" })), "Terminal"] }), _jsxs(DropdownMenuItem, { onClick: actions.openFolder, disabled: actions.folderLoading, className: "gap-2", children: [actions.folderLoading ? (_jsx(Loader2, { className: "size-4 animate-spin" })) : actions.folderError ? (_jsx(CircleAlert, { className: "text-destructive size-4" })) : (_jsx(FolderOpen, { className: "size-4" })), "Folder"] }), _jsxs(DropdownMenuItem, { onClick: actions.openSpecsFolder, disabled: actions.specsLoading || !showSpecs, className: "gap-2", children: [actions.specsLoading ? (_jsx(Loader2, { className: "size-4 animate-spin" })) : actions.specsError ? (_jsx(CircleAlert, { className: "text-destructive size-4" })) : (_jsx(FolderOpen, { className: "size-4" })), "Specs Folder"] }), _jsx(DropdownMenuSeparator, {}), _jsxs(DropdownMenuItem, { onClick: handleCopyPath, className: "gap-2", children: [copied ? _jsx(Check, { className: "size-4 text-green-600" }) : _jsx(Copy, { className: "size-4" }), copied ? 'Copied!' : 'Copy path'] })] })] }));
|
|
18
18
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"open-action-menu.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/open-action-menu/open-action-menu.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;
|
|
1
|
+
{"version":3,"file":"open-action-menu.stories.d.ts","sourceRoot":"","sources":["../../../../../../../src/presentation/web/components/common/open-action-menu/open-action-menu.stories.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAEvD,OAAO,EAAE,cAAc,EAAE,MAAM,oBAAoB,CAAC;AAqBpD,QAAA,MAAM,IAAI,EAAE,IAAI,CAAC,OAAO,cAAc,CAOrC,CAAC;AAEF,eAAe,IAAI,CAAC;AACpB,KAAK,KAAK,GAAG,QAAQ,CAAC,OAAO,cAAc,CAAC,CAAC;AAE7C,4DAA4D;AAC5D,eAAO,MAAM,OAAO,EAAE,KAMrB,CAAC;AAEF,wCAAwC;AACxC,eAAO,MAAM,YAAY,EAAE,KAM1B,CAAC;AAEF,wCAAwC;AACxC,eAAO,MAAM,OAAO,EAAE,KAMrB,CAAC;AAEF,4CAA4C;AAC5C,eAAO,MAAM,SAAS,EAAE,KAMvB,CAAC;AAEF,sEAAsE;AACtE,eAAO,MAAM,gBAAgB,EAAE,KAO9B,CAAC"}
|
package/dist/src/presentation/web/components/common/open-action-menu/open-action-menu.stories.js
CHANGED
|
@@ -3,14 +3,17 @@ import { OpenActionMenu } from './open-action-menu.js';
|
|
|
3
3
|
const defaultActions = {
|
|
4
4
|
openInIde: fn().mockName('openInIde'),
|
|
5
5
|
openInShell: fn().mockName('openInShell'),
|
|
6
|
+
openFolder: fn().mockName('openFolder'),
|
|
6
7
|
openSpecsFolder: fn().mockName('openSpecsFolder'),
|
|
7
8
|
rebaseOnMain: fn().mockName('rebaseOnMain'),
|
|
8
9
|
ideLoading: false,
|
|
9
10
|
shellLoading: false,
|
|
11
|
+
folderLoading: false,
|
|
10
12
|
specsLoading: false,
|
|
11
13
|
rebaseLoading: false,
|
|
12
14
|
ideError: null,
|
|
13
15
|
shellError: null,
|
|
16
|
+
folderError: null,
|
|
14
17
|
specsError: null,
|
|
15
18
|
rebaseError: null,
|
|
16
19
|
};
|
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":"AAIA,OAAO,KAAK,EAAE,IAAI,EAAY,MAAM,eAAe,CAAC;AAKpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAwB5E,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":"AAIA,OAAO,KAAK,EAAE,IAAI,EAAY,MAAM,eAAe,CAAC;AAKpD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,uCAAuC,CAAC;AAwB5E,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,2CA0ZzF"}
|
package/dist/src/presentation/web/components/features/control-center/control-center-inner.js
CHANGED
|
@@ -197,6 +197,24 @@ export function ControlCenterInner({ initialNodes, initialEdges }) {
|
|
|
197
197
|
window.addEventListener('shep:feature-delete-requested', handler);
|
|
198
198
|
return () => window.removeEventListener('shep:feature-delete-requested', handler);
|
|
199
199
|
}, [handleDeleteFeature]);
|
|
200
|
+
// Listen for archive requests from the feature drawer.
|
|
201
|
+
useEffect(() => {
|
|
202
|
+
const handler = (e) => {
|
|
203
|
+
const { featureId } = e.detail;
|
|
204
|
+
handleArchiveFeature(featureId);
|
|
205
|
+
};
|
|
206
|
+
window.addEventListener('shep:feature-archive-requested', handler);
|
|
207
|
+
return () => window.removeEventListener('shep:feature-archive-requested', handler);
|
|
208
|
+
}, [handleArchiveFeature]);
|
|
209
|
+
// Listen for unarchive requests from the feature drawer.
|
|
210
|
+
useEffect(() => {
|
|
211
|
+
const handler = (e) => {
|
|
212
|
+
const { featureId } = e.detail;
|
|
213
|
+
handleUnarchiveFeature(featureId);
|
|
214
|
+
};
|
|
215
|
+
window.addEventListener('shep:feature-unarchive-requested', handler);
|
|
216
|
+
return () => window.removeEventListener('shep:feature-unarchive-requested', handler);
|
|
217
|
+
}, [handleUnarchiveFeature]);
|
|
200
218
|
// Wire callbacks into derived node data (via ref — no re-render).
|
|
201
219
|
useEffect(() => {
|
|
202
220
|
setCallbacks({
|