@backburner/cli 0.1.3 → 0.1.5

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.
@@ -28,7 +28,7 @@ export function buildAntigravityCliArgs(options) {
28
28
  else {
29
29
  args.push("--dangerously-skip-permissions");
30
30
  }
31
- args.push("--print", "-");
31
+ args.push("--print", options.promptText);
32
32
  return args;
33
33
  }
34
34
  export async function writeAntigravitySettings(settingsPath, options) {
@@ -64,7 +64,8 @@ export class AntigravityCliAgent {
64
64
  ...(agentConfig.model ? { model: agentConfig.model } : {}),
65
65
  ...(resumeConversationId ? { conversationId: resumeConversationId } : {}),
66
66
  printTimeout: this.printTimeout,
67
- logFilePath
67
+ logFilePath,
68
+ promptText
68
69
  });
69
70
  this.logger?.info(JSON.stringify({
70
71
  component: "antigravity-launch",
@@ -102,7 +103,6 @@ export class AntigravityCliAgent {
102
103
  }
103
104
  const result = await this.options.commandRunner.run(agentConfig.command, args, {
104
105
  cwd,
105
- input: promptText,
106
106
  env: getAntigravityEnvOverrides(),
107
107
  timeoutMs: this.timeoutMs
108
108
  });
@@ -192,7 +192,9 @@ export class CodexCliAgent {
192
192
  : {})
193
193
  };
194
194
  const parsedThreadId = extractThreadIdFromCodexOutput(stdout);
195
- const providerLimitSignal = detectProviderLimit("codex", exitCode, stdout, stderr);
195
+ const providerLimitSignal = exitCode === 0
196
+ ? undefined
197
+ : detectProviderLimit("codex", exitCode, extractCodexProviderErrorText(stdout), stderr);
196
198
  return {
197
199
  taskStatus: execution.taskStatus,
198
200
  execution,
@@ -259,3 +261,61 @@ function extractCodexStreamJsonAssistantText(streamText) {
259
261
  }
260
262
  return undefined;
261
263
  }
264
+ function extractCodexProviderErrorText(streamText) {
265
+ if (!streamText.trim()) {
266
+ return "";
267
+ }
268
+ const extractedErrors = [];
269
+ let sawJsonLine = false;
270
+ for (const line of streamText.split(/\r?\n/)) {
271
+ const trimmed = line.trim();
272
+ if (!trimmed) {
273
+ continue;
274
+ }
275
+ try {
276
+ const event = JSON.parse(trimmed);
277
+ sawJsonLine = true;
278
+ collectCodexErrorStrings(event, extractedErrors);
279
+ }
280
+ catch {
281
+ // Non-JSON Codex output is a direct process surface and can be scanned.
282
+ extractedErrors.push(trimmed);
283
+ }
284
+ }
285
+ return sawJsonLine ? extractedErrors.join("\n") : streamText;
286
+ }
287
+ function collectCodexErrorStrings(value, out) {
288
+ if (!value || typeof value !== "object") {
289
+ return;
290
+ }
291
+ const record = value;
292
+ const type = typeof record.type === "string" ? record.type : "";
293
+ const isErrorEvent = type.toLowerCase().includes("error");
294
+ if (isErrorEvent) {
295
+ for (const key of ["message", "error", "details"]) {
296
+ const text = stringifyCodexErrorField(record[key]);
297
+ if (text) {
298
+ out.push(text);
299
+ }
300
+ }
301
+ }
302
+ const errorText = stringifyCodexErrorField(record.error);
303
+ if (errorText && (isErrorEvent || record.status === "failed")) {
304
+ out.push(errorText);
305
+ }
306
+ }
307
+ function stringifyCodexErrorField(value) {
308
+ if (typeof value === "string") {
309
+ return value;
310
+ }
311
+ if (value && typeof value === "object") {
312
+ const record = value;
313
+ if (typeof record.message === "string") {
314
+ return record.message;
315
+ }
316
+ if (typeof record.code === "string") {
317
+ return record.code;
318
+ }
319
+ }
320
+ return undefined;
321
+ }
@@ -310,11 +310,12 @@ export async function dispatchPendingTasks(input) {
310
310
  let providerLimitQueueProviders;
311
311
  let providerLimitResetTime;
312
312
  let swappedAfterProviderLimit = false;
313
- if (result.providerLimitSignal) {
313
+ const actionableProviderLimitSignal = result.taskStatus === "completed" ? undefined : result.providerLimitSignal;
314
+ if (actionableProviderLimitSignal) {
314
315
  try {
315
316
  const limitState = await input.stateStore.load();
316
317
  const providerLimits = [...(limitState.providerLimits ?? [])];
317
- const signal = result.providerLimitSignal;
318
+ const signal = actionableProviderLimitSignal;
318
319
  const existingIdx = providerLimits.findIndex(l => l.provider === signal.provider);
319
320
  const newRecord = mapSignalToRecord(signal, now());
320
321
  if (existingIdx !== -1) {
@@ -362,15 +363,15 @@ export async function dispatchPendingTasks(input) {
362
363
  }
363
364
  catch (err) {
364
365
  input.logger?.warn(`[dispatch] Failed to persist provider limit updates: ${err}`);
365
- providerLimitQueueProviders = result.providerLimitSignal.provider;
366
- providerLimitResetTime = result.providerLimitSignal.resetTime;
366
+ providerLimitQueueProviders = actionableProviderLimitSignal.provider;
367
+ providerLimitResetTime = actionableProviderLimitSignal.resetTime;
367
368
  }
368
369
  }
369
- const isProviderLimit = !!result.providerLimitSignal;
370
+ const isProviderLimit = !!actionableProviderLimitSignal;
370
371
  const shouldQueueForProviderLimit = isProviderLimit && !swappedAfterProviderLimit;
371
372
  const finalStatus = shouldQueueForProviderLimit ? "queued" : swappedAfterProviderLimit ? "pending" : result.taskStatus;
372
373
  if (shouldQueueForProviderLimit && !preparingTask.context.notifiedQueued) {
373
- await safelyNotifyQueued(input.lifecycleNotifier, preparingTask, providerLimitQueueProviders ?? result.providerLimitSignal.provider, providerLimitResetTime, input.logger);
374
+ await safelyNotifyQueued(input.lifecycleNotifier, preparingTask, providerLimitQueueProviders ?? actionableProviderLimitSignal.provider, providerLimitResetTime, input.logger);
374
375
  }
375
376
  tasks[index] = {
376
377
  ...preparingTask,
@@ -395,12 +396,12 @@ export async function dispatchPendingTasks(input) {
395
396
  }
396
397
  : {})
397
398
  },
398
- ...(shouldQueueForProviderLimit ? { waitingOnProvider: result.providerLimitSignal.provider } : { waitingOnProvider: undefined })
399
+ ...(shouldQueueForProviderLimit ? { waitingOnProvider: actionableProviderLimitSignal.provider } : { waitingOnProvider: undefined })
399
400
  };
400
401
  await input.stateStore.writeExecutionState(executions);
401
402
  await input.stateStore.writeTaskState(tasks);
402
403
  if (shouldQueueForProviderLimit) {
403
- console.log(`🤖 Task ${preparingTask.id} has been queued (waiting on provider ${result.providerLimitSignal.provider} due to rate limit).`);
404
+ console.log(`🤖 Task ${preparingTask.id} has been queued (waiting on provider ${actionableProviderLimitSignal.provider} due to rate limit).`);
404
405
  }
405
406
  if (assignmentResolution.mode === "pinned") {
406
407
  try {
@@ -11,7 +11,7 @@ export const planBreakdownHandler = {
11
11
  }
12
12
  };
13
13
  function derivePlanBreakdownTask(context, env) {
14
- const { workstream, attention, issue, activePullRequest, repoConfig, repoSyncRecord } = context;
14
+ const { workstream, attention, issue, activePullRequest, activeWorktree, repoConfig, repoSyncRecord } = context;
15
15
  if (hasGeneratedPlanBreakdown(workstream)) {
16
16
  return undefined;
17
17
  }
@@ -23,6 +23,13 @@ function derivePlanBreakdownTask(context, env) {
23
23
  if (!source) {
24
24
  return undefined;
25
25
  }
26
+ const prWorktree = source.kind === "pull_request" &&
27
+ activeWorktree &&
28
+ activePullRequest &&
29
+ activePullRequest.id === source.id &&
30
+ activeWorktree.branchName === activePullRequest.headBranch
31
+ ? activeWorktree
32
+ : undefined;
26
33
  return buildTaskRecord(buildTaskId("plan_breakdown", source.id), "plan_breakdown", source, repoSyncRecord, {
27
34
  reason: `The "${repoConfig.labels.planBreakdownNeeded}" label is present, requesting a technical breakdown before implementation.`,
28
35
  summary: `Break down implementation for ${source.kind.replace("_", " ")} #${source.number}: ${source.title}`,
@@ -40,6 +47,16 @@ function derivePlanBreakdownTask(context, env) {
40
47
  issueBody: source.body
41
48
  }
42
49
  : {}),
43
- ...(repoSyncRecord?.localPath ? { localRepoPath: repoSyncRecord.localPath } : {})
50
+ ...(prWorktree
51
+ ? {
52
+ localRepoPath: prWorktree.path,
53
+ branchName: prWorktree.branchName,
54
+ planDocumentPath: prWorktree.planDocumentPath,
55
+ ...(prWorktree.productSpecDocumentPath ? { productSpecDocumentPath: prWorktree.productSpecDocumentPath } : {}),
56
+ logDocumentPath: prWorktree.logDocumentPath
57
+ }
58
+ : repoSyncRecord?.localPath
59
+ ? { localRepoPath: repoSyncRecord.localPath }
60
+ : {})
44
61
  }), workstream.id);
45
62
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@backburner/cli",
3
- "version": "0.1.3",
3
+ "version": "0.1.5",
4
4
  "type": "module",
5
5
  "description": "Local GitHub-based agent orchestration CLI",
6
6
  "license": "MIT",