@crustjs/skills 0.0.10 → 0.0.12

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
@@ -108,8 +108,8 @@ If auto-update does not appear to work:
108
108
 
109
109
  - Ensure plugin is passed to `runMain(..., { plugins: [...] })`.
110
110
  - Ensure at least one supported agent is detected for your scope:
111
- - `scope: "global"` -> `~/.claude` or `~/.config/opencode`
112
- - `scope: "project"` -> `<cwd>/.claude` or `<cwd>/.opencode` (falls back to global roots)
111
+ - `scope: "global"` -> checks supported global agent config roots (for example `~/.claude`, `~/.config/opencode`, `~/.codex`)
112
+ - `scope: "project"` -> checks project roots first (for example `<cwd>/.claude`, `<cwd>/.opencode`) then falls back to global roots
113
113
  - Check for existing conflicting skill directories without `crust.json`.
114
114
 
115
115
  ## Recommended Export Pattern
@@ -282,7 +282,6 @@ Generated output goes to `<outDir>/skills/use-<name>/` (the `use-` prefix is app
282
282
  ```
283
283
  skills/use-my-cli/
284
284
  SKILL.md # Entrypoint — loaded by the agent
285
- command-index.md # Maps all commands to documentation file paths
286
285
  commands/ # Per-command documentation mirroring the CLI hierarchy
287
286
  my-cli.md # Root command
288
287
  serve.md # Subcommand
@@ -296,10 +295,9 @@ skills/use-my-cli/
296
295
 
297
296
  | File | Purpose |
298
297
  | ------------------ | -------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
299
- | `SKILL.md` | Agent entrypoint with YAML frontmatter. Directs agents to load specific command files on demand (lazy loading). |
300
- | `command-index.md` | Markdown table listing every command, its type (runnable/group), and documentation path. |
298
+ | `SKILL.md` | Agent entrypoint with YAML frontmatter and an embedded command reference table listing every command path, type (runnable/group), and documentation link. |
301
299
  | `commands/*.md` | Per-command reference files. Leaf commands include usage, arguments, flags, defaults, and aliases. Group commands list subcommands with links. |
302
- | `crust.json` | Crust-specific JSON metadata: name, description, version, entrypoint, and list of all command paths. Also serves as an ownership marker — its presence indicates the skill was generated by Crust. |
300
+ | `crust.json` | Crust-specific JSON metadata: name, description, and version. Also serves as an ownership marker — its presence indicates the skill was generated by Crust. |
303
301
 
304
302
  ## Conflict Detection
305
303
 
@@ -324,10 +322,16 @@ try {
324
322
 
325
323
  After generating a skill bundle, consumers can install it by copying the skill directory.
326
324
 
327
- ### OpenCode
325
+ ### Universal agents (OpenCode, Codex, Cursor, and others)
328
326
 
329
327
  ```sh
330
- cp -r skills/use-my-cli/ .opencode/skills/use-my-cli/
328
+ cp -r skills/use-my-cli/ .agents/skills/use-my-cli/
329
+ ```
330
+
331
+ Global install for universal agents:
332
+
333
+ ```sh
334
+ cp -r skills/use-my-cli/ ~/.config/agents/skills/use-my-cli/
331
335
  ```
332
336
 
333
337
  ### Claude Code
package/dist/index.d.ts CHANGED
@@ -69,7 +69,9 @@ interface SkillMeta {
69
69
  allowedTools?: string;
70
70
  }
71
71
  /** Supported agent targets for skill installation. */
72
- type AgentTarget = "claude-code" | "opencode";
72
+ type AgentTarget = "amp" | "adal" | "antigravity" | "augment" | "claude-code" | "cline" | "codebuddy" | "codex" | "command-code" | "continue" | "cortex" | "crush" | "cursor" | "droid" | "gemini-cli" | "github-copilot" | "goose" | "iflow-cli" | "junie" | "kilo" | "kimi-cli" | "kiro-cli" | "kode" | "mcpjam" | "mistral-vibe" | "mux" | "neovate" | "opencode" | "openclaw" | "openhands" | "pi" | "pochi" | "qoder" | "qwen-code" | "replit" | "roo" | "trae" | "trae-cn" | "windsurf" | "zencoder";
73
+ /** Agent install class used by interactive skill management UX. */
74
+ type AgentClass = "universal" | "additional";
73
75
  /** Installation scope — global (home directory) or project (cwd). */
74
76
  type Scope = "global" | "project";
75
77
  /**
@@ -241,44 +243,27 @@ interface SkillPluginOptions {
241
243
  */
242
244
  command?: boolean | string;
243
245
  }
244
- /**
245
- * Options for detecting installed agents.
246
- */
246
+ /** Returns agents that use the canonical `.agents/skills` layout. */
247
+ declare function getUniversalAgents(): AgentTarget[];
248
+ /** Returns agents that use agent-specific skill roots. */
249
+ declare function getAdditionalAgents(): AgentTarget[];
250
+ /** Returns true if the agent uses the canonical `.agents/skills` layout. */
251
+ declare function isUniversalAgent(agent: AgentTarget): boolean;
247
252
  interface DetectInstalledAgentsOptions {
248
- /**
249
- * Detection scope.
250
- * - `global`: checks global config roots under home directory.
251
- * - `project`: checks project-local config roots under cwd, then falls back
252
- * to global roots under home directory when local roots are missing.
253
- * @default "global"
254
- */
253
+ /** Kept for backwards compatibility with previous API. */
255
254
  scope?: Scope;
256
- /** Home directory override used for global detection (tests). */
255
+ /** Kept for backwards compatibility with previous API. */
257
256
  home?: string;
258
- /** Working directory override used for project detection (tests). */
257
+ /** Working directory for command checks. */
259
258
  cwd?: string;
259
+ /** Test-only hook to override command detection. */
260
+ commandChecker?: (command: string, cwd: string) => Promise<boolean>;
260
261
  }
