snow-ai 0.8.10 → 0.8.11

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
@@ -502939,6 +502939,7 @@ Output: ${combinedOutput}`
502939
502939
  var hookResultInterpreter_exports = {};
502940
502940
  __export(hookResultInterpreter_exports, {
502941
502941
  buildErrorDetails: () => buildErrorDetails,
502942
+ extractHookProvidedConfirmation: () => extractHookProvidedConfirmation,
502942
502943
  findFirstFailedCommand: () => findFirstFailedCommand,
502943
502944
  interpretHookResult: () => interpretHookResult
502944
502945
  });
@@ -502965,6 +502966,56 @@ function interpretHookResult(hookType, hookResult, originalContent) {
502965
502966
  const strategy = hookStrategies[hookType];
502966
502967
  return strategy.interpret(hookResult, originalContent);
502967
502968
  }
502969
+ function extractHookProvidedConfirmation(hookResult) {
502970
+ for (const result2 of hookResult.results) {
502971
+ if (result2.type !== "command" || !result2.success || !result2.output) {
502972
+ continue;
502973
+ }
502974
+ const rawOutput = result2.output.trim();
502975
+ if (!rawOutput) {
502976
+ continue;
502977
+ }
502978
+ try {
502979
+ const parsed = JSON.parse(rawOutput);
502980
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed) && typeof parsed.result === "string") {
502981
+ const hookResultValue = parsed.result.toLowerCase();
502982
+ if (hookResultValue === "approve") {
502983
+ return "approve";
502984
+ }
502985
+ if (hookResultValue === "approve_always") {
502986
+ return "approve_always";
502987
+ }
502988
+ if (hookResultValue === "reject") {
502989
+ return "reject";
502990
+ }
502991
+ if (hookResultValue === "reject_with_reply") {
502992
+ return {
502993
+ type: "reject_with_reply",
502994
+ reason: typeof parsed.reason === "string" ? parsed.reason : "Rejected by toolConfirmation hook"
502995
+ };
502996
+ }
502997
+ }
502998
+ } catch {
502999
+ const lowerOutput = rawOutput.toLowerCase().trim();
503000
+ if (lowerOutput === "approve" || lowerOutput === "approve_once") {
503001
+ return "approve";
503002
+ }
503003
+ if (lowerOutput === "approve_always") {
503004
+ return "approve_always";
503005
+ }
503006
+ if (lowerOutput === "reject") {
503007
+ return "reject";
503008
+ }
503009
+ if (lowerOutput === "reject_with_reply") {
503010
+ return {
503011
+ type: "reject_with_reply",
503012
+ reason: "Rejected by toolConfirmation hook"
503013
+ };
503014
+ }
503015
+ }
503016
+ }
503017
+ return null;
503018
+ }
502968
503019
  var init_hookResultInterpreter = __esm({
502969
503020
  "dist/utils/execution/hookResultInterpreter.js"() {
502970
503021
  "use strict";
@@ -535169,6 +535220,9 @@ async function listJsonCommandsRecursively(dir, prefixPath) {
535169
535220
  for (const entry of entries) {
535170
535221
  const entryPath = join32(dir, entry.name);
535171
535222
  if (entry.isDirectory()) {
535223
+ if (entry.name.startsWith(".")) {
535224
+ continue;
535225
+ }
535172
535226
  const childPrefix = prefixPath ? `${prefixPath}/${entry.name}` : entry.name;
535173
535227
  results.push(...await listJsonCommandsRecursively(entryPath, childPrefix));
535174
535228
  continue;
@@ -535192,8 +535246,15 @@ async function loadCustomCommandFromFile(entry, defaultLocation) {
535192
535246
  try {
535193
535247
  const content = await readFile2(entry.filePath, "utf-8");
535194
535248
  const cmd = JSON.parse(content);
535249
+ if (typeof cmd.command !== "string" || cmd.command.length === 0) {
535250
+ return null;
535251
+ }
535252
+ if (cmd.type !== "execute" && cmd.type !== "prompt" && cmd.type !== "panel") {
535253
+ return null;
535254
+ }
535195
535255
  cmd.name = entry.inferredCommandName;
535196
- cmd.description = cmd.description || cmd.command;
535256
+ const rawDesc = cmd.description ?? cmd.command;
535257
+ cmd.description = typeof rawDesc === "string" ? rawDesc : "";
535197
535258
  if (!cmd.location) {
535198
535259
  cmd.location = defaultLocation;
535199
535260
  }
@@ -535270,7 +535331,7 @@ function checkCommandExists(name, location, projectRoot) {
535270
535331
  return false;
535271
535332
  }
535272
535333
  }
535273
- async function saveCustomCommand(name, command, type, description, location = "global", projectRoot) {
535334
+ async function saveCustomCommand(name, command, type, description, location = "global", projectRoot, argsHint, argsOptions) {
535274
535335
  if (isCommandNameConflict(name)) {
535275
535336
  throw new Error(`Command name "${name}" conflicts with an existing built-in or custom command`);
535276
535337
  }
@@ -535278,7 +535339,15 @@ async function saveCustomCommand(name, command, type, description, location = "g
535278
535339
  const dir = getCustomCommandsDir(location, projectRoot);
535279
535340
  const filePath = getCommandJsonFilePath(dir, name);
535280
535341
  await mkdir3(dirname12(filePath), { recursive: true });
535281
- const data = { name, command, type, description, location };
535342
+ const data = {
535343
+ name,
535344
+ command,
535345
+ type,
535346
+ description,
535347
+ location,
535348
+ ...argsHint !== void 0 ? { argsHint } : {},
535349
+ ...argsOptions !== void 0 ? { argsOptions } : {}
535350
+ };
535282
535351
  await writeFile(filePath, JSON.stringify(data, null, 2), "utf-8");
535283
535352
  }
535284
535353
  function getCustomCommands() {
@@ -535293,7 +535362,7 @@ function normalizeImportedCustomCommand(value, location) {
535293
535362
  if (!isRecord3(value)) {
535294
535363
  return null;
535295
535364
  }
535296
- const { name, command, type, description } = value;
535365
+ const { name, command, type, description, argsHint, argsOptions } = value;
535297
535366
  if (typeof name !== "string" || typeof command !== "string" || type !== "execute" && type !== "prompt" && type !== "panel") {
535298
535367
  return null;
535299
535368
  }
@@ -535306,6 +535375,10 @@ function normalizeImportedCustomCommand(value, location) {
535306
535375
  command,
535307
535376
  type,
535308
535377
  ...typeof description === "string" ? { description } : {},
535378
+ ...typeof argsHint === "string" ? { argsHint } : {},
535379
+ ...Array.isArray(argsOptions) ? {
535380
+ argsOptions: argsOptions.filter((v) => typeof v === "string")
535381
+ } : {},
535309
535382
  location
535310
535383
  };
535311
535384
  }
@@ -535335,6 +535408,16 @@ async function deleteCustomCommand(name, location = "global", projectRoot) {
535335
535408
  unregisterCommand(name);
535336
535409
  customCommandsCache = customCommandsCache.filter((cmd) => cmd.name !== name);
535337
535410
  }
535411
+ function applyArgsToCommand(command, args2) {
535412
+ const trimmedArgs = args2 == null ? void 0 : args2.trim();
535413
+ if (command.includes("$ARGUMENTS")) {
535414
+ return command.split("$ARGUMENTS").join(trimmedArgs ?? "");
535415
+ }
535416
+ if (!trimmedArgs) {
535417
+ return command;
535418
+ }
535419
+ return `${command} ${trimmedArgs}`;
535420
+ }
535338
535421
  async function registerCustomCommands(projectRoot) {
535339
535422
  const customCommands = await loadCustomCommands(projectRoot);
535340
535423
  customCommandsCache = customCommands;
@@ -535351,7 +535434,7 @@ async function registerCustomCommands(projectRoot) {
535351
535434
  };
535352
535435
  }
535353
535436
  if (cmd.type === "execute") {
535354
- const finalCommand = args2 ? `${cmd.command} ${args2}` : cmd.command;
535437
+ const finalCommand = applyArgsToCommand(cmd.command, args2);
535355
535438
  return {
535356
535439
  success: true,
535357
535440
  message: `Executing: ${finalCommand}`,
@@ -535367,7 +535450,7 @@ async function registerCustomCommands(projectRoot) {
535367
535450
  prompt: cmd.command
535368
535451
  };
535369
535452
  }
535370
- const finalPrompt = args2 ? `${cmd.command} ${args2}` : cmd.command;
535453
+ const finalPrompt = applyArgsToCommand(cmd.command, args2);
535371
535454
  return {
535372
535455
  success: true,
535373
535456
  message: `Sending to AI: ${finalPrompt}`,
@@ -537071,7 +537154,7 @@ var init_encoderManager = __esm({
537071
537154
  });
537072
537155
 
537073
537156
  // dist/utils/core/todoPreprocessor.js
537074
- function formatTodoContext(todos) {
537157
+ function formatTodoContext(todos, options3) {
537075
537158
  if (todos.length === 0) {
537076
537159
  return "";
537077
537160
  }
@@ -537088,6 +537171,11 @@ function formatTodoContext(todos) {
537088
537171
  '**Important**: Update TODO status immediately after completing each task using todo-manage with action "update".',
537089
537172
  ""
537090
537173
  ];
537174
+ const hasIncomplete = todos.some((t) => t.status !== "completed");
537175
+ if ((options3 == null ? void 0 : options3.isFollowUp) && hasIncomplete) {
537176
+ const toolName = options3.ultraMode ? "todo-ultra" : "todo-manage";
537177
+ lines.push(`**Action Required**: This is a follow-up message with an active TODO list. You MUST call \`${toolName}({action: "get"})\` first (paired with an action tool) to restore your TODO session context before doing any other work. This ensures the TODO list stays in sync and you continue using the TODO workflow for this task.`, "");
537178
+ }
537091
537179
  return lines.join("\n");
