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