@shepai/cli 1.19.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.
Files changed (138) hide show
  1. package/dist/eslint.config.mjs +3 -0
  2. package/dist/src/application/ports/output/agents/feature-agent-process.interface.d.ts +2 -1
  3. package/dist/src/application/ports/output/agents/feature-agent-process.interface.d.ts.map +1 -1
  4. package/dist/src/application/ports/output/agents/index.d.ts +1 -0
  5. package/dist/src/application/ports/output/agents/index.d.ts.map +1 -1
  6. package/dist/src/application/ports/output/agents/phase-timing-repository.interface.d.ts +44 -0
  7. package/dist/src/application/ports/output/agents/phase-timing-repository.interface.d.ts.map +1 -0
  8. package/dist/src/application/ports/output/agents/phase-timing-repository.interface.js +11 -0
  9. package/dist/src/application/use-cases/agents/approve-agent-run.use-case.d.ts.map +1 -1
  10. package/dist/src/application/use-cases/agents/approve-agent-run.use-case.js +6 -2
  11. package/dist/src/application/use-cases/agents/reject-agent-run.use-case.d.ts.map +1 -1
  12. package/dist/src/application/use-cases/agents/reject-agent-run.use-case.js +0 -1
  13. package/dist/src/application/use-cases/features/create-feature.use-case.d.ts +12 -2
  14. package/dist/src/application/use-cases/features/create-feature.use-case.d.ts.map +1 -1
  15. package/dist/src/application/use-cases/features/create-feature.use-case.js +45 -10
  16. package/dist/src/application/use-cases/features/resume-feature.use-case.js +2 -2
  17. package/dist/src/domain/generated/output.d.ts +40 -6
  18. package/dist/src/domain/generated/output.d.ts.map +1 -1
  19. package/dist/src/infrastructure/di/container.d.ts.map +1 -1
  20. package/dist/src/infrastructure/di/container.js +7 -0
  21. package/dist/src/infrastructure/persistence/sqlite/mappers/agent-run.mapper.d.ts +1 -2
  22. package/dist/src/infrastructure/persistence/sqlite/mappers/agent-run.mapper.d.ts.map +1 -1
  23. package/dist/src/infrastructure/persistence/sqlite/mappers/agent-run.mapper.js +4 -4
  24. package/dist/src/infrastructure/persistence/sqlite/migrations.d.ts.map +1 -1
  25. package/dist/src/infrastructure/persistence/sqlite/migrations.js +31 -0
  26. package/dist/src/infrastructure/repositories/agent-run.repository.d.ts.map +1 -1
  27. package/dist/src/infrastructure/repositories/agent-run.repository.js +5 -9
  28. package/dist/src/infrastructure/repositories/sqlite-phase-timing.repository.d.ts +21 -0
  29. package/dist/src/infrastructure/repositories/sqlite-phase-timing.repository.d.ts.map +1 -0
  30. package/dist/src/infrastructure/repositories/sqlite-phase-timing.repository.js +100 -0
  31. package/dist/src/infrastructure/services/agents/feature-agent/feature-agent-graph.d.ts +305 -13
  32. package/dist/src/infrastructure/services/agents/feature-agent/feature-agent-graph.d.ts.map +1 -1
  33. package/dist/src/infrastructure/services/agents/feature-agent/feature-agent-graph.js +124 -7
  34. package/dist/src/infrastructure/services/agents/feature-agent/feature-agent-process.service.d.ts +2 -1
  35. package/dist/src/infrastructure/services/agents/feature-agent/feature-agent-process.service.d.ts.map +1 -1
  36. package/dist/src/infrastructure/services/agents/feature-agent/feature-agent-process.service.js +2 -2
  37. package/dist/src/infrastructure/services/agents/feature-agent/feature-agent-worker.d.ts +2 -1
  38. package/dist/src/infrastructure/services/agents/feature-agent/feature-agent-worker.d.ts.map +1 -1
  39. package/dist/src/infrastructure/services/agents/feature-agent/feature-agent-worker.js +19 -7
  40. package/dist/src/infrastructure/services/agents/feature-agent/nodes/implement.node.js +1 -1
  41. package/dist/src/infrastructure/services/agents/feature-agent/nodes/node-helpers.d.ts +11 -2
  42. package/dist/src/infrastructure/services/agents/feature-agent/nodes/node-helpers.d.ts.map +1 -1
  43. package/dist/src/infrastructure/services/agents/feature-agent/nodes/node-helpers.js +46 -15
  44. package/dist/src/infrastructure/services/agents/feature-agent/nodes/repair.node.d.ts +23 -0
  45. package/dist/src/infrastructure/services/agents/feature-agent/nodes/repair.node.d.ts.map +1 -0
  46. package/dist/src/infrastructure/services/agents/feature-agent/nodes/repair.node.js +77 -0
  47. package/dist/src/infrastructure/services/agents/feature-agent/nodes/schemas/plan.schema.d.ts +4 -0
  48. package/dist/src/infrastructure/services/agents/feature-agent/nodes/schemas/plan.schema.d.ts.map +1 -0
  49. package/dist/src/infrastructure/services/agents/feature-agent/nodes/schemas/plan.schema.js +54 -0
  50. package/dist/src/infrastructure/services/agents/feature-agent/nodes/schemas/research.schema.d.ts +3 -0
  51. package/dist/src/infrastructure/services/agents/feature-agent/nodes/schemas/research.schema.d.ts.map +1 -0
  52. package/dist/src/infrastructure/services/agents/feature-agent/nodes/schemas/research.schema.js +24 -0
  53. package/dist/src/infrastructure/services/agents/feature-agent/nodes/schemas/spec.schema.d.ts +4 -0
  54. package/dist/src/infrastructure/services/agents/feature-agent/nodes/schemas/spec.schema.d.ts.map +1 -0
  55. package/dist/src/infrastructure/services/agents/feature-agent/nodes/schemas/spec.schema.js +50 -0
  56. package/dist/src/infrastructure/services/agents/feature-agent/nodes/schemas/validation.d.ts +8 -0
  57. package/dist/src/infrastructure/services/agents/feature-agent/nodes/schemas/validation.d.ts.map +1 -0
  58. package/dist/src/infrastructure/services/agents/feature-agent/nodes/schemas/validation.js +36 -0
  59. package/dist/src/infrastructure/services/agents/feature-agent/nodes/validate.node.d.ts +12 -0
  60. package/dist/src/infrastructure/services/agents/feature-agent/nodes/validate.node.d.ts.map +1 -0
  61. package/dist/src/infrastructure/services/agents/feature-agent/nodes/validate.node.js +58 -0
  62. package/dist/src/infrastructure/services/agents/feature-agent/phase-timing-context.d.ts +30 -0
  63. package/dist/src/infrastructure/services/agents/feature-agent/phase-timing-context.d.ts.map +1 -0
  64. package/dist/src/infrastructure/services/agents/feature-agent/phase-timing-context.js +68 -0
  65. package/dist/src/infrastructure/services/agents/feature-agent/state.d.ts +5 -1
  66. package/dist/src/infrastructure/services/agents/feature-agent/state.d.ts.map +1 -1
  67. package/dist/src/infrastructure/services/agents/feature-agent/state.js +14 -1
  68. package/dist/src/presentation/cli/commands/feat/approve.command.d.ts +12 -0
  69. package/dist/src/presentation/cli/commands/feat/approve.command.d.ts.map +1 -0
  70. package/dist/src/presentation/cli/commands/feat/approve.command.js +48 -0
  71. package/dist/src/presentation/cli/commands/feat/index.d.ts.map +1 -1
  72. package/dist/src/presentation/cli/commands/feat/index.js +7 -1
  73. package/dist/src/presentation/cli/commands/feat/ls.command.d.ts.map +1 -1
  74. package/dist/src/presentation/cli/commands/feat/ls.command.js +13 -5
  75. package/dist/src/presentation/cli/commands/feat/new.command.d.ts.map +1 -1
  76. package/dist/src/presentation/cli/commands/feat/new.command.js +34 -15
  77. package/dist/src/presentation/cli/commands/feat/reject.command.d.ts +12 -0
  78. package/dist/src/presentation/cli/commands/feat/reject.command.d.ts.map +1 -0
  79. package/dist/src/presentation/cli/commands/feat/reject.command.js +50 -0
  80. package/dist/src/presentation/cli/commands/feat/resolve-waiting-feature.d.ts +30 -0
  81. package/dist/src/presentation/cli/commands/feat/resolve-waiting-feature.d.ts.map +1 -0
  82. package/dist/src/presentation/cli/commands/feat/resolve-waiting-feature.js +57 -0
  83. package/dist/src/presentation/cli/commands/feat/review.command.d.ts +12 -0
  84. package/dist/src/presentation/cli/commands/feat/review.command.d.ts.map +1 -0
  85. package/dist/src/presentation/cli/commands/feat/review.command.js +49 -0
  86. package/dist/src/presentation/cli/commands/feat/show.command.d.ts.map +1 -1
  87. package/dist/src/presentation/cli/commands/feat/show.command.js +51 -6
  88. package/dist/tsconfig.build.tsbuildinfo +1 -1
  89. package/package.json +1 -1
  90. package/web/.next/BUILD_ID +1 -1
  91. package/web/.next/build-manifest.json +2 -2
  92. package/web/.next/cache/.previewinfo +1 -1
  93. package/web/.next/cache/.rscinfo +1 -1
  94. package/web/.next/cache/config.json +3 -3
  95. package/web/.next/fallback-build-manifest.json +2 -2
  96. package/web/.next/prerender-manifest.json +3 -3
  97. package/web/.next/required-server-files.js +1 -1
  98. package/web/.next/required-server-files.json +1 -1
  99. package/web/.next/server/app/_global-error.html +2 -2
  100. package/web/.next/server/app/_global-error.rsc +1 -1
  101. package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  102. package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  103. package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  104. package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  105. package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  106. package/web/.next/server/app/_not-found.html +2 -2
  107. package/web/.next/server/app/_not-found.rsc +1 -1
  108. package/web/.next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  109. package/web/.next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  110. package/web/.next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  111. package/web/.next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  112. package/web/.next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  113. package/web/.next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  114. package/web/.next/server/app/index.html +2 -2
  115. package/web/.next/server/app/index.rsc +1 -1
  116. package/web/.next/server/app/index.segments/__PAGE__.segment.rsc +1 -1
  117. package/web/.next/server/app/index.segments/_full.segment.rsc +1 -1
  118. package/web/.next/server/app/index.segments/_head.segment.rsc +1 -1
  119. package/web/.next/server/app/index.segments/_index.segment.rsc +1 -1
  120. package/web/.next/server/app/index.segments/_tree.segment.rsc +1 -1
  121. package/web/.next/server/app/version.html +2 -2
  122. package/web/.next/server/app/version.rsc +1 -1
  123. package/web/.next/server/app/version.segments/_full.segment.rsc +1 -1
  124. package/web/.next/server/app/version.segments/_head.segment.rsc +1 -1
  125. package/web/.next/server/app/version.segments/_index.segment.rsc +1 -1
  126. package/web/.next/server/app/version.segments/_tree.segment.rsc +1 -1
  127. package/web/.next/server/app/version.segments/version/__PAGE__.segment.rsc +1 -1
  128. package/web/.next/server/app/version.segments/version.segment.rsc +1 -1
  129. package/web/.next/server/chunks/ssr/_19be0743._.js +1 -1
  130. package/web/.next/server/pages/404.html +2 -2
  131. package/web/.next/server/pages/500.html +2 -2
  132. package/web/.next/server/server-reference-manifest.js +1 -1
  133. package/web/.next/server/server-reference-manifest.json +1 -1
  134. package/web/.next/trace +1 -1
  135. package/web/.next/trace-build +1 -1
  136. /package/web/.next/static/{nw4IT0rr_mE5Tx22X9OgO → u-tyZUMnsIne6K_0rPmPO}/_buildManifest.js +0 -0
  137. /package/web/.next/static/{nw4IT0rr_mE5Tx22X9OgO → u-tyZUMnsIne6K_0rPmPO}/_clientMiddlewareManifest.json +0 -0
  138. /package/web/.next/static/{nw4IT0rr_mE5Tx22X9OgO → u-tyZUMnsIne6K_0rPmPO}/_ssgManifest.js +0 -0
@@ -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;AA4DpC,wBAAgB,iBAAiB,IAAI,OAAO,CAyE3C"}
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 phase = run.result?.startsWith('node:')
35
- ? (NODE_TO_PHASE[run.result.slice(5)] ?? run.result.slice(5))
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
- return `${colors.warning(symbols.warning)} ${colors.warning(phase)}`;
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: [