@backburner/cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (202) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +329 -0
  3. package/dist/src/agents/antigravity-launch.js +162 -0
  4. package/dist/src/agents/antigravity.js +251 -0
  5. package/dist/src/agents/claude-launch.js +117 -0
  6. package/dist/src/agents/claude.js +271 -0
  7. package/dist/src/agents/codex-launch.js +82 -0
  8. package/dist/src/agents/codex.js +261 -0
  9. package/dist/src/agents/composite-runner.js +13 -0
  10. package/dist/src/agents/extraction.js +442 -0
  11. package/dist/src/agents/failure-feedback.js +132 -0
  12. package/dist/src/agents/gemini-launch.js +96 -0
  13. package/dist/src/agents/gemini.js +392 -0
  14. package/dist/src/agents/job-agent-assignments.js +180 -0
  15. package/dist/src/agents/lifecycle-feedback.js +147 -0
  16. package/dist/src/agents/limit-detector.js +83 -0
  17. package/dist/src/agents/opencode-launch.js +138 -0
  18. package/dist/src/agents/opencode.js +156 -0
  19. package/dist/src/agents/plan-breakdown-feedback.js +97 -0
  20. package/dist/src/agents/pool.js +168 -0
  21. package/dist/src/agents/prompt.js +462 -0
  22. package/dist/src/agents/provider-sessions.js +105 -0
  23. package/dist/src/agents/review-feedback.js +255 -0
  24. package/dist/src/agents/selection.js +113 -0
  25. package/dist/src/agents/service.js +1087 -0
  26. package/dist/src/agents/types.js +1 -0
  27. package/dist/src/agents/wave-assessment-feedback.js +69 -0
  28. package/dist/src/attention/derive.js +337 -0
  29. package/dist/src/capabilities/index.js +2 -0
  30. package/dist/src/capabilities/projection.js +183 -0
  31. package/dist/src/capabilities/types.js +1 -0
  32. package/dist/src/capabilities/validator.js +87 -0
  33. package/dist/src/cli/commands/broker-smoke.js +96 -0
  34. package/dist/src/cli/commands/broker.js +56 -0
  35. package/dist/src/cli/commands/init.js +4 -0
  36. package/dist/src/cli/commands/journal.js +43 -0
  37. package/dist/src/cli/commands/run-loop.js +56 -0
  38. package/dist/src/cli/commands/run.js +1241 -0
  39. package/dist/src/cli/commands/tui.js +187 -0
  40. package/dist/src/cli/dispatcher.js +51 -0
  41. package/dist/src/cli/errors.js +2 -0
  42. package/dist/src/cli/init.js +92 -0
  43. package/dist/src/cli/options.js +86 -0
  44. package/dist/src/cli/output.js +231 -0
  45. package/dist/src/cli/run-journal.js +342 -0
  46. package/dist/src/cli/run-types.js +1 -0
  47. package/dist/src/cli/run.js +32 -0
  48. package/dist/src/cli/runtime/dispatch-lifecycle.js +772 -0
  49. package/dist/src/cli/runtime/provider-runtime-types.js +1 -0
  50. package/dist/src/cli/runtime/provider-runtime.js +152 -0
  51. package/dist/src/cli/runtime/provider-tools.js +73 -0
  52. package/dist/src/cli/runtime/providers/antigravity.js +26 -0
  53. package/dist/src/cli/runtime/providers/claude.js +20 -0
  54. package/dist/src/cli/runtime/providers/codex.js +20 -0
  55. package/dist/src/cli/runtime/providers/gemini.js +20 -0
  56. package/dist/src/cli/runtime/providers/opencode.js +20 -0
  57. package/dist/src/cli/runtime/run-context.js +131 -0
  58. package/dist/src/cli/tui/index.js +3 -0
  59. package/dist/src/cli/tui/screen.js +388 -0
  60. package/dist/src/cli/tui/tracker.js +558 -0
  61. package/dist/src/cli/tui/types.js +1 -0
  62. package/dist/src/cli/tui/views.js +1006 -0
  63. package/dist/src/config/loader.js +136 -0
  64. package/dist/src/config/schemas.js +403 -0
  65. package/dist/src/config/types.js +1 -0
  66. package/dist/src/context/types.js +331 -0
  67. package/dist/src/domain/entities.js +1 -0
  68. package/dist/src/git/backburner-git-tool-service.js +680 -0
  69. package/dist/src/git/gitops-lifecycle.js +56 -0
  70. package/dist/src/git/merge-prep-workspace.js +357 -0
  71. package/dist/src/git/types.js +484 -0
  72. package/dist/src/github/broker-model-content.js +215 -0
  73. package/dist/src/github/broker-server.js +237 -0
  74. package/dist/src/github/broker.js +638 -0
  75. package/dist/src/github/composed.js +53 -0
  76. package/dist/src/github/gateway.js +478 -0
  77. package/dist/src/github/normalize.js +222 -0
  78. package/dist/src/github/pr-classification.js +73 -0
  79. package/dist/src/github/scoped-broker.js +35 -0
  80. package/dist/src/github/security.js +126 -0
  81. package/dist/src/github/service.js +332 -0
  82. package/dist/src/github/types.js +1 -0
  83. package/dist/src/github/utils.js +16 -0
  84. package/dist/src/journal/index.js +4 -0
  85. package/dist/src/journal/reader.js +62 -0
  86. package/dist/src/journal/renderer.js +50 -0
  87. package/dist/src/journal/service.js +72 -0
  88. package/dist/src/journal/types.js +1 -0
  89. package/dist/src/journal/writer.js +19 -0
  90. package/dist/src/mcps/bridge.js +166 -0
  91. package/dist/src/mcps/index.js +5 -0
  92. package/dist/src/mcps/reconcile.js +113 -0
  93. package/dist/src/mcps/smithery-client.js +186 -0
  94. package/dist/src/mcps/smithery.js +164 -0
  95. package/dist/src/mcps/types.js +1 -0
  96. package/dist/src/memory/json-store.js +71 -0
  97. package/dist/src/memory/prompt.js +16 -0
  98. package/dist/src/memory/scope.js +31 -0
  99. package/dist/src/memory/store.js +1 -0
  100. package/dist/src/memory/tool-service.js +142 -0
  101. package/dist/src/memory/types.js +12 -0
  102. package/dist/src/onboarding/config-writer.js +96 -0
  103. package/dist/src/onboarding/engine.js +86 -0
  104. package/dist/src/onboarding/prompt.js +102 -0
  105. package/dist/src/onboarding/services/provider-discovery.js +58 -0
  106. package/dist/src/onboarding/services/repo-discovery.js +246 -0
  107. package/dist/src/onboarding/steps/check-github-auth.js +32 -0
  108. package/dist/src/onboarding/steps/check-requirements.js +34 -0
  109. package/dist/src/onboarding/steps/configure-models.js +105 -0
  110. package/dist/src/onboarding/steps/configure-paths.js +33 -0
  111. package/dist/src/onboarding/steps/discover-providers.js +38 -0
  112. package/dist/src/onboarding/steps/discover-repos.js +39 -0
  113. package/dist/src/onboarding/steps/generate-config.js +106 -0
  114. package/dist/src/onboarding/steps/readiness-validation.js +158 -0
  115. package/dist/src/onboarding/steps/select-repos.js +76 -0
  116. package/dist/src/onboarding/steps/show-summary.js +97 -0
  117. package/dist/src/onboarding/steps/welcome.js +27 -0
  118. package/dist/src/onboarding/types.js +1 -0
  119. package/dist/src/onboarding/validators/git-access.js +63 -0
  120. package/dist/src/onboarding/validators/github-auth.js +85 -0
  121. package/dist/src/onboarding/validators/tool-checker.js +153 -0
  122. package/dist/src/onboarding/validators/workspace.js +83 -0
  123. package/dist/src/prompts/resolver.js +106 -0
  124. package/dist/src/retrospectives/candidates.js +224 -0
  125. package/dist/src/retrospectives/derive.js +169 -0
  126. package/dist/src/retrospectives/ingest.js +321 -0
  127. package/dist/src/retrospectives/management-prs.js +380 -0
  128. package/dist/src/retrospectives/proposals.js +199 -0
  129. package/dist/src/retrospectives/scopes.js +272 -0
  130. package/dist/src/retrospectives/scoring.js +171 -0
  131. package/dist/src/retrospectives/types.js +1 -0
  132. package/dist/src/state/loader.js +473 -0
  133. package/dist/src/state/types.js +15 -0
  134. package/dist/src/tasks/derivation/builders.js +70 -0
  135. package/dist/src/tasks/derivation/handlers/comment-response.js +169 -0
  136. package/dist/src/tasks/derivation/handlers/implement-plan.js +103 -0
  137. package/dist/src/tasks/derivation/handlers/index.js +54 -0
  138. package/dist/src/tasks/derivation/handlers/packet-pr-control.js +92 -0
  139. package/dist/src/tasks/derivation/handlers/packet-worktree.js +29 -0
  140. package/dist/src/tasks/derivation/handlers/plan-breakdown.js +45 -0
  141. package/dist/src/tasks/derivation/handlers/prepare-for-merge.js +91 -0
  142. package/dist/src/tasks/derivation/handlers/product-discovery.js +36 -0
  143. package/dist/src/tasks/derivation/handlers/retry-failed-task.js +125 -0
  144. package/dist/src/tasks/derivation/handlers/review-pr.js +28 -0
  145. package/dist/src/tasks/derivation/handlers/shared.js +24 -0
  146. package/dist/src/tasks/derivation/handlers/sync-parent-branch.js +100 -0
  147. package/dist/src/tasks/derivation/handlers/wave-assessment.js +223 -0
  148. package/dist/src/tasks/derivation/handlers/write-plan.js +101 -0
  149. package/dist/src/tasks/derivation/handlers/write-product-spec.js +49 -0
  150. package/dist/src/tasks/derivation/runner.js +18 -0
  151. package/dist/src/tasks/derivation/types.js +1 -0
  152. package/dist/src/tasks/derive.js +810 -0
  153. package/dist/src/tasks/mcp-skip.js +10 -0
  154. package/dist/src/tasks/retry.js +10 -0
  155. package/dist/src/tasks/task.js +184 -0
  156. package/dist/src/tasks/types.js +1 -0
  157. package/dist/src/utils/command-runner.js +192 -0
  158. package/dist/src/utils/json.js +38 -0
  159. package/dist/src/utils/logger.js +43 -0
  160. package/dist/src/utils/paths.js +38 -0
  161. package/dist/src/utils/slug.js +10 -0
  162. package/dist/src/workflows/registry.js +174 -0
  163. package/dist/src/workflows/triage.js +90 -0
  164. package/dist/src/workflows/workstream-machine/derive-events.js +121 -0
  165. package/dist/src/workflows/workstream-machine/evaluate.js +24 -0
  166. package/dist/src/workflows/workstream-machine/events.js +1 -0
  167. package/dist/src/workflows/workstream-machine/machine.js +355 -0
  168. package/dist/src/workflows/workstream-machine/selectors.js +19 -0
  169. package/dist/src/workflows/workstream-machine/types.js +1 -0
  170. package/dist/src/workstreams/branch-sync.js +87 -0
  171. package/dist/src/workstreams/derive.js +629 -0
  172. package/dist/src/workstreams/mcp-blockers.js +420 -0
  173. package/dist/src/workstreams/packet-candidates.js +42 -0
  174. package/dist/src/workstreams/packet-lifecycle-feedback.js +60 -0
  175. package/dist/src/workstreams/packet-lifecycle-report.js +199 -0
  176. package/dist/src/workstreams/packet-plan.js +597 -0
  177. package/dist/src/workstreams/packet-projections.js +190 -0
  178. package/dist/src/workstreams/parent-branch-sync-action.js +312 -0
  179. package/dist/src/workstreams/parent-branch-sync.js +148 -0
  180. package/dist/src/workstreams/phases.js +4 -0
  181. package/dist/src/workstreams/plan-breakdown-generator/export.js +19 -0
  182. package/dist/src/workstreams/plan-breakdown-generator/index.js +6 -0
  183. package/dist/src/workstreams/plan-breakdown-generator/inspect.js +50 -0
  184. package/dist/src/workstreams/plan-breakdown-generator/patch.js +139 -0
  185. package/dist/src/workstreams/plan-breakdown-generator/session.js +19 -0
  186. package/dist/src/workstreams/plan-breakdown-generator/store.js +27 -0
  187. package/dist/src/workstreams/plan-breakdown-generator/tools.js +407 -0
  188. package/dist/src/workstreams/plan-breakdown-generator/types.js +6 -0
  189. package/dist/src/workstreams/plan-breakdown-generator/validate.js +212 -0
  190. package/dist/src/workstreams/plan-breakdown-schema.js +175 -0
  191. package/dist/src/workstreams/utils.js +15 -0
  192. package/dist/src/workstreams/wave-assessment/checkpoint.js +172 -0
  193. package/dist/src/workstreams/wave-assessment/index.js +3 -0
  194. package/dist/src/workstreams/wave-assessment/session.js +84 -0
  195. package/dist/src/workstreams/wave-assessment/store.js +51 -0
  196. package/dist/src/workstreams/wave-assessment/tools.js +419 -0
  197. package/dist/src/workstreams/wave-assessment/types.js +1 -0
  198. package/dist/src/workstreams/wave-assessment/validate.js +78 -0
  199. package/dist/src/worktrees/service.js +839 -0
  200. package/dist/src/worktrees/workspace-ownership.js +34 -0
  201. package/dist/src/worktrees/workspace-recovery.js +177 -0
  202. package/package.json +61 -0
