automata-cli 0.1.0-feature-030-do-work.210 → 0.1.0-feature-030-do-work.212

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 (2) hide show
  1. package/dist/index.js +208 -51
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -2431,22 +2431,24 @@ query($owner:String!,$repo:String!,$cursor:String){
2431
2431
  pullRequests(states:OPEN, first:100, after:$cursor, orderBy:{field:UPDATED_AT, direction:DESC}){
2432
2432
  pageInfo{ hasNextPage endCursor }
2433
2433
  nodes{
2434
- number url title headRefName isDraft updatedAt
2434
+ number url title headRefName baseRefName isCrossRepository isDraft updatedAt
2435
2435
  closingIssuesReferences(first:50){
2436
2436
  pageInfo{ hasNextPage }
2437
- nodes{ number }
2437
+ nodes{ number repository{ nameWithOwner } }
2438
2438
  }
2439
2439
  }
2440
2440
  }
2441
2441
  }
2442
2442
  }`.trim();
2443
2443
  var MAX_LINK_MAP_PAGES = 50;
2444
- function indexPullRequest(map, node) {
2444
+ function indexPullRequest(map, node, nameWithOwner) {
2445
2445
  const ref = {
2446
2446
  number: node.number,
2447
2447
  url: node.url,
2448
2448
  title: node.title,
2449
2449
  headRefName: node.headRefName,
2450
+ baseRefName: node.baseRefName,
2451
+ isCrossRepository: node.isCrossRepository,
2450
2452
  state: "OPEN",
2451
2453
  isDraft: node.isDraft,
2452
2454
  updatedAt: node.updatedAt
@@ -2457,6 +2459,7 @@ function indexPullRequest(map, node) {
2457
2459
  );
2458
2460
  }
2459
2461
  for (const issue of node.closingIssuesReferences.nodes) {
2462
+ if (issue.repository.nameWithOwner !== nameWithOwner) continue;
2460
2463
  const existing = map.get(issue.number);
2461
2464
  if (existing) {
2462
2465
  existing.push(ref);
@@ -2475,7 +2478,7 @@ function getOpenPrLinkMap() {
2475
2478
  const response = ghJson(args, "query open pull requests");
2476
2479
  const connection = response.data.repository.pullRequests;
2477
2480
  for (const node of connection.nodes) {
2478
- indexPullRequest(map, node);
2481
+ indexPullRequest(map, node, `${owner}/${repo}`);
2479
2482
  }
2480
2483
  if (!connection.pageInfo?.hasNextPage || connection.pageInfo.endCursor === null) {
2481
2484
  return map;
@@ -2566,7 +2569,7 @@ function getPrSurface(prNumber) {
2566
2569
  "view",
2567
2570
  String(prNumber),
2568
2571
  "--json",
2569
- "number,title,url,headRefName,state,isDraft,body,author,createdAt,updatedAt,comments,reviews"
2572
+ "number,title,url,headRefName,baseRefName,isCrossRepository,state,isDraft,body,author,createdAt,updatedAt,comments,reviews"
2570
2573
  ],
2571
2574
  `read pull request #${String(prNumber)}`
2572
2575
  );
@@ -2594,6 +2597,8 @@ function getPrSurface(prNumber) {
2594
2597
  url: raw.url,
2595
2598
  title: raw.title,
2596
2599
  headRefName: raw.headRefName,
2600
+ baseRefName: raw.baseRefName ?? "",
2601
+ isCrossRepository: raw.isCrossRepository ?? false,
2597
2602
  state,
2598
2603
  isDraft: raw.isDraft ?? false,
2599
2604
  updatedAt: raw.updatedAt ?? raw.createdAt
@@ -2719,7 +2724,24 @@ function decideWork(state, p, baseBranch) {
2719
2724
  };
2720
2725
  }
2721
2726
  const surface = prSurface;
2722
- const prAnalysis = analyzeSurface(surface.messages, p);
2727
+ if (surface.pr.isCrossRepository) {
2728
+ return {
2729
+ kind: "skip",
2730
+ issue,
2731
+ reason: "unsafe-pr-branch",
2732
+ detail: `pull request #${String(surface.pr.number)} comes from a fork; its head branch is not in this repository`
2733
+ };
2734
+ }
2735
+ if (surface.pr.headRefName === baseBranch) {
2736
+ return {
2737
+ kind: "skip",
2738
+ issue,
2739
+ reason: "unsafe-pr-branch",
2740
+ detail: `pull request #${String(surface.pr.number)} has the base branch (${baseBranch}) as its head`
2741
+ };
2742
+ }
2743
+ const agentThreadMessages = surface.threads.flatMap((thread) => thread.comments).filter((comment) => comment.author.toLowerCase() === p.agentUser.toLowerCase());
2744
+ const prAnalysis = analyzeSurface([...surface.messages, ...agentThreadMessages], p);
2723
2745
  const actionableThreads = findActionableThreads(surface.threads, p);