261
262
  /**
262
- * Detects which supported agents are installed by checking for agent
263
- * configuration roots for the requested scope.
263
+ * Detects installed additional agents by probing their CLI binaries.
264
264
  *
265
- * Detection table:
266
- * | Scope | Agent | Config directories checked |
267
- * | --------- | ------------ | ------------------------------------------ |
268
- * | `global` | `claude-code`| `<homedir>/.claude/` |
269
- * | `global` | `opencode` | `<homedir>/.config/opencode/` |
270
- * | `project` | `claude-code`| `<cwd>/.claude/`, fallback `<homedir>/.claude/` |
271
- * | `project` | `opencode` | `<cwd>/.opencode/`, fallback `<homedir>/.config/opencode/` |
272
- *
273
- * @param options - Optional scope/home/cwd overrides. For backwards
274
- * compatibility, passing a string is treated as `home`.
275
- * @returns Array of detected agent targets (may be empty)
276
- *
277
- * @example
278
- * ```ts
279
- * const agents = await detectInstalledAgents();
280
- * // ["claude-code"] — only Claude Code config found
281
- * ```
265
+ * Universal agents are intentionally not detected here so callers can always
266
+ * present them as a single optional "Universal" install target.
282
267
  */
283
268
  declare function detectInstalledAgents(options?: string | DetectInstalledAgentsOptions): Promise<AgentTarget[]>;
284
269
  /** Details about the conflict between an existing skill and an incoming one. */
