@shepai/cli 1.18.0 → 1.20.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/eslint.config.mjs +3 -0
- package/dist/src/application/ports/output/agents/feature-agent-process.interface.d.ts +2 -1
- package/dist/src/application/ports/output/agents/feature-agent-process.interface.d.ts.map +1 -1
- package/dist/src/application/ports/output/agents/index.d.ts +1 -0
- package/dist/src/application/ports/output/agents/index.d.ts.map +1 -1
- package/dist/src/application/ports/output/agents/phase-timing-repository.interface.d.ts +44 -0
- package/dist/src/application/ports/output/agents/phase-timing-repository.interface.d.ts.map +1 -0
- package/dist/src/application/ports/output/agents/phase-timing-repository.interface.js +11 -0
- package/dist/src/application/use-cases/agents/approve-agent-run.use-case.d.ts.map +1 -1
- package/dist/src/application/use-cases/agents/approve-agent-run.use-case.js +6 -2
- package/dist/src/application/use-cases/agents/reject-agent-run.use-case.d.ts.map +1 -1
- package/dist/src/application/use-cases/agents/reject-agent-run.use-case.js +0 -1
- package/dist/src/application/use-cases/features/create-feature.use-case.d.ts +12 -2
- package/dist/src/application/use-cases/features/create-feature.use-case.d.ts.map +1 -1
- package/dist/src/application/use-cases/features/create-feature.use-case.js +45 -10
- package/dist/src/application/use-cases/features/resume-feature.use-case.js +2 -2
- package/dist/src/domain/factories/settings-defaults.factory.js +2 -2
- package/dist/src/domain/generated/output.d.ts +48 -7
- package/dist/src/domain/generated/output.d.ts.map +1 -1
- package/dist/src/domain/generated/output.js +8 -0
- package/dist/src/infrastructure/di/container.d.ts.map +1 -1
- package/dist/src/infrastructure/di/container.js +7 -0
- package/dist/src/infrastructure/persistence/sqlite/mappers/agent-run.mapper.d.ts +1 -2
- package/dist/src/infrastructure/persistence/sqlite/mappers/agent-run.mapper.d.ts.map +1 -1
- package/dist/src/infrastructure/persistence/sqlite/mappers/agent-run.mapper.js +4 -4
- package/dist/src/infrastructure/persistence/sqlite/mappers/settings.mapper.d.ts.map +1 -1
- package/dist/src/infrastructure/persistence/sqlite/migrations.d.ts.map +1 -1
- package/dist/src/infrastructure/persistence/sqlite/migrations.js +31 -0
- package/dist/src/infrastructure/repositories/agent-run.repository.d.ts.map +1 -1
- package/dist/src/infrastructure/repositories/agent-run.repository.js +5 -9
- package/dist/src/infrastructure/repositories/sqlite-phase-timing.repository.d.ts +21 -0
- package/dist/src/infrastructure/repositories/sqlite-phase-timing.repository.d.ts.map +1 -0
- package/dist/src/infrastructure/repositories/sqlite-phase-timing.repository.js +100 -0
- package/dist/src/infrastructure/services/agents/feature-agent/feature-agent-graph.d.ts +305 -13
- package/dist/src/infrastructure/services/agents/feature-agent/feature-agent-graph.d.ts.map +1 -1
- package/dist/src/infrastructure/services/agents/feature-agent/feature-agent-graph.js +124 -7
- package/dist/src/infrastructure/services/agents/feature-agent/feature-agent-process.service.d.ts +2 -1
- package/dist/src/infrastructure/services/agents/feature-agent/feature-agent-process.service.d.ts.map +1 -1
- package/dist/src/infrastructure/services/agents/feature-agent/feature-agent-process.service.js +2 -2
- package/dist/src/infrastructure/services/agents/feature-agent/feature-agent-worker.d.ts +2 -1
- package/dist/src/infrastructure/services/agents/feature-agent/feature-agent-worker.d.ts.map +1 -1
- package/dist/src/infrastructure/services/agents/feature-agent/feature-agent-worker.js +19 -7
- package/dist/src/infrastructure/services/agents/feature-agent/nodes/implement.node.js +1 -1
- package/dist/src/infrastructure/services/agents/feature-agent/nodes/node-helpers.d.ts +11 -2
- package/dist/src/infrastructure/services/agents/feature-agent/nodes/node-helpers.d.ts.map +1 -1
- package/dist/src/infrastructure/services/agents/feature-agent/nodes/node-helpers.js +46 -15
- package/dist/src/infrastructure/services/agents/feature-agent/nodes/repair.node.d.ts +23 -0
- package/dist/src/infrastructure/services/agents/feature-agent/nodes/repair.node.d.ts.map +1 -0
- package/dist/src/infrastructure/services/agents/feature-agent/nodes/repair.node.js +77 -0
- package/dist/src/infrastructure/services/agents/feature-agent/nodes/schemas/plan.schema.d.ts +4 -0
- package/dist/src/infrastructure/services/agents/feature-agent/nodes/schemas/plan.schema.d.ts.map +1 -0
- package/dist/src/infrastructure/services/agents/feature-agent/nodes/schemas/plan.schema.js +54 -0
- package/dist/src/infrastructure/services/agents/feature-agent/nodes/schemas/research.schema.d.ts +3 -0
- package/dist/src/infrastructure/services/agents/feature-agent/nodes/schemas/research.schema.d.ts.map +1 -0
- package/dist/src/infrastructure/services/agents/feature-agent/nodes/schemas/research.schema.js +24 -0
- package/dist/src/infrastructure/services/agents/feature-agent/nodes/schemas/spec.schema.d.ts +4 -0
- package/dist/src/infrastructure/services/agents/feature-agent/nodes/schemas/spec.schema.d.ts.map +1 -0
- package/dist/src/infrastructure/services/agents/feature-agent/nodes/schemas/spec.schema.js +50 -0
- package/dist/src/infrastructure/services/agents/feature-agent/nodes/schemas/validation.d.ts +8 -0
- package/dist/src/infrastructure/services/agents/feature-agent/nodes/schemas/validation.d.ts.map +1 -0
- package/dist/src/infrastructure/services/agents/feature-agent/nodes/schemas/validation.js +36 -0
- package/dist/src/infrastructure/services/agents/feature-agent/nodes/validate.node.d.ts +12 -0
- package/dist/src/infrastructure/services/agents/feature-agent/nodes/validate.node.d.ts.map +1 -0
- package/dist/src/infrastructure/services/agents/feature-agent/nodes/validate.node.js +58 -0
- package/dist/src/infrastructure/services/agents/feature-agent/phase-timing-context.d.ts +30 -0
- package/dist/src/infrastructure/services/agents/feature-agent/phase-timing-context.d.ts.map +1 -0
- package/dist/src/infrastructure/services/agents/feature-agent/phase-timing-context.js +68 -0
- package/dist/src/infrastructure/services/agents/feature-agent/state.d.ts +5 -1
- package/dist/src/infrastructure/services/agents/feature-agent/state.d.ts.map +1 -1
- package/dist/src/infrastructure/services/agents/feature-agent/state.js +14 -1
- package/dist/src/infrastructure/services/ide-launchers/antigravity.launcher.d.ts +10 -0
- package/dist/src/infrastructure/services/ide-launchers/antigravity.launcher.d.ts.map +1 -0
- package/dist/src/infrastructure/services/ide-launchers/antigravity.launcher.js +21 -0
- package/dist/src/infrastructure/services/ide-launchers/cursor.launcher.d.ts +10 -0
- package/dist/src/infrastructure/services/ide-launchers/cursor.launcher.d.ts.map +1 -0
- package/dist/src/infrastructure/services/ide-launchers/cursor.launcher.js +21 -0
- package/dist/src/infrastructure/services/ide-launchers/ide-launcher.interface.d.ts +31 -0
- package/dist/src/infrastructure/services/ide-launchers/ide-launcher.interface.d.ts.map +1 -0
- package/dist/src/infrastructure/services/ide-launchers/ide-launcher.interface.js +8 -0
- package/dist/src/infrastructure/services/ide-launchers/ide-launcher.registry.d.ts +9 -0
- package/dist/src/infrastructure/services/ide-launchers/ide-launcher.registry.d.ts.map +1 -0
- package/dist/src/infrastructure/services/ide-launchers/ide-launcher.registry.js +24 -0
- package/dist/src/infrastructure/services/ide-launchers/vscode.launcher.d.ts +10 -0
- package/dist/src/infrastructure/services/ide-launchers/vscode.launcher.d.ts.map +1 -0
- package/dist/src/infrastructure/services/ide-launchers/vscode.launcher.js +21 -0
- package/dist/src/infrastructure/services/ide-launchers/windsurf.launcher.d.ts +10 -0
- package/dist/src/infrastructure/services/ide-launchers/windsurf.launcher.d.ts.map +1 -0
- package/dist/src/infrastructure/services/ide-launchers/windsurf.launcher.js +21 -0
- package/dist/src/infrastructure/services/ide-launchers/zed.launcher.d.ts +10 -0
- package/dist/src/infrastructure/services/ide-launchers/zed.launcher.d.ts.map +1 -0
- package/dist/src/infrastructure/services/ide-launchers/zed.launcher.js +21 -0
- package/dist/src/presentation/cli/commands/feat/approve.command.d.ts +12 -0
- package/dist/src/presentation/cli/commands/feat/approve.command.d.ts.map +1 -0
- package/dist/src/presentation/cli/commands/feat/approve.command.js +48 -0
- package/dist/src/presentation/cli/commands/feat/index.d.ts.map +1 -1
- package/dist/src/presentation/cli/commands/feat/index.js +7 -1
- package/dist/src/presentation/cli/commands/feat/ls.command.d.ts.map +1 -1
- package/dist/src/presentation/cli/commands/feat/ls.command.js +13 -5
- package/dist/src/presentation/cli/commands/feat/new.command.d.ts.map +1 -1
- package/dist/src/presentation/cli/commands/feat/new.command.js +34 -15
- package/dist/src/presentation/cli/commands/feat/reject.command.d.ts +12 -0
- package/dist/src/presentation/cli/commands/feat/reject.command.d.ts.map +1 -0
- package/dist/src/presentation/cli/commands/feat/reject.command.js +50 -0
- package/dist/src/presentation/cli/commands/feat/resolve-waiting-feature.d.ts +30 -0
- package/dist/src/presentation/cli/commands/feat/resolve-waiting-feature.d.ts.map +1 -0
- package/dist/src/presentation/cli/commands/feat/resolve-waiting-feature.js +57 -0
- package/dist/src/presentation/cli/commands/feat/review.command.d.ts +12 -0
- package/dist/src/presentation/cli/commands/feat/review.command.d.ts.map +1 -0
- package/dist/src/presentation/cli/commands/feat/review.command.js +49 -0
- package/dist/src/presentation/cli/commands/feat/show.command.d.ts.map +1 -1
- package/dist/src/presentation/cli/commands/feat/show.command.js +51 -6
- package/dist/src/presentation/cli/commands/ide-open.command.d.ts +10 -0
- package/dist/src/presentation/cli/commands/ide-open.command.d.ts.map +1 -0
- package/dist/src/presentation/cli/commands/ide-open.command.js +77 -0
- package/dist/src/presentation/cli/commands/settings/ide.command.d.ts +15 -0
- package/dist/src/presentation/cli/commands/settings/ide.command.d.ts.map +1 -0
- package/dist/src/presentation/cli/commands/settings/ide.command.js +76 -0
- package/dist/src/presentation/cli/commands/settings/index.d.ts.map +1 -1
- package/dist/src/presentation/cli/commands/settings/index.js +3 -1
- package/dist/src/presentation/cli/index.js +2 -0
- package/dist/src/presentation/tui/prompts/ide-select.prompt.d.ts +45 -0
- package/dist/src/presentation/tui/prompts/ide-select.prompt.d.ts.map +1 -0
- package/dist/src/presentation/tui/prompts/ide-select.prompt.js +44 -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/cache/.previewinfo +1 -1
- package/web/.next/cache/.rscinfo +1 -1
- package/web/.next/cache/config.json +3 -3
- package/web/.next/fallback-build-manifest.json +2 -2
- package/web/.next/prerender-manifest.json +3 -3
- package/web/.next/required-server-files.js +1 -1
- package/web/.next/required-server-files.json +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.html +2 -2
- package/web/.next/server/app/_not-found.rsc +1 -1
- package/web/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
- package/web/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/web/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
- package/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/web/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
- package/web/.next/server/app/index.html +2 -2
- package/web/.next/server/app/index.rsc +1 -1
- package/web/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
- package/web/.next/server/app/index.segments/_full.segment.rsc +1 -1
- package/web/.next/server/app/index.segments/_head.segment.rsc +1 -1
- package/web/.next/server/app/index.segments/_index.segment.rsc +1 -1
- package/web/.next/server/app/index.segments/_tree.segment.rsc +1 -1
- package/web/.next/server/app/version.html +2 -2
- package/web/.next/server/app/version.rsc +1 -1
- package/web/.next/server/app/version.segments/_full.segment.rsc +1 -1
- package/web/.next/server/app/version.segments/_head.segment.rsc +1 -1
- package/web/.next/server/app/version.segments/_index.segment.rsc +1 -1
- package/web/.next/server/app/version.segments/_tree.segment.rsc +1 -1
- package/web/.next/server/app/version.segments/version/__PAGE__.segment.rsc +1 -1
- package/web/.next/server/app/version.segments/version.segment.rsc +1 -1
- package/web/.next/server/chunks/ssr/_19be0743._.js +1 -1
- package/web/.next/server/pages/404.html +2 -2
- package/web/.next/server/pages/500.html +2 -2
- package/web/.next/server/server-reference-manifest.js +1 -1
- package/web/.next/server/server-reference-manifest.json +1 -1
- package/web/.next/trace +1 -1
- package/web/.next/trace-build +1 -1
- /package/web/.next/static/{iV3kEDpfUq_ttVqv3E57o → u-tyZUMnsIne6K_0rPmPO}/_buildManifest.js +0 -0
- /package/web/.next/static/{iV3kEDpfUq_ttVqv3E57o → u-tyZUMnsIne6K_0rPmPO}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{iV3kEDpfUq_ttVqv3E57o → u-tyZUMnsIne6K_0rPmPO}/_ssgManifest.js +0 -0
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { spawn, execFile } from 'node:child_process';
|
|
2
|
+
import { EditorType } from '../../../domain/generated/output.js';
|
|
3
|
+
export class ZedLauncher {
|
|
4
|
+
name = 'Zed';
|
|
5
|
+
editorId = EditorType.Zed;
|
|
6
|
+
binary = 'zed';
|
|
7
|
+
async launch(path) {
|
|
8
|
+
const child = spawn(this.binary, [path], {
|
|
9
|
+
detached: true,
|
|
10
|
+
stdio: 'ignore',
|
|
11
|
+
});
|
|
12
|
+
child.unref();
|
|
13
|
+
}
|
|
14
|
+
checkAvailable() {
|
|
15
|
+
return new Promise((resolve) => {
|
|
16
|
+
execFile('which', [this.binary], (err) => {
|
|
17
|
+
resolve(!err);
|
|
18
|
+
});
|
|
19
|
+
});
|
|
20
|
+
}
|
|
21
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Feature Approve Command
|
|
3
|
+
*
|
|
4
|
+
* Approves a feature waiting for human approval, resuming
|
|
5
|
+
* the agent to continue with the next phase.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* shep feat approve [id]
|
|
9
|
+
*/
|
|
10
|
+
import { Command } from 'commander';
|
|
11
|
+
export declare function createApproveCommand(): Command;
|
|
12
|
+
//# sourceMappingURL=approve.command.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"approve.command.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/cli/commands/feat/approve.command.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAQpC,wBAAgB,oBAAoB,IAAI,OAAO,CAqC9C"}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Feature Approve Command
|
|
3
|
+
*
|
|
4
|
+
* Approves a feature waiting for human approval, resuming
|
|
5
|
+
* the agent to continue with the next phase.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* shep feat approve [id]
|
|
9
|
+
*/
|
|
10
|
+
import { Command } from 'commander';
|
|
11
|
+
import { container } from '../../../../infrastructure/di/container.js';
|
|
12
|
+
import { ApproveAgentRunUseCase } from '../../../../application/use-cases/agents/approve-agent-run.use-case.js';
|
|
13
|
+
import { resolveWaitingFeature } from './resolve-waiting-feature.js';
|
|
14
|
+
import { colors, messages } from '../../ui/index.js';
|
|
15
|
+
export function createApproveCommand() {
|
|
16
|
+
return new Command('approve')
|
|
17
|
+
.description('Approve a feature waiting for review')
|
|
18
|
+
.argument('[id]', 'Feature ID (auto-resolves if omitted)')
|
|
19
|
+
.action(async (featureId) => {
|
|
20
|
+
try {
|
|
21
|
+
const featureRepo = container.resolve('IFeatureRepository');
|
|
22
|
+
const runRepo = container.resolve('IAgentRunRepository');
|
|
23
|
+
const repoPath = process.cwd();
|
|
24
|
+
const { feature, run } = await resolveWaitingFeature({
|
|
25
|
+
featureId,
|
|
26
|
+
repoPath,
|
|
27
|
+
featureRepo,
|
|
28
|
+
runRepo,
|
|
29
|
+
});
|
|
30
|
+
const approveUseCase = container.resolve(ApproveAgentRunUseCase);
|
|
31
|
+
const result = await approveUseCase.execute(run.id);
|
|
32
|
+
if (!result.approved) {
|
|
33
|
+
throw new Error(result.reason);
|
|
34
|
+
}
|
|
35
|
+
const phase = run.result?.startsWith('node:') ? run.result.slice(5) : 'unknown';
|
|
36
|
+
messages.newline();
|
|
37
|
+
messages.success(`Approved: ${feature.name}`);
|
|
38
|
+
console.log(` ${colors.muted('Phase:')} ${colors.success(phase)} approved`);
|
|
39
|
+
console.log(` ${colors.muted('Agent:')} resumed`);
|
|
40
|
+
messages.newline();
|
|
41
|
+
}
|
|
42
|
+
catch (error) {
|
|
43
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
44
|
+
messages.error('Failed to approve feature', err);
|
|
45
|
+
process.exitCode = 1;
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/cli/commands/feat/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/cli/commands/feat/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAUpC;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,CAW3C"}
|
|
@@ -15,6 +15,9 @@ import { createLsCommand } from './ls.command.js';
|
|
|
15
15
|
import { createShowCommand } from './show.command.js';
|
|
16
16
|
import { createDelCommand } from './del.command.js';
|
|
17
17
|
import { createResumeCommand } from './resume.command.js';
|
|
18
|
+
import { createReviewCommand } from './review.command.js';
|
|
19
|
+
import { createApproveCommand } from './approve.command.js';
|
|
20
|
+
import { createRejectCommand } from './reject.command.js';
|
|
18
21
|
/**
|
|
19
22
|
* Create the feat command group
|
|
20
23
|
*/
|
|
@@ -25,5 +28,8 @@ export function createFeatCommand() {
|
|
|
25
28
|
.addCommand(createLsCommand())
|
|
26
29
|
.addCommand(createShowCommand())
|
|
27
30
|
.addCommand(createDelCommand())
|
|
28
|
-
.addCommand(createResumeCommand())
|
|
31
|
+
.addCommand(createResumeCommand())
|
|
32
|
+
.addCommand(createReviewCommand())
|
|
33
|
+
.addCommand(createApproveCommand())
|
|
34
|
+
.addCommand(createRejectCommand());
|
|
29
35
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ls.command.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/cli/commands/feat/ls.command.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"ls.command.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/cli/commands/feat/ls.command.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA+GpC,wBAAgB,eAAe,IAAI,OAAO,CAqDzC"}
|
|
@@ -15,7 +15,7 @@ import { Command } from 'commander';
|
|
|
15
15
|
import { container } from '../../../../infrastructure/di/container.js';
|
|
16
16
|
import { ListFeaturesUseCase } from '../../../../application/use-cases/features/list-features.use-case.js';
|
|
17
17
|
import { colors, symbols, messages, renderListView } from '../../ui/index.js';
|
|
18
|
-
/** Map graph node names to human-readable phase labels. */
|
|
18
|
+
/** Map graph node names to human-readable phase labels (active). */
|
|
19
19
|
const NODE_TO_PHASE = {
|
|
20
20
|
analyze: 'Analyzing',
|
|
21
21
|
requirements: 'Requirements',
|
|
@@ -23,6 +23,14 @@ const NODE_TO_PHASE = {
|
|
|
23
23
|
plan: 'Planning',
|
|
24
24
|
implement: 'Implementing',
|
|
25
25
|
};
|
|
26
|
+
/** Map graph node names to approval action labels. */
|
|
27
|
+
const NODE_TO_APPROVE = {
|
|
28
|
+
analyze: 'Approve Analysis',
|
|
29
|
+
requirements: 'Approve PRD',
|
|
30
|
+
research: 'Approve Research',
|
|
31
|
+
plan: 'Approve Plan',
|
|
32
|
+
implement: 'Approve Merge',
|
|
33
|
+
};
|
|
26
34
|
/**
|
|
27
35
|
* Derive the display status from the agent run.
|
|
28
36
|
* Returns the current graph node as a phase label with an activity indicator.
|
|
@@ -33,9 +41,8 @@ function formatStatus(feature, run) {
|
|
|
33
41
|
return `${colors.muted(symbols.dotEmpty)} ${colors.muted(feature.lifecycle)}`;
|
|
34
42
|
}
|
|
35
43
|
const isRunning = run.status === 'running' || run.status === 'pending';
|
|
36
|
-
const
|
|
37
|
-
|
|
38
|
-
: feature.lifecycle;
|
|
44
|
+
const nodeName = run.result?.startsWith('node:') ? run.result.slice(5) : undefined;
|
|
45
|
+
const phase = nodeName ? (NODE_TO_PHASE[nodeName] ?? nodeName) : feature.lifecycle;
|
|
39
46
|
if (isRunning) {
|
|
40
47
|
// Check PID liveness for running agents
|
|
41
48
|
if (run.pid && !isProcessAlive(run.pid)) {
|
|
@@ -50,7 +57,8 @@ function formatStatus(feature, run) {
|
|
|
50
57
|
return `${colors.error(symbols.error)} ${colors.error('Failed')}`;
|
|
51
58
|
}
|
|
52
59
|
if (run.status === 'waiting_approval') {
|
|
53
|
-
|
|
60
|
+
const action = nodeName ? (NODE_TO_APPROVE[nodeName] ?? phase) : phase;
|
|
61
|
+
return `${colors.warning(symbols.warning)} ${colors.warning(action)}`;
|
|
54
62
|
}
|
|
55
63
|
if (run.status === 'interrupted') {
|
|
56
64
|
return `${colors.error(symbols.error)} ${colors.error('Interrupted')}`;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"new.command.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/cli/commands/feat/new.command.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"new.command.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/cli/commands/feat/new.command.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAgBpC;;GAEG;AACH,wBAAgB,gBAAgB,IAAI,OAAO,CAiE1C"}
|
|
@@ -10,9 +10,12 @@
|
|
|
10
10
|
* $ shep feat new "Add login page" --repo /path/to/project
|
|
11
11
|
*/
|
|
12
12
|
import { Command } from 'commander';
|
|
13
|
+
import { createHash } from 'node:crypto';
|
|
14
|
+
import { join } from 'node:path';
|
|
13
15
|
import { container } from '../../../../infrastructure/di/container.js';
|
|
14
16
|
import { CreateFeatureUseCase } from '../../../../application/use-cases/features/create-feature.use-case.js';
|
|
15
17
|
import { colors, messages, spinner } from '../../ui/index.js';
|
|
18
|
+
import { SHEP_HOME_DIR } from '../../../../infrastructure/services/filesystem/shep-directory.service.js';
|
|
16
19
|
/**
|
|
17
20
|
* Create the feat new command
|
|
18
21
|
*/
|
|
@@ -21,7 +24,6 @@ export function createNewCommand() {
|
|
|
21
24
|
.description('Create a new feature')
|
|
22
25
|
.argument('<description>', 'Feature description')
|
|
23
26
|
.option('-r, --repo <path>', 'Repository path (defaults to current directory)')
|
|
24
|
-
.option('--interactive', 'Require approval after every agent step')
|
|
25
27
|
.option('--allow-prd', 'Auto-approve through requirements, pause after')
|
|
26
28
|
.option('--allow-plan', 'Auto-approve through planning, pause at implementation')
|
|
27
29
|
.option('--allow-all', 'Run fully autonomous (no approval pauses)')
|
|
@@ -29,29 +31,46 @@ export function createNewCommand() {
|
|
|
29
31
|
try {
|
|
30
32
|
const useCase = container.resolve(CreateFeatureUseCase);
|
|
31
33
|
const repoPath = options.repo ?? process.cwd();
|
|
32
|
-
//
|
|
33
|
-
let
|
|
34
|
-
if (options.interactive)
|
|
35
|
-
approvalMode = 'interactive';
|
|
34
|
+
// Build approval gates from flags (default: pause after every phase)
|
|
35
|
+
let approvalGates = { allowPrd: false, allowPlan: false };
|
|
36
36
|
if (options.allowPrd)
|
|
37
|
-
|
|
37
|
+
approvalGates = { ...approvalGates, allowPrd: true };
|
|
38
38
|
if (options.allowPlan)
|
|
39
|
-
|
|
39
|
+
approvalGates = { allowPrd: true, allowPlan: true };
|
|
40
40
|
if (options.allowAll)
|
|
41
|
-
|
|
42
|
-
const
|
|
41
|
+
approvalGates = undefined; // no gates = fully autonomous
|
|
42
|
+
const result = await spinner('Thinking', () => useCase.execute({
|
|
43
43
|
userInput: description,
|
|
44
44
|
repositoryPath: repoPath,
|
|
45
|
-
|
|
45
|
+
approvalGates,
|
|
46
46
|
}));
|
|
47
|
+
const { feature, warning } = result;
|
|
48
|
+
const repoHash = createHash('sha256').update(repoPath).digest('hex').slice(0, 16);
|
|
49
|
+
const wtSlug = feature.branch.replace(/\//g, '-');
|
|
50
|
+
const worktreePath = join(SHEP_HOME_DIR, 'repos', repoHash, 'wt', wtSlug);
|
|
47
51
|
messages.newline();
|
|
52
|
+
if (warning) {
|
|
53
|
+
messages.warning(warning);
|
|
54
|
+
}
|
|
48
55
|
messages.success('Feature created');
|
|
49
|
-
console.log(` ${colors.muted('ID:')}
|
|
50
|
-
console.log(` ${colors.muted('Name:')}
|
|
51
|
-
console.log(` ${colors.muted('Branch:')}
|
|
52
|
-
console.log(` ${colors.muted('Status:')}
|
|
56
|
+
console.log(` ${colors.muted('ID:')} ${colors.accent(feature.id)}`);
|
|
57
|
+
console.log(` ${colors.muted('Name:')} ${feature.name}`);
|
|
58
|
+
console.log(` ${colors.muted('Branch:')} ${colors.accent(feature.branch)}`);
|
|
59
|
+
console.log(` ${colors.muted('Status:')} ${feature.lifecycle}`);
|
|
60
|
+
console.log(` ${colors.muted('Worktree:')} ${worktreePath}`);
|
|
61
|
+
if (feature.specPath) {
|
|
62
|
+
console.log(` ${colors.muted('Spec:')} ${feature.specPath}`);
|
|
63
|
+
}
|
|
53
64
|
if (feature.agentRunId) {
|
|
54
|
-
console.log(` ${colors.muted('Agent:')}
|
|
65
|
+
console.log(` ${colors.muted('Agent:')} ${colors.success('spawned')} (run ${feature.agentRunId.slice(0, 8)})`);
|
|
66
|
+
}
|
|
67
|
+
if (approvalGates) {
|
|
68
|
+
const hint = !approvalGates.allowPrd
|
|
69
|
+
? 'pause after every phase'
|
|
70
|
+
: !approvalGates.allowPlan
|
|
71
|
+
? 'auto-approve through requirements, pause after'
|
|
72
|
+
: 'auto-approve through planning, pause at implementation';
|
|
73
|
+
console.log(` ${colors.muted('Review:')} ${hint}`);
|
|
55
74
|
}
|
|
56
75
|
messages.newline();
|
|
57
76
|
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Feature Reject Command
|
|
3
|
+
*
|
|
4
|
+
* Rejects a feature waiting for human approval, cancelling
|
|
5
|
+
* the agent run with an optional reason.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* shep feat reject [id] [--reason <text>]
|
|
9
|
+
*/
|
|
10
|
+
import { Command } from 'commander';
|
|
11
|
+
export declare function createRejectCommand(): Command;
|
|
12
|
+
//# sourceMappingURL=reject.command.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"reject.command.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/cli/commands/feat/reject.command.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAQpC,wBAAgB,mBAAmB,IAAI,OAAO,CAsC7C"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Feature Reject Command
|
|
3
|
+
*
|
|
4
|
+
* Rejects a feature waiting for human approval, cancelling
|
|
5
|
+
* the agent run with an optional reason.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* shep feat reject [id] [--reason <text>]
|
|
9
|
+
*/
|
|
10
|
+
import { Command } from 'commander';
|
|
11
|
+
import { container } from '../../../../infrastructure/di/container.js';
|
|
12
|
+
import { RejectAgentRunUseCase } from '../../../../application/use-cases/agents/reject-agent-run.use-case.js';
|
|
13
|
+
import { resolveWaitingFeature } from './resolve-waiting-feature.js';
|
|
14
|
+
import { colors, messages } from '../../ui/index.js';
|
|
15
|
+
export function createRejectCommand() {
|
|
16
|
+
return new Command('reject')
|
|
17
|
+
.description('Reject a feature waiting for review')
|
|
18
|
+
.argument('[id]', 'Feature ID (auto-resolves if omitted)')
|
|
19
|
+
.option('--reason <text>', 'Rejection reason')
|
|
20
|
+
.action(async (featureId, options) => {
|
|
21
|
+
try {
|
|
22
|
+
const featureRepo = container.resolve('IFeatureRepository');
|
|
23
|
+
const runRepo = container.resolve('IAgentRunRepository');
|
|
24
|
+
const repoPath = process.cwd();
|
|
25
|
+
const { feature, run } = await resolveWaitingFeature({
|
|
26
|
+
featureId,
|
|
27
|
+
repoPath,
|
|
28
|
+
featureRepo,
|
|
29
|
+
runRepo,
|
|
30
|
+
});
|
|
31
|
+
const rejectUseCase = container.resolve(RejectAgentRunUseCase);
|
|
32
|
+
const result = await rejectUseCase.execute(run.id, options.reason);
|
|
33
|
+
if (!result.rejected) {
|
|
34
|
+
throw new Error(result.reason);
|
|
35
|
+
}
|
|
36
|
+
messages.newline();
|
|
37
|
+
messages.warning(`Rejected: ${feature.name}`);
|
|
38
|
+
if (options.reason) {
|
|
39
|
+
console.log(` ${colors.muted('Reason:')} ${options.reason}`);
|
|
40
|
+
}
|
|
41
|
+
console.log(` ${colors.muted('Agent:')} cancelled`);
|
|
42
|
+
messages.newline();
|
|
43
|
+
}
|
|
44
|
+
catch (error) {
|
|
45
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
46
|
+
messages.error('Failed to reject feature', err);
|
|
47
|
+
process.exitCode = 1;
|
|
48
|
+
}
|
|
49
|
+
});
|
|
50
|
+
}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve Waiting Feature Helper
|
|
3
|
+
*
|
|
4
|
+
* Shared helper for feat review/approve/reject commands.
|
|
5
|
+
* Given an optional feature ID and repo path, resolves the target
|
|
6
|
+
* feature that is currently waiting for human approval.
|
|
7
|
+
*/
|
|
8
|
+
import type { Feature, AgentRun } from '../../../../domain/generated/output.js';
|
|
9
|
+
import type { IFeatureRepository } from '../../../../application/ports/output/repositories/feature-repository.interface.js';
|
|
10
|
+
import type { IAgentRunRepository } from '../../../../application/ports/output/agents/agent-run-repository.interface.js';
|
|
11
|
+
export interface ResolveWaitingFeatureOptions {
|
|
12
|
+
featureId?: string;
|
|
13
|
+
repoPath: string;
|
|
14
|
+
featureRepo: IFeatureRepository;
|
|
15
|
+
runRepo: IAgentRunRepository;
|
|
16
|
+
}
|
|
17
|
+
export interface ResolvedWaitingFeature {
|
|
18
|
+
feature: Feature;
|
|
19
|
+
run: AgentRun;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Resolve the target feature waiting for approval.
|
|
23
|
+
*
|
|
24
|
+
* If featureId is provided, looks it up directly.
|
|
25
|
+
* Otherwise, lists features for the repo and finds the single waiting one.
|
|
26
|
+
*
|
|
27
|
+
* @throws When feature not found, not waiting, or ambiguous (0 or 2+)
|
|
28
|
+
*/
|
|
29
|
+
export declare function resolveWaitingFeature(options: ResolveWaitingFeatureOptions): Promise<ResolvedWaitingFeature>;
|
|
30
|
+
//# sourceMappingURL=resolve-waiting-feature.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"resolve-waiting-feature.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/cli/commands/feat/resolve-waiting-feature.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,wCAAwC,CAAC;AAEhF,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,mFAAmF,CAAC;AAC5H,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,+EAA+E,CAAC;AAEzH,MAAM,WAAW,4BAA4B;IAC3C,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,QAAQ,EAAE,MAAM,CAAC;IACjB,WAAW,EAAE,kBAAkB,CAAC;IAChC,OAAO,EAAE,mBAAmB,CAAC;CAC9B;AAED,MAAM,WAAW,sBAAsB;IACrC,OAAO,EAAE,OAAO,CAAC;IACjB,GAAG,EAAE,QAAQ,CAAC;CACf;AAED;;;;;;;GAOG;AACH,wBAAsB,qBAAqB,CACzC,OAAO,EAAE,4BAA4B,GACpC,OAAO,CAAC,sBAAsB,CAAC,CAOjC"}
|
|
@@ -0,0 +1,57 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Resolve Waiting Feature Helper
|
|
3
|
+
*
|
|
4
|
+
* Shared helper for feat review/approve/reject commands.
|
|
5
|
+
* Given an optional feature ID and repo path, resolves the target
|
|
6
|
+
* feature that is currently waiting for human approval.
|
|
7
|
+
*/
|
|
8
|
+
import { AgentRunStatus } from '../../../../domain/generated/output.js';
|
|
9
|
+
/**
|
|
10
|
+
* Resolve the target feature waiting for approval.
|
|
11
|
+
*
|
|
12
|
+
* If featureId is provided, looks it up directly.
|
|
13
|
+
* Otherwise, lists features for the repo and finds the single waiting one.
|
|
14
|
+
*
|
|
15
|
+
* @throws When feature not found, not waiting, or ambiguous (0 or 2+)
|
|
16
|
+
*/
|
|
17
|
+
export async function resolveWaitingFeature(options) {
|
|
18
|
+
const { featureId, repoPath, featureRepo, runRepo } = options;
|
|
19
|
+
if (featureId) {
|
|
20
|
+
return resolveExplicit(featureId, featureRepo, runRepo);
|
|
21
|
+
}
|
|
22
|
+
return resolveAuto(repoPath, featureRepo, runRepo);
|
|
23
|
+
}
|
|
24
|
+
async function resolveExplicit(featureId, featureRepo, runRepo) {
|
|
25
|
+
const feature = (await featureRepo.findById(featureId)) ?? (await featureRepo.findByIdPrefix(featureId));
|
|
26
|
+
if (!feature) {
|
|
27
|
+
throw new Error(`Feature not found: "${featureId}"`);
|
|
28
|
+
}
|
|
29
|
+
if (!feature.agentRunId) {
|
|
30
|
+
throw new Error(`Feature "${feature.name}" has no agent run`);
|
|
31
|
+
}
|
|
32
|
+
const run = await runRepo.findById(feature.agentRunId);
|
|
33
|
+
if (!run || run.status !== AgentRunStatus.waitingApproval) {
|
|
34
|
+
throw new Error(`Feature "${feature.name}" is not waiting for approval (status: ${run?.status ?? 'unknown'})`);
|
|
35
|
+
}
|
|
36
|
+
return { feature, run };
|
|
37
|
+
}
|
|
38
|
+
async function resolveAuto(repoPath, featureRepo, runRepo) {
|
|
39
|
+
const features = await featureRepo.list({ repositoryPath: repoPath });
|
|
40
|
+
const waiting = [];
|
|
41
|
+
for (const feature of features) {
|
|
42
|
+
if (!feature.agentRunId)
|
|
43
|
+
continue;
|
|
44
|
+
const run = await runRepo.findById(feature.agentRunId);
|
|
45
|
+
if (run && run.status === AgentRunStatus.waitingApproval) {
|
|
46
|
+
waiting.push({ feature, run });
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
if (waiting.length === 0) {
|
|
50
|
+
throw new Error('No features waiting for approval in this repository');
|
|
51
|
+
}
|
|
52
|
+
if (waiting.length > 1) {
|
|
53
|
+
const names = waiting.map((w) => ` - ${w.feature.name} (${w.feature.id.slice(0, 8)})`);
|
|
54
|
+
throw new Error(`Multiple features waiting for approval. Specify one:\n${names.join('\n')}`);
|
|
55
|
+
}
|
|
56
|
+
return waiting[0];
|
|
57
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Feature Review Command
|
|
3
|
+
*
|
|
4
|
+
* Shows the current state of a feature waiting for approval,
|
|
5
|
+
* including which phase triggered the interrupt and generated content.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* shep feat review [id]
|
|
9
|
+
*/
|
|
10
|
+
import { Command } from 'commander';
|
|
11
|
+
export declare function createReviewCommand(): Command;
|
|
12
|
+
//# sourceMappingURL=review.command.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review.command.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/cli/commands/feat/review.command.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAOpC,wBAAgB,mBAAmB,IAAI,OAAO,CAqC7C"}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Feature Review Command
|
|
3
|
+
*
|
|
4
|
+
* Shows the current state of a feature waiting for approval,
|
|
5
|
+
* including which phase triggered the interrupt and generated content.
|
|
6
|
+
*
|
|
7
|
+
* Usage:
|
|
8
|
+
* shep feat review [id]
|
|
9
|
+
*/
|
|
10
|
+
import { Command } from 'commander';
|
|
11
|
+
import { container } from '../../../../infrastructure/di/container.js';
|
|
12
|
+
import { resolveWaitingFeature } from './resolve-waiting-feature.js';
|
|
13
|
+
import { colors, messages } from '../../ui/index.js';
|
|
14
|
+
export function createReviewCommand() {
|
|
15
|
+
return new Command('review')
|
|
16
|
+
.description('Review a feature waiting for approval')
|
|
17
|
+
.argument('[id]', 'Feature ID (auto-resolves if omitted)')
|
|
18
|
+
.action(async (featureId) => {
|
|
19
|
+
try {
|
|
20
|
+
const featureRepo = container.resolve('IFeatureRepository');
|
|
21
|
+
const runRepo = container.resolve('IAgentRunRepository');
|
|
22
|
+
const repoPath = process.cwd();
|
|
23
|
+
const { feature, run } = await resolveWaitingFeature({
|
|
24
|
+
featureId,
|
|
25
|
+
repoPath,
|
|
26
|
+
featureRepo,
|
|
27
|
+
runRepo,
|
|
28
|
+
});
|
|
29
|
+
const phase = run.result?.startsWith('node:') ? run.result.slice(5) : 'unknown';
|
|
30
|
+
messages.newline();
|
|
31
|
+
messages.info(`Feature waiting for approval: ${colors.accent(feature.name)}`);
|
|
32
|
+
console.log(` ${colors.muted('ID:')} ${feature.id.slice(0, 8)}`);
|
|
33
|
+
console.log(` ${colors.muted('Phase:')} ${colors.warning(phase)}`);
|
|
34
|
+
console.log(` ${colors.muted('Branch:')} ${colors.accent(feature.branch)}`);
|
|
35
|
+
if (feature.specPath) {
|
|
36
|
+
console.log(` ${colors.muted('Specs:')} ${feature.specPath}`);
|
|
37
|
+
}
|
|
38
|
+
messages.newline();
|
|
39
|
+
console.log(` ${colors.muted('To approve:')} shep feat approve ${feature.id.slice(0, 8)}`);
|
|
40
|
+
console.log(` ${colors.muted('To reject:')} shep feat reject ${feature.id.slice(0, 8)}`);
|
|
41
|
+
messages.newline();
|
|
42
|
+
}
|
|
43
|
+
catch (error) {
|
|
44
|
+
const err = error instanceof Error ? error : new Error(String(error));
|
|
45
|
+
messages.error('Failed to review feature', err);
|
|
46
|
+
process.exitCode = 1;
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"show.command.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/cli/commands/feat/show.command.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"show.command.d.ts","sourceRoot":"","sources":["../../../../../../src/presentation/cli/commands/feat/show.command.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAuEpC,wBAAgB,iBAAiB,IAAI,OAAO,CAkH3C"}
|
|
@@ -18,7 +18,7 @@ function computeWorktreePath(repoPath, branch) {
|
|
|
18
18
|
const slug = branch.replace(/\//g, '-');
|
|
19
19
|
return join(SHEP_HOME_DIR, 'repos', repoHash, 'wt', slug);
|
|
20
20
|
}
|
|
21
|
-
/** Map graph node names to human-readable phase labels. */
|
|
21
|
+
/** Map graph node names to human-readable phase labels (active). */
|
|
22
22
|
const NODE_TO_PHASE = {
|
|
23
23
|
analyze: 'Analyzing',
|
|
24
24
|
requirements: 'Requirements',
|
|
@@ -26,14 +26,21 @@ const NODE_TO_PHASE = {
|
|
|
26
26
|
plan: 'Planning',
|
|
27
27
|
implement: 'Implementing',
|
|
28
28
|
};
|
|
29
|
+
/** Map graph node names to approval action labels. */
|
|
30
|
+
const NODE_TO_APPROVE = {
|
|
31
|
+
analyze: 'Approve Analysis',
|
|
32
|
+
requirements: 'Approve PRD',
|
|
33
|
+
research: 'Approve Research',
|
|
34
|
+
plan: 'Approve Plan',
|
|
35
|
+
implement: 'Approve Merge',
|
|
36
|
+
};
|
|
29
37
|
function formatStatus(feature, run) {
|
|
30
38
|
if (!run) {
|
|
31
39
|
return `${colors.muted(symbols.dotEmpty)} ${colors.muted(feature.lifecycle)}`;
|
|
32
40
|
}
|
|
33
41
|
const isRunning = run.status === 'running' || run.status === 'pending';
|
|
34
|
-
const
|
|
35
|
-
|
|
36
|
-
: feature.lifecycle;
|
|
42
|
+
const nodeName = run.result?.startsWith('node:') ? run.result.slice(5) : undefined;
|
|
43
|
+
const phase = nodeName ? (NODE_TO_PHASE[nodeName] ?? nodeName) : feature.lifecycle;
|
|
37
44
|
if (isRunning) {
|
|
38
45
|
if (run.pid && !isProcessAlive(run.pid)) {
|
|
39
46
|
return `${colors.error(symbols.error)} ${colors.error('crashed')}`;
|
|
@@ -44,8 +51,10 @@ function formatStatus(feature, run) {
|
|
|
44
51
|
return `${colors.success(symbols.success)} ${colors.success('Completed')}`;
|
|
45
52
|
if (run.status === 'failed')
|
|
46
53
|
return `${colors.error(symbols.error)} ${colors.error('Failed')}`;
|
|
47
|
-
if (run.status === 'waiting_approval')
|
|
48
|
-
|
|
54
|
+
if (run.status === 'waiting_approval') {
|
|
55
|
+
const action = nodeName ? (NODE_TO_APPROVE[nodeName] ?? phase) : phase;
|
|
56
|
+
return `${colors.warning(symbols.warning)} ${colors.warning(action)}`;
|
|
57
|
+
}
|
|
49
58
|
if (run.status === 'interrupted')
|
|
50
59
|
return `${colors.error(symbols.error)} ${colors.error('Interrupted')}`;
|
|
51
60
|
return `${colors.muted(symbols.dotEmpty)} ${colors.muted(phase)}`;
|
|
@@ -67,8 +76,10 @@ export function createShowCommand() {
|
|
|
67
76
|
try {
|
|
68
77
|
const useCase = container.resolve(ShowFeatureUseCase);
|
|
69
78
|
const runRepo = container.resolve('IAgentRunRepository');
|
|
79
|
+
const timingRepo = container.resolve('IPhaseTimingRepository');
|
|
70
80
|
const feature = await useCase.execute(featureId);
|
|
71
81
|
const run = feature.agentRunId ? await runRepo.findById(feature.agentRunId) : null;
|
|
82
|
+
const timings = feature.agentRunId ? await timingRepo.findByRunId(feature.agentRunId) : [];
|
|
72
83
|
const worktreePath = computeWorktreePath(feature.repositoryPath, feature.branch);
|
|
73
84
|
const formatTs = (ts) => {
|
|
74
85
|
if (ts instanceof Date)
|
|
@@ -92,6 +103,40 @@ export function createShowCommand() {
|
|
|
92
103
|
content: last5,
|
|
93
104
|
});
|
|
94
105
|
}
|
|
106
|
+
if (timings.length > 0) {
|
|
107
|
+
const isWaiting = run?.status === 'waiting_approval';
|
|
108
|
+
const maxDurationMs = Math.max(...timings.map((t) => (t.durationMs != null ? Number(t.durationMs) : 0)));
|
|
109
|
+
const MAX_BAR = 20;
|
|
110
|
+
const lines = timings.map((t) => {
|
|
111
|
+
const label = (NODE_TO_PHASE[t.phase] ?? t.phase).padEnd(16);
|
|
112
|
+
if (t.completedAt && t.durationMs != null) {
|
|
113
|
+
const ms = Number(t.durationMs);
|
|
114
|
+
const secs = (ms / 1000).toFixed(1);
|
|
115
|
+
const barLen = maxDurationMs > 0 ? Math.max(1, Math.round((ms / maxDurationMs) * MAX_BAR)) : 1;
|
|
116
|
+
const bar = `${colors.success('█'.repeat(barLen))}${colors.muted('░'.repeat(MAX_BAR - barLen))}`;
|
|
117
|
+
return `${label} ${bar} ${secs}s`;
|
|
118
|
+
}
|
|
119
|
+
if (isWaiting) {
|
|
120
|
+
return `${label} ${colors.warning('awaiting review')}`;
|
|
121
|
+
}
|
|
122
|
+
return `${label} ${colors.info('running...')}`;
|
|
123
|
+
});
|
|
124
|
+
textBlocks.push({ title: 'Phase Timing', content: lines.join('\n') });
|
|
125
|
+
}
|
|
126
|
+
if (run?.status === 'waiting_approval') {
|
|
127
|
+
const phase = run.result?.startsWith('node:')
|
|
128
|
+
? (NODE_TO_PHASE[run.result.slice(5)] ?? run.result.slice(5))
|
|
129
|
+
: 'current phase';
|
|
130
|
+
textBlocks.push({
|
|
131
|
+
title: 'Awaiting Approval',
|
|
132
|
+
content: [
|
|
133
|
+
`${phase} is waiting for your review.`,
|
|
134
|
+
'',
|
|
135
|
+
` ${colors.accent('shep feat approve')} Resume the agent`,
|
|
136
|
+
` ${colors.accent('shep feat reject')} Cancel with feedback`,
|
|
137
|
+
].join('\n'),
|
|
138
|
+
});
|
|
139
|
+
}
|
|
95
140
|
renderDetailView({
|
|
96
141
|
title: `Feature: ${feature.name}`,
|
|
97
142
|
sections: [
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* IDE Open Command
|
|
3
|
+
*
|
|
4
|
+
* Opens a feature worktree in the configured IDE.
|
|
5
|
+
*
|
|
6
|
+
* Usage: shep ide <feat-id> [--vscode|--cursor|--windsurf|--zed|--antigravity]
|
|
7
|
+
*/
|
|
8
|
+
import { Command } from 'commander';
|
|
9
|
+
export declare function createIdeOpenCommand(): Command;
|
|
10
|
+
//# sourceMappingURL=ide-open.command.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ide-open.command.d.ts","sourceRoot":"","sources":["../../../../../src/presentation/cli/commands/ide-open.command.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AA+CpC,wBAAgB,oBAAoB,IAAI,OAAO,CAwC9C"}
|