svamp-cli 0.2.346 → 0.2.358

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 (33) hide show
  1. package/bin/skills/artifact/SKILL.md +19 -5
  2. package/bin/skills/crew/SKILL.md +42 -11
  3. package/dist/{acpBackend-BZ1MJhQV.mjs → acpBackend-UaBD4zL3.mjs} +3 -0
  4. package/dist/{agentCommands-B2Nl7Fof.mjs → agentCommands-C_KvvYFp.mjs} +5 -5
  5. package/dist/{claudeAuth-iAerdaMr.mjs → claudeAuth-DMDvPNhO.mjs} +55 -6
  6. package/dist/cli.mjs +164 -86
  7. package/dist/{commands-D69mnkYu.mjs → commands-B19lVZjm.mjs} +10 -3
  8. package/dist/{commands-BB1Kcyt-.mjs → commands-Bmoy6Rlw.mjs} +34 -4
  9. package/dist/{commands-CiRCwjkJ.mjs → commands-CFBKkfX8.mjs} +9 -9
  10. package/dist/{commands-D1pZq3d4.mjs → commands-CcdoQIkb.mjs} +126 -25
  11. package/dist/{commands-BOpoVBOM.mjs → commands-DH_YQrAP.mjs} +5 -21
  12. package/dist/{commands-H4PsTGn8.mjs → commands-DRxANaS5.mjs} +65 -19
  13. package/dist/{commands-C2aODeVc.mjs → commands-nkvTnUJj.mjs} +29 -13
  14. package/dist/{detectIsolation-CzoDCEnh.mjs → detectIsolation-CrV8IFDv.mjs} +36 -16
  15. package/dist/{fleet-DM_Q7w69.mjs → fleet-Ca-UjJNL.mjs} +40 -15
  16. package/dist/friendlyName-B-OEwt0t.mjs +341 -0
  17. package/dist/{headlessCli-C8HzQvis.mjs → headlessCli-BpTXz6FD.mjs} +24 -16
  18. package/dist/{hookSettings-DYMTUgVA.mjs → hookSettings-CvvUhwCK.mjs} +294 -55
  19. package/dist/{friendlyName-1UZcyDhu.mjs → inboxGuard-CDqmIypF.mjs} +32 -347
  20. package/dist/index.mjs +10 -9
  21. package/dist/{loopVerify-B47sSjxe.mjs → loopVerify-CxAKJB5a.mjs} +1 -1
  22. package/dist/{notifyCommands-D-IKIxiq.mjs → notifyCommands-CCUE18Q-.mjs} +1 -1
  23. package/dist/package-DTTWvJbp.mjs +64 -0
  24. package/dist/{rpc-Cf0grcru.mjs → rpc-CAlAHQAy.mjs} +8 -3
  25. package/dist/{rpc-BB6RF4-F.mjs → rpc-CacreLQ8.mjs} +13 -9
  26. package/dist/{run-ChdsgaSD.mjs → run-Bc81iurl.mjs} +27 -8
  27. package/dist/{run-DkjwF-zA.mjs → run-DKOND4dO.mjs} +222 -73
  28. package/dist/{scheduler-BY30ZrB9.mjs → scheduler-IyLWBF8T.mjs} +28 -10
  29. package/dist/{serveAuth-DbVLRCRR.mjs → serveAuth-4M0vwMyj.mjs} +53 -11
  30. package/dist/{serveCommands-CUHUiYnZ.mjs → serveCommands-B-Ym_QXc.mjs} +8 -8
  31. package/dist/{store-Bn0ByYev.mjs → store-D8dok6_d.mjs} +62 -14
  32. package/package.json +3 -3
  33. package/dist/package-DtuINqf5.mjs +0 -64
@@ -1,12 +1,12 @@
1
- import{createRequire as _pkgrollCR}from"node:module";const require=_pkgrollCR(import.meta.url);import { a as composeSessionId, g as generateFriendlyName } from './friendlyName-1UZcyDhu.mjs';
1
+ import{createRequire as _pkgrollCR}from"node:module";const require=_pkgrollCR(import.meta.url);import { c as composeSessionId, g as generateFriendlyName } from './friendlyName-B-OEwt0t.mjs';
2
2
  import os from 'node:os';
3
3
  import { resolve, join } from 'node:path';
4
4
  import { existsSync, readFileSync, watch } from 'node:fs';
5
5
  import { c as connectToHypha } from './hyphaClient-ybivOjZo.mjs';
6
- import { c as createSessionStore, r as registerMachineService, g as generateHookSettings } from './hookSettings-DYMTUgVA.mjs';
6
+ import { c as createSessionStore, r as registerMachineService, g as generateHookSettings } from './hookSettings-CvvUhwCK.mjs';
7
7
  import { createServer } from 'node:http';
8
8
  import { spawn } from 'node:child_process';
9
- import { applyClaudeProxyEnv } from './claudeAuth-iAerdaMr.mjs';
9
+ import { applyClaudeProxyEnv } from './claudeAuth-DMDvPNhO.mjs';
10
10
  import { createInterface } from 'node:readline';
11
11
  import 'node:crypto';
12
12
  import 'fs';
@@ -23,9 +23,10 @@ import 'http';
23
23
  import 'net';
24
24
  import 'os';
25
25
  import './instance-CeHz5C8v.mjs';
26
- import './serveAuth-DbVLRCRR.mjs';
26
+ import './serveAuth-4M0vwMyj.mjs';
27
27
  import './envFlag-COOuJ3AH.mjs';
28
28
  import './codexProvider-BtxYc5Rj.mjs';
29
+ import './inboxGuard-CDqmIypF.mjs';
29
30
  import './fileLock-BMPwCrB6.mjs';
30
31
  import 'node:events';
31
32
  import './cron-hHGdb5kU.mjs';
@@ -321,6 +322,7 @@ async function runRemoteMode(opts) {
321
322
  opts.abort.addEventListener("abort", () => abortController.abort(), { once: true });
322
323
  }
