@kanonak-protocol/cli 3.58.0 → 3.59.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/commands/verify.d.ts +14 -0
- package/dist/index.js +46 -43
- package/package.json +3 -3
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `kanonak verify` — check that locked packages match their pinned integrity.
|
|
3
|
+
*
|
|
4
|
+
* The cache is an untrusted accelerator: this re-hashes each cached package and
|
|
5
|
+
* compares it to the committed `kanonak.lock` (catches local tampering/
|
|
6
|
+
* corruption of the cache). With `--remote` it also re-fetches each package
|
|
7
|
+
* from its recorded origin and compares to the lock (catches lock↔origin drift:
|
|
8
|
+
* a tampered lock, a republished package, or a MITM). The lock — committed and
|
|
9
|
+
* reviewed in version control — is the trust root; this command makes any
|
|
10
|
+
* divergence from it detectable rather than silent. Exits non-zero on any
|
|
11
|
+
* mismatch, so it can gate a build in CI.
|
|
12
|
+
*/
|
|
13
|
+
import { Command } from 'commander';
|
|
14
|
+
export declare function verifyCommand(): Command;
|
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 Gi}from"commander";import{readFileSync as Ji}from"fs";import{fileURLToPath as Yi}from"url";import{dirname as Xi,join as Zi}from"path";import{KanonakParser as Qi,PublisherIndex as ec,CredentialStore as nc,createAuthenticatedFetch as tc}from"@kanonak-protocol/sdk";import{readFileSync as eo,statSync as no}from"fs";import{resolve as to,dirname as oo}from"path";import{KanonakParser as ro,KanonakObjectValidator as ao,ValidationSeverity as on}from"@kanonak-protocol/sdk";import{readdirSync as Yt}from"fs";import{join as Xt,dirname as Zt,basename as tn}from"path";import{LocalFirstRepository as fc,buildLocalFirstRepository as Qt}from"@kanonak-protocol/sdk";import{mkdirSync as zt,readFileSync as en,writeFileSync as nn,existsSync as we,appendFileSync as Bt}from"fs";import{join as qt,dirname as Wt,isAbsolute as Gt}from"path";import{getGlobalCachePath as Jt}from"@kanonak-protocol/sdk";var K=class{constructor(e=Jt()){this.cacheDir=e;this.isProjectLocal=!Gt(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 s=this.getPath(e,t,o);zt(Wt(s),{recursive:!0}),nn(s,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;Bt(e,`
|
|
4
4
|
${t}/
|
|
5
|
-
`)}else
|
|
6
|
-
`)}getPath(e,t,o){return
|
|
5
|
+
`)}else nn(e,`${t}/
|
|
6
|
+
`)}getPath(e,t,o){return qt(this.cacheDir,e,`${t}@${o}.kan.yml`)}};function N(n){let e=n;for(;;){let t=Zt(e);if(t===e)break;if(tn(e).includes(".")||tn(t).includes(".")){e=t;continue}break}return e}function $e(n,e){for(let t of Yt(n,{withFileTypes:!0})){let o=Xt(n,t.name);t.isDirectory()&&t.name!=="node_modules"&&t.name!==".kanonak"?$e(o,e):t.name.endsWith(".kan.yml")&&e.push(o)}}async function v(n,e){let t=new K;return Qt(n,e,{httpCache:{getFromCache:(o,r,s)=>t.get(o,r,s),onFetch:(o,r,s,a)=>t.put(o,r,s,a)}})}async function rn(n){let e=to(n),t=no(e),o=t.isDirectory()?N(e):N(oo(e)),r=new ro,s=new ao(r),a=await v(o,r),i=[];if(t.isDirectory()?$e(e,i):i.push(e),i.length===0){console.log("No .kan.yml files found.");return}let c=0,l=0;for(let u of i){let p=eo(u,"utf-8"),d=r.parseWithErrors(p);if(d.errors&&d.errors.length>0){console.log(`
|
|
7
7
|
${u}:`);for(let h of d.errors)console.log(` ERROR (parse): ${h.message} [line ${h.line}:${h.column}]`),c++;continue}let f=d.document;if(!f){console.log(`
|
|
8
|
-
${u}:`),console.log(" ERROR: Failed to parse document"),c++;continue}let g=await
|
|
8
|
+
${u}:`),console.log(" ERROR: Failed to parse document"),c++;continue}let g=await s.validateAsync(f,a),m=g.errors.filter(h=>h.severity===on.Error),k=g.warnings.filter(h=>h.severity===on.Warning);if(m.length>0||k.length>0){let h=f.metadata.namespace_,y=h?`${h.publisher}/${h.package_}@${h.version}`:u;console.log(`
|
|
9
9
|
${y}:`);for(let b of m)console.log(` ERROR: ${b.message}`),b.suggestion&&console.log(` -> ${b.suggestion}`);for(let b of k)console.log(` WARN: ${b.message}`)}c+=m.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 ${f.size} package(s).`)}async function sn(n,e,t,o,r,a,
|
|
10
|
+
${i.length} file(s) validated. ${c} error(s), ${l} warning(s).`),c>0&&process.exit(1)}import{KanonakParser as so,PublisherIndex as io,CredentialStore as co,createAuthenticatedFetch as lo}from"@kanonak-protocol/sdk";import{loadLockFile as uo,saveLockFile as po,computeIntegrity as mo,assertPackageIdentity as fo}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,s=null,a=null,i=o.indexOf("@");if(i!==-1){r=o.substring(0,i);let c=o.substring(i+1),l=c.indexOf("/");l===-1?s=c||null:(s=c.substring(0,l)||null,a=c.substring(l+1)||null)}else{let c=o.indexOf("/");c===-1?r=o:(r=o.substring(0,c),a=o.substring(c+1)||null)}return!r||a&&a.includes("/")||s&&s.includes("@")?null:{publisher:t,packageName:r,version:s,instanceName:a}}async function an(n){let e=new K,t=new so,o=new co,r=lo(o),s=new io({fetchFn:r}),a=uo()??{version:"1",lastUpdated:new Date().toISOString(),packages:{}};if(!n){Object.keys(a.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(a.packages).length} package(s) from kanonak.lock...`);for(let[g,m]of Object.entries(a.packages)){let k=g.indexOf("/"),h=g.substring(0,k),y=g.substring(k+1),b=e.get(h,y,m.version);if(b)console.log(` ${g}@${m.version} (cached)`);else{let w=m.resolved,$=await r(w,h);if(!$.ok)throw new Error(`Failed to fetch ${w} (${$.status} ${$.statusText})`);b=await $.text(),e.put(h,y,m.version,b),console.log(` ${g}@${m.version}`)}}console.log(`
|
|
11
|
+
Installed ${Object.keys(a.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 s.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 f=new Set;await sn(c,l,d,e,t,s,r,f,a),po(a),console.log(`
|
|
12
|
+
Installed ${f.size} package(s).`)}async function sn(n,e,t,o,r,s,a,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 s.getPackageUrl(n,e,t),f,g=!1;if(p)f=p;else{let h=await a(d,n);if(!h.ok)throw new Error(`Failed to fetch ${d} (${h.status} ${h.statusText})`);f=await h.text(),g=!0}let m=r.parse(f);fo(m,n,e,t),g&&o.put(n,e,t,f),console.log(` ${l}${g?"":" (cached)"}`);let k={};if(m.metadata.imports)for(let[h,y]of Object.entries(m.metadata.imports))for(let b of y){let w=await s.resolveVersion(h,b);w?(k[`${h}/${b.packageName}`]=w,await sn(h,b.packageName,w,o,r,s,a,i,c)):console.error(` WARNING: Could not resolve ${h}/${b.packageName} ${b.package_}`)}c.packages[u]={version:t,resolved:d,integrity:mo(f),dependencies:k}}import{readFileSync as go}from"fs";import{resolve as ho,dirname as ko}from"path";import{KanonakParser as yo}from"@kanonak-protocol/sdk";async function cn(n){let e=ho(n),t=go(e,"utf-8"),o=new yo,r=o.parse(t),s=r.metadata.namespace_,a=s?`${s.publisher}/${s.package_}@${s.version}`:n;if(console.log(a),!r.metadata.imports){console.log(" (no imports)");return}let i=N(ko(e)),c=await v(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 s=`${n}/${e.packageName}`;if(o.has(s)){console.log(`${r}${s} (${e.package_}) [circular]`);return}o.add(s);let a;try{a=await t.getHighestCompatibleVersionAsync(n,e)}catch{console.log(`${r}${s} (${e.package_}) [fetch failed]`);return}if(!a){console.log(`${r}${s} (${e.package_}) [not found]`);return}let i=a.metadata.namespace_?.version?.toString()??"?";if(console.log(`${r}${n}/${e.packageName}@${i}`),a.metadata.imports)for(let[c,l]of Object.entries(a.metadata.imports))for(let u of l)await ln(c,u,t,o,r+" ")}import{createHash as wo,randomBytes as dn}from"crypto";import{createServer as $o}from"http";import{execFile as ve}from"child_process";import{CredentialStore as vo,generateDPoPKeyPair as So,createDPoPProof as un,serverSupportsDPoP as Po}from"@kanonak-protocol/sdk";import{normalizeHost as bo}from"@kanonak-protocol/sdk";var A=class{cache=new Map;async discover(e){let t=bo(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 s=`https://${t}/.well-known/openid-configuration`;r=await this.tryEndpoint(s)}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 s=r instanceof Error?r.message:String(r);return s.includes("ENOTFOUND")||s.includes("ECONNREFUSED")?(console.error(` OAuth discovery: ${e} \u2014 host unreachable (${s})`),console.error(" If the server is behind a VPN, ensure you are connected.")):s.includes("CERT")||s.includes("SSL")||s.includes("TLS")?(console.error(` OAuth discovery: ${e} \u2014 TLS error (${s})`),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: ${s}`),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:Y(o.issuer),authorizationEndpoint:Y(o.authorization_endpoint),tokenEndpoint:Y(o.token_endpoint),registrationEndpoint:Y(o.registration_endpoint),revocationEndpoint:Y(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 Y(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 vo}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 s=Po(o.dpopSigningAlgValuesSupported),a=null;if(s){console.log(" Server supports DPoP (RFC 9449) \u2014 generating key pair...");try{a=So()}catch($){return I(`Failed to generate DPoP key pair: ${z($)}
|
|
19
|
+
Ensure your Node.js installation supports EC P-256 curves.`)}}let{redirectUri:i,port:c,waitForCallback:l,close:u}=await Do(),p=await this.credentialStore.getCredential(e),d=p?.clientId??null,f=p?.clientSecret??null;if(!d&&o.registrationEndpoint){console.log(" Registering dynamic OAuth client (RFC 7591)...");let $=await this.registerClient(o.registrationEndpoint,i);if(!$.success)return u(),I($.error);d=$.clientId,f=$.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 g=
|
|
22
|
+
or add a registration_endpoint to the OAuth metadata.`);let g=_o(),m=Ro(g),k=xo(),h=Io(o.authorizationEndpoint,d,i,t,k,m);console.log(` Opening browser for authorization on port ${c}...`),console.log(" If the browser doesn't open, navigate to:"),console.log(` ${h}`),Eo(h);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 $=y.error?`: ${y.error}`:"";return I(`No authorization code received${$}.
|
|
25
25
|
The IDP may have rejected the authorization request.
|
|
26
26
|
Check the IDP admin console for error details.`)}if(y.state!==k)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 b=await this.exchangeCode(o.tokenEndpoint,d,f,y.code,i,g,
|
|
28
|
+
Re-run 'kanonak login ${e}' to start a fresh authorization flow.`);console.log(" Exchanging authorization code for tokens...");let b=await this.exchangeCode(o.tokenEndpoint,d,f,y.code,i,g,a);if(!b.success)return I(b.error);let w={clientId:d,clientSecret:f,accessToken:b.tokens.accessToken,refreshToken:b.tokens.refreshToken,expiresAt:b.tokens.expiresIn?new Date(Date.now()+b.tokens.expiresIn*1e3).toISOString():null,tokenEndpoint:o.tokenEndpoint,dpopKeyPair:a};return await this.credentialStore.store(e,w),console.log(` Successfully authenticated with ${e}`),s&&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 s=await this.discovery.discover(e);if(!s?.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=s.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(a){return{success:!1,error:`Dynamic client registration request to ${e} failed: ${z(a)}
|
|
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 a=await Se(o);return{success:!1,error:`Dynamic client registration (RFC 7591) failed.
|
|
38
38
|
Endpoint: ${e}
|
|
39
|
-
HTTP ${o.status}: ${
|
|
39
|
+
HTTP ${o.status}: ${a}
|
|
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,a,
|
|
41
|
+
Ask your IDP administrator to enable RFC 7591 support, or pre-register a client manually.`}}let r=await o.json(),s=r.client_id;return s?{success:!0,clientId:s,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,s,a,i){let c=new URLSearchParams({grant_type:"authorization_code",client_id:t,code:r,redirect_uri:s,code_verifier:a});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 Se(u),d=
|
|
44
|
+
Ensure the token endpoint is reachable.`}}if(!u.ok){let p=await Se(u),d=Co(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:
|
|
47
|
+
${d}`:"")}}return{success:!0,tokens:pn(await u.json())}}async refreshTokenRequest(e,t,o,r,s){let a=new URLSearchParams({grant_type:"refresh_token",client_id:t,refresh_token:r});o&&a.set("client_secret",o);let i={"Content-Type":"application/x-www-form-urlencoded"};if(s)try{i.DPoP=un(s.privateKey,s.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:a.toString()})}catch(l){return{success:!1,error:`Token refresh request to ${e} failed: ${z(l)}`}}if(!c.ok){let l=await Se(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 Se(n){try{return await n.text()}catch{return"(could not read response body)"}}function Co(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 _o(){return dn(32).toString("base64url")}function Ro(n){return wo("sha256").update(n).digest("base64url")}function xo(){return dn(16).toString("base64url")}function Io(n,e,t,o,r,s){let a=new URLSearchParams({client_id:e,response_type:"code",redirect_uri:t,scope:o.join(" "),state:r,code_challenge:s,code_challenge_method:"S256"});return`${n}?${a}`}var Ko=300*1e3;async function Do(){return new Promise(n=>{let e=$o((r,s)=>{let a=new URL(r.url,"http://localhost"),i=a.searchParams.get("code")??void 0,c=a.searchParams.get("state")??void 0,l=a.searchParams.get("error")??a.searchParams.get("error_description")??void 0,u=l?To(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>";s.writeHead(200,{"Content-Type":"text/html"}),s.end(p),t({code:i,state:c,error:l})}),t,o=new Promise(r=>{t=r,setTimeout(()=>{r(null),e.close()},Ko)});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 To(n){return n.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}function Eo(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 jo}from"@kanonak-protocol/sdk";async function mn(n){try{let e=new A,t=new jo,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 Ao}from"@kanonak-protocol/sdk";async function fn(n){try{let e=new A,t=new Ao,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
|
|
59
|
-
Installed capability "${w}".`),console.log(`Run "kanonak ${w} --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 Q}from"commander";import{readFileSync as
|
|
57
|
+
${t}`),process.exit(1)}}import{Command as sr}from"commander";import{KanonakParser as ir,KanonakObjectParser as cr,PublisherIndex as lr,CredentialStore as ur,createAuthenticatedFetch as pr,computeIntegrity as dr}from"@kanonak-protocol/sdk";import{readFileSync as Oo,writeFileSync as No,existsSync as Lo}from"fs";import{join as Uo}from"path";import gn from"js-yaml";import{getGlobalCachePath as Fo}from"@kanonak-protocol/sdk";var Mo=`# This file is generated by Kanonak CLI. Do not edit manually.
|
|
58
|
+
`;function hn(){let n=Fo();return Uo(n,"..","capabilities.lock")}function q(){let n=hn();if(!Lo(n))return{version:"1",lastUpdated:new Date().toISOString(),capabilities:{}};let e=Oo(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 X(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:'"'});No(hn(),Mo+t,"utf-8")}import{SingleDocumentRepository as mr}from"@kanonak-protocol/sdk/uri-helpers";import{existsSync as Vo,readdirSync as Ho,readFileSync as zo}from"fs";import{join as kn}from"path";import{KanonakObjectParser as Bo,EmbeddedKanonak as $n,ReferenceKanonak as vn,getGlobalCachePath as qo}from"@kanonak-protocol/sdk";import{SingleDocumentRepository as Sn}from"@kanonak-protocol/sdk/uri-helpers";import{uriKey as Pe,findSubjectsByType as Wo,getStringValue as O,getReferenceUri as Ce,getListValues as Pn}from"@kanonak-protocol/sdk/uri-helpers";var P="kanonak.org",C="capabilities",_e={publisher:P,package_:C,name:"Capability"},Go={publisher:P,package_:C,name:"commandName"},Cn={publisher:P,package_:C,name:"description"},Jo={publisher:P,package_:C,name:"managesType"},Yo={publisher:P,package_:C,name:"deploymentTarget"},Xo={publisher:P,package_:C,name:"hasCommand"},Zo={publisher:P,package_:C,name:"subcommandName"},Qo={publisher:P,package_:C,name:"performs"},er={publisher:P,package_:C,name:"hasArgument"},nr={publisher:P,package_:C,name:"argumentName"},yn={publisher:P,package_:C,name:"isRequired"},bn={publisher:P,package_:C,name:"isOption"},tr={publisher:P,package_:C,name:"defaultValue"};async function _n(n,e,t){let o=q(),r=new Bo,s=[],a=!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 or(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,a=!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),f=await r.parseKanonaks(d),g=Rn(f,l.publisher,l.package_,l.version);g?s.push(g):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 a&&X(o),s}async function or(n,e,t,o,r){let s=kn(qo(),e.publisher);if(!Vo(s))return;let a=[];for(let i of Ho(s)){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=zo(kn(s,i),"utf-8")}catch{continue}let f;try{let g=t.parse(d),m=new Sn(g,r),k=await o.parseKanonaks(m);f=Rn(k,e.publisher,u,p)?.commandName}catch{continue}f===n&&a.push({entry:{publisher:e.publisher,package_:u,version:p,resolved:`kanonak://${e.publisher}/${u}@${p}`,integrity:""},content:d})}if(a.length===1)return a[0]}function Rn(n,e,t,o){let r=Wo(n,_e);if(r.length===0)return;let s=r[0],a=O(s,Go)??"",i=O(s,Cn)??"",c=Ce(s,Jo),l=Ce(s,Yo),u=[];for(let p of Pn(s,Xo)){let d=rr(p,n);d&&u.push(d)}return{commandName:a,description:i,managesTypeKey:c?Pe(c):"",deploymentTargetKey:l?Pe(l):"",commands:u,publisher:e,package_:t,version:o}}function rr(n,e){let t;if(n instanceof $n)t=n;else if(n instanceof vn){let c=xn(e,n.subject.publisher,n.subject.package_,n.subject.name);c&&(t=c)}if(!t)return;let o=O(t,Zo)??"",r=O(t,Cn)??"",s=Ce(t,Qo),a=Pn(t,er),i=[];for(let c of a){let l=ar(c,e);l&&i.push(l)}return{subcommandName:o,description:r,arguments:i,actionKey:s?Pe(s):""}}function ar(n,e){let t;if(n instanceof $n)t=n;else if(n instanceof vn){let c=xn(e,n.subject.publisher,n.subject.package_,n.subject.name);c&&(t=c)}if(!t)return;let o=O(t,nr)??"",r=O(t,yn)==="true"||wn(t,yn)===!0,s=O(t,bn)==="true"||wn(t,bn)===!0,a=O(t,tr),i={argumentName:o,required:r,isOption:s};return a!==void 0&&(i.defaultValue=a),i}function wn(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 s=r;if(s.name===o&&!(!s.namespace||typeof s.namespace!="string")&&s.namespace.startsWith(`${e}/${t}@`))return r}}import{findSubjectsByType as fr,getStringValue as gr}from"@kanonak-protocol/sdk/uri-helpers";var hr={publisher:P,package_:C,name:"commandName"};function In(){let n=new sr("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 kr(e)}),n.command("remove <name>").description("Remove an installed capability").action(async e=>{await yr(e)}),n.command("list").description("List installed capabilities").action(async()=>{await br()}),n}async function kr(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:s}=e;s&&(console.error(`\`kanonak capability add\` installs whole packages \u2014 got an instance suffix "/${s}".`),console.error(`Try: kanonak capability add ${t}/${o}${r?"@"+r:""}`),process.exit(1));let a=new K,i=new ir,c=new cr,l=new ur,u=pr(l),p=new lr({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 f=a.get(t,o,d);if(!f){let _=await p.getPackageUrl(t,o,d),D=await u(_,t);if(!D.ok)throw new Error(`Failed to fetch ${_} (${D.status} ${D.statusText})`);f=await D.text(),a.put(t,o,d,f)}let g=i.parse(f),m=await v(process.cwd(),i),k=new mr(g,m),h=await c.parseKanonaks(k),y=fr(h,_e);y.length===0&&(console.error(`Package ${t}/${o}@${d} does not contain a ${P}/${C}/Capability instance.`),process.exit(1));let b=y[0],w=gr(b,hr);w||(console.error(`Capability instance in ${t}/${o}@${d} has no commandName property.`),process.exit(1));let $=q();$.capabilities[w]={publisher:t,package_:o,version:d,resolved:await p.getPackageUrl(t,o,d),integrity:dr(f)},X($),console.log(`
|
|
59
|
+
Installed capability "${w}".`),console.log(`Run "kanonak ${w} --help" to get started.`)}async function yr(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],X(e),console.log(`Removed capability "${n}" (${t.publisher}/${t.package_}@${t.version}).`)}async function br(){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 Q}from"commander";import{readFileSync as wr,writeFileSync as $r,mkdirSync as vr,existsSync as Kn,statSync as Sr}from"fs";import{join as Pr,resolve as Cr}from"path";import{KanonakParser as Ie,KanonakObjectParser as Ke,SubjectKanonak as _r,Reasoner as Rr,KanonakVocabulary as xr,makeUriKey as En,pickHighestDocument as De,formatVersion as jn}from"@kanonak-protocol/sdk";import{SingleDocumentRepository as Z}from"@kanonak-protocol/sdk/uri-helpers";import{findSubjectsByType as Re,findSubjectByUri as Ir}from"@kanonak-protocol/sdk/uri-helpers";import{TX_V3 as Dn}from"@kanonak-protocol/sdk/transformations";import{TransformationRunnerV3 as Kr,SUPPORTED_FORMATS_V3 as An}from"@kanonak-protocol/sdk/transformations";import{compileTransformationV3 as Te}from"@kanonak-protocol/sdk/transformations";function xe(n){return[...Re(n,Dn.InstanceTransformation),...Re(n,Dn.SetTransformation)]}function On(){let n=new Q("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=De(c.map(d=>d.doc));if(!u.chosen)throw new Error(`Could not select a Transformation version for "${
|
|
98
|
+
`);return n.addCommand(Dr()),n.addCommand(Ar()),n.addCommand(Nr()),n.addCommand(Ur()),n}function Dr(){return new Q("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.",Tr,[]).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 Er(n,e)}catch(t){console.error(`Error: ${t.message}`),process.exit(1)}})}function Tr(n,e){return[...e,n]}async function Er(n,e){let t=new Ie,o=new Ke,r=await v(process.cwd(),t),s=await Nn(n,r,o),{transformation:a,transformationKanonaks:i}=s;console.log(`Transformation: ${te(a)}`);let c=Te(a,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 b=await Fr(y,r,t,o);l.push(...b);let w=await Hr(b,c.inputPattern.matchesClass,r);for(let $ of w){let _=zr($);_&&!u.has(_)&&u.set(_,$)}console.log(`Scope: ${y} \u2014 found ${w.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 f=jr(c.outputs,e.format);console.log(`Output format: ${f}`);let g=An[f];if(!g)throw new Error(`Unknown format "${f}". Run \`kanonak transform formats\` to see what the runner supports.`);let k=await new Kr().run({transformation:a,instances:p,allKanonaks:d,transformationKanonaks:i,repository:r,parser:t,objectParser:o,outputFormat:f}),h=Cr(e.out);vr(h,{recursive:!0});for(let y of k){let b=Vr(y.fileName),w=Pr(h,`${b}${g.extension}`);$r(w,y.content,"utf-8"),console.log(` wrote ${w}`)}console.log(`Done. ${k.length} artifact(s) written to ${h}`)}function jr(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 Ar(){return new Q("list").description("Scan the local workspace + cache for every Transformation instance and print a one-line summary per hit.").action(async()=>{try{await Or()}catch(n){console.error(`Error: ${n.message}`),process.exit(1)}})}async function Or(){let n=new Ie,e=new Ke,t=await v(process.cwd(),n),o=await t.getAllDocumentsAsync(),r=new Map;for(let a of o)try{let i=new Z(a,t),c=await e.parseKanonaks(i),l=xe(c);for(let u of l){let p=Ee(u);if(!p)continue;let d=r.get(p)??[];d.push({tx:u,kanonaks:c,doc:a}),r.set(p,d)}}catch{}let s=[];for(let a of r.values()){if(a.length===1){s.push(Tn(a[0].tx,a[0].kanonaks));continue}let i=De(a.map(l=>l.doc));if(!i.chosen)continue;let c=a.find(l=>l.doc===i.chosen);c&&s.push(Tn(c.tx,c.kanonaks))}if(s.length===0){console.log("No Transformation instances found in the current workspace.");return}s.sort((a,i)=>a.uri.localeCompare(i.uri));for(let a of s)console.log(`${a.uri}`),console.log(` matches: ${a.matchesClass}`),console.log(` outputs: ${a.outputs.join(", ")}`)}function Nr(){return new Q("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 Lr(n)}catch(e){console.error(`Error: ${e.message}`),process.exit(1)}})}async function Lr(n){let e=new Ie,t=new Ke,o=await v(process.cwd(),e),{transformation:r,transformationKanonaks:s}=await Nn(n,o,t),a=Te(r,s);if(console.log(`Transformation: ${te(r)}`),console.log(),console.log("Input pattern:"),console.log(` Matches class: ${ne(a.inputPattern.matchesClass)}`),a.inputPattern.requires.length>0){console.log(" Required properties:");for(let i of a.inputPattern.requires)console.log(` - ${ne(i)}`)}else console.log(" Required properties: (none)");if(console.log(),console.log(`Outputs: ${Array.from(a.outputs).sort().join(", ")}`),console.log(),a.overrides.size>0){console.log("Format overrides:");for(let[i,c]of a.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: ${a.rule.kind}`),a.rule.kind==="build-ast-node"&&(console.log(`Rule root AST class: ${ne(a.rule.astClass)}`),console.log(`Rule root bindings: ${a.rule.set.length} field(s)`)),console.log(`Artifact name root kind: ${a.artifactName.kind}`)}function Ur(){return new Q("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,s;if(n.includes("/")){let d=n.indexOf("@"),f=n;if(d!==-1){let m=n.indexOf("/",d);if(m===-1)throw new Error(`Transformation URI "${n}" has @version but no trailing /<name>`);f=n.substring(0,d)+n.substring(m)}let g=f.split("/");if(g.length<3)throw new Error(`Invalid transformation URI "${n}" \u2014 expected publisher/package/name or publisher/package@version/name`);o=g[0],r=g[1],s=g.slice(2).join("/")}else s=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 f=Mr(n),g=Ln(d,f,`${o}/${r}`),m=new Z(g,e),k=await t.parseKanonaks(m),h=Ir(k,{publisher:o,package_:r,name:s,version:""});if(!h){let y=xe(k),b=y.find(w=>w.name===s);if(!b)throw new Error(`Transformation "${s}" not found in package ${o}/${r}. Package contains ${y.length} Transformation(s): ${y.map(w=>w.name).join(", ")||"(none)"}`);return{transformation:b,transformationKanonaks:k}}return{transformation:h,transformationKanonaks:k}}let a=await e.getAllDocumentsAsync(),i=new Map;for(let d of a)try{let f=new Z(d,e),g=await t.parseKanonaks(f),m=xe(g);for(let k of m){if(k.name!==s)continue;let h=Ee(k);if(!h)continue;let y=i.get(h)??[];y.push({tx:k,kanonaks:g,doc:d}),i.set(h,y)}}catch{}if(i.size===0)throw new Error(`No Transformation named "${s}" 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 "${s}" 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=De(c.map(d=>d.doc));if(!u.chosen)throw new Error(`Could not select a Transformation version for "${s}".`);let p=l.get(u.chosen);if(u.multipleVersionsPresent){let d=m=>{let k=m.metadata.namespace_?.version;return k?jn(k):""},f=p.tx.namespace??"",g=f.includes("@")?f.substring(0,f.indexOf("@")):f;console.warn(`Warning: Transformation "${s}" has ${c.length} versions present (${c.map(m=>d(m.doc)).filter(Boolean).join(", ")}); using @${d(u.chosen)}. Pin with ${g}@<version>/${s} to suppress this warning.`)}return{transformation:p.tx,transformationKanonaks:p.kanonaks}}async function Fr(n,e,t,o){if(/^[.\/\\]/.test(n)||/^[A-Za-z]:/.test(n)||n.endsWith(".kan.yml")||Kn(n)&&Sr(n).isFile()){if(!Kn(n))throw new Error(`Scope file not found: ${n}`);let g=wr(n,"utf-8"),m=t.parse(g),k=new Z(m,e);return o.parseKanonaks(k)}let s=n.indexOf("@"),a=s===-1?n:n.substring(0,s),i=s===-1?void 0:n.substring(s+1),c=a.indexOf("/");if(c===-1)throw new Error(`Invalid scope "${n}" \u2014 expected a file path or publisher/package[@version] URI`);let l=a.substring(0,c),u=a.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}`),f=new Z(d,e);return o.parseKanonaks(f)}function Mr(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=s=>{let a=s.metadata.namespace_?.version;return a?jn(a):""},r=De(n,{requestedVersion:e});if(r.exactRequestedVersionMissing){let s=n.map(o).filter(Boolean).sort().join(", ");throw new Error(`${t}@${e} not found in the local workspace or cache. Available versions: ${s||"(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=Te(n,e);return{uri:te(n),matchesClass:ne(t.inputPattern.matchesClass),outputs:Array.from(t.outputs).sort()}}catch(t){return{uri:te(n),matchesClass:`(compile error: ${t.message})`,outputs:[]}}}function te(n){let e=n.namespace||"",t=e.indexOf("@");return`${t===-1?e:e.substring(0,t)}/${n.name}`}function ne(n){return`${n.publisher}/${n.package_}/${n.name}`}function Vr(n){return n.replace(/[\\/:*?"<>|\s]+/g,"_").replace(/^_+|_+$/g,"")}async function Hr(n,e,t){let o=new Map;for(let a of n){if(!(a instanceof _r))continue;let i=Ee(a);i&&o.set(i,a)}let r=[];try{r=(await new Rr({vocabulary:new xr}).reason(t)).getInstancesOfClass(En(e.publisher,e.package_,e.name))}catch{}let s=[];for(let a of r){let i=o.get(a);i&&s.push(i)}return s.length>0?s:Re(n,e)}function Ee(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 zr(n){let e=n.namespace??"";return!e||!n.name?null:`${e}/${n.name}`}import{Command as Br}from"commander";import{writeFileSync as qr,mkdirSync as Wr}from"fs";import{join as Gr,resolve as Jr}from"path";import{KanonakParser as Yr,KanonakObjectParser as Xr,SubjectKanonak as Mn,findDerivation as Zr}from"@kanonak-protocol/sdk";import{TransformationRunnerV3 as Qr}from"@kanonak-protocol/sdk/transformations";var ea={publisher:"kanonak.org",package_:"formats",name:"html"},na={publisher:"kanonak.org",package_:"derivation",name:"default"},ta={html:".html",markdown:".md",json:".json",yaml:".yaml",xml:".xml",svg:".svg",typescript:".ts","c-sharp":".cs",rust:".rs",python:".py"};function oa(n){return n==="markdown"?"markdown-with-frontmatter":n}function Vn(){return new Br("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,25 +108,28 @@ 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 ra(n,e)}catch(t){console.error(`Error: ${t.message}`),process.exit(1)}})}async function ra(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 Yr,r=new Xr,s=await v(process.cwd(),o),a=await r.parseKanonaks(s),i=aa(a,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=ia(e.format),l=ca(e.variant),u=Zr(i,c,l,a);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: ${la(u)} \u2192 ${Fn(u.transformation)}`);let p=sa(a,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=oa(e.format),g=await new Qr().run({transformation:p,instances:[i],allKanonaks:a,repository:s,parser:o,objectParser:r,outputFormat:d}),m=Jr(e.out);Wr(m,{recursive:!0});let k=ta[e.format]??"";for(let h of g){let y=ua(h.fileName),b=Gr(m,`${y}${k}`);qr(b,h.content,"utf-8"),console.log(` wrote ${b}`)}console.log(`Done. ${g.length} artifact(s) written to ${m}`)}function aa(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 sa(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 ia(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{...ea,name:n}}function ca(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{...na,name:n}}function Un(n){return`${n.namespace}/${n.name}`}function Fn(n){return`${n.publisher}/${n.package_}@${n.version}/${n.name}`}function la(n){return n.source==="instance"?"instance override":`class ${n.source.publisher}/${n.source.package_}/${n.source.name}`}function ua(n){return n.replace(/[^a-zA-Z0-9._@-]+/g,"_")}import{Command as pa}from"commander";import{writeFileSync as x,mkdirSync as L}from"fs";import{join as S,resolve as Hn,dirname as da}from"path";import{SubjectKanonak as ma}from"@kanonak-protocol/sdk";import{loadServerModel as fa,route as ga}from"@kanonak-protocol/sdk/server";function zn(){return new pa("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 ha(n)})}async function ha(n){let e=Hn(n.workspace),t=Hn(n.out),o=await fa(e,n.publisher?{publisher:n.publisher}:{}),{catalog:r,lookRenderer:s,localNamespaces:a,rawByNsKey:i,publisher:c}=o;L(t,{recursive:!0}),console.log(`Publishing ${c} \u2014 ${a.size} package version(s) to ${t}`);let l=r.filter(g=>g instanceof ma&&a.has(g.namespace||""));console.log(`Rendering ${l.length} resource(s).`);let u=0,p=0;for(let g of l){let m=(g.namespace||"").split("/")[1]??"",[k,h]=m.split("@");if(!k||!h)continue;let y=S(t,k,h);L(y,{recursive:!0});try{let b=s.renderRawMarkdown(g);b!==void 0&&(x(S(y,`${g.name}.md`),b,"utf-8"),u+=1),x(S(y,`${g.name}.html`),s.renderDocument(g),"utf-8"),x(S(y,`${g.name}.css`),s.renderStylesheet(g),"utf-8"),x(S(y,`${g.name}.svg`),s.renderSvg(g),"utf-8"),u+=3}catch(b){console.warn(` ${g.namespace}/${g.name}: ${b.message}`),p+=1}}console.log(`Done. ${u} artifact(s) written, ${p} skipped.`);let d=ya(t,l,s);console.log(`Wrote ${d} package overview page(s).`),ba(t,l,s);let f=wa(t,l);console.log(`Wrote ${f} version-form redirect stub(s).`),ka(t,o)}function ka(n,e){if(e.rawByNsKey.size===0)return;let t=(o,r)=>{let s=S(n,r);L(da(s),{recursive:!0}),x(s,ga(e,o).body,"utf-8")};t("/.well-known/kanonak.json",".well-known/kanonak.json"),t("/index.txt","index.txt");for(let o of e.rawByNsKey.keys()){let[r,s]=o.split("@");!r||!s||t(`/${r}/${s}.kan.yml`,`${r}/${s}.kan.yml`)}console.log(`Wrote publisher endpoints: index.txt, .well-known/kanonak.json, and ${e.rawByNsKey.size} raw package source(s).`)}function ya(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 f={verStr:p,major:d[0],minor:d[1],patch:d[2]};o.has(u)||o.set(u,[]),o.get(u).push({resource:i,ver:f});let g=r.get(u);(!g||f.major>g.ver.major||f.major===g.ver.major&&f.minor>g.ver.minor||f.major===g.ver.major&&f.minor===g.ver.minor&&f.patch>g.ver.patch)&&r.set(u,{resource:i,ver:f})}let s=(i,c)=>{try{return L(i,{recursive:!0}),x(S(i,"index.html"),t.renderDocument(c),"utf-8"),x(S(i,`${c.name}.css`),t.renderStylesheet(c),"utf-8"),!0}catch{return!1}},a=0;for(let[i,c]of o)for(let{resource:l,ver:u}of c)s(S(n,i,u.verStr),l)&&(a+=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"),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")}a+=1}catch{}}return a}function ba(n,e,t){let o="",r=new Map;for(let a of e){let c=(a.namespace||"").split("/"),[l]=(c[1]??"").split("@");if(!c[0]||!l||(o||(o=c[0]),a.name!==l))continue;let u=(c[1]??"").split("@")[1]??"",p=u.split(".").map(Number);if(p.length!==3||p.some(g=>Number.isNaN(g)))continue;let d={verStr:u,major:p[0],minor:p[1],patch:p[2]},f=r.get(l);(!f||d.major>f.ver.major||d.major===f.ver.major&&d.minor>f.ver.minor||d.major===f.ver.major&&d.minor===f.ver.minor&&d.patch>f.ver.patch)&&r.set(l,{resource:a,ver:d})}if(!o||r.size===0)return;let s=t.publisherSubject(o);x(S(n,"index.html"),t.renderDocument(s,{rootIndex:!0}),"utf-8"),x(S(n,"index.css"),t.renderStylesheet(s),"utf-8")}function wa(n,e){let t=new Map;for(let r of e){let s=r.namespace||"",[,a]=s.split("/");if(!a)continue;let[i,c]=a.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,s]of t){let[a,i]=r.split("/");s.sort((p,d)=>d.major-p.major||d.minor-p.minor||d.patch-p.patch);let c=s[0];x(S(n,a,`${i}.html`),je(`/${a}/${c.verStr}/${i}`),"utf-8"),o+=1;let l=new Set;for(let p of s){if(l.has(p.major))continue;l.add(p.major);let d=S(n,a,String(p.major));L(d,{recursive:!0}),x(S(d,`${i}.html`),je(`/${a}/${p.verStr}/${i}`),"utf-8"),o+=1}let u=new Set;for(let p of s){let d=`${p.major}.${p.minor}`;if(u.has(d))continue;u.add(d);let f=S(n,a,d);L(f,{recursive:!0}),x(S(f,`${i}.html`),je(`/${a}/${p.verStr}/${i}`),"utf-8"),o+=1}}return o}function je(n){let e=n.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""");return`<!doctype html>
|
|
112
112
|
<meta charset="utf-8">
|
|
113
113
|
<title>Redirecting\u2026</title>
|
|
114
114
|
<meta http-equiv="refresh" content="0; url=${e}">
|
|
115
115
|
<link rel="canonical" href="${e}">
|
|
116
116
|
<p>If you are not redirected automatically, follow this <a href="${e}">link</a>.</p>
|
|
117
|
-
`}import{Command as Gn}from"commander";import{writeFileSync as Ae,mkdirSync as oe}from"fs";import{join as Ne,resolve as ys,dirname as Oe}from"path";import{KanonakParser as bs,KanonakObjectParser as ws,SubjectKanonak as Jn,ReferenceStatement as $s,ReferenceKanonak as vs,ListStatement as Ss,StringStatement as Yn,EmbeddedStatement as Ps,findDerivation as zn}from"@kanonak-protocol/sdk";import{SingleDocumentRepository as Cs}from"@kanonak-protocol/sdk/uri-helpers";import{TransformationRunnerV3 as _s}from"@kanonak-protocol/sdk/transformations";import{findSubjectsByType as re}from"@kanonak-protocol/sdk/uri-helpers";var E="kanonak.org",j="site",Bn={publisher:"kanonak.org",package_:"formats",name:"html"},qn={publisher:"kanonak.org",package_:"derivation",name:"default"};function Xn(){let n=new Gn("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(Rs()),n}function Rs(){return new Gn("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 xs(n)}catch(e){console.error(`Error: ${e.message}`),process.exit(1)}})}async function xs(n){let e=new bs,t=new ws,o=await v(process.cwd(),e),r=await t.parseKanonaks(o),a=ys(n.out);oe(a,{recursive:!0});let s=await o.getAllDocumentsAsync(),i=new Set;for(let m of s){let k=m.metadata.namespace_?.toString();k&&i.add(k)}let c={publisher:E,package_:j,name:"StaticPage"},l={publisher:E,package_:j,name:"ResourcePage"},u={publisher:E,package_:j,name:"AggregateView"},p=re(r,c).filter(m=>i.has(m.namespace||"")),d=re(r,l).filter(m=>i.has(m.namespace||"")),f=re(r,u).filter(m=>i.has(m.namespace||""));console.log(`Found ${p.length} StaticPage(s), ${d.length} ResourcePage(s), and ${f.length} AggregateView(s) in the workspace.`);let g=new _s;for(let m of p){let k=Le(m,E,j,"outputPath")??`${m.name}.html`,h=zn(m,Bn,qn,r);if(!h){console.warn(` [skip] ${m.name}: no HTML/default derivation found (check class hierarchy or universal-derivations is loaded)`);continue}let y=Ue(r,h.transformation);if(!y){console.warn(` [skip] ${m.name}: transformation ${Fe(h.transformation)} not found`);continue}let b=await g.run({transformation:y,instances:[m],allKanonaks:r,repository:o,parser:e,objectParser:t,outputFormat:"html"});if(b.length===0){console.warn(` [skip] ${m.name}: transformation produced no artifacts`);continue}let w=Ne(a,k);oe(Oe(w),{recursive:!0}),Ae(w,b[0].content,"utf-8"),console.log(` wrote ${w} (StaticPage ${m.name})`)}for(let m of d){let k=Le(m,E,j,"outputPath")??`${m.name}.html`,h=Wn(m,E,j,"pageOf");if(!h){console.warn(` [skip] ${m.name}: no pageOf declared`);continue}let y=r.find(K=>K instanceof Jn&&K.name===h.name&&(K.namespace||"").startsWith(`${h.publisher}/${h.package_}@`));if(!y){console.warn(` [skip] ${m.name}: pageOf target ${h.publisher}/${h.package_}/${h.name} not found`);continue}let b=zn(y,Bn,qn,r);if(!b){console.warn(` [skip] ${m.name}: no derivation for target ${y.name}`);continue}let w=Ue(r,b.transformation);if(!w){console.warn(` [skip] ${m.name}: transformation ${Fe(b.transformation)} not found`);continue}let $=await g.run({transformation:w,instances:[y],allKanonaks:r,repository:o,parser:e,objectParser:t,outputFormat:"html"});if($.length===0){console.warn(` [skip] ${m.name}: transformation produced no artifacts`);continue}let _=Ne(a,k);oe(Oe(_),{recursive:!0}),Ae(_,$[0].content,"utf-8"),console.log(` wrote ${_} (ResourcePage ${m.name} \u2192 ${y.name})`)}for(let m of f){let k=Le(m,E,j,"outputPath");if(!k){console.warn(` [skip] ${m.name}: no outputPath declared`);continue}let h=Wn(m,E,j,"scopeClass");if(!h){console.warn(` [skip] ${m.name}: no scopeClass declared`);continue}let y={publisher:h.publisher,package_:h.package_,name:h.name},b=Is(m,E,j,"scopeSources"),w=Ks(m);if(!w){console.warn(` [skip] ${m.name}: no transformation declared`);continue}let $=Ue(r,w);if(!$){console.warn(` [skip] ${m.name}: transformation ${Fe(w)} not found`);continue}let _=await Ts(b,o),K=[],Ye=new Set;for(let Ut of _){let Ft=await Es(Ut,o,e,t),Mt=re(Ft,y);for(let be of Mt){let Ze=`${be.namespace}/${be.name}`;Ye.has(Ze)||(Ye.add(Ze),K.push(be))}}console.log(` ${m.name}: ${K.length} instance(s) of ${y.publisher}/${y.package_}/${y.name} across ${_.length} scope(s)`);let Xe=await g.run({transformation:$,instances:K,allKanonaks:r,repository:o,parser:e,objectParser:t,outputFormat:"html"});if(Xe.length===0){console.warn(` [skip] ${m.name}: transformation produced no artifacts`);continue}let ye=Ne(a,k);oe(Oe(ye),{recursive:!0}),Ae(ye,Xe[0].content,"utf-8"),console.log(` wrote ${ye} (AggregateView ${m.name})`)}console.log("Site build complete.")}function Le(n,e,t,o){for(let r of n.statement)if(r instanceof Yn&&se(r,e,t,o))return r.object}function Is(n,e,t,o){for(let r of n.statement){if(!(r instanceof Ss)||!se(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 Wn(n,e,t,o){for(let r of n.statement)if(r instanceof $s&&se(r,e,t,o)&&r.object instanceof vs)return{publisher:r.object.subject.publisher,package_:r.object.subject.package_,name:r.object.subject.name}}function Ks(n){for(let e of n.statement)if(e instanceof Ps&&se(e,E,j,"transformation"))return Ds(e.object)}function Ds(n){let e,t,o,r;for(let a of n.statement){if(!(a instanceof Yn))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 se(n,e,t,o){let r=n.predicate?.subject;return r?r.publisher===e&&r.package_===t&&r.name===o:!1}function Ue(n,e){let t=`${e.publisher}/${e.package_}@${e.version}`;for(let o of n)if(o instanceof Jn&&o.name===e.name&&o.namespace===t)return o}function Fe(n){return`${n.publisher}/${n.package_}@${n.version}/${n.name}`}async function Ts(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 Es(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 Cs(u,e);return o.parseKanonaks(d)}}return[]}import{Command as js}from"commander";import{createServer as As}from"http";import{watch as Ns}from"fs";import{resolve as Os,join as Ls}from"path";import{homedir as Us}from"os";import{loadServerModel as Fs,route as Ms}from"@kanonak-protocol/sdk/server";import{SearchIndex as Hs}from"@kanonak-protocol/sdk/search";import{resolveDisplayValue as Vs,subjectUri as zs}from"@kanonak-protocol/sdk";function Zn(){return new js("serve").description("Serve a publisher's workspace as a live origin \u2014 the same rendering `kanonak publish` produces, plus the machine-facing publisher endpoints, from one process. Use --watch for a dev preview.").option("--root <dir>","Workspace root to serve.",".").option("--port <number>","Port to listen on.","8080").option("--publisher <domain>","Publisher to serve (required only if the workspace has more than one).").option("--watch","Re-load the workspace on .kan.yml changes.",!1).option("--search","Enable opt-in semantic search at ?q= (builds an embedding index).",!1).action(async n=>{let e=Os(n.root),t=Number(n.port);if(!Number.isInteger(t)||t<=0||t>65535)throw new Error(`Invalid --port "${n.port}".`);let o,r,a=async s=>{let i=Date.now(),c=await Fs(e,n.publisher?{publisher:n.publisher}:{});if(o=c,n.search){let u=new Hs,p=await u.build(c.catalog,{cacheDir:Ls(Us(),".kanonak","search"),include:d=>c.localNamespaces.has(d.namespace??"")});r=u,console.log(`[search] indexed ${p.size} resource(s)${p.cached?" (from cache)":""}`)}let l=c.availablePublishers.filter(u=>u!==c.publisher);console.log(`[model] serving ${c.publisher} \u2014 ${c.pkgVersions.size} package(s)${s?` (${s})`:""} in ${Date.now()-i}ms`+(l.length?` [also in workspace: ${l.join(", ")} \u2014 switch with --publisher]`:""))};try{await a()}catch(s){console.error(`[error] ${s.message}`),process.exitCode=1;return}if(n.watch){let s;Ns(e,{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")}As(async(s,i)=>{let c="/";try{let l=new URL(s.url??"/","http://localhost");c=decodeURIComponent(l.pathname);let u=l.searchParams.get("q");if(u&&r){let d=await r.query(u,{scope:Bs(o.publisher,c),limit:30}),f=Ws(o,u,d);i.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),i.end(f),console.log(`200 ${s.method} ${c}?q=${u} (${d.length} hit(s))`);return}let p=Ms(o,c,s.headers.accept??"");i.writeHead(p.status,p.headers),i.end(p.body),console.log(`${p.status} ${s.method} ${c}${p.headers.Location?` -> ${p.headers.Location}`:""}`)}catch(l){i.writeHead(500,{"Content-Type":"text/plain; charset=utf-8"}),i.end(String(l?.stack??l)),console.error(`500 ${c}: ${l?.message??l}`)}}).listen(t,()=>{console.log(`kanonak origin server \u2192 http://localhost:${t}/ (root=${e})`),n.search&&console.log("[search] enabled \u2014 append ?q=<keywords> at any level")})})}function Bs(n,e){let t=e.split("/").filter(Boolean);if(t.length!==0)return`${n}/${t[0]}@`}function qs(n,e){let t=zs(e);if(!t)return"#";let o=t.version?`/${t.version.major}.${t.version.minor}.${t.version.patch}`:"";return t.publisher===n.publisher?`/${t.package_}${o}/${t.name}`:`https://${t.publisher}/${t.package_}${o}/${t.name}`}function W(n){return n.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}function Ws(n,e,t){let o=t.map(r=>{let a=Vs(n.catalog,r.subject),s=qs(n,r.subject),i=Math.max(0,Math.min(100,Math.round(r.score*100))),c=a.summary?`<span class="kan-pkg-card-comment">${W(a.summary.slice(0,160))}</span>`:"";return`<a class="kan-pkg-card" href="${W(s)}"><span class="kan-pkg-card-body"><span class="kan-pkg-card-title">${W(a.label)}</span>${c}<span style="display:block;height:5px;border-radius:3px;margin-top:8px;background:var(--kan-accent,#888);width:${i}%"></span><span class="kan-pkg-card-comment">${i}% match</span></span></a>`}).join("");return`<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Search: ${W(e)}</title><link rel="stylesheet" href="/index.css"></head><body><main class="kan-page" style="max-width:960px;margin:0 auto;padding:2rem"><form method="get" style="margin-bottom:1.5rem"><input name="q" value="${W(e)}" placeholder="Search\u2026" style="width:100%;padding:.6rem .8rem;font-size:1rem;box-sizing:border-box"></form><h1>Results for \u201C${W(e)}\u201D</h1><section class="kan-pkg-grid">${o||"<p>No matches.</p>"}</section></main></body></html>`}import{Command as Gs}from"commander";import{resolve as Js,join as Ys}from"path";import{homedir as Xs}from"os";import{readFileSync as Zs}from"fs";import{KanonakParser as Qn,KanonakObjectParser as Qs,PublisherIndex as et,CredentialStore as nt,createAuthenticatedFetch as tt,FileSystemKanonakDocumentRepository as ea,Reasoner as na,KanonakVocabulary as ta,getGlobalCachePath as oa,makeUriKey as ra,resolveDisplayValue as sa,subjectUri as aa,contextTypesOf as ia,collectKanonakFiles as ca}from"@kanonak-protocol/sdk";import{SearchIndex as la}from"@kanonak-protocol/sdk/search";function ua(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 ot(){return new Gs("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 pa(e);return}n||(console.error(`Nothing to search. Either:
|
|
117
|
+
`}import{Command as Jn}from"commander";import{writeFileSync as Ae,mkdirSync as oe}from"fs";import{join as Oe,resolve as $a,dirname as Ne}from"path";import{KanonakParser as va,KanonakObjectParser as Sa,SubjectKanonak as Yn,ReferenceStatement as Pa,ReferenceKanonak as Ca,ListStatement as _a,StringStatement as Xn,EmbeddedStatement as Ra,findDerivation as Bn}from"@kanonak-protocol/sdk";import{SingleDocumentRepository as xa}from"@kanonak-protocol/sdk/uri-helpers";import{TransformationRunnerV3 as Ia}from"@kanonak-protocol/sdk/transformations";import{findSubjectsByType as re}from"@kanonak-protocol/sdk/uri-helpers";var E="kanonak.org",j="site",qn={publisher:"kanonak.org",package_:"formats",name:"html"},Wn={publisher:"kanonak.org",package_:"derivation",name:"default"};function Zn(){let n=new Jn("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(Ka()),n}function Ka(){return new Jn("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 Da(n)}catch(e){console.error(`Error: ${e.message}`),process.exit(1)}})}async function Da(n){let e=new va,t=new Sa,o=await v(process.cwd(),e),r=await t.parseKanonaks(o),s=$a(n.out);oe(s,{recursive:!0});let a=await o.getAllDocumentsAsync(),i=new Set;for(let m of a){let k=m.metadata.namespace_?.toString();k&&i.add(k)}let c={publisher:E,package_:j,name:"StaticPage"},l={publisher:E,package_:j,name:"ResourcePage"},u={publisher:E,package_:j,name:"AggregateView"},p=re(r,c).filter(m=>i.has(m.namespace||"")),d=re(r,l).filter(m=>i.has(m.namespace||"")),f=re(r,u).filter(m=>i.has(m.namespace||""));console.log(`Found ${p.length} StaticPage(s), ${d.length} ResourcePage(s), and ${f.length} AggregateView(s) in the workspace.`);let g=new Ia;for(let m of p){let k=Le(m,E,j,"outputPath")??`${m.name}.html`,h=Bn(m,qn,Wn,r);if(!h){console.warn(` [skip] ${m.name}: no HTML/default derivation found (check class hierarchy or universal-derivations is loaded)`);continue}let y=Ue(r,h.transformation);if(!y){console.warn(` [skip] ${m.name}: transformation ${Fe(h.transformation)} not found`);continue}let b=await g.run({transformation:y,instances:[m],allKanonaks:r,repository:o,parser:e,objectParser:t,outputFormat:"html"});if(b.length===0){console.warn(` [skip] ${m.name}: transformation produced no artifacts`);continue}let w=Oe(s,k);oe(Ne(w),{recursive:!0}),Ae(w,b[0].content,"utf-8"),console.log(` wrote ${w} (StaticPage ${m.name})`)}for(let m of d){let k=Le(m,E,j,"outputPath")??`${m.name}.html`,h=Gn(m,E,j,"pageOf");if(!h){console.warn(` [skip] ${m.name}: no pageOf declared`);continue}let y=r.find(D=>D instanceof Yn&&D.name===h.name&&(D.namespace||"").startsWith(`${h.publisher}/${h.package_}@`));if(!y){console.warn(` [skip] ${m.name}: pageOf target ${h.publisher}/${h.package_}/${h.name} not found`);continue}let b=Bn(y,qn,Wn,r);if(!b){console.warn(` [skip] ${m.name}: no derivation for target ${y.name}`);continue}let w=Ue(r,b.transformation);if(!w){console.warn(` [skip] ${m.name}: transformation ${Fe(b.transformation)} not found`);continue}let $=await g.run({transformation:w,instances:[y],allKanonaks:r,repository:o,parser:e,objectParser:t,outputFormat:"html"});if($.length===0){console.warn(` [skip] ${m.name}: transformation produced no artifacts`);continue}let _=Oe(s,k);oe(Ne(_),{recursive:!0}),Ae(_,$[0].content,"utf-8"),console.log(` wrote ${_} (ResourcePage ${m.name} \u2192 ${y.name})`)}for(let m of f){let k=Le(m,E,j,"outputPath");if(!k){console.warn(` [skip] ${m.name}: no outputPath declared`);continue}let h=Gn(m,E,j,"scopeClass");if(!h){console.warn(` [skip] ${m.name}: no scopeClass declared`);continue}let y={publisher:h.publisher,package_:h.package_,name:h.name},b=Ta(m,E,j,"scopeSources"),w=Ea(m);if(!w){console.warn(` [skip] ${m.name}: no transformation declared`);continue}let $=Ue(r,w);if(!$){console.warn(` [skip] ${m.name}: transformation ${Fe(w)} not found`);continue}let _=await Aa(b,o),D=[],Xe=new Set;for(let Mt of _){let Vt=await Oa(Mt,o,e,t),Ht=re(Vt,y);for(let be of Ht){let Qe=`${be.namespace}/${be.name}`;Xe.has(Qe)||(Xe.add(Qe),D.push(be))}}console.log(` ${m.name}: ${D.length} instance(s) of ${y.publisher}/${y.package_}/${y.name} across ${_.length} scope(s)`);let Ze=await g.run({transformation:$,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 ye=Oe(s,k);oe(Ne(ye),{recursive:!0}),Ae(ye,Ze[0].content,"utf-8"),console.log(` wrote ${ye} (AggregateView ${m.name})`)}console.log("Site build complete.")}function Le(n,e,t,o){for(let r of n.statement)if(r instanceof Xn&&ae(r,e,t,o))return r.object}function Ta(n,e,t,o){for(let r of n.statement){if(!(r instanceof _a)||!ae(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 Gn(n,e,t,o){for(let r of n.statement)if(r instanceof Pa&&ae(r,e,t,o)&&r.object instanceof Ca)return{publisher:r.object.subject.publisher,package_:r.object.subject.package_,name:r.object.subject.name}}function Ea(n){for(let e of n.statement)if(e instanceof Ra&&ae(e,E,j,"transformation"))return ja(e.object)}function ja(n){let e,t,o,r;for(let s of n.statement){if(!(s instanceof Xn))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 ae(n,e,t,o){let r=n.predicate?.subject;return r?r.publisher===e&&r.package_===t&&r.name===o:!1}function Ue(n,e){let t=`${e.publisher}/${e.package_}@${e.version}`;for(let o of n)if(o instanceof Yn&&o.name===e.name&&o.namespace===t)return o}function Fe(n){return`${n.publisher}/${n.package_}@${n.version}/${n.name}`}async function Aa(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 Oa(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 xa(u,e);return o.parseKanonaks(d)}}return[]}import{Command as Na}from"commander";import{createServer as La}from"http";import{watch as Ua}from"fs";import{resolve as Fa,join as Ma}from"path";import{homedir as Va}from"os";import{loadServerModel as Ha,route as za}from"@kanonak-protocol/sdk/server";import{SearchIndex as Ba}from"@kanonak-protocol/sdk/search";import{resolveDisplayValue as qa,subjectUri as Wa}from"@kanonak-protocol/sdk";function Qn(){return new Na("serve").description("Serve a publisher's workspace as a live origin \u2014 the same rendering `kanonak publish` produces, plus the machine-facing publisher endpoints, from one process. Use --watch for a dev preview.").option("--root <dir>","Workspace root to serve.",".").option("--port <number>","Port to listen on.","8080").option("--publisher <domain>","Publisher to serve (required only if the workspace has more than one).").option("--watch","Re-load the workspace on .kan.yml changes.",!1).option("--search","Enable opt-in semantic search at ?q= (builds an embedding index).",!1).action(async n=>{let e=Fa(n.root),t=Number(n.port);if(!Number.isInteger(t)||t<=0||t>65535)throw new Error(`Invalid --port "${n.port}".`);let o,r,s=async a=>{let i=Date.now(),c=await Ha(e,n.publisher?{publisher:n.publisher}:{});if(o=c,n.search){let u=new Ba,p=await u.build(c.catalog,{cacheDir:Ma(Va(),".kanonak","search"),include:d=>c.localNamespaces.has(d.namespace??"")});r=u,console.log(`[search] indexed ${p.size} resource(s)${p.cached?" (from cache)":""}`)}let l=c.availablePublishers.filter(u=>u!==c.publisher);console.log(`[model] serving ${c.publisher} \u2014 ${c.pkgVersions.size} package(s)${a?` (${a})`:""} in ${Date.now()-i}ms`+(l.length?` [also in workspace: ${l.join(", ")} \u2014 switch with --publisher]`:""))};try{await s()}catch(a){console.error(`[error] ${a.message}`),process.exitCode=1;return}if(n.watch){let a;Ua(e,{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")}La(async(a,i)=>{let c="/";try{let l=new URL(a.url??"/","http://localhost");c=decodeURIComponent(l.pathname);let u=l.searchParams.get("q");if(u&&r){let d=await r.query(u,{scope:Ga(o.publisher,c),limit:30}),f=Ya(o,u,d);i.writeHead(200,{"Content-Type":"text/html; charset=utf-8"}),i.end(f),console.log(`200 ${a.method} ${c}?q=${u} (${d.length} hit(s))`);return}let p=za(o,c,a.headers.accept??"");i.writeHead(p.status,p.headers),i.end(p.body),console.log(`${p.status} ${a.method} ${c}${p.headers.Location?` -> ${p.headers.Location}`:""}`)}catch(l){i.writeHead(500,{"Content-Type":"text/plain; charset=utf-8"}),i.end(String(l?.stack??l)),console.error(`500 ${c}: ${l?.message??l}`)}}).listen(t,()=>{console.log(`kanonak origin server \u2192 http://localhost:${t}/ (root=${e})`),n.search&&console.log("[search] enabled \u2014 append ?q=<keywords> at any level")})})}function Ga(n,e){let t=e.split("/").filter(Boolean);if(t.length!==0)return`${n}/${t[0]}@`}function Ja(n,e){let t=Wa(e);if(!t)return"#";let o=t.version?`/${t.version.major}.${t.version.minor}.${t.version.patch}`:"";return t.publisher===n.publisher?`/${t.package_}${o}/${t.name}`:`https://${t.publisher}/${t.package_}${o}/${t.name}`}function W(n){return n.replace(/&/g,"&").replace(/</g,"<").replace(/>/g,">").replace(/"/g,""")}function Ya(n,e,t){let o=t.map(r=>{let s=qa(n.catalog,r.subject),a=Ja(n,r.subject),i=Math.max(0,Math.min(100,Math.round(r.score*100))),c=s.summary?`<span class="kan-pkg-card-comment">${W(s.summary.slice(0,160))}</span>`:"";return`<a class="kan-pkg-card" href="${W(a)}"><span class="kan-pkg-card-body"><span class="kan-pkg-card-title">${W(s.label)}</span>${c}<span style="display:block;height:5px;border-radius:3px;margin-top:8px;background:var(--kan-accent,#888);width:${i}%"></span><span class="kan-pkg-card-comment">${i}% match</span></span></a>`}).join("");return`<!doctype html><html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1"><title>Search: ${W(e)}</title><link rel="stylesheet" href="/index.css"></head><body><main class="kan-page" style="max-width:960px;margin:0 auto;padding:2rem"><form method="get" style="margin-bottom:1.5rem"><input name="q" value="${W(e)}" placeholder="Search\u2026" style="width:100%;padding:.6rem .8rem;font-size:1rem;box-sizing:border-box"></form><h1>Results for \u201C${W(e)}\u201D</h1><section class="kan-pkg-grid">${o||"<p>No matches.</p>"}</section></main></body></html>`}import{Command as Xa}from"commander";import{resolve as Za,join as Qa}from"path";import{loadLockFile as es,computeIntegrity as Me}from"@kanonak-protocol/sdk";function et(){return new Xa("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 ts(n)})}function ns(n){let e=n.indexOf("/");if(!(e<0))return{publisher:n.slice(0,e),package_:n.slice(e+1)}}async function ts(n){let e=Za(n.workspace),t=es(Qa(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=ns(u);if(!d){console.error(` \u2717 ${u} \u2014 unparseable lock key`),a+=1;continue}let{publisher:f,package_:g}=d,m=o.get(f,g,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 k=await os(u,p);k?(console.error(k),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(`
|
|
118
|
+
${l.join(", ")}.`),a>0&&(console.error("Integrity verification FAILED \u2014 a package does not match the committed lock."),process.exit(1)),console.log("Integrity verified.")}async function os(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})
|
|
119
|
+
lock: ${e.integrity}
|
|
120
|
+
origin: ${r}`}catch(t){return` \u2717 ${n} \u2014 origin fetch failed: ${t.message}`}}import{Command as rs}from"commander";import{resolve as as,join as ss}from"path";import{homedir as is}from"os";import{readFileSync as cs}from"fs";import{KanonakParser as nt,KanonakObjectParser as ls,PublisherIndex as tt,CredentialStore as ot,createAuthenticatedFetch as rt,FileSystemKanonakDocumentRepository as us,Reasoner as ps,KanonakVocabulary as ds,getGlobalCachePath as ms,makeUriKey as fs,resolveDisplayValue as gs,subjectUri as hs,contextTypesOf as ks,collectKanonakFiles as ys}from"@kanonak-protocol/sdk";import{SearchIndex as bs}from"@kanonak-protocol/sdk/search";function ws(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 at(){return new rs("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 $s(e);return}n||(console.error(`Nothing to search. Either:
|
|
118
121
|
\u2022 semantic-search your workspace: kanonak search -q "<keywords>"
|
|
119
122
|
\u2022 browse a publisher's catalogue: kanonak search <publisher>
|
|
120
|
-
\u2022 find instances of a class: kanonak search <publisher> --type <pub>/<pkg>/<Name>`),process.exit(1)),e.type?await
|
|
121
|
-
`)}catch(u){console.error(u.message),process.exit(1)}
|
|
122
|
-
`);for(let u of l)console.log(` ${u.score.toFixed(3)} ${u.label}${u.type?` (${u.type})`:""}`),console.log(` ${u.uri}`)}async function
|
|
123
|
-
`);let
|
|
124
|
-
`),m.sort();for(let k of m)console.log(` ${k}`)}async function
|
|
123
|
+
\u2022 find instances of a class: kanonak search <publisher> --type <pub>/<pkg>/<Name>`),process.exit(1)),e.type?await Ss(n,e.type):await vs(n)})}async function $s(n){let e=as(n.root??"."),t=new nt,o;try{let u=await v(e,t);o=await new ls().parseKanonaks(u)}catch(u){console.error(`Failed to load workspace at ${e}: ${u.message}`),process.exit(1)}let r={cacheDir:ss(is(),".kanonak","search"),onProgress:(u,p)=>process.stderr.write(`\r embedding ${u}/${p}\u2026 `)};if(!n.all){let u=new Set;for(let p of ys(e))try{let d=t.parse(cs(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 s=new bs,a;try{a=await s.build(o,r),a.size>0&&!a.cached&&process.stderr.write(`
|
|
124
|
+
`)}catch(u){console.error(u.message),process.exit(1)}a.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 s.query(n.query,{scope:n.scope,limit:i})).map(u=>{let p=gs(o,u.subject),d=hs(u.subject),f=ks(u.subject)[0]?.name;return{uri:d?`${d.publisher}/${d.package_}/${d.name}`:u.subject.name,label:p.label,type:f??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}":
|
|
125
|
+
`);for(let u of l)console.log(` ${u.score.toFixed(3)} ${u.label}${u.type?` (${u.type})`:""}`),console.log(` ${u.uri}`)}async function vs(n){let e=new ot,t=rt(e),o=new tt({fetchFn:t}),r;try{r=await o.listLatestPackages(n)}catch(a){console.error(`Failed to fetch publisher index for ${n}: ${a.message}`),process.exit(1)}if(r.length===0){console.log(`No packages found at ${n}.`);return}console.log(`Packages published by ${n}:
|
|
126
|
+
`);let s=r.reduce((a,i)=>Math.max(a,i.packageName.length),0);for(let{packageName:a,version:i}of r)console.log(` ${a.padEnd(s)} @${i}`)}async function Ss(n,e){let t=ws(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 nt,r=new ot,s=rt(r),a=new tt({fetchFn:s}),i=new K,c=new Set,l=[];try{l=await a.listLatestPackages(n)}catch(k){console.error(`Failed to fetch publisher index for ${n}: ${k.message}`),process.exit(1)}for(let{packageName:k,version:h}of l)c.add(`${n}|${k}|${h}`);await Ve(a,i,s,"kanonak.org","core-rdf",c),await Ve(a,i,s,"kanonak.org","core-owl",c),await Ve(a,i,s,t.publisher,t.package_,c);for(let k of c){let[h,y,b]=k.split("|");if(!i.has(h,y,b))try{let w=await a.getPackageUrl(h,y,b),$=await s(w,h);if(!$.ok){console.error(`Warning: failed to fetch ${h}/${y}@${b}: ${$.status} ${$.statusText}`);continue}let _=await $.text();i.put(h,y,b,_)}catch(w){console.error(`Warning: failed to fetch ${h}/${y}@${b}: ${w.message}`)}}let u=new us(ms(),!0,o),d=await new ps({vocabulary:new ds}).reason(u),f=fs(t.publisher,t.package_,t.name),m=d.getInstancesOfClass(f).filter(k=>k!==f);if(m.length===0){console.log(`No instances of ${f} found in ${n}'s catalogue.`);return}console.log(`Instances of ${f} in ${n}'s catalogue:
|
|
127
|
+
`),m.sort();for(let k of m)console.log(` ${k}`)}async function Ve(n,e,t,o,r,s){try{let a=await n.getHighestVersion(o,r);if(!a)return;s.add(`${o}|${r}|${a}`)}catch{}}import{existsSync as Ps,readFileSync as Cs}from"fs";import{dirname as _s,resolve as Rs}from"path";import{KanonakObjectParser as xs,KanonakParser as Is,canonicalForm as Ks,canonicalHash as Ds,parseKanonakAddress as Ts,pickHighestDocument as Es}from"@kanonak-protocol/sdk";import{SingleDocumentRepository as js}from"@kanonak-protocol/sdk/uri-helpers";async function st(n,e={}){let t=new Is,o=new xs,{document:r,source:s}=await As(n,t),a=await v(Os(s),t),i=new js(r,a),c=await o.parseKanonaks(i),l=Ds(c);if(console.log(l),e.verbose){let u=Ks(c);process.stderr.write(`# canonical form for ${s}
|
|
125
128
|
`),process.stderr.write(u),process.stderr.write(`
|
|
126
|
-
`)}}async function
|
|
127
|
-
`);for(let
|
|
128
|
-
Updated ${i} instance(s).`)}async search(e,t){let o=t.publisher??"kanonak.org",r=
|
|
129
|
-
`);let
|
|
130
|
-
`);let g=new Map;for(let m of d){let k=`${m.publisher}/${m.package_}@${m.version}`,h=g.get(k);h?h.push(m):g.set(k,[m])}for(let[m,k]of g){let h=k[0],y=`${h.publisher}/${h.package_}`,b=k.length===1;console.log(` ${m}`),console.log(` ${k.length} skill${b?"":"s"}:`);for(let w of k)console.log(` - ${w.subject.name}`);if(console.log(""),b)console.log(" install:"),console.log(` kanonak ${e.commandName} add ${y}/${h.subject.name}`);else{console.log(" install one of them:");for(let w of k)console.log(` kanonak ${e.commandName} add ${y}/${w.subject.name}`);console.log(" install all of them:"),console.log(` kanonak ${e.commandName} add ${y}`)}console.log("")}}async info(e,t,o){let
|
|
131
|
-
`;function ue(n){let e=
|
|
132
|
-
`;function ge(n){let e=
|
|
129
|
+
`)}}async function As(n,e){if(n.endsWith(".kan.yml")){let i=Rs(n);if(!Ps(i))throw new Error(`kanonak hash: file not found: ${i}`);let c=Cs(i,"utf-8");return{document:e.parse(c),source:i}}let t=Ts(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 v(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 s=t.version?`${t.version.major}.${t.version.minor}.${t.version.patch}`:void 0,a=Es(r,s?{requestedVersion:s}:{});if(!a.chosen){let i=s?`@${s}`:"";throw new Error(`kanonak hash: no version of ${t.publisher}/${t.package_}${i} available across local/cache/HTTP`)}return{document:a.chosen,source:n}}function Os(n){return n.endsWith(".kan.yml")?N(_s(n)):process.cwd()}import{Command as it}from"commander";function G(n){return`${P}/${C}/${n}`}var He={[G("fetch-and-deploy")]:(n,e,t,o)=>n.add(e,t[0],o),[G("remove-deployed")]:(n,e,t,o)=>n.remove(e,t[0],o),[G("list-deployed")]:(n,e,t,o)=>n.list(e,o),[G("update-deployed")]:(n,e,t,o)=>n.update(e,t[0],o),[G("search-available")]:(n,e,t,o)=>n.search(e,o),[G("show-info")]:(n,e,t,o)=>n.info(e,t[0],o)};function ct(n,e,t){for(let o of e){let r=new it(o.commandName).description(o.description.trim());for(let s of o.commands){let a=r.command(Ns(s));a.description(s.description);for(let i of s.arguments)if(i.isOption){let c=i.defaultValue!=null?`--${i.argumentName} [value]`:`--${i.argumentName} <value>`;a.option(c,"",i.defaultValue)}a.action(async(...i)=>{let c=Ls(i);await Us(t,o,s,i,c)})}n.addCommand(r)}}function Ns(n){let e=n.arguments.filter(t=>!t.isOption).map(t=>t.required?`<${t.argumentName}>`:`[${t.argumentName}]`);return[n.subcommandName,...e].join(" ")}function Ls(n){for(let e=n.length-1;e>=0;e--)if(n[e]&&typeof n[e]=="object"&&!(n[e]instanceof it))return n[e];return{}}async function Us(n,e,t,o,r){let s=[];for(let i of o)if(typeof i=="string")s.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 a=He[t.actionKey];a||(console.error(`Capability subcommand '${t.subcommandName}' references unknown Action '${t.actionKey}'. Known actions: ${Object.keys(He).join(", ")}.`),process.exit(1)),await a(n,e,s,r)}import{existsSync as lt,readFileSync as Fs,statSync as ut}from"fs";import{resolve as Ms}from"path";import{KanonakObjectParser as Vs,PublisherIndex as ze,PublisherConfigResolver as Hs,formatVersion as pt,pickHighestDocument as zs}from"@kanonak-protocol/sdk";import{SingleDocumentRepository as dt}from"@kanonak-protocol/sdk/uri-helpers";import{uriKey as J,findSubjectsByType as mt}from"@kanonak-protocol/sdk/uri-helpers";var se=class{constructor(e,t,o,r,s,a){this.fileCache=e;this.parser=t;this.publisherIndex=o;this.fetchFn=r;this.handlerRegistry=s;this.repository=a}fileCache;parser;publisherIndex;fetchFn;handlerRegistry;repository;objectParser=new Vs;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 s=T(t);s||(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:a,packageName:i,version:c,instanceName:l}=s,u=await this.repository.getDocumentsByNamespaceAsync(a,i);if(u.length>0){let f=zs(u,{requestedVersion:c??void 0});if(f.chosen){let g=f.chosen.metadata.namespace_;(!g||!g.version)&&(console.error(`Document for ${a}/${i} is missing namespace metadata.`),process.exit(1));let m=pt(g.version);this.fileCache.put(a,i,m,this.parser.save(f.chosen)),await this.deployFromDoc(e,f.chosen,a,i,m,l??void 0,`${a}/${i}@${m}`,o);return}}let p=c??await this.publisherIndex.getHighestVersion(a,i);p||(console.error(`Could not resolve version for "${a}/${i}".`),await this.printPackageSuggestions(a,i,e.commandName),process.exit(1));let d=this.fileCache.get(a,i,p);if(!d){let f=await this.publisherIndex.getPackageUrl(a,i,p),g=await this.fetchFn(f,a);g.ok||(g.status===404?(console.error(`Package ${a}/${i}@${p} not found at ${f}.`),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 ${f} (${g.status} ${g.statusText}).`),process.exit(1)),d=await g.text(),this.fileCache.put(a,i,p,d)}await this.deployFromDoc(e,this.parser.parse(d),a,i,p,l??void 0,`${a}/${i}@${p}`,o)}tryLoadFromLocalFile(e){if(!(/^[.\/\\]/.test(e)||/^[A-Za-z]:[\\/]/.test(e)||e.endsWith(".kan.yml")||lt(e)&&ut(e).isFile()))return;let o=Ms(e);(!lt(o)||!ut(o).isFile())&&(console.error(`Local file not found: ${e}`),process.exit(1));let r=Fs(o,"utf-8"),s=this.parser.parse(r),a=s.metadata.namespace_;return(!a||!a.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:s,content:r,publisher:a.publisher,packageName:a.package_,version:pt(a.version)}}async deployFromDoc(e,t,o,r,s,a,i,c){let l=new dt(t,this.repository),u=await this.objectParser.parseKanonaks(l),p=ft(e.managesTypeKey);p||(console.error(`Capability "${e.commandName}" has no resolved managesType.`),process.exit(1));let d=mt(u,p);d.length===0&&(console.error(`${i} does not contain any ${J(p)} instances.`),process.exit(1));let f=d;if(a&&(f=d.filter(k=>k.name===a),f.length===0)){console.error(`Instance "${a}" not found in ${i}.`),console.error(""),console.error(`Available ${J(p)} instance(s):`);for(let k of d)console.error(` - ${k.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 g=a?`${a} from ${i}`:`${f.length} ${J(p)} instance(s) from ${i}`;console.log(`Installing ${g}...`);let m=this.handlerRegistry.get(e.deploymentTargetKey);m?await m.deploy({instances:f,allKanonaks:u,repository:this.repository,options:c}):console.log(`Cached ${o}/${r}@${s} (no deployment handler for "${e.deploymentTargetKey}")`)}async printPackageSuggestions(e,t,o){let r;try{r=await this.publisherIndex.listLatestPackages(e)}catch{return}let s=r.map(a=>({name:a.packageName,version:a.version,score:Bs(t,a.packageName)})).filter(a=>a.score>0).sort((a,i)=>i.score-a.score).slice(0,5);if(s.length!==0){console.error(""),console.error("Did you mean one of:");for(let a of s)console.error(` kanonak ${o} add ${e}/${a.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}),s=e.managesTypeKey||"managed";if(r.length===0){console.log(`No ${s} instances installed.`);return}console.log(`Installed ${s} instances:
|
|
130
|
+
`);for(let a of r){let i=a.publisher?`${a.publisher}/${a.package_}@${a.version}`:"unmanaged";console.log(` ${a.name} (${i}) ${a.path}`)}}async update(e,t,o){let s=await this.requireHandler(e).list({repository:this.repository,options:o}),a=t?s.filter(c=>c.name===t):s.filter(c=>c.publisher);if(a.length===0){console.log(t?`"${t}" not found.`:"No managed instances to update.");return}let i=0;for(let c of a){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.":`
|
|
131
|
+
Updated ${i} instance(s).`)}async search(e,t){let o=t.publisher??"kanonak.org",r=ft(e.managesTypeKey);if(!r){console.error("Capability has no resolved managesType; nothing to search for.");return}console.log(`Searching ${o} for ${J(r)} instances...
|
|
132
|
+
`);let s=new Hs,a=await s.getConfig(o),i=s.resolveIndexUrl(o,a),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,k]of u){let h=[...k].sort((y,b)=>{let w=ze.parseVersion(y),$=ze.parseVersion(b);return!w||!$?0:w.major!==$.major?$.major-w.major:w.minor!==$.minor?$.minor-w.minor:$.patch-w.patch});p.set(m,h[0])}let d=[],f=0;for(let[m,k]of p){let h=this.fileCache.get(o,m,k);if(!h)try{let y=await this.publisherIndex.getPackageUrl(o,m,k),b=await this.fetchFn(y,o);if(!b.ok)continue;h=await b.text(),this.fileCache.put(o,m,k,h)}catch{continue}try{let y=this.parser.parse(h),b=new dt(y,this.repository),w=await this.objectParser.parseKanonaks(b),$=mt(w,r);for(let _ of $)d.push({publisher:o,package_:m,version:k,subject:_});f++}catch{continue}}if(d.length===0){console.log(`No ${J(r)} instances found across ${f} package(s).`);return}console.log(`Found ${d.length} ${J(r)} instance(s) in ${f} package(s):
|
|
133
|
+
`);let g=new Map;for(let m of d){let k=`${m.publisher}/${m.package_}@${m.version}`,h=g.get(k);h?h.push(m):g.set(k,[m])}for(let[m,k]of g){let h=k[0],y=`${h.publisher}/${h.package_}`,b=k.length===1;console.log(` ${m}`),console.log(` ${k.length} skill${b?"":"s"}:`);for(let w of k)console.log(` - ${w.subject.name}`);if(console.log(""),b)console.log(" install:"),console.log(` kanonak ${e.commandName} add ${y}/${h.subject.name}`);else{console.log(" install one of them:");for(let w of k)console.log(` kanonak ${e.commandName} add ${y}/${w.subject.name}`);console.log(" install all of them:"),console.log(` kanonak ${e.commandName} add ${y}`)}console.log("")}}async info(e,t,o){let a=(await this.requireHandler(e).list({repository:this.repository,options:o})).find(i=>i.name===t);a||(console.error(`"${t}" is not installed.`),process.exit(1)),console.log(`Name: ${a.name}`),console.log(`Type: ${e.managesTypeKey||"n/a"}`),console.log(`Publisher: ${a.publisher||"unmanaged"}`),console.log(`Package: ${a.package_||"n/a"}`),console.log(`Version: ${a.version||"n/a"}`),console.log(`Path: ${a.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 ft(n){if(!n)return;let e=n.split("/");if(e.length===3)return{publisher:e[0],package_:e[1],name:e[2]}}function Bs(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)),s=new Set(o.split("-").filter(Boolean)),a=0;for(let c of r)s.has(c)&&a++;if(a>0)return a*10;let i=qs(t,o);return i===0?100:i<=2?Math.max(1,20-i*5):0}function qs(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 s=0;s<e.length;s++){let a=n[r]===e[s]?0:1;o[s+1]=Math.min(o[s]+1,t[s+1]+1,t[s]+a)}for(let s=0;s<=e.length;s++)t[s]=o[s]}return t[e.length]}var ie=class{handlers=new Map;register(e,t){this.handlers.set(e,t)}get(e){return this.handlers.get(e)??null}};import{mkdirSync as ri,rmSync as ai,existsSync as pe,readdirSync as si,writeFileSync as ii}from"fs";import{join as de}from"path";import{KanonakObjectParser as ci,KanonakParser as li,computeIntegrity as ui,compareVersions as pi}from"@kanonak-protocol/sdk";import{findSubjectsByType as di}from"@kanonak-protocol/sdk/uri-helpers";import{SingleDocumentRepository as mi}from"@kanonak-protocol/sdk/uri-helpers";import{TransformationRunnerV3 as fi}from"@kanonak-protocol/sdk/transformations";import{TX_V3 as gi}from"@kanonak-protocol/sdk/transformations";import{join as Be}from"path";import{homedir as gt}from"os";import{KanonakObjectParser as Ws}from"@kanonak-protocol/sdk";import{SingleDocumentRepository as Gs}from"@kanonak-protocol/sdk/uri-helpers";import{findSubjectsByType as kt,getStringValue as ce}from"@kanonak-protocol/sdk/uri-helpers";var U="kanonak.org",F="agent-skills",yt={publisher:U,package_:F,name:"Client"},bt={publisher:U,package_:F,name:"clientId"},Js={publisher:U,package_:F,name:"projectSkillDir"},Ys={publisher:U,package_:F,name:"userSkillDir"},Xs={publisher:U,package_:F,name:"skillFileName"},wt="agents";async function ee(n,e){let t=(n.client??$t()??wt).toLowerCase(),o=n.scope??"project",r=await St(t,e);if(!r){let i=await Zs(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 a=ce(r,o==="user"?Ys:Js);if(!a)throw new Error(`Client "${t}" has no ${o==="user"?"userSkillDir":"projectSkillDir"} declared.`);return Qs(a)}async function le(n,e,t){let o=await ee(e,t);return Be(o,n)}async function qe(n,e){let t=(n.client??$t()??wt).toLowerCase(),o=await St(t,e);return o?ce(o,Xs)??"SKILL.md":"SKILL.md"}function $t(){if(process.env.CLAUDE_CODE||process.env.CLAUDE_PROJECT_DIR)return"claude-code"}var ht=new WeakMap;async function vt(n){let e=ht.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],s=new Ws,a=new Gs(r,n),i=await s.parseKanonaks(a);return ht.set(n,i),i}async function St(n,e){let t=await vt(e),o=kt(t,yt);for(let r of o)if(ce(r,bt)===n)return r}async function Zs(n){let e=await vt(n),t=kt(e,yt),o=[];for(let r of t){let s=ce(r,bt);s&&o.push(s)}return o}function Qs(n){return n.startsWith("~/")?Be(gt(),n.slice(2)):n==="~"?gt():n.startsWith("/")||/^[A-Za-z]:[\\/]/.test(n)?n:Be(process.cwd(),n)}import{readFileSync as ei,writeFileSync as ni,existsSync as ti}from"fs";import{join as Pt}from"path";import Ct from"js-yaml";var _t="skills.lock",oi=`# This file is generated by Kanonak CLI. Do not edit manually.
|
|
134
|
+
`;function ue(n){let e=Pt(n,_t);if(!ti(e))return{version:"1",lastUpdated:new Date().toISOString(),skills:{}};let t=ei(e,"utf-8"),o=Ct.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 s of Object.keys(e.skills).sort())t[s]=e.skills[s];e.skills=t;let o=Pt(n,_t),r=Ct.dump(e,{lineWidth:-1,sortKeys:!1,quotingType:'"'});ni(o,oi+r,"utf-8")}var Rt="kanonak.org",xt="skill-to-skill-md",me=class{parser=new li;objectParser=new ci;runner=new fi;async deploy(e){let{instances:t,allKanonaks:o,repository:r,options:s}=e;if(t.length===0){console.error("No Skill instances to deploy.");return}let a=await hi(r,this.objectParser);if(!a){console.error(`Cannot deploy: ${Rt}/${xt}@3.0.0 is not installed in the workspace or cache.`);return}let i=await this.runner.run({transformation:a,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 ee(s,r),l=await qe(s,r),u=ue(c),p=t[0].namespace,{publisher:d,package_:f,version:g}=ki(p);for(let m of i){let k=await le(m.fileName,s,r),h=pe(de(k,l));ri(k,{recursive:!0}),ii(de(k,l),m.content,"utf-8"),u.skills[m.fileName]={publisher:d,package_:f,version:g,resolved:d?`kanonak://${d}/${f}@${g}`:"",integrity:ui(m.content)},console.log(` ${h?"Updated":"Installed"} skill "${m.fileName}" \u2192 ${k}`)}We(c,u)}async undeploy(e,t){let{repository:o,options:r}=t,s=await le(e,r,o);pe(s)||(console.error(`Skill "${e}" is not installed at ${s}`),process.exit(1)),ai(s,{recursive:!0,force:!0});let a=await ee(r,o),i=ue(a);delete i.skills[e],We(a,i),console.log(`Removed skill "${e}" from ${s}`)}async list(e){let{repository:t,options:o}=e,r=await ee(o,t),s=ue(r),a=[];for(let[c,l]of Object.entries(s.skills))a.push({name:c,publisher:l.publisher,package_:l.package_,version:l.version,path:await le(c,o,t)});let i=await qe(o,t);if(pe(r))try{let c=si(r,{withFileTypes:!0});for(let l of c){if(!l.isDirectory()||s.skills[l.name])continue;let u=de(r,l.name,i);pe(u)&&a.push({name:l.name,publisher:"",package_:"",version:"",path:de(r,l.name)})}}catch{}return a}};async function hi(n,e){let t=await n.getDocumentsByNamespaceAsync(Rt,xt);if(t.length===0)return;let o=[...t].sort((r,s)=>{let a=r.metadata.namespace_?.version,i=s.metadata.namespace_?.version;return!a||!i?0:pi(i,a)});for(let r of o){let s=new mi(r,n),a=await e.parseKanonaks(s),i=di(a,gi.InstanceTransformation);if(i[0])return i[0]}}function ki(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 Ei,rmSync as ji,existsSync as Ye,readdirSync as Ai,writeFileSync as Oi,statSync as Ni}from"fs";import{join as he}from"path";import{KanonakObjectParser as Li,KanonakParser as Ui,computeIntegrity as Fi}from"@kanonak-protocol/sdk";import{findSubjectsByType as Mi}from"@kanonak-protocol/sdk/uri-helpers";import{SingleDocumentRepository as Vi}from"@kanonak-protocol/sdk/uri-helpers";import{TransformationRunnerV3 as Hi}from"@kanonak-protocol/sdk/transformations";import{TX_V3 as zi}from"@kanonak-protocol/sdk/transformations";import{join as It}from"path";import{homedir as Kt}from"os";import{KanonakObjectParser as yi}from"@kanonak-protocol/sdk";import{SingleDocumentRepository as bi}from"@kanonak-protocol/sdk/uri-helpers";import{findSubjectsByType as Tt,getStringValue as Ge,getReferenceUri as wi}from"@kanonak-protocol/sdk/uri-helpers";var M="kanonak.org",V="agent-skills",Et={publisher:M,package_:V,name:"Client"},jt={publisher:M,package_:V,name:"clientId"},$i={publisher:M,package_:V,name:"projectAgentDir"},vi={publisher:M,package_:V,name:"userAgentDir"},Si={publisher:M,package_:V,name:"agentFileFormat"},Pi="agents";function Ci(){if(process.env.CLAUDE_CODE||process.env.CLAUDE_PROJECT_DIR)return"claude-code"}async function fe(n,e){let t=(n.client??Ci()??Pi).toLowerCase(),o=n.scope??"project",r=await _i(t,e);if(!r){let u=await Ri(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 a=Ge(r,o==="user"?vi:$i);if(!a)throw new Error(`Client "${t}" has no ${o==="user"?"userAgentDir":"projectAgentDir"} declared.`);let c=wi(r,Si)?.name==="toml"?"toml":"markdown-frontmatter",l=c==="toml"?".toml":".md";return{agentsDir:xi(a),format:c,fileExtension:l}}var Dt=new WeakMap;async function At(n){let e=Dt.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],s=new yi,a=new bi(r,n),i=await s.parseKanonaks(a);return Dt.set(n,i),i}async function _i(n,e){let t=await At(e),o=Tt(t,Et);for(let r of o)if(Ge(r,jt)===n)return r}async function Ri(n){let e=await At(n),t=Tt(e,Et),o=[];for(let r of t){let s=Ge(r,jt);s&&o.push(s)}return o}function xi(n){return n.startsWith("~/")?It(Kt(),n.slice(2)):n==="~"?Kt():n.startsWith("/")||/^[A-Za-z]:[\\/]/.test(n)?n:It(process.cwd(),n)}import{readFileSync as Ii,writeFileSync as Ki,existsSync as Di}from"fs";import{join as Ot}from"path";import Nt from"js-yaml";var Lt="agents.lock",Ti=`# This file is generated by Kanonak CLI. Do not edit manually.
|
|
135
|
+
`;function ge(n){let e=Ot(n,Lt);if(!Di(e))return{version:"1",lastUpdated:new Date().toISOString(),agents:{}};let t=Ii(e,"utf-8"),o=Nt.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 s of Object.keys(e.agents).sort())t[s]=e.agents[s];e.agents=t;let o=Ot(n,Lt),r=Nt.dump(e,{lineWidth:-1,sortKeys:!1,quotingType:'"'});Ki(o,Ti+r,"utf-8")}var Ut="kanonak.org",Ft="agent-to-agent-file",ke=class{parser=new Ui;objectParser=new Li;runner=new Hi;async deploy(e){let{instances:t,allKanonaks:o,repository:r,options:s}=e;if(t.length===0){console.error("No Agent instances to deploy.");return}let{agentsDir:a,format:i,fileExtension:c}=await fe(s,r),l=await Bi(r,this.objectParser);if(!l){console.error(`Cannot deploy: ${Ut}/${Ft}@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}Ei(a,{recursive:!0});let d=ge(a),f=t[0].namespace,{publisher:g,package_:m,version:k}=Wi(f);for(let h of p){let y=`${h.fileName}${c}`,b=he(a,y),w=Ye(b);Oi(b,h.content,"utf-8"),d.agents[h.fileName]={publisher:g,package_:m,version:k,resolved:g?`kanonak://${g}/${m}@${k}`:"",integrity:Fi(h.content),fileName:y},console.log(` ${w?"Updated":"Installed"} agent "${h.fileName}" \u2192 ${b}`)}Je(a,d)}async undeploy(e,t){let{repository:o,options:r}=t,{agentsDir:s}=await fe(r,o),a=ge(s),i=a.agents[e];i||(console.error(`Agent "${e}" is not installed at ${s}`),process.exit(1));let c=he(s,i.fileName);Ye(c)&&ji(c,{force:!0}),delete a.agents[e],Je(s,a),console.log(`Removed agent "${e}" from ${c}`)}async list(e){let{repository:t,options:o}=e,{agentsDir:r}=await fe(o,t),s=ge(r),a=[];for(let[i,c]of Object.entries(s.agents))a.push({name:i,publisher:c.publisher,package_:c.package_,version:c.version,path:he(r,c.fileName)});if(Ye(r))try{let i=Ai(r,{withFileTypes:!0});for(let c of i){if(!c.isFile()||c.name==="agents.lock")continue;let l=he(r,c.name),u=qi(c.name);if(!s.agents[u]){try{if(!Ni(l).isFile())continue}catch{continue}a.push({name:u,publisher:"",package_:"",version:"",path:l})}}}catch{}return a}};async function Bi(n,e){let t=await n.getDocumentsByNamespaceAsync(Ut,Ft);if(t.length===0)return;let o=new Vi(t[0],n),r=await e.parseKanonaks(o);return Mi(r,zi.InstanceTransformation)[0]}function qi(n){let e=n.lastIndexOf(".");return e===-1?n:n.substring(0,e)}function Wi(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 oc=Xi(Yi(import.meta.url)),rc=JSON.parse(Ji(Zi(oc,"..","package.json"),"utf-8")),R=new Gi;R.name("kanonak").description("Kanonak Protocol CLI - Validate and resolve Kanonak ontology packages").version(rc.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 an(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.").action(async(n,e)=>{await st(n,e)});R.addCommand(In());R.addCommand(On());R.addCommand(Vn());R.addCommand(zn());R.addCommand(Zn());R.addCommand(Qn());R.addCommand(at());R.addCommand(et());async function ac(){try{let n=new K,e=new Qi,t=new nc,o=tc(t),r=new ec({fetchFn:o}),s=await v(process.cwd(),e),a=new ie;a.register("kanonak.org/capabilities/agent-skill-deployment",new me),a.register("kanonak.org/agent-capabilities/agent-instance-deployment",new ke);let i=await _n(n,e,s),c=new se(n,e,r,o,a,s);ct(R,i,c)}catch{}}await ac();R.parse();
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kanonak-protocol/cli",
|
|
3
|
-
"version": "3.
|
|
3
|
+
"version": "3.59.0",
|
|
4
4
|
"description": "Kanonak Protocol CLI - Validate and resolve Kanonak ontology packages",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "./dist/index.js",
|
|
@@ -34,8 +34,8 @@
|
|
|
34
34
|
"semantic-web"
|
|
35
35
|
],
|
|
36
36
|
"dependencies": {
|
|
37
|
-
"@kanonak-protocol/sdk": "^3.
|
|
38
|
-
"@kanonak-protocol/types": "^3.
|
|
37
|
+
"@kanonak-protocol/sdk": "^3.59.0",
|
|
38
|
+
"@kanonak-protocol/types": "^3.59.0",
|
|
39
39
|
"commander": "^13.0.0",
|
|
40
40
|
"js-yaml": "^4.1.1"
|
|
41
41
|
},
|