@shepai/cli 1.38.0 → 1.39.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/packages/core/src/application/ports/output/agents/feature-agent-process.interface.d.ts +1 -0
- package/dist/packages/core/src/application/ports/output/agents/feature-agent-process.interface.d.ts.map +1 -1
- package/dist/packages/core/src/application/use-cases/agents/approve-agent-run.use-case.d.ts +5 -4
- package/dist/packages/core/src/application/use-cases/agents/approve-agent-run.use-case.d.ts.map +1 -1
- package/dist/packages/core/src/application/use-cases/agents/approve-agent-run.use-case.js +36 -14
- package/dist/packages/core/src/application/use-cases/agents/reject-agent-run.use-case.d.ts +12 -3
- package/dist/packages/core/src/application/use-cases/agents/reject-agent-run.use-case.d.ts.map +1 -1
- package/dist/packages/core/src/application/use-cases/agents/reject-agent-run.use-case.js +88 -8
- package/dist/packages/core/src/application/use-cases/agents/review-feature.use-case.d.ts +35 -0
- package/dist/packages/core/src/application/use-cases/agents/review-feature.use-case.d.ts.map +1 -0
- package/dist/packages/core/src/application/use-cases/agents/review-feature.use-case.js +88 -0
- package/dist/packages/core/src/domain/generated/output.d.ts +102 -0
- package/dist/packages/core/src/domain/generated/output.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/di/container.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/di/container.js +2 -0
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-graph.d.ts +51 -0
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-graph.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-graph.js +21 -2
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-process.service.d.ts +1 -0
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-process.service.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-process.service.js +3 -0
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-worker.d.ts +1 -0
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-worker.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-worker.js +31 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/node-helpers.d.ts +19 -3
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/node-helpers.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/node-helpers.js +101 -16
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/prompts/requirements.prompt.d.ts +2 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/prompts/requirements.prompt.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/prompts/requirements.prompt.js +53 -27
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/phase-timing-context.d.ts +3 -0
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/phase-timing-context.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/phase-timing-context.js +28 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/state.d.ts +3 -0
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/state.d.ts.map +1 -1
- package/dist/packages/core/src/infrastructure/services/agents/feature-agent/state.js +13 -0
- package/dist/src/presentation/cli/commands/agent/reject.command.js +1 -1
- package/dist/src/presentation/cli/commands/feat/reject.command.d.ts.map +1 -1
- package/dist/src/presentation/cli/commands/feat/reject.command.js +6 -4
- package/dist/src/presentation/cli/commands/feat/review.command.d.ts +3 -2
- package/dist/src/presentation/cli/commands/feat/review.command.d.ts.map +1 -1
- package/dist/src/presentation/cli/commands/feat/review.command.js +87 -12
- package/dist/src/presentation/cli/commands/feat/show.command.d.ts.map +1 -1
- package/dist/src/presentation/cli/commands/feat/show.command.js +38 -3
- package/dist/src/presentation/tui/prompts/prd-review-question.prompt.d.ts +30 -0
- package/dist/src/presentation/tui/prompts/prd-review-question.prompt.d.ts.map +1 -0
- package/dist/src/presentation/tui/prompts/prd-review-question.prompt.js +23 -0
- package/dist/src/presentation/tui/prompts/prd-review-summary.prompt.d.ts +29 -0
- package/dist/src/presentation/tui/prompts/prd-review-summary.prompt.d.ts.map +1 -0
- package/dist/src/presentation/tui/prompts/prd-review-summary.prompt.js +29 -0
- package/dist/src/presentation/tui/wizards/merge-review.wizard.d.ts +13 -0
- package/dist/src/presentation/tui/wizards/merge-review.wizard.d.ts.map +1 -0
- package/dist/src/presentation/tui/wizards/merge-review.wizard.js +43 -0
- package/dist/src/presentation/tui/wizards/plan-review.wizard.d.ts +13 -0
- package/dist/src/presentation/tui/wizards/plan-review.wizard.d.ts.map +1 -0
- package/dist/src/presentation/tui/wizards/plan-review.wizard.js +43 -0
- package/dist/src/presentation/tui/wizards/prd-review.wizard.d.ts +26 -0
- package/dist/src/presentation/tui/wizards/prd-review.wizard.d.ts.map +1 -0
- package/dist/src/presentation/tui/wizards/prd-review.wizard.js +42 -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/.tsbuildinfo +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/page/server-reference-manifest.json +9 -9
- package/web/.next/server/app/page_client-reference-manifest.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__03a0dba7._.js +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__03a0dba7._.js.map +1 -1
- package/web/.next/server/chunks/ssr/[root-of-the-server]__19354aea._.js +2 -2
- package/web/.next/server/chunks/ssr/[root-of-the-server]__f12b60be._.js +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_components_e599bb8c._.js.map +1 -1
- package/web/.next/server/chunks/ssr/src_presentation_web_ed0934e5._.js.map +1 -1
- package/web/.next/server/pages/500.html +2 -2
- package/web/.next/server/server-reference-manifest.js +1 -1
- package/web/.next/server/server-reference-manifest.json +10 -10
- package/web/.next/standalone/src/presentation/web/.next/BUILD_ID +1 -1
- package/web/.next/standalone/src/presentation/web/.next/build-manifest.json +2 -2
- package/web/.next/standalone/src/presentation/web/.next/prerender-manifest.json +3 -3
- package/web/.next/standalone/src/presentation/web/.next/required-server-files.json +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.html +2 -2
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.rsc +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/app/page/server-reference-manifest.json +9 -9
- package/web/.next/standalone/src/presentation/web/.next/server/app/page_client-reference-manifest.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__03a0dba7._.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__19354aea._.js +2 -2
- package/web/.next/standalone/src/presentation/web/.next/server/chunks/ssr/[root-of-the-server]__f12b60be._.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/pages/500.html +2 -2
- package/web/.next/standalone/src/presentation/web/.next/server/server-reference-manifest.js +1 -1
- package/web/.next/standalone/src/presentation/web/.next/server/server-reference-manifest.json +10 -10
- package/web/.next/standalone/src/presentation/web/server.js +1 -1
- package/web/.next/static/chunks/{eca1959e083d0a45.js → 429ee8f94032181c.js} +1 -1
- package/web/.next/trace +1 -1
- package/web/.next/trace-build +1 -1
- /package/web/.next/static/{yvV-GEMagQiZhZAF0YqQs → t8z43Apwz2m0TFf1MnAKq}/_buildManifest.js +0 -0
- /package/web/.next/static/{yvV-GEMagQiZhZAF0YqQs → t8z43Apwz2m0TFf1MnAKq}/_clientMiddlewareManifest.json +0 -0
- /package/web/.next/static/{yvV-GEMagQiZhZAF0YqQs → t8z43Apwz2m0TFf1MnAKq}/_ssgManifest.js +0 -0
|
@@ -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;
|
|
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 {
|
|
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,
|
|
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
|
}>;
|
package/dist/packages/core/src/application/use-cases/agents/approve-agent-run.use-case.d.ts.map
CHANGED
|
@@ -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
|
|
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,
|
|
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
|
|
49
|
+
// Look up the feature to get specPath
|
|
46
50
|
const feature = run.featureId ? await this.featureRepository.findById(run.featureId) : null;
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
50
|
-
|
|
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,
|
|
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('
|
|
90
|
-
|
|
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
|
-
*
|
|
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
|
-
|
|
11
|
-
|
|
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
|
package/dist/packages/core/src/application/use-cases/agents/reject-agent-run.use-case.d.ts.map
CHANGED
|
@@ -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
|
|
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
|
-
*
|
|
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
|
-
|
|
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,
|
|
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.
|
|
39
|
-
error: reason ?? 'Rejected by user',
|
|
40
|
-
completedAt: now,
|
|
80
|
+
await this.agentRunRepository.updateStatus(id, AgentRunStatus.running, {
|
|
41
81
|
updatedAt: now,
|
|
42
82
|
});
|
|
43
|
-
|
|
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
|
-
|
|
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
|
*/
|