atlarix 14.42.0 → 14.43.0

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.
@@ -26524,11 +26524,49 @@ var init_zod = __esm({
26524
26524
  }
26525
26525
  });
26526
26526
 
26527
+ // src/lib/i18n/locales.ts
26528
+ var SUPPORTED_LOCALES, LOCALE_ENGLISH_NAMES;
26529
+ var init_locales2 = __esm({
26530
+ "src/lib/i18n/locales.ts"() {
26531
+ SUPPORTED_LOCALES = [
26532
+ "en-us",
26533
+ "zh-hans",
26534
+ "fr",
26535
+ "de",
26536
+ "hi",
26537
+ "it",
26538
+ "ja",
26539
+ "ko",
26540
+ "pl",
26541
+ "pt-br",
26542
+ "ru",
26543
+ "es",
26544
+ "tr"
26545
+ ];
26546
+ LOCALE_ENGLISH_NAMES = {
26547
+ "en-us": "English",
26548
+ "zh-hans": "Simplified Chinese",
26549
+ fr: "French",
26550
+ de: "German",
26551
+ hi: "Hindi",
26552
+ it: "Italian",
26553
+ ja: "Japanese",
26554
+ ko: "Korean",
26555
+ pl: "Polish",
26556
+ "pt-br": "Brazilian Portuguese",
26557
+ ru: "Russian",
26558
+ es: "Spanish",
26559
+ tr: "Turkish"
26560
+ };
26561
+ }
26562
+ });
26563
+
26527
26564
  // src/lib/schemas.ts
26528
26565
  var SecretSchema, ChatSummarySchema, ChatSearchResultSchema, AppSearchResultSchema, AppSearchResultsSchema, LargeLanguageModelSchema, RegularProviderSettingSchema, AzureProviderSettingSchema, VertexProviderSettingSchema, ProviderSettingSchema, RuntimeModeSchema, ChatModeSchema, WorkModeSchema, AgentModeSchema, GuidedConfigSchema, AutonomousConfigSchema, DelegationConfigSchema, SelfReviewConfigSchema, ContextSummarizationConfigSchema, ActivityStreamConfigSchema, AIConfigurationSchema, GlobPathSchema, AppChatContextSchema, ReleaseChannelSchema, ZoomLevelSchema, DBConnectionConfigStoredSchema, DBConnectionStoredSchema, UserSettingsSchema;