2724
2746
  const hasPrWork = prAnalysis.hasNewMessage || actionableThreads.length > 0;
2725
2747
  if (!hasPrWork && !issueAnalysis.hasNewMessage) {
@@ -2850,6 +2872,16 @@ var RUN_LOCK_RELATIVE_PATH = `${LOCK_DIR}/${LOCK_FILE}`;
2850
2872
  function lockPath() {
2851
2873
  return join2(process.cwd(), LOCK_DIR, LOCK_FILE);
2852
2874
  }
2875
+ function processStartedAt(pid) {
2876
+ try {
2877
+ const stat = readFileSync3(`/proc/${String(pid)}/stat`, "utf8");
2878
+ const afterComm = stat.slice(stat.lastIndexOf(")") + 2);
2879
+ const field = afterComm.split(" ")[19];
2880
+ return field === void 0 || field.length === 0 ? null : field;
2881
+ } catch {
2882
+ return null;
2883
+ }
2884
+ }
2853
2885
  function isAlive(pid) {
2854
2886
  try {
2855
2887
  process.kill(pid, 0);
@@ -2867,7 +2899,8 @@ function readOwner(path) {
2867
2899
  startedAt: parsed.startedAt,
2868
2900
  host: parsed.host ?? "unknown",
2869
2901
  command: parsed.command ?? "unknown",
2870
- token: parsed.token ?? ""
2902
+ token: parsed.token ?? "",
2903
+ pidStartedAt: parsed.pidStartedAt
2871
2904
  };
2872
2905
  } catch {
2873
2906
  return null;
@@ -2876,12 +2909,24 @@ function readOwner(path) {
2876
2909
  function isStale(owner, staleMinutes) {
2877
2910
  if (owner === null) return true;
2878
2911
  if (owner.host === hostname()) {
2879
- return !isAlive(owner.pid);
2912
+ if (!isAlive(owner.pid)) return true;
2913
+ const startedAt2 = processStartedAt(owner.pid);
2914
+ if (owner.pidStartedAt !== void 0 && startedAt2 !== null && startedAt2 !== owner.pidStartedAt) {
2915
+ return true;
2916
+ }
2917
+ return false;
2880
2918
  }
2881
2919
  const startedAt = Date.parse(owner.startedAt);
2882
2920
  if (Number.isNaN(startedAt)) return true;
2883
2921
  return Date.now() - startedAt > staleMinutes * 60 * 1e3;
2884
2922
  }
2923
+ function heldTooLong(owner, staleMinutes) {
2924
+ if (owner.host !== hostname()) return false;
2925
+ if (owner.pidStartedAt !== void 0 && processStartedAt(owner.pid) !== null) return false;
2926
+ const startedAt = Date.parse(owner.startedAt);
2927
+ if (Number.isNaN(startedAt)) return true;
2928
+ return Date.now() - startedAt > staleMinutes * 60 * 1e3;
2929
+ }
2885
2930
  function makeHandle(path, token) {
2886
2931
  let released = false;
2887
2932
  return {
@@ -2923,7 +2968,8 @@ function write(path, command, token, flag = "wx") {
2923
2968
  startedAt: (/* @__PURE__ */ new Date()).toISOString(),
2924
2969
  host: hostname(),
2925
2970
  command,
2926
- token
2971
+ token,
2972
+ pidStartedAt: processStartedAt(process.pid) ?? void 0
2927
2973
  };
2928
2974
  writeFileSync(path, JSON.stringify(owner, null, 2) + "\n", { encoding: "utf8", flag });
2929
2975
  }
@@ -2939,9 +2985,10 @@ function acquireRunLock(command, staleMinutes) {
2939
2985
  }
2940
2986
  const owner = readOwner(path);
2941
2987
  if (!isStale(owner, staleMinutes)) {
2942
- return { ok: false, heldBy: owner };
2988
+ const held = owner;
2989
+ return { ok: false, heldBy: held, suspect: heldTooLong(held, staleMinutes) };
2943
2990
  }
2944
- return reclaim(path, command, token);
2991
+ return reclaim(path, command, token, owner);
2945
2992
  }
2946
2993
  var UNKNOWN_OWNER = {
2947
2994
  pid: 0,
@@ -2950,18 +2997,34 @@ var UNKNOWN_OWNER = {
2950
2997
  command: "unknown",
2951
2998
  token: ""
2952
2999
  };
2953
- function claimStaleLock(path, token) {
3000
+ function claimStaleLock(path, token, expected) {
3001
+ const claimed = `${path}.stale.${token}`;
2954
3002
  try {
2955
- renameSync(path, `${path}.stale.${token}`);
2956
- return true;
3003
+ renameSync(path, claimed);
2957
3004
  } catch (err) {
2958
3005
  if (err.code === "ENOENT") return false;
2959
3006
  throw err;
2960
3007
  }
3008
+ if (expected !== void 0) {
3009
+ const taken = readOwner(claimed);
3010
+ const sameFile = expected === null && taken === null || expected !== null && taken !== null && taken.token === expected.token;
3011
+ if (!sameFile) {
3012
+ try {
3013
+ linkSync(claimed, path);
3014
+ } catch {
3015
+ }
3016
+ try {
3017
+ unlinkSync(claimed);
3018
+ } catch {
3019
+ }
3020
+ return false;
3021
+ }
3022
+ }
3023
+ return true;
2961
3024
  }
2962
- function reclaim(path, command, token) {
2963
- if (!claimStaleLock(path, token)) {
2964
- return { ok: false, heldBy: readOwner(path) ?? UNKNOWN_OWNER };
3025
+ function reclaim(path, command, token, expected) {
3026
+ if (!claimStaleLock(path, token, expected)) {
3027
+ return { ok: false, heldBy: readOwner(path) ?? UNKNOWN_OWNER, suspect: false };
2965
3028
  }
2966
3029
  const claimed = `${path}.stale.${token}`;
2967
3030
  try {
@@ -2969,7 +3032,7 @@ function reclaim(path, command, token) {
2969
3032
  return { ok: true, handle: makeHandle(path, token) };
2970
3033
  } catch (err) {
2971
3034
  if (err.code !== "EEXIST") throw err;
2972
- return { ok: false, heldBy: readOwner(path) ?? UNKNOWN_OWNER };
3035
+ return { ok: false, heldBy: readOwner(path) ?? UNKNOWN_OWNER, suspect: false };
2973
3036
  } finally {
2974
3037
  try {
2975
3038
  unlinkSync(claimed);
@@ -3020,6 +3083,7 @@ function preparePrBranch(headRefName) {
3020
3083
  }
3021
3084
 
3022
3085
  // src/commands/doWork.ts
3086
+ var inFlightMarker = null;
3023
3087
  function out(message) {
3024
3088
  process.stdout.write(message);
3025
3089
  }
@@ -3261,6 +3325,40 @@ function describePlan(decisions) {
3261
3325
  });
3262
3326
  return lines.length === 0 ? " (no issues matched the discovery filter)\n" : lines.join("\n") + "\n";
3263
3327
  }
3328
+ function claimIssue(item, settings) {
3329
+ if (!item.needsAssignment) return;
3330
+ try {
3331
+ assignIssueToAgent(item.issue.number, settings.participants.agentUser);
3332
+ progress(` assigned issue #${String(item.issue.number)} to ${settings.participants.agentUser}.
3333
+ `);
3334
+ } catch (err) {
3335
+ progress(` warning: could not assign issue #${String(item.issue.number)}: ${err.message}
3336
+ `);
3337
+ }
3338
+ }
3339
+ function notePickupOnIssue(item, marker) {
3340
+ if (item.turn !== "pr-work" || item.pr === null || !item.issueAnalysis.hasNewMessage) return true;
3341
+ try {
3342
+ postMarker(
3343
+ "issue",
3344
+ item.issue.number,
3345
+ `automata do-work: picked this up on pull request #${String(item.pr.number)} \u2014 ${item.pr.url}`
3346
+ );
3347
+ progress(` noted on issue #${String(item.issue.number)} that the work is on pull request #${String(item.pr.number)}.
3348
+ `);
3349
+ return true;
3350
+ } catch (err) {
3351
+ progress(` skipped: could not note the pickup on issue #${String(item.issue.number)} \u2014 ${err.message}
3352
+ `);
3353
+ try {
3354
+ deleteMarker(marker);
3355
+ } catch (deleteErr) {
3356
+ progress(` warning: could not withdraw the working marker: ${deleteErr.message}
3357
+ `);
3358
+ }
3359
+ return false;
3360
+ }
3361
+ }
3264
3362
  function refreshItem(item, settings) {
3265
3363
  const linkMap = getOpenPrLinkMap();
3266
3364
  return decideWork(
@@ -3269,6 +3367,14 @@ function refreshItem(item, settings) {
3269
3367
  settings.baseBranch
3270
3368
  );
3271
3369
  }
3370
+ function authorizedMessagesSince(messages, participants, marker) {
3371
+ const allowed = participants.allowedUsers.map((user) => user.toLowerCase());
3372
+ const agent = participants.agentUser.toLowerCase();
3373
+ return messages.filter((message) => {
3374
+ const author = message.author.toLowerCase();
3375
+ return author !== agent && allowed.includes(author) && message.createdAt > marker.createdAt;
3376
+ });
3377
+ }
3272
3378
  function readAnsweringSurface(item) {
3273
3379
  if (item.turn === "issue-discuss" || item.pr === null) {
3274
3380
  return getIssueSurface(item.issue.number).messages;
@@ -3279,10 +3385,13 @@ function readAnsweringSurface(item) {
3279
3385
  function markerSurfaceLabel(item) {
3280
3386
  return item.turn === "pr-work" && item.pr ? `pull request #${String(item.pr.number)}` : `issue #${String(item.issue.number)}`;
3281
3387
  }
3282
- function reconcileMarker(item, marker, agentUser, runError) {
3388
+ function reconcileMarker(item, marker, participants, runError) {
3389
+ const agentUser = participants.agentUser;
3390
+ let surfaceMessages = [];
3283
3391
  let answered;
3284
3392
  try {
3285
- answered = agentAnsweredAfter(readAnsweringSurface(item), agentUser, marker);
3393
+ surfaceMessages = readAnsweringSurface(item);
3394
+ answered = agentAnsweredAfter(surfaceMessages, agentUser, marker);
3286
3395
  } catch (err) {
3287
3396
  progress(
3288
3397
  ` warning: could not re-read issue #${String(item.issue.number)} to check for an answer: ${err.message}
@@ -3304,12 +3413,30 @@ function reconcileMarker(item, marker, agentUser, runError) {
3304
3413
  return { outcome: "answered-no-reply", detail: "could not verify whether an answer was posted" };
3305
3414
  }
3306
3415
  if (answered) {
3416
+ const interleaved = authorizedMessagesSince(surfaceMessages, participants, marker);
3417
+ if (interleaved.length > 0) {
3418
+ const authors = [...new Set(interleaved.map((message) => message.author))].join(", ");
3419
+ try {
3420
+ postMarker(
3421
+ item.turn === "pr-work" ? "pr" : "issue",
3422
+ item.turn === "pr-work" && item.pr ? item.pr.number : item.issue.number,
3423
+ `automata do-work: ${authors} posted here while this run was already in progress, so ${interleaved.length === 1 ? "that message was" : "those messages were"} not included in it. Please post again to have them acted on.`
3424
+ );
3425
+ } catch (err) {
3426
+ progress(` warning: could not report the interleaved message(s): ${err.message}
3427
+ `);
3428
+ }
3429
+ }
3307
3430
  try {
3308
3431
  deleteMarker(marker);
3309
3432
  } catch (err) {
3310
3433
  progress(` warning: could not delete the marker comment: ${err.message}
3311
3434
  `);
3312
3435
  }
3436
+ const noted = interleaved.length > 0 ? ` (${String(interleaved.length)} message(s) arrived mid-run and were flagged)` : "";
3437
+ if (interleaved.length > 0) {
3438
+ return { outcome: "answered-no-reply", detail: `answered${noted}` };
3439
+ }
3313
3440
  return runError === null ? { outcome: "answered", detail: "answered" } : { outcome: "answered", detail: `answered, but the run reported: ${runError.message}` };
3314
3441
  }
3315
3442
  const surface = markerSurfaceLabel(item);
@@ -3346,7 +3473,8 @@ function repairIssueLink(item, baseBranch) {
3346
3473
  `);
3347
3474
  return;
3348
3475
  }
3349
- if (pr.body.includes(`Closes #${String(item.issue.number)}`)) {
3476
+ const closesRef = new RegExp(String.raw`\bcloses\s+#` + String(item.issue.number) + String.raw`\b`, "i");
3477
+ if (closesRef.test(pr.body)) {
3350
3478
  progress(` pull request #${String(pr.number)} already closes issue #${String(item.issue.number)}.
3351
3479
  `);
3352
3480
  return;
@@ -3391,31 +3519,7 @@ async function processItem(planned, settings, silent) {
3391
3519
  `);
3392
3520
  return { ...base, outcome: "skipped", detail: `${prepared.reason}: ${prepared.detail}` };
3393
3521
  }
3394
- if (item.needsAssignment) {
3395
- try {
3396
- assignIssueToAgent(item.issue.number, settings.participants.agentUser);
3397
- progress(` assigned issue #${String(item.issue.number)} to ${settings.participants.agentUser}.
3398
- `);
3399
- } catch (err) {
3400
- progress(` warning: could not assign issue #${String(item.issue.number)}: ${err.message}
3401
- `);
3402
- }
3403
- }
3404
- if (item.turn === "pr-work" && item.pr && item.issueAnalysis.hasNewMessage) {
3405
- try {
3406
- postMarker(
3407
- "issue",
3408
- item.issue.number,
3409
- `automata do-work: picked this up on pull request #${String(item.pr.number)} \u2014 ${item.pr.url}`
3410
- );
3411
- progress(` noted on issue #${String(item.issue.number)} that the work is on pull request #${String(item.pr.number)}.
3412
- `);
3413
- } catch (err) {
3414
- progress(` skipped: could not note the pickup on issue #${String(item.issue.number)} \u2014 ${err.message}
3415
- `);
3416
- return { ...base, outcome: "skipped", detail: `issue pickup note failed: ${err.message}` };
3417
- }
3418
- }
3522
+ claimIssue(item, settings);
3419
3523
  let marker;
3420
3524
  const markerSurface = item.turn === "pr-work" && item.pr ? item.pr.number : item.issue.number;
3421
3525
  try {
@@ -3425,6 +3529,11 @@ async function processItem(planned, settings, silent) {
3425
3529
  `);
3426
3530
  return { ...base, outcome: "skipped", detail: `marker failed: ${err.message}` };
3427
3531
  }
3532
+ inFlightMarker = { marker, item };
3533
+ if (!notePickupOnIssue(item, marker)) {
3534
+ inFlightMarker = null;
3535
+ return { ...base, outcome: "skipped", detail: "issue pickup note failed" };
3536
+ }
3428
3537
  const prompt = composePrompt({
3429
3538
  item,
3430
3539
  repo: getRepoSlug(),
@@ -3432,19 +3541,39 @@ async function processItem(planned, settings, silent) {
3432
3541
  baseBranch: settings.baseBranch,
3433
3542
  frame: settings.prompts[item.turn]
3434
3543
  });
3544
+ const MAX_PROMPT_BYTES = 96 * 1024;
3545
+ const promptBytes = Buffer.byteLength(prompt, "utf8");
3546
+ if (promptBytes > MAX_PROMPT_BYTES) {
3547
+ const detail = `the composed prompt is ${String(Math.round(promptBytes / 1024))} KiB, over the ${String(MAX_PROMPT_BYTES / 1024)} KiB limit for a single command-line argument. The conversation is too long to hand to the executor this way.`;
3548
+ progress(` failed: ${detail}
3549
+ `);
3550
+ inFlightMarker = null;
3551
+ try {
3552
+ updateMarker(
3553
+ marker,
3554
+ `automata do-work: could not start a run because ${detail} Summarise the discussion in a new issue, or shorten the thread, and try again.`
3555
+ );
3556
+ } catch (err) {
3557
+ progress(` warning: could not update the marker comment: ${err.message}
3558
+ `);
3559
+ }
3560
+ return { ...base, outcome: "failed", detail };
3561
+ }
3435
3562
  let runError = null;
3436
3563
  try {
3437
3564
  await invokeExecutor(prompt, settings, silent);
3438
3565
  } catch (err) {
3439
3566
  runError = err;
3440
3567
  }
3441
- const reconciled = reconcileMarker(item, marker, settings.participants.agentUser, runError);
3568
+ const ranExecutor = true;
3569
+ inFlightMarker = null;
3570
+ const reconciled = reconcileMarker(item, marker, settings.participants, runError);
3442
3571
  progress(` ${reconciled.detail}
3443
3572
  `);
3444
3573
  if (item.turn === "issue-discuss") {
3445
3574
  repairIssueLink(item, settings.baseBranch);
3446
3575
  }
3447
- return { ...base, outcome: reconciled.outcome, detail: reconciled.detail };
3576
+ return { ...base, outcome: reconciled.outcome, detail: reconciled.detail, ranExecutor };
3448
3577
  }
3449
3578
  function summarize(reports) {
3450
3579
  out("\nTick summary:\n");
@@ -3464,17 +3593,33 @@ var doWorkCommand = new Command6("do-work").description(
3464
3593
  "Print the work plan, plus a summary and the exact command that would be launched for each item, and exit without changing anything"
3465
3594
  ).option("--json", "Emit the work plan and outcomes as JSON on stdout").option("--silent", "Suppress step-by-step Claude output; show only the final summary").action(async (options) => {
3466
3595
  const settings = resolveSettings(options);
3596
+ if (options.dryRun === true) {
3597
+ const exitCode2 = await runTick(settings, options);
3598
+ if (exitCode2 !== 0) process.exit(exitCode2);
3599
+ return;
3600
+ }
3467
3601
  const lock = acquireRunLock("do-work", settings.lockStaleMinutes);
3468
3602
  if (!lock.ok) {
3469
3603
  const held = lock.heldBy;
3470
3604
  const sentence = `Another automata instance is already running here (pid ${String(held.pid)} on ${held.host}, started ${held.startedAt}, command ${held.command}). Doing nothing.
3471
3605
  `;
3606
+ const suspectSentence = lock.suspect ? `Warning: that lock has been held longer than ${String(settings.lockStaleMinutes)} minutes. If no tick is really running, its process id was probably reused; remove ${RUN_LOCK_RELATIVE_PATH} once you have confirmed that.
3607
+ ` : "";
3608
+ const exitCode2 = lock.suspect ? 2 : 0;
3472
3609
  if (options.json === true) {
3473
- progress(sentence);
3474
- out(JSON.stringify({ lockHeld: true, heldBy: held, plan: [], items: [], exitCode: 0 }, null, 2) + "\n");
3610
+ progress(sentence + suspectSentence);
3611
+ out(
3612
+ JSON.stringify(
3613
+ { lockHeld: true, suspect: lock.suspect, heldBy: held, plan: [], items: [], exitCode: exitCode2 },
3614
+ null,
3615
+ 2
3616
+ ) + "\n"
3617
+ );
3475
3618
  } else {
3476
3619
  out(sentence);
3620
+ if (suspectSentence) progress(suspectSentence);
3477
3621
  }
3622
+ if (exitCode2 !== 0) process.exit(exitCode2);
3478
3623
  return;
3479
3624
  }
3480
3625
  const handle = lock.handle;
@@ -3483,6 +3628,18 @@ var doWorkCommand = new Command6("do-work").description(
3483
3628
  if (shuttingDown) return;
3484
3629
  shuttingDown = true;
3485
3630
  progress("\nInterrupted: stopping the executor before releasing the run lock\u2026\n");
3631
+ const pending = inFlightMarker;
3632
+ if (pending !== null) {
3633
+ try {
3634
+ updateMarker(
3635
+ pending.marker,
3636
+ `automata do-work: this run was interrupted before it finished, so no answer was produced. The branch \`${pending.item.branch}\` may have been changed. Reply here to have another attempt made.`
3637
+ );
3638
+ } catch (err) {
3639
+ progress(`Warning: could not update the in-flight marker: ${err.message}
3640
+ `);
3641
+ }
3642
+ }
3486
3643
  void terminateTrackedChildren().then((allExited) => {
3487
3644
  if (allExited) {
3488
3645
  handle.release();
@@ -3548,7 +3705,7 @@ ${describePlan(decisions)}`;
3548
3705
  detail: err.message
3549
3706
  };
3550
3707
  }
3551
- if (report.outcome !== "skipped") runsUsed++;
3708
+ if (report.ranExecutor === true) runsUsed++;
3552
3709
  reports.push(report);
3553
3710
  }
3554
3711
  for (const item of deferred) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "automata-cli",
3
- "version": "0.1.0-feature-030-do-work.210",
3
+ "version": "0.1.0-feature-030-do-work.212",
4
4
  "description": "Automata CLI tool",
5
5
  "type": "module",
6
6
  "bin": {