@crustjs/skills 0.0.15 → 0.0.16

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/dist/index.d.ts CHANGED
@@ -436,7 +436,7 @@ import { CrustPlugin } from "@crustjs/core";
436
436
  * version: "1.0.0",
437
437
  * command: "skill", // registers "my-cli skill" subcommand
438
438
  * }))
439
- * .run(() => { /* ... *​/ });
439
+ * .run(() => { /* ... *�/ });
440
440
  *
441
441
  * await app.execute();
442
442
  * ```
package/dist/index.js CHANGED
@@ -1,11 +1,11 @@
1
1
  // @bun
2
- import{accessSync as fQ,constants as hQ}from"fs";import{homedir as n}from"os";import{delimiter as uQ,join as B}from"path";var y=B(".agents","skills"),cQ=B(".crust","skills");function YQ(Q){if(Q!==n())return B(Q,".config");let X=process.env.XDG_CONFIG_HOME?.trim();return X&&X.length>0?X:B(Q,".config")}function k(Q){return B(Q,".agents","skills")}function pQ(Q){return B(Q,".crust","skills")}var E={amp:{label:"Amp",class:"universal",projectSkillsDir:y,globalSkillsDir:k},adal:{label:"AdaL",class:"additional",projectSkillsDir:B(".adal","skills"),globalSkillsDir:(Q)=>B(Q,".adal","skills"),detectCommands:["adal"]},antigravity:{label:"Antigravity",class:"additional",projectSkillsDir:B(".agent","skills"),globalSkillsDir:(Q)=>B(Q,".gemini","antigravity","skills"),detectCommands:["antigravity"]},augment:{label:"Augment",class:"additional",projectSkillsDir:B(".augment","skills"),globalSkillsDir:(Q)=>B(Q,".augment","skills"),detectCommands:["augment"]},"claude-code":{label:"Claude Code",class:"additional",projectSkillsDir:B(".claude","skills"),globalSkillsDir:(Q)=>B(process.env.CLAUDE_CONFIG_DIR?.trim()||B(Q,".claude"),"skills"),detectCommands:["claude","claude-code"]},cline:{label:"Cline",class:"universal",projectSkillsDir:y,globalSkillsDir:k},codebuddy:{label:"CodeBuddy",class:"additional",projectSkillsDir:B(".codebuddy","skills"),globalSkillsDir:(Q)=>B(Q,".codebuddy","skills"),detectCommands:["codebuddy"]},codex:{label:"Codex",class:"universal",projectSkillsDir:y,globalSkillsDir:k},"command-code":{label:"Command Code",class:"additional",projectSkillsDir:B(".commandcode","skills"),globalSkillsDir:(Q)=>B(Q,".commandcode","skills"),detectCommands:["command-code","commandcode"]},continue:{label:"Continue",class:"additional",projectSkillsDir:B(".continue","skills"),globalSkillsDir:(Q)=>B(Q,".continue","skills"),detectCommands:["continue"]},cortex:{label:"Cortex Code",class:"additional",projectSkillsDir:B(".cortex","skills"),globalSkillsDir:(Q)=>B(Q,".snowflake","cortex","skills"),detectCommands:["cortex"]},crush:{label:"Crush",class:"additional",projectSkillsDir:B(".crush","skills"),globalSkillsDir:(Q)=>B(YQ(Q),"crush","skills"),detectCommands:["crush"]},cursor:{label:"Cursor",class:"universal",projectSkillsDir:y,globalSkillsDir:k},droid:{label:"Droid",class:"additional",projectSkillsDir:B(".factory","skills"),globalSkillsDir:(Q)=>B(Q,".factory","skills"),detectCommands:["droid"]},"gemini-cli":{label:"Gemini CLI",class:"universal",projectSkillsDir:y,globalSkillsDir:k},"github-copilot":{label:"GitHub Copilot",class:"universal",projectSkillsDir:y,globalSkillsDir:k},goose:{label:"Goose",class:"additional",projectSkillsDir:B(".goose","skills"),globalSkillsDir:(Q)=>B(YQ(Q),"goose","skills"),detectCommands:["goose"]},"iflow-cli":{label:"iFlow CLI",class:"additional",projectSkillsDir:B(".iflow","skills"),globalSkillsDir:(Q)=>B(Q,".iflow","skills"),detectCommands:["iflow","iflow-cli"]},junie:{label:"Junie",class:"additional",projectSkillsDir:B(".junie","skills"),globalSkillsDir:(Q)=>B(Q,".junie","skills"),detectCommands:["junie"]},kilo:{label:"Kilo Code",class:"additional",projectSkillsDir:B(".kilocode","skills"),globalSkillsDir:(Q)=>B(Q,".kilocode","skills"),detectCommands:["kilo","kilocode"]},"kimi-cli":{label:"Kimi Code CLI",class:"universal",projectSkillsDir:y,globalSkillsDir:k},"kiro-cli":{label:"Kiro CLI",class:"additional",projectSkillsDir:B(".kiro","skills"),globalSkillsDir:(Q)=>B(Q,".kiro","skills"),detectCommands:["kiro","kiro-cli"]},kode:{label:"Kode",class:"additional",projectSkillsDir:B(".kode","skills"),globalSkillsDir:(Q)=>B(Q,".kode","skills"),detectCommands:["kode"]},mcpjam:{label:"MCPJam",class:"additional",projectSkillsDir:B(".mcpjam","skills"),globalSkillsDir:(Q)=>B(Q,".mcpjam","skills"),detectCommands:["mcpjam"]},"mistral-vibe":{label:"Mistral Vibe",class:"additional",projectSkillsDir:B(".vibe","skills"),globalSkillsDir:(Q)=>B(Q,".vibe","skills"),detectCommands:["mistral-vibe","vibe"]},mux:{label:"Mux",class:"additional",projectSkillsDir:B(".mux","skills"),globalSkillsDir:(Q)=>B(Q,".mux","skills"),detectCommands:["mux"]},neovate:{label:"Neovate",class:"additional",projectSkillsDir:B(".neovate","skills"),globalSkillsDir:(Q)=>B(Q,".neovate","skills"),detectCommands:["neovate"]},opencode:{label:"OpenCode",class:"universal",projectSkillsDir:y,globalSkillsDir:k},openclaw:{label:"OpenClaw",class:"additional",projectSkillsDir:"skills",globalSkillsDir:(Q)=>B(Q,".openclaw","skills"),detectCommands:["openclaw"]},openhands:{label:"OpenHands",class:"additional",projectSkillsDir:B(".openhands","skills"),globalSkillsDir:(Q)=>B(Q,".openhands","skills"),detectCommands:["openhands"]},pi:{label:"Pi",class:"additional",projectSkillsDir:B(".pi","skills"),globalSkillsDir:(Q)=>B(Q,".pi","agent","skills"),detectCommands:["pi"]},pochi:{label:"Pochi",class:"additional",projectSkillsDir:B(".pochi","skills"),globalSkillsDir:(Q)=>B(Q,".pochi","skills"),detectCommands:["pochi"]},qoder:{label:"Qoder",class:"additional",projectSkillsDir:B(".qoder","skills"),globalSkillsDir:(Q)=>B(Q,".qoder","skills"),detectCommands:["qoder"]},"qwen-code":{label:"Qwen Code",class:"additional",projectSkillsDir:B(".qwen","skills"),globalSkillsDir:(Q)=>B(Q,".qwen","skills"),detectCommands:["qwen","qwen-code"]},replit:{label:"Replit",class:"universal",projectSkillsDir:y,globalSkillsDir:k},roo:{label:"Roo Code",class:"additional",projectSkillsDir:B(".roo","skills"),globalSkillsDir:(Q)=>B(Q,".roo","skills"),detectCommands:["roo","roo-code"]},trae:{label:"Trae",class:"additional",projectSkillsDir:B(".trae","skills"),globalSkillsDir:(Q)=>B(Q,".trae","skills"),detectCommands:["trae"]},"trae-cn":{label:"Trae CN",class:"additional",projectSkillsDir:B(".trae","skills"),globalSkillsDir:(Q)=>B(Q,".trae-cn","skills"),detectCommands:["trae-cn","trae"]},windsurf:{label:"Windsurf",class:"additional",projectSkillsDir:B(".windsurf","skills"),globalSkillsDir:(Q)=>B(Q,".codeium","windsurf","skills"),detectCommands:["windsurf"]},zencoder:{label:"Zencoder",class:"additional",projectSkillsDir:B(".zencoder","skills"),globalSkillsDir:(Q)=>B(Q,".zencoder","skills"),detectCommands:["zencoder"]}},p=Object.keys(E),j=Object.fromEntries(p.map((Q)=>[Q,E[Q].label]));function P(){return p.filter((Q)=>E[Q].class==="universal")}function D(){return p.filter((Q)=>E[Q].class==="additional")}function gQ(Q){return E[Q].class==="universal"}async function e(Q){let X=typeof Q==="string"?{home:Q}:Q??{},Z=X.cwd??process.cwd(),$=X.commandChecker??((W)=>Promise.resolve(mQ(W))),H=[];for(let W of D()){let z=E[W].detectCommands??[],J=!1;for(let q of z)if(await $(q,Z)){J=!0;break}if(J)H.push(W)}return H}function v(Q,X,Z){let $=E[Q];if(X==="project")return B(process.cwd(),$.projectSkillsDir,Z);return B($.globalSkillsDir(n()),Z)}function s(Q,X){if(Q==="project")return B(process.cwd(),cQ,X);return B(pQ(n()),X)}function mQ(Q){let Z=(process.env.PATH??"").split(uQ).filter((W)=>W.length>0),$=process.platform==="win32",H=$?(process.env.PATHEXT??".EXE;.CMD;.BAT;.COM").split(";").filter((W)=>W.length>0):[];for(let W of Z){if(!$&&qQ(B(W,Q)))return!0;if($){for(let z of H)if(qQ(B(W,Q+z)))return!0}}return!1}function qQ(Q){try{return fQ(Q,hQ.X_OK),!0}catch{return!1}}class b extends Error{name="SkillConflictError";details;constructor(Q){let X=`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(X);this.details=Q}}import{lstat as kQ,mkdir as bQ,readlink as YZ,realpath as qZ,rm as XQ,symlink as zZ,writeFile as JZ}from"fs/promises";import{dirname as IQ,join as RQ}from"path";function zQ(Q){return JQ(Q,[])}function JQ(Q,X){let Z=dQ(Q.meta.name),$=[...X,Z],H=rQ(Q.args),W=sQ(Q.effectiveFlags),z=oQ(Q.subCommands,$);return{name:Z,path:$,description:Q.meta.description,usage:Q.meta.usage,runnable:typeof Q.run==="function",args:H,flags:W,children:z}}function dQ(Q){return Q.trim().toLowerCase()}function rQ(Q){if(!Q||Q.length===0)return[];return Q.map(lQ)}function lQ(Q){let X={name:Q.name,type:Q.type,required:Q.required===!0,variadic:Q.variadic===!0};if(Q.description!==void 0)X.description=Q.description;if(Q.default!==void 0)X.default=KQ(Q.default);return X}function sQ(Q){if(!Q)return[];return Object.keys(Q).sort().map((Z)=>{return iQ(Z,Q[Z])})}function iQ(Q,X){let Z={name:Q,type:X.type,required:X.required===!0,multiple:X.multiple===!0,short:X.short,aliases:X.aliases?[...X.aliases].sort():[]};if(X.description!==void 0)Z.description=X.description;if(X.default!==void 0)Z.default=KQ(X.default);return Z}function oQ(Q,X){return Object.keys(Q).sort().map(($)=>{return JQ(Q[$],X)})}function KQ(Q){if(Array.isArray(Q))return JSON.stringify(Q);return String(Q)}function g(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 xQ(Q){return Q.replace(/(?<!\\)\|/g,"\\|")}function MQ(Q,X){let Z=[],$=GQ(Q);Z.push({path:"SKILL.md",content:tQ(Q,X,$)});for(let H of $){let W=L(H),z=H.children.length>0?QZ(H,Q):eQ(H,Q);Z.push({path:W,content:z})}return Z}function GQ(Q){let X=[Q];for(let Z of Q.children)X.push(...GQ(Z));return X}function L(Q){if(Q.path.length<=1)return`commands/${Q.name}.md`;return`commands/${Q.path.slice(1).join("/")}.md`}function i(Q){return Q.path.join(" ")}function QQ(Q,X){let Z=Q.split("/").slice(0,-1),$=X.split("/"),H=0;while(H<Z.length&&H<$.length&&Z[H]===$[H])H++;let W=Z.length-H,z=$.slice(H);if(W===0)return z.join("/");return[...Array.from({length:W},()=>".."),...z].join("/")}function tQ(Q,X,Z){let $=[];if($.push("---"),$.push(`name: ${g(X.name)}`),$.push(`description: ${g(X.description)}`),X.license)$.push(`license: ${g(X.license)}`);if(X.compatibility)$.push(`compatibility: ${g(X.compatibility)}`);if(X.disableModelInvocation)$.push("disable-model-invocation: true");if(X.allowedTools)$.push(`allowed-tools: ${g(X.allowedTools)}`);if($.push("metadata:"),$.push(` version: "${X.version}"`),$.push("---"),$.push(""),$.push(`# ${X.name}`),$.push(""),Q.description)$.push(Q.description),$.push("");let H=X.name.startsWith("use-")?X.name.slice(4):X.name;if($.push(`Use this skill when working with \`${H}\` commands, or when you need help with \`${H}\` syntax, flags, or subcommands.`),$.push(""),$.push("## Command Reference"),$.push(""),$.push("This table lists all commands and their documentation paths. **Do not read all command files at once.** Instead:"),$.push(""),$.push("1. Use the table below to find the relevant command"),$.push("2. Use the `Type` column to choose what to execute: commands labeled `runnable` (including `runnable, group`) are executable, while `group` commands are not"),$.push("3. Read only the specific file from the `commands/` directory that you need"),$.push("4. For any command-specific answer, read that command's documentation file before responding"),$.push("5. Treat the command documentation file as the source of truth for usage, flags, options, aliases, and defaults"),$.push("6. Do not invent or assume undocumented flags/options; if something is missing from the file, say it is not documented"),$.push(""),$.push(...aQ(Z)),$.push(""),Q.runnable){$.push("## Usage"),$.push("");let W=L(Q);$.push(`The root command is directly executable. See [${Q.name}](${W}) for usage details.`),$.push("")}return $.join(`
3
- `)}function aQ(Q){let X=[];X.push("| Command | Type | Documentation |"),X.push("| ------- | ---- | ------------- |");for(let Z of Q){let $=i(Z),H=L(Z),W=nQ(Z);X.push(`| \`${$}\` | ${W} | [${H}](${H}) |`)}return X}function nQ(Q){if(Q.runnable&&Q.children.length>0)return"runnable, group";if(Q.runnable)return"runnable";return"group"}function eQ(Q,X){let Z=[],$=i(Q);if(Z.push(`# \`${$}\``),Z.push(""),Q.description)Z.push(Q.description),Z.push("");if(Z.push("## Usage"),Z.push(""),Q.usage)Z.push("```"),Z.push(Q.usage),Z.push("```");else Z.push("```"),Z.push(wQ(Q)),Z.push("```");if(Z.push(""),Q.args.length>0)Z.push("## Arguments"),Z.push(""),Z.push(...FQ(Q.args)),Z.push("");if(Q.flags.length>0)Z.push("## Flags"),Z.push(""),Z.push(...OQ(Q.flags)),Z.push("");return Z.push("## Command Documentation Authority"),Z.push(""),Z.push("Only arguments, flags, options, aliases, and defaults documented in this file are supported for this command."),Z.push("Do not infer or invent additional command-line options."),Z.push(""),Z.push(...UQ(Q,X)),Z.join(`
4
- `)}function QZ(Q,X){let Z=[],$=i(Q),H=L(Q);if(Z.push(`# \`${$}\``),Z.push(""),Q.description)Z.push(Q.description),Z.push("");if(Q.runnable){if(Z.push("## Usage"),Z.push(""),Q.usage)Z.push("```"),Z.push(Q.usage),Z.push("```");else Z.push("```"),Z.push(wQ(Q)),Z.push("```");if(Z.push(""),Q.args.length>0)Z.push("## Arguments"),Z.push(""),Z.push(...FQ(Q.args)),Z.push("");if(Q.flags.length>0)Z.push("## Flags"),Z.push(""),Z.push(...OQ(Q.flags)),Z.push("");Z.push("## Command Documentation Authority"),Z.push(""),Z.push("Only arguments, flags, options, aliases, and defaults documented in this file are supported for this command."),Z.push("Do not infer or invent additional command-line options."),Z.push("")}Z.push("## Subcommands"),Z.push("");for(let W of Q.children){let z=L(W),J=QQ(H,z),q=W.description?` - ${W.description}`:"";Z.push(`- [\`${W.name}\`](${J})${q}`)}return Z.push(""),Z.push(...UQ(Q,X)),Z.join(`
5
- `)}function wQ(Q){let X=[...Q.path];for(let Z of Q.args)if(Z.variadic)X.push(Z.required?`<${Z.name}...>`:`[${Z.name}...]`);else X.push(Z.required?`<${Z.name}>`:`[${Z.name}]`);if(Q.flags.length>0)X.push("[options]");return X.join(" ")}function FQ(Q){let X=[];X.push("| Argument | Type | Required | Description |"),X.push("| -------- | ---- | -------- | ----------- |");for(let Z of Q){let $=Z.variadic?`${Z.name}...`:Z.name,H=Z.required?"Yes":"No",W=xQ(ZZ(Z));X.push(`| \`${$}\` | ${Z.type} | ${H} | ${W} |`)}return X}function ZZ(Q){let X=[];if(Q.description)X.push(Q.description);if(Q.default!==void 0)X.push(`Default: \`${Q.default}\``);return X.join(". ")||"-"}function OQ(Q){let X=[];X.push("| Flag | Type | Required | Description |"),X.push("| ---- | ---- | -------- | ----------- |");for(let Z of Q){let $=XZ(Z),H=Z.required?"Yes":"No",W=xQ($Z(Z));X.push(`| ${$} | ${Z.type} | ${H} | ${W} |`)}return X}function XZ(Q){let X=[`\`--${Q.name}\``];if(Q.short)X.push(`\`-${Q.short}\``);for(let Z of Q.aliases)X.push(`\`--${Z}\``);return X.join(", ")}function $Z(Q){let X=[];if(Q.description)X.push(Q.description);if(Q.multiple)X.push("Can be specified multiple times");if(Q.default!==void 0)X.push(`Default: \`${Q.default}\``);return X.join(". ")||"-"}function UQ(Q,X){let Z=[],$=L(Q);if(Z.push("---"),Z.push(""),Q.path.length>1){let W=Q.path.slice(0,-1),z=VQ(X,W);if(z){let J=L(z),q=QQ($,J),K=i(z);Z.push(`Parent: [\`${K}\`](${q})`),Z.push("")}}let H=QQ($,"SKILL.md");return Z.push(`[Skill Overview](${H})`),Z.push(""),Z}function VQ(Q,X){if(HZ(Q.path,X))return Q;for(let Z of Q.children){let $=VQ(Z,X);if($)return $}return}function HZ(Q,X){if(Q.length!==X.length)return!1;for(let Z=0;Z<Q.length;Z++)if(Q[Z]!==X[Z])return!1;return!0}import{readFile as WZ}from"fs/promises";import{join as BZ}from"path";var ZQ="crust.json";async function m(Q){try{let X=await WZ(BZ(Q,ZQ),"utf-8"),Z=JSON.parse(X);if(typeof Z==="object"&&Z!==null&&"version"in Z&&typeof Z.version==="string")return Z.version;return null}catch{return null}}var KZ="auto",EQ=/^[a-z0-9]+(-[a-z0-9]+)*$/;function PQ(Q){return Q.length>=1&&Q.length<=64&&EQ.test(Q)}function A(Q){return Q.startsWith("use-")?Q:`use-${Q}`}async function S(Q){let{command:X,meta:Z,agents:$,scope:H="global",clean:W=!0,force:z=!1,installMode:J=KZ}=Q,q=A(Z.name);if(!PQ(q))throw Error(`Invalid skill name "${q}": must be 1\u201364 lowercase `+`alphanumeric characters and hyphens, no leading/trailing/consecutive hyphens. Pattern: ${EQ.source}`);let K=$[0];if(!K)return{agents:[]};let x={...Z,name:q},G=zQ(X),w=MQ(G,x),h=OZ(x),C=[...w,...h].sort((M,U)=>M.path<U.path?-1:M.path>U.path?1:0),a=C.map((M)=>M.path),R=new Map;for(let M of $){let U=v(M,H,x.name),T=R.get(U);if(T)T.push(M);else R.set(U,[M])}let l=new Map;for(let M of R.keys())l.set(M,await m(M));let _=s(H,x.name),u=await m(_);if(u===null){if(await CQ(_)&&!z)throw new b({agent:K,outputDir:v(K,H,x.name)})}let c=u!==x.version;if(c){if(W)await HQ(_);await NQ(_,C)}let N=[];for(let[M,U]of R){let T=U[0];if(!T)continue;let I=l.get(M)??null,Y=await LQ(M,_),F=I!==null||Y.exists&&Y.isSymlink&&Y.pointsToCanonical;if(Y.exists&&!F&&!z)throw new b({agent:T,outputDir:M});let O=await MZ({outputDir:M,canonicalOutputDir:_,allFiles:C,clean:W,installMode:J,inspection:Y,installedVersion:I,currentVersion:x.version}),V=xZ({installedVersion:I,currentVersion:x.version,canonicalChanged:c,pathChanged:O});for(let SQ of U)N.push({agent:SQ,outputDir:M,files:V==="up-to-date"?[]:a,status:V,previousVersion:V==="updated"?I??void 0:void 0})}return{agents:N}}async function $Q(Q){let{name:X,agents:Z,scope:$="global"}=Q,H=A(X),W=s($,H),z=[],J=new Map;for(let K of Z){let x=v(K,$,H),G=J.get(x);if(G)G.push(K);else J.set(x,[K])}for(let[K,x]of J)if(await CQ(K)){await XQ(K,{recursive:!0,force:!0});for(let w of x)z.push({agent:w,outputDir:K,status:"removed"})}else for(let w of x)z.push({agent:w,outputDir:K,status:"not-found"});if(!await FZ(H,$))await XQ(W,{recursive:!0,force:!0});return{agents:z}}async function d(Q){let{name:X,agents:Z,scope:$="global"}=Q,H=A(X),W=[],z=new Map;for(let J of Z){let q=v(J,$,H),K=z.get(q);if(K)K.push(J);else z.set(q,[J])}for(let[J,q]of z){let K=await m(J);for(let x of q)W.push({agent:x,outputDir:J,installed:K!==null,version:K??void 0})}return{agents:W}}function xZ(Q){let{installedVersion:X,currentVersion:Z,canonicalChanged:$,pathChanged:H}=Q;if(X===null)return"installed";if(X===Z&&!$&&!H)return"up-to-date";return"updated"}async function MZ(Q){let{outputDir:X,canonicalOutputDir:Z,allFiles:$,clean:H,installMode:W,inspection:z,installedVersion:J,currentVersion:q}=Q;if(W==="copy")return _Q({outputDir:X,allFiles:$,clean:H,inspection:z,installedVersion:J,currentVersion:q});try{return await GZ({outputDir:X,canonicalOutputDir:Z,inspection:z})}catch(K){if(W==="symlink")throw Error(`Failed to create symlink at "${X}" (installMode: symlink).`,{cause:K});let x=await LQ(X,Z);return _Q({outputDir:X,allFiles:$,clean:H,inspection:x,installedVersion:J,currentVersion:q})}}async function _Q(Q){let{outputDir:X,allFiles:Z,clean:$,inspection:H,installedVersion:W,currentVersion:z}=Q;if(!(!H.exists||H.isSymlink||W!==z))return!1;if(H.isSymlink||$)await HQ(X);return await NQ(X,Z),!0}async function GZ(Q){let{outputDir:X,canonicalOutputDir:Z,inspection:$}=Q;if($.exists&&$.isSymlink&&$.pointsToCanonical)return!1;if($.exists)await HQ(X);return await wZ(Z,X),!0}async function LQ(Q,X){let Z;try{Z=await kQ(Q)}catch{return{exists:!1,isSymlink:!1,pointsToCanonical:!1}}let $=process.platform==="win32"&&Z.isDirectory()&&await yQ(Q)!==null;if(!(Z.isSymbolicLink()||$))return{exists:!0,isSymlink:!1,pointsToCanonical:!1};let[W,z,J]=await Promise.all([TQ(Q),TQ(X),yQ(Q)]);return{exists:!0,isSymlink:!0,pointsToCanonical:W!==null&&z!==null&&W===z||J===X}}async function TQ(Q){try{return await qZ(Q)}catch{return null}}async function yQ(Q){try{return await YZ(Q)}catch{return null}}async function wZ(Q,X){await bQ(IQ(X),{recursive:!0});let Z=process.platform==="win32"?"junction":"dir";await zZ(Q,X,Z)}async function CQ(Q){try{return await kQ(Q),!0}catch{return!1}}async function FZ(Q,X){let Z=new Set;for(let $ of p)Z.add(v($,X,Q));for(let $ of Z)if(await m($)!==null)return!0;return!1}function OZ(Q){let X={name:Q.name,description:Q.description,version:Q.version};return[{path:ZQ,content:`${JSON.stringify(X,null,"\t")}
6
- `}]}async function HQ(Q){await XQ(Q,{recursive:!0,force:!0})}async function NQ(Q,X){let Z=new Set;for(let H of X){let W=RQ(Q,H.path),z=IQ(W);Z.add(z)}let $=[...Z].sort();for(let H of $)await bQ(H,{recursive:!0});for(let H of X){let W=RQ(Q,H.path);await JZ(W,H.content,"utf-8")}}import{Crust as DQ,VALIDATION_MODE_ENV as UZ}from"@crustjs/core";import{confirm as VZ,multiselect as RZ,select as _Z,spinner as r}from"@crustjs/prompts";import{bold as t,dim as f,yellow as vQ}from"@crustjs/style";var TZ="skill",yZ="global",o="__universal__";function kZ(Q){return Q==="global"||Q==="project"}async function AQ(Q,X){if(Q!==void 0){if(!kZ(Q))throw Error(`Invalid --scope value: ${String(Q)}. Expected "project" or "global".`);return Q}if(X.defaultScope)return X.defaultScope;return _Z({message:"Select scope",choices:[{label:"Project",value:"project"},{label:"Global",value:"global"}],default:yZ})}function WQ(Q){let X=new Set(P()),Z=[];if(Q.some(($)=>X.has($)))Z.push("Universal");for(let $ of Q){if(X.has($))continue;Z.push(j[$])}return Z}function jQ(Q){let X=new Set(P()),Z=[],$=Q.find((H)=>X.has(H.agent));if($)Z.push({label:"Universal",outputDir:$.outputDir});for(let H of Q){if(X.has(H.agent))continue;Z.push({label:j[H.agent],outputDir:H.outputDir})}return Z}function BQ(Q,X){return{name:Q.meta.name,description:Q.meta.description??"",version:X}}async function bZ(Q,X){let Z=[...P(),...D()];if(Z.length===0)return;let $=BQ(Q,X.version),H=["project","global"];for(let W of H){let J=(await d({name:$.name,agents:Z,scope:W})).agents.filter((q)=>q.installed&&q.version!==$.version);if(J.length===0)continue;try{await r({message:`Updating ${W} skills...`,task:async({updateMessage:q})=>{let K=await S({command:Q,meta:$,agents:J.map((w)=>w.agent),scope:W,installMode:X.installMode}),x=K.agents.filter((w)=>w.status==="updated").map((w)=>w.agent),G=WQ(x);if(G.length>0)q(`Updated skill "${A($.name)}" to v${$.version} for ${G.join(", ")} (${W})`);return K}})}catch(q){if(q instanceof b)console.warn(vQ(`Skill conflict: "${q.details.outputDir}" already exists but was not created by ${$.name}. Skipping auto-update for ${W}. Delete or rename the conflicting skill to resolve.`));else throw q}}}function IZ(Q){let X;return{name:"skills",async setup(Z,$){X=Z.rootCommand;let H=Q.command??TZ;if($.addSubCommand(X,H,EZ(X,Q,H)),process.env[UZ]==="1")return;if(Z.argv[0]===H)return;if(Q.autoUpdate!==!1)await bZ(X,Q)}}}function EZ(Q,X,Z){let $=PZ(Q,X);return new DQ(Z).meta({description:"Manage agent skill installations"}).flags({scope:{type:"string",description:"Install scope (project or global)"}}).run(async(H)=>{let W=BQ(Q,X.version),z=await AQ(H.flags.scope,X),J=await e(),q=P(),K=D(),x=await d({name:W.name,agents:[...q,...K],scope:z}),G=new Set(x.agents.filter((Y)=>Y.installed).map((Y)=>Y.agent)),w=new Set(J),h=new Map(x.agents.map((Y)=>[Y.agent,Y])),C=K.filter((Y)=>{if(w.has(Y))return!0;return h.get(Y)?.installed===!0}),a=C.filter((Y)=>G.has(Y)),R=[];if(q.length>0){let Y=q[0];if(!Y)throw Error("Expected at least one universal agent");let O=h.get(Y)?.outputDir??"path unavailable";R.push({label:"Universal",value:o,hint:O}),console.log(f("Universal installs to the shared .agents/skills directory."))}for(let Y of C){let O=h.get(Y)?.outputDir??"path unavailable";R.push({label:j[Y],value:Y,hint:O})}let l=q.length>0&&q.every((Y)=>G.has(Y)),_=[...a.filter((Y)=>!q.includes(Y))];if(l)_.unshift(o);let u=R.length===0?[]:await RZ({message:"Select agents to install skills for",choices:R,default:_,required:!1}),c=new Set(u.filter((Y)=>Y!==o));if(u.includes(o))for(let Y of q)c.add(Y);let N=[...c],M=N.filter((Y)=>!G.has(Y)),U=N.filter((Y)=>{let F=x.agents.find((O)=>O.agent===Y);return F?.installed===!0&&F.version!==W.version}),T=[...G].filter((Y)=>!N.includes(Y)),I=[...M,...U];if(I.length>0)try{let Y=await r({message:"Installing skills...",task:async()=>S({command:Q,meta:W,agents:I,scope:z,installMode:X.installMode})});console.log(`
7
- ${t(`Installed "${W.name}" v${W.version}`)}`);for(let F of jQ(Y.agents))console.log(f(` ${F.label} \u2192 ${F.outputDir}`))}catch(Y){if(Y instanceof b)if(await VZ({message:`"${Y.details.outputDir}" already exists but was not created by Crust. Overwrite?`,default:!1})){let O=await r({message:"Overwriting skill...",task:async()=>S({command:Q,meta:W,agents:[Y.details.agent],scope:z,force:!0,installMode:X.installMode})});console.log(`
8
- ${t(`Installed "${W.name}" v${W.version}`)}`);for(let V of jQ(O.agents))console.log(f(` ${V.label} \u2192 ${V.outputDir}`))}else console.log(f(`
9
- Skipped ${j[Y.details.agent]}`));else throw Y}if(T.length>0){let F=(await r({message:"Removing skills...",task:async()=>$Q({name:W.name,agents:T,scope:z})})).agents.filter((V)=>V.status==="removed").map((V)=>V.agent),O=WQ(F);if(O.length>0)console.log(`
10
- ${t(`Removed from ${O.join(", ")}`)}`)}if(I.length===0&&T.length===0)console.log(f("No changes."))}).command($)._node}function PZ(Q,X){return new DQ("update").meta({description:"Update installed skills to latest version"}).flags({scope:{type:"string",description:"Update scope (project or global)"}}).run(async(Z)=>{let $=await AQ(Z.flags.scope,X),H=[...P(),...D()],W=BQ(Q,X.version),J=(await d({name:W.name,agents:H,scope:$})).agents.filter((q)=>q.installed&&q.version!==W.version);if(J.length===0){console.log(f(`No updates needed (${$}).`));return}try{let K=(await r({message:`Updating ${$} skills...`,task:async()=>S({command:Q,meta:W,agents:J.map((G)=>G.agent),scope:$,installMode:X.installMode})})).agents.filter((G)=>G.status==="updated").map((G)=>G.agent),x=WQ(K);if(x.length>0)console.log(`
11
- ${t(`Updated "${W.name}" to v${W.version} for ${x.join(", ")} (${$})`)}`)}catch(q){if(q instanceof b)console.warn(vQ(`Skipped ${j[q.details.agent]}: "${q.details.outputDir}" already exists but was not created by ${W.name}. Delete or rename the conflicting directory to resolve.`));else throw q}})}export{$Q as uninstallSkill,d as skillStatus,IZ as skillPlugin,A as resolveSkillName,s as resolveCanonicalSkillPath,PQ as isValidSkillName,gQ as isUniversalAgent,P as getUniversalAgents,D as getAdditionalAgents,S as generateSkill,e as detectInstalledAgents,b as SkillConflictError};
2
+ import{accessSync as fQ,constants as hQ}from"fs";import{homedir as e}from"os";import{delimiter as cQ,join as Y}from"path";var y=Y(".agents","skills"),uQ=Y(".crust","skills");function qQ(Q){if(Q!==e())return Y(Q,".config");let X=process.env.XDG_CONFIG_HOME?.trim();return X&&X.length>0?X:Y(Q,".config")}function k(Q){return Y(Q,".agents","skills")}function pQ(Q){return Y(Q,".crust","skills")}var E={amp:{label:"Amp",class:"universal",projectSkillsDir:y,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:y,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:y,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(qQ(Q),"crush","skills"),detectCommands:["crush"]},cursor:{label:"Cursor",class:"universal",projectSkillsDir:y,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:y,globalSkillsDir:k},"github-copilot":{label:"GitHub Copilot",class:"universal",projectSkillsDir:y,globalSkillsDir:k},goose:{label:"Goose",class:"additional",projectSkillsDir:Y(".goose","skills"),globalSkillsDir:(Q)=>Y(qQ(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:y,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:y,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:y,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"]}},p=Object.keys(E),P=Object.fromEntries(p.map((Q)=>[Q,E[Q].label]));function C(){return p.filter((Q)=>E[Q].class==="universal")}function D(){return p.filter((Q)=>E[Q].class==="additional")}function gQ(Q){return E[Q].class==="universal"}async function QQ(Q){let X=typeof Q==="string"?{home:Q}:Q??{},Z=X.cwd??process.cwd(),$=X.commandChecker??((W)=>Promise.resolve(mQ(W))),H=[];for(let W of D()){let z=E[W].detectCommands??[],J=!1;for(let q of z)if(await $(q,Z)){J=!0;break}if(J)H.push(W)}return H}function v(Q,X,Z){let $=E[Q];if(X==="project")return Y(process.cwd(),$.projectSkillsDir,Z);return Y($.globalSkillsDir(e()),Z)}function s(Q,X){if(Q==="project")return Y(process.cwd(),uQ,X);return Y(pQ(e()),X)}function mQ(Q){let Z=(process.env.PATH??"").split(cQ).filter((W)=>W.length>0),$=process.platform==="win32",H=$?(process.env.PATHEXT??".EXE;.CMD;.BAT;.COM").split(";").filter((W)=>W.length>0):[];for(let W of Z){if(!$&&zQ(Y(W,Q)))return!0;if($){for(let z of H)if(zQ(Y(W,Q+z)))return!0}}return!1}function zQ(Q){try{return fQ(Q,hQ.X_OK),!0}catch{return!1}}class b extends Error{name="SkillConflictError";details;constructor(Q){let X=`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(X);this.details=Q}}import{lstat as bQ,mkdir as IQ,readlink as BZ,realpath as qZ,rm as $Q,symlink as zZ,writeFile as JZ}from"fs/promises";import{dirname as EQ,join as _Q}from"path";function JQ(Q){return KQ(Q,[])}function KQ(Q,X){let Z=dQ(Q.meta.name),$=[...X,Z],H=rQ(Q.args),W=sQ(Q.effectiveFlags),z=oQ(Q.subCommands,$);return{name:Z,path:$,description:Q.meta.description,usage:Q.meta.usage,runnable:typeof Q.run==="function",args:H,flags:W,children:z}}function dQ(Q){return Q.trim().toLowerCase()}function rQ(Q){if(!Q||Q.length===0)return[];return Q.map(lQ)}function lQ(Q){let X={name:Q.name,type:Q.type,required:Q.required===!0,variadic:Q.variadic===!0};if(Q.description!==void 0)X.description=Q.description;if(Q.default!==void 0)X.default=xQ(Q.default);return X}function sQ(Q){if(!Q)return[];return Object.keys(Q).sort().map((Z)=>{return iQ(Z,Q[Z])})}function iQ(Q,X){let Z={name:Q,type:X.type,required:X.required===!0,multiple:X.multiple===!0,short:X.short,aliases:X.aliases?[...X.aliases].sort():[]};if(X.description!==void 0)Z.description=X.description;if(X.default!==void 0)Z.default=xQ(X.default);return Z}function oQ(Q,X){return Object.keys(Q).sort().map(($)=>{return KQ(Q[$],X)})}function xQ(Q){if(Array.isArray(Q))return JSON.stringify(Q);return String(Q)}function g(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 MQ(Q){return Q.replace(/(?<!\\)\|/g,"\\|")}function GQ(Q,X){let Z=[],$=wQ(Q);Z.push({path:"SKILL.md",content:tQ(Q,X,$)});for(let H of $){let W=L(H),z=H.children.length>0?QZ(H,Q):eQ(H,Q);Z.push({path:W,content:z})}return Z}function wQ(Q){let X=[Q];for(let Z of Q.children)X.push(...wQ(Z));return X}function L(Q){if(Q.path.length<=1)return`commands/${Q.name}.md`;return`commands/${Q.path.slice(1).join("/")}.md`}function i(Q){return Q.path.join(" ")}function ZQ(Q,X){let Z=Q.split("/").slice(0,-1),$=X.split("/"),H=0;while(H<Z.length&&H<$.length&&Z[H]===$[H])H++;let W=Z.length-H,z=$.slice(H);if(W===0)return z.join("/");return[...Array.from({length:W},()=>".."),...z].join("/")}function tQ(Q,X,Z){let $=[];if($.push("---"),$.push(`name: ${g(X.name)}`),$.push(`description: ${g(X.description)}`),X.license)$.push(`license: ${g(X.license)}`);if(X.compatibility)$.push(`compatibility: ${g(X.compatibility)}`);if(X.disableModelInvocation)$.push("disable-model-invocation: true");if(X.allowedTools)$.push(`allowed-tools: ${g(X.allowedTools)}`);if($.push("metadata:"),$.push(` version: "${X.version}"`),$.push("---"),$.push(""),$.push(`# ${X.name}`),$.push(""),Q.description)$.push(Q.description),$.push("");let H=X.name.startsWith("use-")?X.name.slice(4):X.name;if($.push(`Use this skill when working with \`${H}\` commands, or when you need help with \`${H}\` syntax, flags, or subcommands.`),$.push(""),$.push("## Command Reference"),$.push(""),$.push("This table lists all commands and their documentation paths. **Do not read all command files at once.** Instead:"),$.push(""),$.push("1. Use the table below to find the relevant command"),$.push("2. Use the `Type` column to choose what to execute: commands labeled `runnable` (including `runnable, group`) are executable, while `group` commands are not"),$.push("3. Read only the specific file from the `commands/` directory that you need"),$.push("4. For any command-specific answer, read that command's documentation file before responding"),$.push("5. Treat the command documentation file as the source of truth for usage, flags, options, aliases, and defaults"),$.push("6. Do not invent or assume undocumented flags/options; if something is missing from the file, say it is not documented"),$.push(""),$.push(...aQ(Z)),$.push(""),Q.runnable){$.push("## Usage"),$.push("");let W=L(Q);$.push(`The root command is directly executable. See [${Q.name}](${W}) for usage details.`),$.push("")}return $.join(`
3
+ `)}function aQ(Q){let X=[];X.push("| Command | Type | Documentation |"),X.push("| ------- | ---- | ------------- |");for(let Z of Q){let $=i(Z),H=L(Z),W=nQ(Z);X.push(`| \`${$}\` | ${W} | [${H}](${H}) |`)}return X}function nQ(Q){if(Q.runnable&&Q.children.length>0)return"runnable, group";if(Q.runnable)return"runnable";return"group"}function eQ(Q,X){let Z=[],$=i(Q);if(Z.push(`# \`${$}\``),Z.push(""),Q.description)Z.push(Q.description),Z.push("");if(Z.push("## Usage"),Z.push(""),Q.usage)Z.push("```"),Z.push(Q.usage),Z.push("```");else Z.push("```"),Z.push(FQ(Q)),Z.push("```");if(Z.push(""),Q.args.length>0)Z.push("## Arguments"),Z.push(""),Z.push(...OQ(Q.args)),Z.push("");if(Q.flags.length>0)Z.push("## Flags"),Z.push(""),Z.push(...UQ(Q.flags)),Z.push("");return Z.push("## Command Documentation Authority"),Z.push(""),Z.push("Only arguments, flags, options, aliases, and defaults documented in this file are supported for this command."),Z.push("Do not infer or invent additional command-line options."),Z.push(""),Z.push(...VQ(Q,X)),Z.join(`
4
+ `)}function QZ(Q,X){let Z=[],$=i(Q),H=L(Q);if(Z.push(`# \`${$}\``),Z.push(""),Q.description)Z.push(Q.description),Z.push("");if(Q.runnable){if(Z.push("## Usage"),Z.push(""),Q.usage)Z.push("```"),Z.push(Q.usage),Z.push("```");else Z.push("```"),Z.push(FQ(Q)),Z.push("```");if(Z.push(""),Q.args.length>0)Z.push("## Arguments"),Z.push(""),Z.push(...OQ(Q.args)),Z.push("");if(Q.flags.length>0)Z.push("## Flags"),Z.push(""),Z.push(...UQ(Q.flags)),Z.push("");Z.push("## Command Documentation Authority"),Z.push(""),Z.push("Only arguments, flags, options, aliases, and defaults documented in this file are supported for this command."),Z.push("Do not infer or invent additional command-line options."),Z.push("")}Z.push("## Subcommands"),Z.push("");for(let W of Q.children){let z=L(W),J=ZQ(H,z),q=W.description?` - ${W.description}`:"";Z.push(`- [\`${W.name}\`](${J})${q}`)}return Z.push(""),Z.push(...VQ(Q,X)),Z.join(`
5
+ `)}function FQ(Q){let X=[...Q.path];for(let Z of Q.args)if(Z.variadic)X.push(Z.required?`<${Z.name}...>`:`[${Z.name}...]`);else X.push(Z.required?`<${Z.name}>`:`[${Z.name}]`);if(Q.flags.length>0)X.push("[options]");return X.join(" ")}function OQ(Q){let X=[];X.push("| Argument | Type | Required | Description |"),X.push("| -------- | ---- | -------- | ----------- |");for(let Z of Q){let $=Z.variadic?`${Z.name}...`:Z.name,H=Z.required?"Yes":"No",W=MQ(ZZ(Z));X.push(`| \`${$}\` | ${Z.type} | ${H} | ${W} |`)}return X}function ZZ(Q){let X=[];if(Q.description)X.push(Q.description);if(Q.default!==void 0)X.push(`Default: \`${Q.default}\``);return X.join(". ")||"-"}function UQ(Q){let X=[];X.push("| Flag | Type | Required | Description |"),X.push("| ---- | ---- | -------- | ----------- |");for(let Z of Q){let $=XZ(Z),H=Z.required?"Yes":"No",W=MQ($Z(Z));X.push(`| ${$} | ${Z.type} | ${H} | ${W} |`)}return X}function XZ(Q){let X=[`\`--${Q.name}\``];if(Q.short)X.push(`\`-${Q.short}\``);for(let Z of Q.aliases)X.push(`\`--${Z}\``);return X.join(", ")}function $Z(Q){let X=[];if(Q.description)X.push(Q.description);if(Q.multiple)X.push("Can be specified multiple times");if(Q.default!==void 0)X.push(`Default: \`${Q.default}\``);return X.join(". ")||"-"}function VQ(Q,X){let Z=[],$=L(Q);if(Z.push("---"),Z.push(""),Q.path.length>1){let W=Q.path.slice(0,-1),z=RQ(X,W);if(z){let J=L(z),q=ZQ($,J),K=i(z);Z.push(`Parent: [\`${K}\`](${q})`),Z.push("")}}let H=ZQ($,"SKILL.md");return Z.push(`[Skill Overview](${H})`),Z.push(""),Z}function RQ(Q,X){if(HZ(Q.path,X))return Q;for(let Z of Q.children){let $=RQ(Z,X);if($)return $}return}function HZ(Q,X){if(Q.length!==X.length)return!1;for(let Z=0;Z<Q.length;Z++)if(Q[Z]!==X[Z])return!1;return!0}import{readFile as WZ}from"fs/promises";import{join as YZ}from"path";var XQ="crust.json";async function m(Q){try{let X=await WZ(YZ(Q,XQ),"utf-8"),Z=JSON.parse(X);if(typeof Z==="object"&&Z!==null&&"version"in Z&&typeof Z.version==="string")return Z.version;return null}catch{return null}}var KZ="auto",PQ=/^[a-z0-9]+(-[a-z0-9]+)*$/;function CQ(Q){return Q.length>=1&&Q.length<=64&&PQ.test(Q)}function S(Q){return Q.startsWith("use-")?Q:`use-${Q}`}async function A(Q){let{command:X,meta:Z,agents:$,scope:H="global",clean:W=!0,force:z=!1,installMode:J=KZ}=Q,q=S(Z.name);if(!CQ(q))throw Error(`Invalid skill name "${q}": must be 1\u201364 lowercase `+`alphanumeric characters and hyphens, no leading/trailing/consecutive hyphens. Pattern: ${PQ.source}`);let K=$[0];if(!K)return{agents:[]};let x={...Z,name:q},G=JQ(X),w=GQ(G,x),h=OZ(x),N=[...w,...h].sort((M,V)=>M.path<V.path?-1:M.path>V.path?1:0),a=N.map((M)=>M.path),R=new Map;for(let M of $){let V=v(M,H,x.name),T=R.get(V);if(T)T.push(M);else R.set(V,[M])}let l=new Map;for(let M of R.keys())l.set(M,await m(M));let _=s(H,x.name),c=await m(_);if(c===null){if(await NQ(_)&&!z)throw new b({agent:K,outputDir:v(K,H,x.name)})}let u=c!==x.version;if(u){if(W)await WQ(_);await jQ(_,N)}let j=[];for(let[M,V]of R){let T=V[0];if(!T)continue;let I=l.get(M)??null,B=await LQ(M,_),F=I!==null||B.exists&&B.isSymlink&&B.pointsToCanonical;if(B.exists&&!F&&!z)throw new b({agent:T,outputDir:M});let O=await MZ({outputDir:M,canonicalOutputDir:_,allFiles:N,clean:W,installMode:J,inspection:B,installedVersion:I,currentVersion:x.version}),U=xZ({installedVersion:I,currentVersion:x.version,canonicalChanged:u,pathChanged:O});for(let n of V)j.push({agent:n,outputDir:M,files:U==="up-to-date"?[]:a,status:U,previousVersion:U==="updated"?I??void 0:void 0})}return{agents:j}}async function HQ(Q){let{name:X,agents:Z,scope:$="global"}=Q,H=S(X),W=s($,H),z=[],J=new Map;for(let K of Z){let x=v(K,$,H),G=J.get(x);if(G)G.push(K);else J.set(x,[K])}for(let[K,x]of J)if(await NQ(K)){await $Q(K,{recursive:!0,force:!0});for(let w of x)z.push({agent:w,outputDir:K,status:"removed"})}else for(let w of x)z.push({agent:w,outputDir:K,status:"not-found"});if(!await FZ(H,$))await $Q(W,{recursive:!0,force:!0});return{agents:z}}async function d(Q){let{name:X,agents:Z,scope:$="global"}=Q,H=S(X),W=[],z=new Map;for(let J of Z){let q=v(J,$,H),K=z.get(q);if(K)K.push(J);else z.set(q,[J])}for(let[J,q]of z){let K=await m(J);for(let x of q)W.push({agent:x,outputDir:J,installed:K!==null,version:K??void 0})}return{agents:W}}function xZ(Q){let{installedVersion:X,currentVersion:Z,canonicalChanged:$,pathChanged:H}=Q;if(X===null)return"installed";if(X===Z&&!$&&!H)return"up-to-date";return"updated"}async function MZ(Q){let{outputDir:X,canonicalOutputDir:Z,allFiles:$,clean:H,installMode:W,inspection:z,installedVersion:J,currentVersion:q}=Q;if(W==="copy")return TQ({outputDir:X,allFiles:$,clean:H,inspection:z,installedVersion:J,currentVersion:q});try{return await GZ({outputDir:X,canonicalOutputDir:Z,inspection:z})}catch(K){if(W==="symlink")throw Error(`Failed to create symlink at "${X}" (installMode: symlink).`,{cause:K});let x=await LQ(X,Z);return TQ({outputDir:X,allFiles:$,clean:H,inspection:x,installedVersion:J,currentVersion:q})}}async function TQ(Q){let{outputDir:X,allFiles:Z,clean:$,inspection:H,installedVersion:W,currentVersion:z}=Q;if(!(!H.exists||H.isSymlink||W!==z))return!1;if(H.isSymlink||$)await WQ(X);return await jQ(X,Z),!0}async function GZ(Q){let{outputDir:X,canonicalOutputDir:Z,inspection:$}=Q;if($.exists&&$.isSymlink&&$.pointsToCanonical)return!1;if($.exists)await WQ(X);return await wZ(Z,X),!0}async function LQ(Q,X){let Z;try{Z=await bQ(Q)}catch{return{exists:!1,isSymlink:!1,pointsToCanonical:!1}}let $=process.platform==="win32"&&Z.isDirectory()&&await kQ(Q)!==null;if(!(Z.isSymbolicLink()||$))return{exists:!0,isSymlink:!1,pointsToCanonical:!1};let[W,z,J]=await Promise.all([yQ(Q),yQ(X),kQ(Q)]);return{exists:!0,isSymlink:!0,pointsToCanonical:W!==null&&z!==null&&W===z||J===X}}async function yQ(Q){try{return await qZ(Q)}catch{return null}}async function kQ(Q){try{return await BZ(Q)}catch{return null}}async function wZ(Q,X){await IQ(EQ(X),{recursive:!0});let Z=process.platform==="win32"?"junction":"dir";await zZ(Q,X,Z)}async function NQ(Q){try{return await bQ(Q),!0}catch{return!1}}async function FZ(Q,X){let Z=new Set;for(let $ of p)Z.add(v($,X,Q));for(let $ of Z)if(await m($)!==null)return!0;return!1}function OZ(Q){let X={name:Q.name,description:Q.description,version:Q.version};return[{path:XQ,content:`${JSON.stringify(X,null,"\t")}
6
+ `}]}async function WQ(Q){await $Q(Q,{recursive:!0,force:!0})}async function jQ(Q,X){let Z=new Set;for(let H of X){let W=_Q(Q,H.path),z=EQ(W);Z.add(z)}let $=[...Z].sort();for(let H of $)await IQ(H,{recursive:!0});for(let H of X){let W=_Q(Q,H.path);await JZ(W,H.content,"utf-8")}}import{Crust as vQ,VALIDATION_MODE_ENV as UZ}from"@crustjs/core";import{confirm as VZ,multiselect as RZ,select as _Z,spinner as r}from"@crustjs/prompts";import{bold as t,dim as f,yellow as SQ}from"@crustjs/style";var TZ="skill",yZ="global",o="__universal__";function kZ(Q){return Q==="global"||Q==="project"}async function AQ(Q,X){if(Q!==void 0){if(!kZ(Q))throw Error(`Invalid --scope value: ${String(Q)}. Expected "project" or "global".`);return Q}if(X.defaultScope)return X.defaultScope;return _Z({message:"Select scope",choices:[{label:"Project",value:"project"},{label:"Global",value:"global"}],default:yZ})}function YQ(Q){let X=new Set(C()),Z=[];if(Q.some(($)=>X.has($)))Z.push("Universal");for(let $ of Q){if(X.has($))continue;Z.push(P[$])}return Z}function DQ(Q){let X=new Set(C()),Z=[],$=Q.find((H)=>X.has(H.agent));if($)Z.push({label:"Universal",outputDir:$.outputDir});for(let H of Q){if(X.has(H.agent))continue;Z.push({label:P[H.agent],outputDir:H.outputDir})}return Z}function BQ(Q,X){return{name:Q.meta.name,description:Q.meta.description??"",version:X}}async function bZ(Q,X){let Z=[...C(),...D()];if(Z.length===0)return;let $=BQ(Q,X.version),H=["project","global"];for(let W of H){let J=(await d({name:$.name,agents:Z,scope:W})).agents.filter((q)=>q.installed&&q.version!==$.version);if(J.length===0)continue;try{await r({message:`Updating ${W} skills...`,task:async({updateMessage:q})=>{let K=await A({command:Q,meta:$,agents:J.map((w)=>w.agent),scope:W,installMode:X.installMode}),x=K.agents.filter((w)=>w.status==="updated").map((w)=>w.agent),G=YQ(x);if(G.length>0)q(`Updated skill "${S($.name)}" to v${$.version} for ${G.join(", ")} (${W})`);return K}})}catch(q){if(q instanceof b)console.warn(SQ(`Skill conflict: "${q.details.outputDir}" already exists but was not created by ${$.name}. Skipping auto-update for ${W}. Delete or rename the conflicting skill to resolve.`));else throw q}}}function IZ(Q){let X;return{name:"skills",async setup(Z,$){X=Z.rootCommand;let H=Q.command??TZ;if($.addSubCommand(X,H,EZ(X,Q,H)),process.env[UZ]==="1")return;if(Z.argv[0]===H)return;if(Q.autoUpdate!==!1)await bZ(X,Q)}}}function EZ(Q,X,Z){let $=PZ(Q,X);return new vQ(Z).meta({description:"Manage agent skill installations"}).flags({scope:{type:"string",description:"Install scope (project or global)"}}).run(async(H)=>{let W=BQ(Q,X.version),z=await AQ(H.flags.scope,X),J=await QQ(),q=C(),K=D(),x=await d({name:W.name,agents:[...q,...K],scope:z}),G=new Set(x.agents.filter((B)=>B.installed).map((B)=>B.agent)),w=new Set(J),h=new Map(x.agents.map((B)=>[B.agent,B])),N=K.filter((B)=>{if(w.has(B))return!0;return h.get(B)?.installed===!0}),a=N.filter((B)=>G.has(B)),R=[];if(q.length>0){let B=q[0];if(!B)throw Error("Expected at least one universal agent");let O=h.get(B)?.outputDir??"path unavailable";R.push({label:"Universal",value:o,hint:O});let U=q.map((n)=>P[n]).join(", ");console.log(f(`Agents supporting universal skills: ${U}`))}for(let B of N){let O=h.get(B)?.outputDir??"path unavailable";R.push({label:P[B],value:B,hint:O})}let l=q.length>0&&q.every((B)=>G.has(B)),_=[...a.filter((B)=>!q.includes(B))];if(l)_.unshift(o);let c=R.length===0?[]:await RZ({message:"Select agents to install skills for",choices:R,default:_,required:!1}),u=new Set(c.filter((B)=>B!==o));if(c.includes(o))for(let B of q)u.add(B);let j=[...u],M=j.filter((B)=>!G.has(B)),V=j.filter((B)=>{let F=x.agents.find((O)=>O.agent===B);return F?.installed===!0&&F.version!==W.version}),T=[...G].filter((B)=>!j.includes(B)),I=[...M,...V];if(I.length>0)try{let B=await r({message:"Installing skills...",task:async()=>A({command:Q,meta:W,agents:I,scope:z,installMode:X.installMode})});console.log(`
7
+ ${t(`Installed "${W.name}" v${W.version}`)}`);for(let F of DQ(B.agents))console.log(f(` ${F.label} \u2192 ${F.outputDir}`))}catch(B){if(B instanceof b)if(await VZ({message:`"${B.details.outputDir}" already exists but was not created by Crust. Overwrite?`,default:!1})){let O=await r({message:"Overwriting skill...",task:async()=>A({command:Q,meta:W,agents:[B.details.agent],scope:z,force:!0,installMode:X.installMode})});console.log(`
8
+ ${t(`Installed "${W.name}" v${W.version}`)}`);for(let U of DQ(O.agents))console.log(f(` ${U.label} \u2192 ${U.outputDir}`))}else console.log(f(`
9
+ Skipped ${P[B.details.agent]}`));else throw B}if(T.length>0){let F=(await r({message:"Removing skills...",task:async()=>HQ({name:W.name,agents:T,scope:z})})).agents.filter((U)=>U.status==="removed").map((U)=>U.agent),O=YQ(F);if(O.length>0)console.log(`
10
+ ${t(`Removed from ${O.join(", ")}`)}`)}if(I.length===0&&T.length===0)console.log(f("No changes."))}).command($)._node}function PZ(Q,X){return new vQ("update").meta({description:"Update installed skills to latest version"}).flags({scope:{type:"string",description:"Update scope (project or global)"}}).run(async(Z)=>{let $=await AQ(Z.flags.scope,X),H=[...C(),...D()],W=BQ(Q,X.version),J=(await d({name:W.name,agents:H,scope:$})).agents.filter((q)=>q.installed&&q.version!==W.version);if(J.length===0){console.log(f(`No updates needed (${$}).`));return}try{let K=(await r({message:`Updating ${$} skills...`,task:async()=>A({command:Q,meta:W,agents:J.map((G)=>G.agent),scope:$,installMode:X.installMode})})).agents.filter((G)=>G.status==="updated").map((G)=>G.agent),x=YQ(K);if(x.length>0)console.log(`
11
+ ${t(`Updated "${W.name}" to v${W.version} for ${x.join(", ")} (${$})`)}`)}catch(q){if(q instanceof b)console.warn(SQ(`Skipped ${P[q.details.agent]}: "${q.details.outputDir}" already exists but was not created by ${W.name}. Delete or rename the conflicting directory to resolve.`));else throw q}})}export{HQ as uninstallSkill,d as skillStatus,IZ as skillPlugin,S as resolveSkillName,s as resolveCanonicalSkillPath,CQ as isValidSkillName,gQ as isUniversalAgent,C as getUniversalAgents,D as getAdditionalAgents,A as generateSkill,QQ as detectInstalledAgents,b as SkillConflictError};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crustjs/skills",
3
- "version": "0.0.15",
3
+ "version": "0.0.16",
4
4
  "description": "Agent skill generation from Crust command definitions",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -42,16 +42,16 @@
42
42
  "test": "bun test"
43
43
  },
44
44
  "dependencies": {
45
- "@crustjs/prompts": "0.0.8",
46
- "@crustjs/style": "0.0.4"
45
+ "@crustjs/prompts": "0.0.9",
46
+ "@crustjs/style": "0.0.5"
47
47
  },
48
48
  "devDependencies": {
49
49
  "@crustjs/config": "0.0.0",
50
- "@crustjs/core": "0.0.12",
50
+ "@crustjs/core": "0.0.13",
51
51
  "bunup": "^0.16.29"
52
52
  },
53
53
  "peerDependencies": {
54
- "@crustjs/core": "0.0.12",
54
+ "@crustjs/core": "0.0.13",
55
55
  "typescript": "^5"
56
56
  }
57
57
  }