@atlasharness/atlascode 0.1.78 → 0.1.80

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 +824 -153
  2. package/package.json +1 -1
package/dist/cli.js CHANGED
@@ -19862,7 +19862,7 @@ var init_openai = __esm(() => {
19862
19862
  });
19863
19863
 
19864
19864
  // src/modelprovider/constants.ts
19865
- var API_IMAGE_MAX_BASE64_SIZE, IMAGE_TARGET_RAW_SIZE, PDF_TARGET_RAW_SIZE, API_PDF_MAX_PAGES = 100, LLM_TIMEOUT_DEFAULT_MS = 900000, LLM_TIMEOUT_CAP_MS = 1800000, LLM_TIMEOUT_UNIT_WARN_THRESHOLD_MS = 60000, SUMMARIZE_CONNECTOR_TEXT_BETA_HEADER, AFK_MODE_BETA_HEADER;
19865
+ var API_IMAGE_MAX_BASE64_SIZE, IMAGE_TARGET_RAW_SIZE, PDF_TARGET_RAW_SIZE, API_PDF_MAX_PAGES = 100, LLM_TIMEOUT_DEFAULT_MS = 900000, LLM_TIMEOUT_CAP_MS = 1800000, LLM_TIMEOUT_UNIT_WARN_THRESHOLD_MS = 60000, STREAM_IDLE_TIMEOUT_MS = 300000, SUMMARIZE_CONNECTOR_TEXT_BETA_HEADER, AFK_MODE_BETA_HEADER;
19866
19866
  var init_constants2 = __esm(() => {
19867
19867
  init_shared();
19868
19868
  API_IMAGE_MAX_BASE64_SIZE = 5 * 1024 * 1024;
@@ -19900,6 +19900,56 @@ var init_clients = __esm(() => {
19900
19900
  clientCache = new Map;
19901
19901
  });
19902
19902
 
19903
+ // src/modelprovider/streamIdleWatchdog.ts
19904
+ async function* withStreamIdleWatchdog(stream, timeoutMs = STREAM_IDLE_TIMEOUT_MS) {
19905
+ if (!Number.isFinite(timeoutMs) || timeoutMs <= 0) {
19906
+ yield* stream;
19907
+ return;
19908
+ }
19909
+ const iterator = typeof stream[Symbol.asyncIterator] === "function" ? stream[Symbol.asyncIterator]() : async function* wrapSyncIterable() {
19910
+ yield* stream;
19911
+ }();
19912
+ try {
19913
+ while (true) {
19914
+ const nextPromise = iterator.next();
19915
+ nextPromise.catch(() => {});
19916
+ let timer;
19917
+ const timerPromise = new Promise((resolve) => {
19918
+ timer = setTimeout(() => resolve("timeout"), timeoutMs);
19919
+ if (typeof timer === "object" && timer !== null && "unref" in timer) {
19920
+ timer.unref();
19921
+ }
19922
+ });
19923
+ const winner = await Promise.race([nextPromise, timerPromise]);
19924
+ if (timer !== undefined)
19925
+ clearTimeout(timer);
19926
+ if (winner === "timeout") {
19927
+ throw new StreamIdleTimeoutError(timeoutMs);
19928
+ }
19929
+ const result = winner;
19930
+ if (result.done)
19931
+ return;
19932
+ yield result.value;
19933
+ }
19934
+ } finally {
19935
+ try {
19936
+ await iterator.return?.();
19937
+ } catch {}
19938
+ }
19939
+ }
19940
+ var StreamIdleTimeoutError;
19941
+ var init_streamIdleWatchdog = __esm(() => {
19942
+ init_constants2();
19943
+ StreamIdleTimeoutError = class StreamIdleTimeoutError extends Error {
19944
+ timeoutMs;
19945
+ constructor(timeoutMs) {
19946
+ super(`Stream idle timeout: no chunk received for ${timeoutMs}ms`);
19947
+ this.name = "StreamIdleTimeoutError";
19948
+ this.timeoutMs = timeoutMs;
19949
+ }
19950
+ };
19951
+ });
19952
+
19903
19953
  // src/modelprovider/roles.ts
19904
19954
  function setEndpointConfigSource(source) {
19905
19955
  activeSource = source;
@@ -26560,6 +26610,46 @@ var init_schema = __esm(() => {
26560
26610
  cache = new WeakMap;
26561
26611
  });
26562
26612
 
26613
+ // src/modelprovider/capabilities.ts
26614
+ function stripProviderPrefix(model) {
26615
+ const idx = model.lastIndexOf("/");
26616
+ return idx >= 0 ? model.slice(idx + 1) : model;
26617
+ }
26618
+ function getModelMeta(modelId) {
26619
+ if (!modelId)
26620
+ return;
26621
+ const providers = getEndpointConfigSource().getProviders();
26622
+ for (const pCfg of Object.values(providers)) {
26623
+ const models = pCfg.models || [];
26624
+ const entry = models.find((m) => m?.id === modelId) ?? models.find((m) => m?.id === stripProviderPrefix(modelId));
26625
+ if (entry) {
26626
+ return {
26627
+ knowledgeCutoff: entry.knowledgeCutoff,
26628
+ supportsThinking: entry.supportsThinking,
26629
+ supportsEffort: entry.supportsEffort,
26630
+ supportsStructuredOutputs: entry.supportsStructuredOutputs,
26631
+ skipCyberMitigation: entry.skipCyberMitigation
26632
+ };
26633
+ }
26634
+ }
26635
+ return;
26636
+ }
26637
+ function getProviderContextWindow(modelId) {
26638
+ if (!modelId)
26639
+ return;
26640
+ const providers = getEndpointConfigSource().getProviders();
26641
+ for (const pCfg of Object.values(providers)) {
26642
+ const models = pCfg.models || [];
26643
+ const entry = models.find((m) => m?.id === modelId) ?? models.find((m) => m?.id === stripProviderPrefix(modelId));
26644
+ if (entry?.contextWindow)
26645
+ return entry.contextWindow;
26646
+ }
26647
+ return;
26648
+ }
26649
+ var init_capabilities = __esm(() => {
26650
+ init_roles7();
26651
+ });
26652
+
26563
26653
  // src/modelprovider/effort.ts
26564
26654
  function isEffortLevel(value) {
26565
26655
  return EFFORT_LEVELS.includes(value);
@@ -26625,6 +26715,13 @@ function lookupEffortByModel(model) {
26625
26715
  if (key.toLowerCase() === wanted)
26626
26716
  return level;
26627
26717
  }
26718
+ const base = stripProviderPrefix(model).toLowerCase();
26719
+ if (base !== wanted) {
26720
+ for (const [key, level] of Object.entries(map)) {
26721
+ if (key.toLowerCase() === base)
26722
+ return level;
26723
+ }
26724
+ }
26628
26725
  return;
26629
26726
  }
26630
26727
  function resolveAppliedEffort(model, appStateEffortValue) {
@@ -26638,6 +26735,7 @@ function resolveAppliedEffort(model, appStateEffortValue) {
26638
26735
  var effortByModelSource = null;
26639
26736
  var init_effort = __esm(() => {
26640
26737
  init_shared();
26738
+ init_capabilities();
26641
26739
  });
26642
26740
 
26643
26741
  // src/modelprovider/params.ts
@@ -26785,7 +26883,23 @@ async function buildOpenAITools(tools, options, emptyPermissionContext) {
26785
26883
  });
26786
26884
  }
26787
26885
  }
26788
- return out;
26886
+ return stableSortDedupeTools(out);
26887
+ }
26888
+ function stableSortDedupeTools(tools) {
26889
+ const nameOf = (t) => t.type === "function" ? t.function.name : t.custom.name;
26890
+ const sorted = [...tools].sort((a, b) => {
26891
+ const an = nameOf(a);
26892
+ const bn = nameOf(b);
26893
+ return an < bn ? -1 : an > bn ? 1 : 0;
26894
+ });
26895
+ const seen = new Set;
26896
+ return sorted.filter((t) => {
26897
+ const n = nameOf(t);
26898
+ if (seen.has(n))
26899
+ return false;
26900
+ seen.add(n);
26901
+ return true;
26902
+ });
26789
26903
  }
26790
26904
  function toResponseFormat(outputFormat) {
26791
26905
  if (!outputFormat)
@@ -26844,24 +26958,47 @@ var init_params = __esm(() => {
26844
26958
  });
26845
26959
 
26846
26960
  // src/modelprovider/types.ts
26847
- var APIError2, APIConnectionError2, APIConnectionTimeoutError2;
26961
+ var APIError2, AuthenticationError2, NotFoundError2, APIConnectionError2, APIConnectionTimeoutError2, APIUserAbortError2;
26848
26962
  var init_types2 = __esm(() => {
26849
26963
  APIError2 = class APIError2 extends Error {
26850
26964
  status;
26965
+ code;
26966
+ headers;
26851
26967
  error;
26852
- constructor(message, status, error) {
26853
- super(message);
26968
+ constructor(message, statusOrOpts, error) {
26969
+ super(message ?? "API error");
26854
26970
  this.name = "APIError";
26855
- if (status !== undefined)
26856
- this.status = status;
26857
- if (error !== undefined)
26858
- this.error = error;
26971
+ if (typeof statusOrOpts === "number") {
26972
+ if (statusOrOpts !== undefined)
26973
+ this.status = statusOrOpts;
26974
+ if (error !== undefined)
26975
+ this.error = error;
26976
+ } else if (statusOrOpts) {
26977
+ if (statusOrOpts.status !== undefined)
26978
+ this.status = statusOrOpts.status;
26979
+ if (statusOrOpts.code !== undefined)
26980
+ this.code = statusOrOpts.code;
26981
+ if (statusOrOpts.headers !== undefined)
26982
+ this.headers = statusOrOpts.headers;
26983
+ if (statusOrOpts.error !== undefined)
26984
+ this.error = statusOrOpts.error;
26985
+ }
26986
+ }
26987
+ };
26988
+ AuthenticationError2 = class AuthenticationError2 extends APIError2 {
26989
+ constructor(message, opts) {
26990
+ super(message, opts);
26991
+ this.name = "AuthenticationError";
26859
26992
  }
26860
26993
  };
26994
+ NotFoundError2 = class NotFoundError2 extends APIError2 {
26995
+ };
26861
26996
  APIConnectionError2 = class APIConnectionError2 extends APIError2 {
26862
26997
  };
26863
26998
  APIConnectionTimeoutError2 = class APIConnectionTimeoutError2 extends APIConnectionError2 {
26864
26999
  };
27000
+ APIUserAbortError2 = class APIUserAbortError2 extends APIError2 {
27001
+ };
26865
27002
  });
26866
27003
 
26867
27004
  // src/modelprovider/errorUtils.ts
@@ -27606,7 +27743,7 @@ class OpenAIProvider {
27606
27743
  let usage = null;
27607
27744
  let streamError = null;
27608
27745
  try {
27609
- for await (const chunk of stream) {
27746
+ for await (const chunk of withStreamIdleWatchdog(stream, STREAM_IDLE_TIMEOUT_MS)) {
27610
27747
  const choice = chunk.choices?.[0];
27611
27748
  const delta = choice?.delta;
27612
27749
  if (delta?.content) {
@@ -27864,6 +28001,8 @@ var init_modelprovider = __esm(() => {
27864
28001
  init_openai();
27865
28002
  init_clients();
27866
28003
  init_constants2();
28004
+ init_constants2();
28005
+ init_streamIdleWatchdog();
27867
28006
  init_roles7();
27868
28007
  init_shared();
27869
28008
  init_shared();
@@ -27889,42 +28028,6 @@ Fix: ${fix}`);
27889
28028
  };
27890
28029
  });
27891
28030
 
27892
- // src/modelprovider/capabilities.ts
27893
- function getModelMeta(modelId) {
27894
- if (!modelId)
27895
- return;
27896
- const providers = getEndpointConfigSource().getProviders();
27897
- for (const pCfg of Object.values(providers)) {
27898
- const models = pCfg.models || [];
27899
- const entry = models.find((m) => m?.id === modelId);
27900
- if (entry) {
27901
- return {
27902
- knowledgeCutoff: entry.knowledgeCutoff,
27903
- supportsThinking: entry.supportsThinking,
27904
- supportsEffort: entry.supportsEffort,
27905
- supportsStructuredOutputs: entry.supportsStructuredOutputs,
27906
- skipCyberMitigation: entry.skipCyberMitigation
27907
- };
27908
- }
27909
- }
27910
- return;
27911
- }
27912
- function getProviderContextWindow(modelId) {
27913
- if (!modelId)
27914
- return;
27915
- const providers = getEndpointConfigSource().getProviders();
27916
- for (const pCfg of Object.values(providers)) {
27917
- const models = pCfg.models || [];
27918
- const entry = models.find((m) => m?.id === modelId);
27919
- if (entry?.contextWindow)
27920
- return entry.contextWindow;
27921
- }
27922
- return;
27923
- }
27924
- var init_capabilities = __esm(() => {
27925
- init_roles7();
27926
- });
27927
-
27928
28031
  // src/modelprovider/roleFallbackStore.ts
27929
28032
  function clearRoleFallback() {
27930
28033
  lastRoleFallback = null;
@@ -28042,6 +28145,7 @@ var init_modelprovider2 = __esm(() => {
28042
28145
  init_roles7();
28043
28146
  init_modelprovider();
28044
28147
  init_constants2();
28148
+ init_streamIdleWatchdog();
28045
28149
  init_modelprovider();
28046
28150
  init_types2();
28047
28151
  init_modelErrors();
@@ -28846,7 +28950,9 @@ var init_hookEvents = __esm(() => {
28846
28950
  "CwdChanged",
28847
28951
  "FileChanged",
28848
28952
  "PreModelSwitch",
28849
- "PostModelSwitch"
28953
+ "PostModelSwitch",
28954
+ "DirectoryAdded",
28955
+ "MessageDisplay"
28850
28956
  ];
28851
28957
  });
28852
28958
 
@@ -28994,6 +29100,9 @@ async function getMatchingHooks(hookEvent, hookInput) {
28994
29100
  case "PostModelSwitch":
28995
29101
  matchQuery = hookInput.new_model;
28996
29102
  break;
29103
+ case "DirectoryAdded":
29104
+ matchQuery = hookInput.directory;
29105
+ break;
28997
29106
  default:
28998
29107
  break;
28999
29108
  }
@@ -29107,6 +29216,8 @@ function interpretHookOutput(p) {
29107
29216
  result.output = "";
29108
29217
  if (json.systemMessage)
29109
29218
  result.systemMessage = json.systemMessage;
29219
+ if (json.terminalSequence)
29220
+ result.terminalSequence = json.terminalSequence;
29110
29221
  } catch {}
29111
29222
  }
29112
29223
  if (!p.aborted && p.code === 2 && !jsonParsed && !result.blockingError) {
@@ -29118,8 +29229,14 @@ function interpretHookOutput(p) {
29118
29229
  return result;
29119
29230
  }
29120
29231
  function mergeAggregated(acc, r) {
29121
- if (r.blockingError && !acc.blockingError)
29232
+ if (r.terminalSequence) {
29233
+ acc.terminalSequence = (acc.terminalSequence ?? "") + r.terminalSequence;
29234
+ }
29235
+ if (r.blockingError && !acc.blockingError) {
29122
29236
  acc.blockingError = r.blockingError;
29237
+ if (r.continueOnBlock)
29238
+ acc.continueOnBlock = true;
29239
+ }
29123
29240
  if (r.preventContinuation)
29124
29241
  acc.preventContinuation = true;
29125
29242
  if (r.stopReason && !acc.stopReason)
@@ -29142,13 +29259,19 @@ ${r.additionalContext}` : r.additionalContext;
29142
29259
  function runOneHook(m, port, env, signal, options) {
29143
29260
  const cmd = m.hook;
29144
29261
  const timeoutMs = cmd.timeoutMs ?? options.timeoutMs ?? HOOK_EXECUTION_TIMEOUT_MS;
29145
- return port.runCommand(cmd.command, env, signal, timeoutMs).then((exec) => interpretHookOutput({
29146
- command: cmd.command,
29147
- stdout: exec.stdout,
29148
- stderr: exec.stderr,
29149
- code: exec.code,
29150
- aborted: exec.aborted
29151
- }), (e) => ({
29262
+ return port.runCommand(cmd.command, env, signal, timeoutMs).then((exec) => {
29263
+ const result = interpretHookOutput({
29264
+ command: cmd.command,
29265
+ stdout: exec.stdout,
29266
+ stderr: exec.stderr,
29267
+ code: exec.code,
29268
+ aborted: exec.aborted
29269
+ });
29270
+ if (result.blockingError && cmd.continueOnBlock === true) {
29271
+ result.continueOnBlock = true;
29272
+ }
29273
+ return result;
29274
+ }, (e) => ({
29152
29275
  command: cmd.command,
29153
29276
  status: -1,
29154
29277
  succeeded: false,
@@ -29172,6 +29295,11 @@ async function runHooks(hookEvent, hookInput, options = {}) {
29172
29295
  results.push(result);
29173
29296
  mergeAggregated(aggregated, result);
29174
29297
  }
29298
+ if (aggregated.terminalSequence) {
29299
+ try {
29300
+ process.stdout.write(aggregated.terminalSequence);
29301
+ } catch {}
29302
+ }
29175
29303
  return aggregated;
29176
29304
  }
29177
29305
  async function runPreToolUseHooks(toolName, toolInput, toolUseID, options = {}) {
@@ -29319,6 +29447,7 @@ var init_hooksSchema = __esm(() => {
29319
29447
  once: boolean2().optional(),
29320
29448
  async: boolean2().optional(),
29321
29449
  asyncRewake: boolean2().optional(),
29450
+ continueOnBlock: boolean2().optional(),
29322
29451
  if: string2().optional()
29323
29452
  }).passthrough();
29324
29453
  PromptHookSchema = object({
@@ -29395,18 +29524,54 @@ var SettingsSchema = () => object({
29395
29524
  defaultShell: union([literal("bash"), literal("powershell")]).optional(),
29396
29525
  skipWebFetchPreflight: boolean2().optional(),
29397
29526
  search: object({ tavilyApiKey: string2().optional() }).optional(),
29398
- tui: object({ fullscreen: boolean2().optional() }).optional()
29527
+ tui: object({ fullscreen: boolean2().optional() }).optional(),
29528
+ idleCompaction: boolean2().optional(),
29529
+ skillOverrides: union([
29530
+ literal("off"),
29531
+ literal("user-invocable-only"),
29532
+ literal("name-only")
29533
+ ]).optional()
29399
29534
  }).passthrough();
29400
29535
  var init_types3 = __esm(() => {
29401
29536
  init_zod();
29402
29537
  init_hooksSchema();
29403
29538
  });
29404
29539
 
29540
+ // src/engine/config/restrictedMode.ts
29541
+ function isRestrictedMode() {
29542
+ return restrictedOverride ?? isEnvTruthy(process.env.ATLAS_RESTRICTED);
29543
+ }
29544
+ function setRestrictedMode(enabled) {
29545
+ restrictedOverride = enabled;
29546
+ }
29547
+ function resetRestrictedMode() {
29548
+ restrictedOverride = undefined;
29549
+ }
29550
+ function isSettingsSourceIgnoredInRestricted(source) {
29551
+ if (!isRestrictedMode())
29552
+ return false;
29553
+ return source === "userSettings" || source === "projectSettings" || source === "localSettings";
29554
+ }
29555
+ function restrictedBypassError(opts) {
29556
+ if (!isRestrictedMode())
29557
+ return null;
29558
+ if (opts.permissionMode === "bypassPermissions" || opts.allowDangerouslySkipPermissions === true || opts.dangerouslySkipPermissions === true) {
29559
+ return "--restricted mode does not allow bypassPermissions or --dangerously-skip-permissions for security reasons";
29560
+ }
29561
+ return null;
29562
+ }
29563
+ var restrictedOverride;
29564
+ var init_restrictedMode = __esm(() => {
29565
+ init_shared();
29566
+ });
29567
+
29405
29568
  // src/engine/config/constants.ts
29406
29569
  function getEnabledSettingSources() {
29407
29570
  const result = new Set(ALLOWED_SETTING_SOURCES);
29408
29571
  result.add("policySettings");
29409
29572
  result.add("flagSettings");
29573
+ if (isRestrictedMode())
29574
+ result.delete("userSettings");
29410
29575
  return Array.from(result);
29411
29576
  }
29412
29577
  function isSettingSourceEnabled(source) {
@@ -29415,6 +29580,7 @@ function isSettingSourceEnabled(source) {
29415
29580
  }
29416
29581
  var SETTING_SOURCES, ALLOWED_SETTING_SOURCES;
29417
29582
  var init_constants3 = __esm(() => {
29583
+ init_restrictedMode();
29418
29584
  SETTING_SOURCES = [
29419
29585
  "userSettings",
29420
29586
  "projectSettings",
@@ -30058,7 +30224,9 @@ var init_permissionRuleParser = __esm(() => {
30058
30224
 
30059
30225
  // src/permissions/mcpRuleNames.ts
30060
30226
  function normalizeNameForMCP(name) {
30061
- return name.replace(/[^a-zA-Z0-9_-]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
30227
+ const folded = name.replace(/[^a-zA-Z0-9_-]/g, "_");
30228
+ const normalized = folded.replace(/_+/g, "_").replace(/^_|_$/g, "");
30229
+ return normalized === "" ? folded : normalized;
30062
30230
  }
30063
30231
  function mcpInfoFromString(toolString) {
30064
30232
  const parts = toolString.split("__");
@@ -31908,6 +32076,8 @@ function getSettingsForSource(source) {
31908
32076
  return result;
31909
32077
  }
31910
32078
  function getSettingsForSourceUncached(source) {
32079
+ if (isSettingsSourceIgnoredInRestricted(source))
32080
+ return null;
31911
32081
  if (source === "policySettings") {
31912
32082
  return loadManagedFileSettings().settings;
31913
32083
  }
@@ -31920,6 +32090,11 @@ function getPolicySettingsOrigin() {
31920
32090
  return settings ? "file" : null;
31921
32091
  }
31922
32092
  function updateSettingsForSource(source, settings) {
32093
+ if (isSettingsSourceIgnoredInRestricted(source)) {
32094
+ return {
32095
+ error: new Error(`Settings source ${source} is ignored in restricted mode (--restricted / ATLAS_RESTRICTED)`)
32096
+ };
32097
+ }
31923
32098
  if (source === "policySettings" || source === "flagSettings") {
31924
32099
  return { error: null };
31925
32100
  }
@@ -32082,6 +32257,7 @@ var init_settings = __esm(() => {
32082
32257
  init_zod();
32083
32258
  init_configRoot();
32084
32259
  init_constants3();
32260
+ init_restrictedMode();
32085
32261
  init_managedPath();
32086
32262
  init_settingsCache();
32087
32263
  init_types3();
@@ -32286,6 +32462,7 @@ var init_autoCompactOverrides = __esm(() => {
32286
32462
  var init_config = __esm(() => {
32287
32463
  init_types3();
32288
32464
  init_constants3();
32465
+ init_restrictedMode();
32289
32466
  init_settingsCache();
32290
32467
  init_managedPath();
32291
32468
  init_configRoot();
@@ -36510,7 +36687,9 @@ var init_killShellTasks = __esm(() => {
36510
36687
 
36511
36688
  // src/engine/tools/mcp.ts
36512
36689
  function normalizeNameForMCP2(name) {
36513
- return name.replace(/[^a-zA-Z0-9_-]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
36690
+ const folded = name.replace(/[^a-zA-Z0-9_-]/g, "_");
36691
+ const normalized = folded.replace(/_+/g, "_").replace(/^_|_$/g, "");
36692
+ return normalized === "" ? folded : normalized;
36514
36693
  }
36515
36694
  function mcpInfoFromString2(toolString) {
36516
36695
  const parts = toolString.split("__");
@@ -37111,14 +37290,24 @@ function isAscendToolsEnabled(env = process.env) {
37111
37290
  }
37112
37291
  function getAllBaseTools(deps = {}) {
37113
37292
  const env = deps.env ?? process.env;
37293
+ const restricted = isRestrictedMode();
37114
37294
  const pool = [AgentTool];
37115
37295
  if (deps.baseTools)
37116
37296
  pool.push(...deps.baseTools);
37117
- if (deps.ascendTools && isAscendToolsEnabled(env))
37297
+ if (deps.ascendTools && isAscendToolsEnabled(env) && !restricted) {
37118
37298
  pool.push(...deps.ascendTools);
37299
+ }
37119
37300
  if (deps.mcpTools)
37120
37301
  pool.push(...deps.mcpTools);
37121
- return uniqByName(pool);
37302
+ const assembled = uniqByName(pool);
37303
+ if (!restricted)
37304
+ return assembled;
37305
+ const stripped = new Set([
37306
+ ...SHELL_TOOL_NAMES,
37307
+ WEB_FETCH_TOOL_NAME,
37308
+ AGENT_TOOL_NAME
37309
+ ]);
37310
+ return assembled.filter((t) => !stripped.has(t.name));
37122
37311
  }
37123
37312
  function uniqByName(tools) {
37124
37313
  const seen = new Set;
@@ -37150,7 +37339,9 @@ function parseToolPreset(preset) {
37150
37339
  var TOOL_PRESETS;
37151
37340
  var init_toolRegistry = __esm(() => {
37152
37341
  init_permissions3();
37342
+ init_config();
37153
37343
  init_AgentTool();
37344
+ init_toolNames();
37154
37345
  TOOL_PRESETS = ["default"];
37155
37346
  });
37156
37347
 
@@ -78377,6 +78568,21 @@ var init_mcpFetch = __esm(() => {
78377
78568
  function getConnectionTimeoutMs() {
78378
78569
  return parseInt(process.env.MCP_TIMEOUT || "", 10) || 30000;
78379
78570
  }
78571
+ function getMcpConnectBackoffMs(env = process.env) {
78572
+ const raw = env.ATLAS_MCP_CONNECT_BACKOFF_MS;
78573
+ if (raw === undefined || raw === "")
78574
+ return DEFAULT_MCP_CONNECT_BACKOFF_MS;
78575
+ const parsed = Number(raw);
78576
+ if (!Number.isFinite(parsed))
78577
+ return DEFAULT_MCP_CONNECT_BACKOFF_MS;
78578
+ return Math.max(0, parsed);
78579
+ }
78580
+ function mcpConnectBackoffDelayMs(failureCount, baseMs = getMcpConnectBackoffMs()) {
78581
+ if (failureCount <= 0 || baseMs <= 0)
78582
+ return 0;
78583
+ const raw = baseMs * 2 ** (failureCount - 1);
78584
+ return Math.min(raw, MAX_MCP_CONNECT_BACKOFF_MS);
78585
+ }
78380
78586
  function isTerminalConnectionError(msg) {
78381
78587
  return msg.includes("ECONNRESET") || msg.includes("ETIMEDOUT") || msg.includes("EPIPE") || msg.includes("EHOSTUNREACH") || msg.includes("ECONNREFUSED") || msg.includes("Body Timeout Error") || msg.includes("terminated") || msg.includes("SSE stream disconnected") || msg.includes("Failed to reconnect SSE stream");
78382
78588
  }
@@ -78425,6 +78631,7 @@ async function terminateChild(name, child) {
78425
78631
  function createMcpConnectionManager() {
78426
78632
  const connections = new Map;
78427
78633
  const pending = new Set;
78634
+ const connectFailures = new Map;
78428
78635
  function fail(name, config, error, authFailure = false) {
78429
78636
  const conn = {
78430
78637
  name,
@@ -78529,6 +78736,7 @@ function createMcpConnectionManager() {
78529
78736
  }
78530
78737
  };
78531
78738
  connections.set(name, connection);
78739
+ connectFailures.delete(name);
78532
78740
  return connection;
78533
78741
  } catch (e) {
78534
78742
  stderr.off("data", stderrHandler);
@@ -78539,6 +78747,8 @@ function createMcpConnectionManager() {
78539
78747
  stderrOutput = "";
78540
78748
  }
78541
78749
  const message = e instanceof McpJsonRpcError || e instanceof Error ? e.message : String(e);
78750
+ const prev = connectFailures.get(name);
78751
+ connectFailures.set(name, { count: (prev?.count ?? 0) + 1, lastFailedAt: Date.now() });
78542
78752
  return fail(name, config, message);
78543
78753
  }
78544
78754
  }
@@ -78546,6 +78756,14 @@ function createMcpConnectionManager() {
78546
78756
  const existing = connections.get(name);
78547
78757
  if (existing?.type === "connected")
78548
78758
  return existing;
78759
+ const record = connectFailures.get(name);
78760
+ const backoffDelayMs = record ? mcpConnectBackoffDelayMs(record.count) : 0;
78761
+ if (record !== undefined && backoffDelayMs > 0) {
78762
+ const sinceLastFailure = Date.now() - record.lastFailedAt;
78763
+ if (sinceLastFailure < backoffDelayMs) {
78764
+ return fail(name, config, `MCP server "${name}" connect deferred (backoff): ${record.count} consecutive failure(s), retry in ~${Math.ceil((backoffDelayMs - sinceLastFailure) / 1000)}s (set ATLAS_MCP_CONNECT_BACKOFF_MS=0 to disable)`);
78765
+ }
78766
+ }
78549
78767
  pending.add(name);
78550
78768
  try {
78551
78769
  const t = config.type;
@@ -78583,7 +78801,7 @@ function createMcpConnectionManager() {
78583
78801
  function getMcpConnectionManager() {
78584
78802
  return singleton ??= createMcpConnectionManager();
78585
78803
  }
78586
- var MAX_ERRORS_BEFORE_RECONNECT = 3, FORWARD_SEAM_MESSAGE = "MCP transport = 前向接缝登记(§8.68 R2:非 stdio 传输真实现待 MCP 标准远程传输(M6 波)(#200 波);G-3 ⑩ D3 型面 8→4 后 4 型 config,仅 stdio 连接支 live)", singleton;
78804
+ var DEFAULT_MCP_CONNECT_BACKOFF_MS = 1000, MAX_MCP_CONNECT_BACKOFF_MS = 30000, MAX_ERRORS_BEFORE_RECONNECT = 3, FORWARD_SEAM_MESSAGE = "MCP transport = 前向接缝登记(§8.68 R2:非 stdio 传输真实现待 MCP 标准远程传输(M6 波)(#200 波);G-3 ⑩ D3 型面 8→4 后 4 型 config,仅 stdio 连接支 live)", singleton;
78587
78805
  var init_mcpConnectionManager = __esm(() => {
78588
78806
  init_shared();
78589
78807
  init_bootstrap();
@@ -78695,6 +78913,85 @@ function buildSchemaNotSentHint(tool, discoveredToolNames) {
78695
78913
  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).`;
78696
78914
  }
78697
78915
 
78916
+ // src/engine/pipeline/mcpAutoBackground.ts
78917
+ function getMcpAutoBackgroundMs(env = process.env) {
78918
+ const raw = env.ATLAS_MCP_AUTO_BACKGROUND_MS;
78919
+ if (!raw)
78920
+ return DEFAULT_MCP_AUTO_BACKGROUND_MS;
78921
+ const parsed = Number(raw);
78922
+ if (!Number.isFinite(parsed))
78923
+ return DEFAULT_MCP_AUTO_BACKGROUND_MS;
78924
+ return Math.max(MIN_MCP_AUTO_BACKGROUND_MS, parsed);
78925
+ }
78926
+ async function callWithMcpAutoBackground(opts, fn) {
78927
+ let settled = false;
78928
+ return new Promise((resolve, reject) => {
78929
+ const pending = fn();
78930
+ const timer = setTimeout(() => {
78931
+ if (settled)
78932
+ return;
78933
+ settled = true;
78934
+ resolve({ backgrounded: true });
78935
+ pending.then((data) => {
78936
+ opts.onBackgrounded({
78937
+ toolUseId: opts.toolUseId,
78938
+ toolName: opts.toolName,
78939
+ outcome: { ok: true, data }
78940
+ });
78941
+ }).catch((error) => {
78942
+ opts.onBackgrounded({
78943
+ toolUseId: opts.toolUseId,
78944
+ toolName: opts.toolName,
78945
+ outcome: { ok: false, error: String(error?.message ?? error) }
78946
+ });
78947
+ });
78948
+ }, opts.backgroundAfterMs);
78949
+ timer.unref?.();
78950
+ pending.then((result) => {
78951
+ if (settled)
78952
+ return;
78953
+ settled = true;
78954
+ clearTimeout(timer);
78955
+ resolve({ backgrounded: false, result });
78956
+ }, (error) => {
78957
+ if (settled)
78958
+ return;
78959
+ settled = true;
78960
+ clearTimeout(timer);
78961
+ reject(error);
78962
+ });
78963
+ });
78964
+ }
78965
+ var DEFAULT_MCP_AUTO_BACKGROUND_MS = 120000, MIN_MCP_AUTO_BACKGROUND_MS = 1000;
78966
+
78967
+ // src/engine/pipeline/toolHeartbeat.ts
78968
+ function getToolHeartbeatIntervalMs(env = process.env) {
78969
+ const raw = env.ATLAS_TOOL_HEARTBEAT_MS;
78970
+ if (!raw)
78971
+ return DEFAULT_TOOL_HEARTBEAT_INTERVAL_MS;
78972
+ const parsed = Number(raw);
78973
+ if (!Number.isFinite(parsed))
78974
+ return DEFAULT_TOOL_HEARTBEAT_INTERVAL_MS;
78975
+ return Math.max(MIN_TOOL_HEARTBEAT_INTERVAL_MS, parsed);
78976
+ }
78977
+ async function runWithToolHeartbeat(opts, fn) {
78978
+ const start = Date.now();
78979
+ const timer = setInterval(() => {
78980
+ opts.onHeartbeat({
78981
+ toolUseId: opts.toolUseId,
78982
+ toolName: opts.toolName,
78983
+ elapsedMs: Date.now() - start
78984
+ });
78985
+ }, opts.intervalMs);
78986
+ timer.unref?.();
78987
+ try {
78988
+ return await fn();
78989
+ } finally {
78990
+ clearInterval(timer);
78991
+ }
78992
+ }
78993
+ var DEFAULT_TOOL_HEARTBEAT_INTERVAL_MS = 30000, MIN_TOOL_HEARTBEAT_INTERVAL_MS = 100;
78994
+
78698
78995
  // src/engine/pipeline/toolExecution.ts
78699
78996
  function mergeHookPermission(hookBehavior, gate, hookReason) {
78700
78997
  if (hookBehavior === "defer") {
@@ -78806,8 +79103,40 @@ async function executeToolUse(tu, assistantMsg, deps) {
78806
79103
  let block;
78807
79104
  let isError = false;
78808
79105
  let toolUseResult;
79106
+ const mcpAutoBackgroundArmed = deps.onMcpToolBackgrounded !== undefined && tool.isMcp === true;
78809
79107
  try {
78810
- const res = await tool.call(callInput, toolCallContext, undefined, assistantMsg);
79108
+ const callTool = () => tool.call(callInput, toolCallContext, undefined, assistantMsg);
79109
+ const withHeartbeat = () => deps.onToolHeartbeat ? runWithToolHeartbeat({
79110
+ toolUseId: tu.id,
79111
+ toolName: tool.name,
79112
+ intervalMs: getToolHeartbeatIntervalMs(),
79113
+ onHeartbeat: deps.onToolHeartbeat
79114
+ }, callTool) : callTool();
79115
+ let res;
79116
+ if (mcpAutoBackgroundArmed) {
79117
+ const raced = await callWithMcpAutoBackground({
79118
+ toolUseId: tu.id,
79119
+ toolName: tool.name,
79120
+ backgroundAfterMs: deps.mcpAutoBackgroundMs ?? getMcpAutoBackgroundMs(),
79121
+ onBackgrounded: deps.onMcpToolBackgrounded
79122
+ }, withHeartbeat);
79123
+ if (raced.backgrounded === true) {
79124
+ const backgroundedContent = `[mcp tool ${tool.name} is still running after exceeding the auto-background threshold; ` + "it has been moved to the background and will keep running. " + "The result will be delivered later as a task notification — do not call this tool again for the same purpose.";
79125
+ return {
79126
+ block: {
79127
+ type: "tool_result",
79128
+ tool_use_id: tu.id,
79129
+ content: backgroundedContent,
79130
+ is_error: false
79131
+ },
79132
+ isError: false,
79133
+ toolUseResult: backgroundedContent
79134
+ };
79135
+ }
79136
+ res = raced.result;
79137
+ } else {
79138
+ res = await withHeartbeat();
79139
+ }
78811
79140
  block = tool.mapToolResultToToolResultBlockParam(res.data, tu.id);
78812
79141
  toolUseResult = res.data;
78813
79142
  } catch (error) {
@@ -78826,6 +79155,17 @@ async function executeToolUse(tu, assistantMsg, deps) {
78826
79155
  block = { ...block, content: postOutcome.updatedToolOutput };
78827
79156
  toolUseResult = postOutcome.updatedToolOutput;
78828
79157
  }
79158
+ if (postOutcome?.blockingError !== undefined) {
79159
+ const hookDenyText = `<tool_use_error>blocked by PostToolUse hook: ${postOutcome.blockingError}</tool_use_error>`;
79160
+ block = {
79161
+ type: "tool_result",
79162
+ tool_use_id: tu.id,
79163
+ content: hookDenyText,
79164
+ is_error: true
79165
+ };
79166
+ isError = true;
79167
+ toolUseResult = hookDenyText;
79168
+ }
78829
79169
  return { block, isError, toolUseResult };
78830
79170
  }
78831
79171
  var init_toolExecution = () => {};
@@ -81526,9 +81866,14 @@ function resolveAutoCompactWindowSingle(setting) {
81526
81866
  }
81527
81867
  return {};
81528
81868
  }
81869
+ function lookupAutoCompactWindowSetting(perModel, model) {
81870
+ if (!model)
81871
+ return perModel.default;
81872
+ return perModel[model] ?? perModel[stripProviderPrefix(model)] ?? perModel.default;
81873
+ }
81529
81874
  function resolveAutoCompactWindow(setting, model) {
81530
81875
  const perModel = normalizeAutoCompactWindowSetting(setting);
81531
- const chosen = model && perModel[model] || perModel.default;
81876
+ const chosen = lookupAutoCompactWindowSetting(perModel, model);
81532
81877
  return resolveAutoCompactWindowSingle(chosen);
81533
81878
  }
81534
81879
  function parseAutoCompactTierInput(raw) {
@@ -81564,6 +81909,7 @@ function parseAutoCompactTierArg(raw) {
81564
81909
  }
81565
81910
  var AUTOCOMPACT_PRESET_WINDOW_TIERS;
81566
81911
  var init_autoCompactWindow = __esm(() => {
81912
+ init_modelprovider2();
81567
81913
  AUTOCOMPACT_PRESET_WINDOW_TIERS = [
81568
81914
  1e5,
81569
81915
  128000,
@@ -81572,6 +81918,56 @@ var init_autoCompactWindow = __esm(() => {
81572
81918
  ];
81573
81919
  });
81574
81920
 
81921
+ // src/engine/context/idleCompaction.ts
81922
+ function resolveIdleCompactionConfig(settingsRaw, envRaw) {
81923
+ const enabled = settingsRaw !== false;
81924
+ let minTokens = IDLE_COMPACT_MIN_TOKENS;
81925
+ if (envRaw !== undefined) {
81926
+ const parsed = Number(envRaw);
81927
+ if (Number.isInteger(parsed) && parsed >= 1)
81928
+ minTokens = parsed;
81929
+ }
81930
+ return { enabled, minTokens };
81931
+ }
81932
+ function shouldIdleCompact(config, idleMs, totalTokens) {
81933
+ return config.enabled && Number.isFinite(idleMs) && idleMs >= IDLE_COMPACT_TRIGGER_MS && Number.isFinite(totalTokens) && totalTokens >= config.minTokens;
81934
+ }
81935
+ function getIdleMs(messages, now = Date.now()) {
81936
+ let lastAssistant;
81937
+ for (let i = messages.length - 1;i >= 0; i--) {
81938
+ const m = messages[i];
81939
+ if (m && m.type === "assistant") {
81940
+ lastAssistant = m;
81941
+ break;
81942
+ }
81943
+ }
81944
+ if (!lastAssistant)
81945
+ return Number.NaN;
81946
+ const raw = lastAssistant.timestamp;
81947
+ if (raw === undefined || raw === null)
81948
+ return Number.NaN;
81949
+ const ts = typeof raw === "number" ? raw : new Date(String(raw)).getTime();
81950
+ if (!Number.isFinite(ts) || ts <= 0)
81951
+ return Number.NaN;
81952
+ return now - ts;
81953
+ }
81954
+ function setIdleCompactionSettingsSource(next) {
81955
+ idleCompactionSettingsSource = next;
81956
+ }
81957
+ function getIdleCompactionConfig() {
81958
+ return resolveIdleCompactionConfig(idleCompactionSettingsSource?.(), process.env.ATLAS_IDLE_COMPACT_MIN_TOKENS);
81959
+ }
81960
+ function resetIdleCompactionForTesting() {
81961
+ idleCompactionSettingsSource = null;
81962
+ }
81963
+ var PROMPT_CACHE_TTL_MS = 3600000, IDLE_COMPACT_TRIGGER_MS = 3240000, IDLE_COMPACT_MIN_TOKENS = 200000, IDLE_COMPACTION_CONFIG_DEFAULTS, idleCompactionSettingsSource = null;
81964
+ var init_idleCompaction = __esm(() => {
81965
+ IDLE_COMPACTION_CONFIG_DEFAULTS = {
81966
+ enabled: true,
81967
+ minTokens: IDLE_COMPACT_MIN_TOKENS
81968
+ };
81969
+ });
81970
+
81575
81971
  // src/engine/context/autoCompact.ts
81576
81972
  import { randomUUID as randomUUID17 } from "crypto";
81577
81973
  function resolveModelContextWindow(model) {
@@ -81717,7 +82113,19 @@ async function shouldAutoCompact(messages, deps) {
81717
82113
  if (!Number.isFinite(tokenCount)) {
81718
82114
  return false;
81719
82115
  }
81720
- return tokenCount >= getAutoCompactThreshold(deps.contextWindow, deps.maxOutputTokens, deps.pctOverride, deps.windowOverride);
82116
+ const thinkingBudget = deps.thinkingBudgetTokens !== undefined && Number.isFinite(deps.thinkingBudgetTokens) ? deps.thinkingBudgetTokens : 0;
82117
+ const thresholdMet = tokenCount + thinkingBudget >= getAutoCompactThreshold(deps.contextWindow, deps.maxOutputTokens, deps.pctOverride, deps.windowOverride);
82118
+ if (thresholdMet) {
82119
+ return true;
82120
+ }
82121
+ const idleConfig = getIdleCompactionConfig();
82122
+ if (idleConfig.enabled) {
82123
+ const idleMs = getIdleMs(messages);
82124
+ if (shouldIdleCompact(idleConfig, idleMs, tokenCount)) {
82125
+ return true;
82126
+ }
82127
+ }
82128
+ return false;
81721
82129
  }
81722
82130
  async function autoCompactIfNeeded(messages, tracking, deps) {
81723
82131
  if (tracking?.consecutiveFailures !== undefined && tracking.consecutiveFailures >= MAX_CONSECUTIVE_AUTOCOMPACT_FAILURES) {
@@ -81754,6 +82162,7 @@ var init_autoCompact = __esm(() => {
81754
82162
  init_config();
81755
82163
  init_compact();
81756
82164
  init_autoCompactWindow();
82165
+ init_idleCompaction();
81757
82166
  });
81758
82167
 
81759
82168
  // src/engine/context/autoCompactRich.ts
@@ -82245,6 +82654,7 @@ var init_autoCompactCircuit = __esm(() => {
82245
82654
  // src/engine/context/index.ts
82246
82655
  var init_context = __esm(() => {
82247
82656
  init_autoCompact();
82657
+ init_idleCompaction();
82248
82658
  init_autoCompactWindow();
82249
82659
  init_autoCompact();
82250
82660
  init_autoCompactRich();
@@ -82340,7 +82750,9 @@ async function queryOneRound(deps, tools, messages) {
82340
82750
  signal: deps.signal,
82341
82751
  checkPermission: deps.checkPermission,
82342
82752
  hooks: deps.hooks?.toolHooks,
82343
- toolContext: deps.toolContext
82753
+ toolContext: deps.toolContext,
82754
+ onToolHeartbeat: deps.emit ? (info) => deps.emit({ type: "tool_heartbeat", ...info }) : undefined,
82755
+ onMcpToolBackgrounded: deps.onMcpToolBackgrounded
82344
82756
  });
82345
82757
  const deferredOutcome = outcomes.find((o) => o.deferred);
82346
82758
  const deferredPayload = deferredOutcome ? {
@@ -82400,7 +82812,7 @@ async function queryAgentLoop(deps, args) {
82400
82812
  deps.emit?.({ type: "loop_start", messageCount: messages.length });
82401
82813
  while (turns < maxTurns) {
82402
82814
  turns++;
82403
- if (args.context?.autoCompact) {
82815
+ if (args.context?.autoCompact && !deps.signal?.aborted) {
82404
82816
  const oc = await autoCompactIfNeeded(messages, tracking, args.context.autoCompact);
82405
82817
  if (oc.wasCompacted && oc.compactionResult && !oc.compactionResult.compactionSkipped) {
82406
82818
  messages = buildPostCompactMessages(oc.compactionResult);
@@ -82422,7 +82834,7 @@ async function queryAgentLoop(deps, args) {
82422
82834
  }
82423
82835
  }
82424
82836
  deps.transcript?.reAppendSessionMetadata?.();
82425
- } else if (oc.consecutiveFailures !== undefined) {
82837
+ } else if (oc.consecutiveFailures !== undefined && !deps.signal?.aborted) {
82426
82838
  tracking = { ...tracking, consecutiveFailures: oc.consecutiveFailures };
82427
82839
  reportAutoCompactCircuitFailures(oc.consecutiveFailures);
82428
82840
  }
@@ -82655,7 +83067,8 @@ function createToolHooks(opts = {}) {
82655
83067
  const r = await runPostToolUseHooks(tool.name, input, block, toolUseId, { ...base, toolUseID: toolUseId });
82656
83068
  const outcome = {
82657
83069
  additionalContext: r.additionalContext,
82658
- updatedToolOutput: r.updatedToolOutput
83070
+ updatedToolOutput: r.updatedToolOutput,
83071
+ blockingError: r.blockingError && r.continueOnBlock ? r.blockingError.blockingError : undefined
82659
83072
  };
82660
83073
  return outcome;
82661
83074
  }
@@ -85339,6 +85752,15 @@ To attach: tmux attach -t ${tmuxSessionName}
85339
85752
  if (!bare) {
85340
85753
  getCommands(getProjectRoot()).catch(() => {});
85341
85754
  }
85755
+ const restrictedBypassErr = restrictedBypassError({
85756
+ permissionMode: options.permissionMode,
85757
+ allowDangerouslySkipPermissions: options.allowDangerouslySkipPermissions === true
85758
+ });
85759
+ if (restrictedBypassErr) {
85760
+ process.stderr.write(`Error: ${restrictedBypassErr}
85761
+ `);
85762
+ process.exit(1);
85763
+ }
85342
85764
  if (options.permissionMode === "bypassPermissions" || options.allowDangerouslySkipPermissions) {
85343
85765
  if (process.platform !== "win32" && typeof process.getuid === "function" && process.getuid() === 0 && process.env.IS_SANDBOX !== "1" && !isEnvTruthy(process.env.ATLAS_BUBBLEWRAP)) {
85344
85766
  process.stderr.write(`--dangerously-skip-permissions cannot be used with root/sudo privileges for security reasons
@@ -88343,6 +88765,19 @@ function buildHeadlessOptions(options) {
88343
88765
  };
88344
88766
  }
88345
88767
  async function mainActionSeam(prompt, options) {
88768
+ if (options.restricted === true) {
88769
+ setRestrictedMode(true);
88770
+ const bypassErr = restrictedBypassError({
88771
+ permissionMode: options.permissionMode,
88772
+ allowDangerouslySkipPermissions: options.allowDangerouslySkipPermissions === true,
88773
+ dangerouslySkipPermissions: options.dangerouslySkipPermissions === true
88774
+ });
88775
+ if (bypassErr) {
88776
+ process.stderr.write(`Error: ${bypassErr}
88777
+ `);
88778
+ process.exit(1);
88779
+ }
88780
+ }
88346
88781
  if (options.initOnly) {
88347
88782
  await runCliSetup({
88348
88783
  permissionMode: options.permissionMode,
@@ -88407,7 +88842,7 @@ function buildProgram() {
88407
88842
  throw new Error("--task-budget must be a positive integer");
88408
88843
  }
88409
88844
  return tokens;
88410
- }).hideHelp()).option("--replay-user-messages", "Re-emit user messages from stdin back on stdout for acknowledgment (only works with --input-format=stream-json and --output-format=stream-json)", () => true).addOption(new Option("--enable-auth-status", "Enable auth status messages in SDK mode").default(false).hideHelp()).option("--allowedTools, --allowed-tools <tools...>", 'Comma or space-separated list of tool names to allow (e.g. "Bash(git:*) Edit")').option("--tools <tools...>", 'Specify the list of available tools from the built-in set. Use "" to disable all tools, "default" to use all tools, or specify tool names (e.g. "Bash,Edit,Read").').option("--disallowedTools, --disallowed-tools <tools...>", 'Comma or space-separated list of tool names to deny (e.g. "Bash(git:*) Edit")').option("--mcp-config <configs...>", "Load MCP servers from JSON files or strings (space-separated)").addOption(new Option("--permission-prompt-tool <tool>", "MCP tool to use for permission prompts (only works with --print)").argParser(String).hideHelp()).addOption(new Option("--system-prompt <prompt>", "System prompt to use for the session").argParser(String)).addOption(new Option("--system-prompt-file <file>", "Read system prompt from a file").argParser(String).hideHelp()).addOption(new Option("--append-system-prompt <prompt>", "Append a system prompt to the default system prompt").argParser(String)).addOption(new Option("--append-system-prompt-file <file>", "Read system prompt from a file and append to the default system prompt").argParser(String).hideHelp()).addOption(new Option("--permission-mode <mode>", "Permission mode to use for the session").argParser(String).choices(PERMISSION_MODES)).addOption(new Option("--permission-prompts <mode>", "Permission prompt policy; 'none' auto-denies prompts that would otherwise ask").argParser(String).choices(["none"])).option("-c, --continue", "Continue the most recent conversation in the current directory", () => true).option("-r, --resume [value]", "Resume a conversation by session ID, or open interactive picker with optional search term", (value) => value || true).option("--fork-session", "When resuming, create a new session ID instead of reusing the original (use with --resume or --continue)", () => true).addOption(new Option("--prefill <text>", "Pre-fill the prompt input with text without submitting it").hideHelp()).addOption(new Option("--deep-link-origin", "Signal that this session was launched from a deep link").hideHelp()).addOption(new Option("--deep-link-repo <slug>", "Repo slug the deep link ?repo= parameter resolved to the current cwd").hideHelp()).addOption(new Option("--deep-link-last-fetch <ms>", "FETCH_HEAD mtime in epoch ms, precomputed by the deep link trampoline").argParser((v) => {
88845
+ }).hideHelp()).option("--replay-user-messages", "Re-emit user messages from stdin back on stdout for acknowledgment (only works with --input-format=stream-json and --output-format=stream-json)", () => true).addOption(new Option("--enable-auth-status", "Enable auth status messages in SDK mode").default(false).hideHelp()).option("--allowedTools, --allowed-tools <tools...>", 'Comma or space-separated list of tool names to allow (e.g. "Bash(git:*) Edit")').option("--tools <tools...>", 'Specify the list of available tools from the built-in set. Use "" to disable all tools, "default" to use all tools, or specify tool names (e.g. "Bash,Edit,Read").').option("--disallowedTools, --disallowed-tools <tools...>", 'Comma or space-separated list of tool names to deny (e.g. "Bash(git:*) Edit")').option("--restricted", "Run in restricted mode: strips command-execution tools (Bash/PowerShell), WebFetch, and Agent; rejects bypassPermissions and --dangerously-skip-permissions; ignores user/project/local settings (env: ATLAS_RESTRICTED)").option("--mcp-config <configs...>", "Load MCP servers from JSON files or strings (space-separated)").addOption(new Option("--permission-prompt-tool <tool>", "MCP tool to use for permission prompts (only works with --print)").argParser(String).hideHelp()).addOption(new Option("--system-prompt <prompt>", "System prompt to use for the session").argParser(String)).addOption(new Option("--system-prompt-file <file>", "Read system prompt from a file").argParser(String).hideHelp()).addOption(new Option("--append-system-prompt <prompt>", "Append a system prompt to the default system prompt").argParser(String)).addOption(new Option("--append-system-prompt-file <file>", "Read system prompt from a file and append to the default system prompt").argParser(String).hideHelp()).addOption(new Option("--permission-mode <mode>", "Permission mode to use for the session").argParser(String).choices(PERMISSION_MODES)).addOption(new Option("--permission-prompts <mode>", "Permission prompt policy; 'none' auto-denies prompts that would otherwise ask").argParser(String).choices(["none"])).option("-c, --continue", "Continue the most recent conversation in the current directory", () => true).option("-r, --resume [value]", "Resume a conversation by session ID, or open interactive picker with optional search term", (value) => value || true).option("--fork-session", "When resuming, create a new session ID instead of reusing the original (use with --resume or --continue)", () => true).addOption(new Option("--prefill <text>", "Pre-fill the prompt input with text without submitting it").hideHelp()).addOption(new Option("--deep-link-origin", "Signal that this session was launched from a deep link").hideHelp()).addOption(new Option("--deep-link-repo <slug>", "Repo slug the deep link ?repo= parameter resolved to the current cwd").hideHelp()).addOption(new Option("--deep-link-last-fetch <ms>", "FETCH_HEAD mtime in epoch ms, precomputed by the deep link trampoline").argParser((v) => {
88411
88846
  const n = Number(v);
88412
88847
  return Number.isFinite(n) ? n : undefined;
88413
88848
  }).hideHelp()).option("--from-pr [value]", "Resume a session linked to a PR by PR number/URL, or open interactive picker with optional search term", (value) => value || true).option("--no-session-persistence", "Disable session persistence - sessions will not be saved to disk and cannot be resumed (only works with --print)").addOption(new Option("--resume-session-at <message id>", "When resuming, only messages up to and including the assistant message with <message.id> (use with --resume in print mode)").argParser(String).hideHelp()).addOption(new Option("--rewind-files <user-message-id>", "Restore files to state at the specified user message and exit (requires --resume)").hideHelp()).option("--model <model>", "Model for the current session. Provide a role alias (e.g. 'small' or 'premium') or a provider/model reference (e.g. 'bailian/qwen38-27b').").addOption(new Option("--effort <level>", "Effort level for the current session (low, medium, high, xhigh, max)").argParser((rawValue) => {
@@ -88513,6 +88948,7 @@ async function runCli() {
88513
88948
  var init_parse4 = __esm(() => {
88514
88949
  init_extra_typings();
88515
88950
  init_bootstrap();
88951
+ init_engine();
88516
88952
  init_permissions3();
88517
88953
  init_shared();
88518
88954
  init_remote();
@@ -96691,34 +97127,8 @@ var init_envUtils2 = __esm(() => {
96691
97127
  });
96692
97128
 
96693
97129
  // src/tui/types/atlas.ts
96694
- var APIError3, AuthenticationError2, NotFoundError2, APIConnectionError3, APIUserAbortError3;
96695
97130
  var init_atlas = __esm(() => {
96696
- APIError3 = class APIError3 extends Error {
96697
- status;
96698
- code;
96699
- headers;
96700
- constructor(message, opts) {
96701
- super(message ?? "API error");
96702
- this.name = "APIError";
96703
- if (opts) {
96704
- this.status = opts.status;
96705
- this.code = opts.code;
96706
- this.headers = opts.headers;
96707
- }
96708
- }
96709
- };
96710
- AuthenticationError2 = class AuthenticationError2 extends APIError3 {
96711
- constructor(message, opts) {
96712
- super(message, opts);
96713
- this.name = "AuthenticationError";
96714
- }
96715
- };
96716
- NotFoundError2 = class NotFoundError2 extends APIError3 {
96717
- };
96718
- APIConnectionError3 = class APIConnectionError3 extends APIError3 {
96719
- };
96720
- APIUserAbortError3 = class APIUserAbortError3 extends APIError3 {
96721
- };
97131
+ init_types2();
96722
97132
  });
96723
97133
 
96724
97134
  // src/tui/utils/errors.ts
@@ -124075,6 +124485,7 @@ var isMcpServerCommandEntry = () => ({}), isMcpServerNameEntry = () => ({}), isM
124075
124485
  prefersReducedMotion: boolean2().optional(),
124076
124486
  syntaxHighlightingDisabled: boolean2().optional(),
124077
124487
  spinnerTipsEnabled: boolean2().optional(),
124488
+ idleCompaction: boolean2().optional(),
124078
124489
  spinnerTipsOverride: any().optional(),
124079
124490
  spinnerVerbs: any().optional(),
124080
124491
  statusLine: any().optional(),
@@ -124104,7 +124515,12 @@ var isMcpServerCommandEntry = () => ({}), isMcpServerNameEntry = () => ({}), isM
124104
124515
  xaaIdp: any().optional(),
124105
124516
  agent: any().optional(),
124106
124517
  local: any().optional(),
124107
- worktree: any().optional()
124518
+ worktree: any().optional(),
124519
+ skillOverrides: union([
124520
+ literal("off"),
124521
+ literal("user-invocable-only"),
124522
+ literal("name-only")
124523
+ ]).optional()
124108
124524
  }).passthrough(), CUSTOMIZATION_SURFACES;
124109
124525
  var init_types7 = __esm(() => {
124110
124526
  init_zod();
@@ -124232,7 +124648,9 @@ var init_stringUtils2 = __esm(() => {
124232
124648
 
124233
124649
  // src/tui/services/mcp/normalization.ts
124234
124650
  function normalizeNameForMCP3(name) {
124235
- return name.replace(/[^a-zA-Z0-9_-]/g, "_").replace(/_+/g, "_").replace(/^_|_$/g, "");
124651
+ const folded = name.replace(/[^a-zA-Z0-9_-]/g, "_");
124652
+ const normalized = folded.replace(/_+/g, "_").replace(/^_|_$/g, "");
124653
+ return normalized === "" ? folded : normalized;
124236
124654
  }
124237
124655
 
124238
124656
  // src/tui/services/mcp/mcpStringUtils.ts
@@ -132706,6 +133124,13 @@ function getPersistedEffortForModel(model) {
132706
133124
  if (key.toLowerCase() === wanted)
132707
133125
  return level;
132708
133126
  }
133127
+ const base = stripProviderPrefix(model).toLowerCase();
133128
+ if (base !== wanted) {
133129
+ for (const [key, level] of Object.entries(getEffortByModel())) {
133130
+ if (key.toLowerCase() === base)
133131
+ return level;
133132
+ }
133133
+ }
132709
133134
  return;
132710
133135
  }
132711
133136
  function withEffortForModel(model, level) {
@@ -132785,6 +133210,7 @@ var init_effort2 = __esm(() => {
132785
133210
  init_thinking();
132786
133211
  init_settings3();
132787
133212
  init_envUtils2();
133213
+ init_modelprovider2();
132788
133214
  EFFORT_LEVELS2 = [
132789
133215
  "low",
132790
133216
  "medium",
@@ -151026,28 +151452,28 @@ function getEventPriority(eventType) {
151026
151452
  case "focus":
151027
151453
  case "blur":
151028
151454
  case "paste":
151029
- return import_constants53.DiscreteEventPriority;
151455
+ return import_constants56.DiscreteEventPriority;
151030
151456
  case "resize":
151031
151457
  case "scroll":
151032
151458
  case "mousemove":
151033
- return import_constants53.ContinuousEventPriority;
151459
+ return import_constants56.ContinuousEventPriority;
151034
151460
  default:
151035
- return import_constants53.DefaultEventPriority;
151461
+ return import_constants56.DefaultEventPriority;
151036
151462
  }
151037
151463
  }
151038
151464
 
151039
151465
  class Dispatcher {
151040
151466
  currentEvent = null;
151041
- currentUpdatePriority = import_constants53.DefaultEventPriority;
151467
+ currentUpdatePriority = import_constants56.DefaultEventPriority;
151042
151468
  discreteUpdates = null;
151043
151469
  resolveEventPriority() {
151044
- if (this.currentUpdatePriority !== import_constants53.NoEventPriority) {
151470
+ if (this.currentUpdatePriority !== import_constants56.NoEventPriority) {
151045
151471
  return this.currentUpdatePriority;
151046
151472
  }
151047
151473
  if (this.currentEvent) {
151048
151474
  return getEventPriority(this.currentEvent.type);
151049
151475
  }
151050
- return import_constants53.DefaultEventPriority;
151476
+ return import_constants56.DefaultEventPriority;
151051
151477
  }
151052
151478
  dispatch(target, event) {
151053
151479
  const previousEvent = this.currentEvent;
@@ -151072,18 +151498,18 @@ class Dispatcher {
151072
151498
  dispatchContinuous(target, event) {
151073
151499
  const previousPriority = this.currentUpdatePriority;
151074
151500
  try {
151075
- this.currentUpdatePriority = import_constants53.ContinuousEventPriority;
151501
+ this.currentUpdatePriority = import_constants56.ContinuousEventPriority;
151076
151502
  return this.dispatch(target, event);
151077
151503
  } finally {
151078
151504
  this.currentUpdatePriority = previousPriority;
151079
151505
  }
151080
151506
  }
151081
151507
  }
151082
- var import_constants53;
151508
+ var import_constants56;
151083
151509
  var init_dispatcher = __esm(() => {
151084
151510
  init_log5();
151085
151511
  init_event_handlers();
151086
- import_constants53 = __toESM(require_constants2(), 1);
151512
+ import_constants56 = __toESM(require_constants2(), 1);
151087
151513
  });
151088
151514
 
151089
151515
  // src/tui/ink/events/terminal-event.ts
@@ -159890,7 +160316,7 @@ function applyPositionedHighlight(screen, stylePool, positions, rowOffset, curre
159890
160316
  }
159891
160317
  return true;
159892
160318
  }
159893
- var import_constants55, timing;
160319
+ var import_constants58, timing;
159894
160320
  var init_render_to_screen = __esm(() => {
159895
160321
  init_debug();
159896
160322
  init_dom();
@@ -159899,7 +160325,7 @@ var init_render_to_screen = __esm(() => {
159899
160325
  init_reconciler();
159900
160326
  init_render_node_to_output();
159901
160327
  init_screen();
159902
- import_constants55 = __toESM(require_constants2(), 1);
160328
+ import_constants58 = __toESM(require_constants2(), 1);
159903
160329
  timing = { reconcile: 0, yoga: 0, paint: 0, scan: 0, calls: 0 };
159904
160330
  });
159905
160331
 
@@ -160205,7 +160631,7 @@ class Ink {
160205
160631
  };
160206
160632
  }
160207
160633
  };
160208
- this.container = reconciler_default.createContainer(this.rootNode, import_constants56.ConcurrentRoot, null, false, null, "id", noop_default, noop_default, noop_default, noop_default);
160634
+ this.container = reconciler_default.createContainer(this.rootNode, import_constants59.ConcurrentRoot, null, false, null, "id", noop_default, noop_default, noop_default, noop_default);
160209
160635
  if (false) {}
160210
160636
  }
160211
160637
  handleResume = () => {
@@ -161018,7 +161444,7 @@ function drainStdin(stdin = process.stdin) {
161018
161444
  }
161019
161445
  }
161020
161446
  }
161021
- var import_constants56, jsx_dev_runtime8, ALT_SCREEN_ANCHOR_CURSOR, CURSOR_HOME_PATCH, ERASE_THEN_HOME_PATCH, CONSOLE_STDOUT_METHODS, CONSOLE_STDERR_METHODS;
161447
+ var import_constants59, jsx_dev_runtime8, ALT_SCREEN_ANCHOR_CURSOR, CURSOR_HOME_PATCH, ERASE_THEN_HOME_PATCH, CONSOLE_STDOUT_METHODS, CONSOLE_STDERR_METHODS;
161022
161448
  var init_ink = __esm(() => {
161023
161449
  init_noop();
161024
161450
  init_throttle2();
@@ -161051,7 +161477,7 @@ var init_ink = __esm(() => {
161051
161477
  init_dec();
161052
161478
  init_osc();
161053
161479
  init_useTerminalNotification();
161054
- import_constants56 = __toESM(require_constants2(), 1);
161480
+ import_constants59 = __toESM(require_constants2(), 1);
161055
161481
  jsx_dev_runtime8 = __toESM(require_jsx_dev_runtime(), 1);
161056
161482
  ALT_SCREEN_ANCHOR_CURSOR = Object.freeze({
161057
161483
  x: 0,
@@ -166814,7 +167240,7 @@ var init_addDirPluginSettings = __esm(() => {
166814
167240
  });
166815
167241
 
166816
167242
  // src/tui/entrypoints/sdk/coreSchemas.ts
166817
- var ModelUsageSchema, OutputFormatTypeSchema, BaseOutputFormatSchema, JsonSchemaOutputFormatSchema, OutputFormatSchema, ApiKeySourceSchema, ConfigScopeSchema2, SdkBetaSchema, ThinkingAdaptiveSchema, ThinkingEnabledSchema, ThinkingDisabledSchema, ThinkingConfigSchema, McpStdioServerConfigSchema2, McpSSEServerConfigSchema2, McpHttpServerConfigSchema, McpSdkServerConfigSchema, McpServerConfigForProcessTransportSchema, McpServerStatusConfigSchema, McpServerStatusSchema, McpSetServersResultSchema, PermissionUpdateDestinationSchema, PermissionBehaviorSchema, PreToolUsePermissionDecisionSchema, PermissionRuleValueSchema, PermissionUpdateSchema, PermissionDecisionClassificationSchema, PermissionResultSchema, PermissionModeSchema2, HOOK_EVENTS2, HookEventSchema, BaseHookInputSchema, PreToolUseHookInputSchema, PermissionRequestHookInputSchema, PostToolUseHookInputSchema, PostToolUseFailureHookInputSchema, PermissionDeniedHookInputSchema, NotificationHookInputSchema, UserPromptSubmitHookInputSchema, SessionStartHookInputSchema, PreModelSwitchHookInputSchema, PostModelSwitchHookInputSchema, SetupHookInputSchema, StopHookInputSchema, StopFailureHookInputSchema, SubagentStartHookInputSchema, SubagentStopHookInputSchema, PreCompactHookInputSchema, PostCompactHookInputSchema, TeammateIdleHookInputSchema, TaskCreatedHookInputSchema, TaskCompletedHookInputSchema, ElicitationHookInputSchema, ElicitationResultHookInputSchema, CONFIG_CHANGE_SOURCES, ConfigChangeHookInputSchema, INSTRUCTIONS_LOAD_REASONS, INSTRUCTIONS_MEMORY_TYPES, InstructionsLoadedHookInputSchema, WorktreeCreateHookInputSchema, WorktreeRemoveHookInputSchema, CwdChangedHookInputSchema, FileChangedHookInputSchema, EXIT_REASONS, ExitReasonSchema, SessionEndHookInputSchema, HookInputSchema, AsyncHookJSONOutputSchema, PreToolUseHookSpecificOutputSchema, UserPromptSubmitHookSpecificOutputSchema, SessionStartHookSpecificOutputSchema, SetupHookSpecificOutputSchema, SubagentStartHookSpecificOutputSchema, PostToolUseHookSpecificOutputSchema, PostToolUseFailureHookSpecificOutputSchema, PermissionDeniedHookSpecificOutputSchema, NotificationHookSpecificOutputSchema, PermissionRequestHookSpecificOutputSchema, CwdChangedHookSpecificOutputSchema, FileChangedHookSpecificOutputSchema, SyncHookJSONOutputSchema, ElicitationHookSpecificOutputSchema, ElicitationResultHookSpecificOutputSchema, WorktreeCreateHookSpecificOutputSchema, HookJSONOutputSchema, PromptRequestOptionSchema, PromptRequestSchema, PromptResponseSchema, SlashCommandSchema, AgentInfoSchema, ModelInfoSchema, AccountInfoSchema, AgentMcpServerSpecSchema, AgentDefinitionSchema, SettingSourceSchema, SdkPluginConfigSchema, RewindFilesResultSchema, APIUserMessagePlaceholder, APIAssistantMessagePlaceholder, RawMessageStreamEventPlaceholder, UUIDPlaceholder, NonNullableUsagePlaceholder, SDKAssistantMessageErrorSchema, SDKStatusSchema, SDKUserMessageContentSchema, SDKUserMessageSchema, SDKUserMessageReplaySchema, SDKRateLimitInfoSchema, SDKAssistantMessageSchema, SDKRateLimitEventSchema, SDKStreamlinedTextMessageSchema, SDKStreamlinedToolUseSummaryMessageSchema, SDKPermissionDenialSchema, SDKResultSuccessSchema, SDKResultErrorSchema, SDKResultMessageSchema, SDKSystemMessageSchema, SDKPartialAssistantMessageSchema, SDKCompactBoundaryMessageSchema, SDKStatusMessageSchema, SDKPostTurnSummaryMessageSchema, SDKAPIRetryMessageSchema, SDKLocalCommandOutputMessageSchema, SDKHookStartedMessageSchema, SDKHookProgressMessageSchema, SDKHookResponseMessageSchema, SDKToolProgressMessageSchema, SDKAuthStatusMessageSchema, SDKFilesPersistedEventSchema, SDKTaskNotificationMessageSchema, SDKTaskStartedMessageSchema, SDKSessionStateChangedMessageSchema, SDKTaskProgressMessageSchema, SDKToolUseSummaryMessageSchema, SDKElicitationCompleteMessageSchema, SDKPromptSuggestionMessageSchema, SDKSessionInfoSchema, SDKMessageSchema, FastModeStateSchema;
167243
+ var ModelUsageSchema, OutputFormatTypeSchema, BaseOutputFormatSchema, JsonSchemaOutputFormatSchema, OutputFormatSchema, ApiKeySourceSchema, ConfigScopeSchema2, SdkBetaSchema, ThinkingAdaptiveSchema, ThinkingEnabledSchema, ThinkingDisabledSchema, ThinkingConfigSchema, McpStdioServerConfigSchema2, McpSSEServerConfigSchema2, McpHttpServerConfigSchema, McpSdkServerConfigSchema, McpServerConfigForProcessTransportSchema, McpServerStatusConfigSchema, McpServerStatusSchema, McpSetServersResultSchema, PermissionUpdateDestinationSchema, PermissionBehaviorSchema, PreToolUsePermissionDecisionSchema, PermissionRuleValueSchema, PermissionUpdateSchema, PermissionDecisionClassificationSchema, PermissionResultSchema, PermissionModeSchema2, HOOK_EVENTS2, HookEventSchema, BaseHookInputSchema, PreToolUseHookInputSchema, PermissionRequestHookInputSchema, PostToolUseHookInputSchema, PostToolUseFailureHookInputSchema, PermissionDeniedHookInputSchema, NotificationHookInputSchema, UserPromptSubmitHookInputSchema, SessionStartHookInputSchema, PreModelSwitchHookInputSchema, PostModelSwitchHookInputSchema, DirectoryAddedHookInputSchema, MessageDisplayHookInputSchema, SetupHookInputSchema, StopHookInputSchema, StopFailureHookInputSchema, SubagentStartHookInputSchema, SubagentStopHookInputSchema, PreCompactHookInputSchema, PostCompactHookInputSchema, TeammateIdleHookInputSchema, TaskCreatedHookInputSchema, TaskCompletedHookInputSchema, ElicitationHookInputSchema, ElicitationResultHookInputSchema, CONFIG_CHANGE_SOURCES, ConfigChangeHookInputSchema, INSTRUCTIONS_LOAD_REASONS, INSTRUCTIONS_MEMORY_TYPES, InstructionsLoadedHookInputSchema, WorktreeCreateHookInputSchema, WorktreeRemoveHookInputSchema, CwdChangedHookInputSchema, FileChangedHookInputSchema, EXIT_REASONS, ExitReasonSchema, SessionEndHookInputSchema, HookInputSchema, AsyncHookJSONOutputSchema, PreToolUseHookSpecificOutputSchema, UserPromptSubmitHookSpecificOutputSchema, SessionStartHookSpecificOutputSchema, SetupHookSpecificOutputSchema, SubagentStartHookSpecificOutputSchema, PostToolUseHookSpecificOutputSchema, PostToolUseFailureHookSpecificOutputSchema, PermissionDeniedHookSpecificOutputSchema, NotificationHookSpecificOutputSchema, PermissionRequestHookSpecificOutputSchema, CwdChangedHookSpecificOutputSchema, FileChangedHookSpecificOutputSchema, SyncHookJSONOutputSchema, ElicitationHookSpecificOutputSchema, ElicitationResultHookSpecificOutputSchema, WorktreeCreateHookSpecificOutputSchema, HookJSONOutputSchema, PromptRequestOptionSchema, PromptRequestSchema, PromptResponseSchema, SlashCommandSchema, AgentInfoSchema, ModelInfoSchema, AccountInfoSchema, AgentMcpServerSpecSchema, AgentDefinitionSchema, SettingSourceSchema, SdkPluginConfigSchema, RewindFilesResultSchema, APIUserMessagePlaceholder, APIAssistantMessagePlaceholder, RawMessageStreamEventPlaceholder, UUIDPlaceholder, NonNullableUsagePlaceholder, SDKAssistantMessageErrorSchema, SDKStatusSchema, SDKUserMessageContentSchema, SDKUserMessageSchema, SDKUserMessageReplaySchema, SDKRateLimitInfoSchema, SDKAssistantMessageSchema, SDKRateLimitEventSchema, SDKStreamlinedTextMessageSchema, SDKStreamlinedToolUseSummaryMessageSchema, SDKPermissionDenialSchema, SDKResultSuccessSchema, SDKResultErrorSchema, SDKResultMessageSchema, SDKSystemMessageSchema, SDKPartialAssistantMessageSchema, SDKCompactBoundaryMessageSchema, SDKStatusMessageSchema, SDKPostTurnSummaryMessageSchema, SDKAPIRetryMessageSchema, SDKLocalCommandOutputMessageSchema, SDKHookStartedMessageSchema, SDKHookProgressMessageSchema, SDKHookResponseMessageSchema, SDKToolProgressMessageSchema, SDKAuthStatusMessageSchema, SDKFilesPersistedEventSchema, SDKTaskNotificationMessageSchema, SDKTaskStartedMessageSchema, SDKSessionStateChangedMessageSchema, SDKTaskProgressMessageSchema, SDKToolUseSummaryMessageSchema, SDKElicitationCompleteMessageSchema, SDKPromptSuggestionMessageSchema, SDKSessionInfoSchema, SDKMessageSchema, FastModeStateSchema;
166818
167244
  var init_coreSchemas = __esm(() => {
166819
167245
  init_v4();
166820
167246
  ModelUsageSchema = lazySchema2(() => object({
@@ -167003,7 +167429,9 @@ var init_coreSchemas = __esm(() => {
167003
167429
  "CwdChanged",
167004
167430
  "FileChanged",
167005
167431
  "PreModelSwitch",
167006
- "PostModelSwitch"
167432
+ "PostModelSwitch",
167433
+ "DirectoryAdded",
167434
+ "MessageDisplay"
167007
167435
  ];
167008
167436
  HookEventSchema = lazySchema2(() => _enum(HOOK_EVENTS2));
167009
167437
  BaseHookInputSchema = lazySchema2(() => object({
@@ -167076,6 +167504,15 @@ var init_coreSchemas = __esm(() => {
167076
167504
  new_model: string2(),
167077
167505
  source: string2()
167078
167506
  })));
167507
+ DirectoryAddedHookInputSchema = lazySchema2(() => BaseHookInputSchema().and(object({
167508
+ hook_event_name: literal("DirectoryAdded"),
167509
+ directory: string2(),
167510
+ source: string2()
167511
+ })));
167512
+ MessageDisplayHookInputSchema = lazySchema2(() => BaseHookInputSchema().and(object({
167513
+ hook_event_name: literal("MessageDisplay"),
167514
+ message: string2()
167515
+ })));
167079
167516
  SetupHookInputSchema = lazySchema2(() => BaseHookInputSchema().and(object({
167080
167517
  hook_event_name: literal("Setup"),
167081
167518
  trigger: _enum(["init", "maintenance"])
@@ -171637,6 +172074,7 @@ function parseAgentFromJson(name, definition, source = "flagSettings") {
171637
172074
  ...parsed.mcpServers && parsed.mcpServers.length > 0 ? { mcpServers: parsed.mcpServers } : {},
171638
172075
  ...parsed.hooks ? { hooks: parsed.hooks } : {},
171639
172076
  ...parsed.maxTurns !== undefined ? { maxTurns: parsed.maxTurns } : {},
172077
+ ...parsed.autoCompactWindow !== undefined ? { autoCompactWindow: parsed.autoCompactWindow } : {},
171640
172078
  ...parsed.skills && parsed.skills.length > 0 ? { skills: parsed.skills } : {},
171641
172079
  ...parsed.initialPrompt ? { initialPrompt: parsed.initialPrompt } : {},
171642
172080
  ...parsed.background ? { background: parsed.background } : {},
@@ -171723,6 +172161,11 @@ function parseAgentFromMarkdown2(filePath, baseDir, frontmatter, content, source
171723
172161
  if (maxTurnsRaw !== undefined && maxTurns === undefined) {
171724
172162
  logForDebugging3(`Agent file ${filePath} has invalid maxTurns '${maxTurnsRaw}'. Must be a positive integer.`);
171725
172163
  }
172164
+ const autoCompactWindowRaw = frontmatter["autoCompactWindow"];
172165
+ const autoCompactWindow = parsePositiveIntFromFrontmatter(autoCompactWindowRaw);
172166
+ if (autoCompactWindowRaw !== undefined && autoCompactWindow === undefined) {
172167
+ logForDebugging3(`Agent file ${filePath} has invalid autoCompactWindow '${autoCompactWindowRaw}'. Must be a positive integer (tokens).`);
172168
+ }
171726
172169
  const filename = basename16(filePath, ".md");
171727
172170
  let tools = parseAgentToolsFromFrontmatter2(frontmatter["tools"]);
171728
172171
  if (isAutoMemoryEnabled2() && memory && tools !== undefined) {
@@ -171782,6 +172225,7 @@ function parseAgentFromMarkdown2(filePath, baseDir, frontmatter, content, source
171782
172225
  ...parsedEffort !== undefined ? { effort: parsedEffort } : {},
171783
172226
  ...isValidPermissionMode ? { permissionMode: permissionModeRaw } : {},
171784
172227
  ...maxTurns !== undefined ? { maxTurns } : {},
172228
+ ...autoCompactWindow !== undefined ? { autoCompactWindow } : {},
171785
172229
  ...background ? { background } : {},
171786
172230
  ...memory ? { memory } : {},
171787
172231
  ...isolation ? { isolation } : {}
@@ -171833,6 +172277,7 @@ var init_loadAgentsDir2 = __esm(() => {
171833
172277
  mcpServers: array(AgentMcpServerSpecSchema2()).optional(),
171834
172278
  hooks: HooksSchema2().optional(),
171835
172279
  maxTurns: number2().int().positive().optional(),
172280
+ autoCompactWindow: number2().int().positive().optional(),
171836
172281
  skills: array(string2()).optional(),
171837
172282
  initialPrompt: string2().optional(),
171838
172283
  memory: _enum(["user", "project", "local"]).optional(),
@@ -180432,6 +180877,9 @@ __export(exports_engineCompat, {
180432
180877
  HookCommandSchema: () => HookCommandSchema,
180433
180878
  HookMatcherSchema: () => HookMatcherSchema,
180434
180879
  HooksSchema: () => HooksSchema,
180880
+ IDLE_COMPACTION_CONFIG_DEFAULTS: () => IDLE_COMPACTION_CONFIG_DEFAULTS,
180881
+ IDLE_COMPACT_MIN_TOKENS: () => IDLE_COMPACT_MIN_TOKENS,
180882
+ IDLE_COMPACT_TRIGGER_MS: () => IDLE_COMPACT_TRIGGER_MS,
180435
180883
  INTERNAL_WORKER_TOOLS: () => INTERNAL_WORKER_TOOLS,
180436
180884
  INTERRUPT_MESSAGE: () => INTERRUPT_MESSAGE,
180437
180885
  INTERRUPT_MESSAGE_FOR_TOOL_USE: () => INTERRUPT_MESSAGE_FOR_TOOL_USE,
@@ -180455,6 +180903,7 @@ __export(exports_engineCompat, {
180455
180903
  NotebookEditTool: () => NotebookEditTool,
180456
180904
  PANEL_GRACE_MS: () => PANEL_GRACE_MS,
180457
180905
  POLL_INTERVAL_MS: () => POLL_INTERVAL_MS2,
180906
+ PROMPT_CACHE_TTL_MS: () => PROMPT_CACHE_TTL_MS,
180458
180907
  PTL_RETRY_MARKER: () => PTL_RETRY_MARKER,
180459
180908
  PermissionModeSchema: () => PermissionModeSchema,
180460
180909
  PlanApprovalRequestMessageSchema: () => PlanApprovalRequestMessageSchema,
@@ -180708,12 +181157,15 @@ __export(exports_engineCompat, {
180708
181157
  getGoalPausedReason: () => getGoalPausedReason,
180709
181158
  getGoalStateForPersistence: () => getGoalStateForPersistence,
180710
181159
  getHooksConfigFromSnapshot: () => getHooksConfigFromSnapshot,
181160
+ getIdleCompactionConfig: () => getIdleCompactionConfig,
181161
+ getIdleMs: () => getIdleMs,
180711
181162
  getInboxPath: () => getInboxPath,
180712
181163
  getInitialSettings: () => getInitialSettings,
180713
181164
  getLastPeerDmSummary: () => getLastPeerDmSummary,
180714
181165
  getLastSummarizedMessageId: () => getLastSummarizedMessageId,
180715
181166
  getManagedSettingsDir: () => getManagedSettingsDir,
180716
181167
  getManagedSettingsDropInDir: () => getManagedSettingsDropInDir,
181168
+ getMcpAutoBackgroundMs: () => getMcpAutoBackgroundMs,
180717
181169
  getMcpClientRegistry: () => getMcpClientRegistry,
180718
181170
  getMcpPrefix: () => getMcpPrefix2,
180719
181171
  getMcpSkillCommands: () => getMcpSkillCommands,
@@ -180833,11 +181285,13 @@ __export(exports_engineCompat, {
180833
181285
  isReactiveCompactRecoverableError: () => isReactiveCompactRecoverableError,
180834
181286
  isReactiveOnlyMode: () => isReactiveOnlyMode,
180835
181287
  isRecurringTaskAged: () => isRecurringTaskAged,
181288
+ isRestrictedMode: () => isRestrictedMode,
180836
181289
  isSafeRefName: () => isSafeRefName,
180837
181290
  isSandboxPermissionRequest: () => isSandboxPermissionRequest,
180838
181291
  isSandboxPermissionResponse: () => isSandboxPermissionResponse,
180839
181292
  isSessionMemoryInitialized: () => isSessionMemoryInitialized,
180840
181293
  isSettingSourceEnabled: () => isSettingSourceEnabled,
181294
+ isSettingsSourceIgnoredInRestricted: () => isSettingsSourceIgnoredInRestricted,
180841
181295
  isShutdownApproved: () => isShutdownApproved,
180842
181296
  isShutdownRejected: () => isShutdownRejected,
180843
181297
  isShutdownRequest: () => isShutdownRequest,
@@ -180877,6 +181331,7 @@ __export(exports_engineCompat, {
180877
181331
  lock: () => lock,
180878
181332
  lockSync: () => lockSync,
180879
181333
  looksLikePrompt: () => looksLikePrompt,
181334
+ lookupAutoCompactWindowSetting: () => lookupAutoCompactWindowSetting,
180880
181335
  makeDeferredToolUseMarker: () => makeDeferredToolUseMarker,
180881
181336
  markAgentsNotified: () => markAgentsNotified,
180882
181337
  markCronTasksFired: () => markCronTasksFired,
@@ -180977,12 +181432,14 @@ __export(exports_engineCompat, {
180977
181432
  resetDomainMountForTests: () => resetDomainMountForTests,
180978
181433
  resetGoalStateForTesting: () => resetGoalStateForTesting,
180979
181434
  resetHooksConfigSnapshot: () => resetHooksConfigSnapshot,
181435
+ resetIdleCompactionForTesting: () => resetIdleCompactionForTesting,
180980
181436
  resetMcpClientRegistry: () => resetMcpClientRegistry,
180981
181437
  resetMcpSkillCommandSource: () => resetMcpSkillCommandSource,
180982
181438
  resetMicrocompactState: () => resetMicrocompactState,
180983
181439
  resetPendingNotifications: () => resetPendingNotifications,
180984
181440
  resetProjectFlushStateForTesting: () => resetProjectFlushStateForTesting,
180985
181441
  resetProjectForTesting: () => resetProjectForTesting,
181442
+ resetRestrictedMode: () => resetRestrictedMode,
180986
181443
  resetSchedulerEnv: () => resetSchedulerEnv,
180987
181444
  resetSdkEventQueueForTesting: () => resetSdkEventQueueForTesting,
180988
181445
  resetSessionContextPort: () => resetSessionContextPort,
@@ -180998,6 +181455,7 @@ __export(exports_engineCompat, {
180998
181455
  resolveAgentTools: () => resolveAgentTools,
180999
181456
  resolveAutoCompactWindow: () => resolveAutoCompactWindow,
181000
181457
  resolveGitDir: () => resolveGitDir,
181458
+ resolveIdleCompactionConfig: () => resolveIdleCompactionConfig,
181001
181459
  resolveRef: () => resolveRef,
181002
181460
  resolveWebSearchApiKey: () => resolveWebSearchApiKey,
181003
181461
  resolveWebSearchProvider: () => resolveWebSearchProvider,
@@ -181005,6 +181463,7 @@ __export(exports_engineCompat, {
181005
181463
  restoreGoalState: () => restoreGoalState,
181006
181464
  restoreSessionMetadata: () => restoreSessionMetadata,
181007
181465
  restoreWorktreeSession: () => restoreWorktreeSession,
181466
+ restrictedBypassError: () => restrictedBypassError,
181008
181467
  resumeGoal: () => resumeGoal,
181009
181468
  roughTokenCountEstimation: () => roughTokenCountEstimation2,
181010
181469
  roughTokenCountEstimationForContent: () => roughTokenCountEstimationForContent,
@@ -181034,6 +181493,7 @@ __export(exports_engineCompat, {
181034
181493
  setCompactPorts: () => setCompactPorts,
181035
181494
  setCronJitterConfigProvider: () => setCronJitterConfigProvider,
181036
181495
  setDynamicTeamContext: () => setDynamicTeamContext,
181496
+ setIdleCompactionSettingsSource: () => setIdleCompactionSettingsSource,
181037
181497
  setLastSummarizedMessageId: () => setLastSummarizedMessageId,
181038
181498
  setLeaderTeamName: () => setLeaderTeamName,
181039
181499
  setMcpClientRegistry: () => setMcpClientRegistry,
@@ -181041,6 +181501,7 @@ __export(exports_engineCompat, {
181041
181501
  setPartialCompactPort: () => setPartialCompactPort,
181042
181502
  setPluginSettingsBase: () => setPluginSettingsBase,
181043
181503
  setReactiveCompactPort: () => setReactiveCompactPort,
181504
+ setRestrictedMode: () => setRestrictedMode,
181044
181505
  setSchedulerEnv: () => setSchedulerEnv,
181045
181506
  setSessionContextPort: () => setSessionContextPort,
181046
181507
  setSessionEnv: () => setSessionEnv,
@@ -181061,6 +181522,7 @@ __export(exports_engineCompat, {
181061
181522
  shouldAutoCompact: () => shouldAutoCompact,
181062
181523
  shouldDisableAllHooksIncludingManaged: () => shouldDisableAllHooksIncludingManaged,
181063
181524
  shouldDisableBypassPermissions: () => shouldDisableBypassPermissions,
181525
+ shouldIdleCompact: () => shouldIdleCompact,
181064
181526
  shouldNudgeForSnips: () => shouldNudgeForSnips,
181065
181527
  shouldPlanUseAutoMode: () => shouldPlanUseAutoMode,
181066
181528
  shouldUseSandbox: () => shouldUseSandbox,
@@ -256424,6 +256886,8 @@ async function* queryEngineLoopStream(params) {
256424
256886
  pending.push(event.messages[0]);
256425
256887
  } else if (event.type === "stream_delta") {
256426
256888
  pending.push(event);
256889
+ } else if (event.type === "tool_heartbeat") {
256890
+ pending.push(event);
256427
256891
  }
256428
256892
  notify();
256429
256893
  }
@@ -263258,6 +263722,10 @@ function CompactSummary(t0) {
263258
263722
  description: "expand history",
263259
263723
  parens: true
263260
263724
  }, undefined, false, undefined, this)
263725
+ }, undefined, false, undefined, this),
263726
+ /* @__PURE__ */ jsx_dev_runtime65.jsxDEV(ThemedText, {
263727
+ dimColor: true,
263728
+ children: "Summary is saved to the session transcript and restored on resume"
263261
263729
  }, undefined, false, undefined, this)
263262
263730
  ]
263263
263731
  }, undefined, true, undefined, this)
@@ -263350,14 +263818,20 @@ function CompactSummary(t0) {
263350
263818
  t2,
263351
263819
  /* @__PURE__ */ jsx_dev_runtime65.jsxDEV(ThemedBox_default, {
263352
263820
  flexDirection: "column",
263353
- children: /* @__PURE__ */ jsx_dev_runtime65.jsxDEV(ThemedText, {
263354
- bold: true,
263355
- children: [
263356
- "Compact summary",
263357
- t3
263358
- ]
263359
- }, undefined, true, undefined, this)
263360
- }, undefined, false, undefined, this)
263821
+ children: [
263822
+ /* @__PURE__ */ jsx_dev_runtime65.jsxDEV(ThemedText, {
263823
+ bold: true,
263824
+ children: [
263825
+ "Compact summary",
263826
+ t3
263827
+ ]
263828
+ }, undefined, true, undefined, this),
263829
+ /* @__PURE__ */ jsx_dev_runtime65.jsxDEV(ThemedText, {
263830
+ dimColor: true,
263831
+ children: "Summary is saved to the session transcript and restored on resume"
263832
+ }, undefined, false, undefined, this)
263833
+ ]
263834
+ }, undefined, true, undefined, this)
263361
263835
  ]
263362
263836
  }, undefined, true, undefined, this);
263363
263837
  $[16] = t3;
@@ -274009,6 +274483,7 @@ async function* runAgent2({
274009
274483
  getAppState: () => agentToolUseContext.getAppState(),
274010
274484
  querySource,
274011
274485
  maxTurns: effectiveMaxTurns,
274486
+ ...agentDefinition.autoCompactWindow !== undefined ? { autoCompactWindowOverride: agentDefinition.autoCompactWindow } : {},
274012
274487
  signal: agentAbortController.signal
274013
274488
  });
274014
274489
  const stream = queryEngineLoopStream({
@@ -274444,7 +274919,7 @@ var init_apiErrors = __esm(() => {
274444
274919
  });
274445
274920
  },
274446
274921
  resolveAuthErrorMessaging: (error, _model) => {
274447
- if (error instanceof APIError3 && error.status === 400 && error.message.toLowerCase().includes("organization has been disabled")) {
274922
+ if (error instanceof APIError2 && error.status === 400 && error.message.toLowerCase().includes("organization has been disabled")) {
274448
274923
  const { source } = getAtlasApiKeyWithSource();
274449
274924
  if (source === "OPENAI_API_KEY" && process.env.OPENAI_API_KEY) {
274450
274925
  const hasStoredOAuth = getOAuthTokens()?.accessToken != null;
@@ -274469,13 +274944,13 @@ var init_apiErrors = __esm(() => {
274469
274944
  content: isExternalSource ? INVALID_API_KEY_ERROR_MESSAGE_EXTERNAL : INVALID_API_KEY_ERROR_MESSAGE
274470
274945
  });
274471
274946
  }
274472
- if (error instanceof APIError3 && error.status === 403 && error.message.includes("OAuth token has been revoked")) {
274947
+ if (error instanceof APIError2 && error.status === 403 && error.message.includes("OAuth token has been revoked")) {
274473
274948
  return createAssistantAPIErrorMessage2({
274474
274949
  error: "authentication_failed",
274475
274950
  content: getTokenRevokedErrorMessage()
274476
274951
  });
274477
274952
  }
274478
- if (error instanceof APIError3 && (error.status === 401 || error.status === 403) && error.message.includes("OAuth authentication is currently not allowed for this organization")) {
274953
+ if (error instanceof APIError2 && (error.status === 401 || error.status === 403) && error.message.includes("OAuth authentication is currently not allowed for this organization")) {
274479
274954
  return createAssistantAPIErrorMessage2({
274480
274955
  error: "authentication_failed",
274481
274956
  content: getOauthOrgNotAllowedErrorMessage()
@@ -274495,7 +274970,7 @@ var init_apiErrors = __esm(() => {
274495
274970
  content: getIsNonInteractiveSession() ? `${API_ERROR_MESSAGE_PREFIX}: provider quota exhausted (403). Top up your provider quota, or switch provider/model via --model, then retry.` : `${API_ERROR_MESSAGE_PREFIX}: provider quota exhausted (403). Top up your provider quota, or run /model to switch provider/model, then retry.`
274496
274971
  });
274497
274972
  }
274498
- if (error instanceof APIError3 && (error.status === 401 || error.status === 403)) {
274973
+ if (error instanceof APIError2 && (error.status === 401 || error.status === 403)) {
274499
274974
  if (isCCRMode()) {
274500
274975
  return createAssistantAPIErrorMessage2({
274501
274976
  error: "authentication_failed",
@@ -299518,14 +299993,14 @@ function handleValidationError(error, modelName) {
299518
299993
  error: `Model '${modelName}' not found`
299519
299994
  };
299520
299995
  }
299521
- if (error instanceof APIError3) {
299996
+ if (error instanceof APIError2) {
299522
299997
  if (error instanceof AuthenticationError2) {
299523
299998
  return {
299524
299999
  valid: false,
299525
300000
  error: "Authentication failed. Please check your API credentials."
299526
300001
  };
299527
300002
  }
299528
- if (error instanceof APIConnectionError3) {
300003
+ if (error instanceof APIConnectionError2) {
299529
300004
  return {
299530
300005
  valid: false,
299531
300006
  error: "Network error. Please check your internet connection."
@@ -308884,7 +309359,7 @@ async function executeAsyncClassifierCheck2(pendingCheck, signal, isNonInteracti
308884
309359
  try {
308885
309360
  classifierResult = speculativeResult ? await speculativeResult : await classifyBashCommand2(command, cwd, descriptions, "allow", signal, isNonInteractiveSession);
308886
309361
  } catch (error) {
308887
- if (error instanceof APIUserAbortError3 || error instanceof AbortError2) {
309362
+ if (error instanceof APIUserAbortError2 || error instanceof AbortError2) {
308888
309363
  callbacks.onComplete?.();
308889
309364
  return;
308890
309365
  }
@@ -321200,14 +321675,19 @@ function buildAgentLoopParams(m) {
321200
321675
  const resolved = pool.length > 0 ? resolveModel(pool[0]) : undefined;
321201
321676
  const toolList = m.tools;
321202
321677
  const countTokens = (msgs) => modelProvider.countTokens(role, sessionModel, msgs, toolList);
321203
- const mergedAutoCompact = mergeAutoCompactOverrides(getAutoCompactEnvOverrides(), getInitialSettings2().autoCompactWindow, mainLoopModel);
321678
+ const envAutoCompact = getAutoCompactEnvOverrides();
321679
+ const mergedAutoCompact = mergeAutoCompactOverrides(envAutoCompact, getInitialSettings2().autoCompactWindow, mainLoopModel);
321680
+ const autoCompactWindowOverride = envAutoCompact.windowOverride !== undefined ? mergedAutoCompact.windowOverride : m.autoCompactWindowOverride ?? mergedAutoCompact.windowOverride;
321204
321681
  const autoCompact = {
321205
321682
  contextWindow: resolved?.contextWindow ?? HARD_DEFAULT_CONTEXT_WINDOW,
321206
321683
  maxOutputTokens: resolved?.maxTokens,
321207
321684
  countTokens,
321208
321685
  enabled: mergedAutoCompact.autoCompactDisabled ? false : undefined,
321209
321686
  pctOverride: mergedAutoCompact.pctOverride,
321210
- windowOverride: mergedAutoCompact.windowOverride,
321687
+ windowOverride: autoCompactWindowOverride,
321688
+ ...m.toolUseContext.options?.thinkingConfig?.type === "enabled" ? {
321689
+ thinkingBudgetTokens: m.toolUseContext.options.thinkingConfig.budgetTokens
321690
+ } : {},
321211
321691
  compact: createAutoCompactCompact({
321212
321692
  trimmedSummarize: async (compactMsgs, prompt) => {
321213
321693
  const resp = await modelProvider.chat({
@@ -335371,6 +335851,22 @@ ${EXPLANATORY_FEATURE_PROMPT}`
335371
335851
  });
335372
335852
  });
335373
335853
 
335854
+ // src/tui/utils/messageDisplayHooks.ts
335855
+ function fireMessageDisplayHooks(message) {
335856
+ (async () => {
335857
+ try {
335858
+ for await (const _hookResult of executeMessageDisplayHooks(message, undefined, MESSAGE_DISPLAY_HOOK_TIMEOUT_MS)) {}
335859
+ } catch (e) {
335860
+ logForDebugging3(`MessageDisplay hook execution failed: ${e instanceof Error ? e.message : String(e)}`);
335861
+ }
335862
+ })();
335863
+ }
335864
+ var MESSAGE_DISPLAY_HOOK_TIMEOUT_MS = 15000;
335865
+ var init_messageDisplayHooks = __esm(() => {
335866
+ init_debug();
335867
+ init_hooks7();
335868
+ });
335869
+
335374
335870
  // src/tui/utils/messages.ts
335375
335871
  import { randomUUID as randomUUID36 } from "crypto";
335376
335872
  function isFeatureOn(name) {
@@ -336787,8 +337283,8 @@ function getContentText(content) {
336787
337283
  }
336788
337284
  return null;
336789
337285
  }
336790
- function handleMessageFromStream(message, onMessage, onUpdateLength, onSetStreamMode, onStreamingToolUses, onTombstone, onStreamingThinking, onApiMetrics, onStreamingText) {
336791
- if (message.type !== "stream_event" && message.type !== "stream_request_start" && message.type !== "stream_delta") {
337286
+ function handleMessageFromStream(message, onMessage, onUpdateLength, onSetStreamMode, onStreamingToolUses, onTombstone, onStreamingThinking, onApiMetrics, onStreamingText, onToolHeartbeat) {
337287
+ if (message.type !== "stream_event" && message.type !== "stream_request_start" && message.type !== "stream_delta" && message.type !== "tool_heartbeat") {
336792
337288
  if (message.type === "tombstone") {
336793
337289
  onTombstone?.(message.message);
336794
337290
  return;
@@ -336805,6 +337301,9 @@ function handleMessageFromStream(message, onMessage, onUpdateLength, onSetStream
336805
337301
  streamingEndedAt: Date.now()
336806
337302
  }));
336807
337303
  }
337304
+ const displayText = getContentText(message.message.content);
337305
+ if (displayText)
337306
+ fireMessageDisplayHooks(displayText);
336808
337307
  }
336809
337308
  onStreamingText?.(() => null);
336810
337309
  onMessage(message);
@@ -336814,6 +337313,10 @@ function handleMessageFromStream(message, onMessage, onUpdateLength, onSetStream
336814
337313
  onSetStreamMode("requesting");
336815
337314
  return;
336816
337315
  }
337316
+ if (message.type === "tool_heartbeat") {
337317
+ onToolHeartbeat?.({ toolName: message.toolName, elapsedMs: message.elapsedMs });
337318
+ return;
337319
+ }
336817
337320
  if (message.type === "stream_delta") {
336818
337321
  if (message.delta.type === "text_delta") {
336819
337322
  onSetStreamMode("responding");
@@ -338269,6 +338772,7 @@ var init_messages3 = __esm(() => {
338269
338772
  init_shared();
338270
338773
  init_last();
338271
338774
  init_outputStyles();
338775
+ init_messageDisplayHooks();
338272
338776
  init_paths3();
338273
338777
  init_growthbook();
338274
338778
  init_modelprovider2();
@@ -339510,7 +340014,7 @@ async function checkRuleBasedPermissions(tool, input, context) {
339510
340014
  const parsedInput = tool.inputSchema.parse(input);
339511
340015
  toolPermissionResult = await tool.checkPermissions(parsedInput, context);
339512
340016
  } catch (e) {
339513
- if (e instanceof AbortError2 || e instanceof APIUserAbortError3) {
340017
+ if (e instanceof AbortError2 || e instanceof APIUserAbortError2) {
339514
340018
  throw e;
339515
340019
  }
339516
340020
  logError3(e);
@@ -339564,7 +340068,7 @@ async function hasPermissionsToUseToolInner(tool, input, context) {
339564
340068
  const parsedInput = tool.inputSchema.parse(input);
339565
340069
  toolPermissionResult = await tool.checkPermissions(parsedInput, context);
339566
340070
  } catch (e) {
339567
- if (e instanceof AbortError2 || e instanceof APIUserAbortError3) {
340071
+ if (e instanceof AbortError2 || e instanceof APIUserAbortError2) {
339568
340072
  throw e;
339569
340073
  }
339570
340074
  logError3(e);
@@ -339798,7 +340302,7 @@ var classifierDecisionModule, autoModeStateModule3, CLASSIFIER_FAIL_CLOSED_REFRE
339798
340302
  };
339799
340303
  }
339800
340304
  } catch (e) {
339801
- if (e instanceof AbortError2 || e instanceof APIUserAbortError3) {
340305
+ if (e instanceof AbortError2 || e instanceof APIUserAbortError2) {
339802
340306
  throw e;
339803
340307
  }
339804
340308
  }
@@ -345033,6 +345537,22 @@ var init_AddWorkspaceDirectory = __esm(() => {
345033
345537
  }];
345034
345538
  });
345035
345539
 
345540
+ // src/tui/utils/directoryAddedHooks.ts
345541
+ function fireDirectoryAddedHooks(directory, source) {
345542
+ (async () => {
345543
+ try {
345544
+ for await (const _hookResult of executeDirectoryAddedHooks(directory, source, undefined, DIRECTORY_ADDED_HOOK_TIMEOUT_MS)) {}
345545
+ } catch (e) {
345546
+ logForDebugging3(`DirectoryAdded hook execution failed: ${e instanceof Error ? e.message : String(e)}`);
345547
+ }
345548
+ })();
345549
+ }
345550
+ var DIRECTORY_ADDED_HOOK_TIMEOUT_MS = 15000;
345551
+ var init_directoryAddedHooks = __esm(() => {
345552
+ init_debug();
345553
+ init_hooks7();
345554
+ });
345555
+
345036
345556
  // src/tui/commands/add-dir/add-dir.tsx
345037
345557
  var exports_add_dir = {};
345038
345558
  __export(exports_add_dir, {
@@ -345138,6 +345658,7 @@ async function call2(onDone, context, args) {
345138
345658
  message = `Added ${source_default.bold(path)} as a working directory for this session`;
345139
345659
  }
345140
345660
  const messageWithHint = `${message} ${source_default.dim("· /permissions to manage")}`;
345661
+ fireDirectoryAddedHooks(path, destination);
345141
345662
  onDone(messageWithHint);
345142
345663
  };
345143
345664
  if (!directoryPath) {
@@ -345178,6 +345699,7 @@ var init_add_dir = __esm(() => {
345178
345699
  init_PermissionUpdate();
345179
345700
  init_sandboxCompat();
345180
345701
  init_validation4();
345702
+ init_directoryAddedHooks();
345181
345703
  import_compiler_runtime110 = __toESM(require_compiler_runtime(), 1);
345182
345704
  import_react77 = __toESM(require_react(), 1);
345183
345705
  jsx_dev_runtime132 = __toESM(require_jsx_dev_runtime(), 1);
@@ -348822,8 +349344,7 @@ __export(exports_autocompact, {
348822
349344
  call: () => call9
348823
349345
  });
348824
349346
  function currentTierFor(raw, model) {
348825
- const map = normalizeAutoCompactWindowSetting(raw);
348826
- return map[model] ?? map.default;
349347
+ return lookupAutoCompactWindowSetting(normalizeAutoCompactWindowSetting(raw), model);
348827
349348
  }
348828
349349
  function currentToOptionValue(setting) {
348829
349350
  if (!setting || setting.kind === "auto")
@@ -354630,6 +355151,21 @@ function Config({
354630
355151
  }));
354631
355152
  }
354632
355153
  },
355154
+ {
355155
+ id: "idleCompaction",
355156
+ label: "Idle compaction",
355157
+ value: settingsData?.idleCompaction ?? true,
355158
+ type: "boolean",
355159
+ onChange(idleCompaction) {
355160
+ updateSettingsForSource2("localSettings", {
355161
+ idleCompaction
355162
+ });
355163
+ setSettingsData((prev_3b) => ({
355164
+ ...prev_3b,
355165
+ idleCompaction
355166
+ }));
355167
+ }
355168
+ },
354633
355169
  {
354634
355170
  id: "prefersReducedMotion",
354635
355171
  label: "Reduce motion",
@@ -355266,6 +355802,7 @@ function Config({
355266
355802
  const il = initialLocalSettings;
355267
355803
  updateSettingsForSource2("localSettings", {
355268
355804
  spinnerTipsEnabled: il?.spinnerTipsEnabled,
355805
+ idleCompaction: il?.idleCompaction,
355269
355806
  prefersReducedMotion: il?.prefersReducedMotion,
355270
355807
  outputStyle: il?.outputStyle
355271
355808
  });
@@ -398925,7 +399462,7 @@ function GenerateStep() {
398925
399462
  });
398926
399463
  goToStep(6);
398927
399464
  } catch (err) {
398928
- if (err instanceof APIUserAbortError3) {} else if (err instanceof Error && !err.message.includes("No assistant message found")) {
399465
+ if (err instanceof APIUserAbortError2) {} else if (err instanceof Error && !err.message.includes("No assistant message found")) {
398929
399466
  setError(err.message || "Failed to generate agent");
398930
399467
  }
398931
399468
  updateWizardData({
@@ -427439,6 +427976,7 @@ var init_hooks6 = __esm(() => {
427439
427976
  decision: _enum(["approve", "block"]).optional(),
427440
427977
  reason: string2().describe("Explanation for the decision").optional(),
427441
427978
  systemMessage: string2().describe("Warning message shown to the user").optional(),
427979
+ terminalSequence: string2().optional(),
427442
427980
  hookSpecificOutput: union([
427443
427981
  object({
427444
427982
  hookEventName: literal("PreToolUse"),
@@ -428447,6 +428985,9 @@ function processHookJSONOutput({
428447
428985
  if (json.systemMessage) {
428448
428986
  result.systemMessage = json.systemMessage;
428449
428987
  }
428988
+ if (json.terminalSequence) {
428989
+ result.terminalSequence = json.terminalSequence;
428990
+ }
428450
428991
  if (json.hookSpecificOutput?.hookEventName === "PreToolUse" && json.hookSpecificOutput.permissionDecision) {
428451
428992
  switch (json.hookSpecificOutput.permissionDecision) {
428452
428993
  case "allow":
@@ -429087,6 +429628,9 @@ async function getMatchingHooks2(appState, sessionId, hookEvent, hookInput, tool
429087
429628
  case "PostModelSwitch":
429088
429629
  matchQuery = hookInput.new_model;
429089
429630
  break;
429631
+ case "DirectoryAdded":
429632
+ matchQuery = hookInput.directory;
429633
+ break;
429090
429634
  default:
429091
429635
  break;
429092
429636
  }
@@ -429764,6 +430308,11 @@ async function* executeHooks({
429764
430308
  let permissionBehavior;
429765
430309
  for await (const result of all2(hookPromises)) {
429766
430310
  outcomes[result.outcome]++;
430311
+ if (result.terminalSequence) {
430312
+ try {
430313
+ process.stdout.write(result.terminalSequence);
430314
+ } catch {}
430315
+ }
429767
430316
  if (result.preventContinuation) {
429768
430317
  logForDebugging3(`Hook ${hookEvent} (${getHookDisplayText(result.hook)}) requested preventContinuation`);
429769
430318
  yield {
@@ -430259,6 +430808,35 @@ async function* executePostModelSwitchHooks(oldModel, newModel, source, signal,
430259
430808
  timeoutMs
430260
430809
  });
430261
430810
  }
430811
+ async function* executeDirectoryAddedHooks(directory, source, signal, timeoutMs = TOOL_HOOK_EXECUTION_TIMEOUT_MS) {
430812
+ const hookInput = {
430813
+ ...createBaseHookInput2(undefined),
430814
+ hook_event_name: "DirectoryAdded",
430815
+ directory,
430816
+ source
430817
+ };
430818
+ yield* executeHooks({
430819
+ hookInput,
430820
+ toolUseID: randomUUID43(),
430821
+ matchQuery: directory,
430822
+ signal,
430823
+ timeoutMs
430824
+ });
430825
+ }
430826
+ async function* executeMessageDisplayHooks(message, signal, timeoutMs = TOOL_HOOK_EXECUTION_TIMEOUT_MS) {
430827
+ const hookInput = {
430828
+ ...createBaseHookInput2(undefined),
430829
+ hook_event_name: "MessageDisplay",
430830
+ message
430831
+ };
430832
+ yield* executeHooks({
430833
+ hookInput,
430834
+ toolUseID: randomUUID43(),
430835
+ matchQuery: undefined,
430836
+ signal,
430837
+ timeoutMs
430838
+ });
430839
+ }
430262
430840
  async function* executeSetupHooks(trigger, signal, timeoutMs = TOOL_HOOK_EXECUTION_TIMEOUT_MS, forceSyncExecution) {
430263
430841
  const hookInput = {
430264
430842
  ...createBaseHookInput2(undefined),
@@ -430935,6 +431513,30 @@ var init_hooks7 = __esm(() => {
430935
431513
  TOOL_HOOK_EXECUTION_TIMEOUT_MS = 10 * 60 * 1000;
430936
431514
  });
430937
431515
 
431516
+ // src/tui/contextBodies/compactModelSwitch.ts
431517
+ function recordMainLoopModelSwitch(previous, next) {
431518
+ if (!previous || previous === next) {
431519
+ previousMainLoopModel = null;
431520
+ return;
431521
+ }
431522
+ previousMainLoopModel = previous;
431523
+ }
431524
+ function resolveSwitchedCompactModel(current) {
431525
+ const previous = previousMainLoopModel;
431526
+ if (!previous || !current || previous === current)
431527
+ return;
431528
+ const previousWindow = getProviderContextWindow(previous) ?? HARD_DEFAULT_CONTEXT_WINDOW;
431529
+ const currentWindow = getProviderContextWindow(current) ?? HARD_DEFAULT_CONTEXT_WINDOW;
431530
+ return previousWindow > currentWindow ? previous : undefined;
431531
+ }
431532
+ function formatCompactStartMessage(summaryModel) {
431533
+ return summaryModel ? `Compacting conversation (summary: ${summaryModel})` : "Compacting conversation";
431534
+ }
431535
+ var previousMainLoopModel = null;
431536
+ var init_compactModelSwitch = __esm(() => {
431537
+ init_modelprovider2();
431538
+ });
431539
+
430938
431540
  // src/tui/utils/memory/types.ts
430939
431541
  var MEMORY_TYPE_VALUES;
430940
431542
  var init_types17 = __esm(() => {
@@ -431855,7 +432457,11 @@ async function streamCompactSummary({
431855
432457
  }
431856
432458
  const retryEnabled = getFeatureValue_CACHED_MAY_BE_STALE("atlas_compact_streaming_retry", false);
431857
432459
  const maxAttempts = retryEnabled ? MAX_COMPACT_STREAMING_RETRIES : 1;
431858
- const compactModel = modelOverride ?? context.options.mainLoopModel;
432460
+ const compactModel = modelOverride ?? resolveSwitchedCompactModel(context.options.mainLoopModel) ?? context.options.mainLoopModel;
432461
+ context.onCompactProgress?.({
432462
+ type: "compact_start",
432463
+ summaryModel: compactModel
432464
+ });
431859
432465
  for (let attempt = 1;attempt <= maxAttempts; attempt++) {
431860
432466
  let hasStartedStreaming = false;
431861
432467
  let response;
@@ -431922,7 +432528,7 @@ async function streamCompactSummary({
431922
432528
  }
431923
432529
  if (attempt < maxAttempts) {
431924
432530
  await sleep9(getRetryDelay(attempt), context.abortController.signal, {
431925
- abortError: () => new APIUserAbortError3
432531
+ abortError: () => new APIUserAbortError2
431926
432532
  });
431927
432533
  continue;
431928
432534
  }
@@ -432108,6 +432714,7 @@ var init_compact4 = __esm(() => {
432108
432714
  init_shared();
432109
432715
  init_uniqBy();
432110
432716
  init_atlas();
432717
+ init_compactModelSwitch();
432111
432718
  init_bootstrapState();
432112
432719
  init_bootstrapState();
432113
432720
  init_FileReadTool();
@@ -432826,6 +433433,7 @@ function wireContextHostPorts() {
432826
433433
  });
432827
433434
  setAutoCompactSettingsSource(() => getGlobalConfig().autoCompactEnabled);
432828
433435
  setAutoCompactWindowSettingsSource(() => getInitialSettings2().autoCompactWindow);
433436
+ setIdleCompactionSettingsSource(() => getInitialSettings2().idleCompaction);
432829
433437
  setLlmTimeoutSettingsSource(() => getInitialSettings2().llmTimeoutMs);
432830
433438
  setEffortByModelSource(() => getEffortByModel());
432831
433439
  setTimeBasedMCConfigSource(() => getFeatureValue_CACHED_MAY_BE_STALE("atlas_slate_heron", TIME_BASED_MC_CONFIG_DEFAULTS));
@@ -433174,13 +433782,17 @@ function truncateEntrypointContent(raw) {
433174
433782
  const byteCount = trimmed.length;
433175
433783
  const wasLineTruncated = lineCount > MAX_ENTRYPOINT_LINES;
433176
433784
  const wasByteTruncated = byteCount > MAX_ENTRYPOINT_BYTES;
433785
+ const nearLimit = (lineCount >= NEAR_LIMIT_LINES || byteCount >= NEAR_LIMIT_BYTES) && !wasLineTruncated && !wasByteTruncated;
433177
433786
  if (!wasLineTruncated && !wasByteTruncated) {
433178
433787
  return {
433179
- content: trimmed,
433788
+ content: nearLimit ? trimmed + `
433789
+
433790
+ > NOTE: ${ENTRYPOINT_NAME} is close to the read limit (${lineCount} lines / ${formatFileSize3(byteCount)}; limits: ${MAX_ENTRYPOINT_LINES} lines / ${formatFileSize3(MAX_ENTRYPOINT_BYTES)}). ${COMPACT_NOW_DIRECTIVE}` : trimmed,
433180
433791
  lineCount,
433181
433792
  byteCount,
433182
433793
  wasLineTruncated,
433183
- wasByteTruncated
433794
+ wasByteTruncated,
433795
+ nearLimit
433184
433796
  };
433185
433797
  }
433186
433798
  let truncated = wasLineTruncated ? contentLines.slice(0, MAX_ENTRYPOINT_LINES).join(`
@@ -433194,11 +433806,12 @@ function truncateEntrypointContent(raw) {
433194
433806
  return {
433195
433807
  content: truncated + `
433196
433808
 
433197
- > WARNING: ${ENTRYPOINT_NAME} is ${reason}. Only part of it was loaded. Keep index entries to one line under ~200 chars; move detail into topic files.`,
433809
+ > WARNING: ${ENTRYPOINT_NAME} is ${reason}. Only part of it was loaded. Keep index entries to one line under ~200 chars; move detail into topic files. ${COMPACT_NOW_DIRECTIVE}`,
433198
433810
  lineCount,
433199
433811
  byteCount,
433200
433812
  wasLineTruncated,
433201
- wasByteTruncated
433813
+ wasByteTruncated,
433814
+ nearLimit: true
433202
433815
  };
433203
433816
  }
433204
433817
  async function ensureMemoryDirExists(memoryDir, store) {
@@ -433342,7 +433955,7 @@ async function loadMemoryPrompt(store) {
433342
433955
  if (getFeatureValue_CACHED_MAY_BE_STALE("atlas_herring_clock", false)) {}
433343
433956
  return null;
433344
433957
  }
433345
- var teamMemPaths5, ENTRYPOINT_NAME = "MEMORY.md", MAX_ENTRYPOINT_LINES = 200, MAX_ENTRYPOINT_BYTES = 25000, teamMemPrompts, DIR_EXISTS_GUIDANCE = "This directory already exists — write to it directly with the Write tool (do not run mkdir or check for its existence).", DIRS_EXIST_GUIDANCE = "Both directories already exist — write to them directly with the Write tool (do not run mkdir or check for their existence).";
433958
+ var teamMemPaths5, ENTRYPOINT_NAME = "MEMORY.md", MAX_ENTRYPOINT_LINES = 200, MAX_ENTRYPOINT_BYTES = 25000, NEAR_LIMIT_FRACTION = 0.8, NEAR_LIMIT_LINES, NEAR_LIMIT_BYTES, COMPACT_NOW_DIRECTIVE = "Compact it now: merge duplicate entries and prune stale ones before adding new lines.", teamMemPrompts, DIR_EXISTS_GUIDANCE = "This directory already exists — write to it directly with the Write tool (do not run mkdir or check for its existence).", DIRS_EXIST_GUIDANCE = "Both directories already exist — write to them directly with the Write tool (do not run mkdir or check for their existence).";
433346
433959
  var init_memdir = __esm(() => {
433347
433960
  init_shared();
433348
433961
  init_memory();
@@ -433360,6 +433973,8 @@ var init_memdir = __esm(() => {
433360
433973
  init_sessionStorage();
433361
433974
  init_memoryTypes2();
433362
433975
  teamMemPaths5 = feature("TEAMMEM") ? (init_teamMemPaths(), __toCommonJS(exports_teamMemPaths)) : null;
433976
+ NEAR_LIMIT_LINES = Math.floor(MAX_ENTRYPOINT_LINES * NEAR_LIMIT_FRACTION);
433977
+ NEAR_LIMIT_BYTES = Math.floor(MAX_ENTRYPOINT_BYTES * NEAR_LIMIT_FRACTION);
433363
433978
  teamMemPrompts = feature("TEAMMEM") ? (init_teamMemPrompts(), __toCommonJS(exports_teamMemPrompts)) : null;
433364
433979
  });
433365
433980
 
@@ -435274,6 +435889,9 @@ function onChangeAppState({
435274
435889
  }
435275
435890
  notifyPermissionModeChanged(newMode);
435276
435891
  }
435892
+ if (newState.mainLoopModel !== oldState.mainLoopModel) {
435893
+ recordMainLoopModelSwitch(oldState.mainLoopModel, newState.mainLoopModel);
435894
+ }
435277
435895
  if (newState.mainLoopModel !== oldState.mainLoopModel && newState.mainLoopModel === null) {
435278
435896
  updateSettingsForSource2("userSettings", { model: undefined });
435279
435897
  setMainLoopModelOverride(null);
@@ -435315,6 +435933,7 @@ function onChangeAppState({
435315
435933
  }
435316
435934
  var init_onChangeAppState = __esm(() => {
435317
435935
  init_bootstrapState();
435936
+ init_compactModelSwitch();
435318
435937
  init_auth4();
435319
435938
  init_config6();
435320
435939
  init_errors4();
@@ -468545,7 +469164,7 @@ function useCanUseTool(setToolUseConfirmQueue, setToolPermissionContext) {
468545
469164
  }
468546
469165
  }
468547
469166
  }).catch((error) => {
468548
- if (error instanceof AbortError2 || error instanceof APIUserAbortError3) {
469167
+ if (error instanceof AbortError2 || error instanceof APIUserAbortError2) {
468549
469168
  logForDebugging3(`Permission check threw ${error.constructor.name} for tool=${tool.name}: ${error.message}`);
468550
469169
  ctx.logCancelled();
468551
469170
  resolve(ctx.cancelAndAbort(undefined, true));
@@ -471807,7 +472426,7 @@ async function generateAwaySummary(messages, signal) {
471807
472426
  });
471808
472427
  return getAssistantMessageText2(response);
471809
472428
  } catch (err) {
471810
- if (err instanceof APIUserAbortError3 || signal.aborted) {
472429
+ if (err instanceof APIUserAbortError2 || signal.aborted) {
471811
472430
  return null;
471812
472431
  }
471813
472432
  logForDebugging3(`[awaySummary] generation failed: ${err}`);
@@ -479379,7 +479998,7 @@ Error: sandbox required but unavailable: ${reason}
479379
479998
  setSpinnerMessage(event.hookType === "pre_compact" ? "Running PreCompact hooks…" : event.hookType === "post_compact" ? "Running PostCompact hooks…" : "Running SessionStart hooks…");
479380
479999
  break;
479381
480000
  case "compact_start":
479382
- setSpinnerMessage("Compacting conversation");
480001
+ setSpinnerMessage(formatCompactStartMessage(event.summaryModel));
479383
480002
  break;
479384
480003
  case "compact_end":
479385
480004
  setSpinnerMessage(null);
@@ -479447,6 +480066,9 @@ Error: sandbox required but unavailable: ${reason}
479447
480066
  onBackgroundQuery: handleBackgroundQuery
479448
480067
  });
479449
480068
  const onQueryEvent = import_react282.useCallback((event) => {
480069
+ if (event.type === "stream_request_start") {
480070
+ setAppState((prev) => ({ ...prev, spinnerTip: undefined }));
480071
+ }
479450
480072
  handleMessageFromStream(event, (newMessage) => {
479451
480073
  if (isCompactBoundaryMessage2(newMessage)) {
479452
480074
  if (isFullscreenEnvEnabled()) {
@@ -479485,8 +480107,13 @@ Error: sandbox required but unavailable: ${reason}
479485
480107
  responseLengthBaseline: baseline,
479486
480108
  endResponseLength: baseline
479487
480109
  });
479488
- }, onStreamingText);
479489
- }, [setMessages, setResponseLength, setStreamMode, setStreamingToolUses, setStreamingThinking, onStreamingText]);
480110
+ }, onStreamingText, (info) => {
480111
+ setAppState((prev) => ({
480112
+ ...prev,
480113
+ spinnerTip: `${info.toolName} 仍在运行 · ${Math.round(info.elapsedMs / 1000)}s`
480114
+ }));
480115
+ });
480116
+ }, [setMessages, setResponseLength, setStreamMode, setStreamingToolUses, setStreamingThinking, onStreamingText, setAppState]);
479490
480117
  const onQueryImpl = import_react282.useCallback(async (messagesIncludingNewMessages, newMessages, abortController, shouldQuery, additionalAllowedTools, mainLoopModelParam, effort) => {
479491
480118
  if (shouldQuery) {
479492
480119
  const freshClients = mergeClients(initialMcpClients, store.getState().mcp.clients);
@@ -479602,8 +480229,30 @@ Error: sandbox required but unavailable: ${reason}
479602
480229
  toolUseContext,
479603
480230
  querySource: getQuerySourceForREPL()
479604
480231
  });
480232
+ const controller = abortController;
480233
+ const handleMcpToolBackgrounded = (info) => {
480234
+ if (controller.signal.aborted)
480235
+ return;
480236
+ let text;
480237
+ if (info.outcome.ok === true) {
480238
+ let serialized;
480239
+ try {
480240
+ serialized = typeof info.outcome.data === "string" ? info.outcome.data : JSON.stringify(info.outcome.data, null, 2);
480241
+ } catch {
480242
+ serialized = String(info.outcome.data);
480243
+ }
480244
+ if (serialized.length > 1e4)
480245
+ serialized = `${serialized.slice(0, 1e4)}
480246
+ …(结果过长已截断)`;
480247
+ text = `【后台 MCP 工具完成】${info.toolName}(后台运行)已完成,结果如下:
480248
+ ${serialized}`;
480249
+ } else {
480250
+ text = `【后台 MCP 工具失败】${info.toolName}(后台运行)失败:${info.outcome.error}`;
480251
+ }
480252
+ enqueuePendingNotification2({ value: text, mode: "task-notification" });
480253
+ };
479605
480254
  const loopGen = queryEngineLoopStream({
479606
- deps: loopDeps,
480255
+ deps: { ...loopDeps, onMcpToolBackgrounded: handleMcpToolBackgrounded },
479607
480256
  args: loopArgs
479608
480257
  });
479609
480258
  let loopResult;
@@ -481405,6 +482054,7 @@ var init_REPL = __esm(() => {
481405
482054
  init_prompts2();
481406
482055
  init_systemPrompt();
481407
482056
  init_context5();
482057
+ init_compactModelSwitch();
481408
482058
  init_memoryFiles();
481409
482059
  init_backgroundHousekeeping();
481410
482060
  init_cost_tracker();
@@ -488968,6 +489618,14 @@ To attach: ${source_default.bold(`tmux attach -t ${tmuxSessionName}`)}`));
488968
489618
  await getRecentActivity();
488969
489619
  }
488970
489620
  }
489621
+ const restrictedBypassErr = restrictedBypassError({
489622
+ permissionMode,
489623
+ allowDangerouslySkipPermissions
489624
+ });
489625
+ if (restrictedBypassErr) {
489626
+ console.error(`Error: ${restrictedBypassErr}`);
489627
+ process.exit(1);
489628
+ }
488971
489629
  if (permissionMode === "bypassPermissions" || allowDangerouslySkipPermissions) {
488972
489630
  if (process.platform !== "win32" && typeof process.getuid === "function" && process.getuid() === 0 && process.env.IS_SANDBOX !== "1" && !isEnvTruthy2(process.env.ATLAS_BUBBLEWRAP)) {
488973
489631
  console.error(`--dangerously-skip-permissions cannot be used with root/sudo privileges for security reasons`);
@@ -488986,6 +489644,7 @@ var init_setup4 = __esm(() => {
488986
489644
  init_Shell2();
488987
489645
  init_sinks();
488988
489646
  init_bootstrap();
489647
+ init_engine();
488989
489648
  init_commands5();
488990
489649
  init_sessionMemory2();
488991
489650
  init_ids();
@@ -492572,7 +493231,7 @@ async function run() {
492572
493231
  throw new Error("--task-budget must be a positive integer");
492573
493232
  }
492574
493233
  return tokens;
492575
- }).hideHelp()).option("--replay-user-messages", "Re-emit user messages from stdin back on stdout for acknowledgment (only works with --input-format=stream-json and --output-format=stream-json)", () => true).addOption(new Option("--enable-auth-status", "Enable auth status messages in SDK mode").default(false).hideHelp()).option("--allowedTools, --allowed-tools <tools...>", 'Comma or space-separated list of tool names to allow (e.g. "Bash(git:*) Edit")').option("--tools <tools...>", 'Specify the list of available tools from the built-in set. Use "" to disable all tools, "default" to use all tools, or specify tool names (e.g. "Bash,Edit,Read").').option("--disallowedTools, --disallowed-tools <tools...>", 'Comma or space-separated list of tool names to deny (e.g. "Bash(git:*) Edit")').option("--mcp-config <configs...>", "Load MCP servers from JSON files or strings (space-separated)").addOption(new Option("--permission-prompt-tool <tool>", "MCP tool to use for permission prompts (only works with --print)").argParser(String).hideHelp()).addOption(new Option("--system-prompt <prompt>", "System prompt to use for the session").argParser(String)).addOption(new Option("--system-prompt-file <file>", "Read system prompt from a file").argParser(String).hideHelp()).addOption(new Option("--append-system-prompt <prompt>", "Append a system prompt to the default system prompt").argParser(String)).addOption(new Option("--append-system-prompt-file <file>", "Read system prompt from a file and append to the default system prompt").argParser(String).hideHelp()).addOption(new Option("--permission-mode <mode>", "Permission mode to use for the session").argParser(String).choices(PERMISSION_MODES2)).addOption(new Option("--permission-prompts <mode>", "Permission prompt policy; 'none' auto-denies prompts that would otherwise ask").argParser(String).choices(["none"])).option("-c, --continue", "Continue the most recent conversation in the current directory", () => true).option("-r, --resume [value]", "Resume a conversation by session ID, or open interactive picker with optional search term", (value) => value || true).option("--fork-session", "When resuming, create a new session ID instead of reusing the original (use with --resume or --continue)", () => true).addOption(new Option("--prefill <text>", "Pre-fill the prompt input with text without submitting it").hideHelp()).addOption(new Option("--deep-link-origin", "Signal that this session was launched from a deep link").hideHelp()).addOption(new Option("--deep-link-repo <slug>", "Repo slug the deep link ?repo= parameter resolved to the current cwd").hideHelp()).addOption(new Option("--deep-link-last-fetch <ms>", "FETCH_HEAD mtime in epoch ms, precomputed by the deep link trampoline").argParser((v) => {
493234
+ }).hideHelp()).option("--replay-user-messages", "Re-emit user messages from stdin back on stdout for acknowledgment (only works with --input-format=stream-json and --output-format=stream-json)", () => true).addOption(new Option("--enable-auth-status", "Enable auth status messages in SDK mode").default(false).hideHelp()).option("--allowedTools, --allowed-tools <tools...>", 'Comma or space-separated list of tool names to allow (e.g. "Bash(git:*) Edit")').option("--tools <tools...>", 'Specify the list of available tools from the built-in set. Use "" to disable all tools, "default" to use all tools, or specify tool names (e.g. "Bash,Edit,Read").').option("--disallowedTools, --disallowed-tools <tools...>", 'Comma or space-separated list of tool names to deny (e.g. "Bash(git:*) Edit")').option("--mcp-config <configs...>", "Load MCP servers from JSON files or strings (space-separated)").addOption(new Option("--permission-prompt-tool <tool>", "MCP tool to use for permission prompts (only works with --print)").argParser(String).hideHelp()).addOption(new Option("--system-prompt <prompt>", "System prompt to use for the session").argParser(String)).addOption(new Option("--system-prompt-file <file>", "Read system prompt from a file").argParser(String).hideHelp()).addOption(new Option("--append-system-prompt <prompt>", "Append a system prompt to the default system prompt").argParser(String)).addOption(new Option("--append-system-prompt-file <file>", "Read system prompt from a file and append to the default system prompt").argParser(String).hideHelp()).addOption(new Option("--permission-mode <mode>", "Permission mode to use for the session").argParser(String).choices(PERMISSION_MODES2)).addOption(new Option("--permission-prompts <mode>", "Permission prompt policy; 'none' auto-denies prompts that would otherwise ask").argParser(String).choices(["none"])).option("--restricted", "Run in restricted mode: strips command-execution tools (Bash/PowerShell), WebFetch, and Agent; rejects bypassPermissions and --dangerously-skip-permissions; ignores user/project/local settings (env: ATLAS_RESTRICTED)", () => true).option("-c, --continue", "Continue the most recent conversation in the current directory", () => true).option("-r, --resume [value]", "Resume a conversation by session ID, or open interactive picker with optional search term", (value) => value || true).option("--fork-session", "When resuming, create a new session ID instead of reusing the original (use with --resume or --continue)", () => true).addOption(new Option("--prefill <text>", "Pre-fill the prompt input with text without submitting it").hideHelp()).addOption(new Option("--deep-link-origin", "Signal that this session was launched from a deep link").hideHelp()).addOption(new Option("--deep-link-repo <slug>", "Repo slug the deep link ?repo= parameter resolved to the current cwd").hideHelp()).addOption(new Option("--deep-link-last-fetch <ms>", "FETCH_HEAD mtime in epoch ms, precomputed by the deep link trampoline").argParser((v) => {
492576
493235
  const n = Number(v);
492577
493236
  return Number.isFinite(n) ? n : undefined;
492578
493237
  }).hideHelp()).option("--from-pr [value]", "Resume a session linked to a PR by PR number/URL, or open interactive picker with optional search term", (value) => value || true).option("--no-session-persistence", "Disable session persistence - sessions will not be saved to disk and cannot be resumed (only works with --print)").addOption(new Option("--resume-session-at <message id>", "When resuming, only messages up to and including the assistant message with <message.id> (use with --resume in print mode)").argParser(String).hideHelp()).addOption(new Option("--rewind-files <user-message-id>", "Restore files to state at the specified user message and exit (requires --resume)").hideHelp()).option("--model <model>", `Model for the current session. Provide a role alias (e.g. 'small' or 'premium') or a provider/model reference (e.g. 'bailian/qwen38-27b').`).addOption(new Option("--effort <level>", `Effort level for the current session (low, medium, high, xhigh, max)`).argParser((rawValue) => {
@@ -492612,6 +493271,18 @@ async function run() {
492612
493271
  includePartialMessages
492613
493272
  } = options;
492614
493273
  const permissionModeCli = permissionModeCliRaw ?? (permissionPrompts === "none" ? "dontAsk" : undefined);
493274
+ if (options.restricted === true) {
493275
+ setRestrictedMode(true);
493276
+ const restrictedBypassErr = restrictedBypassError({
493277
+ permissionMode: permissionModeCliRaw,
493278
+ allowDangerouslySkipPermissions,
493279
+ dangerouslySkipPermissions
493280
+ });
493281
+ if (restrictedBypassErr) {
493282
+ console.error(`Error: ${restrictedBypassErr}`);
493283
+ process.exit(1);
493284
+ }
493285
+ }
492615
493286
  if (options.prefill) {
492616
493287
  seedEarlyInput(options.prefill);
492617
493288
  }