@bastani/atomic 0.9.61 → 0.9.62-alpha.1

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.
@@ -2378,15 +2378,12 @@ class JournalDurableBackend {
2378
2378
  commitCheckpoint(checkpoint, options) {
2379
2379
  if (options?.signal?.aborted)
2380
2380
  return Promise.reject(new JournalOperationAbortedError(checkpoint.workflowId, options.signal.reason instanceof Error ? options.signal.reason : undefined));
2381
- return this.serialize(checkpoint.workflowId, () => this.checkpoint(checkpoint));
2382
- }
2383
- *checkpoint(checkpoint) {
2384
- validateCheckpointInvocationFingerprint(checkpoint);
2385
- if (!(yield* this.current(checkpoint.workflowId)))
2386
- return;
2387
- yield* this.append(checkpoint.workflowId, { type: RUN_EVENT_TYPES.checkpointRecorded, payload: checkpoint }, {
2388
- key: JSON.stringify([RUN_EVENT_TYPES.checkpointRecorded, checkpoint.kind, checkpoint.checkpointId])
2389
- });
2381
+ try {
2382
+ validateCheckpointInvocationFingerprint(checkpoint);
2383
+ } catch (error) {
2384
+ return Promise.reject(error);
2385
+ }
2386
+ return this.queueAppend(checkpoint.workflowId, { type: RUN_EVENT_TYPES.checkpointRecorded, payload: checkpoint }, JSON.stringify([RUN_EVENT_TYPES.checkpointRecorded, checkpoint.kind, checkpoint.checkpointId]), true);
2390
2387
  }
2391
2388
  async commitAdditiveCheckpointBestEffort(checkpoint) {
2392
2389
  try {
@@ -2523,7 +2520,7 @@ class JournalDurableBackend {
2523
2520
  payload: { messageId, delivery, ...accounting === undefined ? {} : { accounting } }
2524
2521
  });
2525
2522
  }
2526
- queueAppend(runId, event, key) {
2523
+ queueAppend(runId, event, key, requiresRegisteredRun = false) {
2527
2524
  try {
2528
2525
  this.ensureOpen();
2529
2526
  this.assertExecutionActive();
@@ -2536,6 +2533,7 @@ class JournalDurableBackend {
2536
2533
  batch.push({
2537
2534
  event,
2538
2535
  ...key === undefined ? {} : { key },
2536
+ ...requiresRegisteredRun ? { requiresRegisteredRun } : {},
2539
2537
  context: AsyncLocalStorage.snapshot(),
2540
2538
  resolve,
2541
2539
  reject
@@ -2550,9 +2548,12 @@ class JournalDurableBackend {
2550
2548
  }
2551
2549
  return queued;
2552
2550
  }
2553
- *appendBatch(runId, batch) {
2554
- if (this.appendBatches.get(runId) === batch)
2551
+ *appendBatch(runId, queued) {
2552
+ if (this.appendBatches.get(runId) === queued)
2555
2553
  this.appendBatches.delete(runId);
2554
+ const batch = yield* this.registeredAppends(runId, queued);
2555
+ if (batch.length === 0)
2556
+ return;
2556
2557
  const appendMany = runJournalAppendMany(this.journal);
2557
2558
  if (appendMany === undefined || batch.length === 1) {
2558
2559
  for (const append of batch) {
@@ -2590,6 +2591,25 @@ class JournalDurableBackend {
2590
2591
  append.reject(failure);
2591
2592
  }
2592
2593
  }
2594
+ *registeredAppends(runId, batch) {
2595
+ if (!batch.some((append) => append.requiresRegisteredRun === true))
2596
+ return [...batch];
2597
+ let registered;
2598
+ try {
2599
+ registered = (yield* this.current(runId)) !== undefined;
2600
+ } catch (error) {
2601
+ for (const append of batch)
2602
+ if (append.requiresRegisteredRun === true)
2603
+ append.reject(error);
2604
+ return batch.filter((append) => append.requiresRegisteredRun !== true);
2605
+ }
2606
+ if (registered)
2607
+ return [...batch];
2608
+ for (const append of batch)
2609
+ if (append.requiresRegisteredRun === true)
2610
+ append.resolve();
2611
+ return batch.filter((append) => append.requiresRegisteredRun !== true);
2612
+ }
2593
2613
  getToolOutput(...args) {
2594
2614
  return this.projection.getToolOutput(...args);
2595
2615
  }
@@ -17442,7 +17462,7 @@ class SqlResourceAdmission {
17442
17462
  signal?.throwIfAborted();
17443
17463
  const operation = randomUUID6();
17444
17464
  const release = (reason = "resource cleanup confirmed") => this.storage.transaction(async (tx) => {
17445
- await tx.run(`UPDATE ${this.permits} SET state = 'released', reason = ? WHERE operation = ? AND state != 'released'`, reason, operation);
17465
+ await tx.run(`UPDATE ${this.permits} SET state = 'released', reason = ? WHERE operation = ? AND (state != 'released' OR reason = ?)`, reason, operation, FENCED_WAITER_REASON);
17446
17466
  });
17447
17467
  release.bindProcess = async (identity) => {
17448
17468
  if (kind !== "process" || identity.kind !== "unix-process-group" || !Number.isSafeInteger(identity.id) || identity.id <= 0)
@@ -17454,6 +17474,15 @@ class SqlResourceAdmission {
17454
17474
  throw new Error("Resource process permit is no longer held");
17455
17475
  });
17456
17476
  };
17477
+ const keepWaiting = async (tx) => {
17478
+ const permit = await tx.get(`SELECT state, reason FROM ${this.permits} WHERE operation = ?`, operation);
17479
+ if (permit?.state === "released" && permit.reason === FENCED_WAITER_REASON)
17480
+ await tx.run(`UPDATE ${this.permits} SET state = 'waiting', reason = NULL WHERE operation = ?`, operation);
17481
+ else if (permit === undefined)
17482
+ throw new AdmissionHolderStoppedError("permit no longer recorded");
17483
+ else if (permit.state !== "waiting")
17484
+ throw new AdmissionHolderStoppedError(permit.reason === null ? undefined : String(permit.reason));
17485
+ };
17457
17486
  await this.storage.transaction(async (tx) => {
17458
17487
  await tx.run(`UPDATE ${this.owners} SET expires_at = CAST(unixepoch('subsec') * 1000 AS INTEGER) + ? WHERE id = ?`, OWNER_LEASE_MS, this.owner);
17459
17488
  await tx.run(`INSERT INTO ${this.permits}(operation, root, holder, kind, state, owner, attempt) VALUES (?, ?, ?, ?, 'waiting', ?, ?)`, operation, this.options.root, this.options.holder, kind, this.owner, this.options.attempt ? JSON.stringify({
@@ -17476,11 +17505,12 @@ class SqlResourceAdmission {
17476
17505
  const granted = await this.storage.transaction(async (tx) => {
17477
17506
  quarantined = undefined;
17478
17507
  await tx.run(`UPDATE ${this.owners} SET expires_at = CAST(unixepoch('subsec') * 1000 AS INTEGER) + ? WHERE id = ?`, OWNER_LEASE_MS, this.owner);
17508
+ await keepWaiting(tx);
17479
17509
  const { root } = this.options;
17480
17510
  if (!await this.assertCurrentAttempt(tx)) {
17481
17511
  const waiting = await tx.run(`UPDATE ${this.permits} SET reason = ? WHERE operation = ? AND state = 'waiting'`, LATE_ATTEMPT_REASON, operation);
17482
17512
  if (waiting.changes !== 1)
17483
- throw new Error("Resource admission holder was stopped");
17513
+ throw new AdmissionHolderStoppedError(undefined);
17484
17514
  return false;
17485
17515
  }
17486
17516
  let reason = hostReason;
@@ -17523,7 +17553,7 @@ class SqlResourceAdmission {
17523
17553
  const stageStart = kind === "session" && request?.delegated !== true;
17524
17554
  const updated = await tx.run(`UPDATE ${this.permits} SET state = ?, reason = ?, granted_at = CASE WHEN ? IS NULL AND ? THEN ${NOW_MS} ELSE NULL END WHERE operation = ? AND state = 'waiting'`, reason ? "waiting" : "granted", reason ?? null, reason ?? null, stageStart ? 1 : 0, operation);
17525
17555
  if (updated.changes !== 1)
17526
- throw new Error("Resource admission holder was stopped");
17556
+ throw new AdmissionHolderStoppedError(undefined);
17527
17557
  return !reason;
17528
17558
  });
17529
17559
  if (granted) {
@@ -17565,7 +17595,7 @@ class SqlResourceAdmission {
17565
17595
  WHERE p.state IN ('waiting', 'granted')`);
17566
17596
  if (live.some((permit) => this.needsFencing(permit, fence)))
17567
17597
  return true;
17568
- return !!await db.get(`SELECT 1 AS prunable FROM ${this.permits} WHERE +state = 'released' AND ticket <= ${this.prunableBefore} LIMIT 1`, RELEASED_PERMIT_RETENTION);
17598
+ return !!await db.get(`SELECT 1 AS prunable FROM ${this.permits} r WHERE ${this.prunable} LIMIT 1`, RELEASED_PERMIT_RETENTION, FENCED_WAITER_REASON, FENCED_WAITER_RETENTION_MS);
17569
17599
  });
17570
17600
  if (!pending)
17571
17601
  return;
@@ -17574,7 +17604,7 @@ class SqlResourceAdmission {
17574
17604
  const owners = await tx.all(`SELECT o.* FROM ${this.owners} o WHERE o.id IN (SELECT owner FROM ${this.permits} WHERE state IN ('waiting', 'granted'))`);
17575
17605
  for (const owner of owners) {
17576
17606
  const { rebooted, stopped } = fence(owner);
17577
- await tx.run(`UPDATE ${this.permits} SET state = 'released', reason = 'abandoned waiter fenced' WHERE owner = ? AND state = 'waiting' AND (? OR EXISTS (SELECT 1 FROM ${this.owners} WHERE id = ? AND expires_at < ${NOW_MS}))`, owner.id, stopped ? 1 : 0, owner.id);
17607
+ await tx.run(`UPDATE ${this.permits} SET state = 'released', reason = ? WHERE owner = ? AND state = 'waiting' AND (? OR EXISTS (SELECT 1 FROM ${this.owners} WHERE id = ? AND expires_at < ${NOW_MS}))`, FENCED_WAITER_REASON, owner.id, stopped ? 1 : 0, owner.id);
17578
17608
  if (rebooted) {
17579
17609
  await tx.run(`UPDATE ${this.permits} SET state = 'released', reason = 'host reboot confirmed' WHERE owner = ? AND state = 'granted'`, owner.id);
17580
17610
  } else if (stopped) {
@@ -17592,13 +17622,17 @@ class SqlResourceAdmission {
17592
17622
  }
17593
17623
  await tx.run(`UPDATE ${this.permits} SET state = 'released', reason = 'legacy waiter fenced' WHERE owner IS NULL AND state = 'waiting'`);
17594
17624
  await tx.run(`UPDATE ${this.permits} SET reason = ? WHERE owner IS NULL AND state = 'granted' AND reason IS NOT ?`, ANONYMOUS_REASON, ANONYMOUS_REASON);
17595
- await tx.run(`DELETE FROM ${this.permits} WHERE ticket IN (SELECT ticket FROM ${this.permits} WHERE +state = 'released'
17596
- AND ticket <= ${this.prunableBefore} ORDER BY ticket LIMIT ?)`, RELEASED_PERMIT_RETENTION, RELEASED_PERMIT_PRUNE_BATCH);
17625
+ await tx.run(`DELETE FROM ${this.permits} WHERE ticket IN (SELECT ticket FROM ${this.permits} r WHERE ${this.prunable}
17626
+ ORDER BY ticket LIMIT ?)`, RELEASED_PERMIT_RETENTION, FENCED_WAITER_REASON, FENCED_WAITER_RETENTION_MS, RELEASED_PERMIT_PRUNE_BATCH);
17597
17627
  });
17598
17628
  }
17599
17629
  get prunableBefore() {
17600
17630
  return `(SELECT ticket FROM ${this.permits} WHERE state = 'released' ORDER BY ticket DESC LIMIT 1 OFFSET ?)`;
17601
17631
  }
17632
+ get prunable() {
17633
+ return `+r.state = 'released' AND r.ticket <= ${this.prunableBefore} AND (r.reason IS NOT ? OR NOT EXISTS
17634
+ (SELECT 1 FROM ${this.owners} o WHERE o.id = r.owner AND o.expires_at >= ${NOW_MS} - ?))`;
17635
+ }
17602
17636
  needsFencing(permit, fence) {
17603
17637
  if (permit.owner === null)
17604
17638
  return permit.state === "waiting" || permit.reason !== ANONYMOUS_REASON;
@@ -17623,6 +17657,7 @@ class SqlResourceAdmission {
17623
17657
  await this.reconcile();
17624
17658
  return this.storage.transaction(async (tx) => {
17625
17659
  await tx.run(`UPDATE ${this.permits} SET state = 'released', reason = 'worker exit confirmed' WHERE root = ? AND holder = ? AND state IN ('waiting', 'granted') AND (kind = 'session' OR state = 'waiting')`, this.options.root, holder);
17660
+ await tx.run(`UPDATE ${this.permits} SET reason = 'worker exit confirmed' WHERE root = ? AND holder = ? AND state = 'released' AND reason = ?`, this.options.root, holder, FENCED_WAITER_REASON);
17626
17661
  await tx.run(`UPDATE ${this.permits} SET reason = ? WHERE root = ? AND holder = ? AND kind = 'process' AND state = 'granted' AND reason IS NOT ?`, UNCONFIRMED_REASON, this.options.root, holder, QUARANTINED_REASON);
17627
17662
  const held = await tx.get(`SELECT COUNT(*) AS count FROM ${this.permits} WHERE root = ? AND holder = ? AND kind = 'process' AND state = 'granted'`, this.options.root, holder);
17628
17663
  return Number(held?.count);
@@ -17695,7 +17730,7 @@ async function reapProcessGroups(journal, root, scope) {
17695
17730
  return { survivors: [], unprobeable: [] };
17696
17731
  return settleProcessGroups(storage, root, scope, true);
17697
17732
  }
17698
- var OWNER_LEASE_MS = 30000, REAP_TERM_GRACE_MS = 5000, REAP_KILL_GRACE_MS = 1e4, REAP_POLL_MS = 50, RELEASED_PERMIT_RETENTION = 256, RELEASED_PERMIT_PRUNE_BATCH = 1000, EXPIRED_REASON = "owner expired; cleanup unconfirmed", UNCONFIRMED_REASON = "cleanup unconfirmed", QUARANTINED_REASON = "cleanup unconfirmed; permit quarantined", ANONYMOUS_REASON = "owner identity unavailable; cleanup unconfirmed", QUARANTINED_CAPACITY_WAIT_MS, QuarantinedCapacityError, NOW_MS = "CAST(unixepoch('subsec') * 1000 AS INTEGER)", LATE_ATTEMPT_POLL_MS = 100, LATE_ATTEMPT_REASON = "waiting for its attempt lease", STAGE_START_SPACING_MS = 5000, STAGE_START_PRESSURE_REASON = "paced for host load";
17733
+ var OWNER_LEASE_MS = 30000, REAP_TERM_GRACE_MS = 5000, REAP_KILL_GRACE_MS = 1e4, REAP_POLL_MS = 50, RELEASED_PERMIT_RETENTION = 256, RELEASED_PERMIT_PRUNE_BATCH = 1000, EXPIRED_REASON = "owner expired; cleanup unconfirmed", UNCONFIRMED_REASON = "cleanup unconfirmed", QUARANTINED_REASON = "cleanup unconfirmed; permit quarantined", ANONYMOUS_REASON = "owner identity unavailable; cleanup unconfirmed", QUARANTINED_CAPACITY_WAIT_MS, QuarantinedCapacityError, FENCED_WAITER_REASON = "abandoned waiter fenced", FENCED_WAITER_RETENTION_MS, AdmissionHolderStoppedError, NOW_MS = "CAST(unixepoch('subsec') * 1000 AS INTEGER)", LATE_ATTEMPT_POLL_MS = 100, LATE_ATTEMPT_REASON = "waiting for its attempt lease", STAGE_START_SPACING_MS = 5000, STAGE_START_PRESSURE_REASON = "paced for host load";
17699
17734
  var init_resource_admission = __esm(() => {
17700
17735
  init_internal();
17701
17736
  init_sql_run_journal();
@@ -17709,6 +17744,12 @@ var init_resource_admission = __esm(() => {
17709
17744
  super("worker_cleanup_unconfirmed", `Local worker process cleanup unconfirmed; process permit refused after ${Math.round(waitedMs)} ms: ${limits} ${capacity.length === 1 ? "is" : "are"} held by quarantined permits of process groups ${groups} that survived SIGKILL`);
17710
17745
  }
17711
17746
  };
17747
+ FENCED_WAITER_RETENTION_MS = 10 * 60000;
17748
+ AdmissionHolderStoppedError = class AdmissionHolderStoppedError extends WorkflowInfrastructureError {
17749
+ constructor(reason) {
17750
+ super("stale_work_lease", `Stale resource admission attempt: the admission holder was stopped${reason === undefined ? "" : ` (${reason})`}`);
17751
+ }
17752
+ };
17712
17753
  });
17713
17754
 
17714
17755
  // dist/builtin/workflows/src/workers/admission-binding.ts
@@ -65111,6 +65152,37 @@ var init_workflow_route_owner = __esm(() => {
65111
65152
  });
65112
65153
 
65113
65154
  // dist/builtin/workflows/src/runs/foreground/sdk-intercom.ts
65155
+ function indexRoots(runs) {
65156
+ const runById = new Map(runs.map((run) => [run.id, run]));
65157
+ const rootOf = new Map;
65158
+ const deliverable = new Set;
65159
+ for (const run of runs) {
65160
+ const root = reciprocalWorkflowRootRunId(runById, run.id);
65161
+ rootOf.set(run.id, root);
65162
+ if (root !== undefined && run.stages.some((stage) => stage.pendingStageDeliveryAvailable === true))
65163
+ deliverable.add(root);
65164
+ }
65165
+ return { rootOf, deliverable };
65166
+ }
65167
+ function createStandaloneRouteOwnership(store, roots) {
65168
+ const activated = new Set;
65169
+ let index;
65170
+ const dispose = store.subscribeInvalidation(() => {
65171
+ index = undefined;
65172
+ });
65173
+ return {
65174
+ owns: (runId) => {
65175
+ index ??= indexRoots(store.runs());
65176
+ const root = index.rootOf.get(runId) ?? runId;
65177
+ if (!roots.has(root))
65178
+ return false;
65179
+ if (!activated.has(root) && index.deliverable.has(root))
65180
+ activated.add(root);
65181
+ return activated.has(root);
65182
+ },
65183
+ dispose
65184
+ };
65185
+ }
65114
65186
  function releaseRoot(owner, runId) {
65115
65187
  const remaining = (owner.roots.get(runId) ?? 1) - 1;
65116
65188
  if (remaining > 0) {
@@ -65126,22 +65198,14 @@ async function acquireStandaloneIntercom(store, runId, cwd) {
65126
65198
  if (hasWorkflowPendingStageRouteOwner(store))
65127
65199
  return async () => {};
65128
65200
  const roots = new Map;
65129
- const activated = new Set;
65130
65201
  owner = {
65131
65202
  roots,
65132
65203
  ready: outsideWorkflowExecutions(async () => {
65133
65204
  await Promise.resolve().then(() => init_workflow_route_owner());
65134
65205
  const routes = createWorkflowRouteOwner(cwd);
65135
- const bridge = registerPendingStageIntercomBridge({ events: routes.events }, store, (id) => {
65136
- const runs = store.runs();
65137
- const root = durableRootRunIdForRun(runs, id) ?? id;
65138
- if (!roots.has(root))
65139
- return false;
65140
- if (!activated.has(root) && runs.some((run) => durableRootRunIdForRun(runs, run.id) === root && run.stages.some((stage) => stage.pendingStageDeliveryAvailable === true)))
65141
- activated.add(root);
65142
- return activated.has(root);
65143
- });
65144
- return { routes, bridge };
65206
+ const ownership = createStandaloneRouteOwnership(store, roots);
65207
+ const bridge = registerPendingStageIntercomBridge({ events: routes.events }, store, ownership.owns);
65208
+ return { routes, bridge, unwatch: ownership.dispose };
65145
65209
  })
65146
65210
  };
65147
65211
  owners2.set(store, owner);
@@ -65165,6 +65229,7 @@ async function acquireStandaloneIntercom(store, runId, cwd) {
65165
65229
  initialized.bridge.refresh();
65166
65230
  if (retained.roots.size === 0) {
65167
65231
  initialized.bridge();
65232
+ initialized.unwatch();
65168
65233
  if (owners2.get(store) === retained)
65169
65234
  owners2.delete(store);
65170
65235
  }
@@ -65176,10 +65241,10 @@ async function acquireStandaloneIntercom(store, runId, cwd) {
65176
65241
  var owners2;
65177
65242
  var init_sdk_intercom = __esm(() => {
65178
65243
  init_execution_context_boundary();
65179
- init_run_owner_backend();
65180
65244
  init_pending_stage_intercom();
65181
65245
  init_intercom_group();
65182
65246
  init_pending_stage_route_readiness();
65247
+ init_workflow_run_ownership();
65183
65248
  owners2 = new WeakMap;
65184
65249
  });
65185
65250
 
@@ -82001,7 +82066,7 @@ async function runWorker(start) {
82001
82066
  try {
82002
82067
  return await admission.acquire(kind, signal, requestOptions);
82003
82068
  } catch (error) {
82004
- if (error instanceof QuarantinedCapacityError && !attemptFenced) {
82069
+ if ((error instanceof QuarantinedCapacityError || error instanceof AdmissionHolderStoppedError) && !attemptFenced) {
82005
82070
  poolFault = error.message;
82006
82071
  attemptFenced = true;
82007
82072
  controller.abort(new WorkAttemptFencedError(error.message));
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "name": "@bastani/atomic",
3
- "version": "0.9.61",
3
+ "version": "0.9.62-alpha.1",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@bastani/atomic",
9
- "version": "0.9.61",
9
+ "version": "0.9.62-alpha.1",
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
- "@bastani/atomic-natives": "0.9.61",
13
- "@bastani/pi-ai": "0.9.61",
12
+ "@bastani/atomic-natives": "0.9.62-alpha.1",
13
+ "@bastani/pi-ai": "0.9.62-alpha.1",
14
14
  "@earendil-works/pi-agent-core": "1.4.0",
15
15
  "@earendil-works/pi-codemode": "1.4.0",
16
16
  "@earendil-works/pi-tui": "1.4.0",
@@ -427,18 +427,18 @@
427
427
  }
428
428
  },
429
429
  "node_modules/@bastani/atomic-natives": {
430
- "version": "0.9.61",
431
- "resolved": "https://registry.npmjs.org/@bastani/atomic-natives/-/atomic-natives-0.9.61.tgz",
430
+ "version": "0.9.62-alpha.1",
431
+ "resolved": "https://registry.npmjs.org/@bastani/atomic-natives/-/atomic-natives-0.9.62-alpha.1.tgz",
432
432
  "license": "MIT",
433
433
  "optionalDependencies": {
434
- "@bastani/atomic-natives-darwin-arm64": "0.9.61",
435
- "@bastani/atomic-natives-darwin-x64": "0.9.61",
436
- "@bastani/atomic-natives-linux-arm64-gnu": "0.9.61",
437
- "@bastani/atomic-natives-linux-arm64-musl": "0.9.61",
438
- "@bastani/atomic-natives-linux-x64-gnu": "0.9.61",
439
- "@bastani/atomic-natives-linux-x64-musl": "0.9.61",
440
- "@bastani/atomic-natives-win32-arm64-msvc": "0.9.61",
441
- "@bastani/atomic-natives-win32-x64-msvc": "0.9.61"
434
+ "@bastani/atomic-natives-darwin-arm64": "0.9.62-alpha.1",
435
+ "@bastani/atomic-natives-darwin-x64": "0.9.62-alpha.1",
436
+ "@bastani/atomic-natives-linux-arm64-gnu": "0.9.62-alpha.1",
437
+ "@bastani/atomic-natives-linux-arm64-musl": "0.9.62-alpha.1",
438
+ "@bastani/atomic-natives-linux-x64-gnu": "0.9.62-alpha.1",
439
+ "@bastani/atomic-natives-linux-x64-musl": "0.9.62-alpha.1",
440
+ "@bastani/atomic-natives-win32-arm64-msvc": "0.9.62-alpha.1",
441
+ "@bastani/atomic-natives-win32-x64-msvc": "0.9.62-alpha.1"
442
442
  },
443
443
  "engines": {
444
444
  "bun": ">=1.4.2",
@@ -446,8 +446,8 @@
446
446
  }
447
447
  },
448
448
  "node_modules/@bastani/atomic-natives-darwin-arm64": {
449
- "version": "0.9.61",
450
- "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-darwin-arm64/-/atomic-natives-darwin-arm64-0.9.61.tgz",
449
+ "version": "0.9.62-alpha.1",
450
+ "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-darwin-arm64/-/atomic-natives-darwin-arm64-0.9.62-alpha.1.tgz",
451
451
  "license": "MIT",
452
452
  "os": [
453
453
  "darwin"
@@ -458,8 +458,8 @@
458
458
  "optional": true
459
459
  },
460
460
  "node_modules/@bastani/atomic-natives-darwin-x64": {
461
- "version": "0.9.61",
462
- "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-darwin-x64/-/atomic-natives-darwin-x64-0.9.61.tgz",
461
+ "version": "0.9.62-alpha.1",
462
+ "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-darwin-x64/-/atomic-natives-darwin-x64-0.9.62-alpha.1.tgz",
463
463
  "license": "MIT",
464
464
  "os": [
465
465
  "darwin"
@@ -470,8 +470,8 @@
470
470
  "optional": true
471
471
  },
472
472
  "node_modules/@bastani/atomic-natives-linux-arm64-gnu": {
473
- "version": "0.9.61",
474
- "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-linux-arm64-gnu/-/atomic-natives-linux-arm64-gnu-0.9.61.tgz",
473
+ "version": "0.9.62-alpha.1",
474
+ "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-linux-arm64-gnu/-/atomic-natives-linux-arm64-gnu-0.9.62-alpha.1.tgz",
475
475
  "license": "MIT",
476
476
  "os": [
477
477
  "linux"
@@ -485,8 +485,8 @@
485
485
  "optional": true
486
486
  },
487
487
  "node_modules/@bastani/atomic-natives-linux-arm64-musl": {
488
- "version": "0.9.61",
489
- "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-linux-arm64-musl/-/atomic-natives-linux-arm64-musl-0.9.61.tgz",
488
+ "version": "0.9.62-alpha.1",
489
+ "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-linux-arm64-musl/-/atomic-natives-linux-arm64-musl-0.9.62-alpha.1.tgz",
490
490
  "license": "MIT",
491
491
  "os": [
492
492
  "linux"
@@ -500,8 +500,8 @@
500
500
  "optional": true
501
501
  },
502
502
  "node_modules/@bastani/atomic-natives-linux-x64-gnu": {
503
- "version": "0.9.61",
504
- "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-linux-x64-gnu/-/atomic-natives-linux-x64-gnu-0.9.61.tgz",
503
+ "version": "0.9.62-alpha.1",
504
+ "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-linux-x64-gnu/-/atomic-natives-linux-x64-gnu-0.9.62-alpha.1.tgz",
505
505
  "license": "MIT",
506
506
  "os": [
507
507
  "linux"
@@ -515,8 +515,8 @@
515
515
  "optional": true
516
516
  },
517
517
  "node_modules/@bastani/atomic-natives-linux-x64-musl": {
518
- "version": "0.9.61",
519
- "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-linux-x64-musl/-/atomic-natives-linux-x64-musl-0.9.61.tgz",
518
+ "version": "0.9.62-alpha.1",
519
+ "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-linux-x64-musl/-/atomic-natives-linux-x64-musl-0.9.62-alpha.1.tgz",
520
520
  "license": "MIT",
521
521
  "os": [
522
522
  "linux"
@@ -530,8 +530,8 @@
530
530
  "optional": true
531
531
  },
532
532
  "node_modules/@bastani/atomic-natives-win32-arm64-msvc": {
533
- "version": "0.9.61",
534
- "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-win32-arm64-msvc/-/atomic-natives-win32-arm64-msvc-0.9.61.tgz",
533
+ "version": "0.9.62-alpha.1",
534
+ "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-win32-arm64-msvc/-/atomic-natives-win32-arm64-msvc-0.9.62-alpha.1.tgz",
535
535
  "license": "MIT",
536
536
  "os": [
537
537
  "win32"
@@ -542,8 +542,8 @@
542
542
  "optional": true
543
543
  },
544
544
  "node_modules/@bastani/atomic-natives-win32-x64-msvc": {
545
- "version": "0.9.61",
546
- "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-win32-x64-msvc/-/atomic-natives-win32-x64-msvc-0.9.61.tgz",
545
+ "version": "0.9.62-alpha.1",
546
+ "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-win32-x64-msvc/-/atomic-natives-win32-x64-msvc-0.9.62-alpha.1.tgz",
547
547
  "license": "MIT",
548
548
  "os": [
549
549
  "win32"
@@ -554,8 +554,8 @@
554
554
  "optional": true
555
555
  },
556
556
  "node_modules/@bastani/pi-ai": {
557
- "version": "0.9.61",
558
- "resolved": "https://registry.npmjs.org/@bastani/pi-ai/-/pi-ai-0.9.61.tgz",
557
+ "version": "0.9.62-alpha.1",
558
+ "resolved": "https://registry.npmjs.org/@bastani/pi-ai/-/pi-ai-0.9.62-alpha.1.tgz",
559
559
  "license": "MIT",
560
560
  "dependencies": {
561
561
  "@anthropic-ai/sdk": "0.129.0",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bastani/atomic",
3
- "version": "0.9.61",
3
+ "version": "0.9.62-alpha.1",
4
4
  "description": "Atomic coding agent CLI with read, bash, edit, write tools and session management",
5
5
  "type": "module",
6
6
  "atomicConfig": {
@@ -89,8 +89,8 @@
89
89
  "prepublishOnly": "bun run clean && bun run build && bun run shrinkwrap"
90
90
  },
91
91
  "dependencies": {
92
- "@bastani/atomic-natives": "0.9.61",
93
- "@bastani/pi-ai": "0.9.61",
92
+ "@bastani/atomic-natives": "0.9.62-alpha.1",
93
+ "@bastani/pi-ai": "0.9.62-alpha.1",
94
94
  "@earendil-works/pi-agent-core": "1.4.0",
95
95
  "@earendil-works/pi-codemode": "1.4.0",
96
96
  "@earendil-works/pi-tui": "1.4.0",