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