@crustjs/skills 0.0.17 → 0.0.20

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/README.md CHANGED
@@ -295,11 +295,11 @@ Resolves the canonical store path where Crust writes the single source-of-truth
295
295
  ```ts
296
296
  import { resolveCanonicalSkillPath } from "@crustjs/skills";
297
297
 
298
- resolveCanonicalSkillPath("project", "use-my-cli");
299
- // → "<cwd>/.crust/skills/use-my-cli"
298
+ resolveCanonicalSkillPath("project", "my-cli");
299
+ // → "<cwd>/.crust/skills/my-cli"
300
300
 
301
- resolveCanonicalSkillPath("global", "use-my-cli");
302
- // → "~/.crust/skills/use-my-cli"
301
+ resolveCanonicalSkillPath("global", "my-cli");
302
+ // → "~/.crust/skills/my-cli"
303
303
  ```
304
304
 
305
305
  ### `isValidSkillName(name)`
@@ -315,7 +315,7 @@ isValidSkillName("-leading"); // false — leading hyphen
315
315
  isValidSkillName("a".repeat(65)); // false — exceeds 64 characters
316
316
  ```
317
317
 
318
- > **Note:** `generateSkill()` automatically validates `meta.name` (after prepending `use-`) and throws a descriptive error if the name is invalid.
318
+ > **Note:** `generateSkill()` automatically validates `meta.name` and throws a descriptive error if the name is invalid.
319
319
 
320
320
  ## Skill Metadata
321
321
 
@@ -353,10 +353,10 @@ No manual escaping is needed — pass raw values and the renderer handles the re
353
353
 
354
354
  ## Output Structure
355
355
 
356
- Generated output goes to `<outDir>/skills/use-<name>/` (the `use-` prefix is applied automatically):
356
+ Generated output goes to `<outDir>/skills/<name>/`:
357
357
 
358
358
  ```
359
- skills/use-my-cli/
359
+ skills/my-cli/
360
360
  SKILL.md # Entrypoint — loaded by the agent
361
361
  commands/ # Per-command documentation mirroring the CLI hierarchy
362
362
  my-cli.md # Root command
@@ -405,19 +405,19 @@ After generating a skill bundle, consumers can install it by copying the skill d
405
405
  ### Universal agents (OpenCode, Codex, Cursor, and others)
406
406
 
407
407
  ```sh
408
- cp -r skills/use-my-cli/ .agents/skills/use-my-cli/
408
+ cp -r skills/my-cli/ .agents/skills/my-cli/
409
409
  ```
410
410
 
411
411
  Global install for universal agents:
412
412
 
413
413
  ```sh
414
- cp -r skills/use-my-cli/ ~/.agents/skills/use-my-cli/
414
+ cp -r skills/my-cli/ ~/.agents/skills/my-cli/
415
415
  ```
416
416
 
417
417
  ### Claude Code
418
418
 
419
419
  ```sh
420
- cp -r skills/use-my-cli/ .claude/skills/use-my-cli/
420
+ cp -r skills/my-cli/ .claude/skills/my-cli/
421
421
  ```
422
422
 
423
423
  The agent will discover the skill from `SKILL.md` and load command documentation on demand from the `commands/` directory.
package/dist/index.d.ts CHANGED
@@ -12,21 +12,21 @@ import { CommandNode } from "@crustjs/core";
12
12
  * description: "CLI tool for managing widgets",
13
13
  * version: "1.0.0",
14
14
  * };
15
- * // generateSkill() will output to `use-my-cli/` with name "use-my-cli"
15
+ * // generateSkill() will output to `my-cli/` with name "my-cli"
16
16
  * ```
17
17
  */
18
18
  interface SkillMeta {
19
19
  /**
20
20
  * Skill name — the user-facing CLI name (e.g. `"my-cli"`).
21
21
  *
22
- * `generateSkill()`, `uninstallSkill()`, and `skillStatus()` automatically
23
- * prefix `use-` to this name for output directory paths, SKILL.md frontmatter,
24
- * and crust.json metadata. For example, `name: "my-cli"` produces output
25
- * under `use-my-cli/`.
22
+ * `generateSkill()`, `uninstallSkill()`, and `skillStatus()` treat this as
23
+ * the canonical raw skill name for output directory paths, SKILL.md
24
+ * frontmatter, and crust.json metadata. For example, `name: "my-cli"`
25
+ * produces output under `my-cli/`.
26
26
  *
27
- * The resolved name (with `use-` prefix) must conform to the Agent Skills
28
- * spec: 1–64 lowercase alphanumeric characters and hyphens, no leading/
29
- * trailing/consecutive hyphens.
27
+ * The resolved name must conform to the Agent Skills spec: 1–64 lowercase
28
+ * alphanumeric characters and hyphens, no leading/trailing/consecutive
29
+ * hyphens.
30
30
  */
31
31
  name: string;
32
32
  /** Human-readable description of what the CLI does */
@@ -91,9 +91,9 @@ type SkillInstallMode = "auto" | "symlink" | "copy";
91
91
  /**
92
92
  * Top-level options for generating a skill bundle from a command tree.
93
93
  *
94
- * The `meta.name` value is automatically prefixed with `use-` for all output
95
- * paths and metadata. For example, `name: "my-cli"` produces skill directories
96
- * named `use-my-cli/` and sets the manifest/frontmatter name to `"use-my-cli"`.
94
+ * The `meta.name` value is used directly for all output paths and metadata.
95
+ * For example, `name: "my-cli"` produces skill directories named `my-cli/`
96
+ * and sets the manifest/frontmatter name to `"my-cli"`.
97
97
  *
98
98
  * @example
99
99
  * ```ts
