skillcraft 0.1.6 → 0.1.8
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.js +64 -60
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{Command as
|
|
3
|
-
`).filter(Boolean):[]}catch{return[]}}async function
|
|
2
|
+
import{Command as ki}from"commander";var nt={name:"skillcraft",version:"0.1.8",description:"Turn your work into verifiable AI credentials. Capture what you build, share your progress, and earn verifiable credentials that prove measurable real-world AI engineering work.",keywords:["skillcraft","cli","ai","evidence","credentials","skills","loadout","git","verification","developer-tools"],repository:{type:"git",url:"git+https://github.com/skillcraft-gg/skillcraft.git"},homepage:"https://skillcraft.gg",bugs:{url:"https://github.com/skillcraft-gg/skillcraft/issues"},type:"module",bin:{skillcraft:"dist/index.js"},files:["dist/index.js","dist/index.js.map","README.md","LICENSE"],scripts:{build:"tsup",clean:"rm -rf dist",test:"npm run build && node --test tests/*.test.mjs",smoke:"npm test",format:"printf ''",start:"node dist/index.js",check:"tsc --noEmit",prepublishOnly:"npm run build"},publishConfig:{access:"public"},dependencies:{commander:"^13.1.0",ora:"^8.2.0",yaml:"^2.6.0",zod:"^3.24.2"},devDependencies:{"@types/node":"^24.8.0",tsup:"^8.5.0",typescript:"^5.7.2"}};import{execFile as Ar}from"child_process";import{promisify as Lr}from"util";import it from"path";var ot=Lr(Ar);async function h(e,t,r={}){try{let{stdout:n}=await ot("git",e,{cwd:t,encoding:"utf8",maxBuffer:10485760,env:r.env});return n.trim()}catch(n){let i=n.message??String(n);throw new Error(`git command failed in ${t}: ${i}`)}}async function O(e){try{return await h(["rev-parse","--git-dir"],e),!0}catch{return!1}}async function ee(e){return it.resolve(await h(["rev-parse","--show-toplevel"],e))}async function z(e,t="origin"){try{return await h(["config","--get",`remote.${t}.url`],e)||void 0}catch{return}}async function st(e,t="HEAD"){return h(["log","--format=%B","-n","1",t],e)}async function te(e){return(await h(["rev-parse","HEAD"],e)).trim()}async function M(e,t){try{return await h(["show-ref","--verify","--quiet",t],e),!0}catch{return!1}}async function at(e,t,r="HEAD"){try{return await h(["merge-base","--is-ancestor",t,r],e),!0}catch{return!1}}async function ct(e,t,r){try{let n=await h(["ls-tree","-r","--name-only",t,"--",...r?[r]:[]],e);return n?n.split(`
|
|
3
|
+
`).filter(Boolean):[]}catch{return[]}}async function dt(e,t,r){try{return await h(["show",`${t}:${r}`],e)}catch{return}}async function fe(e,t){let r=t?String(t):"200",n=await h(["log",`--max-count=${r}`,"--pretty=%H%x00%B"],e);return n?n.split("\0").filter(Boolean).map(i=>{let[o,...s]=i.split(`
|
|
4
4
|
`),c=s.join(`
|
|
5
|
-
`).trimEnd();return{commit:
|
|
6
|
-
`,"utf8"),await
|
|
7
|
-
`)}async function N(e){try{await ue.rm(e,{force:!0})}catch{}}import
|
|
5
|
+
`).trimEnd();return{commit:o,message:c}}):[]}async function lt(e,t){let r={...process.env,SKILLCRAFT_HOOK_DISABLED:"1"},n=it.join(e,".git","SKILLCRAFT_COMMIT_MESSAGE"),{writeFile:i}=await import("fs/promises");return await i(n,`${t}
|
|
6
|
+
`,"utf8"),await ot("git",["commit","--amend","--file",n,"--no-gpg-sign"],{cwd:e,encoding:"utf8",env:r}),te(e)}import Si from"fs/promises";import k from"path";import jr from"os";function qr(){return k.resolve(process.env.HOME||jr.homedir(),".skillcraft")}function I(){return qr()}function Ae(){return k.join(I(),"config.json")}function Le(){return k.join(I(),"repos.json")}function je(){return k.join(I(),"credentials.json")}function ut(){return k.join(I(),"cache","credentials","index.json")}function Nr(e){return k.join(e,".skillcraft")}function A(e){return k.join(e,".git","skillcraft")}function D(e){return k.join(Nr(e),".skillcraft.json")}function re(e){return k.join(e,".git","hooks","post-commit")}function ge(e){return k.join(e,".git","hooks","pre-push")}function he(e){return k.join(e,".git","hooks","post-push")}function L(e){return k.join(A(e),"pending.json")}function R(e){return k.join(A(e),"context.json")}function we(e){return k.join(A(e),"agent.json")}function le(e){return k.join(e,".opencode","plugins","skillcraft.mjs")}function ne(e){return k.join(A(e),"ai-model-context.json")}import ue from"fs/promises";import Fr from"path";async function C(e){await ue.mkdir(e,{recursive:!0})}async function Tr(e){return await ue.readFile(e,"utf8")}async function W(e,t){await C(Fr.dirname(e)),await ue.writeFile(e,t,"utf8")}async function q(e){try{return await ue.access(e),!0}catch{return!1}}async function v(e){if(!await q(e))return null;let t=await Tr(e);return JSON.parse(t)}async function y(e,t){let r=JSON.stringify(t,null,2);await W(e,`${r}
|
|
7
|
+
`)}async function N(e){try{await ue.rm(e,{force:!0})}catch{}}import ie from"fs/promises";function qe(e){let t=process.argv[1]||"skillcraft";return`#!/usr/bin/env sh
|
|
8
8
|
if [ -n "$SKILLCRAFT_HOOK_DISABLED" ]; then
|
|
9
9
|
exit 0
|
|
10
10
|
fi
|
|
@@ -15,33 +15,33 @@ SKILLCRAFT_CLI=${JSON.stringify(t)}
|
|
|
15
15
|
unset GIT_INDEX_FILE
|
|
16
16
|
|
|
17
17
|
${e}
|
|
18
|
-
`}var
|
|
19
|
-
"$SKILLCRAFT_CLI" _hook post-push "$SKILLCRAFT_HOOK_DIR" "$SKILLCRAFT_HOOK_REMOTE" || true`),
|
|
20
|
-
"$SKILLCRAFT_CLI" _hook post-push "$SKILLCRAFT_HOOK_DIR" "$SKILLCRAFT_HOOK_REMOTE" || true`);async function
|
|
21
|
-
`),await
|
|
22
|
-
`),await
|
|
23
|
-
`),await
|
|
24
|
-
`)}import{createHash as
|
|
25
|
-
`),
|
|
18
|
+
`}var _r=qe('"$SKILLCRAFT_CLI" _hook post-commit "$SKILLCRAFT_HOOK_DIR" || true'),Or=qe(`SKILLCRAFT_HOOK_REMOTE="$1"
|
|
19
|
+
"$SKILLCRAFT_CLI" _hook post-push "$SKILLCRAFT_HOOK_DIR" "$SKILLCRAFT_HOOK_REMOTE" || true`),zr=qe(`SKILLCRAFT_HOOK_REMOTE="$1"
|
|
20
|
+
"$SKILLCRAFT_CLI" _hook post-push "$SKILLCRAFT_HOOK_DIR" "$SKILLCRAFT_HOOK_REMOTE" || true`);async function mt(e){await W(re(e),`${_r}
|
|
21
|
+
`),await ie.chmod(re(e),493),await W(he(e),`${Or}
|
|
22
|
+
`),await ie.chmod(he(e),493),await W(ge(e),`${zr}
|
|
23
|
+
`),await ie.chmod(ge(e),493)}async function pt(e){await Promise.all([ie.rm(re(e),{force:!0}),ie.rm(he(e),{force:!0}),ie.rm(ge(e),{force:!0})])}import{z as g}from"zod";var Oi=g.literal(1),J="skillcraft/proofs/v1",ft=g.object({skills:g.array(g.string()).default([])}),gt=g.object({activeLoadouts:g.array(g.string()).default([])}),zi=g.object({provider:g.string().optional()}),Mi=g.object({provider:g.string().optional(),name:g.string().optional()}),G=g.object({githubUser:g.string().optional(),provider:g.enum(["gh"]).default("gh"),version:g.number().int().default(1),proofRef:g.string().default(J)}),Mr=g.object({path:g.string(),remote:g.string().optional(),enabledAt:g.string().optional()}),ht=g.object({repos:g.array(Mr).default([])}),Dr=g.object({id:g.string(),trackedAt:g.string().optional()}),wt=g.object({credentials:g.array(Dr).default([])});async function j(){let e=await v(Ae()),t=G.safeParse(e??{});return t.success?t.data:G.parse({})}async function ye(e){let t=await v(D(e)),r=G.safeParse(t??{});return r.success?r.data:G.parse({})}async function yt(e){await C(I()),await y(Ae(),e)}async function F(){let e=await v(Le()),t=ht.safeParse(e??{});return t.success?t.data:{repos:[]}}async function ke(e){await C(I()),await y(Le(),e)}async function kt(e){let r=(await F()).repos.filter(n=>n.path!==e.path);r.push(e),await ke({repos:r})}async function vt(e){let r=(await F()).repos.filter(n=>n.path!==e);await ke({repos:r})}async function ve(){let e=await v(je()),t=wt.safeParse(e??{});return t.success?t.data:{credentials:[]}}async function xt(e){await C(I()),await y(je(),e)}async function Pt(e){let t=await ve();return t.credentials.some(r=>r.id===e)?!1:(t.credentials.push({id:e,trackedAt:new Date().toISOString()}),t.credentials.sort(Hr),await xt(t),!0)}async function bt(e){let t=await ve(),r=t.credentials.length,n=t.credentials.filter(i=>i.id!==e);return n.length===r?!1:(await xt({credentials:n}),!0)}function Hr(e,t){return e.id.localeCompare(t.id)}async function Rt(){let e=process.cwd();if(!await O(e))throw new Error("Current directory is not a git repository");let t=await ee(e);await Promise.all([N(D(t)),N(L(t)),N(R(t)),N(we(t)),N(le(t)),N(ne(t)),N(A(t))]),await pt(t),await vt(t),process.stdout.write(`disabled skillcraft for ${t}
|
|
24
|
+
`)}import{createHash as Gr}from"crypto";import Pe from"path";import Vr from"os";import $t from"fs/promises";var Kr=/^[a-zA-Z0-9][a-zA-Z0-9._-]*\/[a-zA-Z0-9][a-zA-Z0-9._-]*(?:@[^\s/]+)?$/,Ur=/^[a-zA-Z0-9][a-zA-Z0-9._-]*\/[a-zA-Z0-9][a-zA-Z0-9._-]*$/,Br=/^([a-zA-Z0-9][a-zA-Z0-9._-]*):([a-zA-Z0-9][a-zA-Z0-9._-]*)(?:\/([a-zA-Z0-9][a-zA-Z0-9._-]*))?$/;function Ct(e){let t=H(e);if(t.id)return`${t.id}${t.version?`@${t.version}`:""}`}function Ne(e){return Kr.test(e)}function Fe(e){return!!H(e).id}function H(e){let t=e.trim(),r=Jr(t),n=r.id||"";if(Wr(n)){let[a,u]=n.split("/");return{id:n,owner:a,slug:u,version:r.version}}let i=Br.exec(n);if(!i)return{id:"",slug:"",version:r.version};let o=i[1],s=i[2],c=i[3];return c===void 0?{id:`${o}:${s}`,source:o,slug:s,version:r.version}:{id:`${o}:${s}/${c}`,source:o,owner:s,slug:c,version:r.version}}function Wr(e){return Ur.test(e)}function T(e,t){let r=e.trim();if(!r)throw new Error(`Expected ${t} to be provided`);return r}function Jr(e){let t=e.split("@"),r=t[0]||"",n=t.length>1?t.slice(1).join("@"):void 0;return{id:r,version:n}}function xe(e){let[t,r]=e.split("/");if(!t||!r)throw new Error(`Expected <owner>/<slug>, received ${e}`);return{owner:t,slug:r.trim()}}var Te="proofs";function Et(e){return(e?.trim()||J).replace(/^refs\/heads\//,"")}function It(e){return`${Te}/${e}.json`}async function be(e){let t=await ye(e);return Et(t.proofRef)}async function At(e,t){let r=Et(t),n=`refs/heads/${r}`,i=`refs/remotes/origin/${r}`,o=[];return await M(e,n)&&o.push(r),await M(e,i)&&o.push(`origin/${r}`),o.length||o.push(r),o}async function Zr(e,t){let r=`refs/heads/${t}`;await M(e,r)||await h(["branch",t],e)}async function Xr(e,t,r){await Yr(e,t);let n=await $t.mkdtemp(Pe.join(Vr.tmpdir(),"skillcraft-proof-"));try{return await h(["worktree","add","--quiet",n,t],e),await r(n)}finally{await Lt(e,n)}}async function Lt(e,t){try{await h(["worktree","remove","--force",t],e)}catch{await $t.rm(t,{force:!0,recursive:!0})}}async function Yr(e,t){let r=`refs/heads/${t}`;try{let i=(await h(["worktree","list","--porcelain"],e)).split(`
|
|
25
|
+
`),o,s,c=async()=>{!o||s!==r||await Lt(e,o)};for(let a of i){if(!a){o=void 0,s=void 0;continue}if(a.startsWith("worktree ")){await c(),o=a.slice(9),s=void 0;continue}a.startsWith("branch ")&&(s=a.slice(7))}await c()}catch{return}}async function _e(e){let t=await be(e),r=await At(e,t),n=new Set;for(let o of r){let s=await ct(e,o,Te);for(let c of s)n.add(c)}let i=[];for(let o of n){if(!o.endsWith(".json"))continue;let s=Pe.basename(o,".json"),c=await Oe(e,s);c&&i.push(c)}return i}function Qr(e){let t=H(e);if(t.id&&Fe(t.id))return{id:t.id,version:t.version}}function Re(e){let t=e.filter(Boolean).map(r=>H(r)).filter(r=>!!r.id).map(r=>`${r.id}${r.version?`@${r.version}`:""}`);return Array.from(new Set(t)).filter(Fe).sort()}function jt(e,t,r){let n={skills:e,loadouts:r,timestamp:t};return Gr("sha256").update(JSON.stringify(n)).digest("hex").slice(0,8)}async function oe(e){let t=await v(L(e)),r=ft.safeParse(t??{skills:[]});return r.success?Re(r.data.skills):[]}async function en(e){let t=await v(R(e)),r=gt.safeParse(t??{activeLoadouts:[]});return r.success?r.data.activeLoadouts:[]}async function tn(e){let t=await v(ne(e));if(!t||typeof t!="object"||Array.isArray(t))return{};let r=t,n=r.agent&&typeof r.agent=="object"&&!Array.isArray(r.agent)?r.agent:void 0,i=r.model&&typeof r.model=="object"&&!Array.isArray(r.model)?r.model:void 0;return{agent:typeof n?.provider=="string"?{provider:St(n.provider)}:void 0,model:typeof i?.provider=="string"||typeof i?.name=="string"?{provider:typeof i.provider=="string"?St(i.provider):void 0,name:typeof i.name=="string"?rn(i.name):void 0}:void 0}}function St(e){return e.trim().toLowerCase()}function rn(e){return e.trim()}function nn(e){if(!e||typeof e!="object")return;let t=e;if(typeof t.version!="number"||typeof t.commit!="string"||!Array.isArray(t.skills)||!t.timestamp||typeof t.timestamp!="string")return;let r=Array.isArray(t.loadouts)?t.loadouts.map(String):[],n=t.skills.map(i=>{if(typeof i=="string")return{id:i};if(i&&typeof i=="object"&&"id"in i&&typeof i.id=="string")return{id:i.id,version:typeof i.version=="string"?i.version:void 0}}).filter(i=>!!i);return{version:t.version,commit:t.commit,skills:n,loadouts:r,timestamp:t.timestamp,agent:on(t.agent),model:sn(t.model)}}function on(e){if(!e||typeof e!="object"||Array.isArray(e))return;let t=e.provider;if(typeof t!="string")return;let r=t.trim().toLowerCase();return r?{provider:r}:void 0}function sn(e){if(!e||typeof e!="object"||Array.isArray(e))return;let t=e,r=typeof t.provider=="string"?t.provider.trim().toLowerCase():void 0,n=typeof t.name=="string"?t.name.trim():void 0;if(!(!r&&!n))return{provider:r,name:n}}async function Oe(e,t){let r=await be(e),n=It(t),i=await At(e,r);for(let o of i){let s=await dt(e,o,n);if(!s)continue;let c;try{c=JSON.parse(s)}catch{continue}let a=nn(c);if(a)return a}}async function ze(e,t){let r=jt(t.skills.map(o=>o.id),t.timestamp,t.loadouts),n=await be(e);await Zr(e,n);let i=It(r);return await Xr(e,n,async o=>{await C(Pe.join(o,Te)),await y(Pe.join(o,i),t),await h(["add",i],o,{env:{...process.env,SKILLCRAFT_HOOK_DISABLED:"1"}}),await h(["status","--porcelain","--",i],o,{env:{...process.env,SKILLCRAFT_HOOK_DISABLED:"1"}})&&await h(["commit","--no-gpg-sign","-m",`add Skillcraft proof ${r}`],o,{env:{...process.env,SKILLCRAFT_HOOK_DISABLED:"1"}})}),r}async function qt(e,t="origin"){let r=await be(e);if(!(!await z(e,t)||!t))try{await h(["push",t,`${r}:${r}`],e,{env:{...process.env,SKILLCRAFT_HOOK_DISABLED:"1"}})}catch{return}}async function Nt(e,t){let r=await _e(e);for(let n of r)if(n.commit===t)return jt(n.skills.map(i=>i.id),n.timestamp,n.loadouts)}async function Ft(e,t,r=new Date().toISOString()){let n=await oe(e),i=await en(e),o=await tn(e),s=n.map(u=>Qr(u)).filter(u=>!!u),c={version:1,commit:t,skills:s,loadouts:i,timestamp:r,...o};return{proofId:await ze(e,c),proof:c}}async function an(e){return e.replace(/\nSkillcraft-Ref: .*$/gm,"").trimEnd()}async function Tt(e,t){let r=await st(e),n=await an(r);return n.includes("Skillcraft-Ref:")?n:`${n}
|
|
26
26
|
|
|
27
27
|
Skillcraft-Ref: ${t}
|
|
28
|
-
`}async function P(e){let t=D(e);if(!await q(t))return!1;let r=await v(t);return G.safeParse(r??{}).success}async function
|
|
28
|
+
`}async function P(e){let t=D(e);if(!await q(t))return!1;let r=await v(t);return G.safeParse(r??{}).success}async function _t(e){return q(A(e))}import U from"fs/promises";import Me from"path";import{execFile as cn,execSync as dn}from"child_process";import{promisify as ln}from"util";var un=ln(cn);function mn(){try{return dn("which gh",{stdio:"ignore"}),!0}catch{return!1}}async function K(e){if(!mn())throw new Error("gh CLI is required for this workflow");return(await un("gh",e,{encoding:"utf8"})).stdout.trim()}async function Ot(e,t){await U.mkdir(t,{recursive:!0});let r=await U.readdir(e,{withFileTypes:!0});for(let n of r){if(n.name===".git")continue;let i=Me.join(e,n.name),o=Me.join(t,n.name);if(n.isDirectory()){await Ot(i,o);continue}if(n.isSymbolicLink()){let s=await U.readlink(i);await U.symlink(s,o);continue}n.isFile()&&await U.copyFile(i,o)}}var Ce=class{providerName(){return"gh"}async getUser(){return await K(["api","user","--jq",".login"])}async getIssueUrl(t,r){return`https://github.com/${t}/issues/${r}`}async createIssue(t,r,n){let o=(await K(["issue","create","-R",t,"--title",r,"--body",n])).match(/\b(\d+)$/);return o?Number(o[1]):0}async createPullRequest(t,r,n){let o=(await K(["pr","create","--repo",t,"--head",r,"--base","main","--title",n,"--body",`Generated by skillcraft for ${n}`,"--fill-first"])).match(/\b(\d+)$/);return o?Number(o[1]):0}async openPullRequestForBranch(t,r,n,i,o){let c=(await K(["pr","create","--repo",t,"--head",`${r}:${n}`,"--base","main","--title",i,"--body",o])).match(/\b(\d+)$/);return c?Number(c[1]):0}async getIssueStatus(t,r){let n=await K(["issue","view",String(r),"--repo",t,"--json","state,labels,url"]),i=JSON.parse(n);return{state:i.state,labels:i.labels?.map(o=>o.name)??[],url:i.url}}async listClaimProcessingRuns(t,r){let n=await K(["run","list","--repo",t,"--workflow","Process credential claims","--json","name,status,conclusion,url,createdAt,workflowName"]),i=JSON.parse(n),o=`#${r}`,s=i.filter(a=>{let u=a.name||"",l=a.workflowName||"";return u.includes(o)||l.includes(o)}),c=s.length>0?s:i.filter(a=>a.status&&["in_progress","queued","waiting","action_required","canceling"].includes(a.status));return c.length?c.filter(a=>a.url).map(a=>({status:a.status||"unknown",conclusion:a.conclusion??void 0,url:a.url,name:a.name,createdAt:a.createdAt,workflowName:a.workflowName})):[]}async listClaimIssues(t){let r=await K(["issue","list","--repo",t,"--state","all","--json","number,title,state,body,labels,url","--limit","100"]);return JSON.parse(r).filter(i=>pn(i.title)||fn(i.labels,"skillcraft-claim"))}async cloneRepo(t,r){let n=Me.resolve(r);await K(["repo","clone",t,n])}async copyDirectory(t,r){await U.readdir(r).catch(()=>{})&&await U.rm(r,{recursive:!0,force:!0}),await U.mkdir(r,{recursive:!0}),await Ot(t,r)}};function De(e){return String(e||"").trim().toLowerCase()}function pn(e){return De(e).startsWith("claim:")}function fn(e,t){let r=De(t);return(e||[]).some(n=>De(n?.name)===r)}var gn={gh:()=>new Ce};function $(e){return gn[e]()}async function zt(){let e=process.cwd(),t=await O(e);process.stdout.write(`git: ${t?"enabled":"not a repository"}
|
|
29
29
|
`);let r=await P(e);if(process.stdout.write(`skillcraft: ${r?"enabled":"disabled"}
|
|
30
|
-
`),!t||!r)return;let n=await
|
|
31
|
-
`);let
|
|
32
|
-
`),process.stdout.write(`post-commit hook: ${
|
|
33
|
-
`);let s=await te(e),c=await
|
|
30
|
+
`),!t||!r)return;let n=await oe(e);process.stdout.write(`pending skills: ${n.length}
|
|
31
|
+
`);let i=await q(R(e)),o=await q(re(e));process.stdout.write(`context file: ${i?"present":"missing"}
|
|
32
|
+
`),process.stdout.write(`post-commit hook: ${o?"installed":"missing"}
|
|
33
|
+
`);let s=await te(e),c=await Nt(e,s);process.stdout.write(`head: ${s}
|
|
34
34
|
`),process.stdout.write(`latest proof: ${c??"none"}
|
|
35
|
-
`);let u=(await fe(e,20)).filter(
|
|
36
|
-
`);let d=(await ye(e)).proofRef?.replace(/^refs\/heads\//,"")||"skillcraft/proofs/v1",m=await
|
|
35
|
+
`);let u=(await fe(e,20)).filter(p=>p.message.includes("Skillcraft-Ref:"));process.stdout.write(`recent commits with evidence: ${u.length}
|
|
36
|
+
`);let d=(await ye(e)).proofRef?.replace(/^refs\/heads\//,"")||"skillcraft/proofs/v1",m=await M(e,`refs/heads/${d}`);process.stdout.write(`proof branch: ${m?"present":"missing"}
|
|
37
37
|
`),n.length>0&&process.stdout.write(`pending evidence queued: ${n.join(", ")}
|
|
38
|
-
`)}async function
|
|
38
|
+
`)}async function Mt(){let e=await Promise.all([me("node"),me("npm"),me("git"),me("gh"),me("opencode")]);for(let[n,i]of e)process.stdout.write(`${n}: ${i?"ok":"missing"}
|
|
39
39
|
`);if(!(e.find(([n])=>n==="gh")?.[1]??!1)){process.stdout.write(`gh auth: missing
|
|
40
40
|
`),process.stdout.write(`github user: unknown
|
|
41
|
-
`);return}let r=await
|
|
41
|
+
`);return}let r=await $("gh").getUser().catch(()=>"");process.stdout.write(`gh auth: ${r?"ok":"missing"}
|
|
42
42
|
`),process.stdout.write(`github user: ${r||"unknown"}
|
|
43
|
-
`)}async function me(e){return[e,await
|
|
44
|
-
`)}function
|
|
43
|
+
`)}async function me(e){return[e,await hn(e)]}async function hn(e){try{let{execSync:t}=await import("child_process");return t(`command -v ${e}`,{stdio:"ignore"}),!0}catch{return!1}}import wn from"path";async function Dt(){let e=process.cwd();if(!await O(e))throw new Error("Current directory is not a git repository");let t=await ee(e),r=await j();if(!r.githubUser){let s=await $(r.provider??"gh").getUser().catch(()=>process.env.GITHUB_USER||process.env.USER||"developer");await yt({...r,githubUser:s})}await C(A(t)),await C(wn.dirname(le(t))),await W(le(t),yn()),await y(ne(t),{agent:{provider:"opencode"},model:{}});let n=`refs/heads/${J}`;await M(t,n)||await h(["branch",J],t),await y(D(t),{version:1,proofRef:J}),await C(I()),await y(L(t),{skills:[]}),await y(R(t),{activeLoadouts:[]}),await y(we(t),{version:1,providers:["opencode"],enabled:!0}),await mt(t);let i=await z(t);await kt({path:t,remote:i,enabledAt:new Date().toISOString()}),process.stdout.write(`enabled skillcraft for ${t}
|
|
44
|
+
`)}function yn(){return`import fs from 'node:fs/promises'
|
|
45
45
|
import path from 'node:path'
|
|
46
46
|
|
|
47
47
|
function normalizeProvider(value) {
|
|
@@ -197,66 +197,70 @@ export default async function Skillcraft() {
|
|
|
197
197
|
},
|
|
198
198
|
}
|
|
199
199
|
}
|
|
200
|
-
`}async function
|
|
200
|
+
`}async function Ht(){let e=await F();if(!e.repos.length){process.stdout.write(`no repositories tracked
|
|
201
201
|
`);return}e.repos.forEach((t,r)=>{process.stdout.write(`${r+1}. ${t.path}`),t.remote&&process.stdout.write(` (${t.remote})`),process.stdout.write(`
|
|
202
|
-
`)})}async function
|
|
203
|
-
`)}async function se(e){return _e(e)}import
|
|
202
|
+
`)})}async function Kt(){let e=await F(),t=[];for(let r of e.repos)await O(r.path)&&(await ee(r.path),t.push(r));await ke({repos:t}),process.stdout.write(`pruned repo list: ${e.repos.length} -> ${t.length}
|
|
203
|
+
`)}async function se(e){return _e(e)}import kn from"path";var vn="https://skillcraft.gg/credential-ledger/credentials/index.json",xn=360*60*1e3,Ke=1,ae=ut();function Pn(){return process.env.SKILLCRAFT_CREDENTIAL_INDEX_URL?.trim()||vn}async function Ut(e){try{let t=await v(e);if(!t||!V(t))return null;let r=bn(t.cachedAt);if(r===void 0||r<=0||t.version!==Ke||!("entries"in t))return null;let n=Se(t.entries);return{cachedAt:r,version:Ke,entries:n}}catch{return null}}function bn(e){if(typeof e=="number"&&Number.isFinite(e))return e;if(typeof e=="string"&&e.trim()){let t=Number.parseInt(e,10);if(Number.isFinite(t))return t}}function Rn(e){return Date.now()-e.cachedAt<xn}async function Cn(e={}){let t=process.env.SKILLCRAFT_CREDENTIAL_INDEX_PATH?.trim();if(t)return Bt(t);let r=e.refresh?null:await Ut(ae);if(r&&Rn(r))return r.entries;try{let n=await Sn(Pn());return await $n(n),n}catch(n){if(await q(ae)){let i=await Ut(ae);return i?i.entries:Bt(ae)}throw n instanceof Error?n:new Error("failed to load credential index")}}async function Sn(e){let t=await fetch(e,{headers:{"user-agent":"skillcraft-cli"}});if(!t.ok)throw new Error(`failed to download credential index from ${e}`);let r=await t.json();return Se(r)}async function Bt(e){let t=await v(e);return t?V(t)&&Array.isArray(t.entries)?Se(t.entries):Se(t):[]}async function $n(e){await C(kn.dirname(ae));let t={cachedAt:Date.now(),version:Ke,entries:e};await y(ae,t)}function En(e){let t=V(e)?e:{};if(t.mode!==void 0)throw new Error("requirements.mode is not supported. Use nested and/or expressions instead.");let r=In(t);return{minCommits:Gt(t.min_commits??t.minCommits,0),minRepositories:Gt(t.min_repositories??t.minRepositories,0),tree:r}}function In(e){if(Object.prototype.hasOwnProperty.call(e,"tree"))return Be(e.tree,"requirements.tree");let t=Object.prototype.hasOwnProperty.call(e,"and"),r=Object.prototype.hasOwnProperty.call(e,"or");if(t&&r)throw new Error("requirements cannot include both and and or at the same level");if(t){let n=Object.keys(e).filter(i=>!["and","min_commits","min_repositories","minRepositories","minCommits","tree"].includes(i));if(n.length)throw new Error(`Unexpected requirement fields: ${n.join(", ")}`);return{and:Wt(e.and,"requirements.and")}}if(r){let n=Object.keys(e).filter(i=>!["or","min_commits","min_repositories","minRepositories","minCommits","tree"].includes(i));if(n.length)throw new Error(`Unexpected requirement fields: ${n.join(", ")}`);return{or:Wt(e.or,"requirements.or")}}return{and:An(e)}}function Wt(e,t){if(!Array.isArray(e))throw new Error(`Expected array at ${t}`);return e.map((r,n)=>Be(r,`${t}[${n}]`))}function Jt(e,t){if(e===void 0)return[];if(Array.isArray(e))return e.map(n=>{let i=E(n);if(i===void 0)throw new Error(`Expected text values for ${t}`);return i});let r=E(e);return r?[r]:[]}function An(e){let t=[],r=["and","or","min_commits","min_repositories","minRepositories","minCommits","tree","skill","loadout","agent","model"];for(let a of Jt(e.skill,"requirements.skill"))t.push({skill:a});for(let a of Jt(e.loadout,"requirements.loadout"))t.push({loadout:a});let n=Object.prototype.hasOwnProperty.call(e,"agent"),i=Vt(e.agent);if(i)t.push(i);else if(n)throw new Error("requirements.agent must be an object with a provider");let o=Object.prototype.hasOwnProperty.call(e,"model"),s=Zt(e.model);if(s)t.push(s);else if(o)throw new Error("requirements.model must be an object with optional provider and/or name");let c=Object.keys(e).filter(a=>!r.includes(a)&&!a.startsWith("$"));if(c.length)throw new Error(`Unexpected requirement fields: ${c.join(", ")}`);return t}function Be(e,t){if(!V(e))throw new Error(`Invalid requirement node at ${t}`);let r=Object.keys(e);if(!r.length)throw new Error(`Empty requirement node at ${t}`);if(r.length>1)throw new Error(`Requirement node has multiple keys at ${t}`);let[n]=r;if(n==="and"||n==="or"){let i=e[n];if(!Array.isArray(i))throw new Error(`Requirement node ${t} expected array for ${n}`);return{[n]:i.map((o,s)=>Be(o,`${t}.${n}[${s}]`))}}if(n==="skill"){let i=E(e[n]);if(!i)throw new Error(`Requirement node ${t} has empty skill`);return{skill:i}}if(n==="loadout"){let i=E(e[n]);if(!i)throw new Error(`Requirement node ${t} has empty loadout`);return{loadout:i}}if(n==="agent"){let i=Vt(e[n]);if(!i)throw new Error(`Requirement node ${t} has invalid agent requirement`);return i}if(n==="model"){let i=Zt(e[n]);if(!i)throw new Error(`Requirement node ${t} has invalid model requirement`);return i}throw new Error(`Unexpected requirement key ${n} at ${t}`)}function Vt(e){if(!V(e))return;let t=E(e.provider);if(t)return{agent:{provider:t.toLowerCase()}}}function Zt(e){if(!V(e))return;let t=E(e.provider),r=E(e.name);if(!(!t&&!r))return{model:{...t?{provider:t.toLowerCase()}:{},...r?{name:r}:{}}}}function Xt(e,t,r,n){let i=[],o=[],s=[],c=[],a=Array.from(new Set((t||[]).filter(Boolean))),u=Array.from(new Set((r||[]).filter(Boolean)));for(let p of e){let f=p.proof;for(let B of f.skills){let Q=We(B.id);Q.id&&i.push({id:Q.id,version:Q.version})}for(let B of f.loadouts){let Q=E(B);Q&&o.push(Q)}f.agent?.provider&&typeof f.agent.provider=="string"&&s.push(f.agent.provider);let x=f.model?.provider,Y=f.model?.name;(typeof x=="string"||typeof Y=="string")&&c.push({provider:x,name:Y})}let l=Ue(n.tree,{skills:i,loadouts:o,agents:s,models:c}),d=l.checks,m=[...Ln(d)];return n.minCommits>a.length&&(m.push(`minimum required commits not met: have ${a.length}, need ${n.minCommits}`),l.passed=!1),n.minRepositories>u.length&&(m.push(`minimum required repositories not met: have ${u.length}, need ${n.minRepositories}`),l.passed=!1),{passed:l.passed,proofs:e,provenCommits:a,provenRepos:u,checks:d,reasons:m,noExplicitChecks:l.noExplicitChecks}}function Ue(e,t){if("and"in e){let r=[],n=[],i=!0;for(let o of e.and){let s=Ue(o,t);r.push(...s.checks),n.push(s),s.noExplicitChecks||(i=!1)}return{passed:n.every(o=>o.passed),checks:r,noExplicitChecks:i}}if("or"in e){let r=[],n=[],i=!0;for(let o of e.or){let s=Ue(o,t);r.push(...s.checks),n.push(s),s.noExplicitChecks||(i=!1)}return{passed:n.some(o=>o.passed),checks:r,noExplicitChecks:i}}if("skill"in e){let r=We(e.skill),n=jn(t.skills,r);return{passed:n,checks:[{type:"skill",requirement:e.skill,satisfied:n}],noExplicitChecks:!1}}if("loadout"in e){let r=Nn(e.loadout),n=t.loadouts.includes(e.loadout)||r&&r.id!==""&&t.loadouts.includes(r.id);return{passed:n,checks:[{type:"loadout",requirement:e.loadout,satisfied:n}],noExplicitChecks:!1}}if("agent"in e){let r=He(e.agent.provider),n=t.agents.some(i=>i===r);return{passed:n,checks:[{type:"agent",requirement:`provider=${r}`,satisfied:n}],noExplicitChecks:!1}}if("model"in e){let r=He(e.model.provider),n=He(e.model.name),i=t.models.some(s=>{let c=!r||s.provider===r,a=!n||s.name&&s.name===n;return c&&a}),o=[];return r&&o.push(`provider=${r}`),n&&o.push(`name=${n}`),{passed:i,checks:[{type:"model",requirement:o.join(",")||"model",satisfied:i}],noExplicitChecks:!1}}throw new Error("Unknown requirement node encountered during evaluation")}function Ln(e){return e.filter(t=>!t.satisfied).map(t=>`${t.type} ${t.requirement} not met`)}function jn(e,t){return e.some(r=>qn(r.id,r.version,t))}function qn(e,t,r){return e!==r.id?!1:r.version?t===r.version:!0}function Nn(e){return We(e)}function We(e){let t=E(e);if(!t)return{id:""};let r=t.split("@");return{id:r[0],version:r.length>1?r.slice(1).join("@"):void 0}}function He(e){return typeof e=="string"?e.trim().toLowerCase():""}function E(e){return typeof e!="string"?void 0:e.trim()||void 0}function Gt(e,t){return typeof e!="number"||!Number.isFinite(e)||e<0?t:Math.floor(e)}function V(e){return!!e&&typeof e=="object"&&!Array.isArray(e)}function Se(e){if(!Array.isArray(e))return[];let t=[];for(let r of e){let n=Fn(r);n&&t.push(n)}return t.sort((r,n)=>r.id.localeCompare(n.id))}function Fn(e){if(!V(e))return;let t=E(e.id);if(t)try{return{id:t,name:E(e.name),description:E(e.description),requirements:En(e.requirements)}}catch{return}}async function Je(e={}){return Cn(e)}function Yt(e){process.stdout.write(`${e.join(`
|
|
204
204
|
`)}
|
|
205
|
-
`)}async function
|
|
206
|
-
`);return}let
|
|
205
|
+
`)}async function Tn(){let e=await F(),t=new Set,r=[];for(let n of e.repos)t.has(n.path)||(t.add(n.path),await P(n.path)&&r.push(n.path));return r}async function tr(e={}){let t=await Tn(),n=(await ve()).credentials;if(!n.length){if(e.outputMode==="json"){er(Qt({tracked:t,trackedCredentialsCount:0,proofFiles:0,provenCommits:0,provenRepositories:0,evaluated:[]}));return}process.stdout.write(`no credentials tracked
|
|
206
|
+
`);return}let i=ir(await Je({refresh:e.refreshIndex})),o=0,s=[],c=new Set,a=new Set;for(let f of t){let x=await se(f);if(o+=x.length,!x.length)continue;let Y=await z(f)||f;c.add(Y);for(let B of x)B?.commit&&a.add(B.commit),s.push({proof:B})}let u=Array.from(a),l=Array.from(c),d=Qt({tracked:t,trackedCredentialsCount:n.length,proofFiles:o,provenCommits:u.length,provenRepositories:l.length,evaluated:[]}),m=[];for(let f of n){let x=i.get(f.id);if(!x){m.push(_n(f.id,s.length,u.length,l.length));continue}let Y=Xt(s,u,l,x.requirements);m.push(On(f.id,x,Y,s.length,u.length,l.length))}if(d.credentials=m,e.outputMode==="json"){er(d);return}let p=[];p.push(`tracked credentials: ${n.length}`),p.push(`tracked repositories: ${t.length}`),p.push(`proof files: ${o}`),p.push(`proof commits: ${u.length}`),p.push(`proof repositories: ${l.length}`),p.push("");for(let f of m){if(p.push(`${f.credentialId}: ${f.status}`),p.push(` checks: ${f.passed?"passed":"blocked"}`),p.push(` proof scope: ${f.proofFiles} proofs, ${f.provenCommits}/${f.requiredMinCommits} commits, ${f.provenRepositories}/${f.requiredMinRepositories} repositories`),f.reasons.length){p.push(" reasons:");for(let x of f.reasons)p.push(` - ${x}`)}p.push("")}Yt(p)}async function rr(e){let t=T(e,"credential id");if(!ir(await Je()).has(t))throw new Error(`credential not found in credential index: ${t}`);if(!await Pt(t)){process.stdout.write(`credential already tracked: ${t}
|
|
207
207
|
`);return}process.stdout.write(`tracking credential: ${t}
|
|
208
|
-
`)}async function
|
|
208
|
+
`)}async function nr(e){let t=T(e,"credential id");if(!await bt(t)){process.stdout.write(`credential not tracked: ${t}
|
|
209
209
|
`);return}process.stdout.write(`untracked credential: ${t}
|
|
210
|
-
`)}function
|
|
211
|
-
`)}function
|
|
210
|
+
`)}function Qt(e){return{trackedCredentials:e.trackedCredentialsCount,trackedRepositories:e.tracked.length,evidence:{proofFiles:e.proofFiles,provenCommits:e.provenCommits,provenRepositories:e.provenRepositories},credentials:e.evaluated}}function er(e){process.stdout.write(`${JSON.stringify(e)}
|
|
211
|
+
`)}function ir(e){return new Map(e.map(t=>[t.id,t]))}function _n(e,t,r,n){return{credentialId:e,passed:!1,status:"blocked",reasons:["credential definition is not available"],checks:[],requiredMinCommits:0,requiredMinRepositories:0,provenCommits:r,provenRepositories:n,proofFiles:t}}function On(e,t,r,n,i,o){return{credentialId:e,name:t.name,description:t.description,passed:r.passed,status:r.passed?"eligible":"blocked",reasons:r.reasons,checks:r.checks,requiredMinCommits:t.requirements.minCommits,requiredMinRepositories:t.requirements.minRepositories,provenCommits:i,provenRepositories:o,proofFiles:n}}import Z from"path";import _ from"fs/promises";import{execFile as zn}from"child_process";import{promisify as Mn}from"util";import Dn from"ora";var Hn=Mn(zn);async function lr(e){let t=T(e,"skill id"),{owner:r,slug:n}=xe(t),i=process.cwd();if(!await P(i))throw new Error("Repository is not enabled");let o=await Promise.all([_.access(Z.join(i,"SKILL.md")).then(()=>!0).catch(()=>!1),_.access(Z.join(i,"skill.yaml")).then(()=>!0).catch(()=>!1)]);if(!o[0]||!o[1])throw new Error("SKILL.md and skill.yaml are required for publishing");let s=await j(),c=$(s.provider??"gh");await c.getUser();let a="skillcraft-gg/skills-registry",u=`skillcraft-skill-${r}-${n}`,l=Z.join(process.cwd(),".skillcraft-temp-skill-publish");try{await _.rm(l,{force:!0,recursive:!0}),await c.cloneRepo(a,l),await $e(l,["checkout","-B",u]);let d=Z.join(l,"skills",r,n);await _.rm(d,{force:!0,recursive:!0}),await _.mkdir(Z.dirname(d),{recursive:!0}),await _.cp(i,d,{recursive:!0}),await $e(l,["add",`skills/${r}/${n}`]),await $e(l,["commit","-m",`Publish skill ${t}`]).catch(()=>{throw new Error("nothing to commit; skill may already be published")}),await $e(l,["push","-u","origin",u]).catch(()=>{throw new Error("unable to push skill publish branch")}),await c.createPullRequest(a,u,`Publish skill: ${t}`).catch(()=>{process.stdout.write(`unable to create PR automatically. Please open one manually from your branch.
|
|
212
212
|
`)}),process.stdout.write(`published skill ${t} from ${a}
|
|
213
|
-
`)}finally{await
|
|
214
|
-
`)}async function
|
|
215
|
-
`)}async function
|
|
216
|
-
`);return}let
|
|
213
|
+
`)}finally{await _.rm(l,{force:!0,recursive:!0})}}async function ur(e){let t=process.cwd();if(!await P(t))throw new Error("Repository is not enabled");let r=T(e,"skill id"),n=H(r);if(!n.id)throw new Error("invalid skill id format");if(!(await Zn()).has(n.id))throw new Error(`skill ${n.id} is not listed in the search index`);let o=Re([`${n.id}${n.version?`@${n.version}`:""}`]),s=await oe(t),c=Re([...s,...o]);await y(L(t),{skills:c}),process.stdout.write(`queued skill: ${o[0]}
|
|
214
|
+
`)}async function Kn(){let e=process.cwd(),t=[["SKILL.md",await dr(Z.join(e,"SKILL.md"))],["skill.yaml",await dr(Z.join(e,"skill.yaml"))]];for(let[r,n]of t)process.stdout.write(`${r}: ${n?"ok":"missing"}
|
|
215
|
+
`)}async function mr(){let e=process.cwd();if(!await P(e))throw new Error("Repository is not enabled");let[t,r]=await Promise.all([se(e),oe(e)]),n=new Set;for(let o of t)for(let s of o.skills)n.add(s.id);for(let o of r)n.add(o);if(!n.size){process.stdout.write(`no skills detected
|
|
216
|
+
`);return}let i=Array.from(n).sort().join(`
|
|
217
217
|
`);process.stdout.write(`skills detected (${n.size}):
|
|
218
|
-
${
|
|
219
|
-
`)}async function
|
|
218
|
+
${i}
|
|
219
|
+
`)}async function pr(e,t={}){let r=await Ge(t.outputMode);if(!r.length){t.outputMode==="json"?process.stdout.write(`${JSON.stringify({query:e?.trim(),source:t.source?.trim(),limit:cr(t.limit),count:0,results:[],message:"no skills indexed"})}
|
|
220
220
|
`):process.stdout.write(`no skills indexed
|
|
221
|
-
`);return}let n=e?.trim().toLowerCase(),
|
|
221
|
+
`);return}let n=e?.trim().toLowerCase(),i=t.source?.trim().toLowerCase(),o=cr(t.limit),c=[...r.filter(d=>i&&Ve(d.id)!==i?!1:n?[d.id,d.name,d.owner,d.slug,d.path,d.url,...d.runtime||[],...d.tags||[]].filter(p=>!!p).map(p=>p.toLowerCase()).some(p=>p.includes(n)):!0)].sort((d,m)=>{let p=(d.name||d.id).toLowerCase(),f=(m.name||m.id).toLowerCase();return p===f?d.id.localeCompare(m.id):p.localeCompare(f)}),a=c.slice(0,o);if(!a.length){let d=n?`no skills match "${e?.trim()}"`:"no skills match current filters";t.outputMode==="json"?process.stdout.write(`${JSON.stringify({query:e?.trim(),source:t.source?.trim(),limit:o,count:0,results:[],message:d})}
|
|
222
222
|
`):process.stdout.write(`${d}
|
|
223
|
-
`);return}let u=n?`skills matching "${e?.trim()}"`:"skills index",l=a.map(d=>{let m=(d.runtime||[]).length?` [${d.runtime.join(", ")}]`:"",
|
|
223
|
+
`);return}let u=n?`skills matching "${e?.trim()}"`:"skills index",l=a.map(d=>{let m=(d.runtime||[]).length?` [${d.runtime.join(", ")}]`:"",p=(d.tags||[]).length?` {${d.tags.join(", ")}}`:"",f=ti(d.updatedAt),x=Qn(d);return`${d.id}${x?` \u2014 ${x}`:""}${m}${p}${f}`});if(t.outputMode==="json"){let d={query:e?.trim(),source:t.source?.trim(),limit:o,count:a.length,total:c.length,results:a.map(m=>({id:m.id,name:m.name,path:m.path,url:m.url,owner:m.owner,slug:m.slug,runtime:m.runtime,tags:m.tags}))};process.stdout.write(`${JSON.stringify(d)}
|
|
224
224
|
`);return}process.stdout.write(`${u} (${a.length}):
|
|
225
225
|
${l.join(`
|
|
226
226
|
`)}
|
|
227
|
-
`)}async function
|
|
228
|
-
`);return}let c=
|
|
229
|
-
`)}function
|
|
230
|
-
`)}async function
|
|
227
|
+
`)}async function fr(e,t={}){let r=T(e,"skill id"),n=H(r);if(!n.id)throw new Error("invalid skill id format");let o=(await Ge(t.outputMode)).find(a=>a.id===n.id);if(!o)throw new Error(`skill ${n.id} is not listed in the search index`);let s=await Bn(o);if(t.outputMode==="json"){let a={id:o.id,name:o.name,source:Ve(o.id),owner:o.owner,slug:o.slug,path:o.path,url:o.url,runtime:o.runtime,tags:o.tags,updatedAt:o.updatedAt,manifest:s,version:n.version};process.stdout.write(`${JSON.stringify(a)}
|
|
228
|
+
`);return}let c=Un(o,s);process.stdout.write(`${c}
|
|
229
|
+
`)}function Un(e,t){let r=[];r.push(`skill: ${e.id}`),e.name&&r.push(`name: ${e.name}`);let n=Ve(e.id);return n&&r.push(`source: ${n}`),e.owner&&r.push(`owner: ${e.owner}`),e.slug&&r.push(`slug: ${e.slug}`),e.runtime&&e.runtime.length&&r.push(`runtime: ${e.runtime.join(", ")}`),e.tags&&e.tags.length&&r.push(`tags: ${e.tags.join(", ")}`),e.updatedAt&&r.push(`updated: ${e.updatedAt}`),e.path&&r.push(`path: ${e.path}`),e.url&&r.push(`url: ${e.url}`),t&&(r.push(`manifest: ${t.url}`),t.title&&r.push(`manifest title: ${t.title}`),t.summary&&r.push(`manifest summary: ${t.summary}`),t.error&&r.push(`manifest fetch: ${t.error}`)),r.join(`
|
|
230
|
+
`)}async function Bn(e){let t=Wn(e.url);if(!t)return;let r=new AbortController,n=setTimeout(()=>{r.abort()},5e3);try{let i=await fetch(t,{headers:{"user-agent":"skillcraft-cli"},signal:r.signal});if(!i.ok)return{url:t,error:`unable to fetch manifest (${i.status})`};let o=await i.text();if(Gn(o))return{url:t,error:"unable to parse manifest (not markdown)"};let s=Vn(o);return{url:t,title:s.title,summary:s.summary}}catch(i){return i instanceof Error&&i.name==="AbortError"?{url:t,error:"manifest fetch timed out"}:{url:t,error:i instanceof Error?i.message:"failed to fetch manifest"}}finally{clearTimeout(n)}}function Wn(e){if(!e)return;let t=e.trim();if(!t)return;let r=t.endsWith("/SKILL.md")?t:t.endsWith("/")?`${t}SKILL.md`:`${t}/SKILL.md`;return Jn(r)}function Jn(e){try{let t=new URL(e);if(t.hostname!=="github.com")return e;let r=t.pathname.split("/").filter(Boolean),n=r.indexOf("blob");if(n!==2||r.length<n+2)return e;let i=r[0],o=r[1],s=r.slice(n+1);if(!i||!o||!s.length)return e;let c=[i,o,"raw","refs","heads",...s];return`${t.protocol}//${t.host}/${c.join("/")}`}catch{return e}}function Gn(e){let t=e.replace(/^\s+/,"").toLowerCase();return t.startsWith("<!doctype html")||t.startsWith("<html")}function Vn(e){let r=e.replace(/\r\n/g,`
|
|
231
231
|
`).split(`
|
|
232
|
-
`),n=0;if((r[0]||"").trim()==="---"){for(n=1;n<r.length&&r[n].trim()!=="---";)n+=1;n<r.length&&r[n].trim()==="---"&&(n+=1)}let o
|
|
233
|
-
`).map(r=>r.trim()).filter(Boolean).map(r=>{let n=r.indexOf(" ");if(n===-1)return;let
|
|
232
|
+
`),n=0;if((r[0]||"").trim()==="---"){for(n=1;n<r.length&&r[n].trim()!=="---";)n+=1;n<r.length&&r[n].trim()==="---"&&(n+=1)}let i,o;for(let s=n;s<r.length;s+=1){let c=r[s].trim();if(!c){if(o)break;continue}if(!i&&c.startsWith("#")){i=c.replace(/^#+\s*/,"").trim();continue}if(!o&&!c.startsWith(">")){o=c;break}}return{title:i,summary:o}}function or(e){return Array.isArray(e)}async function Zn(){let e=await Ge();return new Set(e.map(t=>t.id))}async function Ge(e=void 0){let t=process.env.SKILLCRAFT_SEARCH_INDEX_PATH?.trim(),r=t||process.env.SKILLCRAFT_SEARCH_INDEX_URL||"https://skillcraft.gg/skills-registry/search/index.json",n=async()=>{if(t){let u=await _.readFile(t,"utf8"),l=JSON.parse(u);return sr(or(l)?l:[])}let s=process.env.SKILLCRAFT_SEARCH_INDEX_URL||"https://skillcraft.gg/skills-registry/search/index.json",c=await fetch(s,{headers:{"user-agent":"skillcraft-cli"}});if(!c.ok)throw new Error(`failed to download search index from ${s}`);let a=await c.json();return sr(or(a)?a:[])};if(!Xn(e))return n();let i=t?`reading local index from ${r}`:`downloading index from ${r}`,o=Dn({text:`Loading ${i}...`}).start();try{let s=await n();return o.succeed(`loaded ${s.length} indexed entries`),s}catch(s){throw o.fail("failed to load search index"),s}}function Xn(e){return e!=="text"?!1:process.stdout.isTTY===!0||process.stderr.isTTY===!0}function sr(e){return e.map(t=>Yn(t)).filter(t=>!!t)}function Yn(e){let t=gr(e.id),r=Ct(t);if(r)return{id:r,name:ce(e.name),path:ce(e.path),url:ce(e.url),owner:ce(e.owner),slug:ce(e.slug),runtime:ar(e.runtime),tags:ar(e.tags),updatedAt:ce(e.updatedAt)}}function gr(e){return String(e||"").trim()}function ce(e){return gr(e)||void 0}function ar(e){if(e===void 0)return[];if(typeof e=="string")return e.split(",").map(r=>r.trim()).filter(Boolean);if(!Array.isArray(e))return[];let t=[];for(let r of e){if(typeof r!="string")continue;let n=r.trim();n&&t.push(n)}return t}function Ve(e){let t=e.indexOf(":");if(t<1)return;let r=e.slice(0,t).trim();if(r)return r.toLowerCase()}function cr(e){let t=e===void 0?20:Math.floor(e);return Number.isFinite(t)&&t>0?t:20}function Qn(e){let t=(e.name||"").trim();if(!t)return"";let r=ei(e);return r&&t.toLowerCase()===r.toLowerCase()?"":t}function ei(e){if(e.slug&&e.slug.trim())return e.slug.trim();let t=e.id.trim(),r=t.indexOf(":"),n=r>=0?t.slice(r+1):t,i=n.split("/").filter(Boolean);return i.length?i[i.length-1]:n}function ti(e){if(!e)return"";let t=new Date(e);return Number.isNaN(t.getTime())?"":` (updated ${t.toISOString().slice(0,10)})`}async function dr(e){try{return await _.access(e),!0}catch{return!1}}async function $e(e,t){let{stdout:r}=await Hn("git",t,{cwd:e});return r.trim()}async function hr(){await Kn()}import{mkdtemp as ri,rm as ni}from"fs/promises";import ii from"os";import oi from"path";function si(e){let t=e.trim();if(t&&!(/^[a-zA-Z]:[\\/]/.test(t)||t.startsWith("/")||t.startsWith("./")||t.startsWith("../"))&&(/^[a-z][a-z0-9+.-]*:/.test(t)||t.startsWith("git@")||t.startsWith("ssh://")||t.startsWith("http://")||t.startsWith("https://")||t.startsWith("file://")))return t}async function wr(e){try{return(await h(["config","--get-regexp","^remote..*.url$"],e)).split(`
|
|
233
|
+
`).map(r=>r.trim()).filter(Boolean).map(r=>{let n=r.indexOf(" ");if(n===-1)return;let i=r.slice(0,n),o=r.slice(n+1).trim(),s=i.slice(7,-4);if(!(!o||!s))return{name:s,url:o}}).filter(r=>!!r)}catch{return[]}}async function yr(e){return Ze(e,{normalize:!0})}async function Ze(e,t={}){let r=t.normalize??!0,n=[];for(let i of e){let o=r?si(i.repo):i.repo;if(!o){for(let a of i.commits)n.push({repo:i.repo,commit:a});continue}let s=Array.from(new Set(i.commits.map(a=>a.trim()).filter(Boolean)));if(!s.length)continue;let c=await ai(o,s);for(let a of c)n.push({repo:o,commit:a})}return n}async function ai(e,t){let r=Array.from(new Set(t.map(i=>i.trim()).filter(Boolean)));if(!r.length)return[];let n=await ri(oi.join(ii.tmpdir(),"skillcraft-remote-check-"));try{try{await h(["clone","--quiet","--no-checkout",e,n],process.cwd())}catch{return r}let i=[];for(let o of r)await ci(n,o)||i.push(o);return i}finally{await ni(n,{recursive:!0,force:!0})}}async function ci(e,t){try{await h(["cat-file","-e",`${t}^{commit}`],e)}catch{return!1}try{return!!await h(["branch","-r","--contains",t],e)}catch{return!1}}async function kr(){let e=process.cwd();if(!await P(e))throw new Error("Repository is not enabled");let r=(await fe(e,200)).map(l=>l.message.match(/Skillcraft-Ref:\s*(\S+)/)?.[1]).filter(Boolean),n=0,i=[];for(let l of r){let d=await Oe(e,l);if(!d){n+=1,process.stdout.write(`missing proof object: ${l}
|
|
234
234
|
`);continue}if(!d.commit||!d.timestamp){n+=1,process.stdout.write(`invalid proof object: ${l}
|
|
235
|
-
`);continue}
|
|
235
|
+
`);continue}i.push(d.commit)}if(n>0){process.stdout.write(`verify failed: ${n} missing/invalid proofs
|
|
236
236
|
`),process.exitCode=1;return}process.stdout.write(`verify passed: ${r.length} commit proofs resolved
|
|
237
|
-
`);let
|
|
238
|
-
`);return}let s=
|
|
237
|
+
`);let o=await wr(e);if(!o.length){process.stdout.write(`\u26A0\uFE0F Warning: no git remotes configured for repository
|
|
238
|
+
`);return}let s=o.map(l=>({repo:l.url,commits:i})),c=await Ze(s,{normalize:!1}),a=new Map;for(let{repo:l,commit:d}of c){let m=a.get(l);m?m.push(d):a.set(l,[d])}let u=l=>{let d=a.get(l);return d?Array.from(new Set(d)):[]};for(let l of o){let d=u(l.url);d.length>0?process.stdout.write(`\u26A0\uFE0F Warning: proof commits not pushed to ${l.url}: ${d.join(", ")}
|
|
239
239
|
`):process.stdout.write(`remote status: ${l.url} (all referenced proof commits present)
|
|
240
|
-
`)}}import{createHash as
|
|
241
|
-
`);return}for(let
|
|
242
|
-
`)}async function
|
|
243
|
-
`),process.stdout.write(`state: ${
|
|
240
|
+
`)}}import{createHash as di}from"crypto";import vr from"yaml";async function Xe(){let e=await j(),t=$(e.provider??"gh"),r=await Ye(t,e.githubUser),i=(await t.listClaimIssues("skillcraft-gg/credential-ledger")).filter(o=>{let s=Ee(o.body);return s?.claimant===S(r)&&!!s?.credential});if(!i.length){process.stdout.write(`no claims found for ${r||"user"}
|
|
241
|
+
`);return}for(let o of i)process.stdout.write(`#${o.number} ${o.title} (${Qe(o.labels?.map(s=>s?.name)||[])})
|
|
242
|
+
`)}async function xr(e){let t=S(e);if(!t)throw new Error("claim status requires a credential identifier");let r=await j(),n=$(r.provider??"gh"),i=await Ye(n,r.githubUser),o=await li(n,t,i);if(!o)throw new Error(`No claim found for credential ${t} for user ${i||"unknown"}. Run "skillcraft claim" to see your claims.`);let s=await n.getIssueStatus("skillcraft-gg/credential-ledger",o),c=await n.listClaimProcessingRuns("skillcraft-gg/credential-ledger",o);if(process.stdout.write(`issue #${o}
|
|
243
|
+
`),process.stdout.write(`state: ${Qe(s.labels)}
|
|
244
244
|
`),process.stdout.write(`labels: ${s.labels.join(", ")||"none"}
|
|
245
245
|
`),process.stdout.write(`url: ${s.url}
|
|
246
246
|
`),!c.length){process.stdout.write(`processing actions: none found
|
|
247
247
|
`);return}let a=c[0],u=a.conclusion?` (${a.conclusion})`:"";process.stdout.write(`processing actions: ${a.status}${u}
|
|
248
248
|
`),process.stdout.write(`latest run: ${a.url}
|
|
249
249
|
`),c.length>1&&process.stdout.write(`previous attempts: ${c.length-1}
|
|
250
|
-
`)}async function
|
|
250
|
+
`)}async function li(e,t,r){let n=await e.listClaimIssues("skillcraft-gg/credential-ledger"),i=S(t),o=S(r);return n.map(c=>{let a=Ee(c.body);if(!(!a||a.claimant!==o||a.credential!==i))return c.number}).filter(c=>!!c).sort((c,a)=>a-c)[0]}async function ui(e,t,r){let n=await e.listClaimIssues("skillcraft-gg/credential-ledger"),i=S(t),o=S(r);return n.filter(c=>{if(S(c.state)!=="open")return!1;let a=Ee(c.body);return!!a&&a.claimant===o&&a.credential===i}).sort((c,a)=>c.number-a.number)[0]}async function Pr(e,t){let r=await j(),n=$(r.provider??"gh"),i=await Ye(n,r.githubUser),o=await fi(e,{allRepos:t?.allRepos,repo:t?.repo},i),s=S(e),c=S(i),a=await yr(o.sources);if(a.length>0){process.stdout.write(`\u26A0\uFE0F Warning: some claim commits may not be pushed yet. Please push recent commits before re-submitting the claim.
|
|
251
251
|
`);for(let d of a)process.stdout.write(`- ${d.commit} in ${d.repo}
|
|
252
|
-
`);process.exitCode=1;return}s&&c
|
|
252
|
+
`);process.exitCode=1;return}if(s&&c){let d=await ui(n,s,c);if(d){let m=d.url||await n.getIssueUrl("skillcraft-gg/credential-ledger",d.number);process.stdout.write(`claim already submitted
|
|
253
|
+
`),process.stdout.write(`issue: #${d.number}
|
|
254
|
+
`),process.stdout.write(`state: ${Qe(d.labels?.map(p=>p?.name)||[])}
|
|
255
|
+
`),process.stdout.write(`url: ${m}
|
|
256
|
+
`);return}await mi(n,s,c)}let u=vr.stringify(o),l=await n.createIssue("skillcraft-gg/credential-ledger",`claim: ${e}`,u);process.stdout.write(`opened claim: #${l}
|
|
253
257
|
`),process.stdout.write(`payload:
|
|
254
258
|
${u}
|
|
255
|
-
`)}async function
|
|
256
|
-
`),r=
|
|
257
|
-
`)}async function
|
|
258
|
-
`)}async function
|
|
259
|
+
`)}async function Ye(e,t){let r=process.env.GITHUB_USER||process.env.USER||"";try{let n=await e.getUser();if(n)return n}catch{}return t||r||"unknown"}function S(e){return(e||"").trim().toLowerCase()}async function mi(e,t,r){let i=(await e.listClaimIssues("skillcraft-gg/credential-ledger")).find(s=>{if(!pi(s,"skillcraft-issued"))return!1;let c=Ee(s.body);return c?c.credential===t&&c.claimant===r:!1});if(!i)return;let o=i.url?` (${i.url})`:"";throw new Error(`You already have an issued claim for ${t}. Existing issue: #${i.number}${o}`)}function Ee(e){if(e)try{let t=String(e).replace(/\\n/g,`
|
|
260
|
+
`),r=vr.parse(t);if(!r||typeof r!="object")return;let n=r.credential&&typeof r.credential=="string"?r.credential:r.credential?.id,i=r.claimant?.github,o=S(n),s=S(i);return!o||!s?void 0:{credential:o,claimant:s}}catch{return}}function pi(e,t){let r=t.toLowerCase();return(e.labels||[]).some(n=>S(n?.name)===r)}function Qe(e){let t=new Set((e||[]).map(r=>S(r)));return t.has("skillcraft-issued")?"issued":t.has("skillcraft-rejected")?"rejected":t.has("skillcraft-verified")?"verified":t.has("skillcraft-processing")?"processing":"pending"}async function fi(e,t,r="unknown"){let n=await gi(t),i=[];for(let a of n){let u=await se(a),l=await z(a)||a,d=await Promise.all(u.map(async p=>await at(a,p.commit)?p:void 0)),m=Array.from(new Set(d.map(p=>p?.commit).filter(Boolean)));i.push({repo:l,commits:m})}let o=r,s=`${o}:${e}:${i.map(a=>`${a.repo}:${a.commits.length}`).join("|")}:${Date.now()}`,c=di("sha256").update(s).digest("hex").slice(0,8);return{claim_version:1,claimant:{github:o},credential:{id:e},sources:i,claim_id:`sha256:${c}`}}async function gi(e){let t=e.allRepos?(await F()).repos.map(i=>i.path):[process.cwd()],r=e.repo?e.repo:t,n=[];for(let i of r)await _t(i)&&n.push(i);return n}import pe from"path";import X from"fs/promises";import{execFile as hi}from"child_process";import{promisify as wi}from"util";var yi=wi(hi);async function br(e){if(!Ne(e))throw new Error("loadout id must be <owner>/<slug>");let t=process.cwd();if(!await P(t))throw new Error("Repository is not enabled");let r=await v(R(t)),n=Array.isArray(r?.activeLoadouts)?r.activeLoadouts.filter(Boolean):[];n.includes(e)||n.push(e),await y(R(t),{activeLoadouts:n}),process.stdout.write(`activated loadout: ${e}
|
|
261
|
+
`)}async function Rr(){let e=process.cwd();if(!await P(e))throw new Error("Repository is not enabled");await y(R(e),{activeLoadouts:[]}),process.stdout.write(`cleared active loadouts
|
|
262
|
+
`)}async function Cr(e){let t=T(e,"loadout id");if(!Ne(t))throw new Error("loadout id must be <owner>/<slug>");let{owner:r,slug:n}=xe(t),i=process.cwd(),o=pe.join(i,"loadout.yaml");if(await X.access(o),!(await X.stat(o)).isFile())throw new Error("loadout.yaml not found in current directory");let c=await j(),a=$(c.provider??"gh"),u="skillcraft-gg/loadouts",l=pe.join(process.cwd(),".skillcraft-temp-loadout-share"),d=`skillcraft-loadout-${r}-${n}`;try{await X.rm(l,{force:!0,recursive:!0}),await a.cloneRepo(u,l),await Ie(l,["checkout","-B",d]);let m=pe.join(l,"loadouts",r,n);await X.rm(m,{force:!0,recursive:!0}).catch(()=>{}),await X.mkdir(pe.dirname(m),{recursive:!0}),await X.copyFile(o,pe.join(m,"loadout.yaml")),await Ie(l,["add",m]),await Ie(l,["commit","-m",`Loadout: publish ${t}`]).catch(async()=>{throw new Error("nothing to commit; loadout may already be published")}),await Ie(l,["push","-u","origin",d]).catch(()=>{throw new Error("unable to push loadout publish branch")}),await a.createPullRequest(u,d,`Loadout publish: ${t}`).catch(()=>{process.stdout.write(`unable to create PR automatically. Please open one manually from your branch.
|
|
259
263
|
`)}),process.stdout.write(`loadout publish workflow completed for ${t}
|
|
260
|
-
`)}finally{await X.rm(l,{force:!0,recursive:!0})}}async function
|
|
264
|
+
`)}finally{await X.rm(l,{force:!0,recursive:!0})}}async function Ie(e,t){let{stdout:r}=await yi("git",t,{cwd:e});return r.trim()}async function Sr(e){if(!await P(e))return;let t=await te(e),r=new Date().toISOString(),n=await Ft(e,t,r);if(!n)return;let i=await Tt(e,n.proofId);await lt(e,i);let o=await te(e);o!==t&&await ze(e,{...n.proof,commit:o}),await y(L(e),{skills:[]})}async function $r(e,t="origin"){await qt(e,t)}var b=new ki;b.name("skillcraft").description("Skillcraft CLI").version(nt.version);b.option("--json","machine-readable JSON output");b.command("enable").description("Enable Skillcraft in the current repository").action(w(Dt));b.command("disable").description("Disable Skillcraft in the current repository").action(w(Rt));b.command("status").description("Show repository Skillcraft status").action(w(zt));b.command("doctor").description("Check environment and integration readiness").action(w(Mt));var Er=b.command("repos").description("Manage tracked repositories");Er.command("list").description("List tracked repositories").action(w(Ht));Er.command("prune").description("Remove unavailable repository entries").action(w(Kt));var et=b.command("progress").description("Show progress for tracked credentials");et.option("--refresh","refresh the local credential index cache before evaluating progress").action((e,t)=>{let r=t.parent?.opts()?.json?"json":"text";w(()=>tr({outputMode:r,refreshIndex:e.refresh}))()});et.command("track <credential-id>").description("Track a credential for local progress evaluation").action(e=>w(()=>rr(e))());et.command("untrack <credential-id>").description("Untrack a credential from local progress evaluation").action(e=>w(()=>nr(e))());var de=b.command("skills").description("Manage local skill publishing");de.command("add <id>").description("Add a local or external skill from the registry index").action(e=>w(()=>ur(e))());de.command("publish <owner-slug>").description("Publish a skill to the registry").action(e=>w(()=>lr(e))());de.command("validate").description("Validate local skill layout").action(w(hr));de.command("list").description("List detected skills in the current repository").action(w(mr));de.command("inspect <id>").description("Show detailed information for a registry skill").action((e,t,r)=>{let n=r.parent?.parent?.opts()?.json?"json":"text";w(()=>fr(e,{outputMode:n}))()});de.command("search [query]").description("Search the published skill index").option("--source <source>","filter to a registry source").option("--limit <n>","limit number of results",e=>Number.parseInt(e,10)).action((e,t,r)=>{let n=r.parent?.parent?.opts()?.json?"json":"text";w(()=>pr(e,{source:t.source,limit:t.limit,outputMode:n}))()});b.command("verify").description("Verify local Skillcraft proofs and trailers").action(w(kr));var tt=b.command("claim").description("Claim a credential or inspect your claims");tt.argument("[credential]","credential identifier").option("--all-repos","include tracked repositories").option("--repo <path...>","explicit repositories to include").action((e,t)=>{if(!e){w(()=>Xe())();return}w(()=>Pr(e,{allRepos:t.allRepos,repo:t.repo}))()});tt.command("list").description("List your claims in the credentials repository").action(w(Xe));tt.command("status <credential>").description("Show claim status by credential identifier").action(e=>w(()=>xr(e))());var rt=b.command("loadout").description("Manage active loadouts");rt.command("use <id>").description("Activate a loadout in local context").action(e=>w(()=>br(e))());rt.command("clear").description("Clear active loadouts").action(w(Rr));rt.command("share <id>").description("Publish local loadout to registry").action(e=>w(()=>Cr(e))());b.command("_hook <name> [repoPath] [remote]",{hidden:!0}).description("internal hook command").action((e,t,r)=>w(async()=>{e==="post-commit"&&await Sr(t||process.cwd()),(e==="pre-push"||e==="post-push")&&await $r(t||process.cwd(),r||"origin")})());function w(e){return(...t)=>{Promise.resolve(e(...t)).catch(r=>{process.stderr.write(`${r instanceof Error?r.message:String(r)}
|
|
261
265
|
`),process.exitCode=1})}}b.parse(process.argv);
|
|
262
266
|
//# sourceMappingURL=index.js.map
|