agent-pipeline 0.1.0 → 0.1.1

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 (323) hide show
  1. package/CLAUDE.md +2 -3
  2. package/README.md +110 -55
  3. package/dist/cli/commands/agent/info.js +1 -1
  4. package/dist/cli/commands/agent/info.js.map +1 -1
  5. package/dist/cli/commands/agent/list.js +1 -1
  6. package/dist/cli/commands/agent/list.js.map +1 -1
  7. package/dist/cli/commands/agent/pull.d.ts +1 -0
  8. package/dist/cli/commands/agent/pull.d.ts.map +1 -1
  9. package/dist/cli/commands/agent/pull.js +67 -44
  10. package/dist/cli/commands/agent/pull.js.map +1 -1
  11. package/dist/cli/commands/cleanup.d.ts +4 -0
  12. package/dist/cli/commands/cleanup.d.ts.map +1 -1
  13. package/dist/cli/commands/cleanup.js +197 -37
  14. package/dist/cli/commands/cleanup.js.map +1 -1
  15. package/dist/cli/commands/history.d.ts.map +1 -1
  16. package/dist/cli/commands/history.js +3 -22
  17. package/dist/cli/commands/history.js.map +1 -1
  18. package/dist/cli/commands/hooks.d.ts +10 -0
  19. package/dist/cli/commands/hooks.d.ts.map +1 -0
  20. package/dist/cli/commands/hooks.js +88 -0
  21. package/dist/cli/commands/hooks.js.map +1 -0
  22. package/dist/cli/commands/init.d.ts +1 -6
  23. package/dist/cli/commands/init.d.ts.map +1 -1
  24. package/dist/cli/commands/init.js +173 -58
  25. package/dist/cli/commands/init.js.map +1 -1
  26. package/dist/cli/commands/loop-context.d.ts +2 -0
  27. package/dist/cli/commands/loop-context.d.ts.map +1 -0
  28. package/dist/cli/commands/loop-context.js +88 -0
  29. package/dist/cli/commands/loop-context.js.map +1 -0
  30. package/dist/cli/commands/pipeline/create.d.ts.map +1 -1
  31. package/dist/cli/commands/pipeline/create.js +156 -68
  32. package/dist/cli/commands/pipeline/create.js.map +1 -1
  33. package/dist/cli/commands/run.d.ts +1 -1
  34. package/dist/cli/commands/run.d.ts.map +1 -1
  35. package/dist/cli/commands/run.js +29 -5
  36. package/dist/cli/commands/run.js.map +1 -1
  37. package/dist/cli/commands/schema.d.ts +9 -0
  38. package/dist/cli/commands/schema.d.ts.map +1 -0
  39. package/dist/cli/commands/schema.js +541 -0
  40. package/dist/cli/commands/schema.js.map +1 -0
  41. package/dist/cli/commands/status.d.ts.map +1 -1
  42. package/dist/cli/commands/status.js +0 -6
  43. package/dist/cli/commands/status.js.map +1 -1
  44. package/dist/cli/help/index.d.ts +6 -0
  45. package/dist/cli/help/index.d.ts.map +1 -0
  46. package/dist/cli/help/index.js +538 -0
  47. package/dist/cli/help/index.js.map +1 -0
  48. package/dist/cli/help/types.d.ts +22 -0
  49. package/dist/cli/help/types.d.ts.map +1 -0
  50. package/dist/cli/help/types.js +2 -0
  51. package/dist/cli/help/types.js.map +1 -0
  52. package/dist/cli/hooks.d.ts +5 -1
  53. package/dist/cli/hooks.d.ts.map +1 -1
  54. package/dist/cli/hooks.js +106 -12
  55. package/dist/cli/hooks.js.map +1 -1
  56. package/dist/cli/templates/agents/code-review-agents/code-reviewer.md +46 -0
  57. package/dist/cli/templates/agents/code-review-agents/memory-doc-updater.md +189 -0
  58. package/dist/cli/templates/agents/code-review-agents/quality-checker.md +52 -0
  59. package/dist/cli/templates/agents/frontend-agents/brutalist_purist.md +563 -0
  60. package/dist/cli/templates/agents/frontend-agents/cyberpunk_hacker.md +824 -0
  61. package/dist/cli/templates/agents/frontend-agents/frontend-pipeline-ref.md +32 -0
  62. package/dist/cli/templates/agents/frontend-agents/indie_game_dev.md +715 -0
  63. package/dist/cli/templates/agents/frontend-agents/luxury_editorial.md +628 -0
  64. package/dist/cli/templates/agents/frontend-agents/product_owner.md +159 -0
  65. package/dist/cli/templates/agents/frontend-agents/retro_90s_webmaster.md +385 -0
  66. package/dist/cli/templates/agents/frontend-agents/showcase.md +362 -0
  67. package/dist/cli/templates/agents/frontend-agents/swiss_modernist.md +716 -0
  68. package/dist/cli/templates/agents/loop-agents/socratic-explorer.md +91 -0
  69. package/dist/cli/templates/instructions/handover.md +40 -0
  70. package/dist/cli/templates/instructions/loop.md +35 -0
  71. package/dist/cli/templates/pipelines/front-end-parallel-example.yml +81 -0
  72. package/dist/cli/templates/pipelines/loop-example.yml +25 -0
  73. package/dist/cli/templates/pipelines/post-commit-example.yml +49 -58
  74. package/dist/cli/templates/schema/pipeline-config.schema.json +400 -0
  75. package/dist/cli/templates/schema/pipeline-config.schema.yaml +301 -0
  76. package/dist/cli/utils/agent-importer.d.ts +1 -0
  77. package/dist/cli/utils/agent-importer.d.ts.map +1 -1
  78. package/dist/cli/utils/agent-importer.js +67 -0
  79. package/dist/cli/utils/agent-importer.js.map +1 -1
  80. package/dist/cli/utils/interactive-prompts.d.ts +4 -0
  81. package/dist/cli/utils/interactive-prompts.d.ts.map +1 -1
  82. package/dist/cli/utils/interactive-prompts.js +59 -13
  83. package/dist/cli/utils/interactive-prompts.js.map +1 -1
  84. package/dist/config/pipeline-loader.d.ts +4 -1
  85. package/dist/config/pipeline-loader.d.ts.map +1 -1
  86. package/dist/config/pipeline-loader.js +58 -0
  87. package/dist/config/pipeline-loader.js.map +1 -1
  88. package/dist/config/schema.d.ts +65 -35
  89. package/dist/config/schema.d.ts.map +1 -1
  90. package/dist/core/abort-controller.d.ts +16 -0
  91. package/dist/core/abort-controller.d.ts.map +1 -0
  92. package/dist/core/abort-controller.js +52 -0
  93. package/dist/core/abort-controller.js.map +1 -0
  94. package/dist/core/agent-query-runner.d.ts +0 -1
  95. package/dist/core/agent-query-runner.d.ts.map +1 -1
  96. package/dist/core/agent-query-runner.js +0 -22
  97. package/dist/core/agent-query-runner.js.map +1 -1
  98. package/dist/core/agent-runtimes/claude-code-headless-runtime.d.ts +5 -1
  99. package/dist/core/agent-runtimes/claude-code-headless-runtime.d.ts.map +1 -1
  100. package/dist/core/agent-runtimes/claude-code-headless-runtime.js +127 -12
  101. package/dist/core/agent-runtimes/claude-code-headless-runtime.js.map +1 -1
  102. package/dist/core/agent-runtimes/claude-sdk-runtime.d.ts +0 -2
  103. package/dist/core/agent-runtimes/claude-sdk-runtime.d.ts.map +1 -1
  104. package/dist/core/agent-runtimes/claude-sdk-runtime.js +1 -22
  105. package/dist/core/agent-runtimes/claude-sdk-runtime.js.map +1 -1
  106. package/dist/core/branch-manager.d.ts +3 -1
  107. package/dist/core/branch-manager.d.ts.map +1 -1
  108. package/dist/core/branch-manager.js +11 -1
  109. package/dist/core/branch-manager.js.map +1 -1
  110. package/dist/core/git-manager.d.ts +17 -1
  111. package/dist/core/git-manager.d.ts.map +1 -1
  112. package/dist/core/git-manager.js +147 -3
  113. package/dist/core/git-manager.js.map +1 -1
  114. package/dist/core/group-execution-orchestrator.d.ts +7 -13
  115. package/dist/core/group-execution-orchestrator.d.ts.map +1 -1
  116. package/dist/core/group-execution-orchestrator.js +53 -142
  117. package/dist/core/group-execution-orchestrator.js.map +1 -1
  118. package/dist/core/handover-manager.d.ts +24 -0
  119. package/dist/core/handover-manager.d.ts.map +1 -0
  120. package/dist/core/handover-manager.js +214 -0
  121. package/dist/core/handover-manager.js.map +1 -0
  122. package/dist/core/instruction-loader.d.ts +23 -0
  123. package/dist/core/instruction-loader.d.ts.map +1 -0
  124. package/dist/core/instruction-loader.js +112 -0
  125. package/dist/core/instruction-loader.js.map +1 -0
  126. package/dist/core/loop-state-manager.d.ts +12 -7
  127. package/dist/core/loop-state-manager.d.ts.map +1 -1
  128. package/dist/core/loop-state-manager.js +49 -3
  129. package/dist/core/loop-state-manager.js.map +1 -1
  130. package/dist/core/parallel-executor.d.ts +12 -3
  131. package/dist/core/parallel-executor.d.ts.map +1 -1
  132. package/dist/core/parallel-executor.js +92 -14
  133. package/dist/core/parallel-executor.js.map +1 -1
  134. package/dist/core/pipeline-finalizer.d.ts +12 -4
  135. package/dist/core/pipeline-finalizer.d.ts.map +1 -1
  136. package/dist/core/pipeline-finalizer.js +244 -33
  137. package/dist/core/pipeline-finalizer.js.map +1 -1
  138. package/dist/core/pipeline-initializer.d.ts +13 -5
  139. package/dist/core/pipeline-initializer.d.ts.map +1 -1
  140. package/dist/core/pipeline-initializer.js +53 -25
  141. package/dist/core/pipeline-initializer.js.map +1 -1
  142. package/dist/core/pipeline-runner.d.ts +13 -1
  143. package/dist/core/pipeline-runner.d.ts.map +1 -1
  144. package/dist/core/pipeline-runner.js +352 -60
  145. package/dist/core/pipeline-runner.js.map +1 -1
  146. package/dist/core/pr-creator.d.ts +0 -1
  147. package/dist/core/pr-creator.d.ts.map +1 -1
  148. package/dist/core/pr-creator.js +12 -4
  149. package/dist/core/pr-creator.js.map +1 -1
  150. package/dist/core/stage-executor.d.ts +17 -9
  151. package/dist/core/stage-executor.d.ts.map +1 -1
  152. package/dist/core/stage-executor.js +152 -166
  153. package/dist/core/stage-executor.js.map +1 -1
  154. package/dist/core/types/agent-runtime.d.ts +3 -2
  155. package/dist/core/types/agent-runtime.d.ts.map +1 -1
  156. package/dist/core/worktree-manager.d.ts +21 -0
  157. package/dist/core/worktree-manager.d.ts.map +1 -0
  158. package/dist/core/worktree-manager.js +133 -0
  159. package/dist/core/worktree-manager.js.map +1 -0
  160. package/dist/index.js +118 -112
  161. package/dist/index.js.map +1 -1
  162. package/dist/notifications/notification-manager.d.ts +1 -0
  163. package/dist/notifications/notification-manager.d.ts.map +1 -1
  164. package/dist/notifications/notification-manager.js +17 -3
  165. package/dist/notifications/notification-manager.js.map +1 -1
  166. package/dist/notifications/notifiers/local-notifier.d.ts.map +1 -1
  167. package/dist/notifications/notifiers/local-notifier.js +5 -2
  168. package/dist/notifications/notifiers/local-notifier.js.map +1 -1
  169. package/dist/notifications/notifiers/slack-notifier.d.ts.map +1 -1
  170. package/dist/notifications/notifiers/slack-notifier.js +39 -8
  171. package/dist/notifications/notifiers/slack-notifier.js.map +1 -1
  172. package/dist/notifications/types.d.ts +1 -1
  173. package/dist/notifications/types.d.ts.map +1 -1
  174. package/dist/ui/components/execution-group.d.ts.map +1 -1
  175. package/dist/ui/components/execution-group.js +1 -1
  176. package/dist/ui/components/execution-group.js.map +1 -1
  177. package/dist/ui/components/interactive-summary.d.ts +9 -0
  178. package/dist/ui/components/interactive-summary.d.ts.map +1 -0
  179. package/dist/ui/components/interactive-summary.js +166 -0
  180. package/dist/ui/components/interactive-summary.js.map +1 -0
  181. package/dist/ui/components/keyboard-hints.d.ts +12 -0
  182. package/dist/ui/components/keyboard-hints.d.ts.map +1 -0
  183. package/dist/ui/components/keyboard-hints.js +13 -0
  184. package/dist/ui/components/keyboard-hints.js.map +1 -0
  185. package/dist/ui/components/live-timer.d.ts +9 -0
  186. package/dist/ui/components/live-timer.d.ts.map +1 -0
  187. package/dist/ui/components/live-timer.js +25 -0
  188. package/dist/ui/components/live-timer.js.map +1 -0
  189. package/dist/ui/components/loop-iteration-history.d.ts +8 -0
  190. package/dist/ui/components/loop-iteration-history.d.ts.map +1 -0
  191. package/dist/ui/components/loop-iteration-history.js +106 -0
  192. package/dist/ui/components/loop-iteration-history.js.map +1 -0
  193. package/dist/ui/components/loop-session-summary.d.ts +9 -0
  194. package/dist/ui/components/loop-session-summary.d.ts.map +1 -0
  195. package/dist/ui/components/loop-session-summary.js +39 -0
  196. package/dist/ui/components/loop-session-summary.js.map +1 -0
  197. package/dist/ui/components/stage-row.d.ts +0 -1
  198. package/dist/ui/components/stage-row.d.ts.map +1 -1
  199. package/dist/ui/components/stage-row.js +5 -15
  200. package/dist/ui/components/stage-row.js.map +1 -1
  201. package/dist/ui/components/status-badge.d.ts.map +1 -1
  202. package/dist/ui/components/status-badge.js +1 -0
  203. package/dist/ui/components/status-badge.js.map +1 -1
  204. package/dist/ui/pipeline-ui.d.ts +1 -0
  205. package/dist/ui/pipeline-ui.d.ts.map +1 -1
  206. package/dist/ui/pipeline-ui.js +22 -18
  207. package/dist/ui/pipeline-ui.js.map +1 -1
  208. package/dist/utils/error-factory.d.ts.map +1 -1
  209. package/dist/utils/error-factory.js +10 -2
  210. package/dist/utils/error-factory.js.map +1 -1
  211. package/dist/utils/pipeline-formatter.d.ts +8 -2
  212. package/dist/utils/pipeline-formatter.d.ts.map +1 -1
  213. package/dist/utils/pipeline-formatter.js +30 -26
  214. package/dist/utils/pipeline-formatter.js.map +1 -1
  215. package/dist/utils/pipeline-logger.d.ts +19 -0
  216. package/dist/utils/pipeline-logger.d.ts.map +1 -0
  217. package/dist/utils/pipeline-logger.js +80 -0
  218. package/dist/utils/pipeline-logger.js.map +1 -0
  219. package/dist/utils/platform-opener.d.ts +4 -0
  220. package/dist/utils/platform-opener.d.ts.map +1 -0
  221. package/dist/utils/platform-opener.js +52 -0
  222. package/dist/utils/platform-opener.js.map +1 -0
  223. package/dist/validators/agent-validator.d.ts +10 -0
  224. package/dist/validators/agent-validator.d.ts.map +1 -0
  225. package/dist/validators/agent-validator.js +87 -0
  226. package/dist/validators/agent-validator.js.map +1 -0
  227. package/dist/validators/dag-validator.d.ts +9 -0
  228. package/dist/validators/dag-validator.d.ts.map +1 -0
  229. package/dist/validators/dag-validator.js +51 -0
  230. package/dist/validators/dag-validator.js.map +1 -0
  231. package/dist/validators/environment-validator.d.ts +9 -0
  232. package/dist/validators/environment-validator.d.ts.map +1 -0
  233. package/dist/validators/environment-validator.js +35 -0
  234. package/dist/validators/environment-validator.js.map +1 -0
  235. package/dist/validators/execution-validator.d.ts +8 -0
  236. package/dist/validators/execution-validator.d.ts.map +1 -0
  237. package/dist/validators/execution-validator.js +51 -0
  238. package/dist/validators/execution-validator.js.map +1 -0
  239. package/dist/validators/git-validator.d.ts +13 -0
  240. package/dist/validators/git-validator.d.ts.map +1 -0
  241. package/dist/validators/git-validator.js +135 -0
  242. package/dist/validators/git-validator.js.map +1 -0
  243. package/dist/validators/notification-validator.d.ts +8 -0
  244. package/dist/validators/notification-validator.d.ts.map +1 -0
  245. package/dist/validators/notification-validator.js +27 -0
  246. package/dist/validators/notification-validator.js.map +1 -0
  247. package/dist/validators/pipeline-validator.d.ts +3 -26
  248. package/dist/validators/pipeline-validator.d.ts.map +1 -1
  249. package/dist/validators/pipeline-validator.js +5 -515
  250. package/dist/validators/pipeline-validator.js.map +1 -1
  251. package/dist/validators/retry-validator.d.ts +9 -0
  252. package/dist/validators/retry-validator.d.ts.map +1 -0
  253. package/dist/validators/retry-validator.js +34 -0
  254. package/dist/validators/retry-validator.js.map +1 -0
  255. package/dist/validators/runtime-validator.d.ts +9 -0
  256. package/dist/validators/runtime-validator.d.ts.map +1 -0
  257. package/dist/validators/runtime-validator.js +82 -0
  258. package/dist/validators/runtime-validator.js.map +1 -0
  259. package/dist/validators/structure-validator.d.ts +8 -0
  260. package/dist/validators/structure-validator.d.ts.map +1 -0
  261. package/dist/validators/structure-validator.js +39 -0
  262. package/dist/validators/structure-validator.js.map +1 -0
  263. package/dist/validators/types.d.ts +19 -0
  264. package/dist/validators/types.d.ts.map +1 -0
  265. package/dist/validators/types.js +2 -0
  266. package/dist/validators/types.js.map +1 -0
  267. package/dist/validators/validation-orchestrator.d.ts +9 -0
  268. package/dist/validators/validation-orchestrator.d.ts.map +1 -0
  269. package/dist/validators/validation-orchestrator.js +43 -0
  270. package/dist/validators/validation-orchestrator.js.map +1 -0
  271. package/package.json +17 -11
  272. package/dist/cli/commands/install.d.ts +0 -2
  273. package/dist/cli/commands/install.d.ts.map +0 -1
  274. package/dist/cli/commands/install.js +0 -15
  275. package/dist/cli/commands/install.js.map +0 -1
  276. package/dist/cli/commands/uninstall.d.ts +0 -2
  277. package/dist/cli/commands/uninstall.d.ts.map +0 -1
  278. package/dist/cli/commands/uninstall.js +0 -6
  279. package/dist/cli/commands/uninstall.js.map +0 -1
  280. package/dist/cli/templates/agents/cleanup-reporter.md +0 -107
  281. package/dist/cli/templates/agents/code-reducer.md +0 -51
  282. package/dist/cli/templates/agents/code-reviewer.md +0 -34
  283. package/dist/cli/templates/agents/context-reducer.md +0 -94
  284. package/dist/cli/templates/agents/dependency-auditor.md +0 -127
  285. package/dist/cli/templates/agents/detective-empath.md +0 -26
  286. package/dist/cli/templates/agents/detective-linguist.md +0 -26
  287. package/dist/cli/templates/agents/detective-logician.md +0 -26
  288. package/dist/cli/templates/agents/detective-skeptic.md +0 -26
  289. package/dist/cli/templates/agents/detective-statistician.md +0 -26
  290. package/dist/cli/templates/agents/doc-updater.md +0 -30
  291. package/dist/cli/templates/agents/judge.md +0 -27
  292. package/dist/cli/templates/agents/memory-updater.md +0 -72
  293. package/dist/cli/templates/agents/quality-checker.md +0 -32
  294. package/dist/cli/templates/agents/security-auditor.md +0 -32
  295. package/dist/cli/templates/agents/storyteller.md +0 -26
  296. package/dist/cli/templates/agents/summary.md +0 -32
  297. package/dist/cli/templates/agents/synthesizer.md +0 -26
  298. package/dist/cli/templates/pipelines/large-pipeline-example.yml +0 -178
  299. package/dist/cli/templates/pipelines/post-merge-example.yml +0 -78
  300. package/dist/cli/templates/pipelines/pre-commit-example.yml +0 -41
  301. package/dist/cli/templates/pipelines/pre-push-example.yml +0 -51
  302. package/dist/cli/templates/pipelines/test-pipeline.yml +0 -90
  303. package/dist/config/project-config-loader.d.ts +0 -11
  304. package/dist/config/project-config-loader.d.ts.map +0 -1
  305. package/dist/config/project-config-loader.js +0 -100
  306. package/dist/config/project-config-loader.js.map +0 -1
  307. package/dist/core/condition-evaluator.d.ts +0 -16
  308. package/dist/core/condition-evaluator.d.ts.map +0 -1
  309. package/dist/core/condition-evaluator.js +0 -121
  310. package/dist/core/condition-evaluator.js.map +0 -1
  311. package/dist/core/context-reducer.d.ts +0 -15
  312. package/dist/core/context-reducer.d.ts.map +0 -1
  313. package/dist/core/context-reducer.js +0 -224
  314. package/dist/core/context-reducer.js.map +0 -1
  315. package/dist/core/output-storage-manager.d.ts +0 -14
  316. package/dist/core/output-storage-manager.d.ts.map +0 -1
  317. package/dist/core/output-storage-manager.js +0 -68
  318. package/dist/core/output-storage-manager.js.map +0 -1
  319. package/dist/core/output-tool-builder.d.ts +0 -6
  320. package/dist/core/output-tool-builder.d.ts.map +0 -1
  321. package/dist/core/output-tool-builder.js +0 -50
  322. package/dist/core/output-tool-builder.js.map +0 -1
  323. /package/{license → LICENSE} +0 -0
