@shepai/cli 1.38.0 → 1.40.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 (124) hide show
  1. package/dist/packages/core/src/application/ports/output/agents/feature-agent-process.interface.d.ts +1 -0
  2. package/dist/packages/core/src/application/ports/output/agents/feature-agent-process.interface.d.ts.map +1 -1
  3. package/dist/packages/core/src/application/use-cases/agents/approve-agent-run.use-case.d.ts +5 -4
  4. package/dist/packages/core/src/application/use-cases/agents/approve-agent-run.use-case.d.ts.map +1 -1
  5. package/dist/packages/core/src/application/use-cases/agents/approve-agent-run.use-case.js +36 -14
  6. package/dist/packages/core/src/application/use-cases/agents/reject-agent-run.use-case.d.ts +12 -3
  7. package/dist/packages/core/src/application/use-cases/agents/reject-agent-run.use-case.d.ts.map +1 -1
  8. package/dist/packages/core/src/application/use-cases/agents/reject-agent-run.use-case.js +88 -8
  9. package/dist/packages/core/src/application/use-cases/agents/review-feature.use-case.d.ts +35 -0
  10. package/dist/packages/core/src/application/use-cases/agents/review-feature.use-case.d.ts.map +1 -0
  11. package/dist/packages/core/src/application/use-cases/agents/review-feature.use-case.js +88 -0
  12. package/dist/packages/core/src/domain/generated/output.d.ts +102 -0
  13. package/dist/packages/core/src/domain/generated/output.d.ts.map +1 -1
  14. package/dist/packages/core/src/infrastructure/di/container.d.ts.map +1 -1
  15. package/dist/packages/core/src/infrastructure/di/container.js +2 -0
  16. package/dist/packages/core/src/infrastructure/services/agents/common/agent-executor-factory.service.d.ts.map +1 -1
  17. package/dist/packages/core/src/infrastructure/services/agents/common/agent-executor-factory.service.js +5 -1
  18. package/dist/packages/core/src/infrastructure/services/agents/common/agent-validator.service.d.ts.map +1 -1
  19. package/dist/packages/core/src/infrastructure/services/agents/common/agent-validator.service.js +1 -0
  20. package/dist/packages/core/src/infrastructure/services/agents/common/executors/gemini-cli-executor.service.d.ts +52 -0
  21. package/dist/packages/core/src/infrastructure/services/agents/common/executors/gemini-cli-executor.service.d.ts.map +1 -0
  22. package/dist/packages/core/src/infrastructure/services/agents/common/executors/gemini-cli-executor.service.js +337 -0
  23. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-graph.d.ts +51 -0
  24. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-graph.d.ts.map +1 -1
  25. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-graph.js +21 -2
  26. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-process.service.d.ts +1 -0
  27. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-process.service.d.ts.map +1 -1
  28. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-process.service.js +3 -0
  29. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-worker.d.ts +1 -0
  30. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-worker.d.ts.map +1 -1
  31. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-worker.js +31 -1
  32. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/node-helpers.d.ts +19 -3
  33. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/node-helpers.d.ts.map +1 -1
  34. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/node-helpers.js +101 -16
  35. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/prompts/requirements.prompt.d.ts +2 -1
  36. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/prompts/requirements.prompt.d.ts.map +1 -1
  37. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/prompts/requirements.prompt.js +53 -27
  38. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/phase-timing-context.d.ts +3 -0
  39. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/phase-timing-context.d.ts.map +1 -1
  40. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/phase-timing-context.js +28 -1
  41. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/state.d.ts +3 -0
  42. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/state.d.ts.map +1 -1
  43. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/state.js +13 -0
  44. package/dist/src/presentation/cli/commands/agent/reject.command.js +1 -1
  45. package/dist/src/presentation/cli/commands/feat/reject.command.d.ts.map +1 -1
  46. package/dist/src/presentation/cli/commands/feat/reject.command.js +6 -4
  47. package/dist/src/presentation/cli/commands/feat/review.command.d.ts +3 -2
  48. package/dist/src/presentation/cli/commands/feat/review.command.d.ts.map +1 -1
  49. package/dist/src/presentation/cli/commands/feat/review.command.js +87 -12
  50. package/dist/src/presentation/cli/commands/feat/show.command.d.ts.map +1 -1
  51. package/dist/src/presentation/cli/commands/feat/show.command.js +38 -3
  52. package/dist/src/presentation/tui/prompts/agent-select.prompt.d.ts +1 -1
  53. package/dist/src/presentation/tui/prompts/agent-select.prompt.js +1 -1
  54. package/dist/src/presentation/tui/prompts/prd-review-question.prompt.d.ts +30 -0
  55. package/dist/src/presentation/tui/prompts/prd-review-question.prompt.d.ts.map +1 -0
  56. package/dist/src/presentation/tui/prompts/prd-review-question.prompt.js +23 -0
  57. package/dist/src/presentation/tui/prompts/prd-review-summary.prompt.d.ts +29 -0
  58. package/dist/src/presentation/tui/prompts/prd-review-summary.prompt.d.ts.map +1 -0
  59. package/dist/src/presentation/tui/prompts/prd-review-summary.prompt.js +29 -0
  60. package/dist/src/presentation/tui/wizards/merge-review.wizard.d.ts +13 -0
  61. package/dist/src/presentation/tui/wizards/merge-review.wizard.d.ts.map +1 -0
  62. package/dist/src/presentation/tui/wizards/merge-review.wizard.js +43 -0
  63. package/dist/src/presentation/tui/wizards/plan-review.wizard.d.ts +13 -0
  64. package/dist/src/presentation/tui/wizards/plan-review.wizard.d.ts.map +1 -0
  65. package/dist/src/presentation/tui/wizards/plan-review.wizard.js +43 -0
  66. package/dist/src/presentation/tui/wizards/prd-review.wizard.d.ts +26 -0
  67. package/dist/src/presentation/tui/wizards/prd-review.wizard.d.ts.map +1 -0
  68. package/dist/src/presentation/tui/wizards/prd-review.wizard.js +42 -0
  69. package/dist/tsconfig.build.tsbuildinfo +1 -1
  70. package/package.json +1 -1
  71. package/web/.next/BUILD_ID +1 -1
  72. package/web/.next/build-manifest.json +2 -2
  73. package/web/.next/cache/.previewinfo +1 -1
  74. package/web/.next/cache/.rscinfo +1 -1
  75. package/web/.next/cache/.tsbuildinfo +1 -1
  76. package/web/.next/cache/config.json +3 -3
  77. package/web/.next/fallback-build-manifest.json +2 -2
  78. package/web/.next/prerender-manifest.json +3 -3
  79. package/web/.next/required-server-files.js +1 -1
  80. package/web/.next/required-server-files.json +1 -1
  81. package/web/.next/server/app/_global-error.html +2 -2
  82. package/web/.next/server/app/_global-error.rsc +1 -1
  83. package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  84. package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  85. package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  86. package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  87. package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  88. package/web/.next/server/app/page/server-reference-manifest.json +9 -9
  89. package/web/.next/server/app/page_client-reference-manifest.js +1 -1
  90. package/web/.next/server/chunks/ssr/[root-of-the-server]__03a0dba7._.js +1 -1
  91. package/web/.next/server/chunks/ssr/[root-of-the-server]__03a0dba7._.js.map +1 -1
  92. package/web/.next/server/chunks/ssr/[root-of-the-server]__19354aea._.js +2 -2
  93. package/web/.next/server/chunks/ssr/[root-of-the-server]__f12b60be._.js +1 -1
  94. package/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js.map +1 -1
  95. package/web/.next/server/chunks/ssr/src_presentation_web_ed0934e5._.js.map +1 -1
  96. package/web/.next/server/pages/500.html +2 -2
  97. package/web/.next/server/server-reference-manifest.js +1 -1
  98. package/web/.next/server/server-reference-manifest.json +10 -10
  99. package/web/.next/standalone/src/presentation/web/.next/BUILD_ID +1 -1
  100. package/web/.next/standalone/src/presentation/web/.next/build-manifest.json +2 -2
  101. package/web/.next/standalone/src/presentation/web/.next/prerender-manifest.json +3 -3
  102. package/web/.next/standalone/src/presentation/web/.next/required-server-files.json +1 -1
  103. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.html +2 -2
  104. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.rsc +1 -1
  105. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  106. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  107. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  108. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  109. package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  110. package/web/.next/standalone/src/presentation/web/.next/server/app/page/server-reference-manifest.json +9 -9
  111. package/web/.next/standalone/src/presentation/web/.next/server/app/page_client-reference-manifest.js +1 -1
  112. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__03a0dba7._.js +1 -1
  113. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__19354aea._.js +2 -2
  114. package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__f12b60be._.js +1 -1
  115. package/web/.next/standalone/src/presentation/web/.next/server/pages/500.html +2 -2
  116. package/web/.next/standalone/src/presentation/web/.next/server/server-reference-manifest.js +1 -1
  117. package/web/.next/standalone/src/presentation/web/.next/server/server-reference-manifest.json +10 -10
  118. package/web/.next/standalone/src/presentation/web/server.js +1 -1
  119. package/web/.next/static/chunks/{eca1959e083d0a45.js → 8bea0ce8a07abd50.js} +1 -1
  120. package/web/.next/trace +1 -1
  121. package/web/.next/trace-build +1 -1
  122. /package/web/.next/static/{yvV-GEMagQiZhZAF0YqQs → o1NQgNmvCnthgfg2Ubmf_}/_buildManifest.js +0 -0
  123. /package/web/.next/static/{yvV-GEMagQiZhZAF0YqQs → o1NQgNmvCnthgfg2Ubmf_}/_clientMiddlewareManifest.json +0 -0
  124. /package/web/.next/static/{yvV-GEMagQiZhZAF0YqQs → o1NQgNmvCnthgfg2Ubmf_}/_ssgManifest.js +0 -0