@@ -437,4 +422,4 @@ import { CrustPlugin } from "@crustjs/core";
437
422
  * ```
438
423
  */
439
424
  declare function skillPlugin(options: SkillPluginOptions): CrustPlugin;
440
- export { uninstallSkill, skillStatus, skillPlugin, resolveSkillName, isValidSkillName, generateSkill, detectInstalledAgents, UninstallStatus, UninstallResult, UninstallOptions, StatusResult, StatusOptions, SkillPluginOptions, SkillMeta, SkillConflictError, SkillConflictDetails, Scope, InstallStatus, GenerateResult, GenerateOptions, AgentTarget, AgentResult };
425
+ export { uninstallSkill, skillStatus, skillPlugin, resolveSkillName, isValidSkillName, isUniversalAgent, getUniversalAgents, getAdditionalAgents, generateSkill, detectInstalledAgents, UninstallStatus, UninstallResult, UninstallOptions, StatusResult, StatusOptions, SkillPluginOptions, SkillMeta, SkillConflictError, SkillConflictDetails, Scope, InstallStatus, GenerateResult, GenerateOptions, AgentTarget, AgentResult, AgentClass };
package/dist/index.js CHANGED
@@ -1,11 +1,10 @@
1
1
  // @bun
2
- import{access as JQ}from"fs/promises";import{homedir as u}from"os";import{join as z}from"path";var RQ=["claude-code","opencode"],j={"claude-code":"Claude Code",opencode:"OpenCode"};function S(Q,Z,X){let H=Z==="global"?u():process.cwd();switch(Q){case"claude-code":return z(H,".claude","skills",X);case"opencode":if(Z==="global")return z(H,".config","opencode","skills",X);return z(H,".opencode","skills",X)}}async function E(Q){let Z=typeof Q==="string"?{home:Q}:Q??{},X=Z.scope??"global",H=Z.home??u(),W=Z.cwd??process.cwd(),$=[];for(let J of RQ){let R=qQ(J,X,H,W),Y=!1;for(let K of R)if(Y=await JQ(K).then(()=>!0).catch(()=>!1),Y)break;if(Y)$.push(J)}return $}function qQ(Q,Z,X,H){if(Z==="project")switch(Q){case"claude-code":return[z(H,".claude"),z(X,".claude")];case"opencode":return[z(H,".opencode"),z(X,".config","opencode")]}switch(Q){case"claude-code":return[z(X,".claude")];case"opencode":return[z(X,".config","opencode")]}}class M 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{access as n,mkdir as EQ,rm as a,writeFile as LQ}from"fs/promises";import{dirname as TQ,join as t}from"path";function p(Q){return f(Q,[])}function f(Q,Z){let X=YQ(Q.meta.name),H=[...Z,X],W=BQ(Q.args),$=OQ(Q.effectiveFlags),J=GQ(Q.subCommands,H);return{name:X,path:H,description:Q.meta.description,usage:Q.meta.usage,runnable:typeof Q.run==="function",args:W,flags:$,children:J}}function YQ(Q){return Q.trim().toLowerCase()}function BQ(Q){if(!Q||Q.length===0)return[];return Q.map(KQ)}function KQ(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=c(Q.default);return Z}function OQ(Q){if(!Q)return[];return Object.keys(Q).sort().map((X)=>{return xQ(X,Q[X])})}function xQ(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=c(Z.default);return X}function GQ(Q,Z){return Object.keys(Q).sort().map((H)=>{return f(Q[H],Z)})}function c(Q){if(Array.isArray(Q))return JSON.stringify(Q);return String(Q)}function _(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 g(Q){return Q.replace(/(?<!\\)\|/g,"\\|")}function m(Q,Z){let X=[],H=d(Q);X.push({path:"SKILL.md",content:zQ(Q,Z)}),X.push({path:"command-index.md",content:UQ(Q,H)});for(let W of H){let $=U(W),J=W.children.length>0?MQ(W,Q):jQ(W,Q);X.push({path:$,content:J})}return X}function d(Q){let Z=[Q];for(let X of Q.children)Z.push(...d(X));return Z}function U(Q){if(Q.path.length<=1)return`commands/${Q.name}.md`;return`commands/${Q.path.slice(1).join("/")}.md`}function L(Q){return Q.path.join(" ")}function A(Q,Z){let X=Q.split("/").slice(0,-1),H=Z.split("/"),W=0;while(W<X.length&&W<H.length&&X[W]===H[W])W++;let $=X.length-W,J=H.slice(W);if($===0)return J.join("/");return[...Array.from({length:$},()=>".."),...J].join("/")}function zQ(Q,Z){let X=[];if(X.push("---"),X.push(`name: ${_(Z.name)}`),X.push(`description: ${_(Z.description)}`),Z.license)X.push(`license: ${_(Z.license)}`);if(Z.compatibility)X.push(`compatibility: ${_(Z.compatibility)}`);if(Z.disableModelInvocation)X.push("disable-model-invocation: true");if(Z.allowedTools)X.push(`allowed-tools: ${_(Z.allowedTools)}`);if(X.push("metadata:"),X.push(` version: "${Z.version}"`),X.push("---"),X.push(""),X.push(`# ${Z.name}`),X.push(""),Q.description)X.push(Q.description),X.push("");let H=Z.name.startsWith("use-")?Z.name.slice(4):Z.name;if(X.push(`Use this skill when working with \`${H}\` commands, or when you need help with \`${H}\` syntax, flags, or subcommands.`),X.push(""),X.push("## Command Reference"),X.push(""),X.push("For the full list of commands and their documentation paths, see [command-index.md](command-index.md). **Do not read all command files at once.** Instead:"),X.push(""),X.push("1. Check [command-index.md](command-index.md) to find the relevant command"),X.push("2. Read only the specific file from the `commands/` directory that you need"),X.push(""),Q.children.length>0){X.push("## Available Commands"),X.push("");for(let W of Q.children){let $=U(W),J=W.description?` - ${W.description}`:"";X.push(`- [\`${W.name}\`](${$})${J}`)}X.push("")}if(Q.runnable){X.push("## Usage"),X.push("");let W=U(Q);X.push(`The root command is directly executable. See [${Q.name}](${W}) for usage details.`),X.push("")}return X.join(`
3
- `)}function UQ(Q,Z){let X=[];X.push("# Command Index"),X.push(""),X.push("| Command | Type | Documentation |"),X.push("| ------- | ---- | ------------- |");for(let H of Z){let W=L(H),$=U(H),J=VQ(H);X.push(`| \`${W}\` | ${J} | [${$}](${$}) |`)}return X.push(""),X.join(`
4
- `)}function VQ(Q){if(Q.runnable&&Q.children.length>0)return"runnable, group";if(Q.runnable)return"runnable";return"group"}function jQ(Q,Z){let X=[],H=L(Q);if(X.push(`# \`${H}\``),X.push(""),Q.description)X.push(Q.description),X.push("");if(X.push("## Usage"),X.push(""),Q.usage)X.push("```"),X.push(Q.usage),X.push("```");else X.push("```"),X.push(r(Q)),X.push("```");if(X.push(""),Q.args.length>0)X.push("## Arguments"),X.push(""),X.push(...l(Q.args)),X.push("");if(Q.flags.length>0)X.push("## Flags"),X.push(""),X.push(...i(Q.flags)),X.push("");return X.push(...o(Q,Z)),X.join(`
5
- `)}function MQ(Q,Z){let X=[],H=L(Q),W=U(Q);if(X.push(`# \`${H}\``),X.push(""),Q.description)X.push(Q.description),X.push("");if(Q.runnable){if(X.push("## Usage"),X.push(""),Q.usage)X.push("```"),X.push(Q.usage),X.push("```");else X.push("```"),X.push(r(Q)),X.push("```");if(X.push(""),Q.args.length>0)X.push("## Arguments"),X.push(""),X.push(...l(Q.args)),X.push("");if(Q.flags.length>0)X.push("## Flags"),X.push(""),X.push(...i(Q.flags)),X.push("")}X.push("## Subcommands"),X.push("");for(let $ of Q.children){let J=U($),R=A(W,J),Y=$.description?` - ${$.description}`:"";X.push(`- [\`${$.name}\`](${R})${Y}`)}return X.push(""),X.push(...o(Q,Z)),X.join(`
6
- `)}function r(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 l(Q){let Z=[];Z.push("| Argument | Type | Required | Description |"),Z.push("| -------- | ---- | -------- | ----------- |");for(let X of Q){let H=X.variadic?`${X.name}...`:X.name,W=X.required?"Yes":"No",$=g(IQ(X));Z.push(`| \`${H}\` | ${X.type} | ${W} | ${$} |`)}return Z}function IQ(Q){let Z=[];if(Q.description)Z.push(Q.description);if(Q.default!==void 0)Z.push(`Default: \`${Q.default}\``);return Z.join(". ")||"-"}function i(Q){let Z=[];Z.push("| Flag | Type | Required | Description |"),Z.push("| ---- | ---- | -------- | ----------- |");for(let X of Q){let H=_Q(X),W=X.required?"Yes":"No",$=g(wQ(X));Z.push(`| ${H} | ${X.type} | ${W} | ${$} |`)}return Z}function _Q(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 wQ(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 o(Q,Z){let X=[],H=U(Q);if(X.push("---"),X.push(""),Q.path.length>1){let $=Q.path.slice(0,-1),J=s(Z,$);if(J){let R=U(J),Y=A(H,R),K=L(J);X.push(`Parent: [\`${K}\`](${Y})`),X.push("")}}let W=A(H,"command-index.md");return X.push(`[Command Index](${W})`),X.push(""),X}function s(Q,Z){if(kQ(Q.path,Z))return Q;for(let X of Q.children){let H=s(X,Z);if(H)return H}return}function kQ(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 FQ}from"fs/promises";import{join as SQ}from"path";var C="crust.json";async function D(Q){try{let Z=await FQ(SQ(Q,C),"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 e=/^[a-z0-9]+(-[a-z0-9]+)*$/;function QQ(Q){return Q.length>=1&&Q.length<=64&&e.test(Q)}function I(Q){return Q.startsWith("use-")?Q:`use-${Q}`}async function w(Q){let{command:Z,meta:X,agents:H,scope:W="global",clean:$=!0,force:J=!1}=Q,R=I(X.name);if(!QQ(R))throw Error(`Invalid skill name "${R}": must be 1\u201364 lowercase `+`alphanumeric characters and hyphens, no leading/trailing/consecutive hyphens. Pattern: ${e.source}`);let Y={...X,name:R},K=p(Z),O=m(K,Y),y=PQ(K,Y),k=[...O,...y].sort((x,q)=>x.path<q.path?-1:x.path>q.path?1:0),V=[];for(let x of H){let q=S(x,W,Y.name),B=await D(q);if(B===null){if(await n(q).then(()=>!0).catch(()=>!1)&&!J)throw new M({agent:x,outputDir:q})}let G=B===null?"installed":B===Y.version?"up-to-date":"updated";if(G==="up-to-date"){V.push({agent:x,outputDir:q,files:[],status:"up-to-date"});continue}let F=G==="updated"?B??void 0:void 0;if($)await yQ(q);await AQ(q,k),V.push({agent:x,outputDir:q,files:k.map((h)=>h.path),status:G,previousVersion:F})}return{agents:V}}async function N(Q){let{name:Z,agents:X,scope:H="global"}=Q,W=I(Z),$=[];for(let J of X){let R=S(J,H,W);if(await n(R).then(()=>!0).catch(()=>!1))await a(R,{recursive:!0,force:!0}),$.push({agent:J,outputDir:R,status:"removed"});else $.push({agent:J,outputDir:R,status:"not-found"})}return{agents:$}}async function T(Q){let{name:Z,agents:X,scope:H="global"}=Q,W=I(Z),$=[];for(let J of X){let R=S(J,H,W),Y=await D(R);$.push({agent:J,outputDir:R,installed:Y!==null,version:Y??void 0})}return{agents:$}}function PQ(Q,Z){return[{path:C,content:bQ(Q,Z)}]}function bQ(Q,Z){let X=XQ(Q),H={name:Z.name,description:Z.description,version:Z.version,entrypoint:"SKILL.md",commands:X};return`${JSON.stringify(H,null,"\t")}
7
- `}function XQ(Q){let Z=[Q.path.join(" ")];for(let X of Q.children)Z.push(...XQ(X));return Z}async function yQ(Q){await a(Q,{recursive:!0,force:!0})}async function AQ(Q,Z){let X=new Set;for(let W of Z){let $=t(Q,W.path),J=TQ($);X.add(J)}let H=[...X].sort();for(let W of H)await EQ(W,{recursive:!0});for(let W of Z){let $=t(Q,W.path);await LQ($,W.content,"utf-8")}}import{createCommandNode as CQ,VALIDATION_MODE_ENV as DQ}from"@crustjs/core";import{confirm as NQ,multiselect as vQ,spinner as b}from"@crustjs/prompts";import{bold as v,dim as P,yellow as ZQ}from"@crustjs/style";var HQ="skill",WQ="global";function $Q(Q,Z){return{name:Q.meta.name,description:Q.meta.description??"",version:Z}}async function hQ(Q,Z){let X=Z.scope??WQ,H=await E({scope:X});if(H.length===0)return;let W=$Q(Q,Z.version),J=(await T({name:W.name,agents:H,scope:X})).agents.filter((R)=>R.installed&&R.version!==W.version);if(J.length===0)return;try{await b({message:"Updating skills...",task:async({updateMessage:R})=>{let Y=await w({command:Q,meta:W,agents:J.map((O)=>O.agent),scope:Z.scope}),K=Y.agents.filter((O)=>O.status==="updated").map((O)=>j[O.agent]);if(K.length>0)R(`Updated skill "${I(W.name)}" to v${W.version} for ${K.join(", ")}`);return Y}})}catch(R){if(R instanceof M)console.warn(ZQ(`Skill conflict: "${R.details.outputDir}" already exists but was not created by ${W.name}. Skipping auto-update. Delete or rename the conflicting skill to resolve.`));else throw R}}function uQ(Q){let Z;return{name:"skills",async setup(X,H){Z=X.rootCommand;let W=typeof Q.command==="string"?Q.command:HQ;if(Q.command!==!1)H.addSubCommand(Z,W,pQ(Z,Q));if(process.env[DQ]==="1")return;if(Q.command!==!1&&X.argv[0]===W)return;if(Q.autoUpdate!==!1)await hQ(Z,Q)}}}function pQ(Q,Z){let X=CQ(HQ);return X.meta.description="Manage agent skill installations",X.run=async()=>{let H=$Q(Q,Z.version),W=Z.scope??WQ,$=await E({scope:W});if($.length===0){console.log(ZQ("No supported agents detected. Install Claude Code or OpenCode first."));return}let J=await T({name:H.name,agents:$,scope:W}),R=[],Y=J.agents.map((q)=>{let B=q.installed?`v${q.version} installed`:"not installed";if(q.installed)R.push(q.agent);return{label:j[q.agent],value:q.agent,hint:B}}),K=process.stdin.isTTY,O=await vQ({message:"Select agents to install skills for",choices:Y,default:R,initial:!K?$:void 0,required:!1}),y=O.filter((q)=>!R.includes(q)),k=O.filter((q)=>{let B=J.agents.find((G)=>G.agent===q);return B?.installed===!0&&B.version!==H.version}),V=R.filter((q)=>!O.includes(q)),x=[...y,...k];if(x.length>0)try{let q=await b({message:"Installing skills...",task:async()=>w({command:Q,meta:H,agents:x,scope:W})});console.log(`
8
- ${v(`Installed "${H.name}" v${H.version}`)}`);for(let B of q.agents)console.log(P(` ${j[B.agent]} \u2192 ${B.outputDir}`))}catch(q){if(q instanceof M)if(await NQ({message:`"${q.details.outputDir}" already exists but was not created by Crust. Overwrite?`,default:!1,initial:!K?!1:void 0})){let G=await b({message:"Overwriting skill...",task:async()=>w({command:Q,meta:H,agents:[q.details.agent],scope:W,force:!0})});console.log(`
9
- ${v(`Installed "${H.name}" v${H.version}`)}`);for(let F of G.agents)console.log(P(` ${j[F.agent]} \u2192 ${F.outputDir}`))}else console.log(P(`
10
- Skipped ${j[q.details.agent]}`));else throw q}if(V.length>0){let B=(await b({message:"Removing skills...",task:async()=>N({name:H.name,agents:V,scope:W})})).agents.filter((G)=>G.status==="removed").map((G)=>j[G.agent]);if(B.length>0)console.log(`
11
- ${v(`Removed from ${B.join(", ")}`)}`)}if(x.length===0&&V.length===0)console.log(P("No changes."))},X}export{N as uninstallSkill,T as skillStatus,uQ as skillPlugin,I as resolveSkillName,QQ as isValidSkillName,w as generateSkill,E as detectInstalledAgents,M as SkillConflictError};
2
+ import{spawn as kQ}from"child_process";import{homedir as XQ}from"os";import{join as $}from"path";var G=$(".agents","skills");function s(Q){if(Q!==XQ())return $(Q,".config");let Z=process.env.XDG_CONFIG_HOME?.trim();return Z&&Z.length>0?Z:$(Q,".config")}function U(Q){return $(s(Q),"agents","skills")}var P={amp:{label:"Amp",class:"universal",projectSkillsDir:G,globalSkillsDir:U},adal:{label:"AdaL",class:"additional",projectSkillsDir:$(".adal","skills"),globalSkillsDir:(Q)=>$(Q,".adal","skills"),detectCommands:["adal"]},antigravity:{label:"Antigravity",class:"additional",projectSkillsDir:$(".agent","skills"),globalSkillsDir:(Q)=>$(Q,".gemini","antigravity","skills"),detectCommands:["antigravity"]},augment:{label:"Augment",class:"additional",projectSkillsDir:$(".augment","skills"),globalSkillsDir:(Q)=>$(Q,".augment","skills"),detectCommands:["augment"]},"claude-code":{label:"Claude Code",class:"additional",projectSkillsDir:$(".claude","skills"),globalSkillsDir:(Q)=>$(process.env.CLAUDE_CONFIG_DIR?.trim()||$(Q,".claude"),"skills"),detectCommands:["claude","claude-code"]},cline:{label:"Cline",class:"universal",projectSkillsDir:G,globalSkillsDir:U},codebuddy:{label:"CodeBuddy",class:"additional",projectSkillsDir:$(".codebuddy","skills"),globalSkillsDir:(Q)=>$(Q,".codebuddy","skills"),detectCommands:["codebuddy"]},codex:{label:"Codex",class:"universal",projectSkillsDir:G,globalSkillsDir:U},"command-code":{label:"Command Code",class:"additional",projectSkillsDir:$(".commandcode","skills"),globalSkillsDir:(Q)=>$(Q,".commandcode","skills"),detectCommands:["command-code","commandcode"]},continue:{label:"Continue",class:"additional",projectSkillsDir:$(".continue","skills"),globalSkillsDir:(Q)=>$(Q,".continue","skills"),detectCommands:["continue"]},cortex:{label:"Cortex Code",class:"additional",projectSkillsDir:$(".cortex","skills"),globalSkillsDir:(Q)=>$(Q,".snowflake","cortex","skills"),detectCommands:["cortex"]},crush:{label:"Crush",class:"additional",projectSkillsDir:$(".crush","skills"),globalSkillsDir:(Q)=>$(s(Q),"crush","skills"),detectCommands:["crush"]},cursor:{label:"Cursor",class:"universal",projectSkillsDir:G,globalSkillsDir:U},droid:{label:"Droid",class:"additional",projectSkillsDir:$(".factory","skills"),globalSkillsDir:(Q)=>$(Q,".factory","skills"),detectCommands:["droid"]},"gemini-cli":{label:"Gemini CLI",class:"universal",projectSkillsDir:G,globalSkillsDir:U},"github-copilot":{label:"GitHub Copilot",class:"universal",projectSkillsDir:G,globalSkillsDir:U},goose:{label:"Goose",class:"additional",projectSkillsDir:$(".goose","skills"),globalSkillsDir:(Q)=>$(s(Q),"goose","skills"),detectCommands:["goose"]},"iflow-cli":{label:"iFlow CLI",class:"additional",projectSkillsDir:$(".iflow","skills"),globalSkillsDir:(Q)=>$(Q,".iflow","skills"),detectCommands:["iflow","iflow-cli"]},junie:{label:"Junie",class:"additional",projectSkillsDir:$(".junie","skills"),globalSkillsDir:(Q)=>$(Q,".junie","skills"),detectCommands:["junie"]},kilo:{label:"Kilo Code",class:"additional",projectSkillsDir:$(".kilocode","skills"),globalSkillsDir:(Q)=>$(Q,".kilocode","skills"),detectCommands:["kilo","kilocode"]},"kimi-cli":{label:"Kimi Code CLI",class:"universal",projectSkillsDir:G,globalSkillsDir:U},"kiro-cli":{label:"Kiro CLI",class:"additional",projectSkillsDir:$(".kiro","skills"),globalSkillsDir:(Q)=>$(Q,".kiro","skills"),detectCommands:["kiro","kiro-cli"]},kode:{label:"Kode",class:"additional",projectSkillsDir:$(".kode","skills"),globalSkillsDir:(Q)=>$(Q,".kode","skills"),detectCommands:["kode"]},mcpjam:{label:"MCPJam",class:"additional",projectSkillsDir:$(".mcpjam","skills"),globalSkillsDir:(Q)=>$(Q,".mcpjam","skills"),detectCommands:["mcpjam"]},"mistral-vibe":{label:"Mistral Vibe",class:"additional",projectSkillsDir:$(".vibe","skills"),globalSkillsDir:(Q)=>$(Q,".vibe","skills"),detectCommands:["mistral-vibe","vibe"]},mux:{label:"Mux",class:"additional",projectSkillsDir:$(".mux","skills"),globalSkillsDir:(Q)=>$(Q,".mux","skills"),detectCommands:["mux"]},neovate:{label:"Neovate",class:"additional",projectSkillsDir:$(".neovate","skills"),globalSkillsDir:(Q)=>$(Q,".neovate","skills"),detectCommands:["neovate"]},opencode:{label:"OpenCode",class:"universal",projectSkillsDir:G,globalSkillsDir:U},openclaw:{label:"OpenClaw",class:"additional",projectSkillsDir:"skills",globalSkillsDir:(Q)=>$(Q,".openclaw","skills"),detectCommands:["openclaw"]},openhands:{label:"OpenHands",class:"additional",projectSkillsDir:$(".openhands","skills"),globalSkillsDir:(Q)=>$(Q,".openhands","skills"),detectCommands:["openhands"]},pi:{label:"Pi",class:"additional",projectSkillsDir:$(".pi","skills"),globalSkillsDir:(Q)=>$(Q,".pi","agent","skills"),detectCommands:["pi"]},pochi:{label:"Pochi",class:"additional",projectSkillsDir:$(".pochi","skills"),globalSkillsDir:(Q)=>$(Q,".pochi","skills"),detectCommands:["pochi"]},qoder:{label:"Qoder",class:"additional",projectSkillsDir:$(".qoder","skills"),globalSkillsDir:(Q)=>$(Q,".qoder","skills"),detectCommands:["qoder"]},"qwen-code":{label:"Qwen Code",class:"additional",projectSkillsDir:$(".qwen","skills"),globalSkillsDir:(Q)=>$(Q,".qwen","skills"),detectCommands:["qwen","qwen-code"]},replit:{label:"Replit",class:"universal",projectSkillsDir:G,globalSkillsDir:U},roo:{label:"Roo Code",class:"additional",projectSkillsDir:$(".roo","skills"),globalSkillsDir:(Q)=>$(Q,".roo","skills"),detectCommands:["roo","roo-code"]},trae:{label:"Trae",class:"additional",projectSkillsDir:$(".trae","skills"),globalSkillsDir:(Q)=>$(Q,".trae","skills"),detectCommands:["trae"]},"trae-cn":{label:"Trae CN",class:"additional",projectSkillsDir:$(".trae","skills"),globalSkillsDir:(Q)=>$(Q,".trae-cn","skills"),detectCommands:["trae-cn","trae"]},windsurf:{label:"Windsurf",class:"additional",projectSkillsDir:$(".windsurf","skills"),globalSkillsDir:(Q)=>$(Q,".codeium","windsurf","skills"),detectCommands:["windsurf"]},zencoder:{label:"Zencoder",class:"additional",projectSkillsDir:$(".zencoder","skills"),globalSkillsDir:(Q)=>$(Q,".zencoder","skills"),detectCommands:["zencoder"]}},t=Object.keys(P),k=Object.fromEntries(t.map((Q)=>[Q,P[Q].label]));function f(){return t.filter((Q)=>P[Q].class==="universal")}function h(){return t.filter((Q)=>P[Q].class==="additional")}function yQ(Q){return P[Q].class==="universal"}async function p(Q){let Z=typeof Q==="string"?{home:Q}:Q??{},X=Z.cwd??process.cwd(),W=Z.commandChecker??PQ,H=[];for(let q of h()){let B=P[q].detectCommands??[],x=!1;for(let z of B)if(await W(z,X)){x=!0;break}if(x)H.push(q)}return H}function u(Q,Z,X){let W=P[Q];if(Z==="project")return $(process.cwd(),W.projectSkillsDir,X);return $(W.globalSkillsDir(XQ()),X)}async function PQ(Q,Z){for(let X of[["--version"],["-v"],["version"]])if(await bQ(Q,X,Z))return!0;return!1}async function bQ(Q,Z,X){return new Promise((W)=>{let H=kQ(Q,Z,{cwd:X,stdio:"ignore",shell:!1}),q=!1,B=(z)=>{if(q)return;q=!0,W(z)},x=setTimeout(()=>{H.kill("SIGTERM"),B(!1)},1000);H.once("error",()=>{clearTimeout(x),B(!1)}),H.once("exit",(z)=>{clearTimeout(x),B(z===0)})})}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{access as MQ,mkdir as gQ,rm as wQ,writeFile as mQ}from"fs/promises";import{dirname as dQ,join as OQ}from"path";function ZQ(Q){return WQ(Q,[])}function WQ(Q,Z){let X=TQ(Q.meta.name),W=[...Z,X],H=CQ(Q.args),q=_Q(Q.effectiveFlags),B=DQ(Q.subCommands,W);return{name:X,path:W,description:Q.meta.description,usage:Q.meta.usage,runnable:typeof Q.run==="function",args:H,flags:q,children:B}}function TQ(Q){return Q.trim().toLowerCase()}function CQ(Q){if(!Q||Q.length===0)return[];return Q.map(IQ)}function IQ(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=$Q(Q.default);return Z}function _Q(Q){if(!Q)return[];return Object.keys(Q).sort().map((X)=>{return EQ(X,Q[X])})}function EQ(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=$Q(Z.default);return X}function DQ(Q,Z){return Object.keys(Q).sort().map((W)=>{return WQ(Q[W],Z)})}function $Q(Q){if(Array.isArray(Q))return JSON.stringify(Q);return String(Q)}function N(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 HQ(Q){return Q.replace(/(?<!\\)\|/g,"\\|")}function qQ(Q,Z){let X=[],W=YQ(Q);X.push({path:"SKILL.md",content:LQ(Q,Z,W)});for(let H of W){let q=T(H),B=H.children.length>0?vQ(H,Q):SQ(H,Q);X.push({path:q,content:B})}return X}function YQ(Q){let Z=[Q];for(let X of Q.children)Z.push(...YQ(X));return Z}function T(Q){if(Q.path.length<=1)return`commands/${Q.name}.md`;return`commands/${Q.path.slice(1).join("/")}.md`}function c(Q){return Q.path.join(" ")}function o(Q,Z){let X=Q.split("/").slice(0,-1),W=Z.split("/"),H=0;while(H<X.length&&H<W.length&&X[H]===W[H])H++;let q=X.length-H,B=W.slice(H);if(q===0)return B.join("/");return[...Array.from({length:q},()=>".."),...B].join("/")}function LQ(Q,Z,X){let W=[];if(W.push("---"),W.push(`name: ${N(Z.name)}`),W.push(`description: ${N(Z.description)}`),Z.license)W.push(`license: ${N(Z.license)}`);if(Z.compatibility)W.push(`compatibility: ${N(Z.compatibility)}`);if(Z.disableModelInvocation)W.push("disable-model-invocation: true");if(Z.allowedTools)W.push(`allowed-tools: ${N(Z.allowedTools)}`);if(W.push("metadata:"),W.push(` version: "${Z.version}"`),W.push("---"),W.push(""),W.push(`# ${Z.name}`),W.push(""),Q.description)W.push(Q.description),W.push("");let H=Z.name.startsWith("use-")?Z.name.slice(4):Z.name;if(W.push(`Use this skill when working with \`${H}\` commands, or when you need help with \`${H}\` syntax, flags, or subcommands.`),W.push(""),W.push("## Command Reference"),W.push(""),W.push("This table lists all commands and their documentation paths. **Do not read all command files at once.** Instead:"),W.push(""),W.push("1. Use the table below to find the relevant command"),W.push("2. Use the `Type` column to choose what to execute: commands labeled `runnable` (including `runnable, group`) are executable, while `group` commands are not"),W.push("3. Read only the specific file from the `commands/` directory that you need"),W.push(""),W.push(...jQ(X)),W.push(""),Q.runnable){W.push("## Usage"),W.push("");let q=T(Q);W.push(`The root command is directly executable. See [${Q.name}](${q}) for usage details.`),W.push("")}return W.join(`
3
+ `)}function jQ(Q){let Z=[];Z.push("| Command | Type | Documentation |"),Z.push("| ------- | ---- | ------------- |");for(let X of Q){let W=c(X),H=T(X),q=NQ(X);Z.push(`| \`${W}\` | ${q} | [${H}](${H}) |`)}return Z}function NQ(Q){if(Q.runnable&&Q.children.length>0)return"runnable, group";if(Q.runnable)return"runnable";return"group"}function SQ(Q,Z){let X=[],W=c(Q);if(X.push(`# \`${W}\``),X.push(""),Q.description)X.push(Q.description),X.push("");if(X.push("## Usage"),X.push(""),Q.usage)X.push("```"),X.push(Q.usage),X.push("```");else X.push("```"),X.push(BQ(Q)),X.push("```");if(X.push(""),Q.args.length>0)X.push("## Arguments"),X.push(""),X.push(...xQ(Q.args)),X.push("");if(Q.flags.length>0)X.push("## Flags"),X.push(""),X.push(...zQ(Q.flags)),X.push("");return X.push(...JQ(Q,Z)),X.join(`
4
+ `)}function vQ(Q,Z){let X=[],W=c(Q),H=T(Q);if(X.push(`# \`${W}\``),X.push(""),Q.description)X.push(Q.description),X.push("");if(Q.runnable){if(X.push("## Usage"),X.push(""),Q.usage)X.push("```"),X.push(Q.usage),X.push("```");else X.push("```"),X.push(BQ(Q)),X.push("```");if(X.push(""),Q.args.length>0)X.push("## Arguments"),X.push(""),X.push(...xQ(Q.args)),X.push("");if(Q.flags.length>0)X.push("## Flags"),X.push(""),X.push(...zQ(Q.flags)),X.push("")}X.push("## Subcommands"),X.push("");for(let q of Q.children){let B=T(q),x=o(H,B),z=q.description?` - ${q.description}`:"";X.push(`- [\`${q.name}\`](${x})${z}`)}return X.push(""),X.push(...JQ(Q,Z)),X.join(`
5
+ `)}function BQ(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 xQ(Q){let Z=[];Z.push("| Argument | Type | Required | Description |"),Z.push("| -------- | ---- | -------- | ----------- |");for(let X of Q){let W=X.variadic?`${X.name}...`:X.name,H=X.required?"Yes":"No",q=HQ(AQ(X));Z.push(`| \`${W}\` | ${X.type} | ${H} | ${q} |`)}return Z}function AQ(Q){let Z=[];if(Q.description)Z.push(Q.description);if(Q.default!==void 0)Z.push(`Default: \`${Q.default}\``);return Z.join(". ")||"-"}function zQ(Q){let Z=[];Z.push("| Flag | Type | Required | Description |"),Z.push("| ---- | ---- | -------- | ----------- |");for(let X of Q){let W=fQ(X),H=X.required?"Yes":"No",q=HQ(hQ(X));Z.push(`| ${W} | ${X.type} | ${H} | ${q} |`)}return Z}function fQ(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 hQ(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 JQ(Q,Z){let X=[],W=T(Q);if(X.push("---"),X.push(""),Q.path.length>1){let q=Q.path.slice(0,-1),B=KQ(Z,q);if(B){let x=T(B),z=o(W,x),J=c(B);X.push(`Parent: [\`${J}\`](${z})`),X.push("")}}let H=o(W,"SKILL.md");return X.push(`[Skill Overview](${H})`),X.push(""),X}function KQ(Q,Z){if(pQ(Q.path,Z))return Q;for(let X of Q.children){let W=KQ(X,Z);if(W)return W}return}function pQ(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 uQ}from"fs/promises";import{join as cQ}from"path";var a="crust.json";async function n(Q){try{let Z=await uQ(cQ(Q,a),"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 FQ=/^[a-z0-9]+(-[a-z0-9]+)*$/;function VQ(Q){return Q.length>=1&&Q.length<=64&&FQ.test(Q)}function _(Q){return Q.startsWith("use-")?Q:`use-${Q}`}async function S(Q){let{command:Z,meta:X,agents:W,scope:H="global",clean:q=!0,force:B=!1}=Q,x=_(X.name);if(!VQ(x))throw Error(`Invalid skill name "${x}": must be 1\u201364 lowercase `+`alphanumeric characters and hyphens, no leading/trailing/consecutive hyphens. Pattern: ${FQ.source}`);let z={...X,name:x},J=ZQ(Z),O=qQ(J,z),E=rQ(z),D=[...O,...E].sort((K,M)=>K.path<M.path?-1:K.path>M.path?1:0),L=[],V=new Map;for(let K of W){let M=u(K,H,z.name),R=V.get(M);if(R)R.push(K);else V.set(M,[K])}for(let[K,M]of V){let R=M[0];if(!R)continue;let y=await n(K);if(y===null){if(await MQ(K).then(()=>!0).catch(()=>!1)&&!B)throw new b({agent:R,outputDir:K})}let C=y===null?"installed":y===z.version?"up-to-date":"updated";if(C==="up-to-date"){for(let I of M)L.push({agent:I,outputDir:K,files:[],status:"up-to-date"});continue}let j=C==="updated"?y??void 0:void 0;if(q)await iQ(K);await sQ(K,D);for(let I of M)L.push({agent:I,outputDir:K,files:D.map((r)=>r.path),status:C,previousVersion:j})}return{agents:L}}async function e(Q){let{name:Z,agents:X,scope:W="global"}=Q,H=_(Z),q=[],B=new Map;for(let x of X){let z=u(x,W,H),J=B.get(z);if(J)J.push(x);else B.set(z,[x])}for(let[x,z]of B)if(await MQ(x).then(()=>!0).catch(()=>!1)){await wQ(x,{recursive:!0,force:!0});for(let O of z)q.push({agent:O,outputDir:x,status:"removed"})}else for(let O of z)q.push({agent:O,outputDir:x,status:"not-found"});return{agents:q}}async function g(Q){let{name:Z,agents:X,scope:W="global"}=Q,H=_(Z),q=[],B=new Map;for(let x of X){let z=u(x,W,H),J=B.get(z);if(J)J.push(x);else B.set(z,[x])}for(let[x,z]of B){let J=await n(x);for(let O of z)q.push({agent:O,outputDir:x,installed:J!==null,version:J??void 0})}return{agents:q}}function rQ(Q){return[{path:a,content:lQ(Q)}]}function lQ(Q){let Z={name:Q.name,description:Q.description,version:Q.version};return`${JSON.stringify(Z,null,"\t")}
6
+ `}async function iQ(Q){await wQ(Q,{recursive:!0,force:!0})}async function sQ(Q,Z){let X=new Set;for(let H of Z){let q=OQ(Q,H.path),B=dQ(q);X.add(B)}let W=[...X].sort();for(let H of W)await gQ(H,{recursive:!0});for(let H of Z){let q=OQ(Q,H.path);await mQ(q,H.content,"utf-8")}}import{createCommandNode as tQ,VALIDATION_MODE_ENV as oQ}from"@crustjs/core";import{confirm as aQ,multiselect as nQ,spinner as d}from"@crustjs/prompts";import{bold as QQ,dim as v,yellow as eQ}from"@crustjs/style";var GQ="skill",UQ="global",m="__universal__";function RQ(Q,Z){return{name:Q.meta.name,description:Q.meta.description??"",version:Z}}async function QX(Q,Z){let X=Z.scope??UQ,W=[...f(),...await p({scope:X})];if(W.length===0)return;let H=RQ(Q,Z.version),B=(await g({name:H.name,agents:W,scope:X})).agents.filter((x)=>x.installed&&x.version!==H.version);if(B.length===0)return;try{await d({message:"Updating skills...",task:async({updateMessage:x})=>{let z=await S({command:Q,meta:H,agents:B.map((O)=>O.agent),scope:Z.scope}),J=z.agents.filter((O)=>O.status==="updated").map((O)=>k[O.agent]);if(J.length>0)x(`Updated skill "${_(H.name)}" to v${H.version} for ${J.join(", ")}`);return z}})}catch(x){if(x instanceof b)console.warn(eQ(`Skill conflict: "${x.details.outputDir}" already exists but was not created by ${H.name}. Skipping auto-update. Delete or rename the conflicting skill to resolve.`));else throw x}}function XX(Q){let Z;return{name:"skills",async setup(X,W){Z=X.rootCommand;let H=typeof Q.command==="string"?Q.command:GQ;if(Q.command!==!1)W.addSubCommand(Z,H,ZX(Z,Q));if(process.env[oQ]==="1")return;if(Q.command!==!1&&X.argv[0]===H)return;if(Q.autoUpdate!==!1)await QX(Z,Q)}}}function ZX(Q,Z){let X=tQ(GQ);return X.meta.description="Manage agent skill installations",X.run=async()=>{let W=RQ(Q,Z.version),H=Z.scope??UQ,q=await p({scope:H}),B=f(),x=h(),z=await g({name:W.name,agents:[...B,...x],scope:H}),J=new Set(z.agents.filter((Y)=>Y.installed).map((Y)=>Y.agent)),O=new Set(q),E=new Map(z.agents.map((Y)=>[Y.agent,Y])),D=x.filter((Y)=>{if(O.has(Y))return!0;return E.get(Y)?.installed===!0}),L=D.filter((Y)=>J.has(Y)),V=[];if(B.length>0){let Y=B[0];if(!Y)throw Error("Expected at least one universal agent");let F=E.get(Y)?.outputDir??"path unavailable";V.push({label:"Universal",value:m,hint:F}),console.log(v(`Universal includes: ${B.map((A)=>k[A]).join(", ")}`))}for(let Y of D){let F=E.get(Y)?.outputDir??"path unavailable";V.push({label:k[Y],value:Y,hint:F})}let K=B.length>0&&B.every((Y)=>J.has(Y)),M=[...L.filter((Y)=>!B.includes(Y))];if(K)M.unshift(m);let R=process.stdin.isTTY,y=V.length===0?[]:await nQ({message:"Select agents to install skills for",choices:V,default:M,initial:!R?V.map((Y)=>Y.value):void 0,required:!1}),C=new Set(y.filter((Y)=>Y!==m));if(y.includes(m))for(let Y of B)C.add(Y);let j=[...C],I=j.filter((Y)=>!J.has(Y)),r=j.filter((Y)=>{let w=z.agents.find((F)=>F.agent===Y);return w?.installed===!0&&w.version!==W.version}),l=[...J].filter((Y)=>!j.includes(Y)),i=[...I,...r];if(i.length>0)try{let Y=await d({message:"Installing skills...",task:async()=>S({command:Q,meta:W,agents:i,scope:H})});console.log(`
7
+ ${QQ(`Installed "${W.name}" v${W.version}`)}`);for(let w of Y.agents)console.log(v(` ${k[w.agent]} \u2192 ${w.outputDir}`))}catch(Y){if(Y instanceof b)if(await aQ({message:`"${Y.details.outputDir}" already exists but was not created by Crust. Overwrite?`,default:!1,initial:!R?!1:void 0})){let F=await d({message:"Overwriting skill...",task:async()=>S({command:Q,meta:W,agents:[Y.details.agent],scope:H,force:!0})});console.log(`
8
+ ${QQ(`Installed "${W.name}" v${W.version}`)}`);for(let A of F.agents)console.log(v(` ${k[A.agent]} \u2192 ${A.outputDir}`))}else console.log(v(`
9
+ Skipped ${k[Y.details.agent]}`));else throw Y}if(l.length>0){let w=(await d({message:"Removing skills...",task:async()=>e({name:W.name,agents:l,scope:H})})).agents.filter((F)=>F.status==="removed").map((F)=>k[F.agent]);if(w.length>0)console.log(`
10
+ ${QQ(`Removed from ${w.join(", ")}`)}`)}if(i.length===0&&l.length===0)console.log(v("No changes."))},X}export{e as uninstallSkill,g as skillStatus,XX as skillPlugin,_ as resolveSkillName,VQ as isValidSkillName,yQ as isUniversalAgent,f as getUniversalAgents,h as getAdditionalAgents,S as generateSkill,p as detectInstalledAgents,b as SkillConflictError};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@crustjs/skills",
3
- "version": "0.0.10",
3
+ "version": "0.0.12",
4
4
  "description": "Agent skill generation from Crust command definitions",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -47,11 +47,11 @@
47
47
  },
48
48
  "devDependencies": {
49
49
  "@crustjs/config": "0.0.0",
50
- "@crustjs/core": "0.0.10",
50
+ "@crustjs/core": "0.0.11",
51
51
  "bunup": "^0.16.29"
52
52
  },
53
53
  "peerDependencies": {
54
- "@crustjs/core": "0.0.10",
54
+ "@crustjs/core": "0.0.11",
55
55
  "typescript": "^5"
56
56
  }
57
57
  }