@crustjs/skills 0.0.8 → 0.0.9
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 +10 -14
- package/dist/index.js +10 -10
- package/package.json +3 -3
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { CommandNode } from "@crustjs/core";
|
|
2
2
|
/**
|
|
3
3
|
* Metadata for the generated skill bundle.
|
|
4
4
|
*
|
|
@@ -97,7 +97,7 @@ type Scope = "global" | "project";
|
|
|
97
97
|
*/
|
|
98
98
|
interface GenerateOptions {
|
|
99
99
|
/** Root command to generate the skill from */
|
|
100
|
-
command:
|
|
100
|
+
command: CommandNode;
|
|
101
101
|
/** Skill metadata for the generated bundle */
|
|
102
102
|
meta: SkillMeta;
|
|
103
103
|
/** Agent targets to install skills for */
|
|
@@ -423,21 +423,17 @@ import { CrustPlugin } from "@crustjs/core";
|
|
|
423
423
|
*
|
|
424
424
|
* @example
|
|
425
425
|
* ```ts
|
|
426
|
-
* import {
|
|
426
|
+
* import { Crust } from "@crustjs/core";
|
|
427
427
|
* import { skillPlugin } from "@crustjs/skills";
|
|
428
428
|
*
|
|
429
|
-
* const app =
|
|
430
|
-
*
|
|
431
|
-
*
|
|
429
|
+
* const app = new Crust("my-cli").meta({ description: "My CLI" })
|
|
430
|
+
* .use(skillPlugin({
|
|
431
|
+
* version: "1.0.0",
|
|
432
|
+
* command: true, // registers "my-cli skill" subcommand
|
|
433
|
+
* }))
|
|
434
|
+
* .run(() => { /* ... */ });
|
|
432
435
|
*
|
|
433
|
-
*
|
|
434
|
-
* plugins: [
|
|
435
|
-
* skillPlugin({
|
|
436
|
-
* version: "1.0.0",
|
|
437
|
-
* command: true, // registers "my-cli skill" subcommand
|
|
438
|
-
* }),
|
|
439
|
-
* ],
|
|
440
|
-
* });
|
|
436
|
+
* await app.execute();
|
|
441
437
|
* ```
|
|
442
438
|
*/
|
|
443
439
|
declare function skillPlugin(options: SkillPluginOptions): CrustPlugin;
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
// @bun
|
|
2
|
-
import{access as JQ}from"fs/promises";import{homedir as
|
|
3
|
-
`)}function
|
|
4
|
-
`)}function
|
|
5
|
-
`)}function
|
|
6
|
-
`)}function
|
|
7
|
-
`}function
|
|
8
|
-
${
|
|
9
|
-
${
|
|
10
|
-
Skipped ${
|
|
11
|
-
${
|
|
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};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@crustjs/skills",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.9",
|
|
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.
|
|
50
|
+
"@crustjs/core": "0.0.10",
|
|
51
51
|
"bunup": "^0.16.29"
|
|
52
52
|
},
|
|
53
53
|
"peerDependencies": {
|
|
54
|
-
"@crustjs/core": "0.0.
|
|
54
|
+
"@crustjs/core": "0.0.10",
|
|
55
55
|
"typescript": "^5"
|
|
56
56
|
}
|
|
57
57
|
}
|