@@ -7,10 +7,10 @@ import { PipelineInitializer } from './pipeline-initializer.js';
7
7
  import { GroupExecutionOrchestrator } from './group-execution-orchestrator.js';
8
8
  import { PipelineFinalizer } from './pipeline-finalizer.js';
9
9
  import { NotificationManager } from '../notifications/notification-manager.js';
10
- import { ProjectConfigLoader } from '../config/project-config-loader.js';
11
10
  import { PipelineLoader } from '../config/pipeline-loader.js';
12
11
  import { LoopStateManager } from './loop-state-manager.js';
13
12
  import { AgentRuntimeRegistry } from './agent-runtime-registry.js';
13
+ import { PipelineAbortError } from './abort-controller.js';
14
14
  import * as fs from 'fs/promises';
15
15
  import * as path from 'path';
16
16
  export class PipelineRunner {
@@ -27,8 +27,9 @@ export class PipelineRunner {
27
27
  repoPath;
28
28
  runtime;
29
29
  stateUpdateCallbacks = [];
30
- projectConfigLoader;
31
30
  loopStateManager;
31
+ loopExecutionDirs;
32
+ loopMainDirs;
32
33
  constructor(repoPath, dryRun = false) {
33
34
  this.repoPath = repoPath;
34
35
  this.dryRun = dryRun;
@@ -37,55 +38,71 @@ export class PipelineRunner {
37
38
  this.prCreator = new PRCreator();
38
39
  this.stateManager = new StateManager(repoPath);
39
40
  this.dagPlanner = new DAGPlanner();
40
- this.projectConfigLoader = new ProjectConfigLoader(repoPath);
41
41
  this.loopStateManager = new LoopStateManager(repoPath);
42
- this.runtime = AgentRuntimeRegistry.getRuntime('claude-sdk');
43
- this.initializer = new PipelineInitializer(this.gitManager, this.branchManager, this.repoPath, this.dryRun, this.runtime);
44
- this.groupOrchestrator = new GroupExecutionOrchestrator(this.gitManager, this.stateManager, this.repoPath, this.dryRun, this.runtime, this.shouldLog.bind(this), this.notifyStateChange.bind(this), this.notifyStageResults.bind(this));
42
+ this.runtime = AgentRuntimeRegistry.getRuntime('claude-code-headless');
43
+ this.initializer = new PipelineInitializer(this.gitManager, this.repoPath, this.dryRun, this.runtime);
44
+ this.groupOrchestrator = new GroupExecutionOrchestrator(this.stateManager, this.shouldLog.bind(this), this.notifyStateChange.bind(this), this.notifyStageResults.bind(this));
45
45
  this.finalizer = new PipelineFinalizer(this.gitManager, this.branchManager, this.prCreator, this.stateManager, this.repoPath, this.dryRun, this.shouldLog.bind(this));
46
46
  }
47
47
  shouldLog(interactive) {
48
48
  return !interactive;
49
49
  }
50
50
  async notifyStageResults(executions, state) {
51
+ const notificationContexts = [];
51
52
  for (const execution of executions) {
52
53
  if (execution.status === 'success') {
53
- await this.notify({
54
+ notificationContexts.push({
54
55
  event: 'stage.completed',
55
56
  pipelineState: state,
56
57
  stage: execution
57
58
  });
58
59
  }
59
60
  else if (execution.status === 'failed') {
60
- await this.notify({
61
+ notificationContexts.push({
61
62
  event: 'stage.failed',
62
63
  pipelineState: state,
63
64
  stage: execution
64
65
  });
65
66
  }
66
67
  }
68
+ if (notificationContexts.length > 0) {
69
+ await Promise.all(notificationContexts.map(context => this.notify(context)));
70
+ }
67
71
  }
68
72
  async runPipeline(config, options = {}) {
69
73
  const interactive = options.interactive || false;
74
+ const verbose = options.verbose || false;
70
75
  const notificationManager = config.notifications
71
76
  ? new NotificationManager(config.notifications)
72
77
  : undefined;
73
- const loopingConfig = await this.projectConfigLoader.loadLoopingConfig();
74
- let loopEnabled = options.loop || false;
75
- if (loopEnabled && !loopingConfig.enabled) {
76
- console.warn('⚠️ Loop mode requested but looping is disabled in config');
78
+ this.loopExecutionDirs = undefined;
79
+ this.loopMainDirs = undefined;
80
+ let loopSession;
81
+ let loopEnabled;
82
+ let loopingConfig;
83
+ if (options.loop === false) {
77
84
  loopEnabled = false;
85
+ loopingConfig = this.getDefaultLoopingConfig();
86
+ }
87
+ else {
88
+ loopEnabled = config.looping?.enabled ?? false;
89
+ if (loopEnabled) {
90
+ loopSession = await this.loopStateManager.startSession(options.maxLoopIterations ?? config.looping?.maxIterations ?? 100);
91
+ loopingConfig = config.looping;
92
+ }
93
+ else {
94
+ loopingConfig = this.getDefaultLoopingConfig();
95
+ }
78
96
  }
79
- const maxIterations = options.maxLoopIterations ?? loopingConfig.maxIterations ?? 100;
97
+ const maxIterations = options.maxLoopIterations ?? loopingConfig.maxIterations;
80
98
  let iterationCount = 0;
81
99
  let lastState;
82
100
  let currentConfig = config;
83
101
  let currentMetadata = options.loopMetadata;
84
102
  let loopTerminationReason = 'natural';
85
- let loopSession;
86
- if (loopEnabled) {
87
- loopSession = this.loopStateManager.startSession(maxIterations);
88
- }
103
+ let loopDirCreated = false;
104
+ let loopDirs = loopingConfig.directories;
105
+ const loopIterationHistory = [];
89
106
  while (true) {
90
107
  iterationCount++;
91
108
  if (iterationCount > maxIterations) {
@@ -99,20 +116,65 @@ export class PipelineRunner {
99
116
  : currentConfig.name;
100
117
  console.log(`🔁 Loop iteration ${iterationCount}: Running pipeline '${pipelineName}'...`);
101
118
  }
119
+ if (loopEnabled && loopSession) {
120
+ const pipelineName = this.getPipelineName(currentConfig, currentMetadata);
121
+ await this.loopStateManager.appendIteration(loopSession.sessionId, {
122
+ iterationNumber: iterationCount,
123
+ pipelineName,
124
+ status: 'in-progress'
125
+ });
126
+ }
102
127
  const loopContext = loopEnabled && loopingConfig.enabled
103
128
  ? {
104
129
  enabled: true,
105
- directories: loopingConfig.directories,
130
+ directories: loopDirs,
106
131
  currentIteration: iterationCount,
107
- maxIterations
132
+ maxIterations,
133
+ sessionId: loopSession?.sessionId
108
134
  }
109
135
  : undefined;
110
136
  lastState = await this._executeSinglePipeline(currentConfig, currentMetadata, {
111
137
  interactive,
138
+ verbose,
112
139
  notificationManager,
113
140
  loopContext,
114
- loopSessionId: loopSession?.sessionId
141
+ loopSessionId: loopSession?.sessionId,
142
+ abortController: options.abortController,
143
+ isFirstLoopIteration: loopEnabled && !loopDirCreated,
144
+ suppressCompletionNotification: loopEnabled
115
145
  });
146
+ if (loopEnabled && !loopDirCreated && loopContext) {
147
+ loopDirCreated = true;
148
+ loopDirs = loopContext.directories;
149
+ }
150
+ if (loopEnabled && lastState) {
151
+ let totalInput = 0;
152
+ let totalOutput = 0;
153
+ let totalCacheRead = 0;
154
+ for (const stage of lastState.stages) {
155
+ if (stage.tokenUsage) {
156
+ totalInput += stage.tokenUsage.actual_input || 0;
157
+ totalOutput += stage.tokenUsage.output || 0;
158
+ totalCacheRead += stage.tokenUsage.cache_read || 0;
159
+ }
160
+ }
161
+ const historyEntry = {
162
+ iterationNumber: iterationCount,
163
+ pipelineName: currentMetadata?.sourcePath
164
+ ? path.basename(currentMetadata.sourcePath, '.yml')
165
+ : currentConfig.name,
166
+ status: lastState.status === 'completed' ? 'completed'
167
+ : lastState.status === 'aborted' ? 'aborted' : 'failed',
168
+ duration: lastState.artifacts.totalDuration,
169
+ commitCount: lastState.stages.filter(s => s.commitSha).length,
170
+ stageCount: lastState.stages.length,
171
+ successfulStages: lastState.stages.filter(s => s.status === 'success').length,
172
+ failedStages: lastState.stages.filter(s => s.status === 'failed').length,
173
+ tokenUsage: totalInput > 0 ? { totalInput, totalOutput, totalCacheRead } : undefined
174
+ };
175
+ loopIterationHistory.push(historyEntry);
176
+ lastState.loopIterationHistory = [...loopIterationHistory];
177
+ }
116
178
  this.notifyStateChange(lastState);
117
179
  if (this.shouldLog(interactive) && loopEnabled && lastState.status === 'completed') {
118
180
  console.log(`✅ Completed iteration ${iterationCount}`);
@@ -120,8 +182,8 @@ export class PipelineRunner {
120
182
  if (currentMetadata?.sourceType === 'loop-pending') {
121
183
  try {
122
184
  const destDir = lastState.status === 'completed'
123
- ? loopingConfig.directories.finished
124
- : loopingConfig.directories.failed;
185
+ ? loopDirs.finished
186
+ : loopDirs.failed;
125
187
  const fileName = path.basename(currentMetadata.sourcePath);
126
188
  await this._moveFile(currentMetadata.sourcePath, destDir, fileName);
127
189
  if (this.shouldLog(interactive)) {
@@ -133,26 +195,38 @@ export class PipelineRunner {
133
195
  console.error(`⚠️ Failed to move pipeline file: ${error}`);
134
196
  }
135
197
  }
136
- if (lastState.status === 'failed') {
198
+ if (lastState.status === 'aborted') {
137
199
  if (loopEnabled && loopSession) {
138
200
  await this.recordIteration(loopSession.sessionId, lastState, currentMetadata, false);
139
201
  }
140
- loopTerminationReason = 'failure';
141
- const pipelineName = currentMetadata?.sourcePath
142
- ? path.basename(currentMetadata.sourcePath, '.yml')
143
- : currentConfig.name;
144
202
  if (this.shouldLog(interactive)) {
145
- console.log(`Loop: terminating after failure of ${pipelineName}`);
203
+ console.log('Loop: terminating due to abort');
146
204
  }
147
205
  break;
148
206
  }
207
+ if (lastState.status === 'failed') {
208
+ if (loopEnabled && loopSession) {
209
+ await this.recordIteration(loopSession.sessionId, lastState, currentMetadata, false);
210
+ }
211
+ const failureStrategy = currentConfig.execution?.failureStrategy ?? 'stop';
212
+ if (failureStrategy === 'stop') {
213
+ loopTerminationReason = 'failure';
214
+ const pipelineName = currentMetadata?.sourcePath
215
+ ? path.basename(currentMetadata.sourcePath, '.yml')
216
+ : currentConfig.name;
217
+ if (this.shouldLog(interactive)) {
218
+ console.log(`Loop: terminating after failure of ${pipelineName}`);
219
+ }
220
+ break;
221
+ }
222
+ }
149
223
  if (!loopEnabled) {
150
224
  if (loopSession) {
151
225
  await this.recordIteration(loopSession.sessionId, lastState, currentMetadata, false);
152
226
  }
153
227
  break;
154
228
  }
155
- const nextFile = await this._findNextPipelineFile(loopingConfig);
229
+ const nextFile = await this._findNextPipelineFile(loopDirs);
156
230
  const triggeredNext = nextFile !== undefined;
157
231
  if (loopSession) {
158
232
  await this.recordIteration(loopSession.sessionId, lastState, currentMetadata, triggeredNext);
@@ -166,7 +240,7 @@ export class PipelineRunner {
166
240
  const fileName = path.basename(nextFile);
167
241
  let runningPath;
168
242
  try {
169
- runningPath = await this._moveFile(nextFile, loopingConfig.directories.running, fileName);
243
+ runningPath = await this._moveFile(nextFile, loopDirs.running, fileName);
170
244
  }
171
245
  catch (error) {
172
246
  console.error(`❌ Failed to move ${fileName} to running directory: ${error}`);
@@ -181,7 +255,7 @@ export class PipelineRunner {
181
255
  catch (error) {
182
256
  console.error(`❌ Failed to load pipeline ${fileName}: ${error}`);
183
257
  try {
184
- await this._moveFile(runningPath, loopingConfig.directories.failed, fileName);
258
+ await this._moveFile(runningPath, loopDirs.failed, fileName);
185
259
  }
186
260
  catch (moveError) {
187
261
  console.error(`⚠️ Failed to move ${fileName} to failed directory: ${moveError}`);
@@ -194,18 +268,55 @@ export class PipelineRunner {
194
268
  }
195
269
  if (lastState.loopContext) {
196
270
  lastState.loopContext.terminationReason = loopTerminationReason;
271
+ this.notifyStateChange(lastState);
272
+ }
273
+ if (loopEnabled &&
274
+ lastState.artifacts.worktreePath &&
275
+ this.loopExecutionDirs &&
276
+ this.loopMainDirs) {
277
+ try {
278
+ await this.copyLoopDirectories(this.loopExecutionDirs, this.loopMainDirs);
279
+ if (this.shouldLog(interactive)) {
280
+ console.log('📋 Copied loop directories to main repo');
281
+ }
282
+ }
283
+ catch (error) {
284
+ console.warn(`⚠️ Could not copy loop directories: ${error instanceof Error ? error.message : String(error)}`);
285
+ }
197
286
  }
198
287
  if (loopEnabled && loopSession) {
199
- const sessionStatus = loopTerminationReason === 'natural' ? 'completed' :
200
- loopTerminationReason === 'limit-reached' ? 'limit-reached' :
201
- 'failed';
288
+ const sessionStatus = lastState.status === 'aborted' ? 'aborted' :
289
+ loopTerminationReason === 'natural' ? 'completed' :
290
+ loopTerminationReason === 'limit-reached' ? 'limit-reached' :
291
+ 'failed';
202
292
  await this.loopStateManager.completeSession(loopSession.sessionId, sessionStatus);
203
293
  }
294
+ if (loopEnabled) {
295
+ const event = lastState.status === 'aborted'
296
+ ? 'pipeline.aborted'
297
+ : loopTerminationReason === 'natural'
298
+ ? 'pipeline.completed'
299
+ : 'pipeline.failed';
300
+ await this.notify({
301
+ event,
302
+ pipelineState: lastState,
303
+ metadata: {
304
+ loopCompleted: loopTerminationReason === 'natural',
305
+ terminationReason: loopTerminationReason,
306
+ totalIterations: iterationCount
307
+ }
308
+ });
309
+ }
204
310
  return lastState;
205
311
  }
206
312
  notifyStateChange(state) {
313
+ const clonedState = {
314
+ ...state,
315
+ stages: [...state.stages],
316
+ artifacts: { ...state.artifacts }
317
+ };
207
318
  for (const callback of this.stateUpdateCallbacks) {
208
- callback(state);
319
+ callback(clonedState);
209
320
  }
210
321
  }
211
322
  async notify(context) {
@@ -227,9 +338,85 @@ export class PipelineRunner {
227
338
  onStateChange(callback) {
228
339
  this.stateUpdateCallbacks.push(callback);
229
340
  }
230
- async _findNextPipelineFile(loopingConfig) {
341
+ getDefaultLoopingConfig(sessionId) {
342
+ const baseDir = sessionId
343
+ ? `.agent-pipeline/loops/${sessionId}`
344
+ : '.agent-pipeline/loops/default';
345
+ return {
346
+ enabled: true,
347
+ maxIterations: 100,
348
+ directories: this.getSessionLoopDirs(this.repoPath, baseDir),
349
+ };
350
+ }
351
+ getSessionLoopDirs(basePath, sessionBaseDir) {
352
+ return {
353
+ pending: path.resolve(basePath, `${sessionBaseDir}/pending`),
354
+ running: path.resolve(basePath, `${sessionBaseDir}/running`),
355
+ finished: path.resolve(basePath, `${sessionBaseDir}/finished`),
356
+ failed: path.resolve(basePath, `${sessionBaseDir}/failed`),
357
+ };
358
+ }
359
+ resolveLoopDirectories(loopContext, executionRepoPath, worktreePath) {
360
+ const sessionId = loopContext.sessionId ?? 'default';
361
+ const sessionBaseDir = `.agent-pipeline/loops/${sessionId}`;
362
+ const sessionMainDirs = this.getSessionLoopDirs(this.repoPath, sessionBaseDir);
363
+ const sessionExecutionDirs = this.getSessionLoopDirs(executionRepoPath, sessionBaseDir);
364
+ const providedDirs = loopContext.directories;
365
+ const mainDirs = {
366
+ pending: providedDirs.pending || sessionMainDirs.pending,
367
+ running: providedDirs.running || sessionMainDirs.running,
368
+ finished: providedDirs.finished || sessionMainDirs.finished,
369
+ failed: providedDirs.failed || sessionMainDirs.failed,
370
+ };
371
+ if (!worktreePath) {
372
+ return { executionDirs: mainDirs, mainDirs, sessionExecutionDirs };
373
+ }
374
+ const executionDirs = {
375
+ pending: this.mapToExecutionDir(mainDirs.pending, executionRepoPath, sessionExecutionDirs.pending),
376
+ running: this.mapToExecutionDir(mainDirs.running, executionRepoPath, sessionExecutionDirs.running),
377
+ finished: this.mapToExecutionDir(mainDirs.finished, executionRepoPath, sessionExecutionDirs.finished),
378
+ failed: this.mapToExecutionDir(mainDirs.failed, executionRepoPath, sessionExecutionDirs.failed),
379
+ };
380
+ return { executionDirs, mainDirs, sessionExecutionDirs };
381
+ }
382
+ mapToExecutionDir(mainDir, executionRepoPath, fallbackDir) {
383
+ const relativePath = path.relative(this.repoPath, mainDir);
384
+ const isInsideRepo = relativePath && !relativePath.startsWith('..') && !path.isAbsolute(relativePath);
385
+ if (!isInsideRepo) {
386
+ return fallbackDir;
387
+ }
388
+ return path.resolve(executionRepoPath, relativePath);
389
+ }
390
+ areSameLoopDirs(left, right) {
391
+ return left.pending === right.pending &&
392
+ left.running === right.running &&
393
+ left.finished === right.finished &&
394
+ left.failed === right.failed;
395
+ }
396
+ async ensureLoopDirectoriesExist(directories) {
397
+ const dirs = [
398
+ directories.pending,
399
+ directories.running,
400
+ directories.finished,
401
+ directories.failed,
402
+ ];
403
+ await Promise.all(dirs.map(dir => fs.mkdir(dir, { recursive: true })));
404
+ }
405
+ async copyLoopDirectories(executionDirs, mainDirs) {
406
+ const dirPairs = [
407
+ { source: executionDirs.pending, dest: mainDirs.pending },
408
+ { source: executionDirs.running, dest: mainDirs.running },
409
+ { source: executionDirs.finished, dest: mainDirs.finished },
410
+ { source: executionDirs.failed, dest: mainDirs.failed },
411
+ ];
412
+ for (const { source, dest } of dirPairs) {
413
+ await fs.mkdir(path.dirname(dest), { recursive: true });
414
+ await fs.cp(source, dest, { recursive: true, force: true });
415
+ }
416
+ }
417
+ async _findNextPipelineFile(loopDirs) {
231
418
  try {
232
- const pendingDir = loopingConfig.directories.pending;
419
+ const pendingDir = loopDirs.pending;
233
420
  const files = await fs.readdir(pendingDir);
234
421
  const yamlFiles = files.filter(f => f.endsWith('.yml') || f.endsWith('.yaml'));
235
422
  if (yamlFiles.length === 0) {
@@ -267,17 +454,84 @@ export class PipelineRunner {
267
454
  return destPath;
268
455
  }
269
456
  async _executeSinglePipeline(config, metadata, options) {
270
- const { interactive, loopContext, loopSessionId } = options;
271
- this.notificationManager = options.notificationManager;
272
- const initResult = await this.initializer.initialize(config, {
273
- interactive,
274
- notificationManager: this.notificationManager,
275
- loopContext,
276
- loopSessionId,
277
- metadata
278
- }, this.notify.bind(this), this.notifyStateChange.bind(this));
279
- let { state, parallelExecutor, pipelineBranch, originalBranch, startTime } = initResult;
457
+ const { interactive, verbose, loopContext, loopSessionId, abortController, isFirstLoopIteration, suppressCompletionNotification } = options;
458
+ this.notificationManager = options.notificationManager ||
459
+ (config.notifications ? new NotificationManager(config.notifications) : undefined);
460
+ let initResult;
461
+ try {
462
+ initResult = await this.initializer.initialize(config, {
463
+ interactive,
464
+ verbose,
465
+ notificationManager: this.notificationManager,
466
+ loopContext,
467
+ loopSessionId,
468
+ metadata,
469
+ abortController
470
+ }, this.notify.bind(this), this.notifyStateChange.bind(this));
471
+ }
472
+ catch (error) {
473
+ const errorMessage = error instanceof Error ? error.message : String(error);
474
+ const now = new Date().toISOString();
475
+ if (this.shouldLog(interactive)) {
476
+ console.error(`\n❌ Pipeline initialization failed: ${errorMessage}\n`);
477
+ }
478
+ const failedState = {
479
+ runId: 'init-failed',
480
+ pipelineConfig: config,
481
+ trigger: {
482
+ type: config.trigger,
483
+ commitSha: '',
484
+ timestamp: now
485
+ },
486
+ stages: [
487
+ {
488
+ stageName: 'pipeline-initialization',
489
+ status: 'failed',
490
+ startTime: now,
491
+ endTime: now,
492
+ duration: 0,
493
+ error: {
494
+ message: errorMessage,
495
+ timestamp: now
496
+ }
497
+ }
498
+ ],
499
+ status: 'failed',
500
+ artifacts: {
501
+ initialCommit: '',
502
+ changedFiles: [],
503
+ totalDuration: 0,
504
+ handoverDir: ''
505
+ }
506
+ };
507
+ await this.notify({
508
+ event: 'pipeline.failed',
509
+ pipelineState: failedState,
510
+ metadata: { error: errorMessage }
511
+ });
512
+ return failedState;
513
+ }
514
+ let { state, parallelExecutor, pipelineBranch, worktreePath, executionRepoPath, startTime, pipelineLogger } = initResult;
280
515
  this.notificationManager = initResult.notificationManager;
516
+ if (isFirstLoopIteration && loopContext?.sessionId) {
517
+ const { executionDirs, mainDirs, sessionExecutionDirs } = this.resolveLoopDirectories(loopContext, executionRepoPath, worktreePath);
518
+ const usesSessionDirs = this.areSameLoopDirs(executionDirs, sessionExecutionDirs);
519
+ if (usesSessionDirs) {
520
+ await this.loopStateManager.createSessionDirectories(loopContext.sessionId, executionRepoPath);
521
+ }
522
+ else {
523
+ await this.ensureLoopDirectoriesExist(executionDirs);
524
+ }
525
+ loopContext.directories = executionDirs;
526
+ this.loopExecutionDirs = executionDirs;
527
+ this.loopMainDirs = mainDirs;
528
+ if (this.shouldLog(interactive)) {
529
+ const baseDir = usesSessionDirs
530
+ ? this.loopStateManager.getSessionQueueDir(loopContext.sessionId, executionRepoPath)
531
+ : executionRepoPath;
532
+ console.log(`📁 Created loop directories under: ${baseDir}`);
533
+ }
534
+ }
281
535
  try {
282
536
  const executionGraph = this.dagPlanner.buildExecutionPlan(config);
283
537
  if (this.shouldLog(interactive) && executionGraph.plan.groups.length > 0) {
@@ -288,39 +542,77 @@ export class PipelineRunner {
288
542
  }
289
543
  console.log('');
290
544
  }
291
- for (const group of executionGraph.plan.groups) {
292
- const result = await this.groupOrchestrator.processGroup(group, state, config, executionGraph, parallelExecutor, interactive);
545
+ const totalGroups = executionGraph.plan.groups.length;
546
+ let abortedAtGroup;
547
+ for (let groupIndex = 0; groupIndex < totalGroups; groupIndex++) {
548
+ if (abortController?.aborted) {
549
+ state.status = 'aborted';
550
+ abortedAtGroup = groupIndex + 1;
551
+ break;
552
+ }
553
+ const group = executionGraph.plan.groups[groupIndex];
554
+ const isFinalGroup = groupIndex === totalGroups - 1;
555
+ const result = await this.groupOrchestrator.processGroup(group, state, config, parallelExecutor, interactive, initResult.handoverManager, { isFinalGroup }, verbose);
293
556
  state = result.state;
557
+ if (abortController?.aborted) {
558
+ state.status = 'aborted';
559
+ abortedAtGroup = groupIndex + 1;
560
+ break;
561
+ }
294
562
  if (result.shouldStopPipeline) {
295
563
  state.status = 'failed';
296
564
  break;
297
565
  }
298
566
  }
299
- if (state.status === 'running') {
567
+ if (abortedAtGroup !== undefined && this.shouldLog(interactive)) {
568
+ console.log(`\n⚠️ Pipeline aborted at group ${abortedAtGroup}/${totalGroups}\n`);
569
+ }
570
+ if (state.status === 'running' && !abortController?.aborted) {
300
571
  state.status = 'completed';
301
572
  }
302
573
  }
303
574
  catch (error) {
304
- state.status = 'failed';
305
- if (this.shouldLog(interactive)) {
306
- console.error(`\n❌ Pipeline failed: ${error}\n`);
575
+ if (error instanceof PipelineAbortError || abortController?.aborted) {
576
+ state.status = 'aborted';
577
+ if (this.shouldLog(interactive)) {
578
+ console.log(`\n⚠️ Pipeline aborted\n`);
579
+ }
580
+ }
581
+ else {
582
+ state.status = 'failed';
583
+ if (this.shouldLog(interactive)) {
584
+ console.error(`\n❌ Pipeline failed: ${error}\n`);
585
+ }
307
586
  }
308
587
  }
309
- state = await this.finalizer.finalize(state, config, pipelineBranch, originalBranch, startTime, interactive, this.notify.bind(this), this.notifyStateChange.bind(this));
588
+ state = await this.finalizer.finalize(state, config, pipelineBranch, worktreePath, executionRepoPath, startTime, interactive, verbose, this.notify.bind(this), this.notifyStateChange.bind(this), { suppressCompletionNotification, pipelineLogger });
310
589
  return state;
311
590
  }
312
591
  async recordIteration(sessionId, state, metadata, triggeredNext) {
313
- const pipelineName = metadata?.sourcePath
314
- ? path.basename(metadata.sourcePath, '.yml')
315
- : state.pipelineConfig.name;
316
- await this.loopStateManager.appendIteration(sessionId, {
317
- iterationNumber: state.loopContext?.currentIteration ?? 1,
592
+ const pipelineName = this.getPipelineName(state.pipelineConfig, metadata);
593
+ const iterationNumber = state.loopContext?.currentIteration ?? 1;
594
+ const updated = await this.loopStateManager.updateIteration(sessionId, iterationNumber, {
318
595
  pipelineName,
319
596
  runId: state.runId,
320
- status: state.status === 'completed' ? 'completed' : 'failed',
597
+ status: state.status === 'completed' ? 'completed' : state.status === 'aborted' ? 'aborted' : 'failed',
321
598
  duration: state.artifacts.totalDuration,
322
599
  triggeredNext
323
600
  });
601
+ if (!updated) {
602
+ await this.loopStateManager.appendIteration(sessionId, {
603
+ iterationNumber,
604
+ pipelineName,
605
+ runId: state.runId,
606
+ status: state.status === 'completed' ? 'completed' : state.status === 'aborted' ? 'aborted' : 'failed',
607
+ duration: state.artifacts.totalDuration,
608
+ triggeredNext
609
+ });
610
+ }
611
+ }
612
+ getPipelineName(config, metadata) {
613
+ return metadata?.sourcePath
614
+ ? path.basename(metadata.sourcePath, '.yml')
615
+ : config.name;
324
616
  }
325
617
  }
326
618
  //# sourceMappingURL=pipeline-runner.js.map