@@ -103,7 +103,7 @@ type SkillInstallMode = "auto" | "symlink" | "copy";
103
103
  * await generateSkill({
104
104
  * command: rootCommand,
105
105
  * meta: {
106
- * name: "my-cli", // output: use-my-cli/
106
+ * name: "my-cli", // output: my-cli/
107
107
  * description: "CLI tool for managing widgets",
108
108
  * version: "1.0.0",
109
109
  * },
@@ -387,23 +387,23 @@ declare class SkillConflictError extends Error {
387
387
  /**
388
388
  * Validates a resolved skill name against the Agent Skills specification.
389
389
  *
390
- * @param name - The resolved skill name to validate (already has `use-` prefix)
390
+ * @param name - The resolved skill name to validate
391
391
  * @returns `true` if valid, `false` otherwise
392
392
  */
393
393
  declare function isValidSkillName(name: string): boolean;
394
394
  /**
395
- * Resolves the canonical skill name by applying the `use-` prefix.
395
+ * Resolves the canonical current skill name.
396
396
  *
397
397
  * All generated output (directory names, crust.json metadata, SKILL.md content)
398
- * uses the resolved name. Consumers pass the raw CLI name (e.g. `"my-cli"`),
399
- * and this function returns the prefixed form (e.g. `"use-my-cli"`).
398
+ * uses the resolved name directly. Consumers pass the raw CLI name
399
+ * (e.g. `"my-cli"`), and this function returns that same canonical name.
400
400
  *
401
401
  * @param name - The raw CLI tool name
402
- * @returns The prefixed skill name
402
+ * @returns The canonical skill name
403
403
  *
404
404
  * @example
405
405
  * ```ts
406
- * resolveSkillName("my-cli"); // "use-my-cli"
406
+ * resolveSkillName("my-cli"); // "my-cli"
407
407
  * ```
408
408
  */
409
409
  declare function resolveSkillName(name: string): string;
package/dist/index.js CHANGED
@@ -1,11 +1,11 @@
1
1
  // @bun
2
- import{accessSync as mQ,constants as dQ}from"fs";import{homedir as e}from"os";import{delimiter as rQ,join as Y}from"path";var _=Y(".agents","skills"),lQ=Y(".crust","skills");function KQ(Q){if(Q!==e())return Y(Q,".config");let Z=process.env.XDG_CONFIG_HOME?.trim();return Z&&Z.length>0?Z:Y(Q,".config")}function k(Q){return Y(Q,".agents","skills")}function sQ(Q){return Y(Q,".crust","skills")}var P={amp:{label:"Amp",class:"universal",projectSkillsDir:_,globalSkillsDir:k},adal:{label:"AdaL",class:"additional",projectSkillsDir:Y(".adal","skills"),globalSkillsDir:(Q)=>Y(Q,".adal","skills"),detectCommands:["adal"]},antigravity:{label:"Antigravity",class:"additional",projectSkillsDir:Y(".agent","skills"),globalSkillsDir:(Q)=>Y(Q,".gemini","antigravity","skills"),detectCommands:["antigravity"]},augment:{label:"Augment",class:"additional",projectSkillsDir:Y(".augment","skills"),globalSkillsDir:(Q)=>Y(Q,".augment","skills"),detectCommands:["augment"]},"claude-code":{label:"Claude Code",class:"additional",projectSkillsDir:Y(".claude","skills"),globalSkillsDir:(Q)=>Y(process.env.CLAUDE_CONFIG_DIR?.trim()||Y(Q,".claude"),"skills"),detectCommands:["claude","claude-code"]},cline:{label:"Cline",class:"universal",projectSkillsDir:_,globalSkillsDir:k},codebuddy:{label:"CodeBuddy",class:"additional",projectSkillsDir:Y(".codebuddy","skills"),globalSkillsDir:(Q)=>Y(Q,".codebuddy","skills"),detectCommands:["codebuddy"]},codex:{label:"Codex",class:"universal",projectSkillsDir:_,globalSkillsDir:k},"command-code":{label:"Command Code",class:"additional",projectSkillsDir:Y(".commandcode","skills"),globalSkillsDir:(Q)=>Y(Q,".commandcode","skills"),detectCommands:["command-code","commandcode"]},continue:{label:"Continue",class:"additional",projectSkillsDir:Y(".continue","skills"),globalSkillsDir:(Q)=>Y(Q,".continue","skills"),detectCommands:["continue"]},cortex:{label:"Cortex Code",class:"additional",projectSkillsDir:Y(".cortex","skills"),globalSkillsDir:(Q)=>Y(Q,".snowflake","cortex","skills"),detectCommands:["cortex"]},crush:{label:"Crush",class:"additional",projectSkillsDir:Y(".crush","skills"),globalSkillsDir:(Q)=>Y(KQ(Q),"crush","skills"),detectCommands:["crush"]},cursor:{label:"Cursor",class:"universal",projectSkillsDir:_,globalSkillsDir:k},droid:{label:"Droid",class:"additional",projectSkillsDir:Y(".factory","skills"),globalSkillsDir:(Q)=>Y(Q,".factory","skills"),detectCommands:["droid"]},"gemini-cli":{label:"Gemini CLI",class:"universal",projectSkillsDir:_,globalSkillsDir:k},"github-copilot":{label:"GitHub Copilot",class:"universal",projectSkillsDir:_,globalSkillsDir:k},goose:{label:"Goose",class:"additional",projectSkillsDir:Y(".goose","skills"),globalSkillsDir:(Q)=>Y(KQ(Q),"goose","skills"),detectCommands:["goose"]},"iflow-cli":{label:"iFlow CLI",class:"additional",projectSkillsDir:Y(".iflow","skills"),globalSkillsDir:(Q)=>Y(Q,".iflow","skills"),detectCommands:["iflow","iflow-cli"]},junie:{label:"Junie",class:"additional",projectSkillsDir:Y(".junie","skills"),globalSkillsDir:(Q)=>Y(Q,".junie","skills"),detectCommands:["junie"]},kilo:{label:"Kilo Code",class:"additional",projectSkillsDir:Y(".kilocode","skills"),globalSkillsDir:(Q)=>Y(Q,".kilocode","skills"),detectCommands:["kilo","kilocode"]},"kimi-cli":{label:"Kimi Code CLI",class:"universal",projectSkillsDir:_,globalSkillsDir:k},"kiro-cli":{label:"Kiro CLI",class:"additional",projectSkillsDir:Y(".kiro","skills"),globalSkillsDir:(Q)=>Y(Q,".kiro","skills"),detectCommands:["kiro","kiro-cli"]},kode:{label:"Kode",class:"additional",projectSkillsDir:Y(".kode","skills"),globalSkillsDir:(Q)=>Y(Q,".kode","skills"),detectCommands:["kode"]},mcpjam:{label:"MCPJam",class:"additional",projectSkillsDir:Y(".mcpjam","skills"),globalSkillsDir:(Q)=>Y(Q,".mcpjam","skills"),detectCommands:["mcpjam"]},"mistral-vibe":{label:"Mistral Vibe",class:"additional",projectSkillsDir:Y(".vibe","skills"),globalSkillsDir:(Q)=>Y(Q,".vibe","skills"),detectCommands:["mistral-vibe","vibe"]},mux:{label:"Mux",class:"additional",projectSkillsDir:Y(".mux","skills"),globalSkillsDir:(Q)=>Y(Q,".mux","skills"),detectCommands:["mux"]},neovate:{label:"Neovate",class:"additional",projectSkillsDir:Y(".neovate","skills"),globalSkillsDir:(Q)=>Y(Q,".neovate","skills"),detectCommands:["neovate"]},opencode:{label:"OpenCode",class:"universal",projectSkillsDir:_,globalSkillsDir:k},openclaw:{label:"OpenClaw",class:"additional",projectSkillsDir:"skills",globalSkillsDir:(Q)=>Y(Q,".openclaw","skills"),detectCommands:["openclaw"]},openhands:{label:"OpenHands",class:"additional",projectSkillsDir:Y(".openhands","skills"),globalSkillsDir:(Q)=>Y(Q,".openhands","skills"),detectCommands:["openhands"]},pi:{label:"Pi",class:"additional",projectSkillsDir:Y(".pi","skills"),globalSkillsDir:(Q)=>Y(Q,".pi","agent","skills"),detectCommands:["pi"]},pochi:{label:"Pochi",class:"additional",projectSkillsDir:Y(".pochi","skills"),globalSkillsDir:(Q)=>Y(Q,".pochi","skills"),detectCommands:["pochi"]},qoder:{label:"Qoder",class:"additional",projectSkillsDir:Y(".qoder","skills"),globalSkillsDir:(Q)=>Y(Q,".qoder","skills"),detectCommands:["qoder"]},"qwen-code":{label:"Qwen Code",class:"additional",projectSkillsDir:Y(".qwen","skills"),globalSkillsDir:(Q)=>Y(Q,".qwen","skills"),detectCommands:["qwen","qwen-code"]},replit:{label:"Replit",class:"universal",projectSkillsDir:_,globalSkillsDir:k},roo:{label:"Roo Code",class:"additional",projectSkillsDir:Y(".roo","skills"),globalSkillsDir:(Q)=>Y(Q,".roo","skills"),detectCommands:["roo","roo-code"]},trae:{label:"Trae",class:"additional",projectSkillsDir:Y(".trae","skills"),globalSkillsDir:(Q)=>Y(Q,".trae","skills"),detectCommands:["trae"]},"trae-cn":{label:"Trae CN",class:"additional",projectSkillsDir:Y(".trae","skills"),globalSkillsDir:(Q)=>Y(Q,".trae-cn","skills"),detectCommands:["trae-cn","trae"]},windsurf:{label:"Windsurf",class:"additional",projectSkillsDir:Y(".windsurf","skills"),globalSkillsDir:(Q)=>Y(Q,".codeium","windsurf","skills"),detectCommands:["windsurf"]},zencoder:{label:"Zencoder",class:"additional",projectSkillsDir:Y(".zencoder","skills"),globalSkillsDir:(Q)=>Y(Q,".zencoder","skills"),detectCommands:["zencoder"]}},c=Object.keys(P),j=Object.fromEntries(c.map((Q)=>[Q,P[Q].label]));function I(){return c.filter((Q)=>P[Q].class==="universal")}function D(){return c.filter((Q)=>P[Q].class==="additional")}function iQ(Q){return P[Q].class==="universal"}async function QQ(Q){let Z=typeof Q==="string"?{home:Q}:Q??{},X=Z.cwd??process.cwd(),$=Z.commandChecker??((H)=>Promise.resolve(oQ(H))),W=[];for(let H of D()){let B=P[H].detectCommands??[],z=!1;for(let J of B)if(await $(J,X)){z=!0;break}if(z)W.push(H)}return W}function v(Q,Z,X){let $=P[Q];if(Z==="project")return Y(process.cwd(),$.projectSkillsDir,X);return Y($.globalSkillsDir(e()),X)}function s(Q,Z){if(Q==="project")return Y(process.cwd(),lQ,Z);return Y(sQ(e()),Z)}function oQ(Q){let X=(process.env.PATH??"").split(rQ).filter((H)=>H.length>0),$=process.platform==="win32",W=$?(process.env.PATHEXT??".EXE;.CMD;.BAT;.COM").split(";").filter((H)=>H.length>0):[];for(let H of X){if(!$&&xQ(Y(H,Q)))return!0;if($){for(let B of W)if(xQ(Y(H,Q+B)))return!0}}return!1}function xQ(Q){try{return mQ(Q,dQ.X_OK),!0}catch{return!1}}import{Crust as aQ}from"@crustjs/core";function i(Q){if(Q===void 0)return[];return(Array.isArray(Q)?Q:[Q]).flatMap((X)=>X.split(/\r?\n/)).map((X)=>X.trim()).filter((X)=>X.length>0)}function GQ(Q){let Z=Q?.trim();if(!Z)return[];return Z.split(/\r?\n/)}function ZQ(Q){return Q.length>0}var FQ=Symbol("crust.skill.commandAnnotations");function tQ(Q){return Q instanceof aQ?Q._node:Q}function nQ(Q,Z){let X=tQ(Q),$=i(typeof Z==="string"||Array.isArray(Z)?Z:Z.instructions??[]);if($.length===0)return Q;let W=XQ(X)?.instructions??[],H=[...new Set([...W,...$])];return Object.defineProperty(X,FQ,{value:{instructions:H},enumerable:!0,configurable:!0}),Q}function XQ(Q){let Z=Q[FQ];if(!Z?.instructions||Z.instructions.length===0)return;return{instructions:[...Z.instructions]}}class b extends Error{name="SkillConflictError";details;constructor(Q){let Z=`Skill conflict for agent "${Q.agent}": directory "${Q.outputDir}" already exists but was not created by Crust (no crust.json found). Delete or rename the conflicting skill to resolve.`;super(Z);this.details=Q}}import{lstat as NQ,mkdir as LQ,readlink as yZ,realpath as TZ,rm as YQ,symlink as _Z,writeFile as kZ}from"fs/promises";import{dirname as DQ,join as PQ}from"path";function MQ(Q){return wQ(Q,[])}function wQ(Q,Z){let X=eQ(Q.meta.name),$=[...Z,X],W=QZ(Q.args),H=XZ(Q.effectiveFlags),B=WZ(Q.subCommands,$),z=XQ(Q);return{name:X,path:$,description:Q.meta.description,usage:Q.meta.usage,instructions:z?.instructions,runnable:typeof Q.run==="function",args:W,flags:H,children:B}}function eQ(Q){return Q.trim().toLowerCase()}function QZ(Q){if(!Q||Q.length===0)return[];return Q.map(ZZ)}function ZZ(Q){let Z={name:Q.name,type:Q.type,required:Q.required===!0,variadic:Q.variadic===!0};if(Q.description!==void 0)Z.description=Q.description;if(Q.default!==void 0)Z.default=UQ(Q.default);return Z}function XZ(Q){if(!Q)return[];return Object.keys(Q).sort().map((X)=>{return $Z(X,Q[X])})}function $Z(Q,Z){let X={name:Q,type:Z.type,required:Z.required===!0,multiple:Z.multiple===!0,short:Z.short,aliases:Z.aliases?[...Z.aliases].sort():[]};if(Z.description!==void 0)X.description=Z.description;if(Z.default!==void 0)X.default=UQ(Z.default);return X}function WZ(Q,Z){return Object.keys(Q).sort().map(($)=>{return wQ(Q[$],Z)})}function UQ(Q){if(Array.isArray(Q))return JSON.stringify(Q);return String(Q)}function u(Q){if(/[:#[\]{}&*!|>'"`,@?\\]|^\s|\s$|^---|[\n\r]/.test(Q))return`"${Q.replace(/\\/g,"\\\\").replace(/"/g,"\\\"").replace(/\n/g,"\\n").replace(/\r/g,"\\r")}"`;return Q}function OQ(Q){return Q.replace(/(?<!\\)\|/g,"\\|")}function VQ(Q,Z){let X=[],$=RQ(Q);X.push({path:"SKILL.md",content:HZ(Q,Z,$)});for(let W of $){let H=C(W),B=W.children.length>0?JZ(W,Q):BZ(W,Q);X.push({path:H,content:B})}return X}function RQ(Q){let Z=[Q];for(let X of Q.children)Z.push(...RQ(X));return Z}function C(Q){if(Q.path.length<=1)return`commands/${Q.name}.md`;return`commands/${Q.path.slice(1).join("/")}.md`}function WQ(Q){return Q.path.join(" ")}function $Q(Q,Z){let X=Q.split("/").slice(0,-1),$=Z.split("/"),W=0;while(W<X.length&&W<$.length&&X[W]===$[W])W++;let H=X.length-W,B=$.slice(W);if(H===0)return B.join("/");return[...Array.from({length:H},()=>".."),...B].join("/")}function HZ(Q,Z,X){let $=[];if($.push("---"),$.push(`name: ${u(Z.name)}`),$.push(`description: ${u(Z.description)}`),Z.license)$.push(`license: ${u(Z.license)}`);if(Z.compatibility)$.push(`compatibility: ${u(Z.compatibility)}`);if(Z.disableModelInvocation)$.push("disable-model-invocation: true");if(Z.allowedTools)$.push(`allowed-tools: ${u(Z.allowedTools)}`);if($.push("metadata:"),$.push(` version: "${Z.version}"`),$.push("---"),$.push(""),$.push(`# ${Z.name}`),$.push(""),Q.description)$.push(Q.description),$.push("");let W=Z.name.startsWith("use-")?Z.name.slice(4):Z.name;$.push(`Use this skill when you need accurate help with \`${W}\` commands, including command selection, syntax, arguments, flags, defaults, and subcommands.`),$.push("");let H=UZ(Z.instructions);if($.push("## How to Use This Skill"),$.push(""),$.push("1. Find the command that best matches the user's task from the Command Reference below"),$.push("2. Check the `Type` column before suggesting execution: `runnable` and `runnable, group` commands can be executed, while `group` commands are organizational only"),$.push("3. Read only the linked file or files you need from `commands/`"),$.push("4. Before answering a command-specific question or suggesting a command, read that command's file"),$.push("5. Treat the command file as the source of truth for usage, arguments, flags, aliases, and defaults"),$.push("6. If a flag, argument, alias, or default is not documented there, say it is not documented instead of guessing"),$.push(""),ZQ(H))$.push("## General Guidance"),$.push(""),$.push(...H),$.push("");if($.push("## Command Reference"),$.push(""),$.push("Use this table to locate the command file you need."),$.push(""),$.push(...YZ(X)),$.push(""),Q.runnable){$.push("## Usage"),$.push("");let B=C(Q);$.push(`The root command is directly executable. See [${Q.name}](${B}) for usage details.`),$.push("")}return $.join(`
3
- `)}function YZ(Q){let Z=[];Z.push("| Command | Type | Documentation |"),Z.push("| ------- | ---- | ------------- |");for(let X of Q){let $=WQ(X),W=C(X),H=qZ(X);Z.push(`| \`${$}\` | ${H} | [${W}](${W}) |`)}return Z}function qZ(Q){if(Q.runnable&&Q.children.length>0)return"runnable, group";if(Q.runnable)return"runnable";return"group"}function BZ(Q,Z){let X=[];return X.push(...yQ(Q)),X.push(...TQ(Q)),X.push(..._Q(Q)),X.push(...bQ(Q,Z)),X.join(`
4
- `)}function JZ(Q,Z){let X=[],$=C(Q);if(X.push(...yQ(Q)),X.push(...TQ(Q)),Q.runnable)X.push(..._Q(Q));return X.push(...KZ(Q,$)),X.push(...bQ(Q,Z)),X.join(`
5
- `)}function zZ(Q){let Z=[...Q.path];for(let X of Q.args)if(X.variadic)Z.push(X.required?`<${X.name}...>`:`[${X.name}...]`);else Z.push(X.required?`<${X.name}>`:`[${X.name}]`);if(Q.flags.length>0)Z.push("[options]");return Z.join(" ")}function yQ(Q){let Z=[`# \`${WQ(Q)}\``,""];if(Q.description)Z.push(Q.description,"");return Z}function TQ(Q){let Z=Q.instructions??[];if(!ZQ(Z))return[];return["## Command Instructions","",...kQ(Z),""]}function _Q(Q){let Z=["## Usage","","```",Q.usage??zZ(Q),"```",""];if(Q.args.length>0)Z.push("## Arguments","",...xZ(Q.args),"");if(Q.flags.length>0)Z.push("## Flags","",...FZ(Q.flags),"");return Z.push("## Command Documentation Authority","","Only arguments, flags, options, aliases, and defaults documented in this file are supported for this command.","Do not infer or invent additional command-line options.",""),Z}function KZ(Q,Z){let X=["## Subcommands",""];for(let $ of Q.children){let W=C($),H=$Q(Z,W),B=$.description?` - ${$.description}`:"";X.push(`- [\`${$.name}\`](${H})${B}`)}return X.push(""),X}function xZ(Q){let Z=[];Z.push("| Argument | Type | Required | Description |"),Z.push("| -------- | ---- | -------- | ----------- |");for(let X of Q){let $=X.variadic?`${X.name}...`:X.name,W=X.required?"Yes":"No",H=OQ(GZ(X));Z.push(`| \`${$}\` | ${X.type} | ${W} | ${H} |`)}return Z}function GZ(Q){let Z=[];if(Q.description)Z.push(Q.description);if(Q.default!==void 0)Z.push(`Default: \`${Q.default}\``);return Z.join(". ")||"-"}function FZ(Q){let Z=[];Z.push("| Flag | Type | Required | Description |"),Z.push("| ---- | ---- | -------- | ----------- |");for(let X of Q){let $=MZ(X),W=X.required?"Yes":"No",H=OQ(wZ(X));Z.push(`| ${$} | ${X.type} | ${W} | ${H} |`)}return Z}function MZ(Q){let Z=[`\`--${Q.name}\``];if(Q.short)Z.push(`\`-${Q.short}\``);for(let X of Q.aliases)Z.push(`\`--${X}\``);return Z.join(", ")}function wZ(Q){let Z=[];if(Q.description)Z.push(Q.description);if(Q.multiple)Z.push("Can be specified multiple times");if(Q.default!==void 0)Z.push(`Default: \`${Q.default}\``);return Z.join(". ")||"-"}function kQ(Q){return Q.map((Z)=>`- ${Z}`)}function UZ(Q){if(typeof Q==="string")return GQ(Q);return kQ(i(Q))}function bQ(Q,Z){let X=[],$=C(Q);if(X.push("---"),X.push(""),Q.path.length>1){let H=Q.path.slice(0,-1),B=EQ(Z,H);if(B){let z=C(B),J=$Q($,z),K=WQ(B);X.push(`Parent: [\`${K}\`](${J})`),X.push("")}}let W=$Q($,"SKILL.md");return X.push(`[Skill Overview](${W})`),X.push(""),X}function EQ(Q,Z){if(OZ(Q.path,Z))return Q;for(let X of Q.children){let $=EQ(X,Z);if($)return $}return}function OZ(Q,Z){if(Q.length!==Z.length)return!1;for(let X=0;X<Q.length;X++)if(Q[X]!==Z[X])return!1;return!0}import{readFile as VZ}from"fs/promises";import{join as RZ}from"path";var HQ="crust.json";async function m(Q){try{let Z=await VZ(RZ(Q,HQ),"utf-8"),X=JSON.parse(Z);if(typeof X==="object"&&X!==null&&"version"in X&&typeof X.version==="string")return X.version;return null}catch{return null}}var bZ="auto",vQ=/^[a-z0-9]+(-[a-z0-9]+)*$/;function SQ(Q){return Q.length>=1&&Q.length<=64&&vQ.test(Q)}function S(Q){return Q.startsWith("use-")?Q:`use-${Q}`}async function A(Q){let{command:Z,meta:X,agents:$,scope:W="global",clean:H=!0,force:B=!1,installMode:z=bZ}=Q,J=S(X.name);if(!SQ(J))throw Error(`Invalid skill name "${J}": must be 1\u201364 lowercase `+`alphanumeric characters and hyphens, no leading/trailing/consecutive hyphens. Pattern: ${vQ.source}`);let K=$[0];if(!K)return{agents:[]};let x={...X,name:J},F=MQ(Z),M=VQ(F,x),h=NZ(x),N=[...M,...h].sort((G,V)=>G.path<V.path?-1:G.path>V.path?1:0),t=N.map((G)=>G.path),R=new Map;for(let G of $){let V=v(G,W,x.name),T=R.get(V);if(T)T.push(G);else R.set(V,[G])}let l=new Map;for(let G of R.keys())l.set(G,await m(G));let y=s(W,x.name),p=await m(y);if(p===null){if(await fQ(y)&&!B)throw new b({agent:K,outputDir:v(K,W,x.name)})}let g=p!==x.version;if(g){if(H)await BQ(y);await hQ(y,N)}let L=[];for(let[G,V]of R){let T=V[0];if(!T)continue;let E=l.get(G)??null,q=await AQ(G,y),w=E!==null||q.exists&&q.isSymlink&&q.pointsToCanonical;if(q.exists&&!w&&!B)throw new b({agent:T,outputDir:G});let U=await PZ({outputDir:G,canonicalOutputDir:y,allFiles:N,clean:H,installMode:z,inspection:q,installedVersion:E,currentVersion:x.version}),O=EZ({installedVersion:E,currentVersion:x.version,canonicalChanged:g,pathChanged:U});for(let n of V)L.push({agent:n,outputDir:G,files:O==="up-to-date"?[]:t,status:O,previousVersion:O==="updated"?E??void 0:void 0})}return{agents:L}}async function qQ(Q){let{name:Z,agents:X,scope:$="global"}=Q,W=S(Z),H=s($,W),B=[],z=new Map;for(let K of X){let x=v(K,$,W),F=z.get(x);if(F)F.push(K);else z.set(x,[K])}for(let[K,x]of z)if(await fQ(K)){await YQ(K,{recursive:!0,force:!0});for(let M of x)B.push({agent:M,outputDir:K,status:"removed"})}else for(let M of x)B.push({agent:M,outputDir:K,status:"not-found"});if(!await CZ(W,$))await YQ(H,{recursive:!0,force:!0});return{agents:B}}async function d(Q){let{name:Z,agents:X,scope:$="global"}=Q,W=S(Z),H=[],B=new Map;for(let z of X){let J=v(z,$,W),K=B.get(J);if(K)K.push(z);else B.set(J,[z])}for(let[z,J]of B){let K=await m(z);for(let x of J)H.push({agent:x,outputDir:z,installed:K!==null,version:K??void 0})}return{agents:H}}function EZ(Q){let{installedVersion:Z,currentVersion:X,canonicalChanged:$,pathChanged:W}=Q;if(Z===null)return"installed";if(Z===X&&!$&&!W)return"up-to-date";return"updated"}async function PZ(Q){let{outputDir:Z,canonicalOutputDir:X,allFiles:$,clean:W,installMode:H,inspection:B,installedVersion:z,currentVersion:J}=Q;if(H==="copy")return jQ({outputDir:Z,allFiles:$,clean:W,inspection:B,installedVersion:z,currentVersion:J});try{return await jZ({outputDir:Z,canonicalOutputDir:X,inspection:B})}catch(K){if(H==="symlink")throw Error(`Failed to create symlink at "${Z}" (installMode: symlink).`,{cause:K});let x=await AQ(Z,X);return jQ({outputDir:Z,allFiles:$,clean:W,inspection:x,installedVersion:z,currentVersion:J})}}async function jQ(Q){let{outputDir:Z,allFiles:X,clean:$,inspection:W,installedVersion:H,currentVersion:B}=Q;if(!(!W.exists||W.isSymlink||H!==B))return!1;if(W.isSymlink||$)await BQ(Z);return await hQ(Z,X),!0}async function jZ(Q){let{outputDir:Z,canonicalOutputDir:X,inspection:$}=Q;if($.exists&&$.isSymlink&&$.pointsToCanonical)return!1;if($.exists)await BQ(Z);return await IZ(X,Z),!0}async function AQ(Q,Z){let X;try{X=await NQ(Q)}catch{return{exists:!1,isSymlink:!1,pointsToCanonical:!1}}let $=process.platform==="win32"&&X.isDirectory()&&await CQ(Q)!==null;if(!(X.isSymbolicLink()||$))return{exists:!0,isSymlink:!1,pointsToCanonical:!1};let[H,B,z]=await Promise.all([IQ(Q),IQ(Z),CQ(Q)]);return{exists:!0,isSymlink:!0,pointsToCanonical:H!==null&&B!==null&&H===B||z===Z}}async function IQ(Q){try{return await TZ(Q)}catch{return null}}async function CQ(Q){try{return await yZ(Q)}catch{return null}}async function IZ(Q,Z){await LQ(DQ(Z),{recursive:!0});let X=process.platform==="win32"?"junction":"dir";await _Z(Q,Z,X)}async function fQ(Q){try{return await NQ(Q),!0}catch{return!1}}async function CZ(Q,Z){let X=new Set;for(let $ of c)X.add(v($,Z,Q));for(let $ of X)if(await m($)!==null)return!0;return!1}function NZ(Q){let Z={name:Q.name,description:Q.description,version:Q.version};return[{path:HQ,content:`${JSON.stringify(Z,null,"\t")}
6
- `}]}async function BQ(Q){await YQ(Q,{recursive:!0,force:!0})}async function hQ(Q,Z){let X=new Set;for(let W of Z){let H=PQ(Q,W.path),B=DQ(H);X.add(B)}let $=[...X].sort();for(let W of $)await LQ(W,{recursive:!0});for(let W of Z){let H=PQ(Q,W.path);await kZ(H,W.content,"utf-8")}}import{Crust as gQ,VALIDATION_MODE_ENV as LZ}from"@crustjs/core";import{confirm as DZ,multiselect as vZ,select as SZ,spinner as r}from"@crustjs/prompts";import{bold as a,dim as f,yellow as cQ}from"@crustjs/style";var AZ="skill",fZ="global",o="__universal__";function hZ(Q){return Q==="global"||Q==="project"}async function uQ(Q,Z){if(Q!==void 0){if(!hZ(Q))throw Error(`Invalid --scope value: ${String(Q)}. Expected "project" or "global".`);return Q}if(Z.defaultScope)return Z.defaultScope;return SZ({message:"Select scope",choices:[{label:"Project",value:"project"},{label:"Global",value:"global"}],default:fZ})}function JQ(Q){let Z=new Set(I()),X=[];if(Q.some(($)=>Z.has($)))X.push("Universal");for(let $ of Q){if(Z.has($))continue;X.push(j[$])}return X}function pQ(Q){let Z=new Set(I()),X=[],$=Q.find((W)=>Z.has(W.agent));if($)X.push({label:"Universal",outputDir:$.outputDir});for(let W of Q){if(Z.has(W.agent))continue;X.push({label:j[W.agent],outputDir:W.outputDir})}return X}function zQ(Q,Z){return{name:Q.meta.name,description:Q.meta.description??"",version:Z.version,instructions:Z.instructions,license:Z.license,allowedTools:Z.allowedTools,compatibility:Z.compatibility,disableModelInvocation:Z.disableModelInvocation}}async function pZ(Q,Z){let X=[...I(),...D()];if(X.length===0)return;let $=zQ(Q,Z),W=["project","global"];for(let H of W){let z=(await d({name:$.name,agents:X,scope:H})).agents.filter((J)=>J.installed&&J.version!==$.version);if(z.length===0)continue;try{await r({message:`Updating ${H} skills...`,task:async({updateMessage:J})=>{let K=await A({command:Q,meta:$,agents:z.map((M)=>M.agent),scope:H,installMode:Z.installMode}),x=K.agents.filter((M)=>M.status==="updated").map((M)=>M.agent),F=JQ(x);if(F.length>0)J(`Updated skill "${S($.name)}" to v${$.version} for ${F.join(", ")} (${H})`);return K}})}catch(J){if(J instanceof b)console.warn(cQ(`Skill conflict: "${J.details.outputDir}" already exists but was not created by ${$.name}. Skipping auto-update for ${H}. Delete or rename the conflicting skill to resolve.`));else throw J}}}function gZ(Q){let Z;return{name:"skills",async setup(X,$){Z=X.rootCommand;let W=Q.command??AZ;if($.addSubCommand(Z,W,cZ(Z,Q,W)),process.env[LZ]==="1")return;if(X.argv[0]===W)return;if(Q.autoUpdate!==!1)await pZ(Z,Q)}}}function cZ(Q,Z,X){let $=uZ(Q,Z);return new gQ(X).meta({description:"Manage agent skill installations"}).flags({scope:{type:"string",description:"Install scope (project or global)"}}).run(async(W)=>{let H=zQ(Q,Z),B=await uQ(W.flags.scope,Z),z=await QQ(),J=I(),K=D(),x=await d({name:H.name,agents:[...J,...K],scope:B}),F=new Set(x.agents.filter((q)=>q.installed).map((q)=>q.agent)),M=new Set(z),h=new Map(x.agents.map((q)=>[q.agent,q])),N=K.filter((q)=>{if(M.has(q))return!0;return h.get(q)?.installed===!0}),t=N.filter((q)=>F.has(q)),R=[];if(J.length>0){let q=J[0];if(!q)throw Error("Expected at least one universal agent");let U=h.get(q)?.outputDir??"path unavailable";R.push({label:"Universal",value:o,hint:U});let O=J.map((n)=>j[n]).join(", ");console.log(f(`Agents supporting universal skills: ${O}`))}for(let q of N){let U=h.get(q)?.outputDir??"path unavailable";R.push({label:j[q],value:q,hint:U})}let l=J.length>0&&J.every((q)=>F.has(q)),y=[...t.filter((q)=>!J.includes(q))];if(l)y.unshift(o);let p=R.length===0?[]:await vZ({message:"Select agents to install skills for",choices:R,default:y,required:!1}),g=new Set(p.filter((q)=>q!==o));if(p.includes(o))for(let q of J)g.add(q);let L=[...g],G=L.filter((q)=>!F.has(q)),V=L.filter((q)=>{let w=x.agents.find((U)=>U.agent===q);return w?.installed===!0&&w.version!==H.version}),T=[...F].filter((q)=>!L.includes(q)),E=[...G,...V];if(E.length>0)try{let q=await r({message:"Installing skills...",task:async()=>A({command:Q,meta:H,agents:E,scope:B,installMode:Z.installMode})});console.log(`
7
- ${a(`Installed "${H.name}" v${H.version}`)}`);for(let w of pQ(q.agents))console.log(f(` ${w.label} \u2192 ${w.outputDir}`))}catch(q){if(q instanceof b)if(await DZ({message:`"${q.details.outputDir}" already exists but was not created by Crust. Overwrite?`,default:!1})){let U=await r({message:"Overwriting skill...",task:async()=>A({command:Q,meta:H,agents:[q.details.agent],scope:B,force:!0,installMode:Z.installMode})});console.log(`
8
- ${a(`Installed "${H.name}" v${H.version}`)}`);for(let O of pQ(U.agents))console.log(f(` ${O.label} \u2192 ${O.outputDir}`))}else console.log(f(`
9
- Skipped ${j[q.details.agent]}`));else throw q}if(T.length>0){let w=(await r({message:"Removing skills...",task:async()=>qQ({name:H.name,agents:T,scope:B})})).agents.filter((O)=>O.status==="removed").map((O)=>O.agent),U=JQ(w);if(U.length>0)console.log(`
10
- ${a(`Removed from ${U.join(", ")}`)}`)}if(E.length===0&&T.length===0)console.log(f("No changes."))}).command($)._node}function uZ(Q,Z){return new gQ("update").meta({description:"Update installed skills to latest version"}).flags({scope:{type:"string",description:"Update scope (project or global)"}}).run(async(X)=>{let $=await uQ(X.flags.scope,Z),W=[...I(),...D()],H=zQ(Q,Z),z=(await d({name:H.name,agents:W,scope:$})).agents.filter((J)=>J.installed&&J.version!==H.version);if(z.length===0){console.log(f(`No updates needed (${$}).`));return}try{let K=(await r({message:`Updating ${$} skills...`,task:async()=>A({command:Q,meta:H,agents:z.map((F)=>F.agent),scope:$,installMode:Z.installMode})})).agents.filter((F)=>F.status==="updated").map((F)=>F.agent),x=JQ(K);if(x.length>0)console.log(`
11
- ${a(`Updated "${H.name}" to v${H.version} for ${x.join(", ")} (${$})`)}`)}catch(J){if(J instanceof b)console.warn(cQ(`Skipped ${j[J.details.agent]}: "${J.details.outputDir}" already exists but was not created by ${H.name}. Delete or rename the conflicting directory to resolve.`));else throw J}})}export{qQ as uninstallSkill,d as skillStatus,gZ as skillPlugin,S as resolveSkillName,s as resolveCanonicalSkillPath,SQ as isValidSkillName,iQ as isUniversalAgent,I as getUniversalAgents,D as getAdditionalAgents,A as generateSkill,QQ as detectInstalledAgents,nQ as annotate,b as SkillConflictError};
2
+ import{accessSync as aQ,constants as nQ}from"fs";import{homedir as e}from"os";import{delimiter as tQ,join as Y}from"path";var k=Y(".agents","skills"),eQ=Y(".crust","skills");function VQ(Q){if(Q!==e())return Y(Q,".config");let Z=process.env.XDG_CONFIG_HOME?.trim();return Z&&Z.length>0?Z:Y(Q,".config")}function j(Q){return Y(Q,".agents","skills")}function QZ(Q){return Y(Q,".crust","skills")}var C={amp:{label:"Amp",class:"universal",projectSkillsDir:k,globalSkillsDir:j},adal:{label:"AdaL",class:"additional",projectSkillsDir:Y(".adal","skills"),globalSkillsDir:(Q)=>Y(Q,".adal","skills"),detectCommands:["adal"]},antigravity:{label:"Antigravity",class:"additional",projectSkillsDir:Y(".agent","skills"),globalSkillsDir:(Q)=>Y(Q,".gemini","antigravity","skills"),detectCommands:["antigravity"]},augment:{label:"Augment",class:"additional",projectSkillsDir:Y(".augment","skills"),globalSkillsDir:(Q)=>Y(Q,".augment","skills"),detectCommands:["augment"]},"claude-code":{label:"Claude Code",class:"additional",projectSkillsDir:Y(".claude","skills"),globalSkillsDir:(Q)=>Y(process.env.CLAUDE_CONFIG_DIR?.trim()||Y(Q,".claude"),"skills"),detectCommands:["claude","claude-code"]},cline:{label:"Cline",class:"universal",projectSkillsDir:k,globalSkillsDir:j},codebuddy:{label:"CodeBuddy",class:"additional",projectSkillsDir:Y(".codebuddy","skills"),globalSkillsDir:(Q)=>Y(Q,".codebuddy","skills"),detectCommands:["codebuddy"]},codex:{label:"Codex",class:"universal",projectSkillsDir:k,globalSkillsDir:j},"command-code":{label:"Command Code",class:"additional",projectSkillsDir:Y(".commandcode","skills"),globalSkillsDir:(Q)=>Y(Q,".commandcode","skills"),detectCommands:["command-code","commandcode"]},continue:{label:"Continue",class:"additional",projectSkillsDir:Y(".continue","skills"),globalSkillsDir:(Q)=>Y(Q,".continue","skills"),detectCommands:["continue"]},cortex:{label:"Cortex Code",class:"additional",projectSkillsDir:Y(".cortex","skills"),globalSkillsDir:(Q)=>Y(Q,".snowflake","cortex","skills"),detectCommands:["cortex"]},crush:{label:"Crush",class:"additional",projectSkillsDir:Y(".crush","skills"),globalSkillsDir:(Q)=>Y(VQ(Q),"crush","skills"),detectCommands:["crush"]},cursor:{label:"Cursor",class:"universal",projectSkillsDir:k,globalSkillsDir:j},droid:{label:"Droid",class:"additional",projectSkillsDir:Y(".factory","skills"),globalSkillsDir:(Q)=>Y(Q,".factory","skills"),detectCommands:["droid"]},"gemini-cli":{label:"Gemini CLI",class:"universal",projectSkillsDir:k,globalSkillsDir:j},"github-copilot":{label:"GitHub Copilot",class:"universal",projectSkillsDir:k,globalSkillsDir:j},goose:{label:"Goose",class:"additional",projectSkillsDir:Y(".goose","skills"),globalSkillsDir:(Q)=>Y(VQ(Q),"goose","skills"),detectCommands:["goose"]},"iflow-cli":{label:"iFlow CLI",class:"additional",projectSkillsDir:Y(".iflow","skills"),globalSkillsDir:(Q)=>Y(Q,".iflow","skills"),detectCommands:["iflow","iflow-cli"]},junie:{label:"Junie",class:"additional",projectSkillsDir:Y(".junie","skills"),globalSkillsDir:(Q)=>Y(Q,".junie","skills"),detectCommands:["junie"]},kilo:{label:"Kilo Code",class:"additional",projectSkillsDir:Y(".kilocode","skills"),globalSkillsDir:(Q)=>Y(Q,".kilocode","skills"),detectCommands:["kilo","kilocode"]},"kimi-cli":{label:"Kimi Code CLI",class:"universal",projectSkillsDir:k,globalSkillsDir:j},"kiro-cli":{label:"Kiro CLI",class:"additional",projectSkillsDir:Y(".kiro","skills"),globalSkillsDir:(Q)=>Y(Q,".kiro","skills"),detectCommands:["kiro","kiro-cli"]},kode:{label:"Kode",class:"additional",projectSkillsDir:Y(".kode","skills"),globalSkillsDir:(Q)=>Y(Q,".kode","skills"),detectCommands:["kode"]},mcpjam:{label:"MCPJam",class:"additional",projectSkillsDir:Y(".mcpjam","skills"),globalSkillsDir:(Q)=>Y(Q,".mcpjam","skills"),detectCommands:["mcpjam"]},"mistral-vibe":{label:"Mistral Vibe",class:"additional",projectSkillsDir:Y(".vibe","skills"),globalSkillsDir:(Q)=>Y(Q,".vibe","skills"),detectCommands:["mistral-vibe","vibe"]},mux:{label:"Mux",class:"additional",projectSkillsDir:Y(".mux","skills"),globalSkillsDir:(Q)=>Y(Q,".mux","skills"),detectCommands:["mux"]},neovate:{label:"Neovate",class:"additional",projectSkillsDir:Y(".neovate","skills"),globalSkillsDir:(Q)=>Y(Q,".neovate","skills"),detectCommands:["neovate"]},opencode:{label:"OpenCode",class:"universal",projectSkillsDir:k,globalSkillsDir:j},openclaw:{label:"OpenClaw",class:"additional",projectSkillsDir:"skills",globalSkillsDir:(Q)=>Y(Q,".openclaw","skills"),detectCommands:["openclaw"]},openhands:{label:"OpenHands",class:"additional",projectSkillsDir:Y(".openhands","skills"),globalSkillsDir:(Q)=>Y(Q,".openhands","skills"),detectCommands:["openhands"]},pi:{label:"Pi",class:"additional",projectSkillsDir:Y(".pi","skills"),globalSkillsDir:(Q)=>Y(Q,".pi","agent","skills"),detectCommands:["pi"]},pochi:{label:"Pochi",class:"additional",projectSkillsDir:Y(".pochi","skills"),globalSkillsDir:(Q)=>Y(Q,".pochi","skills"),detectCommands:["pochi"]},qoder:{label:"Qoder",class:"additional",projectSkillsDir:Y(".qoder","skills"),globalSkillsDir:(Q)=>Y(Q,".qoder","skills"),detectCommands:["qoder"]},"qwen-code":{label:"Qwen Code",class:"additional",projectSkillsDir:Y(".qwen","skills"),globalSkillsDir:(Q)=>Y(Q,".qwen","skills"),detectCommands:["qwen","qwen-code"]},replit:{label:"Replit",class:"universal",projectSkillsDir:k,globalSkillsDir:j},roo:{label:"Roo Code",class:"additional",projectSkillsDir:Y(".roo","skills"),globalSkillsDir:(Q)=>Y(Q,".roo","skills"),detectCommands:["roo","roo-code"]},trae:{label:"Trae",class:"additional",projectSkillsDir:Y(".trae","skills"),globalSkillsDir:(Q)=>Y(Q,".trae","skills"),detectCommands:["trae"]},"trae-cn":{label:"Trae CN",class:"additional",projectSkillsDir:Y(".trae","skills"),globalSkillsDir:(Q)=>Y(Q,".trae-cn","skills"),detectCommands:["trae-cn","trae"]},windsurf:{label:"Windsurf",class:"additional",projectSkillsDir:Y(".windsurf","skills"),globalSkillsDir:(Q)=>Y(Q,".codeium","windsurf","skills"),detectCommands:["windsurf"]},zencoder:{label:"Zencoder",class:"additional",projectSkillsDir:Y(".zencoder","skills"),globalSkillsDir:(Q)=>Y(Q,".zencoder","skills"),detectCommands:["zencoder"]}},u=Object.keys(C),y=Object.fromEntries(u.map((Q)=>[Q,C[Q].label]));function S(){return u.filter((Q)=>C[Q].class==="universal")}function h(){return u.filter((Q)=>C[Q].class==="additional")}function ZZ(Q){return C[Q].class==="universal"}async function QQ(Q){let Z=typeof Q==="string"?{home:Q}:Q??{},X=Z.cwd??process.cwd(),$=Z.commandChecker??((H)=>Promise.resolve(XZ(H))),W=[];for(let H of h()){let B=C[H].detectCommands??[],z=!1;for(let J of B)if(await $(J,X)){z=!0;break}if(z)W.push(H)}return W}function O(Q,Z,X){let $=C[Q];if(Z==="project")return Y(process.cwd(),$.projectSkillsDir,X);return Y($.globalSkillsDir(e()),X)}function P(Q,Z){if(Q==="project")return Y(process.cwd(),eQ,Z);return Y(QZ(e()),Z)}function XZ(Q){let X=(process.env.PATH??"").split(tQ).filter((H)=>H.length>0),$=process.platform==="win32",W=$?(process.env.PATHEXT??".EXE;.CMD;.BAT;.COM").split(";").filter((H)=>H.length>0):[];for(let H of X){if(!$&&MQ(Y(H,Q)))return!0;if($){for(let B of W)if(MQ(Y(H,Q+B)))return!0}}return!1}function MQ(Q){try{return aQ(Q,nQ.X_OK),!0}catch{return!1}}import{Crust as $Z}from"@crustjs/core";function s(Q){if(Q===void 0)return[];return(Array.isArray(Q)?Q:[Q]).flatMap((X)=>X.split(/\r?\n/)).map((X)=>X.trim()).filter((X)=>X.length>0)}function TQ(Q){let Z=Q?.trim();if(!Z)return[];return Z.split(/\r?\n/)}function ZQ(Q){return Q.length>0}var _Q=Symbol("crust.skill.commandAnnotations");function WZ(Q){return Q instanceof $Z?Q._node:Q}function HZ(Q,Z){let X=WZ(Q),$=s(typeof Z==="string"||Array.isArray(Z)?Z:Z.instructions??[]);if($.length===0)return Q;let W=XQ(X)?.instructions??[],H=[...new Set([...W,...$])];return Object.defineProperty(X,_Q,{value:{instructions:H},enumerable:!0,configurable:!0}),Q}function XQ(Q){let Z=Q[_Q];if(!Z?.instructions||Z.instructions.length===0)return;return{instructions:[...Z.instructions]}}class I extends Error{name="SkillConflictError";details;constructor(Q){let Z=`Skill conflict for agent "${Q.agent}": directory "${Q.outputDir}" already exists but was not created by Crust (no crust.json found). Delete or rename the conflicting skill to resolve.`;super(Z);this.details=Q}}import{lstat as NZ,mkdir as hQ,readlink as LZ,realpath as PZ,rm as m,symlink as CZ,writeFile as yZ}from"fs/promises";import{dirname as pQ,join as SQ}from"path";function bQ(Q){return OQ(Q,[])}function OQ(Q,Z){let X=YZ(Q.meta.name),$=[...Z,X],W=qZ(Q.args),H=JZ(Q.effectiveFlags),B=KZ(Q.subCommands,$),z=XQ(Q);return{name:X,path:$,description:Q.meta.description,usage:Q.meta.usage,instructions:z?.instructions,runnable:typeof Q.run==="function",args:W,flags:H,children:B}}function YZ(Q){return Q.trim().toLowerCase()}function qZ(Q){if(!Q||Q.length===0)return[];return Q.map(BZ)}function BZ(Q){let Z={name:Q.name,type:Q.type,required:Q.required===!0,variadic:Q.variadic===!0};if(Q.description!==void 0)Z.description=Q.description;if(Q.default!==void 0)Z.default=RQ(Q.default);return Z}function JZ(Q){if(!Q)return[];return Object.keys(Q).sort().map((X)=>{return zZ(X,Q[X])})}function zZ(Q,Z){let X={name:Q,type:Z.type,required:Z.required===!0,multiple:Z.multiple===!0,short:Z.short,aliases:Z.aliases?[...Z.aliases].sort():[]};if(Z.description!==void 0)X.description=Z.description;if(Z.default!==void 0)X.default=RQ(Z.default);return X}function KZ(Q,Z){return Object.keys(Q).sort().map(($)=>{return OQ(Q[$],Z)})}function RQ(Q){if(Array.isArray(Q))return JSON.stringify(Q);return String(Q)}function c(Q){if(/[:#[\]{}&*!|>'"`,@?\\]|^\s|\s$|^---|[\n\r]/.test(Q))return`"${Q.replace(/\\/g,"\\\\").replace(/"/g,"\\\"").replace(/\n/g,"\\n").replace(/\r/g,"\\r")}"`;return Q}function EQ(Q){return Q.replace(/(?<!\\)\|/g,"\\|")}function kQ(Q,Z){let X=[],$=jQ(Q);X.push({path:"SKILL.md",content:xZ(Q,Z,$)});for(let W of $){let H=D(W),B=W.children.length>0?UZ(W,Q):wZ(W,Q);X.push({path:H,content:B})}return X}function jQ(Q){let Z=[Q];for(let X of Q.children)Z.push(...jQ(X));return Z}function D(Q){if(Q.path.length<=1)return`commands/${Q.name}.md`;return`commands/${Q.path.slice(1).join("/")}.md`}function WQ(Q){return Q.path.join(" ")}function $Q(Q,Z){let X=Q.split("/").slice(0,-1),$=Z.split("/"),W=0;while(W<X.length&&W<$.length&&X[W]===$[W])W++;let H=X.length-W,B=$.slice(W);if(H===0)return B.join("/");return[...Array.from({length:H},()=>".."),...B].join("/")}function xZ(Q,Z,X){let $=[];if($.push("---"),$.push(`name: ${c(Z.name)}`),$.push(`description: ${c(Z.description)}`),Z.license)$.push(`license: ${c(Z.license)}`);if(Z.compatibility)$.push(`compatibility: ${c(Z.compatibility)}`);if(Z.disableModelInvocation)$.push("disable-model-invocation: true");if(Z.allowedTools)$.push(`allowed-tools: ${c(Z.allowedTools)}`);if($.push("metadata:"),$.push(` version: "${Z.version}"`),$.push("---"),$.push(""),$.push(`# ${Z.name}`),$.push(""),Q.description)$.push(Q.description),$.push("");$.push(`You should use this skill when you need accurate help with \`${Z.name}\` commands, including command selection, syntax, arguments, flags, defaults, and subcommands.`),$.push("");let W=EZ(Z.instructions);if($.push("## How to Use This Skill"),$.push(""),$.push("1. You must find the command that best matches the user's task from the Command Reference below."),$.push("2. You must check the `Type` column before suggesting execution: `runnable` and `runnable, group` commands can be executed, while `group` commands are organizational only."),$.push("3. You should read only the linked file or files you need from `commands/`."),$.push("4. You must read a command's file before answering a command-specific question or suggesting that command."),$.push("5. You must treat the command file as the source of truth for usage, arguments, flags, aliases, and defaults."),$.push("6. If a flag, argument, alias, or default is not documented there, you must say it is not documented instead of guessing."),$.push(""),ZQ(W))$.push("## General Guidance"),$.push(""),$.push(...W),$.push("");if($.push("## Command Reference"),$.push(""),$.push("You should use this table to locate the command file you need."),$.push(""),$.push(...GZ(X)),$.push(""),Q.runnable){$.push("## Usage"),$.push("");let H=D(Q);$.push(`The root command is directly executable. You should see [${Q.name}](${H}) for usage details.`),$.push("")}return $.join(`
3
+ `)}function GZ(Q){let Z=[];Z.push("| Command | Type | Documentation |"),Z.push("| ------- | ---- | ------------- |");for(let X of Q){let $=WQ(X),W=D(X),H=FZ(X);Z.push(`| \`${$}\` | ${H} | [${W}](${W}) |`)}return Z}function FZ(Q){if(Q.runnable&&Q.children.length>0)return"runnable, group";if(Q.runnable)return"runnable";return"group"}function wZ(Q,Z){let X=[];return X.push(...IQ(Q)),X.push(...NQ(Q)),X.push(...LQ(Q)),X.push(...CQ(Q,Z)),X.join(`
4
+ `)}function UZ(Q,Z){let X=[],$=D(Q);if(X.push(...IQ(Q)),X.push(...NQ(Q)),Q.runnable)X.push(...LQ(Q));return X.push(...MZ(Q,$)),X.push(...CQ(Q,Z)),X.join(`
5
+ `)}function VZ(Q){let Z=[...Q.path];for(let X of Q.args)if(X.variadic)Z.push(X.required?`<${X.name}...>`:`[${X.name}...]`);else Z.push(X.required?`<${X.name}>`:`[${X.name}]`);if(Q.flags.length>0)Z.push("[options]");return Z.join(" ")}function IQ(Q){let Z=[`# \`${WQ(Q)}\``,""];if(Q.description)Z.push(Q.description,"");return Z}function NQ(Q){let Z=Q.instructions??[];if(!ZQ(Z))return[];return["## Command Instructions","",...PQ(Z),""]}function LQ(Q){let Z=["## Usage","","```",Q.usage??VZ(Q),"```",""];if(Q.args.length>0)Z.push("## Arguments","",...TZ(Q.args),"");if(Q.flags.length>0)Z.push("## Flags","",...bZ(Q.flags),"");return Z.push("## Command Documentation Authority","","You must treat only the arguments, flags, options, aliases, and defaults documented in this file as supported for this command.","You must not infer or invent additional command-line options.",""),Z}function MZ(Q,Z){let X=["## Subcommands",""];for(let $ of Q.children){let W=D($),H=$Q(Z,W),B=$.description?` - ${$.description}`:"";X.push(`- [\`${$.name}\`](${H})${B}`)}return X.push(""),X}function TZ(Q){let Z=[];Z.push("| Argument | Type | Required | Description |"),Z.push("| -------- | ---- | -------- | ----------- |");for(let X of Q){let $=X.variadic?`${X.name}...`:X.name,W=X.required?"Yes":"No",H=EQ(_Z(X));Z.push(`| \`${$}\` | ${X.type} | ${W} | ${H} |`)}return Z}function _Z(Q){let Z=[];if(Q.description)Z.push(Q.description);if(Q.default!==void 0)Z.push(`Default: \`${Q.default}\``);return Z.join(". ")||"-"}function bZ(Q){let Z=[];Z.push("| Flag | Type | Required | Description |"),Z.push("| ---- | ---- | -------- | ----------- |");for(let X of Q){let $=OZ(X),W=X.required?"Yes":"No",H=EQ(RZ(X));Z.push(`| ${$} | ${X.type} | ${W} | ${H} |`)}return Z}function OZ(Q){let Z=[`\`--${Q.name}\``];if(Q.short)Z.push(`\`-${Q.short}\``);for(let X of Q.aliases)Z.push(`\`--${X}\``);return Z.join(", ")}function RZ(Q){let Z=[];if(Q.description)Z.push(Q.description);if(Q.multiple)Z.push("Can be specified multiple times");if(Q.default!==void 0)Z.push(`Default: \`${Q.default}\``);return Z.join(". ")||"-"}function PQ(Q){return Q.map((Z)=>`- ${Z}`)}function EZ(Q){if(typeof Q==="string")return TQ(Q);return PQ(s(Q))}function CQ(Q,Z){let X=[],$=D(Q);if(X.push("---"),X.push(""),Q.path.length>1){let H=Q.path.slice(0,-1),B=yQ(Z,H);if(B){let z=D(B),J=$Q($,z),K=WQ(B);X.push(`Parent: [\`${K}\`](${J})`),X.push("")}}let W=$Q($,"SKILL.md");return X.push(`[Skill Overview](${W})`),X.push(""),X}function yQ(Q,Z){if(kZ(Q.path,Z))return Q;for(let X of Q.children){let $=yQ(X,Z);if($)return $}return}function kZ(Q,Z){if(Q.length!==Z.length)return!1;for(let X=0;X<Q.length;X++)if(Q[X]!==Z[X])return!1;return!0}import{readFile as jZ}from"fs/promises";import{join as IZ}from"path";var HQ="crust.json";async function A(Q){try{let Z=await jZ(IZ(Q,HQ),"utf-8"),X=JSON.parse(Z);if(typeof X==="object"&&X!==null&&"version"in X&&typeof X.version==="string")return X.version;return null}catch{return null}}var SZ="auto",gQ=/^[a-z0-9]+(-[a-z0-9]+)*$/;function uQ(Q){return Q.length>=1&&Q.length<=64&&gQ.test(Q)}function i(Q){return Q}function BQ(Q){return Q.startsWith("use-")?Q:`use-${Q}`}async function p(Q){let{command:Z,meta:X,agents:$,scope:W="global",clean:H=!0,force:B=!1,installMode:z=SZ}=Q,J=i(X.name),K=BQ(X.name);if(!uQ(J))throw Error(`Invalid skill name "${J}": must be 1\u201364 lowercase `+`alphanumeric characters and hyphens, no leading/trailing/consecutive hyphens. Pattern: ${gQ.source}`);let x=$[0];if(!x)return{agents:[]};let G={...X,name:J},U=bQ(Z),N=kQ(U,G),M=pZ(G),b=[...N,...M].sort((q,F)=>q.path<F.path?-1:q.path>F.path?1:0),R=b.map((q)=>q.path),T=new Map;for(let q of $){let F=O(q,W,G.name),w=T.get(F);if(w)w.push(q);else T.set(F,[q])}let _=P(W,G.name),E=P(W,K),L=new Map;for(let[q,F]of T){let w=F[0];if(!w)continue;L.set(q,await KQ({outputDir:q,legacyOutputDir:O(w,W,K),canonicalOutputDir:_,legacyCanonicalOutputDir:E}))}let l=await A(_);if((await zQ(_,_)).exists&&l===null&&!B)throw new I({agent:x,outputDir:_});let v=l!==G.version;if(v){if(H)await xQ(_);await cQ(_,b)}let f=[];for(let[q,F]of T){let w=F[0];if(!w)continue;let V=L.get(q);if(!V)continue;if(V.current.inspection.exists&&!V.current.isCrustManaged&&!B)throw new I({agent:w,outputDir:q});let n=await AZ({outputDir:q,canonicalOutputDir:_,allFiles:b,clean:H,installMode:z,inspection:V.current.inspection,installedVersion:V.preferredVersion,currentVersion:G.version}),iQ=await fZ(V),t=DZ({installedVersion:V.preferredVersion,currentVersion:G.version,canonicalChanged:v,pathChanged:n||iQ||V.preferredOutputDir!==q});for(let oQ of F)f.push({agent:oQ,outputDir:q,files:t==="up-to-date"?[]:R,status:t,previousVersion:t==="updated"?V.preferredVersion??void 0:void 0})}{let q=await A(E);if(E!==_&&q!==null&&!await qQ(K,W))await m(E,{recursive:!0,force:!0})}return{agents:f}}async function JQ(Q){let{name:Z,agents:X,scope:$="global"}=Q,W=i(Z),H=BQ(Z),B=P($,W),z=P($,H),J=[],K=new Map;for(let x of X){let G=O(x,$,W),U=K.get(G);if(U)U.push(x);else K.set(G,[x])}for(let[x,G]of K){let U=G[0];if(!U)continue;let N=O(U,$,H),M=await KQ({outputDir:x,legacyOutputDir:N,canonicalOutputDir:B,legacyCanonicalOutputDir:z}),b=await YQ(M.current),R=M.legacy.outputDir!==M.current.outputDir?await YQ(M.legacy):!1,T=b||R,_=b?x:R?N:x;for(let E of G)J.push({agent:E,outputDir:_,status:T?"removed":"not-found"})}if(await A(B)!==null&&!await qQ(W,$))await m(B,{recursive:!0,force:!0});{let x=await A(z);if(z!==B&&x!==null&&!await qQ(H,$))await m(z,{recursive:!0,force:!0})}return{agents:J}}async function d(Q){let{name:Z,agents:X,scope:$="global"}=Q,W=i(Z),H=BQ(Z),B=[],z=new Map;for(let J of X){let K=O(J,$,W),x=z.get(K);if(x)x.push(J);else z.set(K,[J])}for(let[J,K]of z){let x=K[0];if(!x)continue;let G=O(x,$,H),U=P($,W),N=P($,H),M=await KQ({outputDir:J,legacyOutputDir:G,canonicalOutputDir:U,legacyCanonicalOutputDir:N}),b=M.preferredOutputDir??J,R=M.preferredVersion;for(let T of K)B.push({agent:T,outputDir:b,installed:R!==null,version:R??void 0})}return{agents:B}}function DZ(Q){let{installedVersion:Z,currentVersion:X,canonicalChanged:$,pathChanged:W}=Q;if(Z===null)return"installed";if(Z===X&&!$&&!W)return"up-to-date";return"updated"}async function AZ(Q){let{outputDir:Z,canonicalOutputDir:X,allFiles:$,clean:W,installMode:H,inspection:B,installedVersion:z,currentVersion:J}=Q;if(H==="copy")return DQ({outputDir:Z,allFiles:$,clean:W,inspection:B,installedVersion:z,currentVersion:J});try{return await vZ({outputDir:Z,canonicalOutputDir:X,inspection:B})}catch(K){if(H==="symlink")throw Error(`Failed to create symlink at "${Z}" (installMode: symlink).`,{cause:K});let x=await zQ(Z,X);return DQ({outputDir:Z,allFiles:$,clean:W,inspection:x,installedVersion:z,currentVersion:J})}}async function DQ(Q){let{outputDir:Z,allFiles:X,clean:$,inspection:W,installedVersion:H,currentVersion:B}=Q;if(!(!W.exists||W.isSymlink||H!==B))return!1;if(W.isSymlink||$)await xQ(Z);return await cQ(Z,X),!0}async function vZ(Q){let{outputDir:Z,canonicalOutputDir:X,inspection:$}=Q;if($.exists&&$.isSymlink&&$.pointsToCanonical)return!1;if($.exists)await xQ(Z);return await hZ(X,Z),!0}async function zQ(Q,Z){let X;try{X=await NZ(Q)}catch{return{exists:!1,isSymlink:!1,pointsToCanonical:!1}}let $=process.platform==="win32"&&X.isDirectory()&&await fQ(Q)!==null;if(!(X.isSymbolicLink()||$))return{exists:!0,isSymlink:!1,pointsToCanonical:!1};let[H,B,z]=await Promise.all([vQ(Q),vQ(Z),fQ(Q)]);return{exists:!0,isSymlink:!0,pointsToCanonical:H!==null&&B!==null&&H===B||z===Z}}async function AQ(Q,Z){let[X,$]=await Promise.all([A(Q),zQ(Q,Z)]),W=X!==null||$.exists&&$.isSymlink&&$.pointsToCanonical;return{outputDir:Q,version:X,inspection:$,isCrustManaged:W}}async function KQ(Q){let{outputDir:Z,legacyOutputDir:X,canonicalOutputDir:$,legacyCanonicalOutputDir:W}=Q,H=await AQ(Z,$),B=X===Z?H:await AQ(X,W);if(H.isCrustManaged)return{current:H,legacy:B,preferredVersion:H.version,preferredOutputDir:H.outputDir};if(B.isCrustManaged)return{current:H,legacy:B,preferredVersion:B.version,preferredOutputDir:B.outputDir};return{current:H,legacy:B,preferredVersion:null,preferredOutputDir:null}}async function YQ(Q){if(!Q.isCrustManaged||!Q.inspection.exists)return!1;return await m(Q.outputDir,{recursive:!0,force:!0}),!0}async function fZ(Q){if(Q.legacy.outputDir===Q.current.outputDir)return!1;return YQ(Q.legacy)}async function vQ(Q){try{return await PZ(Q)}catch{return null}}async function fQ(Q){try{return await LZ(Q)}catch{return null}}async function hZ(Q,Z){await hQ(pQ(Z),{recursive:!0});let X=process.platform==="win32"?"junction":"dir";await CZ(Q,Z,X)}async function qQ(Q,Z){let X=new Set;for(let $ of u)X.add(O($,Z,Q));for(let $ of X)if(await A($)!==null)return!0;return!1}function pZ(Q){let Z={name:Q.name,description:Q.description,version:Q.version};return[{path:HQ,content:`${JSON.stringify(Z,null,"\t")}
6
+ `}]}async function xQ(Q){await m(Q,{recursive:!0,force:!0})}async function cQ(Q,Z){let X=new Set;for(let W of Z){let H=SQ(Q,W.path),B=pQ(H);X.add(B)}let $=[...X].sort();for(let W of $)await hQ(W,{recursive:!0});for(let W of Z){let H=SQ(Q,W.path);await yZ(H,W.content,"utf-8")}}import{Crust as dQ,VALIDATION_MODE_ENV as gZ}from"@crustjs/core";import{confirm as uZ,multiselect as cZ,select as mZ,spinner as r}from"@crustjs/prompts";import{bold as a,dim as g,yellow as rQ}from"@crustjs/style";var dZ="skill",lQ="global",o="__universal__";function rZ(Q){return Q==="global"||Q==="project"}async function sQ(Q,Z){if(Q!==void 0){if(!rZ(Q))throw Error(`Invalid --scope value: ${String(Q)}. Expected "project" or "global".`);return Q}if(Z.defaultScope)return Z.defaultScope;return mZ({message:"Select scope",choices:[{label:"Project",value:"project"},{label:"Global",value:"global"}],default:lQ})}function GQ(Q){let Z=new Set(S()),X=[];if(Q.some(($)=>Z.has($)))X.push("Universal");for(let $ of Q){if(Z.has($))continue;X.push(y[$])}return X}function mQ(Q){let Z=new Set(S()),X=[],$=Q.find((W)=>Z.has(W.agent));if($)X.push({label:"Universal",outputDir:$.outputDir});for(let W of Q){if(Z.has(W.agent))continue;X.push({label:y[W.agent],outputDir:W.outputDir})}return X}function FQ(Q,Z){return{name:Q.meta.name,description:Q.meta.description??"",version:Z.version,instructions:Z.instructions,license:Z.license,allowedTools:Z.allowedTools,compatibility:Z.compatibility,disableModelInvocation:Z.disableModelInvocation}}function wQ(Q,Z,X,$){if(!$.installed)return!1;let W=O(Q,Z,X.name);return $.version!==X.version||$.outputDir!==W}async function lZ(Q,Z){let X=[...S(),...h()];if(X.length===0)return;let $=FQ(Q,Z),W=["project","global"];for(let H of W){let z=(await d({name:$.name,agents:X,scope:H})).agents.filter((J)=>wQ(J.agent,H,$,J));if(z.length===0)continue;try{await r({message:`Updating ${H} skills...`,task:async({updateMessage:J})=>{let K=await p({command:Q,meta:$,agents:z.map((U)=>U.agent),scope:H,installMode:Z.installMode}),x=K.agents.filter((U)=>U.status==="updated").map((U)=>U.agent),G=GQ(x);if(G.length>0)J(`Updated skill "${$.name}" to v${$.version} for ${G.join(", ")} (${H})`);return K}})}catch(J){if(J instanceof I)console.warn(rQ(`Skill conflict: "${J.details.outputDir}" already exists but was not created by ${$.name}. Skipping auto-update for ${H}. Delete or rename the conflicting skill to resolve.`));else throw J}}}function sZ(Q){let Z;return{name:"skills",async setup(X,$){Z=X.rootCommand;let W=Q.command??dZ;if($.addSubCommand(Z,W,iZ(Z,Q,W)),process.env[gZ]==="1")return;if(X.argv[0]===W)return;if(Q.autoUpdate!==!1)await lZ(Z,Q)}}}function iZ(Q,Z,X){let $=oZ(Q,Z);return new dQ(X).meta({description:"Manage agent skill installations"}).flags({scope:{type:"string",description:"Install scope (project or global)"},all:{type:"boolean",description:"Install for all detected agents non-interactively (universal + detected)"}}).run(async(W)=>{let H=FQ(Q,Z),B=W.flags.all===!0,z=B?Z.defaultScope??lQ:await sQ(W.flags.scope,Z),J=await QQ(),K=S(),x=h(),G=await d({name:H.name,agents:[...K,...x],scope:z}),U=new Set(G.agents.filter((q)=>q.installed).map((q)=>q.agent)),N=new Set(J),M=new Map(G.agents.map((q)=>[q.agent,q])),b=x.filter((q)=>{if(N.has(q))return!0;return M.get(q)?.installed===!0}),R=b.filter((q)=>U.has(q)),T=[];if(K.length>0){let q=K[0];if(!q)throw Error("Expected at least one universal agent");let w=M.get(q)?.outputDir??"path unavailable";T.push({label:"Universal",value:o,hint:w});let V=K.map((n)=>y[n]).join(", ");console.log(g(`Agents supporting universal skills: ${V}`))}for(let q of b){let w=M.get(q)?.outputDir??"path unavailable";T.push({label:y[q],value:q,hint:w})}let _=K.length>0&&K.every((q)=>U.has(q)),E=[...R.filter((q)=>!K.includes(q))];if(_)E.unshift(o);let L;if(B)L=[...K,...b];else{let q=T.length===0?[]:await cZ({message:"Select agents to install skills for",choices:T,default:E,required:!1}),F=new Set(q.filter((w)=>w!==o));if(q.includes(o))for(let w of K)F.add(w);L=[...F]}let l=L.filter((q)=>!U.has(q)),UQ=L.filter((q)=>{let F=M.get(q);return F!==void 0&&wQ(q,z,H,F)}),v=[...U].filter((q)=>!L.includes(q)),f=[...l,...UQ];if(f.length>0)try{let q=await r({message:"Installing skills...",task:async()=>p({command:Q,meta:H,agents:f,scope:z,installMode:Z.installMode})});console.log(`
7
+ ${a(`Installed "${H.name}" v${H.version}`)}`);for(let F of mQ(q.agents))console.log(g(` ${F.label} \u2192 ${F.outputDir}`))}catch(q){if(q instanceof I)if(B?!0:await uZ({message:`"${q.details.outputDir}" already exists but was not created by Crust. Overwrite?`,default:!1})){let w=await r({message:"Overwriting skill...",task:async()=>p({command:Q,meta:H,agents:[q.details.agent],scope:z,force:!0,installMode:Z.installMode})});console.log(`
8
+ ${a(`Installed "${H.name}" v${H.version}`)}`);for(let V of mQ(w.agents))console.log(g(` ${V.label} \u2192 ${V.outputDir}`))}else console.log(g(`
9
+ Skipped ${y[q.details.agent]}`));else throw q}if(v.length>0){let F=(await r({message:"Removing skills...",task:async()=>JQ({name:H.name,agents:v,scope:z})})).agents.filter((V)=>V.status==="removed").map((V)=>V.agent),w=GQ(F);if(w.length>0)console.log(`
10
+ ${a(`Removed from ${w.join(", ")}`)}`)}if(f.length===0&&v.length===0)console.log(g("No changes."))}).command($)._node}function oZ(Q,Z){return new dQ("update").meta({description:"Update installed skills to latest version"}).flags({scope:{type:"string",description:"Update scope (project or global)"}}).run(async(X)=>{let $=await sQ(X.flags.scope,Z),W=[...S(),...h()],H=FQ(Q,Z),z=(await d({name:H.name,agents:W,scope:$})).agents.filter((J)=>wQ(J.agent,$,H,J));if(z.length===0){console.log(g(`No updates needed (${$}).`));return}try{let K=(await r({message:`Updating ${$} skills...`,task:async()=>p({command:Q,meta:H,agents:z.map((G)=>G.agent),scope:$,installMode:Z.installMode})})).agents.filter((G)=>G.status==="updated").map((G)=>G.agent),x=GQ(K);if(x.length>0)console.log(`
11
+ ${a(`Updated "${H.name}" to v${H.version} for ${x.join(", ")} (${$})`)}`)}catch(J){if(J instanceof I)console.warn(rQ(`Skipped ${y[J.details.agent]}: "${J.details.outputDir}" already exists but was not created by ${H.name}. Delete or rename the conflicting directory to resolve.`));else throw J}})}export{JQ as uninstallSkill,d as skillStatus,sZ as skillPlugin,i as resolveSkillName,P as resolveCanonicalSkillPath,uQ as isValidSkillName,ZZ as isUniversalAgent,S as getUniversalAgents,h as getAdditionalAgents,p as generateSkill,QQ as detectInstalledAgents,HZ as annotate,I as SkillConflictError};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crustjs/skills",
3
- "version": "0.0.17",
3
+ "version": "0.0.20",
4
4
  "description": "Agent skill generation from Crust command definitions",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -48,11 +48,11 @@
48
48
  },
49
49
  "devDependencies": {
50
50
  "@crustjs/config": "0.0.0",
51
- "@crustjs/core": "0.0.14",
51
+ "@crustjs/core": "0.0.15",
52
52
  "bunup": "^0.16.29"
53
53
  },
54
54
  "peerDependencies": {
55
- "@crustjs/core": "0.0.14",
55
+ "@crustjs/core": "0.0.15",
56
56
  "typescript": "^5"
57
57
  }
58
58
  }