26529
26566
  var init_schemas3 = __esm({
26530
26567
  "src/lib/schemas.ts"() {
26531
26568
  init_zod();
26569
+ init_locales2();
26532
26570
  SecretSchema = external_exports.object({
26533
26571
  value: external_exports.string(),
26534
26572
  encryptionType: external_exports.enum(["electron-safe-storage", "plaintext"]).optional()
@@ -26795,6 +26833,21 @@ var init_schemas3 = __esm({
26795
26833
  * language never needs a schema change (same reasoning as
26796
26834
  * `voiceTranscriptionProvider`). */
26797
26835
  voiceLanguage: external_exports.string().optional(),
26836
+ /**
26837
+ * UI language AND the language the assistant replies in.
26838
+ *
26839
+ * An ENUM, unlike `voiceLanguage` directly above, and the divergence is
26840
+ * deliberate: that one is free-form because any ISO-639-1 code is meaningful to
26841
+ * Whisper, so a new language needs no schema change. A value HERE selects a
26842
+ * bundled catalog, so an unrecognised tag renders a blank UI rather than a
26843
+ * degraded one.
26844
+ *
26845
+ * Unset means "derive from the OS locale", resolved at READ time rather than
26846
+ * defaulted at first launch — so a user who changes their system language sees
26847
+ * Atlarix follow, instead of being frozen to whatever it was when they
26848
+ * installed. That is why there is no entry in DEFAULT_SETTINGS.
26849
+ */
26850
+ appLanguage: external_exports.enum(SUPPORTED_LOCALES).optional(),
26798
26851
  /** @deprecated superseded by the binary `deepThinking` toggle (v14.8.5). */
26799
26852
  thinkingBudget: external_exports.enum(["low", "medium", "high"]).optional(),
26800
26853
  /**
@@ -29483,6 +29536,7 @@ var init_system_prompt = __esm({
29483
29536
  init_agent_memory();
29484
29537
  init_resolve_shell();
29485
29538
  init_settings();
29539
+ init_locales2();
29486
29540
  init_project_memory2();
29487
29541
  init_shared_fragments();
29488
29542
  logger6 = import_electron_log6.default.scope("system_prompt");
@@ -29600,6 +29654,9 @@ Operating system: **${os4.type()} ${os4.release()}** (${os4.arch()}). Shell comm
29600
29654
  This machine has **${cpuCount} CPU cores** and **${totalMemGb} GB RAM**. Dev servers, the browser, and concurrent sub-agents all compete for those \u2014 scale what you run at once to these specs.`;
29601
29655
  const contextBudgetInfo = `# Context budget
29602
29656
  Your context window this session is **${contextSize.toLocaleString("en-US")} tokens**. You are warned explicitly when it is close to full, and older turns are summarised for you \u2014 so a long thread is not a full one. Anything a summary left out is still in this session's transcript: use \`session_search\` to retrieve a specific earlier fact rather than guessing at it.`;
29657
+ const appLanguage = readSettings().appLanguage;
29658
+ const responseLanguage = appLanguage && appLanguage !== "en-us" ? `# Response language
29659
+ Reply in ${LOCALE_ENGLISH_NAMES[appLanguage]}. Keep code, file paths, shell commands, identifiers and commit messages in their original language. The user can change this in Settings \u2192 General \u2192 Language.` : "";
29603
29660
  const stableHeader = [
29604
29661
  runtimeIdentity,
29605
29662
  base.trim(),
@@ -29607,7 +29664,8 @@ Your context window this session is **${contextSize.toLocaleString("en-US")} tok
29607
29664
  outputStyleRule,
29608
29665
  modeBundle,
29609
29666
  deviceInfo,
29610
- contextBudgetInfo
29667
+ contextBudgetInfo,
29668
+ responseLanguage
29611
29669
  ].filter((s3) => s3.length > 0).join("\n\n");
29612
29670
  const currentDate = (/* @__PURE__ */ new Date()).toLocaleDateString("en-US", {
29613
29671
  weekday: "long",
@@ -235874,7 +235932,7 @@ var init_display_snapshot2 = __esm({
235874
235932
 
235875
235933
  // src/lib/attachment-persistence.ts
235876
235934
  function sanitizeAttachmentFilename(name29) {
235877
- return name29.replace(/[^\w\s.\-()·]/g, "_").slice(0, 120) || "attachment";
235935
+ return name29.replace(/[^\p{L}\p{N}\p{M}\s.\-()·]/gu, "_").slice(0, 120) || "attachment";
235878
235936
  }
235879
235937
  function fnv1aHex(input) {
235880
235938
  let hash3 = 2166136261;
@@ -238654,6 +238712,17 @@ var init_tool_result_status = __esm({
238654
238712
  });
238655
238713
 
238656
238714
  // src/lib/tools/registry.ts
238715
+ function largestStringField(o2) {
238716
+ let key = null;
238717
+ let len = -1;
238718
+ for (const [k2, v2] of Object.entries(o2)) {
238719
+ if (typeof v2 === "string" && v2.length > len) {
238720
+ key = k2;
238721
+ len = v2.length;
238722
+ }
238723
+ }
238724
+ return key;
238725
+ }
238657
238726
  async function maybeTruncateToolOutput(toolName, result2) {
238658
238727
  if (NEVER_TRUNCATE.has(toolName) || SELF_PAGINATED_TOOLS.has(toolName) || extractImageMedia(result2)) {
238659
238728
  return { value: result2, truncated: false, totalChars: 0 };
@@ -238673,16 +238742,41 @@ async function maybeTruncateToolOutput(toolName, result2) {
238673
238742
  return { value: result2, truncated: false, totalChars: resultStr.length };
238674
238743
  }
238675
238744
  }
238745
+ const hint = TRUNCATION_HINTS[toolName] ?? TRUNCATION_HINT_DEFAULT;
238746
+ const noticeFor = (omitted, total) => `
238747
+
238748
+ [output truncated: ${omitted.toLocaleString("en-US")} of ${total.toLocaleString("en-US")} chars omitted. To see more: ${hint}]`;
238749
+ if (result2 !== null && typeof result2 === "object" && !Array.isArray(result2)) {
238750
+ const obj2 = result2;
238751
+ const field = largestStringField(obj2);
238752
+ if (field) {
238753
+ const original = obj2[field];
238754
+ const overhead = resultStr.length - original.length;
238755
+ const { text: preview2, omittedChars: omittedChars2 } = truncateLib.headTailTruncateToTokens(
238756
+ original,
238757
+ TOOL_OUTPUT_PREVIEW_HEAD_TOKENS,
238758
+ TOOL_OUTPUT_PREVIEW_TAIL_TOKENS
238759
+ );
238760
+ if (omittedChars2 > 0) {
238761
+ return {
238762
+ value: {
238763
+ ...obj2,
238764
+ [field]: `${preview2}${noticeFor(omittedChars2, original.length)}`
238765
+ },
238766
+ truncated: true,
238767
+ totalChars: resultStr.length
238768
+ };
238769
+ }
238770
+ void overhead;
238771
+ }
238772
+ }
238676
238773
  const { text: preview, omittedChars } = truncateLib.headTailTruncateToTokens(
238677
238774
  resultStr,
238678
238775
  TOOL_OUTPUT_PREVIEW_HEAD_TOKENS,
238679
238776
  TOOL_OUTPUT_PREVIEW_TAIL_TOKENS
238680
238777
  );
238681
- const notice = `
238682
-
238683
- [output truncated: ${omittedChars.toLocaleString("en-US")} of ${resultStr.length.toLocaleString("en-US")} chars omitted. To see more: for a file, call read_file again with offset/limit on the same path; for a command, narrow it (pipe through head/grep or target a specific path).]`;
238684
238778
  return {
238685
- value: `${preview}${notice}`,
238779
+ value: `${preview}${noticeFor(omittedChars, resultStr.length)}`,
238686
238780
  truncated: true,
238687
238781
  totalChars: resultStr.length
238688
238782
  };
@@ -238753,7 +238847,7 @@ function enumParam(nameOrDescription, requiredOrDefault, defaultOrOptions, optio
238753
238847
  if (opts) param2.enum = opts;
238754
238848
  return param2;
238755
238849
  }
238756
- var TOOL_OUTPUT_BYTE_CEILING, TOOL_OUTPUT_CHAR_FLOOR, TOOL_OUTPUT_TOKEN_BUDGET, TOOL_OUTPUT_PREVIEW_HEAD_TOKENS, TOOL_OUTPUT_PREVIEW_TAIL_TOKENS, NEVER_TRUNCATE, SELF_PAGINATED_TOOLS, ToolRegistry;
238850
+ var TOOL_OUTPUT_BYTE_CEILING, TOOL_OUTPUT_CHAR_FLOOR, TOOL_OUTPUT_TOKEN_BUDGET, TOOL_OUTPUT_PREVIEW_HEAD_TOKENS, TOOL_OUTPUT_PREVIEW_TAIL_TOKENS, NEVER_TRUNCATE, SELF_PAGINATED_TOOLS, TRUNCATION_HINTS, TRUNCATION_HINT_DEFAULT, ToolRegistry;
238757
238851
  var init_registry = __esm({
238758
238852
  "src/lib/tools/registry.ts"() {
238759
238853
  init_is_main_node();
@@ -238767,7 +238861,19 @@ var init_registry = __esm({
238767
238861
  TOOL_OUTPUT_PREVIEW_HEAD_TOKENS = 1500;
238768
238862
  TOOL_OUTPUT_PREVIEW_TAIL_TOKENS = 500;
238769
238863
  NEVER_TRUNCATE = /* @__PURE__ */ new Set(["browser_screenshot"]);
238770
- SELF_PAGINATED_TOOLS = /* @__PURE__ */ new Set(["read_file", "read_attachment", "session_search"]);
238864
+ SELF_PAGINATED_TOOLS = /* @__PURE__ */ new Set([
238865
+ "read_file",
238866
+ "read_attachment",
238867
+ "session_search",
238868
+ "web_search"
238869
+ ]);
238870
+ TRUNCATION_HINTS = {
238871
+ mcp_call: "call the same MCP tool with narrower arguments, or ask the server for a specific field.",
238872
+ read_url: "call read_url again with a smaller max_length, or a more specific URL.",
238873
+ grep: "narrow the path/include, or lower max_results.",
238874
+ glob: "narrow the pattern, or lower the limit."
238875
+ };
238876
+ TRUNCATION_HINT_DEFAULT = "for a file, call read_file again with offset/limit on the same path; for a command, narrow it (pipe through head/grep or target a specific path).";
238771
238877
  ToolRegistry = class {
238772
238878
  static tools = /* @__PURE__ */ new Map();
238773
238879
  /**
@@ -269674,6 +269780,49 @@ var require_turndown_cjs = __commonJS({
269674
269780
  });
269675
269781
 
269676
269782
  // src/lib/tools/web.ts
269783
+ function renderFetchedPages(pages) {
269784
+ if (pages.length === 0) return { text: "", fullyIncluded: 0 };
269785
+ const CHROME_PER_PAGE = 220;
269786
+ const perPage = Math.max(
269787
+ 500,
269788
+ Math.floor(SEARCH_OUTPUT_TOTAL_CHARS / pages.length) - CHROME_PER_PAGE
269789
+ );
269790
+ let out = "";
269791
+ let fullyIncluded = 0;
269792
+ pages.forEach((page, idx) => {
269793
+ const total = page.content.length;
269794
+ const kept = Math.min(total, perPage);
269795
+ const complete = kept >= total;
269796
+ if (complete) fullyIncluded++;
269797
+ out += `### ${idx + 1}. ${page.title}
269798
+ `;
269799
+ out += `\u{1F4CD} ${page.source ? `[${page.source}] ` : ""}${page.url}
269800
+ `;
269801
+ out += complete ? `chars 1-${total} of ${total} (complete)
269802
+
269803
+ ` : `chars 1-${kept} of ${total}
269804
+
269805
+ `;
269806
+ out += page.content.slice(0, kept);
269807
+ out += complete ? `
269808
+
269809
+ ---
269810
+
269811
+ ` : `
269812
+
269813
+ (truncated \u2014 ${total - kept} more chars; call read_url with url="${page.url}" for the full page)
269814
+
269815
+ ---
269816
+
269817
+ `;
269818
+ });
269819
+ return { text: out, fullyIncluded };
269820
+ }
269821
+ function deepFetchBudget(pageCount) {
269822
+ if (pageCount <= 0) return DEEP_FETCH_MAX;
269823
+ const share = Math.floor(DEEP_FETCH_TOTAL / pageCount);
269824
+ return Math.min(READ_URL_MAX_CAP, Math.max(DEEP_FETCH_MAX, share));
269825
+ }
269677
269826
  function getTurndown() {
269678
269827
  if (!_turndown) {
269679
269828
  _turndown = new import_turndown.default({
@@ -269924,11 +270073,12 @@ async function runDeepSearch(query, maxSources = 3, sources = "general") {
269924
270073
  const cap = Math.max(1, Math.min(maxSources, 5));
269925
270074
  const searchResults = await aggregator.search(query, sources, cap);
269926
270075
  const topUrls = searchResults.sources.filter((r3) => r3.url && r3.url.startsWith("http")).slice(0, cap);
270076
+ const perPage = deepFetchBudget(topUrls.length);
269927
270077
  const fetchedContent = await Promise.allSettled(
269928
270078
  topUrls.map(async (result2) => {
269929
270079
  const fetched = await fetchUrlContentCached(
269930
270080
  result2.url,
269931
- DEEP_FETCH_MAX,
270081
+ perPage,
269932
270082
  FETCH_TIMEOUT_MS,
269933
270083
  "Atlarix/1.0 (Deep Search)"
269934
270084
  );
@@ -269941,10 +270091,15 @@ async function runDeepSearch(query, maxSources = 3, sources = "general") {
269941
270091
  })
269942
270092
  );
269943
270093
  const validFetched = fetchedContent.filter((r3) => r3.status === "fulfilled" && r3.value !== null).map((r3) => r3.value);
270094
+ const rendered = renderFetchedPages(validFetched);
269944
270095
  let response = `# Deep Search Results for: "${query}"
269945
270096
 
269946
270097
  `;
269947
- response += `_Searched ${searchResults.sources.length} sources, analyzed ${validFetched.length} pages in depth_
270098
+ response += `_Searched ${searchResults.sources.length} sources; ${validFetched.length} page(s) read`;
270099
+ if (validFetched.length > 0) {
270100
+ response += rendered.fullyIncluded === validFetched.length ? `, all included in full` : `, ${rendered.fullyIncluded} in full and ${validFetched.length - rendered.fullyIncluded} excerpted (read_url for the rest)`;
270101
+ }
270102
+ response += `_
269948
270103
 
269949
270104
  `;
269950
270105
  response += `## Quick Overview
@@ -269954,19 +270109,7 @@ ${searchResults.formattedText}
269954
270109
  if (validFetched.length > 0) {
269955
270110
  response += `## Detailed Content Analysis
269956
270111
 
269957
- `;
269958
- validFetched.forEach((page, idx) => {
269959
- response += `### ${idx + 1}. ${page.title}
269960
- `;
269961
- response += `\u{1F4CD} ${page.url}
269962
-
269963
- `;
269964
- response += `${page.content}
269965
-
269966
- ---
269967
-
269968
- `;
269969
- });
270112
+ ${rendered.text}`;
269970
270113
  }
269971
270114
  return {
269972
270115
  // Remote deep-search content is untrusted — data, not instructions.
@@ -270047,7 +270190,7 @@ function optimizeSearchQueryKeywords(rawQuery) {
270047
270190
  const optimized = [...quoted, ...keywords.slice(0, 6)].join(" ").trim();
270048
270191
  return optimized || rawQuery;
270049
270192
  }
270050
- var import_turndown, WEB_SEARCH_SETUP_HINT, READ_URL_DEFAULT_MAX, READ_URL_MAX_CAP, DEEP_FETCH_MAX, FETCH_TIMEOUT_MS, FETCH_TIMEOUT_MAX_MS, BROWSER_USER_AGENT, _turndown, READER_PARTITION, BROWSER_ESCALATION_STATUSES, JS_SHELL_MAX_TEXT_CHARS, JS_SHELL_MIN_HTML_BYTES, EXTERNAL_SCRIPT_RE, BROWSER_EXTRACT_TIMEOUT_MS, POST_RENDER_MIN_CHARS, READER_HTML_SCRIPT, RELEVANCE_STOP_WORDS, WEB_SEARCH_GLOBAL_CACHE, WEB_SEARCH_GLOBAL_IN_FLIGHT, WEB_SEARCH_CACHE_TTL, READ_URL_CACHE, READ_URL_IN_FLIGHT, READ_URL_CACHE_TTL, READ_URL_CACHE_MAX_CHARS, WebSearchAggregator;
270193
+ var import_turndown, WEB_SEARCH_SETUP_HINT, READ_URL_DEFAULT_MAX, READ_URL_MAX_CAP, DEEP_FETCH_MAX, DEEP_FETCH_TOTAL, SEARCH_OUTPUT_TOTAL_CHARS, FETCH_TIMEOUT_MS, FETCH_TIMEOUT_MAX_MS, BROWSER_USER_AGENT, _turndown, READER_PARTITION, BROWSER_ESCALATION_STATUSES, JS_SHELL_MAX_TEXT_CHARS, JS_SHELL_MIN_HTML_BYTES, EXTERNAL_SCRIPT_RE, BROWSER_EXTRACT_TIMEOUT_MS, POST_RENDER_MIN_CHARS, READER_HTML_SCRIPT, RELEVANCE_STOP_WORDS, WEB_SEARCH_GLOBAL_CACHE, WEB_SEARCH_GLOBAL_IN_FLIGHT, WEB_SEARCH_CACHE_TTL, READ_URL_CACHE, READ_URL_IN_FLIGHT, READ_URL_CACHE_TTL, READ_URL_CACHE_MAX_CHARS, WebSearchAggregator;
270051
270194
  var init_web = __esm({
270052
270195
  "src/lib/tools/web.ts"() {
270053
270196
  init_registry();
@@ -270060,6 +270203,8 @@ var init_web = __esm({
270060
270203
  READ_URL_DEFAULT_MAX = 2e4;
270061
270204
  READ_URL_MAX_CAP = 5e4;
270062
270205
  DEEP_FETCH_MAX = 2e4;
270206
+ DEEP_FETCH_TOTAL = 1e5;
270207
+ SEARCH_OUTPUT_TOTAL_CHARS = 24e3;
270063
270208
  FETCH_TIMEOUT_MS = 2e4;
270064
270209
  FETCH_TIMEOUT_MAX_MS = 6e4;
270065
270210
  BROWSER_USER_AGENT = "Mozilla/5.0 (Macintosh; Intel Mac OS X 10_15_7) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/124.0.0.0 Safari/537.36";
@@ -270254,12 +270399,14 @@ ${fetched.content}`;
270254
270399
  })
270255
270400
  );
270256
270401
  const validFetched = fetchedContent.filter((r3) => r3.status === "fulfilled" && r3.value !== null).map((r3) => r3.value);
270402
+ const rendered = renderFetchedPages(validFetched);
270257
270403
  let response = `# \u{1F50D} ${searchMode.toUpperCase()} Search: "${query}"
270258
270404
 
270259
270405
  `;
270260
270406
  response += `_Searched ${searchResults.sources.length} sources`;
270261
270407
  if (validFetched.length > 0) {
270262
- response += `, analyzed ${validFetched.length} pages in depth`;
270408
+ response += `; ${validFetched.length} page(s) read`;
270409
+ response += rendered.fullyIncluded === validFetched.length ? `, all included in full` : `, ${rendered.fullyIncluded} in full and ${validFetched.length - rendered.fullyIncluded} excerpted (read_url for the rest)`;
270263
270410
  }
270264
270411
  response += `_
270265
270412
 
@@ -270271,19 +270418,7 @@ ${searchResults.formattedText}
270271
270418
  if (validFetched.length > 0) {
270272
270419
  response += `## Detailed Content Analysis
270273
270420
 
270274
- `;
270275
- validFetched.forEach((page, idx) => {
270276
- response += `### ${idx + 1}. ${page.title}
270277
- `;
270278
- response += `\u{1F4CD} [${page.source}] ${page.url}
270279
-
270280
- `;
270281
- response += `${page.content}
270282
-
270283
- ---
270284
-
270285
- `;
270286
- });
270421
+ ${rendered.text}`;
270287
270422
  }
270288
270423
  if (searchMode === "comprehensive" && validFetched.length > 1) {
270289
270424
  response += `## Cross-Reference Summary
@@ -323642,7 +323777,7 @@ async function readHierarchy(device) {
323642
323777
  if (gap) return { ok: false, error: gap };
323643
323778
  const r3 = await runDeviceCli(
323644
323779
  "adb",
323645
- ["-s", device.id, "shell", "uiautomator", "dump", "/dev/tty"],
323780
+ ["-s", device.id, "exec-out", "uiautomator", "dump", "/dev/tty"],
323646
323781
  { timeoutMs: 25e3 }
323647
323782
  );
323648
323783
  if (!r3.ok) return { ok: false, error: r3.error };
@@ -323653,7 +323788,9 @@ async function readHierarchy(device) {
323653
323788
  error: 'uiautomator returned no XML. The screen may be mid-transition \u2014 retry once; if it persists the foreground app draws its own surface and only mode:"screenshot" can see it.'
323654
323789
  };
323655
323790
  }
323656
- return { ok: true, xml: r3.stdout.slice(start) };
323791
+ const end = r3.stdout.lastIndexOf("</hierarchy>");
323792
+ const xml = end > start ? r3.stdout.slice(start, end + "</hierarchy>".length) : r3.stdout.slice(start);
323793
+ return { ok: true, xml };
323657
323794
  }
323658
323795
  async function resolveRef2(device, ref) {
323659
323796
  const h3 = await readHierarchy(device);
@@ -323690,7 +323827,11 @@ var init_mobile = __esm({
323690
323827
  // carry the cheap default (a TEXT hierarchy) — not an introduction. Making
323691
323828
  // the default the cheap path is also why this tool needs no NEVER_TRIM
323692
323829
  // entry: a model that calls it with no arguments gets the right read.
323693
- 'Read the screen of a running Android emulator or iOS Simulator as TEXT: called with no `mode` it returns the UI hierarchy \u2014 every interactive element with a stable `ref` for the `mobile` tool to act on \u2014 which answers "what is on screen", "is the button there" and "did the form submit" in a few hundred tokens.\nmode:"screenshot" \u2014 a literal PNG and a LAST RESORT (thousands of tokens): only when the user needs the actual image (a design to match, a rendering artefact, a custom-drawn surface). NEVER to answer "what do you see" or to find an element \u2014 the hierarchy already does that, in text.\nmode:"logs" \u2014 a bounded tail of the device log, filtered to warnings and errors by default. This is where a crash\'s stack trace is.\nmode:"devices" \u2014 what is running, when you need to name one.\niOS Simulator has NO hierarchy and NO input (a `simctl` limitation, not a transient failure): screenshots and logs work, refs and taps do not.'
323830
+ // WAS 311 CHARS AND SILENTLY TRUNCATED at `firstSentence`'s 200-char cap,
323831
+ // which dropped "in a few hundred tokens" — the cheap-default claim this whole
323832
+ // design rests on. Measured and shortened 2026-09-04. Keep it under 200 with no
323833
+ // internal ". ", or the binding loses its point again.
323834
+ 'Read an Android emulator or iOS Simulator screen as TEXT \u2014 with no `mode` it returns the UI hierarchy: every interactive element with a stable `ref` for the `mobile` tool, in a few hundred tokens.\nmode:"screenshot" \u2014 a literal PNG and a LAST RESORT (thousands of tokens): only when the user needs the actual image (a design to match, a rendering artefact, a custom-drawn surface). NEVER to answer "what do you see" or to find an element \u2014 the hierarchy already does that, in text.\nmode:"logs" \u2014 a bounded tail of the device log, filtered to warnings and errors by default. This is where a crash\'s stack trace is.\nmode:"devices" \u2014 what is running, when you need to name one.\niOS Simulator has NO hierarchy and NO input (a `simctl` limitation, not a transient failure): screenshots and logs work, refs and taps do not.'
323694
323835
  ),
323695
323836
  parameters: {
323696
323837
  type: "object",
@@ -323942,13 +324083,30 @@ var init_mobile = __esm({
323942
324083
  error: `"${pkg}" is not a package identifier. Expected something like com.example.app \u2014 letters, digits, dots, dashes and underscores only.`
323943
324084
  };
323944
324085
  }
323945
- const r4 = device.platform === "android" ? await runDeviceCli(
323946
- "adb",
323947
- ["-s", device.id, "shell", "monkey", "-p", pkg, "-c", "android.intent.category.LAUNCHER", "1"],
323948
- { timeoutMs: 25e3 }
323949
- ) : await runDeviceCli("xcrun", ["simctl", "launch", device.id, pkg], {
323950
- timeoutMs: 25e3
323951
- });
324086
+ let r4;
324087
+ if (device.platform === "android") {
324088
+ const resolved3 = await runDeviceCli(
324089
+ "adb",
324090
+ ["-s", device.id, "shell", "cmd", "package", "resolve-activity", "--brief", pkg],
324091
+ { timeoutMs: 15e3 }
324092
+ );
324093
+ const component = resolved3.ok ? resolved3.stdout.split(/\r?\n/).map((l3) => l3.trim()).filter((l3) => /^[A-Za-z0-9_.]+\/[A-Za-z0-9_.$]+$/.test(l3)).pop() ?? "" : "";
324094
+ if (!component) {
324095
+ return {
324096
+ success: false,
324097
+ error: `"${pkg}" has no launchable activity on ${device.label} \u2014 it may not be installed. Check with mobile_inspect(mode:"devices") that you have the right device, and confirm the package name. Do not retry with the same value.`
324098
+ };
324099
+ }
324100
+ r4 = await runDeviceCli(
324101
+ "adb",
324102
+ ["-s", device.id, "shell", "am", "start", "-n", component],
324103
+ { timeoutMs: 25e3 }
324104
+ );
324105
+ } else {
324106
+ r4 = await runDeviceCli("xcrun", ["simctl", "launch", device.id, pkg], {
324107
+ timeoutMs: 25e3
324108
+ });
324109
+ }
323952
324110
  if (!r4.ok) return { success: false, error: r4.error };
323953
324111
  return {
323954
324112
  success: true,
@@ -333963,14 +334121,7 @@ async function runBuildBranch(ctx, deps) {
333963
334121
  String(execResult.command ?? ""),
333964
334122
  permRequest.preview?.workingDirectory
333965
334123
  )
333966
- } : permRequest.operation === "automation_write" ? {
333967
- // The id only exists after approval. The tool
333968
- // description tells the model to run the
333969
- // automation it just created, and name is not a
333970
- // key — two automations may share one — so
333971
- // without this it could only guess via `list`.
333972
- ...execResult.automationId ? { automation_id: execResult.automationId } : {}
333973
- } : {};
334124
+ } : permRequest.operation === "automation_write" ? execResult.automationId ? { automation_id: execResult.automationId } : {} : {};
333974
334125
  const hasCompilationErrors = /error:|Error:|ERROR:|failed to|Failed to|Cannot find|cannot find|is not defined|is not a function|SyntaxError|TypeError|ReferenceError/i.test(
333975
334126
  output
333976
334127
  );
@@ -337647,7 +337798,7 @@ if (!process.env.ATLARIX_MODELS_SNAPSHOT) {
337647
337798
  const shipped = path50.join(here, "models-snapshot.json.gz");
337648
337799
  if (fs40.existsSync(shipped)) process.env.ATLARIX_MODELS_SNAPSHOT = shipped;
337649
337800
  }
337650
- var VERSION15 = false ? "dev" : "14.42.0";
337801
+ var VERSION15 = false ? "dev" : "14.43.0";
337651
337802
  if (process.argv[2] === "run") process.argv.splice(2, 1);
337652
337803
  function arg(name29) {
337653
337804
  const i4 = process.argv.indexOf(`--${name29}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "atlarix",
3
- "version": "14.42.0",
3
+ "version": "14.43.0",
4
4
  "description": "Headless Atlarix coding agent — the Electron-free agent loop as a CLI, for benchmarks, CI and unattended runs.",
5
5
  "license": "PROPRIETARY",
6
6
  "author": {