@kanonak-protocol/cli 4.6.0 → 4.8.0
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 +46 -46
- package/package.json +3 -3
package/dist/index.js
CHANGED
|
@@ -1,63 +1,63 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{Command as
|
|
3
|
-
`).some(r=>r.trim()===t||r.trim()===t+"/"))return;
|
|
2
|
+
import{Command as sc}from"commander";import{readFileSync as ac}from"fs";import{fileURLToPath as ic}from"url";import{dirname as cc,join as lc}from"path";import{KanonakParser as uc,PublisherIndex as pc,CredentialStore as dc,createAuthenticatedFetch as mc}from"@kanonak-protocol/sdk";import{readFileSync as ao,statSync as io}from"fs";import{resolve as co,dirname as lo}from"path";import{KanonakParser as uo,KanonakObjectValidator as po,ValidationSeverity as on}from"@kanonak-protocol/sdk";import{readdirSync as to}from"fs";import{join as oo,dirname as ro,basename as tn}from"path";import{LocalFirstRepository as Cc,buildLocalFirstRepository as so}from"@kanonak-protocol/sdk";import{mkdirSync as Yt,readFileSync as en,writeFileSync as nn,existsSync as we,appendFileSync as Xt}from"fs";import{join as Zt,dirname as Qt,isAbsolute as eo}from"path";import{getGlobalCachePath as no}from"@kanonak-protocol/sdk";var K=class{constructor(e=no()){this.cacheDir=e;this.isProjectLocal=!eo(e)}cacheDir;gitignoreChecked=!1;isProjectLocal;get(e,t,o){let r=this.getPath(e,t,o);return we(r)?en(r,"utf-8"):null}put(e,t,o,r){let a=this.getPath(e,t,o);Yt(Qt(a),{recursive:!0}),nn(a,r,"utf-8"),this.isProjectLocal&&this.ensureGitignore()}has(e,t,o){return we(this.getPath(e,t,o))}ensureGitignore(){if(this.gitignoreChecked)return;this.gitignoreChecked=!0;let e=".gitignore",t=this.cacheDir;if(we(e)){if(en(e,"utf-8").split(`
|
|
3
|
+
`).some(r=>r.trim()===t||r.trim()===t+"/"))return;Xt(e,`
|
|
4
4
|
${t}/
|
|
5
5
|
`)}else nn(e,`${t}/
|
|
6
|
-
`)}getPath(e,t,o){return
|
|
6
|
+
`)}getPath(e,t,o){return Zt(this.cacheDir,e,`${t}@${o}.kan.yml`)}};function N(n){let e=n;for(;;){let t=ro(e);if(t===e)break;if(tn(e).includes(".")||tn(t).includes(".")){e=t;continue}break}return e}function be(n,e){for(let t of to(n,{withFileTypes:!0})){let o=oo(n,t.name);t.isDirectory()&&t.name!=="node_modules"&&t.name!==".kanonak"?be(o,e):t.name.endsWith(".kan.yml")&&e.push(o)}}async function $(n,e){let t=new K;return so(n,e,{httpCache:{getFromCache:(o,r,a)=>t.get(o,r,a),onFetch:(o,r,a,s)=>t.put(o,r,a,s)}})}async function rn(n){let e=co(n),t=io(e),o=t.isDirectory()?N(e):N(lo(e)),r=new uo,a=new po(r),s=await $(o,r),i=[];if(t.isDirectory()?be(e,i):i.push(e),i.length===0){console.log("No .kan.yml files found.");return}let c=0,l=0,u=[];for(let f of i){let m=ao(f,"utf-8"),h=r.parseWithErrors(m);if(h.errors&&h.errors.length>0){console.log(`
|
|
7
7
|
${f}:`);for(let k of h.errors)console.log(` ERROR (parse): ${k.message} [line ${k.line}:${k.column}]`),c++;continue}if(!h.document){console.log(`
|
|
8
|
-
${f}:`),console.log(" ERROR: Failed to parse document"),c++;continue}u.push({file:f,document:h.document})}let p=u.map(f=>f.document),d=new Map(u.map(f=>[f.document,f.file])),g=await
|
|
8
|
+
${f}:`),console.log(" ERROR: Failed to parse document"),c++;continue}u.push({file:f,document:h.document})}let p=u.map(f=>f.document),d=new Map(u.map(f=>[f.document,f.file])),g=await a.validateDocumentsAsync(p,s);for(let{document:f,result:m}of g){let h=m.errors.filter(y=>y.severity===on.Error),k=m.warnings.filter(y=>y.severity===on.Warning);if(h.length>0||k.length>0){let y=f.metadata.namespace_,w=y?`${y.publisher}/${y.package_}@${y.version}`:d.get(f)??"(unknown)";console.log(`
|
|
9
9
|
${w}:`);for(let b of h)console.log(` ERROR: ${b.message}`),b.suggestion&&console.log(` -> ${b.suggestion}`);for(let b of k)console.log(` WARN: ${b.message}`)}c+=h.length,l+=k.length}console.log(`
|
|
10
|
-
${i.length} file(s) validated. ${c} error(s), ${l} warning(s).`),c>0&&process.exit(1)}import{KanonakParser as
|
|
11
|
-
Installed ${Object.keys(
|
|
12
|
-
Installed ${g.size} package(s).`)}async function
|
|
10
|
+
${i.length} file(s) validated. ${c} error(s), ${l} warning(s).`),c>0&&process.exit(1)}import{KanonakParser as mo,PublisherIndex as fo,CredentialStore as go,createAuthenticatedFetch as ho}from"@kanonak-protocol/sdk";import{loadLockFile as ko,saveLockFile as yo,computeIntegrity as wo,assertPackageIdentity as bo}from"@kanonak-protocol/sdk";function T(n){if(!n)return null;let e=n.indexOf("/");if(e===-1)return null;let t=n.substring(0,e),o=n.substring(e+1);if(!t||!o)return null;let r,a=null,s=null,i=o.indexOf("@");if(i!==-1){r=o.substring(0,i);let c=o.substring(i+1),l=c.indexOf("/");l===-1?a=c||null:(a=c.substring(0,l)||null,s=c.substring(l+1)||null)}else{let c=o.indexOf("/");c===-1?r=o:(r=o.substring(0,c),s=o.substring(c+1)||null)}return!r||s&&s.includes("/")||a&&a.includes("@")?null:{publisher:t,packageName:r,version:a,instanceName:s}}async function sn(n){let e=new K,t=new mo,o=new go,r=ho(o),a=new fo({fetchFn:r}),s=ko()??{version:"1",lastUpdated:new Date().toISOString(),packages:{}};if(!n){Object.keys(s.packages).length===0&&(console.error("No kanonak.lock file found or lock file is empty."),console.error("Usage: kanonak install {publisher}/{package}[@{version}]"),process.exit(1)),console.log(`Installing ${Object.keys(s.packages).length} package(s) from kanonak.lock...`);for(let[f,m]of Object.entries(s.packages)){let h=f.indexOf("/"),k=f.substring(0,h),y=f.substring(h+1),w=e.get(k,y,m.version);if(w)console.log(` ${f}@${m.version} (cached)`);else{let b=m.resolved,v=await r(b,k);if(!v.ok)throw new Error(`Failed to fetch ${b} (${v.status} ${v.statusText})`);w=await v.text(),e.put(k,y,m.version,w),console.log(` ${f}@${m.version}`)}}console.log(`
|
|
11
|
+
Installed ${Object.keys(s.packages).length} package(s) from lock file.`);return}let i=T(n);i||(console.error(`Invalid package reference: "${n}"`),console.error("Expected format: {publisher}/{package}[@{version}]"),process.exit(1));let{publisher:c,packageName:l,version:u,instanceName:p}=i;p&&(console.error(`\`kanonak install\` works on whole packages \u2014 got an instance suffix "/${p}".`),console.error(`Try: kanonak install ${c}/${l}${u?"@"+u:""}`),console.error("(Use `kanonak <capability> add` if you want to install one named instance.)"),process.exit(1));let d=u??await a.getHighestVersion(c,l);d||(console.error(`Could not resolve version for "${c}/${l}".`),console.error("Check the spelling, or run a search to see what the publisher offers."),process.exit(1)),console.log(`Installing ${c}/${l}@${d}...`);let g=new Set;await an(c,l,d,e,t,a,r,g,s),yo(s),console.log(`
|
|
12
|
+
Installed ${g.size} package(s).`)}async function an(n,e,t,o,r,a,s,i,c){let l=`${n}/${e}@${t}`;if(i.has(l))return;i.add(l);let u=`${n}/${e}`,p=o.get(n,e,t),d=await a.getPackageUrl(n,e,t),g,f=!1;if(p)g=p;else{let k=await s(d,n);if(!k.ok)throw new Error(`Failed to fetch ${d} (${k.status} ${k.statusText})`);g=await k.text(),f=!0}let m=r.parse(g);bo(m,n,e,t),f&&o.put(n,e,t,g),console.log(` ${l}${f?"":" (cached)"}`);let h={};if(m.metadata.imports)for(let[k,y]of Object.entries(m.metadata.imports))for(let w of y){let b=await a.resolveVersion(k,w);b?(h[`${k}/${w.packageName}`]=b,await an(k,w.packageName,b,o,r,a,s,i,c)):console.error(` WARNING: Could not resolve ${k}/${w.packageName} ${w.package_}`)}c.packages[u]={version:t,resolved:d,integrity:wo(g),dependencies:h}}import{readFileSync as vo}from"fs";import{resolve as $o,dirname as So}from"path";import{KanonakParser as Po}from"@kanonak-protocol/sdk";async function cn(n){let e=$o(n),t=vo(e,"utf-8"),o=new Po,r=o.parse(t),a=r.metadata.namespace_,s=a?`${a.publisher}/${a.package_}@${a.version}`:n;if(console.log(s),!r.metadata.imports){console.log(" (no imports)");return}let i=N(So(e)),c=await $(i,o),l=new Set;for(let[u,p]of Object.entries(r.metadata.imports))for(let d of p)await ln(u,d,c,l," ")}async function ln(n,e,t,o,r){let a=`${n}/${e.packageName}`;if(o.has(a)){console.log(`${r}${a} (${e.package_}) [circular]`);return}o.add(a);let s;try{s=await t.getHighestCompatibleVersionAsync(n,e)}catch{console.log(`${r}${a} (${e.package_}) [fetch failed]`);return}if(!s){console.log(`${r}${a} (${e.package_}) [not found]`);return}let i=s.metadata.namespace_?.version?.toString()??"?";if(console.log(`${r}${n}/${e.packageName}@${i}`),s.metadata.imports)for(let[c,l]of Object.entries(s.metadata.imports))for(let u of l)await ln(c,u,t,o,r+" ")}import{createHash as Ro,randomBytes as dn}from"crypto";import{createServer as _o}from"http";import{execFile as ve}from"child_process";import{CredentialStore as xo,generateDPoPKeyPair as Io,createDPoPProof as un,serverSupportsDPoP as Ko}from"@kanonak-protocol/sdk";import{normalizeHost as Co}from"@kanonak-protocol/sdk";var A=class{cache=new Map;async discover(e){let t=Co(e);if(this.cache.has(t))return this.cache.get(t);let o=`https://${t}/.well-known/oauth-authorization-server`,r=await this.tryEndpoint(o);if(!r){let a=`https://${t}/.well-known/openid-configuration`;r=await this.tryEndpoint(a)}return this.cache.set(t,r),r}async supportsOAuth(e){return await this.discover(e)!==null}static supportsPkceS256(e){return e.codeChallengeMethodsSupported?.some(t=>t.toUpperCase()==="S256")??!1}static supportsDynamicRegistration(e){return!!e.registrationEndpoint}static supportsAuthorizationCode(e){return e.responseTypesSupported?.some(t=>t.toLowerCase()==="code")??!1}async tryEndpoint(e){let t;try{t=await fetch(e)}catch(r){let a=r instanceof Error?r.message:String(r);return a.includes("ENOTFOUND")||a.includes("ECONNREFUSED")?(console.error(` OAuth discovery: ${e} \u2014 host unreachable (${a})`),console.error(" If the server is behind a VPN, ensure you are connected.")):a.includes("CERT")||a.includes("SSL")||a.includes("TLS")?(console.error(` OAuth discovery: ${e} \u2014 TLS error (${a})`),console.error(" If using a custom CA certificate, set NODE_EXTRA_CA_CERTS=/path/to/ca.pem")):console.error(` OAuth discovery: ${e} \u2014 network error: ${a}`),null}if(!t.ok)return t.status===404||(t.status===403?(console.error(` OAuth discovery: ${e} \u2014 HTTP 403 Forbidden`),console.error(" Access may be blocked by a firewall, proxy, or WAF.")):t.status>=500&&(console.error(` OAuth discovery: ${e} \u2014 HTTP ${t.status} server error`),console.error(" The authorization server returned an internal error. Contact your IDP administrator."))),null;let o;try{o=await t.json()}catch{return console.error(` OAuth discovery: ${e} \u2014 response is not valid JSON`),console.error(" The endpoint may be returning HTML instead of JSON. Check IDP configuration."),null}return{issuer:J(o.issuer),authorizationEndpoint:J(o.authorization_endpoint),tokenEndpoint:J(o.token_endpoint),registrationEndpoint:J(o.registration_endpoint),revocationEndpoint:J(o.revocation_endpoint),scopesSupported:H(o.scopes_supported),responseTypesSupported:H(o.response_types_supported),grantTypesSupported:H(o.grant_types_supported),codeChallengeMethodsSupported:H(o.code_challenge_methods_supported),tokenEndpointAuthMethodsSupported:H(o.token_endpoint_auth_methods_supported),dpopSigningAlgValuesSupported:H(o.dpop_signing_alg_values_supported)}}};function J(n){return typeof n=="string"?n:null}function H(n){return Array.isArray(n)?n.filter(e=>typeof e=="string"):null}var B=class{discovery;credentialStore;constructor(e,t){this.discovery=e??new A,this.credentialStore=t??new xo}async authorize(e,t=[]){console.log(`Starting OAuth flow for ${e}...`);let o=await this.discovery.discover(e);if(!o)return I(`No OAuth discovery endpoint found for '${e}'.
|
|
13
13
|
The server must expose one of:
|
|
14
14
|
- https://${e}/.well-known/oauth-authorization-server (RFC 8414)
|
|
15
15
|
- https://${e}/.well-known/openid-configuration (OpenID Connect)
|
|
16
16
|
Verify the hostname is correct and HTTPS is configured.
|
|
17
17
|
If using a corporate proxy, ensure it is not blocking the discovery request.`);let r=[];if(o.authorizationEndpoint||r.push("authorization_endpoint"),o.tokenEndpoint||r.push("token_endpoint"),r.length>0)return I(`OAuth metadata for '${e}' is missing required fields: ${r.join(", ")}.
|
|
18
|
-
Contact the IDP administrator to ensure these are included in the discovery document.`);let
|
|
19
|
-
Ensure your Node.js installation supports EC P-256 curves.`)}}let{redirectUri:i,port:c,waitForCallback:l,close:u}=await
|
|
18
|
+
Contact the IDP administrator to ensure these are included in the discovery document.`);let a=Ko(o.dpopSigningAlgValuesSupported),s=null;if(a){console.log(" Server supports DPoP (RFC 9449) \u2014 generating key pair...");try{s=Io()}catch(v){return I(`Failed to generate DPoP key pair: ${z(v)}
|
|
19
|
+
Ensure your Node.js installation supports EC P-256 curves.`)}}let{redirectUri:i,port:c,waitForCallback:l,close:u}=await No(),p=await this.credentialStore.getCredential(e),d=p?.clientId??null,g=p?.clientSecret??null;if(!d&&o.registrationEndpoint){console.log(" Registering dynamic OAuth client (RFC 7591)...");let v=await this.registerClient(o.registrationEndpoint,i);if(!v.success)return u(),I(v.error);d=v.clientId,g=v.clientSecret??null}if(!d)return u(),I(`No OAuth client credentials for '${e}' and the server does not support dynamic client registration (no registration_endpoint in metadata).
|
|
20
20
|
You must pre-register a client with your IDP and configure the client_id.
|
|
21
21
|
Ask your IDP administrator to enable dynamic client registration (RFC 7591),
|
|
22
|
-
or add a registration_endpoint to the OAuth metadata.`);let f=
|
|
22
|
+
or add a registration_endpoint to the OAuth metadata.`);let f=To(),m=Eo(f),h=jo(),k=Ao(o.authorizationEndpoint,d,i,t,h,m);console.log(` Opening browser for authorization on port ${c}...`),console.log(" If the browser doesn't open, navigate to:"),console.log(` ${k}`),Uo(k);let y=await l();if(u(),!y)return I(`Authorization timed out after 5 minutes.
|
|
23
23
|
The browser authorization was not completed in time.
|
|
24
24
|
Re-run 'kanonak login ${e}' and complete the browser authorization promptly.`);if(!y.code){let v=y.error?`: ${y.error}`:"";return I(`No authorization code received${v}.
|
|
25
25
|
The IDP may have rejected the authorization request.
|
|
26
26
|
Check the IDP admin console for error details.`)}if(y.state!==h)return I(`Authorization state mismatch \u2014 possible CSRF attack.
|
|
27
27
|
The response did not match the expected session.
|
|
28
|
-
Re-run 'kanonak login ${e}' to start a fresh authorization flow.`);console.log(" Exchanging authorization code for tokens...");let w=await this.exchangeCode(o.tokenEndpoint,d,g,y.code,i,f,
|
|
28
|
+
Re-run 'kanonak login ${e}' to start a fresh authorization flow.`);console.log(" Exchanging authorization code for tokens...");let w=await this.exchangeCode(o.tokenEndpoint,d,g,y.code,i,f,s);if(!w.success)return I(w.error);let b={clientId:d,clientSecret:g,accessToken:w.tokens.accessToken,refreshToken:w.tokens.refreshToken,expiresAt:w.tokens.expiresIn?new Date(Date.now()+w.tokens.expiresIn*1e3).toISOString():null,tokenEndpoint:o.tokenEndpoint,dpopKeyPair:s};return await this.credentialStore.store(e,b),console.log(` Successfully authenticated with ${e}`),a&&console.log(" DPoP proof-of-possession is active"),{success:!0,host:e}}async refresh(e){let t=await this.credentialStore.getCredential(e);if(!t)return I(`No stored credentials for '${e}'. Run 'kanonak login ${e}' to authenticate first.`);if(!t.refreshToken)return I(`No refresh token available for '${e}'.
|
|
29
29
|
The authorization server may not issue refresh tokens for this client.
|
|
30
30
|
Run 'kanonak login ${e}' to re-authenticate.`);if(!t.clientId)return I(`No client ID in stored credentials for '${e}'.
|
|
31
|
-
The stored credential may be corrupted. Run 'kanonak logout ${e}' then 'kanonak login ${e}'.`);let o=t.tokenEndpoint;if(!o){let
|
|
31
|
+
The stored credential may be corrupted. Run 'kanonak logout ${e}' then 'kanonak login ${e}'.`);let o=t.tokenEndpoint;if(!o){let a=await this.discovery.discover(e);if(!a?.tokenEndpoint)return I(`Cannot find token endpoint for '${e}'.
|
|
32
32
|
The OAuth discovery endpoint may be unreachable.
|
|
33
|
-
Check network connectivity and run 'kanonak login ${e}' to re-authenticate.`);o=
|
|
33
|
+
Check network connectivity and run 'kanonak login ${e}' to re-authenticate.`);o=a.tokenEndpoint}let r=await this.refreshTokenRequest(o,t.clientId,t.clientSecret,t.refreshToken,t.dpopKeyPair);return r.success?(t.accessToken=r.tokens.accessToken,r.tokens.refreshToken&&(t.refreshToken=r.tokens.refreshToken),t.expiresAt=r.tokens.expiresIn?new Date(Date.now()+r.tokens.expiresIn*1e3).toISOString():null,t.tokenEndpoint=o,await this.credentialStore.store(e,t),{success:!0,host:e}):I(`${r.error}
|
|
34
34
|
The refresh token may have expired. Run 'kanonak login ${e}' to re-authenticate.`)}async logout(e){let t=await this.credentialStore.getCredential(e);if(!t)return I(`No stored credentials for '${e}'.
|
|
35
|
-
You may not be logged in, or credentials may be stored in a different backend.`);let o=await this.discovery.discover(e);if(o?.revocationEndpoint&&t.accessToken&&t.clientId)try{await this.revokeToken(o.revocationEndpoint,t.accessToken,t.clientId)}catch{console.warn(` Warning: Token revocation failed for '${e}'. The token has been removed locally but may still be valid on the server until it expires.`)}return await this.credentialStore.remove(e),{success:!0,host:e}}async registerClient(e,t){let o;try{o=await fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({client_name:"Kanonak CLI",redirect_uris:[t],grant_types:["authorization_code","refresh_token"],response_types:["code"],token_endpoint_auth_method:"none"})})}catch(
|
|
35
|
+
You may not be logged in, or credentials may be stored in a different backend.`);let o=await this.discovery.discover(e);if(o?.revocationEndpoint&&t.accessToken&&t.clientId)try{await this.revokeToken(o.revocationEndpoint,t.accessToken,t.clientId)}catch{console.warn(` Warning: Token revocation failed for '${e}'. The token has been removed locally but may still be valid on the server until it expires.`)}return await this.credentialStore.remove(e),{success:!0,host:e}}async registerClient(e,t){let o;try{o=await fetch(e,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify({client_name:"Kanonak CLI",redirect_uris:[t],grant_types:["authorization_code","refresh_token"],response_types:["code"],token_endpoint_auth_method:"none"})})}catch(s){return{success:!1,error:`Dynamic client registration request to ${e} failed: ${z(s)}
|
|
36
36
|
Ensure the IDP is reachable and HTTPS is properly configured.
|
|
37
|
-
If using a corporate proxy or custom CA, set NODE_EXTRA_CA_CERTS.`}}if(!o.ok){let
|
|
37
|
+
If using a corporate proxy or custom CA, set NODE_EXTRA_CA_CERTS.`}}if(!o.ok){let s=await $e(o);return{success:!1,error:`Dynamic client registration (RFC 7591) failed.
|
|
38
38
|
Endpoint: ${e}
|
|
39
|
-
HTTP ${o.status}: ${
|
|
39
|
+
HTTP ${o.status}: ${s}
|
|
40
40
|
The IDP may not support dynamic registration for public clients.
|
|
41
|
-
Ask your IDP administrator to enable RFC 7591 support, or pre-register a client manually.`}}let r=await o.json(),
|
|
42
|
-
The IDP response may be malformed. Contact your IDP administrator.`}}async exchangeCode(e,t,o,r,s,
|
|
41
|
+
Ask your IDP administrator to enable RFC 7591 support, or pre-register a client manually.`}}let r=await o.json(),a=r.client_id;return a?{success:!0,clientId:a,clientSecret:r.client_secret}:{success:!1,error:`Dynamic client registration response from ${e} did not contain a client_id.
|
|
42
|
+
The IDP response may be malformed. Contact your IDP administrator.`}}async exchangeCode(e,t,o,r,a,s,i){let c=new URLSearchParams({grant_type:"authorization_code",client_id:t,code:r,redirect_uri:a,code_verifier:s});o&&c.set("client_secret",o);let l={"Content-Type":"application/x-www-form-urlencoded"};if(i)try{l.DPoP=un(i.privateKey,i.publicKey,"POST",e)}catch(p){return{success:!1,error:`Failed to create DPoP proof for token exchange: ${z(p)}
|
|
43
43
|
The stored key pair may be corrupted. Run 'kanonak login' to re-authenticate.`}}let u;try{u=await fetch(e,{method:"POST",headers:l,body:c.toString()})}catch(p){return{success:!1,error:`Token exchange request to ${e} failed: ${z(p)}
|
|
44
|
-
Ensure the token endpoint is reachable.`}}if(!u.ok){let p=await $e(u),d=
|
|
44
|
+
Ensure the token endpoint is reachable.`}}if(!u.ok){let p=await $e(u),d=Do(p);return{success:!1,error:`Token exchange failed.
|
|
45
45
|
Endpoint: ${e}
|
|
46
46
|
HTTP ${u.status}: ${p}`+(d?`
|
|
47
|
-
${d}`:"")}}return{success:!0,tokens:pn(await u.json())}}async refreshTokenRequest(e,t,o,r,
|
|
47
|
+
${d}`:"")}}return{success:!0,tokens:pn(await u.json())}}async refreshTokenRequest(e,t,o,r,a){let s=new URLSearchParams({grant_type:"refresh_token",client_id:t,refresh_token:r});o&&s.set("client_secret",o);let i={"Content-Type":"application/x-www-form-urlencoded"};if(a)try{i.DPoP=un(a.privateKey,a.publicKey,"POST",e)}catch(l){return{success:!1,error:`Failed to create DPoP proof for token refresh: ${z(l)}`}}let c;try{c=await fetch(e,{method:"POST",headers:i,body:s.toString()})}catch(l){return{success:!1,error:`Token refresh request to ${e} failed: ${z(l)}`}}if(!c.ok){let l=await $e(c);return{success:!1,error:`Token refresh failed \u2014 HTTP ${c.status}: ${l}`}}return{success:!0,tokens:pn(await c.json())}}async revokeToken(e,t,o){await fetch(e,{method:"POST",headers:{"Content-Type":"application/x-www-form-urlencoded"},body:new URLSearchParams({token:t,client_id:o}).toString()})}};function I(n){return{success:!1,error:n}}function pn(n){return{accessToken:n.access_token,refreshToken:n.refresh_token,expiresIn:typeof n.expires_in=="number"?n.expires_in:void 0}}function z(n){return n instanceof Error?n.message:String(n)}async function $e(n){try{return await n.text()}catch{return"(could not read response body)"}}function Do(n){try{let e=JSON.parse(n);switch(e.error){case"invalid_grant":return"Hint: The authorization code may have expired or already been used. Re-run the login flow.";case"invalid_client":return"Hint: The client credentials were rejected. The client_id may be invalid or the client_secret may be wrong.";case"redirect_uri_mismatch":return"Hint: The redirect_uri does not match what was registered with the IDP.";case"unsupported_grant_type":return"Hint: The IDP does not support authorization_code grants. Contact your IDP administrator.";case"invalid_scope":return"Hint: One or more requested scopes are not allowed. Check the scopes configured on the IDP.";case"use_dpop_nonce":return"Hint: The server requires a DPoP nonce. This should be handled automatically \u2014 please report this as a bug.";default:return e.error_description?`IDP says: ${e.error_description}`:null}}catch{return null}}function To(){return dn(32).toString("base64url")}function Eo(n){return Ro("sha256").update(n).digest("base64url")}function jo(){return dn(16).toString("base64url")}function Ao(n,e,t,o,r,a){let s=new URLSearchParams({client_id:e,response_type:"code",redirect_uri:t,scope:o.join(" "),state:r,code_challenge:a,code_challenge_method:"S256"});return`${n}?${s}`}var Oo=300*1e3;async function No(){return new Promise(n=>{let e=_o((r,a)=>{let s=new URL(r.url,"http://localhost"),i=s.searchParams.get("code")??void 0,c=s.searchParams.get("state")??void 0,l=s.searchParams.get("error")??s.searchParams.get("error_description")??void 0,u=l?Lo(l):null,p=u?`<html><body><h1>Authorization failed</h1><p>${u}</p></body></html>`:"<html><body><h1>Authorization successful!</h1><p>You can close this window.</p></body></html>";a.writeHead(200,{"Content-Type":"text/html"}),a.end(p),t({code:i,state:c,error:l})}),t,o=new Promise(r=>{t=r,setTimeout(()=>{r(null),e.close()},Oo)});e.listen(0,"127.0.0.1",()=>{let r=e.address();n({redirectUri:`http://localhost:${r.port}/callback`,port:r.port,waitForCallback:()=>o,close:()=>e.close()})})})}function Lo(n){return n.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}function Uo(n){try{process.platform==="win32"?ve("cmd",["/c","start","",n]):process.platform==="darwin"?ve("open",[n]):ve("xdg-open",[n])}catch{console.log(" Could not open browser automatically. Please navigate to the URL above manually.")}}import{CredentialStore as Fo}from"@kanonak-protocol/sdk";async function mn(n){try{let e=new A,t=new Fo,r=await new B(e,t).authorize(n);r.success?console.log(`
|
|
48
48
|
Authenticated with ${n}.`):(console.error(`
|
|
49
49
|
Authentication failed:
|
|
50
50
|
${r.error}`),process.exit(1))}catch(e){let t=e instanceof Error?e.message:String(e);console.error(`
|
|
51
51
|
Authentication failed unexpectedly:
|
|
52
52
|
${t}`),console.error(`
|
|
53
|
-
If this persists, see https://github.com/kanonak-protocol for support channels.`),process.exit(1)}}import{CredentialStore as
|
|
53
|
+
If this persists, see https://github.com/kanonak-protocol for support channels.`),process.exit(1)}}import{CredentialStore as Mo}from"@kanonak-protocol/sdk";async function fn(n){try{let e=new A,t=new Mo,r=await new B(e,t).logout(n);r.success?console.log(`Logged out from ${n}.`):(console.error(`
|
|
54
54
|
Logout failed:
|
|
55
55
|
${r.error}`),process.exit(1))}catch(e){let t=e instanceof Error?e.message:String(e);console.error(`
|
|
56
56
|
Logout failed unexpectedly:
|
|
57
|
-
${t}`),process.exit(1)}}import{Command as
|
|
58
|
-
`;function hn(){let n=
|
|
59
|
-
Installed capability "${b}".`),console.log(`Run "kanonak ${b} --help" to get started.`)}async function
|
|
60
|
-
`);for(let[t,o]of e)console.log(` ${t} ${o.publisher}/${o.package_}@${o.version}`)}import{Command as Z}from"commander";import{readFileSync as
|
|
57
|
+
${t}`),process.exit(1)}}import{Command as dr}from"commander";import{KanonakParser as mr,KanonakObjectParser as fr,PublisherIndex as gr,CredentialStore as hr,createAuthenticatedFetch as kr,computeIntegrity as yr}from"@kanonak-protocol/sdk";import{readFileSync as Vo,writeFileSync as Ho,existsSync as zo}from"fs";import{join as Bo}from"path";import gn from"js-yaml";import{getGlobalCachePath as qo}from"@kanonak-protocol/sdk";var Wo=`# This file is generated by Kanonak CLI. Do not edit manually.
|
|
58
|
+
`;function hn(){let n=qo();return Bo(n,"..","capabilities.lock")}function q(){let n=hn();if(!zo(n))return{version:"1",lastUpdated:new Date().toISOString(),capabilities:{}};let e=Vo(n,"utf-8"),t=gn.load(e);return!t||typeof t!="object"||t.version!=="1"?{version:"1",lastUpdated:new Date().toISOString(),capabilities:{}}:{version:"1",lastUpdated:t.lastUpdated??new Date().toISOString(),capabilities:t.capabilities??{}}}function Y(n){n.lastUpdated=new Date().toISOString();let e={};for(let o of Object.keys(n.capabilities).sort())e[o]=n.capabilities[o];n.capabilities=e;let t=gn.dump(n,{lineWidth:-1,sortKeys:!1,quotingType:'"'});Ho(hn(),Wo+t,"utf-8")}import{SingleDocumentRepository as wr}from"@kanonak-protocol/sdk/uri-helpers";import{existsSync as Go,readdirSync as Jo,readFileSync as Yo}from"fs";import{join as kn}from"path";import{KanonakObjectParser as Xo,EmbeddedKanonak as vn,ReferenceKanonak as $n,getGlobalCachePath as Zo}from"@kanonak-protocol/sdk";import{SingleDocumentRepository as Sn}from"@kanonak-protocol/sdk/uri-helpers";import{uriKey as Se,findSubjectsByType as Qo,getStringValue as O,getReferenceUri as Pe,getListValues as Pn}from"@kanonak-protocol/sdk/uri-helpers";var P="kanonak.org",C="capabilities",Ce={publisher:P,package_:C,name:"Capability"},er={publisher:P,package_:C,name:"commandName"},Cn={publisher:P,package_:C,name:"description"},nr={publisher:P,package_:C,name:"managesType"},tr={publisher:P,package_:C,name:"deploymentTarget"},or={publisher:P,package_:C,name:"hasCommand"},rr={publisher:P,package_:C,name:"subcommandName"},sr={publisher:P,package_:C,name:"performs"},ar={publisher:P,package_:C,name:"hasArgument"},ir={publisher:P,package_:C,name:"argumentName"},yn={publisher:P,package_:C,name:"isRequired"},wn={publisher:P,package_:C,name:"isOption"},cr={publisher:P,package_:C,name:"defaultValue"};async function Rn(n,e,t){let o=q(),r=new Xo,a=[],s=!1;for(let[i,c]of Object.entries(o.capabilities)){let l=c,u=n.get(l.publisher,l.package_,l.version);if(!u){let p=await lr(i,l,e,r,t);if(p)console.error(` Healed capability "${i}": ${l.publisher}/${l.package_}@${l.version} \u2192 ${p.entry.publisher}/${p.entry.package_}@${p.entry.version} (package was renamed)`),o.capabilities[i]=p.entry,l=p.entry,u=p.content,s=!0;else{console.error(` WARNING: Cached content missing for capability "${i}" (${l.publisher}/${l.package_}@${l.version}). Reinstall it with: kanonak capability remove ${i} && kanonak capability add ${l.publisher}/${l.package_}`);continue}}try{let p=e.parse(u),d=new Sn(p,t),g=await r.parseKanonaks(d),f=_n(g,l.publisher,l.package_,l.version);f?a.push(f):console.error(` WARNING: No Capability instance found in "${i}" (${l.publisher}/${l.package_}@${l.version})`)}catch(p){console.error(` WARNING: Failed to parse capability "${i}": ${p}`)}}return s&&Y(o),a}async function lr(n,e,t,o,r){let a=kn(Zo(),e.publisher);if(!Go(a))return;let s=[];for(let i of Jo(a)){if(!i.endsWith(".kan.yml"))continue;let c=i.slice(0,-8),l=c.lastIndexOf("@");if(l===-1)continue;let u=c.substring(0,l),p=c.substring(l+1);if(u===e.package_&&p===e.version)continue;let d;try{d=Yo(kn(a,i),"utf-8")}catch{continue}let g;try{let f=t.parse(d),m=new Sn(f,r),h=await o.parseKanonaks(m);g=_n(h,e.publisher,u,p)?.commandName}catch{continue}g===n&&s.push({entry:{publisher:e.publisher,package_:u,version:p,resolved:`kanonak://${e.publisher}/${u}@${p}`,integrity:""},content:d})}if(s.length===1)return s[0]}function _n(n,e,t,o){let r=Qo(n,Ce);if(r.length===0)return;let a=r[0],s=O(a,er)??"",i=O(a,Cn)??"",c=Pe(a,nr),l=Pe(a,tr),u=[];for(let p of Pn(a,or)){let d=ur(p,n);d&&u.push(d)}return{commandName:s,description:i,managesTypeKey:c?Se(c):"",deploymentTargetKey:l?Se(l):"",commands:u,publisher:e,package_:t,version:o}}function ur(n,e){let t;if(n instanceof vn)t=n;else if(n instanceof $n){let c=xn(e,n.subject.publisher,n.subject.package_,n.subject.name);c&&(t=c)}if(!t)return;let o=O(t,rr)??"",r=O(t,Cn)??"",a=Pe(t,sr),s=Pn(t,ar),i=[];for(let c of s){let l=pr(c,e);l&&i.push(l)}return{subcommandName:o,description:r,arguments:i,actionKey:a?Se(a):""}}function pr(n,e){let t;if(n instanceof vn)t=n;else if(n instanceof $n){let c=xn(e,n.subject.publisher,n.subject.package_,n.subject.name);c&&(t=c)}if(!t)return;let o=O(t,ir)??"",r=O(t,yn)==="true"||bn(t,yn)===!0,a=O(t,wn)==="true"||bn(t,wn)===!0,s=O(t,cr),i={argumentName:o,required:r,isOption:a};return s!==void 0&&(i.defaultValue=s),i}function bn(n,e){for(let t of n.statement){let o=t,r=o.predicate;if(r?.subject&&r.subject.publisher===e.publisher&&r.subject.package_===e.package_&&r.subject.name===e.name)return typeof o.object=="boolean"?o.object:void 0}}function xn(n,e,t,o){for(let r of n){if(!("name"in r)||!("namespace"in r))continue;let a=r;if(a.name===o&&!(!a.namespace||typeof a.namespace!="string")&&a.namespace.startsWith(`${e}/${t}@`))return r}}import{findSubjectsByType as br,getStringValue as vr}from"@kanonak-protocol/sdk/uri-helpers";var $r={publisher:P,package_:C,name:"commandName"};function In(){let n=new dr("capability").description("Manage Kanonak CLI capabilities (pluggable command groups)");return n.command("add <package>").description("Install a capability from a Kanonak publisher").action(async e=>{await Sr(e)}),n.command("remove <name>").description("Remove an installed capability").action(async e=>{await Pr(e)}),n.command("list").description("List installed capabilities").action(async()=>{await Cr()}),n}async function Sr(n){let e=T(n);e||(console.error(`Invalid package reference: "${n}"`),console.error("Expected format: {publisher}/{package}[@{version}]"),process.exit(1));let{publisher:t,packageName:o,version:r,instanceName:a}=e;a&&(console.error(`\`kanonak capability add\` installs whole packages \u2014 got an instance suffix "/${a}".`),console.error(`Try: kanonak capability add ${t}/${o}${r?"@"+r:""}`),process.exit(1));let s=new K,i=new mr,c=new fr,l=new hr,u=kr(l),p=new gr({fetchFn:u}),d=r??await p.getHighestVersion(t,o);d||(console.error(`Could not resolve version for "${t}/${o}".`),process.exit(1)),console.log(`Installing capability ${t}/${o}@${d}...`);let g=s.get(t,o,d);if(!g){let _=await p.getPackageUrl(t,o,d),D=await u(_,t);if(!D.ok)throw new Error(`Failed to fetch ${_} (${D.status} ${D.statusText})`);g=await D.text(),s.put(t,o,d,g)}let f=i.parse(g),m=await $(process.cwd(),i),h=new wr(f,m),k=await c.parseKanonaks(h),y=br(k,Ce);y.length===0&&(console.error(`Package ${t}/${o}@${d} does not contain a ${P}/${C}/Capability instance.`),process.exit(1));let w=y[0],b=vr(w,$r);b||(console.error(`Capability instance in ${t}/${o}@${d} has no commandName property.`),process.exit(1));let v=q();v.capabilities[b]={publisher:t,package_:o,version:d,resolved:await p.getPackageUrl(t,o,d),integrity:yr(g)},Y(v),console.log(`
|
|
59
|
+
Installed capability "${b}".`),console.log(`Run "kanonak ${b} --help" to get started.`)}async function Pr(n){let e=q();e.capabilities[n]||(console.error(`Capability "${n}" is not installed.`),process.exit(1));let t=e.capabilities[n];delete e.capabilities[n],Y(e),console.log(`Removed capability "${n}" (${t.publisher}/${t.package_}@${t.version}).`)}async function Cr(){let n=q(),e=Object.entries(n.capabilities);if(e.length===0){console.log("No capabilities installed."),console.log("Install one with: kanonak capability add {publisher}/{package}");return}console.log(`Installed capabilities:
|
|
60
|
+
`);for(let[t,o]of e)console.log(` ${t} ${o.publisher}/${o.package_}@${o.version}`)}import{Command as Z}from"commander";import{readFileSync as Rr,writeFileSync as _r,mkdirSync as xr,existsSync as Kn,statSync as Ir}from"fs";import{join as Kr,resolve as Dr}from"path";import{KanonakParser as xe,KanonakObjectParser as Ie,SubjectKanonak as Tr,Reasoner as Er,KanonakVocabulary as jr,makeUriKey as En,pickHighestDocument as Ke,formatVersion as jn}from"@kanonak-protocol/sdk";import{SingleDocumentRepository as X}from"@kanonak-protocol/sdk/uri-helpers";import{findSubjectsByType as Re,findSubjectByUri as Ar}from"@kanonak-protocol/sdk/uri-helpers";import{TX_V3 as Dn}from"@kanonak-protocol/sdk/transformations";import{TransformationRunnerV3 as Or,SUPPORTED_FORMATS_V3 as An}from"@kanonak-protocol/sdk/transformations";import{compileTransformationV3 as De}from"@kanonak-protocol/sdk/transformations";function _e(n){return[...Re(n,Dn.InstanceTransformation),...Re(n,Dn.SetTransformation)]}function On(){let n=new Z("transform").description("Run ontology-driven transformations against Kanonak packages. Transformations are declarative YAML rules (instances of `kanonak.org/transformations/Transformation`) that convert ontology instances into output files. The runner produces one or more Artifacts per matched input; format backends serialize them to Markdown, HTML, SVG, TOML, JSON, or (with post-processing) PDF.").addHelpText("after",`
|
|
61
61
|
Examples:
|
|
62
62
|
|
|
63
63
|
# List every Transformation available in the local workspace
|
|
@@ -95,9 +95,9 @@ Examples:
|
|
|
95
95
|
|
|
96
96
|
# List the registered format backends
|
|
97
97
|
$ kanonak transform formats
|
|
98
|
-
`);return n.addCommand(
|
|
99
|
-
`);throw new Error(`Multiple Transformations named "${
|
|
100
|
-
${d}`)}let c=Array.from(i.values())[0];if(c.length===1)return{transformation:c[0].tx,transformationKanonaks:c[0].kanonaks};let l=new Map(c.map(d=>[d.doc,d])),u=Ke(c.map(d=>d.doc));if(!u.chosen)throw new Error(`Could not select a Transformation version for "${
|
|
98
|
+
`);return n.addCommand(Nr()),n.addCommand(Mr()),n.addCommand(Hr()),n.addCommand(Br()),n}function Nr(){return new Z("run").description("Run a transformation against an input scope and write the resulting Artifacts to disk.").argument("<transformation>","Transformation URI (`publisher/package/name`, optional `@version`) or just the local name if unique in the workspace.").requiredOption("--scope <scope>","Input source \u2014 either a package URI `publisher/package[@version]` (resolved via the local workspace + cache + HTTP tiers) or a file path to a `.kan.yml` document. Repeatable: pass `--scope X --scope Y` to aggregate matching instances across multiple packages, useful for index pages and other cross-package SetTransformations.",Lr,[]).option("--format <name>","OutputFormat name to target (e.g. `markdown-with-frontmatter`, `html`, `svg`, `json`). If omitted and the transformation declares exactly one output, that single format is used.").option("--out <dir>","Directory to write artifacts into.",".").action(async(n,e)=>{try{await Ur(n,e)}catch(t){console.error(`Error: ${t.message}`),process.exit(1)}})}function Lr(n,e){return[...e,n]}async function Ur(n,e){let t=new xe,o=new Ie,r=await $(process.cwd(),t),a=await Nn(n,r,o),{transformation:s,transformationKanonaks:i}=a;console.log(`Transformation: ${ne(s)}`);let c=De(s,i);e.scope.length===0&&(console.error("At least one --scope is required."),process.exit(1));let l=[],u=new Map;for(let y of e.scope){let w=await qr(y,r,t,o);l.push(...w);let b=await Jr(w,c.inputPattern.matchesClass,r);for(let v of b){let _=Yr(v);_&&!u.has(_)&&u.set(_,v)}console.log(`Scope: ${y} \u2014 found ${b.length} instance(s) of ${c.inputPattern.matchesClass.publisher}/${c.inputPattern.matchesClass.package_}/${c.inputPattern.matchesClass.name}`)}let p=[...u.values()],d=l;e.scope.length>1&&console.log(`Total across ${e.scope.length} scope(s): ${p.length} unique instance(s)`),p.length===0&&c.kind==="instance"&&(console.error("No matching input instances across the supplied scope(s). Check the transformation's inputPattern.matchesClass vs. the scope package(s)."),process.exit(1));let g=Fr(c.outputs,e.format);console.log(`Output format: ${g}`);let f=An[g];if(!f)throw new Error(`Unknown format "${g}". Run \`kanonak transform formats\` to see what the runner supports.`);let h=await new Or().run({transformation:s,instances:p,allKanonaks:d,transformationKanonaks:i,repository:r,parser:t,objectParser:o,outputFormat:g}),k=Dr(e.out);xr(k,{recursive:!0});for(let y of h){let w=Gr(y.fileName),b=Kr(k,`${w}${f.extension}`);_r(b,y.content,"utf-8"),console.log(` wrote ${b}`)}console.log(`Done. ${h.length} artifact(s) written to ${k}`)}function Fr(n,e){if(e){if(!n.has(e))throw new Error(`Transformation does not declare --format "${e}" in its outputs. Declared outputs: ${Array.from(n).sort().join(", ")}`);return e}if(n.size===1)return Array.from(n)[0];throw new Error(`Transformation supports multiple output formats (${Array.from(n).sort().join(", ")}); pass --format <name> to select one.`)}function Mr(){return new Z("list").description("Scan the local workspace + cache for every Transformation instance and print a one-line summary per hit.").action(async()=>{try{await Vr()}catch(n){console.error(`Error: ${n.message}`),process.exit(1)}})}async function Vr(){let n=new xe,e=new Ie,t=await $(process.cwd(),n),o=await t.getAllDocumentsAsync(),r=new Map;for(let s of o)try{let i=new X(s,t),c=await e.parseKanonaks(i),l=_e(c);for(let u of l){let p=Te(u);if(!p)continue;let d=r.get(p)??[];d.push({tx:u,kanonaks:c,doc:s}),r.set(p,d)}}catch{}let a=[];for(let s of r.values()){if(s.length===1){a.push(Tn(s[0].tx,s[0].kanonaks));continue}let i=Ke(s.map(l=>l.doc));if(!i.chosen)continue;let c=s.find(l=>l.doc===i.chosen);c&&a.push(Tn(c.tx,c.kanonaks))}if(a.length===0){console.log("No Transformation instances found in the current workspace.");return}a.sort((s,i)=>s.uri.localeCompare(i.uri));for(let s of a)console.log(`${s.uri}`),console.log(` matches: ${s.matchesClass}`),console.log(` outputs: ${s.outputs.join(", ")}`)}function Hr(){return new Z("show").description("Compile a transformation and print a human-readable summary (input pattern, outputs, format overrides, rule shape).").argument("<transformation>","Transformation URI or local name").action(async n=>{try{await zr(n)}catch(e){console.error(`Error: ${e.message}`),process.exit(1)}})}async function zr(n){let e=new xe,t=new Ie,o=await $(process.cwd(),e),{transformation:r,transformationKanonaks:a}=await Nn(n,o,t),s=De(r,a);if(console.log(`Transformation: ${ne(r)}`),console.log(),console.log("Input pattern:"),console.log(` Matches class: ${ee(s.inputPattern.matchesClass)}`),s.inputPattern.requires.length>0){console.log(" Required properties:");for(let i of s.inputPattern.requires)console.log(` - ${ee(i)}`)}else console.log(" Required properties: (none)");if(console.log(),console.log(`Outputs: ${Array.from(s.outputs).sort().join(", ")}`),console.log(),s.overrides.size>0){console.log("Format overrides:");for(let[i,c]of s.overrides){if(console.log(` ${i}:`),c.metadataKeys&&console.log(` metadata keys: ${c.metadataKeys.join(", ")}`),c.metadataRenames.size>0){let l=[];for(let[u,p]of c.metadataRenames)l.push(`${u} \u2192 ${p}`);console.log(` metadata renames: ${l.join(", ")}`)}c.trailingNewline!==void 0&&console.log(` trailing newline: ${c.trailingNewline}`)}console.log()}console.log(`Rule root kind: ${s.rule.kind}`),s.rule.kind==="build-ast-node"&&(console.log(`Rule root AST class: ${ee(s.rule.astClass)}`),console.log(`Rule root bindings: ${s.rule.set.length} field(s)`)),console.log(`Artifact name root kind: ${s.artifactName.kind}`)}function Br(){return new Z("formats").description("List the OutputFormat names the runner can serialize to.").action(()=>{console.log("Registered format backends:");let n=Object.entries(An).sort(([e],[t])=>e.localeCompare(t));for(let[e,t]of n)console.log(` ${e.padEnd(28)} ${t.extension.padEnd(6)} ${t.formatUri}`)})}async function Nn(n,e,t){let o,r,a;if(n.includes("/")){let d=n.indexOf("@"),g=n;if(d!==-1){let m=n.indexOf("/",d);if(m===-1)throw new Error(`Transformation URI "${n}" has @version but no trailing /<name>`);g=n.substring(0,d)+n.substring(m)}let f=g.split("/");if(f.length<3)throw new Error(`Invalid transformation URI "${n}" \u2014 expected publisher/package/name or publisher/package@version/name`);o=f[0],r=f[1],a=f.slice(2).join("/")}else a=n;if(o&&r){let d=await e.getDocumentsByNamespaceAsync(o,r);if(d.length===0)throw new Error(`Package ${o}/${r} not found in the local workspace or cache.`);let g=Wr(n),f=Ln(d,g,`${o}/${r}`),m=new X(f,e),h=await t.parseKanonaks(m),k=Ar(h,{publisher:o,package_:r,name:a,version:""});if(!k){let y=_e(h),w=y.find(b=>b.name===a);if(!w)throw new Error(`Transformation "${a}" not found in package ${o}/${r}. Package contains ${y.length} Transformation(s): ${y.map(b=>b.name).join(", ")||"(none)"}`);return{transformation:w,transformationKanonaks:h}}return{transformation:k,transformationKanonaks:h}}let s=await e.getAllDocumentsAsync(),i=new Map;for(let d of s)try{let g=new X(d,e),f=await t.parseKanonaks(g),m=_e(f);for(let h of m){if(h.name!==a)continue;let k=Te(h);if(!k)continue;let y=i.get(k)??[];y.push({tx:h,kanonaks:f,doc:d}),i.set(k,y)}}catch{}if(i.size===0)throw new Error(`No Transformation named "${a}" found in the workspace. Try \`kanonak transform list\` to see available transformations.`);if(i.size>1){let d=Array.from(i.keys()).sort().join(`
|
|
99
|
+
`);throw new Error(`Multiple Transformations named "${a}" in the workspace \u2014 disambiguate with a full publisher/package/name URI:
|
|
100
|
+
${d}`)}let c=Array.from(i.values())[0];if(c.length===1)return{transformation:c[0].tx,transformationKanonaks:c[0].kanonaks};let l=new Map(c.map(d=>[d.doc,d])),u=Ke(c.map(d=>d.doc));if(!u.chosen)throw new Error(`Could not select a Transformation version for "${a}".`);let p=l.get(u.chosen);if(u.multipleVersionsPresent){let d=m=>{let h=m.metadata.namespace_?.version;return h?jn(h):""},g=p.tx.namespace??"",f=g.includes("@")?g.substring(0,g.indexOf("@")):g;console.warn(`Warning: Transformation "${a}" has ${c.length} versions present (${c.map(m=>d(m.doc)).filter(Boolean).join(", ")}); using @${d(u.chosen)}. Pin with ${f}@<version>/${a} to suppress this warning.`)}return{transformation:p.tx,transformationKanonaks:p.kanonaks}}async function qr(n,e,t,o){if(/^[.\/\\]/.test(n)||/^[A-Za-z]:/.test(n)||n.endsWith(".kan.yml")||Kn(n)&&Ir(n).isFile()){if(!Kn(n))throw new Error(`Scope file not found: ${n}`);let f=Rr(n,"utf-8"),m=t.parse(f),h=new X(m,e);return o.parseKanonaks(h)}let a=n.indexOf("@"),s=a===-1?n:n.substring(0,a),i=a===-1?void 0:n.substring(a+1),c=s.indexOf("/");if(c===-1)throw new Error(`Invalid scope "${n}" \u2014 expected a file path or publisher/package[@version] URI`);let l=s.substring(0,c),u=s.substring(c+1),p=await e.getDocumentsByNamespaceAsync(l,u);if(p.length===0)throw new Error(`Scope package ${l}/${u} not found in the local workspace or cache.`);let d=Ln(p,i,`${l}/${u}`),g=new X(d,e);return o.parseKanonaks(g)}function Wr(n){let e=n.indexOf("@");if(e===-1)return;let t=n.substring(e+1),o=t.indexOf("/");return o===-1?t:t.substring(0,o)}function Ln(n,e,t){let o=a=>{let s=a.metadata.namespace_?.version;return s?jn(s):""},r=Ke(n,{requestedVersion:e});if(r.exactRequestedVersionMissing){let a=n.map(o).filter(Boolean).sort().join(", ");throw new Error(`${t}@${e} not found in the local workspace or cache. Available versions: ${a||"(none with parseable namespace)"}`)}if(!r.chosen)throw new Error(`${t} not found in the local workspace or cache.`);return!e&&r.multipleVersionsPresent&&console.warn(`Warning: ${t} has ${n.length} versions present (${n.map(o).filter(Boolean).join(", ")}); using @${o(r.chosen)}. Pin with ${t}@<version> to suppress this warning.`),r.chosen}function Tn(n,e){try{let t=De(n,e);return{uri:ne(n),matchesClass:ee(t.inputPattern.matchesClass),outputs:Array.from(t.outputs).sort()}}catch(t){return{uri:ne(n),matchesClass:`(compile error: ${t.message})`,outputs:[]}}}function ne(n){let e=n.namespace||"",t=e.indexOf("@");return`${t===-1?e:e.substring(0,t)}/${n.name}`}function ee(n){return`${n.publisher}/${n.package_}/${n.name}`}function Gr(n){return n.replace(/[\\/:*?"<>|\s]+/g,"_").replace(/^_+|_+$/g,"")}async function Jr(n,e,t){let o=new Map;for(let s of n){if(!(s instanceof Tr))continue;let i=Te(s);i&&o.set(i,s)}let r=[];try{r=(await new Er({vocabulary:new jr}).reason(t)).getInstancesOfClass(En(e.publisher,e.package_,e.name))}catch{}let a=[];for(let s of r){let i=o.get(s);i&&a.push(i)}return a.length>0?a:Re(n,e)}function Te(n){let e=n.namespace??"",t=e.indexOf("@"),o=t===-1?e:e.substring(0,t),r=o.indexOf("/");return r===-1||!n.name?null:En(o.substring(0,r),o.substring(r+1),n.name)}function Yr(n){let e=n.namespace??"";return!e||!n.name?null:`${e}/${n.name}`}import{Command as Xr}from"commander";import{writeFileSync as Zr,mkdirSync as Qr}from"fs";import{join as es,resolve as ns}from"path";import{KanonakParser as ts,KanonakObjectParser as os,SubjectKanonak as Mn,findDerivation as rs}from"@kanonak-protocol/sdk";import{TransformationRunnerV3 as ss}from"@kanonak-protocol/sdk/transformations";var as={publisher:"kanonak.org",package_:"formats",name:"html"},is={publisher:"kanonak.org",package_:"derivation",name:"default"},cs={html:".html",markdown:".md",json:".json",yaml:".yaml",xml:".xml",svg:".svg",typescript:".ts","c-sharp":".cs",rust:".rs",python:".py"};function ls(n){return n==="markdown"?"markdown-with-frontmatter":n}function Vn(){return new Xr("derive").description("Materialize a derived artifact from a Kanonak resource by walking the polymorphic derivation discovery: instance overrides \u2192 class hierarchy \u2192 universal defaults. The result is written to disk.").argument("<resource>","Resource URI in the form publisher/package[@version]/name. Identifies the specific instance to derive.").option("--format <name>","Format instance name (e.g. html, markdown, json). Defaults to html.","html").option("--variant <name>","Variant instance name (e.g. default, compact, summary). Defaults to default.","default").option("--out <dir>","Directory to write the artifact into.",".").addHelpText("after",`
|
|
101
101
|
Examples:
|
|
102
102
|
|
|
103
103
|
# Render a resource as HTML using whatever derivation the discovery
|
|
@@ -108,7 +108,7 @@ Examples:
|
|
|
108
108
|
|
|
109
109
|
# Materialize the JSON view (universal default unless overridden).
|
|
110
110
|
$ kanonak derive my-publisher.com/my-package/my-resource --format json
|
|
111
|
-
`).action(async(n,e)=>{try{await
|
|
111
|
+
`).action(async(n,e)=>{try{await us(n,e)}catch(t){console.error(`Error: ${t.message}`),process.exit(1)}})}async function us(n,e){let t=T(n);if(!t||!t.instanceName)throw new Error(`Invalid resource URI "${n}". Expected publisher/package[@version]/instance.`);let o=new ts,r=new os,a=await $(process.cwd(),o),s=await r.parseKanonaks(a),i=ps(s,t);if(!i)throw new Error(`Resource ${t.publisher}/${t.packageName}${t.version?`@${t.version}`:""}/${t.instanceName} not found in the workspace or cache.`);console.log(`Resource: ${Un(i)}`);let c=ms(e.format),l=fs(e.variant),u=rs(i,c,l,s);if(!u)throw new Error(`No derivation found for resource ${Un(i)} at (format=${e.format}, variant=${e.variant}). The class hierarchy declares no binding and no universal default applies.`);console.log(`Derivation: ${gs(u)} \u2192 ${Fn(u.transformation)}`);let p=ds(s,u.transformation);if(!p)throw new Error(`Transformation ${Fn(u.transformation)} not found in the workspace or cache. The binding pointed at a transformation the resolver cannot locate.`);let d=ls(e.format),f=await new ss().run({transformation:p,instances:[i],allKanonaks:s,repository:a,parser:o,objectParser:r,outputFormat:d}),m=ns(e.out);Qr(m,{recursive:!0});let h=cs[e.format]??"";for(let k of f){let y=hs(k.fileName),w=es(m,`${y}${h}`);Zr(w,k.content,"utf-8"),console.log(` wrote ${w}`)}console.log(`Done. ${f.length} artifact(s) written to ${m}`)}function ps(n,e){for(let t of n){if(!(t instanceof Mn)||t.name!==e.instanceName)continue;let o=t.namespace||"",r=`${e.publisher}/${e.packageName}@`;if(o.startsWith(r))if(e.version){if(o===`${e.publisher}/${e.packageName}@${e.version}`)return t}else return t}}function ds(n,e){let t=`${e.publisher}/${e.package_}@${e.version}`;for(let o of n)if(o instanceof Mn&&o.name===e.name&&o.namespace===t)return o}function ms(n){if(n.includes("/")){let e=T(n);if(!e||!e.instanceName)throw new Error(`Invalid --format URI "${n}".`);return{publisher:e.publisher,package_:e.packageName,name:e.instanceName}}return{...as,name:n}}function fs(n){if(n.includes("/")){let e=T(n);if(!e||!e.instanceName)throw new Error(`Invalid --variant URI "${n}".`);return{publisher:e.publisher,package_:e.packageName,name:e.instanceName}}return{...is,name:n}}function Un(n){return`${n.namespace}/${n.name}`}function Fn(n){return`${n.publisher}/${n.package_}@${n.version}/${n.name}`}function gs(n){return n.source==="instance"?"instance override":`class ${n.source.publisher}/${n.source.package_}/${n.source.name}`}function hs(n){return n.replace(/[^a-zA-Z0-9._@-]+/g,"_")}import{Command as ks}from"commander";import{writeFileSync as ys}from"fs";import{join as ws,resolve as bs}from"path";import{KanonakParser as vs,ViewMaterializer as $s,LockAwareRepository as Ss,loadLockFile as Ps}from"@kanonak-protocol/sdk";function Hn(){let n=new ks("view").description("Run and materialize Views \u2014 the producer-agnostic query primitive. A View selects instances of its bind class, filters by its where predicates, and projects each into its produces output class.");return n.command("run").description("Materialize a view.View against the local catalog into an EphemeralPackage (content-addressed, versionless). Prints the result as .kan.yml, or writes it with --out.").argument("<view>","View URI in the form publisher/package[@version]/name. May name a view.View directly or a view.ViewPackage (its rootView is followed).").option("--out <file>","Write the EphemeralPackage to this file instead of stdout.").option("--id <id>","Record a per-invocation id on the result (provenance, not identity).").addHelpText("after",`
|
|
112
112
|
Examples:
|
|
113
113
|
|
|
114
114
|
# Materialize a published view and print the EphemeralPackage.
|
|
@@ -116,29 +116,29 @@ Examples:
|
|
|
116
116
|
|
|
117
117
|
# Write the result to a file.
|
|
118
118
|
$ kanonak view run example.org/authors/AuthorView --out ./result.kan.yml
|
|
119
|
-
`).action(async(e,t)=>{try{await
|
|
120
|
-
${
|
|
119
|
+
`).action(async(e,t)=>{try{await Cs(e,t)}catch(o){console.error(`Error: ${o.message}`),process.exit(1)}}),n}async function Cs(n,e){let t=T(n);if(!t||!t.instanceName)throw new Error(`Invalid view URI "${n}". Expected publisher/package[@version]/name.`);let o=new vs,r=await $(process.cwd(),o),a=Ps(ws(process.cwd(),"kanonak.lock")),s=a?new Ss(r,a):r,i=new $s(s,o),c={resolvedAt:new Date().toISOString()};e.id&&(c.invocationId=e.id);let l=await i.materialize({publisher:t.publisher,package_:t.packageName,name:t.instanceName},c);if(e.out){let u=bs(e.out);ys(u,l.yaml,"utf-8"),console.error(`Materialized ${l.rowCount} result(s) \u2192 ${u}
|
|
120
|
+
${l.publisher}/${l.packageName} (${l.contentHash})`)}else process.stdout.write(l.yaml)}import{Command as Rs}from"commander";import{writeFileSync as x,mkdirSync as L}from"fs";import{join as S,resolve as zn,dirname as _s}from"path";import{SubjectKanonak as xs}from"@kanonak-protocol/sdk";import{loadServerModel as Is,route as Ks}from"@kanonak-protocol/sdk/server";function Bn(){return new Rs("publish").description("Generate a static Kanonak site from the local workspace \u2014 the same origin `kanonak serve` produces (it shares serve's model + renderer), frozen to disk under --out.").option("--workspace <dir>","Workspace directory containing .kan.yml package files. Defaults to current directory.",process.cwd()).option("--out <dir>","Output directory for the generated site. Defaults to _site.","_site").option("--publisher <domain>","Publisher to publish (required only if the workspace has more than one).").action(async n=>{await Ds(n)})}async function Ds(n){let e=zn(n.workspace),t=zn(n.out),o=await Is(e,{...n.publisher?{publisher:n.publisher}:{},log:console.log}),{catalog:r,lookRenderer:a,localNamespaces:s,rawByNsKey:i,publisher:c}=o;o.renderStack.warnings.length>0&&console.error(`[render-stack] \u2717 ${o.renderStack.warnings.length} problem(s) \u2014 the published site will render unstyled or incomplete. Run \`kanonak serve\` and open /.well-known/kanonak-render to diagnose.`),L(t,{recursive:!0}),console.log(`Publishing ${c} \u2014 ${s.size} package version(s) to ${t}`);let l=r.filter(f=>f instanceof xs&&s.has(f.namespace||""));console.log(`Rendering ${l.length} resource(s).`);let u=0,p=0;for(let f of l){let m=(f.namespace||"").split("/")[1]??"",[h,k]=m.split("@");if(!h||!k)continue;let y=S(t,h,k);L(y,{recursive:!0});try{let w=a.renderRawMarkdown(f);w!==void 0&&(x(S(y,`${f.name}.md`),w,"utf-8"),u+=1),x(S(y,`${f.name}.html`),await a.renderDocument(f),"utf-8"),x(S(y,`${f.name}.css`),a.renderStylesheet(f),"utf-8"),x(S(y,`${f.name}.svg`),await a.renderSvg(f),"utf-8"),u+=3}catch(w){console.warn(` ${f.namespace}/${f.name}: ${w.message}`),p+=1}}console.log(`Done. ${u} artifact(s) written, ${p} skipped.`);let d=await Es(t,l,a);console.log(`Wrote ${d} package overview page(s).`),await js(t,l,a);let g=As(t,l);console.log(`Wrote ${g} version-form redirect stub(s).`),await Ts(t,o)}async function Ts(n,e){if(e.rawByNsKey.size===0)return;let t=async(o,r)=>{let a=S(n,r);L(_s(a),{recursive:!0}),x(a,(await Ks(e,o)).body,"utf-8")};await t("/.well-known/kanonak.json",".well-known/kanonak.json"),await t("/index.txt","index.txt");for(let o of e.rawByNsKey.keys()){let[r,a]=o.split("@");!r||!a||await t(`/${r}/${a}.kan.yml`,`${r}/${a}.kan.yml`)}console.log(`Wrote publisher endpoints: index.txt, .well-known/kanonak.json, and ${e.rawByNsKey.size} raw package source(s).`)}async function Es(n,e,t){let o=new Map,r=new Map;for(let i of e){let c=i.namespace||"",[,l]=c.split("/");if(!l)continue;let[u,p]=l.split("@");if(!u||!p||i.name!==u)continue;let d=p.split(".").map(Number);if(d.length!==3||d.some(m=>Number.isNaN(m)))continue;let g={verStr:p,major:d[0],minor:d[1],patch:d[2]};o.has(u)||o.set(u,[]),o.get(u).push({resource:i,ver:g});let f=r.get(u);(!f||g.major>f.ver.major||g.major===f.ver.major&&g.minor>f.ver.minor||g.major===f.ver.major&&g.minor===f.ver.minor&&g.patch>f.ver.patch)&&r.set(u,{resource:i,ver:g})}let a=async(i,c)=>{try{return L(i,{recursive:!0}),x(S(i,"index.html"),await t.renderDocument(c),"utf-8"),x(S(i,`${c.name}.css`),t.renderStylesheet(c),"utf-8"),!0}catch{return!1}},s=0;for(let[i,c]of o)for(let{resource:l,ver:u}of c)await a(S(n,i,u.verStr),l)&&(s+=1);for(let[i,{resource:c}]of r){let l=S(n,i);try{if(L(l,{recursive:!0}),t.hasDeclaredView(c))x(S(l,"index.html"),await t.renderDocument(c,{bareOverview:!0}),"utf-8"),x(S(l,`${c.name}.css`),t.renderStylesheet(c),"utf-8");else{let u=(o.get(i)??[]).slice().sort((p,d)=>d.ver.major-p.ver.major||d.ver.minor-p.ver.minor||d.ver.patch-p.ver.patch).map(p=>p.ver.verStr);x(S(l,"index.html"),t.renderPackageVersionList(i,u,c),"utf-8"),x(S(l,`${c.name}.css`),t.renderStylesheet(c),"utf-8")}s+=1}catch{}}return s}async function js(n,e,t){let o="",r=new Map;for(let s of e){let c=(s.namespace||"").split("/"),[l]=(c[1]??"").split("@");if(!c[0]||!l||(o||(o=c[0]),s.name!==l))continue;let u=(c[1]??"").split("@")[1]??"",p=u.split(".").map(Number);if(p.length!==3||p.some(f=>Number.isNaN(f)))continue;let d={verStr:u,major:p[0],minor:p[1],patch:p[2]},g=r.get(l);(!g||d.major>g.ver.major||d.major===g.ver.major&&d.minor>g.ver.minor||d.major===g.ver.major&&d.minor===g.ver.minor&&d.patch>g.ver.patch)&&r.set(l,{resource:s,ver:d})}if(!o||r.size===0)return;let a=t.publisherSubject(o);x(S(n,"index.html"),await t.renderDocument(a,{rootIndex:!0}),"utf-8"),x(S(n,"index.css"),t.renderStylesheet(a),"utf-8")}function As(n,e){let t=new Map;for(let r of e){let a=r.namespace||"",[,s]=a.split("/");if(!s)continue;let[i,c]=s.split("@");if(!i||!c)continue;let l=c.split(".").map(Number);if(l.length!==3||l.some(p=>Number.isNaN(p)))continue;let u=`${i}/${r.name}`;t.has(u)||t.set(u,[]),t.get(u).push({verStr:c,major:l[0],minor:l[1],patch:l[2]})}let o=0;for(let[r,a]of t){let[s,i]=r.split("/");a.sort((p,d)=>d.major-p.major||d.minor-p.minor||d.patch-p.patch);let c=a[0];x(S(n,s,`${i}.html`),Ee(`/${s}/${c.verStr}/${i}`),"utf-8"),o+=1;let l=new Set;for(let p of a){if(l.has(p.major))continue;l.add(p.major);let d=S(n,s,String(p.major));L(d,{recursive:!0}),x(S(d,`${i}.html`),Ee(`/${s}/${p.verStr}/${i}`),"utf-8"),o+=1}let u=new Set;for(let p of a){let d=`${p.major}.${p.minor}`;if(u.has(d))continue;u.add(d);let g=S(n,s,d);L(g,{recursive:!0}),x(S(g,`${i}.html`),Ee(`/${s}/${p.verStr}/${i}`),"utf-8"),o+=1}}return o}function Ee(n){let e=n.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""");return`<!doctype html>
|
|
121
121
|
<meta charset="utf-8">
|
|
122
122
|
<title>Redirecting\u2026</title>
|
|
123
123
|
<meta http-equiv="refresh" content="0; url=${e}">
|
|
124
124
|
<link rel="canonical" href="${e}">
|
|
125
125
|
<p>If you are not redirected automatically, follow this <a href="${e}">link</a>.</p>
|
|
126
|
-
`}import{Command as Yn}from"commander";import{writeFileSync as je,mkdirSync as te}from"fs";import{join as Ae,resolve as Ta,dirname as Oe}from"path";import{KanonakParser as Ea,KanonakObjectParser as ja,SubjectKanonak as Xn,ReferenceStatement as Aa,ReferenceKanonak as Oa,ListStatement as Na,StringStatement as Zn,EmbeddedStatement as La,findDerivation as qn}from"@kanonak-protocol/sdk";import{SingleDocumentRepository as Ua}from"@kanonak-protocol/sdk/uri-helpers";import{TransformationRunnerV3 as Fa}from"@kanonak-protocol/sdk/transformations";import{findSubjectsByType as oe}from"@kanonak-protocol/sdk/uri-helpers";var E="kanonak.org",j="site",Wn={publisher:"kanonak.org",package_:"formats",name:"html"},Gn={publisher:"kanonak.org",package_:"derivation",name:"default"};function Qn(){let n=new Yn("site").description("Materialize a publisher's site \u2014 every StaticPage and AggregateView in the workspace gets rendered to its declared output path under the --out directory.");return n.addCommand(Ma()),n}function Ma(){return new Yn("build").description("Walk the workspace, find every StaticPage and AggregateView, and write each materialized artifact to its declared output path under the --out directory.").option("--out <dir>","Output base directory.","./_site").action(async n=>{try{await Va(n)}catch(e){console.error(`Error: ${e.message}`),process.exit(1)}})}async function Va(n){let e=new Ea,t=new ja,o=await $(process.cwd(),e),r=await t.parseKanonaks(o),s=Ta(n.out);te(s,{recursive:!0});let a=await o.getAllDocumentsAsync(),i=new Set;for(let m of a){let h=m.metadata.namespace_?.toString();h&&i.add(h)}let c={publisher:E,package_:j,name:"StaticPage"},l={publisher:E,package_:j,name:"ResourcePage"},u={publisher:E,package_:j,name:"AggregateView"},p=oe(r,c).filter(m=>i.has(m.namespace||"")),d=oe(r,l).filter(m=>i.has(m.namespace||"")),g=oe(r,u).filter(m=>i.has(m.namespace||""));console.log(`Found ${p.length} StaticPage(s), ${d.length} ResourcePage(s), and ${g.length} AggregateView(s) in the workspace.`);let f=new Fa;for(let m of p){let h=Ne(m,E,j,"outputPath")??`${m.name}.html`,k=qn(m,Wn,Gn,r);if(!k){console.warn(` [skip] ${m.name}: no HTML/default derivation found (check class hierarchy or universal-derivations is loaded)`);continue}let y=Le(r,k.transformation);if(!y){console.warn(` [skip] ${m.name}: transformation ${Ue(k.transformation)} not found`);continue}let w=await f.run({transformation:y,instances:[m],allKanonaks:r,repository:o,parser:e,objectParser:t,outputFormat:"html"});if(w.length===0){console.warn(` [skip] ${m.name}: transformation produced no artifacts`);continue}let b=Ae(s,h);te(Oe(b),{recursive:!0}),je(b,w[0].content,"utf-8"),console.log(` wrote ${b} (StaticPage ${m.name})`)}for(let m of d){let h=Ne(m,E,j,"outputPath")??`${m.name}.html`,k=Jn(m,E,j,"pageOf");if(!k){console.warn(` [skip] ${m.name}: no pageOf declared`);continue}let y=r.find(D=>D instanceof Xn&&D.name===k.name&&(D.namespace||"").startsWith(`${k.publisher}/${k.package_}@`));if(!y){console.warn(` [skip] ${m.name}: pageOf target ${k.publisher}/${k.package_}/${k.name} not found`);continue}let w=qn(y,Wn,Gn,r);if(!w){console.warn(` [skip] ${m.name}: no derivation for target ${y.name}`);continue}let b=Le(r,w.transformation);if(!b){console.warn(` [skip] ${m.name}: transformation ${Ue(w.transformation)} not found`);continue}let v=await f.run({transformation:b,instances:[y],allKanonaks:r,repository:o,parser:e,objectParser:t,outputFormat:"html"});if(v.length===0){console.warn(` [skip] ${m.name}: transformation produced no artifacts`);continue}let _=Ae(s,h);te(Oe(_),{recursive:!0}),je(_,v[0].content,"utf-8"),console.log(` wrote ${_} (ResourcePage ${m.name} \u2192 ${y.name})`)}for(let m of g){let h=Ne(m,E,j,"outputPath");if(!h){console.warn(` [skip] ${m.name}: no outputPath declared`);continue}let k=Jn(m,E,j,"scopeClass");if(!k){console.warn(` [skip] ${m.name}: no scopeClass declared`);continue}let y={publisher:k.publisher,package_:k.package_,name:k.name},w=Ha(m,E,j,"scopeSources"),b=za(m);if(!b){console.warn(` [skip] ${m.name}: no transformation declared`);continue}let v=Le(r,b);if(!v){console.warn(` [skip] ${m.name}: transformation ${Ue(b)} not found`);continue}let _=await qa(w,o),D=[],Xe=new Set;for(let qt of _){let Wt=await Wa(qt,o,e,t),Gt=oe(Wt,y);for(let ye of Gt){let Qe=`${ye.namespace}/${ye.name}`;Xe.has(Qe)||(Xe.add(Qe),D.push(ye))}}console.log(` ${m.name}: ${D.length} instance(s) of ${y.publisher}/${y.package_}/${y.name} across ${_.length} scope(s)`);let Ze=await f.run({transformation:v,instances:D,allKanonaks:r,repository:o,parser:e,objectParser:t,outputFormat:"html"});if(Ze.length===0){console.warn(` [skip] ${m.name}: transformation produced no artifacts`);continue}let ke=Ae(s,h);te(Oe(ke),{recursive:!0}),je(ke,Ze[0].content,"utf-8"),console.log(` wrote ${ke} (AggregateView ${m.name})`)}console.log("Site build complete.")}function Ne(n,e,t,o){for(let r of n.statement)if(r instanceof Zn&&re(r,e,t,o))return r.object}function Ha(n,e,t,o){for(let r of n.statement){if(!(r instanceof Na)||!re(r,e,t,o))continue;let s=[];for(let a of r.object??[]){let i=a.value;typeof i=="string"&&s.push(i)}return s}return[]}function Jn(n,e,t,o){for(let r of n.statement)if(r instanceof Aa&&re(r,e,t,o)&&r.object instanceof Oa)return{publisher:r.object.subject.publisher,package_:r.object.subject.package_,name:r.object.subject.name}}function za(n){for(let e of n.statement)if(e instanceof La&&re(e,E,j,"transformation"))return Ba(e.object)}function Ba(n){let e,t,o,r;for(let s of n.statement){if(!(s instanceof Zn))continue;let a=s.predicate?.subject?.name;a==="publisher"?e=s.object:a==="package"?t=s.object:a==="version"?o=s.object:a==="name"&&(r=s.object)}if(!(!e||!t||!o||!r))return{publisher:e,package_:t,version:o,name:r}}function re(n,e,t,o){let r=n.predicate?.subject;return r?r.publisher===e&&r.package_===t&&r.name===o:!1}function Le(n,e){let t=`${e.publisher}/${e.package_}@${e.version}`;for(let o of n)if(o instanceof Xn&&o.name===e.name&&o.namespace===t)return o}function Ue(n){return`${n.publisher}/${n.package_}@${n.version}/${n.name}`}async function qa(n,e){let t=[];for(let o of n){let r=o.indexOf("@*");if(r===-1){t.push(o);continue}let s=o.substring(0,r),a=s.indexOf("/");if(a===-1){t.push(o);continue}let i=s.substring(0,a),c=s.substring(a+1),l=await e.getDocumentsByNamespaceAsync(i,c);for(let u of l){let p=u.metadata.namespace_;if(!p)continue;let d=p.version;t.push(`${p.publisher}/${p.package_}@${d.major}.${d.minor}.${d.patch}`)}}return t}async function Wa(n,e,t,o){let r=n.indexOf("/"),s=n.indexOf("@");if(r===-1||s===-1)return[];let a=n.substring(0,r),i=n.substring(r+1,s),c=n.substring(s+1),l=await e.getDocumentsByNamespaceAsync(a,i);for(let u of l){let p=u.metadata.namespace_?.version;if(p&&`${p.major}.${p.minor}.${p.patch}`===c){let d=new Ua(u,e);return o.parseKanonaks(d)}}return[]}import{Command as Ga}from"commander";import{createServer as et}from"http";import{watch as nt}from"fs";import{resolve as Ja}from"path";import{loadServerModel as tt,route as Ya,RequestRouter as Xa}from"@kanonak-protocol/sdk/server";var Fe={"Access-Control-Allow-Origin":"*"};function ot(n,e){n.writeHead(e.status,{...e.headers,...Fe}),n.end(e.body)}function rt(){return new Ga("serve").description("Serve Kanonak resources as a live origin \u2014 the same rendering `kanonak publish` produces, plus the machine-facing publisher endpoints, from one process. With --publisher it serves that single publisher (closed world, like the published site); without it, it serves any publisher per request path and links across publishers (open world). Use --watch for a dev preview.").option("--root <dir>","Workspace root to serve.",".").option("--port <number>","Port to listen on.","8080").option("--publisher <domain>","Serve ONLY this publisher (closed world \u2014 no links to other publishers, mirroring the published site). Omit for the open-world model.").option("--watch","Re-load on .kan.yml changes.",!1).action(async n=>{let e=Ja(n.root),t=Number(n.port);if(!Number.isInteger(t)||t<=0||t>65535)throw new Error(`Invalid --port "${n.port}".`);if(n.publisher){let o;try{o=await tt(e,{publisher:n.publisher})}catch(r){console.error(`[error] ${r.message}`),process.exitCode=1;return}Za(e,t,n,o)}else Qa(e,t,n)})}function Za(n,e,t,o){let r=o,s=async a=>{let i=Date.now();r=await tt(n,t.publisher?{publisher:t.publisher}:{});let c=r.availablePublishers.filter(l=>l!==r.publisher);console.log(`[model] serving ${r.publisher} \u2014 ${r.pkgVersions.size} package(s)${a?` (${a})`:""} in ${Date.now()-i}ms`+(c.length?` [also in workspace: ${c.join(", ")} \u2014 switch with --publisher]`:""))};if(t.watch){let a;nt(n,{recursive:!0},(i,c)=>{!c||!String(c).endsWith(".kan.yml")||(clearTimeout(a),a=setTimeout(()=>{s(`changed: ${c}`).catch(l=>console.error("[reload error]",l.message))},150))}),console.log("[watch] re-loading on .kan.yml changes")}et(async(a,i)=>{let c="/";try{let l=new URL(a.url??"/","http://localhost");c=decodeURIComponent(l.pathname);let u=await Ya(r,c,a.headers.accept??"");ot(i,u),console.log(`${u.status} ${a.method} ${c}${u.headers.Location?` -> ${u.headers.Location}`:""}`)}catch(l){i.writeHead(500,{"Content-Type":"text/plain; charset=utf-8",...Fe}),i.end(String(l?.stack??l)),console.error(`500 ${c}: ${l?.message??l}`)}}).listen(e,()=>{console.log(`kanonak origin server \u2192 http://localhost:${e}/ (root=${n}, publisher=${r.publisher})`)})}function Qa(n,e,t){let o=new Xa({root:n});if(t.watch){let r;nt(n,{recursive:!0},(s,a)=>{!a||!String(a).endsWith(".kan.yml")||(clearTimeout(r),r=setTimeout(()=>{o.clearCache(),console.log("[watch] cleared model cache")},150))}),console.log("[watch] clearing model cache on .kan.yml changes")}et(async(r,s)=>{let a="/";try{let i=new URL(r.url??"/","http://localhost");a=decodeURIComponent(i.pathname);let c=await o.handle(a,r.headers.accept??"");ot(s,c),console.log(`${c.status} ${r.method} ${a}${c.headers.Location?` -> ${c.headers.Location}`:""}`)}catch(i){s.writeHead(502,{"Content-Type":"text/plain; charset=utf-8",...Fe}),s.end(String(i?.message??i)),console.error(`502 ${a}: ${i?.message??i}`)}}).listen(e,()=>{console.log(`kanonak request-driven origin \u2192 http://localhost:${e}/ (root=${n})`),console.log("[request-driven] no publisher pinned \u2014 derive per path: /{publisher}/{package}/{version}/{resource}")})}import{Command as es}from"commander";import{resolve as ns,join as ts}from"path";import{loadLockFile as os,computeIntegrity as Me}from"@kanonak-protocol/sdk";function at(){return new es("verify").description("Verify cached packages against kanonak.lock (the cache is untrusted). With --remote, also re-fetch each package from its origin and compare. Exits non-zero on any integrity mismatch.").option("--workspace <dir>","Workspace directory containing kanonak.lock.",process.cwd()).option("--remote","Also re-fetch each package from its recorded origin and verify.",!1).action(async n=>{await as(n)})}function rs(n){let e=n.indexOf("/");if(!(e<0))return{publisher:n.slice(0,e),package_:n.slice(e+1)}}async function as(n){let e=ns(n.workspace),t=os(ts(e,"kanonak.lock"));t||(console.error(`No kanonak.lock found in ${e} \u2014 nothing to verify (run \`kanonak install\` first).`),process.exit(1));let o=new K,r=Object.entries(t.packages);console.log(`Verifying ${r.length} locked package(s) against kanonak.lock${n.remote?" (cache + origin)":" (cache)"}\u2026`);let s=0,a=0,i=0,c=0;for(let[u,p]of r){let d=rs(u);if(!d){console.error(` \u2717 ${u} \u2014 unparseable lock key`),a+=1;continue}let{publisher:g,package_:f}=d,m=o.get(g,f,p.version);if(m===null?(console.warn(` ? ${u} \u2014 not in cache`),i+=1):Me(m)===p.integrity?s+=1:(console.error(` \u2717 ${u} \u2014 CACHE does not match lock`),console.error(` lock: ${p.integrity}`),console.error(` cache: ${Me(m)}`),a+=1),n.remote){let h=await ss(u,p);h?(console.error(h),a+=1):c+=1}}let l=[`${s} cache OK`];n.remote&&l.push(`${c} origin OK`),i&&l.push(`${i} not cached`),l.push(`${a} mismatch`),console.log(`
|
|
127
|
-
${l.join(", ")}.`),
|
|
126
|
+
`}import{Command as Yn}from"commander";import{writeFileSync as je,mkdirSync as te}from"fs";import{join as Ae,resolve as Os,dirname as Oe}from"path";import{KanonakParser as Ns,KanonakObjectParser as Ls,SubjectKanonak as Xn,ReferenceStatement as Us,ReferenceKanonak as Fs,ListStatement as Ms,StringStatement as Zn,EmbeddedStatement as Vs,findDerivation as qn}from"@kanonak-protocol/sdk";import{SingleDocumentRepository as Hs}from"@kanonak-protocol/sdk/uri-helpers";import{TransformationRunnerV3 as zs}from"@kanonak-protocol/sdk/transformations";import{findSubjectsByType as oe}from"@kanonak-protocol/sdk/uri-helpers";var E="kanonak.org",j="site",Wn={publisher:"kanonak.org",package_:"formats",name:"html"},Gn={publisher:"kanonak.org",package_:"derivation",name:"default"};function Qn(){let n=new Yn("site").description("Materialize a publisher's site \u2014 every StaticPage and AggregateView in the workspace gets rendered to its declared output path under the --out directory.");return n.addCommand(Bs()),n}function Bs(){return new Yn("build").description("Walk the workspace, find every StaticPage and AggregateView, and write each materialized artifact to its declared output path under the --out directory.").option("--out <dir>","Output base directory.","./_site").action(async n=>{try{await qs(n)}catch(e){console.error(`Error: ${e.message}`),process.exit(1)}})}async function qs(n){let e=new Ns,t=new Ls,o=await $(process.cwd(),e),r=await t.parseKanonaks(o),a=Os(n.out);te(a,{recursive:!0});let s=await o.getAllDocumentsAsync(),i=new Set;for(let m of s){let h=m.metadata.namespace_?.toString();h&&i.add(h)}let c={publisher:E,package_:j,name:"StaticPage"},l={publisher:E,package_:j,name:"ResourcePage"},u={publisher:E,package_:j,name:"AggregateView"},p=oe(r,c).filter(m=>i.has(m.namespace||"")),d=oe(r,l).filter(m=>i.has(m.namespace||"")),g=oe(r,u).filter(m=>i.has(m.namespace||""));console.log(`Found ${p.length} StaticPage(s), ${d.length} ResourcePage(s), and ${g.length} AggregateView(s) in the workspace.`);let f=new zs;for(let m of p){let h=Ne(m,E,j,"outputPath")??`${m.name}.html`,k=qn(m,Wn,Gn,r);if(!k){console.warn(` [skip] ${m.name}: no HTML/default derivation found (check class hierarchy or universal-derivations is loaded)`);continue}let y=Le(r,k.transformation);if(!y){console.warn(` [skip] ${m.name}: transformation ${Ue(k.transformation)} not found`);continue}let w=await f.run({transformation:y,instances:[m],allKanonaks:r,repository:o,parser:e,objectParser:t,outputFormat:"html"});if(w.length===0){console.warn(` [skip] ${m.name}: transformation produced no artifacts`);continue}let b=Ae(a,h);te(Oe(b),{recursive:!0}),je(b,w[0].content,"utf-8"),console.log(` wrote ${b} (StaticPage ${m.name})`)}for(let m of d){let h=Ne(m,E,j,"outputPath")??`${m.name}.html`,k=Jn(m,E,j,"pageOf");if(!k){console.warn(` [skip] ${m.name}: no pageOf declared`);continue}let y=r.find(D=>D instanceof Xn&&D.name===k.name&&(D.namespace||"").startsWith(`${k.publisher}/${k.package_}@`));if(!y){console.warn(` [skip] ${m.name}: pageOf target ${k.publisher}/${k.package_}/${k.name} not found`);continue}let w=qn(y,Wn,Gn,r);if(!w){console.warn(` [skip] ${m.name}: no derivation for target ${y.name}`);continue}let b=Le(r,w.transformation);if(!b){console.warn(` [skip] ${m.name}: transformation ${Ue(w.transformation)} not found`);continue}let v=await f.run({transformation:b,instances:[y],allKanonaks:r,repository:o,parser:e,objectParser:t,outputFormat:"html"});if(v.length===0){console.warn(` [skip] ${m.name}: transformation produced no artifacts`);continue}let _=Ae(a,h);te(Oe(_),{recursive:!0}),je(_,v[0].content,"utf-8"),console.log(` wrote ${_} (ResourcePage ${m.name} \u2192 ${y.name})`)}for(let m of g){let h=Ne(m,E,j,"outputPath");if(!h){console.warn(` [skip] ${m.name}: no outputPath declared`);continue}let k=Jn(m,E,j,"scopeClass");if(!k){console.warn(` [skip] ${m.name}: no scopeClass declared`);continue}let y={publisher:k.publisher,package_:k.package_,name:k.name},w=Ws(m,E,j,"scopeSources"),b=Gs(m);if(!b){console.warn(` [skip] ${m.name}: no transformation declared`);continue}let v=Le(r,b);if(!v){console.warn(` [skip] ${m.name}: transformation ${Ue(b)} not found`);continue}let _=await Ys(w,o),D=[],Xe=new Set;for(let Wt of _){let Gt=await Xs(Wt,o,e,t),Jt=oe(Gt,y);for(let ye of Jt){let Qe=`${ye.namespace}/${ye.name}`;Xe.has(Qe)||(Xe.add(Qe),D.push(ye))}}console.log(` ${m.name}: ${D.length} instance(s) of ${y.publisher}/${y.package_}/${y.name} across ${_.length} scope(s)`);let Ze=await f.run({transformation:v,instances:D,allKanonaks:r,repository:o,parser:e,objectParser:t,outputFormat:"html"});if(Ze.length===0){console.warn(` [skip] ${m.name}: transformation produced no artifacts`);continue}let ke=Ae(a,h);te(Oe(ke),{recursive:!0}),je(ke,Ze[0].content,"utf-8"),console.log(` wrote ${ke} (AggregateView ${m.name})`)}console.log("Site build complete.")}function Ne(n,e,t,o){for(let r of n.statement)if(r instanceof Zn&&re(r,e,t,o))return r.object}function Ws(n,e,t,o){for(let r of n.statement){if(!(r instanceof Ms)||!re(r,e,t,o))continue;let a=[];for(let s of r.object??[]){let i=s.value;typeof i=="string"&&a.push(i)}return a}return[]}function Jn(n,e,t,o){for(let r of n.statement)if(r instanceof Us&&re(r,e,t,o)&&r.object instanceof Fs)return{publisher:r.object.subject.publisher,package_:r.object.subject.package_,name:r.object.subject.name}}function Gs(n){for(let e of n.statement)if(e instanceof Vs&&re(e,E,j,"transformation"))return Js(e.object)}function Js(n){let e,t,o,r;for(let a of n.statement){if(!(a instanceof Zn))continue;let s=a.predicate?.subject?.name;s==="publisher"?e=a.object:s==="package"?t=a.object:s==="version"?o=a.object:s==="name"&&(r=a.object)}if(!(!e||!t||!o||!r))return{publisher:e,package_:t,version:o,name:r}}function re(n,e,t,o){let r=n.predicate?.subject;return r?r.publisher===e&&r.package_===t&&r.name===o:!1}function Le(n,e){let t=`${e.publisher}/${e.package_}@${e.version}`;for(let o of n)if(o instanceof Xn&&o.name===e.name&&o.namespace===t)return o}function Ue(n){return`${n.publisher}/${n.package_}@${n.version}/${n.name}`}async function Ys(n,e){let t=[];for(let o of n){let r=o.indexOf("@*");if(r===-1){t.push(o);continue}let a=o.substring(0,r),s=a.indexOf("/");if(s===-1){t.push(o);continue}let i=a.substring(0,s),c=a.substring(s+1),l=await e.getDocumentsByNamespaceAsync(i,c);for(let u of l){let p=u.metadata.namespace_;if(!p)continue;let d=p.version;t.push(`${p.publisher}/${p.package_}@${d.major}.${d.minor}.${d.patch}`)}}return t}async function Xs(n,e,t,o){let r=n.indexOf("/"),a=n.indexOf("@");if(r===-1||a===-1)return[];let s=n.substring(0,r),i=n.substring(r+1,a),c=n.substring(a+1),l=await e.getDocumentsByNamespaceAsync(s,i);for(let u of l){let p=u.metadata.namespace_?.version;if(p&&`${p.major}.${p.minor}.${p.patch}`===c){let d=new Hs(u,e);return o.parseKanonaks(d)}}return[]}import{Command as Zs}from"commander";import{createServer as nt}from"http";import{watch as tt}from"fs";import{resolve as Qs}from"path";import{loadServerModel as ot,route as ea,RequestRouter as na}from"@kanonak-protocol/sdk/server";var Fe={"Access-Control-Allow-Origin":"*"};function rt(n,e){n.writeHead(e.status,{...e.headers,...Fe}),n.end(e.body)}function et(n,e){let t=n.renderStack,o=t.packages.filter(r=>r.origin==="missing").length;t.warnings.length===0?console.log(`[render-stack] \u2713 all ${t.packages.length} look-stack package(s) resolved \u2014 pages will render styled`):(console.error(`[render-stack] \u2717 ${t.warnings.length} problem(s)`+(o>0?` (${o} package(s) missing)`:"")+" \u2014 pages may render unstyled or incomplete"),console.error(`[render-stack] diagnose: http://localhost:${e}/.well-known/kanonak-render`))}function st(){return new Zs("serve").description("Serve Kanonak resources as a live origin \u2014 the same rendering `kanonak publish` produces, plus the machine-facing publisher endpoints, from one process. With --publisher it serves that single publisher (closed world, like the published site); without it, it serves any publisher per request path and links across publishers (open world). Use --watch for a dev preview.").option("--root <dir>","Workspace root to serve.",".").option("--port <number>","Port to listen on.","8080").option("--publisher <domain>","Serve ONLY this publisher (closed world \u2014 no links to other publishers, mirroring the published site). Omit for the open-world model.").option("--watch","Re-load on .kan.yml changes.",!1).action(async n=>{let e=Qs(n.root),t=Number(n.port);if(!Number.isInteger(t)||t<=0||t>65535)throw new Error(`Invalid --port "${n.port}".`);if(n.publisher){let o;try{o=await ot(e,{publisher:n.publisher,log:console.log})}catch(r){console.error(`[error] ${r.message}`),process.exitCode=1;return}ta(e,t,n,o)}else oa(e,t,n)})}function ta(n,e,t,o){let r=o;et(r,e);let a=async s=>{let i=Date.now();r=await ot(n,{...t.publisher?{publisher:t.publisher}:{},log:console.log});let c=r.availablePublishers.filter(l=>l!==r.publisher);console.log(`[model] serving ${r.publisher} \u2014 ${r.pkgVersions.size} package(s)${s?` (${s})`:""} in ${Date.now()-i}ms`+(c.length?` [also in workspace: ${c.join(", ")} \u2014 switch with --publisher]`:"")),et(r,e)};if(t.watch){let s;tt(n,{recursive:!0},(i,c)=>{!c||!String(c).endsWith(".kan.yml")||(clearTimeout(s),s=setTimeout(()=>{a(`changed: ${c}`).catch(l=>console.error("[reload error]",l.message))},150))}),console.log("[watch] re-loading on .kan.yml changes")}nt(async(s,i)=>{let c="/";try{let l=new URL(s.url??"/","http://localhost");c=decodeURIComponent(l.pathname);let u=await ea(r,c,s.headers.accept??"");rt(i,u),console.log(`${u.status} ${s.method} ${c}${u.headers.Location?` -> ${u.headers.Location}`:""}`)}catch(l){i.writeHead(500,{"Content-Type":"text/plain; charset=utf-8",...Fe}),i.end(String(l?.stack??l)),console.error(`500 ${c}: ${l?.message??l}`)}}).listen(e,()=>{console.log(`kanonak origin server \u2192 http://localhost:${e}/ (root=${n}, publisher=${r.publisher})`),console.log(`render diagnostics \u2192 http://localhost:${e}/.well-known/kanonak-render`)})}function oa(n,e,t){let o=new na({root:n,log:console.log});if(t.watch){let r;tt(n,{recursive:!0},(a,s)=>{!s||!String(s).endsWith(".kan.yml")||(clearTimeout(r),r=setTimeout(()=>{o.clearCache(),console.log("[watch] cleared model cache")},150))}),console.log("[watch] clearing model cache on .kan.yml changes")}nt(async(r,a)=>{let s="/";try{let i=new URL(r.url??"/","http://localhost");s=decodeURIComponent(i.pathname);let c=await o.handle(s,r.headers.accept??"");rt(a,c),console.log(`${c.status} ${r.method} ${s}${c.headers.Location?` -> ${c.headers.Location}`:""}`)}catch(i){a.writeHead(502,{"Content-Type":"text/plain; charset=utf-8",...Fe}),a.end(String(i?.message??i)),console.error(`502 ${s}: ${i?.message??i}`)}}).listen(e,()=>{console.log(`kanonak request-driven origin \u2192 http://localhost:${e}/ (root=${n})`),console.log("[request-driven] no publisher pinned \u2014 derive per path: /{publisher}/{package}/{version}/{resource}"),console.log("[request-driven] render diagnostics per publisher: /{publisher}/.well-known/kanonak-render")})}import{Command as ra}from"commander";import{resolve as sa,join as aa}from"path";import{loadLockFile as ia,computeIntegrity as Me}from"@kanonak-protocol/sdk";function at(){return new ra("verify").description("Verify cached packages against kanonak.lock (the cache is untrusted). With --remote, also re-fetch each package from its origin and compare. Exits non-zero on any integrity mismatch.").option("--workspace <dir>","Workspace directory containing kanonak.lock.",process.cwd()).option("--remote","Also re-fetch each package from its recorded origin and verify.",!1).action(async n=>{await la(n)})}function ca(n){let e=n.indexOf("/");if(!(e<0))return{publisher:n.slice(0,e),package_:n.slice(e+1)}}async function la(n){let e=sa(n.workspace),t=ia(aa(e,"kanonak.lock"));t||(console.error(`No kanonak.lock found in ${e} \u2014 nothing to verify (run \`kanonak install\` first).`),process.exit(1));let o=new K,r=Object.entries(t.packages);console.log(`Verifying ${r.length} locked package(s) against kanonak.lock${n.remote?" (cache + origin)":" (cache)"}\u2026`);let a=0,s=0,i=0,c=0;for(let[u,p]of r){let d=ca(u);if(!d){console.error(` \u2717 ${u} \u2014 unparseable lock key`),s+=1;continue}let{publisher:g,package_:f}=d,m=o.get(g,f,p.version);if(m===null?(console.warn(` ? ${u} \u2014 not in cache`),i+=1):Me(m)===p.integrity?a+=1:(console.error(` \u2717 ${u} \u2014 CACHE does not match lock`),console.error(` lock: ${p.integrity}`),console.error(` cache: ${Me(m)}`),s+=1),n.remote){let h=await ua(u,p);h?(console.error(h),s+=1):c+=1}}let l=[`${a} cache OK`];n.remote&&l.push(`${c} origin OK`),i&&l.push(`${i} not cached`),l.push(`${s} mismatch`),console.log(`
|
|
127
|
+
${l.join(", ")}.`),s>0&&(console.error("Integrity verification FAILED \u2014 a package does not match the committed lock."),process.exit(1)),console.log("Integrity verified.")}async function ua(n,e){try{let t=await fetch(e.resolved);if(!t.ok)return` \u2717 ${n} \u2014 origin fetch ${t.status} from ${e.resolved}`;let o=await t.text(),r=Me(o);return r===e.integrity?void 0:` \u2717 ${n} \u2014 ORIGIN does not match lock (${e.resolved})
|
|
128
128
|
lock: ${e.integrity}
|
|
129
|
-
origin: ${r}`}catch(t){return` \u2717 ${n} \u2014 origin fetch failed: ${t.message}`}}import{Command as
|
|
129
|
+
origin: ${r}`}catch(t){return` \u2717 ${n} \u2014 origin fetch failed: ${t.message}`}}import{Command as pa}from"commander";import{resolve as da,join as ma}from"path";import{homedir as fa}from"os";import{readFileSync as ga}from"fs";import{KanonakParser as it,KanonakObjectParser as ha,PublisherIndex as ct,CredentialStore as lt,createAuthenticatedFetch as ut,FileSystemKanonakDocumentRepository as ka,Reasoner as ya,KanonakVocabulary as wa,getGlobalCachePath as ba,makeUriKey as va,resolveDisplayValue as $a,subjectUri as Sa,contextTypesOf as Pa,collectKanonakFiles as Ca}from"@kanonak-protocol/sdk";import{SearchIndex as Ra}from"@kanonak-protocol/sdk/search";function _a(n){let e=n.split("/");if(e.length!==3)return null;let[t,o,r]=e;return!t||!o||!r?null:{publisher:t,package_:o,name:r}}function pt(){return new pa("search").description("Semantic-search your workspace (-q), browse a publisher's catalogue, or find instances of a class").argument("[publisher]","Publisher domain (e.g. kanonak.org) \u2014 for the catalogue / --type modes").option("-q, --query <text>","Semantically search the LOCAL workspace for resources matching free-text keywords").option("--root <dir>","Workspace root for -q",".").option("--scope <prefix>","Limit -q to namespaces starting with this prefix (e.g. kanonak.org/look@)").option("--limit <n>","Max results for -q","20").option("--format <fmt>","Output for -q: text | json","text").option("--all","For -q: index imported packages too (default: only your workspace's own resources)",!1).option("--type <uri>","Class URI to search for, in publisher/package/Name form").action(async(n,e)=>{if(e.query){await xa(e);return}n||(console.error(`Nothing to search. Either:
|
|
130
130
|
\u2022 semantic-search your workspace: kanonak search -q "<keywords>"
|
|
131
131
|
\u2022 browse a publisher's catalogue: kanonak search <publisher>
|
|
132
|
-
\u2022 find instances of a class: kanonak search <publisher> --type <pub>/<pkg>/<Name>`),process.exit(1)),e.type?await
|
|
133
|
-
`)}catch(u){console.error(u.message),process.exit(1)}
|
|
134
|
-
`);for(let u of l)console.log(` ${u.score.toFixed(3)} ${u.label}${u.type?` (${u.type})`:""}`),console.log(` ${u.uri}`)}async function
|
|
135
|
-
`);let
|
|
136
|
-
`),m.sort();for(let h of m)console.log(` ${h}`)}async function Ve(n,e,t,o,r,
|
|
132
|
+
\u2022 find instances of a class: kanonak search <publisher> --type <pub>/<pkg>/<Name>`),process.exit(1)),e.type?await Ka(n,e.type):await Ia(n)})}async function xa(n){let e=da(n.root??"."),t=new it,o;try{let u=await $(e,t);o=await new ha().parseKanonaks(u)}catch(u){console.error(`Failed to load workspace at ${e}: ${u.message}`),process.exit(1)}let r={cacheDir:ma(fa(),".kanonak","search"),onProgress:(u,p)=>process.stderr.write(`\r embedding ${u}/${p}\u2026 `)};if(!n.all){let u=new Set;for(let p of Ca(e))try{let d=t.parse(ga(p,"utf-8")).metadata?.namespace_;d?.version&&u.add(`${d.publisher}/${d.package_}@${d.version.major}.${d.version.minor}.${d.version.patch}`)}catch{}r.include=p=>u.has(p.namespace??"")}let a=new Ra,s;try{s=await a.build(o,r),s.size>0&&!s.cached&&process.stderr.write(`
|
|
133
|
+
`)}catch(u){console.error(u.message),process.exit(1)}s.size===0&&(console.error(n.all?`No resources found in the workspace at ${e}.`:`No resources defined in the workspace at ${e}. (It imports packages but defines none of its own \u2014 use --all to also search imported packages.)`),process.exit(1));let i=Number(n.limit)||20,l=(await a.query(n.query,{scope:n.scope,limit:i})).map(u=>{let p=$a(o,u.subject),d=Sa(u.subject),g=Pa(u.subject)[0]?.name;return{uri:d?`${d.publisher}/${d.package_}/${d.name}`:u.subject.name,label:p.label,type:g??null,score:Number(u.score.toFixed(4))}});if(n.format==="json"){console.log(JSON.stringify(l,null,2));return}if(l.length===0){console.log(`No matches for "${n.query}".`);return}console.log(`Results for "${n.query}":
|
|
134
|
+
`);for(let u of l)console.log(` ${u.score.toFixed(3)} ${u.label}${u.type?` (${u.type})`:""}`),console.log(` ${u.uri}`)}async function Ia(n){let e=new lt,t=ut(e),o=new ct({fetchFn:t}),r;try{r=await o.listLatestPackages(n)}catch(s){console.error(`Failed to fetch publisher index for ${n}: ${s.message}`),process.exit(1)}if(r.length===0){console.log(`No packages found at ${n}.`);return}console.log(`Packages published by ${n}:
|
|
135
|
+
`);let a=r.reduce((s,i)=>Math.max(s,i.packageName.length),0);for(let{packageName:s,version:i}of r)console.log(` ${s.padEnd(a)} @${i}`)}async function Ka(n,e){let t=_a(e);t||(console.error(`Invalid --type value: ${e}`),console.error("Expected: publisher/package/Name (e.g. kanonak.org/capabilities/Capability)"),process.exit(1));let o=new it,r=new lt,a=ut(r),s=new ct({fetchFn:a}),i=new K,c=new Set,l=[];try{l=await s.listLatestPackages(n)}catch(h){console.error(`Failed to fetch publisher index for ${n}: ${h.message}`),process.exit(1)}for(let{packageName:h,version:k}of l)c.add(`${n}|${h}|${k}`);await Ve(s,i,a,"kanonak.org","core-rdf",c),await Ve(s,i,a,"kanonak.org","core-owl",c),await Ve(s,i,a,t.publisher,t.package_,c);for(let h of c){let[k,y,w]=h.split("|");if(!i.has(k,y,w))try{let b=await s.getPackageUrl(k,y,w),v=await a(b,k);if(!v.ok){console.error(`Warning: failed to fetch ${k}/${y}@${w}: ${v.status} ${v.statusText}`);continue}let _=await v.text();i.put(k,y,w,_)}catch(b){console.error(`Warning: failed to fetch ${k}/${y}@${w}: ${b.message}`)}}let u=new ka(ba(),!0,o),d=await new ya({vocabulary:new wa}).reason(u),g=va(t.publisher,t.package_,t.name),m=d.getInstancesOfClass(g).filter(h=>h!==g);if(m.length===0){console.log(`No instances of ${g} found in ${n}'s catalogue.`);return}console.log(`Instances of ${g} in ${n}'s catalogue:
|
|
136
|
+
`),m.sort();for(let h of m)console.log(` ${h}`)}async function Ve(n,e,t,o,r,a){try{let s=await n.getHighestVersion(o,r);if(!s)return;a.add(`${o}|${r}|${s}`)}catch{}}import{existsSync as Da,readFileSync as Ta}from"fs";import{dirname as Ea,join as ja,resolve as Aa}from"path";import{KanonakObjectParser as Oa,KanonakParser as Na,canonicalForm as La,canonicalHash as Ua,parseKanonakAddress as Fa,pickHighestDocument as Ma,loadLockFile as Va,LockAwareRepository as Ha}from"@kanonak-protocol/sdk";import{SingleDocumentRepository as za}from"@kanonak-protocol/sdk/uri-helpers";async function dt(n,e={}){let t=new Na,o=new Oa,{document:r,source:a}=await Ba(n,t),s=Wa(a),i=await $(s,t),c=ja(s,"kanonak.lock"),l=Va(c);if(e.frozen){if(!l)throw new Error(`kanonak hash --frozen: no kanonak.lock found at ${c}. Run 'kanonak install' to generate one.`);qa(r,l,c)}let u=l?new Ha(i,l):i,p=new za(r,u),d=await o.parseKanonaks(p),g=Ua(d);if(console.log(g),e.verbose){let f=La(d);process.stderr.write(`# canonical form for ${a}
|
|
137
137
|
`),process.stderr.write(f),process.stderr.write(`
|
|
138
|
-
`)}}async function
|
|
139
|
-
`);for(let
|
|
140
|
-
Updated ${i} instance(s).`)}async search(e,t){let o=t.publisher??"kanonak.org",r=
|
|
141
|
-
`);let
|
|
142
|
-
`);let f=new Map;for(let m of d){let h=`${m.publisher}/${m.package_}@${m.version}`,k=f.get(h);k?k.push(m):f.set(h,[m])}for(let[m,h]of f){let k=h[0],y=`${k.publisher}/${k.package_}`,w=h.length===1;console.log(` ${m}`),console.log(` ${h.length} skill${w?"":"s"}:`);for(let b of h)console.log(` - ${b.subject.name}`);if(console.log(""),w)console.log(" install:"),console.log(` kanonak ${e.commandName} add ${y}/${k.subject.name}`);else{console.log(" install one of them:");for(let b of h)console.log(` kanonak ${e.commandName} add ${y}/${b.subject.name}`);console.log(" install all of them:"),console.log(` kanonak ${e.commandName} add ${y}`)}console.log("")}}async info(e,t,o){let
|
|
143
|
-
`;function le(n){let e=
|
|
144
|
-
`;function fe(n){let e=
|
|
138
|
+
`)}}async function Ba(n,e){if(n.endsWith(".kan.yml")){let i=Aa(n);if(!Da(i))throw new Error(`kanonak hash: file not found: ${i}`);let c=Ta(i,"utf-8");return{document:e.parse(c),source:i}}let t=Fa(n);if(t.kind!=="package")throw new Error(`kanonak hash: expected a package address (publisher/package[@version]) or a path ending in .kan.yml; got ${t.kind} address "${n}"`);let r=await(await $(process.cwd(),e)).getDocumentsByNamespaceAsync(t.publisher,t.package_);if(r.length===0)throw new Error(`kanonak hash: could not find ${n} in local workspace, global cache, or publisher HTTP`);let a=t.version?`${t.version.major}.${t.version.minor}.${t.version.patch}`:void 0,s=Ma(r,a?{requestedVersion:a}:{});if(!s.chosen){let i=a?`@${a}`:"";throw new Error(`kanonak hash: no version of ${t.publisher}/${t.package_}${i} available across local/cache/HTTP`)}return{document:s.chosen,source:n}}function qa(n,e,t){let o=new Set(["kanonak.org/core-kanonak"]);for(let a of n.metadata.allImports??[])o.add(`${a.publisher??"kanonak.org"}/${a.packageName}`);let r=[...o].filter(a=>!e.packages[a]);if(r.length>0)throw new Error(`kanonak hash --frozen: kanonak.lock (${t}) is missing pins for: ${r.join(", ")}. Run 'kanonak install' to refresh the lock.`)}function Wa(n){return n.endsWith(".kan.yml")?N(Ea(n)):process.cwd()}import{Command as mt}from"commander";function W(n){return`${P}/${C}/${n}`}var He={[W("fetch-and-deploy")]:(n,e,t,o)=>n.add(e,t[0],o),[W("remove-deployed")]:(n,e,t,o)=>n.remove(e,t[0],o),[W("list-deployed")]:(n,e,t,o)=>n.list(e,o),[W("update-deployed")]:(n,e,t,o)=>n.update(e,t[0],o),[W("search-available")]:(n,e,t,o)=>n.search(e,o),[W("show-info")]:(n,e,t,o)=>n.info(e,t[0],o)};function ft(n,e,t){for(let o of e){let r=new mt(o.commandName).description(o.description.trim());for(let a of o.commands){let s=r.command(Ga(a));s.description(a.description);for(let i of a.arguments)if(i.isOption){let c=i.defaultValue!=null?`--${i.argumentName} [value]`:`--${i.argumentName} <value>`;s.option(c,"",i.defaultValue)}s.action(async(...i)=>{let c=Ja(i);await Ya(t,o,a,i,c)})}n.addCommand(r)}}function Ga(n){let e=n.arguments.filter(t=>!t.isOption).map(t=>t.required?`<${t.argumentName}>`:`[${t.argumentName}]`);return[n.subcommandName,...e].join(" ")}function Ja(n){for(let e=n.length-1;e>=0;e--)if(n[e]&&typeof n[e]=="object"&&!(n[e]instanceof mt))return n[e];return{}}async function Ya(n,e,t,o,r){let a=[];for(let i of o)if(typeof i=="string")a.push(i);else break;t.actionKey||(console.error(`Capability subcommand '${t.subcommandName}' has no resolved \`performs:\` Action. Every CapabilityCommand must declare a performs value pointing at a named Action instance from the capabilities ontology. Known actions: ${Object.keys(He).join(", ")}.`),process.exit(1));let s=He[t.actionKey];s||(console.error(`Capability subcommand '${t.subcommandName}' references unknown Action '${t.actionKey}'. Known actions: ${Object.keys(He).join(", ")}.`),process.exit(1)),await s(n,e,a,r)}import{existsSync as gt,readFileSync as Xa,statSync as ht}from"fs";import{resolve as Za}from"path";import{KanonakObjectParser as Qa,PublisherIndex as ze,PublisherConfigResolver as ei,formatVersion as kt,pickHighestDocument as ni}from"@kanonak-protocol/sdk";import{SingleDocumentRepository as yt}from"@kanonak-protocol/sdk/uri-helpers";import{uriKey as G,findSubjectsByType as wt}from"@kanonak-protocol/sdk/uri-helpers";var se=class{constructor(e,t,o,r,a,s){this.fileCache=e;this.parser=t;this.publisherIndex=o;this.fetchFn=r;this.handlerRegistry=a;this.repository=s}fileCache;parser;publisherIndex;fetchFn;handlerRegistry;repository;objectParser=new Qa;async add(e,t,o){let r=this.tryLoadFromLocalFile(t);if(r){this.fileCache.put(r.publisher,r.packageName,r.version,r.content),await this.deployFromDoc(e,r.doc,r.publisher,r.packageName,r.version,void 0,`local file ${t}`,o);return}let a=T(t);a||(console.error(`Invalid package reference: "${t}"`),console.error(""),console.error("Accepted forms:"),console.error(" publisher/package (install all instances, latest version)"),console.error(" publisher/package@version (install all instances, pinned)"),console.error(" publisher/package/instance (install one instance, latest version)"),console.error(" publisher/package@version/instance (install one instance, pinned)"),console.error(" ./path/to/file.kan.yml (install all instances from a local document)"),console.error(""),console.error("Tip: copy a URI directly from `kanonak "+e.commandName+" search`."),process.exit(1));let{publisher:s,packageName:i,version:c,instanceName:l}=a,u=await this.repository.getDocumentsByNamespaceAsync(s,i);if(u.length>0){let g=ni(u,{requestedVersion:c??void 0});if(g.chosen){let f=g.chosen.metadata.namespace_;(!f||!f.version)&&(console.error(`Document for ${s}/${i} is missing namespace metadata.`),process.exit(1));let m=kt(f.version);this.fileCache.put(s,i,m,this.parser.save(g.chosen)),await this.deployFromDoc(e,g.chosen,s,i,m,l??void 0,`${s}/${i}@${m}`,o);return}}let p=c??await this.publisherIndex.getHighestVersion(s,i);p||(console.error(`Could not resolve version for "${s}/${i}".`),await this.printPackageSuggestions(s,i,e.commandName),process.exit(1));let d=this.fileCache.get(s,i,p);if(!d){let g=await this.publisherIndex.getPackageUrl(s,i,p),f=await this.fetchFn(g,s);f.ok||(f.status===404?(console.error(`Package ${s}/${i}@${p} not found at ${g}.`),console.error(`The publisher index lists this version but the file is missing \u2014 it may have been unpublished. Try \`kanonak ${e.commandName} search\` to see the current catalogue.`)):console.error(`Failed to fetch ${g} (${f.status} ${f.statusText}).`),process.exit(1)),d=await f.text(),this.fileCache.put(s,i,p,d)}await this.deployFromDoc(e,this.parser.parse(d),s,i,p,l??void 0,`${s}/${i}@${p}`,o)}tryLoadFromLocalFile(e){if(!(/^[.\/\\]/.test(e)||/^[A-Za-z]:[\\/]/.test(e)||e.endsWith(".kan.yml")||gt(e)&&ht(e).isFile()))return;let o=Za(e);(!gt(o)||!ht(o).isFile())&&(console.error(`Local file not found: ${e}`),process.exit(1));let r=Xa(o,"utf-8"),a=this.parser.parse(r),s=a.metadata.namespace_;return(!s||!s.version)&&(console.error(`${e} has no namespace metadata; cannot determine publisher/package/version. A Kanonak document must declare \`type: Package\` with publisher and version.`),process.exit(1)),{doc:a,content:r,publisher:s.publisher,packageName:s.package_,version:kt(s.version)}}async deployFromDoc(e,t,o,r,a,s,i,c){let l=new yt(t,this.repository),u=await this.objectParser.parseKanonaks(l),p=bt(e.managesTypeKey);p||(console.error(`Capability "${e.commandName}" has no resolved managesType.`),process.exit(1));let d=wt(u,p);d.length===0&&(console.error(`${i} does not contain any ${G(p)} instances.`),process.exit(1));let g=d;if(s&&(g=d.filter(h=>h.name===s),g.length===0)){console.error(`Instance "${s}" not found in ${i}.`),console.error(""),console.error(`Available ${G(p)} instance(s):`);for(let h of d)console.error(` - ${h.name}`);console.error(""),console.error("To install all of them, drop the instance suffix:"),console.error(` kanonak ${e.commandName} add ${o}/${r}`),process.exit(1)}let f=s?`${s} from ${i}`:`${g.length} ${G(p)} instance(s) from ${i}`;console.log(`Installing ${f}...`);let m=this.handlerRegistry.get(e.deploymentTargetKey);m?await m.deploy({instances:g,allKanonaks:u,repository:this.repository,options:c}):console.log(`Cached ${o}/${r}@${a} (no deployment handler for "${e.deploymentTargetKey}")`)}async printPackageSuggestions(e,t,o){let r;try{r=await this.publisherIndex.listLatestPackages(e)}catch{return}let a=r.map(s=>({name:s.packageName,version:s.version,score:ti(t,s.packageName)})).filter(s=>s.score>0).sort((s,i)=>i.score-s.score).slice(0,5);if(a.length!==0){console.error(""),console.error("Did you mean one of:");for(let s of a)console.error(` kanonak ${o} add ${e}/${s.name}`)}}async remove(e,t,o){await this.requireHandler(e).undeploy(t,{repository:this.repository,options:o})}async list(e,t){let r=await this.requireHandler(e).list({repository:this.repository,options:t}),a=e.managesTypeKey||"managed";if(r.length===0){console.log(`No ${a} instances installed.`);return}console.log(`Installed ${a} instances:
|
|
139
|
+
`);for(let s of r){let i=s.publisher?`${s.publisher}/${s.package_}@${s.version}`:"unmanaged";console.log(` ${s.name} (${i}) ${s.path}`)}}async update(e,t,o){let a=await this.requireHandler(e).list({repository:this.repository,options:o}),s=t?a.filter(c=>c.name===t):a.filter(c=>c.publisher);if(s.length===0){console.log(t?`"${t}" not found.`:"No managed instances to update.");return}let i=0;for(let c of s){let l=await this.publisherIndex.getHighestVersion(c.publisher,c.package_);!l||l===c.version||(console.log(`Updating ${c.name}: ${c.version} \u2192 ${l}`),await this.add(e,`${c.publisher}/${c.package_}@${l}`,o),i++)}console.log(i===0?"All instances are up to date.":`
|
|
140
|
+
Updated ${i} instance(s).`)}async search(e,t){let o=t.publisher??"kanonak.org",r=bt(e.managesTypeKey);if(!r){console.error("Capability has no resolved managesType; nothing to search for.");return}console.log(`Searching ${o} for ${G(r)} instances...
|
|
141
|
+
`);let a=new ei,s=await a.getConfig(o),i=a.resolveIndexUrl(o,s),c=await this.fetchFn(i,o);if(!c.ok){console.error(`Failed to fetch package index from ${o}.`);return}let l=await c.text(),u=ze.parseIndex(l);if(u.size===0){console.error(`No packages found for publisher "${o}".`);return}let p=new Map;for(let[m,h]of u){let k=[...h].sort((y,w)=>{let b=ze.parseVersion(y),v=ze.parseVersion(w);return!b||!v?0:b.major!==v.major?v.major-b.major:b.minor!==v.minor?v.minor-b.minor:v.patch-b.patch});p.set(m,k[0])}let d=[],g=0;for(let[m,h]of p){let k=this.fileCache.get(o,m,h);if(!k)try{let y=await this.publisherIndex.getPackageUrl(o,m,h),w=await this.fetchFn(y,o);if(!w.ok)continue;k=await w.text(),this.fileCache.put(o,m,h,k)}catch{continue}try{let y=this.parser.parse(k),w=new yt(y,this.repository),b=await this.objectParser.parseKanonaks(w),v=wt(b,r);for(let _ of v)d.push({publisher:o,package_:m,version:h,subject:_});g++}catch{continue}}if(d.length===0){console.log(`No ${G(r)} instances found across ${g} package(s).`);return}console.log(`Found ${d.length} ${G(r)} instance(s) in ${g} package(s):
|
|
142
|
+
`);let f=new Map;for(let m of d){let h=`${m.publisher}/${m.package_}@${m.version}`,k=f.get(h);k?k.push(m):f.set(h,[m])}for(let[m,h]of f){let k=h[0],y=`${k.publisher}/${k.package_}`,w=h.length===1;console.log(` ${m}`),console.log(` ${h.length} skill${w?"":"s"}:`);for(let b of h)console.log(` - ${b.subject.name}`);if(console.log(""),w)console.log(" install:"),console.log(` kanonak ${e.commandName} add ${y}/${k.subject.name}`);else{console.log(" install one of them:");for(let b of h)console.log(` kanonak ${e.commandName} add ${y}/${b.subject.name}`);console.log(" install all of them:"),console.log(` kanonak ${e.commandName} add ${y}`)}console.log("")}}async info(e,t,o){let s=(await this.requireHandler(e).list({repository:this.repository,options:o})).find(i=>i.name===t);s||(console.error(`"${t}" is not installed.`),process.exit(1)),console.log(`Name: ${s.name}`),console.log(`Type: ${e.managesTypeKey||"n/a"}`),console.log(`Publisher: ${s.publisher||"unmanaged"}`),console.log(`Package: ${s.package_||"n/a"}`),console.log(`Version: ${s.version||"n/a"}`),console.log(`Path: ${s.path}`)}requireHandler(e){let t=this.handlerRegistry.get(e.deploymentTargetKey);return t||(console.error(`No deployment handler registered for "${e.deploymentTargetKey}". Ensure the capability's deploymentTarget resolves to a DeploymentTarget instance whose URI is registered in the CLI at startup.`),process.exit(1)),t}};function bt(n){if(!n)return;let e=n.split("/");if(e.length===3)return{publisher:e[0],package_:e[1],name:e[2]}}function ti(n,e){let t=n.toLowerCase(),o=e.toLowerCase();if(t===o)return 100;if(o.includes(t)||t.includes(o))return 50;let r=new Set(t.split("-").filter(Boolean)),a=new Set(o.split("-").filter(Boolean)),s=0;for(let c of r)a.has(c)&&s++;if(s>0)return s*10;let i=oi(t,o);return i===0?100:i<=2?Math.max(1,20-i*5):0}function oi(n,e){if(n===e)return 0;if(n.length===0)return e.length;if(e.length===0)return n.length;let t=new Array(e.length+1),o=new Array(e.length+1);for(let r=0;r<=e.length;r++)t[r]=r;for(let r=0;r<n.length;r++){o[0]=r+1;for(let a=0;a<e.length;a++){let s=n[r]===e[a]?0:1;o[a+1]=Math.min(o[a]+1,t[a+1]+1,t[a]+s)}for(let a=0;a<=e.length;a++)t[a]=o[a]}return t[e.length]}var ae=class{handlers=new Map;register(e,t){this.handlers.set(e,t)}get(e){return this.handlers.get(e)??null}};import{mkdirSync as gi,rmSync as hi,existsSync as ue,readdirSync as ki,writeFileSync as yi}from"fs";import{join as pe}from"path";import{KanonakObjectParser as wi,KanonakParser as bi,computeIntegrity as vi,compareVersions as $i}from"@kanonak-protocol/sdk";import{findSubjectsByType as Si}from"@kanonak-protocol/sdk/uri-helpers";import{SingleDocumentRepository as Pi}from"@kanonak-protocol/sdk/uri-helpers";import{TransformationRunnerV3 as Ci}from"@kanonak-protocol/sdk/transformations";import{TX_V3 as Ri}from"@kanonak-protocol/sdk/transformations";import{join as Be}from"path";import{homedir as vt}from"os";import{KanonakObjectParser as ri}from"@kanonak-protocol/sdk";import{SingleDocumentRepository as si}from"@kanonak-protocol/sdk/uri-helpers";import{findSubjectsByType as St,getStringValue as ie}from"@kanonak-protocol/sdk/uri-helpers";var U="kanonak.org",F="agent-skills",Pt={publisher:U,package_:F,name:"Client"},Ct={publisher:U,package_:F,name:"clientId"},ai={publisher:U,package_:F,name:"projectSkillDir"},ii={publisher:U,package_:F,name:"userSkillDir"},ci={publisher:U,package_:F,name:"skillFileName"},Rt="agents";async function Q(n,e){let t=(n.client??_t()??Rt).toLowerCase(),o=n.scope??"project",r=await It(t,e);if(!r){let i=await li(e);throw new Error(`Unknown client "${t}". Known clients: ${i.join(", ")||"(none)"}. Add a Client instance to a package that imports kanonak.org/agent-skills and install that package to make it available.`)}let s=ie(r,o==="user"?ii:ai);if(!s)throw new Error(`Client "${t}" has no ${o==="user"?"userSkillDir":"projectSkillDir"} declared.`);return ui(s)}async function ce(n,e,t){let o=await Q(e,t);return Be(o,n)}async function qe(n,e){let t=(n.client??_t()??Rt).toLowerCase(),o=await It(t,e);return o?ie(o,ci)??"SKILL.md":"SKILL.md"}function _t(){if(process.env.CLAUDE_CODE||process.env.CLAUDE_PROJECT_DIR)return"claude-code"}var $t=new WeakMap;async function xt(n){let e=$t.get(n);if(e)return e;let t=await n.getDocumentsByNamespaceAsync(U,F);if(t.length===0)throw new Error(`Could not find ${U}/${F} in the repository. Install a skill capability (which transitively imports agent-skills) or fetch agent-skills directly to populate the cache.`);let r=[...t].sort((c,l)=>{let u=c.metadata.namespace_?.version,p=l.metadata.namespace_?.version;return!u||!p?0:u.major!==p.major?p.major-u.major:u.minor!==p.minor?p.minor-u.minor:p.patch-u.patch})[0],a=new ri,s=new si(r,n),i=await a.parseKanonaks(s);return $t.set(n,i),i}async function It(n,e){let t=await xt(e),o=St(t,Pt);for(let r of o)if(ie(r,Ct)===n)return r}async function li(n){let e=await xt(n),t=St(e,Pt),o=[];for(let r of t){let a=ie(r,Ct);a&&o.push(a)}return o}function ui(n){return n.startsWith("~/")?Be(vt(),n.slice(2)):n==="~"?vt():n.startsWith("/")||/^[A-Za-z]:[\\/]/.test(n)?n:Be(process.cwd(),n)}import{readFileSync as pi,writeFileSync as di,existsSync as mi}from"fs";import{join as Kt}from"path";import Dt from"js-yaml";var Tt="skills.lock",fi=`# This file is generated by Kanonak CLI. Do not edit manually.
|
|
143
|
+
`;function le(n){let e=Kt(n,Tt);if(!mi(e))return{version:"1",lastUpdated:new Date().toISOString(),skills:{}};let t=pi(e,"utf-8"),o=Dt.load(t);return!o||typeof o!="object"||o.version!=="1"?{version:"1",lastUpdated:new Date().toISOString(),skills:{}}:{version:"1",lastUpdated:o.lastUpdated??new Date().toISOString(),skills:o.skills??{}}}function We(n,e){e.lastUpdated=new Date().toISOString();let t={};for(let a of Object.keys(e.skills).sort())t[a]=e.skills[a];e.skills=t;let o=Kt(n,Tt),r=Dt.dump(e,{lineWidth:-1,sortKeys:!1,quotingType:'"'});di(o,fi+r,"utf-8")}var Et="kanonak.org",jt="skill-to-skill-md",de=class{parser=new bi;objectParser=new wi;runner=new Ci;async deploy(e){let{instances:t,allKanonaks:o,repository:r,options:a}=e;if(t.length===0){console.error("No Skill instances to deploy.");return}let s=await _i(r,this.objectParser);if(!s){console.error(`Cannot deploy: ${Et}/${jt}@3.0.0 is not installed in the workspace or cache.`);return}let i=await this.runner.run({transformation:s,instances:t,allKanonaks:o,repository:r,parser:this.parser,objectParser:this.objectParser,outputFormat:"markdown-with-frontmatter"});if(i.length===0){console.error("No skills could be transformed from the package.");return}let c=await Q(a,r),l=await qe(a,r),u=le(c),p=t[0].namespace,{publisher:d,package_:g,version:f}=xi(p);for(let m of i){let h=await ce(m.fileName,a,r),k=ue(pe(h,l));gi(h,{recursive:!0}),yi(pe(h,l),m.content,"utf-8"),u.skills[m.fileName]={publisher:d,package_:g,version:f,resolved:d?`kanonak://${d}/${g}@${f}`:"",integrity:vi(m.content)},console.log(` ${k?"Updated":"Installed"} skill "${m.fileName}" \u2192 ${h}`)}We(c,u)}async undeploy(e,t){let{repository:o,options:r}=t,a=await ce(e,r,o);ue(a)||(console.error(`Skill "${e}" is not installed at ${a}`),process.exit(1)),hi(a,{recursive:!0,force:!0});let s=await Q(r,o),i=le(s);delete i.skills[e],We(s,i),console.log(`Removed skill "${e}" from ${a}`)}async list(e){let{repository:t,options:o}=e,r=await Q(o,t),a=le(r),s=[];for(let[c,l]of Object.entries(a.skills))s.push({name:c,publisher:l.publisher,package_:l.package_,version:l.version,path:await ce(c,o,t)});let i=await qe(o,t);if(ue(r))try{let c=ki(r,{withFileTypes:!0});for(let l of c){if(!l.isDirectory()||a.skills[l.name])continue;let u=pe(r,l.name,i);ue(u)&&s.push({name:l.name,publisher:"",package_:"",version:"",path:pe(r,l.name)})}}catch{}return s}};async function _i(n,e){let t=await n.getDocumentsByNamespaceAsync(Et,jt);if(t.length===0)return;let o=[...t].sort((r,a)=>{let s=r.metadata.namespace_?.version,i=a.metadata.namespace_?.version;return!s||!i?0:$i(i,s)});for(let r of o){let a=new Pi(r,n),s=await e.parseKanonaks(a),i=Si(s,Ri.InstanceTransformation);if(i[0])return i[0]}}function xi(n){if(!n)return{publisher:"",package_:"",version:""};let e=n.indexOf("@");if(e===-1)return{publisher:"",package_:"",version:""};let t=n.substring(0,e),o=n.substring(e+1),r=t.indexOf("/");return r===-1?{publisher:"",package_:"",version:""}:{publisher:t.substring(0,r),package_:t.substring(r+1),version:o}}import{mkdirSync as zi,rmSync as Bi,existsSync as Ye,readdirSync as qi,writeFileSync as Wi,statSync as Gi}from"fs";import{join as ge}from"path";import{KanonakObjectParser as Ji,KanonakParser as Yi,computeIntegrity as Xi}from"@kanonak-protocol/sdk";import{findSubjectsByType as Zi}from"@kanonak-protocol/sdk/uri-helpers";import{SingleDocumentRepository as Qi}from"@kanonak-protocol/sdk/uri-helpers";import{TransformationRunnerV3 as ec}from"@kanonak-protocol/sdk/transformations";import{TX_V3 as nc}from"@kanonak-protocol/sdk/transformations";import{join as At}from"path";import{homedir as Ot}from"os";import{KanonakObjectParser as Ii}from"@kanonak-protocol/sdk";import{SingleDocumentRepository as Ki}from"@kanonak-protocol/sdk/uri-helpers";import{findSubjectsByType as Lt,getStringValue as Ge,getReferenceUri as Di}from"@kanonak-protocol/sdk/uri-helpers";var M="kanonak.org",V="agent-skills",Ut={publisher:M,package_:V,name:"Client"},Ft={publisher:M,package_:V,name:"clientId"},Ti={publisher:M,package_:V,name:"projectAgentDir"},Ei={publisher:M,package_:V,name:"userAgentDir"},ji={publisher:M,package_:V,name:"agentFileFormat"},Ai="agents";function Oi(){if(process.env.CLAUDE_CODE||process.env.CLAUDE_PROJECT_DIR)return"claude-code"}async function me(n,e){let t=(n.client??Oi()??Ai).toLowerCase(),o=n.scope??"project",r=await Ni(t,e);if(!r){let u=await Li(e);throw new Error(`Unknown client "${t}". Known clients: ${u.join(", ")||"(none)"}. Add a Client instance to a package that imports kanonak.org/agent-skills and install that package to make it available.`)}let s=Ge(r,o==="user"?Ei:Ti);if(!s)throw new Error(`Client "${t}" has no ${o==="user"?"userAgentDir":"projectAgentDir"} declared.`);let c=Di(r,ji)?.name==="toml"?"toml":"markdown-frontmatter",l=c==="toml"?".toml":".md";return{agentsDir:Ui(s),format:c,fileExtension:l}}var Nt=new WeakMap;async function Mt(n){let e=Nt.get(n);if(e)return e;let t=await n.getDocumentsByNamespaceAsync(M,V);if(t.length===0)throw new Error(`Could not find ${M}/${V} in the repository. Install a capability that imports agent-skills to populate the cache.`);let r=[...t].sort((c,l)=>{let u=c.metadata.namespace_?.version,p=l.metadata.namespace_?.version;return!u||!p?0:u.major!==p.major?p.major-u.major:u.minor!==p.minor?p.minor-u.minor:p.patch-u.patch})[0],a=new Ii,s=new Ki(r,n),i=await a.parseKanonaks(s);return Nt.set(n,i),i}async function Ni(n,e){let t=await Mt(e),o=Lt(t,Ut);for(let r of o)if(Ge(r,Ft)===n)return r}async function Li(n){let e=await Mt(n),t=Lt(e,Ut),o=[];for(let r of t){let a=Ge(r,Ft);a&&o.push(a)}return o}function Ui(n){return n.startsWith("~/")?At(Ot(),n.slice(2)):n==="~"?Ot():n.startsWith("/")||/^[A-Za-z]:[\\/]/.test(n)?n:At(process.cwd(),n)}import{readFileSync as Fi,writeFileSync as Mi,existsSync as Vi}from"fs";import{join as Vt}from"path";import Ht from"js-yaml";var zt="agents.lock",Hi=`# This file is generated by Kanonak CLI. Do not edit manually.
|
|
144
|
+
`;function fe(n){let e=Vt(n,zt);if(!Vi(e))return{version:"1",lastUpdated:new Date().toISOString(),agents:{}};let t=Fi(e,"utf-8"),o=Ht.load(t);return!o||typeof o!="object"||o.version!=="1"?{version:"1",lastUpdated:new Date().toISOString(),agents:{}}:{version:"1",lastUpdated:o.lastUpdated??new Date().toISOString(),agents:o.agents??{}}}function Je(n,e){e.lastUpdated=new Date().toISOString();let t={};for(let a of Object.keys(e.agents).sort())t[a]=e.agents[a];e.agents=t;let o=Vt(n,zt),r=Ht.dump(e,{lineWidth:-1,sortKeys:!1,quotingType:'"'});Mi(o,Hi+r,"utf-8")}var Bt="kanonak.org",qt="agent-to-agent-file",he=class{parser=new Yi;objectParser=new Ji;runner=new ec;async deploy(e){let{instances:t,allKanonaks:o,repository:r,options:a}=e;if(t.length===0){console.error("No Agent instances to deploy.");return}let{agentsDir:s,format:i,fileExtension:c}=await me(a,r),l=await tc(r,this.objectParser);if(!l){console.error(`Cannot deploy: ${Bt}/${qt}@3.0.0 is not installed in the workspace or cache.`);return}let u=i==="toml"?"toml":"markdown-with-frontmatter",p=await this.runner.run({transformation:l,instances:t,allKanonaks:o,repository:r,parser:this.parser,objectParser:this.objectParser,outputFormat:u});if(p.length===0){console.error("No agents could be transformed from the package.");return}zi(s,{recursive:!0});let d=fe(s),g=t[0].namespace,{publisher:f,package_:m,version:h}=rc(g);for(let k of p){let y=`${k.fileName}${c}`,w=ge(s,y),b=Ye(w);Wi(w,k.content,"utf-8"),d.agents[k.fileName]={publisher:f,package_:m,version:h,resolved:f?`kanonak://${f}/${m}@${h}`:"",integrity:Xi(k.content),fileName:y},console.log(` ${b?"Updated":"Installed"} agent "${k.fileName}" \u2192 ${w}`)}Je(s,d)}async undeploy(e,t){let{repository:o,options:r}=t,{agentsDir:a}=await me(r,o),s=fe(a),i=s.agents[e];i||(console.error(`Agent "${e}" is not installed at ${a}`),process.exit(1));let c=ge(a,i.fileName);Ye(c)&&Bi(c,{force:!0}),delete s.agents[e],Je(a,s),console.log(`Removed agent "${e}" from ${c}`)}async list(e){let{repository:t,options:o}=e,{agentsDir:r}=await me(o,t),a=fe(r),s=[];for(let[i,c]of Object.entries(a.agents))s.push({name:i,publisher:c.publisher,package_:c.package_,version:c.version,path:ge(r,c.fileName)});if(Ye(r))try{let i=qi(r,{withFileTypes:!0});for(let c of i){if(!c.isFile()||c.name==="agents.lock")continue;let l=ge(r,c.name),u=oc(c.name);if(!a.agents[u]){try{if(!Gi(l).isFile())continue}catch{continue}s.push({name:u,publisher:"",package_:"",version:"",path:l})}}}catch{}return s}};async function tc(n,e){let t=await n.getDocumentsByNamespaceAsync(Bt,qt);if(t.length===0)return;let o=new Qi(t[0],n),r=await e.parseKanonaks(o);return Zi(r,nc.InstanceTransformation)[0]}function oc(n){let e=n.lastIndexOf(".");return e===-1?n:n.substring(0,e)}function rc(n){if(!n)return{publisher:"",package_:"",version:""};let e=n.indexOf("@");if(e===-1)return{publisher:"",package_:"",version:""};let t=n.substring(0,e),o=n.substring(e+1),r=t.indexOf("/");return r===-1?{publisher:"",package_:"",version:""}:{publisher:t.substring(0,r),package_:t.substring(r+1),version:o}}var fc=cc(ic(import.meta.url)),gc=JSON.parse(ac(lc(fc,"..","package.json"),"utf-8")),R=new sc;R.name("kanonak").description("Kanonak Protocol CLI - Validate and resolve Kanonak ontology packages").version(gc.version);R.command("validate <path>").description("Validate .kan.yml file(s). Resolves imports via HTTP from publisher domains.").action(async n=>{await rn(n)});R.command("install [package]").description("Install a package and its dependencies, or install all from kanonak.lock.").action(async n=>{await sn(n)});R.command("deps <path>").description("Show resolved dependency tree for a .kan.yml file.").action(async n=>{await cn(n)});R.command("login <publisher>").description("Authenticate with a package publisher using OAuth 2.0.").action(async n=>{await mn(n)});R.command("logout <publisher>").description("Revoke tokens and remove stored credentials for a publisher.").action(async n=>{await fn(n)});R.command("hash <target>").description("Print the canonical structural hash (sha256:\u2026) of a Kanonak package.").option("-v, --verbose","Also print the canonical form on stderr.").option("--frozen","Resolve identity strictly through kanonak.lock; error if the lock or any needed pin is missing.").action(async(n,e)=>{await dt(n,e)});R.addCommand(In());R.addCommand(On());R.addCommand(Vn());R.addCommand(Hn());R.addCommand(Bn());R.addCommand(Qn());R.addCommand(st());R.addCommand(pt());R.addCommand(at());async function hc(){try{let n=new K,e=new uc,t=new dc,o=mc(t),r=new pc({fetchFn:o}),a=await $(process.cwd(),e),s=new ae;s.register("kanonak.org/capabilities/agent-skill-deployment",new de),s.register("kanonak.org/agent-capabilities/agent-instance-deployment",new he);let i=await Rn(n,e,a),c=new se(n,e,r,o,s,a);ft(R,i,c)}catch{}}await hc();R.parse();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kanonak-protocol/cli",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.8.0",
|
|
4
4
|
"description": "Command-line tool for the Kanonak Protocol — validate, resolve, preview, and publish semantic ontology packages.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -35,8 +35,8 @@
|
|
|
35
35
|
"semantic-web"
|
|
36
36
|
],
|
|
37
37
|
"dependencies": {
|
|
38
|
-
"@kanonak-protocol/sdk": "^4.
|
|
39
|
-
"@kanonak-protocol/types": "^4.
|
|
38
|
+
"@kanonak-protocol/sdk": "^4.8.0",
|
|
39
|
+
"@kanonak-protocol/types": "^4.8.0",
|
|
40
40
|
"commander": "^13.0.0",
|
|
41
41
|
"js-yaml": "^4.1.1"
|
|
42
42
|
},
|