snow-ai 0.5.23 → 0.5.25

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
@@ -1429,11 +1429,11 @@ var require_react_development = __commonJS({
1429
1429
  var dispatcher = resolveDispatcher();
1430
1430
  return dispatcher.useReducer(reducer3, initialArg, init);
1431
1431
  }
1432
- function useRef13(initialValue) {
1432
+ function useRef14(initialValue) {
1433
1433
  var dispatcher = resolveDispatcher();
1434
1434
  return dispatcher.useRef(initialValue);
1435
1435
  }
1436
- function useEffect50(create3, deps) {
1436
+ function useEffect51(create3, deps) {
1437
1437
  var dispatcher = resolveDispatcher();
1438
1438
  return dispatcher.useEffect(create3, deps);
1439
1439
  }
@@ -2216,14 +2216,14 @@ var require_react_development = __commonJS({
2216
2216
  exports2.useContext = useContext13;
2217
2217
  exports2.useDebugValue = useDebugValue;
2218
2218
  exports2.useDeferredValue = useDeferredValue;
2219
- exports2.useEffect = useEffect50;
2219
+ exports2.useEffect = useEffect51;
2220
2220
  exports2.useId = useId;
2221
2221
  exports2.useImperativeHandle = useImperativeHandle2;
2222
2222
  exports2.useInsertionEffect = useInsertionEffect;
2223
2223
  exports2.useLayoutEffect = useLayoutEffect2;
2224
2224
  exports2.useMemo = useMemo30;
2225
2225
  exports2.useReducer = useReducer8;
2226
- exports2.useRef = useRef13;
2226
+ exports2.useRef = useRef14;
2227
2227
  exports2.useState = useState57;
2228
2228
  exports2.useSyncExternalStore = useSyncExternalStore;
2229
2229
  exports2.useTransition = useTransition;
@@ -45437,10 +45437,10 @@ var require_symlink = __commonJS({
45437
45437
  pathExists2(dstpath, (err, destinationExists) => {
45438
45438
  if (err) return callback(err);
45439
45439
  if (destinationExists) return callback(null);
45440
- symlinkPaths(srcpath, dstpath, (err2, relative8) => {
45440
+ symlinkPaths(srcpath, dstpath, (err2, relative9) => {
45441
45441
  if (err2) return callback(err2);
45442
- srcpath = relative8.toDst;
45443
- symlinkType(relative8.toCwd, type, (err3, type2) => {
45442
+ srcpath = relative9.toDst;
45443
+ symlinkType(relative9.toCwd, type, (err3, type2) => {
45444
45444
  if (err3) return callback(err3);
45445
45445
  const dir = path53.dirname(dstpath);
45446
45446
  pathExists2(dir, (err4, dirExists) => {
@@ -45458,9 +45458,9 @@ var require_symlink = __commonJS({
45458
45458
  function createSymlinkSync(srcpath, dstpath, type) {
45459
45459
  const destinationExists = fs42.existsSync(dstpath);
45460
45460
  if (destinationExists) return void 0;
45461
- const relative8 = symlinkPathsSync(srcpath, dstpath);
45462
- srcpath = relative8.toDst;
45463
- type = symlinkTypeSync(relative8.toCwd, type);
45461
+ const relative9 = symlinkPathsSync(srcpath, dstpath);
45462
+ srcpath = relative9.toDst;
45463
+ type = symlinkTypeSync(relative9.toCwd, type);
45464
45464
  const dir = path53.dirname(dstpath);
45465
45465
  const exists = fs42.existsSync(dir);
45466
45466
  if (exists) return fs42.symlinkSync(srcpath, dstpath, type);
@@ -45971,8 +45971,8 @@ var init_logger = __esm({
45971
45971
  const timestamp = Date.now();
45972
45972
  const ext = path5.extname(filePath);
45973
45973
  const basename6 = path5.basename(filePath, ext);
45974
- const dirname10 = path5.dirname(filePath);
45975
- const rotatedPath = path5.join(dirname10, `${basename6}-${timestamp}${ext}`);
45974
+ const dirname11 = path5.dirname(filePath);
45975
+ const rotatedPath = path5.join(dirname11, `${basename6}-${timestamp}${ext}`);
45976
45976
  fs5.renameSync(filePath, rotatedPath);
45977
45977
  }
45978
45978
  writeLog(level, message, meta) {
@@ -47918,11 +47918,11 @@ var init_systemPrompt = __esm({
47918
47918
 
47919
47919
  ### Rigorous Coding Habits
47920
47920
  - **Location Code**: Must First use a search tool to locate the line number of the code, then use \`filesystem-read\` to read the code content
47921
- - **Boundary verification**: MUST use \`filesystem-read\` to identify complete code boundaries before ANY edit. Never guess line numbers or code structure
47921
+ - **Boundary verification - COMPLETE CODE BLOCKS ONLY**: MUST use \`filesystem-read\` to identify COMPLETE code boundaries before ANY edit. Never guess line numbers or code structure. MANDATORY: verify ALL closing pairs are included - every \`{\` must have \`}\`, every \`(\` must have \`)\`, every \`[\` must have \`]\`, every \`<tag>\` must have \`</tag>\`. Count and match ALL opening/closing symbols before editing. ABSOLUTE PROHIBITIONS: NEVER edit partial functions (missing closing brace), NEVER edit incomplete HTML/XML/JSX tags (missing closing tag), NEVER edit partial code blocks (unmatched brackets/braces/parentheses).
47922
47922
  - **Impact analysis**: Consider modification impact and conflicts with existing business logic
47923
47923
  - **Optimal solution**: Avoid hardcoding/shortcuts unless explicitly requested
47924
47924
  - **Avoid duplication**: Search for existing reusable functions before creating new ones
47925
- - **Compilable code**: No syntax errors - always verify complete syntactic units
47925
+ - **Compilable code**: No syntax errors - always verify complete syntactic units with ALL opening/closing pairs matched
47926
47926
 
47927
47927
  ### Smart Action Mode
47928
47928
  **Principle: Understand enough to code correctly, but don't over-investigate**
@@ -47987,9 +47987,11 @@ AI: todo-add(content=["Read utils module structure", "Identify refactor targets"
47987
47987
  **CRITICAL: BOUNDARY-FIRST EDITING**
47988
47988
 
47989
47989
  **MANDATORY WORKFLOW:**
47990
- 1. **READ & VERIFY** - Use \`filesystem-read\` to identify COMPLETE units (functions: opening to closing brace, markup: full tags, check indentation)
47991
- 2. **COPY COMPLETE CODE** - Remove line numbers, preserve all content
47992
- 3. **EDIT** - \`filesystem-edit_search\` (fuzzy match, safer) or \`filesystem-edit\` (line-based, for add/delete)
47990
+ 1. **READ & VERIFY** - Use \`filesystem-read\` to identify COMPLETE units (functions: entire declaration to final closing brace \`}\`, HTML/XML/JSX markup: full opening \`<tag>\` to closing \`</tag>\` pairs, code blocks: ALL matching brackets/braces/parentheses with proper indentation)
47991
+ 2. **COUNT & MATCH** - Before editing, MANDATORY verification: count ALL opening and closing symbols - every \`{\` must have \`}\`, every \`(\` must have \`)\`, every \`[\` must have \`]\`, every \`<tag>\` must have \`</tag>\`. Verify indentation levels are consistent.
47992
+ 3. **COPY COMPLETE CODE** - Remove line numbers, preserve ALL content including ALL closing symbols
47993
+ 4. **ABSOLUTE PROHIBITIONS** - NEVER edit partial functions (missing closing brace \`}\`), NEVER edit incomplete markup (missing \`</tag>\`), NEVER edit partial code blocks (unmatched \`{\`, \`}\`, \`(\`, \`)\`, \`[\`, \`]\`), NEVER copy line numbers from filesystem-read output
47994
+ 5. **EDIT** - \`filesystem-edit_search\` (fuzzy match, safer) or \`filesystem-edit\` (line-based, for add/delete) - use ONLY after verification passes
47993
47995
 
47994
47996
  **BATCH OPERATIONS:** Modify 2+ files? Use batch: \`filesystem-read(filePath=["a.ts","b.ts"])\` or \`filesystem-edit_search(filePath=[{path:"a.ts",...},{path:"b.ts",...}])\`
47995
47997
 
@@ -60384,7 +60386,7 @@ var require_snapshot_recorder = __commonJS({
60384
60386
  "node_modules/undici/lib/mock/snapshot-recorder.js"(exports2, module2) {
60385
60387
  "use strict";
60386
60388
  var { writeFile: writeFile4, readFile: readFile3, mkdir: mkdir5 } = __require("node:fs/promises");
60387
- var { dirname: dirname10, resolve: resolve12 } = __require("node:path");
60389
+ var { dirname: dirname11, resolve: resolve12 } = __require("node:path");
60388
60390
  var { setTimeout: setTimeout2, clearTimeout: clearTimeout2 } = __require("node:timers");
60389
60391
  var { InvalidArgumentError, UndiciError } = require_errors();
60390
60392
  var { hashId, isUrlExcludedFactory, normalizeHeaders, createHeaderFilters } = require_snapshot_utils();
@@ -60608,7 +60610,7 @@ var require_snapshot_recorder = __commonJS({
60608
60610
  throw new InvalidArgumentError("Snapshot path is required");
60609
60611
  }
60610
60612
  const resolvedPath = resolve12(path53);
60611
- await mkdir5(dirname10(resolvedPath), { recursive: true });
60613
+ await mkdir5(dirname11(resolvedPath), { recursive: true });
60612
60614
  const data = Array.from(this.#snapshots.entries()).map(([hash, snapshot]) => ({
60613
60615
  hash,
60614
60616
  snapshot
@@ -76195,46 +76197,313 @@ var init_role = __esm({
76195
76197
  var skills_exports = {};
76196
76198
  __export(skills_exports, {
76197
76199
  checkSkillExists: () => checkSkillExists,
76200
+ createSkillFromGenerated: () => createSkillFromGenerated,
76198
76201
  createSkillTemplate: () => createSkillTemplate,
76199
76202
  default: () => skills_default,
76200
76203
  generateExamplesTemplate: () => generateExamplesTemplate,
76201
76204
  generateReferenceTemplate: () => generateReferenceTemplate,
76205
+ generateSkillDraftWithAI: () => generateSkillDraftWithAI,
76202
76206
  generateSkillTemplate: () => generateSkillTemplate,
76203
76207
  getSkillDirectory: () => getSkillDirectory,
76208
+ validateSkillId: () => validateSkillId,
76204
76209
  validateSkillName: () => validateSkillName
76205
76210
  });
76206
76211
  import { homedir as homedir8 } from "os";
76207
76212
  import { join as join10 } from "path";
76208
76213
  import { mkdir as mkdir2, writeFile as writeFile2 } from "fs/promises";
76209
76214
  import { existsSync as existsSync10 } from "fs";
76210
- function validateSkillName(name) {
76215
+ function validateSkillId(name) {
76211
76216
  if (!name || name.trim().length === 0) {
76212
76217
  return { valid: false, error: "Skill name cannot be empty" };
76213
76218
  }
76214
76219
  const trimmedName = name.trim();
76215
- if (trimmedName.length > 64) {
76216
- return { valid: false, error: "Skill name must be 64 characters or less" };
76220
+ if (trimmedName.length > 256) {
76221
+ return { valid: false, error: "Skill name must be 256 characters or less" };
76222
+ }
76223
+ if (trimmedName.includes("\\")) {
76224
+ return {
76225
+ valid: false,
76226
+ error: 'Skill name must use "/" as namespace separator (backslashes are not allowed)'
76227
+ };
76217
76228
  }
76218
- const validNamePattern = /^[a-z0-9-]+$/;
76219
- if (!validNamePattern.test(trimmedName)) {
76229
+ if (trimmedName.includes(":")) {
76230
+ return { valid: false, error: 'Skill name must not contain ":"' };
76231
+ }
76232
+ if (trimmedName.startsWith("/") || trimmedName.endsWith("/")) {
76233
+ return { valid: false, error: 'Skill name must not start or end with "/"' };
76234
+ }
76235
+ const segments = trimmedName.split("/");
76236
+ if (segments.some((segment) => segment.length === 0)) {
76220
76237
  return {
76221
76238
  valid: false,
76222
- error: "Skill name must contain only lowercase letters, numbers, and hyphens"
76239
+ error: "Skill name must not contain empty namespace segments"
76223
76240
  };
76224
76241
  }
76242
+ const validSegmentPattern = /^[a-z0-9-]+$/;
76243
+ for (const segment of segments) {
76244
+ if (segment === "." || segment === "..") {
76245
+ return {
76246
+ valid: false,
76247
+ error: 'Skill name must not contain "." or ".." segments'
76248
+ };
76249
+ }
76250
+ if (segment.length > 64) {
76251
+ return {
76252
+ valid: false,
76253
+ error: "Each skill name segment must be 64 characters or less"
76254
+ };
76255
+ }
76256
+ if (!validSegmentPattern.test(segment)) {
76257
+ return {
76258
+ valid: false,
76259
+ error: "Skill name segments must contain only lowercase letters, numbers, and hyphens"
76260
+ };
76261
+ }
76262
+ }
76225
76263
  return { valid: true };
76226
76264
  }
76265
+ function validateSkillName(name) {
76266
+ return validateSkillId(name);
76267
+ }
76268
+ function stripLeadingFrontMatter(markdown) {
76269
+ const content = markdown.trim();
76270
+ const descriptionPattern = /^---\s*[\s\S]*?---\s*/;
76271
+ if (descriptionPattern.test(content)) {
76272
+ return content.replace(descriptionPattern, "").trim();
76273
+ }
76274
+ return content;
76275
+ }
76276
+ function sanitizeSkillName(input2) {
76277
+ const raw = input2.trim().toLowerCase();
76278
+ const replaced = raw.replace(/[\s_]+/g, "-");
76279
+ const filtered = replaced.replace(/[^a-z0-9-]/g, "");
76280
+ const collapsed = filtered.replace(/-+/g, "-").replace(/^-|-$/g, "");
76281
+ return collapsed.slice(0, 64);
76282
+ }
76283
+ function makeUniqueSkillName(baseName, projectRoot) {
76284
+ const validation = validateSkillName(baseName);
76285
+ let safeBase = validation.valid ? baseName : sanitizeSkillName(baseName);
76286
+ if (!safeBase) {
76287
+ safeBase = "generated-skill";
76288
+ }
76289
+ let candidate = safeBase;
76290
+ let suffix = 2;
76291
+ while (checkSkillExists(candidate, "global") || checkSkillExists(candidate, "project", projectRoot)) {
76292
+ const suffixText = `-${suffix++}`;
76293
+ const maxBaseLen = 64 - suffixText.length;
76294
+ const truncatedBase = safeBase.slice(0, Math.max(1, maxBaseLen));
76295
+ candidate = `${truncatedBase}${suffixText}`;
76296
+ }
76297
+ return candidate;
76298
+ }
76299
+ function extractTaggedJson(text3) {
76300
+ const match2 = text3.match(/<json>\s*([\s\S]*?)\s*<\/json>/i);
76301
+ if (match2 && match2[1]) {
76302
+ return match2[1].trim();
76303
+ }
76304
+ return null;
76305
+ }
76306
+ function extractTaggedFiles(text3) {
76307
+ var _a21;
76308
+ const map3 = /* @__PURE__ */ new Map();
76309
+ const re = /<file\s+path="([^"]+)">\s*([\s\S]*?)\s*<\/file>/gi;
76310
+ let match2;
76311
+ while (match2 = re.exec(text3)) {
76312
+ const path53 = (_a21 = match2[1]) == null ? void 0 : _a21.trim();
76313
+ const content = match2[2] ?? "";
76314
+ if (path53) {
76315
+ map3.set(path53, content);
76316
+ }
76317
+ }
76318
+ return map3;
76319
+ }
76320
+ function buildSkillGenerationSystemPrompt() {
76321
+ return `You create Snow CLI Skills (Claude Code compatible).
76322
+
76323
+ Rules (MUST FOLLOW):
76324
+ 1) Output MUST ONLY contain: <json>...</json> and <file path="...">...</file> blocks. No other text.
76325
+ 2) The <json> block MUST be valid JSON with keys: name, description.
76326
+ 3) name MUST be a directory-safe slug: lowercase letters, numbers, hyphens only (^[a-z0-9-]+$), max 64 chars.
76327
+ 4) description and ALL file contents MUST be written in the SAME LANGUAGE as the user's requirement.
76328
+ 5) Generate exactly 3 file blocks with these paths (case-sensitive):
76329
+ - SKILL.md
76330
+ - reference.md
76331
+ - examples.md
76332
+ 6) The SKILL.md content MUST NOT include YAML front matter. Start with a single H1 title and include these sections:
76333
+ - ## Instructions
76334
+ - ### Context
76335
+ - ### Steps (numbered)
76336
+ - ## Examples (at least 2)
76337
+ - ## Best Practices
76338
+ - ## Common Pitfalls
76339
+ - ## Related Skills
76340
+ - ## References
76341
+ 7) Do NOT mention or include allowed-tools (Snow CLI will manage it).
76342
+
76343
+ Quality bar:
76344
+ - Be concrete, step-by-step, with realistic examples.
76345
+ - Keep it helpful and production-oriented.`;
76346
+ }
76347
+ function buildSkillGenerationUserPrompt(requirement) {
76348
+ return `Generate a Snow CLI Skill from the requirement below.
76349
+
76350
+ CRITICAL OUTPUT FORMAT (no extra text):
76351
+ <json>
76352
+ {"name":"example-skill","description":"..."}
76353
+ </json>
76354
+ <file path="SKILL.md">
76355
+ # ...
76356
+ </file>
76357
+ <file path="reference.md">
76358
+ # ...
76359
+ </file>
76360
+ <file path="examples.md">
76361
+ # ...
76362
+ </file>
76363
+
76364
+ Rules:
76365
+ - Output ONLY the <json> and <file> blocks.
76366
+ - <json> must be valid JSON with keys: name, description (no other keys).
76367
+ - name must be a slug: lowercase letters, numbers, hyphens only (^[a-z0-9-]+$), max 64 chars.
76368
+ - description and ALL file contents MUST be written in the SAME LANGUAGE as the requirement.
76369
+ - The SKILL.md content MUST NOT include YAML front matter.
76370
+ - Do NOT mention allowed-tools.
76371
+
76372
+ Requirement:
76373
+ ${requirement}`;
76374
+ }
76375
+ async function callModelForText(messages, abortSignal) {
76376
+ var _a21, _b14;
76377
+ const config3 = getOpenAiConfig();
76378
+ const model = config3.advancedModel || config3.basicModel;
76379
+ if (!model) {
76380
+ throw new Error("\u672A\u914D\u7F6E\u6A21\u578B\uFF0C\u8BF7\u5148\u5728\u8BBE\u7F6E\u4E2D\u9009\u62E9\u6A21\u578B");
76381
+ }
76382
+ let stream;
76383
+ switch (config3.requestMethod) {
76384
+ case "anthropic":
76385
+ stream = createStreamingAnthropicCompletion({
76386
+ model,
76387
+ messages,
76388
+ max_tokens: 3e3,
76389
+ includeBuiltinSystemPrompt: false,
76390
+ disableThinking: true
76391
+ }, abortSignal);
76392
+ break;
76393
+ case "gemini":
76394
+ stream = createStreamingGeminiCompletion({
76395
+ model,
76396
+ messages,
76397
+ includeBuiltinSystemPrompt: false
76398
+ }, abortSignal);
76399
+ break;
76400
+ case "responses":
76401
+ stream = createStreamingResponse({
76402
+ model,
76403
+ messages,
76404
+ includeBuiltinSystemPrompt: false,
76405
+ tool_choice: "none"
76406
+ }, abortSignal);
76407
+ break;
76408
+ case "chat":
76409
+ default:
76410
+ stream = createStreamingChatCompletion({
76411
+ model,
76412
+ messages,
76413
+ includeBuiltinSystemPrompt: false,
76414
+ // NOTE: chat.ts uses `options.temperature || 0.7`, so 0 would be ignored.
76415
+ temperature: 1e-4
76416
+ }, abortSignal);
76417
+ break;
76418
+ }
76419
+ let text3 = "";
76420
+ for await (const chunk2 of stream) {
76421
+ if (abortSignal == null ? void 0 : abortSignal.aborted) {
76422
+ throw new Error("Request aborted");
76423
+ }
76424
+ if (chunk2 && typeof chunk2 === "object") {
76425
+ if (chunk2.type === "content" && typeof chunk2.content === "string") {
76426
+ text3 += chunk2.content;
76427
+ continue;
76428
+ }
76429
+ const maybeChoices = chunk2.choices;
76430
+ const deltaContent = (_b14 = (_a21 = maybeChoices == null ? void 0 : maybeChoices[0]) == null ? void 0 : _a21.delta) == null ? void 0 : _b14.content;
76431
+ if (typeof deltaContent === "string") {
76432
+ text3 += deltaContent;
76433
+ }
76434
+ }
76435
+ }
76436
+ if (!text3.trim()) {
76437
+ throw new Error("\u6A21\u578B\u672A\u8FD4\u56DE\u53EF\u7528\u5185\u5BB9");
76438
+ }
76439
+ return text3;
76440
+ }
76441
+ async function generateSkillDraftWithAI(requirement, projectRoot, abortSignal) {
76442
+ const trimmed = requirement.trim();
76443
+ if (!trimmed) {
76444
+ throw new Error("\u6280\u80FD\u9700\u6C42\u4E0D\u80FD\u4E3A\u7A7A");
76445
+ }
76446
+ const systemPrompt = buildSkillGenerationSystemPrompt();
76447
+ const userPrompt = buildSkillGenerationUserPrompt(trimmed);
76448
+ const messages = [
76449
+ { role: "system", content: systemPrompt },
76450
+ { role: "user", content: userPrompt }
76451
+ ];
76452
+ const raw = await callModelForText(messages, abortSignal);
76453
+ const jsonText = extractTaggedJson(raw);
76454
+ const files = extractTaggedFiles(raw);
76455
+ if (!jsonText) {
76456
+ throw new Error("AI \u8F93\u51FA\u7F3A\u5C11 <json> \u5757");
76457
+ }
76458
+ const parseResult = parseJsonWithFix(jsonText, {
76459
+ toolName: "skills ai json",
76460
+ logWarning: true,
76461
+ logError: true
76462
+ });
76463
+ if (!parseResult.success || !parseResult.data) {
76464
+ throw new Error("AI \u8F93\u51FA JSON \u89E3\u6790\u5931\u8D25");
76465
+ }
76466
+ const nameRaw = typeof parseResult.data.name === "string" ? parseResult.data.name.trim() : "";
76467
+ const descriptionRaw = typeof parseResult.data.description === "string" ? parseResult.data.description.trim() : "";
76468
+ const skillBody = files.get("SKILL.md");
76469
+ const referenceMd = files.get("reference.md");
76470
+ const examplesMd = files.get("examples.md");
76471
+ if (!skillBody || !referenceMd || !examplesMd) {
76472
+ throw new Error("AI \u8F93\u51FA\u7F3A\u5C11\u6587\u4EF6\u5185\u5BB9\uFF08\u9700\u8981 SKILL.md/reference.md/examples.md\uFF09");
76473
+ }
76474
+ const uniqueName = makeUniqueSkillName(nameRaw, projectRoot);
76475
+ return {
76476
+ skillName: uniqueName,
76477
+ description: descriptionRaw || uniqueName,
76478
+ generated: {
76479
+ skillMarkdownBody: stripLeadingFrontMatter(skillBody),
76480
+ referenceMarkdown: stripLeadingFrontMatter(referenceMd),
76481
+ examplesMarkdown: stripLeadingFrontMatter(examplesMd)
76482
+ }
76483
+ };
76484
+ }
76485
+ function generateSkillMarkdownWithFrontMatter(metadata, bodyMarkdown) {
76486
+ const cleanedBody = stripLeadingFrontMatter(bodyMarkdown).trim();
76487
+ return `---
76488
+ name: ${metadata.name}
76489
+ description: ${metadata.description}
76490
+ allowed-tools:
76491
+ ---
76492
+
76493
+ ${cleanedBody}
76494
+ `;
76495
+ }
76227
76496
  function checkSkillExists(skillName, location, projectRoot) {
76228
76497
  const skillDir = getSkillDirectory(skillName, location, projectRoot);
76229
76498
  return existsSync10(skillDir);
76230
76499
  }
76231
76500
  function getSkillDirectory(skillName, location, projectRoot) {
76501
+ const segments = skillName.split("/").filter(Boolean);
76232
76502
  if (location === "global") {
76233
- return join10(homedir8(), ".snow", "skills", skillName);
76234
- } else {
76235
- const root2 = projectRoot || process.cwd();
76236
- return join10(root2, ".snow", "skills", skillName);
76503
+ return join10(homedir8(), ".snow", "skills", ...segments);
76237
76504
  }
76505
+ const root2 = projectRoot || process.cwd();
76506
+ return join10(root2, ".snow", "skills", ...segments);
76238
76507
  }
76239
76508
  function generateSkillTemplate(metadata) {
76240
76509
  return `---
@@ -76360,6 +76629,69 @@ What this advanced example demonstrates.
76360
76629
  **Result:** What was achieved
76361
76630
  `;
76362
76631
  }
76632
+ async function createSkillFromGenerated(skillName, description, generated, location, projectRoot) {
76633
+ try {
76634
+ const skillDir = getSkillDirectory(skillName, location, projectRoot);
76635
+ if (existsSync10(skillDir)) {
76636
+ return {
76637
+ success: false,
76638
+ path: skillDir,
76639
+ error: `Skill "${skillName}" already exists at ${skillDir}`
76640
+ };
76641
+ }
76642
+ await mkdir2(skillDir, { recursive: true });
76643
+ await mkdir2(join10(skillDir, "scripts"), { recursive: true });
76644
+ await mkdir2(join10(skillDir, "templates"), { recursive: true });
76645
+ const leafName = skillName.split("/").filter(Boolean).pop() || skillName;
76646
+ const skillContent = generateSkillMarkdownWithFrontMatter({ name: leafName, description }, generated.skillMarkdownBody);
76647
+ await writeFile2(join10(skillDir, "SKILL.md"), skillContent, "utf-8");
76648
+ await writeFile2(join10(skillDir, "reference.md"), generated.referenceMarkdown.trim() + "\n", "utf-8");
76649
+ await writeFile2(join10(skillDir, "examples.md"), generated.examplesMarkdown.trim() + "\n", "utf-8");
76650
+ const templateContent = `This is a template file for ${skillName}.
76651
+
76652
+ You can use this as a starting point for generating code, configurations, or documentation.
76653
+
76654
+ Variables can be referenced like: {{variable_name}}
76655
+ `;
76656
+ await writeFile2(join10(skillDir, "templates", "template.txt"), templateContent, "utf-8");
76657
+ const scriptContent = `#!/usr/bin/env python3
76658
+ """
76659
+ Helper script for ${skillName}
76660
+
76661
+ Usage:
76662
+ python scripts/helper.py <input_file>
76663
+ """
76664
+
76665
+ import sys
76666
+
76667
+ def main():
76668
+ if len(sys.argv) < 2:
76669
+ print("Usage: python helper.py <input_file>")
76670
+ sys.exit(1)
76671
+
76672
+ input_file = sys.argv[1]
76673
+ print(f"Processing {input_file}...")
76674
+
76675
+ # Add your processing logic here
76676
+
76677
+ print("Done!")
76678
+
76679
+ if __name__ == "__main__":
76680
+ main()
76681
+ `;
76682
+ await writeFile2(join10(skillDir, "scripts", "helper.py"), scriptContent, "utf-8");
76683
+ return {
76684
+ success: true,
76685
+ path: skillDir
76686
+ };
76687
+ } catch (error) {
76688
+ return {
76689
+ success: false,
76690
+ path: "",
76691
+ error: error instanceof Error ? error.message : "Unknown error"
76692
+ };
76693
+ }
76694
+ }
76363
76695
  async function createSkillTemplate(skillName, description, location, projectRoot) {
76364
76696
  try {
76365
76697
  const skillDir = getSkillDirectory(skillName, location, projectRoot);
@@ -76373,7 +76705,8 @@ async function createSkillTemplate(skillName, description, location, projectRoot
76373
76705
  await mkdir2(skillDir, { recursive: true });
76374
76706
  await mkdir2(join10(skillDir, "scripts"), { recursive: true });
76375
76707
  await mkdir2(join10(skillDir, "templates"), { recursive: true });
76376
- const skillContent = generateSkillTemplate({ name: skillName, description });
76708
+ const leafName = skillName.split("/").filter(Boolean).pop() || skillName;
76709
+ const skillContent = generateSkillTemplate({ name: leafName, description });
76377
76710
  await writeFile2(join10(skillDir, "SKILL.md"), skillContent, "utf-8");
76378
76711
  const referenceContent = generateReferenceTemplate();
76379
76712
  await writeFile2(join10(skillDir, "reference.md"), referenceContent, "utf-8");
@@ -76429,6 +76762,12 @@ var init_skills = __esm({
76429
76762
  "dist/utils/commands/skills.js"() {
76430
76763
  "use strict";
76431
76764
  init_commandExecutor();
76765
+ init_apiConfig();
76766
+ init_chat();
76767
+ init_responses();
76768
+ init_gemini();
76769
+ init_anthropic();
76770
+ init_retryUtils();
76432
76771
  registerCommand("skills", {
76433
76772
  execute: async () => {
76434
76773
  return {
@@ -80592,7 +80931,12 @@ var init_en = __esm({
80592
80931
  confirmSave: "Save this custom command? (y/n)",
80593
80932
  confirmYes: "Yes",
80594
80933
  confirmNo: "Cancel",
80595
- escCancel: "Press ESC to cancel"
80934
+ escCancel: "Press ESC to cancel",
80935
+ resultTypeExecute: "Execute in terminal",
80936
+ resultTypePrompt: "Send to AI",
80937
+ resultLocationGlobal: "Global (~/.snow/commands/)",
80938
+ resultLocationProject: "Project (.snow/commands/)",
80939
+ saveSuccessMessage: "Custom command '{name}' saved successfully!\nType: {type}\nLocation: {location}\nYou can now use /{name}"
80596
80940
  },
80597
80941
  chatScreen: {
80598
80942
  // Header
@@ -80798,9 +81142,24 @@ var init_en = __esm({
80798
81142
  },
80799
81143
  skillsCreation: {
80800
81144
  title: "Create New Skill",
81145
+ modeLabel: "Creation Mode:",
81146
+ modeAi: "AI Generate (describe requirement)",
81147
+ modeManual: "Manual (create templates)",
81148
+ requirementLabel: "Requirement:",
81149
+ requirementHint: "Describe what you want this Skill to do (content will follow this language)",
81150
+ requirementPlaceholder: "e.g., Generate a Skill for releasing npm packages...",
81151
+ generatingLabel: "AI Generating...",
81152
+ generatingMessage: "Generating skill files, please wait",
81153
+ filesLabel: "Files to be created:",
81154
+ editName: "Edit Name",
81155
+ editNameLabel: "Current Skill Name:",
81156
+ editNameHint: "Enter a new skill name (lowercase letters/numbers/hyphens, max 64 chars)",
81157
+ editNamePlaceholder: "new-skill-name",
81158
+ regenerate: "Regenerate",
81159
+ cancel: "Cancel",
80801
81160
  nameLabel: "Skill Name:",
80802
- nameHint: "Use lowercase letters, numbers, and hyphens only (max 64 chars)",
80803
- namePlaceholder: "my-skill-name",
81161
+ nameHint: 'Use lowercase letters, numbers, and hyphens. Use "/" to namespace (max 64 chars per segment)',
81162
+ namePlaceholder: "team/my-skill-name",
80804
81163
  descriptionLabel: "Description:",
80805
81164
  descriptionHint: "Brief description of what this Skill does and when to use it",
80806
81165
  descriptionPlaceholder: "A brief description...",
@@ -80817,7 +81176,15 @@ var init_en = __esm({
80817
81176
  errorInvalidName: "Invalid skill name",
80818
81177
  errorExistsBoth: 'Skill "{name}" already exists in both global and project locations',
80819
81178
  errorExistsGlobal: 'Skill "{name}" already exists in global location (~/.snow/skills/)',
80820
- errorExistsProject: 'Skill "{name}" already exists in project location (.snow/skills/)'
81179
+ errorExistsProject: 'Skill "{name}" already exists in project location (.snow/skills/)',
81180
+ errorExistsAny: 'Skill "{name}" already exists, please choose another name',
81181
+ errorGeneration: "AI generation failed",
81182
+ errorNoGeneratedContent: "No generated content, please retry",
81183
+ resultModeAi: "AI Generated",
81184
+ resultModeManual: "Manual Template",
81185
+ createSuccessMessage: 'Skill "{name}" created successfully!\nMode: {mode}\nLocation: {location}\nPath: {path}\n\nThe following files have been created:\n- SKILL.md (main skill documentation)\n- reference.md (detailed reference)\n- examples.md (usage examples)\n- templates/template.txt (template file)\n- scripts/helper.py (helper script)\n\nYou can now edit these files to customize your skill.',
81186
+ createErrorMessage: "Failed to create skill: {error}",
81187
+ errorUnknown: "Unknown error"
80821
81188
  },
80822
81189
  askUser: {
80823
81190
  header: "[User Input Required]",
@@ -81563,7 +81930,12 @@ var init_zh = __esm({
81563
81930
  confirmSave: "\u4FDD\u5B58\u6B64\u81EA\u5B9A\u4E49\u547D\u4EE4? (y/n)",
81564
81931
  confirmYes: "Yes",
81565
81932
  confirmNo: "Cancel",
81566
- escCancel: "\u6309 ESC \u53D6\u6D88"
81933
+ escCancel: "\u6309 ESC \u53D6\u6D88",
81934
+ resultTypeExecute: "\u5728\u7EC8\u7AEF\u6267\u884C",
81935
+ resultTypePrompt: "\u53D1\u9001\u7ED9 AI",
81936
+ resultLocationGlobal: "\u5168\u5C40 (~/.snow/commands/)",
81937
+ resultLocationProject: "\u9879\u76EE (.snow/commands/)",
81938
+ saveSuccessMessage: "\u81EA\u5B9A\u4E49\u547D\u4EE4 '{name}' \u4FDD\u5B58\u6210\u529F\uFF01\n\u7C7B\u578B: {type}\n\u4F4D\u7F6E: {location}\n\u4F60\u73B0\u5728\u53EF\u4EE5\u4F7F\u7528 /{name}"
81567
81939
  },
81568
81940
  chatScreen: {
81569
81941
  // Header
@@ -81769,9 +82141,24 @@ var init_zh = __esm({
81769
82141
  },
81770
82142
  skillsCreation: {
81771
82143
  title: "\u521B\u5EFA\u65B0\u6280\u80FD",
82144
+ modeLabel: "\u9009\u62E9\u521B\u5EFA\u65B9\u5F0F:",
82145
+ modeAi: "AI \u751F\u6210\uFF08\u8F93\u5165\u9700\u6C42\u5373\u53EF\uFF09",
82146
+ modeManual: "\u624B\u52A8\u521B\u5EFA\uFF08\u751F\u6210\u6A21\u677F\uFF09",
82147
+ requirementLabel: "\u6280\u80FD\u9700\u6C42:",
82148
+ requirementHint: "\u7B80\u8981\u63CF\u8FF0\u4F60\u5E0C\u671B\u8BE5\u6280\u80FD\u5B8C\u6210\u4EC0\u4E48\uFF08\u751F\u6210\u5185\u5BB9\u5C06\u8DDF\u968F\u6B64\u8BED\u8A00\uFF09",
82149
+ requirementPlaceholder: "\u4F8B\u5982\uFF1A\u751F\u6210\u4E00\u4E2A\u7528\u4E8E\u53D1\u5E03 npm \u5305\u7684\u6280\u80FD\u2026",
82150
+ generatingLabel: "AI \u751F\u6210\u4E2D...",
82151
+ generatingMessage: "\u6B63\u5728\u751F\u6210\u6280\u80FD\u6587\u4EF6\uFF0C\u8BF7\u7A0D\u7B49",
82152
+ filesLabel: "\u5C06\u521B\u5EFA\u6587\u4EF6:",
82153
+ editName: "\u7F16\u8F91\u540D\u79F0",
82154
+ editNameLabel: "\u5F53\u524D\u6280\u80FD\u540D\u79F0:",
82155
+ editNameHint: "\u8F93\u5165\u65B0\u7684\u6280\u80FD\u540D\u79F0\uFF08\u5C0F\u5199\u5B57\u6BCD/\u6570\u5B57/\u8FDE\u5B57\u7B26\uFF0C\u6700\u591A 64 \u4E2A\u5B57\u7B26\uFF09",
82156
+ editNamePlaceholder: "new-skill-name",
82157
+ regenerate: "\u91CD\u65B0\u751F\u6210",
82158
+ cancel: "\u53D6\u6D88",
81772
82159
  nameLabel: "\u6280\u80FD\u540D\u79F0:",
81773
- nameHint: "\u4EC5\u4F7F\u7528\u5C0F\u5199\u5B57\u6BCD\u3001\u6570\u5B57\u548C\u8FDE\u5B57\u7B26\uFF08\u6700\u591A 64 \u4E2A\u5B57\u7B26\uFF09",
81774
- namePlaceholder: "my-skill-name",
82160
+ nameHint: '\u4EC5\u4F7F\u7528\u5C0F\u5199\u5B57\u6BCD\u3001\u6570\u5B57\u548C\u8FDE\u5B57\u7B26\uFF0C\u53EF\u7528 "/" \u4F5C\u4E3A\u547D\u540D\u7A7A\u95F4\u5206\u9694\uFF08\u6BCF\u6BB5\u6700\u591A 64 \u4E2A\u5B57\u7B26\uFF09',
82161
+ namePlaceholder: "team/my-skill-name",
81775
82162
  descriptionLabel: "\u63CF\u8FF0:",
81776
82163
  descriptionHint: "\u7B80\u8981\u63CF\u8FF0\u6B64\u6280\u80FD\u7684\u7528\u9014\u548C\u4F7F\u7528\u573A\u666F",
81777
82164
  descriptionPlaceholder: "\u7B80\u8981\u63CF\u8FF0...",
@@ -81788,7 +82175,15 @@ var init_zh = __esm({
81788
82175
  errorInvalidName: "\u65E0\u6548\u7684\u6280\u80FD\u540D\u79F0",
81789
82176
  errorExistsBoth: '\u6280\u80FD "{name}" \u5728\u5168\u5C40\u548C\u9879\u76EE\u4F4D\u7F6E\u90FD\u5DF2\u5B58\u5728',
81790
82177
  errorExistsGlobal: '\u6280\u80FD "{name}" \u5DF2\u5B58\u5728\u4E8E\u5168\u5C40\u4F4D\u7F6E (~/.snow/skills/)',
81791
- errorExistsProject: '\u6280\u80FD "{name}" \u5DF2\u5B58\u5728\u4E8E\u9879\u76EE\u4F4D\u7F6E (.snow/skills/)'
82178
+ errorExistsProject: '\u6280\u80FD "{name}" \u5DF2\u5B58\u5728\u4E8E\u9879\u76EE\u4F4D\u7F6E (.snow/skills/)',
82179
+ errorExistsAny: '\u6280\u80FD "{name}" \u5DF2\u5B58\u5728\uFF0C\u8BF7\u6362\u4E00\u4E2A\u540D\u79F0',
82180
+ errorGeneration: "AI \u751F\u6210\u5931\u8D25",
82181
+ errorNoGeneratedContent: "\u7F3A\u5C11\u751F\u6210\u5185\u5BB9\uFF0C\u8BF7\u91CD\u8BD5",
82182
+ resultModeAi: "AI \u751F\u6210",
82183
+ resultModeManual: "\u624B\u52A8\u6A21\u677F",
82184
+ createSuccessMessage: '\u6280\u80FD "{name}" \u521B\u5EFA\u6210\u529F\uFF01\n\u6A21\u5F0F: {mode}\n\u4F4D\u7F6E: {location}\n\u8DEF\u5F84: {path}\n\n\u5DF2\u521B\u5EFA\u4EE5\u4E0B\u6587\u4EF6\uFF1A\n- SKILL.md\uFF08\u4E3B\u6280\u80FD\u6587\u6863\uFF09\n- reference.md\uFF08\u8BE6\u7EC6\u53C2\u8003\uFF09\n- examples.md\uFF08\u4F7F\u7528\u793A\u4F8B\uFF09\n- templates/template.txt\uFF08\u6A21\u677F\u6587\u4EF6\uFF09\n- scripts/helper.py\uFF08\u8F85\u52A9\u811A\u672C\uFF09\n\n\u4F60\u73B0\u5728\u53EF\u4EE5\u7F16\u8F91\u8FD9\u4E9B\u6587\u4EF6\u6765\u81EA\u5B9A\u4E49\u6280\u80FD\u3002',
82185
+ createErrorMessage: "\u521B\u5EFA\u6280\u80FD\u5931\u8D25\uFF1A{error}",
82186
+ errorUnknown: "\u672A\u77E5\u9519\u8BEF"
81792
82187
  },
81793
82188
  askUser: {
81794
82189
  header: "[\u9700\u8981\u7528\u6237\u8F93\u5165]",
@@ -82534,7 +82929,12 @@ var init_zh_TW = __esm({
82534
82929
  confirmSave: "Save this custom command? (y/n)",
82535
82930
  confirmYes: "Yes",
82536
82931
  confirmNo: "Cancel",
82537
- escCancel: "Press ESC to cancel"
82932
+ escCancel: "Press ESC to cancel",
82933
+ resultTypeExecute: "\u5728\u7D42\u7AEF\u57F7\u884C",
82934
+ resultTypePrompt: "\u50B3\u9001\u7D66 AI",
82935
+ resultLocationGlobal: "\u5168\u57DF (~/.snow/commands/)",
82936
+ resultLocationProject: "\u5C08\u6848 (.snow/commands/)",
82937
+ saveSuccessMessage: "\u81EA\u8A02\u547D\u4EE4 '{name}' \u5132\u5B58\u6210\u529F\uFF01\n\u985E\u578B: {type}\n\u4F4D\u7F6E: {location}\n\u4F60\u73FE\u5728\u53EF\u4EE5\u4F7F\u7528 /{name}"
82538
82938
  },
82539
82939
  chatScreen: {
82540
82940
  // Header
@@ -82740,6 +83140,21 @@ var init_zh_TW = __esm({
82740
83140
  },
82741
83141
  skillsCreation: {
82742
83142
  title: "\u5275\u5EFA\u65B0\u6280\u80FD",
83143
+ modeLabel: "\u9078\u64C7\u5275\u5EFA\u65B9\u5F0F:",
83144
+ modeAi: "AI \u751F\u6210\uFF08\u8F38\u5165\u9700\u6C42\u5373\u53EF\uFF09",
83145
+ modeManual: "\u624B\u52D5\u5275\u5EFA\uFF08\u751F\u6210\u6A21\u677F\uFF09",
83146
+ requirementLabel: "\u6280\u80FD\u9700\u6C42:",
83147
+ requirementHint: "\u7C21\u8981\u63CF\u8FF0\u4F60\u5E0C\u671B\u8A72\u6280\u80FD\u5B8C\u6210\u4EC0\u9EBC\uFF08\u751F\u6210\u5167\u5BB9\u5C07\u8DDF\u96A8\u6B64\u8A9E\u8A00\uFF09",
83148
+ requirementPlaceholder: "\u4F8B\u5982\uFF1A\u751F\u6210\u4E00\u500B\u7528\u65BC\u767C\u4F48 npm \u5957\u4EF6\u7684\u6280\u80FD\u2026",
83149
+ generatingLabel: "AI \u751F\u6210\u4E2D...",
83150
+ generatingMessage: "\u6B63\u5728\u751F\u6210\u6280\u80FD\u6A94\u6848\uFF0C\u8ACB\u7A0D\u7B49",
83151
+ filesLabel: "\u5C07\u5275\u5EFA\u6A94\u6848:",
83152
+ editName: "\u7DE8\u8F2F\u540D\u7A31",
83153
+ editNameLabel: "\u76EE\u524D\u6280\u80FD\u540D\u7A31:",
83154
+ editNameHint: "\u8F38\u5165\u65B0\u7684\u6280\u80FD\u540D\u7A31\uFF08\u5C0F\u5BEB\u5B57\u6BCD/\u6578\u5B57/\u9023\u5B57\u7B26\uFF0C\u6700\u591A 64 \u500B\u5B57\u7B26\uFF09",
83155
+ editNamePlaceholder: "new-skill-name",
83156
+ regenerate: "\u91CD\u65B0\u751F\u6210",
83157
+ cancel: "\u53D6\u6D88",
82743
83158
  nameLabel: "\u6280\u80FD\u540D\u7A31:",
82744
83159
  nameHint: "\u50C5\u4F7F\u7528\u5C0F\u5BEB\u5B57\u6BCD\u3001\u6578\u5B57\u548C\u9023\u5B57\u7B26\uFF08\u6700\u591A 64 \u500B\u5B57\u7B26\uFF09",
82745
83160
  namePlaceholder: "my-skill-name",
@@ -82758,7 +83173,15 @@ var init_zh_TW = __esm({
82758
83173
  errorInvalidName: "\u7121\u6548\u7684\u6280\u80FD\u540D\u7A31",
82759
83174
  errorExistsBoth: '\u6280\u80FD "{name}" \u5728\u5168\u5C40\u548C\u9805\u76EE\u4F4D\u7F6E\u90FD\u5DF2\u5B58\u5728',
82760
83175
  errorExistsGlobal: '\u6280\u80FD "{name}" \u5DF2\u5B58\u5728\u65BC\u5168\u5C40\u4F4D\u7F6E (~/.snow/skills/)',
82761
- errorExistsProject: '\u6280\u80FD "{name}" \u5DF2\u5B58\u5728\u65BC\u9805\u76EE\u4F4D\u7F6E (.snow/skills/)'
83176
+ errorExistsProject: '\u6280\u80FD "{name}" \u5DF2\u5B58\u5728\u65BC\u9805\u76EE\u4F4D\u7F6E (.snow/skills/)',
83177
+ errorExistsAny: '\u6280\u80FD "{name}" \u5DF2\u5B58\u5728\uFF0C\u8ACB\u63DB\u4E00\u500B\u540D\u7A31',
83178
+ errorGeneration: "AI \u751F\u6210\u5931\u6557",
83179
+ errorNoGeneratedContent: "\u7F3A\u5C11\u751F\u6210\u5167\u5BB9\uFF0C\u8ACB\u91CD\u8A66",
83180
+ resultModeAi: "AI \u751F\u6210",
83181
+ resultModeManual: "\u624B\u52D5\u6A21\u677F",
83182
+ createSuccessMessage: '\u6280\u80FD "{name}" \u5275\u5EFA\u6210\u529F\uFF01\n\u6A21\u5F0F: {mode}\n\u4F4D\u7F6E: {location}\n\u8DEF\u5F91: {path}\n\n\u5DF2\u5275\u5EFA\u4EE5\u4E0B\u6A94\u6848\uFF1A\n- SKILL.md\uFF08\u4E3B\u6280\u80FD\u6587\u4EF6\uFF09\n- reference.md\uFF08\u8A73\u7D30\u53C3\u8003\uFF09\n- examples.md\uFF08\u4F7F\u7528\u7BC4\u4F8B\uFF09\n- templates/template.txt\uFF08\u6A21\u677F\u6A94\u6848\uFF09\n- scripts/helper.py\uFF08\u8F14\u52A9\u8173\u672C\uFF09\n\n\u4F60\u73FE\u5728\u53EF\u4EE5\u7DE8\u8F2F\u9019\u4E9B\u6A94\u6848\u4F86\u81EA\u8A02\u6280\u80FD\u3002',
83183
+ createErrorMessage: "\u5275\u5EFA\u6280\u80FD\u5931\u6557\uFF1A{error}",
83184
+ errorUnknown: "\u672A\u77E5\u932F\u8AA4"
82762
83185
  },
82763
83186
  askUser: {
82764
83187
  header: "[\u9700\u8981\u4F7F\u7528\u8005\u8F38\u5165]",
@@ -87966,6 +88389,7 @@ function ConfigScreen({ onBack, onSave, inlineMode = false }) {
87966
88389
  const [searchTerm, setSearchTerm] = (0, import_react62.useState)("");
87967
88390
  const [manualInputMode, setManualInputMode] = (0, import_react62.useState)(false);
87968
88391
  const [manualInputValue, setManualInputValue] = (0, import_react62.useState)("");
88392
+ const [editingThresholdValue, setEditingThresholdValue] = (0, import_react62.useState)("");
87969
88393
  const [, forceUpdate] = (0, import_react62.useState)(0);
87970
88394
  const MAX_VISIBLE_FIELDS = 8;
87971
88395
  const supportsXHigh = requestMethod === "responses";
@@ -88827,7 +89251,7 @@ function ConfigScreen({ onBack, onSave, inlineMode = false }) {
88827
89251
  { color: theme14.colors.menuInfo },
88828
89252
  t.configScreen.enterValue,
88829
89253
  " ",
88830
- editSimilarityThreshold
89254
+ editingThresholdValue || editSimilarityThreshold
88831
89255
  )
88832
89256
  ),
88833
89257
  !isCurrentlyEditing && import_react62.default.createElement(
@@ -88929,20 +89353,28 @@ function ConfigScreen({ onBack, onSave, inlineMode = false }) {
88929
89353
  if (currentField === "maxContextTokens" || currentField === "maxTokens" || currentField === "thinkingBudgetTokens" || currentField === "geminiThinkingBudget" || currentField === "editSimilarityThreshold") {
88930
89354
  if (currentField === "editSimilarityThreshold") {
88931
89355
  if (input2 && input2.match(/[0-9.]/)) {
88932
- const currentStr = editSimilarityThreshold.toString();
89356
+ const currentStr = editingThresholdValue || editSimilarityThreshold.toString();
89357
+ if (input2 === "." && currentStr.includes(".")) {
89358
+ return;
89359
+ }
88933
89360
  const newStr = currentStr + input2;
88934
- const newValue = parseFloat(newStr);
88935
- if (!isNaN(newValue) && newValue >= 0 && newValue <= 1) {
88936
- setEditSimilarityThreshold(newValue);
89361
+ if (newStr === "." || newStr === "0." || /^[0-9]*\.?[0-9]*$/.test(newStr)) {
89362
+ setEditingThresholdValue(newStr);
88937
89363
  }
88938
89364
  } else if (key.backspace || key.delete) {
88939
- const currentStr = editSimilarityThreshold.toString();
89365
+ const currentStr = editingThresholdValue || editSimilarityThreshold.toString();
88940
89366
  const newStr = currentStr.slice(0, -1);
88941
- const newValue = parseFloat(newStr);
88942
- setEditSimilarityThreshold(!isNaN(newValue) ? newValue : 0);
89367
+ setEditingThresholdValue(newStr);
88943
89368
  } else if (key.return) {
88944
- const finalValue = editSimilarityThreshold < 0.1 ? 0.1 : editSimilarityThreshold;
88945
- setEditSimilarityThreshold(finalValue);
89369
+ const valueToSave = editingThresholdValue || editSimilarityThreshold.toString();
89370
+ const finalValue = parseFloat(valueToSave);
89371
+ if (!isNaN(finalValue) && finalValue >= 0.1 && finalValue <= 1) {
89372
+ setEditSimilarityThreshold(finalValue);
89373
+ } else if (finalValue < 0.1) {
89374
+ setEditSimilarityThreshold(0.1);
89375
+ } else {
89376
+ }
89377
+ setEditingThresholdValue("");
88946
89378
  setIsEditing(false);
88947
89379
  }
88948
89380
  return;
@@ -89027,6 +89459,9 @@ function ConfigScreen({ onBack, onSave, inlineMode = false }) {
89027
89459
  setResponsesReasoningEnabled(!responsesReasoningEnabled);
89028
89460
  } else if (currentField === "maxContextTokens" || currentField === "maxTokens" || currentField === "thinkingBudgetTokens" || currentField === "geminiThinkingBudget") {
89029
89461
  setIsEditing(true);
89462
+ } else if (currentField === "editSimilarityThreshold") {
89463
+ setEditingThresholdValue("");
89464
+ setIsEditing(true);
89030
89465
  } else if (currentField === "responsesReasoningEffort") {
89031
89466
  setIsEditing(true);
89032
89467
  } else if (currentField === "advancedModel" || currentField === "basicModel") {
@@ -98754,49 +99189,49 @@ var require_fast_uri = __commonJS({
98754
99189
  schemelessOptions.skipEscape = true;
98755
99190
  return serialize(resolved, schemelessOptions);
98756
99191
  }
98757
- function resolveComponent(base, relative8, options3, skipNormalization) {
99192
+ function resolveComponent(base, relative9, options3, skipNormalization) {
98758
99193
  const target = {};
98759
99194
  if (!skipNormalization) {
98760
99195
  base = parse3(serialize(base, options3), options3);
98761
- relative8 = parse3(serialize(relative8, options3), options3);
99196
+ relative9 = parse3(serialize(relative9, options3), options3);
98762
99197
  }
98763
99198
  options3 = options3 || {};
98764
- if (!options3.tolerant && relative8.scheme) {
98765
- target.scheme = relative8.scheme;
98766
- target.userinfo = relative8.userinfo;
98767
- target.host = relative8.host;
98768
- target.port = relative8.port;
98769
- target.path = removeDotSegments(relative8.path || "");
98770
- target.query = relative8.query;
99199
+ if (!options3.tolerant && relative9.scheme) {
99200
+ target.scheme = relative9.scheme;
99201
+ target.userinfo = relative9.userinfo;
99202
+ target.host = relative9.host;
99203
+ target.port = relative9.port;
99204
+ target.path = removeDotSegments(relative9.path || "");
99205
+ target.query = relative9.query;
98771
99206
  } else {
98772
- if (relative8.userinfo !== void 0 || relative8.host !== void 0 || relative8.port !== void 0) {
98773
- target.userinfo = relative8.userinfo;
98774
- target.host = relative8.host;
98775
- target.port = relative8.port;
98776
- target.path = removeDotSegments(relative8.path || "");
98777
- target.query = relative8.query;
99207
+ if (relative9.userinfo !== void 0 || relative9.host !== void 0 || relative9.port !== void 0) {
99208
+ target.userinfo = relative9.userinfo;
99209
+ target.host = relative9.host;
99210
+ target.port = relative9.port;
99211
+ target.path = removeDotSegments(relative9.path || "");
99212
+ target.query = relative9.query;
98778
99213
  } else {
98779
- if (!relative8.path) {
99214
+ if (!relative9.path) {
98780
99215
  target.path = base.path;
98781
- if (relative8.query !== void 0) {
98782
- target.query = relative8.query;
99216
+ if (relative9.query !== void 0) {
99217
+ target.query = relative9.query;
98783
99218
  } else {
98784
99219
  target.query = base.query;
98785
99220
  }
98786
99221
  } else {
98787
- if (relative8.path[0] === "/") {
98788
- target.path = removeDotSegments(relative8.path);
99222
+ if (relative9.path[0] === "/") {
99223
+ target.path = removeDotSegments(relative9.path);
98789
99224
  } else {
98790
99225
  if ((base.userinfo !== void 0 || base.host !== void 0 || base.port !== void 0) && !base.path) {
98791
- target.path = "/" + relative8.path;
99226
+ target.path = "/" + relative9.path;
98792
99227
  } else if (!base.path) {
98793
- target.path = relative8.path;
99228
+ target.path = relative9.path;
98794
99229
  } else {
98795
- target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative8.path;
99230
+ target.path = base.path.slice(0, base.path.lastIndexOf("/") + 1) + relative9.path;
98796
99231
  }
98797
99232
  target.path = removeDotSegments(target.path);
98798
99233
  }
98799
- target.query = relative8.query;
99234
+ target.query = relative9.query;
98800
99235
  }
98801
99236
  target.userinfo = base.userinfo;
98802
99237
  target.host = base.host;
@@ -98804,7 +99239,7 @@ var require_fast_uri = __commonJS({
98804
99239
  }
98805
99240
  target.scheme = base.scheme;
98806
99241
  }
98807
- target.fragment = relative8.fragment;
99242
+ target.fragment = relative9.fragment;
98808
99243
  return target;
98809
99244
  }
98810
99245
  function equal(uriA, uriB, options3) {
@@ -280474,7 +280909,7 @@ var require_files = __commonJS({
280474
280909
  var fs42 = __require("fs");
280475
280910
  var url = __require("url");
280476
280911
  var os23 = __require("os");
280477
- var dirname10 = __require("path").dirname;
280912
+ var dirname11 = __require("path").dirname;
280478
280913
  var resolvePath = __require("path").resolve;
280479
280914
  var isAbsolutePath = require_path_is_absolute();
280480
280915
  var promises = require_promises();
@@ -280489,7 +280924,7 @@ var require_files = __commonJS({
280489
280924
  }
280490
280925
  };
280491
280926
  }
280492
- var base = options3.relativeToFile ? dirname10(options3.relativeToFile) : null;
280927
+ var base = options3.relativeToFile ? dirname11(options3.relativeToFile) : null;
280493
280928
  function read2(uri, encoding) {
280494
280929
  return resolveUri(uri).then(function(path53) {
280495
280930
  return readFile3(path53, encoding).caught(function(error) {
@@ -288411,8 +288846,8 @@ var require_xlsx = __commonJS({
288411
288846
  }
288412
288847
  return L.length - R.length;
288413
288848
  }
288414
- function dirname10(p) {
288415
- if (p.charAt(p.length - 1) == "/") return p.slice(0, -1).indexOf("/") === -1 ? p : dirname10(p.slice(0, -1));
288849
+ function dirname11(p) {
288850
+ if (p.charAt(p.length - 1) == "/") return p.slice(0, -1).indexOf("/") === -1 ? p : dirname11(p.slice(0, -1));
288416
288851
  var c = p.lastIndexOf("/");
288417
288852
  return c === -1 ? p : p.slice(0, c + 1);
288418
288853
  }
@@ -288833,7 +289268,7 @@ var require_xlsx = __commonJS({
288833
289268
  data.push([cfb.FullPaths[i2], cfb.FileIndex[i2]]);
288834
289269
  }
288835
289270
  for (i2 = 0; i2 < data.length; ++i2) {
288836
- var dad = dirname10(data[i2][0]);
289271
+ var dad = dirname11(data[i2][0]);
288837
289272
  s = fullPaths[dad];
288838
289273
  if (!s) {
288839
289274
  data.push([dad, {
@@ -288869,13 +289304,13 @@ var require_xlsx = __commonJS({
288869
289304
  elt.size = 0;
288870
289305
  elt.type = 5;
288871
289306
  } else if (nm.slice(-1) == "/") {
288872
- for (j = i2 + 1; j < data.length; ++j) if (dirname10(cfb.FullPaths[j]) == nm) break;
289307
+ for (j = i2 + 1; j < data.length; ++j) if (dirname11(cfb.FullPaths[j]) == nm) break;
288873
289308
  elt.C = j >= data.length ? -1 : j;
288874
- for (j = i2 + 1; j < data.length; ++j) if (dirname10(cfb.FullPaths[j]) == dirname10(nm)) break;
289309
+ for (j = i2 + 1; j < data.length; ++j) if (dirname11(cfb.FullPaths[j]) == dirname11(nm)) break;
288875
289310
  elt.R = j >= data.length ? -1 : j;
288876
289311
  elt.type = 1;
288877
289312
  } else {
288878
- if (dirname10(cfb.FullPaths[i2 + 1] || "") == dirname10(nm)) elt.R = i2 + 1;
289313
+ if (dirname11(cfb.FullPaths[i2 + 1] || "") == dirname11(nm)) elt.R = i2 + 1;
288879
289314
  elt.type = 2;
288880
289315
  }
288881
289316
  }
@@ -350830,7 +351265,7 @@ ${fileList}`,
350830
351265
  let errorMessage = `\u274C Search content not found in file: ${filePath}
350831
351266
 
350832
351267
  `;
350833
- errorMessage += `\u{1F50D} Using smart fuzzy matching (threshold: 60%)
351268
+ errorMessage += `\u{1F50D} Using smart fuzzy matching (threshold: ${threshold})
350834
351269
  `;
350835
351270
  if (isOverEscaped(searchContent)) {
350836
351271
  errorMessage += `\u26A0\uFE0F Detected over-escaped content, automatic fix attempted but failed
@@ -351376,7 +351811,7 @@ ${formattedDiagnostics}`;
351376
351811
  },
351377
351812
  {
351378
351813
  name: "filesystem-edit_search",
351379
- description: 'RECOMMENDED for most edits: Search-and-replace with SMART FUZZY MATCHING. **CRITICAL PATH REQUIREMENTS**: (1) filePath parameter is REQUIRED - MUST be a valid non-empty string or array, never use undefined/null/empty string, (2) Use EXACT file paths from search results or user input - never use placeholders like "path/to/file", (3) If uncertain about path, use search tools first to find the correct file. **SUPPORTS BATCH EDITING**: Pass (1) single file with search/replace, (2) array of file paths with unified search/replace, or (3) array of {path, searchContent, replaceContent, occurrence?} for per-file edits. **CRITICAL WORKFLOW FOR CODE SAFETY**: (1) Use search tools (codebase-search or ACE tools) to locate code, (2) MUST use filesystem-read to identify COMPLETE code boundaries (entire function body with all braces, complete markup tags with opening/closing pairs, full code blocks), (3) Copy the COMPLETE code block (without line numbers), (4) Verify boundaries are intact (matching braces/brackets/tags), (5) Use THIS tool. **WHY USE THIS**: No line tracking needed, auto-handles spacing/tabs differences, finds best fuzzy match even with whitespace changes, safer than line-based editing. **SMART MATCHING**: Uses similarity algorithm (60% threshold) to find code even if indentation/spacing differs from your search string. Automatically corrects over-escaped content. If multiple matches found, selects best match first (highest similarity score). **COMMON ERRORS TO AVOID**: Using invalid/empty file paths, modifying only part of a function (missing closing brace), incomplete markup tags (HTML/Vue/JSX), partial code blocks, copying line numbers from filesystem-read output. Always include complete syntactic units with all opening/closing pairs. **BATCH EXAMPLE**: filePath=[{path:"a.ts", searchContent:"old1", replaceContent:"new1"}, {path:"b.ts", searchContent:"old2", replaceContent:"new2"}]',
351814
+ description: 'RECOMMENDED for most edits: Search-and-replace with SMART FUZZY MATCHING. **CRITICAL PATH REQUIREMENTS**: (1) filePath parameter is REQUIRED - MUST be a valid non-empty string or array, never use undefined/null/empty string, (2) Use EXACT file paths from search results or user input - never use placeholders like "path/to/file", (3) If uncertain about path, use search tools first to find the correct file. **SUPPORTS BATCH EDITING**: Pass (1) single file with search/replace, (2) array of file paths with unified search/replace, or (3) array of {path, searchContent, replaceContent, occurrence?} for per-file edits. **CRITICAL WORKFLOW FOR CODE SAFETY - COMPLETE BOUNDARIES REQUIRED**: (1) Use search tools (codebase-search or ACE tools) to locate code, (2) MUST use filesystem-read to identify COMPLETE code boundaries with ALL closing pairs: entire function from declaration to final closing brace `}`, complete HTML/XML/JSX tags from opening `<tag>` to closing `</tag>`, full code blocks with ALL matching brackets/braces/parentheses, (3) Copy the COMPLETE code block (without line numbers) - verify you have captured ALL opening and closing symbols, (4) MANDATORY verification: Count and match ALL pairs - every `{` must have `}`, every `(` must have `)`, every `[` must have `]`, every `<tag>` must have `</tag>`, (5) Use THIS tool only after verification passes. **ABSOLUTE PROHIBITIONS**: NEVER edit partial functions (missing closing brace), NEVER edit incomplete markup (missing closing tag), NEVER edit partial code blocks (unmatched brackets), NEVER copy line numbers from filesystem-read output. **WHY USE THIS**: No line tracking needed, auto-handles spacing/tabs differences, finds best fuzzy match even with whitespace changes, safer than line-based editing. **SMART MATCHING**: Uses similarity algorithm to find code even if indentation/spacing differs from your search string. Automatically corrects over-escaped content. If multiple matches found, selects best match first (highest similarity score). **COMMON FATAL ERRORS TO AVOID**: Using invalid/empty file paths, modifying only part of a function (missing closing brace `}`), incomplete markup tags (HTML/Vue/JSX missing `</tag>`), partial code blocks (unmatched `{`, `}`, `(`, `)`, `[`, `]`), copying line numbers from filesystem-read output. You MUST include complete syntactic units with ALL opening/closing pairs verified and matched. **BATCH EXAMPLE**: filePath=[{path:"a.ts", searchContent:"old1", replaceContent:"new1"}, {path:"b.ts", searchContent:"old2", replaceContent:"new2"}]',
351380
351815
  inputSchema: {
351381
351816
  type: "object",
351382
351817
  properties: {
@@ -351446,7 +351881,7 @@ ${formattedDiagnostics}`;
351446
351881
  },
351447
351882
  {
351448
351883
  name: "filesystem-edit",
351449
- description: 'Line-based editing for precise control. **CRITICAL PATH REQUIREMENTS**: (1) filePath parameter is REQUIRED - MUST be a valid non-empty string or array, never use undefined/null/empty string, (2) Use EXACT file paths from search results or user input - never use placeholders like "path/to/file", (3) If uncertain about path, use search tools first to find the correct file. **SUPPORTS BATCH EDITING**: Pass (1) single file with line range, (2) array of file paths with unified line range, or (3) array of {path, startLine, endLine, newContent} for per-file edits. **WHEN TO USE**: (1) Adding new code sections, (2) Deleting specific line ranges, (3) When search-replace not suitable. **CRITICAL WORKFLOW FOR CODE SAFETY**: (1) Use search tools (codebase-search or ACE tools) to locate area, (2) MUST use filesystem-read to identify COMPLETE code boundaries - for functions: include opening line to closing brace; for markup tags (HTML/Vue/JSX): include opening tag to closing tag; for code blocks: include all braces/brackets, (3) Verify line range covers the ENTIRE syntactic unit (check indentation levels, matching pairs), (4) Use THIS tool with exact startLine/endLine. **BEST PRACTICE**: Keep edits small (under 15 lines recommended) for better accuracy. For larger changes, make multiple parallel edits to non-overlapping sections instead of one large edit. **RECOMMENDATION**: For modifying existing code, use filesystem-edit_search - safer and no line tracking needed. **WHY LINE-BASED IS RISKIER**: Line numbers can shift during editing, making it easy to target wrong lines. Search-replace avoids this by matching actual content. **COMMON ERRORS TO AVOID**: Using invalid/empty file paths, line range stops mid-function (missing closing brace), partial markup tags, incomplete code blocks, targeting wrong lines after file changes. Always verify boundaries with filesystem-read first. **BATCH EXAMPLE**: filePath=[{path:"a.ts", startLine:10, endLine:20, newContent:"..."}, {path:"b.ts", startLine:50, endLine:60, newContent:"..."}]',
351884
+ description: 'Line-based editing for precise control. **CRITICAL PATH REQUIREMENTS**: (1) filePath parameter is REQUIRED - MUST be a valid non-empty string or array, never use undefined/null/empty string, (2) Use EXACT file paths from search results or user input - never use placeholders like "path/to/file", (3) If uncertain about path, use search tools first to find the correct file. **SUPPORTS BATCH EDITING**: Pass (1) single file with line range, (2) array of file paths with unified line range, or (3) array of {path, startLine, endLine, newContent} for per-file edits. **WHEN TO USE**: (1) Adding new code sections, (2) Deleting specific line ranges, (3) When search-replace not suitable. **CRITICAL WORKFLOW FOR CODE SAFETY - COMPLETE BOUNDARIES REQUIRED**: (1) Use search tools (codebase-search or ACE tools) to locate area, (2) MUST use filesystem-read to identify COMPLETE code boundaries with ALL closing pairs: for functions - include opening declaration to final closing brace `}`; for HTML/XML/JSX markup tags - include opening `<tag>` to closing `</tag>`; for code blocks - include ALL matching braces/brackets/parentheses, (3) MANDATORY verification before editing: count opening and closing symbols in your target range - every `{` must have matching `}`, every `(` must have `)`, every `[` must have `]`, every `<tag>` must have `</tag>`, verify indentation levels are consistent, (4) Use THIS tool with exact startLine/endLine ONLY after verification passes. **ABSOLUTE PROHIBITIONS**: NEVER edit line range that stops mid-function (missing closing brace `}`), NEVER edit partial markup tags (missing `</tag>`), NEVER edit incomplete code blocks (unmatched brackets), NEVER edit without verifying boundaries first. **BEST PRACTICE**: Keep edits small (under 15 lines recommended) for better accuracy. For larger changes, make multiple parallel edits to non-overlapping sections instead of one large edit. **RECOMMENDATION**: For modifying existing code, use filesystem-edit_search - safer and no line tracking needed. **WHY LINE-BASED IS RISKIER**: Line numbers can shift during editing, making it easy to target wrong lines. Search-replace avoids this by matching actual content. **COMMON FATAL ERRORS TO AVOID**: Using invalid/empty file paths, line range stops mid-function (missing closing brace `}`), partial markup tags (missing `</tag>`), incomplete code blocks (unmatched `{`, `}`, `(`, `)`, `[`, `]`), targeting wrong lines after file changes, not verifying boundaries with filesystem-read first. You MUST verify complete syntactic units with ALL opening/closing pairs matched. **BATCH EXAMPLE**: filePath=[{path:"a.ts", startLine:10, endLine:20, newContent:"..."}, {path:"b.ts", startLine:50, endLine:60, newContent:"..."}]',
351450
351885
  inputSchema: {
351451
351886
  type: "object",
351452
351887
  properties: {
@@ -403908,7 +404343,7 @@ var require_util12 = __commonJS({
403908
404343
  exports2.isAbsolute = function(aPath) {
403909
404344
  return aPath.charAt(0) === "/" || urlRegexp.test(aPath);
403910
404345
  };
403911
- function relative8(aRoot, aPath) {
404346
+ function relative9(aRoot, aPath) {
403912
404347
  if (aRoot === "") {
403913
404348
  aRoot = ".";
403914
404349
  }
@@ -403927,7 +404362,7 @@ var require_util12 = __commonJS({
403927
404362
  }
403928
404363
  return Array(level + 1).join("../") + aPath.substr(aRoot.length + 1);
403929
404364
  }
403930
- exports2.relative = relative8;
404365
+ exports2.relative = relative9;
403931
404366
  var supportsNullProto = (function() {
403932
404367
  var obj2 = /* @__PURE__ */ Object.create(null);
403933
404368
  return !("__proto__" in obj2);
@@ -435981,7 +436416,7 @@ var require_gray_matter = __commonJS({
435981
436416
  });
435982
436417
 
435983
436418
  // dist/mcp/skills.js
435984
- import { join as join21 } from "path";
436419
+ import { dirname as dirname8, join as join21, relative as relative6 } from "path";
435985
436420
  import { existsSync as existsSync21 } from "fs";
435986
436421
  import { readFile as readFile2 } from "fs/promises";
435987
436422
  import { homedir as homedir14 } from "os";
@@ -436020,64 +436455,75 @@ async function readSkillFile(skillPath) {
436020
436455
  return null;
436021
436456
  }
436022
436457
  }
436023
- async function loadAvailableSkills(projectRoot) {
436024
- const skills = /* @__PURE__ */ new Map();
436025
- const globalSkillsDir = join21(homedir14(), ".snow", "skills");
436026
- const projectSkillsDir = projectRoot ? join21(projectRoot, ".snow", "skills") : null;
436027
- if (existsSync21(globalSkillsDir)) {
436028
- try {
436029
- const { readdirSync: readdirSync3 } = await import("fs");
436030
- const entries = readdirSync3(globalSkillsDir, { withFileTypes: true });
436031
- for (const entry of entries) {
436032
- if (entry.isDirectory()) {
436033
- const skillPath = join21(globalSkillsDir, entry.name);
436034
- const skillData = await readSkillFile(skillPath);
436035
- if (skillData) {
436036
- skills.set(entry.name, {
436037
- name: skillData.metadata.name || entry.name,
436038
- description: skillData.metadata.description || "",
436039
- location: "global",
436040
- path: skillPath,
436041
- content: skillData.content,
436042
- allowedTools: skillData.metadata.allowedTools
436043
- });
436044
- }
436045
- }
436046
- }
436047
- } catch (error) {
436048
- console.error("Failed to load global skills:", error);
436049
- }
436458
+ function normalizeSkillId(skillId) {
436459
+ return skillId.replace(/\\/g, "/").replace(/^\.\/+/, "");
436460
+ }
436461
+ async function loadSkillsFromDirectory(skills, baseSkillsDir, location) {
436462
+ if (!existsSync21(baseSkillsDir)) {
436463
+ return;
436050
436464
  }
436051
- if (projectSkillsDir && existsSync21(projectSkillsDir)) {
436052
- try {
436053
- const { readdirSync: readdirSync3 } = await import("fs");
436054
- const entries = readdirSync3(projectSkillsDir, { withFileTypes: true });
436465
+ try {
436466
+ const { readdirSync: readdirSync3 } = await import("fs");
436467
+ const pendingDirs = [baseSkillsDir];
436468
+ while (pendingDirs.length > 0) {
436469
+ const currentDir = pendingDirs.pop();
436470
+ if (!currentDir)
436471
+ continue;
436472
+ let entries;
436473
+ try {
436474
+ entries = readdirSync3(currentDir, { withFileTypes: true });
436475
+ } catch {
436476
+ continue;
436477
+ }
436055
436478
  for (const entry of entries) {
436056
436479
  if (entry.isDirectory()) {
436057
- const skillPath = join21(projectSkillsDir, entry.name);
436058
- const skillData = await readSkillFile(skillPath);
436059
- if (skillData) {
436060
- skills.set(entry.name, {
436061
- name: skillData.metadata.name || entry.name,
436062
- description: skillData.metadata.description || "",
436063
- location: "project",
436064
- path: skillPath,
436065
- content: skillData.content,
436066
- allowedTools: skillData.metadata.allowedTools
436067
- });
436068
- }
436480
+ pendingDirs.push(join21(currentDir, entry.name));
436481
+ continue;
436482
+ }
436483
+ if (!entry.isFile() || entry.name !== "SKILL.md") {
436484
+ continue;
436485
+ }
436486
+ const skillFile = join21(currentDir, entry.name);
436487
+ const skillDir = dirname8(skillFile);
436488
+ const rawSkillId = relative6(baseSkillsDir, skillDir);
436489
+ const skillId = normalizeSkillId(rawSkillId);
436490
+ if (!skillId || skillId === ".") {
436491
+ continue;
436069
436492
  }
436493
+ const skillData = await readSkillFile(skillDir);
436494
+ if (!skillData) {
436495
+ continue;
436496
+ }
436497
+ const fallbackName = skillId.split("/").filter(Boolean).pop() || skillId;
436498
+ skills.set(skillId, {
436499
+ id: skillId,
436500
+ name: skillData.metadata.name || fallbackName,
436501
+ description: skillData.metadata.description || "",
436502
+ location,
436503
+ path: skillDir,
436504
+ content: skillData.content,
436505
+ allowedTools: skillData.metadata.allowedTools
436506
+ });
436070
436507
  }
436071
- } catch (error) {
436072
- console.error("Failed to load project skills:", error);
436073
436508
  }
436509
+ } catch (error) {
436510
+ console.error(`Failed to load ${location} skills:`, error);
436511
+ }
436512
+ }
436513
+ async function loadAvailableSkills(projectRoot) {
436514
+ const skills = /* @__PURE__ */ new Map();
436515
+ const globalSkillsDir = join21(homedir14(), ".snow", "skills");
436516
+ const projectSkillsDir = projectRoot ? join21(projectRoot, ".snow", "skills") : null;
436517
+ await loadSkillsFromDirectory(skills, globalSkillsDir, "global");
436518
+ if (projectSkillsDir) {
436519
+ await loadSkillsFromDirectory(skills, projectSkillsDir, "project");
436074
436520
  }
436075
436521
  return skills;
436076
436522
  }
436077
436523
  function generateSkillToolDescription(skills) {
436078
436524
  const skillsList = Array.from(skills.values()).map((skill) => `<skill>
436079
436525
  <name>
436080
- ${skill.name}
436526
+ ${skill.id}
436081
436527
  </name>
436082
436528
  <description>
436083
436529
  ${skill.description}
@@ -436092,7 +436538,7 @@ ${skill.location}
436092
436538
  When users ask you to perform tasks, check if any of the available skills below can help complete the task more effectively. Skills provide specialized capabilities and domain knowledge.
436093
436539
 
436094
436540
  How to use skills:
436095
- - Invoke skills using this tool with the skill name only (no arguments)
436541
+ - Invoke skills using this tool with the skill id only (no arguments)
436096
436542
  - When you invoke a skill, you will see <command-message>The "{name}" skill is loading</command-message>
436097
436543
  - The skill's prompt will expand and provide detailed instructions on how to complete the task
436098
436544
  - Examples:
@@ -436124,7 +436570,7 @@ async function getMCPTools2(projectRoot) {
436124
436570
  properties: {
436125
436571
  skill: {
436126
436572
  type: "string",
436127
- description: 'The skill name (no arguments). E.g., "pdf" or "data-analysis"'
436573
+ description: 'The skill id (no arguments). E.g., "pdf", "data-analysis", or "helloagents/analyze"'
436128
436574
  }
436129
436575
  },
436130
436576
  required: ["skill"],
@@ -436184,15 +436630,16 @@ async function executeSkillTool(toolName, args2, projectRoot) {
436184
436630
  if (toolName !== "skill-execute") {
436185
436631
  throw new Error(`Unknown tool: ${toolName}`);
436186
436632
  }
436187
- const skillName = args2.skill;
436188
- if (!skillName || typeof skillName !== "string") {
436633
+ const requestedSkillId = args2.skill;
436634
+ if (!requestedSkillId || typeof requestedSkillId !== "string") {
436189
436635
  throw new Error("skill parameter is required and must be a string");
436190
436636
  }
436637
+ const skillId = normalizeSkillId(requestedSkillId);
436191
436638
  const skills = await loadAvailableSkills(projectRoot);
436192
- const skill = skills.get(skillName);
436639
+ const skill = skills.get(skillId);
436193
436640
  if (!skill) {
436194
436641
  const availableSkills = Array.from(skills.keys()).join(", ");
436195
- throw new Error(`Skill "${skillName}" not found. Available skills: ${availableSkills || "none"}`);
436642
+ throw new Error(`Skill "${skillId}" not found. Available skills: ${availableSkills || "none"}`);
436196
436643
  }
436197
436644
  const directoryTree = await generateSkillTree(skill.path);
436198
436645
  let toolRestriction = "";
@@ -543950,6 +544397,7 @@ var init_SkillsCreationPanel = __esm({
543950
544397
  "use strict";
543951
544398
  import_react115 = __toESM(require_react(), 1);
543952
544399
  await init_build2();
544400
+ await init_build3();
543953
544401
  await init_build4();
543954
544402
  init_ThemeContext();
543955
544403
  init_I18nContext();
@@ -543957,16 +544405,145 @@ var init_SkillsCreationPanel = __esm({
543957
544405
  SkillsCreationPanel = ({ onSave, onCancel, projectRoot }) => {
543958
544406
  const { theme: theme14 } = useTheme();
543959
544407
  const { t } = useI18n();
543960
- const [step, setStep] = (0, import_react115.useState)("name");
544408
+ const [step, setStep] = (0, import_react115.useState)("mode");
544409
+ const [mode, setMode] = (0, import_react115.useState)("manual");
543961
544410
  const [skillName, setSkillName] = (0, import_react115.useState)("");
543962
544411
  const [description, setDescription] = (0, import_react115.useState)("");
543963
544412
  const [location, setLocation] = (0, import_react115.useState)("global");
544413
+ const [requirement, setRequirement] = (0, import_react115.useState)("");
544414
+ const [generated, setGenerated] = (0, import_react115.useState)();
543964
544415
  const [errorMessage, setErrorMessage] = (0, import_react115.useState)("");
544416
+ const abortControllerRef = (0, import_react115.useRef)(null);
544417
+ const handleCancel = (0, import_react115.useCallback)(() => {
544418
+ var _a21;
544419
+ try {
544420
+ (_a21 = abortControllerRef.current) == null ? void 0 : _a21.abort();
544421
+ } catch {
544422
+ }
544423
+ onCancel();
544424
+ }, [onCancel]);
544425
+ const handleNameSubmit = (0, import_react115.useCallback)((value) => {
544426
+ if (!value.trim()) {
544427
+ return;
544428
+ }
544429
+ const trimmedName = value.trim();
544430
+ const validation = validateSkillId(trimmedName);
544431
+ if (!validation.valid) {
544432
+ setErrorMessage(validation.error || t.skillsCreation.errorInvalidName);
544433
+ return;
544434
+ }
544435
+ const existsGlobal = checkSkillExists(trimmedName, "global");
544436
+ const existsProject = checkSkillExists(trimmedName, "project", projectRoot);
544437
+ if (existsGlobal && existsProject) {
544438
+ setErrorMessage(t.skillsCreation.errorExistsBoth.replace("{name}", trimmedName));
544439
+ return;
544440
+ }
544441
+ if (existsGlobal) {
544442
+ setErrorMessage(t.skillsCreation.errorExistsGlobal.replace("{name}", trimmedName));
544443
+ return;
544444
+ }
544445
+ if (existsProject) {
544446
+ setErrorMessage(t.skillsCreation.errorExistsProject.replace("{name}", trimmedName));
544447
+ return;
544448
+ }
544449
+ setErrorMessage("");
544450
+ setSkillName(trimmedName);
544451
+ setStep("description");
544452
+ }, [projectRoot, t.skillsCreation]);
544453
+ const handleDescriptionSubmit = (0, import_react115.useCallback)((value) => {
544454
+ if (value.trim()) {
544455
+ setDescription(value.trim());
544456
+ setStep("location");
544457
+ }
544458
+ }, []);
544459
+ const handleRequirementSubmit = (0, import_react115.useCallback)((value) => {
544460
+ if (value.trim()) {
544461
+ setRequirement(value.trim());
544462
+ setErrorMessage("");
544463
+ setStep("ai-location");
544464
+ }
544465
+ }, []);
544466
+ const handleConfirmManual = (0, import_react115.useCallback)(async () => {
544467
+ await onSave(skillName, description, location);
544468
+ }, [skillName, description, location, onSave]);
544469
+ const handleConfirmAI = (0, import_react115.useCallback)(async () => {
544470
+ if (!generated) {
544471
+ setErrorMessage(t.skillsCreation.errorNoGeneratedContent);
544472
+ return;
544473
+ }
544474
+ await onSave(skillName, description, location, generated);
544475
+ }, [generated, skillName, description, location, onSave, t.skillsCreation]);
544476
+ const handleEditNameSubmit = (0, import_react115.useCallback)((value) => {
544477
+ if (!value.trim()) {
544478
+ return;
544479
+ }
544480
+ const trimmedName = value.trim();
544481
+ const validation = validateSkillId(trimmedName);
544482
+ if (!validation.valid) {
544483
+ setErrorMessage(validation.error || t.skillsCreation.errorInvalidName);
544484
+ return;
544485
+ }
544486
+ const existsGlobal = checkSkillExists(trimmedName, "global");
544487
+ const existsProject = checkSkillExists(trimmedName, "project", projectRoot);
544488
+ if (existsGlobal || existsProject) {
544489
+ setErrorMessage(t.skillsCreation.errorExistsAny.replace("{name}", trimmedName));
544490
+ return;
544491
+ }
544492
+ setErrorMessage("");
544493
+ setSkillName(trimmedName);
544494
+ setStep("ai-preview");
544495
+ }, [projectRoot, t.skillsCreation]);
544496
+ (0, import_react115.useEffect)(() => {
544497
+ if (step !== "ai-generating") {
544498
+ return;
544499
+ }
544500
+ const controller = new AbortController();
544501
+ abortControllerRef.current = controller;
544502
+ setErrorMessage("");
544503
+ setGenerated(void 0);
544504
+ generateSkillDraftWithAI(requirement, projectRoot, controller.signal).then((draft) => {
544505
+ setSkillName(draft.skillName);
544506
+ setDescription(draft.description);
544507
+ setGenerated(draft.generated);
544508
+ setStep("ai-preview");
544509
+ }).catch((error) => {
544510
+ if (controller.signal.aborted) {
544511
+ return;
544512
+ }
544513
+ const message = error instanceof Error ? error.message : t.skillsCreation.errorGeneration;
544514
+ setErrorMessage(message);
544515
+ setStep("ai-error");
544516
+ }).finally(() => {
544517
+ abortControllerRef.current = null;
544518
+ });
544519
+ return () => {
544520
+ try {
544521
+ controller.abort();
544522
+ } catch {
544523
+ }
544524
+ };
544525
+ }, [step, requirement, projectRoot, t.skillsCreation.errorGeneration]);
544526
+ const keyHandlingActive = step === "mode" || step === "location" || step === "confirm" || step === "ai-location" || step === "ai-generating" || step === "ai-preview" || step === "ai-error";
543965
544527
  use_input_default((input2, key) => {
543966
544528
  if (key.escape) {
543967
544529
  handleCancel();
543968
544530
  return;
543969
544531
  }
544532
+ if (step === "mode") {
544533
+ if (input2.toLowerCase() === "m") {
544534
+ setMode("manual");
544535
+ setErrorMessage("");
544536
+ setStep("name");
544537
+ } else if (input2.toLowerCase() === "a") {
544538
+ setMode("ai");
544539
+ setErrorMessage("");
544540
+ setSkillName("");
544541
+ setDescription("");
544542
+ setGenerated(void 0);
544543
+ setStep("ai-requirement");
544544
+ }
544545
+ return;
544546
+ }
543970
544547
  if (step === "location") {
543971
544548
  if (input2.toLowerCase() === "g") {
543972
544549
  setLocation("global");
@@ -543975,51 +544552,45 @@ var init_SkillsCreationPanel = __esm({
543975
544552
  setLocation("project");
543976
544553
  setStep("confirm");
543977
544554
  }
543978
- } else if (step === "confirm") {
544555
+ return;
544556
+ }
544557
+ if (step === "confirm") {
543979
544558
  if (input2.toLowerCase() === "y") {
543980
- handleConfirm();
544559
+ handleConfirmManual();
543981
544560
  } else if (input2.toLowerCase() === "n") {
543982
544561
  handleCancel();
543983
544562
  }
544563
+ return;
543984
544564
  }
543985
- }, { isActive: step === "location" || step === "confirm" });
543986
- const handleNameSubmit = (0, import_react115.useCallback)((value) => {
543987
- if (value.trim()) {
543988
- const trimmedName = value.trim();
543989
- const validation = validateSkillName(trimmedName);
543990
- if (!validation.valid) {
543991
- setErrorMessage(validation.error || t.skillsCreation.errorInvalidName);
543992
- return;
544565
+ if (step === "ai-location") {
544566
+ if (input2.toLowerCase() === "g") {
544567
+ setLocation("global");
544568
+ setStep("ai-generating");
544569
+ } else if (input2.toLowerCase() === "p") {
544570
+ setLocation("project");
544571
+ setStep("ai-generating");
543993
544572
  }
543994
- const existsGlobal = checkSkillExists(trimmedName, "global");
543995
- const existsProject = checkSkillExists(trimmedName, "project", projectRoot);
543996
- if (existsGlobal && existsProject) {
543997
- setErrorMessage(t.skillsCreation.errorExistsBoth.replace("{name}", trimmedName));
543998
- return;
543999
- } else if (existsGlobal) {
544000
- setErrorMessage(t.skillsCreation.errorExistsGlobal.replace("{name}", trimmedName));
544001
- return;
544002
- } else if (existsProject) {
544003
- setErrorMessage(t.skillsCreation.errorExistsProject.replace("{name}", trimmedName));
544004
- return;
544573
+ return;
544574
+ }
544575
+ if (step === "ai-preview") {
544576
+ if (input2.toLowerCase() === "y") {
544577
+ handleConfirmAI();
544578
+ } else if (input2.toLowerCase() === "e") {
544579
+ setErrorMessage("");
544580
+ setStep("ai-edit-name");
544581
+ } else if (input2.toLowerCase() === "r") {
544582
+ setErrorMessage("");
544583
+ setStep("ai-generating");
544005
544584
  }
544006
- setErrorMessage("");
544007
- setSkillName(trimmedName);
544008
- setStep("description");
544585
+ return;
544009
544586
  }
544010
- }, [projectRoot, t.skillsCreation]);
544011
- const handleDescriptionSubmit = (0, import_react115.useCallback)((value) => {
544012
- if (value.trim()) {
544013
- setDescription(value.trim());
544014
- setStep("location");
544587
+ if (step === "ai-error") {
544588
+ if (input2.toLowerCase() === "r") {
544589
+ setErrorMessage("");
544590
+ setStep("ai-generating");
544591
+ }
544015
544592
  }
544016
- }, []);
544017
- const handleConfirm = (0, import_react115.useCallback)(async () => {
544018
- await onSave(skillName, description, location);
544019
- }, [skillName, description, location, onSave]);
544020
- const handleCancel = (0, import_react115.useCallback)(() => {
544021
- onCancel();
544022
- }, [onCancel]);
544593
+ }, { isActive: keyHandlingActive });
544023
544594
  return import_react115.default.createElement(
544024
544595
  Box_default,
544025
544596
  { flexDirection: "column", padding: 1, borderStyle: "round", borderColor: theme14.colors.border },
@@ -544028,7 +544599,47 @@ var init_SkillsCreationPanel = __esm({
544028
544599
  { marginBottom: 1 },
544029
544600
  import_react115.default.createElement(Text, { bold: true, color: theme14.colors.menuSelected }, t.skillsCreation.title)
544030
544601
  ),
544031
- step === "name" && import_react115.default.createElement(
544602
+ step === "mode" && import_react115.default.createElement(
544603
+ Box_default,
544604
+ { flexDirection: "column" },
544605
+ import_react115.default.createElement(
544606
+ Box_default,
544607
+ { marginBottom: 1 },
544608
+ import_react115.default.createElement(Text, { color: theme14.colors.text }, t.skillsCreation.modeLabel)
544609
+ ),
544610
+ import_react115.default.createElement(
544611
+ Box_default,
544612
+ { gap: 2 },
544613
+ import_react115.default.createElement(
544614
+ Box_default,
544615
+ null,
544616
+ import_react115.default.createElement(Text, { color: theme14.colors.success, bold: true }, "[A]"),
544617
+ import_react115.default.createElement(
544618
+ Text,
544619
+ { color: theme14.colors.text },
544620
+ " ",
544621
+ t.skillsCreation.modeAi
544622
+ )
544623
+ ),
544624
+ import_react115.default.createElement(
544625
+ Box_default,
544626
+ null,
544627
+ import_react115.default.createElement(Text, { color: theme14.colors.menuSelected, bold: true }, "[M]"),
544628
+ import_react115.default.createElement(
544629
+ Text,
544630
+ { color: theme14.colors.text },
544631
+ " ",
544632
+ t.skillsCreation.modeManual
544633
+ )
544634
+ )
544635
+ ),
544636
+ import_react115.default.createElement(
544637
+ Box_default,
544638
+ { marginTop: 1 },
544639
+ import_react115.default.createElement(Text, { dimColor: true }, t.skillsCreation.escCancel)
544640
+ )
544641
+ ),
544642
+ mode === "manual" && step === "name" && import_react115.default.createElement(
544032
544643
  Box_default,
544033
544644
  { flexDirection: "column" },
544034
544645
  import_react115.default.createElement(
@@ -544053,7 +544664,7 @@ var init_SkillsCreationPanel = __esm({
544053
544664
  import_react115.default.createElement(Text, { dimColor: true }, t.skillsCreation.escCancel)
544054
544665
  )
544055
544666
  ),
544056
- step === "description" && import_react115.default.createElement(
544667
+ mode === "manual" && step === "description" && import_react115.default.createElement(
544057
544668
  Box_default,
544058
544669
  { flexDirection: "column" },
544059
544670
  import_react115.default.createElement(
@@ -544084,7 +544695,293 @@ var init_SkillsCreationPanel = __esm({
544084
544695
  import_react115.default.createElement(Text, { dimColor: true }, t.skillsCreation.escCancel)
544085
544696
  )
544086
544697
  ),
544087
- step === "location" && import_react115.default.createElement(
544698
+ mode === "manual" && step === "location" && import_react115.default.createElement(
544699
+ Box_default,
544700
+ { flexDirection: "column" },
544701
+ import_react115.default.createElement(
544702
+ Box_default,
544703
+ { marginBottom: 1 },
544704
+ import_react115.default.createElement(
544705
+ Text,
544706
+ { color: theme14.colors.text },
544707
+ t.skillsCreation.nameLabel,
544708
+ " ",
544709
+ import_react115.default.createElement(Text, { bold: true, color: theme14.colors.success }, skillName)
544710
+ )
544711
+ ),
544712
+ import_react115.default.createElement(
544713
+ Box_default,
544714
+ { marginBottom: 1 },
544715
+ import_react115.default.createElement(
544716
+ Text,
544717
+ { color: theme14.colors.text },
544718
+ t.skillsCreation.descriptionLabel,
544719
+ " ",
544720
+ import_react115.default.createElement(Text, { color: theme14.colors.menuNormal }, description)
544721
+ )
544722
+ ),
544723
+ import_react115.default.createElement(
544724
+ Box_default,
544725
+ { marginBottom: 1, marginTop: 1 },
544726
+ import_react115.default.createElement(Text, { color: theme14.colors.text }, t.skillsCreation.locationLabel)
544727
+ ),
544728
+ import_react115.default.createElement(
544729
+ Box_default,
544730
+ { marginTop: 1, flexDirection: "column", gap: 1 },
544731
+ import_react115.default.createElement(
544732
+ Box_default,
544733
+ null,
544734
+ import_react115.default.createElement(Text, { color: theme14.colors.success, bold: true }, "[G]"),
544735
+ import_react115.default.createElement(
544736
+ Text,
544737
+ { color: theme14.colors.text },
544738
+ " ",
544739
+ t.skillsCreation.locationGlobal
544740
+ )
544741
+ ),
544742
+ import_react115.default.createElement(
544743
+ Box_default,
544744
+ { marginLeft: 4 },
544745
+ import_react115.default.createElement(Text, { dimColor: true }, t.skillsCreation.locationGlobalInfo)
544746
+ ),
544747
+ import_react115.default.createElement(
544748
+ Box_default,
544749
+ { marginTop: 1 },
544750
+ import_react115.default.createElement(Text, { color: theme14.colors.menuSelected, bold: true }, "[P]"),
544751
+ import_react115.default.createElement(
544752
+ Text,
544753
+ { color: theme14.colors.text },
544754
+ " ",
544755
+ t.skillsCreation.locationProject
544756
+ )
544757
+ ),
544758
+ import_react115.default.createElement(
544759
+ Box_default,
544760
+ { marginLeft: 4 },
544761
+ import_react115.default.createElement(Text, { dimColor: true }, t.skillsCreation.locationProjectInfo)
544762
+ )
544763
+ ),
544764
+ import_react115.default.createElement(
544765
+ Box_default,
544766
+ { marginTop: 1 },
544767
+ import_react115.default.createElement(Text, { dimColor: true }, t.skillsCreation.escCancel)
544768
+ )
544769
+ ),
544770
+ mode === "manual" && step === "confirm" && import_react115.default.createElement(
544771
+ Box_default,
544772
+ { flexDirection: "column" },
544773
+ import_react115.default.createElement(
544774
+ Box_default,
544775
+ { marginBottom: 1 },
544776
+ import_react115.default.createElement(
544777
+ Text,
544778
+ { color: theme14.colors.text },
544779
+ t.skillsCreation.nameLabel,
544780
+ " ",
544781
+ import_react115.default.createElement(Text, { bold: true, color: theme14.colors.success }, skillName)
544782
+ )
544783
+ ),
544784
+ import_react115.default.createElement(
544785
+ Box_default,
544786
+ { marginBottom: 1 },
544787
+ import_react115.default.createElement(
544788
+ Text,
544789
+ { color: theme14.colors.text },
544790
+ t.skillsCreation.descriptionLabel,
544791
+ " ",
544792
+ import_react115.default.createElement(Text, { color: theme14.colors.menuNormal }, description)
544793
+ )
544794
+ ),
544795
+ import_react115.default.createElement(
544796
+ Box_default,
544797
+ { marginBottom: 1 },
544798
+ import_react115.default.createElement(
544799
+ Text,
544800
+ { color: theme14.colors.text },
544801
+ t.skillsCreation.locationLabel,
544802
+ " ",
544803
+ import_react115.default.createElement(Text, { bold: true, color: theme14.colors.menuSelected }, location === "global" ? t.skillsCreation.locationGlobal : t.skillsCreation.locationProject)
544804
+ )
544805
+ ),
544806
+ import_react115.default.createElement(
544807
+ Box_default,
544808
+ { marginTop: 1 },
544809
+ import_react115.default.createElement(Text, { color: theme14.colors.text }, t.skillsCreation.confirmQuestion)
544810
+ ),
544811
+ import_react115.default.createElement(
544812
+ Box_default,
544813
+ { marginTop: 1, gap: 2 },
544814
+ import_react115.default.createElement(
544815
+ Box_default,
544816
+ null,
544817
+ import_react115.default.createElement(Text, { color: theme14.colors.success, bold: true }, "[Y]"),
544818
+ import_react115.default.createElement(
544819
+ Text,
544820
+ { color: theme14.colors.text },
544821
+ " ",
544822
+ t.skillsCreation.confirmYes
544823
+ )
544824
+ ),
544825
+ import_react115.default.createElement(
544826
+ Box_default,
544827
+ null,
544828
+ import_react115.default.createElement(Text, { color: theme14.colors.error, bold: true }, "[N]"),
544829
+ import_react115.default.createElement(
544830
+ Text,
544831
+ { color: theme14.colors.text },
544832
+ " ",
544833
+ t.skillsCreation.confirmNo
544834
+ )
544835
+ )
544836
+ )
544837
+ ),
544838
+ mode === "ai" && step === "ai-requirement" && import_react115.default.createElement(
544839
+ Box_default,
544840
+ { flexDirection: "column" },
544841
+ import_react115.default.createElement(
544842
+ Box_default,
544843
+ { marginBottom: 1 },
544844
+ import_react115.default.createElement(Text, { color: theme14.colors.text }, t.skillsCreation.requirementLabel)
544845
+ ),
544846
+ import_react115.default.createElement(
544847
+ Box_default,
544848
+ { marginBottom: 1 },
544849
+ import_react115.default.createElement(Text, { dimColor: true }, t.skillsCreation.requirementHint)
544850
+ ),
544851
+ import_react115.default.createElement(TextInput, { placeholder: t.skillsCreation.requirementPlaceholder, onSubmit: handleRequirementSubmit }),
544852
+ import_react115.default.createElement(
544853
+ Box_default,
544854
+ { marginTop: 1 },
544855
+ import_react115.default.createElement(Text, { dimColor: true }, t.skillsCreation.escCancel)
544856
+ )
544857
+ ),
544858
+ mode === "ai" && step === "ai-location" && import_react115.default.createElement(
544859
+ Box_default,
544860
+ { flexDirection: "column" },
544861
+ import_react115.default.createElement(
544862
+ Box_default,
544863
+ { marginBottom: 1 },
544864
+ import_react115.default.createElement(
544865
+ Text,
544866
+ { color: theme14.colors.text },
544867
+ t.skillsCreation.requirementLabel,
544868
+ " ",
544869
+ import_react115.default.createElement(Text, { color: theme14.colors.menuNormal }, requirement)
544870
+ )
544871
+ ),
544872
+ import_react115.default.createElement(
544873
+ Box_default,
544874
+ { marginBottom: 1, marginTop: 1 },
544875
+ import_react115.default.createElement(Text, { color: theme14.colors.text }, t.skillsCreation.locationLabel)
544876
+ ),
544877
+ import_react115.default.createElement(
544878
+ Box_default,
544879
+ { marginTop: 1, flexDirection: "column", gap: 1 },
544880
+ import_react115.default.createElement(
544881
+ Box_default,
544882
+ null,
544883
+ import_react115.default.createElement(Text, { color: theme14.colors.success, bold: true }, "[G]"),
544884
+ import_react115.default.createElement(
544885
+ Text,
544886
+ { color: theme14.colors.text },
544887
+ " ",
544888
+ t.skillsCreation.locationGlobal
544889
+ )
544890
+ ),
544891
+ import_react115.default.createElement(
544892
+ Box_default,
544893
+ { marginLeft: 4 },
544894
+ import_react115.default.createElement(Text, { dimColor: true }, t.skillsCreation.locationGlobalInfo)
544895
+ ),
544896
+ import_react115.default.createElement(
544897
+ Box_default,
544898
+ { marginTop: 1 },
544899
+ import_react115.default.createElement(Text, { color: theme14.colors.menuSelected, bold: true }, "[P]"),
544900
+ import_react115.default.createElement(
544901
+ Text,
544902
+ { color: theme14.colors.text },
544903
+ " ",
544904
+ t.skillsCreation.locationProject
544905
+ )
544906
+ ),
544907
+ import_react115.default.createElement(
544908
+ Box_default,
544909
+ { marginLeft: 4 },
544910
+ import_react115.default.createElement(Text, { dimColor: true }, t.skillsCreation.locationProjectInfo)
544911
+ )
544912
+ ),
544913
+ import_react115.default.createElement(
544914
+ Box_default,
544915
+ { marginTop: 1 },
544916
+ import_react115.default.createElement(Text, { dimColor: true }, t.skillsCreation.escCancel)
544917
+ )
544918
+ ),
544919
+ mode === "ai" && step === "ai-generating" && import_react115.default.createElement(
544920
+ Box_default,
544921
+ { flexDirection: "column" },
544922
+ import_react115.default.createElement(
544923
+ Box_default,
544924
+ { marginBottom: 1 },
544925
+ import_react115.default.createElement(Text, { color: theme14.colors.text }, t.skillsCreation.generatingLabel)
544926
+ ),
544927
+ import_react115.default.createElement(
544928
+ Box_default,
544929
+ null,
544930
+ import_react115.default.createElement(
544931
+ Text,
544932
+ { color: theme14.colors.menuNormal },
544933
+ import_react115.default.createElement(build_default, { type: "dots" }),
544934
+ " ",
544935
+ t.skillsCreation.generatingMessage
544936
+ )
544937
+ ),
544938
+ import_react115.default.createElement(
544939
+ Box_default,
544940
+ { marginTop: 1 },
544941
+ import_react115.default.createElement(Text, { dimColor: true }, t.skillsCreation.escCancel)
544942
+ )
544943
+ ),
544944
+ mode === "ai" && step === "ai-error" && import_react115.default.createElement(
544945
+ Box_default,
544946
+ { flexDirection: "column" },
544947
+ import_react115.default.createElement(
544948
+ Box_default,
544949
+ { marginBottom: 1 },
544950
+ import_react115.default.createElement(Text, { color: theme14.colors.error }, t.skillsCreation.errorGeneration)
544951
+ ),
544952
+ errorMessage && import_react115.default.createElement(
544953
+ Box_default,
544954
+ { marginBottom: 1 },
544955
+ import_react115.default.createElement(Text, { color: theme14.colors.error }, errorMessage)
544956
+ ),
544957
+ import_react115.default.createElement(
544958
+ Box_default,
544959
+ { marginTop: 1, gap: 2 },
544960
+ import_react115.default.createElement(
544961
+ Box_default,
544962
+ null,
544963
+ import_react115.default.createElement(Text, { color: theme14.colors.menuSelected, bold: true }, "[R]"),
544964
+ import_react115.default.createElement(
544965
+ Text,
544966
+ { color: theme14.colors.text },
544967
+ " ",
544968
+ t.skillsCreation.regenerate
544969
+ )
544970
+ ),
544971
+ import_react115.default.createElement(
544972
+ Box_default,
544973
+ null,
544974
+ import_react115.default.createElement(Text, { color: theme14.colors.menuSecondary, dimColor: true }, "[ESC]"),
544975
+ import_react115.default.createElement(
544976
+ Text,
544977
+ { color: theme14.colors.text },
544978
+ " ",
544979
+ t.skillsCreation.cancel
544980
+ )
544981
+ )
544982
+ )
544983
+ ),
544984
+ mode === "ai" && step === "ai-preview" && import_react115.default.createElement(
544088
544985
  Box_default,
544089
544986
  { flexDirection: "column" },
544090
544987
  import_react115.default.createElement(
@@ -544111,43 +545008,74 @@ var init_SkillsCreationPanel = __esm({
544111
545008
  ),
544112
545009
  import_react115.default.createElement(
544113
545010
  Box_default,
544114
- { marginBottom: 1, marginTop: 1 },
544115
- import_react115.default.createElement(Text, { color: theme14.colors.text }, t.skillsCreation.locationLabel)
545011
+ { marginBottom: 1 },
545012
+ import_react115.default.createElement(
545013
+ Text,
545014
+ { color: theme14.colors.text },
545015
+ t.skillsCreation.locationLabel,
545016
+ " ",
545017
+ import_react115.default.createElement(Text, { bold: true, color: theme14.colors.menuSelected }, location === "global" ? t.skillsCreation.locationGlobal : t.skillsCreation.locationProject)
545018
+ )
544116
545019
  ),
544117
545020
  import_react115.default.createElement(
544118
545021
  Box_default,
544119
- { marginTop: 1, flexDirection: "column", gap: 1 },
545022
+ { marginTop: 1, flexDirection: "column" },
545023
+ import_react115.default.createElement(Text, { color: theme14.colors.text }, t.skillsCreation.filesLabel),
545024
+ import_react115.default.createElement(
545025
+ Box_default,
545026
+ { marginLeft: 2, flexDirection: "column" },
545027
+ import_react115.default.createElement(Text, { dimColor: true }, "- SKILL.md"),
545028
+ import_react115.default.createElement(Text, { dimColor: true }, "- reference.md"),
545029
+ import_react115.default.createElement(Text, { dimColor: true }, "- examples.md"),
545030
+ import_react115.default.createElement(Text, { dimColor: true }, "- templates/template.txt"),
545031
+ import_react115.default.createElement(Text, { dimColor: true }, "- scripts/helper.py")
545032
+ )
545033
+ ),
545034
+ errorMessage && import_react115.default.createElement(
545035
+ Box_default,
545036
+ { marginTop: 1 },
545037
+ import_react115.default.createElement(Text, { color: theme14.colors.error }, errorMessage)
545038
+ ),
545039
+ import_react115.default.createElement(
545040
+ Box_default,
545041
+ { marginTop: 1 },
545042
+ import_react115.default.createElement(Text, { color: theme14.colors.text }, t.skillsCreation.confirmQuestion)
545043
+ ),
545044
+ import_react115.default.createElement(
545045
+ Box_default,
545046
+ { marginTop: 1, gap: 2 },
544120
545047
  import_react115.default.createElement(
544121
545048
  Box_default,
544122
545049
  null,
544123
- import_react115.default.createElement(Text, { color: theme14.colors.success, bold: true }, "[G]"),
545050
+ import_react115.default.createElement(Text, { color: theme14.colors.success, bold: true }, "[Y]"),
544124
545051
  import_react115.default.createElement(
544125
545052
  Text,
544126
545053
  { color: theme14.colors.text },
544127
545054
  " ",
544128
- t.skillsCreation.locationGlobal
545055
+ t.skillsCreation.confirmYes
544129
545056
  )
544130
545057
  ),
544131
545058
  import_react115.default.createElement(
544132
545059
  Box_default,
544133
- { marginLeft: 4 },
544134
- import_react115.default.createElement(Text, { dimColor: true }, t.skillsCreation.locationGlobalInfo)
544135
- ),
544136
- import_react115.default.createElement(
544137
- Box_default,
544138
- { marginTop: 1 },
544139
- import_react115.default.createElement(Text, { color: theme14.colors.menuSelected, bold: true }, "[P]"),
545060
+ null,
545061
+ import_react115.default.createElement(Text, { color: theme14.colors.menuSelected, bold: true }, "[E]"),
544140
545062
  import_react115.default.createElement(
544141
545063
  Text,
544142
545064
  { color: theme14.colors.text },
544143
545065
  " ",
544144
- t.skillsCreation.locationProject
545066
+ t.skillsCreation.editName
544145
545067
  )
544146
545068
  ),
544147
545069
  import_react115.default.createElement(
544148
545070
  Box_default,
544149
- { marginLeft: 4 },
544150
- import_react115.default.createElement(Text, { dimColor: true }, t.skillsCreation.locationProjectInfo)
545071
+ null,
545072
+ import_react115.default.createElement(Text, { color: theme14.colors.warning, bold: true }, "[R]"),
545073
+ import_react115.default.createElement(
545074
+ Text,
545075
+ { color: theme14.colors.text },
545076
+ " ",
545077
+ t.skillsCreation.regenerate
545078
+ )
544151
545079
  )
544152
545080
  ),
544153
545081
  import_react115.default.createElement(
@@ -544156,7 +545084,7 @@ var init_SkillsCreationPanel = __esm({
544156
545084
  import_react115.default.createElement(Text, { dimColor: true }, t.skillsCreation.escCancel)
544157
545085
  )
544158
545086
  ),
544159
- step === "confirm" && import_react115.default.createElement(
545087
+ mode === "ai" && step === "ai-edit-name" && import_react115.default.createElement(
544160
545088
  Box_default,
544161
545089
  { flexDirection: "column" },
544162
545090
  import_react115.default.createElement(
@@ -544165,63 +545093,26 @@ var init_SkillsCreationPanel = __esm({
544165
545093
  import_react115.default.createElement(
544166
545094
  Text,
544167
545095
  { color: theme14.colors.text },
544168
- t.skillsCreation.nameLabel,
545096
+ t.skillsCreation.editNameLabel,
544169
545097
  " ",
544170
- import_react115.default.createElement(Text, { bold: true, color: theme14.colors.success }, skillName)
545098
+ import_react115.default.createElement(Text, { color: theme14.colors.menuNormal }, skillName)
544171
545099
  )
544172
545100
  ),
544173
545101
  import_react115.default.createElement(
544174
545102
  Box_default,
544175
545103
  { marginBottom: 1 },
544176
- import_react115.default.createElement(
544177
- Text,
544178
- { color: theme14.colors.text },
544179
- t.skillsCreation.descriptionLabel,
544180
- " ",
544181
- import_react115.default.createElement(Text, { color: theme14.colors.menuNormal }, description)
544182
- )
544183
- ),
544184
- import_react115.default.createElement(
544185
- Box_default,
544186
- { marginBottom: 1 },
544187
- import_react115.default.createElement(
544188
- Text,
544189
- { color: theme14.colors.text },
544190
- t.skillsCreation.locationLabel,
544191
- " ",
544192
- import_react115.default.createElement(Text, { bold: true, color: theme14.colors.menuSelected }, location === "global" ? t.skillsCreation.locationGlobal : t.skillsCreation.locationProject)
544193
- )
545104
+ import_react115.default.createElement(Text, { dimColor: true }, t.skillsCreation.editNameHint)
544194
545105
  ),
544195
- import_react115.default.createElement(
545106
+ import_react115.default.createElement(TextInput, { placeholder: t.skillsCreation.editNamePlaceholder, onSubmit: handleEditNameSubmit }),
545107
+ errorMessage && import_react115.default.createElement(
544196
545108
  Box_default,
544197
545109
  { marginTop: 1 },
544198
- import_react115.default.createElement(Text, { color: theme14.colors.text }, t.skillsCreation.confirmQuestion)
545110
+ import_react115.default.createElement(Text, { color: theme14.colors.error }, errorMessage)
544199
545111
  ),
544200
545112
  import_react115.default.createElement(
544201
545113
  Box_default,
544202
- { marginTop: 1, gap: 2 },
544203
- import_react115.default.createElement(
544204
- Box_default,
544205
- null,
544206
- import_react115.default.createElement(Text, { color: theme14.colors.success, bold: true }, "[Y]"),
544207
- import_react115.default.createElement(
544208
- Text,
544209
- { color: theme14.colors.text },
544210
- " ",
544211
- t.skillsCreation.confirmYes
544212
- )
544213
- ),
544214
- import_react115.default.createElement(
544215
- Box_default,
544216
- null,
544217
- import_react115.default.createElement(Text, { color: theme14.colors.error, bold: true }, "[N]"),
544218
- import_react115.default.createElement(
544219
- Text,
544220
- { color: theme14.colors.text },
544221
- " ",
544222
- t.skillsCreation.confirmNo
544223
- )
544224
- )
545114
+ { marginTop: 1 },
545115
+ import_react115.default.createElement(Text, { dimColor: true }, t.skillsCreation.escCancel)
544225
545116
  )
544226
545117
  )
544227
545118
  );
@@ -548236,7 +549127,10 @@ async function handleConversationWithTools(options3) {
548236
549127
  if (subAgentMessage.message.type === "tool_calls") {
548237
549128
  const toolCalls = subAgentMessage.message.tool_calls;
548238
549129
  if (toolCalls && toolCalls.length > 0) {
548239
- const toolMessages = toolCalls.filter((toolCall) => isToolNeedTwoStepDisplay(toolCall.function.name)).map((toolCall) => {
549130
+ const timeConsumingTools = toolCalls.filter((tc) => isToolNeedTwoStepDisplay(tc.function.name));
549131
+ const quickTools = toolCalls.filter((tc) => !isToolNeedTwoStepDisplay(tc.function.name));
549132
+ const newMessages = [];
549133
+ for (const toolCall of timeConsumingTools) {
548240
549134
  const toolDisplay = formatToolCallMessage(toolCall);
548241
549135
  let toolArgs;
548242
549136
  try {
@@ -548252,7 +549146,6 @@ async function handleConversationWithTools(options3) {
548252
549146
  name: toolCall.function.name,
548253
549147
  arguments: toolArgs
548254
549148
  },
548255
- // Don't include toolDisplay for sub-agent tools to avoid showing parameters
548256
549149
  toolCallId: toolCall.id,
548257
549150
  toolPending: true,
548258
549151
  subAgent: {
@@ -548261,109 +549154,176 @@ async function handleConversationWithTools(options3) {
548261
549154
  isComplete: false
548262
549155
  },
548263
549156
  subAgentInternal: true
548264
- // Mark as internal sub-agent message
548265
549157
  };
548266
- return uiMsg;
548267
- });
549158
+ newMessages.push(uiMsg);
549159
+ }
549160
+ if (quickTools.length > 0) {
549161
+ const toolLines = quickTools.map((tc, index) => {
549162
+ const display = formatToolCallMessage(tc);
549163
+ const isLast = index === quickTools.length - 1;
549164
+ const prefix = isLast ? "\u2514\u2500" : "\u251C\u2500";
549165
+ const params = display.args.map((arg) => `${arg.key}: ${arg.value}`).join(", ");
549166
+ return `
549167
+ \x1B[2m${prefix} ${display.toolName}${params ? ` (${params})` : ""}\x1B[0m`;
549168
+ });
549169
+ const uiMsg = {
549170
+ role: "subagent",
549171
+ content: `\x1B[38;2;184;122;206m\u2687 ${subAgentMessage.agentName}${toolLines.join("")}\x1B[0m`,
549172
+ streaming: false,
549173
+ subAgent: {
549174
+ agentId: subAgentMessage.agentId,
549175
+ agentName: subAgentMessage.agentName,
549176
+ isComplete: false
549177
+ },
549178
+ subAgentInternal: true,
549179
+ // Store pending tool call IDs for later status update
549180
+ pendingToolIds: quickTools.map((tc) => tc.id)
549181
+ };
549182
+ newMessages.push(uiMsg);
549183
+ }
548268
549184
  const sessionMsg = {
548269
549185
  role: "assistant",
548270
549186
  content: toolCalls.map((tc) => {
548271
549187
  const display = formatToolCallMessage(tc);
548272
- return `\u2687\u26A1 ${display.toolName}`;
549188
+ return isToolNeedTwoStepDisplay(tc.function.name) ? `\u2687\u26A1 ${display.toolName}` : `\u2687 ${display.toolName}`;
548273
549189
  }).join(", "),
548274
549190
  subAgentInternal: true,
548275
549191
  tool_calls: toolCalls
548276
549192
  };
548277
549193
  saveMessage(sessionMsg).catch((err) => console.error("Failed to save sub-agent tool call:", err));
548278
- return [...prev, ...toolMessages];
549194
+ return [...prev, ...newMessages];
548279
549195
  }
548280
549196
  }
548281
549197
  if (subAgentMessage.message.type === "tool_result") {
548282
549198
  const msg = subAgentMessage.message;
548283
549199
  const isError2 = msg.content.startsWith("Error:");
548284
- const statusIcon = isError2 ? "\u2717" : "\u2713";
548285
- const statusText = isError2 ? `
549200
+ const isTimeConsumingTool = isToolNeedTwoStepDisplay(msg.tool_name);
549201
+ const sessionMsg = {
549202
+ role: "tool",
549203
+ tool_call_id: msg.tool_call_id,
549204
+ content: msg.content,
549205
+ subAgentInternal: true
549206
+ };
549207
+ saveMessage(sessionMsg).catch((err) => console.error("Failed to save sub-agent tool result:", err));
549208
+ if (isTimeConsumingTool) {
549209
+ const statusIcon = isError2 ? "\u2717" : "\u2713";
549210
+ const statusText = isError2 ? `
548286
549211
  \u2514\u2500 ${msg.content}` : "";
548287
- let terminalResultData;
548288
- if (msg.tool_name === "terminal-execute" && !isError2) {
548289
- try {
548290
- const resultData = JSON.parse(msg.content);
548291
- if (resultData.stdout !== void 0 || resultData.stderr !== void 0) {
548292
- terminalResultData = {
548293
- stdout: resultData.stdout,
548294
- stderr: resultData.stderr,
548295
- exitCode: resultData.exitCode,
548296
- command: resultData.command
548297
- };
549212
+ let terminalResultData;
549213
+ if (msg.tool_name === "terminal-execute" && !isError2) {
549214
+ try {
549215
+ const resultData = JSON.parse(msg.content);
549216
+ if (resultData.stdout !== void 0 || resultData.stderr !== void 0) {
549217
+ terminalResultData = {
549218
+ stdout: resultData.stdout,
549219
+ stderr: resultData.stderr,
549220
+ exitCode: resultData.exitCode,
549221
+ command: resultData.command
549222
+ };
549223
+ }
549224
+ } catch (e) {
548298
549225
  }
548299
- } catch (e) {
548300
549226
  }
549227
+ let fileToolData = void 0;
549228
+ if (!isError2 && (msg.tool_name === "filesystem-create" || msg.tool_name === "filesystem-edit" || msg.tool_name === "filesystem-edit_search")) {
549229
+ try {
549230
+ const resultData = JSON.parse(msg.content);
549231
+ if (resultData.content) {
549232
+ fileToolData = {
549233
+ name: msg.tool_name,
549234
+ arguments: {
549235
+ content: resultData.content,
549236
+ path: resultData.path || resultData.filename
549237
+ }
549238
+ };
549239
+ } else if (resultData.oldContent && resultData.newContent) {
549240
+ fileToolData = {
549241
+ name: msg.tool_name,
549242
+ arguments: {
549243
+ oldContent: resultData.oldContent,
549244
+ newContent: resultData.newContent,
549245
+ filename: resultData.path || resultData.filename,
549246
+ completeOldContent: resultData.completeOldContent,
549247
+ completeNewContent: resultData.completeNewContent,
549248
+ contextStartLine: resultData.contextStartLine
549249
+ }
549250
+ };
549251
+ } else if (resultData.batchResults && Array.isArray(resultData.batchResults)) {
549252
+ fileToolData = {
549253
+ name: msg.tool_name,
549254
+ arguments: {
549255
+ isBatch: true,
549256
+ batchResults: resultData.batchResults
549257
+ }
549258
+ };
549259
+ }
549260
+ } catch (e) {
549261
+ }
549262
+ }
549263
+ const uiMsg = {
549264
+ role: "subagent",
549265
+ content: `\x1B[38;2;0;186;255m\u2687${statusIcon} ${msg.tool_name}\x1B[0m${statusText}`,
549266
+ streaming: false,
549267
+ toolResult: !isError2 ? msg.content : void 0,
549268
+ terminalResult: terminalResultData,
549269
+ toolCall: terminalResultData ? {
549270
+ name: msg.tool_name,
549271
+ arguments: terminalResultData
549272
+ } : fileToolData ? fileToolData : void 0,
549273
+ subAgent: {
549274
+ agentId: subAgentMessage.agentId,
549275
+ agentName: subAgentMessage.agentName,
549276
+ isComplete: false
549277
+ },
549278
+ subAgentInternal: true
549279
+ };
549280
+ return [...prev, uiMsg];
548301
549281
  }
548302
- let fileToolData = void 0;
548303
- if (!isError2 && (msg.tool_name === "filesystem-create" || msg.tool_name === "filesystem-edit" || msg.tool_name === "filesystem-edit_search")) {
548304
- try {
548305
- const resultData = JSON.parse(msg.content);
548306
- if (resultData.content) {
548307
- fileToolData = {
548308
- name: msg.tool_name,
548309
- arguments: {
548310
- content: resultData.content,
548311
- path: resultData.path || resultData.filename
548312
- }
548313
- };
548314
- } else if (resultData.oldContent && resultData.newContent) {
548315
- fileToolData = {
548316
- name: msg.tool_name,
548317
- arguments: {
548318
- oldContent: resultData.oldContent,
548319
- newContent: resultData.newContent,
548320
- filename: resultData.path || resultData.filename,
548321
- completeOldContent: resultData.completeOldContent,
548322
- completeNewContent: resultData.completeNewContent,
548323
- contextStartLine: resultData.contextStartLine
548324
- }
549282
+ if (isError2) {
549283
+ const statusText = `
549284
+ \u2514\u2500 ${msg.content}`;
549285
+ const uiMsg = {
549286
+ role: "subagent",
549287
+ content: `\x1B[38;2;255;100;100m\u2687\u2717 ${msg.tool_name}\x1B[0m${statusText}`,
549288
+ streaming: false,
549289
+ subAgent: {
549290
+ agentId: subAgentMessage.agentId,
549291
+ agentName: subAgentMessage.agentName,
549292
+ isComplete: false
549293
+ },
549294
+ subAgentInternal: true
549295
+ };
549296
+ return [...prev, uiMsg];
549297
+ }
549298
+ const pendingMsgIndex = prev.findIndex((m) => {
549299
+ var _a22, _b14, _c6;
549300
+ return m.role === "subagent" && ((_a22 = m.subAgent) == null ? void 0 : _a22.agentId) === subAgentMessage.agentId && !((_b14 = m.subAgent) == null ? void 0 : _b14.isComplete) && ((_c6 = m.pendingToolIds) == null ? void 0 : _c6.includes(msg.tool_call_id));
549301
+ });
549302
+ if (pendingMsgIndex !== -1) {
549303
+ const updated = [...prev];
549304
+ const pendingMsg = updated[pendingMsgIndex];
549305
+ if (pendingMsg && pendingMsg.pendingToolIds) {
549306
+ const newPendingIds = pendingMsg.pendingToolIds.filter((id) => id !== msg.tool_call_id);
549307
+ if (newPendingIds.length === 0) {
549308
+ updated[pendingMsgIndex] = {
549309
+ ...pendingMsg,
549310
+ content: `${pendingMsg.content} \x1B[38;2;100;200;100m\u2713\x1B[0m`,
549311
+ pendingToolIds: newPendingIds
548325
549312
  };
548326
- } else if (resultData.batchResults && Array.isArray(resultData.batchResults)) {
548327
- fileToolData = {
548328
- name: msg.tool_name,
548329
- arguments: {
548330
- isBatch: true,
548331
- batchResults: resultData.batchResults
548332
- }
549313
+ } else {
549314
+ updated[pendingMsgIndex] = {
549315
+ ...pendingMsg,
549316
+ pendingToolIds: newPendingIds
548333
549317
  };
548334
549318
  }
548335
- } catch (e) {
548336
549319
  }
549320
+ return updated;
548337
549321
  }
548338
- const uiMsg = {
548339
- role: "subagent",
548340
- content: `\x1B[38;2;0;186;255m\u2687${statusIcon} ${msg.tool_name}\x1B[0m${statusText}`,
548341
- streaming: false,
548342
- toolResult: !isError2 ? msg.content : void 0,
548343
- terminalResult: terminalResultData,
548344
- toolCall: terminalResultData ? {
548345
- name: msg.tool_name,
548346
- arguments: terminalResultData
548347
- } : fileToolData ? fileToolData : void 0,
548348
- subAgent: {
548349
- agentId: subAgentMessage.agentId,
548350
- agentName: subAgentMessage.agentName,
548351
- isComplete: false
548352
- },
548353
- subAgentInternal: true
548354
- };
548355
- const sessionMsg = {
548356
- role: "tool",
548357
- tool_call_id: msg.tool_call_id,
548358
- content: msg.content,
548359
- subAgentInternal: true
548360
- };
548361
- saveMessage(sessionMsg).catch((err) => console.error("Failed to save sub-agent tool result:", err));
548362
- return [...prev, uiMsg];
549322
+ return prev;
548363
549323
  }
548364
549324
  const existingIndex = prev.findIndex((m) => {
548365
549325
  var _a22, _b14;
548366
- return m.role === "subagent" && ((_a22 = m.subAgent) == null ? void 0 : _a22.agentId) === subAgentMessage.agentId && !((_b14 = m.subAgent) == null ? void 0 : _b14.isComplete) && !m.toolCall;
549326
+ return m.role === "subagent" && ((_a22 = m.subAgent) == null ? void 0 : _a22.agentId) === subAgentMessage.agentId && !((_b14 = m.subAgent) == null ? void 0 : _b14.isComplete) && !m.pendingToolIds;
548367
549327
  });
548368
549328
  let content = "";
548369
549329
  if (subAgentMessage.message.type === "content") {
@@ -548855,43 +549815,64 @@ function convertSessionMessagesToUI(sessionMessages) {
548855
549815
  const msg = sessionMessages[i];
548856
549816
  if (!msg)
548857
549817
  continue;
548858
- if (msg.role === "system")
548859
- continue;
548860
549818
  if (msg.subAgentInternal && msg.role === "assistant" && msg.tool_calls) {
548861
- for (const toolCall of msg.tool_calls) {
548862
- if (isToolNeedTwoStepDisplay(toolCall.function.name)) {
548863
- const toolDisplay = formatToolCallMessage(toolCall);
548864
- let toolArgs;
548865
- try {
548866
- toolArgs = JSON.parse(toolCall.function.arguments);
548867
- } catch (e) {
548868
- toolArgs = {};
548869
- }
548870
- uiMessages.push({
548871
- role: "subagent",
548872
- content: `\x1B[38;2;184;122;206m\u2687\u26A1 ${toolDisplay.toolName}\x1B[0m`,
548873
- streaming: false,
548874
- toolCall: {
548875
- name: toolCall.function.name,
548876
- arguments: toolArgs
548877
- },
548878
- // Don't include toolDisplay for sub-agent tools to avoid showing parameters
548879
- toolCallId: toolCall.id,
548880
- toolPending: false,
548881
- subAgentInternal: true
548882
- });
549819
+ const timeConsumingTools = msg.tool_calls.filter((tc) => isToolNeedTwoStepDisplay(tc.function.name));
549820
+ const quickTools = msg.tool_calls.filter((tc) => !isToolNeedTwoStepDisplay(tc.function.name));
549821
+ for (const toolCall of timeConsumingTools) {
549822
+ const toolDisplay = formatToolCallMessage(toolCall);
549823
+ let toolArgs;
549824
+ try {
549825
+ toolArgs = JSON.parse(toolCall.function.arguments);
549826
+ } catch (e) {
549827
+ toolArgs = {};
548883
549828
  }
549829
+ uiMessages.push({
549830
+ role: "subagent",
549831
+ content: `\x1B[38;2;184;122;206m\u2687\u26A1 ${toolDisplay.toolName}\x1B[0m`,
549832
+ streaming: false,
549833
+ toolCall: {
549834
+ name: toolCall.function.name,
549835
+ arguments: toolArgs
549836
+ },
549837
+ toolCallId: toolCall.id,
549838
+ toolPending: false,
549839
+ subAgentInternal: true
549840
+ });
548884
549841
  processedToolCalls.add(toolCall.id);
548885
549842
  }
549843
+ if (quickTools.length > 0) {
549844
+ let agentName = "Sub-Agent";
549845
+ for (let j = i + 1; j < sessionMessages.length; j++) {
549846
+ const nextMsg = sessionMessages[j];
549847
+ if (nextMsg && nextMsg.subAgentInternal && nextMsg.role === "tool") {
549848
+ break;
549849
+ }
549850
+ }
549851
+ const toolLines = quickTools.map((tc, index) => {
549852
+ const display = formatToolCallMessage(tc);
549853
+ const isLast = index === quickTools.length - 1;
549854
+ const prefix = isLast ? "\u2514\u2500" : "\u251C\u2500";
549855
+ const params = display.args.map((arg) => `${arg.key}: ${arg.value}`).join(", ");
549856
+ return `
549857
+ \x1B[2m${prefix} ${display.toolName}${params ? ` (${params})` : ""}\x1B[0m`;
549858
+ });
549859
+ uiMessages.push({
549860
+ role: "subagent",
549861
+ content: `\x1B[38;2;184;122;206m\u2687 ${agentName}${toolLines.join("")}\x1B[0m`,
549862
+ streaming: false,
549863
+ subAgentInternal: true,
549864
+ pendingToolIds: quickTools.map((tc) => tc.id)
549865
+ });
549866
+ for (const tc of quickTools) {
549867
+ processedToolCalls.add(tc.id);
549868
+ }
549869
+ }
548886
549870
  continue;
548887
549871
  }
548888
549872
  if (msg.subAgentInternal && msg.role === "tool" && msg.tool_call_id) {
548889
549873
  const isError2 = msg.content.startsWith("Error:");
548890
- const statusIcon = isError2 ? "\u2717" : "\u2713";
548891
- const statusText = isError2 ? `
548892
- \u2514\u2500 ${msg.content}` : "";
548893
549874
  let toolName = "tool";
548894
- let terminalResultData;
549875
+ let isTimeConsumingTool = false;
548895
549876
  for (let j = i - 1; j >= 0; j--) {
548896
549877
  const prevMsg = sessionMessages[j];
548897
549878
  if (!prevMsg)
@@ -548900,36 +549881,90 @@ function convertSessionMessagesToUI(sessionMessages) {
548900
549881
  const tc = prevMsg.tool_calls.find((t) => t.id === msg.tool_call_id);
548901
549882
  if (tc) {
548902
549883
  toolName = tc.function.name;
548903
- if (toolName === "terminal-execute" && !isError2) {
548904
- try {
548905
- const resultData = JSON.parse(msg.content);
548906
- if (resultData.stdout !== void 0 || resultData.stderr !== void 0) {
548907
- terminalResultData = {
548908
- stdout: resultData.stdout,
548909
- stderr: resultData.stderr,
548910
- exitCode: resultData.exitCode,
548911
- command: resultData.command
548912
- };
549884
+ isTimeConsumingTool = isToolNeedTwoStepDisplay(toolName);
549885
+ break;
549886
+ }
549887
+ }
549888
+ }
549889
+ if (isTimeConsumingTool) {
549890
+ const statusIcon = isError2 ? "\u2717" : "\u2713";
549891
+ const statusText = isError2 ? `
549892
+ \u2514\u2500 ${msg.content}` : "";
549893
+ let terminalResultData;
549894
+ if (toolName === "terminal-execute" && !isError2) {
549895
+ try {
549896
+ const resultData = JSON.parse(msg.content);
549897
+ if (resultData.stdout !== void 0 || resultData.stderr !== void 0) {
549898
+ terminalResultData = {
549899
+ stdout: resultData.stdout,
549900
+ stderr: resultData.stderr,
549901
+ exitCode: resultData.exitCode,
549902
+ command: resultData.command
549903
+ };
549904
+ }
549905
+ } catch (e) {
549906
+ }
549907
+ }
549908
+ let fileToolData = void 0;
549909
+ if (!isError2 && (toolName === "filesystem-create" || toolName === "filesystem-edit" || toolName === "filesystem-edit_search")) {
549910
+ try {
549911
+ const resultData = JSON.parse(msg.content);
549912
+ if (resultData.content) {
549913
+ fileToolData = {
549914
+ name: toolName,
549915
+ arguments: {
549916
+ content: resultData.content,
549917
+ path: resultData.path || resultData.filename
548913
549918
  }
548914
- } catch (e) {
548915
- }
549919
+ };
549920
+ } else if (resultData.oldContent && resultData.newContent) {
549921
+ fileToolData = {
549922
+ name: toolName,
549923
+ arguments: {
549924
+ oldContent: resultData.oldContent,
549925
+ newContent: resultData.newContent,
549926
+ filename: resultData.path || resultData.filename,
549927
+ completeOldContent: resultData.completeOldContent,
549928
+ completeNewContent: resultData.completeNewContent,
549929
+ contextStartLine: resultData.contextStartLine
549930
+ }
549931
+ };
549932
+ } else if (resultData.batchResults && Array.isArray(resultData.batchResults)) {
549933
+ fileToolData = {
549934
+ name: toolName,
549935
+ arguments: {
549936
+ isBatch: true,
549937
+ batchResults: resultData.batchResults
549938
+ }
549939
+ };
548916
549940
  }
548917
- break;
549941
+ } catch (e) {
548918
549942
  }
548919
549943
  }
549944
+ uiMessages.push({
549945
+ role: "subagent",
549946
+ content: `\x1B[38;2;0;186;255m\u2687${statusIcon} ${toolName}\x1B[0m${statusText}`,
549947
+ streaming: false,
549948
+ toolResult: !isError2 ? msg.content : void 0,
549949
+ terminalResult: terminalResultData,
549950
+ toolCall: terminalResultData ? {
549951
+ name: toolName,
549952
+ arguments: terminalResultData
549953
+ } : fileToolData ? fileToolData : void 0,
549954
+ subAgentInternal: true
549955
+ });
549956
+ } else {
549957
+ if (isError2) {
549958
+ const statusText = `
549959
+ \u2514\u2500 ${msg.content}`;
549960
+ uiMessages.push({
549961
+ role: "subagent",
549962
+ content: `\x1B[38;2;255;100;100m\u2687\u2717 ${toolName}\x1B[0m${statusText}`,
549963
+ streaming: false,
549964
+ subAgentInternal: true
549965
+ });
549966
+ }
548920
549967
  }
548921
- uiMessages.push({
548922
- role: "subagent",
548923
- content: `\x1B[38;2;0;186;255m\u2687${statusIcon} ${toolName}\x1B[0m${statusText}`,
548924
- streaming: false,
548925
- toolResult: !isError2 ? msg.content : void 0,
548926
- terminalResult: terminalResultData,
548927
- toolCall: terminalResultData ? {
548928
- name: toolName,
548929
- arguments: terminalResultData
548930
- } : void 0,
548931
- subAgentInternal: true
548932
- });
548933
549968
  continue;
548934
549969
  }
548935
549970
  if (msg.role === "assistant" && msg.tool_calls && msg.tool_calls.length > 0 && !msg.subAgentInternal) {
@@ -551359,9 +552394,9 @@ var init_handler = __esm({
551359
552394
  if (this.fsw.closed) {
551360
552395
  return;
551361
552396
  }
551362
- const dirname10 = sysPath.dirname(file);
552397
+ const dirname11 = sysPath.dirname(file);
551363
552398
  const basename6 = sysPath.basename(file);
551364
- const parent = this.fsw._getWatchedDir(dirname10);
552399
+ const parent = this.fsw._getWatchedDir(dirname11);
551365
552400
  let prevStats = stats;
551366
552401
  if (parent.has(basename6))
551367
552402
  return;
@@ -551388,7 +552423,7 @@ var init_handler = __esm({
551388
552423
  prevStats = newStats2;
551389
552424
  }
551390
552425
  } catch (error) {
551391
- this.fsw._remove(dirname10, basename6);
552426
+ this.fsw._remove(dirname11, basename6);
551392
552427
  }
551393
552428
  } else if (parent.has(basename6)) {
551394
552429
  const at = newStats.atimeMs;
@@ -551633,11 +552668,11 @@ function createPattern(matcher2) {
551633
552668
  if (matcher2.path === string)
551634
552669
  return true;
551635
552670
  if (matcher2.recursive) {
551636
- const relative8 = sysPath2.relative(matcher2.path, string);
551637
- if (!relative8) {
552671
+ const relative9 = sysPath2.relative(matcher2.path, string);
552672
+ if (!relative9) {
551638
552673
  return false;
551639
552674
  }
551640
- return !relative8.startsWith("..") && !sysPath2.isAbsolute(relative8);
552675
+ return !relative9.startsWith("..") && !sysPath2.isAbsolute(relative9);
551641
552676
  }
551642
552677
  return false;
551643
552678
  };
@@ -554055,43 +555090,34 @@ function ChatScreen({ autoResume, enableYolo }) {
554055
555090
  await saveCustomCommand(name, command, type, void 0, location, workingDirectory);
554056
555091
  await registerCustomCommands(workingDirectory);
554057
555092
  panelState.setShowCustomCommandConfig(false);
554058
- const typeDesc = type === "execute" ? "Execute in terminal" : "Send to AI";
554059
- const locationDesc = location === "global" ? "Global (~/.snow/commands/)" : "Project (.snow/commands/)";
555093
+ const typeDesc = type === "execute" ? t.customCommand.resultTypeExecute : t.customCommand.resultTypePrompt;
555094
+ const locationDesc = location === "global" ? t.customCommand.resultLocationGlobal : t.customCommand.resultLocationProject;
555095
+ const content = t.customCommand.saveSuccessMessage.replace("{name}", name).replace("{type}", typeDesc).replace("{location}", locationDesc);
554060
555096
  const successMessage = {
554061
555097
  role: "command",
554062
- content: `Custom command '${name}' saved successfully!
554063
- Type: ${typeDesc}
554064
- Location: ${locationDesc}
554065
- You can now use /${name}`,
555098
+ content,
554066
555099
  commandName: "custom"
554067
555100
  };
554068
555101
  setMessages((prev) => [...prev, successMessage]);
554069
- }, onSkillsSave: async (skillName, description, location) => {
554070
- const result2 = await createSkillTemplate(skillName, description, location, workingDirectory);
555102
+ }, onSkillsSave: async (skillName, description, location, generated) => {
555103
+ const result2 = generated ? await createSkillFromGenerated(skillName, description, generated, location, workingDirectory) : await createSkillTemplate(skillName, description, location, workingDirectory);
554071
555104
  panelState.setShowSkillsCreation(false);
554072
555105
  if (result2.success) {
554073
- const locationDesc = location === "global" ? "Global (~/.snow/skills/)" : "Project (.snow/skills/)";
555106
+ const locationDesc = location === "global" ? t.skillsCreation.locationGlobal : t.skillsCreation.locationProject;
555107
+ const modeDesc = generated ? t.skillsCreation.resultModeAi : t.skillsCreation.resultModeManual;
555108
+ const content = t.skillsCreation.createSuccessMessage.replace("{name}", skillName).replace("{mode}", modeDesc).replace("{location}", locationDesc).replace("{path}", result2.path);
554074
555109
  const successMessage = {
554075
555110
  role: "command",
554076
- content: `Skill '${skillName}' created successfully!
554077
- Location: ${locationDesc}
554078
- Path: ${result2.path}
554079
-
554080
- The following files have been created:
554081
- - SKILL.md (main skill documentation)
554082
- - reference.md (detailed reference)
554083
- - examples.md (usage examples)
554084
- - templates/template.txt (template file)
554085
- - scripts/helper.py (helper script)
554086
-
554087
- You can now edit these files to customize your skill.`,
555111
+ content,
554088
555112
  commandName: "skills"
554089
555113
  };
554090
555114
  setMessages((prev) => [...prev, successMessage]);
554091
555115
  } else {
555116
+ const errorText = result2.error || t.skillsCreation.errorUnknown;
555117
+ const content = t.skillsCreation.createErrorMessage.replace("{error}", errorText);
554092
555118
  const errorMessage = {
554093
555119
  role: "command",
554094
- content: `Failed to create skill: ${result2.error}`,
555120
+ content,
554095
555121
  commandName: "skills"
554096
555122
  };
554097
555123
  setMessages((prev) => [...prev, errorMessage]);