snow-ai 0.7.29 → 0.7.31

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
@@ -48418,168 +48418,10 @@ var require_lib4 = __commonJS({
48418
48418
  }
48419
48419
  });
48420
48420
 
48421
- // dist/utils/core/logger.js
48422
- var logger_exports = {};
48423
- __export(logger_exports, {
48424
- LogLevel: () => LogLevel,
48425
- Logger: () => Logger,
48426
- default: () => logger_default,
48427
- logger: () => logger
48428
- });
48429
- import fs7 from "node:fs";
48430
- import path7 from "node:path";
48431
- import { homedir } from "node:os";
48432
- function getDefaultLogger() {
48433
- if (!_defaultLogger) {
48434
- _defaultLogger = new Logger();
48435
- }
48436
- return _defaultLogger;
48437
- }
48438
- var LogLevel, Logger, _defaultLogger, logger, logger_default;
48439
- var init_logger = __esm({
48440
- "dist/utils/core/logger.js"() {
48441
- "use strict";
48442
- (function(LogLevel3) {
48443
- LogLevel3[LogLevel3["ERROR"] = 0] = "ERROR";
48444
- LogLevel3[LogLevel3["WARN"] = 1] = "WARN";
48445
- LogLevel3[LogLevel3["INFO"] = 2] = "INFO";
48446
- LogLevel3[LogLevel3["DEBUG"] = 3] = "DEBUG";
48447
- })(LogLevel || (LogLevel = {}));
48448
- Logger = class {
48449
- constructor(config3 = {}) {
48450
- Object.defineProperty(this, "logDir", {
48451
- enumerable: true,
48452
- configurable: true,
48453
- writable: true,
48454
- value: void 0
48455
- });
48456
- Object.defineProperty(this, "maxFileSize", {
48457
- enumerable: true,
48458
- configurable: true,
48459
- writable: true,
48460
- value: void 0
48461
- });
48462
- this.logDir = config3.logDir || path7.join(homedir(), ".snow", "log");
48463
- this.maxFileSize = config3.maxFileSize || 10 * 1024 * 1024;
48464
- this.ensureLogDirectory();
48465
- }
48466
- ensureLogDirectory() {
48467
- if (!fs7.existsSync(this.logDir)) {
48468
- fs7.mkdirSync(this.logDir, { recursive: true });
48469
- }
48470
- }
48471
- formatDate(date5) {
48472
- const year = date5.getFullYear();
48473
- const month = String(date5.getMonth() + 1).padStart(2, "0");
48474
- const day = String(date5.getDate()).padStart(2, "0");
48475
- return `${year}-${month}-${day}`;
48476
- }
48477
- formatTimestamp(date5) {
48478
- return date5.toISOString();
48479
- }
48480
- getLogFilePath(level) {
48481
- const dateString = this.formatDate(/* @__PURE__ */ new Date());
48482
- const levelName = LogLevel[level].toLowerCase();
48483
- return path7.join(this.logDir, `${dateString}-${levelName}.log`);
48484
- }
48485
- shouldRotateLog(filePath) {
48486
- if (!fs7.existsSync(filePath)) {
48487
- return false;
48488
- }
48489
- const stats = fs7.statSync(filePath);
48490
- return stats.size >= this.maxFileSize;
48491
- }
48492
- rotateLog(filePath) {
48493
- const timestamp = Date.now();
48494
- const ext = path7.extname(filePath);
48495
- const basename7 = path7.basename(filePath, ext);
48496
- const dirname13 = path7.dirname(filePath);
48497
- const rotatedPath = path7.join(dirname13, `${basename7}-${timestamp}${ext}`);
48498
- fs7.renameSync(filePath, rotatedPath);
48499
- }
48500
- writeLog(level, message, meta) {
48501
- const timestamp = this.formatTimestamp(/* @__PURE__ */ new Date());
48502
- const levelName = LogLevel[level].toUpperCase().padEnd(5);
48503
- const logEntry = {
48504
- timestamp,
48505
- level: levelName.trim(),
48506
- message,
48507
- ...meta && { meta }
48508
- };
48509
- const logLine = JSON.stringify(logEntry) + "\n";
48510
- const filePath = this.getLogFilePath(level);
48511
- if (this.shouldRotateLog(filePath)) {
48512
- this.rotateLog(filePath);
48513
- }
48514
- fs7.appendFileSync(filePath, logLine, "utf8");
48515
- }
48516
- error(message, meta) {
48517
- this.writeLog(LogLevel.ERROR, message, meta);
48518
- }
48519
- warn(message, meta) {
48520
- this.writeLog(LogLevel.WARN, message, meta);
48521
- }
48522
- info(message, meta) {
48523
- this.writeLog(LogLevel.INFO, message, meta);
48524
- }
48525
- debug(message, meta) {
48526
- this.writeLog(LogLevel.DEBUG, message, meta);
48527
- }
48528
- log(level, message, meta) {
48529
- this.writeLog(level, message, meta);
48530
- }
48531
- };
48532
- _defaultLogger = null;
48533
- logger = {
48534
- error(message, meta) {
48535
- getDefaultLogger().error(message, meta);
48536
- },
48537
- warn(message, meta) {
48538
- getDefaultLogger().warn(message, meta);
48539
- },
48540
- info(message, meta) {
48541
- getDefaultLogger().info(message, meta);
48542
- },
48543
- debug(message, meta) {
48544
- getDefaultLogger().debug(message, meta);
48545
- },
48546
- log(level, message, meta) {
48547
- getDefaultLogger().log(level, message, meta);
48548
- }
48549
- };
48550
- logger_default = logger;
48551
- }
48552
- });
48553
-
48554
48421
  // dist/utils/config/workingDirConfig.js
48555
- import path8 from "path";
48422
+ import path7 from "path";
48556
48423
  import process17 from "process";
