@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
@@ -35,6 +35,9 @@ export declare function createFeatureAgentGraph(depsOrExecutor: FeatureAgentGrap
35
35
  validationRetries: number;
36
36
  lastValidationTarget: string;
37
37
  lastValidationErrors: string[];
38
+ _approvalAction: string | null;
39
+ _rejectionFeedback: string | null;
40
+ _needsReexecution: boolean;
38
41
  prUrl: string | null;
39
42
  prNumber: number | null;
40
43
  commitHash: string | null;
@@ -53,6 +56,9 @@ export declare function createFeatureAgentGraph(depsOrExecutor: FeatureAgentGrap
53
56
  validationRetries?: number | undefined;
54
57
  lastValidationTarget?: string | undefined;
55
58
  lastValidationErrors?: string[] | undefined;
59
+ _approvalAction?: string | null | undefined;
60
+ _rejectionFeedback?: string | null | undefined;
61
+ _needsReexecution?: boolean | undefined;
56
62
  prUrl?: string | null | undefined;
57
63
  prNumber?: number | null | undefined;
58
64
  commitHash?: string | null | undefined;
@@ -91,6 +97,9 @@ export declare function createFeatureAgentGraph(depsOrExecutor: FeatureAgentGrap
91
97
  validationRetries: import("@langchain/langgraph").BinaryOperatorAggregate<number, number>;
92
98
  lastValidationTarget: import("@langchain/langgraph").BinaryOperatorAggregate<string, string>;
93
99
  lastValidationErrors: import("@langchain/langgraph").BinaryOperatorAggregate<string[], string[]>;
100
+ _approvalAction: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
101
+ _rejectionFeedback: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
102
+ _needsReexecution: import("@langchain/langgraph").BinaryOperatorAggregate<boolean, boolean>;
94
103
  prUrl: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
95
104
  prNumber: import("@langchain/langgraph").BinaryOperatorAggregate<number | null, number | null>;
96
105
  commitHash: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
@@ -129,6 +138,9 @@ export declare function createFeatureAgentGraph(depsOrExecutor: FeatureAgentGrap
129
138
  validationRetries: import("@langchain/langgraph").BinaryOperatorAggregate<number, number>;
130
139
  lastValidationTarget: import("@langchain/langgraph").BinaryOperatorAggregate<string, string>;
131
140
  lastValidationErrors: import("@langchain/langgraph").BinaryOperatorAggregate<string[], string[]>;
141
+ _approvalAction: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
142
+ _rejectionFeedback: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
143
+ _needsReexecution: import("@langchain/langgraph").BinaryOperatorAggregate<boolean, boolean>;
132
144
  prUrl: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
133
145
  prNumber: import("@langchain/langgraph").BinaryOperatorAggregate<number | null, number | null>;
134
146
  commitHash: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
@@ -168,6 +180,9 @@ export declare function createFeatureAgentGraph(depsOrExecutor: FeatureAgentGrap
168
180
  validationRetries: import("@langchain/langgraph").BinaryOperatorAggregate<number, number>;
169
181
  lastValidationTarget: import("@langchain/langgraph").BinaryOperatorAggregate<string, string>;
170
182
  lastValidationErrors: import("@langchain/langgraph").BinaryOperatorAggregate<string[], string[]>;
183
+ _approvalAction: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
184
+ _rejectionFeedback: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
185
+ _needsReexecution: import("@langchain/langgraph").BinaryOperatorAggregate<boolean, boolean>;
171
186
  prUrl: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
172
187
  prNumber: import("@langchain/langgraph").BinaryOperatorAggregate<number | null, number | null>;
173
188
  commitHash: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
@@ -207,6 +222,9 @@ export declare function createFeatureAgentGraph(depsOrExecutor: FeatureAgentGrap
207
222
  validationRetries: import("@langchain/langgraph").BinaryOperatorAggregate<number, number>;
208
223
  lastValidationTarget: import("@langchain/langgraph").BinaryOperatorAggregate<string, string>;
209
224
  lastValidationErrors: import("@langchain/langgraph").BinaryOperatorAggregate<string[], string[]>;
225
+ _approvalAction: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
226
+ _rejectionFeedback: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
227
+ _needsReexecution: import("@langchain/langgraph").BinaryOperatorAggregate<boolean, boolean>;
210
228
  prUrl: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
211
229
  prNumber: import("@langchain/langgraph").BinaryOperatorAggregate<number | null, number | null>;
212
230
  commitHash: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
@@ -246,6 +264,9 @@ export declare function createFeatureAgentGraph(depsOrExecutor: FeatureAgentGrap
246
264
  validationRetries: import("@langchain/langgraph").BinaryOperatorAggregate<number, number>;
247
265
  lastValidationTarget: import("@langchain/langgraph").BinaryOperatorAggregate<string, string>;
248
266
  lastValidationErrors: import("@langchain/langgraph").BinaryOperatorAggregate<string[], string[]>;
267
+ _approvalAction: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
268
+ _rejectionFeedback: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
269
+ _needsReexecution: import("@langchain/langgraph").BinaryOperatorAggregate<boolean, boolean>;
249
270
  prUrl: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
250
271
  prNumber: import("@langchain/langgraph").BinaryOperatorAggregate<number | null, number | null>;
251
272
  commitHash: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
@@ -285,6 +306,9 @@ export declare function createFeatureAgentGraph(depsOrExecutor: FeatureAgentGrap
285
306
  validationRetries: import("@langchain/langgraph").BinaryOperatorAggregate<number, number>;
286
307
  lastValidationTarget: import("@langchain/langgraph").BinaryOperatorAggregate<string, string>;
287
308
  lastValidationErrors: import("@langchain/langgraph").BinaryOperatorAggregate<string[], string[]>;
309
+ _approvalAction: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
310
+ _rejectionFeedback: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
311
+ _needsReexecution: import("@langchain/langgraph").BinaryOperatorAggregate<boolean, boolean>;
288
312
  prUrl: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
289
313
  prNumber: import("@langchain/langgraph").BinaryOperatorAggregate<number | null, number | null>;
290
314
  commitHash: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
@@ -324,6 +348,9 @@ export declare function createFeatureAgentGraph(depsOrExecutor: FeatureAgentGrap
324
348
  validationRetries: import("@langchain/langgraph").BinaryOperatorAggregate<number, number>;
325
349
  lastValidationTarget: import("@langchain/langgraph").BinaryOperatorAggregate<string, string>;
326
350
  lastValidationErrors: import("@langchain/langgraph").BinaryOperatorAggregate<string[], string[]>;
351
+ _approvalAction: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
352
+ _rejectionFeedback: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
353
+ _needsReexecution: import("@langchain/langgraph").BinaryOperatorAggregate<boolean, boolean>;
327
354
  prUrl: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
328
355
  prNumber: import("@langchain/langgraph").BinaryOperatorAggregate<number | null, number | null>;
329
356
  commitHash: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
@@ -363,6 +390,9 @@ export declare function createFeatureAgentGraph(depsOrExecutor: FeatureAgentGrap
363
390
  validationRetries: import("@langchain/langgraph").BinaryOperatorAggregate<number, number>;
364
391
  lastValidationTarget: import("@langchain/langgraph").BinaryOperatorAggregate<string, string>;
365
392
  lastValidationErrors: import("@langchain/langgraph").BinaryOperatorAggregate<string[], string[]>;
393
+ _approvalAction: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
394
+ _rejectionFeedback: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
395
+ _needsReexecution: import("@langchain/langgraph").BinaryOperatorAggregate<boolean, boolean>;
366
396
  prUrl: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
367
397
  prNumber: import("@langchain/langgraph").BinaryOperatorAggregate<number | null, number | null>;
368
398
  commitHash: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
@@ -402,6 +432,9 @@ export declare function createFeatureAgentGraph(depsOrExecutor: FeatureAgentGrap
402
432
  validationRetries: import("@langchain/langgraph").BinaryOperatorAggregate<number, number>;
403
433
  lastValidationTarget: import("@langchain/langgraph").BinaryOperatorAggregate<string, string>;
404
434
  lastValidationErrors: import("@langchain/langgraph").BinaryOperatorAggregate<string[], string[]>;
435
+ _approvalAction: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
436
+ _rejectionFeedback: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
437
+ _needsReexecution: import("@langchain/langgraph").BinaryOperatorAggregate<boolean, boolean>;
405
438
  prUrl: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
406
439
  prNumber: import("@langchain/langgraph").BinaryOperatorAggregate<number | null, number | null>;
407
440
  commitHash: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
@@ -441,6 +474,9 @@ export declare function createFeatureAgentGraph(depsOrExecutor: FeatureAgentGrap
441
474
  validationRetries: import("@langchain/langgraph").BinaryOperatorAggregate<number, number>;
442
475
  lastValidationTarget: import("@langchain/langgraph").BinaryOperatorAggregate<string, string>;
443
476
  lastValidationErrors: import("@langchain/langgraph").BinaryOperatorAggregate<string[], string[]>;
477
+ _approvalAction: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
478
+ _rejectionFeedback: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
479
+ _needsReexecution: import("@langchain/langgraph").BinaryOperatorAggregate<boolean, boolean>;
444
480
  prUrl: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
445
481
  prNumber: import("@langchain/langgraph").BinaryOperatorAggregate<number | null, number | null>;
446
482
  commitHash: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
@@ -480,6 +516,9 @@ export declare function createFeatureAgentGraph(depsOrExecutor: FeatureAgentGrap
480
516
  validationRetries: import("@langchain/langgraph").BinaryOperatorAggregate<number, number>;
481
517
  lastValidationTarget: import("@langchain/langgraph").BinaryOperatorAggregate<string, string>;
482
518
  lastValidationErrors: import("@langchain/langgraph").BinaryOperatorAggregate<string[], string[]>;
519
+ _approvalAction: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
520
+ _rejectionFeedback: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
521
+ _needsReexecution: import("@langchain/langgraph").BinaryOperatorAggregate<boolean, boolean>;
483
522
  prUrl: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
484
523
  prNumber: import("@langchain/langgraph").BinaryOperatorAggregate<number | null, number | null>;
485
524
  commitHash: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
@@ -519,6 +558,9 @@ export declare function createFeatureAgentGraph(depsOrExecutor: FeatureAgentGrap
519
558
  validationRetries: import("@langchain/langgraph").BinaryOperatorAggregate<number, number>;
520
559
  lastValidationTarget: import("@langchain/langgraph").BinaryOperatorAggregate<string, string>;
521
560
  lastValidationErrors: import("@langchain/langgraph").BinaryOperatorAggregate<string[], string[]>;
561
+ _approvalAction: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
562
+ _rejectionFeedback: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
563
+ _needsReexecution: import("@langchain/langgraph").BinaryOperatorAggregate<boolean, boolean>;
522
564
  prUrl: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
523
565
  prNumber: import("@langchain/langgraph").BinaryOperatorAggregate<number | null, number | null>;
524
566
  commitHash: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
@@ -558,6 +600,9 @@ export declare function createFeatureAgentGraph(depsOrExecutor: FeatureAgentGrap
558
600
  validationRetries: import("@langchain/langgraph").BinaryOperatorAggregate<number, number>;
559
601
  lastValidationTarget: import("@langchain/langgraph").BinaryOperatorAggregate<string, string>;
560
602
  lastValidationErrors: import("@langchain/langgraph").BinaryOperatorAggregate<string[], string[]>;
603
+ _approvalAction: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
604
+ _rejectionFeedback: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
605
+ _needsReexecution: import("@langchain/langgraph").BinaryOperatorAggregate<boolean, boolean>;
561
606
  prUrl: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
562
607
  prNumber: import("@langchain/langgraph").BinaryOperatorAggregate<number | null, number | null>;
563
608
  commitHash: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
@@ -597,6 +642,9 @@ export declare function createFeatureAgentGraph(depsOrExecutor: FeatureAgentGrap
597
642
  validationRetries: import("@langchain/langgraph").BinaryOperatorAggregate<number, number>;
598
643
  lastValidationTarget: import("@langchain/langgraph").BinaryOperatorAggregate<string, string>;
599
644
  lastValidationErrors: import("@langchain/langgraph").BinaryOperatorAggregate<string[], string[]>;
645
+ _approvalAction: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
646
+ _rejectionFeedback: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
647
+ _needsReexecution: import("@langchain/langgraph").BinaryOperatorAggregate<boolean, boolean>;
600
648
  prUrl: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
601
649
  prNumber: import("@langchain/langgraph").BinaryOperatorAggregate<number | null, number | null>;
602
650
  commitHash: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
@@ -636,6 +684,9 @@ export declare function createFeatureAgentGraph(depsOrExecutor: FeatureAgentGrap
636
684
  validationRetries: import("@langchain/langgraph").BinaryOperatorAggregate<number, number>;
637
685
  lastValidationTarget: import("@langchain/langgraph").BinaryOperatorAggregate<string, string>;
638
686
  lastValidationErrors: import("@langchain/langgraph").BinaryOperatorAggregate<string[], string[]>;
687
+ _approvalAction: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
688
+ _rejectionFeedback: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
689
+ _needsReexecution: import("@langchain/langgraph").BinaryOperatorAggregate<boolean, boolean>;
639
690
  prUrl: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
640
691
  prNumber: import("@langchain/langgraph").BinaryOperatorAggregate<number | null, number | null>;
641
692
  commitHash: import("@langchain/langgraph").BinaryOperatorAggregate<string | null, string | null>;
@@ -1 +1 @@
1
- {"version":3,"file":"feature-agent-graph.d.ts","sourceRoot":"","sources":["../../../../../../../../packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-graph.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0B,KAAK,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AACxF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+DAA+D,CAAC;AAOpG,OAAO,EAAmB,KAAK,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAS5E,OAAO,EAAE,sBAAsB,EAAE,KAAK,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE5E;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,cAAc,CAAC;IACzB,aAAa,EAAE,aAAa,CAAC;CAC9B;AAuGD;;;;;;;;;;;;GAYG;AACH,wBAAgB,uBAAuB,CACrC,cAAc,EAAE,qBAAqB,GAAG,cAAc,EACtD,YAAY,CAAC,EAAE,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBAmEnC"}
1
+ {"version":3,"file":"feature-agent-graph.d.ts","sourceRoot":"","sources":["../../../../../../../../packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-graph.ts"],"names":[],"mappings":"AAAA,OAAO,EAA0B,KAAK,mBAAmB,EAAE,MAAM,sBAAsB,CAAC;AACxF,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,+DAA+D,CAAC;AAOpG,OAAO,EAAmB,KAAK,aAAa,EAAE,MAAM,uBAAuB,CAAC;AAS5E,OAAO,EAAE,sBAAsB,EAAE,KAAK,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE5E;;;GAGG;AACH,MAAM,WAAW,qBAAqB;IACpC,QAAQ,EAAE,cAAc,CAAC;IACzB,aAAa,EAAE,aAAa,CAAC;CAC9B;AAyHD;;;;;;;;;;;;GAYG;AACH,wBAAgB,uBAAuB,CACrC,cAAc,EAAE,qBAAqB,GAAG,cAAc,EACtD,YAAY,CAAC,EAAE,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;qBA0EnC"}
@@ -14,6 +14,21 @@ import { validatePlan, validateTasks } from './nodes/schemas/plan.schema.js';
14
14
  import { readSpecFile, safeYamlLoad, createNodeLogger } from './nodes/node-helpers.js';
15
15
  // Re-export state types for consumers
16
16
  export { FeatureAgentAnnotation } from './state.js';
17
+ /**
18
+ * Factory that creates a conditional edge function for re-execution routing.
19
+ *
20
+ * After an interruptible node resumes, it returns early with _needsReexecution
21
+ * set to true (rejection) or false (approval). This edge routes back to the
22
+ * same node on rejection for a fresh invocation, avoiding the stale interrupt
23
+ * replay bug caused by dual interrupt() calls.
24
+ */
25
+ function routeReexecution(selfNode, nextNode) {
26
+ return (state) => {
27
+ if (state._needsReexecution)
28
+ return selfNode;
29
+ return nextNode;
30
+ };
31
+ }
17
32
  /**
18
33
  * Factory that creates a conditional edge function for validation routing.
19
34
  *
@@ -141,17 +156,21 @@ export function createFeatureAgentGraph(depsOrExecutor, checkpointer) {
141
156
  .addNode('repair_research', createRepairNode('research.yaml', executor))
142
157
  .addNode('repair_plan_tasks', createRepairNode(['plan.yaml', 'tasks.yaml'], executor))
143
158
  // --- Edges: linear flow with validation gates ---
159
+ // Interruptible nodes (requirements, plan) use conditional edges that
160
+ // check _needsReexecution to loop back on rejection. This ensures each
161
+ // re-execution is a fresh node invocation with a clean interrupt index,
162
+ // avoiding the stale interrupt replay bug with dual interrupt() calls.
144
163
  .addEdge(START, 'analyze')
145
164
  .addEdge('analyze', 'validate_spec_analyze')
146
165
  .addConditionalEdges('validate_spec_analyze', routeValidation('requirements', 'repair_spec_analyze'))
147
166
  .addEdge('repair_spec_analyze', 'validate_spec_analyze')
148
- .addEdge('requirements', 'validate_spec_requirements')
167
+ .addConditionalEdges('requirements', routeReexecution('requirements', 'validate_spec_requirements'))
149
168
  .addConditionalEdges('validate_spec_requirements', routeValidation('research', 'repair_spec_requirements'))
150
169
  .addEdge('repair_spec_requirements', 'validate_spec_requirements')
151
170
  .addEdge('research', 'validate_research')
152
171
  .addConditionalEdges('validate_research', routeValidation('plan', 'repair_research'))
153
172
  .addEdge('repair_research', 'validate_research')
154
- .addEdge('plan', 'validate_plan_tasks')
173
+ .addConditionalEdges('plan', routeReexecution('plan', 'validate_plan_tasks'))
155
174
  .addConditionalEdges('validate_plan_tasks', routeValidation('implement', 'repair_plan_tasks'))
156
175
  .addEdge('repair_plan_tasks', 'validate_plan_tasks');
157
176
  // --- Merge node: wired when deps are provided ---
@@ -18,6 +18,7 @@ export declare class FeatureAgentProcessService implements IFeatureAgentProcessS
18
18
  resumeFromInterrupt?: boolean;
19
19
  push?: boolean;
20
20
  openPr?: boolean;
21
+ resumePayload?: string;
21
22
  }): number;
22
23
  isAlive(pid: number): boolean;
23
24
  checkAndMarkCrashed(runId: string): Promise<void>;
@@ -1 +1 @@
1
- {"version":3,"file":"feature-agent-process.service.d.ts","sourceRoot":"","sources":["../../../../../../../../packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-process.service.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AASH,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,sEAAsE,CAAC;AACxH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qEAAqE,CAAC;AAC/G,OAAO,EAAkB,KAAK,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAYlF,qBAAa,0BAA2B,YAAW,2BAA2B;IAChE,OAAO,CAAC,QAAQ,CAAC,aAAa;gBAAb,aAAa,EAAE,mBAAmB;IAE/D,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;IAuDT,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IASvB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAexD"}
1
+ {"version":3,"file":"feature-agent-process.service.d.ts","sourceRoot":"","sources":["../../../../../../../../packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-process.service.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AASH,OAAO,KAAK,EAAE,2BAA2B,EAAE,MAAM,sEAAsE,CAAC;AACxH,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,qEAAqE,CAAC;AAC/G,OAAO,EAAkB,KAAK,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAYlF,qBAAa,0BAA2B,YAAW,2BAA2B;IAChE,OAAO,CAAC,QAAQ,CAAC,aAAa;gBAAb,aAAa,EAAE,mBAAmB;IAE/D,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;IA0DT,OAAO,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO;IASvB,mBAAmB,CAAC,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAexD"}
@@ -59,6 +59,9 @@ export class FeatureAgentProcessService {
59
59
  if (options?.openPr) {
60
60
  args.push('--open-pr');
61
61
  }
62
+ if (options?.resumePayload) {
63
+ args.push('--resume-payload', options.resumePayload);
64
+ }
62
65
  // Create log file for worker output (for debugging)
63
66
  const logsDir = join(homedir(), '.shep', 'logs');
64
67
  mkdirSync(logsDir, { recursive: true });
@@ -22,6 +22,7 @@ export interface WorkerArgs {
22
22
  resumeFromInterrupt?: boolean;
23
23
  push?: boolean;
24
24
  openPr?: boolean;
25
+ resumePayload?: string;
25
26
  }
26
27
  /**
27
28
  * Parse CLI arguments into a WorkerArgs object.
@@ -1 +1 @@
1
- {"version":3,"file":"feature-agent-worker.d.ts","sourceRoot":"","sources":["../../../../../../../../packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-worker.ts"],"names":[],"mappings":";AACA;;;;;;;;GAQG;AAEH,OAAO,kBAAkB,CAAC;AAqB1B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAElE,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,CA6C1D;AAgCD;;;GAGG;AACH,wBAAsB,SAAS,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAoK/D"}
1
+ {"version":3,"file":"feature-agent-worker.d.ts","sourceRoot":"","sources":["../../../../../../../../packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-worker.ts"],"names":[],"mappings":";AACA;;;;;;;;GAQG;AAEH,OAAO,kBAAkB,CAAC;AAqB1B,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAElE,MAAM,WAAW,UAAU;IACzB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,MAAM,CAAC;IACd,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,YAAY,CAAC,EAAE,MAAM,CAAC;IACtB,aAAa,CAAC,EAAE,aAAa,CAAC;IAC9B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,mBAAmB,CAAC,EAAE,OAAO,CAAC;IAC9B,IAAI,CAAC,EAAE,OAAO,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB;AAED;;;GAGG;AACH,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,UAAU,CAoD1D;AAgCD;;;GAGG;AACH,wBAAsB,SAAS,CAAC,IAAI,EAAE,UAAU,GAAG,OAAO,CAAC,IAAI,CAAC,CAkM/D"}
@@ -53,6 +53,10 @@ export function parseWorkerArgs(args) {
53
53
  const openPr = args.includes('--open-pr');
54
54
  const threadIdx = args.indexOf('--thread-id');
55
55
  const threadId = threadIdx !== -1 && threadIdx + 1 < args.length ? args[threadIdx + 1] : undefined;
56
+ const resumePayloadIdx = args.indexOf('--resume-payload');
57
+ const resumePayload = resumePayloadIdx !== -1 && resumePayloadIdx + 1 < args.length
58
+ ? args[resumePayloadIdx + 1]
59
+ : undefined;
56
60
  return {
57
61
  featureId: getArg('feature-id'),
58
62
  runId: getArg('run-id'),
@@ -65,6 +69,7 @@ export function parseWorkerArgs(args) {
65
69
  resumeFromInterrupt,
66
70
  push,
67
71
  openPr,
72
+ resumePayload,
68
73
  };
69
74
  }
70
75
  /** Simple worker logger — writes to stdout which is redirected to log file by the parent. */
@@ -163,8 +168,33 @@ export async function runWorker(args) {
163
168
  let result;
164
169
  if (args.resume && args.resumeFromInterrupt) {
165
170
  // Resume from an interrupt (human-in-the-loop approval)
171
+ let resumeValue = { approved: true }; // default backward-compatible
172
+ if (args.resumePayload) {
173
+ try {
174
+ resumeValue = JSON.parse(args.resumePayload);
175
+ log(`Resuming with typed payload: ${args.resumePayload.slice(0, 200)}`);
176
+ }
177
+ catch (e) {
178
+ log(`Warning: Failed to parse --resume-payload, using default approval: ${e}`);
179
+ }
180
+ }
181
+ // Derive state updates from the resume payload so executeNode() can
182
+ // read _approvalAction from state instead of from interrupt() return
183
+ // value (fixes the dual-interrupt stale replay bug).
184
+ const stateUpdate = {};
185
+ if (typeof resumeValue === 'object' &&
186
+ resumeValue !== null &&
187
+ 'rejected' in resumeValue &&
188
+ resumeValue.rejected === true) {
189
+ stateUpdate._approvalAction = 'rejected';
190
+ stateUpdate._rejectionFeedback = resumeValue.feedback ?? null;
191
+ }
192
+ else {
193
+ stateUpdate._approvalAction = 'approved';
194
+ stateUpdate._rejectionFeedback = null;
195
+ }
166
196
  log('Resuming graph from interrupt checkpoint...');
167
- result = await graph.invoke(new Command({ resume: { approved: true } }), graphConfig);
197
+ result = await graph.invoke(new Command({ resume: resumeValue, update: stateUpdate }), graphConfig);
168
198
  }
169
199
  else if (args.resume) {
170
200
  // Resume from error — re-invoke with initial state; LangGraph continues
@@ -39,9 +39,8 @@ export declare function safeYamlLoad(content: string): unknown;
39
39
  * - allowPlan: when true, skip interrupt after plan phase
40
40
  * - allowMerge: when true, skip interrupt after merge phase
41
41
  *
42
- * Nodes not covered by a gate (analyze, research) never interrupt.
43
- * The implement node always interrupts when gates are present
44
- * (unless all three gates are true, meaning fully autonomous).
42
+ * Nodes not covered by a gate (analyze, research, implement) never interrupt.
43
+ * Implementation always proceeds to merge; the merge node handles its own gate.
45
44
  *
46
45
  */
47
46
  export declare function shouldInterrupt(nodeName: string, gates: ApprovalGates | undefined): boolean;
@@ -75,10 +74,27 @@ export declare function retryExecute(executor: IAgentExecutor, prompt: string, o
75
74
  * Read completed phases from feature.yaml.
76
75
  */
77
76
  export declare function getCompletedPhases(specDir: string): string[];
77
+ /**
78
+ * Remove a phase from completedPhases in feature.yaml.
79
+ * Used when a phase is rejected and needs to re-execute.
80
+ */
81
+ export declare function clearCompletedPhase(specDir: string, phaseId: string, log?: NodeLogger): void;
82
+ /**
83
+ * Type guard to detect rejection payloads from interrupt() return value.
84
+ */
85
+ export declare function isRejectionPayload(value: unknown): value is {
86
+ rejected: true;
87
+ feedback: string;
88
+ };
78
89
  /**
79
90
  * Mark a phase as complete in feature.yaml by adding its ID to completedPhases.
80
91
  */
81
92
  export declare function markPhaseComplete(specDir: string, phaseId: string, log?: NodeLogger): void;
93
+ /**
94
+ * Write a spec file atomically using temp-file-then-rename pattern.
95
+ * Prevents corruption on crash mid-write.
96
+ */
97
+ export declare function writeSpecFileAtomic(specDir: string, filename: string, content: string): void;
82
98
  /**
83
99
  * Execute a node with consistent logging and error handling.
84
100
  *
@@ -1 +1 @@
1
- {"version":3,"file":"node-helpers.d.ts","sourceRoot":"","sources":["../../../../../../../../../packages/core/src/infrastructure/services/agents/feature-agent/nodes/node-helpers.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,KAAK,EACV,cAAc,EACd,qBAAqB,EACrB,oBAAoB,EACrB,MAAM,+DAA+D,CAAC;AACvE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AASrD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM;kBAE/B,MAAM,GAAG,IAAI;mBAIZ,MAAM,GAAG,IAAI;EAK/B;AAED,MAAM,MAAM,UAAU,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE7D;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAMtE;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,iBAAiB,GAAG,qBAAqB,CAMpF;AAeD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAQrD;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,SAAS,GAAG,OAAO,CAS3F;AAMD,MAAM,MAAM,aAAa,GAAG,eAAe,GAAG,mBAAmB,GAAG,eAAe,GAAG,SAAS,CAAC;AAMhG;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,YAAY,EAAE,MAAM,GAAG,aAAa,CAKjE;AAED,MAAM,WAAW,YAAY;IAC3B,wDAAwD;IACxD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kFAAkF;IAClF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0CAA0C;IAC1C,MAAM,CAAC,EAAE,UAAU,CAAC;CACrB;AAED;;;;;;GAMG;AACH,wBAAsB,YAAY,CAChC,QAAQ,EAAE,cAAc,EACxB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,qBAAqB,EAC9B,SAAS,CAAC,EAAE,YAAY,GACvB,OAAO,CAAC,oBAAoB,CAAC,CA6B/B;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAW5D;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,UAAU,GAAG,IAAI,CAwB1F;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CACzB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,cAAc,EACxB,WAAW,EAAE,CAAC,KAAK,EAAE,iBAAiB,EAAE,GAAG,EAAE,UAAU,KAAK,MAAM,GACjE,CAAC,KAAK,EAAE,iBAAiB,KAAK,OAAO,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAiFnE"}
1
+ {"version":3,"file":"node-helpers.d.ts","sourceRoot":"","sources":["../../../../../../../../../packages/core/src/infrastructure/services/agents/feature-agent/nodes/node-helpers.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAMH,OAAO,KAAK,EACV,cAAc,EACd,qBAAqB,EACrB,oBAAoB,EACrB,MAAM,+DAA+D,CAAC;AACvE,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAC;AAClE,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AASrD;;;GAGG;AACH,wBAAgB,gBAAgB,CAAC,QAAQ,EAAE,MAAM;kBAE/B,MAAM,GAAG,IAAI;mBAIZ,MAAM,GAAG,IAAI;EAK/B;AAED,MAAM,MAAM,UAAU,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;AAE7D;;GAEG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,MAAM,CAMtE;AAED;;GAEG;AACH,wBAAgB,oBAAoB,CAAC,KAAK,EAAE,iBAAiB,GAAG,qBAAqB,CAMpF;AAeD;;;;GAIG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAQrD;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,EAAE,KAAK,EAAE,aAAa,GAAG,SAAS,GAAG,OAAO,CAQ3F;AAMD,MAAM,MAAM,aAAa,GAAG,eAAe,GAAG,mBAAmB,GAAG,eAAe,GAAG,SAAS,CAAC;AAMhG;;;;;;;GAOG;AACH,wBAAgB,aAAa,CAAC,YAAY,EAAE,MAAM,GAAG,aAAa,CAKjE;AAED,MAAM,WAAW,YAAY;IAC3B,wDAAwD;IACxD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,kFAAkF;IAClF,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,0CAA0C;IAC1C,MAAM,CAAC,EAAE,UAAU,CAAC;CACrB;AAED;;;;;;GAMG;AACH,wBAAsB,YAAY,CAChC,QAAQ,EAAE,cAAc,EACxB,MAAM,EAAE,MAAM,EACd,OAAO,EAAE,qBAAqB,EAC9B,SAAS,CAAC,EAAE,YAAY,GACvB,OAAO,CAAC,oBAAoB,CAAC,CA6B/B;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,GAAG,MAAM,EAAE,CAW5D;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,UAAU,GAAG,IAAI,CAqB5F;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,OAAO,GAAG,KAAK,IAAI;IAAE,QAAQ,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAOhG;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,EAAE,GAAG,CAAC,EAAE,UAAU,GAAG,IAAI,CAwB1F;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,MAAM,GAAG,IAAI,CAa5F;AAED;;;;;;;GAOG;AACH,wBAAgB,WAAW,CACzB,QAAQ,EAAE,MAAM,EAChB,QAAQ,EAAE,cAAc,EACxB,WAAW,EAAE,CAAC,KAAK,EAAE,iBAAiB,EAAE,GAAG,EAAE,UAAU,KAAK,MAAM,GACjE,CAAC,KAAK,EAAE,iBAAiB,KAAK,OAAO,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAmHnE"}
@@ -5,7 +5,7 @@
5
5
  * and error handling so every node follows the same patterns.
6
6
  */
7
7
  import yaml from 'js-yaml';
8
- import { readFileSync, writeFileSync } from 'node:fs';
8
+ import { readFileSync, writeFileSync, renameSync, unlinkSync } from 'node:fs';
9
9
  import { join } from 'node:path';
10
10
  import { interrupt, isGraphBubbleUp } from '@langchain/langgraph';
11
11
  import { reportNodeStart } from '../heartbeat.js';
@@ -81,9 +81,8 @@ export function safeYamlLoad(content) {
81
81
  * - allowPlan: when true, skip interrupt after plan phase
82
82
  * - allowMerge: when true, skip interrupt after merge phase
83
83
  *
84
- * Nodes not covered by a gate (analyze, research) never interrupt.
85
- * The implement node always interrupts when gates are present
86
- * (unless all three gates are true, meaning fully autonomous).
84
+ * Nodes not covered by a gate (analyze, research, implement) never interrupt.
85
+ * Implementation always proceeds to merge; the merge node handles its own gate.
87
86
  *
88
87
  */
89
88
  export function shouldInterrupt(nodeName, gates) {
@@ -97,8 +96,6 @@ export function shouldInterrupt(nodeName, gates) {
97
96
  return !gates.allowPlan;
98
97
  if (nodeName === 'merge')
99
98
  return !gates.allowMerge;
100
- if (nodeName === 'implement')
101
- return true;
102
99
  return false;
103
100
  }
104
101
  const API_ERROR_RE = /API Error: (400|429|5\d{2})/;
@@ -169,6 +166,38 @@ export function getCompletedPhases(specDir) {
169
166
  return [];
170
167
  }
171
168
  }
169
+ /**
170
+ * Remove a phase from completedPhases in feature.yaml.
171
+ * Used when a phase is rejected and needs to re-execute.
172
+ */
173
+ export function clearCompletedPhase(specDir, phaseId, log) {
174
+ try {
175
+ const content = readSpecFile(specDir, 'feature.yaml');
176
+ if (!content)
177
+ return;
178
+ const data = yaml.load(content);
179
+ if (!data || typeof data !== 'object')
180
+ return;
181
+ const status = (data.status ?? {});
182
+ const completedPhases = Array.isArray(status.completedPhases)
183
+ ? status.completedPhases.filter((p) => p !== phaseId)
184
+ : [];
185
+ data.status = { ...status, completedPhases };
186
+ writeFileSync(join(specDir, 'feature.yaml'), yaml.dump(data, { indent: 2, lineWidth: -1 }), 'utf-8');
187
+ }
188
+ catch (err) {
189
+ log?.error(`Failed to clear completed phase: ${err instanceof Error ? err.message : String(err)}`);
190
+ }
191
+ }
192
+ /**
193
+ * Type guard to detect rejection payloads from interrupt() return value.
194
+ */
195
+ export function isRejectionPayload(value) {
196
+ return (typeof value === 'object' &&
197
+ value !== null &&
198
+ 'rejected' in value &&
199
+ value.rejected === true);
200
+ }
172
201
  /**
173
202
  * Mark a phase as complete in feature.yaml by adding its ID to completedPhases.
174
203
  */
@@ -194,6 +223,26 @@ export function markPhaseComplete(specDir, phaseId, log) {
194
223
  log?.error(`Failed to mark phase complete: ${err instanceof Error ? err.message : String(err)}`);
195
224
  }
196
225
  }
226
+ /**
227
+ * Write a spec file atomically using temp-file-then-rename pattern.
228
+ * Prevents corruption on crash mid-write.
229
+ */
230
+ export function writeSpecFileAtomic(specDir, filename, content) {
231
+ const targetPath = join(specDir, filename);
232
+ const tempPath = join(specDir, `.${filename}.tmp`);
233
+ try {
234
+ writeFileSync(tempPath, content, 'utf-8');
235
+ renameSync(tempPath, targetPath);
236
+ }
237
+ finally {
238
+ try {
239
+ unlinkSync(tempPath);
240
+ }
241
+ catch {
242
+ // Temp file already renamed or doesn't exist
243
+ }
244
+ }
245
+ }
197
246
  /**
198
247
  * Execute a node with consistent logging and error handling.
199
248
  *
@@ -210,16 +259,46 @@ export function executeNode(nodeName, executor, buildPrompt) {
210
259
  // Update feature lifecycle to reflect the current phase
211
260
  await updateNodeLifecycle(nodeName);
212
261
  // On resume from interrupt, LangGraph re-executes the node function from
213
- // the top. Skip the expensive executor call if this phase already completed
214
- // (markPhaseComplete is called before interrupt, so completed = done but
215
- // awaiting approval; the approval has now been granted).
262
+ // the top. Instead of re-executing within this invocation (which would
263
+ // require a second interrupt() call and trigger the stale-replay bug),
264
+ // we return early. Rejection sets _needsReexecution=true so a conditional
265
+ // edge in the graph routes back to this node for a fresh invocation.
216
266
  const completedPhases = getCompletedPhases(state.specDir);
217
267
  if (completedPhases.includes(nodeName)) {
218
- log.info('Phase already completed (resuming from approval), skipping execution');
219
- return {
220
- currentNode: nodeName,
221
- messages: [`[${nodeName}] Approved continuing`],
222
- };
268
+ if (shouldInterrupt(nodeName, state.approvalGates)) {
269
+ if (state._approvalAction === 'rejected') {
270
+ const feedback = state._rejectionFeedback ?? '(no feedback)';
271
+ log.info(`Phase rejected with feedback: "${feedback}"scheduling re-execution`);
272
+ clearCompletedPhase(state.specDir, nodeName, log);
273
+ // Return early — the conditional edge will route back to this node
274
+ // for a fresh invocation with a clean interrupt index.
275
+ return {
276
+ currentNode: nodeName,
277
+ messages: [`[${nodeName}] Rejected — will re-execute`],
278
+ _approvalAction: null,
279
+ _rejectionFeedback: null,
280
+ _needsReexecution: true,
281
+ };
282
+ }
283
+ else {
284
+ log.info('Phase approved, skipping re-execution');
285
+ return {
286
+ currentNode: nodeName,
287
+ messages: [`[${nodeName}] Approved — continuing`],
288
+ _approvalAction: null,
289
+ _rejectionFeedback: null,
290
+ _needsReexecution: false,
291
+ };
292
+ }
293
+ }
294
+ else {
295
+ log.info('Phase already completed (no gate), skipping execution');
296
+ return {
297
+ currentNode: nodeName,
298
+ messages: [`[${nodeName}] Approved — continuing`],
299
+ _needsReexecution: false,
300
+ };
301
+ }
223
302
  }
224
303
  const startTime = Date.now();
225
304
  // Record phase start (no-op if timing context not set)
@@ -236,13 +315,19 @@ export function executeNode(nodeName, executor, buildPrompt) {
236
315
  // Record phase completion
237
316
  await recordPhaseEnd(timingId, durationMs);
238
317
  // Mark phase complete BEFORE interrupting so that on resume the
239
- // node detects the work is already done and skips re-execution.
318
+ // node detects the work is already done and returns early.
240
319
  markPhaseComplete(state.specDir, nodeName, log);
241
320
  const nodeResult = {
242
321
  currentNode: nodeName,
243
322
  messages: [`[${nodeName}] Complete (${result.result.length} chars, ${elapsed}s)`],
323
+ _approvalAction: null,
324
+ _rejectionFeedback: null,
325
+ _needsReexecution: false,
244
326
  };
245
- // Human-in-the-loop: interrupt after node execution for review
327
+ // Human-in-the-loop: interrupt after node execution for review.
328
+ // This is the ONLY interrupt() call in the entire execution path.
329
+ // On resume, the node returns early (above) without calling interrupt(),
330
+ // so there is no stale interrupt replay.
246
331
  if (shouldInterrupt(nodeName, state.approvalGates)) {
247
332
  log.info('Interrupting for human approval');
248
333
  await recordApprovalWaitStart(timingId);
@@ -2,7 +2,8 @@
2
2
  * Requirements Phase Prompt
3
3
  *
4
4
  * Instructs the agent to build comprehensive requirements from the analysis,
5
- * including product questions with AI-recommended default answers.
5
+ * including product questions with structured QuestionOption[] arrays
6
+ * and AI-recommended default answers.
6
7
  * Writes back to spec.yaml with full requirements.
7
8
  */
8
9
  import type { FeatureAgentState } from '../../state.js';
@@ -1 +1 @@
1
- {"version":3,"file":"requirements.prompt.d.ts","sourceRoot":"","sources":["../../../../../../../../../../packages/core/src/infrastructure/services/agents/feature-agent/nodes/prompts/requirements.prompt.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAExD,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,iBAAiB,GAAG,MAAM,CAoIxE"}
1
+ {"version":3,"file":"requirements.prompt.d.ts","sourceRoot":"","sources":["../../../../../../../../../../packages/core/src/infrastructure/services/agents/feature-agent/nodes/prompts/requirements.prompt.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AAExD,wBAAgB,uBAAuB,CAAC,KAAK,EAAE,iBAAiB,GAAG,MAAM,CAkKxE"}