@@ -0,0 +1,342 @@
1
+ /**
2
+ * Journal helper functions for run.ts.
3
+ *
4
+ * Extracted here to keep run.ts clean. Handles:
5
+ * - buildEntityMaps: builds lookup maps from scan data
6
+ * - resolveTaskJournalIds: resolves issueNumber/prNumber for a task
7
+ * - resolveRepoActionState: comprehensive no-action logic per repo
8
+ * - journalWorkstreamTransitions: journals workstream phase/attention/status changes
9
+ * - journalTaskTransitions: journals task status changes after dispatch
10
+ * - journalWorktreeTransitions: journals worktree status changes
11
+ * - journalNewExecutions: journals only newly-created executions
12
+ * - journalPacketWaveEvents: journals packet wave advancements and blocks
13
+ */
14
+ export function buildEntityMaps(issues, prs, enabledRepos) {
15
+ const issueIdToNumber = new Map();
16
+ for (const issue of issues) {
17
+ issueIdToNumber.set(issue.id, issue.number);
18
+ }
19
+ const prIdToNumber = new Map();
20
+ for (const pr of prs) {
21
+ prIdToNumber.set(pr.id, pr.number);
22
+ }
23
+ const repoSlugToId = new Map();
24
+ for (const repo of enabledRepos) {
25
+ repoSlugToId.set(`${repo.owner}/${repo.name}`, repo.id);
26
+ repoSlugToId.set(repo.id, repo.id); // fallback: repoKey stored as id resolves to itself
27
+ }
28
+ return { issueIdToNumber, prIdToNumber, repoSlugToId };
29
+ }
30
+ export function resolveTaskJournalIds(task, maps, workstreams) {
31
+ let issueNumber;
32
+ let prNumber;
33
+ if (task.sourceKind === "issue") {
34
+ issueNumber = maps.issueIdToNumber.get(task.sourceId);
35
+ }
36
+ else if (task.sourceKind === "pull_request") {
37
+ prNumber = maps.prIdToNumber.get(task.sourceId);
38
+ }
39
+ else if (task.sourceKind === "comment") {
40
+ if (task.parentSourceKind === "issue" && task.parentSourceId !== undefined) {
41
+ issueNumber = maps.issueIdToNumber.get(task.parentSourceId);
42
+ }
43
+ else if (task.parentSourceKind === "pull_request" && task.parentSourceId !== undefined) {
44
+ prNumber = maps.prIdToNumber.get(task.parentSourceId);
45
+ }
46
+ }
47
+ // Also check workstream's activePrNumber if task belongs to one
48
+ if (task.workstreamId && workstreams) {
49
+ const ws = workstreams.find((w) => w.id === task.workstreamId);
50
+ if (ws?.activePrNumber !== undefined && prNumber === undefined) {
51
+ prNumber = ws.activePrNumber;
52
+ }
53
+ }
54
+ return {
55
+ ...(issueNumber !== undefined ? { issueNumber } : {}),
56
+ ...(prNumber !== undefined ? { prNumber } : {})
57
+ };
58
+ }
59
+ export function resolveRepoActionState(input) {
60
+ const { repoId, repoSlug, syncRecord, tasks, workstreams, issues, prs } = input;
61
+ // 1. Sync failed
62
+ if (syncRecord?.status === "failed") {
63
+ const reason = syncRecord.error?.message ?? syncRecord.message ?? "Unknown sync error";
64
+ return { hasAction: false, noActionReason: `Repository failed to sync: ${reason}` };
65
+ }
66
+ // 2. Scan failed
67
+ const scan = syncRecord?.githubScan;
68
+ if (scan?.status === "failed") {
69
+ return { hasAction: false, noActionReason: "GitHub scan failed — issue and PR data unavailable" };
70
+ }
71
+ // 3. Pending relevant tasks → has action
72
+ const pendingRelevant = tasks.filter((t) => t.repoId === repoId && t.status === "pending" && t.relevant);
73
+ if (pendingRelevant.length > 0) {
74
+ return { hasAction: true };
75
+ }
76
+ // 4. Dispatched tasks → has action
77
+ const dispatched = tasks.filter((t) => t.repoId === repoId && t.status === "dispatched");
78
+ if (dispatched.length > 0) {
79
+ return { hasAction: true };
80
+ }
81
+ // Check workstreams for this repo
82
+ const repoWorkstreams = workstreams.filter((ws) => {
83
+ return ws.repoKey === repoSlug || ws.repoKey === repoId;
84
+ });
85
+ for (const ws of repoWorkstreams) {
86
+ const wsTasks = tasks.filter((t) => t.workstreamId === ws.id);
87
+ const hasFailedTasks = wsTasks.some((t) => t.status === "failed");
88
+ const hasPendingOrDispatched = wsTasks.some((t) => t.status === "pending" || t.status === "dispatched");
89
+ // 5. Workstream blocked by failed tasks
90
+ if (hasFailedTasks && !hasPendingOrDispatched) {
91
+ return { hasAction: false, noActionReason: "Workstream blocked by failed prior execution" };
92
+ }
93
+ // 6. Waiting for Product approval
94
+ if (ws.phase === "product_discovery") {
95
+ const approvalLabel = ws.product?.approvalLabel ?? "agent-product-approved";
96
+ const num = ws.origin.number;
97
+ return {
98
+ hasAction: false,
99
+ noActionReason: `Waiting for ${approvalLabel} label on issue #${num} to proceed`
100
+ };
101
+ }
102
+ // 7. Waiting for plan approval
103
+ if (ws.phase === "plan_feedback") {
104
+ const num = ws.origin.number;
105
+ const kind = ws.origin.type === "issue" ? "issue" : "PR";
106
+ return {
107
+ hasAction: false,
108
+ noActionReason: `Waiting for plan approval (${kind} #${num})`
109
+ };
110
+ }
111
+ // 8. Waiting for implementation feedback
112
+ if (ws.phase === "implementation_feedback") {
113
+ return { hasAction: false, noActionReason: "Waiting for implementation feedback" };
114
+ }
115
+ // 9. Waiting for PR review
116
+ if (ws.phase === "pr_review") {
117
+ return { hasAction: false, noActionReason: "Waiting for PR review" };
118
+ }
119
+ }
120
+ // 10. No issues or PRs at all
121
+ const repoIssues = issues.filter((i) => i.repoId === repoId);
122
+ const repoPrs = prs.filter((p) => p.repoId === repoId);
123
+ if (repoIssues.length === 0 && repoPrs.length === 0) {
124
+ return { hasAction: false, noActionReason: "No open issues or PRs found for this repository" };
125
+ }
126
+ // 11. Default
127
+ return { hasAction: false, noActionReason: "No open issues or PRs requiring attention this cycle" };
128
+ }
129
+ // ── Workstream Transitions ────────────────────────────────────────────────────
130
+ export async function journalWorkstreamTransitions(opts) {
131
+ const { cycleId, previousWorkstreams, currentWorkstreams, journal, entityMaps } = opts;
132
+ const prevById = new Map(previousWorkstreams.map((ws) => [ws.id, ws]));
133
+ for (const ws of currentWorkstreams) {
134
+ const prev = prevById.get(ws.id);
135
+ if (!prev)
136
+ continue; // new workstream, not a transition
137
+ // Resolve repoId from repoKey (slug format "owner/name")
138
+ const repoId = entityMaps.repoSlugToId.get(ws.repoKey);
139
+ // Resolve issueNumber/prNumber from workstream origin
140
+ let issueNumber;
141
+ let prNumber;
142
+ if (ws.origin.type === "issue") {
143
+ issueNumber = ws.origin.number;
144
+ }
145
+ else {
146
+ prNumber = ws.origin.number;
147
+ }
148
+ if (ws.activePrNumber !== undefined) {
149
+ prNumber = ws.activePrNumber;
150
+ }
151
+ const commonOpts = {
152
+ cycleId,
153
+ scope: "workstream",
154
+ scopeId: ws.id,
155
+ workstreamId: ws.id,
156
+ ...(repoId !== undefined ? { repoId } : {}),
157
+ ...(issueNumber !== undefined ? { issueNumber } : {}),
158
+ ...(prNumber !== undefined ? { prNumber } : {})
159
+ };
160
+ // Phase change
161
+ if (prev.phase !== ws.phase) {
162
+ await journal.recordStateTransition({
163
+ ...commonOpts,
164
+ from: prev.phase,
165
+ to: ws.phase,
166
+ trigger: "cycle",
167
+ summary: `Workstream ${ws.id} phase: ${prev.phase} → ${ws.phase}`
168
+ });
169
+ }
170
+ // Attention change
171
+ if (prev.attention !== ws.attention) {
172
+ await journal.recordStateTransition({
173
+ ...commonOpts,
174
+ from: prev.attention,
175
+ to: ws.attention,
176
+ trigger: "cycle",
177
+ summary: `Workstream ${ws.id} attention: ${prev.attention} → ${ws.attention}`
178
+ });
179
+ }
180
+ // Status change
181
+ if (prev.status !== ws.status) {
182
+ await journal.recordStateTransition({
183
+ ...commonOpts,
184
+ from: prev.status,
185
+ to: ws.status,
186
+ trigger: "cycle",
187
+ summary: `Workstream ${ws.id} status: ${prev.status} → ${ws.status}`
188
+ });
189
+ }
190
+ }
191
+ }
192
+ // ── Task Transitions ──────────────────────────────────────────────────────────
193
+ const MEANINGFUL_TRANSITIONS = new Set([
194
+ "pending→dispatched",
195
+ "pending→completed",
196
+ "dispatched→completed",
197
+ "dispatched→failed",
198
+ "pending→failed",
199
+ "pending→queued",
200
+ "queued→dispatched",
201
+ "queued→failed",
202
+ "dispatched→queued",
203
+ "queued→pending"
204
+ ]);
205
+ export async function journalTaskTransitions(opts) {
206
+ const { cycleId, tasksBefore, tasksAfter, journal, entityMaps, workstreams } = opts;
207
+ const prevById = new Map(tasksBefore.map((t) => [t.id, t]));
208
+ for (const task of tasksAfter) {
209
+ const prev = prevById.get(task.id);
210
+ if (!prev)
211
+ continue;
212
+ if (prev.status === task.status)
213
+ continue;
214
+ const transitionKey = `${prev.status}→${task.status}`;
215
+ if (!MEANINGFUL_TRANSITIONS.has(transitionKey))
216
+ continue;
217
+ const ids = resolveTaskJournalIds(task, entityMaps, workstreams);
218
+ await journal.recordStateTransition({
219
+ cycleId,
220
+ scope: task.workstreamId ? "workstream" : "repo",
221
+ scopeId: task.workstreamId ?? task.repoId,
222
+ repoId: task.repoId,
223
+ ...(task.workstreamId !== undefined ? { workstreamId: task.workstreamId } : {}),
224
+ ...(ids.issueNumber !== undefined ? { issueNumber: ids.issueNumber } : {}),
225
+ ...(ids.prNumber !== undefined ? { prNumber: ids.prNumber } : {}),
226
+ from: prev.status,
227
+ to: task.status,
228
+ trigger: "dispatch",
229
+ summary: `Task ${task.id} status: ${prev.status} → ${task.status}`,
230
+ derivedState: { taskId: task.id, kind: task.kind, taskStatus: task.status }
231
+ });
232
+ }
233
+ }
234
+ // ── Worktree Transitions ──────────────────────────────────────────────────────
235
+ export async function journalWorktreeTransitions(opts) {
236
+ const { cycleId, previousWorktrees, currentWorktrees, journal } = opts;
237
+ const prevById = new Map(previousWorktrees.map((wt) => [wt.id, wt]));
238
+ for (const wt of currentWorktrees) {
239
+ const prev = prevById.get(wt.id);
240
+ if (!prev)
241
+ continue;
242
+ if (prev.status === wt.status)
243
+ continue;
244
+ const workstreamId = wt.packet?.parentWorkstreamId;
245
+ await journal.recordStateTransition({
246
+ cycleId,
247
+ scope: "worktree",
248
+ scopeId: wt.id,
249
+ repoId: wt.repoId,
250
+ ...(workstreamId !== undefined ? { workstreamId } : {}),
251
+ ...(wt.issueNumber !== undefined ? { issueNumber: wt.issueNumber } : {}),
252
+ ...(wt.prNumber !== undefined ? { prNumber: wt.prNumber } : {}),
253
+ from: prev.status,
254
+ to: wt.status,
255
+ trigger: "cycle",
256
+ summary: `Worktree ${wt.id} status: ${prev.status} → ${wt.status}`,
257
+ derivedState: { worktreeId: wt.id, branchName: wt.branchName }
258
+ });
259
+ }
260
+ }
261
+ // ── Execution Journaling ──────────────────────────────────────────────────────
262
+ export async function journalNewExecutions(opts) {
263
+ const { cycleId, executionIdsBeforeCycle, dispatchResult, journal, entityMaps, workstreams } = opts;
264
+ const allNewExecutions = dispatchResult.executions.filter((e) => !executionIdsBeforeCycle.has(e.id));
265
+ for (const exec of allNewExecutions) {
266
+ const task = dispatchResult.tasks.find((t) => t.id === exec.taskId);
267
+ if (!task)
268
+ continue;
269
+ if (task.status !== "completed" && task.status !== "failed")
270
+ continue;
271
+ if (task.lastExecutionId !== exec.id)
272
+ continue;
273
+ const ids = resolveTaskJournalIds(task, entityMaps, workstreams);
274
+ await journal.write({
275
+ cycleId,
276
+ scope: "execution",
277
+ scopeId: exec.id,
278
+ repoId: task.repoId,
279
+ ...(task.workstreamId !== undefined ? { workstreamId: task.workstreamId } : {}),
280
+ executionId: exec.id,
281
+ ...(ids.issueNumber !== undefined ? { issueNumber: ids.issueNumber } : {}),
282
+ ...(ids.prNumber !== undefined ? { prNumber: ids.prNumber } : {}),
283
+ category: task.status === "completed" ? "execution_completed" : "execution_failed",
284
+ severity: task.status === "completed" ? "info" : "error",
285
+ summary: task.status === "completed"
286
+ ? `Completed ${task.kind} for ${task.repoSlug}`
287
+ : `Failed ${task.kind} for ${task.repoSlug}`,
288
+ observedState: {
289
+ exitCode: exec.exitCode,
290
+ startedAt: exec.startedAt,
291
+ endedAt: exec.endedAt,
292
+ agentProvider: exec.agentProvider,
293
+ promptArtifactPath: exec.promptArtifactPath,
294
+ stdoutArtifactPath: exec.stdoutArtifactPath,
295
+ stderrArtifactPath: exec.stderrArtifactPath
296
+ },
297
+ derivedState: {
298
+ taskId: task.id,
299
+ taskKind: task.kind,
300
+ taskStatus: task.status
301
+ },
302
+ ...(task.status === "failed"
303
+ ? { noActionReason: exec.errorMessage ?? "Agent execution failed" }
304
+ : {})
305
+ });
306
+ }
307
+ }
308
+ // ── Packet Wave Events ────────────────────────────────────────────────────────
309
+ export async function journalPacketWaveEvents(opts) {
310
+ const { cycleId, packetWaveAdvancementsThisRun, packetWaveBlockedThisRun, journal } = opts;
311
+ for (const adv of packetWaveAdvancementsThisRun) {
312
+ await journal.recordStateTransition({
313
+ cycleId,
314
+ scope: "workstream",
315
+ scopeId: adv.workstreamId,
316
+ workstreamId: adv.workstreamId,
317
+ ...(adv.parentPrNumber !== undefined ? { prNumber: adv.parentPrNumber } : {}),
318
+ from: `wave:${adv.fromWaveIndex}`,
319
+ to: `wave:${adv.toWaveIndex}`,
320
+ trigger: "packet_wave_advancement",
321
+ summary: `Packet wave advanced: wave ${adv.fromWaveIndex} → wave ${adv.toWaveIndex} for workstream ${adv.workstreamId}`,
322
+ derivedState: {
323
+ completedPacketIds: adv.completedPacketIds,
324
+ newlyCurrentPacketIds: adv.newlyCurrentPacketIds
325
+ }
326
+ });
327
+ }
328
+ for (const blocked of packetWaveBlockedThisRun) {
329
+ await journal.recordBlocked({
330
+ cycleId,
331
+ scope: "workstream",
332
+ scopeId: blocked.workstreamId,
333
+ workstreamId: blocked.workstreamId,
334
+ ...(blocked.parentPrNumber !== undefined ? { prNumber: blocked.parentPrNumber } : {}),
335
+ reason: `Packet wave blocked: ${blocked.reason}`,
336
+ observedState: {
337
+ currentWaveIndex: blocked.currentWaveIndex,
338
+ incompletePacketIds: blocked.incompletePacketIds
339
+ }
340
+ });
341
+ }
342
+ }
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,32 @@
1
+ #!/usr/bin/env node
2
+ import { realpathSync } from "node:fs";
3
+ import { fileURLToPath } from "node:url";
4
+ export { runCli, buildPacketWaveAdvancementEvaluationForRun } from "./commands/run.js";
5
+ export { buildEffectiveProviderBrokerToolAllowLists } from "./runtime/provider-tools.js";
6
+ export { runDispatchWithMergePrepLifecycle } from "./runtime/dispatch-lifecycle.js";
7
+ export { runLoopCli, SerializedCycleRunner } from "./commands/run-loop.js";
8
+ export { runJournalCli } from "./commands/journal.js";
9
+ export { shouldUseRuntimeStatusScreen } from "./commands/tui.js";
10
+ export { main } from "./dispatcher.js";
11
+ import { main } from "./dispatcher.js";
12
+ import { CliUsageError } from "./errors.js";
13
+ const entrypointPath = process.argv[1];
14
+ if (entrypointPath) {
15
+ const executedAsScript = resolveEntrypointPath(entrypointPath) === resolveEntrypointPath(fileURLToPath(import.meta.url));
16
+ if (executedAsScript) {
17
+ main(process.argv.slice(2)).catch((error) => {
18
+ const message = error instanceof Error ? error.message : String(error);
19
+ const prefix = error instanceof CliUsageError ? "Usage error" : "Run failed";
20
+ process.stderr.write(`${prefix}: ${message}\n`);
21
+ process.exitCode = 1;
22
+ });
23
+ }
24
+ }
25
+ function resolveEntrypointPath(entrypointPathValue) {
26
+ try {
27
+ return realpathSync(entrypointPathValue);
28
+ }
29
+ catch {
30
+ return entrypointPathValue;
31
+ }
32
+ }