@bastani/atomic 0.9.51 → 0.9.52-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.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bastani/intercom",
3
- "version": "0.9.51",
3
+ "version": "0.9.52-alpha.1",
4
4
  "private": true,
5
5
  "description": "Atomic extension providing a private coordination channel between parent and child agent sessions. Fork of: https://github.com/nicobailon/pi-intercom",
6
6
  "contributors": [
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bastani/mcp",
3
- "version": "0.9.51",
3
+ "version": "0.9.52-alpha.1",
4
4
  "private": true,
5
5
  "description": "Atomic's pi-compatible MCP integration for server connections, OAuth, tools, resources, and terminal management.",
6
6
  "contributors": [
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bastani/subagents",
3
- "version": "0.9.51",
3
+ "version": "0.9.52-alpha.1",
4
4
  "private": true,
5
5
  "description": "Atomic extension for delegating tasks to subagents with parallel execution. Fork of: https://github.com/nicobailon/pi-subagents",
6
6
  "contributors": [
@@ -4,6 +4,12 @@ All notable changes to this project will be documented in this file.
4
4
 
5
5
  ## [Unreleased]
6
6
 
7
+ ## [0.9.52-alpha.1] - 2026-10-29
8
+
9
+ ### Fixed
10
+
11
+ - `web_search` no longer ends with `Search curation cancelled (stale).` when the search curator is enabled but cannot open (for example on a machine with no desktop browser), or when the session has no human to answer it, such as a subagent or workflow stage. It returns the raw results, with a note that points to `/curator off` when the curator failed to open. When no search provider is reachable, the error now names the `EXA_API_KEY`, `PERPLEXITY_API_KEY`, and `GEMINI_API_KEY` environment variables, the `exaApiKey`, `perplexityApiKey`, and `geminiApiKey` fields in `~/.atomic/web-search.json`, and `/curator` ([#4087](https://github.com/bastani-inc/atomic/issues/4087)).
12
+
7
13
  ## [0.9.40] - 2026-10-20
8
14
 
9
15
  ### Changed
@@ -96673,6 +96673,14 @@ function normalizeSearchProvider(value) {
96673
96673
  const normalized = typeof value === "string" ? value.trim().toLowerCase() : "";
96674
96674
  return normalized === "auto" || normalized === "perplexity" || normalized === "gemini" || normalized === "exa" ? normalized : "auto";
96675
96675
  }
96676
+ function providerSetupHint() {
96677
+ return `To configure a search provider, either:
96678
+ ` + ` 1. Set EXA_API_KEY, PERPLEXITY_API_KEY, or GEMINI_API_KEY in the environment
96679
+ ` + ` 2. Add exaApiKey, perplexityApiKey, or geminiApiKey to ~/${CONFIG_DIR_NAME4}/web-search.json
96680
+ ` + " 3. Sign into gemini.google.com in a supported Chromium-based browser and allow browser cookies " + `(allowBrowserCookies: true in ~/${CONFIG_DIR_NAME4}/web-search.json)
96681
+ ` + `Without a key, Exa's keyless fallback needs network access to mcp.exa.ai.
96682
+ ` + "/curator only toggles the interactive review browser; it does not add a search provider. " + "Run /curator off if the curator keeps failing to open.";
96683
+ }
96676
96684
  function errorMessage3(err) {
96677
96685
  return err instanceof Error ? err.message : String(err);
96678
96686
  }
@@ -96776,13 +96784,11 @@ async function search(query, options = {}) {
96776
96784
  if (fallbackErrors.length > 0) {
96777
96785
  throw new Error(`Auto provider search failed:
96778
96786
  - ${fallbackErrors.join(`
96779
- - `)}`);
96787
+ - `)}
96788
+ ${providerSetupHint()}`);
96780
96789
  }
96781
- throw new Error(`No search provider available. Either:
96782
- ` + ` 1. Set perplexityApiKey in ~/${CONFIG_DIR_NAME4}/web-search.json
96783
- ` + ` 2. Set EXA_API_KEY (or exaApiKey) in ~/${CONFIG_DIR_NAME4}/web-search.json
96784
- ` + ` 3. Set GEMINI_API_KEY in ~/${CONFIG_DIR_NAME4}/web-search.json
96785
- ` + " 4. Sign into gemini.google.com in a supported Chromium-based browser");
96790
+ throw new Error(`No search provider available.
96791
+ ${providerSetupHint()}`);
96786
96792
  }
96787
96793
  async function searchWithGeminiApi(query, options = {}) {
96788
96794
  const apiKey = getApiKey2();
@@ -97739,8 +97745,11 @@ async function openCuratorBrowser(deps, pc, searchesComplete = true) {
97739
97745
  const message = err instanceof Error ? err.message : String(err);
97740
97746
  if (!reportOwnedWebDiagnostic())
97741
97747
  console.error(`Failed to open curator UI: ${message}`);
97742
- if (deps.state.pendingCurate === pc || handle && deps.state.activeCurator === handle) {
97743
- deps.closeCurator();
97748
+ if (deps.state.pendingCurate === pc)
97749
+ pc.curatorUnavailable(message);
97750
+ if (handle && deps.state.activeCurator === handle) {
97751
+ deps.state.activeCurator = null;
97752
+ handle.close();
97744
97753
  }
97745
97754
  }
97746
97755
  }
@@ -98150,7 +98159,8 @@ function registerWebSearchTool(pi, deps) {
98150
98159
  const rawQueryList = Array.isArray(params.queries) ? params.queries : params.query !== undefined ? [params.query] : [];
98151
98160
  const queryList = normalizeQueryList(rawQueryList);
98152
98161
  const configWorkflow = loadConfigForExtensionInit().workflow;
98153
- const workflow = resolveWorkflow(configWorkflow, ctx?.hasUI !== false);
98162
+ const canCurate = ctx?.hasUI !== false && ctx?.hasHumanInput !== false;
98163
+ const workflow = resolveWorkflow(configWorkflow, canCurate);
98154
98164
  const shouldCurate = workflow !== "none";
98155
98165
  if (queryList.length === 0) {
98156
98166
  return {
@@ -98183,6 +98193,7 @@ function registerWebSearchTool(pi, deps) {
98183
98193
  const searchAbort = new AbortController;
98184
98194
  const searchSignal = signal ? AbortSignal.any([signal, searchAbort.signal]) : searchAbort.signal;
98185
98195
  let cancelled = false;
98196
+ let curatorFailure;
98186
98197
  const bootstrap = await loadCuratorBootstrap(params.provider);
98187
98198
  const availableProviders = bootstrap.availableProviders;
98188
98199
  const defaultProvider = bootstrap.defaultProvider;
@@ -98216,7 +98227,8 @@ function registerWebSearchTool(pi, deps) {
98216
98227
  searchAbort.abort();
98217
98228
  },
98218
98229
  finish: () => {},
98219
- cancel: () => {}
98230
+ cancel: () => {},
98231
+ curatorUnavailable: () => {}
98220
98232
  };
98221
98233
  const onAbort = () => deps.closeCurator();
98222
98234
  const finish = (value) => {
@@ -98233,8 +98245,16 @@ function registerWebSearchTool(pi, deps) {
98233
98245
  return;
98234
98246
  finish(buildCurationCancelledReturn(reason));
98235
98247
  };
98248
+ const curatorUnavailable = (reason) => {
98249
+ if (cancelled)
98250
+ return;
98251
+ curatorFailure = reason;
98252
+ if (deps.state.pendingCurate === pc)
98253
+ deps.state.pendingCurate = null;
98254
+ };
98236
98255
  pc.finish = finish;
98237
98256
  pc.cancel = cancel;
98257
+ pc.curatorUnavailable = curatorUnavailable;
98238
98258
  deps.state.pendingCurate = pc;
98239
98259
  signal?.addEventListener("abort", onAbort, { once: true });
98240
98260
  pc.browserPromise = deps.openCuratorBrowser(pc, false);
@@ -98282,6 +98302,25 @@ function registerWebSearchTool(pi, deps) {
98282
98302
  return promise;
98283
98303
  }
98284
98304
  await pc.browserPromise;
98305
+ if (curatorFailure !== undefined) {
98306
+ const all = collectAllResultsAndUrls(searchResults);
98307
+ const raw = await deps.buildSearchReturn({
98308
+ queryList: all.results.map((r) => r.query),
98309
+ results: all.results,
98310
+ urls: all.urls,
98311
+ includeContent,
98312
+ inlineContent: allInlineContent.length > 0 ? allInlineContent : undefined
98313
+ });
98314
+ const note = `Note: the search curator could not open (${curatorFailure}), so these are raw results. ` + "Run /curator off to stop opening it.";
98315
+ const [first, ...rest] = raw.content;
98316
+ finish({
98317
+ content: [{ type: "text", text: `${note}
98318
+
98319
+ ${first?.text ?? ""}`.trim() }, ...rest],
98320
+ details: { ...raw.details, curatorUnavailable: curatorFailure }
98321
+ });
98322
+ return promise;
98323
+ }
98285
98324
  if (deps.state.activeCurator) {
98286
98325
  deps.state.activeCurator.searchesDone();
98287
98326
  pc.onUpdate?.({
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bastani/web-access",
3
- "version": "0.9.51",
3
+ "version": "0.9.52-alpha.1",
4
4
  "private": true,
5
5
  "description": "Atomic extension for web search, URL fetching, GitHub repo cloning, PDF/video extraction. Fork of: https://github.com/nicobailon/pi-web-access",
6
6
  "contributors": [
@@ -6,6 +6,17 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
6
 
7
7
  ## [Unreleased]
8
8
 
9
+ ## [0.9.52-alpha.1] - 2026-10-29
10
+
11
+ Stage chats show their own status lines, and web search keeps its results.
12
+
13
+ - **A stage chat's own status lines:** an attached stage chat's footer shows the extension statuses its stage's session writes, such as a tokens-per-second counter, and no longer the main session's ([#4094](https://github.com/bastani-inc/atomic/issues/4094))
14
+ - **Web search results that arrive:** `web_search` returns its results when the search curator can't open or nobody can answer it, instead of `Search curation cancelled (stale).`, and says which keys or settings to configure when no search provider works ([#4087](https://github.com/bastani-inc/atomic/issues/4087))
15
+
16
+ ### Fixed
17
+
18
+ - An attached stage chat's footer now shows the extension status lines (such as a tokens-per-second counter) written by that stage's own session, and no longer shows the main session's. Status writes from a stage's extensions used to be dropped, while the chat footer displayed the main chat's statuses: a sleeping stage showed a live counter driven by the main agent, and a streaming stage showed a stale one. The main chat footer keeps showing only the main session's statuses ([#4094](https://github.com/bastani-inc/atomic/issues/4094))
19
+
9
20
  ## [0.9.46] - 2026-10-27
10
21
 
11
22
  ### Added
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@bastani/workflows",
3
- "version": "0.9.51",
3
+ "version": "0.9.52-alpha.1",
4
4
  "private": true,
5
5
  "description": "Atomic extension for multi-stage workflow authoring and execution.",
6
6
  "contributors": [
@@ -5041,9 +5041,49 @@ class StageUiBroker {
5041
5041
  resolvedPromptIds = new Map;
5042
5042
  resolvedListeners = new Set;
5043
5043
  registeredListeners = new Set;
5044
+ statuses = new Map;
5045
+ statusListeners = new Set;
5044
5046
  constructor(store = currentWorkflowStore()) {
5045
5047
  this.store = store;
5046
5048
  }
5049
+ setStageStatus(runId, stageId, statusKey, text) {
5050
+ const stageKey = key(runId, stageId);
5051
+ const current = this.statuses.get(stageKey);
5052
+ if (text === undefined) {
5053
+ if (!current?.delete(statusKey))
5054
+ return;
5055
+ if (current.size === 0)
5056
+ this.statuses.delete(stageKey);
5057
+ } else {
5058
+ if (current?.get(statusKey) === text)
5059
+ return;
5060
+ if (current)
5061
+ current.set(statusKey, text);
5062
+ else
5063
+ this.statuses.set(stageKey, new Map([[statusKey, text]]));
5064
+ }
5065
+ this.notifyStatusesChanged();
5066
+ }
5067
+ getStageStatuses(runId, stageId) {
5068
+ return this.statuses.get(key(runId, stageId)) ?? EMPTY_STATUSES;
5069
+ }
5070
+ clearStageStatuses(runId, stageId) {
5071
+ if (this.statuses.delete(key(runId, stageId)))
5072
+ this.notifyStatusesChanged();
5073
+ }
5074
+ onStageStatusesChanged(listener) {
5075
+ this.statusListeners.add(listener);
5076
+ return () => {
5077
+ this.statusListeners.delete(listener);
5078
+ };
5079
+ }
5080
+ notifyStatusesChanged() {
5081
+ for (const listener of this.statusListeners) {
5082
+ try {
5083
+ listener();
5084
+ } catch {}
5085
+ }
5086
+ }
5047
5087
  provideStagePrompt(runId, stageId, adapter) {
5048
5088
  const hostKey = key(runId, stageId);
5049
5089
  this.adapters.set(hostKey, adapter);
@@ -5270,10 +5310,11 @@ function adoptStageUiBroker(scope, preserveCurrentWhenTargetExists = false, stor
5270
5310
  function currentStageUiBroker() {
5271
5311
  return singleton3.current();
5272
5312
  }
5273
- var SESSION_KEY3 = "workflows:stage-ui:v1", singleton3, stageUiBroker;
5313
+ var EMPTY_STATUSES, SESSION_KEY3 = "workflows:stage-ui:v1", singleton3, stageUiBroker;
5274
5314
  var init_stage_ui_broker = __esm(() => {
5275
5315
  init_session_scoped_singleton();
5276
5316
  init_store_factory();
5317
+ EMPTY_STATUSES = new Map;
5277
5318
  singleton3 = createSessionScopedSingleton(SESSION_KEY3, () => new StageUiBroker);
5278
5319
  stageUiBroker = singleton3.facade;
5279
5320
  });
@@ -12360,9 +12401,9 @@ function makeStageExtensionUiContext(ui, meta, broker, inheritedBindingRevision,
12360
12401
  onTerminalInput: ui.onTerminalInput ?? (() => () => {
12361
12402
  return;
12362
12403
  }),
12363
- setStatus: ui.setStatus ?? (() => {
12404
+ setStatus: meta === undefined ? ui.setStatus ?? (() => {
12364
12405
  return;
12365
- }),
12406
+ }) : (statusKey, text) => broker.setStageStatus(meta.runId, meta.stageId, statusKey, text),
12366
12407
  setWorkingMessage: ui.setWorkingMessage ?? (() => {
12367
12408
  return;
12368
12409
  }),
@@ -12497,6 +12538,8 @@ function buildRuntimeAdapters(builtWith, options = {}) {
12497
12538
  if (meta?.isFallbackAttempt && inheritedOptions.model && inheritedOptions.isFallbackModelAllowed?.(inheritedOptions.model, inheritedOptions.thinkingLevel) === false)
12498
12539
  throw new Error("Workflow stage fallback model unavailable under inherited policy.");
12499
12540
  const sessionOptions = withWorkflowStageSessionOptions(inheritedOptions, meta, pi);
12541
+ if (meta !== undefined)
12542
+ broker.clearStageStatuses(meta.runId, meta.stageId);
12500
12543
  const stageUi = shouldBindStageUiContext(pi, meta) ? makeStageExtensionUiContext(pi.ui ?? {}, meta, broker, inheritedOptions.extensionBindings?.humanInput === undefined ? 0 : 1, stageOptions.extensionBindings?.humanInput !== undefined) : undefined;
12501
12544
  if (stageUi)
12502
12545
  sessionOptions.extensionBindings = {
@@ -79686,6 +79729,7 @@ function createWorkflowStageFactory(input) {
79686
79729
  stageSnapshot.artifacts = artifacts;
79687
79730
  input.activeStore.recordStageEnd(input.runId, stageSnapshot);
79688
79731
  input.stageUiBroker.cancelStagePrompt(input.runId, stageId, new Error(`atomic-workflows: stage ${stageId} completed with pending custom UI`));
79732
+ input.stageUiBroker.clearStageStatuses(input.runId, stageId);
79689
79733
  if (input.opts.onStageEnd) {
79690
79734
  await runCallback3({ kind: "workflow.stage_adapter", name: `onStageEnd:${name}`, runId: input.runId, stageId }, () => input.opts.onStageEnd(input.runId, stageSnapshot));
79691
79735
  }
@@ -90223,7 +90267,10 @@ function editorRuleColor(ctx, disabled, agentSession, state) {
90223
90267
 
90224
90268
  // dist/builtin/workflows/src/tui/stage-chat-view-state.ts
90225
90269
  init_stage_ui_broker();
90226
- import { ChatSessionHost, classifyChatCommand } from "@bastani/atomic";
90270
+ import {
90271
+ ChatSessionHost,
90272
+ classifyChatCommand
90273
+ } from "@bastani/atomic";
90227
90274
  import { Editor } from "@earendil-works/pi-tui";
90228
90275
 
90229
90276
  // dist/builtin/workflows/src/tui/prompt-card-input.ts
@@ -91064,8 +91111,8 @@ function initializeStageChatView(ctx, opts) {
91064
91111
  ctx.piEditorFactory = opts.piEditorFactory;
91065
91112
  ctx.getToolsExpanded = opts.getToolsExpanded;
91066
91113
  ctx.setToolsExpanded = opts.setToolsExpanded;
91067
- ctx.footerData = opts.footerData;
91068
91114
  ctx.stageUiBroker = opts.stageUiBroker ?? stageUiBroker;
91115
+ ctx.footerData = opts.footerData && stageFooterData(opts.footerData, ctx.stageUiBroker, opts.runId, opts.stageId);
91069
91116
  ctx.canSubmitPrompt = opts.canSubmitPrompt;
91070
91117
  ctx.mountedCustomUi = null;
91071
91118
  ctx.mountingRequestId = null;
@@ -91113,7 +91160,12 @@ function initializeStageChatView(ctx, opts) {
91113
91160
  if (initialChatIsTerminal)
91114
91161
  ctx.chatHost.clearBusyForTerminalWorkflowStage();
91115
91162
  ctx._unsubscribeStore = subscribeStoreInvalidation(ctx.store, () => handleStoreUpdate(ctx));
91116
- ctx._unsubscribeFooterData = ctx.footerData?.onBranchChange(() => ctx.requestRender?.()) ?? null;
91163
+ const unsubscribeBranch = ctx.footerData?.onBranchChange(() => ctx.requestRender?.());
91164
+ const unsubscribeStatuses = ctx.footerData ? ctx.stageUiBroker.onStageStatusesChanged(() => ctx.requestRender?.()) : undefined;
91165
+ ctx._unsubscribeFooterData = () => {
91166
+ unsubscribeBranch?.();
91167
+ unsubscribeStatuses?.();
91168
+ };
91117
91169
  if (ctx.handle) {
91118
91170
  ctx._unsubscribeDeliveryActivity = subscribeStageChatDeliveryActivity(ctx);
91119
91171
  ctx._unsubscribeHandle = ctx.handle.subscribe((event) => applyStageChatLiveHandleEvent(ctx, event));
@@ -91163,6 +91215,14 @@ function installFocusHold(ctx) {
91163
91215
  ctx.requestFocus?.();
91164
91216
  }, 150);
91165
91217
  }
91218
+ function stageFooterData(hostFooterData, broker, runId, stageId) {
91219
+ return {
91220
+ getGitBranch: (cwd) => hostFooterData.getGitBranch(cwd),
91221
+ getAvailableProviderCount: () => hostFooterData.getAvailableProviderCount(),
91222
+ onBranchChange: (callback, cwd) => hostFooterData.onBranchChange(callback, cwd),
91223
+ getExtensionStatuses: () => broker.getStageStatuses(runId, stageId)
91224
+ };
91225
+ }
91166
91226
  function createChatHost(ctx, opts) {
91167
91227
  return new ChatSessionHost({
91168
91228
  taskRowsInChat: false,
@@ -91266,7 +91326,7 @@ function createChatHost(ctx, opts) {
91266
91326
  editorFactory: opts.piEditorFactory,
91267
91327
  editorTheme: editorThemeFromGraphTheme(ctx.theme),
91268
91328
  getChatRenderSettings: () => stageChatRenderSettings(ctx, opts),
91269
- footerData: opts.footerData,
91329
+ footerData: ctx.footerData,
91270
91330
  renderExtraEntry: (entry) => noticeRow(entry, ctx.theme)
91271
91331
  });
91272
91332
  }
@@ -9246,9 +9246,49 @@ class StageUiBroker {
9246
9246
  resolvedPromptIds = new Map;
9247
9247
  resolvedListeners = new Set;
9248
9248
  registeredListeners = new Set;
9249
+ statuses = new Map;
9250
+ statusListeners = new Set;
9249
9251
  constructor(store = currentWorkflowStore()) {
9250
9252
  this.store = store;
9251
9253
  }
9254
+ setStageStatus(runId, stageId, statusKey, text) {
9255
+ const stageKey = key(runId, stageId);
9256
+ const current = this.statuses.get(stageKey);
9257
+ if (text === undefined) {
9258
+ if (!current?.delete(statusKey))
9259
+ return;
9260
+ if (current.size === 0)
9261
+ this.statuses.delete(stageKey);
9262
+ } else {
9263
+ if (current?.get(statusKey) === text)
9264
+ return;
9265
+ if (current)
9266
+ current.set(statusKey, text);
9267
+ else
9268
+ this.statuses.set(stageKey, new Map([[statusKey, text]]));
9269
+ }
9270
+ this.notifyStatusesChanged();
9271
+ }
9272
+ getStageStatuses(runId, stageId) {
9273
+ return this.statuses.get(key(runId, stageId)) ?? EMPTY_STATUSES;
9274
+ }
9275
+ clearStageStatuses(runId, stageId) {
9276
+ if (this.statuses.delete(key(runId, stageId)))
9277
+ this.notifyStatusesChanged();
9278
+ }
9279
+ onStageStatusesChanged(listener) {
9280
+ this.statusListeners.add(listener);
9281
+ return () => {
9282
+ this.statusListeners.delete(listener);
9283
+ };
9284
+ }
9285
+ notifyStatusesChanged() {
9286
+ for (const listener of this.statusListeners) {
9287
+ try {
9288
+ listener();
9289
+ } catch {}
9290
+ }
9291
+ }
9252
9292
  provideStagePrompt(runId, stageId, adapter) {
9253
9293
  const hostKey = key(runId, stageId);
9254
9294
  this.adapters.set(hostKey, adapter);
@@ -9442,10 +9482,11 @@ class StageUiBroker {
9442
9482
  function currentStageUiBroker() {
9443
9483
  return singleton2.current();
9444
9484
  }
9445
- var SESSION_KEY2 = "workflows:stage-ui:v1", singleton2, stageUiBroker;
9485
+ var EMPTY_STATUSES, SESSION_KEY2 = "workflows:stage-ui:v1", singleton2, stageUiBroker;
9446
9486
  var init_stage_ui_broker = __esm(() => {
9447
9487
  init_session_scoped_singleton();
9448
9488
  init_store_factory();
9489
+ EMPTY_STATUSES = new Map;
9449
9490
  singleton2 = createSessionScopedSingleton(SESSION_KEY2, () => new StageUiBroker);
9450
9491
  stageUiBroker = singleton2.facade;
9451
9492
  });
@@ -9851,9 +9892,9 @@ function makeStageExtensionUiContext(ui, meta, broker, inheritedBindingRevision,
9851
9892
  onTerminalInput: ui.onTerminalInput ?? (() => () => {
9852
9893
  return;
9853
9894
  }),
9854
- setStatus: ui.setStatus ?? (() => {
9895
+ setStatus: meta === undefined ? ui.setStatus ?? (() => {
9855
9896
  return;
9856
- }),
9897
+ }) : (statusKey, text) => broker.setStageStatus(meta.runId, meta.stageId, statusKey, text),
9857
9898
  setWorkingMessage: ui.setWorkingMessage ?? (() => {
9858
9899
  return;
9859
9900
  }),
@@ -9988,6 +10029,8 @@ function buildRuntimeAdapters(builtWith, options = {}) {
9988
10029
  if (meta?.isFallbackAttempt && inheritedOptions.model && inheritedOptions.isFallbackModelAllowed?.(inheritedOptions.model, inheritedOptions.thinkingLevel) === false)
9989
10030
  throw new Error("Workflow stage fallback model unavailable under inherited policy.");
9990
10031
  const sessionOptions = withWorkflowStageSessionOptions(inheritedOptions, meta, pi);
10032
+ if (meta !== undefined)
10033
+ broker.clearStageStatuses(meta.runId, meta.stageId);
9991
10034
  const stageUi = shouldBindStageUiContext(pi, meta) ? makeStageExtensionUiContext(pi.ui ?? {}, meta, broker, inheritedOptions.extensionBindings?.humanInput === undefined ? 0 : 1, stageOptions.extensionBindings?.humanInput !== undefined) : undefined;
9992
10035
  if (stageUi)
9993
10036
  sessionOptions.extensionBindings = {
@@ -77524,6 +77567,7 @@ function createWorkflowStageFactory(input) {
77524
77567
  stageSnapshot.artifacts = artifacts;
77525
77568
  input.activeStore.recordStageEnd(input.runId, stageSnapshot);
77526
77569
  input.stageUiBroker.cancelStagePrompt(input.runId, stageId, new Error(`atomic-workflows: stage ${stageId} completed with pending custom UI`));
77570
+ input.stageUiBroker.clearStageStatuses(input.runId, stageId);
77527
77571
  if (input.opts.onStageEnd) {
77528
77572
  await runCallback3({ kind: "workflow.stage_adapter", name: `onStageEnd:${name}`, runId: input.runId, stageId }, () => input.opts.onStageEnd(input.runId, stageSnapshot));
77529
77573
  }
@@ -6556,9 +6556,49 @@ class StageUiBroker {
6556
6556
  resolvedPromptIds = new Map;
6557
6557
  resolvedListeners = new Set;
6558
6558
  registeredListeners = new Set;
6559
+ statuses = new Map;
6560
+ statusListeners = new Set;
6559
6561
  constructor(store = currentWorkflowStore()) {
6560
6562
  this.store = store;
6561
6563
  }
6564
+ setStageStatus(runId, stageId, statusKey, text) {
6565
+ const stageKey = key(runId, stageId);
6566
+ const current = this.statuses.get(stageKey);
6567
+ if (text === undefined) {
6568
+ if (!current?.delete(statusKey))
6569
+ return;
6570
+ if (current.size === 0)
6571
+ this.statuses.delete(stageKey);
6572
+ } else {
6573
+ if (current?.get(statusKey) === text)
6574
+ return;
6575
+ if (current)
6576
+ current.set(statusKey, text);
6577
+ else
6578
+ this.statuses.set(stageKey, new Map([[statusKey, text]]));
6579
+ }
6580
+ this.notifyStatusesChanged();
6581
+ }
6582
+ getStageStatuses(runId, stageId) {
6583
+ return this.statuses.get(key(runId, stageId)) ?? EMPTY_STATUSES;
6584
+ }
6585
+ clearStageStatuses(runId, stageId) {
6586
+ if (this.statuses.delete(key(runId, stageId)))
6587
+ this.notifyStatusesChanged();
6588
+ }
6589
+ onStageStatusesChanged(listener) {
6590
+ this.statusListeners.add(listener);
6591
+ return () => {
6592
+ this.statusListeners.delete(listener);
6593
+ };
6594
+ }
6595
+ notifyStatusesChanged() {
6596
+ for (const listener of this.statusListeners) {
6597
+ try {
6598
+ listener();
6599
+ } catch {}
6600
+ }
6601
+ }
6562
6602
  provideStagePrompt(runId, stageId, adapter) {
6563
6603
  const hostKey = key(runId, stageId);
6564
6604
  this.adapters.set(hostKey, adapter);
@@ -6752,10 +6792,11 @@ class StageUiBroker {
6752
6792
  function currentStageUiBroker() {
6753
6793
  return singleton2.current();
6754
6794
  }
6755
- var SESSION_KEY2 = "workflows:stage-ui:v1", singleton2, stageUiBroker;
6795
+ var EMPTY_STATUSES, SESSION_KEY2 = "workflows:stage-ui:v1", singleton2, stageUiBroker;
6756
6796
  var init_stage_ui_broker = __esm(() => {
6757
6797
  init_session_scoped_singleton();
6758
6798
  init_store_factory();
6799
+ EMPTY_STATUSES = new Map;
6759
6800
  singleton2 = createSessionScopedSingleton(SESSION_KEY2, () => new StageUiBroker);
6760
6801
  stageUiBroker = singleton2.facade;
6761
6802
  });
@@ -7161,9 +7202,9 @@ function makeStageExtensionUiContext(ui, meta, broker, inheritedBindingRevision,
7161
7202
  onTerminalInput: ui.onTerminalInput ?? (() => () => {
7162
7203
  return;
7163
7204
  }),
7164
- setStatus: ui.setStatus ?? (() => {
7205
+ setStatus: meta === undefined ? ui.setStatus ?? (() => {
7165
7206
  return;
7166
- }),
7207
+ }) : (statusKey, text) => broker.setStageStatus(meta.runId, meta.stageId, statusKey, text),
7167
7208
  setWorkingMessage: ui.setWorkingMessage ?? (() => {
7168
7209
  return;
7169
7210
  }),
@@ -7298,6 +7339,8 @@ function buildRuntimeAdapters(builtWith, options = {}) {
7298
7339
  if (meta?.isFallbackAttempt && inheritedOptions.model && inheritedOptions.isFallbackModelAllowed?.(inheritedOptions.model, inheritedOptions.thinkingLevel) === false)
7299
7340
  throw new Error("Workflow stage fallback model unavailable under inherited policy.");
7300
7341
  const sessionOptions = withWorkflowStageSessionOptions(inheritedOptions, meta, pi);
7342
+ if (meta !== undefined)
7343
+ broker.clearStageStatuses(meta.runId, meta.stageId);
7301
7344
  const stageUi = shouldBindStageUiContext(pi, meta) ? makeStageExtensionUiContext(pi.ui ?? {}, meta, broker, inheritedOptions.extensionBindings?.humanInput === undefined ? 0 : 1, stageOptions.extensionBindings?.humanInput !== undefined) : undefined;
7302
7345
  if (stageUi)
7303
7346
  sessionOptions.extensionBindings = {
@@ -77504,6 +77547,7 @@ function createWorkflowStageFactory(input) {
77504
77547
  stageSnapshot.artifacts = artifacts;
77505
77548
  input.activeStore.recordStageEnd(input.runId, stageSnapshot);
77506
77549
  input.stageUiBroker.cancelStagePrompt(input.runId, stageId, new Error(`atomic-workflows: stage ${stageId} completed with pending custom UI`));
77550
+ input.stageUiBroker.clearStageStatuses(input.runId, stageId);
77507
77551
  if (input.opts.onStageEnd) {
77508
77552
  await runCallback3({ kind: "workflow.stage_adapter", name: `onStageEnd:${name}`, runId: input.runId, stageId }, () => input.opts.onStageEnd(input.runId, stageSnapshot));
77509
77553
  }
@@ -9246,9 +9246,49 @@ class StageUiBroker {
9246
9246
  resolvedPromptIds = new Map;
9247
9247
  resolvedListeners = new Set;
9248
9248
  registeredListeners = new Set;
9249
+ statuses = new Map;
9250
+ statusListeners = new Set;
9249
9251
  constructor(store = currentWorkflowStore()) {
9250
9252
  this.store = store;
9251
9253
  }
9254
+ setStageStatus(runId, stageId, statusKey, text) {
9255
+ const stageKey = key(runId, stageId);
9256
+ const current = this.statuses.get(stageKey);
9257
+ if (text === undefined) {
9258
+ if (!current?.delete(statusKey))
9259
+ return;
9260
+ if (current.size === 0)
9261
+ this.statuses.delete(stageKey);
9262
+ } else {
9263
+ if (current?.get(statusKey) === text)
9264
+ return;
9265
+ if (current)
9266
+ current.set(statusKey, text);
9267
+ else
9268
+ this.statuses.set(stageKey, new Map([[statusKey, text]]));
9269
+ }
9270
+ this.notifyStatusesChanged();
9271
+ }
9272
+ getStageStatuses(runId, stageId) {
9273
+ return this.statuses.get(key(runId, stageId)) ?? EMPTY_STATUSES;
9274
+ }
9275
+ clearStageStatuses(runId, stageId) {
9276
+ if (this.statuses.delete(key(runId, stageId)))
9277
+ this.notifyStatusesChanged();
9278
+ }
9279
+ onStageStatusesChanged(listener) {
9280
+ this.statusListeners.add(listener);
9281
+ return () => {
9282
+ this.statusListeners.delete(listener);
9283
+ };
9284
+ }
9285
+ notifyStatusesChanged() {
9286
+ for (const listener of this.statusListeners) {
9287
+ try {
9288
+ listener();
9289
+ } catch {}
9290
+ }
9291
+ }
9252
9292
  provideStagePrompt(runId, stageId, adapter) {
9253
9293
  const hostKey = key(runId, stageId);
9254
9294
  this.adapters.set(hostKey, adapter);
@@ -9442,10 +9482,11 @@ class StageUiBroker {
9442
9482
  function currentStageUiBroker() {
9443
9483
  return singleton2.current();
9444
9484
  }
9445
- var SESSION_KEY2 = "workflows:stage-ui:v1", singleton2, stageUiBroker;
9485
+ var EMPTY_STATUSES, SESSION_KEY2 = "workflows:stage-ui:v1", singleton2, stageUiBroker;
9446
9486
  var init_stage_ui_broker = __esm(() => {
9447
9487
  init_session_scoped_singleton();
9448
9488
  init_store_factory();
9489
+ EMPTY_STATUSES = new Map;
9449
9490
  singleton2 = createSessionScopedSingleton(SESSION_KEY2, () => new StageUiBroker);
9450
9491
  stageUiBroker = singleton2.facade;
9451
9492
  });
@@ -9851,9 +9892,9 @@ function makeStageExtensionUiContext(ui, meta, broker, inheritedBindingRevision,
9851
9892
  onTerminalInput: ui.onTerminalInput ?? (() => () => {
9852
9893
  return;
9853
9894
  }),
9854
- setStatus: ui.setStatus ?? (() => {
9895
+ setStatus: meta === undefined ? ui.setStatus ?? (() => {
9855
9896
  return;
9856
- }),
9897
+ }) : (statusKey, text) => broker.setStageStatus(meta.runId, meta.stageId, statusKey, text),
9857
9898
  setWorkingMessage: ui.setWorkingMessage ?? (() => {
9858
9899
  return;
9859
9900
  }),
@@ -9988,6 +10029,8 @@ function buildRuntimeAdapters(builtWith, options = {}) {
9988
10029
  if (meta?.isFallbackAttempt && inheritedOptions.model && inheritedOptions.isFallbackModelAllowed?.(inheritedOptions.model, inheritedOptions.thinkingLevel) === false)
9989
10030
  throw new Error("Workflow stage fallback model unavailable under inherited policy.");
9990
10031
  const sessionOptions = withWorkflowStageSessionOptions(inheritedOptions, meta, pi);
10032
+ if (meta !== undefined)
10033
+ broker.clearStageStatuses(meta.runId, meta.stageId);
9991
10034
  const stageUi = shouldBindStageUiContext(pi, meta) ? makeStageExtensionUiContext(pi.ui ?? {}, meta, broker, inheritedOptions.extensionBindings?.humanInput === undefined ? 0 : 1, stageOptions.extensionBindings?.humanInput !== undefined) : undefined;
9992
10035
  if (stageUi)
9993
10036
  sessionOptions.extensionBindings = {
@@ -77524,6 +77567,7 @@ function createWorkflowStageFactory(input) {
77524
77567
  stageSnapshot.artifacts = artifacts;
77525
77568
  input.activeStore.recordStageEnd(input.runId, stageSnapshot);
77526
77569
  input.stageUiBroker.cancelStagePrompt(input.runId, stageId, new Error(`atomic-workflows: stage ${stageId} completed with pending custom UI`));
77570
+ input.stageUiBroker.clearStageStatuses(input.runId, stageId);
77527
77571
  if (input.opts.onStageEnd) {
77528
77572
  await runCallback3({ kind: "workflow.stage_adapter", name: `onStageEnd:${name}`, runId: input.runId, stageId }, () => input.opts.onStageEnd(input.runId, stageSnapshot));
77529
77573
  }
@@ -1,8 +1,46 @@
1
- # Fetching web content
1
+ # Web access
2
+
3
+ Atomic bundles `web_search` for searching the web and `fetch_content` for reading pages. `web_search` works with no setup; the sections below cover how it picks a provider and how to configure one.
4
+
5
+ ## Searching with `web_search`
6
+
7
+ Pass `query`, or `queries` for several angles at once. `provider` can be `auto` (the default), `exa`, `perplexity`, or `gemini`.
8
+
9
+ With `auto`, Atomic uses the first provider that works:
10
+
11
+ 1. **Exa**: with a key it calls the Exa API; without one it uses Exa's free keyless MCP endpoint (`mcp.exa.ai`), so an unconfigured machine with network access still gets results.
12
+ 2. **Perplexity**, with a key.
13
+ 3. **Gemini API**, with a key.
14
+ 4. **Gemini Web**, using your signed-in Chromium-based browser. Browser cookie access is off by default; enable it with `allowBrowserCookies: true` or `ATOMIC_ALLOW_BROWSER_COOKIES=1`.
15
+
16
+ Keys come from the environment or from `~/.atomic/web-search.json`:
17
+
18
+ | Provider | Environment variable | `web-search.json` field |
19
+ | --- | --- | --- |
20
+ | Exa | `EXA_API_KEY` | `exaApiKey` |
21
+ | Perplexity | `PERPLEXITY_API_KEY` | `perplexityApiKey` |
22
+ | Gemini API | `GEMINI_API_KEY` | `geminiApiKey` |
23
+
24
+ ```json
25
+ {
26
+ "exaApiKey": "your-key",
27
+ "provider": "auto"
28
+ }
29
+ ```
30
+
31
+ `provider` sets the default provider. When no provider can be reached, the error names these settings.
32
+
33
+ ### The search curator
34
+
35
+ By default `web_search` returns raw results. `/curator on` (or `"workflow": "summary-review"` in `web-search.json`) opens a browser page where you review the results and approve a summary before the agent sees them; `/curator off` turns it back off. The curator changes how results are reviewed, not which provider is used.
36
+
37
+ It needs an interactive session with a person at a browser. Subagents, workflow stages, and non-interactive runs skip it and return raw results. If the page cannot open, for example on a machine with no desktop browser, `web_search` returns raw results with a note instead of failing; run `/curator off` to stop trying.
38
+
39
+ ## Fetching with `fetch_content`
2
40
 
3
41
  Atomic's bundled `fetch_content` tool reads webpages, PDFs, GitHub repositories, YouTube videos, and local video files.
4
42
 
5
- ## Arguments
43
+ ### Arguments
6
44
 
7
45
  Always pass the lowercase `urls` field as a nonempty array of strings, even for one URL:
8
46
 
@@ -38,7 +76,7 @@ Existing prompts or integrations using `{"url": "..."}` must change to `{"urls":
38
76
 
39
77
  Atomic can normalize a scalar `urls` string into a one-item array. Always use the documented array form in prompts and integrations; the legacy `url` field is not normalized.
40
78
 
41
- ## Troubleshooting
79
+ ### Troubleshooting
42
80
 
43
81
  If argument validation fails, check that:
44
82
 
@@ -211,7 +211,7 @@ Surface behavior:
211
211
  - **Wheel and trackpad** - While the workflow graph is active, vertical wheel/trackpad gestures pan it up and down, and horizontal gestures pan wide graphs left and right when the terminal exposes horizontal wheel events. Focused graph and stage-chat overlays receive those gestures through the fullscreen application route, so scrolling stays inside the active workflow surface instead of falling through to terminal or main-chat scrollback.
212
212
  - **Selection and copying** - Graph panning, stage scrolling, click-to-attach, and drag or multi-click selection work without a separate selection mode. Copy uses OSC 52; if the terminal blocks it, use its Shift/Option modifier-drag bypass. `ctrl+t` retains the host thinking toggle, not a workflow action.
213
213
  - **Tool and node detail** - Attached stage chats match main chat's tool-detail expansion behavior while keeping expansion state local to the workflow UI context. Press Ctrl+O (the configurable `app.tools.expand` binding) to expand every visible workflow node and tool card, including single, parallel, and nested subagent progress, current tool activity, and artifact paths; press it again to collapse them. The toggle works for active, completed, and archived stage views, including at the supported 40-column terminal minimum. A mounted prompt, custom question, or other input-owning overlay keeps the key instead of changing it.
214
- - **Footer context** - An attached live stage chat shows its own current folder and Git branch and mirrors live extension status lines such as the MCP server indicator. Branch changes trigger a repaint through the host's cached footer provider. The compact `/tasks` picker retains this context and the stage's model and reasoning level even while its foreground turn streams; detail, transcript, input, and confirmation pages remain fullscreen.
214
+ - **Footer context** - An attached live stage chat shows its own current folder and Git branch and shows the live extension status lines that the stage's own session sets, such as the MCP server indicator, never the main chat's. Branch changes trigger a repaint through the host's cached footer provider. The compact `/tasks` picker retains this context and the stage's model and reasoning level even while its foreground turn streams; detail, transcript, input, and confirmation pages remain fullscreen.
215
215
  - **Working indicator** - Stage chat shows `∀` during accepted prompt startup and active work, including retained-session follow-ups. Retry, fallback, compaction, cancellation, and errors take precedence. `NO_COLOR` removes foreground colors; `ATOMIC_REDUCED_MOTION=1` makes the indicator static.
216
216
  - **Subagent statusline** - If a subagent is running while the fullscreen workflow graph is open, the graph statusline mirrors its summary so the run remains visible; hide the graph with `h`, leave it with `ctrl+x`, or reconnect later to return to the full below-editor widget.
217
217
  - **Run control** - Use `pause` and `resume` for resumable live work. Pause holds a stage's queued steering and follow-up items in place without dequeuing them or starting continuation; `resume` releases those items once in their existing per-queue order, but queue release alone does not start a model turn. `resume` on a non-paused run reopens the saved snapshot or overlay. Use `quit` to pause a live run gracefully while preserving it for `/workflow resume`. `/workflow pause` selects the active run by default, accepts a full run id or `--all`, and does not open a stage picker. `/workflow pause <run-id> <stage>` pauses only that stage, named by id, name or unique prefix as `/workflow attach` resolves it, and `/workflow resume <run-id> <stage>` resumes it. The workflow tool's `stageId` does the same and also targets tool nodes.
@@ -1,16 +1,16 @@
1
1
  {
2
2
  "name": "@bastani/atomic",
3
- "version": "0.9.51",
3
+ "version": "0.9.52-alpha.1",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@bastani/atomic",
9
- "version": "0.9.51",
9
+ "version": "0.9.52-alpha.1",
10
10
  "license": "MIT",
11
11
  "dependencies": {
12
- "@bastani/atomic-natives": "0.9.51",
13
- "@bastani/pi-ai": "0.9.51",
12
+ "@bastani/atomic-natives": "0.9.52-alpha.1",
13
+ "@bastani/pi-ai": "0.9.52-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.51",
431
- "resolved": "https://registry.npmjs.org/@bastani/atomic-natives/-/atomic-natives-0.9.51.tgz",
430
+ "version": "0.9.52-alpha.1",
431
+ "resolved": "https://registry.npmjs.org/@bastani/atomic-natives/-/atomic-natives-0.9.52-alpha.1.tgz",
432
432
  "license": "MIT",
433
433
  "optionalDependencies": {
434
- "@bastani/atomic-natives-darwin-arm64": "0.9.51",
435
- "@bastani/atomic-natives-darwin-x64": "0.9.51",
436
- "@bastani/atomic-natives-linux-arm64-gnu": "0.9.51",
437
- "@bastani/atomic-natives-linux-arm64-musl": "0.9.51",
438
- "@bastani/atomic-natives-linux-x64-gnu": "0.9.51",
439
- "@bastani/atomic-natives-linux-x64-musl": "0.9.51",
440
- "@bastani/atomic-natives-win32-arm64-msvc": "0.9.51",
441
- "@bastani/atomic-natives-win32-x64-msvc": "0.9.51"
434
+ "@bastani/atomic-natives-darwin-arm64": "0.9.52-alpha.1",
435
+ "@bastani/atomic-natives-darwin-x64": "0.9.52-alpha.1",
436
+ "@bastani/atomic-natives-linux-arm64-gnu": "0.9.52-alpha.1",
437
+ "@bastani/atomic-natives-linux-arm64-musl": "0.9.52-alpha.1",
438
+ "@bastani/atomic-natives-linux-x64-gnu": "0.9.52-alpha.1",
439
+ "@bastani/atomic-natives-linux-x64-musl": "0.9.52-alpha.1",
440
+ "@bastani/atomic-natives-win32-arm64-msvc": "0.9.52-alpha.1",
441
+ "@bastani/atomic-natives-win32-x64-msvc": "0.9.52-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.51",
450
- "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-darwin-arm64/-/atomic-natives-darwin-arm64-0.9.51.tgz",
449
+ "version": "0.9.52-alpha.1",
450
+ "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-darwin-arm64/-/atomic-natives-darwin-arm64-0.9.52-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.51",
462
- "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-darwin-x64/-/atomic-natives-darwin-x64-0.9.51.tgz",
461
+ "version": "0.9.52-alpha.1",
462
+ "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-darwin-x64/-/atomic-natives-darwin-x64-0.9.52-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.51",
474
- "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-linux-arm64-gnu/-/atomic-natives-linux-arm64-gnu-0.9.51.tgz",
473
+ "version": "0.9.52-alpha.1",
474
+ "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-linux-arm64-gnu/-/atomic-natives-linux-arm64-gnu-0.9.52-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.51",
489
- "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-linux-arm64-musl/-/atomic-natives-linux-arm64-musl-0.9.51.tgz",
488
+ "version": "0.9.52-alpha.1",
489
+ "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-linux-arm64-musl/-/atomic-natives-linux-arm64-musl-0.9.52-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.51",
504
- "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-linux-x64-gnu/-/atomic-natives-linux-x64-gnu-0.9.51.tgz",
503
+ "version": "0.9.52-alpha.1",
504
+ "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-linux-x64-gnu/-/atomic-natives-linux-x64-gnu-0.9.52-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.51",
519
- "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-linux-x64-musl/-/atomic-natives-linux-x64-musl-0.9.51.tgz",
518
+ "version": "0.9.52-alpha.1",
519
+ "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-linux-x64-musl/-/atomic-natives-linux-x64-musl-0.9.52-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.51",
534
- "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-win32-arm64-msvc/-/atomic-natives-win32-arm64-msvc-0.9.51.tgz",
533
+ "version": "0.9.52-alpha.1",
534
+ "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-win32-arm64-msvc/-/atomic-natives-win32-arm64-msvc-0.9.52-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.51",
546
- "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-win32-x64-msvc/-/atomic-natives-win32-x64-msvc-0.9.51.tgz",
545
+ "version": "0.9.52-alpha.1",
546
+ "resolved": "https://registry.npmjs.org/@bastani/atomic-natives-win32-x64-msvc/-/atomic-natives-win32-x64-msvc-0.9.52-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.51",
558
- "resolved": "https://registry.npmjs.org/@bastani/pi-ai/-/pi-ai-0.9.51.tgz",
557
+ "version": "0.9.52-alpha.1",
558
+ "resolved": "https://registry.npmjs.org/@bastani/pi-ai/-/pi-ai-0.9.52-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.51",
3
+ "version": "0.9.52-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.51",
93
- "@bastani/pi-ai": "0.9.51",
92
+ "@bastani/atomic-natives": "0.9.52-alpha.1",
93
+ "@bastani/pi-ai": "0.9.52-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",