@hasna/loops 0.4.8 → 0.4.9

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.
@@ -581,7 +581,7 @@ import { isAbsolute, resolve } from "path";
581
581
 
582
582
  // src/lib/agent-adapter.ts
583
583
  import { spawn } from "child_process";
584
- var UNSAFE_CODEWITH_DURABLE_EXTRA_ARGS = new Set([
584
+ var UNSAFE_CODEWITH_EXEC_EXTRA_ARGS = new Set([
585
585
  "e",
586
586
  "exec",
587
587
  "agent",
@@ -630,12 +630,12 @@ function validateAgentOptions(target, label, capabilities) {
630
630
  throw new Error(`${label}.agent is not supported for provider codex`);
631
631
  }
632
632
  if (provider === "codewith" && target.agent !== undefined) {
633
- throw new Error(`${label}.agent is not supported for provider codewith durable background-agent execution`);
633
+ throw new Error(`${label}.agent is not supported for provider codewith`);
634
634
  }
635
635
  if (provider === "codewith") {
636
- const unsafe = target.extraArgs?.find((arg) => UNSAFE_CODEWITH_DURABLE_EXTRA_ARGS.has(arg));
636
+ const unsafe = target.extraArgs?.find((arg) => UNSAFE_CODEWITH_EXEC_EXTRA_ARGS.has(arg));
637
637
  if (unsafe) {
638
- throw new Error(`${label}.extraArgs cannot include ${unsafe}; codewith agent steps use durable agent start, not exec/ephemeral flags`);
638
+ throw new Error(`${label}.extraArgs cannot include ${unsafe}; codewith exec launch flags are managed by the adapter`);
639
639
  }
640
640
  }
641
641
  if (target.addDirs?.length && !["codewith", "codex"].includes(provider)) {
@@ -718,7 +718,10 @@ function buildAgentInvocation(target) {
718
718
  args.push(...target.authProfile ? ["--auth-profile", target.authProfile] : []);
719
719
  if (target.variant)
720
720
  args.push("-c", `model_reasoning_effort=${configStringValue(target.variant)}`);
721
- args.push("--ask-for-approval", "never", "--sandbox", codewithLikeSandbox(target));
721
+ const sandbox = codewithLikeSandbox(target);
722
+ if (sandbox === "workspace-write")
723
+ args.push("-c", "sandbox_workspace_write.network_access=true");
724
+ args.push("--ask-for-approval", "never", "exec", "--json", "--ephemeral", "--sandbox", sandbox, "--skip-git-repo-check");
722
725
  if (target.cwd)
723
726
  args.push("--cd", target.cwd);
724
727
  for (const dir of target.addDirs ?? [])
@@ -726,11 +729,7 @@ function buildAgentInvocation(target) {
726
729
  if (target.model)
727
730
  args.push("--model", target.model);
728
731
  args.push(...target.extraArgs ?? []);
729
- args.push("agent", "start", "--json");
730
- if (target.cwd)
731
- args.push("--cwd", target.cwd);
732
- args.push(target.prompt);
733
- return { command: "codewith", args };
732
+ return { command: "codewith", args, stdin: target.prompt };
734
733
  }
735
734
  case "codex": {
736
735
  if (target.variant)
@@ -783,7 +782,7 @@ function adapterFor(provider, capabilities) {
783
782
  var PROVIDER_ADAPTERS = {
784
783
  claude: adapterFor("claude", { sandbox: [], durable: false, remote: true, promptChannel: "stdin" }),
785
784
  cursor: adapterFor("cursor", { sandbox: CURSOR_SANDBOXES, durable: false, remote: true, promptChannel: "stdin" }),
786
- codewith: adapterFor("codewith", { sandbox: CODEX_LIKE_SANDBOXES, durable: true, remote: false, promptChannel: "argv" }),
785
+ codewith: adapterFor("codewith", { sandbox: CODEX_LIKE_SANDBOXES, durable: false, remote: true, promptChannel: "stdin" }),
787
786
  codex: adapterFor("codex", { sandbox: CODEX_LIKE_SANDBOXES, durable: false, remote: true, promptChannel: "stdin" }),
788
787
  aicopilot: adapterFor("aicopilot", { sandbox: [], durable: false, remote: true, promptChannel: "stdin" }),
789
788
  opencode: adapterFor("opencode", { sandbox: [], durable: false, remote: true, promptChannel: "stdin" })
@@ -5063,11 +5062,6 @@ var TRANSPORT_ENV_KEYS = new Set([
5063
5062
  "USER",
5064
5063
  "XDG_RUNTIME_DIR"
5065
5064
  ]);
5066
- function boundedText(text, maxBytes) {
5067
- const buffer = new BoundedOutputBuffer(maxBytes);
5068
- buffer.append(text);
5069
- return buffer.value();
5070
- }
5071
5065
  function buildResult(status, startedAt, fields = {}) {
5072
5066
  const finishedAt = fields.finishedAt ?? nowIso();
5073
5067
  return {
@@ -5131,21 +5125,6 @@ function metadataEnv(metadata) {
5131
5125
  env.LOOPS_GOAL_NODE_KEY = metadata.goalNodeKey;
5132
5126
  return env;
5133
5127
  }
5134
- function codewithAgentIdempotencyKey(metadata) {
5135
- const parts = [
5136
- "openloops",
5137
- metadata.workflowRunId ? `workflow-run:${metadata.workflowRunId}` : undefined,
5138
- metadata.workflowStepId ? `step:${metadata.workflowStepId}` : undefined,
5139
- metadata.runId ? `loop-run:${metadata.runId}` : undefined,
5140
- metadata.loopId ? `loop:${metadata.loopId}` : undefined,
5141
- metadata.scheduledFor ? `scheduled:${metadata.scheduledFor}` : undefined,
5142
- metadata.goalId ? `goal:${metadata.goalId}` : undefined,
5143
- metadata.goalNodeKey ? `node:${metadata.goalNodeKey}` : undefined
5144
- ].filter(Boolean);
5145
- if (parts.length > 1)
5146
- return parts.join(":");
5147
- return `openloops:adhoc:${randomBytes2(16).toString("hex")}`;
5148
- }
5149
5128
  function allowlistEnv(allowlist) {
5150
5129
  const env = {};
5151
5130
  if (allowlist?.tools?.length)
@@ -5200,8 +5179,7 @@ function commandSpec(target, opts) {
5200
5179
  preflightAnyOf: invocation.preflightAnyOf,
5201
5180
  stdin: invocation.stdin,
5202
5181
  allowlist: agentTarget.allowlist,
5203
- worktree: agentTarget.worktree,
5204
- codewithDurableAgent: adapter.capabilities.durable ? { target: agentTarget } : undefined
5182
+ worktree: agentTarget.worktree
5205
5183
  };
5206
5184
  }
5207
5185
  function composeExecutionEnv(spec, metadata, opts, accountEnv) {
@@ -5411,266 +5389,6 @@ async function preflightNativeAuthProfile(spec, env) {
5411
5389
  const result = await spawnCapture(spec.command, ["profile", "list"], { env, timeoutMs: 15000 });
5412
5390
  assertCodewithProfileListed(spec.nativeAuthProfile.profile, result);
5413
5391
  }
5414
- function codewithAgentStartArgs(target, idempotencyKey) {
5415
- const args = providerAdapter(target.provider).buildInvocation(target).args;
5416
- const startIndex = args.findIndex((arg, index) => arg === "start" && args[index - 1] === "agent");
5417
- if (startIndex === -1)
5418
- throw new Error("internal error: codewith durable agent args missing agent start");
5419
- args.splice(startIndex + 1, 0, "--idempotency-key", idempotencyKey);
5420
- return args;
5421
- }
5422
- function codewithAgentControlArgs(target, command, agentId) {
5423
- return [
5424
- ...target.authProfile ? ["--auth-profile", target.authProfile] : [],
5425
- "agent",
5426
- command,
5427
- ...command === "logs" ? ["--limit", "20"] : [],
5428
- "--json",
5429
- agentId
5430
- ];
5431
- }
5432
- function extractFirstJsonObject(text) {
5433
- let depth = 0;
5434
- let start = -1;
5435
- let inString = false;
5436
- let escaped = false;
5437
- for (let i = 0;i < text.length; i += 1) {
5438
- const ch = text[i];
5439
- if (inString) {
5440
- if (escaped)
5441
- escaped = false;
5442
- else if (ch === "\\")
5443
- escaped = true;
5444
- else if (ch === '"')
5445
- inString = false;
5446
- continue;
5447
- }
5448
- if (ch === '"') {
5449
- inString = true;
5450
- } else if (ch === "{") {
5451
- if (depth === 0)
5452
- start = i;
5453
- depth += 1;
5454
- } else if (ch === "}") {
5455
- if (depth > 0) {
5456
- depth -= 1;
5457
- if (depth === 0 && start !== -1)
5458
- return text.slice(start, i + 1);
5459
- }
5460
- }
5461
- }
5462
- return;
5463
- }
5464
- function parseJsonOutput(stdout, label) {
5465
- const raw = stdout || "{}";
5466
- const candidates = [raw.trim()];
5467
- const scanned = extractFirstJsonObject(raw);
5468
- if (scanned && scanned !== raw.trim())
5469
- candidates.push(scanned);
5470
- let lastError;
5471
- for (const candidate of candidates) {
5472
- try {
5473
- const value = JSON.parse(candidate);
5474
- if (!value || typeof value !== "object" || Array.isArray(value))
5475
- throw new Error("not an object");
5476
- return value;
5477
- } catch (error) {
5478
- lastError = error;
5479
- }
5480
- }
5481
- throw new Error(`${label} did not return JSON${lastError instanceof Error ? `: ${lastError.message}` : ""}`);
5482
- }
5483
- function recordField(value, key) {
5484
- if (!value || typeof value !== "object" || Array.isArray(value))
5485
- return;
5486
- const field = value[key];
5487
- return field && typeof field === "object" && !Array.isArray(field) ? field : undefined;
5488
- }
5489
- function stringField(value, key) {
5490
- const field = value?.[key];
5491
- return typeof field === "string" ? field : undefined;
5492
- }
5493
- function numberField(value, key) {
5494
- const field = value?.[key];
5495
- return typeof field === "number" && Number.isFinite(field) ? field : undefined;
5496
- }
5497
- function codewithAgentStatus(readJson) {
5498
- return stringField(recordField(readJson, "agent"), "status") ?? stringField(recordField(readJson, "statusSnapshot"), "status");
5499
- }
5500
- function codewithAgentLastEventSeq(readJson) {
5501
- const agentSeq = numberField(recordField(readJson, "agent"), "lastEventSeq");
5502
- const snapshotSeq = numberField(recordField(readJson, "statusSnapshot"), "lastEventSeq");
5503
- if (agentSeq !== undefined && snapshotSeq !== undefined)
5504
- return Math.max(agentSeq, snapshotSeq);
5505
- return agentSeq ?? snapshotSeq;
5506
- }
5507
- function codewithAgentEvidence(startJson, readJson, logsJson) {
5508
- const agent = recordField(readJson, "agent") ?? recordField(startJson, "agent");
5509
- const statusSnapshot = recordField(readJson, "statusSnapshot");
5510
- const events = Array.isArray(logsJson?.data) ? logsJson.data.filter((event) => Boolean(event) && typeof event === "object" && !Array.isArray(event)).map((event) => ({
5511
- seq: numberField(event, "seq"),
5512
- eventType: stringField(event, "eventType"),
5513
- createdAt: numberField(event, "createdAt")
5514
- })) : undefined;
5515
- return JSON.stringify({
5516
- codewithAgent: {
5517
- agentId: stringField(agent, "agentId"),
5518
- status: stringField(agent, "status"),
5519
- desiredState: stringField(agent, "desiredState"),
5520
- statusReason: stringField(agent, "statusReason"),
5521
- threadId: stringField(agent, "threadId"),
5522
- rolloutPath: stringField(agent, "rolloutPath"),
5523
- pid: numberField(agent, "pid"),
5524
- exitCode: numberField(agent, "exitCode"),
5525
- created: typeof startJson.created === "boolean" ? startJson.created : undefined
5526
- },
5527
- statusSnapshot: statusSnapshot ? {
5528
- seq: numberField(statusSnapshot, "seq"),
5529
- status: stringField(statusSnapshot, "status"),
5530
- summary: stringField(statusSnapshot, "summary"),
5531
- pendingInteractionCount: numberField(statusSnapshot, "pendingInteractionCount"),
5532
- lastEventSeq: numberField(statusSnapshot, "lastEventSeq")
5533
- } : undefined,
5534
- events
5535
- }, null, 2);
5536
- }
5537
- function codewithAgentProgress(readJson) {
5538
- const agent = recordField(readJson, "agent");
5539
- const statusSnapshot = recordField(readJson, "statusSnapshot");
5540
- return {
5541
- provider: "codewith",
5542
- agentId: stringField(agent, "agentId"),
5543
- status: stringField(agent, "status") ?? stringField(statusSnapshot, "status"),
5544
- summary: stringField(statusSnapshot, "summary"),
5545
- statusReason: stringField(agent, "statusReason"),
5546
- threadId: stringField(agent, "threadId"),
5547
- rolloutPath: stringField(agent, "rolloutPath"),
5548
- pid: numberField(agent, "pid"),
5549
- lastEventSeq: codewithAgentLastEventSeq(readJson)
5550
- };
5551
- }
5552
- function sleep(ms) {
5553
- return new Promise((resolve3) => setTimeout(resolve3, ms));
5554
- }
5555
- async function executeCodewithDurableAgent(spec, metadata, opts, env, startedAt) {
5556
- const target = spec.codewithDurableAgent?.target;
5557
- if (!target)
5558
- throw new Error("internal error: missing codewith durable target");
5559
- const maxOutputBytes = opts.maxOutputBytes ?? DEFAULT_MAX_OUTPUT_BYTES;
5560
- const idempotencyKey = codewithAgentIdempotencyKey(metadata);
5561
- const start = await spawnCapture(spec.command, codewithAgentStartArgs(target, idempotencyKey), {
5562
- cwd: spec.cwd,
5563
- env,
5564
- timeoutMs: 30000,
5565
- maxOutputBytes
5566
- });
5567
- const stderr = new BoundedOutputBuffer(maxOutputBytes);
5568
- stderr.append(start.stderr);
5569
- if (start.error || (start.status ?? 1) !== 0) {
5570
- return failureResult(startedAt, start.error ?? `codewith agent start exited with code ${start.status ?? "unknown"}`, {
5571
- exitCode: start.status ?? undefined,
5572
- stdout: start.stdout,
5573
- stderr: stderr.value()
5574
- });
5575
- }
5576
- let startJson;
5577
- try {
5578
- startJson = parseJsonOutput(start.stdout || "{}", "codewith agent start");
5579
- } catch (error) {
5580
- return failureResult(startedAt, error instanceof Error ? error.message : String(error), { stdout: start.stdout, stderr: stderr.value() });
5581
- }
5582
- const agentId = stringField(recordField(startJson, "agent"), "agentId");
5583
- if (!agentId) {
5584
- return failureResult(startedAt, "codewith agent start did not return agent.agentId", { stdout: start.stdout, stderr: stderr.value() });
5585
- }
5586
- opts.onAgentProgress?.(codewithAgentProgress(startJson));
5587
- const stopAgent = async () => {
5588
- await spawnCapture(spec.command, codewithAgentControlArgs(target, "stop", agentId), {
5589
- cwd: spec.cwd,
5590
- env,
5591
- timeoutMs: 15000,
5592
- maxOutputBytes
5593
- });
5594
- };
5595
- const pollMs = Math.max(100, Number(opts.env?.LOOPS_CODEWITH_AGENT_POLL_MS ?? process.env.LOOPS_CODEWITH_AGENT_POLL_MS ?? 2000) || 2000);
5596
- let lastReadJson = startJson;
5597
- let lastLogsJson;
5598
- let lastFingerprint;
5599
- let lastProgressAt = Date.now();
5600
- const evidence = () => boundedText(codewithAgentEvidence(startJson, lastReadJson, lastLogsJson), maxOutputBytes);
5601
- while (true) {
5602
- if (opts.signal?.aborted) {
5603
- await stopAgent();
5604
- return failureResult(startedAt, "cancelled", { stdout: evidence(), stderr: stderr.value() });
5605
- }
5606
- const read = await spawnCapture(spec.command, codewithAgentControlArgs(target, "read", agentId), {
5607
- cwd: spec.cwd,
5608
- env,
5609
- timeoutMs: 30000,
5610
- maxOutputBytes
5611
- });
5612
- stderr.append(read.stderr);
5613
- if (read.error || (read.status ?? 1) !== 0) {
5614
- return failureResult(startedAt, read.error ?? `codewith agent read exited with code ${read.status ?? "unknown"}`, {
5615
- exitCode: read.status ?? undefined,
5616
- stdout: evidence(),
5617
- stderr: stderr.value()
5618
- });
5619
- }
5620
- try {
5621
- lastReadJson = parseJsonOutput(read.stdout || "{}", "codewith agent read");
5622
- } catch (error) {
5623
- return failureResult(startedAt, error instanceof Error ? error.message : String(error), {
5624
- stdout: boundedText(read.stdout, maxOutputBytes),
5625
- stderr: stderr.value()
5626
- });
5627
- }
5628
- const status = codewithAgentStatus(lastReadJson);
5629
- const fingerprint = JSON.stringify({
5630
- status,
5631
- agentLastEventSeq: numberField(recordField(lastReadJson, "agent"), "lastEventSeq"),
5632
- snapshot: recordField(lastReadJson, "statusSnapshot") ?? null
5633
- });
5634
- if (fingerprint !== lastFingerprint) {
5635
- lastFingerprint = fingerprint;
5636
- lastProgressAt = Date.now();
5637
- opts.onAgentProgress?.(codewithAgentProgress(lastReadJson));
5638
- }
5639
- if (status === "completed" || status === "failed" || status === "cancelled") {
5640
- const logs = await spawnCapture(spec.command, codewithAgentControlArgs(target, "logs", agentId), {
5641
- cwd: spec.cwd,
5642
- env,
5643
- timeoutMs: 30000,
5644
- maxOutputBytes
5645
- });
5646
- if (!logs.error && (logs.status ?? 1) === 0) {
5647
- try {
5648
- lastLogsJson = parseJsonOutput(logs.stdout || "{}", "codewith agent logs");
5649
- } catch {
5650
- lastLogsJson = undefined;
5651
- }
5652
- } else {
5653
- stderr.append(logs.stderr || logs.error || "");
5654
- }
5655
- if (status === "completed") {
5656
- return successResult(startedAt, { exitCode: 0, stdout: evidence(), stderr: stderr.value() });
5657
- }
5658
- return failureResult(startedAt, stringField(recordField(lastReadJson, "agent"), "statusReason") ?? `codewith agent ${status}`, { exitCode: 1, stdout: evidence(), stderr: stderr.value() });
5659
- }
5660
- if (typeof spec.timeoutMs === "number" && new Date(nowIso()).getTime() - new Date(startedAt).getTime() >= spec.timeoutMs) {
5661
- await stopAgent();
5662
- return timeoutResult(startedAt, `timed out after ${spec.timeoutMs}ms`, { stdout: evidence(), stderr: stderr.value() });
5663
- }
5664
- if (typeof spec.idleTimeoutMs === "number" && Date.now() - lastProgressAt >= spec.idleTimeoutMs) {
5665
- await stopAgent();
5666
- return timeoutResult(startedAt, `idle timed out after ${spec.idleTimeoutMs}ms without agent progress`, {
5667
- stdout: evidence(),
5668
- stderr: stderr.value()
5669
- });
5670
- }
5671
- await sleep(pollMs);
5672
- }
5673
- }
5674
5392
  function resolvedDirEquals(left, right) {
5675
5393
  try {
5676
5394
  return realpathSync(left) === realpathSync(right);
@@ -5904,9 +5622,6 @@ function preflightTarget(target, metadata = {}, opts = {}) {
5904
5622
  async function executeTarget(target, metadata = {}, opts = {}) {
5905
5623
  let spec = commandSpec(target, opts);
5906
5624
  const machine = resolvedMachine(opts);
5907
- if (machine && !machine.local && spec.codewithDurableAgent) {
5908
- return failureResult(nowIso(), "remote Codewith durable background-agent steps require remote status polling support; run this Codewith step locally or add remote durable readback before dispatch");
5909
- }
5910
5625
  if (machine && !machine.local) {
5911
5626
  const remoteFallbackSpec = spec.worktree?.enabled && spec.worktree.mode === "auto" ? worktreeFallbackSpec(target, opts, spec.worktree.originalCwd) : undefined;
5912
5627
  return executeRemoteSpec(spec, machine, metadata, opts, remoteFallbackSpec);
@@ -5937,9 +5652,6 @@ async function executeTarget(target, metadata = {}, opts = {}) {
5937
5652
  if (worktreeEntry?.fallbackCwd) {
5938
5653
  spec = worktreeFallbackSpec(target, opts, worktreeEntry.fallbackCwd) ?? spec;
5939
5654
  }
5940
- if (spec.codewithDurableAgent) {
5941
- return executeCodewithDurableAgent(spec, metadata, opts, env, startedAt);
5942
- }
5943
5655
  const child = spawn2(spec.command, spec.args, {
5944
5656
  cwd: spec.cwd,
5945
5657
  env,
@@ -7412,7 +7124,7 @@ function realSleep(ms) {
7412
7124
  return new Promise((resolve3) => setTimeout(resolve3, ms));
7413
7125
  }
7414
7126
  async function runLoop(opts) {
7415
- const sleep2 = opts.sleep ?? realSleep;
7127
+ const sleep = opts.sleep ?? realSleep;
7416
7128
  const sliceMs = opts.sliceMs ?? 200;
7417
7129
  while (!opts.shouldStop()) {
7418
7130
  try {
@@ -7423,7 +7135,7 @@ async function runLoop(opts) {
7423
7135
  let waited = 0;
7424
7136
  while (waited < opts.intervalMs && !opts.shouldStop()) {
7425
7137
  const chunk = Math.min(sliceMs, opts.intervalMs - waited);
7426
- await sleep2(chunk);
7138
+ await sleep(chunk);
7427
7139
  waited += chunk;
7428
7140
  }
7429
7141
  }
@@ -7515,7 +7227,7 @@ function processExists(pid) {
7515
7227
  }
7516
7228
  }
7517
7229
  async function reapProcessGroups(entries, opts = {}) {
7518
- const sleep2 = opts.sleep ?? realSleep;
7230
+ const sleep = opts.sleep ?? realSleep;
7519
7231
  const graceMs = Math.max(100, opts.graceMs ?? 2000);
7520
7232
  const ownPgid = ownProcessGroupId();
7521
7233
  const targets = new Map;
@@ -7544,7 +7256,7 @@ async function reapProcessGroups(entries, opts = {}) {
7544
7256
  const steps = Math.max(1, Math.ceil(graceMs / 100));
7545
7257
  let remaining = live;
7546
7258
  for (let i = 0;i < steps && remaining.length > 0; i++) {
7547
- await sleep2(100);
7259
+ await sleep(100);
7548
7260
  remaining = remaining.filter((target) => signalReapTarget(target, 0));
7549
7261
  }
7550
7262
  for (const target of remaining) {
@@ -7586,7 +7298,7 @@ async function stopDaemon(opts = {}) {
7586
7298
  }
7587
7299
  if (!state.running || !state.pid)
7588
7300
  return { wasRunning: false, stopped: false, forced: false };
7589
- const sleep2 = opts.sleep ?? realSleep;
7301
+ const sleep = opts.sleep ?? realSleep;
7590
7302
  const store = new Store(join5(dirname4(path), "loops.db"));
7591
7303
  try {
7592
7304
  const lease = store.getDaemonLease();
@@ -7599,7 +7311,7 @@ async function stopDaemon(opts = {}) {
7599
7311
  }
7600
7312
  const steps = Math.max(1, Math.ceil((opts.timeoutMs ?? 6000) / 100));
7601
7313
  for (let i = 0;i < steps; i++) {
7602
- await sleep2(100);
7314
+ await sleep(100);
7603
7315
  if (!isAlive(state.pid, record?.startedAt)) {
7604
7316
  removePid(path);
7605
7317
  return { wasRunning: true, stopped: true, forced: false, pid: state.pid };
@@ -7608,13 +7320,13 @@ async function stopDaemon(opts = {}) {
7608
7320
  try {
7609
7321
  process.kill(state.pid, "SIGKILL");
7610
7322
  } catch {}
7611
- await sleep2(150);
7323
+ await sleep(150);
7612
7324
  removePid(path);
7613
7325
  let reapedPgids = [];
7614
7326
  if (leaseVerified && lease) {
7615
7327
  const ownedRuns = store.listRuns({ status: "running", limit: 1000 }).filter((run) => run.claimedBy !== undefined && run.claimedBy.endsWith(`:${lease.id}`));
7616
7328
  reapedPgids = await reapProcessGroups(ownedRuns.map(toReapableProcess), {
7617
- sleep: sleep2,
7329
+ sleep,
7618
7330
  graceMs: opts.reapGraceMs
7619
7331
  });
7620
7332
  }
@@ -7686,7 +7398,7 @@ async function runDaemon(opts = {}) {
7686
7398
  const leaseTtlMs = opts.leaseTtlMs ?? Math.max(60000, intervalMs * 10);
7687
7399
  const concurrency = Math.max(1, opts.concurrency ?? concurrencyFromEnv() ?? 4);
7688
7400
  const log = opts.log ?? defaultDaemonLog;
7689
- const sleep2 = opts.sleep ?? realSleep;
7401
+ const sleep = opts.sleep ?? realSleep;
7690
7402
  const lease = store.acquireDaemonLease({
7691
7403
  id: leaseId,
7692
7404
  pid: process.pid,
@@ -7750,7 +7462,7 @@ async function runDaemon(opts = {}) {
7750
7462
  const entries = recovered.map(toReapableProcess).filter((entry) => entry.pid !== undefined || entry.pgid !== undefined);
7751
7463
  if (entries.length === 0)
7752
7464
  return;
7753
- const killed = await reapProcessGroups(entries, { sleep: sleep2, graceMs: opts.reapGraceMs, log });
7465
+ const killed = await reapProcessGroups(entries, { sleep, graceMs: opts.reapGraceMs, log });
7754
7466
  if (killed.length > 0)
7755
7467
  log(`reaped orphan process groups: ${killed.join(", ")}`);
7756
7468
  };
@@ -7825,7 +7537,7 @@ async function runDaemon(opts = {}) {
7825
7537
  }
7826
7538
  await runLoop({
7827
7539
  intervalMs,
7828
- sleep: sleep2,
7540
+ sleep,
7829
7541
  shouldStop: opts.shouldStop ?? (() => stopFlag),
7830
7542
  onTickError: (err) => log(`tick error: ${err instanceof Error ? err.message : String(err)}`),
7831
7543
  tickFn: async () => {
@@ -7875,10 +7587,10 @@ async function startDaemon(opts) {
7875
7587
  stdio: ["ignore", out, out]
7876
7588
  });
7877
7589
  child.unref();
7878
- const sleep2 = opts.sleep ?? realSleep;
7590
+ const sleep = opts.sleep ?? realSleep;
7879
7591
  const deadline = Math.max(1, Math.ceil((opts.waitMs ?? 4000) / 100));
7880
7592
  for (let i = 0;i < deadline; i++) {
7881
- await sleep2(100);
7593
+ await sleep(100);
7882
7594
  const current = isDaemonRunning();
7883
7595
  if (current.running)
7884
7596
  return { started: true, alreadyRunning: false, pid: current.pid };
@@ -8003,7 +7715,7 @@ function enableStartup(result) {
8003
7715
  // package.json
8004
7716
  var package_default = {
8005
7717
  name: "@hasna/loops",
8006
- version: "0.4.8",
7718
+ version: "0.4.9",
8007
7719
  description: "Persistent local loop and workflow runner for deterministic commands and headless AI coding agents",
8008
7720
  type: "module",
8009
7721
  main: "dist/index.js",