@shepai/cli 1.122.1 → 1.122.2-pr381.7d9e407

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 (148) hide show
  1. package/dist/packages/core/src/infrastructure/services/agents/common/agent-executor-factory.service.js +1 -1
  2. package/dist/packages/core/src/infrastructure/services/agents/common/executors/cursor-executor.service.d.ts +28 -8
  3. package/dist/packages/core/src/infrastructure/services/agents/common/executors/cursor-executor.service.d.ts.map +1 -1
  4. package/dist/packages/core/src/infrastructure/services/agents/common/executors/cursor-executor.service.js +187 -29
  5. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-graph.d.ts.map +1 -1
  6. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-graph.js +21 -4
  7. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-worker.d.ts.map +1 -1
  8. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/feature-agent-worker.js +9 -0
  9. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge/merge.node.d.ts +5 -0
  10. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge/merge.node.d.ts.map +1 -1
  11. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/merge/merge.node.js +82 -54
  12. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/node-helpers.d.ts +1 -1
  13. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/node-helpers.js +2 -2
  14. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/validate.node.d.ts +7 -1
  15. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/validate.node.d.ts.map +1 -1
  16. package/dist/packages/core/src/infrastructure/services/agents/feature-agent/nodes/validate.node.js +24 -2
  17. package/dist/tsconfig.build.tsbuildinfo +1 -1
  18. package/package.json +1 -1
  19. package/web/.next/BUILD_ID +1 -1
  20. package/web/.next/build-manifest.json +2 -2
  21. package/web/.next/fallback-build-manifest.json +2 -2
  22. package/web/.next/prerender-manifest.json +3 -3
  23. package/web/.next/required-server-files.js +3 -3
  24. package/web/.next/required-server-files.json +3 -3
  25. package/web/.next/server/app/(dashboard)/@drawer/create/page/server-reference-manifest.json +22 -22
  26. package/web/.next/server/app/(dashboard)/@drawer/create/page.js.nft.json +1 -1
  27. package/web/.next/server/app/(dashboard)/@drawer/create/page_client-reference-manifest.js +1 -1
  28. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page/server-reference-manifest.json +28 -28
  29. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page.js.nft.json +1 -1
  30. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/[tab]/page_client-reference-manifest.js +1 -1
  31. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page/server-reference-manifest.json +28 -28
  32. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page.js.nft.json +1 -1
  33. package/web/.next/server/app/(dashboard)/@drawer/feature/[featureId]/page_client-reference-manifest.js +1 -1
  34. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page/server-reference-manifest.json +20 -20
  35. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page.js.nft.json +1 -1
  36. package/web/.next/server/app/(dashboard)/@drawer/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  37. package/web/.next/server/app/(dashboard)/create/page/server-reference-manifest.json +22 -22
  38. package/web/.next/server/app/(dashboard)/create/page.js.nft.json +1 -1
  39. package/web/.next/server/app/(dashboard)/create/page_client-reference-manifest.js +1 -1
  40. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page/server-reference-manifest.json +28 -28
  41. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page.js.nft.json +1 -1
  42. package/web/.next/server/app/(dashboard)/feature/[featureId]/[tab]/page_client-reference-manifest.js +1 -1
  43. package/web/.next/server/app/(dashboard)/feature/[featureId]/page/server-reference-manifest.json +28 -28
  44. package/web/.next/server/app/(dashboard)/feature/[featureId]/page.js.nft.json +1 -1
  45. package/web/.next/server/app/(dashboard)/feature/[featureId]/page_client-reference-manifest.js +1 -1
  46. package/web/.next/server/app/(dashboard)/page/server-reference-manifest.json +20 -20
  47. package/web/.next/server/app/(dashboard)/page.js.nft.json +1 -1
  48. package/web/.next/server/app/(dashboard)/page_client-reference-manifest.js +1 -1
  49. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page/server-reference-manifest.json +20 -20
  50. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page.js.nft.json +1 -1
  51. package/web/.next/server/app/(dashboard)/repository/[repositoryId]/page_client-reference-manifest.js +1 -1
  52. package/web/.next/server/app/_global-error.html +2 -2
  53. package/web/.next/server/app/_global-error.rsc +1 -1
  54. package/web/.next/server/app/_global-error.segments/__PAGE__.segment.rsc +1 -1
  55. package/web/.next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  56. package/web/.next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  57. package/web/.next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  58. package/web/.next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  59. package/web/.next/server/app/_not-found/page/server-reference-manifest.json +1 -1
  60. package/web/.next/server/app/_not-found/page_client-reference-manifest.js +1 -1
  61. package/web/.next/server/app/settings/page/server-reference-manifest.json +6 -6
  62. package/web/.next/server/app/settings/page.js.nft.json +1 -1
  63. package/web/.next/server/app/settings/page_client-reference-manifest.js +1 -1
  64. package/web/.next/server/app/skills/page/server-reference-manifest.json +6 -6
  65. package/web/.next/server/app/skills/page_client-reference-manifest.js +1 -1
  66. package/web/.next/server/app/tools/page/server-reference-manifest.json +6 -6
  67. package/web/.next/server/app/tools/page_client-reference-manifest.js +1 -1
  68. package/web/.next/server/app/version/page/server-reference-manifest.json +1 -1
  69. package/web/.next/server/app/version/page_client-reference-manifest.js +1 -1
  70. package/web/.next/server/chunks/[root-of-the-server]__a402b567._.js +1 -1
  71. package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js +1 -1
  72. package/web/.next/server/chunks/ssr/744ca_web_components_common_control-center-drawer_create-drawer-client_tsx_5e26fc0a._.js.map +1 -1
  73. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_f30d0343.js +1 -1
  74. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_@drawer_repository_[repositoryId]_page_actions_f30d0343.js.map +1 -1
  75. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_9f1775bb.js +1 -1
  76. package/web/.next/server/chunks/ssr/8ba4b_server_app_(dashboard)_repository_[repositoryId]_page_actions_9f1775bb.js.map +1 -1
  77. package/web/.next/server/chunks/ssr/[root-of-the-server]__06fef644._.js +1 -1
  78. package/web/.next/server/chunks/ssr/[root-of-the-server]__2698e9f4._.js +1 -1
  79. package/web/.next/server/chunks/ssr/[root-of-the-server]__2698e9f4._.js.map +1 -1
  80. package/web/.next/server/chunks/ssr/[root-of-the-server]__545792ab._.js +1 -1
  81. package/web/.next/server/chunks/ssr/[root-of-the-server]__545792ab._.js.map +1 -1
  82. package/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js +1 -1
  83. package/web/.next/server/chunks/ssr/[root-of-the-server]__6b17a22d._.js.map +1 -1
  84. package/web/.next/server/chunks/ssr/[root-of-the-server]__6bb00d90._.js +2 -2
  85. package/web/.next/server/chunks/ssr/[root-of-the-server]__6bb00d90._.js.map +1 -1
  86. package/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js +1 -1
  87. package/web/.next/server/chunks/ssr/[root-of-the-server]__804c006d._.js.map +1 -1
  88. package/web/.next/server/chunks/ssr/[root-of-the-server]__8c553503._.js +2 -2
  89. package/web/.next/server/chunks/ssr/[root-of-the-server]__8e3bf5d7._.js +1 -1
  90. package/web/.next/server/chunks/ssr/[root-of-the-server]__8e3bf5d7._.js.map +1 -1
  91. package/web/.next/server/chunks/ssr/[root-of-the-server]__a022445f._.js +2 -2
  92. package/web/.next/server/chunks/ssr/[root-of-the-server]__a7de2711._.js +2 -2
  93. package/web/.next/server/chunks/ssr/[root-of-the-server]__c07f9f79._.js +1 -1
  94. package/web/.next/server/chunks/ssr/[root-of-the-server]__c07f9f79._.js.map +1 -1
  95. package/web/.next/server/chunks/ssr/[root-of-the-server]__c605a375._.js +1 -1
  96. package/web/.next/server/chunks/ssr/[root-of-the-server]__c605a375._.js.map +1 -1
  97. package/web/.next/server/chunks/ssr/_0dc2cfd3._.js +1 -1
  98. package/web/.next/server/chunks/ssr/_0dc2cfd3._.js.map +1 -1
  99. package/web/.next/server/chunks/ssr/_135edb9c._.js +1 -1
  100. package/web/.next/server/chunks/ssr/_135edb9c._.js.map +1 -1
  101. package/web/.next/server/chunks/ssr/_204ecb5a._.js +3 -0
  102. package/web/.next/server/chunks/ssr/{_469c5451._.js.map → _204ecb5a._.js.map} +1 -1
  103. package/web/.next/server/chunks/ssr/_2f6f48b8._.js +1 -1
  104. package/web/.next/server/chunks/ssr/_2f6f48b8._.js.map +1 -1
  105. package/web/.next/server/chunks/ssr/{_92d851b4._.js → _434878d3._.js} +2 -2
  106. package/web/.next/server/chunks/ssr/{_92d851b4._.js.map → _434878d3._.js.map} +1 -1
  107. package/web/.next/server/chunks/ssr/{_b294a667._.js → _510be09a._.js} +2 -2
  108. package/web/.next/server/chunks/ssr/{_b294a667._.js.map → _510be09a._.js.map} +1 -1
  109. package/web/.next/server/chunks/ssr/_cc77a143._.js +1 -1
  110. package/web/.next/server/chunks/ssr/_cc77a143._.js.map +1 -1
  111. package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js +1 -1
  112. package/web/.next/server/chunks/ssr/b1a17_presentation_web_components_features_settings_settings-page-client_tsx_6ed9d5f8._.js.map +1 -1
  113. package/web/.next/server/chunks/ssr/src_presentation_web_5f039db1._.js +2 -2
  114. package/web/.next/server/chunks/ssr/src_presentation_web_5f039db1._.js.map +1 -1
  115. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_2a52b697.js +1 -1
  116. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_(dashboard)_page_actions_2a52b697.js.map +1 -1
  117. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_1fa8042e.js +1 -1
  118. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_skills_page_actions_1fa8042e.js.map +1 -1
  119. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_24684200.js +1 -1
  120. package/web/.next/server/chunks/ssr/src_presentation_web__next-internal_server_app_tools_page_actions_24684200.js.map +1 -1
  121. package/web/.next/server/chunks/ssr/src_presentation_web_c4337169._.js +2 -2
  122. package/web/.next/server/chunks/ssr/src_presentation_web_c4337169._.js.map +1 -1
  123. package/web/.next/server/chunks/ssr/src_presentation_web_components_bf50c527._.js +1 -1
  124. package/web/.next/server/chunks/ssr/src_presentation_web_components_bf50c527._.js.map +1 -1
  125. package/web/.next/server/chunks/ssr/src_presentation_web_components_de814675._.js +1 -1
  126. package/web/.next/server/chunks/ssr/src_presentation_web_components_de814675._.js.map +1 -1
  127. package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js +1 -1
  128. package/web/.next/server/chunks/ssr/src_presentation_web_components_features_control-center_7ac3562e._.js.map +1 -1
  129. package/web/.next/server/pages/500.html +2 -2
  130. package/web/.next/server/server-reference-manifest.js +1 -1
  131. package/web/.next/server/server-reference-manifest.json +34 -34
  132. package/web/.next/static/chunks/{e6a2fb8707e079ff.js → 19401b65e1298cb0.js} +1 -1
  133. package/web/.next/static/chunks/{941c13dcdb1978a4.js → 2c0191c062d5f7ae.js} +2 -2
  134. package/web/.next/static/chunks/{9df4681de92ebfc3.js → 4da275e6ef808c4d.js} +1 -1
  135. package/web/.next/static/chunks/{78ab7b134f0649ac.js → 50bf223ed146d4ed.js} +1 -1
  136. package/web/.next/static/chunks/5a9e671eb04de758.js +1 -0
  137. package/web/.next/static/chunks/6a8fb1992b738cc9.js +1 -0
  138. package/web/.next/static/chunks/{37ac7fe1cd493293.js → 89ffd07cdb158389.js} +1 -1
  139. package/web/.next/static/chunks/{50dd80c8aafa3b20.js → a637e16d364af323.js} +1 -1
  140. package/web/.next/static/chunks/bc1ce100834f414a.js +1 -0
  141. package/web/.next/static/chunks/{658fc2f5f65cf3b5.js → df88f3e08b196bbf.js} +2 -2
  142. package/web/.next/server/chunks/ssr/_469c5451._.js +0 -3
  143. package/web/.next/static/chunks/11e4439096f8d652.js +0 -1
  144. package/web/.next/static/chunks/df85e52b1afb7340.js +0 -1
  145. package/web/.next/static/chunks/e9c3fbbeb418cbfa.js +0 -1
  146. /package/web/.next/static/{hsK1x0unrjI_pUsvQhn6P → NKkt3_PEmNxKD_ihRAzNE}/_buildManifest.js +0 -0
  147. /package/web/.next/static/{hsK1x0unrjI_pUsvQhn6P → NKkt3_PEmNxKD_ihRAzNE}/_clientMiddlewareManifest.json +0 -0
  148. /package/web/.next/static/{hsK1x0unrjI_pUsvQhn6P → NKkt3_PEmNxKD_ihRAzNE}/_ssgManifest.js +0 -0
