@intrect/openswarm 0.17.2 → 0.17.4

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 (263) hide show
  1. package/README.md +21 -5
  2. package/config.example.yaml +18 -0
  3. package/dist/adapters/agenticLoop.d.ts +2 -0
  4. package/dist/adapters/agenticLoop.d.ts.map +1 -1
  5. package/dist/adapters/agenticLoop.js +6 -3
  6. package/dist/adapters/agenticLoop.js.map +1 -1
  7. package/dist/adapters/base.d.ts.map +1 -1
  8. package/dist/adapters/base.js +9 -0
  9. package/dist/adapters/base.js.map +1 -1
  10. package/dist/adapters/claude.d.ts.map +1 -1
  11. package/dist/adapters/claude.js +6 -3
  12. package/dist/adapters/claude.js.map +1 -1
  13. package/dist/adapters/codex.d.ts.map +1 -1
  14. package/dist/adapters/codex.js +3 -2
  15. package/dist/adapters/codex.js.map +1 -1
  16. package/dist/adapters/codexResponses.d.ts +2 -1
  17. package/dist/adapters/codexResponses.d.ts.map +1 -1
  18. package/dist/adapters/codexResponses.js +34 -30
  19. package/dist/adapters/codexResponses.js.map +1 -1
  20. package/dist/adapters/errorClassification.d.ts +11 -0
  21. package/dist/adapters/errorClassification.d.ts.map +1 -1
  22. package/dist/adapters/errorClassification.js +21 -0
  23. package/dist/adapters/errorClassification.js.map +1 -1
  24. package/dist/adapters/gpt.d.ts.map +1 -1
  25. package/dist/adapters/gpt.js +1 -0
  26. package/dist/adapters/gpt.js.map +1 -1
  27. package/dist/adapters/local.d.ts.map +1 -1
  28. package/dist/adapters/local.js +1 -0
  29. package/dist/adapters/local.js.map +1 -1
  30. package/dist/adapters/openrouter.d.ts.map +1 -1
  31. package/dist/adapters/openrouter.js +1 -0
  32. package/dist/adapters/openrouter.js.map +1 -1
  33. package/dist/adapters/processRegistry.d.ts.map +1 -1
  34. package/dist/adapters/processRegistry.js +8 -0
  35. package/dist/adapters/processRegistry.js.map +1 -1
  36. package/dist/adapters/types.d.ts +2 -0
  37. package/dist/adapters/types.d.ts.map +1 -1
  38. package/dist/agents/pairPipeline.d.ts +10 -139
  39. package/dist/agents/pairPipeline.d.ts.map +1 -1
  40. package/dist/agents/pairPipeline.js +161 -37
  41. package/dist/agents/pairPipeline.js.map +1 -1
  42. package/dist/agents/pairPipelineTypes.d.ts +111 -0
  43. package/dist/agents/pairPipelineTypes.d.ts.map +1 -0
  44. package/dist/agents/pairPipelineTypes.js +2 -0
  45. package/dist/agents/pairPipelineTypes.js.map +1 -0
  46. package/dist/agents/pipelineGuards.d.ts.map +1 -1
  47. package/dist/agents/pipelineGuards.js +346 -0
  48. package/dist/agents/pipelineGuards.js.map +1 -1
  49. package/dist/agents/pipelineTaskPrefix.d.ts +3 -0
  50. package/dist/agents/pipelineTaskPrefix.d.ts.map +1 -0
  51. package/dist/agents/pipelineTaskPrefix.js +16 -0
  52. package/dist/agents/pipelineTaskPrefix.js.map +1 -0
  53. package/dist/agents/reflection.d.ts +9 -1
  54. package/dist/agents/reflection.d.ts.map +1 -1
  55. package/dist/agents/reflection.js +27 -1
  56. package/dist/agents/reflection.js.map +1 -1
  57. package/dist/agents/reviewer.d.ts +6 -0
  58. package/dist/agents/reviewer.d.ts.map +1 -1
  59. package/dist/agents/reviewer.js +4 -1
  60. package/dist/agents/reviewer.js.map +1 -1
  61. package/dist/agents/stageErrorClassification.d.ts +16 -0
  62. package/dist/agents/stageErrorClassification.d.ts.map +1 -0
  63. package/dist/agents/stageErrorClassification.js +38 -0
  64. package/dist/agents/stageErrorClassification.js.map +1 -0
  65. package/dist/agents/stageModelResolver.d.ts +8 -0
  66. package/dist/agents/stageModelResolver.d.ts.map +1 -0
  67. package/dist/agents/stageModelResolver.js +22 -0
  68. package/dist/agents/stageModelResolver.js.map +1 -0
  69. package/dist/agents/worker.d.ts +33 -0
  70. package/dist/agents/worker.d.ts.map +1 -1
  71. package/dist/agents/worker.js +59 -4
  72. package/dist/agents/worker.js.map +1 -1
  73. package/dist/agents/workerFanout.d.ts +38 -0
  74. package/dist/agents/workerFanout.d.ts.map +1 -0
  75. package/dist/agents/workerFanout.js +292 -0
  76. package/dist/agents/workerFanout.js.map +1 -0
  77. package/dist/agents/workerFanoutGate.d.ts +48 -0
  78. package/dist/agents/workerFanoutGate.d.ts.map +1 -0
  79. package/dist/agents/workerFanoutGate.js +146 -0
  80. package/dist/agents/workerFanoutGate.js.map +1 -0
  81. package/dist/agents/workerValidationEvidence.d.ts +5 -0
  82. package/dist/agents/workerValidationEvidence.d.ts.map +1 -0
  83. package/dist/agents/workerValidationEvidence.js +75 -0
  84. package/dist/agents/workerValidationEvidence.js.map +1 -0
  85. package/dist/automation/autonomousRunner.d.ts +26 -6
  86. package/dist/automation/autonomousRunner.d.ts.map +1 -1
  87. package/dist/automation/autonomousRunner.js +243 -45
  88. package/dist/automation/autonomousRunner.js.map +1 -1
  89. package/dist/automation/backlogGrooming.d.ts +52 -0
  90. package/dist/automation/backlogGrooming.d.ts.map +1 -0
  91. package/dist/automation/backlogGrooming.js +231 -0
  92. package/dist/automation/backlogGrooming.js.map +1 -0
  93. package/dist/automation/runnerExecution.d.ts +1 -1
  94. package/dist/automation/runnerExecution.d.ts.map +1 -1
  95. package/dist/automation/runnerExecution.js +31 -9
  96. package/dist/automation/runnerExecution.js.map +1 -1
  97. package/dist/automation/runnerState.d.ts +9 -0
  98. package/dist/automation/runnerState.d.ts.map +1 -1
  99. package/dist/automation/runnerState.js +17 -0
  100. package/dist/automation/runnerState.js.map +1 -1
  101. package/dist/automation/runnerTypes.d.ts +3 -1
  102. package/dist/automation/runnerTypes.d.ts.map +1 -1
  103. package/dist/automation/taskSource.d.ts +6 -3
  104. package/dist/automation/taskSource.d.ts.map +1 -1
  105. package/dist/automation/taskSource.js +5 -0
  106. package/dist/automation/taskSource.js.map +1 -1
  107. package/dist/cli/daemon.d.ts +20 -3
  108. package/dist/cli/daemon.d.ts.map +1 -1
  109. package/dist/cli/daemon.js +42 -2
  110. package/dist/cli/daemon.js.map +1 -1
  111. package/dist/cli/fixBoard.d.ts +14 -0
  112. package/dist/cli/fixBoard.d.ts.map +1 -0
  113. package/dist/cli/fixBoard.js +32 -0
  114. package/dist/cli/fixBoard.js.map +1 -0
  115. package/dist/cli/fixCommand.d.ts +8 -0
  116. package/dist/cli/fixCommand.d.ts.map +1 -1
  117. package/dist/cli/fixCommand.js +47 -8
  118. package/dist/cli/fixCommand.js.map +1 -1
  119. package/dist/cli/memoryCommand.d.ts +37 -0
  120. package/dist/cli/memoryCommand.d.ts.map +1 -0
  121. package/dist/cli/memoryCommand.js +156 -0
  122. package/dist/cli/memoryCommand.js.map +1 -0
  123. package/dist/cli/reviewAudit.d.ts +68 -0
  124. package/dist/cli/reviewAudit.d.ts.map +1 -1
  125. package/dist/cli/reviewAudit.js +147 -4
  126. package/dist/cli/reviewAudit.js.map +1 -1
  127. package/dist/cli/reviewMaxCommand.d.ts +2 -0
  128. package/dist/cli/reviewMaxCommand.d.ts.map +1 -1
  129. package/dist/cli/reviewMaxCommand.js +61 -36
  130. package/dist/cli/reviewMaxCommand.js.map +1 -1
  131. package/dist/cli.js +68 -13
  132. package/dist/cli.js.map +1 -1
  133. package/dist/core/config.d.ts +413 -0
  134. package/dist/core/config.d.ts.map +1 -1
  135. package/dist/core/config.js +51 -5
  136. package/dist/core/config.js.map +1 -1
  137. package/dist/core/eventHub.d.ts +22 -0
  138. package/dist/core/eventHub.d.ts.map +1 -1
  139. package/dist/core/eventHub.js +1 -0
  140. package/dist/core/eventHub.js.map +1 -1
  141. package/dist/core/providerOverride.d.ts +9 -0
  142. package/dist/core/providerOverride.d.ts.map +1 -1
  143. package/dist/core/providerOverride.js +12 -0
  144. package/dist/core/providerOverride.js.map +1 -1
  145. package/dist/core/service.d.ts.map +1 -1
  146. package/dist/core/service.js +8 -2
  147. package/dist/core/service.js.map +1 -1
  148. package/dist/core/types.d.ts +61 -1
  149. package/dist/core/types.d.ts.map +1 -1
  150. package/dist/linear/linear.d.ts +2 -1
  151. package/dist/linear/linear.d.ts.map +1 -1
  152. package/dist/linear/linear.js +16 -6
  153. package/dist/linear/linear.js.map +1 -1
  154. package/dist/locale/prompts/en.d.ts.map +1 -1
  155. package/dist/locale/prompts/en.js +11 -1
  156. package/dist/locale/prompts/en.js.map +1 -1
  157. package/dist/locale/prompts/ko.d.ts.map +1 -1
  158. package/dist/locale/prompts/ko.js +11 -1
  159. package/dist/locale/prompts/ko.js.map +1 -1
  160. package/dist/memory/compaction.d.ts +2 -2
  161. package/dist/memory/compaction.d.ts.map +1 -1
  162. package/dist/memory/compaction.js +22 -17
  163. package/dist/memory/compaction.js.map +1 -1
  164. package/dist/memory/index.d.ts +3 -3
  165. package/dist/memory/index.js +3 -3
  166. package/dist/memory/memoryCore.d.ts +15 -27
  167. package/dist/memory/memoryCore.d.ts.map +1 -1
  168. package/dist/memory/memoryCore.js +112 -97
  169. package/dist/memory/memoryCore.js.map +1 -1
  170. package/dist/memory/memoryFilters.d.ts +8 -0
  171. package/dist/memory/memoryFilters.d.ts.map +1 -0
  172. package/dist/memory/memoryFilters.js +26 -0
  173. package/dist/memory/memoryFilters.js.map +1 -0
  174. package/dist/memory/memoryOps.d.ts +7 -23
  175. package/dist/memory/memoryOps.d.ts.map +1 -1
  176. package/dist/memory/memoryOps.js +49 -109
  177. package/dist/memory/memoryOps.js.map +1 -1
  178. package/dist/memory/repoKnowledge.d.ts.map +1 -1
  179. package/dist/memory/repoKnowledge.js +48 -3
  180. package/dist/memory/repoKnowledge.js.map +1 -1
  181. package/dist/orchestration/conflictDetector.d.ts.map +1 -1
  182. package/dist/orchestration/conflictDetector.js +26 -7
  183. package/dist/orchestration/conflictDetector.js.map +1 -1
  184. package/dist/orchestration/decisionEngine.d.ts +1 -0
  185. package/dist/orchestration/decisionEngine.d.ts.map +1 -1
  186. package/dist/orchestration/decisionEngine.js.map +1 -1
  187. package/dist/orchestration/taskScheduler.d.ts +5 -0
  188. package/dist/orchestration/taskScheduler.d.ts.map +1 -1
  189. package/dist/orchestration/taskScheduler.js +36 -12
  190. package/dist/orchestration/taskScheduler.js.map +1 -1
  191. package/dist/registry/memoryBridge.js +4 -4
  192. package/dist/registry/memoryBridge.js.map +1 -1
  193. package/dist/support/chatMemory.js +1 -1
  194. package/dist/support/chatMemory.js.map +1 -1
  195. package/dist/support/dashboardHtml.d.ts +1 -1
  196. package/dist/support/dashboardHtml.d.ts.map +1 -1
  197. package/dist/support/dashboardHtml.js +12 -0
  198. package/dist/support/dashboardHtml.js.map +1 -1
  199. package/dist/support/gitTracker.d.ts +30 -3
  200. package/dist/support/gitTracker.d.ts.map +1 -1
  201. package/dist/support/gitTracker.js +108 -29
  202. package/dist/support/gitTracker.js.map +1 -1
  203. package/dist/support/repoMetadata.d.ts +10 -0
  204. package/dist/support/repoMetadata.d.ts.map +1 -1
  205. package/dist/support/repoMetadata.js +31 -0
  206. package/dist/support/repoMetadata.js.map +1 -1
  207. package/dist/support/updateNotifier.d.ts +12 -0
  208. package/dist/support/updateNotifier.d.ts.map +1 -1
  209. package/dist/support/updateNotifier.js +71 -0
  210. package/dist/support/updateNotifier.js.map +1 -1
  211. package/dist/support/web.d.ts.map +1 -1
  212. package/dist/support/web.js +5 -3
  213. package/dist/support/web.js.map +1 -1
  214. package/dist/support/worktreeManager.d.ts +33 -0
  215. package/dist/support/worktreeManager.d.ts.map +1 -1
  216. package/dist/support/worktreeManager.js +172 -2
  217. package/dist/support/worktreeManager.js.map +1 -1
  218. package/dist/tui/App.js +1 -1
  219. package/dist/tui/App.js.map +1 -1
  220. package/dist/tui/components/AuditBoard.d.ts +3 -2
  221. package/dist/tui/components/AuditBoard.d.ts.map +1 -1
  222. package/dist/tui/components/AuditBoard.js +13 -4
  223. package/dist/tui/components/AuditBoard.js.map +1 -1
  224. package/dist/tui/components/DataTable.d.ts +3 -1
  225. package/dist/tui/components/DataTable.d.ts.map +1 -1
  226. package/dist/tui/components/DataTable.js +22 -5
  227. package/dist/tui/components/DataTable.js.map +1 -1
  228. package/dist/tui/components/StageTimeline.d.ts +1 -1
  229. package/dist/tui/components/StageTimeline.d.ts.map +1 -1
  230. package/dist/tui/components/StageTimeline.js +5 -2
  231. package/dist/tui/components/StageTimeline.js.map +1 -1
  232. package/dist/tui/components/SubagentTree.d.ts +6 -6
  233. package/dist/tui/components/SubagentTree.d.ts.map +1 -1
  234. package/dist/tui/components/SubagentTree.js +33 -5
  235. package/dist/tui/components/SubagentTree.js.map +1 -1
  236. package/dist/tui/eventCoalescer.d.ts +29 -0
  237. package/dist/tui/eventCoalescer.d.ts.map +1 -0
  238. package/dist/tui/eventCoalescer.js +56 -0
  239. package/dist/tui/eventCoalescer.js.map +1 -0
  240. package/dist/tui/hooks/usePipelineEvents.d.ts +1 -1
  241. package/dist/tui/hooks/usePipelineEvents.d.ts.map +1 -1
  242. package/dist/tui/hooks/usePipelineEvents.js +18 -4
  243. package/dist/tui/hooks/usePipelineEvents.js.map +1 -1
  244. package/dist/tui/monitorRows.d.ts +41 -2
  245. package/dist/tui/monitorRows.d.ts.map +1 -1
  246. package/dist/tui/monitorRows.js +86 -7
  247. package/dist/tui/monitorRows.js.map +1 -1
  248. package/dist/tui/panels/MonitorPanel.d.ts +2 -1
  249. package/dist/tui/panels/MonitorPanel.d.ts.map +1 -1
  250. package/dist/tui/panels/MonitorPanel.js +2 -2
  251. package/dist/tui/panels/MonitorPanel.js.map +1 -1
  252. package/dist/tui/panels/PipelinePanel.d.ts.map +1 -1
  253. package/dist/tui/panels/PipelinePanel.js +6 -1
  254. package/dist/tui/panels/PipelinePanel.js.map +1 -1
  255. package/dist/tui/pipelineEvents.d.ts +14 -0
  256. package/dist/tui/pipelineEvents.d.ts.map +1 -1
  257. package/dist/tui/pipelineEvents.js +89 -1
  258. package/dist/tui/pipelineEvents.js.map +1 -1
  259. package/dist/tui/subagentTree.d.ts +26 -3
  260. package/dist/tui/subagentTree.d.ts.map +1 -1
  261. package/dist/tui/subagentTree.js +89 -14
  262. package/dist/tui/subagentTree.js.map +1 -1
  263. package/package.json +1 -1
