@atlasharness/atlascode 0.1.15 → 0.1.17

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (2) hide show
  1. package/dist/cli.js +507 -318
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -129,6 +129,29 @@ function cliOk(msg) {
129
129
  return;
130
130
  }
131
131
 
132
+ // src/cli/crashBackstop.ts
133
+ function registerGlobalCrashBackstop() {
134
+ if (registered) {
135
+ return;
136
+ }
137
+ registered = true;
138
+ process.on("uncaughtException", (error) => {
139
+ writeCrashDiag("uncaughtException", error);
140
+ });
141
+ process.on("unhandledRejection", (reason) => {
142
+ writeCrashDiag("unhandledRejection", reason);
143
+ });
144
+ }
145
+ function writeCrashDiag(kind, value) {
146
+ const formatted = value instanceof Error ? `${value.name}: ${value.message}
147
+ ${value.stack ?? ""}`.trim() : String(value);
148
+ try {
149
+ process.stderr.write(`[atlas][${kind}] ${formatted}
150
+ `);
151
+ } catch {}
152
+ }
153
+ var registered = false;
154
+
132
155
  // src/shared/feature.ts
133
156
  function feature(name) {
134
157
  const key = "FEATURE_" + name;
@@ -668,266 +691,6 @@ var init_shared = __esm(() => {
668
691
  init_types();
669
692
  });
670
693
 
671
- // src/engine/pipeline/errorClassification.ts
672
- function classifyToolError(error) {
673
- if (error instanceof Error) {
674
- const errnoCode = error.code;
675
- if (typeof errnoCode === "string") {
676
- return `Error:${errnoCode}`;
677
- }
678
- if (error.name && error.name !== "Error" && error.name.length > 3) {
679
- return error.name.slice(0, 60);
680
- }
681
- return "Error";
682
- }
683
- return "UnknownError";
684
- }
685
-
686
- // src/engine/pipeline/schemaValidation.ts
687
- function typeName(v) {
688
- if (v === null)
689
- return "null";
690
- if (Array.isArray(v))
691
- return "array";
692
- return typeof v;
693
- }
694
- function checkBasicType(value, type) {
695
- switch (type) {
696
- case "string":
697
- return typeof value === "string" ? null : `expected string, got ${typeName(value)}`;
698
- case "number":
699
- if (typeof value === "number") {
700
- return Number.isFinite(value) ? null : "expected number, got non-finite number";
701
- }
702
- return `expected number, got ${typeName(value)}`;
703
- case "integer":
704
- if (typeof value === "number") {
705
- return Number.isInteger(value) ? null : "expected integer, got non-integer number";
706
- }
707
- return `expected integer, got ${typeName(value)}`;
708
- case "boolean":
709
- return typeof value === "boolean" ? null : `expected boolean, got ${typeName(value)}`;
710
- case "array":
711
- return Array.isArray(value) ? null : `expected array, got ${typeName(value)}`;
712
- case "object":
713
- return typeof value === "object" && value !== null && !Array.isArray(value) ? null : `expected object, got ${typeName(value)}`;
714
- case "null":
715
- return value === null ? null : `expected null, got ${typeName(value)}`;
716
- default:
717
- return null;
718
- }
719
- }
720
- function validateInputBySchema(input, schema) {
721
- if (!schema) {
722
- return { valid: true };
723
- }
724
- if (input === null || typeof input !== "object" || Array.isArray(input)) {
725
- return { valid: false, message: "expected object input" };
726
- }
727
- const record = input;
728
- const errors = [];
729
- const required = schema.required;
730
- if (Array.isArray(required)) {
731
- for (const rawKey of required) {
732
- const key = String(rawKey);
733
- if (!(key in record) || record[key] === undefined) {
734
- errors.push(`missing required field "${key}"`);
735
- }
736
- }
737
- }
738
- const properties = schema.properties;
739
- if (properties) {
740
- for (const [key, value] of Object.entries(record)) {
741
- if (value === undefined)
742
- continue;
743
- const propSchema = properties[key];
744
- if (!propSchema || typeof propSchema !== "object")
745
- continue;
746
- const type = propSchema.type;
747
- if (typeof type !== "string")
748
- continue;
749
- const err = checkBasicType(value, type);
750
- if (err)
751
- errors.push(`field "${key}": ${err}`);
752
- }
753
- }
754
- return errors.length > 0 ? { valid: false, message: errors.join("; ") } : { valid: true };
755
- }
756
- function buildSchemaNotSentHint(tool, discoveredToolNames) {
757
- if (!tool.shouldDefer)
758
- return null;
759
- if (discoveredToolNames.has(tool.name))
760
- return null;
761
- return `
762
-
763
- This tool's schema was not sent to the API — it was not in the discovered-tool set derived from message history. ` + `Without the schema in your prompt, typed parameters (arrays, numbers, booleans) get emitted as strings and the client-side parser rejects them. ` + `Re-issue the call with correctly-typed parameters (arrays/numbers/booleans, not their string forms).`;
764
- }
765
-
766
- // src/engine/pipeline/toolExecution.ts
767
- function mergeHookPermission(hookBehavior, gate) {
768
- if (hookBehavior === "deny") {
769
- return { allowed: false, reason: "blocked by hook" };
770
- }
771
- if (!gate.allowed)
772
- return gate;
773
- if (hookBehavior === "ask") {
774
- return { allowed: false, ask: true, reason: "hook requested confirmation" };
775
- }
776
- return gate;
777
- }
778
- function findTool(tools, name) {
779
- return tools.find((t) => t.name === name || (t.aliases?.includes(name) ?? false));
780
- }
781
- async function executeToolUse(tu, assistantMsg, deps) {
782
- const tool = findTool(deps.tools, tu.name);
783
- if (!tool) {
784
- return {
785
- block: {
786
- type: "tool_result",
787
- tool_use_id: tu.id,
788
- content: `unknown tool: ${tu.name}`,
789
- is_error: true
790
- },
791
- isError: true
792
- };
793
- }
794
- const toolCallContext = deps.toolContext !== undefined ? { ...deps.toolContext, signal: deps.signal, checkPermission: deps.checkPermission } : { signal: deps.signal, checkPermission: deps.checkPermission };
795
- const schemaResult = validateInputBySchema(tu.input, tool.inputSchema);
796
- if (schemaResult.valid === false) {
797
- const discovered = deps.discoveredToolNames ?? new Set(deps.tools.map((t) => t.name));
798
- const schemaHint = buildSchemaNotSentHint(tool, discovered);
799
- const errorContent = schemaHint ? `${schemaResult.message}${schemaHint}` : schemaResult.message;
800
- return {
801
- block: {
802
- type: "tool_result",
803
- tool_use_id: tu.id,
804
- content: `<tool_use_error>InputValidationError: ${errorContent}</tool_use_error>`,
805
- is_error: true
806
- },
807
- isError: true
808
- };
809
- }
810
- const validation = await tool.validateInput?.(tu.input, toolCallContext);
811
- if (validation && validation.result === false) {
812
- return {
813
- block: {
814
- type: "tool_result",
815
- tool_use_id: tu.id,
816
- content: `<tool_use_error>InputValidationError: ${validation.message}</tool_use_error>`,
817
- is_error: true
818
- },
819
- isError: true
820
- };
821
- }
822
- const preOutcome = await deps.hooks?.preToolUse?.(tool, tu.input, tu.id);
823
- if (preOutcome?.blockingError) {
824
- return {
825
- block: {
826
- type: "tool_result",
827
- tool_use_id: tu.id,
828
- content: `<tool_use_error>hook blocked: ${preOutcome.blockingError}</tool_use_error>`,
829
- is_error: true
830
- },
831
- isError: true
832
- };
833
- }
834
- if (preOutcome?.preventContinuation) {
835
- return {
836
- block: {
837
- type: "tool_result",
838
- tool_use_id: tu.id,
839
- content: `<tool_use_error>Execution stopped by PreToolUse hook${preOutcome.stopReason ? `: ${preOutcome.stopReason}` : ""}</tool_use_error>`,
840
- is_error: true
841
- },
842
- isError: true
843
- };
844
- }
845
- const effectiveInput = preOutcome?.updatedInput ?? tu.input;
846
- const gateVerdict = deps.checkPermission ? await deps.checkPermission(tool, effectiveInput, {
847
- toolUseId: tu.id,
848
- assistantMessage: assistantMsg
849
- }) : { allowed: true };
850
- const verdict = mergeHookPermission(preOutcome?.hookBehavior, gateVerdict);
851
- if (!verdict.allowed) {
852
- const content = verdict.ask ? `<tool_use_error>permission confirmation required (prompt 面残留守): ${verdict.reason ?? tu.name}</tool_use_error>` : `<tool_use_error>permission denied: ${verdict.reason ?? tu.name}</tool_use_error>`;
853
- return {
854
- block: {
855
- type: "tool_result",
856
- tool_use_id: tu.id,
857
- content,
858
- is_error: true
859
- },
860
- isError: true
861
- };
862
- }
863
- const callInput = verdict.updatedInput ?? effectiveInput;
864
- let block;
865
- let isError = false;
866
- let toolUseResult;
867
- try {
868
- const res = await tool.call(callInput, toolCallContext, undefined, assistantMsg);
869
- block = tool.mapToolResultToToolResultBlockParam(res.data, tu.id);
870
- toolUseResult = res.data;
871
- } catch (error) {
872
- const errorText = `tool error [${classifyToolError(error)}]: ${String(error?.message ?? error)}`;
873
- block = {
874
- type: "tool_result",
875
- tool_use_id: tu.id,
876
- content: `<tool_use_error>${errorText}</tool_use_error>`,
877
- is_error: true
878
- };
879
- isError = true;
880
- toolUseResult = errorText;
881
- }
882
- const postOutcome = await deps.hooks?.postToolUse?.(tool, callInput, block, tu.id);
883
- return { block, isError, toolUseResult };
884
- }
885
- var init_toolExecution = () => {};
886
-
887
- // src/engine/pipeline/toolOrchestration.ts
888
- function partitionToolCalls(toolUses, tools) {
889
- return toolUses.reduce((acc, tu) => {
890
- const tool = findTool(tools, tu.name);
891
- let safe = false;
892
- try {
893
- safe = tool ? tool.isConcurrencySafe(tu.input) : false;
894
- } catch {
895
- safe = false;
896
- }
897
- if (safe && acc[acc.length - 1]?.isConcurrencySafe) {
898
- acc[acc.length - 1].blocks.push(tu);
899
- } else {
900
- acc.push({ isConcurrencySafe: safe, blocks: [tu] });
901
- }
902
- return acc;
903
- }, []);
904
- }
905
- async function runToolBatch(toolUses, assistantMsg, deps) {
906
- const outcomes = [];
907
- for (const batch of partitionToolCalls(toolUses, deps.tools)) {
908
- for (const tu of batch.blocks) {
909
- const r = await executeToolUse(tu, assistantMsg, deps);
910
- outcomes.push({
911
- toolUseId: tu.id,
912
- name: tu.name,
913
- block: r.block,
914
- isError: r.isError,
915
- toolUseResult: r.toolUseResult
916
- });
917
- }
918
- }
919
- return outcomes;
920
- }
921
- var init_toolOrchestration = __esm(() => {
922
- init_toolExecution();
923
- });
924
-
925
- // src/engine/pipeline/index.ts
926
- var init_pipeline = __esm(() => {
927
- init_toolExecution();
928
- init_toolOrchestration();
929
- });
930
-
931
694
  // node_modules/openai/internal/tslib.mjs
932
695
  function __classPrivateFieldSet(receiver, state, value, kind, f) {
933
696
  if (kind === "m")
@@ -20052,6 +19815,17 @@ var init_openai = __esm(() => {
20052
19815
  init_bedrock2();
20053
19816
  });
20054
19817
 
19818
+ // src/modelprovider/constants.ts
19819
+ var API_IMAGE_MAX_BASE64_SIZE, IMAGE_TARGET_RAW_SIZE, PDF_TARGET_RAW_SIZE, API_PDF_MAX_PAGES = 100, LLM_TIMEOUT_DEFAULT_MS = 600000, LLM_TIMEOUT_CAP_MS = 1800000, SUMMARIZE_CONNECTOR_TEXT_BETA_HEADER, AFK_MODE_BETA_HEADER;
19820
+ var init_constants2 = __esm(() => {
19821
+ init_shared();
19822
+ API_IMAGE_MAX_BASE64_SIZE = 5 * 1024 * 1024;
19823
+ IMAGE_TARGET_RAW_SIZE = API_IMAGE_MAX_BASE64_SIZE * 3 / 4;
19824
+ PDF_TARGET_RAW_SIZE = 20 * 1024 * 1024;
19825
+ SUMMARIZE_CONNECTOR_TEXT_BETA_HEADER = feature("CONNECTOR_TEXT") ? "summarize-connector-text-2026-03-13" : "";
19826
+ AFK_MODE_BETA_HEADER = feature("TRANSCRIPT_CLASSIFIER") ? "afk-mode-2026-01-31" : "";
19827
+ });
19828
+
20055
19829
  // src/modelprovider/clients.ts
20056
19830
  function clientCacheKey(provider, baseURL, apiKey) {
20057
19831
  return provider + "|" + (baseURL || "") + "|" + (apiKey || "");
@@ -20066,7 +19840,7 @@ function getClientForEntry(entry) {
20066
19840
  baseURL: entry.baseURL,
20067
19841
  apiKey: entry.apiKey,
20068
19842
  maxRetries: 0,
20069
- timeout: 120000
19843
+ timeout: LLM_TIMEOUT_DEFAULT_MS
20070
19844
  });
20071
19845
  clientCache.set(key, client);
20072
19846
  return client;
@@ -20074,6 +19848,7 @@ function getClientForEntry(entry) {
20074
19848
  var clientCache;
20075
19849
  var init_clients = __esm(() => {
20076
19850
  init_openai();
19851
+ init_constants2();
20077
19852
  clientCache = new Map;
20078
19853
  });
20079
19854
 
@@ -27007,6 +26782,27 @@ var init_params = __esm(() => {
27007
26782
  init_effort();
27008
26783
  });
27009
26784
 
26785
+ // src/modelprovider/types.ts
26786
+ var APIError2, APIConnectionError2, APIConnectionTimeoutError2;
26787
+ var init_types2 = __esm(() => {
26788
+ APIError2 = class APIError2 extends Error {
26789
+ status;
26790
+ error;
26791
+ constructor(message, status, error) {
26792
+ super(message);
26793
+ this.name = "APIError";
26794
+ if (status !== undefined)
26795
+ this.status = status;
26796
+ if (error !== undefined)
26797
+ this.error = error;
26798
+ }
26799
+ };
26800
+ APIConnectionError2 = class APIConnectionError2 extends APIError2 {
26801
+ };
26802
+ APIConnectionTimeoutError2 = class APIConnectionTimeoutError2 extends APIConnectionError2 {
26803
+ };
26804
+ });
26805
+
27010
26806
  // src/modelprovider/modelprovider.ts
27011
26807
  import { randomUUID } from "crypto";
27012
26808
  function mapOpenAIUsage(u) {
@@ -27025,6 +26821,29 @@ function isRetryableError(err) {
27025
26821
  const msg = String(err?.message || err?.code || "");
27026
26822
  return /timeout|ECONN|EPIPE|fetch failed|socket|aborted/i.test(msg);
27027
26823
  }
26824
+ function isClientRequestTimeout(err) {
26825
+ if (!err || typeof err !== "object")
26826
+ return false;
26827
+ const e = err;
26828
+ if (err instanceof APIConnectionTimeoutError2)
26829
+ return true;
26830
+ if (e.name === "APIConnectionTimeoutError" || e.name === "APITimeoutError")
26831
+ return true;
26832
+ return false;
26833
+ }
26834
+ function shouldRetryModelError(err, signal) {
26835
+ if (signal?.aborted)
26836
+ return false;
26837
+ if (isClientRequestTimeout(err))
26838
+ return false;
26839
+ return isRetryableError(err);
26840
+ }
26841
+ function llmTimeoutRemediationHint(error, currentTimeoutMs) {
26842
+ if (!isClientRequestTimeout(error))
26843
+ return null;
26844
+ const head = typeof currentTimeoutMs === "number" && currentTimeoutMs > 0 ? `当前超时 ${Math.round(currentTimeoutMs / 1000)}s` : "慢模型长生成可能超过缺省超时";
26845
+ return `LLM 请求超时(${head})。可调大:env ATLAS_LLM_TIMEOUT=<毫秒> 或 settings.json llmTimeoutMs 键(上限 ${Math.round(LLM_TIMEOUT_CAP_MS / 60000)}min)。`;
26846
+ }
27028
26847
  function startLlmWaitHeartbeat(modelId, attempt, totalRetries) {
27029
26848
  const startedAt = Date.now();
27030
26849
  const id = setInterval(() => {
@@ -27038,9 +26857,14 @@ function startLlmWaitHeartbeat(modelId, attempt, totalRetries) {
27038
26857
  class OpenAIProvider {
27039
26858
  maxRetriesPerModel;
27040
26859
  timeoutMs;
27041
- constructor(maxRetriesPerModel = 3, timeoutMs = 120000) {
26860
+ timeoutResolver;
26861
+ constructor(maxRetriesPerModel = 3, timeoutMs = LLM_TIMEOUT_DEFAULT_MS, timeoutResolver) {
27042
26862
  this.maxRetriesPerModel = maxRetriesPerModel;
27043
26863
  this.timeoutMs = timeoutMs;
26864
+ this.timeoutResolver = timeoutResolver;
26865
+ }
26866
+ getTimeoutMs() {
26867
+ return this.timeoutResolver ? this.timeoutResolver() : this.timeoutMs;
27044
26868
  }
27045
26869
  async chat(args) {
27046
26870
  const refs = getRoleModels(args.role, args.sessionModel, args.fallbackModel);
@@ -27080,7 +26904,7 @@ class OpenAIProvider {
27080
26904
  const stopWait = startLlmWaitHeartbeat(entry.modelId, attempt, this.maxRetriesPerModel);
27081
26905
  let res;
27082
26906
  try {
27083
- res = await client.chat.completions.create(params, { signal: args.signal, timeout: this.timeoutMs });
26907
+ res = await client.chat.completions.create(params, { signal: args.signal, timeout: this.getTimeoutMs() });
27084
26908
  } finally {
27085
26909
  stopWait();
27086
26910
  }
@@ -27128,7 +26952,7 @@ class OpenAIProvider {
27128
26952
  };
27129
26953
  } catch (err) {
27130
26954
  lastErr = err;
27131
- if (!isRetryableError(err) || args.signal?.aborted)
26955
+ if (!shouldRetryModelError(err, args.signal))
27132
26956
  break;
27133
26957
  }
27134
26958
  }
@@ -27178,7 +27002,7 @@ class OpenAIProvider {
27178
27002
  break;
27179
27003
  } catch (err) {
27180
27004
  lastErr = err;
27181
- if (!isRetryableError(err) || args.signal?.aborted)
27005
+ if (!shouldRetryModelError(err, args.signal))
27182
27006
  break;
27183
27007
  }
27184
27008
  }
@@ -27188,7 +27012,7 @@ class OpenAIProvider {
27188
27012
  if (lastErr) {
27189
27013
  const message = lastErr instanceof Error ? lastErr.message || lastErr.name : String(lastErr);
27190
27014
  const code = lastErr?.name === "TimeoutError" ? "TIMEOUT" : "API_ERROR";
27191
- yield { type: "error", code, message, retryable: isRetryableError(lastErr) };
27015
+ yield { type: "error", code, message, retryable: shouldRetryModelError(lastErr, args.signal) };
27192
27016
  return;
27193
27017
  }
27194
27018
  throw new Error(`No models configured for role '${args.role}'.`);
@@ -27197,7 +27021,7 @@ class OpenAIProvider {
27197
27021
  const stopWait = startLlmWaitHeartbeat(entry.modelId, attempt, totalRetries);
27198
27022
  let stream;
27199
27023
  try {
27200
- stream = await client.chat.completions.create({ ...params, stream: true, stream_options: { include_usage: true } }, { signal, timeout: this.timeoutMs });
27024
+ stream = await client.chat.completions.create({ ...params, stream: true, stream_options: { include_usage: true } }, { signal, timeout: this.getTimeoutMs() });
27201
27025
  } finally {
27202
27026
  stopWait();
27203
27027
  }
@@ -27385,7 +27209,7 @@ class OpenAIProvider {
27385
27209
  const wav = Buffer.concat([header, pcm]);
27386
27210
  const file = new File([wav], "audio.wav", { type: "audio/wav" });
27387
27211
  const client = getClientForEntry(entry);
27388
- const resp = await client.audio.transcriptions.create({ file, model, ...language ? { language } : {} }, { timeout: this.timeoutMs });
27212
+ const resp = await client.audio.transcriptions.create({ file, model, ...language ? { language } : {} }, { timeout: this.getTimeoutMs() });
27389
27213
  return resp?.text ?? "";
27390
27214
  }
27391
27215
  async synthesizeSpeech(text, model, voice) {
@@ -27399,7 +27223,7 @@ class OpenAIProvider {
27399
27223
  voice: voice || "alloy",
27400
27224
  input: text,
27401
27225
  response_format: "mp3"
27402
- }, { timeout: this.timeoutMs });
27226
+ }, { timeout: this.getTimeoutMs() });
27403
27227
  const buf = await resp.arrayBuffer();
27404
27228
  return Buffer.from(buf);
27405
27229
  }
@@ -27434,15 +27258,15 @@ class OpenAIProvider {
27434
27258
  var init_modelprovider = __esm(() => {
27435
27259
  init_openai();
27436
27260
  init_clients();
27261
+ init_constants2();
27437
27262
  init_roles7();
27438
27263
  init_shared();
27439
27264
  init_shared();
27440
27265
  init_params();
27266
+ init_types2();
27267
+ init_constants2();
27441
27268
  });
27442
27269
 
27443
- // src/modelprovider/types.ts
27444
- var init_types2 = () => {};
27445
-
27446
27270
  // src/modelprovider/errorUtils.ts
27447
27271
  function extractConnectionErrorDetails(error) {
27448
27272
  if (!error || typeof error !== "object") {
@@ -27581,17 +27405,6 @@ var init_errorUtils = __esm(() => {
27581
27405
  ]);
27582
27406
  });
27583
27407
 
27584
- // src/modelprovider/constants.ts
27585
- var API_IMAGE_MAX_BASE64_SIZE, IMAGE_TARGET_RAW_SIZE, PDF_TARGET_RAW_SIZE, API_PDF_MAX_PAGES = 100, SUMMARIZE_CONNECTOR_TEXT_BETA_HEADER, AFK_MODE_BETA_HEADER;
27586
- var init_constants2 = __esm(() => {
27587
- init_shared();
27588
- API_IMAGE_MAX_BASE64_SIZE = 5 * 1024 * 1024;
27589
- IMAGE_TARGET_RAW_SIZE = API_IMAGE_MAX_BASE64_SIZE * 3 / 4;
27590
- PDF_TARGET_RAW_SIZE = 20 * 1024 * 1024;
27591
- SUMMARIZE_CONNECTOR_TEXT_BETA_HEADER = feature("CONNECTOR_TEXT") ? "summarize-connector-text-2026-03-13" : "";
27592
- AFK_MODE_BETA_HEADER = feature("TRANSCRIPT_CLASSIFIER") ? "afk-mode-2026-01-31" : "";
27593
- });
27594
-
27595
27408
  // src/modelprovider/errorMessaging.ts
27596
27409
  function registerErrorMessagingPorts(p) {
27597
27410
  ports = p;
@@ -27731,10 +27544,22 @@ var init_queryWithRoleFallback = __esm(() => {
27731
27544
 
27732
27545
  // src/modelprovider/index.ts
27733
27546
  function getModelProvider() {
27734
- return _provider ??= new OpenAIProvider(3, resolveLlmTimeoutMs());
27547
+ return _provider ??= new OpenAIProvider(3, LLM_TIMEOUT_DEFAULT_MS, () => resolveLlmTimeoutMs(process.env.ATLAS_LLM_TIMEOUT, llmTimeoutSettingsSource?.()));
27548
+ }
27549
+ function setLlmTimeoutSettingsSource(next) {
27550
+ llmTimeoutSettingsSource = next;
27551
+ }
27552
+ function getCurrentLlmTimeoutMs() {
27553
+ return resolveLlmTimeoutMs(process.env.ATLAS_LLM_TIMEOUT, llmTimeoutSettingsSource?.());
27735
27554
  }
27736
- function resolveLlmTimeoutMs() {
27737
- return parseBoundedIntEnv("ATLAS_LLM_TIMEOUT", process.env.ATLAS_LLM_TIMEOUT, 120000, 1800000, 1).effective;
27555
+ function resolveLlmTimeoutMs(envRaw = process.env.ATLAS_LLM_TIMEOUT, settingsMs) {
27556
+ const fromSettings = () => typeof settingsMs === "number" && Number.isInteger(settingsMs) && settingsMs >= 1 ? Math.min(settingsMs, LLM_TIMEOUT_CAP_MS) : LLM_TIMEOUT_DEFAULT_MS;
27557
+ if (envRaw === undefined || envRaw === "")
27558
+ return fromSettings();
27559
+ const env = parseBoundedIntEnv("ATLAS_LLM_TIMEOUT", envRaw, LLM_TIMEOUT_DEFAULT_MS, LLM_TIMEOUT_CAP_MS, 1);
27560
+ if (env.status !== "invalid")
27561
+ return env.effective;
27562
+ return fromSettings();
27738
27563
  }
27739
27564
  function lazyProxy(resolve) {
27740
27565
  return new Proxy({}, {
@@ -27745,13 +27570,16 @@ function lazyProxy(resolve) {
27745
27570
  }
27746
27571
  });
27747
27572
  }
27748
- var _provider, modelProvider;
27573
+ var _provider, llmTimeoutSettingsSource = null, modelProvider;
27749
27574
  var init_modelprovider2 = __esm(() => {
27750
27575
  init_modelprovider();
27576
+ init_constants2();
27751
27577
  init_shared();
27578
+ init_constants2();
27752
27579
  init_modelprovider();
27753
27580
  init_types2();
27754
27581
  init_modelErrors();
27582
+ init_modelprovider();
27755
27583
  init_params();
27756
27584
  init_roles7();
27757
27585
  init_errorUtils();
@@ -27766,6 +27594,345 @@ var init_modelprovider2 = __esm(() => {
27766
27594
  modelProvider = lazyProxy(getModelProvider);
27767
27595
  });
27768
27596
 
27597
+ // src/engine/query/turnRecovery.ts
27598
+ function parseNonNegativeInt(value, fallback) {
27599
+ if (value === undefined || value === "")
27600
+ return fallback;
27601
+ const n = Number.parseInt(value, 10);
27602
+ return Number.isFinite(n) && n >= 0 ? n : fallback;
27603
+ }
27604
+ function resolveTurnRecoveryConfig(env = process.env) {
27605
+ return {
27606
+ enabled: env.ATLAS_TURN_RECOVER_ENABLED !== "0",
27607
+ maxRetries: parseNonNegativeInt(env.ATLAS_TURN_RECOVER_MAX, DEFAULT_MAX_RETRIES),
27608
+ backoffBaseMs: parseNonNegativeInt(env.ATLAS_TURN_RECOVER_BACKOFF_MS, DEFAULT_BACKOFF_BASE_MS),
27609
+ backoffCapMs: parseNonNegativeInt(env.ATLAS_TURN_RECOVER_BACKOFF_CAP_MS, DEFAULT_BACKOFF_CAP_MS)
27610
+ };
27611
+ }
27612
+ function turnRecoveryBackoffMs(attempt, baseMs, capMs) {
27613
+ const base = Math.max(0, baseMs);
27614
+ const cap = Math.max(base, capMs);
27615
+ if (attempt <= 0)
27616
+ return Math.min(base, cap);
27617
+ return Math.min(base * 2 ** attempt, cap);
27618
+ }
27619
+ function sleepSignalAware(ms, signal) {
27620
+ if (ms <= 0)
27621
+ return Promise.resolve();
27622
+ return new Promise((resolve) => {
27623
+ if (signal?.aborted) {
27624
+ resolve();
27625
+ return;
27626
+ }
27627
+ let settled = false;
27628
+ const timer = setTimeout(() => {
27629
+ settled = true;
27630
+ if (signal)
27631
+ signal.removeEventListener("abort", onAbort);
27632
+ resolve();
27633
+ }, ms);
27634
+ function onAbort() {
27635
+ if (settled)
27636
+ return;
27637
+ settled = true;
27638
+ clearTimeout(timer);
27639
+ resolve();
27640
+ }
27641
+ if (signal)
27642
+ signal.addEventListener("abort", onAbort, { once: true });
27643
+ });
27644
+ }
27645
+ async function withTurnRecovery(attempt, options = {}) {
27646
+ const cfg = options.config ?? resolveTurnRecoveryConfig();
27647
+ if (!cfg.enabled) {
27648
+ return attempt();
27649
+ }
27650
+ let lastErr;
27651
+ for (let i = 0;i <= cfg.maxRetries; i++) {
27652
+ if (i > 0 && options.signal?.aborted) {
27653
+ throw options.signal.reason ?? new Error("aborted");
27654
+ }
27655
+ try {
27656
+ return await attempt();
27657
+ } catch (err) {
27658
+ lastErr = err;
27659
+ if (i < cfg.maxRetries && shouldRetryModelError(err, options.signal)) {
27660
+ const backoff = turnRecoveryBackoffMs(i, cfg.backoffBaseMs, cfg.backoffCapMs);
27661
+ if (backoff > 0) {
27662
+ await sleepSignalAware(backoff, options.signal);
27663
+ }
27664
+ continue;
27665
+ }
27666
+ throw err;
27667
+ }
27668
+ }
27669
+ throw lastErr;
27670
+ }
27671
+ var DEFAULT_MAX_RETRIES = 13, DEFAULT_BACKOFF_BASE_MS = 100, DEFAULT_BACKOFF_CAP_MS = 1000;
27672
+ var init_turnRecovery = __esm(() => {
27673
+ init_modelprovider2();
27674
+ });
27675
+
27676
+ // src/engine/pipeline/errorClassification.ts
27677
+ function classifyToolError(error) {
27678
+ if (error instanceof Error) {
27679
+ const errnoCode = error.code;
27680
+ if (typeof errnoCode === "string") {
27681
+ return `Error:${errnoCode}`;
27682
+ }
27683
+ if (error.name && error.name !== "Error" && error.name.length > 3) {
27684
+ return error.name.slice(0, 60);
27685
+ }
27686
+ return "Error";
27687
+ }
27688
+ return "UnknownError";
27689
+ }
27690
+
27691
+ // src/engine/pipeline/schemaValidation.ts
27692
+ function typeName(v) {
27693
+ if (v === null)
27694
+ return "null";
27695
+ if (Array.isArray(v))
27696
+ return "array";
27697
+ return typeof v;
27698
+ }
27699
+ function checkBasicType(value, type) {
27700
+ switch (type) {
27701
+ case "string":
27702
+ return typeof value === "string" ? null : `expected string, got ${typeName(value)}`;
27703
+ case "number":
27704
+ if (typeof value === "number") {
27705
+ return Number.isFinite(value) ? null : "expected number, got non-finite number";
27706
+ }
27707
+ return `expected number, got ${typeName(value)}`;
27708
+ case "integer":
27709
+ if (typeof value === "number") {
27710
+ return Number.isInteger(value) ? null : "expected integer, got non-integer number";
27711
+ }
27712
+ return `expected integer, got ${typeName(value)}`;
27713
+ case "boolean":
27714
+ return typeof value === "boolean" ? null : `expected boolean, got ${typeName(value)}`;
27715
+ case "array":
27716
+ return Array.isArray(value) ? null : `expected array, got ${typeName(value)}`;
27717
+ case "object":
27718
+ return typeof value === "object" && value !== null && !Array.isArray(value) ? null : `expected object, got ${typeName(value)}`;
27719
+ case "null":
27720
+ return value === null ? null : `expected null, got ${typeName(value)}`;
27721
+ default:
27722
+ return null;
27723
+ }
27724
+ }
27725
+ function validateInputBySchema(input, schema) {
27726
+ if (!schema) {
27727
+ return { valid: true };
27728
+ }
27729
+ if (input === null || typeof input !== "object" || Array.isArray(input)) {
27730
+ return { valid: false, message: "expected object input" };
27731
+ }
27732
+ const record = input;
27733
+ const errors = [];
27734
+ const required = schema.required;
27735
+ if (Array.isArray(required)) {
27736
+ for (const rawKey of required) {
27737
+ const key = String(rawKey);
27738
+ if (!(key in record) || record[key] === undefined) {
27739
+ errors.push(`missing required field "${key}"`);
27740
+ }
27741
+ }
27742
+ }
27743
+ const properties = schema.properties;
27744
+ if (properties) {
27745
+ for (const [key, value] of Object.entries(record)) {
27746
+ if (value === undefined)
27747
+ continue;
27748
+ const propSchema = properties[key];
27749
+ if (!propSchema || typeof propSchema !== "object")
27750
+ continue;
27751
+ const type = propSchema.type;
27752
+ if (typeof type !== "string")
27753
+ continue;
27754
+ const err = checkBasicType(value, type);
27755
+ if (err)
27756
+ errors.push(`field "${key}": ${err}`);
27757
+ }
27758
+ }
27759
+ return errors.length > 0 ? { valid: false, message: errors.join("; ") } : { valid: true };
27760
+ }
27761
+ function buildSchemaNotSentHint(tool, discoveredToolNames) {
27762
+ if (!tool.shouldDefer)
27763
+ return null;
27764
+ if (discoveredToolNames.has(tool.name))
27765
+ return null;
27766
+ return `
27767
+
27768
+ This tool's schema was not sent to the API — it was not in the discovered-tool set derived from message history. ` + `Without the schema in your prompt, typed parameters (arrays, numbers, booleans) get emitted as strings and the client-side parser rejects them. ` + `Re-issue the call with correctly-typed parameters (arrays/numbers/booleans, not their string forms).`;
27769
+ }
27770
+
27771
+ // src/engine/pipeline/toolExecution.ts
27772
+ function mergeHookPermission(hookBehavior, gate) {
27773
+ if (hookBehavior === "deny") {
27774
+ return { allowed: false, reason: "blocked by hook" };
27775
+ }
27776
+ if (!gate.allowed)
27777
+ return gate;
27778
+ if (hookBehavior === "ask") {
27779
+ return { allowed: false, ask: true, reason: "hook requested confirmation" };
27780
+ }
27781
+ return gate;
27782
+ }
27783
+ function findTool(tools, name) {
27784
+ return tools.find((t) => t.name === name || (t.aliases?.includes(name) ?? false));
27785
+ }
27786
+ async function executeToolUse(tu, assistantMsg, deps) {
27787
+ const tool = findTool(deps.tools, tu.name);
27788
+ if (!tool) {
27789
+ return {
27790
+ block: {
27791
+ type: "tool_result",
27792
+ tool_use_id: tu.id,
27793
+ content: `unknown tool: ${tu.name}`,
27794
+ is_error: true
27795
+ },
27796
+ isError: true
27797
+ };
27798
+ }
27799
+ const toolCallContext = deps.toolContext !== undefined ? { ...deps.toolContext, signal: deps.signal, checkPermission: deps.checkPermission } : { signal: deps.signal, checkPermission: deps.checkPermission };
27800
+ const schemaResult = validateInputBySchema(tu.input, tool.inputSchema);
27801
+ if (schemaResult.valid === false) {
27802
+ const discovered = deps.discoveredToolNames ?? new Set(deps.tools.map((t) => t.name));
27803
+ const schemaHint = buildSchemaNotSentHint(tool, discovered);
27804
+ const errorContent = schemaHint ? `${schemaResult.message}${schemaHint}` : schemaResult.message;
27805
+ return {
27806
+ block: {
27807
+ type: "tool_result",
27808
+ tool_use_id: tu.id,
27809
+ content: `<tool_use_error>InputValidationError: ${errorContent}</tool_use_error>`,
27810
+ is_error: true
27811
+ },
27812
+ isError: true
27813
+ };
27814
+ }
27815
+ const validation = await tool.validateInput?.(tu.input, toolCallContext);
27816
+ if (validation && validation.result === false) {
27817
+ return {
27818
+ block: {
27819
+ type: "tool_result",
27820
+ tool_use_id: tu.id,
27821
+ content: `<tool_use_error>InputValidationError: ${validation.message}</tool_use_error>`,
27822
+ is_error: true
27823
+ },
27824
+ isError: true
27825
+ };
27826
+ }
27827
+ const preOutcome = await deps.hooks?.preToolUse?.(tool, tu.input, tu.id);
27828
+ if (preOutcome?.blockingError) {
27829
+ return {
27830
+ block: {
27831
+ type: "tool_result",
27832
+ tool_use_id: tu.id,
27833
+ content: `<tool_use_error>hook blocked: ${preOutcome.blockingError}</tool_use_error>`,
27834
+ is_error: true
27835
+ },
27836
+ isError: true
27837
+ };
27838
+ }
27839
+ if (preOutcome?.preventContinuation) {
27840
+ return {
27841
+ block: {
27842
+ type: "tool_result",
27843
+ tool_use_id: tu.id,
27844
+ content: `<tool_use_error>Execution stopped by PreToolUse hook${preOutcome.stopReason ? `: ${preOutcome.stopReason}` : ""}</tool_use_error>`,
27845
+ is_error: true
27846
+ },
27847
+ isError: true
27848
+ };
27849
+ }
27850
+ const effectiveInput = preOutcome?.updatedInput ?? tu.input;
27851
+ const gateVerdict = deps.checkPermission ? await deps.checkPermission(tool, effectiveInput, {
27852
+ toolUseId: tu.id,
27853
+ assistantMessage: assistantMsg
27854
+ }) : { allowed: true };
27855
+ const verdict = mergeHookPermission(preOutcome?.hookBehavior, gateVerdict);
27856
+ if (!verdict.allowed) {
27857
+ const content = verdict.ask ? `<tool_use_error>permission confirmation required (prompt 面残留守): ${verdict.reason ?? tu.name}</tool_use_error>` : `<tool_use_error>permission denied: ${verdict.reason ?? tu.name}</tool_use_error>`;
27858
+ return {
27859
+ block: {
27860
+ type: "tool_result",
27861
+ tool_use_id: tu.id,
27862
+ content,
27863
+ is_error: true
27864
+ },
27865
+ isError: true
27866
+ };
27867
+ }
27868
+ const callInput = verdict.updatedInput ?? effectiveInput;
27869
+ let block;
27870
+ let isError = false;
27871
+ let toolUseResult;
27872
+ try {
27873
+ const res = await tool.call(callInput, toolCallContext, undefined, assistantMsg);
27874
+ block = tool.mapToolResultToToolResultBlockParam(res.data, tu.id);
27875
+ toolUseResult = res.data;
27876
+ } catch (error) {
27877
+ const errorText = `tool error [${classifyToolError(error)}]: ${String(error?.message ?? error)}`;
27878
+ block = {
27879
+ type: "tool_result",
27880
+ tool_use_id: tu.id,
27881
+ content: `<tool_use_error>${errorText}</tool_use_error>`,
27882
+ is_error: true
27883
+ };
27884
+ isError = true;
27885
+ toolUseResult = errorText;
27886
+ }
27887
+ const postOutcome = await deps.hooks?.postToolUse?.(tool, callInput, block, tu.id);
27888
+ return { block, isError, toolUseResult };
27889
+ }
27890
+ var init_toolExecution = () => {};
27891
+
27892
+ // src/engine/pipeline/toolOrchestration.ts
27893
+ function partitionToolCalls(toolUses, tools) {
27894
+ return toolUses.reduce((acc, tu) => {
27895
+ const tool = findTool(tools, tu.name);
27896
+ let safe = false;
27897
+ try {
27898
+ safe = tool ? tool.isConcurrencySafe(tu.input) : false;
27899
+ } catch {
27900
+ safe = false;
27901
+ }
27902
+ if (safe && acc[acc.length - 1]?.isConcurrencySafe) {
27903
+ acc[acc.length - 1].blocks.push(tu);
27904
+ } else {
27905
+ acc.push({ isConcurrencySafe: safe, blocks: [tu] });
27906
+ }
27907
+ return acc;
27908
+ }, []);
27909
+ }
27910
+ async function runToolBatch(toolUses, assistantMsg, deps) {
27911
+ const outcomes = [];
27912
+ for (const batch of partitionToolCalls(toolUses, deps.tools)) {
27913
+ for (const tu of batch.blocks) {
27914
+ const r = await executeToolUse(tu, assistantMsg, deps);
27915
+ outcomes.push({
27916
+ toolUseId: tu.id,
27917
+ name: tu.name,
27918
+ block: r.block,
27919
+ isError: r.isError,
27920
+ toolUseResult: r.toolUseResult
27921
+ });
27922
+ }
27923
+ }
27924
+ return outcomes;
27925
+ }
27926
+ var init_toolOrchestration = __esm(() => {
27927
+ init_toolExecution();
27928
+ });
27929
+
27930
+ // src/engine/pipeline/index.ts
27931
+ var init_pipeline = __esm(() => {
27932
+ init_toolExecution();
27933
+ init_toolOrchestration();
27934
+ });
27935
+
27769
27936
  // node_modules/zod/index.js
27770
27937
  var init_zod = __esm(() => {
27771
27938
  init_external();
@@ -76317,7 +76484,7 @@ Important:
76317
76484
  // src/engine/tools/skill/skillTool.ts
76318
76485
  import { randomUUID as randomUUID14 } from "crypto";
76319
76486
  async function getAllCommands() {
76320
- return getCommands(getProjectRoot());
76487
+ return getCommands(process.cwd());
76321
76488
  }
76322
76489
  function getToolUseIDFromParentMessage(parentMessage, toolName) {
76323
76490
  if (!parentMessage)
@@ -76388,7 +76555,6 @@ function skillHasOnlySafeProperties(command) {
76388
76555
  }
76389
76556
  var SKILL_TOOL_INPUT_SCHEMA, SAFE_SKILL_PROPERTIES, SkillTool;
76390
76557
  var init_skillTool = __esm(() => {
76391
- init_bootstrap();
76392
76558
  init_shared();
76393
76559
  init_permissions3();
76394
76560
  init_modelprovider2();
@@ -76455,7 +76621,7 @@ var init_skillTool = __esm(() => {
76455
76621
  return skill ?? "";
76456
76622
  },
76457
76623
  async description() {
76458
- return getSkillPrompt(getProjectRoot());
76624
+ return getSkillPrompt(process.cwd());
76459
76625
  },
76460
76626
  async checkPermissions(input, context) {
76461
76627
  const { skill, args } = input;
@@ -80550,7 +80716,9 @@ async function queryOneRound(deps, tools, messages) {
80550
80716
  fallbackModel: deps.fallbackModel,
80551
80717
  options: deps.effortValue !== undefined ? { effortValue: deps.effortValue } : undefined
80552
80718
  };
80553
- let resp = await deps.modelProvider.chat(chatArgs);
80719
+ let resp = await withTurnRecovery(() => deps.modelProvider.chat(chatArgs), {
80720
+ signal: deps.signal
80721
+ });
80554
80722
  let assistantContent = resp.message.content ?? [];
80555
80723
  const isEmptyContent = (content) => {
80556
80724
  if (!Array.isArray(content))
@@ -80565,7 +80733,9 @@ async function queryOneRound(deps, tools, messages) {
80565
80733
  });
80566
80734
  };
80567
80735
  if (isEmptyContent(assistantContent) && !deps.signal?.aborted) {
80568
- const retried = await deps.modelProvider.chat(chatArgs);
80736
+ const retried = await withTurnRecovery(() => deps.modelProvider.chat(chatArgs), {
80737
+ signal: deps.signal
80738
+ });
80569
80739
  const retriedContent = retried.message.content ?? [];
80570
80740
  if (!isEmptyContent(retriedContent)) {
80571
80741
  resp = retried;
@@ -80697,6 +80867,7 @@ async function queryAgentLoop(deps, args) {
80697
80867
  var DEFAULT_AGENT_LOOP_MAX_TURNS = 20;
80698
80868
  var init_loop = __esm(() => {
80699
80869
  init_shared();
80870
+ init_turnRecovery();
80700
80871
  init_pipeline();
80701
80872
  init_context();
80702
80873
  });
@@ -80717,6 +80888,7 @@ var init_QueryEngine = __esm(() => {
80717
80888
  // src/engine/query/index.ts
80718
80889
  var init_query2 = __esm(() => {
80719
80890
  init_loop();
80891
+ init_turnRecovery();
80720
80892
  init_QueryEngine();
80721
80893
  });
80722
80894
 
@@ -121613,6 +121785,7 @@ var isMcpServerCommandEntry = () => ({}), isMcpServerNameEntry = () => ({}), isM
121613
121785
  object({ kind: literal("window"), tokens: number2().int().min(1000) }),
121614
121786
  object({ kind: literal("pct"), pct: number2().min(1).max(100) })
121615
121787
  ]).optional(),
121788
+ llmTimeoutMs: number2().int().positive().optional(),
121616
121789
  prefersReducedMotion: boolean2().optional(),
121617
121790
  syntaxHighlightingDisabled: boolean2().optional(),
121618
121791
  spinnerTipsEnabled: boolean2().optional(),
@@ -148277,28 +148450,28 @@ function getEventPriority(eventType) {
148277
148450
  case "focus":
148278
148451
  case "blur":
148279
148452
  case "paste":
148280
- return import_constants48.DiscreteEventPriority;
148453
+ return import_constants53.DiscreteEventPriority;
148281
148454
  case "resize":
148282
148455
  case "scroll":
148283
148456
  case "mousemove":
148284
- return import_constants48.ContinuousEventPriority;
148457
+ return import_constants53.ContinuousEventPriority;
148285
148458
  default:
148286
- return import_constants48.DefaultEventPriority;
148459
+ return import_constants53.DefaultEventPriority;
148287
148460
  }
148288
148461
  }
148289
148462
 
148290
148463
  class Dispatcher {
148291
148464
  currentEvent = null;
148292
- currentUpdatePriority = import_constants48.DefaultEventPriority;
148465
+ currentUpdatePriority = import_constants53.DefaultEventPriority;
148293
148466
  discreteUpdates = null;
148294
148467
  resolveEventPriority() {
148295
- if (this.currentUpdatePriority !== import_constants48.NoEventPriority) {
148468
+ if (this.currentUpdatePriority !== import_constants53.NoEventPriority) {
148296
148469
  return this.currentUpdatePriority;
148297
148470
  }
148298
148471
  if (this.currentEvent) {
148299
148472
  return getEventPriority(this.currentEvent.type);
148300
148473
  }
148301
- return import_constants48.DefaultEventPriority;
148474
+ return import_constants53.DefaultEventPriority;
148302
148475
  }
148303
148476
  dispatch(target, event) {
148304
148477
  const previousEvent = this.currentEvent;
@@ -148323,18 +148496,18 @@ class Dispatcher {
148323
148496
  dispatchContinuous(target, event) {
148324
148497
  const previousPriority = this.currentUpdatePriority;
148325
148498
  try {
148326
- this.currentUpdatePriority = import_constants48.ContinuousEventPriority;
148499
+ this.currentUpdatePriority = import_constants53.ContinuousEventPriority;
148327
148500
  return this.dispatch(target, event);
148328
148501
  } finally {
148329
148502
  this.currentUpdatePriority = previousPriority;
148330
148503
  }
148331
148504
  }
148332
148505
  }
148333
- var import_constants48;
148506
+ var import_constants53;
148334
148507
  var init_dispatcher = __esm(() => {
148335
148508
  init_log5();
148336
148509
  init_event_handlers();
148337
- import_constants48 = __toESM(require_constants2(), 1);
148510
+ import_constants53 = __toESM(require_constants2(), 1);
148338
148511
  });
148339
148512
 
148340
148513
  // src/tui/ink/events/terminal-event.ts
@@ -157141,7 +157314,7 @@ function applyPositionedHighlight(screen, stylePool, positions, rowOffset, curre
157141
157314
  }
157142
157315
  return true;
157143
157316
  }
157144
- var import_constants50, timing;
157317
+ var import_constants55, timing;
157145
157318
  var init_render_to_screen = __esm(() => {
157146
157319
  init_debug();
157147
157320
  init_dom();
@@ -157150,7 +157323,7 @@ var init_render_to_screen = __esm(() => {
157150
157323
  init_reconciler();
157151
157324
  init_render_node_to_output();
157152
157325
  init_screen();
157153
- import_constants50 = __toESM(require_constants2(), 1);
157326
+ import_constants55 = __toESM(require_constants2(), 1);
157154
157327
  timing = { reconcile: 0, yoga: 0, paint: 0, scan: 0, calls: 0 };
157155
157328
  });
157156
157329
 
@@ -157456,7 +157629,7 @@ class Ink {
157456
157629
  };
157457
157630
  }
157458
157631
  };
157459
- this.container = reconciler_default.createContainer(this.rootNode, import_constants51.ConcurrentRoot, null, false, null, "id", noop_default, noop_default, noop_default, noop_default);
157632
+ this.container = reconciler_default.createContainer(this.rootNode, import_constants56.ConcurrentRoot, null, false, null, "id", noop_default, noop_default, noop_default, noop_default);
157460
157633
  if (false) {}
157461
157634
  }
157462
157635
  handleResume = () => {
@@ -158269,7 +158442,7 @@ function drainStdin(stdin = process.stdin) {
158269
158442
  }
158270
158443
  }
158271
158444
  }
158272
- var import_constants51, jsx_dev_runtime8, ALT_SCREEN_ANCHOR_CURSOR, CURSOR_HOME_PATCH, ERASE_THEN_HOME_PATCH, CONSOLE_STDOUT_METHODS, CONSOLE_STDERR_METHODS;
158445
+ var import_constants56, jsx_dev_runtime8, ALT_SCREEN_ANCHOR_CURSOR, CURSOR_HOME_PATCH, ERASE_THEN_HOME_PATCH, CONSOLE_STDOUT_METHODS, CONSOLE_STDERR_METHODS;
158273
158446
  var init_ink = __esm(() => {
158274
158447
  init_noop();
158275
158448
  init_throttle2();
@@ -158302,7 +158475,7 @@ var init_ink = __esm(() => {
158302
158475
  init_dec();
158303
158476
  init_osc();
158304
158477
  init_useTerminalNotification();
158305
- import_constants51 = __toESM(require_constants2(), 1);
158478
+ import_constants56 = __toESM(require_constants2(), 1);
158306
158479
  jsx_dev_runtime8 = __toESM(require_jsx_dev_runtime(), 1);
158307
158480
  ALT_SCREEN_ANCHOR_CURSOR = Object.freeze({
158308
158481
  x: 0,
@@ -203040,7 +203213,7 @@ var init_drainRunLoop = __esm(() => {
203040
203213
 
203041
203214
  // src/tui/utils/computerUse/escHotkey.ts
203042
203215
  function registerEscHotkey(onEscape) {
203043
- if (registered)
203216
+ if (registered2)
203044
203217
  return true;
203045
203218
  const cu = requireComputerUseSwift();
203046
203219
  if (!cu.hotkey.registerEscape(onEscape)) {
@@ -203048,16 +203221,16 @@ function registerEscHotkey(onEscape) {
203048
203221
  return false;
203049
203222
  }
203050
203223
  retainPump();
203051
- registered = true;
203224
+ registered2 = true;
203052
203225
  logForDebugging3("[cu-esc] registered");
203053
203226
  return true;
203054
203227
  }
203055
203228
  function notifyExpectedEscape() {
203056
- if (!registered)
203229
+ if (!registered2)
203057
203230
  return;
203058
203231
  requireComputerUseSwift().hotkey.notifyExpectedEscape();
203059
203232
  }
203060
- var registered = false;
203233
+ var registered2 = false;
203061
203234
  var init_escHotkey = __esm(() => {
203062
203235
  init_debug();
203063
203236
  init_drainRunLoop();
@@ -271660,7 +271833,7 @@ async function* runAgent2({
271660
271833
  }
271661
271834
  const skillsToPreload = agentDefinition.skills ?? [];
271662
271835
  if (skillsToPreload.length > 0) {
271663
- const allSkills = await getSkillToolCommands2(getProjectRoot());
271836
+ const allSkills = await getSkillToolCommands2(process.cwd());
271664
271837
  const validSkills = [];
271665
271838
  for (const skillName of skillsToPreload) {
271666
271839
  const resolvedName = resolveSkillName(skillName, allSkills, agentDefinition);
@@ -272269,9 +272442,9 @@ function getDefaultMaxRetries() {
272269
272442
  if (process.env.ATLAS_MAX_RETRIES) {
272270
272443
  return parseInt(process.env.ATLAS_MAX_RETRIES || "", 10);
272271
272444
  }
272272
- return DEFAULT_MAX_RETRIES;
272445
+ return DEFAULT_MAX_RETRIES2;
272273
272446
  }
272274
- var DEFAULT_MAX_RETRIES = 10, BASE_DELAY_MS = 500, FOREGROUND_529_RETRY_SOURCES, PERSISTENT_MAX_BACKOFF_MS, PERSISTENT_RESET_CAP_MS;
272447
+ var DEFAULT_MAX_RETRIES2 = 10, BASE_DELAY_MS = 500, FOREGROUND_529_RETRY_SOURCES, PERSISTENT_MAX_BACKOFF_MS, PERSISTENT_RESET_CAP_MS;
272275
272448
  var init_withRetry = __esm(() => {
272276
272449
  init_shared();
272277
272450
  init_atlas();
@@ -274526,8 +274699,8 @@ var init_UI10 = __esm(() => {
274526
274699
  async function getAllCommands2(context) {
274527
274700
  const mcpSkills = context.getAppState().mcp.commands.filter((cmd) => cmd.type === "prompt" && cmd.loadedFrom === "mcp");
274528
274701
  if (mcpSkills.length === 0)
274529
- return getCommands2(getProjectRoot());
274530
- const localCommands = await getCommands2(getProjectRoot());
274702
+ return getCommands2(process.cwd());
274703
+ const localCommands = await getCommands2(process.cwd());
274531
274704
  return uniqBy_default([...localCommands, ...mcpSkills], "name");
274532
274705
  }
274533
274706
  async function executeForkedSkill2(command, commandName, args, context, canUseTool, parentMessage, onProgress) {
@@ -274623,7 +274796,6 @@ function isOfficialMarketplaceSkill(command) {
274623
274796
  var inputSchema14, outputSchema12, SkillTool2, SAFE_SKILL_PROPERTIES2;
274624
274797
  var init_SkillTool = __esm(() => {
274625
274798
  init_uniqBy();
274626
- init_bootstrap();
274627
274799
  init_commands5();
274628
274800
  init_Tool();
274629
274801
  init_debug();
@@ -274673,7 +274845,7 @@ var init_SkillTool = __esm(() => {
274673
274845
  return outputSchema12();
274674
274846
  },
274675
274847
  description: async ({ skill }) => `Execute skill: ${skill}`,
274676
- prompt: async () => getPrompt20(getProjectRoot()),
274848
+ prompt: async () => getPrompt20(process.cwd()),
274677
274849
  toAutoClassifierInput: ({ skill }) => skill ?? "",
274678
274850
  async validateInput({ skill }, context) {
274679
274851
  const trimmed = skill.trim();
@@ -430263,6 +430435,7 @@ function wireContextHostPorts() {
430263
430435
  });
430264
430436
  setAutoCompactSettingsSource(() => getGlobalConfig().autoCompactEnabled);
430265
430437
  setAutoCompactWindowSettingsSource(() => getInitialSettings2().autoCompactWindow);
430438
+ setLlmTimeoutSettingsSource(() => getInitialSettings2().llmTimeoutMs);
430266
430439
  setTimeBasedMCConfigSource(() => getFeatureValue_CACHED_MAY_BE_STALE("atlas_slate_heron", TIME_BASED_MC_CONFIG_DEFAULTS));
430267
430440
  clearPostCompactResetsForTesting();
430268
430441
  if (feature("CONTEXT_COLLAPSE")) {
@@ -430291,6 +430464,7 @@ function wireContextHostPorts() {
430291
430464
  }
430292
430465
  var init_contextHostWiring = __esm(() => {
430293
430466
  init_shared();
430467
+ init_modelprovider2();
430294
430468
  init_engine();
430295
430469
  init_config6();
430296
430470
  init_settings3();
@@ -475922,7 +476096,8 @@ Error: sandbox required but unavailable: ${reason}
475922
476096
  await onQueryImpl(latestMessages, newMessages, abortController, shouldQuery, additionalAllowedTools, mainLoopModelParam, effort);
475923
476097
  } catch (error) {
475924
476098
  logError3(error);
475925
- setMessages((prev) => [...prev, createSystemMessage(`本轮执行出错:${errorMessage2(error)}。请重试。`, "error")]);
476099
+ const llmTimeoutHint = llmTimeoutRemediationHint(error, getCurrentLlmTimeoutMs());
476100
+ setMessages((prev) => [...prev, createSystemMessage(`本轮执行出错:${errorMessage2(error)}。${llmTimeoutHint ? `${llmTimeoutHint} ` : ""}请重试。`, "error")]);
475926
476101
  } finally {
475927
476102
  if (queryGuard.end(thisGeneration)) {
475928
476103
  setLastQueryCompletionTime(Date.now());
@@ -477601,6 +477776,7 @@ Note: ctrl + z now suspends AtlasHarness, ctrl + _ undoes input.
477601
477776
  var import_compiler_runtime323, React137, import_react280, jsx_dev_runtime427, UltraplanChoiceDialog = () => null, UltraplanLaunchDialog = () => null, launchUltraplan2 = null, useVoiceIntegration2, VoiceKeybindingHandler2, useAntOrgWarningNotification = () => {}, getCoordinatorUserContext3, SUGGEST_BG_PR_NOOP = (_p, _n) => false, useScheduledTasks2, EMPTY_MCP_CLIENTS2, RECENT_SCROLL_REPIN_WINDOW_MS = 3000, TITLE_ANIMATION_FRAMES, TITLE_STATIC_PREFIX = "✳", TITLE_ANIMATION_INTERVAL_MS = 960;
477602
477777
  var init_REPL = __esm(() => {
477603
477778
  init_shared();
477779
+ init_modelprovider2();
477604
477780
  init_bootstrap();
477605
477781
  init_bootstrapState();
477606
477782
  init_tokenBudget();
@@ -490824,6 +491000,14 @@ function createCoreDependencies() {
490824
491000
  return;
490825
491001
  }
490826
491002
  });
491003
+ setLlmTimeoutSettingsSource(() => {
491004
+ try {
491005
+ const v = getInitialSettings().llmTimeoutMs;
491006
+ return typeof v === "number" ? v : undefined;
491007
+ } catch {
491008
+ return;
491009
+ }
491010
+ });
490827
491011
  return {
490828
491012
  sandboxManager,
490829
491013
  modelProvider: getModelProvider(),
@@ -493912,6 +494096,11 @@ async function binMain() {
493912
494096
  await main2();
493913
494097
  return;
493914
494098
  }
494099
+ registerGlobalCrashBackstop();
494100
+ if (process.env.ATLAS_TEST_CRASH_BACKSTOP === "1") {
494101
+ process.emit("uncaughtException", new Error("atlas crash-backstop live probe"));
494102
+ process.exit(0);
494103
+ }
493915
494104
  getCoreDependencies();
493916
494105
  await main();
493917
494106
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@atlasharness/atlascode",
3
- "version": "0.1.15",
3
+ "version": "0.1.17",
4
4
  "description": "AtlasCode \u2014 Coding Agent for the domestic computing ecosystem (Ascend NPU + domestic LLM backends)",
5
5
  "bin": {
6
6
  "atlas": "dist/cli.js",