@@ -98,66 +98,94 @@ export function createMergeNode(deps) {
98
98
  : undefined;
99
99
  // --- Agent Call 1: Commit + Push + PR (skip on approval resume) ---
100
100
  if (!isResumeAfterInterrupt) {
101
- if (!remoteAvailable) {
102
- log.info('No git remote configured — skipping push and PR, will merge locally');
103
- }
104
101
  const effectiveState = remoteAvailable ? state : { ...state, push: false, openPr: false };
105
- log.info('Agent call 1: commit + push + PR');
106
- const commitPushPrPrompt = buildCommitPushPrPrompt(effectiveState, branch, baseBranch, repoUrl);
107
- const commitResult = await retryExecute(executor, commitPushPrPrompt, options, {
108
- logger: log,
109
- });
110
- totalInputTokens += commitResult.usage?.inputTokens ?? 0;
111
- totalOutputTokens += commitResult.usage?.outputTokens ?? 0;
112
- totalCostUsd += commitResult.usage?.costUsd ?? 0;
113
- totalNumTurns += commitResult.usage?.numTurns ?? 0;
114
- totalDurationApiMs += commitResult.usage?.durationApiMs ?? 0;
115
- commitHash = parseCommitHash(commitResult.result) ?? state.commitHash;
116
- messages.push(`[merge] Agent completed commit/push/PR operations`);
117
- if (effectiveState.openPr) {
118
- const prResult = parsePrUrl(commitResult.result);
119
- if (prResult) {
120
- prUrl = prResult.url;
121
- prNumber = prResult.number;
122
- // Cross-validate agent-parsed PR URL against authoritative source.
123
- // The agent may hallucinate the repo URL or PR number, so we look up
124
- // the real PR for this branch via the GitHub API.
125
- try {
126
- const prStatuses = await deps.gitPrService.listPrStatuses(cwd);
127
- const matchingPr = prStatuses.find((pr) => pr.headRefName === branch);
128
- if (matchingPr) {
129
- prUrl = matchingPr.url;
130
- prNumber = matchingPr.number;
131
- }
102
+ const needsAgentCall = effectiveState.push || effectiveState.openPr;
103
+ if (!needsAgentCall) {
104
+ // Local-only: commit programmatically in worktree, no agent needed.
105
+ // This avoids calling the agent executor just to run git commit,
106
+ // which is slow/unreliable on some platforms (e.g. cursor on Windows hangs).
107
+ log.info('Local-only mode committing in worktree programmatically (no agent)');
108
+ const worktreeCwd = state.worktreePath ?? cwd;
109
+ try {
110
+ const msg = `feat: ${branch}`;
111
+ const hash = await deps.commitAll(worktreeCwd, msg);
112
+ if (hash) {
113
+ commitHash = hash;
114
+ log.info(`Committed changes in worktree: ${commitHash}`);
115
+ messages.push(`[merge] Programmatic commit: ${commitHash}`);
132
116
  }
133
- catch {
134
- // gh CLI unavailable or API failure — fall back to agent-parsed URL
117
+ else {
118
+ log.info('No changes to commit in worktree');
119
+ messages.push(`[merge] No changes to commit`);
135
120
  }
136
- messages.push(`[merge] PR created: ${prUrl}`);
121
+ }
122
+ catch (commitErr) {
123
+ const errMsg = commitErr instanceof Error ? commitErr.message : String(commitErr);
124
+ log.info(`Programmatic commit failed: ${errMsg} — falling back to agent`);
125
+ messages.push(`[merge] Programmatic commit failed, falling back to agent`);
126
+ // Fall through — needsAgentCall stays false so agent won't run either.
127
+ // The localMergeSquash will handle uncommitted changes via --squash.
137
128
  }
138
129
  }
139
- // --- CI watch/fix loop (when push or openPr is enabled and CI watch is not disabled) ---
140
- const ciWatchEnabled = getSettings().workflow?.ciWatchEnabled !== false;
141
- if (ciWatchEnabled && (effectiveState.push || effectiveState.openPr)) {
142
- const ciResult = await runCiWatchFixLoop({
143
- executor,
144
- gitPrService: deps.gitPrService,
145
- featureRepository: deps.featureRepository,
146
- }, {
147
- cwd,
148
- branch,
149
- options,
150
- feature,
151
- prUrl,
152
- prNumber,
153
- existingAttempts: ciFixAttempts,
154
- messages,
155
- log,
130
+ if (needsAgentCall) {
131
+ if (!remoteAvailable) {
132
+ log.info('No git remote configured — skipping push and PR, will merge locally');
133
+ }
134
+ log.info('Agent call 1: commit + push + PR');
135
+ const commitPushPrPrompt = buildCommitPushPrPrompt(effectiveState, branch, baseBranch, repoUrl);
136
+ const commitResult = await retryExecute(executor, commitPushPrPrompt, options, {
137
+ logger: log,
156
138
  });
157
- ciStatus = ciResult.ciStatus;
158
- ciFixAttempts = ciResult.ciFixAttempts;
159
- ciFixHistory = ciResult.ciFixHistory;
160
- ciFixStatus = ciResult.ciFixStatus;
139
+ totalInputTokens += commitResult.usage?.inputTokens ?? 0;
140
+ totalOutputTokens += commitResult.usage?.outputTokens ?? 0;
141
+ totalCostUsd += commitResult.usage?.costUsd ?? 0;
142
+ totalNumTurns += commitResult.usage?.numTurns ?? 0;
143
+ totalDurationApiMs += commitResult.usage?.durationApiMs ?? 0;
144
+ commitHash = parseCommitHash(commitResult.result) ?? state.commitHash;
145
+ messages.push(`[merge] Agent completed commit/push/PR operations`);
146
+ if (effectiveState.openPr) {
147
+ const prResult = parsePrUrl(commitResult.result);
148
+ if (prResult) {
149
+ prUrl = prResult.url;
150
+ prNumber = prResult.number;
151
+ // Cross-validate agent-parsed PR URL against authoritative source.
152
+ try {
153
+ const prStatuses = await deps.gitPrService.listPrStatuses(cwd);
154
+ const matchingPr = prStatuses.find((pr) => pr.headRefName === branch);
155
+ if (matchingPr) {
156
+ prUrl = matchingPr.url;
157
+ prNumber = matchingPr.number;
158
+ }
159
+ }
160
+ catch {
161
+ // gh CLI unavailable or API failure — fall back to agent-parsed URL
162
+ }
163
+ messages.push(`[merge] PR created: ${prUrl}`);
164
+ }
165
+ }
166
+ // --- CI watch/fix loop (when push or openPr is enabled and CI watch is not disabled) ---
167
+ const ciWatchEnabled = getSettings().workflow?.ciWatchEnabled !== false;
168
+ if (ciWatchEnabled && (effectiveState.push || effectiveState.openPr)) {
169
+ const ciResult = await runCiWatchFixLoop({
170
+ executor,
171
+ gitPrService: deps.gitPrService,
172
+ featureRepository: deps.featureRepository,
173
+ }, {
174
+ cwd,
175
+ branch,
176
+ options,
177
+ feature,
178
+ prUrl,
179
+ prNumber,
180
+ existingAttempts: ciFixAttempts,
181
+ messages,
182
+ log,
183
+ });
184
+ ciStatus = ciResult.ciStatus;
185
+ ciFixAttempts = ciResult.ciFixAttempts;
186
+ ciFixHistory = ciResult.ciFixHistory;
187
+ ciFixStatus = ciResult.ciFixStatus;
188
+ }
161
189
  }
162
190
  // --- Persist lifecycle + PR data before approval gate ---
163
191
  // Setting lifecycle to Review serves as the resume detection marker
@@ -32,7 +32,7 @@ export declare function getStageTimeoutMs(nodeName: string): number;
32
32
  /**
33
33
  * Build executor options with cwd. Each node gets a clean agent context.
34
34
  * The timeout is resolved per-stage from settings (workflow.stageTimeouts)
35
- * with a fallback to DEFAULT_STAGE_TIMEOUT_MS (10 min).
35
+ * with a fallback to DEFAULT_STAGE_TIMEOUT_MS (10 min per call, 30 min max with retries).
36
36
  *
37
37
  * When no `nodeName` is provided, the current node from state is used.
38
38
  */
@@ -46,7 +46,7 @@ export function readSpecFile(specDir, filename) {
46
46
  }
47
47
  }
48
48
  /** Default timeout per agent call (30 minutes) — prevents infinite hangs. */
49
- const DEFAULT_STAGE_TIMEOUT_MS = 1_800_000;
49
+ const DEFAULT_STAGE_TIMEOUT_MS = 600_000; // 10 minutes per agent call (retryExecute retries 3x, so 30min max per phase)
50
50
  /**
51
51
  * Map from node name to the corresponding StageTimeouts field.
52
52
  * `fast-implement` reuses the implement timeout; `evidence` also reuses implement.
@@ -80,7 +80,7 @@ export function getStageTimeoutMs(nodeName) {
80
80
  /**
81
81
  * Build executor options with cwd. Each node gets a clean agent context.
82
82
  * The timeout is resolved per-stage from settings (workflow.stageTimeouts)
83
- * with a fallback to DEFAULT_STAGE_TIMEOUT_MS (10 min).
83
+ * with a fallback to DEFAULT_STAGE_TIMEOUT_MS (10 min per call, 30 min max with retries).
84
84
  *
85
85
  * When no `nodeName` is provided, the current node from state is used.
86
86
  */
@@ -6,7 +6,13 @@ type SchemaValidator = (data: unknown) => ValidationResult;
6
6
  *
7
7
  * On success: resets validationRetries to 0, clears errors.
8
8
  * On failure: increments validationRetries, sets errors for repair node.
9
+ *
10
+ * @param successorPhase - The phase that runs AFTER this validation passes.
11
+ * If provided, skip validation when the successor is already completed — this
12
+ * proves the validation already passed in a prior run and the pipeline progressed
13
+ * beyond it. Checking the successor (not the producer) avoids skipping validation
14
+ * when the producer ran but validation itself failed.
9
15
  */
10
- export declare function createValidateNode(filename: string, schema: SchemaValidator): (state: FeatureAgentState) => Promise<Partial<FeatureAgentState>>;
16
+ export declare function createValidateNode(filename: string, schema: SchemaValidator, successorPhase?: string): (state: FeatureAgentState) => Promise<Partial<FeatureAgentState>>;
11
17
  export {};
12
18
  //# sourceMappingURL=validate.node.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"validate.node.d.ts","sourceRoot":"","sources":["../../../../../../../../../packages/core/src/infrastructure/services/agents/feature-agent/nodes/validate.node.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAGhE,KAAK,eAAe,GAAG,CAAC,IAAI,EAAE,OAAO,KAAK,gBAAgB,CAAC;AAE3D;;;;;GAKG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,eAAe,GACtB,CAAC,KAAK,EAAE,iBAAiB,KAAK,OAAO,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAuDnE"}
1
+ {"version":3,"file":"validate.node.d.ts","sourceRoot":"","sources":["../../../../../../../../../packages/core/src/infrastructure/services/agents/feature-agent/nodes/validate.node.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAC;AAQhE,KAAK,eAAe,GAAG,CAAC,IAAI,EAAE,OAAO,KAAK,gBAAgB,CAAC;AAE3D;;;;;;;;;;;GAWG;AACH,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,MAAM,EAChB,MAAM,EAAE,eAAe,EACvB,cAAc,CAAC,EAAE,MAAM,GACtB,CAAC,KAAK,EAAE,iBAAiB,KAAK,OAAO,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAyEnE"}
@@ -1,14 +1,36 @@
1
- import { readSpecFile, safeYamlLoad, createNodeLogger } from './node-helpers.js';
1
+ import { readSpecFile, safeYamlLoad, createNodeLogger, getCompletedPhases, } from './node-helpers.js';
2
2
  /**
3
3
  * Factory that creates a validate node for a specific YAML file.
4
4
  *
5
5
  * On success: resets validationRetries to 0, clears errors.
6
6
  * On failure: increments validationRetries, sets errors for repair node.
7
+ *
8
+ * @param successorPhase - The phase that runs AFTER this validation passes.
9
+ * If provided, skip validation when the successor is already completed — this
10
+ * proves the validation already passed in a prior run and the pipeline progressed
11
+ * beyond it. Checking the successor (not the producer) avoids skipping validation
12
+ * when the producer ran but validation itself failed.
7
13
  */
8
- export function createValidateNode(filename, schema) {
14
+ export function createValidateNode(filename, schema, successorPhase) {
9
15
  const log = createNodeLogger(`validate:${filename}`);
10
16
  return async (state) => {
11
17
  log.activate();
18
+ // Skip validation when the successor phase is already completed.
19
+ // This means: the validation already passed in a prior run AND the next phase
20
+ // ran successfully. On resume, LangGraph replays nodes from the last checkpoint.
21
+ // The producer node skips (via getCompletedPhases), but if we only checked the
22
+ // producer we'd also skip validation when it previously FAILED (since
23
+ // markPhaseComplete runs before validation). Checking the successor is safe:
24
+ // if the successor completed, this validation must have passed to get there.
25
+ if (successorPhase && getCompletedPhases(state.specDir).includes(successorPhase)) {
26
+ log.info(`Successor phase '${successorPhase}' already completed, skipping validation`);
27
+ return {
28
+ lastValidationTarget: filename,
29
+ lastValidationErrors: [],
30
+ validationRetries: 0,
31
+ messages: [`[validate:${filename}] SKIP (successor '${successorPhase}' already completed)`],
32
+ };
33
+ }
12
34
  log.info(`Validating ${filename}`);
13
35
  const content = readSpecFile(state.specDir, filename);
14
36
  if (!content) {