snow-ai 0.7.32 → 0.7.34

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.
package/bundle/cli.mjs CHANGED
@@ -1545,7 +1545,7 @@ var require_react_development = __commonJS({
1545
1545
  var dispatcher = resolveDispatcher();
1546
1546
  return dispatcher.useReducer(reducer2, initialArg, init);
1547
1547
  }
1548
- function useRef31(initialValue) {
1548
+ function useRef32(initialValue) {
1549
1549
  var dispatcher = resolveDispatcher();
1550
1550
  return dispatcher.useRef(initialValue);
1551
1551
  }
@@ -2136,8 +2136,8 @@ var require_react_development = __commonJS({
2136
2136
  if (enqueueTaskImpl === null) {
2137
2137
  try {
2138
2138
  var requireString = ("require" + Math.random()).slice(0, 7);
2139
- var nodeRequire = module2 && module2[requireString];
2140
- enqueueTaskImpl = nodeRequire.call(module2, "timers").setImmediate;
2139
+ var nodeRequire2 = module2 && module2[requireString];
2140
+ enqueueTaskImpl = nodeRequire2.call(module2, "timers").setImmediate;
2141
2141
  } catch (_err) {
2142
2142
  enqueueTaskImpl = function(callback) {
2143
2143
  {
@@ -2339,7 +2339,7 @@ var require_react_development = __commonJS({
2339
2339
  exports2.useLayoutEffect = useLayoutEffect2;
2340
2340
  exports2.useMemo = useMemo48;
2341
2341
  exports2.useReducer = useReducer8;
2342
- exports2.useRef = useRef31;
2342
+ exports2.useRef = useRef32;
2343
2343
  exports2.useState = useState94;
2344
2344
  exports2.useSyncExternalStore = useSyncExternalStore4;
2345
2345
  exports2.useTransition = useTransition;
@@ -49434,10 +49434,10 @@ var init_esm = __esm({
49434
49434
  }
49435
49435
  async _formatEntry(dirent, path62) {
49436
49436
  let entry;
49437
- const basename7 = this._isDirent ? dirent.name : dirent;
49437
+ const basename8 = this._isDirent ? dirent.name : dirent;
49438
49438
  try {
49439
- const fullPath = presolve(pjoin(path62, basename7));
49440
- entry = { path: prelative(this._root, fullPath), fullPath, basename: basename7 };
49439
+ const fullPath = presolve(pjoin(path62, basename8));
49440
+ entry = { path: prelative(this._root, fullPath), fullPath, basename: basename8 };
49441
49441
  entry[this._statsProp] = this._isDirent ? dirent : await this._stat(fullPath);
49442
49442
  } catch (err) {
49443
49443
  this._onError(err);
@@ -49965,9 +49965,9 @@ var init_handler = __esm({
49965
49965
  _watchWithNodeFs(path62, listener) {
49966
49966
  const opts = this.fsw.options;
49967
49967
  const directory = sysPath.dirname(path62);
49968
- const basename7 = sysPath.basename(path62);
49968
+ const basename8 = sysPath.basename(path62);
49969
49969
  const parent = this.fsw._getWatchedDir(directory);
49970
- parent.add(basename7);
49970
+ parent.add(basename8);
49971
49971
  const absolutePath = sysPath.resolve(path62);
49972
49972
  const options3 = {
49973
49973
  persistent: opts.persistent
@@ -49977,7 +49977,7 @@ var init_handler = __esm({
49977
49977
  let closer;
49978
49978
  if (opts.usePolling) {
49979
49979
  const enableBin = opts.interval !== opts.binaryInterval;
49980
- options3.interval = enableBin && isBinaryPath(basename7) ? opts.binaryInterval : opts.interval;
49980
+ options3.interval = enableBin && isBinaryPath(basename8) ? opts.binaryInterval : opts.interval;
49981
49981
  closer = setFsWatchFileListener(path62, absolutePath, options3, {
49982
49982
  listener,
49983
49983
  rawEmitter: this.fsw._emitRaw
@@ -50000,10 +50000,10 @@ var init_handler = __esm({
50000
50000
  return;
50001
50001
  }
50002
50002
  const dirname13 = sysPath.dirname(file2);
50003
- const basename7 = sysPath.basename(file2);
50003
+ const basename8 = sysPath.basename(file2);
50004
50004
  const parent = this.fsw._getWatchedDir(dirname13);
50005
50005
  let prevStats = stats;
50006
- if (parent.has(basename7))
50006
+ if (parent.has(basename8))
50007
50007
  return;
50008
50008
  const listener = async (path62, newStats) => {
50009
50009
  if (!this.fsw._throttle(THROTTLE_MODE_WATCH, file2, 5))
@@ -50028,9 +50028,9 @@ var init_handler = __esm({
50028
50028
  prevStats = newStats2;
50029
50029
  }
50030
50030
  } catch (error40) {
50031
- this.fsw._remove(dirname13, basename7);
50031
+ this.fsw._remove(dirname13, basename8);
50032
50032
  }
50033
- } else if (parent.has(basename7)) {
50033
+ } else if (parent.has(basename8)) {
50034
50034
  const at = newStats.atimeMs;
50035
50035
  const mt = newStats.mtimeMs;
50036
50036
  if (!at || at <= mt || mt !== prevStats.mtimeMs) {
@@ -51048,9 +51048,9 @@ var init_logger = __esm({
51048
51048
  rotateLog(filePath) {
51049
51049
  const timestamp = Date.now();
51050
51050
  const ext = path8.extname(filePath);
51051
- const basename7 = path8.basename(filePath, ext);
51051
+ const basename8 = path8.basename(filePath, ext);
51052
51052
  const dirname13 = path8.dirname(filePath);
51053
- const rotatedPath = path8.join(dirname13, `${basename7}-${timestamp}${ext}`);
51053
+ const rotatedPath = path8.join(dirname13, `${basename8}-${timestamp}${ext}`);
51054
51054
  fs8.renameSync(filePath, rotatedPath);
51055
51055
  }
51056
51056
  writeLog(level, message, meta) {
@@ -53660,6 +53660,7 @@ __export(apiConfig_exports, {
53660
53660
  getSnowConfig: () => getSnowConfig,
53661
53661
  getSystemPromptConfig: () => getSystemPromptConfig,
53662
53662
  loadConfig: () => loadConfig,
53663
+ normalizeBaseUrlMode: () => normalizeBaseUrlMode,
53663
53664
  reloadConfig: () => reloadConfig,
53664
53665
  saveConfig: () => saveConfig,
53665
53666
  saveCustomHeaders: () => saveCustomHeaders,
@@ -53679,6 +53680,12 @@ function normalizeStreamIdleTimeoutSec(value) {
53679
53680
  }
53680
53681
  return value;
53681
53682
  }
53683
+ function normalizeBaseUrlMode(value) {
53684
+ if (value === "base" || value === "endpoint") {
53685
+ return value;
53686
+ }
53687
+ return "auto";
53688
+ }
53682
53689
  function getGlobalMCPConfigFilePath() {
53683
53690
  return join3(CONFIG_DIR, "settings.json");
53684
53691
  }
@@ -53735,12 +53742,14 @@ function loadConfig() {
53735
53742
  apiConfig = {
53736
53743
  ...DEFAULT_CONFIG3.snowcfg,
53737
53744
  ...configWithoutMcp.snowcfg,
53745
+ baseUrlMode: normalizeBaseUrlMode(configWithoutMcp.snowcfg.baseUrlMode),
53738
53746
  requestMethod: normalizeRequestMethod(configWithoutMcp.snowcfg.requestMethod),
53739
53747
  streamIdleTimeoutSec: normalizeStreamIdleTimeoutSec(configWithoutMcp.snowcfg.streamIdleTimeoutSec)
53740
53748
  };
53741
53749
  } else {
53742
53750
  apiConfig = {
53743
53751
  ...DEFAULT_CONFIG3.snowcfg,
53752
+ baseUrlMode: DEFAULT_CONFIG3.snowcfg.baseUrlMode,
53744
53753
  requestMethod: DEFAULT_CONFIG3.snowcfg.requestMethod,
53745
53754
  streamIdleTimeoutSec: DEFAULT_STREAM_IDLE_TIMEOUT_SEC
53746
53755
  };
@@ -53788,11 +53797,13 @@ function reloadConfig() {
53788
53797
  async function updateSnowConfig(apiConfig) {
53789
53798
  const currentConfig = loadConfig();
53790
53799
  const normalizedIdleTimeoutSec = normalizeStreamIdleTimeoutSec(apiConfig.streamIdleTimeoutSec ?? currentConfig.snowcfg.streamIdleTimeoutSec);
53800
+ const normalizedBaseUrlMode = normalizeBaseUrlMode(apiConfig.baseUrlMode ?? currentConfig.snowcfg.baseUrlMode);
53791
53801
  const updatedConfig = {
53792
53802
  ...currentConfig,
53793
53803
  snowcfg: {
53794
53804
  ...currentConfig.snowcfg,
53795
53805
  ...apiConfig,
53806
+ baseUrlMode: normalizedBaseUrlMode,
53796
53807
  streamIdleTimeoutSec: normalizedIdleTimeoutSec
53797
53808
  }
53798
53809
  };
@@ -54123,6 +54134,7 @@ var init_apiConfig = __esm({
54123
54134
  DEFAULT_CONFIG3 = {
54124
54135
  snowcfg: {
54125
54136
  baseUrl: "https://api.openai.com/v1",
54137
+ baseUrlMode: "auto",
54126
54138
  apiKey: "",
54127
54139
  requestMethod: "chat",
54128
54140
  advancedModel: "",
@@ -56315,6 +56327,103 @@ var init_version = __esm({
56315
56327
  }
56316
56328
  });
56317
56329
 
56330
+ // dist/api/endpointResolver.js
56331
+ function normalizeBaseUrlValue(baseUrl) {
56332
+ return baseUrl.trim().replace(/\/+$/, "");
56333
+ }
56334
+ function resolveApiEndpoint(baseUrl, kind, mode = "auto", options3 = {}) {
56335
+ const normalizedBaseUrl = normalizeBaseUrlValue(baseUrl);
56336
+ if (mode === "endpoint") {
56337
+ return normalizedBaseUrl;
56338
+ }
56339
+ if (mode === "auto" && isFullEndpointForKind(normalizedBaseUrl, kind)) {
56340
+ return normalizedBaseUrl;
56341
+ }
56342
+ const baseForAppend = mode === "auto" ? stripKnownEndpointSuffix(normalizedBaseUrl) || normalizedBaseUrl : normalizedBaseUrl;
56343
+ return appendEndpointSuffix(baseForAppend, kind, options3);
56344
+ }
56345
+ function appendEndpointSuffix(baseUrl, kind, options3) {
56346
+ const normalizedBaseUrl = normalizeBaseUrlValue(baseUrl);
56347
+ if (kind === "geminiStreamGenerateContent") {
56348
+ const modelName = normalizeGeminiModelName(options3.modelName || "model-id");
56349
+ return `${normalizedBaseUrl}/${modelName}:streamGenerateContent?alt=sse`;
56350
+ }
56351
+ if (kind === "anthropicMessages") {
56352
+ const betaQuery = options3.anthropicBeta ? "?beta=true" : "";
56353
+ return `${normalizedBaseUrl}${ENDPOINT_SUFFIXES.anthropicMessages}${betaQuery}`;
56354
+ }
56355
+ return `${normalizedBaseUrl}${ENDPOINT_SUFFIXES[kind]}`;
56356
+ }
56357
+ function normalizeGeminiModelName(modelName) {
56358
+ const trimmed = modelName.trim() || "model-id";
56359
+ return trimmed.startsWith("models/") ? trimmed : `models/${trimmed}`;
56360
+ }
56361
+ function isFullEndpointForKind(baseUrl, kind) {
56362
+ const pathname = getNormalizedPathname(baseUrl);
56363
+ if (!pathname) {
56364
+ return false;
56365
+ }
56366
+ if (kind === "geminiStreamGenerateContent") {
56367
+ return pathname.endsWith(":streamGenerateContent");
56368
+ }
56369
+ return pathname.endsWith(ENDPOINT_SUFFIXES[kind]);
56370
+ }
56371
+ function stripKnownEndpointSuffix(baseUrl) {
56372
+ try {
56373
+ const url2 = new URL(baseUrl);
56374
+ const pathname = normalizePathname(url2.pathname);
56375
+ const knownSuffix = getKnownEndpointSuffix(pathname);
56376
+ if (!knownSuffix) {
56377
+ return void 0;
56378
+ }
56379
+ const nextPathname = pathname.slice(0, -knownSuffix.length) || "/";
56380
+ url2.pathname = nextPathname;
56381
+ url2.search = "";
56382
+ url2.hash = "";
56383
+ return normalizeBaseUrlValue(url2.toString());
56384
+ } catch {
56385
+ return void 0;
56386
+ }
56387
+ }
56388
+ function getKnownEndpointSuffix(pathname) {
56389
+ if (pathname.endsWith(ENDPOINT_SUFFIXES.chat)) {
56390
+ return ENDPOINT_SUFFIXES.chat;
56391
+ }
56392
+ if (pathname.endsWith(ENDPOINT_SUFFIXES.responses)) {
56393
+ return ENDPOINT_SUFFIXES.responses;
56394
+ }
56395
+ if (pathname.endsWith(ENDPOINT_SUFFIXES.anthropicMessages)) {
56396
+ return ENDPOINT_SUFFIXES.anthropicMessages;
56397
+ }
56398
+ if (pathname.endsWith(ENDPOINT_SUFFIXES.models)) {
56399
+ return ENDPOINT_SUFFIXES.models;
56400
+ }
56401
+ const geminiEndpointMatch = pathname.match(/\/models\/[^/]+:streamGenerateContent$/);
56402
+ return geminiEndpointMatch == null ? void 0 : geminiEndpointMatch[0];
56403
+ }
56404
+ function getNormalizedPathname(baseUrl) {
56405
+ try {
56406
+ return normalizePathname(new URL(baseUrl).pathname);
56407
+ } catch {
56408
+ return void 0;
56409
+ }
56410
+ }
56411
+ function normalizePathname(pathname) {
56412
+ return pathname.replace(/\/+$/, "") || "/";
56413
+ }
56414
+ var ENDPOINT_SUFFIXES;
56415
+ var init_endpointResolver = __esm({
56416
+ "dist/api/endpointResolver.js"() {
56417
+ "use strict";
56418
+ ENDPOINT_SUFFIXES = {
56419
+ chat: "/chat/completions",
56420
+ responses: "/responses",
56421
+ models: "/models",
56422
+ anthropicMessages: "/messages"
56423
+ };
56424
+ }
56425
+ });
56426
+
56318
56427
  // dist/api/chat.js
56319
56428
  var chat_exports = {};
56320
56429
  __export(chat_exports, {
@@ -56610,7 +56719,7 @@ async function* createStreamingChatCompletion(options3, abortSignal, onRetry) {
56610
56719
  requestBody["reasoning_effort"] = config3.chatThinking.reasoning_effort;
56611
56720
  }
56612
56721
  }
56613
- const url2 = `${config3.baseUrl}/chat/completions`;
56722
+ const url2 = resolveApiEndpoint(config3.baseUrl, "chat", config3.baseUrlMode);
56614
56723
  const customHeaders = options3.customHeaders || getCustomHeadersForConfig(config3);
56615
56724
  const fetchOptions = addProxyToFetchOptions(url2, {
56616
56725
  method: "POST",
@@ -56780,6 +56889,7 @@ var init_chat = __esm({
56780
56889
  init_proxyUtils();
56781
56890
  init_usageLogger();
56782
56891
  init_version();
56892
+ init_endpointResolver();
56783
56893
  }
56784
56894
  });
56785
56895
 
@@ -57113,7 +57223,7 @@ async function* createStreamingResponse(options3, abortSignal, onRetry) {
57113
57223
  include: ["reasoning.encrypted_content"],
57114
57224
  prompt_cache_key: options3.prompt_cache_key
57115
57225
  };
57116
- const url2 = `${config3.baseUrl}/responses`;
57226
+ const url2 = resolveApiEndpoint(config3.baseUrl, "responses", config3.baseUrlMode);
57117
57227
  const customHeaders = options3.customHeaders || getCustomHeadersForConfig(config3);
57118
57228
  const fetchOptions = addProxyToFetchOptions(url2, {
57119
57229
  method: "POST",
@@ -57296,6 +57406,7 @@ var init_responses = __esm({
57296
57406
  init_proxyUtils();
57297
57407
  init_usageLogger();
57298
57408
  init_version();
57409
+ init_endpointResolver();
57299
57410
  }
57300
57411
  });
57301
57412
 
@@ -57566,9 +57677,7 @@ async function* createStreamingGeminiCompletion(options3, abortSignal, onRetry)
57566
57677
  const effectiveModel = options3.model || config3.advancedModel || "";
57567
57678
  const modelName = effectiveModel.startsWith("models/") ? effectiveModel : `models/${effectiveModel}`;
57568
57679
  const baseUrl = config3.baseUrl && config3.baseUrl !== "https://api.openai.com/v1" ? config3.baseUrl : "https://generativelanguage.googleapis.com/v1beta";
57569
- const urlObj = new URL(`${baseUrl}/${modelName}:streamGenerateContent`);
57570
- urlObj.searchParams.set("alt", "sse");
57571
- const url2 = urlObj.toString();
57680
+ const url2 = resolveApiEndpoint(baseUrl, "geminiStreamGenerateContent", config3.baseUrlMode, { modelName });
57572
57681
  const customHeaders = options3.customHeaders || getCustomHeadersForConfig(config3);
57573
57682
  const fetchOptions = addProxyToFetchOptions(url2, {
57574
57683
  method: "POST",
@@ -57783,6 +57892,7 @@ var init_gemini = __esm({
57783
57892
  init_proxyUtils();
57784
57893
  init_usageLogger();
57785
57894
  init_version();
57895
+ init_endpointResolver();
57786
57896
  geminiConfig = null;
57787
57897
  }
57788
57898
  });
@@ -58272,7 +58382,7 @@ async function* createStreamingAnthropicCompletion(options3, abortSignal, onRetr
58272
58382
  ...customHeaders
58273
58383
  };
58274
58384
  const baseUrl = (config3.baseUrl && config3.baseUrl !== "https://api.openai.com/v1" ? config3.baseUrl : "https://api.anthropic.com/v1").replace(/\/+$/, "");
58275
- const url2 = config3.anthropicBeta ? `${baseUrl}/messages?beta=true` : `${baseUrl}/messages`;
58385
+ const url2 = resolveApiEndpoint(baseUrl, "anthropicMessages", config3.baseUrlMode, { anthropicBeta: config3.anthropicBeta });
58276
58386
  const fetchOptions = addProxyToFetchOptions(url2, {
58277
58387
  method: "POST",
58278
58388
  headers,
@@ -58479,6 +58589,7 @@ var init_anthropic = __esm({
58479
58589
  init_usageLogger();
58480
58590
  init_devMode();
58481
58591
  init_version();
58592
+ init_endpointResolver();
58482
58593
  anthropicConfig = null;
58483
58594
  persistentUserId = null;
58484
58595
  }
@@ -180307,6 +180418,10 @@ var init_en = __esm({
180307
180418
  moreBelow: "{count} more below",
180308
180419
  profile: "Profile:",
180309
180420
  baseUrl: "Base URL:",
180421
+ baseUrlMode: "Base URL Mode:",
180422
+ baseUrlModeAuto: "Auto",
180423
+ baseUrlModeBase: "Base URL",
180424
+ baseUrlModeEndpoint: "Full Endpoint",
180310
180425
  apiKey: "API Key:",
180311
180426
  requestMethod: "Request Method:",
180312
180427
  requestUrlLabel: "Request URL: ",
@@ -180730,6 +180845,7 @@ var init_en = __esm({
180730
180845
  toolSearch: "Toggle Tool Search (progressive tool loading). Enabled by default to save context",
180731
180846
  hybridCompress: "Toggle Hybrid Compress mode (AI summary + smart truncation for /compact and auto-compress)",
180732
180847
  team: "Toggle Agent Team mode - orchestrate multiple agents working together in independent Git worktrees",
180848
+ ultraTodo: "Toggle Ultra TODO mode - phase-gated task management with required completion checks",
180733
180849
  branch: "Fork current conversation into a new branch",
180734
180850
  worktree: "Open Git branch management panel for switching, creating and deleting branches",
180735
180851
  diff: "Review file changes from a conversation in IDE diff view",
@@ -180765,6 +180881,14 @@ var init_en = __esm({
180765
180881
  statusEnabled: "Simple mode: Enabled",
180766
180882
  statusDisabled: "Simple mode: Disabled"
180767
180883
  },
180884
+ // Ultra TODO command messages
180885
+ ultraTodo: {
180886
+ toggling: "Toggling Ultra TODO mode",
180887
+ enabled: "Ultra TODO enabled. todo-manage is disabled and todo-ultra is available.",
180888
+ disabled: "Ultra TODO disabled. todo-manage is available again.",
180889
+ failed: "Failed to toggle Ultra TODO: {error}",
180890
+ unknownError: "Unknown error"
180891
+ },
180768
180892
  // Export command messages
180769
180893
  export: {
180770
180894
  exporting: "Exporting conversation...",
@@ -181330,6 +181454,7 @@ var init_en = __esm({
181330
181454
  toolSearchEnabled: "\u267E\uFE0E Tool Search ON - Tools loaded on demand",
181331
181455
  hybridCompressEnabled: "\u21CC Hybrid Compress ON - AI summary + smart truncation",
181332
181456
  teamModeActive: "\u2691 Agent Team Mode Active - Orchestrating multiple agents with independent worktrees",
181457
+ ultraTodoActive: "\u25C8 Ultra TODO Mode Active - phase advancement requires completion checks",
181333
181458
  tokens: " tokens",
181334
181459
  cached: "cached",
181335
181460
  newCache: "new cache"
@@ -182110,6 +182235,10 @@ var init_zh = __esm({
182110
182235
  moreBelow: "\u4E0B\u65B9\u8FD8\u6709 {count} \u9879",
182111
182236
  profile: "\u914D\u7F6E\u6587\u4EF6:",
182112
182237
  baseUrl: "Base URL:",
182238
+ baseUrlMode: "Base URL \u6A21\u5F0F:",
182239
+ baseUrlModeAuto: "\u81EA\u52A8",
182240
+ baseUrlModeBase: "\u57FA\u7840\u5730\u5740",
182241
+ baseUrlModeEndpoint: "\u5B8C\u6574\u7AEF\u70B9",
182113
182242
  apiKey: "API \u5BC6\u94A5:",
182114
182243
  requestMethod: "\u8BF7\u6C42\u65B9\u5F0F:",
182115
182244
  requestUrlLabel: "\u8BF7\u6C42 URL: ",
@@ -182533,6 +182662,7 @@ var init_zh = __esm({
182533
182662
  toolSearch: "\u5207\u6362\u5DE5\u5177\u641C\u7D22\uFF08\u6E10\u8FDB\u5F0F\u5DE5\u5177\u52A0\u8F7D\uFF09\u3002\u9ED8\u8BA4\u542F\u7528\u4EE5\u8282\u7701\u4E0A\u4E0B\u6587",
182534
182663
  hybridCompress: "\u5207\u6362\u6DF7\u5408\u538B\u7F29\u6A21\u5F0F\uFF08AI \u6458\u8981 + \u667A\u80FD\u622A\u65AD\uFF0C\u7528\u4E8E /compact \u548C\u81EA\u52A8\u538B\u7F29\uFF09",
182535
182664
  team: "\u5207\u6362 Agent Team \u6A21\u5F0F - \u534F\u8C03\u591A\u4E2A\u4EE3\u7406\u5728\u72EC\u7ACB Git Worktree \u4E2D\u5E76\u884C\u5DE5\u4F5C",
182665
+ ultraTodo: "\u5207\u6362 Ultra TODO \u6A21\u5F0F - \u6309\u9636\u6BB5\u7EC6\u5206\u4EFB\u52A1\u5E76\u5728\u9636\u6BB5\u63A8\u8FDB\u524D\u5F3A\u5236\u6821\u9A8C",
182536
182666
  branch: "\u5C06\u5F53\u524D\u5BF9\u8BDD\u5206\u53C9\u4E3A\u65B0\u5206\u652F\uFF0C\u53EF\u7528 /resume \u8FD4\u56DE\u539F\u4F1A\u8BDD",
182537
182667
  worktree: "\u6253\u5F00 Git \u5206\u652F\u7BA1\u7406\u9762\u677F\uFF0C\u652F\u6301\u5207\u6362\u3001\u65B0\u5EFA\u548C\u5220\u9664\u5206\u652F",
182538
182668
  diff: "\u5728 IDE \u4E2D\u67E5\u770B\u5BF9\u8BDD\u7684\u6587\u4EF6\u4FEE\u6539 Diff",
@@ -182568,6 +182698,14 @@ var init_zh = __esm({
182568
182698
  statusEnabled: "\u7B80\u6613\u6A21\u5F0F: \u5DF2\u542F\u7528",
182569
182699
  statusDisabled: "\u7B80\u6613\u6A21\u5F0F: \u5DF2\u7981\u7528"
182570
182700
  },
182701
+ // Ultra TODO 命令消息
182702
+ ultraTodo: {
182703
+ toggling: "\u6B63\u5728\u5207\u6362 Ultra TODO \u6A21\u5F0F",
182704
+ enabled: "Ultra TODO \u5DF2\u542F\u7528\u3002todo-manage \u5DF2\u7981\u7528\uFF0Ctodo-ultra \u53EF\u7528\u3002",
182705
+ disabled: "Ultra TODO \u5DF2\u7981\u7528\u3002todo-manage \u5DF2\u91CD\u65B0\u53EF\u7528\u3002",
182706
+ failed: "\u5207\u6362 Ultra TODO \u5931\u8D25\uFF1A{error}",
182707
+ unknownError: "\u672A\u77E5\u9519\u8BEF"
182708
+ },
182571
182709
  // 导出命令消息
182572
182710
  export: {
182573
182711
  exporting: "\u6B63\u5728\u5BFC\u51FA\u5BF9\u8BDD...",
@@ -183132,6 +183270,7 @@ var init_zh = __esm({
183132
183270
  toolSearchEnabled: "\u267E\uFE0E \u5DE5\u5177\u641C\u7D22\u5DF2\u5F00\u542F - \u6309\u9700\u641C\u7D22\u52A0\u8F7D\u5DE5\u5177",
183133
183271
  hybridCompressEnabled: "\u21CC \u6DF7\u5408\u538B\u7F29\u5DF2\u5F00\u542F - AI \u6458\u8981 + \u667A\u80FD\u622A\u65AD",
183134
183272
  teamModeActive: "\u2691 Agent Team \u6A21\u5F0F\u5DF2\u6FC0\u6D3B - \u591A\u4EE3\u7406\u72EC\u7ACB Worktree \u534F\u540C\u5DE5\u4F5C",
183273
+ ultraTodoActive: "\u25C8 Ultra TODO \u6A21\u5F0F\u5DF2\u6FC0\u6D3B - \u9636\u6BB5\u4EFB\u52A1\u63A8\u8FDB\u5C06\u5F3A\u5236\u6821\u9A8C",
183135
183274
  tokens: " \u4E2A\u8BCD\u5143",
183136
183275
  cached: "\u5DF2\u7F13\u5B58",
183137
183276
  newCache: "\u65B0\u7F13\u5B58"
@@ -183912,6 +184051,10 @@ var init_zh_TW = __esm({
183912
184051
  moreBelow: "\u4E0B\u65B9\u9084\u6709 {count} \u9805",
183913
184052
  profile: "\u914D\u7F6E\u6A94\u6848:",
183914
184053
  baseUrl: "Base URL:",
184054
+ baseUrlMode: "Base URL \u6A21\u5F0F:",
184055
+ baseUrlModeAuto: "\u81EA\u52D5",
184056
+ baseUrlModeBase: "\u57FA\u790E\u5730\u5740",
184057
+ baseUrlModeEndpoint: "\u5B8C\u6574\u7AEF\u9EDE",
183915
184058
  apiKey: "API \u91D1\u9470:",
183916
184059
  requestMethod: "\u8ACB\u6C42\u65B9\u5F0F:",
183917
184060
  requestUrlLabel: "\u8ACB\u6C42 URL: ",
@@ -184335,6 +184478,7 @@ var init_zh_TW = __esm({
184335
184478
  toolSearch: "\u5207\u63DB\u5DE5\u5177\u641C\u5C0B\uFF08\u6F38\u9032\u5F0F\u5DE5\u5177\u8F09\u5165\uFF09\u3002\u9810\u8A2D\u555F\u7528\u4EE5\u7BC0\u7701\u4E0A\u4E0B\u6587",
184336
184479
  hybridCompress: "\u5207\u63DB\u6DF7\u5408\u58D3\u7E2E\u6A21\u5F0F\uFF08AI \u6458\u8981 + \u667A\u6167\u622A\u65B7\uFF0C\u7528\u65BC /compact \u548C\u81EA\u52D5\u58D3\u7E2E\uFF09",
184337
184480
  team: "\u5207\u63DB Agent Team \u6A21\u5F0F - \u5354\u8ABF\u591A\u500B\u4EE3\u7406\u5728\u7368\u7ACB Git Worktree \u4E2D\u4E26\u884C\u5DE5\u4F5C",
184481
+ ultraTodo: "\u5207\u63DB Ultra TODO \u6A21\u5F0F - \u6309\u968E\u6BB5\u7D30\u5206\u4EFB\u52D9\u4E26\u5728\u968E\u6BB5\u63A8\u9032\u524D\u5F37\u5236\u6821\u9A57",
184338
184482
  branch: "\u5C07\u76EE\u524D\u5C0D\u8A71\u5206\u53C9\u70BA\u65B0\u5206\u652F\uFF0C\u53EF\u7528 /resume \u8FD4\u56DE\u539F\u6703\u8A71",
184339
184483
  worktree: "\u958B\u555F Git \u5206\u652F\u7BA1\u7406\u9762\u677F\uFF0C\u652F\u63F4\u5207\u63DB\u3001\u65B0\u5EFA\u548C\u522A\u9664\u5206\u652F",
184340
184484
  diff: "\u5728 IDE \u4E2D\u67E5\u770B\u5C0D\u8A71\u7684\u6A94\u6848\u4FEE\u6539 Diff",
@@ -184370,6 +184514,14 @@ var init_zh_TW = __esm({
184370
184514
  statusEnabled: "\u7C21\u6613\u6A21\u5F0F: \u5DF2\u555F\u7528",
184371
184515
  statusDisabled: "\u7C21\u6613\u6A21\u5F0F: \u5DF2\u505C\u7528"
184372
184516
  },
184517
+ // Ultra TODO 命令訊息
184518
+ ultraTodo: {
184519
+ toggling: "\u6B63\u5728\u5207\u63DB Ultra TODO \u6A21\u5F0F",
184520
+ enabled: "Ultra TODO \u5DF2\u555F\u7528\u3002todo-manage \u5DF2\u505C\u7528\uFF0Ctodo-ultra \u53EF\u7528\u3002",
184521
+ disabled: "Ultra TODO \u5DF2\u505C\u7528\u3002todo-manage \u5DF2\u91CD\u65B0\u53EF\u7528\u3002",
184522
+ failed: "\u5207\u63DB Ultra TODO \u5931\u6557\uFF1A{error}",
184523
+ unknownError: "\u672A\u77E5\u932F\u8AA4"
184524
+ },
184373
184525
  // 導出命令消息
184374
184526
  export: {
184375
184527
  exporting: "\u6B63\u5728\u5C0E\u51FA\u5C0D\u8A71...",
@@ -184934,6 +185086,7 @@ var init_zh_TW = __esm({
184934
185086
  toolSearchEnabled: "\u267E\uFE0E \u5DE5\u5177\u641C\u5C0B\u5DF2\u958B\u555F - \u6309\u9700\u641C\u5C0B\u8F09\u5165\u5DE5\u5177",
184935
185087
  hybridCompressEnabled: "\u21CC \u6DF7\u5408\u58D3\u7E2E\u5DF2\u958B\u555F - AI \u6458\u8981 + \u667A\u6167\u622A\u65B7",
184936
185088
  teamModeActive: "\u2691 Agent Team \u6A21\u5F0F\u5DF2\u555F\u7528 - \u591A\u4EE3\u7406\u7368\u7ACB Worktree \u5354\u540C\u5DE5\u4F5C",
185089
+ ultraTodoActive: "\u25C8 Ultra TODO \u6A21\u5F0F\u5DF2\u555F\u7528 - \u968E\u6BB5\u4EFB\u52D9\u63A8\u9032\u5C07\u5F37\u5236\u6821\u9A57",
184937
185090
  tokens: " \u500B\u8A5E\u5143",
184938
185091
  cached: "\u5DF2\u5FEB\u53D6",
184939
185092
  newCache: "\u65B0\u5FEB\u53D6"
@@ -335614,8 +335767,8 @@ ${fromBody}`;
335614
335767
  }
335615
335768
  exports22.endsWithSlashGlobStar = endsWithSlashGlobStar;
335616
335769
  function isAffectDepthOfReadingPattern(pattern) {
335617
- const basename7 = path62.basename(pattern);
335618
- return endsWithSlashGlobStar(pattern) || isStaticPattern(basename7);
335770
+ const basename8 = path62.basename(pattern);
335771
+ return endsWithSlashGlobStar(pattern) || isStaticPattern(basename8);
335619
335772
  }
335620
335773
  exports22.isAffectDepthOfReadingPattern = isAffectDepthOfReadingPattern;
335621
335774
  function expandPatternsWithBraceExpansion(patterns) {
@@ -364508,6 +364661,7 @@ __export(projectSettings_exports, {
364508
364661
  getSubAgentMaxSpawnDepth: () => getSubAgentMaxSpawnDepth,
364509
364662
  getTeamMode: () => getTeamMode,
364510
364663
  getToolSearchEnabled: () => getToolSearchEnabled,
364664
+ getUltraTodoEnabled: () => getUltraTodoEnabled,
364511
364665
  getVulnerabilityHuntingMode: () => getVulnerabilityHuntingMode,
364512
364666
  getYoloMode: () => getYoloMode,
364513
364667
  setAutoFormatEnabled: () => setAutoFormatEnabled,
@@ -364517,6 +364671,7 @@ __export(projectSettings_exports, {
364517
364671
  setSubAgentMaxSpawnDepth: () => setSubAgentMaxSpawnDepth,
364518
364672
  setTeamMode: () => setTeamMode,
364519
364673
  setToolSearchEnabled: () => setToolSearchEnabled,
364674
+ setUltraTodoEnabled: () => setUltraTodoEnabled,
364520
364675
  setVulnerabilityHuntingMode: () => setVulnerabilityHuntingMode,
364521
364676
  setYoloMode: () => setYoloMode
364522
364677
  });
@@ -364538,7 +364693,8 @@ function loadSettings() {
364538
364693
  planMode: pick2("planMode"),
364539
364694
  vulnerabilityHuntingMode: pick2("vulnerabilityHuntingMode"),
364540
364695
  hybridCompressEnabled: pick2("hybridCompressEnabled"),
364541
- teamMode: pick2("teamMode")
364696
+ teamMode: pick2("teamMode"),
364697
+ ultraTodoEnabled: pick2("ultraTodoEnabled")
364542
364698
  };
364543
364699
  }
364544
364700
  function setField(key, value, scope = "project") {
@@ -364618,6 +364774,13 @@ function getTeamMode() {
364618
364774
  function setTeamMode(enabled) {
364619
364775
  setField("teamMode", enabled);
364620
364776
  }
364777
+ function getUltraTodoEnabled() {
364778
+ const settings = loadSettings();
364779
+ return settings.ultraTodoEnabled ?? false;
364780
+ }
364781
+ function setUltraTodoEnabled(enabled) {
364782
+ setField("ultraTodoEnabled", enabled);
364783
+ }
364621
364784
  var DEFAULT_SUB_AGENT_MAX_SPAWN_DEPTH;
364622
364785
  var init_projectSettings = __esm({
364623
364786
  "dist/utils/config/projectSettings.js"() {
@@ -366828,6 +366991,17 @@ ${exportList}`);
366828
366991
  */
366829
366992
  async editFile(filePath, operations, contextLines = 8) {
366830
366993
  if (Array.isArray(filePath)) {
366994
+ if (filePath.length > 0 && typeof filePath[0] === "string") {
366995
+ if (!operations || operations.length === 0) {
366996
+ throw new Error("operations array is required when filePath is an array of path strings");
366997
+ }
366998
+ const pathList = filePath;
366999
+ const configs = pathList.map((file2) => ({
367000
+ path: file2,
367001
+ operations
367002
+ }));
367003
+ return await this.editFile(configs, void 0, contextLines);
367004
+ }
366831
367005
  return await executeBatchOperation(filePath, (fileItem) => {
366832
367006
  const cfg = fileItem;
366833
367007
  return { path: cfg.path, operations: cfg.operations };
@@ -367041,7 +367215,7 @@ ${exportList}`);
367041
367215
  },
367042
367216
  {
367043
367217
  name: "filesystem-edit",
367044
- description: 'OPTIONAL strict edit tool: Hash-anchored editing using content hashes from filesystem-read. Line format: "lineNum:hash\u2192content" (e.g. "42:a3\u2192code"). Use anchors "lineNum:hash" to reference lines \u2014 no text reproduction needed. **OPERATIONS**: (1) replace \u2014 replaces startAnchor..endAnchor with content; (2) insert_after \u2014 inserts content after startAnchor; (3) delete \u2014 removes startAnchor..endAnchor, set content to empty string "". **WORKFLOW**: filesystem-read \u2192 note anchors \u2192 call this tool with operations. **ANCHOR FORMAT**: "lineNum:hash" e.g. "10:a3". endAnchor is always required (inclusive range). Single-line edits: set endAnchor to the same anchor as startAnchor. **SUPPORTS BATCH**: Pass array of {path, operations} for multi-file edits.',
367218
+ description: 'OPTIONAL strict edit tool: Hash-anchored editing using content hashes from filesystem-read. Line format: "lineNum:hash\u2192content" (e.g. "42:a3\u2192code"). Use anchors "lineNum:hash" to reference lines \u2014 no text reproduction needed. **OPERATIONS**: (1) replace \u2014 replaces startAnchor..endAnchor with content; (2) insert_after \u2014 inserts content after startAnchor; (3) delete \u2014 removes startAnchor..endAnchor, set content to empty string "". **WORKFLOW**: filesystem-read \u2192 note anchors \u2192 call this tool with operations. **ANCHOR FORMAT**: "lineNum:hash" e.g. "10:a3". endAnchor is always required (inclusive range). Single-line edits: set endAnchor to the same anchor as startAnchor. **SUPPORTS BATCH**: Pass array of {path, operations}, or path string[] with shared top-level operations (same as filesystem-replaceedit batch).',
367045
367219
  inputSchema: {
367046
367220
  type: "object",
367047
367221
  properties: {
@@ -367051,6 +367225,14 @@ ${exportList}`);
367051
367225
  type: "string",
367052
367226
  description: "Path to a single file to edit"
367053
367227
  },
367228
+ {
367229
+ type: "array",
367230
+ items: {
367231
+ type: "string",
367232
+ description: "File path (use with top-level operations for unified batch edit)"
367233
+ },
367234
+ description: "Array of file paths sharing the same top-level operations"
367235
+ },
367054
367236
  {
367055
367237
  type: "array",
367056
367238
  items: {
@@ -369842,8 +370024,9 @@ __export(aceCodeSearch_exports, {
369842
370024
  import { promises as fs26, createReadStream as createReadStream2 } from "fs";
369843
370025
  import * as path26 from "path";
369844
370026
  import { spawn as spawn4 } from "child_process";
370027
+ import { createRequire } from "module";
369845
370028
  import { createInterface as createInterface2 } from "readline";
369846
- var ACECodeSearchService, mcpTools3, aceCodeSearchService;
370029
+ var nodeRequire, ACECodeSearchService, mcpTools3, aceCodeSearchService;
369847
370030
  var init_aceCodeSearch = __esm({
369848
370031
  "dist/mcp/aceCodeSearch.js"() {
369849
370032
  "use strict";
@@ -369860,6 +370043,7 @@ var init_aceCodeSearch = __esm({
369860
370043
  init_pathRemote_utils();
369861
370044
  init_remote_utils();
369862
370045
  init_constants_utils();
370046
+ nodeRequire = createRequire(import.meta.url);
369863
370047
  ACECodeSearchService = class _ACECodeSearchService {
369864
370048
  constructor(basePath = process.cwd(), options3) {
369865
370049
  Object.defineProperty(this, "basePath", {
@@ -369940,6 +370124,12 @@ var init_aceCodeSearch = __esm({
369940
370124
  writable: true,
369941
370125
  value: /* @__PURE__ */ new Map()
369942
370126
  });
370127
+ Object.defineProperty(this, "bundledRipgrepPath", {
370128
+ enumerable: true,
370129
+ configurable: true,
370130
+ writable: true,
370131
+ value: void 0
370132
+ });
369943
370133
  Object.defineProperty(this, "isGitRepoCache", {
369944
370134
  enumerable: true,
369945
370135
  configurable: true,
@@ -370137,6 +370327,7 @@ var init_aceCodeSearch = __esm({
370137
370327
  }
370138
370328
  if (!(options3 == null ? void 0 : options3.preserveCommandCache)) {
370139
370329
  this.commandAvailabilityCache.clear();
370330
+ this.bundledRipgrepPath = void 0;
370140
370331
  this.isGitRepoCache = null;
370141
370332
  }
370142
370333
  }
@@ -370239,6 +370430,26 @@ var init_aceCodeSearch = __esm({
370239
370430
  this.commandAvailabilityCache.set(command, available);
370240
370431
  return available;
370241
370432
  }
370433
+ /**
370434
+ * Get the ripgrep binary bundled by @vscode/ripgrep.
370435
+ * Keep this dependency loaded at runtime so local search does not depend on a
370436
+ * system-level rg installation.
370437
+ */
370438
+ getBundledRipgrepPath() {
370439
+ const cached2 = this.bundledRipgrepPath;
370440
+ if (cached2 !== void 0) {
370441
+ return cached2;
370442
+ }
370443
+ try {
370444
+ const ripgrep = nodeRequire("@vscode/ripgrep");
370445
+ const rgPath = typeof ripgrep.rgPath === "string" ? ripgrep.rgPath : "";
370446
+ this.bundledRipgrepPath = rgPath.length > 0 ? rgPath : null;
370447
+ } catch (error40) {
370448
+ logger.debug("Bundled ripgrep unavailable, falling back to system search tools", error40);
370449
+ this.bundledRipgrepPath = null;
370450
+ }
370451
+ return this.bundledRipgrepPath;
370452
+ }
370242
370453
  /**
370243
370454
  * Check if a directory is a Git repository (with caching)
370244
370455
  */
@@ -370691,17 +370902,22 @@ var init_aceCodeSearch = __esm({
370691
370902
  });
370692
370903
  }
370693
370904
  /**
370694
- * Strategy 2: Use system grep (or ripgrep if available) for fast searching
370695
- * Enhanced with timeout protection to prevent hanging on Windows
370905
+ * Strategy 2: Use ripgrep/grep for fast searching.
370906
+ * Enhanced with timeout protection to prevent hanging on Windows.
370696
370907
  */
370697
- async systemGrepSearch(pattern, fileGlob, maxResults = 100, grepCommand = "grep") {
370908
+ async systemGrepSearch(pattern, fileGlob, maxResults = 100, grepCommand = "grep", isRegex = true) {
370698
370909
  this.markActivity();
370699
- const isRipgrep = grepCommand === "rg";
370910
+ const commandName = path26.basename(grepCommand).toLowerCase();
370911
+ const isRipgrep = commandName === "rg" || commandName === "rg.exe";
370912
+ const displayCommand = isRipgrep ? "rg" : commandName || grepCommand;
370700
370913
  const timeoutMs = 15e3;
370701
370914
  return new Promise((resolve13, reject2) => {
370702
370915
  var _a20;
370703
- const args2 = isRipgrep ? ["-n", "-i", "--no-heading"] : ["-r", "-n", "-H", "-E", "-i"];
370916
+ const args2 = isRipgrep ? ["-n", "-i", "--no-heading", "--color=never", "--hidden"] : ["-r", "-n", "-H", "-i"];
370704
370917
  if (isRipgrep) {
370918
+ if (!isRegex) {
370919
+ args2.push("-F");
370920
+ }
370705
370921
  GREP_EXCLUDE_DIRS.forEach((dir) => args2.push("--glob", `!${dir}/`));
370706
370922
  if (fileGlob) {
370707
370923
  const normalizedGlob = fileGlob.replace(/\\/g, "/");
@@ -370709,6 +370925,7 @@ var init_aceCodeSearch = __esm({
370709
370925
  expandedGlobs.forEach((glob) => args2.push("--glob", glob));
370710
370926
  }
370711
370927
  } else {
370928
+ args2.push(isRegex ? "-E" : "-F");
370712
370929
  GREP_EXCLUDE_DIRS.forEach((dir) => args2.push(`--exclude-dir=${dir}`));
370713
370930
  if (fileGlob) {
370714
370931
  const normalizedGlob = fileGlob.replace(/\\/g, "/");
@@ -370745,8 +370962,8 @@ var init_aceCodeSearch = __esm({
370745
370962
  };
370746
370963
  const timeoutId = setTimeout(() => {
370747
370964
  finalize(() => {
370748
- logger.warn(`${grepCommand} timed out after ${timeoutMs}ms, killing process`);
370749
- reject2(new Error(`${grepCommand} timed out after ${timeoutMs}ms`));
370965
+ logger.warn(`${displayCommand} timed out after ${timeoutMs}ms, killing process`);
370966
+ reject2(new Error(`${displayCommand} timed out after ${timeoutMs}ms`));
370750
370967
  }, true);
370751
370968
  }, timeoutMs);
370752
370969
  (_a20 = timeoutId.unref) == null ? void 0 : _a20.call(timeoutId);
@@ -370759,7 +370976,7 @@ var init_aceCodeSearch = __esm({
370759
370976
  });
370760
370977
  child.once("error", (err) => {
370761
370978
  finalize(() => {
370762
- reject2(new Error(`Failed to start ${grepCommand}: ${err.message}`));
370979
+ reject2(new Error(`Failed to start ${displayCommand}: ${err.message}`));
370763
370980
  });
370764
370981
  });
370765
370982
  child.once("close", (code) => {
@@ -370772,7 +370989,7 @@ var init_aceCodeSearch = __esm({
370772
370989
  } else if (code === 1) {
370773
370990
  resolve13([]);
370774
370991
  } else if (stderrData) {
370775
- reject2(new Error(`${grepCommand} exited with code ${code}: ${stderrData}`));
370992
+ reject2(new Error(`${displayCommand} exited with code ${code}: ${stderrData}`));
370776
370993
  } else {
370777
370994
  resolve13([]);
370778
370995
  }
@@ -370992,19 +371209,37 @@ var init_aceCodeSearch = __esm({
370992
371209
  * Internal text search implementation (separated for timeout wrapping)
370993
371210
  *
370994
371211
  * Strategy priority:
370995
- * 1. git grep (fastest, works in git repos)
370996
- * 2. system grep (reliable on all platforms, especially Windows)
370997
- * 3. ripgrep (fast but can hang on Windows)
370998
- * 4. JavaScript fallback (always works)
371212
+ * 1. bundled ripgrep from @vscode/ripgrep (consistent local rg search)
371213
+ * 2. system ripgrep (if bundled rg is unavailable)
371214
+ * 3. git grep (fast fallback in Git repositories)
371215
+ * 4. system grep
371216
+ * 5. JavaScript fallback (always works)
370999
371217
  */
371000
371218
  async executeTextSearch(pattern, fileGlob, isRegex = true, maxResults = 100) {
371001
371219
  this.markActivity();
371220
+ const bundledRipgrepPath = this.getBundledRipgrepPath();
371221
+ if (bundledRipgrepPath) {
371222
+ try {
371223
+ const results2 = await this.systemGrepSearch(pattern, fileGlob, maxResults, bundledRipgrepPath, isRegex);
371224
+ return await this.sortResultsByRecency(results2);
371225
+ } catch (error40) {
371226
+ logger.info("Bundled ripgrep failed, trying next strategy");
371227
+ }
371228
+ }
371002
371229
  const [isGitRepo3, gitAvailable, rgAvailable, grepAvailable] = await Promise.all([
371003
371230
  this.isGitRepository(),
371004
371231
  this.isCommandAvailableCached("git"),
371005
371232
  this.isCommandAvailableCached("rg"),
371006
371233
  this.isCommandAvailableCached("grep")
371007
371234
  ]);
371235
+ if (rgAvailable) {
371236
+ try {
371237
+ const results2 = await this.systemGrepSearch(pattern, fileGlob, maxResults, "rg", isRegex);
371238
+ return await this.sortResultsByRecency(results2);
371239
+ } catch (error40) {
371240
+ logger.info("System ripgrep failed, trying next strategy");
371241
+ }
371242
+ }
371008
371243
  if (isGitRepo3 && gitAvailable) {
371009
371244
  try {
371010
371245
  const results2 = await this.gitGrepSearch(pattern, fileGlob, maxResults, isRegex);
@@ -371014,17 +371249,9 @@ var init_aceCodeSearch = __esm({
371014
371249
  } catch (error40) {
371015
371250
  }
371016
371251
  }
371017
- if (rgAvailable) {
371018
- try {
371019
- const results2 = await this.systemGrepSearch(pattern, fileGlob, maxResults, "rg");
371020
- return await this.sortResultsByRecency(results2);
371021
- } catch (error40) {
371022
- logger.info("Ripgrep failed, trying next strategy");
371023
- }
371024
- }
371025
371252
  if (grepAvailable) {
371026
371253
  try {
371027
- const results2 = await this.systemGrepSearch(pattern, fileGlob, maxResults, "grep");
371254
+ const results2 = await this.systemGrepSearch(pattern, fileGlob, maxResults, "grep", isRegex);
371028
371255
  return await this.sortResultsByRecency(results2);
371029
371256
  } catch (error40) {
371030
371257
  logger.info("System grep failed, falling back to JavaScript search");
@@ -445252,7 +445479,10 @@ var init_todo = __esm({
445252
445479
  sessionId,
445253
445480
  todos,
445254
445481
  createdAt: (existingList == null ? void 0 : existingList.createdAt) ?? now,
445255
- updatedAt: now
445482
+ updatedAt: now,
445483
+ ultraMode: existingList == null ? void 0 : existingList.ultraMode,
445484
+ phases: existingList == null ? void 0 : existingList.phases,
445485
+ currentPhaseId: existingList == null ? void 0 : existingList.currentPhaseId
445256
445486
  };
445257
445487
  await fs35.writeFile(todoPath, JSON.stringify(todoList, null, 2));
445258
445488
  todoEvents.emitTodoUpdate(sessionId, todos);
@@ -445391,6 +445621,271 @@ var init_todo = __esm({
445391
445621
  async createEmptyTodo(sessionId) {
445392
445622
  return this.saveTodoList(sessionId, [], null);
445393
445623
  }
445624
+ createId(prefix) {
445625
+ return `${prefix}-${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
445626
+ }
445627
+ createTextResult(value) {
445628
+ return {
445629
+ content: [
445630
+ {
445631
+ type: "text",
445632
+ text: typeof value === "string" ? value : JSON.stringify(value, null, 2)
445633
+ }
445634
+ ]
445635
+ };
445636
+ }
445637
+ createErrorResult(text2) {
445638
+ return {
445639
+ content: [
445640
+ {
445641
+ type: "text",
445642
+ text: text2
445643
+ }
445644
+ ],
445645
+ isError: true
445646
+ };
445647
+ }
445648
+ async getOrCreateTodoList(sessionId, ultraMode = false) {
445649
+ const existingList = await this.getTodoList(sessionId);
445650
+ if (!existingList) {
445651
+ const now = (/* @__PURE__ */ new Date()).toISOString();
445652
+ return this.saveTodoList(sessionId, [], {
445653
+ sessionId,
445654
+ todos: [],
445655
+ createdAt: now,
445656
+ updatedAt: now,
445657
+ ultraMode,
445658
+ phases: ultraMode ? [] : void 0
445659
+ });
445660
+ }
445661
+ if (ultraMode && !existingList.ultraMode) {
445662
+ return this.saveTodoList(sessionId, existingList.todos, {
445663
+ ...existingList,
445664
+ ultraMode: true,
445665
+ phases: existingList.phases ?? []
445666
+ });
445667
+ }
445668
+ return existingList;
445669
+ }
445670
+ saveUltraTodoList(sessionId, todoList) {
445671
+ return this.saveTodoList(sessionId, todoList.todos, {
445672
+ ...todoList,
445673
+ ultraMode: true,
445674
+ phases: todoList.phases ?? []
445675
+ });
445676
+ }
445677
+ getPhaseTodos(todoList, phaseId) {
445678
+ return todoList.todos.filter((todo) => todo.phaseId === phaseId);
445679
+ }
445680
+ getIncompletePhaseTodos(todoList, phaseId) {
445681
+ return this.getPhaseTodos(todoList, phaseId).filter((todo) => todo.status !== "completed");
445682
+ }
445683
+ findPhase(todoList, phaseId) {
445684
+ var _a20;
445685
+ return (_a20 = todoList.phases) == null ? void 0 : _a20.find((phase) => phase.id === phaseId);
445686
+ }
445687
+ normalizeStringArray(value) {
445688
+ if (Array.isArray(value) && value.every((item) => typeof item === "string")) {
445689
+ return value.map((item) => item.trim()).filter(Boolean);
445690
+ }
445691
+ if (typeof value === "string") {
445692
+ try {
445693
+ const parsed = JSON.parse(value);
445694
+ if (Array.isArray(parsed) && parsed.every((item) => typeof item === "string")) {
445695
+ return parsed.map((item) => item.trim()).filter(Boolean);
445696
+ }
445697
+ } catch {
445698
+ return [value.trim()].filter(Boolean);
445699
+ }
445700
+ }
445701
+ return null;
445702
+ }
445703
+ buildIncompletePhaseMessage(phase, incompleteTodos) {
445704
+ const items = incompleteTodos.map((todo) => `- ${todo.id} [${todo.status}]: ${todo.content}`).join("\n");
445705
+ return `Blocked: phase "${phase.title}" cannot advance because ${incompleteTodos.length} item(s) are not completed. Complete or update them first.
445706
+ ${items}`;
445707
+ }
445708
+ async executeUltraTodoTool(sessionId, args2) {
445709
+ const rawAction = args2["action"];
445710
+ const allowedActions = [
445711
+ "get",
445712
+ "add_phase",
445713
+ "add_item",
445714
+ "update_item",
445715
+ "complete_phase",
445716
+ "advance_phase",
445717
+ "delete_item"
445718
+ ];
445719
+ if (typeof rawAction !== "string" || !allowedActions.includes(rawAction)) {
445720
+ return this.createErrorResult('Error: "action" must be one of: get, add_phase, add_item, update_item, complete_phase, advance_phase, delete_item');
445721
+ }
445722
+ try {
445723
+ const action = rawAction;
445724
+ const todoList = await this.getOrCreateTodoList(sessionId, true);
445725
+ todoList.phases = todoList.phases ?? [];
445726
+ switch (action) {
445727
+ case "get": {
445728
+ if (todoList.todos.length > 0) {
445729
+ todoEvents.emitTodoUpdate(sessionId, todoList.todos);
445730
+ }
445731
+ return this.createTextResult(todoList);
445732
+ }
445733
+ case "add_phase": {
445734
+ const title = typeof args2["title"] === "string" ? args2["title"].trim() : "";
445735
+ const items = this.normalizeStringArray(args2["items"]);
445736
+ if (!title) {
445737
+ return this.createErrorResult('Error: action=add_phase requires "title"');
445738
+ }
445739
+ if (!items || items.length === 0) {
445740
+ return this.createErrorResult('Error: action=add_phase requires non-empty "items" so every phase is decomposed into concrete TODO items');
445741
+ }
445742
+ const now = (/* @__PURE__ */ new Date()).toISOString();
445743
+ const phaseId = this.createId("phase");
445744
+ const shouldBecomeCurrent = !todoList.currentPhaseId;
445745
+ const phase = {
445746
+ id: phaseId,
445747
+ title,
445748
+ status: shouldBecomeCurrent ? "inProgress" : "pending",
445749
+ createdAt: now,
445750
+ updatedAt: now
445751
+ };
445752
+ const phaseTodos = items.map((content) => ({
445753
+ id: this.createId("todo"),
445754
+ content,
445755
+ status: "pending",
445756
+ createdAt: now,
445757
+ updatedAt: now,
445758
+ phaseId
445759
+ }));
445760
+ todoList.phases.push(phase);
445761
+ todoList.todos = [...todoList.todos, ...phaseTodos];
445762
+ if (shouldBecomeCurrent) {
445763
+ todoList.currentPhaseId = phaseId;
445764
+ }
445765
+ const result2 = await this.saveUltraTodoList(sessionId, todoList);
445766
+ return this.createTextResult(result2);
445767
+ }
445768
+ case "add_item": {
445769
+ const content = typeof args2["content"] === "string" ? args2["content"].trim() : "";
445770
+ const phaseId = typeof args2["phaseId"] === "string" && args2["phaseId"].trim() ? args2["phaseId"].trim() : todoList.currentPhaseId;
445771
+ const parentId = typeof args2["parentId"] === "string" && args2["parentId"].trim() ? args2["parentId"].trim() : void 0;
445772
+ if (!content) {
445773
+ return this.createErrorResult('Error: action=add_item requires "content"');
445774
+ }
445775
+ if (!phaseId || !this.findPhase(todoList, phaseId)) {
445776
+ return this.createErrorResult('Error: action=add_item requires a valid "phaseId" or an active current phase');
445777
+ }
445778
+ const validatedParentId = parentId && todoList.todos.some((todo) => todo.id === parentId) ? parentId : void 0;
445779
+ const now = (/* @__PURE__ */ new Date()).toISOString();
445780
+ todoList.todos.push({
445781
+ id: this.createId("todo"),
445782
+ content,
445783
+ status: "pending",
445784
+ createdAt: now,
445785
+ updatedAt: now,
445786
+ parentId: validatedParentId,
445787
+ phaseId
445788
+ });
445789
+ const result2 = await this.saveUltraTodoList(sessionId, todoList);
445790
+ return this.createTextResult(result2);
445791
+ }
445792
+ case "update_item": {
445793
+ const todoId = args2["todoId"];
445794
+ const status = args2["status"];
445795
+ const content = args2["content"];
445796
+ if (todoId === void 0 || todoId === null) {
445797
+ return this.createErrorResult('Error: action=update_item requires "todoId"');
445798
+ }
445799
+ if (status !== void 0 && !["pending", "inProgress", "completed"].includes(status)) {
445800
+ return this.createErrorResult('Error: "status" must be one of: pending, inProgress, completed');
445801
+ }
445802
+ const ids = Array.isArray(todoId) ? todoId : [todoId];
445803
+ const idSet = new Set(ids);
445804
+ const updatedAt = (/* @__PURE__ */ new Date()).toISOString();
445805
+ let anyFound = false;
445806
+ todoList.todos = todoList.todos.map((todo) => {
445807
+ if (!idSet.has(todo.id)) {
445808
+ return todo;
445809
+ }
445810
+ anyFound = true;
445811
+ return {
445812
+ ...todo,
445813
+ ...status ? { status } : {},
445814
+ ...typeof content === "string" ? { content } : {},
445815
+ updatedAt
445816
+ };
445817
+ });
445818
+ if (!anyFound) {
445819
+ return this.createTextResult("TODO item not found");
445820
+ }
445821
+ const result2 = await this.saveUltraTodoList(sessionId, todoList);
445822
+ return this.createTextResult(result2);
445823
+ }
445824
+ case "complete_phase": {
445825
+ const phaseId = typeof args2["phaseId"] === "string" && args2["phaseId"].trim() ? args2["phaseId"].trim() : todoList.currentPhaseId;
445826
+ if (!phaseId) {
445827
+ return this.createErrorResult('Error: action=complete_phase requires "phaseId" or an active current phase');
445828
+ }
445829
+ const phase = this.findPhase(todoList, phaseId);
445830
+ if (!phase) {
445831
+ return this.createErrorResult(`Error: phase not found: ${phaseId}`);
445832
+ }
445833
+ const incompleteTodos = this.getIncompletePhaseTodos(todoList, phaseId);
445834
+ if (incompleteTodos.length > 0) {
445835
+ return this.createErrorResult(this.buildIncompletePhaseMessage(phase, incompleteTodos));
445836
+ }
445837
+ phase.status = "completed";
445838
+ phase.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
445839
+ const result2 = await this.saveUltraTodoList(sessionId, todoList);
445840
+ return this.createTextResult(result2);
445841
+ }
445842
+ case "advance_phase": {
445843
+ const currentPhaseId = todoList.currentPhaseId;
445844
+ if (currentPhaseId) {
445845
+ const currentPhase = this.findPhase(todoList, currentPhaseId);
445846
+ if (!currentPhase) {
445847
+ return this.createErrorResult(`Error: current phase not found: ${currentPhaseId}`);
445848
+ }
445849
+ const incompleteTodos = this.getIncompletePhaseTodos(todoList, currentPhaseId);
445850
+ if (incompleteTodos.length > 0) {
445851
+ return this.createErrorResult(this.buildIncompletePhaseMessage(currentPhase, incompleteTodos));
445852
+ }
445853
+ currentPhase.status = "completed";
445854
+ currentPhase.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
445855
+ }
445856
+ const requestedNextPhaseId = typeof args2["nextPhaseId"] === "string" && args2["nextPhaseId"].trim() ? args2["nextPhaseId"].trim() : void 0;
445857
+ const nextPhase = requestedNextPhaseId ? this.findPhase(todoList, requestedNextPhaseId) : todoList.phases.find((phase) => phase.status !== "completed");
445858
+ if (requestedNextPhaseId && !nextPhase) {
445859
+ return this.createErrorResult(`Error: next phase not found: ${requestedNextPhaseId}`);
445860
+ }
445861
+ if (nextPhase) {
445862
+ nextPhase.status = "inProgress";
445863
+ nextPhase.updatedAt = (/* @__PURE__ */ new Date()).toISOString();
445864
+ todoList.currentPhaseId = nextPhase.id;
445865
+ } else {
445866
+ todoList.currentPhaseId = void 0;
445867
+ }
445868
+ const result2 = await this.saveUltraTodoList(sessionId, todoList);
445869
+ return this.createTextResult(result2);
445870
+ }
445871
+ case "delete_item": {
445872
+ const todoId = args2["todoId"];
445873
+ if (todoId === void 0 || todoId === null) {
445874
+ return this.createErrorResult('Error: action=delete_item requires "todoId"');
445875
+ }
445876
+ const ids = Array.isArray(todoId) ? todoId : [todoId];
445877
+ const idSet = new Set(ids);
445878
+ todoList.todos = todoList.todos.filter((todo) => !idSet.has(todo.id) && !idSet.has(todo.parentId ?? ""));
445879
+ const result2 = await this.saveUltraTodoList(sessionId, todoList);
445880
+ return this.createTextResult(result2);
445881
+ }
445882
+ default:
445883
+ return this.createErrorResult(`Unknown action: ${String(action)}`);
445884
+ }
445885
+ } catch (error40) {
445886
+ return this.createErrorResult(`Error executing ultra-todo (${rawAction}): ${error40 instanceof Error ? error40.message : String(error40)}`);
445887
+ }
445888
+ }
445394
445889
  /**
445395
445890
  * 复制 TODO 列表到新会话(用于会话压缩时继承 TODO)
445396
445891
  * @param fromSessionId - 源会话ID
@@ -445409,7 +445904,12 @@ var init_todo = __esm({
445409
445904
  // 更新时间戳
445410
445905
  updatedAt: now
445411
445906
  }));
445412
- return this.saveTodoList(toSessionId, copiedTodos, null);
445907
+ return this.saveTodoList(toSessionId, copiedTodos, {
445908
+ ...sourceTodoList,
445909
+ sessionId: toSessionId,
445910
+ createdAt: now,
445911
+ updatedAt: now
445912
+ });
445413
445913
  }
445414
445914
  /**
445415
445915
  * 删除整个会话的 TODO 列表
@@ -445443,7 +445943,89 @@ var init_todo = __esm({
445443
445943
  /**
445444
445944
  * 获取所有工具定义(单一 todo-manage,通过 action 区分 get / add / update / delete)
445445
445945
  */
445446
- getTools() {
445946
+ getTools(ultraMode = false) {
445947
+ if (ultraMode) {
445948
+ return [
445949
+ {
445950
+ name: "todo-ultra",
445951
+ description: `Ultra TODO session planner: use required field "action" \u2014 one of get | add_phase | add_item | update_item | complete_phase | advance_phase | delete_item.
445952
+
445953
+ Ultra TODO is stricter than todo-manage. Every requirement phase MUST be decomposed into concrete TODO items. Before advancing to the next phase, the current phase is automatically checked; if any item is not completed, the tool blocks advancement and returns the incomplete items.
445954
+
445955
+ ACTIONS:
445956
+ - get: Current ultra TODO state with phases, currentPhaseId, and items.
445957
+ - add_phase: Create a phase and its decomposed TODO items. Required: "title" and non-empty "items" (string[] or JSON string array).
445958
+ - add_item: Add one item to a phase. Required: "content" and a valid "phaseId" unless there is an active current phase. Optional "parentId".
445959
+ - update_item: Update item status/content. Required "todoId" (string or string[]). Optional "status" (pending|inProgress|completed) and/or "content".
445960
+ - complete_phase: Mark a phase completed only if all its items are completed. Optional "phaseId"; defaults to current phase.
445961
+ - advance_phase: Move from current phase to the next phase. Blocks if current phase has incomplete items. Optional "nextPhaseId".
445962
+ - delete_item: Delete item(s), cascading direct children. Required "todoId" (string or string[]).
445963
+
445964
+ IMPORTANT:
445965
+ - Do not start a new phase until advance_phase succeeds.
445966
+ - If advance_phase or complete_phase is blocked, update every listed incomplete item before trying again.
445967
+ - In Ultra TODO mode, the legacy todo-manage tool is not available.`,
445968
+ inputSchema: {
445969
+ type: "object",
445970
+ properties: {
445971
+ action: {
445972
+ type: "string",
445973
+ enum: [
445974
+ "get",
445975
+ "add_phase",
445976
+ "add_item",
445977
+ "update_item",
445978
+ "complete_phase",
445979
+ "advance_phase",
445980
+ "delete_item"
445981
+ ],
445982
+ description: "Which Ultra TODO operation to run."
445983
+ },
445984
+ title: {
445985
+ type: "string",
445986
+ description: "For action=add_phase: phase title."
445987
+ },
445988
+ items: {
445989
+ oneOf: [
445990
+ { type: "array", items: { type: "string" } },
445991
+ { type: "string" }
445992
+ ],
445993
+ description: "For action=add_phase: required decomposed items as string[] or JSON string array."
445994
+ },
445995
+ phaseId: {
445996
+ type: "string",
445997
+ description: "For add_item/complete_phase: target phase id. Defaults to current phase where applicable."
445998
+ },
445999
+ nextPhaseId: {
446000
+ type: "string",
446001
+ description: "For action=advance_phase: optional explicit next phase id."
446002
+ },
446003
+ content: {
446004
+ type: "string",
446005
+ description: "For add_item: item content. For update_item: optional updated content."
446006
+ },
446007
+ parentId: {
446008
+ type: "string",
446009
+ description: "For action=add_item: optional parent TODO id."
446010
+ },
446011
+ todoId: {
446012
+ oneOf: [
446013
+ { type: "string" },
446014
+ { type: "array", items: { type: "string" } }
446015
+ ],
446016
+ description: "For update_item/delete_item: item id(s) from action=get."
446017
+ },
446018
+ status: {
446019
+ type: "string",
446020
+ enum: ["pending", "inProgress", "completed"],
446021
+ description: "For action=update_item only."
446022
+ }
446023
+ },
446024
+ required: ["action"]
446025
+ }
446026
+ }
446027
+ ];
446028
+ }
445447
446029
  return [
445448
446030
  {
445449
446031
  name: "todo-manage",
@@ -445534,6 +446116,9 @@ EXAMPLES:
445534
446116
  isError: true
445535
446117
  };
445536
446118
  }
446119
+ if (toolName === "ultra" || toolName === "ultra-todo") {
446120
+ return this.executeUltraTodoTool(sessionId, args2);
446121
+ }
445537
446122
  if (toolName !== "manage") {
445538
446123
  return {
445539
446124
  content: [
@@ -453420,6 +454005,14 @@ var init_messageFormatter = __esm({
453420
454005
  });
453421
454006
 
453422
454007
  // dist/utils/config/toolDisplayConfig.js
454008
+ var toolDisplayConfig_exports = {};
454009
+ __export(toolDisplayConfig_exports, {
454010
+ TWO_STEP_DISPLAY_TOOL_NAMES: () => TWO_STEP_DISPLAY_TOOL_NAMES,
454011
+ extractFilesystemEditDiffDataForPersistence: () => extractFilesystemEditDiffDataForPersistence,
454012
+ extractFilesystemEditDiffFromRawResult: () => extractFilesystemEditDiffFromRawResult,
454013
+ isToolNeedTwoStepDisplay: () => isToolNeedTwoStepDisplay,
454014
+ isToolOnlyShowCompleted: () => isToolOnlyShowCompleted
454015
+ });
453423
454016
  function isToolNeedTwoStepDisplay(toolName) {
453424
454017
  if (TWO_STEP_TOOLS.has(toolName)) {
453425
454018
  return true;
@@ -453429,6 +454022,35 @@ function isToolNeedTwoStepDisplay(toolName) {
453429
454022
  }
453430
454023
  return false;
453431
454024
  }
454025
+ function isToolOnlyShowCompleted(toolName) {
454026
+ return !isToolNeedTwoStepDisplay(toolName);
454027
+ }
454028
+ function extractFilesystemEditDiffFromRawResult(toolName, toolResult) {
454029
+ if (toolName !== "filesystem-edit" && toolName !== "filesystem-replaceedit") {
454030
+ return void 0;
454031
+ }
454032
+ if (!toolResult || typeof toolResult !== "object") {
454033
+ return void 0;
454034
+ }
454035
+ const result2 = toolResult;
454036
+ if (result2["oldContent"] && result2["newContent"]) {
454037
+ return {
454038
+ oldContent: result2["oldContent"],
454039
+ newContent: result2["newContent"],
454040
+ filename: result2["filePath"] || result2["path"] || result2["filename"],
454041
+ completeOldContent: result2["completeOldContent"],
454042
+ completeNewContent: result2["completeNewContent"],
454043
+ contextStartLine: result2["contextStartLine"]
454044
+ };
454045
+ }
454046
+ if (Array.isArray(result2["results"]) && result2["results"].length > 0) {
454047
+ return {
454048
+ batchResults: result2["results"],
454049
+ isBatch: true
454050
+ };
454051
+ }
454052
+ return void 0;
454053
+ }
453432
454054
  function extractFilesystemEditDiffDataForPersistence(toolName, content) {
453433
454055
  if (toolName !== "filesystem-edit" && toolName !== "filesystem-replaceedit" || content.startsWith("Error:")) {
453434
454056
  return void 0;
@@ -464325,6 +464947,7 @@ var init_useSchedulerExecutionState = __esm({
464325
464947
  var tokenLimiter_exports = {};
464326
464948
  __export(tokenLimiter_exports, {
464327
464949
  getToolResultTokenLimit: () => getToolResultTokenLimit,
464950
+ stripFilesystemDiffPayload: () => stripFilesystemDiffPayload,
464328
464951
  validateTokenLimit: () => validateTokenLimit,
464329
464952
  wrapToolResultWithTokenLimit: () => wrapToolResultWithTokenLimit
464330
464953
  });
@@ -464450,29 +465073,62 @@ async function truncateToTokenLimit(content, maxTokens) {
464450
465073
  return content.slice(0, maxChars);
464451
465074
  }
464452
465075
  }
465076
+ function stripFilesystemDiffPayload(result2) {
465077
+ if (!result2 || typeof result2 !== "object") {
465078
+ return result2;
465079
+ }
465080
+ if (result2.oldContent !== void 0 || result2.newContent !== void 0) {
465081
+ const { oldContent: _oldContent, newContent: _newContent, completeOldContent: _completeOldContent, completeNewContent: _completeNewContent, replacedContent: _replacedContent, ...rest2 } = result2;
465082
+ return rest2;
465083
+ }
465084
+ if (Array.isArray(result2.results)) {
465085
+ return {
465086
+ ...result2,
465087
+ results: result2.results.map((item) => {
465088
+ if (!item || typeof item !== "object") {
465089
+ return item;
465090
+ }
465091
+ const { oldContent: _oldContent, newContent: _newContent, completeOldContent: _completeOldContent, completeNewContent: _completeNewContent, replacedContent: _replacedContent, ...rest2 } = item;
465092
+ return rest2;
465093
+ })
465094
+ };
465095
+ }
465096
+ return result2;
465097
+ }
465098
+ function isFilesystemEditToolName(toolName) {
465099
+ return toolName === "filesystem-edit" || toolName === "filesystem-replaceedit";
465100
+ }
464453
465101
  async function wrapToolResultWithTokenLimit(result2, toolName, maxTokens) {
464454
465102
  const limit = maxTokens ?? getToolResultTokenLimit();
464455
465103
  const validation = await validateTokenLimit(result2, limit);
464456
- if (!validation.isValid) {
464457
- let contentStr;
464458
- if (typeof result2 === "string") {
464459
- contentStr = result2;
464460
- } else if (typeof result2 === "object") {
464461
- contentStr = JSON.stringify(result2, null, 2);
464462
- } else {
464463
- contentStr = String(result2);
465104
+ if (validation.isValid) {
465105
+ return result2;
465106
+ }
465107
+ const strippedForModel = isFilesystemEditToolName(toolName) && result2 && typeof result2 === "object" ? stripFilesystemDiffPayload(result2) : null;
465108
+ if (strippedForModel) {
465109
+ const strippedValidation = await validateTokenLimit(strippedForModel, limit);
465110
+ if (strippedValidation.isValid) {
465111
+ return strippedForModel;
464464
465112
  }
464465
- const reservedTokens = 100;
464466
- const truncateLimit = Math.max(limit - reservedTokens, limit * 0.9);
464467
- const truncatedContent = await truncateToTokenLimit(contentStr, truncateLimit);
464468
- const truncationNotice = `
465113
+ }
465114
+ const sourceForTruncation = strippedForModel ?? result2;
465115
+ let contentStr;
465116
+ if (typeof sourceForTruncation === "string") {
465117
+ contentStr = sourceForTruncation;
465118
+ } else if (typeof sourceForTruncation === "object") {
465119
+ contentStr = JSON.stringify(sourceForTruncation, null, 2);
465120
+ } else {
465121
+ contentStr = String(sourceForTruncation);
465122
+ }
465123
+ const reservedTokens = 100;
465124
+ const truncateLimit = Math.max(limit - reservedTokens, limit * 0.9);
465125
+ const truncatedContent = await truncateToTokenLimit(contentStr, truncateLimit);
465126
+ const truncationNotice = `
464469
465127
 
464470
465128
  [TRUNCATED] Tool "${toolName}" output was truncated due to token limit.
464471
465129
  Original: ~${validation.tokenCount} tokens | Limit: ${limit} tokens
464472
465130
  The content above is incomplete. Consider using more specific queries or filters to get smaller results.`;
464473
- return truncatedContent + truncationNotice;
464474
- }
464475
- return result2;
465131
+ return truncatedContent + truncationNotice;
464476
465132
  }
464477
465133
  var DEFAULT_TOOL_RESULT_TOKEN_LIMIT;
464478
465134
  var init_tokenLimiter = __esm({
@@ -464547,7 +465203,7 @@ async function generateConfigHash() {
464547
465203
  const skillTools = await getMCPTools2(projectRoot);
464548
465204
  const { loadCodebaseConfig: loadCodebaseConfig2 } = await Promise.resolve().then(() => (init_codebaseConfig(), codebaseConfig_exports));
464549
465205
  const codebaseConfig = loadCodebaseConfig2();
464550
- const { getTeamMode: getTeamMode2 } = await Promise.resolve().then(() => (init_projectSettings(), projectSettings_exports));
465206
+ const { getTeamMode: getTeamMode2, getUltraTodoEnabled: getUltraTodoEnabled2 } = await Promise.resolve().then(() => (init_projectSettings(), projectSettings_exports));
464551
465207
  const sessionHasGoal = !!((_a20 = sessionManager.getCurrentSession()) == null ? void 0 : _a20.hasGoal);
464552
465208
  const sessionId = ((_b14 = sessionManager.getCurrentSession()) == null ? void 0 : _b14.id) || "";
464553
465209
  return JSON.stringify({
@@ -464560,6 +465216,7 @@ async function generateConfigHash() {
464560
465216
  disabledMCPTools: getDisabledMCPTools(),
464561
465217
  optInEnabledMCPTools: getOptInEnabledMCPKeysMerged(),
464562
465218
  teamMode: getTeamMode2(),
465219
+ ultraTodoEnabled: getUltraTodoEnabled2(),
464563
465220
  sessionHasGoal,
464564
465221
  sessionId
464565
465222
  });
@@ -464620,7 +465277,9 @@ async function refreshToolsCache() {
464620
465277
  addBuiltInService("terminal", mcpTools2, "terminal");
464621
465278
  const todoSvc = getTodoService();
464622
465279
  await todoSvc.initialize();
464623
- const todoTools = todoSvc.getTools();
465280
+ const { getUltraTodoEnabled: getUltraTodoEnabled2 } = await Promise.resolve().then(() => (init_projectSettings(), projectSettings_exports));
465281
+ const ultraTodoEnabled = getUltraTodoEnabled2();
465282
+ const todoTools = todoSvc.getTools(ultraTodoEnabled);
464624
465283
  addBuiltInService("todo", todoTools.map((t) => ({
464625
465284
  name: t.name,
464626
465285
  description: t.description || "",
@@ -465302,6 +465961,16 @@ async function executeMCPTool(toolName, args2, abortSignal, onTokenUpdate) {
465302
465961
  if (!isMCPToolEnabled(serviceName, actualToolName)) {
465303
465962
  throw new Error(`Tool "${actualToolName}" in service "${serviceName}" is currently disabled. You can re-enable it in the MCP panel (V to view tools, Tab to toggle).`);
465304
465963
  }
465964
+ if (serviceName === "todo") {
465965
+ const { getUltraTodoEnabled: getUltraTodoEnabled2 } = await Promise.resolve().then(() => (init_projectSettings(), projectSettings_exports));
465966
+ const ultraTodoEnabled = getUltraTodoEnabled2();
465967
+ if (ultraTodoEnabled && actualToolName === "manage") {
465968
+ throw new Error("Legacy todo-manage is disabled while Ultra TODO mode is enabled. Use todo-ultra instead.");
465969
+ }
465970
+ if (!ultraTodoEnabled && actualToolName === "ultra") {
465971
+ throw new Error("Ultra TODO tool is disabled. Enable it with /ultra-todo first.");
465972
+ }
465973
+ }
465305
465974
  if (serviceName === "todo") {
465306
465975
  result2 = await getTodoService().executeTool(actualToolName, args2);
465307
465976
  } else if (serviceName === "goal") {
@@ -465676,8 +466345,16 @@ Received: ${JSON.stringify(args2.description)}`
465676
466345
  } catch (error40) {
465677
466346
  throw error40;
465678
466347
  }
466348
+ const { extractFilesystemEditDiffFromRawResult: extractFilesystemEditDiffFromRawResult2 } = await Promise.resolve().then(() => (init_toolDisplayConfig(), toolDisplayConfig_exports));
466349
+ const preservedEditDiffData = extractFilesystemEditDiffFromRawResult2(toolName, result2);
465679
466350
  const { wrapToolResultWithTokenLimit: wrapToolResultWithTokenLimit2 } = await Promise.resolve().then(() => (init_tokenLimiter(), tokenLimiter_exports));
465680
466351
  result2 = await wrapToolResultWithTokenLimit2(result2, toolName);
466352
+ if (preservedEditDiffData) {
466353
+ return {
466354
+ __toolResultContent: result2,
466355
+ editDiffData: preservedEditDiffData
466356
+ };
466357
+ }
465681
466358
  return result2;
465682
466359
  }
465683
466360
  function isConnectionError(error40) {
@@ -470603,25 +471280,21 @@ ${injectedSummary}`
470603
471280
  }
470604
471281
  } else {
470605
471282
  const toolResult = await executeMCPTool(toolCall.function.name, args2, abortSignal, onTokenUpdate);
471283
+ const { extractFilesystemEditDiffFromRawResult: extractFilesystemEditDiffFromRawResult2 } = await Promise.resolve().then(() => (init_toolDisplayConfig(), toolDisplayConfig_exports));
470606
471284
  let editDiffData;
470607
- if (typeof toolResult === "object" && toolResult !== null && (toolCall.function.name === "filesystem-edit" || toolCall.function.name === "filesystem-replaceedit")) {
470608
- if (toolResult.oldContent && toolResult.newContent) {
470609
- editDiffData = {
470610
- oldContent: toolResult.oldContent,
470611
- newContent: toolResult.newContent,
470612
- filename: args2["filePath"],
470613
- completeOldContent: toolResult.completeOldContent,
470614
- completeNewContent: toolResult.completeNewContent,
470615
- contextStartLine: toolResult.contextStartLine
470616
- };
470617
- } else if (toolResult.results && Array.isArray(toolResult.results)) {
470618
- editDiffData = {
470619
- batchResults: toolResult.results,
470620
- isBatch: true
470621
- };
471285
+ let contentSource = toolResult;
471286
+ if (toolResult && typeof toolResult === "object" && "editDiffData" in toolResult && toolResult.editDiffData) {
471287
+ editDiffData = toolResult.editDiffData;
471288
+ if ("__toolResultContent" in toolResult) {
471289
+ contentSource = toolResult.__toolResultContent;
471290
+ }
471291
+ } else {
471292
+ editDiffData = extractFilesystemEditDiffFromRawResult2(toolCall.function.name, toolResult);
471293
+ if (editDiffData && !editDiffData["filename"] && typeof args2["filePath"] === "string") {
471294
+ editDiffData["filename"] = args2["filePath"];
470622
471295
  }
470623
471296
  }
470624
- const { textContent, images } = extractMultimodalContent(toolResult);
471297
+ const { textContent, images } = extractMultimodalContent(contentSource);
470625
471298
  result2 = {
470626
471299
  tool_call_id: toolCall.id,
470627
471300
  role: "tool",
@@ -471147,6 +471820,14 @@ var init_useGlobalNavigation = __esm({
471147
471820
  });
471148
471821
 
471149
471822
  // dist/utils/execution/terminal.js
471823
+ function getTerminalColumns(stream = process.stdout) {
471824
+ const columns = stream.columns;
471825
+ return typeof columns === "number" && Number.isFinite(columns) && columns > 0 ? Math.floor(columns) : DEFAULT_TERMINAL_COLUMNS;
471826
+ }
471827
+ function getAvailableTerminalColumns(reservedColumns = 0, stream = process.stdout) {
471828
+ const safeReservedColumns = Number.isFinite(reservedColumns) && reservedColumns > 0 ? Math.floor(reservedColumns) : 0;
471829
+ return Math.max(1, getTerminalColumns(stream) - safeReservedColumns);
471830
+ }
471150
471831
  function resetTerminal(stream) {
471151
471832
  const target = stream ?? process.stdout;
471152
471833
  if (!target || typeof target.write !== "function") {
@@ -471162,9 +471843,11 @@ function resetTerminal(stream) {
471162
471843
  }).catch(() => {
471163
471844
  });
471164
471845
  }
471846
+ var DEFAULT_TERMINAL_COLUMNS;
471165
471847
  var init_terminal = __esm({
471166
471848
  "dist/utils/execution/terminal.js"() {
471167
471849
  "use strict";
471850
+ DEFAULT_TERMINAL_COLUMNS = 80;
471168
471851
  }
471169
471852
  });
471170
471853
 
@@ -473343,6 +474026,30 @@ function useCommandHandler(options3) {
473343
474026
  }
473344
474027
  return newValue;
473345
474028
  });
474029
+ } else if (result2.success && result2.action === "toggleUltraTodo") {
474030
+ const messages = translations[getCurrentLanguage()].commandPanel.commandOutput.ultraTodo;
474031
+ try {
474032
+ const { getUltraTodoEnabled: getUltraTodoEnabled2, setUltraTodoEnabled: setUltraTodoEnabled2 } = await Promise.resolve().then(() => (init_projectSettings(), projectSettings_exports));
474033
+ const { refreshMCPToolsCache: refreshMCPToolsCache2 } = await Promise.resolve().then(() => (init_mcpToolsManager(), mcpToolsManager_exports));
474034
+ const newValue = !getUltraTodoEnabled2();
474035
+ setUltraTodoEnabled2(newValue);
474036
+ options3.setUltraTodoEnabled(newValue);
474037
+ await refreshMCPToolsCache2();
474038
+ const commandMessage = {
474039
+ role: "command",
474040
+ content: newValue ? messages.enabled : messages.disabled,
474041
+ commandName
474042
+ };
474043
+ options3.setMessages((prev) => [...prev, commandMessage]);
474044
+ } catch (error40) {
474045
+ const errorMsg = error40 instanceof Error ? error40.message : messages.unknownError;
474046
+ const errorMessage = {
474047
+ role: "command",
474048
+ content: messages.failed.replace("{error}", errorMsg),
474049
+ commandName
474050
+ };
474051
+ options3.setMessages((prev) => [...prev, errorMessage]);
474052
+ }
473346
474053
  } else if (result2.success && result2.action === "initProject" && result2.prompt) {
473347
474054
  const commandMessage = {
473348
474055
  role: "command",
@@ -473894,21 +474601,18 @@ function extractEditDiffData(toolCall, result2) {
473894
474601
  }
473895
474602
  try {
473896
474603
  const resultData = JSON.parse(result2.content);
473897
- if (resultData.oldContent && resultData.newContent) {
473898
- return {
473899
- oldContent: resultData.oldContent,
473900
- newContent: resultData.newContent,
473901
- filename: JSON.parse(toolCall.function.arguments).filePath,
473902
- completeOldContent: resultData.completeOldContent,
473903
- completeNewContent: resultData.completeNewContent,
473904
- contextStartLine: resultData.contextStartLine
473905
- };
473906
- }
473907
- if (resultData.results && Array.isArray(resultData.results)) {
473908
- return {
473909
- batchResults: resultData.results,
473910
- isBatch: true
473911
- };
474604
+ const fromParsed = extractFilesystemEditDiffFromRawResult(toolCall.function.name, resultData);
474605
+ if (fromParsed) {
474606
+ if (!fromParsed["filename"]) {
474607
+ try {
474608
+ const callArgs = JSON.parse(toolCall.function.arguments);
474609
+ if (typeof callArgs.filePath === "string") {
474610
+ fromParsed["filename"] = callArgs.filePath;
474611
+ }
474612
+ } catch {
474613
+ }
474614
+ }
474615
+ return fromParsed;
473912
474616
  }
473913
474617
  } catch {
473914
474618
  }
@@ -477141,6 +477845,36 @@ var init_toolsearch = __esm({
477141
477845
  }
477142
477846
  });
477143
477847
 
477848
+ // dist/utils/commands/ultraTodo.js
477849
+ var ultraTodo_exports = {};
477850
+ __export(ultraTodo_exports, {
477851
+ default: () => ultraTodo_default
477852
+ });
477853
+ function getMessages5() {
477854
+ const currentLanguage = getCurrentLanguage();
477855
+ return translations[currentLanguage].commandPanel.commandOutput.ultraTodo;
477856
+ }
477857
+ var ultraTodo_default;
477858
+ var init_ultraTodo = __esm({
477859
+ "dist/utils/commands/ultraTodo.js"() {
477860
+ "use strict";
477861
+ init_languageConfig();
477862
+ init_commandExecutor();
477863
+ init_i18n();
477864
+ registerCommand("ultra-todo", {
477865
+ execute: () => {
477866
+ const messages = getMessages5();
477867
+ return {
477868
+ success: true,
477869
+ action: "toggleUltraTodo",
477870
+ message: messages.toggling
477871
+ };
477872
+ }
477873
+ });
477874
+ ultraTodo_default = {};
477875
+ }
477876
+ });
477877
+
477144
477878
  // dist/utils/commands/hybridCompress.js
477145
477879
  var hybridCompress_exports = {};
477146
477880
  __export(hybridCompress_exports, {
@@ -477209,7 +477943,7 @@ var autoformat_exports = {};
477209
477943
  __export(autoformat_exports, {
477210
477944
  default: () => autoformat_default
477211
477945
  });
477212
- function getMessages5() {
477946
+ function getMessages6() {
477213
477947
  const currentLanguage = getCurrentLanguage();
477214
477948
  return translations[currentLanguage].commandPanel.commandOutput.autoFormat;
477215
477949
  }
@@ -477225,7 +477959,7 @@ var init_autoformat = __esm({
477225
477959
  execute: (args2) => {
477226
477960
  const trimmedArgs = args2 == null ? void 0 : args2.trim().toLowerCase();
477227
477961
  const enabled = getAutoFormatEnabled();
477228
- const messages = getMessages5();
477962
+ const messages = getMessages6();
477229
477963
  if (trimmedArgs === "status") {
477230
477964
  return {
477231
477965
  success: true,
@@ -477422,6 +478156,7 @@ var init_utils2 = __esm({
477422
478156
  init_todoPicker();
477423
478157
  init_todolist();
477424
478158
  init_toolsearch();
478159
+ init_ultraTodo();
477425
478160
  init_hybridCompress();
477426
478161
  init_usage();
477427
478162
  init_vulnerability_hunting();
@@ -481264,7 +481999,7 @@ function Menu({ options: options3, onSelect, onSelectionChange, maxHeight, defau
481264
481999
  { key: option.value },
481265
482000
  import_react64.default.createElement(
481266
482001
  Text,
481267
- { color: actualIndex === selectedIndex ? theme14.colors.menuSelected : option.color || theme14.colors.menuNormal, bold: true },
482002
+ { color: option.color || (actualIndex === selectedIndex ? theme14.colors.menuSelected : theme14.colors.menuNormal), bold: true },
481268
482003
  actualIndex === selectedIndex ? "\u276F " : " ",
481269
482004
  option.label
481270
482005
  )
@@ -484101,6 +484836,7 @@ var init_types5 = __esm({
484101
484836
  };
484102
484837
  SELECT_FIELDS = [
484103
484838
  "profile",
484839
+ "baseUrlMode",
484104
484840
  "requestMethod",
484105
484841
  "systemPromptId",
484106
484842
  "customHeadersSchemeId",
@@ -484119,8 +484855,8 @@ var init_types5 = __esm({
484119
484855
  });
484120
484856
 
484121
484857
  // dist/api/models.js
484122
- async function fetchOpenAIModels(baseUrl, apiKey, customHeaders) {
484123
- const url2 = `${baseUrl}/models`;
484858
+ async function fetchOpenAIModels(modelsUrl, apiKey, customHeaders) {
484859
+ const url2 = modelsUrl;
484124
484860
  const headers = {
484125
484861
  "Content-Type": "application/json",
484126
484862
  ...customHeaders
@@ -484228,7 +484964,7 @@ async function fetchAvailableModels(overrideConfig) {
484228
484964
  case "chat":
484229
484965
  case "responses":
484230
484966
  default:
484231
- models = await fetchOpenAIModels(config3.baseUrl.replace(/\/$/, ""), config3.apiKey, customHeaders);
484967
+ models = await fetchOpenAIModels(resolveApiEndpoint(config3.baseUrl, "models", config3.baseUrlMode), config3.apiKey, customHeaders);
484232
484968
  break;
484233
484969
  }
484234
484970
  return models.sort((a, b) => a.id.localeCompare(b.id));
@@ -484251,6 +484987,7 @@ var init_models2 = __esm({
484251
484987
  "use strict";
484252
484988
  init_apiConfig();
484253
484989
  init_proxyUtils();
484990
+ init_endpointResolver();
484254
484991
  }
484255
484992
  });
484256
484993
 
@@ -484266,6 +485003,7 @@ function useConfigState(options3) {
484266
485003
  const [renameProfileName, setRenameProfileName] = (0, import_react69.useState)("");
484267
485004
  const [markedProfiles, setMarkedProfiles] = (0, import_react69.useState)(/* @__PURE__ */ new Set());
484268
485005
  const [baseUrl, setBaseUrl] = (0, import_react69.useState)("");
485006
+ const [baseUrlMode, setBaseUrlMode] = (0, import_react69.useState)("auto");
484269
485007
  const [apiKey, setApiKey] = (0, import_react69.useState)("");
484270
485008
  const [requestMethod, setRequestMethod] = (0, import_react69.useState)("chat");
484271
485009
  const [systemPromptId, setSystemPromptId] = (0, import_react69.useState)(void 0);
@@ -484336,6 +485074,7 @@ function useConfigState(options3) {
484336
485074
  // 防止用户切换 active profile 或对 profile 进行增删改。
484337
485075
  ...targetProfileName ? [] : ["profile"],
484338
485076
  "baseUrl",
485077
+ "baseUrlMode",
484339
485078
  "apiKey",
484340
485079
  "requestMethod",
484341
485080
  "systemPromptId",
@@ -484437,6 +485176,7 @@ function useConfigState(options3) {
484437
485176
  const targetConfig = targetProfileName ? loadProfile(targetProfileName) : void 0;
484438
485177
  const config3 = (targetConfig == null ? void 0 : targetConfig.snowcfg) ?? getSnowConfig();
484439
485178
  setBaseUrl(config3.baseUrl);
485179
+ setBaseUrlMode(config3.baseUrlMode || "auto");
484440
485180
  setApiKey(config3.apiKey);
484441
485181
  setRequestMethod(config3.requestMethod || "chat");
484442
485182
  setSystemPromptId(config3.systemPromptId);
@@ -484479,6 +485219,7 @@ function useConfigState(options3) {
484479
485219
  setLoadError("");
484480
485220
  const tempConfig = {
484481
485221
  baseUrl,
485222
+ baseUrlMode,
484482
485223
  apiKey,
484483
485224
  requestMethod,
484484
485225
  customHeadersSchemeId
@@ -484516,6 +485257,8 @@ function useConfigState(options3) {
484516
485257
  return activeProfile;
484517
485258
  if (currentField === "baseUrl")
484518
485259
  return baseUrl;
485260
+ if (currentField === "baseUrlMode")
485261
+ return baseUrlMode;
484519
485262
  if (currentField === "apiKey")
484520
485263
  return apiKey;
484521
485264
  if (currentField === "advancedModel")
@@ -484573,18 +485316,15 @@ function useConfigState(options3) {
484573
485316
  const getRequestUrl = () => {
484574
485317
  const resolvedBaseUrl = getResolvedBaseUrl(requestMethod);
484575
485318
  if (requestMethod === "responses") {
484576
- return `${resolvedBaseUrl}/responses`;
485319
+ return resolveApiEndpoint(resolvedBaseUrl, "responses", baseUrlMode);
484577
485320
  }
484578
485321
  if (requestMethod === "anthropic") {
484579
- const endpoint = anthropicBeta ? "/messages?beta=true" : "/messages";
484580
- return `${resolvedBaseUrl}${endpoint}`;
485322
+ return resolveApiEndpoint(resolvedBaseUrl, "anthropicMessages", baseUrlMode, { anthropicBeta });
484581
485323
  }
484582
485324
  if (requestMethod === "gemini") {
484583
- const effectiveModel = advancedModel || "model-id";
484584
- const modelName = effectiveModel.startsWith("models/") ? effectiveModel : `models/${effectiveModel}`;
484585
- return `${resolvedBaseUrl}/${modelName}:streamGenerateContent?alt=sse`;
485325
+ return resolveApiEndpoint(resolvedBaseUrl, "geminiStreamGenerateContent", baseUrlMode, { modelName: advancedModel || "model-id" });
484586
485326
  }
484587
- return `${resolvedBaseUrl}/chat/completions`;
485327
+ return resolveApiEndpoint(resolvedBaseUrl, "chat", baseUrlMode);
484588
485328
  };
484589
485329
  const getSystemPromptSelectItems = () => {
484590
485330
  const activeNames = activeSystemPromptIds.map((id) => getSystemPromptNameById(id)).join(", ");
@@ -484657,6 +485397,7 @@ function useConfigState(options3) {
484657
485397
  const currentConfig = {
484658
485398
  snowcfg: {
484659
485399
  baseUrl,
485400
+ baseUrlMode,
484660
485401
  apiKey,
484661
485402
  requestMethod,
484662
485403
  systemPromptId,
@@ -484771,6 +485512,7 @@ function useConfigState(options3) {
484771
485512
  if (validationErrors.length === 0) {
484772
485513
  const config3 = {
484773
485514
  baseUrl,
485515
+ baseUrlMode,
484774
485516
  apiKey,
484775
485517
  requestMethod,
484776
485518
  systemPromptId,
@@ -484824,6 +485566,7 @@ function useConfigState(options3) {
484824
485566
  const fullConfig = {
484825
485567
  snowcfg: {
484826
485568
  baseUrl,
485569
+ baseUrlMode,
484827
485570
  apiKey,
484828
485571
  requestMethod,
484829
485572
  systemPromptId,
@@ -484884,6 +485627,8 @@ function useConfigState(options3) {
484884
485627
  // API settings
484885
485628
  baseUrl,
484886
485629
  setBaseUrl,
485630
+ baseUrlMode,
485631
+ setBaseUrlMode,
484887
485632
  apiKey,
484888
485633
  setApiKey,
484889
485634
  requestMethod,
@@ -485005,6 +485750,7 @@ var init_useConfigState = __esm({
485005
485750
  import_react69 = __toESM(require_react(), 1);
485006
485751
  init_apiConfig();
485007
485752
  init_models2();
485753
+ init_endpointResolver();
485008
485754
  init_configManager();
485009
485755
  init_i18n();
485010
485756
  init_ThemeContext();
@@ -485601,6 +486347,7 @@ function ConfigFieldRenderer({ field, state }) {
485601
486347
  // API settings
485602
486348
  baseUrl,
485603
486349
  setBaseUrl,
486350
+ baseUrlMode,
485604
486351
  apiKey,
485605
486352
  setApiKey,
485606
486353
  requestMethod,
@@ -485687,6 +486434,22 @@ function ConfigFieldRenderer({ field, state }) {
485687
486434
  import_react72.default.createElement(Text, { color: theme14.colors.menuSecondary }, baseUrl || t.configScreen.notSet)
485688
486435
  )
485689
486436
  );
486437
+ case "baseUrlMode":
486438
+ return import_react72.default.createElement(
486439
+ Box_default,
486440
+ { key: field, flexDirection: "column" },
486441
+ import_react72.default.createElement(
486442
+ Text,
486443
+ { color: activeColor },
486444
+ activeIndicator,
486445
+ t.configScreen.baseUrlMode
486446
+ ),
486447
+ !isCurrentlyEditing && import_react72.default.createElement(
486448
+ Box_default,
486449
+ { marginLeft: 3 },
486450
+ import_react72.default.createElement(Text, { color: theme14.colors.menuSecondary }, baseUrlMode === "base" ? t.configScreen.baseUrlModeBase : baseUrlMode === "endpoint" ? t.configScreen.baseUrlModeEndpoint : t.configScreen.baseUrlModeAuto)
486451
+ )
486452
+ );
485690
486453
  case "apiKey":
485691
486454
  return import_react72.default.createElement(
485692
486455
  Box_default,
@@ -486397,13 +487160,15 @@ var init_ConfigFieldRenderer = __esm({
486397
487160
 
486398
487161
  // dist/ui/pages/configScreen/ConfigSelectPanel.js
486399
487162
  function ConfigSelectPanel({ state }) {
486400
- const { t, theme: theme14, currentField, setIsEditing, requestMethod, setRequestMethod, requestMethodOptions, thinkingMode, setThinkingMode, thinkingEffort, setThinkingEffort, geminiThinkingLevel, setGeminiThinkingLevel, responsesVerbosity, setResponsesVerbosity, anthropicSpeed, setAnthropicSpeed, chatReasoningEffort, setChatReasoningEffort, getCustomHeadersSchemeSelectItems, getCustomHeadersSchemeSelectedValue, applyCustomHeadersSchemeSelectValue } = state;
487163
+ const { t, theme: theme14, currentField, setIsEditing, baseUrlMode, setBaseUrlMode, requestMethod, setRequestMethod, requestMethodOptions, thinkingMode, setThinkingMode, thinkingEffort, setThinkingEffort, geminiThinkingLevel, setGeminiThinkingLevel, responsesVerbosity, setResponsesVerbosity, anthropicSpeed, setAnthropicSpeed, chatReasoningEffort, setChatReasoningEffort, getCustomHeadersSchemeSelectItems, getCustomHeadersSchemeSelectedValue, applyCustomHeadersSchemeSelectValue } = state;
486401
487164
  const getFieldLabel = () => {
486402
487165
  switch (currentField) {
486403
487166
  case "profile":
486404
487167
  return t.configScreen.profile.replace(":", "");
486405
487168
  case "requestMethod":
486406
487169
  return t.configScreen.requestMethod.replace(":", "");
487170
+ case "baseUrlMode":
487171
+ return t.configScreen.baseUrlMode.replace(":", "");
486407
487172
  case "advancedModel":
486408
487173
  return t.configScreen.advancedModel.replace(":", "");
486409
487174
  case "basicModel":
@@ -486447,6 +487212,17 @@ function ConfigSelectPanel({ state }) {
486447
487212
  setRequestMethod(item.value);
486448
487213
  setIsEditing(false);
486449
487214
  } }),
487215
+ currentField === "baseUrlMode" && import_react73.default.createElement(ScrollableSelectInput, { items: [
487216
+ { label: t.configScreen.baseUrlModeAuto, value: "auto" },
487217
+ { label: t.configScreen.baseUrlModeBase, value: "base" },
487218
+ {
487219
+ label: t.configScreen.baseUrlModeEndpoint,
487220
+ value: "endpoint"
487221
+ }
487222
+ ], initialIndex: Math.max(0, ["auto", "base", "endpoint"].indexOf(baseUrlMode)), isFocused: true, onSelect: (item) => {
487223
+ setBaseUrlMode(item.value);
487224
+ setIsEditing(false);
487225
+ } }),
486450
487226
  currentField === "systemPromptId" && import_react73.default.createElement(SystemPromptSelect, { state }),
486451
487227
  currentField === "customHeadersSchemeId" && (() => {
486452
487228
  const items = getCustomHeadersSchemeSelectItems();
@@ -551479,6 +552255,66 @@ var init_marked_terminal = __esm({
551479
552255
  }
551480
552256
  });
551481
552257
 
552258
+ // dist/utils/core/textUtils.js
552259
+ function toCodePoints(str2) {
552260
+ return Array.from(str2);
552261
+ }
552262
+ function cpLen(str2) {
552263
+ return toCodePoints(str2).length;
552264
+ }
552265
+ function cpSlice(str2, start, end) {
552266
+ const codePoints = toCodePoints(str2);
552267
+ return codePoints.slice(start, end).join("");
552268
+ }
552269
+ function visualWidth(str2) {
552270
+ return stringWidth4(str2);
552271
+ }
552272
+ function codePointToVisualPos(str2, codePointIndex) {
552273
+ const codePoints = toCodePoints(str2);
552274
+ let visualPos = 0;
552275
+ for (let i = 0; i < Math.min(codePointIndex, codePoints.length); i++) {
552276
+ const char = codePoints[i] || "";
552277
+ visualPos += visualWidth(char);
552278
+ }
552279
+ return visualPos;
552280
+ }
552281
+ function visualPosToCodePoint(str2, visualPos) {
552282
+ const codePoints = toCodePoints(str2);
552283
+ let currentVisualPos = 0;
552284
+ for (let i = 0; i < codePoints.length; i++) {
552285
+ const char = codePoints[i] || "";
552286
+ const charWidth = visualWidth(char);
552287
+ if (currentVisualPos + charWidth > visualPos) {
552288
+ return i;
552289
+ }
552290
+ currentVisualPos += charWidth;
552291
+ if (currentVisualPos >= visualPos) {
552292
+ return i + 1;
552293
+ }
552294
+ }
552295
+ return codePoints.length;
552296
+ }
552297
+ function formatElapsedTime(seconds) {
552298
+ if (seconds < 60) {
552299
+ return `${seconds}s`;
552300
+ } else if (seconds < 3600) {
552301
+ const minutes = Math.floor(seconds / 60);
552302
+ const remainingSeconds = seconds % 60;
552303
+ return `${minutes}m ${remainingSeconds}s`;
552304
+ } else {
552305
+ const hours = Math.floor(seconds / 3600);
552306
+ const remainingMinutes = Math.floor(seconds % 3600 / 60);
552307
+ const remainingSeconds = seconds % 60;
552308
+ return `${hours}h ${remainingMinutes}m ${remainingSeconds}s`;
552309
+ }
552310
+ }
552311
+ var init_textUtils = __esm({
552312
+ "dist/utils/core/textUtils.js"() {
552313
+ "use strict";
552314
+ init_string_width4();
552315
+ }
552316
+ });
552317
+
551482
552318
  // node_modules/katex/dist/katex.mjs
551483
552319
  function escape4(text2) {
551484
552320
  return String(text2).replace(ESCAPE_REGEX, (match) => ESCAPE_LOOKUP[match]);
@@ -566135,6 +566971,39 @@ var init_unicodeMath = __esm({
566135
566971
  });
566136
566972
 
566137
566973
  // dist/ui/components/common/MarkdownRenderer.js
566974
+ function renderInlineTokens(parser3, cell) {
566975
+ return cell.tokens ? parser3.parseInline(cell.tokens) : cell.text;
566976
+ }
566977
+ function calculateHorizontalTableWidth(headers, rows) {
566978
+ const widths = headers.map((header) => visualWidth(header));
566979
+ for (const row of rows) {
566980
+ row.forEach((cell, index) => {
566981
+ widths[index] = Math.max(widths[index] ?? 0, visualWidth(cell));
566982
+ });
566983
+ }
566984
+ return widths.reduce((total, width) => total + width + 2, 0) + widths.length + 1;
566985
+ }
566986
+ function formatVerticalTableSeparator(width) {
566987
+ return VERTICAL_TABLE_SEPARATOR_CHAR.repeat(Math.max(1, width));
566988
+ }
566989
+ function renderVerticalTable(token, parser3) {
566990
+ const headers = token.header.map((cell) => renderInlineTokens(parser3, cell));
566991
+ const rows = token.rows.map((row) => row.map((cell) => renderInlineTokens(parser3, cell)));
566992
+ const terminalWidth = getAvailableTerminalColumns(VERTICAL_TABLE_RESERVED_COLUMNS);
566993
+ const horizontalTableWidth = calculateHorizontalTableWidth(headers, rows);
566994
+ if (horizontalTableWidth <= terminalWidth) {
566995
+ return false;
566996
+ }
566997
+ const separator = formatVerticalTableSeparator(terminalWidth);
566998
+ const blocks = rows.map((row) => {
566999
+ return headers.map((header, index) => `${header}: ${row[index] ?? ""}`).join("\n");
567000
+ });
567001
+ return `
567002
+ ${blocks.join(`
567003
+ ${separator}
567004
+ `)}
567005
+ `;
567006
+ }
566138
567007
  function sanitizeMarkdownContent(content) {
566139
567008
  return content.replace(/<ol\s+start=["']?(0|-\d+)["']?>/gi, '<ol start="1">');
566140
567009
  }
@@ -566207,7 +567076,7 @@ function MarkdownRenderer({ content }) {
566207
567076
  return renderFallback(content);
566208
567077
  }
566209
567078
  }
566210
- var import_react85, import_cli_highlight3, ANSI_PATTERN;
567079
+ var import_react85, import_cli_highlight3, VERTICAL_TABLE_SEPARATOR_CHAR, VERTICAL_TABLE_RESERVED_COLUMNS, ANSI_PATTERN;
566211
567080
  var init_MarkdownRenderer = __esm({
566212
567081
  async "dist/ui/components/common/MarkdownRenderer.js"() {
566213
567082
  "use strict";
@@ -566217,9 +567086,11 @@ var init_MarkdownRenderer = __esm({
566217
567086
  init_marked_terminal();
566218
567087
  import_cli_highlight3 = __toESM(require_dist14(), 1);
566219
567088
  init_logger();
567089
+ init_textUtils();
567090
+ init_terminal();
566220
567091
  init_unicodeMath();
566221
567092
  marked.use(markedTerminal({
566222
- width: process.stdout.columns || 80,
567093
+ width: getTerminalColumns(),
566223
567094
  reflowText: true,
566224
567095
  unescape: true,
566225
567096
  showSectionPrefix: false,
@@ -566238,6 +567109,15 @@ var init_MarkdownRenderer = __esm({
566238
567109
  }
566239
567110
  }
566240
567111
  });
567112
+ VERTICAL_TABLE_SEPARATOR_CHAR = "\u2500";
567113
+ VERTICAL_TABLE_RESERVED_COLUMNS = 2;
567114
+ marked.use({
567115
+ renderer: {
567116
+ table(token) {
567117
+ return renderVerticalTable(token, this.parser);
567118
+ }
567119
+ }
567120
+ });
566241
567121
  marked.use({
566242
567122
  extensions: [
566243
567123
  {
@@ -566964,66 +567844,6 @@ var init_skillMask = __esm({
566964
567844
  }
566965
567845
  });
566966
567846
 
566967
- // dist/utils/core/textUtils.js
566968
- function toCodePoints(str2) {
566969
- return Array.from(str2);
566970
- }
566971
- function cpLen(str2) {
566972
- return toCodePoints(str2).length;
566973
- }
566974
- function cpSlice(str2, start, end) {
566975
- const codePoints = toCodePoints(str2);
566976
- return codePoints.slice(start, end).join("");
566977
- }
566978
- function visualWidth(str2) {
566979
- return stringWidth4(str2);
566980
- }
566981
- function codePointToVisualPos(str2, codePointIndex) {
566982
- const codePoints = toCodePoints(str2);
566983
- let visualPos = 0;
566984
- for (let i = 0; i < Math.min(codePointIndex, codePoints.length); i++) {
566985
- const char = codePoints[i] || "";
566986
- visualPos += visualWidth(char);
566987
- }
566988
- return visualPos;
566989
- }
566990
- function visualPosToCodePoint(str2, visualPos) {
566991
- const codePoints = toCodePoints(str2);
566992
- let currentVisualPos = 0;
566993
- for (let i = 0; i < codePoints.length; i++) {
566994
- const char = codePoints[i] || "";
566995
- const charWidth = visualWidth(char);
566996
- if (currentVisualPos + charWidth > visualPos) {
566997
- return i;
566998
- }
566999
- currentVisualPos += charWidth;
567000
- if (currentVisualPos >= visualPos) {
567001
- return i + 1;
567002
- }
567003
- }
567004
- return codePoints.length;
567005
- }
567006
- function formatElapsedTime(seconds) {
567007
- if (seconds < 60) {
567008
- return `${seconds}s`;
567009
- } else if (seconds < 3600) {
567010
- const minutes = Math.floor(seconds / 60);
567011
- const remainingSeconds = seconds % 60;
567012
- return `${minutes}m ${remainingSeconds}s`;
567013
- } else {
567014
- const hours = Math.floor(seconds / 3600);
567015
- const remainingMinutes = Math.floor(seconds % 3600 / 60);
567016
- const remainingSeconds = seconds % 60;
567017
- return `${hours}h ${remainingMinutes}m ${remainingSeconds}s`;
567018
- }
567019
- }
567020
- var init_textUtils = __esm({
567021
- "dist/utils/core/textUtils.js"() {
567022
- "use strict";
567023
- init_string_width4();
567024
- }
567025
- });
567026
-
567027
567847
  // dist/ui/components/chat/MessageRenderer.js
567028
567848
  function cleanThinkingContent5(content) {
567029
567849
  return content.replace(/\s*<\/?think(?:ing)?>\s*/gi, "").trim();
@@ -570854,6 +571674,10 @@ function useCommandPanel(buffer, isProcessing = false) {
570854
571674
  name: "team",
570855
571675
  description: t.commandPanel.commands.team || "Toggle Agent Team mode - orchestrate multiple agents working together"
570856
571676
  },
571677
+ {
571678
+ name: "ultra-todo",
571679
+ description: t.commandPanel.commands.ultraTodo || "Toggle Ultra TODO mode with phase-gated task management"
571680
+ },
570857
571681
  {
570858
571682
  name: "pixel",
570859
571683
  description: t.commandPanel.commands.pixel || "Open the terminal pixel editor",
@@ -572669,8 +573493,7 @@ function clipboardHandler(ctx) {
572669
573493
  const { input: input2, key, options: options3, refs } = ctx;
572670
573494
  const { pasteFromClipboard } = options3;
572671
573495
  const isLegacyImagePasteShortcut = process.platform === "darwin" ? key.ctrl && input2 === "v" : key.meta && input2 === "v";
572672
- const isForwardedSystemPasteShortcut = process.platform !== "darwin" && key.ctrl && input2 === "v";
572673
- if (isLegacyImagePasteShortcut || isForwardedSystemPasteShortcut) {
573496
+ if (isLegacyImagePasteShortcut) {
572674
573497
  refs.lastPasteShortcutAt.current = Date.now();
572675
573498
  pasteFromClipboard();
572676
573499
  return true;
@@ -577564,6 +578387,7 @@ var init_builtinIds = __esm({
577564
578387
  modePlan: "builtin.mode-plan",
577565
578388
  modeHunt: "builtin.mode-hunt",
577566
578389
  modeTeam: "builtin.mode-team",
578390
+ modeUltraTodo: "builtin.mode-ultra-todo",
577567
578391
  toolSearch: "builtin.tool-search",
577568
578392
  hybridCompress: "builtin.hybrid-compress",
577569
578393
  ideConnection: "builtin.ide-connection",
@@ -577730,7 +578554,7 @@ function buildContextWindowState(contextUsage) {
577730
578554
  hasAnyCache: hasAnthropicCache || hasOpenAICache
577731
578555
  };
577732
578556
  }
577733
- function StatusLine({ yoloMode = false, planMode = false, vulnerabilityHuntingMode = false, toolSearchDisabled = true, hybridCompressEnabled = false, teamMode = false, vscodeConnectionStatus, editorContext, connectionStatus, connectionInstanceName, contextUsage, codebaseIndexing = false, codebaseProgress, watcherEnabled = false, fileUpdateNotification, copyStatusMessage, currentProfileName, compressBlockToast }) {
578557
+ function StatusLine({ yoloMode = false, planMode = false, vulnerabilityHuntingMode = false, toolSearchDisabled = true, hybridCompressEnabled = false, teamMode = false, ultraTodoEnabled = false, vscodeConnectionStatus, editorContext, connectionStatus, connectionInstanceName, contextUsage, codebaseIndexing = false, codebaseProgress, watcherEnabled = false, fileUpdateNotification, copyStatusMessage, currentProfileName, compressBlockToast }) {
577734
578558
  const { t, language } = useI18n();
577735
578559
  const { theme: theme14 } = useTheme();
577736
578560
  const simpleMode = getSimpleMode();
@@ -577764,6 +578588,7 @@ function StatusLine({ yoloMode = false, planMode = false, vulnerabilityHuntingMo
577764
578588
  toolSearchEnabled: !toolSearchDisabled,
577765
578589
  hybridCompress: hybridCompressEnabled,
577766
578590
  team: teamMode,
578591
+ ultraTodo: ultraTodoEnabled,
577767
578592
  simple: simpleMode
577768
578593
  },
577769
578594
  ide: {
@@ -577847,6 +578672,7 @@ function StatusLine({ yoloMode = false, planMode = false, vulnerabilityHuntingMo
577847
578672
  vscodeConnectionStatus,
577848
578673
  vulnerabilityHuntingMode,
577849
578674
  watcherEnabled,
578675
+ ultraTodoEnabled,
577850
578676
  yoloMode
577851
578677
  ]);
577852
578678
  const { items: statusLineHookItems, externalHookIds } = useStatusLineHookItems(statusLineHookContext);
@@ -577924,7 +578750,7 @@ function StatusLine({ yoloMode = false, planMode = false, vulnerabilityHuntingMo
577924
578750
  )
577925
578751
  );
577926
578752
  };
577927
- const hasAnyStatus = yoloMode || planMode || vulnerabilityHuntingMode || teamMode || !toolSearchDisabled || hybridCompressEnabled || vscodeConnectionStatus && vscodeConnectionStatus !== "disconnected" || connectionStatus && connectionStatus !== "disconnected" || contextUsage || codebaseIndexing || watcherEnabled || fileUpdateNotification || copyStatusMessage || currentProfileName || compressBlockToast || statusLineHookItems.length > 0 || detailedMemoryStatusText;
578753
+ const hasAnyStatus = yoloMode || planMode || vulnerabilityHuntingMode || teamMode || ultraTodoEnabled || !toolSearchDisabled || hybridCompressEnabled || vscodeConnectionStatus && vscodeConnectionStatus !== "disconnected" || connectionStatus && connectionStatus !== "disconnected" || contextUsage || codebaseIndexing || watcherEnabled || fileUpdateNotification || copyStatusMessage || currentProfileName || compressBlockToast || statusLineHookItems.length > 0 || detailedMemoryStatusText;
577928
578754
  if (!hasAnyStatus) {
577929
578755
  return null;
577930
578756
  }
@@ -577960,6 +578786,9 @@ function StatusLine({ yoloMode = false, planMode = false, vulnerabilityHuntingMo
577960
578786
  if (teamMode && !isBuiltinOverridden(BUILTIN_STATUSLINE_IDS.modeTeam)) {
577961
578787
  statusItems.push({ text: "\u2691 Team", color: "#10B981" });
577962
578788
  }
578789
+ if (ultraTodoEnabled && !isBuiltinOverridden(BUILTIN_STATUSLINE_IDS.modeUltraTodo)) {
578790
+ statusItems.push({ text: "\u25C8 Ultra TODO", color: "#A78BFA" });
578791
+ }
577963
578792
  if (hybridCompressEnabled && !isBuiltinOverridden(BUILTIN_STATUSLINE_IDS.hybridCompress)) {
577964
578793
  statusItems.push({
577965
578794
  text: "\u21CC Hybrid Compress",
@@ -578100,6 +578929,11 @@ function StatusLine({ yoloMode = false, planMode = false, vulnerabilityHuntingMo
578100
578929
  null,
578101
578930
  import_react121.default.createElement(Text, { color: "#10B981", dimColor: true }, t.chatScreen.teamModeActive)
578102
578931
  ),
578932
+ ultraTodoEnabled && !isBuiltinOverridden(BUILTIN_STATUSLINE_IDS.modeUltraTodo) && import_react121.default.createElement(
578933
+ Box_default,
578934
+ null,
578935
+ import_react121.default.createElement(Text, { color: "#A78BFA", dimColor: true }, t.chatScreen.ultraTodoActive)
578936
+ ),
578103
578937
  hybridCompressEnabled && !isBuiltinOverridden(BUILTIN_STATUSLINE_IDS.hybridCompress) && import_react121.default.createElement(
578104
578938
  Box_default,
578105
578939
  null,
@@ -580327,6 +581161,7 @@ var init_ChatFooter = __esm({
580327
581161
  await init_TodoTree();
580328
581162
  init_sessionManager();
580329
581163
  init_todoEvents();
581164
+ init_mcpToolsManager();
580330
581165
  init_ConnectionManager();
580331
581166
  await init_IdeSelectPanel();
580332
581167
  ReviewCommitPanel2 = (0, import_react132.lazy)(() => init_ReviewCommitPanel().then(() => ReviewCommitPanel_exports));
@@ -580350,22 +581185,55 @@ var init_ChatFooter = __esm({
580350
581185
  return unsubscribe;
580351
581186
  }, []);
580352
581187
  (0, import_react132.useEffect)(() => {
580353
- const currentSession = sessionManager.getCurrentSession();
580354
- if (!currentSession) {
580355
- setShowTodos(false);
580356
- setTodos([]);
580357
- return;
580358
- }
581188
+ var _a20;
581189
+ let disposed = false;
581190
+ let observedSessionId = ((_a20 = sessionManager.getCurrentSession()) == null ? void 0 : _a20.id) ?? null;
581191
+ const loadTodosForCurrentSession = async (force = false) => {
581192
+ var _a21;
581193
+ const currentSession = sessionManager.getCurrentSession();
581194
+ const nextSessionId = (currentSession == null ? void 0 : currentSession.id) ?? null;
581195
+ if (!force && nextSessionId === observedSessionId) {
581196
+ return;
581197
+ }
581198
+ observedSessionId = nextSessionId;
581199
+ if (!currentSession) {
581200
+ if (!disposed) {
581201
+ setShowTodos(false);
581202
+ setTodos([]);
581203
+ }
581204
+ return;
581205
+ }
581206
+ try {
581207
+ const todoList = await getTodoService().getTodoList(currentSession.id);
581208
+ if (disposed || ((_a21 = sessionManager.getCurrentSession()) == null ? void 0 : _a21.id) !== currentSession.id) {
581209
+ return;
581210
+ }
581211
+ setTodos((todoList == null ? void 0 : todoList.todos) ?? []);
581212
+ } catch (error40) {
581213
+ console.error("Failed to load current session TODO list:", error40);
581214
+ if (!disposed) {
581215
+ setTodos([]);
581216
+ }
581217
+ }
581218
+ };
580359
581219
  const handleTodoUpdate = (data) => {
580360
- if (data.sessionId === currentSession.id) {
581220
+ const currentSession = sessionManager.getCurrentSession();
581221
+ if (currentSession && data.sessionId === currentSession.id) {
581222
+ observedSessionId = currentSession.id;
580361
581223
  setTodos(data.todos);
580362
581224
  if (data.todos.length > 0 && props.isProcessing) {
580363
581225
  setShowTodos(true);
580364
581226
  }
580365
581227
  }
580366
581228
  };
581229
+ const unsubscribeSessionChanges = sessionManager.onMessagesChanged(() => {
581230
+ void loadTodosForCurrentSession(false);
581231
+ });
581232
+ void loadTodosForCurrentSession(true);
580367
581233
  todoEvents.onTodoUpdate(handleTodoUpdate);
580368
581234
  return () => {
581235
+ disposed = true;
581236
+ unsubscribeSessionChanges();
580369
581237
  todoEvents.offTodoUpdate(handleTodoUpdate);
580370
581238
  };
580371
581239
  }, [props.isProcessing]);
@@ -580432,7 +581300,7 @@ var init_ChatFooter = __esm({
580432
581300
  { marginTop: 1 },
580433
581301
  import_react132.default.createElement(TodoTree, { todos })
580434
581302
  ),
580435
- import_react132.default.createElement(StatusLine, { yoloMode: props.yoloMode, planMode: props.planMode, vulnerabilityHuntingMode: props.vulnerabilityHuntingMode, toolSearchDisabled: props.toolSearchDisabled, hybridCompressEnabled: props.hybridCompressEnabled, teamMode: props.teamMode, vscodeConnectionStatus: props.vscodeConnectionStatus, editorContext: props.editorContext, connectionStatus, connectionInstanceName, contextUsage: props.contextUsage, codebaseIndexing: props.codebaseIndexing, codebaseProgress: props.codebaseProgress, watcherEnabled: props.watcherEnabled, fileUpdateNotification: props.fileUpdateNotification, copyStatusMessage, currentProfileName: props.currentProfileName, compressBlockToast: props.compressBlockToast }),
581303
+ import_react132.default.createElement(StatusLine, { yoloMode: props.yoloMode, planMode: props.planMode, vulnerabilityHuntingMode: props.vulnerabilityHuntingMode, toolSearchDisabled: props.toolSearchDisabled, hybridCompressEnabled: props.hybridCompressEnabled, teamMode: props.teamMode, ultraTodoEnabled: props.ultraTodoEnabled, vscodeConnectionStatus: props.vscodeConnectionStatus, editorContext: props.editorContext, connectionStatus, connectionInstanceName, contextUsage: props.contextUsage, codebaseIndexing: props.codebaseIndexing, codebaseProgress: props.codebaseProgress, watcherEnabled: props.watcherEnabled, fileUpdateNotification: props.fileUpdateNotification, copyStatusMessage, currentProfileName: props.currentProfileName, compressBlockToast: props.compressBlockToast }),
580436
581304
  props.showBackgroundPanel && import_react132.default.createElement(BackgroundProcessPanel, { processes: props.backgroundProcesses, selectedIndex: props.selectedProcessIndex, terminalWidth: props.terminalWidth })
580437
581305
  ),
580438
581306
  props.showReviewCommitPanel && import_react132.default.createElement(
@@ -588875,6 +589743,7 @@ function TodoListPanel({ onClose }) {
588875
589743
  const [loading, setLoading] = (0, import_react164.useState)(true);
588876
589744
  const [deleting, setDeleting] = (0, import_react164.useState)(false);
588877
589745
  const [currentSessionId2, setCurrentSessionId] = (0, import_react164.useState)(null);
589746
+ const currentSessionIdRef = (0, import_react164.useRef)(null);
588878
589747
  const [selectedIndex, setSelectedIndex] = (0, import_react164.useState)(0);
588879
589748
  const [markedTodoIds, setMarkedTodoIds] = (0, import_react164.useState)(/* @__PURE__ */ new Set());
588880
589749
  const [pendingDelete, setPendingDelete] = (0, import_react164.useState)(false);
@@ -588907,7 +589776,9 @@ function TodoListPanel({ onClose }) {
588907
589776
  const showOverflowHint = flattenedTodos.length > maxVisibleItems;
588908
589777
  const loadTodos = (0, import_react164.useCallback)(async () => {
588909
589778
  const currentSession = sessionManager.getCurrentSession();
588910
- setCurrentSessionId((currentSession == null ? void 0 : currentSession.id) ?? null);
589779
+ const nextSessionId = (currentSession == null ? void 0 : currentSession.id) ?? null;
589780
+ currentSessionIdRef.current = nextSessionId;
589781
+ setCurrentSessionId(nextSessionId);
588911
589782
  if (!currentSession) {
588912
589783
  setTodos([]);
588913
589784
  setLoading(false);
@@ -588927,6 +589798,16 @@ function TodoListPanel({ onClose }) {
588927
589798
  (0, import_react164.useEffect)(() => {
588928
589799
  void loadTodos();
588929
589800
  }, [loadTodos]);
589801
+ (0, import_react164.useEffect)(() => {
589802
+ const handleSessionChange = () => {
589803
+ var _a20;
589804
+ const nextSessionId = ((_a20 = sessionManager.getCurrentSession()) == null ? void 0 : _a20.id) ?? null;
589805
+ if (nextSessionId !== currentSessionIdRef.current) {
589806
+ void loadTodos();
589807
+ }
589808
+ };
589809
+ return sessionManager.onMessagesChanged(handleSessionChange);
589810
+ }, [loadTodos]);
588930
589811
  (0, import_react164.useEffect)(() => {
588931
589812
  const handleTodoUpdate = (data) => {
588932
589813
  if (data.sessionId === currentSessionId2) {
@@ -593798,6 +594679,7 @@ function useChatScreenCommands(workingDirectory) {
593798
594679
  Promise.resolve().then(() => (init_newPrompt(), newPrompt_exports)),
593799
594680
  Promise.resolve().then(() => (init_autoformat(), autoformat_exports)),
593800
594681
  Promise.resolve().then(() => (init_toolsearch(), toolsearch_exports)),
594682
+ Promise.resolve().then(() => (init_ultraTodo(), ultraTodo_exports)),
593801
594683
  Promise.resolve().then(() => (init_hybridCompress(), hybridCompress_exports)),
593802
594684
  Promise.resolve().then(() => (init_team2(), team_exports)),
593803
594685
  Promise.resolve().then(() => (init_btw(), btw_exports)),
@@ -594042,6 +594924,7 @@ function useChatScreenModes({ enableYolo, enablePlan }) {
594042
594924
  const [toolSearchDisabled, setToolSearchDisabled] = (0, import_react182.useState)(() => !getToolSearchEnabled());
594043
594925
  const [hybridCompressEnabled, setHybridCompressEnabled2] = (0, import_react182.useState)(() => getHybridCompressEnabled());
594044
594926
  const [teamMode, setTeamMode2] = (0, import_react182.useState)(() => getTeamMode());
594927
+ const [ultraTodoEnabled, setUltraTodoEnabled2] = (0, import_react182.useState)(() => getUltraTodoEnabled());
594045
594928
  const [simpleMode, setSimpleMode2] = (0, import_react182.useState)(() => getSimpleMode());
594046
594929
  const [showThinking, setShowThinking] = (0, import_react182.useState)(() => {
594047
594930
  const config3 = getSnowConfig();
@@ -594065,6 +594948,9 @@ function useChatScreenModes({ enableYolo, enablePlan }) {
594065
594948
  (0, import_react182.useEffect)(() => {
594066
594949
  setTeamMode(teamMode);
594067
594950
  }, [teamMode]);
594951
+ (0, import_react182.useEffect)(() => {
594952
+ setUltraTodoEnabled(ultraTodoEnabled);
594953
+ }, [ultraTodoEnabled]);
594068
594954
  (0, import_react182.useEffect)(() => {
594069
594955
  const interval = setInterval(() => {
594070
594956
  const currentSimpleMode = getSimpleMode();
@@ -594100,6 +594986,8 @@ function useChatScreenModes({ enableYolo, enablePlan }) {
594100
594986
  setHybridCompressEnabled: setHybridCompressEnabled2,
594101
594987
  teamMode,
594102
594988
  setTeamMode: setTeamMode2,
594989
+ ultraTodoEnabled,
594990
+ setUltraTodoEnabled: setUltraTodoEnabled2,
594103
594991
  simpleMode,
594104
594992
  showThinking
594105
594993
  };
@@ -594345,7 +595233,7 @@ function ChatScreen({ autoResume, resumeSessionId: resumeSessionId2, enableYolo,
594345
595233
  const { columns: terminalWidth, rows: terminalHeight } = useTerminalSize();
594346
595234
  const workingDirectory = process.cwd();
594347
595235
  const { messages, setMessages, isSaving, pendingMessages, setPendingMessages, pendingMessagesRef, userInterruptedRef, remountKey, setRemountKey, setCurrentContextPercentage, currentContextPercentageRef, isExecutingTerminalCommand, setIsExecutingTerminalCommand, customCommandExecution, setCustomCommandExecution, isCompressing, setIsCompressing, compressionError, setCompressionError, showPermissionsPanel, setShowPermissionsPanel, showSubAgentDepthPanel, setShowSubAgentDepthPanel, restoreInputContent, setRestoreInputContent, inputDraftContent, setInputDraftContent, bashSensitiveCommand, setBashSensitiveCommand, suppressLoadingIndicator, setSuppressLoadingIndicator, hookError, setHookError, pendingUserQuestion, setPendingUserQuestion, requestUserQuestion, compressionStatus, setCompressionStatus, isResumingSession, setIsResumingSession, btwPrompt, setBtwPrompt } = useChatScreenLocalState();
594348
- const { yoloMode, setYoloMode: setYoloMode2, planMode, setPlanMode: setPlanMode2, vulnerabilityHuntingMode, setVulnerabilityHuntingMode: setVulnerabilityHuntingMode2, toolSearchDisabled, setToolSearchDisabled, hybridCompressEnabled, setHybridCompressEnabled: setHybridCompressEnabled2, teamMode, setTeamMode: setTeamMode2, simpleMode, showThinking } = useChatScreenModes({ enableYolo, enablePlan });
595236
+ const { yoloMode, setYoloMode: setYoloMode2, planMode, setPlanMode: setPlanMode2, vulnerabilityHuntingMode, setVulnerabilityHuntingMode: setVulnerabilityHuntingMode2, toolSearchDisabled, setToolSearchDisabled, hybridCompressEnabled, setHybridCompressEnabled: setHybridCompressEnabled2, teamMode, setTeamMode: setTeamMode2, ultraTodoEnabled, setUltraTodoEnabled: setUltraTodoEnabled2, simpleMode, showThinking } = useChatScreenModes({ enableYolo, enablePlan });
594349
595237
  const streamingState = useStreamingState();
594350
595238
  const vscodeState = useVSCodeState();
594351
595239
  const snapshotState = useSnapshotState(messages.length);
@@ -594502,6 +595390,7 @@ function ChatScreen({ autoResume, resumeSessionId: resumeSessionId2, enableYolo,
594502
595390
  setToolSearchDisabled,
594503
595391
  setHybridCompressEnabled: setHybridCompressEnabled2,
594504
595392
  setTeamMode: setTeamMode2,
595393
+ setUltraTodoEnabled: setUltraTodoEnabled2,
594505
595394
  setContextUsage: streamingState.setContextUsage,
594506
595395
  setCurrentContextPercentage,
594507
595396
  currentContextPercentageRef,
@@ -594674,6 +595563,7 @@ function ChatScreen({ autoResume, resumeSessionId: resumeSessionId2, enableYolo,
594674
595563
  toolSearchDisabled,
594675
595564
  hybridCompressEnabled,
594676
595565
  teamMode,
595566
+ ultraTodoEnabled,
594677
595567
  setTeamMode: setTeamMode2,
594678
595568
  contextUsage: footerContextUsage,
594679
595569
  initialContent: restoreInputContent,
@@ -597657,7 +598547,7 @@ __export(daemonLogger_exports, {
597657
598547
  DaemonLogger: () => DaemonLogger
597658
598548
  });
597659
598549
  import { existsSync as existsSync38, statSync as statSync2, renameSync as renameSync2, writeFileSync as writeFileSync22, appendFileSync as appendFileSync2, mkdirSync as mkdirSync21 } from "fs";
597660
- import { join as join43, dirname as dirname12, basename as basename6 } from "path";
598550
+ import { join as join43, dirname as dirname12, basename as basename7 } from "path";
597661
598551
  var DaemonLogger;
597662
598552
  var init_daemonLogger = __esm({
597663
598553
  "dist/utils/sse/daemonLogger.js"() {
@@ -597748,7 +598638,7 @@ var init_daemonLogger = __esm({
597748
598638
  */
597749
598639
  rotate() {
597750
598640
  const logDir = dirname12(this.logFilePath);
597751
- const logFileName = basename6(this.logFilePath);
598641
+ const logFileName = basename7(this.logFilePath);
597752
598642
  const dateDir = this.getDateDirectory();
597753
598643
  const archiveDateDir = join43(logDir, "archive", dateDir);
597754
598644
  if (!existsSync38(archiveDateDir)) {
@@ -611097,7 +611987,7 @@ var require_package3 = __commonJS({
611097
611987
  "package.json"(exports2, module2) {
611098
611988
  module2.exports = {
611099
611989
  name: "snow-ai",
611100
- version: "0.7.32",
611990
+ version: "0.7.34",
611101
611991
  description: "Agentic coding in your terminal",
611102
611992
  license: "MIT",
611103
611993
  bin: {
@@ -611149,6 +612039,7 @@ var require_package3 = __commonJS({
611149
612039
  ],
611150
612040
  dependencies: {
611151
612041
  "@microsoft/signalr": "^10.0.0",
612042
+ "@vscode/ripgrep": "^1.18.0",
611152
612043
  "abort-controller": "^3.0.0",
611153
612044
  eventsource: "^2.0.2",
611154
612045
  "fetch-cookie": "^3.0.1",