@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,87 @@
1
+ /**
2
+ * Validates requested capabilities against declared MCP dependencies and their current status.
3
+ *
4
+ * This implementation takes a normalized capabilities object as returned
5
+ * by loadCapabilitiesConfig() or loadConfig().
6
+ */
7
+ export function validateCapabilities(capabilities, declaredMcps, mcpStatuses) {
8
+ const { sensors, controllers } = capabilities;
9
+ const declaredHandles = new Set(declaredMcps.map((d) => d.handle));
10
+ const statusByHandle = new Map(mcpStatuses.map((s) => [s.handle, s]));
11
+ const valid = [];
12
+ const blocked = [];
13
+ const processCapability = (name, uses, kind) => {
14
+ if (!declaredHandles.has(uses)) {
15
+ blocked.push({ name, kind, uses, reason: "missing_mcp_handle" });
16
+ return;
17
+ }
18
+ const statusRecord = statusByHandle.get(uses);
19
+ if (!statusRecord) {
20
+ blocked.push({
21
+ name,
22
+ kind,
23
+ uses,
24
+ reason: "mcp_not_connection_ready",
25
+ message: "MCP has not been checked yet — no status record available.",
26
+ });
27
+ return;
28
+ }
29
+ const message = statusRecord.actionRequired?.message ?? statusRecord.message;
30
+ switch (statusRecord.status) {
31
+ case "ready":
32
+ valid.push({ name, kind, uses, mcpStatus: "ready" });
33
+ break;
34
+ case "action_required":
35
+ blocked.push({
36
+ name,
37
+ kind,
38
+ uses,
39
+ reason: "mcp_action_required",
40
+ mcpStatus: "action_required",
41
+ ...(message ? { message } : {}),
42
+ });
43
+ break;
44
+ case "resolved":
45
+ blocked.push({
46
+ name,
47
+ kind,
48
+ uses,
49
+ reason: "mcp_not_connection_ready",
50
+ mcpStatus: "resolved",
51
+ ...(message ? { message } : {}),
52
+ });
53
+ break;
54
+ case "resolution_failed":
55
+ blocked.push({
56
+ name,
57
+ kind,
58
+ uses,
59
+ reason: "mcp_resolution_failed",
60
+ mcpStatus: "resolution_failed",
61
+ ...(message ? { message } : {}),
62
+ });
63
+ break;
64
+ case "error":
65
+ blocked.push({
66
+ name,
67
+ kind,
68
+ uses,
69
+ reason: "mcp_error",
70
+ mcpStatus: "error",
71
+ ...(message ? { message } : {}),
72
+ });
73
+ break;
74
+ default: {
75
+ const _exhaustive = statusRecord.status;
76
+ throw new Error(`Unexpected MCP status: ${_exhaustive}`);
77
+ }
78
+ }
79
+ };
80
+ for (const sensor of sensors) {
81
+ processCapability(sensor.name, sensor.uses, "sensor");
82
+ }
83
+ for (const controller of controllers) {
84
+ processCapability(controller.name, controller.uses, "controller");
85
+ }
86
+ return { valid, blocked };
87
+ }
@@ -0,0 +1,96 @@
1
+ import * as path from "node:path";
2
+ import { ExecFileCommandRunner } from "../../utils/command-runner.js";
3
+ import { loadConfig } from "../../config/loader.js";
4
+ import { GhCliGitHubGateway } from "../../github/gateway.js";
5
+ import { GitHubBrokerService } from "../../github/broker.js";
6
+ import { startGitHubBrokerServer } from "../../github/broker-server.js";
7
+ import { ComposedBrokerService } from "../../github/composed.js";
8
+ import { PlanBreakdownSessionStore } from "../../workstreams/plan-breakdown-generator/store.js";
9
+ import { PlanBreakdownToolService } from "../../workstreams/plan-breakdown-generator/tools.js";
10
+ import { WaveAssessmentSessionStore } from "../../workstreams/wave-assessment/store.js";
11
+ import { WaveAssessmentToolService } from "../../workstreams/wave-assessment/tools.js";
12
+ import { defaultBackburnerManagementRoot } from "../../utils/paths.js";
13
+ import { defaultStderrLogger } from "../../utils/logger.js";
14
+ import { DEFAULT_GITHUB_BROKER_PORT, readOptionalNumberFlag, readOptionalStringFlag, readStringFlag } from "../options.js";
15
+ export async function runBrokerSmokeCli(argv, logger = defaultStderrLogger) {
16
+ const managementDir = path.resolve(readStringFlag(argv, "--management-dir", defaultBackburnerManagementRoot()));
17
+ const host = "127.0.0.1";
18
+ const config = await loadConfig(managementDir);
19
+ const commandRunner = new ExecFileCommandRunner();
20
+ const gitHubGateway = new GhCliGitHubGateway(commandRunner, config.allowedUsers);
21
+ const githubBrokerService = new GitHubBrokerService(gitHubGateway, config.repos, logger);
22
+ const planBreakdownSessionStore = new PlanBreakdownSessionStore();
23
+ const planBreakdownToolService = new PlanBreakdownToolService(planBreakdownSessionStore, logger);
24
+ const waveAssessmentSessionStore = new WaveAssessmentSessionStore();
25
+ const waveAssessmentToolService = new WaveAssessmentToolService(waveAssessmentSessionStore, logger);
26
+ const brokerService = new ComposedBrokerService([
27
+ githubBrokerService,
28
+ planBreakdownToolService,
29
+ waveAssessmentToolService
30
+ ]);
31
+ const server = await startGitHubBrokerServer({
32
+ brokerService,
33
+ host,
34
+ port: DEFAULT_GITHUB_BROKER_PORT,
35
+ logger
36
+ });
37
+ try {
38
+ const initializeResponse = await postJson(server.url, {
39
+ jsonrpc: "2.0",
40
+ id: 1,
41
+ method: "initialize",
42
+ params: {
43
+ protocolVersion: "2024-11-05",
44
+ capabilities: {},
45
+ clientInfo: {
46
+ name: "backburner-smoke",
47
+ version: "0.1.0"
48
+ }
49
+ }
50
+ });
51
+ const toolsResponse = await postJson(server.url, {
52
+ jsonrpc: "2.0",
53
+ id: 2,
54
+ method: "tools/list",
55
+ params: {}
56
+ });
57
+ process.stdout.write(JSON.stringify({
58
+ serverUrl: server.url,
59
+ initialize: initializeResponse.result,
60
+ tools: toolsResponse.result?.tools ?? []
61
+ }, null, 2) + "\n");
62
+ const repo = readOptionalStringFlag(argv, "--repo");
63
+ const issueNumber = readOptionalNumberFlag(argv, "--issue-number");
64
+ if (repo && issueNumber) {
65
+ const issueResponse = await postJson(server.url, {
66
+ jsonrpc: "2.0",
67
+ id: 3,
68
+ method: "tools/call",
69
+ params: {
70
+ name: "get_issue",
71
+ arguments: {
72
+ repo,
73
+ issueNumber
74
+ }
75
+ }
76
+ });
77
+ process.stdout.write(`${JSON.stringify(issueResponse.result, null, 2)}\n`);
78
+ }
79
+ }
80
+ finally {
81
+ await server.close();
82
+ }
83
+ }
84
+ async function postJson(url, payload) {
85
+ const response = await fetch(url, {
86
+ method: "POST",
87
+ headers: {
88
+ "content-type": "application/json"
89
+ },
90
+ body: JSON.stringify(payload)
91
+ });
92
+ if (!response.ok) {
93
+ throw new Error(`Broker smoke request failed with HTTP ${response.status}`);
94
+ }
95
+ return (await response.json());
96
+ }
@@ -0,0 +1,56 @@
1
+ import * as path from "node:path";
2
+ import { ExecFileCommandRunner } from "../../utils/command-runner.js";
3
+ import { loadConfig } from "../../config/loader.js";
4
+ import { GhCliGitHubGateway } from "../../github/gateway.js";
5
+ import { GitHubBrokerService } from "../../github/broker.js";
6
+ import { startGitHubBrokerServer } from "../../github/broker-server.js";
7
+ import { ComposedBrokerService } from "../../github/composed.js";
8
+ import { PlanBreakdownSessionStore } from "../../workstreams/plan-breakdown-generator/store.js";
9
+ import { PlanBreakdownToolService } from "../../workstreams/plan-breakdown-generator/tools.js";
10
+ import { WaveAssessmentSessionStore } from "../../workstreams/wave-assessment/store.js";
11
+ import { WaveAssessmentToolService } from "../../workstreams/wave-assessment/tools.js";
12
+ import { defaultBackburnerManagementRoot } from "../../utils/paths.js";
13
+ import { defaultStderrLogger } from "../../utils/logger.js";
14
+ import { DEFAULT_GITHUB_BROKER_PORT, readNumberFlag, readStringFlag } from "../options.js";
15
+ export async function runBrokerCli(argv, logger = defaultStderrLogger) {
16
+ const managementDir = path.resolve(readStringFlag(argv, "--management-dir", defaultBackburnerManagementRoot()));
17
+ const port = readNumberFlag(argv, "--port", DEFAULT_GITHUB_BROKER_PORT);
18
+ const host = readStringFlag(argv, "--host", "127.0.0.1");
19
+ const config = await loadConfig(managementDir);
20
+ const commandRunner = new ExecFileCommandRunner();
21
+ const gitHubGateway = new GhCliGitHubGateway(commandRunner, config.allowedUsers);
22
+ const githubBrokerService = new GitHubBrokerService(gitHubGateway, config.repos, logger);
23
+ const planBreakdownSessionStore = new PlanBreakdownSessionStore();
24
+ const planBreakdownToolService = new PlanBreakdownToolService(planBreakdownSessionStore, logger);
25
+ const waveAssessmentSessionStore = new WaveAssessmentSessionStore();
26
+ const waveAssessmentToolService = new WaveAssessmentToolService(waveAssessmentSessionStore, logger);
27
+ const brokerService = new ComposedBrokerService([
28
+ githubBrokerService,
29
+ planBreakdownToolService,
30
+ waveAssessmentToolService
31
+ ]);
32
+ const server = await startGitHubBrokerServer({
33
+ brokerService,
34
+ host,
35
+ port,
36
+ logger
37
+ });
38
+ process.stdout.write(`${server.url}\n`);
39
+ await new Promise((resolve, reject) => {
40
+ const shutdown = async () => {
41
+ process.off("SIGINT", onSigint);
42
+ process.off("SIGTERM", onSigterm);
43
+ try {
44
+ await server.close();
45
+ resolve();
46
+ }
47
+ catch (error) {
48
+ reject(error);
49
+ }
50
+ };
51
+ const onSigint = () => void shutdown();
52
+ const onSigterm = () => void shutdown();
53
+ process.on("SIGINT", onSigint);
54
+ process.on("SIGTERM", onSigterm);
55
+ });
56
+ }
@@ -0,0 +1,4 @@
1
+ import { runInitCli } from "../init.js";
2
+ export async function runInitCommand(argv) {
3
+ await runInitCli(argv);
4
+ }
@@ -0,0 +1,43 @@
1
+ import * as path from "node:path";
2
+ import { JournalReader } from "../../journal/index.js";
3
+ import { renderJournalEntries } from "../../journal/renderer.js";
4
+ import { defaultBackburnerOutputsRoot, resolveOutputsJournalRoot } from "../../utils/paths.js";
5
+ import { CliUsageError } from "../errors.js";
6
+ import { readOptionalStringFlag, readStringFlag } from "../options.js";
7
+ export async function runJournalCli(argv, injectedJournal) {
8
+ const outputsDir = path.resolve(readStringFlag(argv, "--outputs-dir", defaultBackburnerOutputsRoot()));
9
+ const journalDir = resolveOutputsJournalRoot(outputsDir);
10
+ const reader = injectedJournal ? injectedJournal.reader : new JournalReader(journalDir);
11
+ const repoId = readOptionalStringFlag(argv, "--repo");
12
+ const workstreamId = readOptionalStringFlag(argv, "--workstream");
13
+ const issueRaw = readOptionalStringFlag(argv, "--issue");
14
+ const prRaw = readOptionalStringFlag(argv, "--pr");
15
+ const since = readOptionalStringFlag(argv, "--since");
16
+ const lastRaw = readOptionalStringFlag(argv, "--last");
17
+ const isJson = argv.includes("--json");
18
+ const isVerbose = argv.includes("--verbose");
19
+ const issueNumber = issueRaw !== undefined ? Number(issueRaw) : undefined;
20
+ const prNumber = prRaw !== undefined ? Number(prRaw) : undefined;
21
+ const limit = lastRaw !== undefined ? Number(lastRaw) : 50;
22
+ if (issueRaw !== undefined && (!Number.isInteger(issueNumber) || issueNumber <= 0)) {
23
+ throw new CliUsageError(`--issue must be a positive integer, got: ${issueRaw}`);
24
+ }
25
+ if (prRaw !== undefined && (!Number.isInteger(prNumber) || prNumber <= 0)) {
26
+ throw new CliUsageError(`--pr must be a positive integer, got: ${prRaw}`);
27
+ }
28
+ if (lastRaw !== undefined && (!Number.isInteger(limit) || limit <= 0)) {
29
+ throw new CliUsageError(`--last must be a positive integer, got: ${lastRaw}`);
30
+ }
31
+ if (since !== undefined && isNaN(new Date(since).getTime())) {
32
+ throw new CliUsageError(`--since must be a valid ISO date, got: ${since}`);
33
+ }
34
+ const entries = await reader.query({
35
+ ...(repoId !== undefined ? { repoId } : {}),
36
+ ...(workstreamId !== undefined ? { workstreamId } : {}),
37
+ ...(issueNumber !== undefined ? { issueNumber } : {}),
38
+ ...(prNumber !== undefined ? { prNumber } : {}),
39
+ ...(since !== undefined ? { since } : {}),
40
+ limit
41
+ });
42
+ process.stdout.write(renderJournalEntries(entries, { json: isJson, verbose: isVerbose }));
43
+ }
@@ -0,0 +1,56 @@
1
+ import { formatRunSummary } from "../output.js";
2
+ import { defaultStderrLogger } from "../../utils/logger.js";
3
+ import { CliUsageError } from "../errors.js";
4
+ import { delayWithAbort, isAbortError, readIntervalMs } from "../options.js";
5
+ import { runCli } from "./run.js";
6
+ import { runInteractiveTui, shouldUseRuntimeStatusScreen, SerializedCycleRunner } from "./tui.js";
7
+ export { SerializedCycleRunner };
8
+ export async function runLoopCli(argv, options = {}) {
9
+ const [command, ...rest] = argv;
10
+ if (command !== "run-loop") {
11
+ throw new CliUsageError('Expected command: backburner run-loop [--code-root <path>] [--management-dir <path>] [--outputs-dir <path>] [--log-dir <path>] [--broker-port <port>] [--interval-seconds <seconds> | --interval-minutes <minutes>] [--headless]');
12
+ }
13
+ if (shouldUseRuntimeStatusScreen(rest)) {
14
+ await runInteractiveTui(["run", ...rest]);
15
+ return;
16
+ }
17
+ const intervalMs = readIntervalMs(rest);
18
+ const logger = options.logger ?? defaultStderrLogger;
19
+ const delay = options.delay ?? delayWithAbort;
20
+ const signalRegistrar = options.signalRegistrar ?? process;
21
+ const abortController = new AbortController();
22
+ let stopRequested = false;
23
+ const requestStop = () => {
24
+ stopRequested = true;
25
+ abortController.abort();
26
+ };
27
+ signalRegistrar.on("SIGINT", requestStop);
28
+ signalRegistrar.on("SIGTERM", requestStop);
29
+ try {
30
+ logger.info(`Starting orchestrator run loop with interval ${Math.floor(intervalMs / 1000)}s`);
31
+ while (!stopRequested) {
32
+ const summary = await runCli(["run", ...rest], options);
33
+ process.stdout.write(formatRunSummary(summary));
34
+ if (stopRequested) {
35
+ break;
36
+ }
37
+ logger.info(`Waiting ${Math.floor(intervalMs / 1000)}s before the next orchestration cycle`);
38
+ try {
39
+ await delay(intervalMs, abortController.signal);
40
+ }
41
+ catch (error) {
42
+ if (!isAbortError(error)) {
43
+ throw error;
44
+ }
45
+ }
46
+ if (stopRequested) {
47
+ break;
48
+ }
49
+ }
50
+ logger.info("Run loop stopped after the current orchestration cycle completed.");
51
+ }
52
+ finally {
53
+ signalRegistrar.off("SIGINT", requestStop);
54
+ signalRegistrar.off("SIGTERM", requestStop);
55
+ }
56
+ }