@@ -1,149 +1,19 @@
1
1
  import { EventEmitter } from 'node:events';
2
2
  import type { TaskItem } from '../orchestration/decisionEngine.js';
3
- import type { WorkerResult, ReviewResult, PairSession } from './agentPair.js';
4
- import type { TesterResult } from './tester.js';
5
- import type { DocumenterResult } from './documenter.js';
6
- import type { AuditorResult } from './auditor.js';
7
- import type { SkillDocumenterResult } from './skillDocumenter.js';
8
- import type { PipelineStage, RoleConfig, PipelineGuardsConfig, JobProfile } from '../core/types.js';
9
- import { type CostInfo } from '../support/costTracker.js';
10
- import { type GuardsRunResult } from './pipelineGuards.js';
11
- import { type ReflectionState } from './reflection.js';
12
- export interface PipelineConfig {
13
- /** List of active stages (executed in order) */
14
- stages: PipelineStage[];
15
- /** Whether to continue on test failure */
16
- continueOnTestFail?: boolean;
17
- /** Skip Documenter if no changes */
18
- skipDocumenterIfNoChange?: boolean;
19
- /** Max total iterations (one cycle = Worker → Reviewer → Tester) */
20
- maxIterations?: number;
21
- /**
22
- * Max objective self-repair attempts (lint/bs/test failures) before the loop
23
- * gives up on bad edits. Independent of maxIterations so an operator can cap
24
- * token burn on reflection without shrinking the reviewer-revise budget.
25
- * Default: DEFAULT_MAX_REFLECTIONS (3).
26
- */
27
- maxReflections?: number;
28
- /** Per-role configuration */
29
- roles?: {
30
- worker?: RoleConfig;
31
- reviewer?: RoleConfig;
32
- tester?: RoleConfig;
33
- documenter?: RoleConfig;
34
- auditor?: RoleConfig;
35
- 'skill-documenter'?: RoleConfig;
36
- };
37
- /** Pipeline guards configuration */
38
- guards?: Partial<PipelineGuardsConfig>;
39
- /** Optional job profiles for model selection */
40
- jobProfiles?: JobProfile[];
41
- /** Skip tester if no code files (.ts/.js/.py etc.) changed (default: true) */
42
- skipTesterIfNoCodeChange?: boolean;
43
- /** Skip auditor if fewer than N files changed (default: 3) */
44
- skipAuditorUnderFileCount?: number;
45
- /** Enable verbose logging (detailed stage info, agent decisions, timing) */
46
- verbose?: boolean;
47
- /** Draft Analyzer 사전 분석 결과 (Haiku) — Worker/Planner에 주입 */
48
- draftAnalysis?: {
49
- taskType: string;
50
- intentSummary: string;
51
- relevantFiles: string[];
52
- suggestedApproach: string;
53
- projectStats?: string;
54
- completionCriteria?: string[];
55
- sufficient?: boolean;
56
- impactAnalysis?: import('../knowledge/types.js').ImpactAnalysis;
57
- registrySnapshot?: Array<{
58
- filePath: string;
59
- summary: string;
60
- highlights: string[];
61
- }>;
62
- };
63
- }
64
- export interface StageResult {
65
- stage: PipelineStage;
66
- success: boolean;
67
- result: WorkerResult | ReviewResult | TesterResult | DocumenterResult | AuditorResult | SkillDocumenterResult | {
68
- success: false;
69
- error: string;
70
- };
71
- duration: number;
72
- /** Stage start time (epoch ms) */
73
- startedAt: number;
74
- /** Stage completion time (epoch ms) */
75
- completedAt: number;
76
- }
77
- export interface PipelineResult {
78
- success: boolean;
79
- sessionId: string;
80
- stages: StageResult[];
81
- finalStatus: 'approved' | 'rejected' | 'failed' | 'cancelled' | 'decomposed' | 'rate_limited' | 'infra_error';
82
- /** Unix timestamp (ms) when the rate-limit quota resets — set when finalStatus is 'rate_limited'. */
83
- rateLimitResetsAt?: number;
84
- totalDuration: number;
85
- /** Total number of completed iterations */
86
- iterations: number;
87
- workerResult?: WorkerResult;
88
- reviewResult?: ReviewResult;
89
- testerResult?: TesterResult;
90
- documenterResult?: DocumenterResult;
91
- auditorResult?: AuditorResult;
92
- skillDocumenterResult?: SkillDocumenterResult;
93
- /** Task context (for reporting) */
94
- taskContext?: {
95
- issueIdentifier?: string;
96
- projectName?: string;
97
- projectPath?: string;
98
- taskTitle?: string;
99
- };
100
- /** PR URL (auto-created PR in worktree mode) */
101
- prUrl?: string;
102
- /** Total cost across all stages */
103
- totalCost?: CostInfo;
104
- }
105
- export interface PipelineContext {
106
- task: TaskItem;
107
- projectPath: string;
108
- session: PairSession;
109
- config: PipelineConfig;
110
- /** Current iteration number (1-based) */
111
- currentIteration: number;
112
- /** Formatted task prefix for consistent logging (e.g., "OpenSwarm | INT-1171 | worktree/abc123") */
113
- taskPrefix: string;
114
- workerResult?: WorkerResult;
115
- reviewResult?: ReviewResult;
116
- testerResult?: TesterResult;
117
- documenterResult?: DocumenterResult;
118
- auditorResult?: AuditorResult;
119
- skillDocumenterResult?: SkillDocumenterResult;
120
- guardsResult?: GuardsRunResult;
121
- /** Accumulated objective (lint/bs/test) errors for self-repair reflection */
122
- reflection: ReflectionState;
123
- /**
124
- * Source of the latest revise feedback. 'objective' failures (lint/bs/test)
125
- * flow through the reflection trail and are preserved across fresh-context
126
- * resets; 'review' feedback (reviewer/halt) is subjective and dropped on a
127
- * fresh-context retry.
128
- */
129
- feedbackSource?: 'objective' | 'review';
130
- }
131
- /**
132
- * Build a consistent task prefix for logging across all pipeline stages.
133
- * Format: "ProjectName | INT-XXX | worktree/abc123" or "ProjectName | INT-XXX"
134
- */
135
- export declare function buildTaskPrefix(task: TaskItem, projectPath: string): string;
136
- export type PipelineEventType = 'stage:start' | 'stage:complete' | 'stage:fail' | 'iteration:start' | 'iteration:complete' | 'iteration:fail' | 'pipeline:complete' | 'pipeline:fail' | 'halt';
137
- /** Thrown when the pipeline is cancelled mid-run (project disable / manual stop). */
138
- export declare class PipelineCancelledError extends Error {
139
- constructor();
140
- }
3
+ import type { PipelineGuardsConfig, JobProfile } from '../core/types.js';
4
+ import type { PipelineConfig, PipelineResult, PipelineRunMetadata } from './pairPipelineTypes.js';
5
+ import { PipelineCancelledError } from './stageErrorClassification.js';
6
+ export { PipelineCancelledError };
7
+ export type { PipelineConfig, PipelineContext, PipelineEventType, PipelineResult, PipelineRunMetadata, StageResult, } from './pairPipelineTypes.js';
8
+ export { buildTaskPrefix } from './pipelineTaskPrefix.js';
141
9
  export declare class PairPipeline extends EventEmitter {
142
10
  private config;
143
11
  private stuckDetector;
144
12
  private jobProfiles;
145
13
  /** Set per run() — aborts the pipeline + in-flight adapter call on cancel/disable. */
146
14
  private abortSignal?;
15
+ /** Cache of adapter default models (heavy: OAuth + live catalog) keyed by adapter name. (INT-2393) */
16
+ private defaultModelCache;
147
17
  /** Throw if this run has been cancelled. Called at iteration/stage boundaries. */
148
18
  private throwIfAborted;
149
19
  constructor(config: PipelineConfig);
@@ -174,6 +44,7 @@ export declare class PairPipeline extends EventEmitter {
174
44
  * Run a single stage
175
45
  */
176
46
  private runStage;
47
+ private stageMetadata;
177
48
  /**
178
49
  * Determine stage success
179
50
  */
@@ -210,6 +81,6 @@ export declare function createFullPipeline(config?: Partial<PipelineConfig>): Pa
210
81
  /**
211
82
  * Create pipeline from configuration
212
83
  */
213
- export declare function createPipelineFromConfig(roles: PipelineConfig['roles'], maxIterations?: number, guards?: Partial<PipelineGuardsConfig>, jobProfiles?: JobProfile[], draftAnalysis?: PipelineConfig['draftAnalysis'], maxReflections?: number): PairPipeline;
84
+ export declare function createPipelineFromConfig(roles: PipelineConfig['roles'], maxIterations?: number, guards?: Partial<PipelineGuardsConfig>, jobProfiles?: JobProfile[], draftAnalysis?: PipelineConfig['draftAnalysis'], maxReflections?: number, runMetadata?: PipelineRunMetadata): PairPipeline;
214
85
  export { formatPipelineResult, formatPipelineResultEmbed } from './pipelineFormat.js';
215
86
  //# sourceMappingURL=pairPipeline.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"pairPipeline.d.ts","sourceRoot":"","sources":["../../src/agents/pairPipeline.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"pairPipeline.d.ts","sourceRoot":"","sources":["../../src/agents/pairPipeline.ts"],"names":[],"mappings":"AAKA,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAC3C,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,oCAAoC,CAAC;AAMnE,OAAO,KAAK,EAAiB,oBAAoB,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAC;AAwBxF,OAAO,KAAK,EACV,cAAc,EAEd,cAAc,EACd,mBAAmB,EAEpB,MAAM,wBAAwB,CAAC;AAUhC,OAAO,EAA2E,sBAAsB,EAAE,MAAM,+BAA+B,CAAC;AAOhJ,OAAO,EAAE,sBAAsB,EAAE,CAAC;AAClC,YAAY,EACV,cAAc,EACd,eAAe,EACf,iBAAiB,EACjB,cAAc,EACd,mBAAmB,EACnB,WAAW,GACZ,MAAM,wBAAwB,CAAC;AAEhC,OAAO,EAAE,eAAe,EAAE,MAAM,yBAAyB,CAAC;AAI1D,qBAAa,YAAa,SAAQ,YAAY;IAC5C,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,aAAa,CAAgB;IACrC,OAAO,CAAC,WAAW,CAAe;IAClC,sFAAsF;IACtF,OAAO,CAAC,WAAW,CAAC,CAAc;IAClC,sGAAsG;IACtG,OAAO,CAAC,iBAAiB,CAAkD;IAE3E,kFAAkF;IAClF,OAAO,CAAC,cAAc;gBAIV,MAAM,EAAE,cAAc;IAiBlC,OAAO,CAAC,cAAc;IAQtB,OAAO,CAAC,iBAAiB;IAKzB,OAAO,CAAC,eAAe;IAMvB,gFAAgF;IAChF,OAAO,CAAC,gBAAgB;IAQxB;;;;;OAKG;IACG,GAAG,CAAC,IAAI,EAAE,QAAQ,EAAE,WAAW,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,WAAW,CAAA;KAAE,GAAG,OAAO,CAAC,cAAc,CAAC;IA8IxG;;;OAGG;YACW,oBAAoB;IAuGlC;;OAEG;IACH,OAAO,CAAC,QAAQ;IAIhB;;OAEG;YACW,QAAQ;IAkVtB,OAAO,CAAC,aAAa;IAarB;;OAEG;IACH,OAAO,CAAC,cAAc;IA4BtB;;;;;;OAMG;IACH,OAAO,CAAC,qBAAqB;IA4B7B;;;;;;OAMG;YACW,oBAAoB;IAwZlC;;OAEG;IACH,OAAO,CAAC,WAAW;CAyDpB;AAID;;GAEG;AACH,wBAAgB,qBAAqB,CAAC,aAAa,SAAI,GAAG,YAAY,CAKrE;AAED;;GAEG;AACH,wBAAgB,kBAAkB,CAChC,MAAM,CAAC,EAAE,OAAO,CAAC,cAAc,CAAC,GAC/B,YAAY,CAQd;AAED;;GAEG;AACH,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,cAAc,CAAC,OAAO,CAAC,EAC9B,aAAa,SAAI,EACjB,MAAM,CAAC,EAAE,OAAO,CAAC,oBAAoB,CAAC,EACtC,WAAW,CAAC,EAAE,UAAU,EAAE,EAC1B,aAAa,CAAC,EAAE,cAAc,CAAC,eAAe,CAAC,EAC/C,cAAc,CAAC,EAAE,MAAM,EACvB,WAAW,CAAC,EAAE,mBAAmB,GAChC,YAAY,CAgCd;AAgHD,OAAO,EAAE,oBAAoB,EAAE,yBAAyB,EAAE,MAAM,qBAAqB,CAAC"}
@@ -8,11 +8,13 @@ import { broadcastEvent } from '../core/eventHub.js';
8
8
  import { CONFIDENCE_THRESHOLDS } from './agentPair.js';
9
9
  import * as agentPair from './agentPair.js';
10
10
  import { runGuards } from './pipelineGuards.js';
11
- import { createReflectionState, recordReflection, shouldStopReflecting, buildReflectionFeedback, DEFAULT_MAX_REFLECTIONS, } from './reflection.js';
11
+ import { createReflectionState, recordReflection, shouldStopReflecting, buildReflectionFeedback, similarReviewFeedback, DEFAULT_MAX_REFLECTIONS, } from './reflection.js';
12
12
  import { hasRepoSnapshot, scanAndCache, analyzeIssue } from '../knowledge/index.js';
13
13
  import { getRegistryStore } from '../registry/sqliteStore.js';
14
14
  import { recallRepoKnowledge } from '../memory/repoKnowledge.js';
15
15
  import * as workerAgent from './worker.js';
16
+ import { buildTaskPrefix } from './pipelineTaskPrefix.js';
17
+ import { emitWorkerFanoutGateDecision, evaluateWorkerFanoutGate, runWorkerWithOptionalFanout } from './workerFanoutGate.js';
16
18
  import * as reviewerAgent from './reviewer.js';
17
19
  import * as testerAgent from './tester.js';
18
20
  import * as documenterAgent from './documenter.js';
@@ -21,41 +23,20 @@ import * as skillDocumenterAgent from './skillDocumenter.js';
21
23
  import { createStuckDetector } from '../support/stuckDetector.js';
22
24
  import { RateLimitError } from '../adapters/rateLimitError.js';
23
25
  import { isInfraError } from '../adapters/errorClassification.js';
24
- /**
25
- * Build a consistent task prefix for logging across all pipeline stages.
26
- * Format: "ProjectName | INT-XXX | worktree/abc123" or "ProjectName | INT-XXX"
27
- */
28
- export function buildTaskPrefix(task, projectPath) {
29
- const parts = [];
30
- const projectName = task.linearProject?.name || projectPath.split('/').pop() || 'unknown';
31
- parts.push(projectName);
32
- if (task.issueIdentifier) {
33
- parts.push(task.issueIdentifier);
34
- }
35
- else if (task.issueId) {
36
- parts.push(task.issueId.slice(0, 8));
37
- }
38
- // Detect worktree path
39
- const worktreeMatch = projectPath.match(/worktree\/([a-f0-9-]+)/);
40
- if (worktreeMatch) {
41
- parts.push(`worktree/${worktreeMatch[1].slice(0, 8)}`);
42
- }
43
- return parts.join(' | ');
44
- }
26
+ import { resolveAdapterDefaultModel } from './stageModelResolver.js';
27
+ import { isClassifiedStageError, rethrowClassified, extractClassifiedStageResult, PipelineCancelledError } from './stageErrorClassification.js';
28
+ import { isTesterCodeFile, missingWorkerValidationIssues, testerWouldRunForWorkerResult, } from './workerValidationEvidence.js';
29
+ export { PipelineCancelledError };
30
+ export { buildTaskPrefix } from './pipelineTaskPrefix.js';
45
31
  // Pair Pipeline
46
- /** Thrown when the pipeline is cancelled mid-run (project disable / manual stop). */
47
- export class PipelineCancelledError extends Error {
48
- constructor() {
49
- super('Pipeline cancelled');
50
- this.name = 'PipelineCancelledError';
51
- }
52
- }
53
32
  export class PairPipeline extends EventEmitter {
54
33
  config;
55
34
  stuckDetector;
56
35
  jobProfiles;
57
36
  /** Set per run() — aborts the pipeline + in-flight adapter call on cancel/disable. */
58
37
  abortSignal;
38
+ /** Cache of adapter default models (heavy: OAuth + live catalog) keyed by adapter name. (INT-2393) */
39
+ defaultModelCache = new Map();
59
40
  /** Throw if this run has been cancelled. Called at iteration/stage boundaries. */
60
41
  throwIfAborted() {
61
42
  if (this.abortSignal?.aborted)
@@ -201,6 +182,9 @@ export class PairPipeline extends EventEmitter {
201
182
  // spawn, timeout) is not a task failure — surface it distinctly so the
202
183
  // runner does a backoff retry instead of counting it toward STUCK. (INT-2010)
203
184
  const infra = !cancelled && !rateLimited && isInfraError(error);
185
+ const classifiedStage = extractClassifiedStageResult(error); // INT-2424
186
+ if (classifiedStage)
187
+ stages.push(classifiedStage);
204
188
  if (cancelled) {
205
189
  console.log(`[${context.taskPrefix}] Pipeline cancelled`);
206
190
  }
@@ -346,11 +330,16 @@ export class PairPipeline extends EventEmitter {
346
330
  */
347
331
  async runStage(stage, context, overrides) {
348
332
  const startTime = Date.now();
349
- const stageModel = overrides?.model ?? this.getModelForRole(stage, context.task);
333
+ // Display model: explicit override → configured (jobProfile/role) → adapter
334
+ // default (so the TUI/dashboard aren't blank when config omits it). (INT-2393)
335
+ const stageModel = overrides?.model
336
+ ?? this.getModelForRole(stage, context.task)
337
+ ?? await resolveAdapterDefaultModel(this.config.roles?.[stage]?.adapter, this.defaultModelCache);
350
338
  const prefix = context.taskPrefix;
339
+ const metadata = this.stageMetadata(context);
351
340
  console.log(`[${prefix}] Stage starting: ${stage}`);
352
341
  this.emit('stage:start', { stage, context, model: stageModel });
353
- broadcastEvent({ type: 'pipeline:stage', data: { taskId: context.task.id, stage, status: 'start', model: stageModel } });
342
+ broadcastEvent({ type: 'pipeline:stage', data: { taskId: context.task.id, stage, status: 'start', model: stageModel, ...metadata } });
354
343
  if (this.config.verbose) {
355
344
  this.emit('log', { line: `[verbose] Stage: ${stage} | model: ${stageModel ?? 'default'} | iteration: ${context.currentIteration}` });
356
345
  }
@@ -389,8 +378,18 @@ export class PairPipeline extends EventEmitter {
389
378
  const reviewPart = includeReview
390
379
  ? reviewerAgent.buildRevisionPrompt(context.reviewResult)
391
380
  : undefined;
392
- const combinedFeedback = [reflectionPart, reviewPart].filter(Boolean).join('\n\n') || undefined;
393
- result = await workerAgent.runWorker({
381
+ // Cross-SESSION feedback: a re-picked task that failed/was rejected
382
+ // before carries the last reviewer feedback (persisted in task state).
383
+ // Without this the new session starts blind and repeats the exact
384
+ // mistake the reviewer already called out (INT-2474). First iteration
385
+ // only — later iterations have fresher in-session feedback above.
386
+ const priorSessionPart = context.currentIteration === 1 && context.task.priorAttemptFeedback
387
+ ? '## Previous attempt failed (feedback from an earlier session)\n'
388
+ + 'A prior run of this task did not pass. Address these points first and do not repeat them:\n'
389
+ + context.task.priorAttemptFeedback
390
+ : undefined;
391
+ const combinedFeedback = [priorSessionPart, reflectionPart, reviewPart].filter(Boolean).join('\n\n') || undefined;
392
+ const workerOptions = {
394
393
  taskTitle: context.task.title,
395
394
  taskDescription: context.task.description || '',
396
395
  projectPath: context.projectPath,
@@ -404,6 +403,7 @@ export class PairPipeline extends EventEmitter {
404
403
  maxTurns: this.config.roles?.worker?.maxTurns,
405
404
  adapterName: this.config.roles?.worker?.adapter,
406
405
  reasoningEffort: this.getEffortForTask(context.task),
406
+ bashTimeoutMs: await workerAgent.resolveWorkerBashTimeout(context.projectPath, this.getEffortForTask(context.task)), // INT-2415
407
407
  // No-edit guard (re-applied from stranded feat/v0.7.0 commit 2eea3bc):
408
408
  // reasoning workers frequently end with analysis only and never call
409
409
  // edit_file. Without this the guard defaults to 0 (disabled) — measured:
@@ -416,6 +416,15 @@ export class PairPipeline extends EventEmitter {
416
416
  processContext: { taskId: context.task.id, stage: 'worker' },
417
417
  workerContext,
418
418
  signal: this.abortSignal,
419
+ };
420
+ result = await runWorkerWithOptionalFanout({
421
+ projectPath: context.projectPath,
422
+ workerOptions,
423
+ fanoutDecision: context.workerFanoutDecision,
424
+ fanoutConfig: this.config.roles?.worker?.fanout,
425
+ guards: this.config.guards,
426
+ onLog,
427
+ runWorker: workerAgent.runWorker,
419
428
  });
420
429
  agentPair.saveWorkerResult(context.session.id, result);
421
430
  context.workerResult = result;
@@ -471,6 +480,11 @@ export class PairPipeline extends EventEmitter {
471
480
  adapterName: this.config.roles?.reviewer?.adapter,
472
481
  reasoningEffort: this.getEffortForTask(context.task),
473
482
  completionCriteria: this.config.draftAnalysis?.completionCriteria,
483
+ // Surface non-blocking guard warnings (dead-module, reformat/scope)
484
+ // so the reviewer verifies them instead of them dying in a log. (INT-2388)
485
+ guardWarnings: context.guardsResult?.results
486
+ .filter(r => !r.passed && !r.blocking)
487
+ .flatMap(r => r.issues),
474
488
  processContext: { taskId: context.task.id, stage: 'reviewer' },
475
489
  signal: this.abortSignal,
476
490
  };
@@ -579,7 +593,8 @@ export class PairPipeline extends EventEmitter {
579
593
  }
580
594
  broadcastEvent({ type: 'pipeline:stage', data: {
581
595
  taskId: context.task.id, stage, status: 'complete',
582
- model: costInfo?.model,
596
+ ...metadata,
597
+ model: costInfo?.model ?? stageModel,
583
598
  inputTokens: costInfo?.inputTokens,
584
599
  outputTokens: costInfo?.outputTokens,
585
600
  costUsd: costInfo?.costUsd,
@@ -605,12 +620,29 @@ export class PairPipeline extends EventEmitter {
605
620
  this.emit('stage:fail', { stage, result: stageResult, context, error });
606
621
  broadcastEvent({ type: 'pipeline:stage', data: {
607
622
  taskId: context.task.id, stage, status: 'fail',
623
+ ...metadata,
624
+ model: stageModel,
608
625
  durationMs: stageResult.duration,
626
+ rateLimitResetsAt: error instanceof RateLimitError && error.resetsAt ? error.resetsAt * 1000 : undefined,
609
627
  error: error instanceof Error ? error.message : String(error),
610
628
  } });
629
+ if (isClassifiedStageError(error))
630
+ rethrowClassified(error, stageResult); // INT-2424
611
631
  return stageResult;
612
632
  }
613
633
  }
634
+ stageMetadata(context) {
635
+ const configured = this.config.runMetadata ?? {};
636
+ const projectPath = configured.projectPath ?? context.projectPath;
637
+ return {
638
+ repository: configured.repository ?? context.task.linearProject?.name ?? repoNameFromPath(projectPath),
639
+ projectPath,
640
+ worktree: configured.worktree ?? worktreeNameFromPath(projectPath),
641
+ branch: configured.branch,
642
+ issueIdentifier: configured.issueIdentifier ?? context.task.issueIdentifier ?? context.task.issueId,
643
+ title: configured.title ?? context.task.title,
644
+ };
645
+ }
614
646
  /**
615
647
  * Determine stage success
616
648
  */
@@ -719,6 +751,21 @@ export class PairPipeline extends EventEmitter {
719
751
  toModel: escalateModel,
720
752
  } });
721
753
  }
754
+ const fanoutDecision = evaluateWorkerFanoutGate({
755
+ task: context.task,
756
+ draftAnalysis: this.config.draftAnalysis,
757
+ iteration: context.currentIteration,
758
+ feedbackSource: context.feedbackSource,
759
+ effort: this.getEffortForTask(context.task),
760
+ config: this.config.roles?.worker?.fanout,
761
+ });
762
+ context.workerFanoutDecision = fanoutDecision;
763
+ emitWorkerFanoutGateDecision({
764
+ context,
765
+ decision: fanoutDecision,
766
+ verbose: this.config.verbose,
767
+ emit: (event, payload) => this.emit(event, payload),
768
+ });
722
769
  agentPair.updateSessionStatus(context.session.id, 'working');
723
770
  const workerResult = await this.runStage('worker', context, workerOverrides);
724
771
  stages.push(workerResult);
@@ -786,6 +833,52 @@ export class PairPipeline extends EventEmitter {
786
833
  });
787
834
  }
788
835
  }
836
+ // A code-changing worker that reports no commands is usually a low-accuracy
837
+ // partial implementation: the reviewer then spends a full pass rediscovering
838
+ // that nothing was built, tested, or smoke-checked. When there is no tester
839
+ // stage to provide objective evidence, bounce it back immediately with a
840
+ // ground-truth validation reflection.
841
+ if (hasReviewer && context.workerResult && !testerWouldRunForWorkerResult(context.workerResult, hasTester, this.config.skipTesterIfNoCodeChange ?? true)) {
842
+ const validationIssues = missingWorkerValidationIssues(context.workerResult);
843
+ if (validationIssues.length > 0) {
844
+ const { progressed } = recordReflection(context.reflection, {
845
+ iteration: context.currentIteration,
846
+ source: 'validation',
847
+ errors: validationIssues,
848
+ });
849
+ // Missing validation evidence is a nudge, not a verdict: the worker may
850
+ // simply be unable to self-report its commands (e.g. git-detected
851
+ // changes with no JSON block — worker.ts promotes those to success with
852
+ // commands=[]). Bounce it back to re-run with validation while that can
853
+ // still make progress; once it stagnates or the reflection budget is
854
+ // spent, DEFER to the reviewer (pre-gate behavior) rather than
855
+ // hard-failing the whole task. This is a pure predicate — do NOT reuse
856
+ // shouldAbortSelfRepair here: it marks the session 'failed' as a side
857
+ // effect (see ~L795), which would sink an otherwise-approvable task.
858
+ const reflectionBudget = this.config.maxReflections ?? DEFAULT_MAX_REFLECTIONS;
859
+ const canRetryForValidation = progressed && !shouldStopReflecting(context.reflection, reflectionBudget);
860
+ if (canRetryForValidation) {
861
+ console.log(`[${context.taskPrefix}] Missing worker validation evidence: ${validationIssues.join('; ')}`);
862
+ context.reviewResult = {
863
+ decision: 'revise',
864
+ feedback: `Worker validation evidence missing: ${validationIssues.join('; ')}`,
865
+ issues: validationIssues,
866
+ suggestions: ['Run a relevant validation command before asking for review'],
867
+ };
868
+ context.feedbackSource = 'objective';
869
+ agentPair.trackFailure(context.session.id);
870
+ this.emit('iteration:fail', {
871
+ iteration: context.currentIteration,
872
+ stage: 'worker',
873
+ context,
874
+ });
875
+ agentPair.updateSessionStatus(context.session.id, 'revising');
876
+ continue;
877
+ }
878
+ console.log(`[${context.taskPrefix}] Validation evidence still missing after retries — deferring to reviewer`);
879
+ this.emit('log', { line: '⚠️ Validation evidence missing; deferring to reviewer' });
880
+ }
881
+ }
789
882
  // ========== HALT CHECK (confidence too low) ==========
790
883
  if (context.workerResult) {
791
884
  const confidence = agentPair.calculateConfidence(context.workerResult);
@@ -826,9 +919,8 @@ export class PairPipeline extends EventEmitter {
826
919
  if (hasTester) {
827
920
  // Skip tester if no code files changed (configurable, default true)
828
921
  const skipIfNoCode = this.config.skipTesterIfNoCodeChange ?? true;
829
- const codeExtensions = /\.(ts|tsx|js|jsx|py|rs|go|java|rb|c|cpp|h|hpp)$/;
830
922
  const changedFiles = context.workerResult?.filesChanged || [];
831
- const hasCodeChange = changedFiles.some(f => codeExtensions.test(f));
923
+ const hasCodeChange = changedFiles.some(isTesterCodeFile);
832
924
  if (skipIfNoCode && !hasCodeChange) {
833
925
  console.log(`[${context.taskPrefix}] Skipping tester: no code files changed (${changedFiles.length} files: ${changedFiles.join(', ') || 'none'})`);
834
926
  }
@@ -906,6 +998,28 @@ export class PairPipeline extends EventEmitter {
906
998
  return { success: false };
907
999
  }
908
1000
  if (decision === 'revise') {
1001
+ const reviseFeedback = reviewerResult.result.feedback ?? '';
1002
+ // The reflection stagnation detector only counts OBJECTIVE sources, so
1003
+ // a reviewer that keeps saying the same thing never trips it — failing
1004
+ // sessions used to burn every remaining iteration on feedback the
1005
+ // worker demonstrably isn't absorbing (measured: 146 max-iteration
1006
+ // exhaustions vs 21 objective aborts). Two consecutive near-identical
1007
+ // revise feedbacks → end the session now; the runner persists this
1008
+ // feedback and the NEXT attempt starts with it injected (INT-2474).
1009
+ if (context.lastReviseFeedback
1010
+ && similarReviewFeedback(context.lastReviseFeedback, reviseFeedback)) {
1011
+ const reason = 'reviewer repeated the same revise feedback — worker is not absorbing it';
1012
+ console.log(`[${context.taskPrefix}] Aborting session early: ${reason}`);
1013
+ this.emit('log', { line: `🛑 ${reason}` });
1014
+ this.emit('iteration:fail', {
1015
+ iteration: context.currentIteration,
1016
+ stage: 'reviewer',
1017
+ context,
1018
+ });
1019
+ agentPair.updateSessionStatus(context.session.id, 'failed');
1020
+ return { success: false };
1021
+ }
1022
+ context.lastReviseFeedback = reviseFeedback;
909
1023
  // revise = next iteration. Reviewer feedback is subjective → it travels
910
1024
  // through the reviewer channel and is dropped on a fresh-context reset.
911
1025
  console.log(`[${context.taskPrefix}] Reviewer requested revision`);
@@ -1022,7 +1136,7 @@ export function createFullPipeline(config) {
1022
1136
  /**
1023
1137
  * Create pipeline from configuration
1024
1138
  */
1025
- export function createPipelineFromConfig(roles, maxIterations = 3, guards, jobProfiles, draftAnalysis, maxReflections) {
1139
+ export function createPipelineFromConfig(roles, maxIterations = 3, guards, jobProfiles, draftAnalysis, maxReflections, runMetadata) {
1026
1140
  const stages = [];
1027
1141
  if (roles?.worker?.enabled !== false) {
1028
1142
  stages.push('worker');
@@ -1050,8 +1164,18 @@ export function createPipelineFromConfig(roles, maxIterations = 3, guards, jobPr
1050
1164
  guards,
1051
1165
  jobProfiles,
1052
1166
  draftAnalysis,
1167
+ runMetadata,
1053
1168
  });
1054
1169
  }
1170
+ function repoNameFromPath(projectPath) {
1171
+ if (!projectPath)
1172
+ return undefined;
1173
+ const normalized = projectPath.replace(/\/+$/, '').replace(/\/worktree\/[^/]+$/, '');
1174
+ return normalized.split('/').pop();
1175
+ }
1176
+ function worktreeNameFromPath(projectPath) {
1177
+ return projectPath?.match(/\/worktree\/([^/]+)\/?$/)?.[1];
1178
+ }
1055
1179
  // Helpers
1056
1180
  /**
1057
1181
  * Extract a worker-readable summary of what the agent did during a stage so