48557
- function getSnowDirPath() {
48558
- return path8.join(process17.cwd(), SNOW_DIR);
48559
- }
48560
- function getConfigFilePath() {
48561
- return path8.join(getSnowDirPath(), WORKING_DIR_FILE);
48562
- }
48563
- async function ensureSnowDir() {
48564
- const snowDir = getSnowDirPath();
48565
- try {
48566
- await import_fs_extra.default.ensureDir(snowDir);
48567
- } catch (error40) {
48568
- logger.error("Failed to create .snow directory", error40);
48569
- throw error40;
48570
- }
48571
- }
48572
- async function loadWorkingDirConfig() {
48573
- const configPath = getConfigFilePath();
48574
- try {
48575
- if (await import_fs_extra.default.pathExists(configPath)) {
48576
- const content = await import_fs_extra.default.readFile(configPath, "utf-8");
48577
- const config3 = JSON.parse(content);
48578
- return config3;
48579
- }
48580
- } catch (error40) {
48581
- logger.error("Failed to load working directory config", error40);
48582
- }
48424
+ function createDefaultWorkingDirConfig() {
48583
48425
  return {
48584
48426
  directories: [
48585
48427
  {
@@ -48590,18 +48432,26 @@ async function loadWorkingDirConfig() {
48590
48432
  ]
48591
48433
  };
48592
48434
  }
48593
- async function saveWorkingDirConfig(config3) {
48594
- await ensureSnowDir();
48595
- const configPath = getConfigFilePath();
48596
- try {
48597
- await import_fs_extra.default.writeFile(configPath, JSON.stringify(config3, null, 2), "utf-8");
48598
- } catch (error40) {
48599
- logger.error("Failed to save working directory config", error40);
48600
- throw error40;
48435
+ function toWorkingDirConfig(directories) {
48436
+ if (!Array.isArray(directories)) {
48437
+ return createDefaultWorkingDirConfig();
48601
48438
  }
48439
+ return {
48440
+ directories
48441
+ };
48442
+ }
48443
+ function loadWorkingDirConfig() {
48444
+ const settings = readSettings("project");
48445
+ return Promise.resolve(toWorkingDirConfig(settings.workingDirectories));
48446
+ }
48447
+ function saveWorkingDirConfig(config3) {
48448
+ updateSettings("project", (settings) => {
48449
+ settings.workingDirectories = config3.directories;
48450
+ });
48451
+ return Promise.resolve();
48602
48452
  }
48603
48453
  async function addWorkingDirectory(dirPath) {
48604
- const absolutePath = path8.resolve(dirPath);
48454
+ const absolutePath = path7.resolve(dirPath);
48605
48455
  try {
48606
48456
  const stats = await import_fs_extra.default.stat(absolutePath);
48607
48457
  if (!stats.isDirectory()) {
@@ -48656,14 +48506,12 @@ async function addSSHWorkingDirectory(sshConfig, remotePath, displayName) {
48656
48506
  await saveWorkingDirConfig(config3);
48657
48507
  return true;
48658
48508
  }
48659
- var import_fs_extra, SNOW_DIR, WORKING_DIR_FILE;
48509
+ var import_fs_extra;
48660
48510
  var init_workingDirConfig = __esm({
48661
48511
  "dist/utils/config/workingDirConfig.js"() {
48662
48512
  "use strict";
48663
48513
  import_fs_extra = __toESM(require_lib4(), 1);
48664
- init_logger();
48665
- SNOW_DIR = ".snow";
48666
- WORKING_DIR_FILE = "working-dirs.json";
48514
+ init_unifiedSettings();
48667
48515
  }
48668
48516
  });
48669
48517
 
@@ -51094,6 +50942,139 @@ var init_esm2 = __esm({
51094
50942
  }
51095
50943
  });
51096
50944
 
50945
+ // dist/utils/core/logger.js
50946
+ var logger_exports = {};
50947
+ __export(logger_exports, {
50948
+ LogLevel: () => LogLevel,
50949
+ Logger: () => Logger,
50950
+ default: () => logger_default,
50951
+ logger: () => logger
50952
+ });
50953
+ import fs8 from "node:fs";
50954
+ import path8 from "node:path";
50955
+ import { homedir } from "node:os";
50956
+ function getDefaultLogger() {
50957
+ if (!_defaultLogger) {
50958
+ _defaultLogger = new Logger();
50959
+ }
50960
+ return _defaultLogger;
50961
+ }
50962
+ var LogLevel, Logger, _defaultLogger, logger, logger_default;
50963
+ var init_logger = __esm({
50964
+ "dist/utils/core/logger.js"() {
50965
+ "use strict";
50966
+ (function(LogLevel3) {
50967
+ LogLevel3[LogLevel3["ERROR"] = 0] = "ERROR";
50968
+ LogLevel3[LogLevel3["WARN"] = 1] = "WARN";
50969
+ LogLevel3[LogLevel3["INFO"] = 2] = "INFO";
50970
+ LogLevel3[LogLevel3["DEBUG"] = 3] = "DEBUG";
50971
+ })(LogLevel || (LogLevel = {}));
50972
+ Logger = class {
50973
+ constructor(config3 = {}) {
50974
+ Object.defineProperty(this, "logDir", {
50975
+ enumerable: true,
50976
+ configurable: true,
50977
+ writable: true,
50978
+ value: void 0
50979
+ });
50980
+ Object.defineProperty(this, "maxFileSize", {
50981
+ enumerable: true,
50982
+ configurable: true,
50983
+ writable: true,
50984
+ value: void 0
50985
+ });
50986
+ this.logDir = config3.logDir || path8.join(homedir(), ".snow", "log");
50987
+ this.maxFileSize = config3.maxFileSize || 10 * 1024 * 1024;
50988
+ this.ensureLogDirectory();
50989
+ }
50990
+ ensureLogDirectory() {
50991
+ if (!fs8.existsSync(this.logDir)) {
50992
+ fs8.mkdirSync(this.logDir, { recursive: true });
50993
+ }
50994
+ }
50995
+ formatDate(date5) {
50996
+ const year = date5.getFullYear();
50997
+ const month = String(date5.getMonth() + 1).padStart(2, "0");
50998
+ const day = String(date5.getDate()).padStart(2, "0");
50999
+ return `${year}-${month}-${day}`;
51000
+ }
51001
+ formatTimestamp(date5) {
51002
+ return date5.toISOString();
51003
+ }
51004
+ getLogFilePath(level) {
51005
+ const dateString = this.formatDate(/* @__PURE__ */ new Date());
51006
+ const levelName = LogLevel[level].toLowerCase();
51007
+ return path8.join(this.logDir, `${dateString}-${levelName}.log`);
51008
+ }
51009
+ shouldRotateLog(filePath) {
51010
+ if (!fs8.existsSync(filePath)) {
51011
+ return false;
51012
+ }
51013
+ const stats = fs8.statSync(filePath);
51014
+ return stats.size >= this.maxFileSize;
51015
+ }
51016
+ rotateLog(filePath) {
51017
+ const timestamp = Date.now();
51018
+ const ext = path8.extname(filePath);
51019
+ const basename7 = path8.basename(filePath, ext);
51020
+ const dirname13 = path8.dirname(filePath);
51021
+ const rotatedPath = path8.join(dirname13, `${basename7}-${timestamp}${ext}`);
51022
+ fs8.renameSync(filePath, rotatedPath);
51023
+ }
51024
+ writeLog(level, message, meta) {
51025
+ const timestamp = this.formatTimestamp(/* @__PURE__ */ new Date());
51026
+ const levelName = LogLevel[level].toUpperCase().padEnd(5);
51027
+ const logEntry = {
51028
+ timestamp,
51029
+ level: levelName.trim(),
51030
+ message,
51031
+ ...meta && { meta }
51032
+ };
51033
+ const logLine = JSON.stringify(logEntry) + "\n";
51034
+ const filePath = this.getLogFilePath(level);
51035
+ if (this.shouldRotateLog(filePath)) {
51036
+ this.rotateLog(filePath);
51037
+ }
51038
+ fs8.appendFileSync(filePath, logLine, "utf8");
51039
+ }
51040
+ error(message, meta) {
51041
+ this.writeLog(LogLevel.ERROR, message, meta);
51042
+ }
51043
+ warn(message, meta) {
51044
+ this.writeLog(LogLevel.WARN, message, meta);
51045
+ }
51046
+ info(message, meta) {
51047
+ this.writeLog(LogLevel.INFO, message, meta);
51048
+ }
51049
+ debug(message, meta) {
51050
+ this.writeLog(LogLevel.DEBUG, message, meta);
51051
+ }
51052
+ log(level, message, meta) {
51053
+ this.writeLog(level, message, meta);
51054
+ }
51055
+ };
51056
+ _defaultLogger = null;
51057
+ logger = {
51058
+ error(message, meta) {
51059
+ getDefaultLogger().error(message, meta);
51060
+ },
51061
+ warn(message, meta) {
51062
+ getDefaultLogger().warn(message, meta);
51063
+ },
51064
+ info(message, meta) {
51065
+ getDefaultLogger().info(message, meta);
51066
+ },
51067
+ debug(message, meta) {
51068
+ getDefaultLogger().debug(message, meta);
51069
+ },
51070
+ log(level, message, meta) {
51071
+ getDefaultLogger().log(level, message, meta);
51072
+ }
51073
+ };
51074
+ logger_default = logger;
51075
+ }
51076
+ });
51077
+
51097
51078
  // node_modules/sql.js/dist/sql-wasm.js
51098
51079
  var require_sql_wasm = __commonJS({
51099
51080
  "node_modules/sql.js/dist/sql-wasm.js"(exports2, module2) {
@@ -57785,9 +57766,9 @@ import { createHash, randomUUID } from "crypto";
57785
57766
  import { existsSync as existsSync3, mkdirSync as mkdirSync2, readFileSync as readFileSync5, writeFileSync as writeFileSync2 } from "fs";
57786
57767
  import { homedir as homedir3 } from "os";
57787
57768
  import { join as join5 } from "path";
57788
- function ensureSnowDir2() {
57789
- if (!existsSync3(SNOW_DIR2)) {
57790
- mkdirSync2(SNOW_DIR2, { recursive: true });
57769
+ function ensureSnowDir() {
57770
+ if (!existsSync3(SNOW_DIR)) {
57771
+ mkdirSync2(SNOW_DIR, { recursive: true });
57791
57772
  }
57792
57773
  }
57793
57774
  function generateDevUserId() {
@@ -57796,7 +57777,7 @@ function generateDevUserId() {
57796
57777
  return `user_${hash}_account__session_${sessionId}`;
57797
57778
  }
57798
57779
  function getDevUserId() {
57799
- ensureSnowDir2();
57780
+ ensureSnowDir();
57800
57781
  if (existsSync3(DEV_USER_ID_FILE)) {
57801
57782
  const userId2 = readFileSync5(DEV_USER_ID_FILE, "utf-8").trim();
57802
57783
  if (userId2) {
@@ -57813,12 +57794,12 @@ function isDevMode() {
57813
57794
  function enableDevMode() {
57814
57795
  process.env["SNOW_DEV_MODE"] = "true";
57815
57796
  }
57816
- var SNOW_DIR2, DEV_USER_ID_FILE;
57797
+ var SNOW_DIR, DEV_USER_ID_FILE;
57817
57798
  var init_devMode = __esm({
57818
57799
  "dist/utils/core/devMode.js"() {
57819
57800
  "use strict";
57820
- SNOW_DIR2 = join5(homedir3(), ".snow");
57821
- DEV_USER_ID_FILE = join5(SNOW_DIR2, "dev-user-id");
57801
+ SNOW_DIR = join5(homedir3(), ".snow");
57802
+ DEV_USER_ID_FILE = join5(SNOW_DIR, "dev-user-id");
57822
57803
  }
57823
57804
  });
57824
57805
 
@@ -448379,7 +448360,7 @@ ${conversationTranscript}`
448379
448360
  return messages;
448380
448361
  }
448381
448362
  async function compressWithChatCompletions(modelName, conversationMessages, customSystemPrompts, options3) {
448382
- var _a20;
448363
+ var _a20, _b14;
448383
448364
  const messages = prepareMessagesForCompression(conversationMessages, customSystemPrompts);
448384
448365
  let summary = "";
448385
448366
  let usage = {
@@ -448392,8 +448373,11 @@ async function compressWithChatCompletions(modelName, conversationMessages, cust
448392
448373
  messages,
448393
448374
  stream: true
448394
448375
  })) {
448376
+ if (chunk2.type === "reasoning_delta" && chunk2.delta) {
448377
+ (_a20 = options3 == null ? void 0 : options3.onStreamStart) == null ? void 0 : _a20.call(options3, chunk2.delta);
448378
+ }
448395
448379
  if (chunk2.type === "content" && chunk2.content) {
448396
- (_a20 = options3 == null ? void 0 : options3.onStreamStart) == null ? void 0 : _a20.call(options3, chunk2.content);
448380
+ (_b14 = options3 == null ? void 0 : options3.onStreamStart) == null ? void 0 : _b14.call(options3, chunk2.content);
448397
448381
  summary += chunk2.content;
448398
448382
  }
448399
448383
  if (chunk2.type === "usage" && chunk2.usage) {
@@ -448410,7 +448394,7 @@ async function compressWithChatCompletions(modelName, conversationMessages, cust
448410
448394
  return { summary, usage };
448411
448395
  }
448412
448396
  async function compressWithResponses(modelName, conversationMessages, customSystemPrompts, options3) {
448413
- var _a20;
448397
+ var _a20, _b14;
448414
448398
  const messages = prepareMessagesForCompression(conversationMessages, customSystemPrompts);
448415
448399
  let summary = "";
448416
448400
  let usage = {
@@ -448423,8 +448407,11 @@ async function compressWithResponses(modelName, conversationMessages, customSyst
448423
448407
  messages,
448424
448408
  stream: true
448425
448409
  })) {
448410
+ if (chunk2.type === "reasoning_delta" && chunk2.delta) {
448411
+ (_a20 = options3 == null ? void 0 : options3.onStreamStart) == null ? void 0 : _a20.call(options3, chunk2.delta);
448412
+ }
448426
448413
  if (chunk2.type === "content" && chunk2.content) {
448427
- (_a20 = options3 == null ? void 0 : options3.onStreamStart) == null ? void 0 : _a20.call(options3, chunk2.content);
448414
+ (_b14 = options3 == null ? void 0 : options3.onStreamStart) == null ? void 0 : _b14.call(options3, chunk2.content);
448428
448415
  summary += chunk2.content;
448429
448416
  }
448430
448417
  if (chunk2.type === "usage" && chunk2.usage) {
@@ -448441,7 +448428,7 @@ async function compressWithResponses(modelName, conversationMessages, customSyst
448441
448428
  return { summary, usage };
448442
448429
  }
448443
448430
  async function compressWithGemini(modelName, conversationMessages, customSystemPrompts, options3) {
448444
- var _a20;
448431
+ var _a20, _b14;
448445
448432
  const messages = prepareMessagesForCompression(conversationMessages, customSystemPrompts);
448446
448433
  let summary = "";
448447
448434
  let usage = {
@@ -448453,8 +448440,11 @@ async function compressWithGemini(modelName, conversationMessages, customSystemP
448453
448440
  model: modelName,
448454
448441
  messages
448455
448442
  })) {
448443
+ if (chunk2.type === "reasoning_delta" && chunk2.delta) {
448444
+ (_a20 = options3 == null ? void 0 : options3.onStreamStart) == null ? void 0 : _a20.call(options3, chunk2.delta);
448445
+ }
448456
448446
  if (chunk2.type === "content" && chunk2.content) {
448457
- (_a20 = options3 == null ? void 0 : options3.onStreamStart) == null ? void 0 : _a20.call(options3, chunk2.content);
448447
+ (_b14 = options3 == null ? void 0 : options3.onStreamStart) == null ? void 0 : _b14.call(options3, chunk2.content);
448458
448448
  summary += chunk2.content;
448459
448449
  }
448460
448450
  if (chunk2.type === "usage" && chunk2.usage) {
@@ -448471,7 +448461,7 @@ async function compressWithGemini(modelName, conversationMessages, customSystemP
448471
448461
  return { summary, usage };
448472
448462
  }
448473
448463
  async function compressWithAnthropic(modelName, conversationMessages, customSystemPrompts, options3) {
448474
- var _a20;
448464
+ var _a20, _b14;
448475
448465
  const messages = prepareMessagesForCompression(conversationMessages, customSystemPrompts);
448476
448466
  let summary = "";
448477
448467
  let usage = {
@@ -448486,8 +448476,11 @@ async function compressWithAnthropic(modelName, conversationMessages, customSyst
448486
448476
  disableThinking: true
448487
448477
  // Context compression 不使用 Extended Thinking
448488
448478
  })) {
448479
+ if (chunk2.type === "reasoning_delta" && chunk2.delta) {
448480
+ (_a20 = options3 == null ? void 0 : options3.onStreamStart) == null ? void 0 : _a20.call(options3, chunk2.delta);
448481
+ }
448489
448482
  if (chunk2.type === "content" && chunk2.content) {
448490
- (_a20 = options3 == null ? void 0 : options3.onStreamStart) == null ? void 0 : _a20.call(options3, chunk2.content);
448483
+ (_b14 = options3 == null ? void 0 : options3.onStreamStart) == null ? void 0 : _b14.call(options3, chunk2.content);
448491
448484
  summary += chunk2.content;
448492
448485
  }
448493
448486
  if (chunk2.type === "usage" && chunk2.usage) {
@@ -451052,12 +451045,12 @@ function deleteTeamData(teamName) {
451052
451045
  return false;
451053
451046
  }
451054
451047
  }
451055
- var SNOW_DIR3, TEAMS_DIR;
451048
+ var SNOW_DIR2, TEAMS_DIR;
451056
451049
  var init_teamConfig = __esm({
451057
451050
  "dist/utils/team/teamConfig.js"() {
451058
451051
  "use strict";
451059
- SNOW_DIR3 = join21(homedir10(), ".snow");
451060
- TEAMS_DIR = join21(SNOW_DIR3, "teams");
451052
+ SNOW_DIR2 = join21(homedir10(), ".snow");
451053
+ TEAMS_DIR = join21(SNOW_DIR2, "teams");
451061
451054
  }
451062
451055
  });
451063
451056
 
@@ -451213,12 +451206,12 @@ function clearTasks(teamName) {
451213
451206
  writeTaskList(teamName, { tasks: [], updatedAt: (/* @__PURE__ */ new Date()).toISOString() });
451214
451207
  }
451215
451208
  }
451216
- var SNOW_DIR4, TEAMS_DIR2;
451209
+ var SNOW_DIR3, TEAMS_DIR2;
451217
451210
  var init_teamTaskList = __esm({
451218
451211
  "dist/utils/team/teamTaskList.js"() {
451219
451212
  "use strict";
451220
- SNOW_DIR4 = join22(homedir11(), ".snow");
451221
- TEAMS_DIR2 = join22(SNOW_DIR4, "teams");
451213
+ SNOW_DIR3 = join22(homedir11(), ".snow");
451214
+ TEAMS_DIR2 = join22(SNOW_DIR3, "teams");
451222
451215
  }
451223
451216
  });
451224
451217
 
@@ -469584,7 +469577,12 @@ async function appendUserMessageAndSyncContext(options3) {
469584
469577
  if (updatedSession) {
469585
469578
  const { convertSessionMessagesToUI: convertSessionMessagesToUI2 } = await Promise.resolve().then(() => (init_sessionConverter(), sessionConverter_exports));
469586
469579
  const uiMessages = convertSessionMessagesToUI2(updatedSession.messages);
469587
- setConversationContext2(updatedSession.id, uiMessages.length);
469580
+ const compressedSummaryIndex = uiMessages.findIndex((msg) => {
469581
+ var _a20;
469582
+ return (msg == null ? void 0 : msg.role) === "user" && ((_a20 = msg.content) == null ? void 0 : _a20.trim()) && !msg.subAgentDirected;
469583
+ });
469584
+ const snapshotMessageIndex = updatedSession.compressedFrom != null ? Math.max(0, compressedSummaryIndex) : uiMessages.length;
469585
+ setConversationContext2(updatedSession.id, snapshotMessageIndex);
469588
469586
  }
469589
469587
  } catch (error40) {
469590
469588
  console.error("Failed to set conversation context:", error40);
@@ -471636,26 +471634,71 @@ async function executeContextCompression(sessionId, onStatusUpdate) {
471636
471634
  let compressionStreamStarted = false;
471637
471635
  let compressionStreamScore = 0;
471638
471636
  let compressionProgress = 0;
471639
- const notifyCompressionStreamStarted = (content) => {
471640
- compressionStreamStarted = true;
471641
- compressionStreamScore += Math.max(1, Math.ceil(((content == null ? void 0 : content.length) ?? 0) / 1500));
471642
- const nextProgress = Math.min(90, 10 + Math.floor((1 - Math.exp(-compressionStreamScore / 800)) * 80));
471643
- if (nextProgress <= compressionProgress) {
471644
- return;
471637
+ let compressionStreamLineBuffer = "";
471638
+ const compressionStreamLines = [];
471639
+ const MAX_COMPRESSION_STREAM_LINES = 80;
471640
+ const MAX_COMPRESSION_STREAM_LINE_LENGTH = 120;
471641
+ const appendCompressionStreamLine = (line) => {
471642
+ compressionStreamLines.push(line);
471643
+ if (compressionStreamLines.length > MAX_COMPRESSION_STREAM_LINES) {
471644
+ compressionStreamLines.splice(0, compressionStreamLines.length - MAX_COMPRESSION_STREAM_LINES);
471645
471645
  }
471646
- compressionProgress = nextProgress;
471646
+ };
471647
+ const emitCompressionStreamUpdate = () => {
471647
471648
  onStatusUpdate == null ? void 0 : onStatusUpdate({
471648
471649
  step: "compressing",
471649
471650
  sessionId,
471650
471651
  progress: compressionProgress,
471651
- streamStarted: compressionStreamStarted
471652
+ streamStarted: compressionStreamStarted,
471653
+ streamContent: compressionStreamLines.join("\n")
471652
471654
  });
471653
471655
  };
471656
+ const flushCompressionStreamBuffer = (force = false) => {
471657
+ if (!compressionStreamStarted) {
471658
+ return;
471659
+ }
471660
+ if (force && compressionStreamLineBuffer) {
471661
+ appendCompressionStreamLine(compressionStreamLineBuffer);
471662
+ compressionStreamLineBuffer = "";
471663
+ }
471664
+ if (compressionStreamLines.length === 0) {
471665
+ return;
471666
+ }
471667
+ emitCompressionStreamUpdate();
471668
+ };
471669
+ const notifyCompressionStreamStarted = (content) => {
471670
+ if (!content) {
471671
+ return;
471672
+ }
471673
+ compressionStreamStarted = true;
471674
+ compressionStreamLineBuffer += content.replace(/\r\n?/g, "\n");
471675
+ let shouldEmit = false;
471676
+ const lineParts = compressionStreamLineBuffer.split("\n");
471677
+ compressionStreamLineBuffer = lineParts.pop() ?? "";
471678
+ for (const line of lineParts) {
471679
+ appendCompressionStreamLine(line);
471680
+ shouldEmit = true;
471681
+ }
471682
+ while (compressionStreamLineBuffer.length >= MAX_COMPRESSION_STREAM_LINE_LENGTH) {
471683
+ appendCompressionStreamLine(compressionStreamLineBuffer.slice(0, MAX_COMPRESSION_STREAM_LINE_LENGTH));
471684
+ compressionStreamLineBuffer = compressionStreamLineBuffer.slice(MAX_COMPRESSION_STREAM_LINE_LENGTH);
471685
+ shouldEmit = true;
471686
+ }
471687
+ compressionStreamScore += Math.max(1, Math.ceil(content.length / 1500));
471688
+ const nextProgress = Math.min(90, 10 + Math.floor((1 - Math.exp(-compressionStreamScore / 800)) * 80));
471689
+ if (nextProgress > compressionProgress) {
471690
+ compressionProgress = nextProgress;
471691
+ }
471692
+ if (shouldEmit) {
471693
+ emitCompressionStreamUpdate();
471694
+ }
471695
+ };
471654
471696
  onStatusUpdate == null ? void 0 : onStatusUpdate({
471655
471697
  step: "compressing",
471656
471698
  sessionId,
471657
471699
  progress: 0,
471658
- streamStarted: false
471700
+ streamStarted: false,
471701
+ streamContent: ""
471659
471702
  });
471660
471703
  if (useHybridCompress) {
471661
471704
  const apiConfig = getSnowConfig();
@@ -471665,6 +471708,7 @@ async function executeContextCompression(sessionId, onStatusUpdate) {
471665
471708
  maxTokens: apiConfig.maxTokens,
471666
471709
  onStreamStart: notifyCompressionStreamStarted
471667
471710
  });
471711
+ flushCompressionStreamBuffer(true);
471668
471712
  if (!hybridResult.compressed) {
471669
471713
  onStatusUpdate == null ? void 0 : onStatusUpdate({
471670
471714
  step: "skipped",
@@ -471701,6 +471745,7 @@ ${first3.content || ""}`;
471701
471745
  compressedSession2.summary = currentSession.summary;
471702
471746
  compressedSession2.compressedFrom = currentSession.id;
471703
471747
  compressedSession2.compressedAt = Date.now();
471748
+ compressedSession2.originalMessageIndex = currentSession.messages.length;
471704
471749
  if (currentSession.hasGoal) {
471705
471750
  compressedSession2.hasGoal = true;
471706
471751
  }
@@ -471746,6 +471791,7 @@ ${first3.content || ""}`;
471746
471791
  const compressionResult = await compressContext(chatMessages, {
471747
471792
  onStreamStart: notifyCompressionStreamStarted
471748
471793
  });
471794
+ flushCompressionStreamBuffer(true);
471749
471795
  if (!compressionResult) {
471750
471796
  onStatusUpdate == null ? void 0 : onStatusUpdate({
471751
471797
  step: "skipped",
@@ -473003,7 +473049,12 @@ async function handlePendingMessages(options3) {
473003
473049
  if (updatedSession) {
473004
473050
  const { convertSessionMessagesToUI: convertSessionMessagesToUI2 } = await Promise.resolve().then(() => (init_sessionConverter(), sessionConverter_exports));
473005
473051
  const uiMessages = convertSessionMessagesToUI2(updatedSession.messages);
473006
- setConversationContext2(updatedSession.id, uiMessages.length);
473052
+ const compressedSummaryIndex = uiMessages.findIndex((msg) => {
473053
+ var _a20;
473054
+ return (msg == null ? void 0 : msg.role) === "user" && ((_a20 = msg.content) == null ? void 0 : _a20.trim()) && !msg.subAgentDirected;
473055
+ });
473056
+ const snapshotMessageIndex = updatedSession.compressedFrom != null ? Math.max(0, compressedSummaryIndex) : uiMessages.length;
473057
+ setConversationContext2(updatedSession.id, snapshotMessageIndex);
473007
473058
  }
473008
473059
  } catch (error40) {
473009
473060
  console.error("Failed to save pending user message:", error40);
@@ -567474,7 +567525,7 @@ function getSystemEditor2() {
567474
567525
  }
567475
567526
  return null;
567476
567527
  }
567477
- function getConfigFilePath2(scope) {
567528
+ function getConfigFilePath(scope) {
567478
567529
  if (scope === "project") {
567479
567530
  return join36(process.cwd(), ".snow", "mcp-config.draft.json");
567480
567531
  }
@@ -567484,7 +567535,7 @@ function getConfigByScope(scope) {
567484
567535
  return scope === "project" ? getProjectMCPConfig() : getGlobalMCPConfig();
567485
567536
  }
567486
567537
  function openEditorForScope(scope, onBack, i18nMessages) {
567487
- const configFilePath = getConfigFilePath2(scope);
567538
+ const configFilePath = getConfigFilePath(scope);
567488
567539
  const config3 = getConfigByScope(scope);
567489
567540
  const originalContent = JSON.stringify(config3, null, 2);
567490
567541
  const dir = join36(configFilePath, "..");
@@ -568120,6 +568171,66 @@ var init_WelcomeScreen = __esm({
568120
568171
  function sanitizeInput2(str2) {
568121
568172
  return str2.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/\t/g, " ").replace(/\x1b\[[IO]/g, "").replace(/(^|\s+)\[(?:I|O)(?=(?:\s|$|["'~\\\/]|[A-Za-z]:))/g, "$1").replace(/[\x00-\x08\x0B\x0C\x0E-\x1F\x7F]/g, "");
568122
568173
  }
568174
+ function decodeStrictBase64(base64Data) {
568175
+ if (base64Data.length <= 100)
568176
+ return null;
568177
+ if (base64Data.length % 4 !== 0)
568178
+ return null;
568179
+ if (!/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(base64Data))
568180
+ return null;
568181
+ const decoded = Buffer.from(base64Data, "base64");
568182
+ if (decoded.length === 0)
568183
+ return null;
568184
+ return decoded;
568185
+ }
568186
+ function hasAscii(bytes, offset, text2) {
568187
+ if (bytes.length < offset + text2.length)
568188
+ return false;
568189
+ for (let index = 0; index < text2.length; index += 1) {
568190
+ if (bytes[offset + index] !== text2.charCodeAt(index))
568191
+ return false;
568192
+ }
568193
+ return true;
568194
+ }
568195
+ function hasPngSignature(bytes) {
568196
+ const signature = [137, 80, 78, 71, 13, 10, 26, 10];
568197
+ return signature.every((value, index) => bytes[index] === value);
568198
+ }
568199
+ function isCompleteImageData(bytes, mimeType) {
568200
+ if (mimeType === "image/png") {
568201
+ return bytes.length >= 45 && hasPngSignature(bytes) && bytes[bytes.length - 12] === 0 && bytes[bytes.length - 11] === 0 && bytes[bytes.length - 10] === 0 && bytes[bytes.length - 9] === 0 && hasAscii(bytes, bytes.length - 8, "IEND");
568202
+ }
568203
+ if (mimeType === "image/jpeg") {
568204
+ return bytes.length >= 4 && bytes[0] === 255 && bytes[1] === 216 && bytes[bytes.length - 2] === 255 && bytes[bytes.length - 1] === 217;
568205
+ }
568206
+ if (mimeType === "image/gif") {
568207
+ return bytes.length >= 14 && (hasAscii(bytes, 0, "GIF87a") || hasAscii(bytes, 0, "GIF89a")) && bytes[bytes.length - 1] === 59;
568208
+ }
568209
+ if (mimeType === "image/webp") {
568210
+ if (bytes.length < 20 || !hasAscii(bytes, 0, "RIFF") || !hasAscii(bytes, 8, "WEBP")) {
568211
+ return false;
568212
+ }
568213
+ const riffSize = (bytes.at(4) ?? 0) + (bytes.at(5) ?? 0) * 256 + (bytes.at(6) ?? 0) * 65536 + (bytes.at(7) ?? 0) * 16777216;
568214
+ return riffSize === bytes.length - 8;
568215
+ }
568216
+ return false;
568217
+ }
568218
+ function parsePastedImageDataUrl(input2) {
568219
+ const trimmed = input2.trim();
568220
+ if (!trimmed)
568221
+ return null;
568222
+ const markdownImageMatch = trimmed.match(/^!\[[^\]]*\]\((data:image\/(?:png|jpe?g|gif|webp);base64,[\s\S]+)\)$/i);
568223
+ const dataUrl = (markdownImageMatch == null ? void 0 : markdownImageMatch[1]) ?? trimmed;
568224
+ const dataUrlMatch = dataUrl.match(/^data:(image\/(?:png|jpe?g|gif|webp));base64,([\s\S]+)$/i);
568225
+ if (!dataUrlMatch)
568226
+ return null;
568227
+ const mimeType = (dataUrlMatch[1] || "image/png").toLowerCase().replace("image/jpg", "image/jpeg");
568228
+ const base64Data = (dataUrlMatch[2] || "").replace(/\s/g, "");
568229
+ const decoded = decodeStrictBase64(base64Data);
568230
+ if (!decoded || !isCompleteImageData(decoded, mimeType))
568231
+ return null;
568232
+ return { base64Data, mimeType };
568233
+ }
568123
568234
  var TextBuffer;
568124
568235
  var init_textBuffer = __esm({
568125
568236
  "dist/utils/ui/textBuffer.js"() {
@@ -568373,6 +568484,13 @@ var init_textBuffer = __esm({
568373
568484
  if (!sanitized) {
568374
568485
  return;
568375
568486
  }
568487
+ const pastedImage = parsePastedImageDataUrl(sanitized);
568488
+ if (pastedImage) {
568489
+ this.lastTextPlaceholderId = null;
568490
+ this.lastTextPlaceholderAt = 0;
568491
+ this.insertImage(pastedImage.base64Data, pastedImage.mimeType);
568492
+ return;
568493
+ }
568376
568494
  const charCount = sanitized.length;
568377
568495
  const hasPastingIndicator = this.tempPastingPlaceholder !== null;
568378
568496
  if (this.tempPastingPlaceholder) {
@@ -568460,8 +568578,8 @@ var init_textBuffer = __esm({
568460
568578
  * 与 insertPastingIndicator 共用 tempPastingPlaceholder 字段,
568461
568579
  * 任意时刻只允许一个临时占位符存在。
568462
568580
  */
568463
- insertImageLoadingIndicator() {
568464
- if (this.tempPastingPlaceholder) {
568581
+ insertImageLoadingIndicator(isImagePaste) {
568582
+ if (!isImagePaste || this.tempPastingPlaceholder) {
568465
568583
  return;
568466
568584
  }
568467
568585
  this.tempPastingPlaceholder = `[image upload...]`;
@@ -570537,21 +570655,53 @@ import { exec as exec8 } from "child_process";
570537
570655
  import { promisify as promisify3 } from "util";
570538
570656
  function useClipboard(buffer, updateCommandPanelState, updateFilePickerState, triggerUpdate) {
570539
570657
  const pasteFromClipboard = (0, import_react99.useCallback)(async () => {
570540
- buffer.insertImageLoadingIndicator();
570541
- {
570658
+ let imageInserted = false;
570659
+ let imageLoadingIndicatorShown = false;
570660
+ const showImageLoadingIndicator = async () => {
570661
+ if (imageLoadingIndicatorShown) {
570662
+ return;
570663
+ }
570664
+ imageLoadingIndicatorShown = true;
570665
+ buffer.insertImageLoadingIndicator(true);
570542
570666
  const text2 = buffer.getFullText();
570543
570667
  const cursorPos = buffer.getCursorPosition();
570544
570668
  updateCommandPanelState(text2);
570545
570669
  updateFilePickerState(text2, cursorPos);
570546
- }
570547
- triggerUpdate();
570548
- await new Promise((resolve13) => setTimeout(resolve13, 0));
570549
- let imageInserted = false;
570670
+ triggerUpdate();
570671
+ await new Promise((resolve13) => setTimeout(resolve13, 0));
570672
+ };
570673
+ const insertClipboardText = (clipboardText) => {
570674
+ if (!clipboardText) {
570675
+ return false;
570676
+ }
570677
+ buffer.insert(clipboardText);
570678
+ const fullText = buffer.getFullText();
570679
+ const cursorPos = buffer.getCursorPosition();
570680
+ updateCommandPanelState(fullText);
570681
+ updateFilePickerState(fullText, cursorPos);
570682
+ triggerUpdate();
570683
+ return true;
570684
+ };
570550
570685
  try {
570551
570686
  const isWslEnv = process.platform === "linux" && isWSL();
570552
570687
  const psCmd = isWslEnv ? "powershell.exe" : "powershell";
570553
570688
  if (process.platform === "win32" || isWslEnv) {
570554
570689
  try {
570690
+ const probeScript = "Add-Type -AssemblyName System.Windows.Forms; $hasImage = [System.Windows.Forms.Clipboard]::ContainsImage(); $textBase64 = ''; if (-not $hasImage) { $text = [System.Windows.Forms.Clipboard]::GetText(); if ($null -eq $text) { $text = '' }; $textBase64 = [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($text)); }; Write-Output $hasImage; Write-Output $textBase64";
570691
+ const encodedProbe = Buffer.from(probeScript, "utf16le").toString("base64");
570692
+ const { stdout: probeStdout } = await execAsync3(`${psCmd} -NoProfile -EncodedCommand ${encodedProbe}`, {
570693
+ encoding: "utf-8",
570694
+ timeout: 2e3,
570695
+ maxBuffer: 10 * 1024 * 1024
570696
+ });
570697
+ const [hasImageLine = "", ...textBase64Lines] = probeStdout.split(/\r?\n/);
570698
+ if (!/^true$/i.test(hasImageLine.trim())) {
570699
+ const textBase64 = textBase64Lines.join("").replace(/\s/g, "");
570700
+ const clipboardText = textBase64 ? Buffer.from(textBase64, "base64").toString("utf8") : "";
570701
+ insertClipboardText(clipboardText);
570702
+ return;
570703
+ }
570704
+ await showImageLoadingIndicator();
570555
570705
  const psScript = "Add-Type -AssemblyName System.Windows.Forms; Add-Type -AssemblyName System.Drawing; $clipboard = [System.Windows.Forms.Clipboard]::GetImage(); if ($clipboard -ne $null) { $ms = New-Object System.IO.MemoryStream; $width = $clipboard.Width; $height = $clipboard.Height; $maxSize = 2048; if ($width -gt $maxSize -or $height -gt $maxSize) { $ratio = [Math]::Min($maxSize / $width, $maxSize / $height); $newWidth = [int]($width * $ratio); $newHeight = [int]($height * $ratio); $resized = New-Object System.Drawing.Bitmap($newWidth, $newHeight); $graphics = [System.Drawing.Graphics]::FromImage($resized); $graphics.CompositingQuality = [System.Drawing.Drawing2D.CompositingQuality]::HighQuality; $graphics.InterpolationMode = [System.Drawing.Drawing2D.InterpolationMode]::HighQualityBicubic; $graphics.SmoothingMode = [System.Drawing.Drawing2D.SmoothingMode]::HighQuality; $graphics.DrawImage($clipboard, 0, 0, $newWidth, $newHeight); $resized.Save($ms, [System.Drawing.Imaging.ImageFormat]::Png); $graphics.Dispose(); $resized.Dispose(); } else { $clipboard.Save($ms, [System.Drawing.Imaging.ImageFormat]::Png); }; $bytes = $ms.ToArray(); $ms.Close(); [Convert]::ToBase64String($bytes); }";
570556
570706
  let base64Raw;
570557
570707
  if (isWslEnv) {
@@ -570598,6 +570748,7 @@ end try'`;
570598
570748
  });
570599
570749
  const hasImage = hasImageStdout.trim();
570600
570750
  if (hasImage === "hasImage") {
570751
+ await showImageLoadingIndicator();
570601
570752
  const tmpFile = `/tmp/snow_clipboard_${Date.now()}.png`;
570602
570753
  const saveScript = `osascript -e 'set imgData to the clipboard as \xABclass PNGf\xBB' -e 'set fileRef to open for access POSIX file "${tmpFile}" with write permission' -e 'write imgData to fileRef' -e 'close access fileRef'`;
570603
570754
  await execAsync3(saveScript, {
@@ -570651,11 +570802,14 @@ end try'`;
570651
570802
  try {
570652
570803
  let clipboardText = "";
570653
570804
  if (process.platform === "win32" || isWslEnv) {
570654
- const { stdout } = await execAsync3(`${psCmd} -NoProfile -Command "Get-Clipboard"`, {
570805
+ const textScript = "Add-Type -AssemblyName System.Windows.Forms; $text = [System.Windows.Forms.Clipboard]::GetText(); if ($null -eq $text) { $text = '' }; [Convert]::ToBase64String([System.Text.Encoding]::UTF8.GetBytes($text))";
570806
+ const encoded = Buffer.from(textScript, "utf16le").toString("base64");
570807
+ const { stdout } = await execAsync3(`${psCmd} -NoProfile -EncodedCommand ${encoded}`, {
570655
570808
  encoding: "utf-8",
570656
- timeout: 2e3
570809
+ timeout: 2e3,
570810
+ maxBuffer: 10 * 1024 * 1024
570657
570811
  });
570658
- clipboardText = stdout.trim();
570812
+ clipboardText = Buffer.from(stdout.replace(/\s/g, ""), "base64").toString("utf8");
570659
570813
  } else if (process.platform === "darwin") {
570660
570814
  const { stdout } = await execAsync3("pbpaste", {
570661
570815
  encoding: "utf-8",
@@ -570669,14 +570823,7 @@ end try'`;
570669
570823
  });
570670
570824
  clipboardText = stdout.trim();
570671
570825
  }
570672
- if (clipboardText) {
570673
- buffer.insert(clipboardText);
570674
- const fullText = buffer.getFullText();
570675
- const cursorPos = buffer.getCursorPosition();
570676
- updateCommandPanelState(fullText);
570677
- updateFilePickerState(fullText, cursorPos);
570678
- triggerUpdate();
570679
- }
570826
+ insertClipboardText(clipboardText);
570680
570827
  } catch (textError) {
570681
570828
  logger.error("Failed to read text from clipboard:", textError);
570682
570829
  }
@@ -571557,8 +571704,9 @@ var init_editing = __esm({
571557
571704
  function clipboardHandler(ctx) {
571558
571705
  const { input: input2, key, options: options3, refs } = ctx;
571559
571706
  const { pasteFromClipboard } = options3;
571560
- const isPasteShortcut = process.platform === "darwin" ? key.ctrl && input2 === "v" : key.meta && input2 === "v";
571561
- if (isPasteShortcut) {
571707
+ const isLegacyImagePasteShortcut = process.platform === "darwin" ? key.ctrl && input2 === "v" : key.meta && input2 === "v";
571708
+ const isForwardedSystemPasteShortcut = process.platform !== "darwin" && key.ctrl && input2 === "v";
571709
+ if (isLegacyImagePasteShortcut || isForwardedSystemPasteShortcut) {
571562
571710
  refs.lastPasteShortcutAt.current = Date.now();
571563
571711
  pasteFromClipboard();
571564
571712
  return true;
@@ -571675,7 +571823,8 @@ function commandPanelHandler(ctx) {
571675
571823
  const selectedCommand = filteredCommands[commandSelectedIndex];
571676
571824
  if (selectedCommand) {
571677
571825
  if (inlineTrigger) {
571678
- buffer.replaceRange(inlineTrigger.slashIndex, inlineTrigger.endIndex, "/" + selectedCommand.name);
571826
+ const inlineInsertionText = !inlineTrigger.isAtStart && isInlineInsertionCommand(selectedCommand) ? selectedCommand.insertionText : void 0;
571827
+ buffer.replaceRange(inlineTrigger.slashIndex, inlineTrigger.endIndex, inlineInsertionText ?? "/" + selectedCommand.name);
571679
571828
  } else {
571680
571829
  buffer.setText("/" + selectedCommand.name);
571681
571830
  buffer.setCursorPosition(buffer.text.length);
@@ -572029,7 +572178,8 @@ function regularInputHandler(ctx) {
572029
572178
  const now = Date.now();
572030
572179
  const isPasteShortcutActive = now - refs.lastPasteShortcutAt.current <= pasteShortcutTimeoutMs;
572031
572180
  const isSingleCharInput = input2.length === 1;
572032
- const isSmallMultiCharInput = input2.length > 1 && !input2.includes("\n");
572181
+ const looksLikeImageDataPaste = /data:image\/(?:png|jpe?g|gif|webp);base64,/i.test(input2);
572182
+ const isSmallMultiCharInput = input2.length > 1 && input2.length <= pasteIndicatorThreshold && !input2.includes("\n") && !looksLikeImageDataPaste;
572033
572183
  if (isSingleCharInput && !refs.isProcessingInput.current) {
572034
572184
  buffer.insert(input2);
572035
572185
  const text2 = buffer.getFullText();
@@ -577226,7 +577376,7 @@ function getDelayAwareColor(waitingSeconds, baseColor, criticalColor) {
577226
577376
  }
577227
577377
  return baseColor;
577228
577378
  }
577229
- function LoadingIndicator({ isStreaming, isStopping, isSaving, isCompressing, hasPendingToolConfirmation, hasPendingUserQuestion, hasBlockingOverlay, terminalWidth, animationFrame, retryStatus, codebaseSearchStatus, isReasoning, streamTokenCount, elapsedSeconds, currentModel, teamMode }) {
577379
+ function LoadingIndicator({ isStreaming, isStopping, isSaving, isCompressing, isAutoCompressing = false, hasPendingToolConfirmation, hasPendingUserQuestion, hasBlockingOverlay, terminalWidth, animationFrame, retryStatus, codebaseSearchStatus, isReasoning, streamTokenCount, elapsedSeconds, currentModel, teamMode }) {
577230
577380
  const { theme: theme14 } = useTheme();
577231
577381
  const { t } = useI18n();
577232
577382
  const teammateStream = (0, import_react124.useSyncExternalStore)(subscribeTeammateStream, getTeammateStreamSnapshot);
@@ -577238,11 +577388,12 @@ function LoadingIndicator({ isStreaming, isStopping, isSaving, isCompressing, ha
577238
577388
  ].join("|");
577239
577389
  const previousStreamActivityMarkerRef = (0, import_react124.useRef)(null);
577240
577390
  const lastStreamActivityElapsedSecondsRef = (0, import_react124.useRef)(elapsedSeconds);
577241
- if (!isStreaming || isCompressing || previousStreamActivityMarkerRef.current !== streamActivityMarker) {
577391
+ const shouldIgnoreStreamDelay = isCompressing || isAutoCompressing;
577392
+ if (!isStreaming || shouldIgnoreStreamDelay || previousStreamActivityMarkerRef.current !== streamActivityMarker) {
577242
577393
  previousStreamActivityMarkerRef.current = streamActivityMarker;
577243
577394
  lastStreamActivityElapsedSecondsRef.current = elapsedSeconds;
577244
577395
  }
577245
- const waitingForStreamSeconds = isStreaming && !isCompressing ? Math.max(0, elapsedSeconds - lastStreamActivityElapsedSecondsRef.current) : 0;
577396
+ const waitingForStreamSeconds = isStreaming && !shouldIgnoreStreamDelay ? Math.max(0, elapsedSeconds - lastStreamActivityElapsedSecondsRef.current) : 0;
577246
577397
  const streamDelayStage = getStreamDelayStage(waitingForStreamSeconds);
577247
577398
  const loadingShimmerColors = STREAM_DELAY_SHIMMER_COLORS[streamDelayStage];
577248
577399
  const loadingIconColor = getDelayAwareColor(waitingForStreamSeconds, [theme14.colors.cyan, theme14.colors.menuInfo][animationFrame % 2], STREAM_DELAY_SHIMMER_COLORS.critical.base);
@@ -579286,7 +579437,7 @@ var init_ChatFooter = __esm({
579286
579437
  !props.showReviewCommitPanel && !props.showIdeSelectPanel && !props.showDiffReviewPanel && !props.showSkillsListPanel && import_react132.default.createElement(
579287
579438
  import_react132.default.Fragment,
579288
579439
  null,
579289
- import_react132.default.createElement(LoadingIndicator, { isStreaming: props.isStreaming, isStopping: props.isStopping, isSaving: props.isSaving, isCompressing: props.isCompressing, hasPendingToolConfirmation: props.hasPendingToolConfirmation, hasPendingUserQuestion: props.hasPendingUserQuestion, hasBlockingOverlay: props.hasBlockingOverlay, terminalWidth: props.terminalWidth, animationFrame: props.animationFrame, retryStatus: props.retryStatus, codebaseSearchStatus: props.codebaseSearchStatus, isReasoning: props.isReasoning, streamTokenCount: props.streamTokenCount, elapsedSeconds: props.elapsedSeconds, currentModel: props.currentModel, teamMode: props.teamMode }),
579440
+ import_react132.default.createElement(LoadingIndicator, { isStreaming: props.isStreaming, isStopping: props.isStopping, isSaving: props.isSaving, isCompressing: props.isCompressing, isAutoCompressing: props.isAutoCompressing, hasPendingToolConfirmation: props.hasPendingToolConfirmation, hasPendingUserQuestion: props.hasPendingUserQuestion, hasBlockingOverlay: props.hasBlockingOverlay, terminalWidth: props.terminalWidth, animationFrame: props.animationFrame, retryStatus: props.retryStatus, codebaseSearchStatus: props.codebaseSearchStatus, isReasoning: props.isReasoning, streamTokenCount: props.streamTokenCount, elapsedSeconds: props.elapsedSeconds, currentModel: props.currentModel, teamMode: props.teamMode }),
579290
579441
  props.btwPrompt ? import_react132.default.createElement(
579291
579442
  import_react132.Suspense,
579292
579443
  { fallback: import_react132.default.createElement(
@@ -579451,14 +579602,14 @@ var init_useSessionSave = __esm({
579451
579602
  // dist/utils/config/permissionsConfig.js
579452
579603
  import { join as join39 } from "path";
579453
579604
  import { readFileSync as readFileSync26, writeFileSync as writeFileSync19, existsSync as existsSync35, mkdirSync as mkdirSync18 } from "fs";
579454
- function getSnowDirPath2(workingDirectory) {
579455
- return join39(workingDirectory, SNOW_DIR5);
579605
+ function getSnowDirPath(workingDirectory) {
579606
+ return join39(workingDirectory, SNOW_DIR4);
579456
579607
  }
579457
579608
  function getPermissionsFilePath(workingDirectory) {
579458
- return join39(getSnowDirPath2(workingDirectory), PERMISSIONS_FILE);
579609
+ return join39(getSnowDirPath(workingDirectory), PERMISSIONS_FILE);
579459
579610
  }
579460
579611
  function ensureConfigDirectory7(workingDirectory) {
579461
- const snowDir = getSnowDirPath2(workingDirectory);
579612
+ const snowDir = getSnowDirPath(workingDirectory);
579462
579613
  if (!existsSync35(snowDir)) {
579463
579614
  mkdirSync18(snowDir, { recursive: true });
579464
579615
  }
@@ -579522,11 +579673,11 @@ function removeToolFromPermissions(workingDirectory, toolName) {
579522
579673
  function clearAllPermissions(workingDirectory) {
579523
579674
  savePermissionsConfig(workingDirectory, { alwaysApprovedTools: [] });
579524
579675
  }
579525
- var SNOW_DIR5, PERMISSIONS_FILE, DEFAULT_CONFIG6;
579676
+ var SNOW_DIR4, PERMISSIONS_FILE, DEFAULT_CONFIG6;
579526
579677
  var init_permissionsConfig = __esm({
579527
579678
  "dist/utils/config/permissionsConfig.js"() {
579528
579679
  "use strict";
579529
- SNOW_DIR5 = ".snow";
579680
+ SNOW_DIR4 = ".snow";
579530
579681
  PERMISSIONS_FILE = "permissions.json";
579531
579682
  DEFAULT_CONFIG6 = {
579532
579683
  alwaysApprovedTools: []
@@ -580276,6 +580427,14 @@ function resolveSnapshotIndex(liveMessages, liveIndex, sessionMessages) {
580276
580427
  }
580277
580428
  return liveIndex;
580278
580429
  }
580430
+ function getCompressedSummarySnapshotIndex(sessionMessages) {
580431
+ const uiMessages = convertSessionMessagesToUI(sessionMessages);
580432
+ const firstUserIndex = uiMessages.findIndex((msg) => {
580433
+ var _a20;
580434
+ return (msg == null ? void 0 : msg.role) === "user" && ((_a20 = msg.content) == null ? void 0 : _a20.trim()) && !msg.subAgentDirected;
580435
+ });
580436
+ return firstUserIndex >= 0 ? firstUserIndex : 0;
580437
+ }
580279
580438
  function useRollback(props) {
580280
580439
  const { messages, setMessages, snapshotState, clearSavedMessages, setRemountKey, setRestoreInputContent, currentContextPercentageRef, streamingState } = props;
580281
580440
  const { stdout } = use_stdout_default();
@@ -580299,7 +580458,7 @@ function useRollback(props) {
580299
580458
  const performRollback = async (selectedIndex, rollbackFiles, rollbackConversation, selectedFiles) => {
580300
580459
  var _a20;
580301
580460
  const currentSession = sessionManager.getCurrentSession();
580302
- const sIdx = getSnapshotIndex(selectedIndex);
580461
+ const sIdx = (currentSession == null ? void 0 : currentSession.compressedFrom) != null && selectedIndex === 0 ? getCompressedSummarySnapshotIndex(currentSession.messages) : getSnapshotIndex(selectedIndex);
580303
580462
  if (rollbackFiles && currentSession) {
580304
580463
  if (selectedFiles && selectedFiles.length > 0) {
580305
580464
  await hashBasedSnapshotManager.rollbackToMessageIndex(currentSession.id, sIdx, selectedFiles);
@@ -580449,7 +580608,8 @@ function useRollback(props) {
580449
580608
  const currentSession = sessionManager.getCurrentSession();
580450
580609
  if (!currentSession)
580451
580610
  return;
580452
- const sIdx = getSnapshotIndex(selectedIndex);
580611
+ const isCompressedSummaryRollback = selectedIndex === 0 && currentSession.compressedFrom != null;
580612
+ const sIdx = isCompressedSummaryRollback ? getCompressedSummarySnapshotIndex(currentSession.messages) : getSnapshotIndex(selectedIndex);
580453
580613
  if (selectedIndex === 0 && currentSession.compressedFrom !== void 0 && currentSession.compressedFrom !== null) {
580454
580614
  const filePaths2 = await hashBasedSnapshotManager.getFilesToRollback(currentSession.id, sIdx);
580455
580615
  const nbCount2 = getNotebookRollbackCount(currentSession.id, sIdx);
@@ -583544,7 +583704,7 @@ function clampProgress(progress) {
583544
583704
  return Math.max(0, Math.min(100, Math.round(progress)));
583545
583705
  }
583546
583706
  function buildProgressBar(progress, terminalWidth) {
583547
- const barWidth = Math.max(20, Math.min(46, terminalWidth - 12));
583707
+ const barWidth = Math.max(4, Math.min(46, terminalWidth - 12));
583548
583708
  const filled = Math.max(0, Math.min(barWidth, Math.round(progress / 100 * barWidth)));
583549
583709
  const empty = barWidth - filled;
583550
583710
  return {
@@ -583552,6 +583712,50 @@ function buildProgressBar(progress, terminalWidth) {
583552
583712
  emptyBar: "\u25B1".repeat(empty)
583553
583713
  };
583554
583714
  }
583715
+ function getSafeLineWidth(terminalWidth, reservedColumns = 0) {
583716
+ return Math.max(1, terminalWidth - reservedColumns);
583717
+ }
583718
+ function getSafeIndentedLineWidth(terminalWidth) {
583719
+ return getSafeLineWidth(terminalWidth, INDENT_WIDTH + STREAM_VIEWPORT_RESERVED_COLUMNS);
583720
+ }
583721
+ function normalizeStreamContent(content) {
583722
+ return (content == null ? void 0 : content.replace(/\r\n/g, "\n").replace(/\r/g, "\n").replace(/[\t\v\f]+/g, " ")) ?? "";
583723
+ }
583724
+ function sliceByVisualWidth(text2, maxWidth) {
583725
+ if (!text2 || maxWidth <= 0) {
583726
+ return "";
583727
+ }
583728
+ let result2 = "";
583729
+ let width = 0;
583730
+ for (const char of text2) {
583731
+ const charWidth = stringWidth4(char);
583732
+ if (width + charWidth > maxWidth) {
583733
+ break;
583734
+ }
583735
+ result2 += char;
583736
+ width += charWidth;
583737
+ }
583738
+ return result2;
583739
+ }
583740
+ function buildStreamViewportLines(content, terminalWidth) {
583741
+ const width = getSafeLineWidth(terminalWidth, STREAM_VIEWPORT_INDENT_WIDTH + STREAM_VIEWPORT_RESERVED_COLUMNS);
583742
+ const logicalLines = normalizeStreamContent(content).split("\n");
583743
+ const visibleLines = logicalLines.slice(-STREAM_VIEWPORT_HEIGHT);
583744
+ return [
583745
+ ...Array(Math.max(0, STREAM_VIEWPORT_HEIGHT - visibleLines.length)).fill({
583746
+ text: " "
583747
+ }),
583748
+ ...visibleLines.map((line) => ({
583749
+ text: sliceByVisualWidth(line || " ", width) || " "
583750
+ }))
583751
+ ];
583752
+ }
583753
+ function buildSafeInlineText(text2, terminalWidth) {
583754
+ return sliceByVisualWidth(text2, getSafeLineWidth(terminalWidth, 1)) || " ";
583755
+ }
583756
+ function buildSafeIndentedText(text2, terminalWidth) {
583757
+ return sliceByVisualWidth(text2, getSafeIndentedLineWidth(terminalWidth)) || " ";
583758
+ }
583555
583759
  function CompressionStatus({ status, terminalWidth }) {
583556
583760
  const { theme: theme14 } = useTheme();
583557
583761
  const [animatedProgress, setAnimatedProgress] = import_react151.default.useState(0);
@@ -583587,37 +583791,38 @@ function CompressionStatus({ status, terminalWidth }) {
583587
583791
  if (step === "compressing") {
583588
583792
  const progress = clampProgress(animatedProgress);
583589
583793
  const { filledBar, emptyBar } = buildProgressBar(progress, terminalWidth);
583794
+ const streamViewportLines = buildStreamViewportLines(status.streamContent, terminalWidth);
583795
+ const safeTitle = buildSafeInlineText("\u2735 Compacting conversation...", terminalWidth);
583796
+ const sessionLine = sessionId ? buildSafeIndentedText(`Session: ${sessionId}`, terminalWidth) : void 0;
583797
+ const progressLine = buildSafeIndentedText(`${filledBar}${emptyBar} ${progress}%`, terminalWidth);
583798
+ const messageLine = message ? buildSafeIndentedText(message, terminalWidth) : void 0;
583590
583799
  return import_react151.default.createElement(
583591
583800
  Box_default,
583592
583801
  { flexDirection: "column", width: terminalWidth },
583593
583802
  import_react151.default.createElement(
583594
583803
  Box_default,
583595
- null,
583596
- import_react151.default.createElement(Text, { color: theme14.colors.menuInfo }, "\u2735 Compacting conversation...")
583804
+ { height: 1 },
583805
+ import_react151.default.createElement(Text, { color: theme14.colors.menuInfo, wrap: "truncate" }, safeTitle)
583597
583806
  ),
583598
- sessionId && import_react151.default.createElement(
583807
+ import_react151.default.createElement(Box_default, { paddingLeft: STREAM_VIEWPORT_INDENT_WIDTH, marginTop: 1, flexDirection: "column" }, streamViewportLines.map((line, index) => import_react151.default.createElement(
583808
+ Box_default,
583809
+ { key: `compression-stream-line-${index}`, height: 1 },
583810
+ import_react151.default.createElement(Text, { italic: true, dimColor: true, color: theme14.colors.menuSecondary, wrap: "truncate" }, line.text)
583811
+ ))),
583812
+ sessionLine && import_react151.default.createElement(
583599
583813
  Box_default,
583600
- { paddingLeft: 2, marginTop: 1 },
583601
- import_react151.default.createElement(Text, { dimColor: true }, "Session: "),
583602
- import_react151.default.createElement(Text, { color: theme14.colors.menuSecondary }, sessionId)
583814
+ { paddingLeft: 2, marginTop: 1, height: 1 },
583815
+ import_react151.default.createElement(Text, { color: theme14.colors.menuSecondary, wrap: "truncate" }, sessionLine)
583603
583816
  ),
583604
583817
  import_react151.default.createElement(
583605
583818
  Box_default,
583606
- { paddingLeft: 2, marginTop: 1 },
583607
- import_react151.default.createElement(Text, { color: theme14.colors.text }, filledBar),
583608
- import_react151.default.createElement(Text, { dimColor: true }, emptyBar),
583609
- import_react151.default.createElement(
583610
- Text,
583611
- { dimColor: true },
583612
- " ",
583613
- progress,
583614
- "%"
583615
- )
583819
+ { paddingLeft: 2, marginTop: 1, height: 1 },
583820
+ import_react151.default.createElement(Text, { color: theme14.colors.text, wrap: "truncate" }, progressLine)
583616
583821
  ),
583617
- message && import_react151.default.createElement(
583822
+ messageLine && import_react151.default.createElement(
583618
583823
  Box_default,
583619
- { paddingLeft: 2, marginTop: 1 },
583620
- import_react151.default.createElement(Text, { dimColor: true, wrap: "truncate" }, message)
583824
+ { paddingLeft: 2, marginTop: 1, height: 1 },
583825
+ import_react151.default.createElement(Text, { dimColor: true, wrap: "truncate" }, messageLine)
583621
583826
  )
583622
583827
  );
583623
583828
  }
@@ -583676,13 +583881,14 @@ function CompressionStatus({ status, terminalWidth }) {
583676
583881
  )
583677
583882
  );
583678
583883
  }
583679
- var import_react151, stepIcons, stepLabels;
583884
+ var import_react151, stepIcons, stepLabels, STREAM_VIEWPORT_HEIGHT, STREAM_VIEWPORT_RESERVED_COLUMNS, STREAM_VIEWPORT_INDENT_WIDTH, INDENT_WIDTH;
583680
583885
  var init_CompressionStatus = __esm({
583681
583886
  async "dist/ui/components/compression/CompressionStatus.js"() {
583682
583887
  "use strict";
583683
583888
  import_react151 = __toESM(require_react(), 1);
583684
583889
  await init_src();
583685
583890
  await init_build2();
583891
+ init_string_width4();
583686
583892
  init_ThemeContext();
583687
583893
  stepIcons = {
583688
583894
  saving: { icon: "\u25C9", color: "yellow" },
@@ -583702,6 +583908,10 @@ var init_CompressionStatus = __esm({
583702
583908
  failed: "Compression failed",
583703
583909
  skipped: "Compression skipped"
583704
583910
  };
583911
+ STREAM_VIEWPORT_HEIGHT = 5;
583912
+ STREAM_VIEWPORT_RESERVED_COLUMNS = 8;
583913
+ STREAM_VIEWPORT_INDENT_WIDTH = 2;
583914
+ INDENT_WIDTH = 2;
583705
583915
  }
583706
583916
  });
583707
583917
 
@@ -593518,6 +593728,7 @@ function ChatScreen({ autoResume, resumeSessionId: resumeSessionId2, enableYolo,
593518
593728
  fileUpdateNotification,
593519
593729
  currentProfileName: panelState.currentProfileName,
593520
593730
  isCompressing,
593731
+ isAutoCompressing: streamingState.isAutoCompressing,
593521
593732
  compressionError,
593522
593733
  backgroundProcesses: backgroundProcesses.processes,
593523
593734
  showBackgroundPanel: backgroundProcesses.showPanel,
@@ -595274,15 +595485,15 @@ ${formatMessage(t.foundInvalidPids, {
595274
595485
  console.log(t.autoCleanupHint);
595275
595486
  }
595276
595487
  }
595277
- var SNOW_DIR6, DAEMON_DIR, LOG_DIR;
595488
+ var SNOW_DIR5, DAEMON_DIR, LOG_DIR;
595278
595489
  var init_sseDaemon = __esm({
595279
595490
  "dist/utils/sse/sseDaemon.js"() {
595280
595491
  "use strict";
595281
595492
  init_languageConfig();
595282
595493
  init_i18n();
595283
- SNOW_DIR6 = join42(homedir24(), ".snow");
595284
- DAEMON_DIR = join42(SNOW_DIR6, "sse-daemons");
595285
- LOG_DIR = join42(SNOW_DIR6, "sse-logs");
595494
+ SNOW_DIR5 = join42(homedir24(), ".snow");
595495
+ DAEMON_DIR = join42(SNOW_DIR5, "sse-daemons");
595496
+ LOG_DIR = join42(SNOW_DIR5, "sse-logs");
595286
595497
  if (!existsSync37(DAEMON_DIR)) {
595287
595498
  mkdirSync20(DAEMON_DIR, { recursive: true });
595288
595499
  }
@@ -609918,7 +610129,7 @@ var require_package3 = __commonJS({
609918
610129
  "package.json"(exports2, module2) {
609919
610130
  module2.exports = {
609920
610131
  name: "snow-ai",
609921
- version: "0.7.29",
610132
+ version: "0.7.31",
609922
610133
  description: "Agentic coding in your terminal",
609923
610134
  license: "MIT",
609924
610135
  bin: {
@@ -611379,6 +611590,7 @@ import path6 from "node:path";
611379
611590
  var LEGACY_FILES = {
611380
611591
  codebase: "codebase.json",
611381
611592
  connection: "connection.json",
611593
+ workingDirs: "working-dirs.json",
611382
611594
  disabledBuiltin: "disabled-builtin-tools.json",
611383
611595
  disabledMcp: "disabled-mcp-tools.json",
611384
611596
  optInMcp: "opt-in-mcp-tools.json",
@@ -611464,6 +611676,14 @@ function migrateScope(scope, workingDirectory) {
611464
611676
  return false;
611465
611677
  });
611466
611678
  }
611679
+ tryMigrate(LEGACY_FILES.workingDirs, (data) => {
611680
+ if (Array.isArray(data.directories) && settings.workingDirectories === void 0) {
611681
+ const isWorkingDirectory = (d) => !!d && typeof d === "object" && typeof d["path"] === "string" && typeof d["isDefault"] === "boolean" && typeof d["addedAt"] === "number";
611682
+ settings.workingDirectories = data.directories.filter(isWorkingDirectory);
611683
+ return true;
611684
+ }
611685
+ return false;
611686
+ });
611467
611687
  tryMigrate(LEGACY_FILES.disabledBuiltin, (data) => {
611468
611688
  if (Array.isArray(data.disabledServices) && settings.disabledBuiltInServices === void 0) {
611469
611689
  settings.disabledBuiltInServices = data.disabledServices.filter((v) => typeof v === "string");
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "snow-ai",
3
- "version": "0.7.29",
3
+ "version": "0.7.31",
4
4
  "description": "Agentic coding in your terminal",
5
5
  "license": "MIT",
6
6
  "bin": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "snow-ai",
3
- "version": "0.7.29",
3
+ "version": "0.7.31",
4
4
  "description": "Agentic coding in your terminal",
5
5
  "license": "MIT",
6
6
  "bin": {