snow-ai 0.5.24 → 0.5.26

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]",
@@ -98766,49 +99189,49 @@ var require_fast_uri = __commonJS({
98766
99189
  schemelessOptions.skipEscape = true;
98767
99190
  return serialize(resolved, schemelessOptions);
98768
99191
  }
98769
- function resolveComponent(base, relative8, options3, skipNormalization) {
99192
+ function resolveComponent(base, relative9, options3, skipNormalization) {
98770
99193
  const target = {};
98771
99194
  if (!skipNormalization) {
98772
99195
  base = parse3(serialize(base, options3), options3);
98773
- relative8 = parse3(serialize(relative8, options3), options3);
99196
+ relative9 = parse3(serialize(relative9, options3), options3);
98774
99197
  }
98775
99198
  options3 = options3 || {};
98776
- if (!options3.tolerant && relative8.scheme) {
98777
- target.scheme = relative8.scheme;
98778
- target.userinfo = relative8.userinfo;
98779
- target.host = relative8.host;
98780
- target.port = relative8.port;
98781
- target.path = removeDotSegments(relative8.path || "");
98782
- 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;
98783
99206
  } else {
98784
- if (relative8.userinfo !== void 0 || relative8.host !== void 0 || relative8.port !== void 0) {
98785
- target.userinfo = relative8.userinfo;
98786
- target.host = relative8.host;
98787
- target.port = relative8.port;
98788
- target.path = removeDotSegments(relative8.path || "");
98789
- 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;
98790
99213
  } else {
98791
- if (!relative8.path) {
99214
+ if (!relative9.path) {
98792
99215
  target.path = base.path;
98793
- if (relative8.query !== void 0) {
98794
- target.query = relative8.query;
99216
+ if (relative9.query !== void 0) {
99217
+ target.query = relative9.query;
98795
99218
  } else {
98796
99219
  target.query = base.query;
98797
99220
  }
98798
99221
  } else {
98799
- if (relative8.path[0] === "/") {
98800
- target.path = removeDotSegments(relative8.path);
99222
+ if (relative9.path[0] === "/") {
99223
+ target.path = removeDotSegments(relative9.path);
98801
99224
  } else {
98802
99225
  if ((base.userinfo !== void 0 || base.host !== void 0 || base.port !== void 0) && !base.path) {
98803
- target.path = "/" + relative8.path;
99226
+ target.path = "/" + relative9.path;
98804
99227
  } else if (!base.path) {
98805
- target.path = relative8.path;
99228
+ target.path = relative9.path;
98806
99229
  } else {
98807
- 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;
98808
99231
  }
98809
99232
  target.path = removeDotSegments(target.path);
98810
99233
  }
98811
- target.query = relative8.query;
99234
+ target.query = relative9.query;
98812
99235
  }
98813
99236
  target.userinfo = base.userinfo;
98814
99237
  target.host = base.host;
@@ -98816,7 +99239,7 @@ var require_fast_uri = __commonJS({
98816
99239
  }
98817
99240
  target.scheme = base.scheme;
98818
99241
  }
98819
- target.fragment = relative8.fragment;
99242
+ target.fragment = relative9.fragment;
98820
99243
  return target;
98821
99244
  }
98822
99245
  function equal(uriA, uriB, options3) {
@@ -280486,7 +280909,7 @@ var require_files = __commonJS({
280486
280909
  var fs42 = __require("fs");
280487
280910
  var url = __require("url");
280488
280911
  var os23 = __require("os");
280489
- var dirname10 = __require("path").dirname;
280912
+ var dirname11 = __require("path").dirname;
280490
280913
  var resolvePath = __require("path").resolve;
280491
280914
  var isAbsolutePath = require_path_is_absolute();
280492
280915
  var promises = require_promises();
@@ -280501,7 +280924,7 @@ var require_files = __commonJS({
280501
280924
  }
280502
280925
  };
280503
280926
  }
280504
- var base = options3.relativeToFile ? dirname10(options3.relativeToFile) : null;
280927
+ var base = options3.relativeToFile ? dirname11(options3.relativeToFile) : null;
280505
280928
  function read2(uri, encoding) {
280506
280929
  return resolveUri(uri).then(function(path53) {
280507
280930
  return readFile3(path53, encoding).caught(function(error) {
@@ -288423,8 +288846,8 @@ var require_xlsx = __commonJS({
288423
288846
  }
288424
288847
  return L.length - R.length;
288425
288848
  }
288426
- function dirname10(p) {
288427
- 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));
288428
288851
  var c = p.lastIndexOf("/");
288429
288852
  return c === -1 ? p : p.slice(0, c + 1);
288430
288853
  }
@@ -288845,7 +289268,7 @@ var require_xlsx = __commonJS({
288845
289268
  data.push([cfb.FullPaths[i2], cfb.FileIndex[i2]]);
288846
289269
  }
288847
289270
  for (i2 = 0; i2 < data.length; ++i2) {
288848
- var dad = dirname10(data[i2][0]);
289271
+ var dad = dirname11(data[i2][0]);
288849
289272
  s = fullPaths[dad];
288850
289273
  if (!s) {
288851
289274
  data.push([dad, {
@@ -288881,13 +289304,13 @@ var require_xlsx = __commonJS({
288881
289304
  elt.size = 0;
288882
289305
  elt.type = 5;
288883
289306
  } else if (nm.slice(-1) == "/") {
288884
- 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;
288885
289308
  elt.C = j >= data.length ? -1 : j;
288886
- 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;
288887
289310
  elt.R = j >= data.length ? -1 : j;
288888
289311
  elt.type = 1;
288889
289312
  } else {
288890
- 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;
288891
289314
  elt.type = 2;
288892
289315
  }
288893
289316
  }
@@ -350842,7 +351265,7 @@ ${fileList}`,
350842
351265
  let errorMessage = `\u274C Search content not found in file: ${filePath}
350843
351266
 
350844
351267
  `;
350845
- errorMessage += `\u{1F50D} Using smart fuzzy matching (threshold: 60%)
351268
+ errorMessage += `\u{1F50D} Using smart fuzzy matching (threshold: ${threshold})
350846
351269
  `;
350847
351270
  if (isOverEscaped(searchContent)) {
350848
351271
  errorMessage += `\u26A0\uFE0F Detected over-escaped content, automatic fix attempted but failed
@@ -351388,7 +351811,7 @@ ${formattedDiagnostics}`;
351388
351811
  },
351389
351812
  {
351390
351813
  name: "filesystem-edit_search",
351391
- 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"}]',
351392
351815
  inputSchema: {
351393
351816
  type: "object",
351394
351817
  properties: {
@@ -351458,7 +351881,7 @@ ${formattedDiagnostics}`;
351458
351881
  },
351459
351882
  {
351460
351883
  name: "filesystem-edit",
351461
- 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:"..."}]',
351462
351885
  inputSchema: {
351463
351886
  type: "object",
351464
351887
  properties: {
@@ -403920,7 +404343,7 @@ var require_util12 = __commonJS({
403920
404343
  exports2.isAbsolute = function(aPath) {
403921
404344
  return aPath.charAt(0) === "/" || urlRegexp.test(aPath);
403922
404345
  };
403923
- function relative8(aRoot, aPath) {
404346
+ function relative9(aRoot, aPath) {
403924
404347
  if (aRoot === "") {
403925
404348
  aRoot = ".";
403926
404349
  }
@@ -403939,7 +404362,7 @@ var require_util12 = __commonJS({
403939
404362
  }
403940
404363
  return Array(level + 1).join("../") + aPath.substr(aRoot.length + 1);
403941
404364
  }
403942
- exports2.relative = relative8;
404365
+ exports2.relative = relative9;
403943
404366
  var supportsNullProto = (function() {
403944
404367
  var obj2 = /* @__PURE__ */ Object.create(null);
403945
404368
  return !("__proto__" in obj2);
@@ -429708,6 +430131,16 @@ var init_codebaseSearch = __esm({
429708
430131
  return lastResults;
429709
430132
  } catch (error) {
429710
430133
  logger.error("Codebase search failed:", error);
430134
+ if (enableAgentReview) {
430135
+ codebaseSearchEvents.emitSearchEvent({
430136
+ type: "search-complete",
430137
+ attempt: 0,
430138
+ maxAttempts: MAX_SEARCH_RETRIES,
430139
+ currentTopN: topN,
430140
+ message: `Search failed: ${error instanceof Error ? error.message : "Unknown error"}`,
430141
+ query
430142
+ });
430143
+ }
429711
430144
  throw error;
429712
430145
  }
429713
430146
  }
@@ -435993,7 +436426,7 @@ var require_gray_matter = __commonJS({
435993
436426
  });
435994
436427
 
435995
436428
  // dist/mcp/skills.js
435996
- import { join as join21 } from "path";
436429
+ import { dirname as dirname8, join as join21, relative as relative6 } from "path";
435997
436430
  import { existsSync as existsSync21 } from "fs";
435998
436431
  import { readFile as readFile2 } from "fs/promises";
435999
436432
  import { homedir as homedir14 } from "os";
@@ -436032,64 +436465,75 @@ async function readSkillFile(skillPath) {
436032
436465
  return null;
436033
436466
  }
436034
436467
  }
436035
- async function loadAvailableSkills(projectRoot) {
436036
- const skills = /* @__PURE__ */ new Map();
436037
- const globalSkillsDir = join21(homedir14(), ".snow", "skills");
436038
- const projectSkillsDir = projectRoot ? join21(projectRoot, ".snow", "skills") : null;
436039
- if (existsSync21(globalSkillsDir)) {
436040
- try {
436041
- const { readdirSync: readdirSync3 } = await import("fs");
436042
- const entries = readdirSync3(globalSkillsDir, { withFileTypes: true });
436043
- for (const entry of entries) {
436044
- if (entry.isDirectory()) {
436045
- const skillPath = join21(globalSkillsDir, entry.name);
436046
- const skillData = await readSkillFile(skillPath);
436047
- if (skillData) {
436048
- skills.set(entry.name, {
436049
- name: skillData.metadata.name || entry.name,
436050
- description: skillData.metadata.description || "",
436051
- location: "global",
436052
- path: skillPath,
436053
- content: skillData.content,
436054
- allowedTools: skillData.metadata.allowedTools
436055
- });
436056
- }
436057
- }
436058
- }
436059
- } catch (error) {
436060
- console.error("Failed to load global skills:", error);
436061
- }
436468
+ function normalizeSkillId(skillId) {
436469
+ return skillId.replace(/\\/g, "/").replace(/^\.\/+/, "");
436470
+ }
436471
+ async function loadSkillsFromDirectory(skills, baseSkillsDir, location) {
436472
+ if (!existsSync21(baseSkillsDir)) {
436473
+ return;
436062
436474
  }
436063
- if (projectSkillsDir && existsSync21(projectSkillsDir)) {
436064
- try {
436065
- const { readdirSync: readdirSync3 } = await import("fs");
436066
- const entries = readdirSync3(projectSkillsDir, { withFileTypes: true });
436475
+ try {
436476
+ const { readdirSync: readdirSync3 } = await import("fs");
436477
+ const pendingDirs = [baseSkillsDir];
436478
+ while (pendingDirs.length > 0) {
436479
+ const currentDir = pendingDirs.pop();
436480
+ if (!currentDir)
436481
+ continue;
436482
+ let entries;
436483
+ try {
436484
+ entries = readdirSync3(currentDir, { withFileTypes: true });
436485
+ } catch {
436486
+ continue;
436487
+ }
436067
436488
  for (const entry of entries) {
436068
436489
  if (entry.isDirectory()) {
436069
- const skillPath = join21(projectSkillsDir, entry.name);
436070
- const skillData = await readSkillFile(skillPath);
436071
- if (skillData) {
436072
- skills.set(entry.name, {
436073
- name: skillData.metadata.name || entry.name,
436074
- description: skillData.metadata.description || "",
436075
- location: "project",
436076
- path: skillPath,
436077
- content: skillData.content,
436078
- allowedTools: skillData.metadata.allowedTools
436079
- });
436080
- }
436490
+ pendingDirs.push(join21(currentDir, entry.name));
436491
+ continue;
436081
436492
  }
436493
+ if (!entry.isFile() || entry.name !== "SKILL.md") {
436494
+ continue;
436495
+ }
436496
+ const skillFile = join21(currentDir, entry.name);
436497
+ const skillDir = dirname8(skillFile);
436498
+ const rawSkillId = relative6(baseSkillsDir, skillDir);
436499
+ const skillId = normalizeSkillId(rawSkillId);
436500
+ if (!skillId || skillId === ".") {
436501
+ continue;
436502
+ }
436503
+ const skillData = await readSkillFile(skillDir);
436504
+ if (!skillData) {
436505
+ continue;
436506
+ }
436507
+ const fallbackName = skillId.split("/").filter(Boolean).pop() || skillId;
436508
+ skills.set(skillId, {
436509
+ id: skillId,
436510
+ name: skillData.metadata.name || fallbackName,
436511
+ description: skillData.metadata.description || "",
436512
+ location,
436513
+ path: skillDir,
436514
+ content: skillData.content,
436515
+ allowedTools: skillData.metadata.allowedTools
436516
+ });
436082
436517
  }
436083
- } catch (error) {
436084
- console.error("Failed to load project skills:", error);
436085
436518
  }
436519
+ } catch (error) {
436520
+ console.error(`Failed to load ${location} skills:`, error);
436521
+ }
436522
+ }
436523
+ async function loadAvailableSkills(projectRoot) {
436524
+ const skills = /* @__PURE__ */ new Map();
436525
+ const globalSkillsDir = join21(homedir14(), ".snow", "skills");
436526
+ const projectSkillsDir = projectRoot ? join21(projectRoot, ".snow", "skills") : null;
436527
+ await loadSkillsFromDirectory(skills, globalSkillsDir, "global");
436528
+ if (projectSkillsDir) {
436529
+ await loadSkillsFromDirectory(skills, projectSkillsDir, "project");
436086
436530
  }
436087
436531
  return skills;
436088
436532
  }
436089
436533
  function generateSkillToolDescription(skills) {
436090
436534
  const skillsList = Array.from(skills.values()).map((skill) => `<skill>
436091
436535
  <name>
436092
- ${skill.name}
436536
+ ${skill.id}
436093
436537
  </name>
436094
436538
  <description>
436095
436539
  ${skill.description}
@@ -436104,7 +436548,7 @@ ${skill.location}
436104
436548
  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.
436105
436549
 
436106
436550
  How to use skills:
436107
- - Invoke skills using this tool with the skill name only (no arguments)
436551
+ - Invoke skills using this tool with the skill id only (no arguments)
436108
436552
  - When you invoke a skill, you will see <command-message>The "{name}" skill is loading</command-message>
436109
436553
  - The skill's prompt will expand and provide detailed instructions on how to complete the task
436110
436554
  - Examples:
@@ -436136,7 +436580,7 @@ async function getMCPTools2(projectRoot) {
436136
436580
  properties: {
436137
436581
  skill: {
436138
436582
  type: "string",
436139
- description: 'The skill name (no arguments). E.g., "pdf" or "data-analysis"'
436583
+ description: 'The skill id (no arguments). E.g., "pdf", "data-analysis", or "helloagents/analyze"'
436140
436584
  }
436141
436585
  },
436142
436586
  required: ["skill"],
@@ -436196,15 +436640,16 @@ async function executeSkillTool(toolName, args2, projectRoot) {
436196
436640
  if (toolName !== "skill-execute") {
436197
436641
  throw new Error(`Unknown tool: ${toolName}`);
436198
436642
  }
436199
- const skillName = args2.skill;
436200
- if (!skillName || typeof skillName !== "string") {
436643
+ const requestedSkillId = args2.skill;
436644
+ if (!requestedSkillId || typeof requestedSkillId !== "string") {
436201
436645
  throw new Error("skill parameter is required and must be a string");
436202
436646
  }
436647
+ const skillId = normalizeSkillId(requestedSkillId);
436203
436648
  const skills = await loadAvailableSkills(projectRoot);
436204
- const skill = skills.get(skillName);
436649
+ const skill = skills.get(skillId);
436205
436650
  if (!skill) {
436206
436651
  const availableSkills = Array.from(skills.keys()).join(", ");
436207
- throw new Error(`Skill "${skillName}" not found. Available skills: ${availableSkills || "none"}`);
436652
+ throw new Error(`Skill "${skillId}" not found. Available skills: ${availableSkills || "none"}`);
436208
436653
  }
436209
436654
  const directoryTree = await generateSkillTree(skill.path);
436210
436655
  let toolRestriction = "";
@@ -441549,7 +441994,8 @@ error: ${error || "(empty)"}`);
441549
441994
  } else {
441550
441995
  try {
441551
441996
  const mcpConfig = getMCPConfig();
441552
- for (const configuredServiceName of Object.keys(mcpConfig.mcpServers)) {
441997
+ const serviceNames = Object.keys(mcpConfig.mcpServers).sort((a, b) => b.length - a.length);
441998
+ for (const configuredServiceName of serviceNames) {
441553
441999
  const prefix = `${configuredServiceName}-`;
441554
442000
  if (toolName.startsWith(prefix)) {
441555
442001
  serviceName = configuredServiceName;
@@ -543557,7 +544003,7 @@ function LoadingIndicator({ isStreaming, isStopping, isSaving, hasPendingToolCon
543557
544003
  retryStatus.attempt,
543558
544004
  "/5)"
543559
544005
  )
543560
- ) : (codebaseSearchStatus == null ? void 0 : codebaseSearchStatus.isSearching) ? import_react113.default.createElement(CodebaseSearchStatus, { status: codebaseSearchStatus }) : codebaseSearchStatus && !codebaseSearchStatus.isSearching && codebaseSearchStatus.reviewResults ? import_react113.default.createElement(CodebaseSearchStatus, { status: codebaseSearchStatus }) : import_react113.default.createElement(
544006
+ ) : (codebaseSearchStatus == null ? void 0 : codebaseSearchStatus.isSearching) ? import_react113.default.createElement(CodebaseSearchStatus, { status: codebaseSearchStatus }) : codebaseSearchStatus && !codebaseSearchStatus.isSearching ? import_react113.default.createElement(CodebaseSearchStatus, { status: codebaseSearchStatus }) : import_react113.default.createElement(
543561
544007
  Text,
543562
544008
  { color: theme14.colors.menuSecondary, dimColor: true },
543563
544009
  import_react113.default.createElement(ShimmerText, { text: isReasoning ? t.chatScreen.statusDeepThinking : streamTokenCount > 0 ? t.chatScreen.statusWriting : t.chatScreen.statusThinking }),
@@ -543962,6 +544408,7 @@ var init_SkillsCreationPanel = __esm({
543962
544408
  "use strict";
543963
544409
  import_react115 = __toESM(require_react(), 1);
543964
544410
  await init_build2();
544411
+ await init_build3();
543965
544412
  await init_build4();
543966
544413
  init_ThemeContext();
543967
544414
  init_I18nContext();
@@ -543969,16 +544416,145 @@ var init_SkillsCreationPanel = __esm({
543969
544416
  SkillsCreationPanel = ({ onSave, onCancel, projectRoot }) => {
543970
544417
  const { theme: theme14 } = useTheme();
543971
544418
  const { t } = useI18n();
543972
- const [step, setStep] = (0, import_react115.useState)("name");
544419
+ const [step, setStep] = (0, import_react115.useState)("mode");
544420
+ const [mode, setMode] = (0, import_react115.useState)("manual");
543973
544421
  const [skillName, setSkillName] = (0, import_react115.useState)("");
543974
544422
  const [description, setDescription] = (0, import_react115.useState)("");
543975
544423
  const [location, setLocation] = (0, import_react115.useState)("global");
544424
+ const [requirement, setRequirement] = (0, import_react115.useState)("");
544425
+ const [generated, setGenerated] = (0, import_react115.useState)();
543976
544426
  const [errorMessage, setErrorMessage] = (0, import_react115.useState)("");
544427
+ const abortControllerRef = (0, import_react115.useRef)(null);
544428
+ const handleCancel = (0, import_react115.useCallback)(() => {
544429
+ var _a21;
544430
+ try {
544431
+ (_a21 = abortControllerRef.current) == null ? void 0 : _a21.abort();
544432
+ } catch {
544433
+ }
544434
+ onCancel();
544435
+ }, [onCancel]);
544436
+ const handleNameSubmit = (0, import_react115.useCallback)((value) => {
544437
+ if (!value.trim()) {
544438
+ return;
544439
+ }
544440
+ const trimmedName = value.trim();
544441
+ const validation = validateSkillId(trimmedName);
544442
+ if (!validation.valid) {
544443
+ setErrorMessage(validation.error || t.skillsCreation.errorInvalidName);
544444
+ return;
544445
+ }
544446
+ const existsGlobal = checkSkillExists(trimmedName, "global");
544447
+ const existsProject = checkSkillExists(trimmedName, "project", projectRoot);
544448
+ if (existsGlobal && existsProject) {
544449
+ setErrorMessage(t.skillsCreation.errorExistsBoth.replace("{name}", trimmedName));
544450
+ return;
544451
+ }
544452
+ if (existsGlobal) {
544453
+ setErrorMessage(t.skillsCreation.errorExistsGlobal.replace("{name}", trimmedName));
544454
+ return;
544455
+ }
544456
+ if (existsProject) {
544457
+ setErrorMessage(t.skillsCreation.errorExistsProject.replace("{name}", trimmedName));
544458
+ return;
544459
+ }
544460
+ setErrorMessage("");
544461
+ setSkillName(trimmedName);
544462
+ setStep("description");
544463
+ }, [projectRoot, t.skillsCreation]);
544464
+ const handleDescriptionSubmit = (0, import_react115.useCallback)((value) => {
544465
+ if (value.trim()) {
544466
+ setDescription(value.trim());
544467
+ setStep("location");
544468
+ }
544469
+ }, []);
544470
+ const handleRequirementSubmit = (0, import_react115.useCallback)((value) => {
544471
+ if (value.trim()) {
544472
+ setRequirement(value.trim());
544473
+ setErrorMessage("");
544474
+ setStep("ai-location");
544475
+ }
544476
+ }, []);
544477
+ const handleConfirmManual = (0, import_react115.useCallback)(async () => {
544478
+ await onSave(skillName, description, location);
544479
+ }, [skillName, description, location, onSave]);
544480
+ const handleConfirmAI = (0, import_react115.useCallback)(async () => {
544481
+ if (!generated) {
544482
+ setErrorMessage(t.skillsCreation.errorNoGeneratedContent);
544483
+ return;
544484
+ }
544485
+ await onSave(skillName, description, location, generated);
544486
+ }, [generated, skillName, description, location, onSave, t.skillsCreation]);
544487
+ const handleEditNameSubmit = (0, import_react115.useCallback)((value) => {
544488
+ if (!value.trim()) {
544489
+ return;
544490
+ }
544491
+ const trimmedName = value.trim();
544492
+ const validation = validateSkillId(trimmedName);
544493
+ if (!validation.valid) {
544494
+ setErrorMessage(validation.error || t.skillsCreation.errorInvalidName);
544495
+ return;
544496
+ }
544497
+ const existsGlobal = checkSkillExists(trimmedName, "global");
544498
+ const existsProject = checkSkillExists(trimmedName, "project", projectRoot);
544499
+ if (existsGlobal || existsProject) {
544500
+ setErrorMessage(t.skillsCreation.errorExistsAny.replace("{name}", trimmedName));
544501
+ return;
544502
+ }
544503
+ setErrorMessage("");
544504
+ setSkillName(trimmedName);
544505
+ setStep("ai-preview");
544506
+ }, [projectRoot, t.skillsCreation]);
544507
+ (0, import_react115.useEffect)(() => {
544508
+ if (step !== "ai-generating") {
544509
+ return;
544510
+ }
544511
+ const controller = new AbortController();
544512
+ abortControllerRef.current = controller;
544513
+ setErrorMessage("");
544514
+ setGenerated(void 0);
544515
+ generateSkillDraftWithAI(requirement, projectRoot, controller.signal).then((draft) => {
544516
+ setSkillName(draft.skillName);
544517
+ setDescription(draft.description);
544518
+ setGenerated(draft.generated);
544519
+ setStep("ai-preview");
544520
+ }).catch((error) => {
544521
+ if (controller.signal.aborted) {
544522
+ return;
544523
+ }
544524
+ const message = error instanceof Error ? error.message : t.skillsCreation.errorGeneration;
544525
+ setErrorMessage(message);
544526
+ setStep("ai-error");
544527
+ }).finally(() => {
544528
+ abortControllerRef.current = null;
544529
+ });
544530
+ return () => {
544531
+ try {
544532
+ controller.abort();
544533
+ } catch {
544534
+ }
544535
+ };
544536
+ }, [step, requirement, projectRoot, t.skillsCreation.errorGeneration]);
544537
+ const keyHandlingActive = step === "mode" || step === "location" || step === "confirm" || step === "ai-location" || step === "ai-generating" || step === "ai-preview" || step === "ai-error";
543977
544538
  use_input_default((input2, key) => {
543978
544539
  if (key.escape) {
543979
544540
  handleCancel();
543980
544541
  return;
543981
544542
  }
544543
+ if (step === "mode") {
544544
+ if (input2.toLowerCase() === "m") {
544545
+ setMode("manual");
544546
+ setErrorMessage("");
544547
+ setStep("name");
544548
+ } else if (input2.toLowerCase() === "a") {
544549
+ setMode("ai");
544550
+ setErrorMessage("");
544551
+ setSkillName("");
544552
+ setDescription("");
544553
+ setGenerated(void 0);
544554
+ setStep("ai-requirement");
544555
+ }
544556
+ return;
544557
+ }
543982
544558
  if (step === "location") {
543983
544559
  if (input2.toLowerCase() === "g") {
543984
544560
  setLocation("global");
@@ -543987,51 +544563,45 @@ var init_SkillsCreationPanel = __esm({
543987
544563
  setLocation("project");
543988
544564
  setStep("confirm");
543989
544565
  }
543990
- } else if (step === "confirm") {
544566
+ return;
544567
+ }
544568
+ if (step === "confirm") {
543991
544569
  if (input2.toLowerCase() === "y") {
543992
- handleConfirm();
544570
+ handleConfirmManual();
543993
544571
  } else if (input2.toLowerCase() === "n") {
543994
544572
  handleCancel();
543995
544573
  }
544574
+ return;
543996
544575
  }
543997
- }, { isActive: step === "location" || step === "confirm" });
543998
- const handleNameSubmit = (0, import_react115.useCallback)((value) => {
543999
- if (value.trim()) {
544000
- const trimmedName = value.trim();
544001
- const validation = validateSkillName(trimmedName);
544002
- if (!validation.valid) {
544003
- setErrorMessage(validation.error || t.skillsCreation.errorInvalidName);
544004
- return;
544576
+ if (step === "ai-location") {
544577
+ if (input2.toLowerCase() === "g") {
544578
+ setLocation("global");
544579
+ setStep("ai-generating");
544580
+ } else if (input2.toLowerCase() === "p") {
544581
+ setLocation("project");
544582
+ setStep("ai-generating");
544005
544583
  }
544006
- const existsGlobal = checkSkillExists(trimmedName, "global");
544007
- const existsProject = checkSkillExists(trimmedName, "project", projectRoot);
544008
- if (existsGlobal && existsProject) {
544009
- setErrorMessage(t.skillsCreation.errorExistsBoth.replace("{name}", trimmedName));
544010
- return;
544011
- } else if (existsGlobal) {
544012
- setErrorMessage(t.skillsCreation.errorExistsGlobal.replace("{name}", trimmedName));
544013
- return;
544014
- } else if (existsProject) {
544015
- setErrorMessage(t.skillsCreation.errorExistsProject.replace("{name}", trimmedName));
544016
- return;
544584
+ return;
544585
+ }
544586
+ if (step === "ai-preview") {
544587
+ if (input2.toLowerCase() === "y") {
544588
+ handleConfirmAI();
544589
+ } else if (input2.toLowerCase() === "e") {
544590
+ setErrorMessage("");
544591
+ setStep("ai-edit-name");
544592
+ } else if (input2.toLowerCase() === "r") {
544593
+ setErrorMessage("");
544594
+ setStep("ai-generating");
544017
544595
  }
544018
- setErrorMessage("");
544019
- setSkillName(trimmedName);
544020
- setStep("description");
544596
+ return;
544021
544597
  }
544022
- }, [projectRoot, t.skillsCreation]);
544023
- const handleDescriptionSubmit = (0, import_react115.useCallback)((value) => {
544024
- if (value.trim()) {
544025
- setDescription(value.trim());
544026
- setStep("location");
544598
+ if (step === "ai-error") {
544599
+ if (input2.toLowerCase() === "r") {
544600
+ setErrorMessage("");
544601
+ setStep("ai-generating");
544602
+ }
544027
544603
  }
544028
- }, []);
544029
- const handleConfirm = (0, import_react115.useCallback)(async () => {
544030
- await onSave(skillName, description, location);
544031
- }, [skillName, description, location, onSave]);
544032
- const handleCancel = (0, import_react115.useCallback)(() => {
544033
- onCancel();
544034
- }, [onCancel]);
544604
+ }, { isActive: keyHandlingActive });
544035
544605
  return import_react115.default.createElement(
544036
544606
  Box_default,
544037
544607
  { flexDirection: "column", padding: 1, borderStyle: "round", borderColor: theme14.colors.border },
@@ -544040,7 +544610,47 @@ var init_SkillsCreationPanel = __esm({
544040
544610
  { marginBottom: 1 },
544041
544611
  import_react115.default.createElement(Text, { bold: true, color: theme14.colors.menuSelected }, t.skillsCreation.title)
544042
544612
  ),
544043
- step === "name" && import_react115.default.createElement(
544613
+ step === "mode" && import_react115.default.createElement(
544614
+ Box_default,
544615
+ { flexDirection: "column" },
544616
+ import_react115.default.createElement(
544617
+ Box_default,
544618
+ { marginBottom: 1 },
544619
+ import_react115.default.createElement(Text, { color: theme14.colors.text }, t.skillsCreation.modeLabel)
544620
+ ),
544621
+ import_react115.default.createElement(
544622
+ Box_default,
544623
+ { gap: 2 },
544624
+ import_react115.default.createElement(
544625
+ Box_default,
544626
+ null,
544627
+ import_react115.default.createElement(Text, { color: theme14.colors.success, bold: true }, "[A]"),
544628
+ import_react115.default.createElement(
544629
+ Text,
544630
+ { color: theme14.colors.text },
544631
+ " ",
544632
+ t.skillsCreation.modeAi
544633
+ )
544634
+ ),
544635
+ import_react115.default.createElement(
544636
+ Box_default,
544637
+ null,
544638
+ import_react115.default.createElement(Text, { color: theme14.colors.menuSelected, bold: true }, "[M]"),
544639
+ import_react115.default.createElement(
544640
+ Text,
544641
+ { color: theme14.colors.text },
544642
+ " ",
544643
+ t.skillsCreation.modeManual
544644
+ )
544645
+ )
544646
+ ),
544647
+ import_react115.default.createElement(
544648
+ Box_default,
544649
+ { marginTop: 1 },
544650
+ import_react115.default.createElement(Text, { dimColor: true }, t.skillsCreation.escCancel)
544651
+ )
544652
+ ),
544653
+ mode === "manual" && step === "name" && import_react115.default.createElement(
544044
544654
  Box_default,
544045
544655
  { flexDirection: "column" },
544046
544656
  import_react115.default.createElement(
@@ -544065,7 +544675,7 @@ var init_SkillsCreationPanel = __esm({
544065
544675
  import_react115.default.createElement(Text, { dimColor: true }, t.skillsCreation.escCancel)
544066
544676
  )
544067
544677
  ),
544068
- step === "description" && import_react115.default.createElement(
544678
+ mode === "manual" && step === "description" && import_react115.default.createElement(
544069
544679
  Box_default,
544070
544680
  { flexDirection: "column" },
544071
544681
  import_react115.default.createElement(
@@ -544096,7 +544706,293 @@ var init_SkillsCreationPanel = __esm({
544096
544706
  import_react115.default.createElement(Text, { dimColor: true }, t.skillsCreation.escCancel)
544097
544707
  )
544098
544708
  ),
544099
- step === "location" && import_react115.default.createElement(
544709
+ mode === "manual" && step === "location" && import_react115.default.createElement(
544710
+ Box_default,
544711
+ { flexDirection: "column" },
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.nameLabel,
544719
+ " ",
544720
+ import_react115.default.createElement(Text, { bold: true, color: theme14.colors.success }, skillName)
544721
+ )
544722
+ ),
544723
+ import_react115.default.createElement(
544724
+ Box_default,
544725
+ { marginBottom: 1 },
544726
+ import_react115.default.createElement(
544727
+ Text,
544728
+ { color: theme14.colors.text },
544729
+ t.skillsCreation.descriptionLabel,
544730
+ " ",
544731
+ import_react115.default.createElement(Text, { color: theme14.colors.menuNormal }, description)
544732
+ )
544733
+ ),
544734
+ import_react115.default.createElement(
544735
+ Box_default,
544736
+ { marginBottom: 1, marginTop: 1 },
544737
+ import_react115.default.createElement(Text, { color: theme14.colors.text }, t.skillsCreation.locationLabel)
544738
+ ),
544739
+ import_react115.default.createElement(
544740
+ Box_default,
544741
+ { marginTop: 1, flexDirection: "column", gap: 1 },
544742
+ import_react115.default.createElement(
544743
+ Box_default,
544744
+ null,
544745
+ import_react115.default.createElement(Text, { color: theme14.colors.success, bold: true }, "[G]"),
544746
+ import_react115.default.createElement(
544747
+ Text,
544748
+ { color: theme14.colors.text },
544749
+ " ",
544750
+ t.skillsCreation.locationGlobal
544751
+ )
544752
+ ),
544753
+ import_react115.default.createElement(
544754
+ Box_default,
544755
+ { marginLeft: 4 },
544756
+ import_react115.default.createElement(Text, { dimColor: true }, t.skillsCreation.locationGlobalInfo)
544757
+ ),
544758
+ import_react115.default.createElement(
544759
+ Box_default,
544760
+ { marginTop: 1 },
544761
+ import_react115.default.createElement(Text, { color: theme14.colors.menuSelected, bold: true }, "[P]"),
544762
+ import_react115.default.createElement(
544763
+ Text,
544764
+ { color: theme14.colors.text },
544765
+ " ",
544766
+ t.skillsCreation.locationProject
544767
+ )
544768
+ ),
544769
+ import_react115.default.createElement(
544770
+ Box_default,
544771
+ { marginLeft: 4 },
544772
+ import_react115.default.createElement(Text, { dimColor: true }, t.skillsCreation.locationProjectInfo)
544773
+ )
544774
+ ),
544775
+ import_react115.default.createElement(
544776
+ Box_default,
544777
+ { marginTop: 1 },
544778
+ import_react115.default.createElement(Text, { dimColor: true }, t.skillsCreation.escCancel)
544779
+ )
544780
+ ),
544781
+ mode === "manual" && step === "confirm" && import_react115.default.createElement(
544782
+ Box_default,
544783
+ { flexDirection: "column" },
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.nameLabel,
544791
+ " ",
544792
+ import_react115.default.createElement(Text, { bold: true, color: theme14.colors.success }, skillName)
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.descriptionLabel,
544802
+ " ",
544803
+ import_react115.default.createElement(Text, { color: theme14.colors.menuNormal }, description)
544804
+ )
544805
+ ),
544806
+ import_react115.default.createElement(
544807
+ Box_default,
544808
+ { marginBottom: 1 },
544809
+ import_react115.default.createElement(
544810
+ Text,
544811
+ { color: theme14.colors.text },
544812
+ t.skillsCreation.locationLabel,
544813
+ " ",
544814
+ import_react115.default.createElement(Text, { bold: true, color: theme14.colors.menuSelected }, location === "global" ? t.skillsCreation.locationGlobal : t.skillsCreation.locationProject)
544815
+ )
544816
+ ),
544817
+ import_react115.default.createElement(
544818
+ Box_default,
544819
+ { marginTop: 1 },
544820
+ import_react115.default.createElement(Text, { color: theme14.colors.text }, t.skillsCreation.confirmQuestion)
544821
+ ),
544822
+ import_react115.default.createElement(
544823
+ Box_default,
544824
+ { marginTop: 1, gap: 2 },
544825
+ import_react115.default.createElement(
544826
+ Box_default,
544827
+ null,
544828
+ import_react115.default.createElement(Text, { color: theme14.colors.success, bold: true }, "[Y]"),
544829
+ import_react115.default.createElement(
544830
+ Text,
544831
+ { color: theme14.colors.text },
544832
+ " ",
544833
+ t.skillsCreation.confirmYes
544834
+ )
544835
+ ),
544836
+ import_react115.default.createElement(
544837
+ Box_default,
544838
+ null,
544839
+ import_react115.default.createElement(Text, { color: theme14.colors.error, bold: true }, "[N]"),
544840
+ import_react115.default.createElement(
544841
+ Text,
544842
+ { color: theme14.colors.text },
544843
+ " ",
544844
+ t.skillsCreation.confirmNo
544845
+ )
544846
+ )
544847
+ )
544848
+ ),
544849
+ mode === "ai" && step === "ai-requirement" && import_react115.default.createElement(
544850
+ Box_default,
544851
+ { flexDirection: "column" },
544852
+ import_react115.default.createElement(
544853
+ Box_default,
544854
+ { marginBottom: 1 },
544855
+ import_react115.default.createElement(Text, { color: theme14.colors.text }, t.skillsCreation.requirementLabel)
544856
+ ),
544857
+ import_react115.default.createElement(
544858
+ Box_default,
544859
+ { marginBottom: 1 },
544860
+ import_react115.default.createElement(Text, { dimColor: true }, t.skillsCreation.requirementHint)
544861
+ ),
544862
+ import_react115.default.createElement(TextInput, { placeholder: t.skillsCreation.requirementPlaceholder, onSubmit: handleRequirementSubmit }),
544863
+ import_react115.default.createElement(
544864
+ Box_default,
544865
+ { marginTop: 1 },
544866
+ import_react115.default.createElement(Text, { dimColor: true }, t.skillsCreation.escCancel)
544867
+ )
544868
+ ),
544869
+ mode === "ai" && step === "ai-location" && import_react115.default.createElement(
544870
+ Box_default,
544871
+ { flexDirection: "column" },
544872
+ import_react115.default.createElement(
544873
+ Box_default,
544874
+ { marginBottom: 1 },
544875
+ import_react115.default.createElement(
544876
+ Text,
544877
+ { color: theme14.colors.text },
544878
+ t.skillsCreation.requirementLabel,
544879
+ " ",
544880
+ import_react115.default.createElement(Text, { color: theme14.colors.menuNormal }, requirement)
544881
+ )
544882
+ ),
544883
+ import_react115.default.createElement(
544884
+ Box_default,
544885
+ { marginBottom: 1, marginTop: 1 },
544886
+ import_react115.default.createElement(Text, { color: theme14.colors.text }, t.skillsCreation.locationLabel)
544887
+ ),
544888
+ import_react115.default.createElement(
544889
+ Box_default,
544890
+ { marginTop: 1, flexDirection: "column", gap: 1 },
544891
+ import_react115.default.createElement(
544892
+ Box_default,
544893
+ null,
544894
+ import_react115.default.createElement(Text, { color: theme14.colors.success, bold: true }, "[G]"),
544895
+ import_react115.default.createElement(
544896
+ Text,
544897
+ { color: theme14.colors.text },
544898
+ " ",
544899
+ t.skillsCreation.locationGlobal
544900
+ )
544901
+ ),
544902
+ import_react115.default.createElement(
544903
+ Box_default,
544904
+ { marginLeft: 4 },
544905
+ import_react115.default.createElement(Text, { dimColor: true }, t.skillsCreation.locationGlobalInfo)
544906
+ ),
544907
+ import_react115.default.createElement(
544908
+ Box_default,
544909
+ { marginTop: 1 },
544910
+ import_react115.default.createElement(Text, { color: theme14.colors.menuSelected, bold: true }, "[P]"),
544911
+ import_react115.default.createElement(
544912
+ Text,
544913
+ { color: theme14.colors.text },
544914
+ " ",
544915
+ t.skillsCreation.locationProject
544916
+ )
544917
+ ),
544918
+ import_react115.default.createElement(
544919
+ Box_default,
544920
+ { marginLeft: 4 },
544921
+ import_react115.default.createElement(Text, { dimColor: true }, t.skillsCreation.locationProjectInfo)
544922
+ )
544923
+ ),
544924
+ import_react115.default.createElement(
544925
+ Box_default,
544926
+ { marginTop: 1 },
544927
+ import_react115.default.createElement(Text, { dimColor: true }, t.skillsCreation.escCancel)
544928
+ )
544929
+ ),
544930
+ mode === "ai" && step === "ai-generating" && import_react115.default.createElement(
544931
+ Box_default,
544932
+ { flexDirection: "column" },
544933
+ import_react115.default.createElement(
544934
+ Box_default,
544935
+ { marginBottom: 1 },
544936
+ import_react115.default.createElement(Text, { color: theme14.colors.text }, t.skillsCreation.generatingLabel)
544937
+ ),
544938
+ import_react115.default.createElement(
544939
+ Box_default,
544940
+ null,
544941
+ import_react115.default.createElement(
544942
+ Text,
544943
+ { color: theme14.colors.menuNormal },
544944
+ import_react115.default.createElement(build_default, { type: "dots" }),
544945
+ " ",
544946
+ t.skillsCreation.generatingMessage
544947
+ )
544948
+ ),
544949
+ import_react115.default.createElement(
544950
+ Box_default,
544951
+ { marginTop: 1 },
544952
+ import_react115.default.createElement(Text, { dimColor: true }, t.skillsCreation.escCancel)
544953
+ )
544954
+ ),
544955
+ mode === "ai" && step === "ai-error" && import_react115.default.createElement(
544956
+ Box_default,
544957
+ { flexDirection: "column" },
544958
+ import_react115.default.createElement(
544959
+ Box_default,
544960
+ { marginBottom: 1 },
544961
+ import_react115.default.createElement(Text, { color: theme14.colors.error }, t.skillsCreation.errorGeneration)
544962
+ ),
544963
+ errorMessage && import_react115.default.createElement(
544964
+ Box_default,
544965
+ { marginBottom: 1 },
544966
+ import_react115.default.createElement(Text, { color: theme14.colors.error }, errorMessage)
544967
+ ),
544968
+ import_react115.default.createElement(
544969
+ Box_default,
544970
+ { marginTop: 1, gap: 2 },
544971
+ import_react115.default.createElement(
544972
+ Box_default,
544973
+ null,
544974
+ import_react115.default.createElement(Text, { color: theme14.colors.menuSelected, bold: true }, "[R]"),
544975
+ import_react115.default.createElement(
544976
+ Text,
544977
+ { color: theme14.colors.text },
544978
+ " ",
544979
+ t.skillsCreation.regenerate
544980
+ )
544981
+ ),
544982
+ import_react115.default.createElement(
544983
+ Box_default,
544984
+ null,
544985
+ import_react115.default.createElement(Text, { color: theme14.colors.menuSecondary, dimColor: true }, "[ESC]"),
544986
+ import_react115.default.createElement(
544987
+ Text,
544988
+ { color: theme14.colors.text },
544989
+ " ",
544990
+ t.skillsCreation.cancel
544991
+ )
544992
+ )
544993
+ )
544994
+ ),
544995
+ mode === "ai" && step === "ai-preview" && import_react115.default.createElement(
544100
544996
  Box_default,
544101
544997
  { flexDirection: "column" },
544102
544998
  import_react115.default.createElement(
@@ -544123,43 +545019,74 @@ var init_SkillsCreationPanel = __esm({
544123
545019
  ),
544124
545020
  import_react115.default.createElement(
544125
545021
  Box_default,
544126
- { marginBottom: 1, marginTop: 1 },
544127
- import_react115.default.createElement(Text, { color: theme14.colors.text }, t.skillsCreation.locationLabel)
545022
+ { marginBottom: 1 },
545023
+ import_react115.default.createElement(
545024
+ Text,
545025
+ { color: theme14.colors.text },
545026
+ t.skillsCreation.locationLabel,
545027
+ " ",
545028
+ import_react115.default.createElement(Text, { bold: true, color: theme14.colors.menuSelected }, location === "global" ? t.skillsCreation.locationGlobal : t.skillsCreation.locationProject)
545029
+ )
544128
545030
  ),
544129
545031
  import_react115.default.createElement(
544130
545032
  Box_default,
544131
- { marginTop: 1, flexDirection: "column", gap: 1 },
545033
+ { marginTop: 1, flexDirection: "column" },
545034
+ import_react115.default.createElement(Text, { color: theme14.colors.text }, t.skillsCreation.filesLabel),
545035
+ import_react115.default.createElement(
545036
+ Box_default,
545037
+ { marginLeft: 2, flexDirection: "column" },
545038
+ import_react115.default.createElement(Text, { dimColor: true }, "- SKILL.md"),
545039
+ import_react115.default.createElement(Text, { dimColor: true }, "- reference.md"),
545040
+ import_react115.default.createElement(Text, { dimColor: true }, "- examples.md"),
545041
+ import_react115.default.createElement(Text, { dimColor: true }, "- templates/template.txt"),
545042
+ import_react115.default.createElement(Text, { dimColor: true }, "- scripts/helper.py")
545043
+ )
545044
+ ),
545045
+ errorMessage && import_react115.default.createElement(
545046
+ Box_default,
545047
+ { marginTop: 1 },
545048
+ import_react115.default.createElement(Text, { color: theme14.colors.error }, errorMessage)
545049
+ ),
545050
+ import_react115.default.createElement(
545051
+ Box_default,
545052
+ { marginTop: 1 },
545053
+ import_react115.default.createElement(Text, { color: theme14.colors.text }, t.skillsCreation.confirmQuestion)
545054
+ ),
545055
+ import_react115.default.createElement(
545056
+ Box_default,
545057
+ { marginTop: 1, gap: 2 },
544132
545058
  import_react115.default.createElement(
544133
545059
  Box_default,
544134
545060
  null,
544135
- import_react115.default.createElement(Text, { color: theme14.colors.success, bold: true }, "[G]"),
545061
+ import_react115.default.createElement(Text, { color: theme14.colors.success, bold: true }, "[Y]"),
544136
545062
  import_react115.default.createElement(
544137
545063
  Text,
544138
545064
  { color: theme14.colors.text },
544139
545065
  " ",
544140
- t.skillsCreation.locationGlobal
545066
+ t.skillsCreation.confirmYes
544141
545067
  )
544142
545068
  ),
544143
545069
  import_react115.default.createElement(
544144
545070
  Box_default,
544145
- { marginLeft: 4 },
544146
- import_react115.default.createElement(Text, { dimColor: true }, t.skillsCreation.locationGlobalInfo)
544147
- ),
544148
- import_react115.default.createElement(
544149
- Box_default,
544150
- { marginTop: 1 },
544151
- import_react115.default.createElement(Text, { color: theme14.colors.menuSelected, bold: true }, "[P]"),
545071
+ null,
545072
+ import_react115.default.createElement(Text, { color: theme14.colors.menuSelected, bold: true }, "[E]"),
544152
545073
  import_react115.default.createElement(
544153
545074
  Text,
544154
545075
  { color: theme14.colors.text },
544155
545076
  " ",
544156
- t.skillsCreation.locationProject
545077
+ t.skillsCreation.editName
544157
545078
  )
544158
545079
  ),
544159
545080
  import_react115.default.createElement(
544160
545081
  Box_default,
544161
- { marginLeft: 4 },
544162
- import_react115.default.createElement(Text, { dimColor: true }, t.skillsCreation.locationProjectInfo)
545082
+ null,
545083
+ import_react115.default.createElement(Text, { color: theme14.colors.warning, bold: true }, "[R]"),
545084
+ import_react115.default.createElement(
545085
+ Text,
545086
+ { color: theme14.colors.text },
545087
+ " ",
545088
+ t.skillsCreation.regenerate
545089
+ )
544163
545090
  )
544164
545091
  ),
544165
545092
  import_react115.default.createElement(
@@ -544168,7 +545095,7 @@ var init_SkillsCreationPanel = __esm({
544168
545095
  import_react115.default.createElement(Text, { dimColor: true }, t.skillsCreation.escCancel)
544169
545096
  )
544170
545097
  ),
544171
- step === "confirm" && import_react115.default.createElement(
545098
+ mode === "ai" && step === "ai-edit-name" && import_react115.default.createElement(
544172
545099
  Box_default,
544173
545100
  { flexDirection: "column" },
544174
545101
  import_react115.default.createElement(
@@ -544177,63 +545104,26 @@ var init_SkillsCreationPanel = __esm({
544177
545104
  import_react115.default.createElement(
544178
545105
  Text,
544179
545106
  { color: theme14.colors.text },
544180
- t.skillsCreation.nameLabel,
545107
+ t.skillsCreation.editNameLabel,
544181
545108
  " ",
544182
- import_react115.default.createElement(Text, { bold: true, color: theme14.colors.success }, skillName)
545109
+ import_react115.default.createElement(Text, { color: theme14.colors.menuNormal }, skillName)
544183
545110
  )
544184
545111
  ),
544185
545112
  import_react115.default.createElement(
544186
545113
  Box_default,
544187
545114
  { marginBottom: 1 },
544188
- import_react115.default.createElement(
544189
- Text,
544190
- { color: theme14.colors.text },
544191
- t.skillsCreation.descriptionLabel,
544192
- " ",
544193
- import_react115.default.createElement(Text, { color: theme14.colors.menuNormal }, description)
544194
- )
545115
+ import_react115.default.createElement(Text, { dimColor: true }, t.skillsCreation.editNameHint)
544195
545116
  ),
544196
- import_react115.default.createElement(
544197
- Box_default,
544198
- { marginBottom: 1 },
544199
- import_react115.default.createElement(
544200
- Text,
544201
- { color: theme14.colors.text },
544202
- t.skillsCreation.locationLabel,
544203
- " ",
544204
- import_react115.default.createElement(Text, { bold: true, color: theme14.colors.menuSelected }, location === "global" ? t.skillsCreation.locationGlobal : t.skillsCreation.locationProject)
544205
- )
544206
- ),
544207
- import_react115.default.createElement(
545117
+ import_react115.default.createElement(TextInput, { placeholder: t.skillsCreation.editNamePlaceholder, onSubmit: handleEditNameSubmit }),
545118
+ errorMessage && import_react115.default.createElement(
544208
545119
  Box_default,
544209
545120
  { marginTop: 1 },
544210
- import_react115.default.createElement(Text, { color: theme14.colors.text }, t.skillsCreation.confirmQuestion)
545121
+ import_react115.default.createElement(Text, { color: theme14.colors.error }, errorMessage)
544211
545122
  ),
544212
545123
  import_react115.default.createElement(
544213
545124
  Box_default,
544214
- { marginTop: 1, gap: 2 },
544215
- import_react115.default.createElement(
544216
- Box_default,
544217
- null,
544218
- import_react115.default.createElement(Text, { color: theme14.colors.success, bold: true }, "[Y]"),
544219
- import_react115.default.createElement(
544220
- Text,
544221
- { color: theme14.colors.text },
544222
- " ",
544223
- t.skillsCreation.confirmYes
544224
- )
544225
- ),
544226
- import_react115.default.createElement(
544227
- Box_default,
544228
- null,
544229
- import_react115.default.createElement(Text, { color: theme14.colors.error, bold: true }, "[N]"),
544230
- import_react115.default.createElement(
544231
- Text,
544232
- { color: theme14.colors.text },
544233
- " ",
544234
- t.skillsCreation.confirmNo
544235
- )
544236
- )
545125
+ { marginTop: 1 },
545126
+ import_react115.default.createElement(Text, { dimColor: true }, t.skillsCreation.escCancel)
544237
545127
  )
544238
545128
  )
544239
545129
  );
@@ -545930,41 +546820,6 @@ var init_useToolConfirmation = __esm({
545930
546820
  });
545931
546821
 
545932
546822
  // dist/utils/execution/toolExecutor.js
545933
- function fixMergedToolName(toolName) {
545934
- const knownPrefixes = getRegisteredServicePrefixes();
545935
- let foundPrefixes = [];
545936
- for (const prefix of knownPrefixes) {
545937
- let searchIndex = 0;
545938
- while (true) {
545939
- const index = toolName.indexOf(prefix, searchIndex);
545940
- if (index === -1)
545941
- break;
545942
- foundPrefixes.push({ prefix, index });
545943
- searchIndex = index + 1;
545944
- }
545945
- }
545946
- foundPrefixes.sort((a, b) => a.index - b.index);
545947
- if (foundPrefixes.length > 1) {
545948
- const firstPrefix = foundPrefixes[0];
545949
- const secondPrefix = foundPrefixes[1];
545950
- if (firstPrefix && secondPrefix && firstPrefix.index === 0) {
545951
- const firstToolName = toolName.substring(0, secondPrefix.index);
545952
- console.warn(`[Tool Name Fix] Detected merged tool names: "${toolName}"`);
545953
- console.warn(`[Tool Name Fix] Extracted first tool: "${firstToolName}"`);
545954
- console.warn(`[Tool Name Fix] Ignored second tool starting at: "${toolName.substring(secondPrefix.index)}"`);
545955
- return {
545956
- fixedName: firstToolName,
545957
- wasMerged: true,
545958
- originalName: toolName
545959
- };
545960
- }
545961
- }
545962
- return {
545963
- fixedName: toolName,
545964
- wasMerged: false,
545965
- originalName: toolName
545966
- };
545967
- }
545968
546823
  function safeParseToolArguments(argsString) {
545969
546824
  if (!argsString || argsString.trim() === "") {
545970
546825
  return {};
@@ -546058,16 +546913,6 @@ function extractMultimodalContent(result2) {
546058
546913
  };
546059
546914
  }
546060
546915
  async function executeToolCall(toolCall, abortSignal, onTokenUpdate, onSubAgentMessage, requestToolConfirmation, isToolAutoApproved, yoloMode, addToAlwaysApproved, onUserInteractionNeeded) {
546061
- const toolNameFix = fixMergedToolName(toolCall.function.name);
546062
- if (toolNameFix.wasMerged) {
546063
- toolCall = {
546064
- ...toolCall,
546065
- function: {
546066
- ...toolCall.function,
546067
- name: toolNameFix.fixedName
546068
- }
546069
- };
546070
- }
546071
546916
  let result2;
546072
546917
  let executionError = null;
546073
546918
  let escKeyListener;
@@ -548248,7 +549093,10 @@ async function handleConversationWithTools(options3) {
548248
549093
  if (subAgentMessage.message.type === "tool_calls") {
548249
549094
  const toolCalls = subAgentMessage.message.tool_calls;
548250
549095
  if (toolCalls && toolCalls.length > 0) {
548251
- const toolMessages = toolCalls.filter((toolCall) => isToolNeedTwoStepDisplay(toolCall.function.name)).map((toolCall) => {
549096
+ const timeConsumingTools = toolCalls.filter((tc) => isToolNeedTwoStepDisplay(tc.function.name));
549097
+ const quickTools = toolCalls.filter((tc) => !isToolNeedTwoStepDisplay(tc.function.name));
549098
+ const newMessages = [];
549099
+ for (const toolCall of timeConsumingTools) {
548252
549100
  const toolDisplay = formatToolCallMessage(toolCall);
548253
549101
  let toolArgs;
548254
549102
  try {
@@ -548264,7 +549112,6 @@ async function handleConversationWithTools(options3) {
548264
549112
  name: toolCall.function.name,
548265
549113
  arguments: toolArgs
548266
549114
  },
548267
- // Don't include toolDisplay for sub-agent tools to avoid showing parameters
548268
549115
  toolCallId: toolCall.id,
548269
549116
  toolPending: true,
548270
549117
  subAgent: {
@@ -548273,109 +549120,176 @@ async function handleConversationWithTools(options3) {
548273
549120
  isComplete: false
548274
549121
  },
548275
549122
  subAgentInternal: true
548276
- // Mark as internal sub-agent message
548277
549123
  };
548278
- return uiMsg;
548279
- });
549124
+ newMessages.push(uiMsg);
549125
+ }
549126
+ if (quickTools.length > 0) {
549127
+ const toolLines = quickTools.map((tc, index) => {
549128
+ const display = formatToolCallMessage(tc);
549129
+ const isLast = index === quickTools.length - 1;
549130
+ const prefix = isLast ? "\u2514\u2500" : "\u251C\u2500";
549131
+ const params = display.args.map((arg) => `${arg.key}: ${arg.value}`).join(", ");
549132
+ return `
549133
+ \x1B[2m${prefix} ${display.toolName}${params ? ` (${params})` : ""}\x1B[0m`;
549134
+ });
549135
+ const uiMsg = {
549136
+ role: "subagent",
549137
+ content: `\x1B[38;2;184;122;206m\u2687 ${subAgentMessage.agentName}${toolLines.join("")}\x1B[0m`,
549138
+ streaming: false,
549139
+ subAgent: {
549140
+ agentId: subAgentMessage.agentId,
549141
+ agentName: subAgentMessage.agentName,
549142
+ isComplete: false
549143
+ },
549144
+ subAgentInternal: true,
549145
+ // Store pending tool call IDs for later status update
549146
+ pendingToolIds: quickTools.map((tc) => tc.id)
549147
+ };
549148
+ newMessages.push(uiMsg);
549149
+ }
548280
549150
  const sessionMsg = {
548281
549151
  role: "assistant",
548282
549152
  content: toolCalls.map((tc) => {
548283
549153
  const display = formatToolCallMessage(tc);
548284
- return `\u2687\u26A1 ${display.toolName}`;
549154
+ return isToolNeedTwoStepDisplay(tc.function.name) ? `\u2687\u26A1 ${display.toolName}` : `\u2687 ${display.toolName}`;
548285
549155
  }).join(", "),
548286
549156
  subAgentInternal: true,
548287
549157
  tool_calls: toolCalls
548288
549158
  };
548289
549159
  saveMessage(sessionMsg).catch((err) => console.error("Failed to save sub-agent tool call:", err));
548290
- return [...prev, ...toolMessages];
549160
+ return [...prev, ...newMessages];
548291
549161
  }
548292
549162
  }
548293
549163
  if (subAgentMessage.message.type === "tool_result") {
548294
549164
  const msg = subAgentMessage.message;
548295
549165
  const isError2 = msg.content.startsWith("Error:");
548296
- const statusIcon = isError2 ? "\u2717" : "\u2713";
548297
- const statusText = isError2 ? `
549166
+ const isTimeConsumingTool = isToolNeedTwoStepDisplay(msg.tool_name);
549167
+ const sessionMsg = {
549168
+ role: "tool",
549169
+ tool_call_id: msg.tool_call_id,
549170
+ content: msg.content,
549171
+ subAgentInternal: true
549172
+ };
549173
+ saveMessage(sessionMsg).catch((err) => console.error("Failed to save sub-agent tool result:", err));
549174
+ if (isTimeConsumingTool) {
549175
+ const statusIcon = isError2 ? "\u2717" : "\u2713";
549176
+ const statusText = isError2 ? `
548298
549177
  \u2514\u2500 ${msg.content}` : "";
548299
- let terminalResultData;
548300
- if (msg.tool_name === "terminal-execute" && !isError2) {
548301
- try {
548302
- const resultData = JSON.parse(msg.content);
548303
- if (resultData.stdout !== void 0 || resultData.stderr !== void 0) {
548304
- terminalResultData = {
548305
- stdout: resultData.stdout,
548306
- stderr: resultData.stderr,
548307
- exitCode: resultData.exitCode,
548308
- command: resultData.command
548309
- };
549178
+ let terminalResultData;
549179
+ if (msg.tool_name === "terminal-execute" && !isError2) {
549180
+ try {
549181
+ const resultData = JSON.parse(msg.content);
549182
+ if (resultData.stdout !== void 0 || resultData.stderr !== void 0) {
549183
+ terminalResultData = {
549184
+ stdout: resultData.stdout,
549185
+ stderr: resultData.stderr,
549186
+ exitCode: resultData.exitCode,
549187
+ command: resultData.command
549188
+ };
549189
+ }
549190
+ } catch (e) {
549191
+ }
549192
+ }
549193
+ let fileToolData = void 0;
549194
+ if (!isError2 && (msg.tool_name === "filesystem-create" || msg.tool_name === "filesystem-edit" || msg.tool_name === "filesystem-edit_search")) {
549195
+ try {
549196
+ const resultData = JSON.parse(msg.content);
549197
+ if (resultData.content) {
549198
+ fileToolData = {
549199
+ name: msg.tool_name,
549200
+ arguments: {
549201
+ content: resultData.content,
549202
+ path: resultData.path || resultData.filename
549203
+ }
549204
+ };
549205
+ } else if (resultData.oldContent && resultData.newContent) {
549206
+ fileToolData = {
549207
+ name: msg.tool_name,
549208
+ arguments: {
549209
+ oldContent: resultData.oldContent,
549210
+ newContent: resultData.newContent,
549211
+ filename: resultData.path || resultData.filename,
549212
+ completeOldContent: resultData.completeOldContent,
549213
+ completeNewContent: resultData.completeNewContent,
549214
+ contextStartLine: resultData.contextStartLine
549215
+ }
549216
+ };
549217
+ } else if (resultData.batchResults && Array.isArray(resultData.batchResults)) {
549218
+ fileToolData = {
549219
+ name: msg.tool_name,
549220
+ arguments: {
549221
+ isBatch: true,
549222
+ batchResults: resultData.batchResults
549223
+ }
549224
+ };
549225
+ }
549226
+ } catch (e) {
548310
549227
  }
548311
- } catch (e) {
548312
549228
  }
549229
+ const uiMsg = {
549230
+ role: "subagent",
549231
+ content: `\x1B[38;2;0;186;255m\u2687${statusIcon} ${msg.tool_name}\x1B[0m${statusText}`,
549232
+ streaming: false,
549233
+ toolResult: !isError2 ? msg.content : void 0,
549234
+ terminalResult: terminalResultData,
549235
+ toolCall: terminalResultData ? {
549236
+ name: msg.tool_name,
549237
+ arguments: terminalResultData
549238
+ } : fileToolData ? fileToolData : void 0,
549239
+ subAgent: {
549240
+ agentId: subAgentMessage.agentId,
549241
+ agentName: subAgentMessage.agentName,
549242
+ isComplete: false
549243
+ },
549244
+ subAgentInternal: true
549245
+ };
549246
+ return [...prev, uiMsg];
548313
549247
  }
548314
- let fileToolData = void 0;
548315
- if (!isError2 && (msg.tool_name === "filesystem-create" || msg.tool_name === "filesystem-edit" || msg.tool_name === "filesystem-edit_search")) {
548316
- try {
548317
- const resultData = JSON.parse(msg.content);
548318
- if (resultData.content) {
548319
- fileToolData = {
548320
- name: msg.tool_name,
548321
- arguments: {
548322
- content: resultData.content,
548323
- path: resultData.path || resultData.filename
548324
- }
548325
- };
548326
- } else if (resultData.oldContent && resultData.newContent) {
548327
- fileToolData = {
548328
- name: msg.tool_name,
548329
- arguments: {
548330
- oldContent: resultData.oldContent,
548331
- newContent: resultData.newContent,
548332
- filename: resultData.path || resultData.filename,
548333
- completeOldContent: resultData.completeOldContent,
548334
- completeNewContent: resultData.completeNewContent,
548335
- contextStartLine: resultData.contextStartLine
548336
- }
549248
+ if (isError2) {
549249
+ const statusText = `
549250
+ \u2514\u2500 ${msg.content}`;
549251
+ const uiMsg = {
549252
+ role: "subagent",
549253
+ content: `\x1B[38;2;255;100;100m\u2687\u2717 ${msg.tool_name}\x1B[0m${statusText}`,
549254
+ streaming: false,
549255
+ subAgent: {
549256
+ agentId: subAgentMessage.agentId,
549257
+ agentName: subAgentMessage.agentName,
549258
+ isComplete: false
549259
+ },
549260
+ subAgentInternal: true
549261
+ };
549262
+ return [...prev, uiMsg];
549263
+ }
549264
+ const pendingMsgIndex = prev.findIndex((m) => {
549265
+ var _a22, _b14, _c6;
549266
+ 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));
549267
+ });
549268
+ if (pendingMsgIndex !== -1) {
549269
+ const updated = [...prev];
549270
+ const pendingMsg = updated[pendingMsgIndex];
549271
+ if (pendingMsg && pendingMsg.pendingToolIds) {
549272
+ const newPendingIds = pendingMsg.pendingToolIds.filter((id) => id !== msg.tool_call_id);
549273
+ if (newPendingIds.length === 0) {
549274
+ updated[pendingMsgIndex] = {
549275
+ ...pendingMsg,
549276
+ content: `${pendingMsg.content} \x1B[38;2;100;200;100m\u2713\x1B[0m`,
549277
+ pendingToolIds: newPendingIds
548337
549278
  };
548338
- } else if (resultData.batchResults && Array.isArray(resultData.batchResults)) {
548339
- fileToolData = {
548340
- name: msg.tool_name,
548341
- arguments: {
548342
- isBatch: true,
548343
- batchResults: resultData.batchResults
548344
- }
549279
+ } else {
549280
+ updated[pendingMsgIndex] = {
549281
+ ...pendingMsg,
549282
+ pendingToolIds: newPendingIds
548345
549283
  };
548346
549284
  }
548347
- } catch (e) {
548348
549285
  }
549286
+ return updated;
548349
549287
  }
548350
- const uiMsg = {
548351
- role: "subagent",
548352
- content: `\x1B[38;2;0;186;255m\u2687${statusIcon} ${msg.tool_name}\x1B[0m${statusText}`,
548353
- streaming: false,
548354
- toolResult: !isError2 ? msg.content : void 0,
548355
- terminalResult: terminalResultData,
548356
- toolCall: terminalResultData ? {
548357
- name: msg.tool_name,
548358
- arguments: terminalResultData
548359
- } : fileToolData ? fileToolData : void 0,
548360
- subAgent: {
548361
- agentId: subAgentMessage.agentId,
548362
- agentName: subAgentMessage.agentName,
548363
- isComplete: false
548364
- },
548365
- subAgentInternal: true
548366
- };
548367
- const sessionMsg = {
548368
- role: "tool",
548369
- tool_call_id: msg.tool_call_id,
548370
- content: msg.content,
548371
- subAgentInternal: true
548372
- };
548373
- saveMessage(sessionMsg).catch((err) => console.error("Failed to save sub-agent tool result:", err));
548374
- return [...prev, uiMsg];
549288
+ return prev;
548375
549289
  }
548376
549290
  const existingIndex = prev.findIndex((m) => {
548377
549291
  var _a22, _b14;
548378
- return m.role === "subagent" && ((_a22 = m.subAgent) == null ? void 0 : _a22.agentId) === subAgentMessage.agentId && !((_b14 = m.subAgent) == null ? void 0 : _b14.isComplete) && !m.toolCall;
549292
+ return m.role === "subagent" && ((_a22 = m.subAgent) == null ? void 0 : _a22.agentId) === subAgentMessage.agentId && !((_b14 = m.subAgent) == null ? void 0 : _b14.isComplete) && !m.pendingToolIds;
548379
549293
  });
548380
549294
  let content = "";
548381
549295
  if (subAgentMessage.message.type === "content") {
@@ -548867,43 +549781,64 @@ function convertSessionMessagesToUI(sessionMessages) {
548867
549781
  const msg = sessionMessages[i];
548868
549782
  if (!msg)
548869
549783
  continue;
548870
- if (msg.role === "system")
548871
- continue;
548872
549784
  if (msg.subAgentInternal && msg.role === "assistant" && msg.tool_calls) {
548873
- for (const toolCall of msg.tool_calls) {
548874
- if (isToolNeedTwoStepDisplay(toolCall.function.name)) {
548875
- const toolDisplay = formatToolCallMessage(toolCall);
548876
- let toolArgs;
548877
- try {
548878
- toolArgs = JSON.parse(toolCall.function.arguments);
548879
- } catch (e) {
548880
- toolArgs = {};
548881
- }
548882
- uiMessages.push({
548883
- role: "subagent",
548884
- content: `\x1B[38;2;184;122;206m\u2687\u26A1 ${toolDisplay.toolName}\x1B[0m`,
548885
- streaming: false,
548886
- toolCall: {
548887
- name: toolCall.function.name,
548888
- arguments: toolArgs
548889
- },
548890
- // Don't include toolDisplay for sub-agent tools to avoid showing parameters
548891
- toolCallId: toolCall.id,
548892
- toolPending: false,
548893
- subAgentInternal: true
548894
- });
549785
+ const timeConsumingTools = msg.tool_calls.filter((tc) => isToolNeedTwoStepDisplay(tc.function.name));
549786
+ const quickTools = msg.tool_calls.filter((tc) => !isToolNeedTwoStepDisplay(tc.function.name));
549787
+ for (const toolCall of timeConsumingTools) {
549788
+ const toolDisplay = formatToolCallMessage(toolCall);
549789
+ let toolArgs;
549790
+ try {
549791
+ toolArgs = JSON.parse(toolCall.function.arguments);
549792
+ } catch (e) {
549793
+ toolArgs = {};
548895
549794
  }
549795
+ uiMessages.push({
549796
+ role: "subagent",
549797
+ content: `\x1B[38;2;184;122;206m\u2687\u26A1 ${toolDisplay.toolName}\x1B[0m`,
549798
+ streaming: false,
549799
+ toolCall: {
549800
+ name: toolCall.function.name,
549801
+ arguments: toolArgs
549802
+ },
549803
+ toolCallId: toolCall.id,
549804
+ toolPending: false,
549805
+ subAgentInternal: true
549806
+ });
548896
549807
  processedToolCalls.add(toolCall.id);
548897
549808
  }
549809
+ if (quickTools.length > 0) {
549810
+ let agentName = "Sub-Agent";
549811
+ for (let j = i + 1; j < sessionMessages.length; j++) {
549812
+ const nextMsg = sessionMessages[j];
549813
+ if (nextMsg && nextMsg.subAgentInternal && nextMsg.role === "tool") {
549814
+ break;
549815
+ }
549816
+ }
549817
+ const toolLines = quickTools.map((tc, index) => {
549818
+ const display = formatToolCallMessage(tc);
549819
+ const isLast = index === quickTools.length - 1;
549820
+ const prefix = isLast ? "\u2514\u2500" : "\u251C\u2500";
549821
+ const params = display.args.map((arg) => `${arg.key}: ${arg.value}`).join(", ");
549822
+ return `
549823
+ \x1B[2m${prefix} ${display.toolName}${params ? ` (${params})` : ""}\x1B[0m`;
549824
+ });
549825
+ uiMessages.push({
549826
+ role: "subagent",
549827
+ content: `\x1B[38;2;184;122;206m\u2687 ${agentName}${toolLines.join("")}\x1B[0m`,
549828
+ streaming: false,
549829
+ subAgentInternal: true,
549830
+ pendingToolIds: quickTools.map((tc) => tc.id)
549831
+ });
549832
+ for (const tc of quickTools) {
549833
+ processedToolCalls.add(tc.id);
549834
+ }
549835
+ }
548898
549836
  continue;
548899
549837
  }
548900
549838
  if (msg.subAgentInternal && msg.role === "tool" && msg.tool_call_id) {
548901
549839
  const isError2 = msg.content.startsWith("Error:");
548902
- const statusIcon = isError2 ? "\u2717" : "\u2713";
548903
- const statusText = isError2 ? `
548904
- \u2514\u2500 ${msg.content}` : "";
548905
549840
  let toolName = "tool";
548906
- let terminalResultData;
549841
+ let isTimeConsumingTool = false;
548907
549842
  for (let j = i - 1; j >= 0; j--) {
548908
549843
  const prevMsg = sessionMessages[j];
548909
549844
  if (!prevMsg)
@@ -548912,36 +549847,90 @@ function convertSessionMessagesToUI(sessionMessages) {
548912
549847
  const tc = prevMsg.tool_calls.find((t) => t.id === msg.tool_call_id);
548913
549848
  if (tc) {
548914
549849
  toolName = tc.function.name;
548915
- if (toolName === "terminal-execute" && !isError2) {
548916
- try {
548917
- const resultData = JSON.parse(msg.content);
548918
- if (resultData.stdout !== void 0 || resultData.stderr !== void 0) {
548919
- terminalResultData = {
548920
- stdout: resultData.stdout,
548921
- stderr: resultData.stderr,
548922
- exitCode: resultData.exitCode,
548923
- command: resultData.command
548924
- };
549850
+ isTimeConsumingTool = isToolNeedTwoStepDisplay(toolName);
549851
+ break;
549852
+ }
549853
+ }
549854
+ }
549855
+ if (isTimeConsumingTool) {
549856
+ const statusIcon = isError2 ? "\u2717" : "\u2713";
549857
+ const statusText = isError2 ? `
549858
+ \u2514\u2500 ${msg.content}` : "";
549859
+ let terminalResultData;
549860
+ if (toolName === "terminal-execute" && !isError2) {
549861
+ try {
549862
+ const resultData = JSON.parse(msg.content);
549863
+ if (resultData.stdout !== void 0 || resultData.stderr !== void 0) {
549864
+ terminalResultData = {
549865
+ stdout: resultData.stdout,
549866
+ stderr: resultData.stderr,
549867
+ exitCode: resultData.exitCode,
549868
+ command: resultData.command
549869
+ };
549870
+ }
549871
+ } catch (e) {
549872
+ }
549873
+ }
549874
+ let fileToolData = void 0;
549875
+ if (!isError2 && (toolName === "filesystem-create" || toolName === "filesystem-edit" || toolName === "filesystem-edit_search")) {
549876
+ try {
549877
+ const resultData = JSON.parse(msg.content);
549878
+ if (resultData.content) {
549879
+ fileToolData = {
549880
+ name: toolName,
549881
+ arguments: {
549882
+ content: resultData.content,
549883
+ path: resultData.path || resultData.filename
548925
549884
  }
548926
- } catch (e) {
548927
- }
549885
+ };
549886
+ } else if (resultData.oldContent && resultData.newContent) {
549887
+ fileToolData = {
549888
+ name: toolName,
549889
+ arguments: {
549890
+ oldContent: resultData.oldContent,
549891
+ newContent: resultData.newContent,
549892
+ filename: resultData.path || resultData.filename,
549893
+ completeOldContent: resultData.completeOldContent,
549894
+ completeNewContent: resultData.completeNewContent,
549895
+ contextStartLine: resultData.contextStartLine
549896
+ }
549897
+ };
549898
+ } else if (resultData.batchResults && Array.isArray(resultData.batchResults)) {
549899
+ fileToolData = {
549900
+ name: toolName,
549901
+ arguments: {
549902
+ isBatch: true,
549903
+ batchResults: resultData.batchResults
549904
+ }
549905
+ };
548928
549906
  }
548929
- break;
549907
+ } catch (e) {
548930
549908
  }
548931
549909
  }
549910
+ uiMessages.push({
549911
+ role: "subagent",
549912
+ content: `\x1B[38;2;0;186;255m\u2687${statusIcon} ${toolName}\x1B[0m${statusText}`,
549913
+ streaming: false,
549914
+ toolResult: !isError2 ? msg.content : void 0,
549915
+ terminalResult: terminalResultData,
549916
+ toolCall: terminalResultData ? {
549917
+ name: toolName,
549918
+ arguments: terminalResultData
549919
+ } : fileToolData ? fileToolData : void 0,
549920
+ subAgentInternal: true
549921
+ });
549922
+ } else {
549923
+ if (isError2) {
549924
+ const statusText = `
549925
+ \u2514\u2500 ${msg.content}`;
549926
+ uiMessages.push({
549927
+ role: "subagent",
549928
+ content: `\x1B[38;2;255;100;100m\u2687\u2717 ${toolName}\x1B[0m${statusText}`,
549929
+ streaming: false,
549930
+ subAgentInternal: true
549931
+ });
549932
+ }
548932
549933
  }
548933
- uiMessages.push({
548934
- role: "subagent",
548935
- content: `\x1B[38;2;0;186;255m\u2687${statusIcon} ${toolName}\x1B[0m${statusText}`,
548936
- streaming: false,
548937
- toolResult: !isError2 ? msg.content : void 0,
548938
- terminalResult: terminalResultData,
548939
- toolCall: terminalResultData ? {
548940
- name: toolName,
548941
- arguments: terminalResultData
548942
- } : void 0,
548943
- subAgentInternal: true
548944
- });
548945
549934
  continue;
548946
549935
  }
548947
549936
  if (msg.role === "assistant" && msg.tool_calls && msg.tool_calls.length > 0 && !msg.subAgentInternal) {
@@ -551371,9 +552360,9 @@ var init_handler = __esm({
551371
552360
  if (this.fsw.closed) {
551372
552361
  return;
551373
552362
  }
551374
- const dirname10 = sysPath.dirname(file);
552363
+ const dirname11 = sysPath.dirname(file);
551375
552364
  const basename6 = sysPath.basename(file);
551376
- const parent = this.fsw._getWatchedDir(dirname10);
552365
+ const parent = this.fsw._getWatchedDir(dirname11);
551377
552366
  let prevStats = stats;
551378
552367
  if (parent.has(basename6))
551379
552368
  return;
@@ -551400,7 +552389,7 @@ var init_handler = __esm({
551400
552389
  prevStats = newStats2;
551401
552390
  }
551402
552391
  } catch (error) {
551403
- this.fsw._remove(dirname10, basename6);
552392
+ this.fsw._remove(dirname11, basename6);
551404
552393
  }
551405
552394
  } else if (parent.has(basename6)) {
551406
552395
  const at = newStats.atimeMs;
@@ -551645,11 +552634,11 @@ function createPattern(matcher2) {
551645
552634
  if (matcher2.path === string)
551646
552635
  return true;
551647
552636
  if (matcher2.recursive) {
551648
- const relative8 = sysPath2.relative(matcher2.path, string);
551649
- if (!relative8) {
552637
+ const relative9 = sysPath2.relative(matcher2.path, string);
552638
+ if (!relative9) {
551650
552639
  return false;
551651
552640
  }
551652
- return !relative8.startsWith("..") && !sysPath2.isAbsolute(relative8);
552641
+ return !relative9.startsWith("..") && !sysPath2.isAbsolute(relative9);
551653
552642
  }
551654
552643
  return false;
551655
552644
  };
@@ -554067,43 +555056,34 @@ function ChatScreen({ autoResume, enableYolo }) {
554067
555056
  await saveCustomCommand(name, command, type, void 0, location, workingDirectory);
554068
555057
  await registerCustomCommands(workingDirectory);
554069
555058
  panelState.setShowCustomCommandConfig(false);
554070
- const typeDesc = type === "execute" ? "Execute in terminal" : "Send to AI";
554071
- const locationDesc = location === "global" ? "Global (~/.snow/commands/)" : "Project (.snow/commands/)";
555059
+ const typeDesc = type === "execute" ? t.customCommand.resultTypeExecute : t.customCommand.resultTypePrompt;
555060
+ const locationDesc = location === "global" ? t.customCommand.resultLocationGlobal : t.customCommand.resultLocationProject;
555061
+ const content = t.customCommand.saveSuccessMessage.replace("{name}", name).replace("{type}", typeDesc).replace("{location}", locationDesc);
554072
555062
  const successMessage = {
554073
555063
  role: "command",
554074
- content: `Custom command '${name}' saved successfully!
554075
- Type: ${typeDesc}
554076
- Location: ${locationDesc}
554077
- You can now use /${name}`,
555064
+ content,
554078
555065
  commandName: "custom"
554079
555066
  };
554080
555067
  setMessages((prev) => [...prev, successMessage]);
554081
- }, onSkillsSave: async (skillName, description, location) => {
554082
- const result2 = await createSkillTemplate(skillName, description, location, workingDirectory);
555068
+ }, onSkillsSave: async (skillName, description, location, generated) => {
555069
+ const result2 = generated ? await createSkillFromGenerated(skillName, description, generated, location, workingDirectory) : await createSkillTemplate(skillName, description, location, workingDirectory);
554083
555070
  panelState.setShowSkillsCreation(false);
554084
555071
  if (result2.success) {
554085
- const locationDesc = location === "global" ? "Global (~/.snow/skills/)" : "Project (.snow/skills/)";
555072
+ const locationDesc = location === "global" ? t.skillsCreation.locationGlobal : t.skillsCreation.locationProject;
555073
+ const modeDesc = generated ? t.skillsCreation.resultModeAi : t.skillsCreation.resultModeManual;
555074
+ const content = t.skillsCreation.createSuccessMessage.replace("{name}", skillName).replace("{mode}", modeDesc).replace("{location}", locationDesc).replace("{path}", result2.path);
554086
555075
  const successMessage = {
554087
555076
  role: "command",
554088
- content: `Skill '${skillName}' created successfully!
554089
- Location: ${locationDesc}
554090
- Path: ${result2.path}
554091
-
554092
- The following files have been created:
554093
- - SKILL.md (main skill documentation)
554094
- - reference.md (detailed reference)
554095
- - examples.md (usage examples)
554096
- - templates/template.txt (template file)
554097
- - scripts/helper.py (helper script)
554098
-
554099
- You can now edit these files to customize your skill.`,
555077
+ content,
554100
555078
  commandName: "skills"
554101
555079
  };
554102
555080
  setMessages((prev) => [...prev, successMessage]);
554103
555081
  } else {
555082
+ const errorText = result2.error || t.skillsCreation.errorUnknown;
555083
+ const content = t.skillsCreation.createErrorMessage.replace("{error}", errorText);
554104
555084
  const errorMessage = {
554105
555085
  role: "command",
554106
- content: `Failed to create skill: ${result2.error}`,
555086
+ content,
554107
555087
  commandName: "skills"
554108
555088
  };
554109
555089
  setMessages((prev) => [...prev, errorMessage]);