@@ -30,6 +30,7 @@ export interface IFeatureAgentProcessService {
30
30
  resumeFromInterrupt?: boolean;
31
31
  push?: boolean;
32
32
  openPr?: boolean;
33
+ resumePayload?: string;
33
34
  }): number;
34
35
  /**
35
36
  * Check if a process is still alive.
@@ -1 +1 @@
1
- {"version":3,"file":"feature-agent-process.interface.d.ts","sourceRoot":"","sources":["../../../../../../../../packages/core/src/application/ports/output/agents/feature-agent-process.interface.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAC;AAE5E;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC1C;;;;;;;;OAQG;IACH,KAAK,CACH,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,YAAY,CAAC,EAAE,MAAM,EACrB,OAAO,CAAC,EAAE;QACR,aAAa,CAAC,EAAE,aAAa,CAAC;QAC9B,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,mBAAmB,CAAC,EAAE,OAAO,CAAC;QAC9B,IAAI,CAAC,EAAE,OAAO,CAAC;QACf,MAAM,CAAC,EAAE,OAAO,CAAC;KAClB,GACA,MAAM,CAAC;IAEV;;;;;OAKG;IACH,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IAE9B;;;;;OAKG;IACH,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACnD"}
1
+ {"version":3,"file":"feature-agent-process.interface.d.ts","sourceRoot":"","sources":["../../../../../../../../packages/core/src/application/ports/output/agents/feature-agent-process.interface.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,wCAAwC,CAAC;AAE5E;;GAEG;AACH,MAAM,WAAW,2BAA2B;IAC1C;;;;;;;;OAQG;IACH,KAAK,CACH,SAAS,EAAE,MAAM,EACjB,KAAK,EAAE,MAAM,EACb,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,MAAM,EACf,YAAY,CAAC,EAAE,MAAM,EACrB,OAAO,CAAC,EAAE;QACR,aAAa,CAAC,EAAE,aAAa,CAAC;QAC9B,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;QAClB,mBAAmB,CAAC,EAAE,OAAO,CAAC;QAC9B,IAAI,CAAC,EAAE,OAAO,CAAC;QACf,MAAM,CAAC,EAAE,OAAO,CAAC;QACjB,aAAa,CAAC,EAAE,MAAM,CAAC;KACxB,GACA,MAAM,CAAC;IAEV;;;;;OAKG;IACH,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;IAE9B;;;;;OAKG;IACH,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAAC;CACnD"}
@@ -3,20 +3,21 @@
3
3
  *
4
4
  * Approves a paused agent run (waiting_approval status) and
5
5
  * spawns a new resume worker to continue graph execution.
6
+ * Optionally accepts a PrdApprovalPayload to update spec.yaml
7
+ * selections before resuming.
6
8
  */