323
324
  try {
325
+ let liveSessionId = opts.claudeSessionId;
324
326
  while (!exitReason && !abortController.signal.aborted) {
325
327
  const message = await Promise.race([
326
328
  opts.nextMessage(),
@@ -334,12 +336,25 @@ async function runRemoteMode(opts) {
334
336
  claudeBin,
335
337
  cwd,
336
338
  message,
337
- sessionId: opts.claudeSessionId,
339
+ // #1703: read the LIVE id, not the one captured when runRemoteMode was called.
340
+ //
341
+ // This used to pass `opts.claudeSessionId`, which is frozen at entry — and the id
342
+ // discovered on turn 1 is written by onSessionFound into loop.ts's own variable,
343
+ // which this function will not re-read until it returns and is called again. So
344
+ // turn 2 spawned with NO --resume: the web app sent "read foo.ts" then "now
345
+ // refactor it", and the second turn had never heard of foo.ts. EVERY remote-mode
346
+ // turn after the first was amnesiac, and each one was a full uncached prefix.
347
+ // loop.ts's header states the intended contract: "Session ID is preserved across
348
+ // switches (same Claude conversation)."
349
+ sessionId: liveSessionId,
338
350
  permissionMode: opts.permissionMode,
339
351
  hookSettingsPath: opts.hookSettingsPath,
340
352
  claudeArgs: opts.claudeArgs,
341
353
  signal: abortController.signal,
342
- onSessionFound: opts.onSessionFound,
354
+ onSessionFound: (id) => {
355
+ liveSessionId = id;
356
+ opts.onSessionFound(id);
357
+ },
343
358
  onThinkingChange,
344
359
  onMessage,
345
360
  log
@@ -385,6 +400,8 @@ async function runClaudeTurn(opts) {
385
400
  `);
386
401
  const spawnEnv = { ...process.env, CLAUDE_CODE_ENTRYPOINT: "sdk-ts" };
387
402
  delete spawnEnv.CLAUDECODE;
403
+ const proxyDesc = applyClaudeProxyEnv(spawnEnv);
404
+ if (proxyDesc) opts.log?.(`[remote] Claude auth: ${proxyDesc}`);
388
405
  const child = spawn(opts.claudeBin, args, {
389
406
  stdio: ["pipe", "pipe", "pipe"],
390
407
  cwd: opts.cwd,
@@ -526,7 +543,7 @@ function mapPermissionMode(mode) {
526
543
  async function loop(opts) {
527
544
  const { log } = opts;
528
545
  let mode = opts.startingMode;
529
- let claudeSessionId = null;
546
+ let claudeSessionId = opts.resumeSessionId || null;
530
547
  const onSessionFound = (id) => {
531
548
  if (id !== claudeSessionId) {
532
549
  log(`[loop] Session ID: ${id}`);
@@ -872,7 +889,7 @@ async function runInteractive(options) {
872
889
  process.on("SIGTERM", handleExit);
873
890
  process.on("SIGINT", handleExit);
874
891
  const claudeArgs = [...options.claudeArgs || []];
875
- if (options.resumeSessionId) ; else if (options.continueSession) {
892
+ if (!options.resumeSessionId && options.continueSession) {
876
893
  claudeArgs.push("--continue");
877
894
  }
878
895
  restoreConsoleLogs();
@@ -898,6 +915,8 @@ async function runInteractive(options) {
898
915
  try {
899
916
  const exitCode = await loop({
900
917
  cwd,
918
+ resumeSessionId: options.resumeSessionId,
919
+ // #1702
901
920
  startingMode: "local",
902
921
  hookSettingsPath: hookSettings?.settingsPath || "",
903
922
  permissionMode,
@@ -1,19 +1,20 @@
1
1
  import os from 'os';
2
2
  import fs from 'fs/promises';
3
- import fs__default, { existsSync as existsSync$1, readFileSync as readFileSync$1, realpathSync, writeFileSync as writeFileSync$1, renameSync as renameSync$1, rmSync as rmSync$1, mkdirSync as mkdirSync$1, copyFileSync, unlinkSync as unlinkSync$1, readdirSync as readdirSync$1, watch, rmdirSync, statSync as statSync$1 } from 'fs';
3
+ import fs__default, { existsSync as existsSync$1, readFileSync as readFileSync$1, realpathSync, writeFileSync as writeFileSync$1, renameSync as renameSync$1, rmSync as rmSync$1, mkdirSync as mkdirSync$1, copyFileSync, unlinkSync as unlinkSync$1, readdirSync as readdirSync$1, watch, rmdirSync, statSync as statSync$1, chmodSync } from 'fs';
4
4
  import { delimiter, join as join$1, resolve, dirname as dirname$1, basename as basename$1 } from 'path';
5
5
  import { fileURLToPath } from 'url';
6
6
  import { spawn as spawn$1, execFile, exec } from 'child_process';
7
7
  import { randomUUID, createHash } from 'crypto';
8
- import { a as authorizeRequest, b as countFileLines, P as ProcessSupervisor, d as retryStreakExhausted, e as computeRetryDelayMs, f as getRateLimitRetryConfig, g as generateHookSettings, h as getAccount, i as resolveAccountEnv, j as isRetryableRateLimit, c as createSessionStore, E as EXEC_MAX_BUFFER, k as execFailureOutcome, l as execSuccessOutcome, m as formatInboxMessageXml, n as loadInbox, o as isPending, p as ensureCodexHome, q as loadPersistedMachineMetadata, s as savePersistedMachineMetadata, r as registerMachineService, t as channelKeyGrantsFileAccess, C as ChannelStore, u as refreshDueAnthropicAccounts, v as refreshAnthropicToken } from './hookSettings-DYMTUgVA.mjs';
9
- import { a as composeSessionId, g as generateFriendlyName, d as friendlyNameFromId, f as formatHandle, e as clearInboundContext, w as writeInboundContext, i as isHopCapParked, j as classifyInbound, k as consumeAwaitingReply, l as peekAwaitingReply } from './friendlyName-1UZcyDhu.mjs';
8
+ import { a as authorizeRequest, b as countFileLines, P as ProcessSupervisor, d as retryStreakExhausted, e as computeRetryDelayMs, f as getRateLimitRetryConfig, g as generateHookSettings, h as getAccount, i as resolveAccountEnv, j as isRetryableRateLimit, c as createSessionStore, E as EXEC_MAX_BUFFER, k as execFailureOutcome, l as execSuccessOutcome, m as formatInboxMessageXml, n as loadInbox, o as isPending, p as ensureCodexHome, q as loadPersistedMachineMetadata, s as savePersistedMachineMetadata, r as registerMachineService, t as channelKeyGrantsFileAccess, C as ChannelStore, u as refreshDueAnthropicAccounts, v as refreshAnthropicToken } from './hookSettings-CvvUhwCK.mjs';
9
+ import { c as composeSessionId, g as generateFriendlyName, a as friendlyNameFromId, f as formatHandle } from './friendlyName-B-OEwt0t.mjs';
10
10
  import { w as withFileLock } from './fileLock-BMPwCrB6.mjs';
11
11
  import { mkdirSync, writeFileSync, rmSync, existsSync, renameSync, readFileSync, statSync, openSync, fstatSync, readSync, closeSync, readdirSync, unlinkSync, linkSync } from 'node:fs';
12
12
  import { join, dirname, basename, resolve as resolve$1 } from 'node:path';
13
13
  import { c as connectToHypha } from './hyphaClient-ybivOjZo.mjs';
14
+ import { clearInboundContext, writeInboundContext, isHopCapParked, classifyInbound, consumeAwaitingReply, peekAwaitingReply } from './inboxGuard-CDqmIypF.mjs';
14
15
  import { execSync, execFileSync, spawn } from 'node:child_process';
15
16
  import { S as SharingNotificationSync } from './sharingNotificationSync-qGIQ-3yf.mjs';
16
- import { AcpBackend } from './acpBackend-BZ1MJhQV.mjs';
17
+ import { AcpBackend } from './acpBackend-UaBD4zL3.mjs';
17
18
  import { KNOWN_ACP_AGENTS, KNOWN_CODEX_AGENTS } from './acpAgentConfig-CObOPlA8.mjs';
18
19
  import { c as codexAppServerAvailable, C as CodexAppServerBackend } from './codexAppServerBackend-VGsYtbqg.mjs';
19
20
  import { codexPermissionSettings, codexForcedModel, codexModelMenu, codexClampModel, resolveCodexProvider, codexDefaultModel } from './codexProvider-BtxYc5Rj.mjs';
@@ -22,19 +23,19 @@ import { GeminiTransport } from './GeminiTransport-3OkhtFRO.mjs';
22
23
  import { KimiTransport } from './KimiTransport-D8n009Tr.mjs';
23
24
  import { kimiModelMenu, kimiClampModel, kimiSpawnEnv, kimiDefaultModel } from './kimiProvider-DbxODebR.mjs';
24
25
  import { ensureKimiProviderConfigured } from './kimiSetup-NGsoYB5h.mjs';
25
- import { detectIsolationCapabilities } from './detectIsolation-CzoDCEnh.mjs';
26
+ import { detectIsolationCapabilities } from './detectIsolation-CrV8IFDv.mjs';
26
27
  import { w as wrapWithIsolation } from './wrapCommand-CdNawSaa.mjs';
27
28
  import { applySecurityContext } from './securityContext-Cm5UTCuD.mjs';
28
- import { mkdir, copyFile, writeFile, rm, readdir, stat, readFile, rename } from 'node:fs/promises';
29
+ import { mkdir, copyFile, writeFile, chmod, rm, readdir, stat, readFile, rename } from 'node:fs/promises';
29
30
  import { homedir, platform } from 'node:os';
30
- import { applyClaudeProxyEnv, updateEnvFile } from './claudeAuth-iAerdaMr.mjs';
31
+ import { applyClaudeProxyEnv, probeLongContext1MEntitlement, LONG_CONTEXT_ENTITLEMENT_RECHECK_MS, updateEnvFile } from './claudeAuth-DMDvPNhO.mjs';
31
32
  import { d as decodeTokenExpiry, i as isTokenExpired, c as classifyBootFailure, w as writeBootStatus, a as clearBootStatus, b as isAuthExpiryError, s as shouldRenewToken, T as TOKEN_LIFETIME_SEC, R as RENEW_CHECK_INTERVAL_MS } from './bootStatus-DqtNgJch.mjs';
32
33
  import { e as envFlagEnabled } from './envFlag-COOuJ3AH.mjs';
33
- import { r as resolveEvaluatorModel, c as backlogOraclePending, d as runLoopVerification, l as loopCancelledDuringVerify, e as resolveLoopDurable, f as decideLoopContinuation, g as resolveMaxAutoResumes, h as grantedExtensionCount, i as resolveMaxExtensions, j as resolveStuckLimit, k as decideVerifyErrorHandling, m as resolveVerifyErrorRetries, t as terminalPhaseForDone, n as accumulateLedger, s as sumUsageTokens, o as effectiveSoftCap, p as checkLoopBudget, q as isHardBudgetStop, u as isCostCeiling, v as summarizeExtensions, w as rearmStartedAt, x as oracleScopeSessionId, y as shouldRearmDormantLoop, z as parseDaemonShareEmails, D as DAEMON_SHARE_EMAILS_ENV, A as applyDaemonShareSeed, a as buildMachineShareUrl, B as recordProgressMarker, C as assessLoopProgress, E as resolveExtensionTurns, F as grantLoopExtension, G as buildGoalCondition, H as computeSoftTurnCap, U as UNBOUNDED_LOOP_ITERATIONS } from './loopVerify-B47sSjxe.mjs';
34
- import { p as parseJwtEmail } from './serveAuth-DbVLRCRR.mjs';
34
+ import { r as resolveEvaluatorModel, c as backlogOraclePending, d as runLoopVerification, l as loopCancelledDuringVerify, e as resolveLoopDurable, f as decideLoopContinuation, g as resolveMaxAutoResumes, h as grantedExtensionCount, i as resolveMaxExtensions, j as resolveStuckLimit, k as decideVerifyErrorHandling, m as resolveVerifyErrorRetries, t as terminalPhaseForDone, n as accumulateLedger, s as sumUsageTokens, o as effectiveSoftCap, p as checkLoopBudget, q as isHardBudgetStop, u as isCostCeiling, v as summarizeExtensions, w as rearmStartedAt, x as oracleScopeSessionId, y as shouldRearmDormantLoop, z as parseDaemonShareEmails, D as DAEMON_SHARE_EMAILS_ENV, A as applyDaemonShareSeed, a as buildMachineShareUrl, B as recordProgressMarker, C as assessLoopProgress, E as resolveExtensionTurns, F as grantLoopExtension, G as buildGoalCondition, H as computeSoftTurnCap, U as UNBOUNDED_LOOP_ITERATIONS } from './loopVerify-CxAKJB5a.mjs';
35
+ import { p as parseJwtEmail } from './serveAuth-4M0vwMyj.mjs';
35
36
  import { getSkillsServer, getArtifactBaseUrl } from './api-BHjyC0Ph.mjs';
36
37
  import { l as loadInstanceConfig } from './instance-CeHz5C8v.mjs';
37
- import { l as listIssues, h as addIssue, o as routeCrewVerdict, r as resolveProjectRoot$1 } from './store-Bn0ByYev.mjs';
38
+ import { r as resolveProjectRoot$1, l as listIssues, i as addIssue, q as routeCrewVerdict } from './store-D8dok6_d.mjs';
38
39
  import { c as workflowSteps, d as workflowsDir, l as listWorkflows, i as isWorkflowEnabled } from './store-fi0f-ff1.mjs';
39
40
  import { randomBytes } from 'node:crypto';
40
41
 
@@ -1390,7 +1391,8 @@ async function stageCredentialsForSharing(sessionId) {
1390
1391
  "-w"
1391
1392
  ], { encoding: "utf-8", timeout: 5e3 }).trim();
1392
1393
  if (keychainData.startsWith("{") || keychainData.startsWith("[")) {
1393
- await writeFile(stagedCredFile, keychainData);
1394
+ await writeFile(stagedCredFile, keychainData, { mode: 384 });
1395
+ await chmod(stagedCredFile, 384);
1394
1396
  }
1395
1397
  } catch {
1396
1398
  }
@@ -1550,6 +1552,25 @@ function resolveContainedCwd(directory, cwd, hasSecurityContext) {
1550
1552
  return resolved;
1551
1553
  }
1552
1554
 
1555
+ function getLoopDir(directory, sessionId) {
1556
+ let root = directory;
1557
+ try {
1558
+ root = resolveProjectRoot$1(directory);
1559
+ } catch {
1560
+ }
1561
+ if (sessionId) {
1562
+ const rooted = join(root, ".svamp", sessionId, "loop");
1563
+ if (existsSync(join(rooted, "loop-state.json"))) return rooted;
1564
+ const rawScoped = join(directory, ".svamp", sessionId, "loop");
1565
+ if (existsSync(join(rawScoped, "loop-state.json"))) return rawScoped;
1566
+ for (const legacy of [join(root, ".claude", "loop"), join(directory, ".claude", "loop")]) {
1567
+ if (existsSync(join(legacy, "loop-state.json"))) return legacy;
1568
+ }
1569
+ return rooted;
1570
+ }
1571
+ return join(root, ".claude", "loop");
1572
+ }
1573
+
1553
1574
  const DEFAULT_LOG_PRUNE_POLICY = {
1554
1575
  keepFiles: 10,
1555
1576
  maxAgeDays: 14,
@@ -1682,6 +1703,25 @@ function shortRunId(seed) {
1682
1703
  return (h >>> 0).toString(36).padStart(7, "0").slice(0, 7);
1683
1704
  }
1684
1705
  const RECONCILE_GRACE_MS = 12e4;
1706
+ const reportedWriteErrnos = /* @__PURE__ */ new Set();
1707
+ const RUN_STORE_LOCK_OPTS = (where) => ({
1708
+ deadlineMs: 3e3,
1709
+ breakOnDeadOwner: true,
1710
+ onFailOpen: (lockPath) => reportRunStoreWriteFailure(
1711
+ `${where}/fail-open`,
1712
+ Object.assign(new Error(`lock timeout on ${lockPath} \u2014 wrote UNLOCKED, a concurrent run record may have been lost`), { code: "ELOCKTIMEOUT" })
1713
+ )
1714
+ });
1715
+ function reportRunStoreWriteFailure(where, err) {
1716
+ const code = String(err?.code || err?.name || "UNKNOWN");
1717
+ if (reportedWriteErrnos.has(code)) return;
1718
+ reportedWriteErrnos.add(code);
1719
+ const hint = code === "ENOSPC" ? " \u2014 THE DISK IS FULL. Workflow run records are being DROPPED, and session transcripts are likely failing to persist too. This also mimics a concurrency bug (#0681/#1631)." : code === "EROFS" ? " \u2014 the filesystem is read-only." : code === "EACCES" || code === "EPERM" ? " \u2014 permission denied on the runs directory." : "";
1720
+ console.error(`[workflow] run-store write failed in ${where} (${code})${hint} Further ${code} failures will not be repeated. (#1631)`);
1721
+ }
1722
+ function __resetRunStoreWriteFailureReporting() {
1723
+ reportedWriteErrnos.clear();
1724
+ }
1685
1725
  function recordRun(projectRoot, run) {
1686
1726
  try {
1687
1727
  const dir = runsDir(projectRoot);
@@ -1696,8 +1736,9 @@ function recordRun(projectRoot, run) {
1696
1736
  const tmp = `${file}.tmp-${process.pid}-${randomBytes(4).toString("hex")}`;
1697
1737
  writeFileSync(tmp, kept.map((r) => JSON.stringify(r)).join("\n") + "\n");
1698
1738
  renameSync(tmp, file);
1699
- });
1700
- } catch {
1739
+ }, RUN_STORE_LOCK_OPTS("recordRun"));
1740
+ } catch (err) {
1741
+ reportRunStoreWriteFailure("recordRun", err);
1701
1742
  }
1702
1743
  }
1703
1744
  function loadRuns(projectRoot, workflow) {
@@ -1740,40 +1781,47 @@ function reconcileInterruptedRuns(projectRoot) {
1740
1781
  for (const entry of readdirSync(dir)) {
1741
1782
  if (!entry.endsWith(".jsonl")) continue;
1742
1783
  const file = join(dir, entry);
1743
- let runs;
1784
+ let fixedHere = 0;
1744
1785
  try {
1745
- runs = readFileSync(file, "utf-8").split("\n").filter(Boolean).map((l) => {
1786
+ withFileLock(`${file}.lock`, () => {
1787
+ let runs;
1746
1788
  try {
1747
- return JSON.parse(l);
1789
+ runs = readFileSync(file, "utf-8").split("\n").filter(Boolean).map((l) => {
1790
+ try {
1791
+ return JSON.parse(l);
1792
+ } catch {
1793
+ return null;
1794
+ }
1795
+ }).filter((r) => !!r);
1748
1796
  } catch {
1749
- return null;
1797
+ return;
1750
1798
  }
1751
- }).filter((r) => !!r);
1752
- } catch {
1753
- continue;
1754
- }
1755
- let changed = false;
1756
- for (const r of runs) {
1757
- if (r.status !== "running") continue;
1758
- if (isWorkflowInFlight(projectRoot, r.workflow)) continue;
1759
- if (typeof r.startedAt === "number" && Date.now() - r.startedAt < RECONCILE_GRACE_MS) continue;
1760
- r.status = "failed";
1761
- r.error = r.error || "interrupted by daemon restart";
1762
- r.finishedAt = r.finishedAt || r.startedAt;
1763
- changed = true;
1764
- fixed++;
1765
- }
1766
- if (!changed) continue;
1767
- try {
1768
- withFileLock(`${file}.lock`, () => {
1799
+ let changed = false;
1800
+ for (const r of runs) {
1801
+ if (r.status !== "running") continue;
1802
+ if (isWorkflowInFlight(projectRoot, r.workflow)) continue;
1803
+ const raw = r.startedAt;
1804
+ const startedMs = typeof raw === "number" ? raw : Date.parse(String(raw ?? ""));
1805
+ if (Number.isFinite(startedMs) && Date.now() - startedMs < RECONCILE_GRACE_MS) continue;
1806
+ r.status = "failed";
1807
+ r.error = r.error || "interrupted by daemon restart";
1808
+ r.finishedAt = r.finishedAt || r.startedAt;
1809
+ changed = true;
1810
+ fixedHere++;
1811
+ }
1812
+ if (!changed) return;
1813
+ const kept = runs.slice(-maxRunsPerWorkflow());
1769
1814
  const tmp = `${file}.tmp-${process.pid}-${randomBytes(4).toString("hex")}`;
1770
- writeFileSync(tmp, runs.map((r) => JSON.stringify(r)).join("\n") + "\n");
1815
+ writeFileSync(tmp, kept.map((r) => JSON.stringify(r)).join("\n") + "\n");
1771
1816
  renameSync(tmp, file);
1772
- });
1773
- } catch {
1817
+ }, RUN_STORE_LOCK_OPTS("reconcileInterruptedRuns"));
1818
+ } catch (err) {
1819
+ reportRunStoreWriteFailure("reconcileInterruptedRuns", err);
1774
1820
  }
1821
+ fixed += fixedHere;
1775
1822
  }
1776
- } catch {
1823
+ } catch (err) {
1824
+ reportRunStoreWriteFailure("reconcileInterruptedRuns/outer", err);
1777
1825
  }
1778
1826
  return fixed;
1779
1827
  }
@@ -1960,6 +2008,7 @@ var runStore = /*#__PURE__*/Object.freeze({
1960
2008
  MAX_RUNS_PER_WORKFLOW: MAX_RUNS_PER_WORKFLOW,
1961
2009
  MAX_STREAM_CHARS: MAX_STREAM_CHARS,
1962
2010
  STEP_TIMEOUT_MS: STEP_TIMEOUT_MS,
2011
+ __resetRunStoreWriteFailureReporting: __resetRunStoreWriteFailureReporting,
1963
2012
  capStream: capStream,
1964
2013
  escalateWorkflowFailure: escalateWorkflowFailure,
1965
2014
  getRun: getRun,
@@ -1969,6 +2018,7 @@ var runStore = /*#__PURE__*/Object.freeze({
1969
2018
  maxRunsPerWorkflow: maxRunsPerWorkflow,
1970
2019
  reconcileInterruptedRuns: reconcileInterruptedRuns,
1971
2020
  recordRun: recordRun,
2021
+ reportRunStoreWriteFailure: reportRunStoreWriteFailure,
1972
2022
  runWorkflow: runWorkflow,
1973
2023
  runsDir: runsDir,
1974
2024
  stepTimeoutMs: stepTimeoutMs
@@ -2353,7 +2403,16 @@ function acquireSupervisorLock(pidFile, pid = process.pid) {
2353
2403
  }
2354
2404
  return { acquired: false, staleCleaned: true };
2355
2405
  }
2356
- if (isPidAlive(existingPid)) {
2406
+ const alive = isPidAlive(existingPid);
2407
+ const verdict = classifyLockHolder({
2408
+ pid: existingPid,
2409
+ alive,
2410
+ // Only interrogate a live pid — a dead one is already stale, and `ps` costs a fork.
2411
+ holderStartedMs: alive ? readProcessStartMs(existingPid) : null,
2412
+ lockWrittenMs: getFileWrittenMs(pidFile),
2413
+ bootTimeMs: getBootTimeMs()
2414
+ });
2415
+ if (verdict === "held") {
2357
2416
  return { acquired: false, heldBy: existingPid };
2358
2417
  }
2359
2418
  try {
@@ -2362,6 +2421,62 @@ function acquireSupervisorLock(pidFile, pid = process.pid) {
2362
2421
  }
2363
2422
  return { acquired: false, staleCleaned: true };
2364
2423
  }
2424
+ const RECYCLED_PID_TOLERANCE_MS = 5e3;
2425
+ function classifyLockHolder(opts) {
2426
+ const { pid, alive, holderStartedMs = null, lockWrittenMs = null, bootTimeMs = null } = opts;
2427
+ if (!pid || Number.isNaN(pid) || pid <= 0) return "stale";
2428
+ if (!alive) return "stale";
2429
+ if (bootTimeMs !== null && lockWrittenMs !== null && lockWrittenMs < bootTimeMs) return "stale";
2430
+ if (holderStartedMs !== null && lockWrittenMs !== null && holderStartedMs > lockWrittenMs + RECYCLED_PID_TOLERANCE_MS) {
2431
+ return "stale";
2432
+ }
2433
+ return "held";
2434
+ }
2435
+ function readProcessStartMs(pid) {
2436
+ if (!pid || Number.isNaN(pid) || pid <= 0) return null;
2437
+ if (process.platform === "win32") return null;
2438
+ try {
2439
+ const out = execFileSync("ps", ["-ww", "-o", "lstart=", "-p", String(pid)], {
2440
+ encoding: "utf-8",
2441
+ timeout: 5e3,
2442
+ stdio: ["ignore", "pipe", "ignore"]
2443
+ }).trim();
2444
+ if (!out) return null;
2445
+ const ms = Date.parse(out);
2446
+ return Number.isFinite(ms) ? ms : null;
2447
+ } catch {
2448
+ return null;
2449
+ }
2450
+ }
2451
+ function getFileWrittenMs(file) {
2452
+ try {
2453
+ return statSync(file).mtimeMs;
2454
+ } catch {
2455
+ return null;
2456
+ }
2457
+ }
2458
+ function getBootTimeMs() {
2459
+ if (process.platform === "win32") return null;
2460
+ try {
2461
+ if (process.platform === "linux") {
2462
+ const uptimeSec = parseFloat(readFileSync("/proc/uptime", "utf-8").trim().split(/\s+/)[0]);
2463
+ if (!Number.isFinite(uptimeSec) || uptimeSec < 0) return null;
2464
+ return Date.now() - uptimeSec * 1e3;
2465
+ }
2466
+ const out = execFileSync("sysctl", ["-n", "kern.boottime"], {
2467
+ encoding: "utf-8",
2468
+ timeout: 5e3,
2469
+ stdio: ["ignore", "pipe", "ignore"]
2470
+ });
2471
+ const m = out.match(/sec\s*=\s*(\d+)/);
2472
+ if (!m) return null;
2473
+ const sec = parseInt(m[1], 10);
2474
+ if (!Number.isFinite(sec) || sec <= 0) return null;
2475
+ return sec * 1e3;
2476
+ } catch {
2477
+ return null;
2478
+ }
2479
+ }
2365
2480
  function acquireSupervisorLockWithRetry(pidFile, pid = process.pid) {
2366
2481
  let result = acquireSupervisorLock(pidFile, pid);
2367
2482
  if (!result.acquired && result.staleCleaned) {
@@ -2390,7 +2505,7 @@ function isSupervisorPid(pid) {
2390
2505
  if (!pid || Number.isNaN(pid) || pid <= 0) return false;
2391
2506
  if (process.platform === "win32") return null;
2392
2507
  try {
2393
- const out = execFileSync("ps", ["-o", "command=", "-p", String(pid)], {
2508
+ const out = execFileSync("ps", ["-ww", "-o", "command=", "-p", String(pid)], {
2394
2509
  encoding: "utf-8",
2395
2510
  timeout: 5e3,
2396
2511
  stdio: ["ignore", "pipe", "ignore"]
@@ -2510,11 +2625,15 @@ var supervisorLock = /*#__PURE__*/Object.freeze({
2510
2625
  __proto__: null,
2511
2626
  acquireSupervisorLock: acquireSupervisorLock,
2512
2627
  acquireSupervisorLockWithRetry: acquireSupervisorLockWithRetry,
2628
+ classifyLockHolder: classifyLockHolder,
2513
2629
  findOrphanedSyncPids: findOrphanedSyncPids,
2630
+ getBootTimeMs: getBootTimeMs,
2631
+ getFileWrittenMs: getFileWrittenMs,
2514
2632
  getPpid: getPpid,
2515
2633
  isPidAlive: isPidAlive,
2516
2634
  isSupervisorPid: isSupervisorPid,
2517
2635
  killOrphanedSyncs: killOrphanedSyncs,
2636
+ readProcessStartMs: readProcessStartMs,
2518
2637
  releaseSupervisorLock: releaseSupervisorLock,
2519
2638
  shouldSignalSupervisor: shouldSignalSupervisor,
2520
2639
  watchParentLiveness: watchParentLiveness
@@ -3119,16 +3238,6 @@ function writeSvampConfig(configPath, config) {
3119
3238
  }
3120
3239
  const DEFAULT_LOOP_MAX_ITERATIONS = UNBOUNDED_LOOP_ITERATIONS;
3121
3240
  const LOOP_CHECKPOINT_CADENCE = 25;
3122
- function getLoopDir(directory, sessionId) {
3123
- if (sessionId) {
3124
- const scoped = join$1(directory, ".svamp", sessionId, "loop");
3125
- if (existsSync$1(join$1(scoped, "loop-state.json"))) return scoped;
3126
- const legacy = join$1(directory, ".claude", "loop");
3127
- if (existsSync$1(join$1(legacy, "loop-state.json"))) return legacy;
3128
- return scoped;
3129
- }
3130
- return join$1(directory, ".claude", "loop");
3131
- }
3132
3241
  function readLoopState(directory, sessionId) {
3133
3242
  try {
3134
3243
  const p = join$1(getLoopDir(directory, sessionId), "loop-state.json");
@@ -4237,7 +4346,11 @@ async function startDaemon(options) {
4237
4346
  function saveExposedTunnels(specs) {
4238
4347
  try {
4239
4348
  mkdirSync$1(SVAMP_HOME, { recursive: true });
4240
- writeFileSync$1(EXPOSED_TUNNELS_FILE, JSON.stringify({ tunnels: specs }, null, 2));
4349
+ writeFileSync$1(EXPOSED_TUNNELS_FILE, JSON.stringify({ tunnels: specs }, null, 2), { mode: 384 });
4350
+ try {
4351
+ chmodSync(EXPOSED_TUNNELS_FILE, 384);
4352
+ } catch {
4353
+ }
4241
4354
  } catch (err) {
4242
4355
  logger.log(`[exposed-tunnels] Persist failed: ${err.message}`);
4243
4356
  }
@@ -4256,7 +4369,7 @@ async function startDaemon(options) {
4256
4369
  try {
4257
4370
  const dir = loadSessionIndex()[sessionId]?.directory;
4258
4371
  if (!dir) return;
4259
- const { reconcileServiceLinks } = await import('./agentCommands-B2Nl7Fof.mjs');
4372
+ const { reconcileServiceLinks } = await import('./agentCommands-C_KvvYFp.mjs');
4260
4373
  const configPath = getSvampConfigPath(dir, sessionId);
4261
4374
  const config = readSvampConfig(configPath);
4262
4375
  const entries = Array.from(urls.entries());
@@ -4278,7 +4391,7 @@ async function startDaemon(options) {
4278
4391
  try {
4279
4392
  const dir = loadSessionIndex()[sessionId]?.directory;
4280
4393
  if (!dir) return;
4281
- const { reconcileServiceLinks } = await import('./agentCommands-B2Nl7Fof.mjs');
4394
+ const { reconcileServiceLinks } = await import('./agentCommands-C_KvvYFp.mjs');
4282
4395
  const configPath = getSvampConfigPath(dir, sessionId);
4283
4396
  const config = readSvampConfig(configPath);
4284
4397
  const incoming = [{
@@ -4299,7 +4412,7 @@ async function startDaemon(options) {
4299
4412
  try {
4300
4413
  const dir = loadSessionIndex()[sessionId]?.directory;
4301
4414
  if (!dir) return;
4302
- const { dropServiceLinks } = await import('./agentCommands-B2Nl7Fof.mjs');
4415
+ const { dropServiceLinks } = await import('./agentCommands-C_KvvYFp.mjs');
4303
4416
  const configPath = getSvampConfigPath(dir, sessionId);
4304
4417
  const config = readSvampConfig(configPath);
4305
4418
  if (dropServiceLinks(config, "serve", mountName)) {
@@ -4315,7 +4428,7 @@ async function startDaemon(options) {
4315
4428
  try {
4316
4429
  const dir = loadSessionIndex()[sessionId]?.directory;
4317
4430
  if (!dir) return;
4318
- const { dropServiceLinks } = await import('./agentCommands-B2Nl7Fof.mjs');
4431
+ const { dropServiceLinks } = await import('./agentCommands-C_KvvYFp.mjs');
4319
4432
  const configPath = getSvampConfigPath(dir, sessionId);
4320
4433
  const config = readSvampConfig(configPath);
4321
4434
  if (dropServiceLinks(config, "tunnel", tunnelName)) {
@@ -4332,7 +4445,7 @@ async function startDaemon(options) {
4332
4445
  let managedLinkSessionsSeeded = false;
4333
4446
  async function reconcileAllServiceLinks() {
4334
4447
  try {
4335
- const { reconcileServiceLinksExact, hasManagedServiceLink } = await import('./agentCommands-B2Nl7Fof.mjs');
4448
+ const { reconcileServiceLinksExact, hasManagedServiceLink } = await import('./agentCommands-C_KvvYFp.mjs');
4336
4449
  const desiredBySession = /* @__PURE__ */ new Map();
4337
4450
  const push = (sessionId, entry) => {
4338
4451
  if (!sessionId || !entry.url) return;
@@ -4406,7 +4519,7 @@ async function startDaemon(options) {
4406
4519
  }, delayMs);
4407
4520
  }
4408
4521
  async function createExposedTunnel(spec) {
4409
- const { FrpcTunnel } = await import('./hookSettings-DYMTUgVA.mjs').then(function (n) { return n.w; });
4522
+ const { FrpcTunnel } = await import('./hookSettings-CvvUhwCK.mjs').then(function (n) { return n.w; });
4410
4523
  const tunnel = new FrpcTunnel({
4411
4524
  name: spec.name,
4412
4525
  ports: spec.ports,
@@ -4427,7 +4540,7 @@ async function startDaemon(options) {
4427
4540
  }
4428
4541
  const tunnelRecreateState = /* @__PURE__ */ new Map();
4429
4542
  const tunnelRecreateInFlight = /* @__PURE__ */ new Set();
4430
- const { ServeManager } = await import('./hookSettings-DYMTUgVA.mjs').then(function (n) { return n.y; });
4543
+ const { ServeManager } = await import('./hookSettings-CvvUhwCK.mjs').then(function (n) { return n.y; });
4431
4544
  const serveManager = new ServeManager(SVAMP_HOME, (msg) => logger.log(`[SERVE] ${msg}`), hyphaServerUrl);
4432
4545
  serveManager.setMountUnboundHook((sessionId, mountName) => {
4433
4546
  void dropMountSessionLink(sessionId, mountName);
@@ -5354,21 +5467,34 @@ ${parts.join("\n")}`);
5354
5467
  } catch (e) {
5355
5468
  logger.log(`[Session ${sessionId}] verifyGoalCompletion threw \u2014 failing closed (retry/park): ${e?.message || e}`);
5356
5469
  try {
5470
+ const curLsErr = readLoopState(directory, sessionId);
5471
+ if (loopCancelledDuringVerify(curLsErr)) {
5472
+ logger.log(`[Session ${sessionId}] loop was cancelled during a FAILED verification \u2014 not re-kicking (#0308/#1542)`);
5473
+ return;
5474
+ }
5475
+ const freshErr = curLsErr || ls;
5476
+ const carry = {
5477
+ ledger: freshErr.ledger ?? ls.ledger,
5478
+ progress_history: freshErr.progress_history ?? ls.progress_history,
5479
+ extensions: freshErr.extensions ?? ls.extensions,
5480
+ auto_resumes: freshErr.auto_resumes ?? ls.auto_resumes,
5481
+ holds: freshErr.holds ?? ls.holds
5482
+ };
5357
5483
  const durable2 = resolveLoopDurable({ durable: ls.durable, oracle: oracleCmd });
5358
5484
  const decision = decideVerifyErrorHandling({
5359
- priorErrors: ls.verify_errors,
5485
+ priorErrors: freshErr.verify_errors ?? ls.verify_errors,
5360
5486
  maxRetries: resolveVerifyErrorRetries(process.env.SVAMP_LOOP_VERIFY_ERROR_RETRIES),
5361
5487
  reason: `verify threw: ${e?.message || e}`
5362
5488
  });
5363
5489
  if (decision.action === "retry") {
5364
5490
  const cond = ls.task || "";
5365
- writeGoalLoopState(directory, sessionId, { ...ls, active: true, phase: "continue", started_at: startedAt, verify_errors: decision.attempt });
5491
+ writeGoalLoopState(directory, sessionId, { ...ls, ...carry, active: true, phase: "continue", started_at: startedAt, verify_errors: decision.attempt });
5366
5492
  sessionService.pushMessage({ type: "message", message: `\u26A0\uFE0F Loop verification error \u2014 ${decision.reason}`, level: "warning" }, "event");
5367
5493
  enqueueLoopMessage(`/goal ${cond} \u2014 the completion check could not run; CONTINUE and it will be re-verified. Not done.`, "\u26A0\uFE0F Re-verifying loop");
5368
5494
  if (!trackedSession.stopped) setTimeout(() => processMessageQueueRef?.(), 200);
5369
5495
  } else {
5370
5496
  const parkPhase = terminalPhaseForDone(durable2);
5371
- writeGoalLoopState(directory, sessionId, { ...ls, active: parkPhase === "dormant", phase: parkPhase, completed_at: Date.now(), verify_errors: 0 });
5497
+ writeGoalLoopState(directory, sessionId, { ...ls, ...carry, active: parkPhase === "dormant", phase: parkPhase, completed_at: Date.now(), verify_errors: 0 });
5372
5498
  checkSvampConfig?.();
5373
5499
  }
5374
5500
  } catch {
@@ -5851,7 +5977,7 @@ ${parts.join("\n")}`);
5851
5977
  const hasBackgroundTasks = backgroundTaskCount > 0;
5852
5978
  if (hasBackgroundTasks) {
5853
5979
  const taskInfo = `Background tasks still running (${backgroundTaskCount}): ${backgroundTaskNames.join(", ")}`;
5854
- sessionService.pushMessage({ type: "session_event", message: taskInfo }, "session");
5980
+ sessionService.pushMessage({ type: "message", message: taskInfo, level: "warning" }, "event");
5855
5981
  }
5856
5982
  signalProcessing(false);
5857
5983
  sessionWasProcessing = false;
@@ -5974,7 +6100,7 @@ ${parts.join("\n")}`);
5974
6100
  if (backgroundTaskCount > 0) {
5975
6101
  const taskInfo = `Background tasks still running (${backgroundTaskCount}): ${backgroundTaskNames.join(", ")}`;
5976
6102
  logger.log(`[Session ${sessionId}] ${taskInfo}`);
5977
- sessionService.pushMessage({ type: "session_event", message: taskInfo }, "session");
6103
+ sessionService.pushMessage({ type: "message", message: taskInfo, level: "warning" }, "event");
5978
6104
  }
5979
6105
  justCompactedTurn = false;
5980
6106
  compactTurnLatch = false;
@@ -6889,12 +7015,12 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
6889
7015
  });
6890
7016
  },
6891
7017
  onIssue: async (params) => {
6892
- const { issueRpc } = await import('./rpc-Cf0grcru.mjs');
7018
+ const { issueRpc } = await import('./rpc-CAlAHQAy.mjs');
6893
7019
  const issueCwd = resolveContainedCwd(directory, params?.cwd, !!sessionMetadata.securityContext);
6894
7020
  return issueRpc(issueCwd, params || {}, { notifySession: notifyIssueOwner, rekickLoopOwner });
6895
7021
  },
6896
7022
  onWorkflow: async (params) => {
6897
- const { workflowRpc } = await import('./rpc-BB6RF4-F.mjs');
7023
+ const { workflowRpc } = await import('./rpc-CacreLQ8.mjs');
6898
7024
  const wfCwd = resolveContainedCwd(directory, params?.cwd, !!sessionMetadata.securityContext);
6899
7025
  return workflowRpc(wfCwd, params || {});
6900
7026
  },
@@ -7646,12 +7772,12 @@ ${capturedError}${buildClaudeErrorHint(capturedError)}`;
7646
7772
  });
7647
7773
  },
7648
7774
  onIssue: async (params) => {
7649
- const { issueRpc } = await import('./rpc-Cf0grcru.mjs');
7775
+ const { issueRpc } = await import('./rpc-CAlAHQAy.mjs');
7650
7776
  const issueCwd = resolveContainedCwd(directory, params?.cwd, !!sessionMetadata.securityContext);
7651
7777
  return issueRpc(issueCwd, params || {}, { notifySession: notifyIssueOwner, rekickLoopOwner });
7652
7778
  },
7653
7779
  onWorkflow: async (params) => {
7654
- const { workflowRpc } = await import('./rpc-BB6RF4-F.mjs');
7780
+ const { workflowRpc } = await import('./rpc-CacreLQ8.mjs');
7655
7781
  const wfCwd = resolveContainedCwd(directory, params?.cwd, !!sessionMetadata.securityContext);
7656
7782
  return workflowRpc(wfCwd, params || {});
7657
7783
  },
@@ -8391,6 +8517,24 @@ ${oracle.output.trim().slice(0, 500)}`, "\u{1F501} Continuing loop");
8391
8517
  }
8392
8518
  return { success: false, message: `Session ${sessionId} not found or already stopped.` };
8393
8519
  };
8520
+ {
8521
+ let lastEntitlementState;
8522
+ const runEntitlementProbe = (first) => {
8523
+ const env = {};
8524
+ applyClaudeProxyEnv(env);
8525
+ void probeLongContext1MEntitlement(env.ANTHROPIC_BASE_URL, env.ANTHROPIC_API_KEY).then((state) => {
8526
+ if (!first && state === lastEntitlementState) return;
8527
+ lastEntitlementState = state;
8528
+ if (state === "entitled") logger.log("[1m-context] entitlement confirmed \u2014 sessions will request the 1M window");
8529
+ else if (state === "not-entitled") logger.log("[1m-context] NOT entitled for this account \u2014 NOT requesting the 1M beta (sessions compact at the 200K window). See #1585.");
8530
+ else logger.log("[1m-context] entitlement could not be determined \u2014 NOT requesting the 1M beta (safe default). See #1585.");
8531
+ }).catch(() => {
8532
+ });
8533
+ };
8534
+ runEntitlementProbe(true);
8535
+ const entitlementTimer = setInterval(() => runEntitlementProbe(false), LONG_CONTEXT_ENTITLEMENT_RECHECK_MS);
8536
+ if (typeof entitlementTimer.unref === "function") entitlementTimer.unref();
8537
+ }
8394
8538
  let isolationCapabilities;
8395
8539
  try {
8396
8540
  isolationCapabilities = await detectIsolationCapabilities();
@@ -9007,13 +9151,18 @@ ${oracle.output.trim().slice(0, 500)}`, "\u{1F501} Continuing loop");
9007
9151
  const PING_TIMEOUT_MS = 15e3;
9008
9152
  const POST_RECONNECT_GRACE_MS = 2e4;
9009
9153
  const RECONNECT_JITTER_MS = 2500;
9010
- const { WorkflowScheduler } = await import('./scheduler-BY30ZrB9.mjs');
9154
+ const { WorkflowScheduler } = await import('./scheduler-IyLWBF8T.mjs');
9011
9155
  const workflowProjectRoots = () => {
9012
- const dirs = /* @__PURE__ */ new Set();
9156
+ const roots = /* @__PURE__ */ new Set();
9013
9157
  for (const s of pidToTrackedSession.values()) {
9014
- if (!s.stopped && s.directory) dirs.add(s.directory);
9158
+ if (s.stopped || !s.directory) continue;
9159
+ try {
9160
+ roots.add(resolveProjectRoot$1(s.directory));
9161
+ } catch {
9162
+ roots.add(s.directory);
9163
+ }
9015
9164
  }
9016
- return [...dirs];
9165
+ return [...roots];
9017
9166
  };
9018
9167
  try {
9019
9168
  const { reconcileInterruptedRuns } = await Promise.resolve().then(function () { return runStore; });
@@ -9692,4 +9841,4 @@ var run = /*#__PURE__*/Object.freeze({
9692
9841
  writeStopMarker: writeStopMarker
9693
9842
  });
9694
9843
 
9695
- export { stopDaemon as a, stopMarkerExists as b, clearStopMarker as c, daemonStatus as d, runStore as e, supervisorLock as f, getRun as g, run as h, listRuns as l, projectInfo as p, runWorkflow as r, startDaemon as s };
9844
+ export { stopDaemon as a, stopMarkerExists as b, clearStopMarker as c, daemonStatus as d, loadRuns as e, runStore as f, getRun as g, supervisorLock as h, run as i, listRuns as l, projectInfo as p, runWorkflow as r, startDaemon as s };