537092
537180
  }
537093
537181
  var init_todoPreprocessor = __esm({
@@ -537133,14 +537221,18 @@ async function initializeConversationSession(planMode, vulnerabilityHuntingMode,
537133
537221
  ${companionPromptAddon}` : baseSystemPrompt
537134
537222
  }
537135
537223
  ];
537224
+ const session = sessionManager.getCurrentSession();
537136
537225
  if (existingTodoList && existingTodoList.todos.length > 0) {
537137
- const todoContext = formatTodoContext(existingTodoList.todos);
537226
+ const isFollowUp = !!session && session.messages.length > 0;
537227
+ const todoContext = formatTodoContext(existingTodoList.todos, {
537228
+ isFollowUp,
537229
+ ultraMode: existingTodoList.ultraMode
537230
+ });
537138
537231
  conversationMessages.push({
537139
537232
  role: "user",
537140
537233
  content: todoContext
537141
537234
  });
537142
537235
  }
537143
- const session = sessionManager.getCurrentSession();
537144
537236
  if (session && session.messages.length > 0) {
537145
537237
  const filteredMessages = session.messages.filter((msg) => !msg.subAgentInternal);
537146
537238
  conversationMessages.push(...filteredMessages);
@@ -544056,6 +544148,39 @@ function extractMultimodalContent(result2) {
544056
544148
  textContent: JSON.stringify(result2)
544057
544149
  };
544058
544150
  }
544151
+ function formatAskUserAnswer(selected, customInput) {
544152
+ const selectedText = Array.isArray(selected) ? selected.join(", ") : selected;
544153
+ return customInput ? `${selectedText}: ${customInput}` : selectedText;
544154
+ }
544155
+ function extractHookProvidedAnswer(hookResult) {
544156
+ for (const result2 of hookResult.results) {
544157
+ if (result2.type !== "command" || !result2.success || !result2.output) {
544158
+ continue;
544159
+ }
544160
+ const rawOutput = result2.output.trim();
544161
+ if (!rawOutput) {
544162
+ continue;
544163
+ }
544164
+ try {
544165
+ const parsed = JSON.parse(rawOutput);
544166
+ if (parsed && typeof parsed === "object" && !Array.isArray(parsed) && parsed.selected !== void 0) {
544167
+ const selected = parsed.selected;
544168
+ if (typeof selected === "string" || Array.isArray(selected) && selected.every((s) => typeof s === "string")) {
544169
+ return {
544170
+ selected,
544171
+ customInput: typeof parsed.customInput === "string" ? parsed.customInput : void 0
544172
+ };
544173
+ }
544174
+ }
544175
+ if (Array.isArray(parsed) && parsed.every((s) => typeof s === "string")) {
544176
+ return { selected: parsed };
544177
+ }
544178
+ } catch {
544179
+ return { selected: rawOutput };
544180
+ }
544181
+ }
544182
+ return null;
544183
+ }
544059
544184
  async function executeToolCall(toolCall, abortSignal, onTokenUpdate, onSubAgentMessage, requestToolConfirmation, isToolAutoApproved, yoloMode, addToAlwaysApproved, onUserInteractionNeeded, sessionId, workingDirectory) {
544060
544185
  let result2;
544061
544186
  let executionError = null;
@@ -544086,11 +544211,12 @@ async function executeToolCall(toolCall, abortSignal, onTokenUpdate, onSubAgentM
544086
544211
  try {
544087
544212
  const args2 = safeParseToolArguments(toolCall.function.arguments);
544088
544213
  recordToolContent(telemetry.span, "tool.input", args2, telemetry.metricAttributes);
544214
+ let beforeHookResult = null;
544089
544215
  try {
544090
544216
  const { unifiedHooksExecutor: unifiedHooksExecutor2 } = await Promise.resolve().then(() => (init_unifiedHooksExecutor(), unifiedHooksExecutor_exports));
544091
544217
  const { interpretHookResult: interpretHookResult2 } = await Promise.resolve().then(() => (init_hookResultInterpreter(), hookResultInterpreter_exports));
544092
- const hookResult = await unifiedHooksExecutor2.executeHooks("beforeToolCall", { toolName: toolCall.function.name, args: args2 });
544093
- const interpreted = interpretHookResult2("beforeToolCall", hookResult);
544218
+ beforeHookResult = await unifiedHooksExecutor2.executeHooks("beforeToolCall", { toolName: toolCall.function.name, args: args2 });
544219
+ const interpreted = interpretHookResult2("beforeToolCall", beforeHookResult);
544094
544220
  if (interpreted.action === "block") {
544095
544221
  result2 = {
544096
544222
  tool_call_id: toolCall.id,
@@ -544104,6 +544230,22 @@ async function executeToolCall(toolCall, abortSignal, onTokenUpdate, onSubAgentM
544104
544230
  } catch (error42) {
544105
544231
  console.warn("Failed to execute beforeToolCall hook:", error42);
544106
544232
  }
544233
+ if (toolCall.function.name === "askuser-ask_question" && beforeHookResult) {
544234
+ const hookAnswer = extractHookProvidedAnswer(beforeHookResult);
544235
+ if (hookAnswer) {
544236
+ const answerText = formatAskUserAnswer(hookAnswer.selected, hookAnswer.customInput);
544237
+ result2 = {
544238
+ tool_call_id: toolCall.id,
544239
+ role: "tool",
544240
+ content: JSON.stringify({
544241
+ answer: answerText,
544242
+ selected: hookAnswer.selected,
544243
+ customInput: hookAnswer.customInput
544244
+ })
544245
+ };
544246
+ return result2;
544247
+ }
544248
+ }
544107
544249
  if (toolCall.function.name.startsWith("team-")) {
544108
544250
  const teamToolName = toolCall.function.name.substring("team-".length);
544109
544251
  const teamArgs = args2;
@@ -544286,7 +544428,7 @@ ${injectedSummary}`
544286
544428
  };
544287
544429
  return result2;
544288
544430
  }
544289
- const answerText = response.customInput ? `${Array.isArray(response.selected) ? response.selected.join(", ") : response.selected}: ${response.customInput}` : Array.isArray(response.selected) ? response.selected.join(", ") : response.selected;
544431
+ const answerText = formatAskUserAnswer(response.selected, response.customInput);
544290
544432
  result2 = {
544291
544433
  tool_call_id: toolCall.id,
544292
544434
  role: "tool",
@@ -642366,8 +642508,8 @@ var init_HookErrorDisplay = __esm({
642366
642508
  });
642367
642509
 
642368
642510
  // dist/utils/ui/skillMask.js
642369
- function isSkillHeaderLine(line) {
642370
- return line.startsWith("# Skill:");
642511
+ function findSkillHeaderIndex(line) {
642512
+ return line.indexOf("# Skill:");
642371
642513
  }
642372
642514
  function splitSkillEndRemainder(line) {
642373
642515
  const trimmed = line.trimStart();
@@ -642379,7 +642521,9 @@ function isSkillEndLine(line) {
642379
642521
  return line.trim() === "# Skill End";
642380
642522
  }
642381
642523
  function parseSkillIdFromHeader(line) {
642382
- return line.replace(/^# Skill:\s*/i, "").trim() || "unknown";
642524
+ const headerIndex = findSkillHeaderIndex(line);
642525
+ const headerPart = headerIndex >= 0 ? line.slice(headerIndex) : line;
642526
+ return headerPart.replace(/^# Skill:\s*/i, "").trim() || "unknown";
642383
642527
  }
642384
642528
  function maskSkillInjectedText(text2) {
642385
642529
  if (!text2)
@@ -642390,18 +642534,25 @@ function maskSkillInjectedText(text2) {
642390
642534
  let i = 0;
642391
642535
  while (i < lines.length) {
642392
642536
  const line = lines[i] ?? "";
642393
- if (!isSkillHeaderLine(line)) {
642537
+ const headerIndex = findSkillHeaderIndex(line);
642538
+ if (headerIndex < 0) {
642394
642539
  out.push(line);
642395
642540
  i++;
642396
642541
  continue;
642397
642542
  }
642543
+ if (headerIndex > 0) {
642544
+ const prefix = line.slice(0, headerIndex).trimEnd();
642545
+ if (prefix.length > 0) {
642546
+ out.push(prefix);
642547
+ }
642548
+ }
642398
642549
  const skillId = parseSkillIdFromHeader(line);
642399
642550
  skillIds.push(skillId);
642400
642551
  out.push(`[Skill:${skillId}]`);
642401
642552
  i++;
642402
642553
  while (i < lines.length) {
642403
642554
  const next = lines[i] ?? "";
642404
- if (isSkillHeaderLine(next))
642555
+ if (findSkillHeaderIndex(next) >= 0)
642405
642556
  break;
642406
642557
  const remainder = splitSkillEndRemainder(next);
642407
642558
  if (remainder !== null) {
@@ -642427,8 +642578,8 @@ var init_skillMask = __esm({
642427
642578
  });
642428
642579
 
642429
642580
  // dist/utils/ui/gitLineMask.js
642430
- function isGitLineHeaderLine(line) {
642431
- return line.startsWith("# GitLine:");
642581
+ function findGitLineHeaderIndex(line) {
642582
+ return line.indexOf("# GitLine:");
642432
642583
  }
642433
642584
  function isGitLineEndLine(line) {
642434
642585
  return line.trim() === "# GitLine End";
@@ -642440,7 +642591,9 @@ function splitGitLineEndRemainder(line) {
642440
642591
  return trimmed.slice("# GitLine End".length);
642441
642592
  }
642442
642593
  function parseGitLineIdFromHeader(line) {
642443
- const id = line.replace(/^# GitLine:\s*/i, "").trim() || "unknown";
642594
+ const headerIndex = findGitLineHeaderIndex(line);
642595
+ const headerPart = headerIndex >= 0 ? line.slice(headerIndex) : line;
642596
+ const id = headerPart.replace(/^# GitLine:\s*/i, "").trim() || "unknown";
642444
642597
  return id.slice(0, 8);
642445
642598
  }
642446
642599
  function maskGitLineText(text2) {
@@ -642452,18 +642605,25 @@ function maskGitLineText(text2) {
642452
642605
  let i = 0;
642453
642606
  while (i < lines.length) {
642454
642607
  const line = lines[i] ?? "";
642455
- if (!isGitLineHeaderLine(line)) {
642608
+ const headerIndex = findGitLineHeaderIndex(line);
642609
+ if (headerIndex < 0) {
642456
642610
  out.push(line);
642457
642611
  i++;
642458
642612
  continue;
642459
642613
  }
642614
+ if (headerIndex > 0) {
642615
+ const prefix = line.slice(0, headerIndex).trimEnd();
642616
+ if (prefix.length > 0) {
642617
+ out.push(prefix);
642618
+ }
642619
+ }
642460
642620
  const gitLineId = parseGitLineIdFromHeader(line);
642461
642621
  gitLineIds.push(gitLineId);
642462
642622
  out.push(`[GitLine:${gitLineId}]`);
642463
642623
  i++;
642464
642624
  while (i < lines.length) {
642465
642625
  const next = lines[i] ?? "";
642466
- if (isGitLineHeaderLine(next))
642626
+ if (findGitLineHeaderIndex(next) >= 0)
642467
642627
  break;
642468
642628
  const remainder = splitGitLineEndRemainder(next);
642469
642629
  if (remainder !== null) {
@@ -646027,6 +646187,10 @@ var init_textBuffer = __esm({
646027
646187
  while ((m = bracketPattern.exec(text2)) !== null) {
646028
646188
  pushRange(m.index, m.index + m[0].length, "bracket");
646029
646189
  }
646190
+ const wsTagPattern = /@\[[^\]]+\]/g;
646191
+ while ((m = wsTagPattern.exec(text2)) !== null) {
646192
+ pushRange(m.index, m.index + m[0].length, "wsTag");
646193
+ }
646030
646194
  const agentPattern = /(^|\s)(#[A-Za-z][\w-]*)/g;
646031
646195
  while ((m = agentPattern.exec(text2)) !== null) {
646032
646196
  const leading = m[1] ?? "";
@@ -646601,7 +646765,7 @@ var init_textBuffer = __esm({
646601
646765
  const hasTrailingSpace = codePoints[closePos + 1] === " ";
646602
646766
  const placeholderText = hasTrailingSpace ? `${baseText} ` : baseText;
646603
646767
  const end = hasTrailingSpace ? closePos + 2 : closePos + 1;
646604
- if (placeholderText.match(/^\[Paste \d+ lines #\d+\] ?$/) || placeholderText.match(/^\[image #\d+\] ?$/) || placeholderText === "[Pasting...]" || placeholderText === "[Pasting...] " || placeholderText.match(/^\[Skill:[^\]]+\] ?$/)) {
646768
+ if (placeholderText.match(/^\[Paste \d+ lines #\d+\] ?$/) || placeholderText.match(/^\[image #\d+\] ?$/) || placeholderText === "[Pasting...]" || placeholderText === "[Pasting...] " || placeholderText.match(/^\[Skill:[^\]]+\] ?$/) || placeholderText.match(/^\[GitLine:[^\]]+\] ?$/)) {
646605
646769
  return { start: openPos, end };
646606
646770
  }
646607
646771
  }
@@ -647074,7 +647238,23 @@ function getCommandArgsOptions(commandName, inputText) {
647074
647238
  if (commandName === "buddy" && /^\/buddy\s+profile\s*$/.test(inputText ?? "")) {
647075
647239
  return getBuddyProfileArgOptions();
647076
647240
  }
647077
- return COMMAND_ARGS_OPTIONS[commandName] ?? [];
647241
+ const staticOptions = COMMAND_ARGS_OPTIONS[commandName];
647242
+ if (staticOptions) {
647243
+ return staticOptions;
647244
+ }
647245
+ const customCmd = getCustomCommands().find((cmd) => cmd.name === commandName);
647246
+ if ((customCmd == null ? void 0 : customCmd.argsOptions) && customCmd.argsOptions.length > 0) {
647247
+ return customCmd.argsOptions;
647248
+ }
647249
+ return [];
647250
+ }
647251
+ function getCommandArgsHint(commandName) {
647252
+ const staticHint = COMMAND_ARGS_HINTS[commandName];
647253
+ if (staticHint) {
647254
+ return staticHint;
647255
+ }
647256
+ const customCmd = getCustomCommands().find((cmd) => cmd.name === commandName);
647257
+ return (customCmd == null ? void 0 : customCmd.argsHint) ?? "";
647078
647258
  }
647079
647259
  function useCommandPanel(buffer, isProcessing = false) {
647080
647260
  const { t } = useI18n();
@@ -647611,11 +647791,7 @@ function useFilePicker(buffer, triggerUpdate) {
647611
647791
  const newText2 = beforeAt + tagText + afterCursor;
647612
647792
  buffer.setText(newText2);
647613
647793
  const targetPos2 = state.atSymbolPosition + tagText.length;
647614
- for (let i = 0; i < targetPos2; i++) {
647615
- if (i < buffer.text.length) {
647616
- buffer.moveRight();
647617
- }
647618
- }
647794
+ buffer.setCursorPosition(targetPos2);
647619
647795
  dispatch({
647620
647796
  type: "SHOW",
647621
647797
  query: "",
@@ -647632,11 +647808,7 @@ function useFilePicker(buffer, triggerUpdate) {
647632
647808
  buffer.setText(newText);
647633
647809
  const insertedLength = prefix.length + filePath.length + suffix.length;
647634
647810
  const targetPos = state.atSymbolPosition + insertedLength;
647635
- for (let i = 0; i < targetPos; i++) {
647636
- if (i < buffer.text.length) {
647637
- buffer.moveRight();
647638
- }
647639
- }
647811
+ buffer.setCursorPosition(targetPos);
647640
647812
  if (isDirectoryContinuation) {
647641
647813
  dispatch({
647642
647814
  type: "SHOW",
@@ -647672,11 +647844,7 @@ function useFilePicker(buffer, triggerUpdate) {
647672
647844
  const newText = beforeAt + insertedSegment + afterCursor;
647673
647845
  buffer.setText(newText);
647674
647846
  const targetPos = state.atSymbolPosition + insertedSegment.length;
647675
- for (let i = 0; i < targetPos; i++) {
647676
- if (i < buffer.text.length) {
647677
- buffer.moveRight();
647678
- }
647679
- }
647847
+ buffer.setCursorPosition(targetPos);
647680
647848
  dispatch({ type: "SELECT_FILE" });
647681
647849
  triggerUpdate();
647682
647850
  }, [state.atSymbolPosition, state.searchMode, buffer, triggerUpdate]);
@@ -648625,7 +648793,7 @@ function argsPickerHandler(ctx) {
648625
648793
  if (selected) {
648626
648794
  const value = getCommandArgOptionValue(selected);
648627
648795
  const text2 = buffer.text;
648628
- const hasTrailingSpace = /^\/[a-zA-Z0-9_-]+(?:\s+\S+)*\s+$/.test(text2);
648796
+ const hasTrailingSpace = /^\/[a-zA-Z0-9_:-]+(?:\s+\S+)*\s+$/.test(text2);
648629
648797
  const suffix = hasTrailingSpace ? value : " " + value;
648630
648798
  buffer.insert(suffix);
648631
648799
  buffer.setCursorPosition(buffer.text.length);
@@ -649417,7 +649585,7 @@ function tabArgsPickerHandler(ctx) {
649417
649585
  const { showCommands, showFilePicker, showArgsPicker, setShowArgsPicker, setArgsSelectedIndex } = options3;
649418
649586
  if (key.tab && !showCommands && !showFilePicker && !showArgsPicker) {
649419
649587
  const text2 = buffer.text;
649420
- const rootMatch = text2.match(/^\/([a-zA-Z0-9_-]+)\s*$/);
649588
+ const rootMatch = text2.match(/^\/([a-zA-Z0-9_:-]+)\s*$/);
649421
649589
  const buddyProfileMatch = text2.match(/^\/(buddy)\s+profile\s*$/);
649422
649590
  const inlineTrigger = findInlineCommandTrigger(text2, buffer.getCursorPosition());
649423
649591
  const cmdName = (rootMatch == null ? void 0 : rootMatch[1]) ?? (buddyProfileMatch == null ? void 0 : buddyProfileMatch[1]) ?? (inlineTrigger == null ? void 0 : inlineTrigger.query) ?? "";
@@ -650468,21 +650636,46 @@ function createStagedEntry(fileCount) {
650468
650636
  fileCount
650469
650637
  };
650470
650638
  }
650639
+ function createUnstagedEntry(fileCount) {
650640
+ return {
650641
+ sha: UNSTAGED_ENTRY_SHA,
650642
+ subject: "Unstaged changes",
650643
+ authorName: "",
650644
+ dateIso: "",
650645
+ kind: "unstaged",
650646
+ fileCount
650647
+ };
650648
+ }
650471
650649
  function buildInjectedGitLineText(commit, gitRoot) {
650472
- const patch = commit.kind === "staged" ? reviewAgent.getStagedDiff(gitRoot).trim() : reviewAgent.getCommitPatch(gitRoot, commit.sha).trim();
650473
650650
  if (commit.kind === "staged") {
650651
+ const patch2 = reviewAgent.getStagedDiff(gitRoot).trim();
650474
650652
  return [
650475
650653
  "# GitLine: staged",
650476
650654
  "Type: staged",
650477
650655
  commit.fileCount !== void 0 ? `Files: ${commit.fileCount}` : void 0,
650478
650656
  "",
650479
650657
  "```git",
650480
- patch,
650658
+ patch2,
650659
+ "```",
650660
+ "# GitLine End",
650661
+ ""
650662
+ ].filter((line) => line !== void 0).join("\n");
650663
+ }
650664
+ if (commit.kind === "unstaged") {
650665
+ const patch2 = reviewAgent.getUnstagedDiff(gitRoot).trim();
650666
+ return [
650667
+ "# GitLine: unstaged",
650668
+ "Type: unstaged",
650669
+ commit.fileCount !== void 0 ? `Files: ${commit.fileCount}` : void 0,
650670
+ "",
650671
+ "```git",
650672
+ patch2,
650481
650673
  "```",
650482
650674
  "# GitLine End",
650483
650675
  ""
650484
650676
  ].filter((line) => line !== void 0).join("\n");
650485
650677
  }
650678
+ const patch = reviewAgent.getCommitPatch(gitRoot, commit.sha).trim();
650486
650679
  return [
650487
650680
  `# GitLine: ${commit.sha}`,
650488
650681
  `Commit: ${commit.sha}`,
@@ -650502,6 +650695,7 @@ function useGitLinePicker(buffer, triggerUpdate) {
650502
650695
  const [gitLineSelectedIndex, setGitLineSelectedIndex] = (0, import_react106.useState)(0);
650503
650696
  const [commits, setCommits] = (0, import_react106.useState)([]);
650504
650697
  const [stagedEntry, setStagedEntry] = (0, import_react106.useState)(null);
650698
+ const [unstagedEntry, setUnstagedEntry] = (0, import_react106.useState)(null);
650505
650699
  const [selectedCommits, setSelectedCommits] = (0, import_react106.useState)(/* @__PURE__ */ new Set());
650506
650700
  const [isLoading, setIsLoading] = (0, import_react106.useState)(false);
650507
650701
  const [isLoadingMore, setIsLoadingMore] = (0, import_react106.useState)(false);
@@ -650512,8 +650706,15 @@ function useGitLinePicker(buffer, triggerUpdate) {
650512
650706
  const [gitRoot, setGitRoot] = (0, import_react106.useState)(null);
650513
650707
  const [insertionRange, setInsertionRange] = (0, import_react106.useState)(null);
650514
650708
  const allCommits = (0, import_react106.useMemo)(() => {
650515
- return stagedEntry ? [stagedEntry, ...commits] : commits;
650516
- }, [commits, stagedEntry]);
650709
+ const entries = [];
650710
+ if (stagedEntry) {
650711
+ entries.push(stagedEntry);
650712
+ }
650713
+ if (unstagedEntry) {
650714
+ entries.push(unstagedEntry);
650715
+ }
650716
+ return [...entries, ...commits];
650717
+ }, [commits, stagedEntry, unstagedEntry]);
650517
650718
  const filteredCommits = (0, import_react106.useMemo)(() => {
650518
650719
  const query = searchQuery.trim().toLowerCase();
650519
650720
  if (!query) {
@@ -650529,6 +650730,9 @@ function useGitLinePicker(buffer, triggerUpdate) {
650529
650730
  if (commit.kind === "staged") {
650530
650731
  searchableFields.push("staged", "staged changes");
650531
650732
  }
650733
+ if (commit.kind === "unstaged") {
650734
+ searchableFields.push("unstaged", "unstaged changes");
650735
+ }
650532
650736
  return searchableFields.some((field) => field.toLowerCase().includes(query));
650533
650737
  });
650534
650738
  }, [allCommits, searchQuery]);
@@ -650542,6 +650746,7 @@ function useGitLinePicker(buffer, triggerUpdate) {
650542
650746
  setGitRoot(null);
650543
650747
  setCommits([]);
650544
650748
  setStagedEntry(null);
650749
+ setUnstagedEntry(null);
650545
650750
  setHasMore(false);
650546
650751
  setSkip(0);
650547
650752
  setError(gitCheck.error || "Not a git repository");
@@ -650551,6 +650756,7 @@ function useGitLinePicker(buffer, triggerUpdate) {
650551
650756
  const result2 = reviewAgent.listCommitsPaginated(gitCheck.gitRoot, 0, PAGE_SIZE);
650552
650757
  setGitRoot(gitCheck.gitRoot);
650553
650758
  setStagedEntry(status.hasStaged ? createStagedEntry(status.stagedFileCount) : null);
650759
+ setUnstagedEntry(status.hasUnstaged ? createUnstagedEntry(status.unstagedFileCount) : null);
650554
650760
  setCommits(result2.commits.map((commit) => ({
650555
650761
  ...commit,
650556
650762
  kind: "commit"
@@ -650562,6 +650768,7 @@ function useGitLinePicker(buffer, triggerUpdate) {
650562
650768
  setGitRoot(null);
650563
650769
  setCommits([]);
650564
650770
  setStagedEntry(null);
650771
+ setUnstagedEntry(null);
650565
650772
  setHasMore(false);
650566
650773
  setSkip(0);
650567
650774
  setError(loadError instanceof Error ? loadError.message : "Failed to load git commits");
@@ -650636,6 +650843,7 @@ function useGitLinePicker(buffer, triggerUpdate) {
650636
650843
  setSkip(0);
650637
650844
  setIsLoadingMore(false);
650638
650845
  setStagedEntry(null);
650846
+ setUnstagedEntry(null);
650639
650847
  setInsertionRange(null);
650640
650848
  triggerUpdate();
650641
650849
  }, [triggerUpdate]);
@@ -650689,6 +650897,7 @@ function useGitLinePicker(buffer, triggerUpdate) {
650689
650897
  setSkip(0);
650690
650898
  setIsLoadingMore(false);
650691
650899
  setStagedEntry(null);
650900
+ setUnstagedEntry(null);
650692
650901
  setInsertionRange(null);
650693
650902
  triggerUpdate();
650694
650903
  }, [
@@ -650722,7 +650931,7 @@ function useGitLinePicker(buffer, triggerUpdate) {
650722
650931
  loadMoreGitLineCommits
650723
650932
  };
650724
650933
  }
650725
- var import_react106, PAGE_SIZE, STAGED_ENTRY_SHA;
650934
+ var import_react106, PAGE_SIZE, STAGED_ENTRY_SHA, UNSTAGED_ENTRY_SHA;
650726
650935
  var init_useGitLinePicker = __esm({
650727
650936
  "dist/hooks/picker/useGitLinePicker.js"() {
650728
650937
  "use strict";
@@ -650730,6 +650939,7 @@ var init_useGitLinePicker = __esm({
650730
650939
  init_reviewAgent();
650731
650940
  PAGE_SIZE = 30;
650732
650941
  STAGED_ENTRY_SHA = "staged";
650942
+ UNSTAGED_ENTRY_SHA = "unstaged";
650733
650943
  }
650734
650944
  });
650735
650945
 
@@ -653635,8 +653845,7 @@ var init_GitLinePickerPanel = __esm({
653635
653845
  Text,
653636
653846
  { color: theme14.colors.menuInfo },
653637
653847
  t.gitLinePickerPanel.selectedLabel,
653638
- ":",
653639
- " ",
653848
+ ": ",
653640
653849
  selectedCommits.size
653641
653850
  )
653642
653851
  ) : void 0, scrollHintFormat: (above, below) => import_react115.default.createElement(
@@ -653665,8 +653874,9 @@ var init_GitLinePickerPanel = __esm({
653665
653874
  )
653666
653875
  ), renderItem: (commit, isSelected) => {
653667
653876
  const isChecked = selectedCommits.has(commit.sha);
653668
- const title = commit.kind === "staged" ? `${t.reviewCommitPanel.stagedLabel} (${commit.fileCount ?? 0} ${t.reviewCommitPanel.filesLabel})` : `${formatShortSha(commit.sha)} ${truncateText2(commit.subject, 72)}`;
653669
- const subtitle = commit.kind === "staged" ? "" : `${commit.authorName} \xB7 ${formatDate(commit.dateIso)}`;
653877
+ const isWorkingTreeEntry = commit.kind === "staged" || commit.kind === "unstaged";
653878
+ const title = isWorkingTreeEntry ? `${commit.kind === "staged" ? t.reviewCommitPanel.stagedLabel : t.reviewCommitPanel.unstagedLabel} (${commit.fileCount ?? 0} ${t.reviewCommitPanel.filesLabel})` : `${formatShortSha(commit.sha)} ${truncateText2(commit.subject, 72)}`;
653879
+ const subtitle = isWorkingTreeEntry ? "" : `${commit.authorName} \xB7 ${formatDate(commit.dateIso)}`;
653670
653880
  return import_react115.default.createElement(
653671
653881
  import_react115.default.Fragment,
653672
653882
  null,
@@ -654198,7 +654408,7 @@ function ChatInput({ onSubmit, onCommand, placeholder = "Type your message...",
654198
654408
  const [argsSelectedIndex, setArgsSelectedIndex] = import_react120.default.useState(0);
654199
654409
  const argsPickerContext = (0, import_react120.useMemo)(() => {
654200
654410
  const text2 = buffer.text;
654201
- const rootMatch = text2.match(/^\/([a-zA-Z0-9_-]+)(?:\s+\S+)*\s*$/);
654411
+ const rootMatch = text2.match(/^\/([a-zA-Z0-9_:-]+)(?:\s+\S+)*\s*$/);
654202
654412
  const inlineTrigger = findInlineCommandTrigger(text2, buffer.getCursorPosition());
654203
654413
  const cmd = (rootMatch == null ? void 0 : rootMatch[1]) ?? (inlineTrigger == null ? void 0 : inlineTrigger.query) ?? "";
654204
654414
  const options3 = getCommandArgsOptions(cmd, text2);
@@ -654514,11 +654724,11 @@ function ChatInput({ onSubmit, onCommand, placeholder = "Type your message...",
654514
654724
  const text2 = buffer.text;
654515
654725
  if (!text2.startsWith("/"))
654516
654726
  return "";
654517
- const match = text2.match(/^\/([a-zA-Z0-9_-]+)(\s*)$/);
654727
+ const match = text2.match(/^\/([a-zA-Z0-9_:-]+)(\s*)$/);
654518
654728
  if (!match)
654519
654729
  return "";
654520
654730
  const cmd = match[1] ?? "";
654521
- const hint = COMMAND_ARGS_HINTS[cmd];
654731
+ const hint = getCommandArgsHint(cmd);
654522
654732
  if (!hint)
654523
654733
  return "";
654524
654734
  return match[2] && match[2].length > 0 ? hint : ` ${hint}`;
@@ -654577,7 +654787,7 @@ function ChatInput({ onSubmit, onCommand, placeholder = "Type your message...",
654577
654787
  plainBuf = "";
654578
654788
  }
654579
654789
  };
654580
- const isPlaceholderTag = (tag2) => /^\[Paste \d+ lines #\d+\]$/.test(tag2) || /^\[image #\d+\]$/.test(tag2) || /^\[Skill:[^\]]+\]$/.test(tag2) || /^\[GitLine:[^\]]+\]$/.test(tag2) || /^\[»[^\]]*\]$/.test(tag2);
654790
+ const isPlaceholderTag = (tag2) => /^\[Paste \d+ lines #\d+\]$/.test(tag2) || /^\[image #\d+\]$/.test(tag2) || /^\[Skill:[^\]]+\]$/.test(tag2) || /^\[GitLine:[^\]]+\]$/.test(tag2) || /^\[»[^\]]*\]$/.test(tag2) || /^\[[^\]]+\]$/.test(tag2);
654581
654791
  let i = 0;
654582
654792
  while (i < line.length) {
654583
654793
  const ch = line[i];
@@ -654603,8 +654813,14 @@ function ChatInput({ onSubmit, onCommand, placeholder = "Type your message...",
654603
654813
  if (closeIdx !== -1) {
654604
654814
  const tagText = line.slice(i, closeIdx + 1);
654605
654815
  if (isPlaceholderTag(tagText)) {
654816
+ const atPrefix = i > 0 && line[i - 1] === "@" ? "@" : "";
654817
+ if (atPrefix) {
654818
+ if (plainBuf.endsWith("@")) {
654819
+ plainBuf = plainBuf.slice(0, -1);
654820
+ }
654821
+ }
654606
654822
  flushPlain();
654607
- tokens.push({ text: tagText, highlight: true });
654823
+ tokens.push({ text: atPrefix + tagText, highlight: true });
654608
654824
  i = closeIdx + 1;
654609
654825
  continue;
654610
654826
  }
@@ -663245,16 +663461,25 @@ function ToolConfirmation({ toolName, toolArguments, allTools, onConfirm, onHook
663245
663461
  };
663246
663462
  }, [terminalCommand, commandPageOffset, terminalColumns]);
663247
663463
  (0, import_react149.useEffect)(() => {
663464
+ var _a21, _b14;
663248
663465
  const context3 = {
663249
663466
  toolName,
663250
663467
  args: toolArguments,
663251
663468
  isSensitive: sensitiveCommandCheck.isSensitive,
663469
+ matchedPattern: (_a21 = sensitiveCommandCheck.matchedCommand) == null ? void 0 : _a21.pattern,
663470
+ matchedReason: (_b14 = sensitiveCommandCheck.matchedCommand) == null ? void 0 : _b14.description,
663252
663471
  allTools: allTools == null ? void 0 : allTools.map((t2) => ({
663253
663472
  name: t2.function.name,
663254
663473
  arguments: t2.function.arguments
663255
663474
  }))
663256
663475
  };
663257
663476
  unifiedHooksExecutor.executeHooks("toolConfirmation", context3).then((hookResult) => {
663477
+ const autoResult = extractHookProvidedConfirmation(hookResult);
663478
+ if (autoResult) {
663479
+ setHasSelected(true);
663480
+ onConfirm(autoResult);
663481
+ return;
663482
+ }
663258
663483
  const interpreted = interpretHookResult("toolConfirmation", hookResult);
663259
663484
  if (interpreted.action === "warn" && interpreted.warningMessage) {
663260
663485
  console.warn(interpreted.warningMessage);
@@ -663268,7 +663493,13 @@ function ToolConfirmation({ toolName, toolArguments, allTools, onConfirm, onHook
663268
663493
  }).catch((error42) => {
663269
663494
  console.error("Failed to execute toolConfirmation hook:", error42);
663270
663495
  });
663271
- }, [toolName, toolArguments, sensitiveCommandCheck.isSensitive, allTools]);
663496
+ }, [
663497
+ toolName,
663498
+ toolArguments,
663499
+ sensitiveCommandCheck.isSensitive,
663500
+ sensitiveCommandCheck.matchedCommand,
663501
+ allTools
663502
+ ]);
663272
663503
  (0, import_react149.useEffect)(() => {
663273
663504
  if (!vscodeConnection.isConnected()) {
663274
663505
  return;
@@ -679093,6 +679324,8 @@ var init_sseManager = __esm({
679093
679324
  init_hashBasedSnapshot();
679094
679325
  init_permissionsConfig();
679095
679326
  init_sensitiveCommandManager();
679327
+ init_unifiedHooksExecutor();
679328
+ init_hookResultInterpreter();
679096
679329
  SSEManager = class {
679097
679330
  constructor() {
679098
679331
  Object.defineProperty(this, "server", {
@@ -679482,6 +679715,25 @@ var init_sseManager = __esm({
679482
679715
  });
679483
679716
  }
679484
679717
  availableOptions.push({ value: "reject_with_reply", label: "Reject with reply" }, { value: "reject", label: "Reject and end session" });
679718
+ try {
679719
+ const hookContext = {
679720
+ toolName: toolCall.function.name,
679721
+ args: toolCall.function.arguments,
679722
+ isSensitive,
679723
+ matchedPattern: sensitiveInfo == null ? void 0 : sensitiveInfo.pattern,
679724
+ matchedReason: sensitiveInfo == null ? void 0 : sensitiveInfo.description,
679725
+ allTools: allTools == null ? void 0 : allTools.map((t) => ({
679726
+ name: t.function.name,
679727
+ arguments: t.function.arguments
679728
+ }))
679729
+ };
679730
+ const hookResult = await unifiedHooksExecutor.executeHooks("toolConfirmation", hookContext);
679731
+ const autoResult = extractHookProvidedConfirmation(hookResult);
679732
+ if (autoResult) {
679733
+ return autoResult;
679734
+ }
679735
+ } catch {
679736
+ }
679485
679737
  sendEvent({
679486
679738
  type: "tool_confirmation_request",
679487
679739
  data: {
@@ -693069,7 +693321,7 @@ var require_package4 = __commonJS({
693069
693321
  "package.json"(exports2, module2) {
693070
693322
  module2.exports = {
693071
693323
  name: "snow-ai",
693072
- version: "0.8.10",
693324
+ version: "0.8.11",
693073
693325
  description: "Agentic coding in your terminal",
693074
693326
  license: "MIT",
693075
693327
  bin: {
@@ -693269,6 +693521,8 @@ var init_acpManager = __esm({
693269
693521
  init_sessionManager();
693270
693522
  init_permissionsConfig();
693271
693523
  init_sensitiveCommandManager();
693524
+ init_unifiedHooksExecutor();
693525
+ init_hookResultInterpreter();
693272
693526
  init_chat();
693273
693527
  init_responses();
693274
693528
  init_anthropic();
@@ -693694,6 +693948,26 @@ var init_acpManager = __esm({
693694
693948
  name: "Reject",
693695
693949
  kind: "reject_once"
693696
693950
  });
693951
+ try {
693952
+ const hookContext = {
693953
+ toolName: toolCall.function.name,
693954
+ args: toolCall.function.arguments,
693955
+ isSensitive,
693956
+ allTools: void 0
693957
+ };
693958
+ const hookResult = await unifiedHooksExecutor.executeHooks("toolConfirmation", hookContext);
693959
+ const autoResult = extractHookProvidedConfirmation(hookResult);
693960
+ if (autoResult) {
693961
+ if (autoResult === "approve" || autoResult === "approve_always") {
693962
+ if (autoResult === "approve_always") {
693963
+ addToolToPermissions(workingDirectory, toolCall.function.name);
693964
+ }
693965
+ return true;
693966
+ }
693967
+ return false;
693968
+ }
693969
+ } catch {
693970
+ }
693697
693971
  const toolCallUpdate = {
693698
693972
  toolCallId: toolCall.id,
693699
693973
  title: toolCall.function.name
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "snow-ai",
3
- "version": "0.8.10",
3
+ "version": "0.8.11",
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.8.10",
3
+ "version": "0.8.11",
4
4
  "description": "Agentic coding in your terminal",
5
5
  "license": "MIT",
6
6
  "bin": {