7
9
  import type { IAgentRunRepository } from '../../ports/output/agents/agent-run-repository.interface.js';
8
10
  import type { IFeatureAgentProcessService } from '../../ports/output/agents/feature-agent-process.interface.js';
9
11
  import type { IPhaseTimingRepository } from '../../ports/output/agents/phase-timing-repository.interface.js';
10
12
  import type { IFeatureRepository } from '../../ports/output/repositories/feature-repository.interface.js';
11
- import type { IWorktreeService } from '../../ports/output/services/worktree-service.interface.js';
13
+ import type { PrdApprovalPayload } from '../../../domain/generated/output.js';
12
14
  export declare class ApproveAgentRunUseCase {
13
15
  private readonly agentRunRepository;
14
16
  private readonly processService;
15
17
  private readonly featureRepository;
16
- private readonly worktreeService;
17
18
  private readonly phaseTimingRepository;
18
- constructor(agentRunRepository: IAgentRunRepository, processService: IFeatureAgentProcessService, featureRepository: IFeatureRepository, worktreeService: IWorktreeService, phaseTimingRepository: IPhaseTimingRepository);
19
- execute(id: string): Promise<{
19
+ constructor(agentRunRepository: IAgentRunRepository, processService: IFeatureAgentProcessService, featureRepository: IFeatureRepository, phaseTimingRepository: IPhaseTimingRepository);
20
+ execute(id: string, payload?: PrdApprovalPayload): Promise<{
20
21
  approved: boolean;
21
22
  reason: string;
22
23
  }>;
@@ -1 +1 @@
1
- {"version":3,"file":"approve-agent-run.use-case.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/application/use-cases/agents/approve-agent-run.use-case.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,6DAA6D,CAAC;AACvG,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,8DAA8D,CAAC;AAChH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gEAAgE,CAAC;AAC7G,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iEAAiE,CAAC;AAC1G,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,2DAA2D,CAAC;AAGlG,qBACa,sBAAsB;IAG/B,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IAEnC,OAAO,CAAC,QAAQ,CAAC,cAAc;IAE/B,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAElC,OAAO,CAAC,QAAQ,CAAC,eAAe;IAEhC,OAAO,CAAC,QAAQ,CAAC,qBAAqB;gBARrB,kBAAkB,EAAE,mBAAmB,EAEvC,cAAc,EAAE,2BAA2B,EAE3C,iBAAiB,EAAE,kBAAkB,EAErC,eAAe,EAAE,gBAAgB,EAEjC,qBAAqB,EAAE,sBAAsB;IAG1D,OAAO,CAAC,EAAE,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CA8D1E"}
1
+ {"version":3,"file":"approve-agent-run.use-case.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/application/use-cases/agents/approve-agent-run.use-case.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAMH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,6DAA6D,CAAC;AACvG,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,8DAA8D,CAAC;AAChH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gEAAgE,CAAC;AAC7G,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iEAAiE,CAAC;AAE1G,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,qCAAqC,CAAC;AAG9E,qBACa,sBAAsB;IAG/B,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IAEnC,OAAO,CAAC,QAAQ,CAAC,cAAc;IAE/B,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAElC,OAAO,CAAC,QAAQ,CAAC,qBAAqB;gBANrB,kBAAkB,EAAE,mBAAmB,EAEvC,cAAc,EAAE,2BAA2B,EAE3C,iBAAiB,EAAE,kBAAkB,EAErC,qBAAqB,EAAE,sBAAsB;IAG1D,OAAO,CACX,EAAE,EAAE,MAAM,EACV,OAAO,CAAC,EAAE,kBAAkB,GAC3B,OAAO,CAAC;QAAE,QAAQ,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAqFlD"}
@@ -3,6 +3,8 @@
3
3
  *
4
4
  * Approves a paused agent run (waiting_approval status) and
5
5
  * spawns a new resume worker to continue graph execution.
6
+ * Optionally accepts a PrdApprovalPayload to update spec.yaml
7
+ * selections before resuming.
6
8
  */
7
9
  var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
8
10
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
@@ -17,21 +19,23 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
17
19
  return function (target, key) { decorator(target, key, paramIndex); }
18
20
  };
19
21
  import { injectable, inject } from 'tsyringe';
22
+ import yaml from 'js-yaml';
23
+ import { readFileSync } from 'node:fs';
24
+ import { join } from 'node:path';
20
25
  import { AgentRunStatus } from '../../../domain/generated/output.js';
26
+ import { writeSpecFileAtomic } from '../../../infrastructure/services/agents/feature-agent/nodes/node-helpers.js';
21
27
  let ApproveAgentRunUseCase = class ApproveAgentRunUseCase {
22
28
  agentRunRepository;
23
29
  processService;
24
30
  featureRepository;
25
- worktreeService;
26
31
  phaseTimingRepository;
27
- constructor(agentRunRepository, processService, featureRepository, worktreeService, phaseTimingRepository) {
32
+ constructor(agentRunRepository, processService, featureRepository, phaseTimingRepository) {
28
33
  this.agentRunRepository = agentRunRepository;
29
34
  this.processService = processService;
30
35
  this.featureRepository = featureRepository;
31
- this.worktreeService = worktreeService;
32
36
  this.phaseTimingRepository = phaseTimingRepository;
33
37
  }
34
- async execute(id) {
38
+ async execute(id, payload) {
35
39
  const run = await this.agentRunRepository.findById(id);
36
40
  if (!run) {
37
41
  return { approved: false, reason: 'Agent run not found' };
@@ -42,12 +46,31 @@ let ApproveAgentRunUseCase = class ApproveAgentRunUseCase {
42
46
  reason: `Agent run is not waiting for approval (status: ${run.status})`,
43
47
  };
44
48
  }
45
- // Look up the feature to get the branch for worktree path derivation
49
+ // Look up the feature to get specPath
46
50
  const feature = run.featureId ? await this.featureRepository.findById(run.featureId) : null;
47
- const repoPath = run.repositoryPath ?? '';
48
- const worktreePath = feature
49
- ? this.worktreeService.getWorktreePath(repoPath, feature.branch)
50
- : repoPath;
51
+ // Write updated selections to spec.yaml if changedSelections provided
52
+ if (payload?.changedSelections && payload.changedSelections.length > 0 && feature?.specPath) {
53
+ try {
54
+ const specDir = feature.specPath;
55
+ const specContent = readFileSync(join(specDir, 'spec.yaml'), 'utf-8');
56
+ const spec = yaml.load(specContent);
57
+ if (Array.isArray(spec?.openQuestions)) {
58
+ for (const change of payload.changedSelections) {
59
+ const question = spec.openQuestions.find((q) => q.question === change.questionId);
60
+ if (question && Array.isArray(question.options)) {
61
+ for (const opt of question.options) {
62
+ opt.selected = opt.option === change.selectedOption;
63
+ }
64
+ question.answer = change.selectedOption;
65
+ }
66
+ }
67
+ }
68
+ writeSpecFileAtomic(specDir, 'spec.yaml', yaml.dump(spec));
69
+ }
70
+ catch {
71
+ // Non-fatal: selection update failure should not block approval
72
+ }
73
+ }
51
74
  const now = new Date();
52
75
  await this.agentRunRepository.updateStatus(id, AgentRunStatus.running, {
53
76
  updatedAt: now,
@@ -69,14 +92,14 @@ let ApproveAgentRunUseCase = class ApproveAgentRunUseCase {
69
92
  catch {
70
93
  // Non-fatal: approval wait timing failure should not block approval
71
94
  }
72
- this.processService.spawn(run.featureId ?? '', id, repoPath, worktreePath, // specDir = worktree path (same as initial spawn)
73
- worktreePath, {
95
+ this.processService.spawn(run.featureId ?? '', id, feature?.repositoryPath ?? run.repositoryPath ?? '', feature?.specPath ?? '', feature?.worktreePath, {
74
96
  resume: true,
75
97
  approvalGates: run.approvalGates,
76
98
  threadId: run.threadId,
77
99
  resumeFromInterrupt: true,
78
100
  push: feature?.push ?? false,
79
101
  openPr: feature?.openPr ?? false,
102
+ ...(payload ? { resumePayload: JSON.stringify(payload) } : {}),
80
103
  });
81
104
  return { approved: true, reason: 'Approved and resumed' };
82
105
  }
@@ -86,8 +109,7 @@ ApproveAgentRunUseCase = __decorate([
86
109
  __param(0, inject('IAgentRunRepository')),
87
110
  __param(1, inject('IFeatureAgentProcessService')),
88
111
  __param(2, inject('IFeatureRepository')),
89
- __param(3, inject('IWorktreeService')),
90
- __param(4, inject('IPhaseTimingRepository')),
91
- __metadata("design:paramtypes", [Object, Object, Object, Object, Object])
112
+ __param(3, inject('IPhaseTimingRepository')),
113
+ __metadata("design:paramtypes", [Object, Object, Object, Object])
92
114
  ], ApproveAgentRunUseCase);
93
115
  export { ApproveAgentRunUseCase };
@@ -2,15 +2,24 @@
2
2
  * Reject Agent Run Use Case
3
3
  *
4
4
  * Rejects a paused agent run (waiting_approval status) and
5
- * marks it as cancelled with the rejection reason.
5
+ * spawns a resume worker to iterate with user feedback.
6
+ * Appends rejection feedback to spec.yaml for tracking.
6
7
  */
7
8
  import type { IAgentRunRepository } from '../../ports/output/agents/agent-run-repository.interface.js';
9
+ import type { IFeatureAgentProcessService } from '../../ports/output/agents/feature-agent-process.interface.js';
10
+ import type { IPhaseTimingRepository } from '../../ports/output/agents/phase-timing-repository.interface.js';
11
+ import type { IFeatureRepository } from '../../ports/output/repositories/feature-repository.interface.js';
8
12
  export declare class RejectAgentRunUseCase {
9
13
  private readonly agentRunRepository;
10
- constructor(agentRunRepository: IAgentRunRepository);
11
- execute(id: string, reason?: string): Promise<{
14
+ private readonly processService;
15
+ private readonly featureRepository;
16
+ private readonly phaseTimingRepository;
17
+ constructor(agentRunRepository: IAgentRunRepository, processService: IFeatureAgentProcessService, featureRepository: IFeatureRepository, phaseTimingRepository: IPhaseTimingRepository);
18
+ execute(id: string, feedback: string): Promise<{
12
19
  rejected: boolean;
13
20
  reason: string;
21
+ iteration?: number;
22
+ iterationWarning?: boolean;
14
23
  }>;
15
24
  }
16
25
  //# sourceMappingURL=reject-agent-run.use-case.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"reject-agent-run.use-case.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/application/use-cases/agents/reject-agent-run.use-case.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,6DAA6D,CAAC;AAGvG,qBACa,qBAAqB;IAG9B,OAAO,CAAC,QAAQ,CAAC,kBAAkB;gBAAlB,kBAAkB,EAAE,mBAAmB;IAGpD,OAAO,CAAC,EAAE,EAAE,MAAM,EAAE,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC;QAAE,QAAQ,EAAE,OAAO,CAAC;QAAC,MAAM,EAAE,MAAM,CAAA;KAAE,CAAC;CAsB3F"}
1
+ {"version":3,"file":"reject-agent-run.use-case.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/application/use-cases/agents/reject-agent-run.use-case.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAMH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,6DAA6D,CAAC;AACvG,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,8DAA8D,CAAC;AAChH,OAAO,KAAK,EAAE,sBAAsB,EAAE,MAAM,gEAAgE,CAAC;AAC7G,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iEAAiE,CAAC;AAQ1G,qBACa,qBAAqB;IAG9B,OAAO,CAAC,QAAQ,CAAC,kBAAkB;IAEnC,OAAO,CAAC,QAAQ,CAAC,cAAc;IAE/B,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IAElC,OAAO,CAAC,QAAQ,CAAC,qBAAqB;gBANrB,kBAAkB,EAAE,mBAAmB,EAEvC,cAAc,EAAE,2BAA2B,EAE3C,iBAAiB,EAAE,kBAAkB,EAErC,qBAAqB,EAAE,sBAAsB;IAG1D,OAAO,CACX,EAAE,EAAE,MAAM,EACV,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC;QACT,QAAQ,EAAE,OAAO,CAAC;QAClB,MAAM,EAAE,MAAM,CAAC;QACf,SAAS,CAAC,EAAE,MAAM,CAAC;QACnB,gBAAgB,CAAC,EAAE,OAAO,CAAC;KAC5B,CAAC;CAuGH"}
@@ -2,7 +2,8 @@
2
2
  * Reject Agent Run Use Case
3
3
  *
4
4
  * Rejects a paused agent run (waiting_approval status) and
5
- * marks it as cancelled with the rejection reason.
5
+ * spawns a resume worker to iterate with user feedback.
6
+ * Appends rejection feedback to spec.yaml for tracking.
6
7
  */
7
8
  var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
8
9
  var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
@@ -17,13 +18,23 @@ var __param = (this && this.__param) || function (paramIndex, decorator) {
17
18
  return function (target, key) { decorator(target, key, paramIndex); }
18
19
  };
19
20
  import { injectable, inject } from 'tsyringe';
21
+ import yaml from 'js-yaml';
22
+ import { readFileSync } from 'node:fs';
23
+ import { join } from 'node:path';
20
24
  import { AgentRunStatus } from '../../../domain/generated/output.js';
25
+ import { writeSpecFileAtomic } from '../../../infrastructure/services/agents/feature-agent/nodes/node-helpers.js';
21
26
  let RejectAgentRunUseCase = class RejectAgentRunUseCase {
22
27
  agentRunRepository;
23
- constructor(agentRunRepository) {
28
+ processService;
29
+ featureRepository;
30
+ phaseTimingRepository;
31
+ constructor(agentRunRepository, processService, featureRepository, phaseTimingRepository) {
24
32
  this.agentRunRepository = agentRunRepository;
33
+ this.processService = processService;
34
+ this.featureRepository = featureRepository;
35
+ this.phaseTimingRepository = phaseTimingRepository;
25
36
  }
26
- async execute(id, reason) {
37
+ async execute(id, feedback) {
27
38
  const run = await this.agentRunRepository.findById(id);
28
39
  if (!run) {
29
40
  return { rejected: false, reason: 'Agent run not found' };
@@ -34,18 +45,87 @@ let RejectAgentRunUseCase = class RejectAgentRunUseCase {
34
45
  reason: `Agent run is not waiting for approval (status: ${run.status})`,
35
46
  };
36
47
  }
48
+ // Validate non-empty feedback
49
+ if (!feedback?.trim()) {
50
+ return { rejected: false, reason: 'Feedback is required for rejection' };
51
+ }
52
+ // Look up feature for spec path
53
+ const feature = run.featureId ? await this.featureRepository.findById(run.featureId) : null;
54
+ if (!feature?.specPath) {
55
+ return { rejected: false, reason: 'Feature has no spec path' };
56
+ }
57
+ // Read and update spec.yaml with rejection feedback
58
+ const specDir = feature.specPath;
59
+ let iteration = 1;
60
+ try {
61
+ const specContent = readFileSync(join(specDir, 'spec.yaml'), 'utf-8');
62
+ const spec = yaml.load(specContent);
63
+ const existingFeedback = Array.isArray(spec?.rejectionFeedback)
64
+ ? spec.rejectionFeedback
65
+ : [];
66
+ iteration = existingFeedback.length + 1;
67
+ const newEntry = {
68
+ iteration,
69
+ message: feedback,
70
+ timestamp: new Date().toISOString(),
71
+ };
72
+ spec.rejectionFeedback = [...existingFeedback, newEntry];
73
+ writeSpecFileAtomic(specDir, 'spec.yaml', yaml.dump(spec));
74
+ }
75
+ catch {
76
+ // If spec.yaml can't be read, still proceed with iteration 1
77
+ }
78
+ // Update run status to running (NOT cancelled)
37
79
  const now = new Date();
38
- await this.agentRunRepository.updateStatus(id, AgentRunStatus.cancelled, {
39
- error: reason ?? 'Rejected by user',
40
- completedAt: now,
80
+ await this.agentRunRepository.updateStatus(id, AgentRunStatus.running, {
41
81
  updatedAt: now,
42
82
  });
43
- return { rejected: true, reason: 'Rejected and cancelled' };
83
+ // Record approval wait duration
84
+ try {
85
+ const timings = await this.phaseTimingRepository.findByRunId(id);
86
+ const waitingTiming = timings.find((t) => t.waitingApprovalAt && !t.approvalWaitMs);
87
+ if (waitingTiming) {
88
+ const waitStart = waitingTiming.waitingApprovalAt instanceof Date
89
+ ? waitingTiming.waitingApprovalAt.getTime()
90
+ : Number(waitingTiming.waitingApprovalAt);
91
+ const approvalWaitMs = BigInt(now.getTime() - waitStart);
92
+ await this.phaseTimingRepository.updateApprovalWait(waitingTiming.id, {
93
+ approvalWaitMs,
94
+ });
95
+ }
96
+ }
97
+ catch {
98
+ // Non-fatal
99
+ }
100
+ // Spawn worker with rejection payload
101
+ const rejectionPayload = {
102
+ rejected: true,
103
+ feedback,
104
+ iteration,
105
+ };
106
+ this.processService.spawn(run.featureId ?? '', id, feature.repositoryPath, feature.specPath, feature.worktreePath, {
107
+ resume: true,
108
+ approvalGates: run.approvalGates,
109
+ threadId: run.threadId,
110
+ resumeFromInterrupt: true,
111
+ push: feature?.push ?? false,
112
+ openPr: feature?.openPr ?? false,
113
+ resumePayload: JSON.stringify(rejectionPayload),
114
+ });
115
+ return {
116
+ rejected: true,
117
+ reason: 'Rejected and iterating',
118
+ iteration,
119
+ iterationWarning: iteration >= 5,
120
+ };
44
121
  }
45
122
  };
46
123
  RejectAgentRunUseCase = __decorate([
47
124
  injectable(),
48
125
  __param(0, inject('IAgentRunRepository')),
49
- __metadata("design:paramtypes", [Object])
126
+ __param(1, inject('IFeatureAgentProcessService')),
127
+ __param(2, inject('IFeatureRepository')),
128
+ __param(3, inject('IPhaseTimingRepository')),
129
+ __metadata("design:paramtypes", [Object, Object, Object, Object])
50
130
  ], RejectAgentRunUseCase);
51
131
  export { RejectAgentRunUseCase };
@@ -0,0 +1,35 @@
1
+ /**
2
+ * Review Feature Use Case
3
+ *
4
+ * Reads spec.yaml open questions for a feature waiting for approval,
5
+ * returning structured data for the TUI review wizard.
6
+ */
7
+ import type { IFeatureRepository } from '../../ports/output/repositories/feature-repository.interface.js';
8
+ import type { IAgentRunRepository } from '../../ports/output/agents/agent-run-repository.interface.js';
9
+ import type { QuestionOption } from '../../../domain/generated/output.js';
10
+ export interface OpenQuestion {
11
+ question: string;
12
+ options: QuestionOption[];
13
+ selectedOption: string;
14
+ selectionRationale?: string;
15
+ answer?: string;
16
+ }
17
+ export interface ReviewFeatureResult {
18
+ success: true;
19
+ questions: OpenQuestion[];
20
+ featureName: string;
21
+ phase: string;
22
+ runId: string;
23
+ repoPath: string;
24
+ }
25
+ export interface ReviewFeatureError {
26
+ success: false;
27
+ reason: string;
28
+ }
29
+ export declare class ReviewFeatureUseCase {
30
+ private readonly featureRepository;
31
+ private readonly agentRunRepository;
32
+ constructor(featureRepository: IFeatureRepository, agentRunRepository: IAgentRunRepository);
33
+ execute(featureId: string, repoPath: string): Promise<ReviewFeatureResult | ReviewFeatureError>;
34
+ }
35
+ //# sourceMappingURL=review-feature.use-case.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"review-feature.use-case.d.ts","sourceRoot":"","sources":["../../../../../../../packages/core/src/application/use-cases/agents/review-feature.use-case.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,iEAAiE,CAAC;AAC1G,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,6DAA6D,CAAC;AAEvG,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,qCAAqC,CAAC;AAE1E,MAAM,WAAW,YAAY;IAC3B,QAAQ,EAAE,MAAM,CAAC;IACjB,OAAO,EAAE,cAAc,EAAE,CAAC;IAC1B,cAAc,EAAE,MAAM,CAAC;IACvB,kBAAkB,CAAC,EAAE,MAAM,CAAC;IAC5B,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,mBAAmB;IAClC,OAAO,EAAE,IAAI,CAAC;IACd,SAAS,EAAE,YAAY,EAAE,CAAC;IAC1B,WAAW,EAAE,MAAM,CAAC;IACpB,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED,MAAM,WAAW,kBAAkB;IACjC,OAAO,EAAE,KAAK,CAAC;IACf,MAAM,EAAE,MAAM,CAAC;CAChB;AAED,qBACa,oBAAoB;IAEC,OAAO,CAAC,QAAQ,CAAC,iBAAiB;IACjC,OAAO,CAAC,QAAQ,CAAC,kBAAkB;gBADnB,iBAAiB,EAAE,kBAAkB,EACpC,kBAAkB,EAAE,mBAAmB;IAGnF,OAAO,CACX,SAAS,EAAE,MAAM,EACjB,QAAQ,EAAE,MAAM,GACf,OAAO,CAAC,mBAAmB,GAAG,kBAAkB,CAAC;CAqDrD"}
@@ -0,0 +1,88 @@
1
+ /**
2
+ * Review Feature Use Case
3
+ *
4
+ * Reads spec.yaml open questions for a feature waiting for approval,
5
+ * returning structured data for the TUI review wizard.
6
+ */
7
+ var __decorate = (this && this.__decorate) || function (decorators, target, key, desc) {
8
+ var c = arguments.length, r = c < 3 ? target : desc === null ? desc = Object.getOwnPropertyDescriptor(target, key) : desc, d;
9
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc);
10
+ else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
11
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
12
+ };
13
+ var __metadata = (this && this.__metadata) || function (k, v) {
14
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
15
+ };
16
+ var __param = (this && this.__param) || function (paramIndex, decorator) {
17
+ return function (target, key) { decorator(target, key, paramIndex); }
18
+ };
19
+ import { injectable, inject } from 'tsyringe';
20
+ import yaml from 'js-yaml';
21
+ import { readFileSync } from 'node:fs';
22
+ import { join } from 'node:path';
23
+ import { AgentRunStatus } from '../../../domain/generated/output.js';
24
+ let ReviewFeatureUseCase = class ReviewFeatureUseCase {
25
+ featureRepository;
26
+ agentRunRepository;
27
+ constructor(featureRepository, agentRunRepository) {
28
+ this.featureRepository = featureRepository;
29
+ this.agentRunRepository = agentRunRepository;
30
+ }
31
+ async execute(featureId, repoPath) {
32
+ // Find feature (try exact match, then prefix)
33
+ const feature = (await this.featureRepository.findById(featureId)) ??
34
+ (await this.featureRepository.findByIdPrefix(featureId));
35
+ if (!feature)
36
+ return { success: false, reason: 'Feature not found' };
37
+ // Find agent run
38
+ if (!feature.agentRunId)
39
+ return { success: false, reason: 'Feature has no agent run' };
40
+ const run = await this.agentRunRepository.findById(feature.agentRunId);
41
+ if (!run || run.status !== AgentRunStatus.waitingApproval) {
42
+ return {
43
+ success: false,
44
+ reason: `Feature is not waiting for approval (status: ${run?.status ?? 'unknown'})`,
45
+ };
46
+ }
47
+ // Read spec.yaml using feature's stored specPath
48
+ if (!feature.specPath) {
49
+ return { success: false, reason: 'Feature has no spec path' };
50
+ }
51
+ const specPath = join(feature.specPath, 'spec.yaml');
52
+ let specContent;
53
+ try {
54
+ specContent = readFileSync(specPath, 'utf-8');
55
+ }
56
+ catch {
57
+ return { success: false, reason: 'Could not read spec.yaml' };
58
+ }
59
+ // Parse openQuestions
60
+ const spec = yaml.load(specContent);
61
+ const openQuestions = spec?.openQuestions;
62
+ if (!Array.isArray(openQuestions) || openQuestions.length === 0) {
63
+ return { success: false, reason: 'No open questions found in spec.yaml' };
64
+ }
65
+ const questions = openQuestions.map((q) => ({
66
+ question: String(q.question ?? ''),
67
+ options: Array.isArray(q.options) ? q.options : [],
68
+ selectedOption: String(q.answer ?? ''),
69
+ selectionRationale: q.selectionRationale ? String(q.selectionRationale) : undefined,
70
+ answer: q.answer ? String(q.answer) : undefined,
71
+ }));
72
+ return {
73
+ success: true,
74
+ questions,
75
+ featureName: feature.name,
76
+ phase: 'requirements',
77
+ runId: run.id,
78
+ repoPath: run.repositoryPath ?? repoPath,
79
+ };
80
+ }
81
+ };
82
+ ReviewFeatureUseCase = __decorate([
83
+ injectable(),
84
+ __param(0, inject('IFeatureRepository')),
85
+ __param(1, inject('IAgentRunRepository')),
86
+ __metadata("design:paramtypes", [Object, Object])
87
+ ], ReviewFeatureUseCase);
88
+ export { ReviewFeatureUseCase };
@@ -791,6 +791,23 @@ export type TechDecision = {
791
791
  */
792
792
  rationale: string;
793
793
  };
794
+ /**
795
+ * Rejection feedback entry for PRD iteration tracking
796
+ */
797
+ export type RejectionFeedbackEntry = {
798
+ /**
799
+ * Iteration number (1-based)
800
+ */
801
+ iteration: number;
802
+ /**
803
+ * User's feedback message explaining what needs to change
804
+ */
805
+ message: string;
806
+ /**
807
+ * When the rejection occurred
808
+ */
809
+ timestamp: any;
810
+ };
794
811
  /**
795
812
  * Implementation phase grouping related tasks
796
813
  */
@@ -898,6 +915,10 @@ export type FeatureArtifact = SpecArtifactBase & {
898
915
  * Size estimate: XS, S, M, L, or XL
899
916
  */
900
917
  sizeEstimate: string;
918
+ /**
919
+ * Rejection feedback history for PRD iterations (append-only)
920
+ */
921
+ rejectionFeedback?: RejectionFeedbackEntry[];
901
922
  };
902
923
  /**
903
924
  * Research artifact documenting technical analysis and decisions
@@ -1597,6 +1618,87 @@ export type PhaseTiming = BaseEntity & {
1597
1618
  */
1598
1619
  approvalWaitMs?: bigint;
1599
1620
  };
1621
+ /**
1622
+ * Change to a question's selected option during PRD review
1623
+ */
1624
+ export type QuestionSelectionChange = {
1625
+ /**
1626
+ * ID of the open question being changed (the question text)
1627
+ */
1628
+ questionId: string;
1629
+ /**
1630
+ * The option text that the user selected
1631
+ */
1632
+ selectedOption: string;
1633
+ };
1634
+ /**
1635
+ * Payload sent when user approves a PRD with optional selection changes
1636
+ */
1637
+ export type PrdApprovalPayload = {
1638
+ /**
1639
+ * Always true for approval payloads
1640
+ */
1641
+ approved: boolean;
1642
+ /**
1643
+ * List of selection changes the user made during review (empty if no changes)
1644
+ */
1645
+ changedSelections?: QuestionSelectionChange[];
1646
+ };
1647
+ /**
1648
+ * Payload sent when user rejects a PRD with feedback for iteration
1649
+ */
1650
+ export type PrdRejectionPayload = {
1651
+ /**
1652
+ * Always true for rejection payloads
1653
+ */
1654
+ rejected: boolean;
1655
+ /**
1656
+ * User's feedback explaining what needs to change
1657
+ */
1658
+ feedback: string;
1659
+ /**
1660
+ * Iteration number (1-based, derived from PhaseTiming row count)
1661
+ */
1662
+ iteration: number;
1663
+ };
1664
+ /**
1665
+ * A single question with its options as presented in the review TUI
1666
+ */
1667
+ export type ReviewQuestion = {
1668
+ /**
1669
+ * The question text
1670
+ */
1671
+ question: string;
1672
+ /**
1673
+ * Available options with selection state
1674
+ */
1675
+ options: QuestionOption[];
1676
+ /**
1677
+ * The option text that was selected by the user
1678
+ */
1679
+ selectedOption: string;
1680
+ /**
1681
+ * Whether the user changed the selection from the AI default
1682
+ */
1683
+ changed: boolean;
1684
+ };
1685
+ /**
1686
+ * Result of the PRD review TUI interaction
1687
+ */
1688
+ export type PrdReviewResult = {
1689
+ /**
1690
+ * All questions with their final selection state
1691
+ */
1692
+ questions: ReviewQuestion[];
1693
+ /**
1694
+ * User action: approve or reject
1695
+ */
1696
+ action: string;
1697
+ /**
1698
+ * Rejection feedback (only present when action is 'reject')
1699
+ */
1700
+ feedback?: string;
1701
+ };
1600
1702
  /**
1601
1703
  * A selectable option within a PRD questionnaire question
1602
1704
  */