@kanonak-protocol/cli 1.3.0 → 1.5.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.
@@ -1,5 +1,15 @@
1
- import type { KanonakParser } from '@kanonak-protocol/sdk';
1
+ import { KanonakParser } from '@kanonak-protocol/sdk';
2
+ import type { IKanonakDocumentRepository } from '@kanonak-protocol/sdk';
2
3
  import { FileCache } from '../cache/FileCache.js';
4
+ import { EntityUri } from './UriHelpers.js';
5
+ /**
6
+ * Canonical URIs from the kanonak.org/capabilities ontology that the CLI
7
+ * dispatches against. Version is intentionally omitted from matching so
8
+ * the CLI accepts any backwards-compatible minor version.
9
+ */
10
+ export declare const CAPABILITIES_PUB = "kanonak.org";
11
+ export declare const CAPABILITIES_PKG = "capabilities";
12
+ export declare const CAPABILITY_CLASS_URI: EntityUri;
3
13
  /**
4
14
  * A loaded command argument definition.
5
15
  */
@@ -10,29 +20,26 @@ export interface LoadedArgument {
10
20
  defaultValue?: string;
11
21
  }
12
22
  /**
13
- * A loaded subcommand definition.
23
+ * A loaded subcommand definition. `actionKey` is the canonical URI of
24
+ * the Action this subcommand performs, formatted as
25
+ * `publisher/package/name` (version omitted). The command registrar
26
+ * dispatches by this key.
14
27
  */
15
28
  export interface LoadedCommand {
16
29
  subcommandName: string;
17
30
  description: string;
18
31
  arguments: LoadedArgument[];
19
- /**
20
- * Name of the Action that this subcommand performs (e.g., "fetchAndDeploy",
21
- * "listDeployed"). Extracted from the `performs` property on the Kanonak
22
- * CapabilityCommand instance. Empty string when no action is specified — in
23
- * that case the dispatcher falls back to interpreting the subcommand verb
24
- * as a legacy action (add → fetchAndDeploy, list → listDeployed, etc.).
25
- */
26
- actionName: string;
32
+ actionKey: string;
27
33
  }
28
34
  /**
29
35
  * A fully loaded capability with its command structure.
36
+ * All identifier fields are canonical URI keys — not local names.
30
37
  */
31
38
  export interface LoadedCapability {
32
39
  commandName: string;
33
40
  description: string;
34
- managesType: string;
35
- deploymentTargetName: string;
41
+ managesTypeKey: string;
42
+ deploymentTargetKey: string;
36
43
  commands: LoadedCommand[];
37
44
  publisher: string;
38
45
  package_: string;
@@ -41,7 +48,14 @@ export interface LoadedCapability {
41
48
  /**
42
49
  * Load all installed capabilities from the capability store.
43
50
  *
44
- * Reads capabilities.lock, loads each capability's .kan.yml from the
45
- * file cache, parses it, and extracts the Capability instance structure.
51
+ * Reads `capabilities.lock`, looks up each capability's cached
52
+ * document, parses it through `KanonakObjectParser.parseKanonaks`
53
+ * against a `SingleDocumentRepository` that delegates import
54
+ * resolution to the given broader repo, then walks the resulting
55
+ * `SubjectKanonak.statement[]` tree to extract the Capability
56
+ * instance and its subcommands.
57
+ *
58
+ * Every identifier returned is a canonical URI key — alias handling
59
+ * happens inside the SDK, never in this file.
46
60
  */
47
- export declare function loadInstalledCapabilities(fileCache: FileCache, parser: KanonakParser): Promise<LoadedCapability[]>;
61
+ export declare function loadInstalledCapabilities(fileCache: FileCache, parser: KanonakParser, repository: IKanonakDocumentRepository): Promise<LoadedCapability[]>;
@@ -2,10 +2,11 @@ import { Command } from 'commander';
2
2
  import type { LoadedCapability } from './CapabilityLoader.js';
3
3
  import type { GenericCapabilityHandler } from './GenericCapabilityHandler.js';
4
4
  /**
5
- * Register Commander.js commands dynamically from loaded capability definitions.
6
- *
7
- * For each installed capability, creates a command group (e.g., "skill") with
8
- * subcommands (e.g., "add", "remove", "list") as defined in the capability's
9
- * Kanonak YAML. Routes actions to the GenericCapabilityHandler.
5
+ * Register Commander.js commands dynamically from loaded capability
6
+ * definitions. For each installed capability, create a command group
7
+ * named after its `commandName` property and attach each subcommand
8
+ * with its declared positional and option arguments. All routing is
9
+ * done through the Action URI each subcommand's `performs:` resolves
10
+ * to.
10
11
  */
11
12
  export declare function registerCapabilityCommands(program: Command, capabilities: LoadedCapability[], handler: GenericCapabilityHandler): void;
@@ -1,4 +1,4 @@
1
- import type { KanonakDocument, InstanceSearchResult } from '@kanonak-protocol/sdk';
1
+ import type { IKanonakDocumentRepository, SubjectKanonak, Kanonak } from '@kanonak-protocol/sdk';
2
2
  /**
3
3
  * Information about a deployed instance.
4
4
  */
@@ -10,36 +10,60 @@ export interface DeployedInstance {
10
10
  path: string;
11
11
  }
12
12
  /**
13
- * Handler that deploys/undeploys instances of a managed type to the local system.
13
+ * Context passed to a deployment handler for a `deploy` call.
14
14
  *
15
- * Each deployment target type (e.g., AgentSkillDeployment) has a concrete
16
- * handler that knows how to transform Kanonak YAML into the target format.
15
+ * `instances` is the list of `SubjectKanonak`s (each one is an
16
+ * instance of the capability's `managesType`) to deploy. `allKanonaks`
17
+ * is the full parsed kanonak list from the source document — handlers
18
+ * use it to follow references (e.g. a skill's `license` reference to
19
+ * the actual `License` subject for its `spdxId`).
20
+ *
21
+ * `repository` is the broader repository (local cache + HTTP) that the
22
+ * handler can use to fetch entities from other packages when needed
23
+ * (e.g. a `Tool` instance or `Client` instance defined in
24
+ * `agent-skills`).
25
+ */
26
+ export interface DeploymentContext {
27
+ instances: SubjectKanonak[];
28
+ allKanonaks: Kanonak[];
29
+ repository: IKanonakDocumentRepository;
30
+ options: Record<string, string>;
31
+ }
32
+ /**
33
+ * Context passed to a deployment handler for lifecycle operations
34
+ * that are NOT about deploying a fresh instance (undeploy, list).
35
+ * Carries the broader repository so handlers can still resolve
36
+ * ontology entities like `Client` for per-product skill paths.
37
+ */
38
+ export interface OperationContext {
39
+ repository: IKanonakDocumentRepository;
40
+ options: Record<string, string>;
41
+ }
42
+ /**
43
+ * Handler that deploys/undeploys instances of a managed type to the
44
+ * local system.
45
+ *
46
+ * Each `DeploymentTarget` instance in the `kanonak.org/capabilities`
47
+ * ontology has a matching handler in the `DeploymentHandlerRegistry`,
48
+ * keyed by the target's canonical URI string
49
+ * (`{publisher}/{package}/{name}`).
17
50
  */
18
51
  export interface DeploymentHandler {
19
- /**
20
- * Deploy instances from a Kanonak document to the local system.
21
- */
22
- deploy(doc: KanonakDocument, instances: InstanceSearchResult[], options: Record<string, string>): Promise<void>;
23
- /**
24
- * Remove a deployed instance by name.
25
- */
26
- undeploy(name: string, options: Record<string, string>): Promise<void>;
27
- /**
28
- * List all deployed instances.
29
- */
30
- list(options: Record<string, string>): Promise<DeployedInstance[]>;
52
+ deploy(context: DeploymentContext): Promise<void>;
53
+ undeploy(name: string, context: OperationContext): Promise<void>;
54
+ list(context: OperationContext): Promise<DeployedInstance[]>;
31
55
  }
32
56
  /**
33
- * Registry that maps deployment target type names to handler implementations.
57
+ * Registry that maps a DeploymentTarget URI key to its handler.
58
+ *
59
+ * The URI key is the canonical `{publisher}/{package}/{name}` string
60
+ * of a named DeploymentTarget instance (e.g.
61
+ * `kanonak.org/capabilities/AgentSkillDeployment`). Version is not
62
+ * part of the key: new compatible versions of the ontology continue
63
+ * to dispatch to the same handler.
34
64
  */
35
65
  export declare class DeploymentHandlerRegistry {
36
66
  private readonly handlers;
37
- /**
38
- * Register a handler for a deployment target type.
39
- */
40
- register(targetType: string, handler: DeploymentHandler): void;
41
- /**
42
- * Get the handler for a deployment target type.
43
- */
44
- get(targetType: string): DeploymentHandler | null;
67
+ register(targetUriKey: string, handler: DeploymentHandler): void;
68
+ get(targetUriKey: string): DeploymentHandler | null;
45
69
  }
@@ -1,12 +1,17 @@
1
1
  import { KanonakParser, PublisherIndex } from '@kanonak-protocol/sdk';
2
- import type { AuthenticatedFetchFn } from '@kanonak-protocol/sdk';
2
+ import type { AuthenticatedFetchFn, IKanonakDocumentRepository } from '@kanonak-protocol/sdk';
3
3
  import { FileCache } from '../cache/FileCache.js';
4
4
  import type { LoadedCapability } from './CapabilityLoader.js';
5
5
  import type { DeploymentHandlerRegistry } from './DeploymentHandlerRegistry.js';
6
6
  /**
7
- * Generic command handler that implements standard operations (add, remove,
8
- * list, update, search, info) in a type-agnostic way, parameterized by
9
- * the capability definition.
7
+ * Generic command handler that implements the standard Action set
8
+ * (fetchAndDeploy, removeDeployed, listDeployed, updateDeployed,
9
+ * searchAvailable, showInfo) in a type-agnostic way.
10
+ *
11
+ * The handler is parameterized by the LoadedCapability — specifically
12
+ * its URI-keyed `managesTypeKey` and `deploymentTargetKey` — so the
13
+ * same implementation supports any capability whose ontology resolves
14
+ * cleanly through the SDK object model.
10
15
  */
11
16
  export declare class GenericCapabilityHandler {
12
17
  private readonly fileCache;
@@ -14,29 +19,22 @@ export declare class GenericCapabilityHandler {
14
19
  private readonly publisherIndex;
15
20
  private readonly fetchFn;
16
21
  private readonly handlerRegistry;
17
- constructor(fileCache: FileCache, parser: KanonakParser, publisherIndex: PublisherIndex, fetchFn: AuthenticatedFetchFn, handlerRegistry: DeploymentHandlerRegistry);
22
+ private readonly repository;
23
+ private readonly objectParser;
24
+ constructor(fileCache: FileCache, parser: KanonakParser, publisherIndex: PublisherIndex, fetchFn: AuthenticatedFetchFn, handlerRegistry: DeploymentHandlerRegistry, repository: IKanonakDocumentRepository);
18
25
  /**
19
- * Install instances of the managed type from a Kanonak publisher.
26
+ * Fetch a package and deploy every instance of the capability's
27
+ * managed type.
20
28
  */
21
29
  add(capability: LoadedCapability, packageRef: string, options: Record<string, string>): Promise<void>;
22
- /**
23
- * Remove a deployed instance by name.
24
- */
25
30
  remove(capability: LoadedCapability, name: string, options: Record<string, string>): Promise<void>;
26
- /**
27
- * List deployed instances.
28
- */
29
31
  list(capability: LoadedCapability, options: Record<string, string>): Promise<void>;
30
- /**
31
- * Update deployed instances to latest versions.
32
- */
33
32
  update(capability: LoadedCapability, name: string | undefined, options: Record<string, string>): Promise<void>;
34
33
  /**
35
- * Search for instances of the managed type from a publisher.
34
+ * Search a publisher's package index for any package that contains
35
+ * instances of this capability's `managesType`.
36
36
  */
37
37
  search(capability: LoadedCapability, options: Record<string, string>): Promise<void>;
38
- /**
39
- * Show details about a deployed instance.
40
- */
41
38
  info(capability: LoadedCapability, name: string, options: Record<string, string>): Promise<void>;
39
+ private requireHandler;
42
40
  }
@@ -0,0 +1,28 @@
1
+ import type { KanonakDocument, Import, DocumentReference } from '@kanonak-protocol/types/document/models/types';
2
+ import type { IKanonakDocumentRepository } from '@kanonak-protocol/sdk';
3
+ /**
4
+ * A repository that exposes exactly one target document through
5
+ * `getAllDocumentsAsync` but delegates every import-resolution lookup
6
+ * (`getHighestCompatibleVersionAsync`, `getDocumentAsync`, etc.) to a
7
+ * broader backing repository.
8
+ *
9
+ * This is what lets `KanonakObjectParser.parseKanonaks` parse a single
10
+ * capability or skill document with full URI resolution across its
11
+ * transitive imports, without inheriting every other cached document's
12
+ * entities.
13
+ */
14
+ export declare class SingleDocumentRepository implements IKanonakDocumentRepository {
15
+ private readonly doc;
16
+ private readonly broader;
17
+ constructor(doc: KanonakDocument, broader: IKanonakDocumentRepository);
18
+ getAllDocumentsAsync(): Promise<KanonakDocument[]>;
19
+ getDocumentAsync(identifier: string): Promise<KanonakDocument | null>;
20
+ getDocumentsByNamespaceAsync(publisher: string, package_: string): Promise<KanonakDocument[]>;
21
+ getHighestCompatibleVersionAsync(publisher: string, import_: Import): Promise<KanonakDocument | null>;
22
+ saveDocumentAsync(): Promise<void>;
23
+ deleteDocumentAsync(): Promise<void>;
24
+ clearNamespaceAsync(): Promise<void>;
25
+ getAllDocumentReferencesAsync(): Promise<DocumentReference[]>;
26
+ getDocumentContentAsync(identifier: string): Promise<string | null>;
27
+ getDocumentUriAsync(identifier: string): Promise<string | null>;
28
+ }
@@ -0,0 +1,66 @@
1
+ import { SubjectKanonak, EmbeddedKanonak, DefinedKanonak, Kanonak, KanonakUri } from '@kanonak-protocol/sdk';
2
+ /**
3
+ * Canonical URI identity for an ontology entity.
4
+ *
5
+ * Version is intentionally omitted: the CLI compares against
6
+ * publisher + package + name so it can accept any backwards-compatible
7
+ * version of the ontology it was built against. If a new major version
8
+ * breaks semantics, a separate entry (or explicit version check) is
9
+ * added at that point.
10
+ */
11
+ export interface EntityUri {
12
+ publisher: string;
13
+ package_: string;
14
+ name: string;
15
+ }
16
+ /**
17
+ * Convert a `KanonakUri` or `EntityUri` into a stable map key.
18
+ * Version is dropped.
19
+ */
20
+ export declare function uriKey(uri: KanonakUri | EntityUri): string;
21
+ /**
22
+ * True when a resolved `KanonakUri` matches the given publisher + package
23
+ * + local name (version ignored).
24
+ */
25
+ export declare function uriMatches(uri: KanonakUri, target: EntityUri): boolean;
26
+ /**
27
+ * True when a `Kanonak` is a `DefinedKanonak` whose `type` statement's
28
+ * object URI matches the given class URI.
29
+ */
30
+ export declare function hasType(kanonak: Kanonak, target: EntityUri): boolean;
31
+ /**
32
+ * Filter a list of parsed kanonaks down to `SubjectKanonak`s whose type
33
+ * matches the given class URI.
34
+ */
35
+ export declare function findSubjectsByType(kanonaks: Kanonak[], target: EntityUri): SubjectKanonak[];
36
+ /**
37
+ * Look up a `SubjectKanonak` by full URI across a list of kanonaks.
38
+ * Used for following a reference to its definition (e.g. to read a
39
+ * `License`'s `spdxId` or a `Tool`'s `label`).
40
+ */
41
+ export declare function findSubjectByUri(kanonaks: Kanonak[], uri: KanonakUri): SubjectKanonak | undefined;
42
+ /**
43
+ * Read a datatype property value (string, number, boolean) off a defined
44
+ * kanonak, by property URI. Returns `undefined` when the property is not
45
+ * set or not a datatype value.
46
+ */
47
+ export declare function getDatatypeValue(defined: DefinedKanonak, property: EntityUri): string | number | boolean | undefined;
48
+ export declare function getStringValue(defined: DefinedKanonak, property: EntityUri): string | undefined;
49
+ /**
50
+ * Read the target `KanonakUri` of an ObjectProperty reference off a
51
+ * defined kanonak, by property URI. Returns `undefined` when the
52
+ * property is not set or not a reference statement.
53
+ */
54
+ export declare function getReferenceUri(defined: DefinedKanonak, property: EntityUri): KanonakUri | undefined;
55
+ /**
56
+ * Read an embedded kanonak off a defined kanonak, by property URI.
57
+ * Returns `undefined` when the property is not set or not an embedded
58
+ * statement.
59
+ */
60
+ export declare function getEmbeddedValue(defined: DefinedKanonak, property: EntityUri): EmbeddedKanonak | undefined;
61
+ /**
62
+ * Read the list values off a ListStatement property. Each item is either
63
+ * a `ReferenceKanonak` (named reference) or an `EmbeddedKanonak` (inline).
64
+ * Returns an empty array when the property is unset or not a list.
65
+ */
66
+ export declare function getListValues(defined: DefinedKanonak, property: EntityUri): Kanonak[];
@@ -2,7 +2,8 @@ import { Command } from 'commander';
2
2
  /**
3
3
  * Create the built-in "capability" command group.
4
4
  *
5
- * This is the bootstrap mechanism — always available, not dynamically loaded.
6
- * Used to install, remove, and list capabilities that extend the CLI.
5
+ * This is the bootstrap mechanism — always available, not dynamically
6
+ * loaded. Used to install, remove, and list capabilities that extend
7
+ * the CLI.
7
8
  */
8
9
  export declare function capabilityCommand(): Command;
package/dist/index.js CHANGED
@@ -1,73 +1,71 @@
1
1
  #!/usr/bin/env node
2
- import{Command as yn}from"commander";import{readFileSync as kn}from"fs";import{fileURLToPath as bn}from"url";import{dirname as wn,join as vn}from"path";import{KanonakParser as $n,PublisherIndex as Sn,CredentialStore as Cn,createAuthenticatedFetch as Pn}from"@kanonak-protocol/sdk";import{readFileSync as Ge,statSync as Be}from"fs";import{resolve as Je,dirname as Xe}from"path";import{KanonakParser as Ye,KanonakObjectValidator as Qe,ValidationSeverity as se}from"@kanonak-protocol/sdk";import{readFileSync as Ke,readdirSync as Ue}from"fs";import{join as He,dirname as ze,basename as re}from"path";import{InMemoryKanonakDocumentRepository as Ve,FileSystemKanonakDocumentRepository as Me,HttpKanonakDocumentRepository as We,getGlobalCachePath as qe}from"@kanonak-protocol/sdk";import{mkdirSync as Oe,readFileSync as ne,writeFileSync as oe,existsSync as q,appendFileSync as Ne}from"fs";import{join as Le,dirname as Ee,isAbsolute as Fe}from"path";import{getGlobalCachePath as je}from"@kanonak-protocol/sdk";var $=class{constructor(e=je()){this.cacheDir=e;this.isProjectLocal=!Fe(e)}cacheDir;gitignoreChecked=!1;isProjectLocal;get(e,t,o){let r=this.getPath(e,t,o);return q(r)?ne(r,"utf-8"):null}put(e,t,o,r){let s=this.getPath(e,t,o);Oe(Ee(s),{recursive:!0}),oe(s,r,"utf-8"),this.isProjectLocal&&this.ensureGitignore()}has(e,t,o){return q(this.getPath(e,t,o))}ensureGitignore(){if(this.gitignoreChecked)return;this.gitignoreChecked=!0;let e=".gitignore",t=this.cacheDir;if(q(e)){if(ne(e,"utf-8").split(`
3
- `).some(r=>r.trim()===t||r.trim()===t+"/"))return;Ne(e,`
2
+ import{Command as Io}from"commander";import{readFileSync as Ko}from"fs";import{fileURLToPath as Ao}from"url";import{dirname as xo,join as Eo}from"path";import{KanonakParser as To,PublisherIndex as Oo,CredentialStore as Uo,createAuthenticatedFetch as Lo}from"@kanonak-protocol/sdk";import{readFileSync as vt,statSync as $t}from"fs";import{resolve as Rt,dirname as _t}from"path";import{KanonakParser as Ct,KanonakObjectValidator as Dt,ValidationSeverity as Se}from"@kanonak-protocol/sdk";import{readFileSync as ft,readdirSync as yt}from"fs";import{join as ht,dirname as kt,basename as we}from"path";import{InMemoryKanonakDocumentRepository as bt,FileSystemKanonakDocumentRepository as Pt,HttpKanonakDocumentRepository as wt,getGlobalCachePath as St}from"@kanonak-protocol/sdk";import{mkdirSync as lt,readFileSync as be,writeFileSync as Pe,existsSync as re,appendFileSync as pt}from"fs";import{join as dt,dirname as ut,isAbsolute as mt}from"path";import{getGlobalCachePath as gt}from"@kanonak-protocol/sdk";var C=class{constructor(e=gt()){this.cacheDir=e;this.isProjectLocal=!mt(e)}cacheDir;gitignoreChecked=!1;isProjectLocal;get(e,t,o){let r=this.getPath(e,t,o);return re(r)?be(r,"utf-8"):null}put(e,t,o,r){let s=this.getPath(e,t,o);lt(ut(s),{recursive:!0}),Pe(s,r,"utf-8"),this.isProjectLocal&&this.ensureGitignore()}has(e,t,o){return re(this.getPath(e,t,o))}ensureGitignore(){if(this.gitignoreChecked)return;this.gitignoreChecked=!0;let e=".gitignore",t=this.cacheDir;if(re(e)){if(be(e,"utf-8").split(`
3
+ `).some(r=>r.trim()===t||r.trim()===t+"/"))return;pt(e,`
4
4
  ${t}/
5
- `)}else oe(e,`${t}/
6
- `)}getPath(e,t,o){return Le(this.cacheDir,e,`${t}@${o}.kan.yml`)}};function O(n){let e=n;for(;;){let t=ze(e);if(t===e)break;if(re(e).includes(".")||re(t).includes(".")){e=t;continue}break}return e}function F(n,e){for(let t of Ue(n,{withFileTypes:!0})){let o=He(n,t.name);t.isDirectory()&&t.name!=="node_modules"&&t.name!==".kanonak"?F(o,e):t.name.endsWith(".kan.yml")&&e.push(o)}}var G=class{repos;constructor(...e){this.repos=e}async getHighestCompatibleVersionAsync(e,t){for(let o of this.repos)try{let r=await o.getHighestCompatibleVersionAsync(e,t);if(r)return r}catch{}return null}async getAllDocumentsAsync(){let e=[];for(let t of this.repos)try{e.push(...await t.getAllDocumentsAsync())}catch{}return e}async getDocumentAsync(e){for(let t of this.repos)try{let o=await t.getDocumentAsync(e);if(o)return o}catch{}return null}async getDocumentsByNamespaceAsync(e,t){for(let o of this.repos)try{let r=await o.getDocumentsByNamespaceAsync(e,t);if(r.length>0)return r}catch{}return[]}async saveDocumentAsync(e,t){await this.repos[0].saveDocumentAsync(e,t)}async deleteDocumentAsync(e){await this.repos[0].deleteDocumentAsync(e)}async clearNamespaceAsync(e,t){await this.repos[0].clearNamespaceAsync(e,t)}async getAllDocumentReferencesAsync(){return this.repos[0].getAllDocumentReferencesAsync()}async getDocumentContentAsync(e){for(let t of this.repos)try{let o=await t.getDocumentContentAsync(e);if(o)return o}catch{}return null}async getDocumentUriAsync(e){for(let t of this.repos)try{let o=await t.getDocumentUriAsync(e);if(o)return o}catch{}return null}};async function j(n,e){let t=[];F(n,t);let o=new Ve(e);for(let a of t)try{let c=Ke(a,"utf-8"),l=e.parse(c),d=l.metadata.namespace_;if(d){let p=`${d.publisher}/${d.package_}@${d.version}`;await o.saveDocumentAsync(l,p)}}catch{}let r=new Me(qe(),!0,e),s=new $,i=new We({getFromCache:(a,c,l)=>s.get(a,c,l),onFetch:(a,c,l,d)=>s.put(a,c,l,d)});return new G(o,r,i)}async function ie(n){let e=Je(n),t=Be(e),o=t.isDirectory()?O(e):O(Xe(e)),r=new Ye,s=new Qe(r),i=await j(o,r),a=[];if(t.isDirectory()?F(e,a):a.push(e),a.length===0){console.log("No .kan.yml files found.");return}let c=0,l=0;for(let d of a){let p=Ge(d,"utf-8"),u=r.parseWithErrors(p);if(u.errors&&u.errors.length>0){console.log(`
7
- ${d}:`);for(let f of u.errors)console.log(` ERROR (parse): ${f.message} [line ${f.line}:${f.column}]`),c++;continue}let y=u.document;if(!y){console.log(`
8
- ${d}:`),console.log(" ERROR: Failed to parse document"),c++;continue}let m=await s.validateAsync(y,i),g=m.errors.filter(f=>f.severity===se.Error),k=m.errors.filter(f=>f.severity===se.Warning);if(g.length>0||k.length>0){let f=y.metadata.namespace_,h=f?`${f.publisher}/${f.package_}@${f.version}`:d;console.log(`
9
- ${h}:`);for(let b of g)console.log(` ERROR: ${b.message}`),b.suggestion&&console.log(` -> ${b.suggestion}`);for(let b of k)console.log(` WARN: ${b.message}`)}c+=g.length,l+=k.length}console.log(`
10
- ${a.length} file(s) validated. ${c} error(s), ${l} warning(s).`),c>0&&process.exit(1)}import{KanonakParser as rt,PublisherIndex as st,CredentialStore as it,createAuthenticatedFetch as at}from"@kanonak-protocol/sdk";import{readFileSync as Ze,writeFileSync as et,existsSync as tt}from"fs";import{createHash as nt}from"crypto";import ae from"js-yaml";var B="kanonak.lock",ot=`# This file is generated by Kanonak CLI. Do not edit manually.
11
- `;function ce(){if(!tt(B))return null;let n=Ze(B,"utf-8"),e=ae.load(n);return!e||typeof e!="object"||e.version!=="1"?null:{version:"1",lastUpdated:e.lastUpdated??new Date().toISOString(),packages:e.packages??{}}}function le(n){n.lastUpdated=new Date().toISOString();let e={};for(let o of Object.keys(n.packages).sort())e[o]=n.packages[o];n.packages=e;let t=ae.dump(n,{lineWidth:-1,sortKeys:!1,quotingType:'"'});et(B,ot+t,"utf-8")}function D(n){return`sha256:${nt("sha256").update(n).digest("hex")}`}function T(n){let e=n.indexOf("@"),t,o=null;e!==-1?(t=n.substring(0,e),o=n.substring(e+1)||null):t=n;let r=t.indexOf("/");if(r===-1)return null;let s=t.substring(0,r),i=t.substring(r+1);return!s||!i?null:{publisher:s,packageName:i,version:o}}async function de(n){let e=new $,t=new rt,o=new it,r=at(o),s=new st({fetchFn:r}),i=ce()??{version:"1",lastUpdated:new Date().toISOString(),packages:{}};if(!n){Object.keys(i.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(i.packages).length} package(s) from kanonak.lock...`);for(let[y,m]of Object.entries(i.packages)){let g=y.indexOf("/"),k=y.substring(0,g),f=y.substring(g+1),h=e.get(k,f,m.version);if(h)console.log(` ${y}@${m.version} (cached)`);else{let b=m.resolved,w=await r(b,k);if(!w.ok)throw new Error(`Failed to fetch ${b} (${w.status} ${w.statusText})`);h=await w.text(),e.put(k,f,m.version,h),console.log(` ${y}@${m.version}`)}}console.log(`
12
- Installed ${Object.keys(i.packages).length} package(s) from lock file.`);return}let a=T(n);a||(console.error(`Invalid package reference: ${n}`),console.error("Expected format: {publisher}/{package}@{version} or {publisher}/{package}"),process.exit(1));let{publisher:c,packageName:l,version:d}=a,p=d??await s.getHighestVersion(c,l);p||(console.error(`Could not resolve version for ${c}/${l}`),process.exit(1)),console.log(`Installing ${c}/${l}@${p}...`);let u=new Set;await pe(c,l,p,e,t,s,r,u,i),le(i),console.log(`
13
- Installed ${u.size} package(s).`)}async function pe(n,e,t,o,r,s,i,a,c){let l=`${n}/${e}@${t}`;if(a.has(l))return;a.add(l);let d=`${n}/${e}`,p=o.get(n,e,t),u;if(p)console.log(` ${l} (cached)`),u=await s.getPackageUrl(n,e,t);else{u=await s.getPackageUrl(n,e,t);let g=await i(u,n);if(!g.ok)throw new Error(`Failed to fetch ${u} (${g.status} ${g.statusText})`);p=await g.text(),o.put(n,e,t,p),console.log(` ${l}`)}let y={},m=r.parse(p);if(m.metadata.imports)for(let[g,k]of Object.entries(m.metadata.imports))for(let f of k){let h=await s.resolveVersion(g,f);h?(y[`${g}/${f.packageName}`]=h,await pe(g,f.packageName,h,o,r,s,i,a,c)):console.error(` WARNING: Could not resolve ${g}/${f.packageName} ${f.package_}`)}c.packages[d]={version:t,resolved:u,integrity:D(p),dependencies:y}}import{readFileSync as ct}from"fs";import{resolve as lt,dirname as dt}from"path";import{KanonakParser as pt}from"@kanonak-protocol/sdk";async function ue(n){let e=lt(n),t=ct(e,"utf-8"),o=new pt,r=o.parse(t),s=r.metadata.namespace_,i=s?`${s.publisher}/${s.package_}@${s.version}`:n;if(console.log(i),!r.metadata.imports){console.log(" (no imports)");return}let a=O(dt(e)),c=await j(a,o),l=new Set;for(let[d,p]of Object.entries(r.metadata.imports))for(let u of p)await ge(d,u,c,l," ")}async function ge(n,e,t,o,r){let s=`${n}/${e.packageName}`;if(o.has(s)){console.log(`${r}${s} (${e.package_}) [circular]`);return}o.add(s);let i;try{i=await t.getHighestCompatibleVersionAsync(n,e)}catch{console.log(`${r}${s} (${e.package_}) [fetch failed]`);return}if(!i){console.log(`${r}${s} (${e.package_}) [not found]`);return}let a=i.metadata.namespace_?.version?.toString()??"?";if(console.log(`${r}${n}/${e.packageName}@${a}`),i.metadata.imports)for(let[c,l]of Object.entries(i.metadata.imports))for(let d of l)await ge(c,d,t,o,r+" ")}import{createHash as gt,randomBytes as he}from"crypto";import{createServer as mt}from"http";import{execFile as J}from"child_process";import{CredentialStore as ft,generateDPoPKeyPair as ht,createDPoPProof as me,serverSupportsDPoP as yt}from"@kanonak-protocol/sdk";import{normalizeHost as ut}from"@kanonak-protocol/sdk";var P=class{cache=new Map;async discover(e){let t=ut(e);if(this.cache.has(t))return this.cache.get(t);let o=`https://${t}/.well-known/oauth-authorization-server`,r=await this.tryEndpoint(o);if(!r){let s=`https://${t}/.well-known/openid-configuration`;r=await this.tryEndpoint(s)}return this.cache.set(t,r),r}async supportsOAuth(e){return await this.discover(e)!==null}static supportsPkceS256(e){return e.codeChallengeMethodsSupported?.some(t=>t.toUpperCase()==="S256")??!1}static supportsDynamicRegistration(e){return!!e.registrationEndpoint}static supportsAuthorizationCode(e){return e.responseTypesSupported?.some(t=>t.toLowerCase()==="code")??!1}async tryEndpoint(e){let t;try{t=await fetch(e)}catch(r){let s=r instanceof Error?r.message:String(r);return s.includes("ENOTFOUND")||s.includes("ECONNREFUSED")?(console.error(` OAuth discovery: ${e} \u2014 host unreachable (${s})`),console.error(" If the server is behind a VPN, ensure you are connected.")):s.includes("CERT")||s.includes("SSL")||s.includes("TLS")?(console.error(` OAuth discovery: ${e} \u2014 TLS error (${s})`),console.error(" If using a custom CA certificate, set NODE_EXTRA_CA_CERTS=/path/to/ca.pem")):console.error(` OAuth discovery: ${e} \u2014 network error: ${s}`),null}if(!t.ok)return t.status===404||(t.status===403?(console.error(` OAuth discovery: ${e} \u2014 HTTP 403 Forbidden`),console.error(" Access may be blocked by a firewall, proxy, or WAF.")):t.status>=500&&(console.error(` OAuth discovery: ${e} \u2014 HTTP ${t.status} server error`),console.error(" The authorization server returned an internal error. Contact your IDP administrator."))),null;let o;try{o=await t.json()}catch{return console.error(` OAuth discovery: ${e} \u2014 response is not valid JSON`),console.error(" The endpoint may be returning HTML instead of JSON. Check IDP configuration."),null}return{issuer:N(o.issuer),authorizationEndpoint:N(o.authorization_endpoint),tokenEndpoint:N(o.token_endpoint),registrationEndpoint:N(o.registration_endpoint),revocationEndpoint:N(o.revocation_endpoint),scopesSupported:x(o.scopes_supported),responseTypesSupported:x(o.response_types_supported),grantTypesSupported:x(o.grant_types_supported),codeChallengeMethodsSupported:x(o.code_challenge_methods_supported),tokenEndpointAuthMethodsSupported:x(o.token_endpoint_auth_methods_supported),dpopSigningAlgValuesSupported:x(o.dpop_signing_alg_values_supported)}}};function N(n){return typeof n=="string"?n:null}function x(n){return Array.isArray(n)?n.filter(e=>typeof e=="string"):null}var I=class{discovery;credentialStore;constructor(e,t){this.discovery=e??new P,this.credentialStore=t??new ft}async authorize(e,t=[]){console.log(`Starting OAuth flow for ${e}...`);let o=await this.discovery.discover(e);if(!o)return v(`No OAuth discovery endpoint found for '${e}'.
5
+ `)}else Pe(e,`${t}/
6
+ `)}getPath(e,t,o){return dt(this.cacheDir,e,`${t}@${o}.kan.yml`)}};function G(n){let e=n;for(;;){let t=kt(e);if(t===e)break;if(we(e).includes(".")||we(t).includes(".")){e=t;continue}break}return e}function J(n,e){for(let t of yt(n,{withFileTypes:!0})){let o=ht(n,t.name);t.isDirectory()&&t.name!=="node_modules"&&t.name!==".kanonak"?J(o,e):t.name.endsWith(".kan.yml")&&e.push(o)}}var se=class{repos;constructor(...e){this.repos=e}async getHighestCompatibleVersionAsync(e,t){for(let o of this.repos)try{let r=await o.getHighestCompatibleVersionAsync(e,t);if(r)return r}catch{}return null}async getAllDocumentsAsync(){let e=[];for(let t of this.repos)try{e.push(...await t.getAllDocumentsAsync())}catch{}return e}async getDocumentAsync(e){for(let t of this.repos)try{let o=await t.getDocumentAsync(e);if(o)return o}catch{}return null}async getDocumentsByNamespaceAsync(e,t){for(let o of this.repos)try{let r=await o.getDocumentsByNamespaceAsync(e,t);if(r.length>0)return r}catch{}return[]}async saveDocumentAsync(e,t){await this.repos[0].saveDocumentAsync(e,t)}async deleteDocumentAsync(e){await this.repos[0].deleteDocumentAsync(e)}async clearNamespaceAsync(e,t){await this.repos[0].clearNamespaceAsync(e,t)}async getAllDocumentReferencesAsync(){return this.repos[0].getAllDocumentReferencesAsync()}async getDocumentContentAsync(e){for(let t of this.repos)try{let o=await t.getDocumentContentAsync(e);if(o)return o}catch{}return null}async getDocumentUriAsync(e){for(let t of this.repos)try{let o=await t.getDocumentUriAsync(e);if(o)return o}catch{}return null}};async function A(n,e){let t=[];J(n,t);let o=new bt(e);for(let a of t)try{let c=ft(a,"utf-8"),l=e.parse(c),p=l.metadata.namespace_;if(p){let d=`${p.publisher}/${p.package_}@${p.version}`;await o.saveDocumentAsync(l,d)}}catch{}let r=new Pt(St(),!0,e),s=new C,i=new wt({getFromCache:(a,c,l)=>s.get(a,c,l),onFetch:(a,c,l,p)=>s.put(a,c,l,p)});return new se(o,r,i)}async function ve(n){let e=Rt(n),t=$t(e),o=t.isDirectory()?G(e):G(_t(e)),r=new Ct,s=new Dt(r),i=await A(o,r),a=[];if(t.isDirectory()?J(e,a):a.push(e),a.length===0){console.log("No .kan.yml files found.");return}let c=0,l=0;for(let p of a){let d=vt(p,"utf-8"),u=r.parseWithErrors(d);if(u.errors&&u.errors.length>0){console.log(`
7
+ ${p}:`);for(let m of u.errors)console.log(` ERROR (parse): ${m.message} [line ${m.line}:${m.column}]`),c++;continue}let g=u.document;if(!g){console.log(`
8
+ ${p}:`),console.log(" ERROR: Failed to parse document"),c++;continue}let f=await s.validateAsync(g,i),y=f.errors.filter(m=>m.severity===Se.Error),k=f.errors.filter(m=>m.severity===Se.Warning);if(y.length>0||k.length>0){let m=g.metadata.namespace_,b=m?`${m.publisher}/${m.package_}@${m.version}`:p;console.log(`
9
+ ${b}:`);for(let h of y)console.log(` ERROR: ${h.message}`),h.suggestion&&console.log(` -> ${h.suggestion}`);for(let h of k)console.log(` WARN: ${h.message}`)}c+=y.length,l+=k.length}console.log(`
10
+ ${a.length} file(s) validated. ${c} error(s), ${l} warning(s).`),c>0&&process.exit(1)}import{KanonakParser as Tt,PublisherIndex as Ot,CredentialStore as Ut,createAuthenticatedFetch as Lt}from"@kanonak-protocol/sdk";import{readFileSync as It,writeFileSync as Kt,existsSync as At}from"fs";import{createHash as xt}from"crypto";import $e from"js-yaml";var ie="kanonak.lock",Et=`# This file is generated by Kanonak CLI. Do not edit manually.
11
+ `;function Re(){if(!At(ie))return null;let n=It(ie,"utf-8"),e=$e.load(n);return!e||typeof e!="object"||e.version!=="1"?null:{version:"1",lastUpdated:e.lastUpdated??new Date().toISOString(),packages:e.packages??{}}}function _e(n){n.lastUpdated=new Date().toISOString();let e={};for(let o of Object.keys(n.packages).sort())e[o]=n.packages[o];n.packages=e;let t=$e.dump(n,{lineWidth:-1,sortKeys:!1,quotingType:'"'});Kt(ie,Et+t,"utf-8")}function O(n){return`sha256:${xt("sha256").update(n).digest("hex")}`}function U(n){let e=n.indexOf("@"),t,o=null;e!==-1?(t=n.substring(0,e),o=n.substring(e+1)||null):t=n;let r=t.indexOf("/");if(r===-1)return null;let s=t.substring(0,r),i=t.substring(r+1);return!s||!i?null:{publisher:s,packageName:i,version:o}}async function Ce(n){let e=new C,t=new Tt,o=new Ut,r=Lt(o),s=new Ot({fetchFn:r}),i=Re()??{version:"1",lastUpdated:new Date().toISOString(),packages:{}};if(!n){Object.keys(i.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(i.packages).length} package(s) from kanonak.lock...`);for(let[g,f]of Object.entries(i.packages)){let y=g.indexOf("/"),k=g.substring(0,y),m=g.substring(y+1),b=e.get(k,m,f.version);if(b)console.log(` ${g}@${f.version} (cached)`);else{let h=f.resolved,w=await r(h,k);if(!w.ok)throw new Error(`Failed to fetch ${h} (${w.status} ${w.statusText})`);b=await w.text(),e.put(k,m,f.version,b),console.log(` ${g}@${f.version}`)}}console.log(`
12
+ Installed ${Object.keys(i.packages).length} package(s) from lock file.`);return}let a=U(n);a||(console.error(`Invalid package reference: ${n}`),console.error("Expected format: {publisher}/{package}@{version} or {publisher}/{package}"),process.exit(1));let{publisher:c,packageName:l,version:p}=a,d=p??await s.getHighestVersion(c,l);d||(console.error(`Could not resolve version for ${c}/${l}`),process.exit(1)),console.log(`Installing ${c}/${l}@${d}...`);let u=new Set;await De(c,l,d,e,t,s,r,u,i),_e(i),console.log(`
13
+ Installed ${u.size} package(s).`)}async function De(n,e,t,o,r,s,i,a,c){let l=`${n}/${e}@${t}`;if(a.has(l))return;a.add(l);let p=`${n}/${e}`,d=o.get(n,e,t),u;if(d)console.log(` ${l} (cached)`),u=await s.getPackageUrl(n,e,t);else{u=await s.getPackageUrl(n,e,t);let y=await i(u,n);if(!y.ok)throw new Error(`Failed to fetch ${u} (${y.status} ${y.statusText})`);d=await y.text(),o.put(n,e,t,d),console.log(` ${l}`)}let g={},f=r.parse(d);if(f.metadata.imports)for(let[y,k]of Object.entries(f.metadata.imports))for(let m of k){let b=await s.resolveVersion(y,m);b?(g[`${y}/${m.packageName}`]=b,await De(y,m.packageName,b,o,r,s,i,a,c)):console.error(` WARNING: Could not resolve ${y}/${m.packageName} ${m.package_}`)}c.packages[p]={version:t,resolved:u,integrity:O(d),dependencies:g}}import{readFileSync as jt}from"fs";import{resolve as Nt,dirname as Ft}from"path";import{KanonakParser as Ht}from"@kanonak-protocol/sdk";async function Ie(n){let e=Nt(n),t=jt(e,"utf-8"),o=new Ht,r=o.parse(t),s=r.metadata.namespace_,i=s?`${s.publisher}/${s.package_}@${s.version}`:n;if(console.log(i),!r.metadata.imports){console.log(" (no imports)");return}let a=G(Ft(e)),c=await A(a,o),l=new Set;for(let[p,d]of Object.entries(r.metadata.imports))for(let u of d)await Ke(p,u,c,l," ")}async function Ke(n,e,t,o,r){let s=`${n}/${e.packageName}`;if(o.has(s)){console.log(`${r}${s} (${e.package_}) [circular]`);return}o.add(s);let i;try{i=await t.getHighestCompatibleVersionAsync(n,e)}catch{console.log(`${r}${s} (${e.package_}) [fetch failed]`);return}if(!i){console.log(`${r}${s} (${e.package_}) [not found]`);return}let a=i.metadata.namespace_?.version?.toString()??"?";if(console.log(`${r}${n}/${e.packageName}@${a}`),i.metadata.imports)for(let[c,l]of Object.entries(i.metadata.imports))for(let p of l)await Ke(c,p,t,o,r+" ")}import{createHash as Vt,randomBytes as Ee}from"crypto";import{createServer as Bt}from"http";import{execFile as ae}from"child_process";import{CredentialStore as zt,generateDPoPKeyPair as Gt,createDPoPProof as Ae,serverSupportsDPoP as Wt}from"@kanonak-protocol/sdk";import{normalizeHost as Mt}from"@kanonak-protocol/sdk";var x=class{cache=new Map;async discover(e){let t=Mt(e);if(this.cache.has(t))return this.cache.get(t);let o=`https://${t}/.well-known/oauth-authorization-server`,r=await this.tryEndpoint(o);if(!r){let s=`https://${t}/.well-known/openid-configuration`;r=await this.tryEndpoint(s)}return this.cache.set(t,r),r}async supportsOAuth(e){return await this.discover(e)!==null}static supportsPkceS256(e){return e.codeChallengeMethodsSupported?.some(t=>t.toUpperCase()==="S256")??!1}static supportsDynamicRegistration(e){return!!e.registrationEndpoint}static supportsAuthorizationCode(e){return e.responseTypesSupported?.some(t=>t.toLowerCase()==="code")??!1}async tryEndpoint(e){let t;try{t=await fetch(e)}catch(r){let s=r instanceof Error?r.message:String(r);return s.includes("ENOTFOUND")||s.includes("ECONNREFUSED")?(console.error(` OAuth discovery: ${e} \u2014 host unreachable (${s})`),console.error(" If the server is behind a VPN, ensure you are connected.")):s.includes("CERT")||s.includes("SSL")||s.includes("TLS")?(console.error(` OAuth discovery: ${e} \u2014 TLS error (${s})`),console.error(" If using a custom CA certificate, set NODE_EXTRA_CA_CERTS=/path/to/ca.pem")):console.error(` OAuth discovery: ${e} \u2014 network error: ${s}`),null}if(!t.ok)return t.status===404||(t.status===403?(console.error(` OAuth discovery: ${e} \u2014 HTTP 403 Forbidden`),console.error(" Access may be blocked by a firewall, proxy, or WAF.")):t.status>=500&&(console.error(` OAuth discovery: ${e} \u2014 HTTP ${t.status} server error`),console.error(" The authorization server returned an internal error. Contact your IDP administrator."))),null;let o;try{o=await t.json()}catch{return console.error(` OAuth discovery: ${e} \u2014 response is not valid JSON`),console.error(" The endpoint may be returning HTML instead of JSON. Check IDP configuration."),null}return{issuer:W(o.issuer),authorizationEndpoint:W(o.authorization_endpoint),tokenEndpoint:W(o.token_endpoint),registrationEndpoint:W(o.registration_endpoint),revocationEndpoint:W(o.revocation_endpoint),scopesSupported:L(o.scopes_supported),responseTypesSupported:L(o.response_types_supported),grantTypesSupported:L(o.grant_types_supported),codeChallengeMethodsSupported:L(o.code_challenge_methods_supported),tokenEndpointAuthMethodsSupported:L(o.token_endpoint_auth_methods_supported),dpopSigningAlgValuesSupported:L(o.dpop_signing_alg_values_supported)}}};function W(n){return typeof n=="string"?n:null}function L(n){return Array.isArray(n)?n.filter(e=>typeof e=="string"):null}var N=class{discovery;credentialStore;constructor(e,t){this.discovery=e??new x,this.credentialStore=t??new zt}async authorize(e,t=[]){console.log(`Starting OAuth flow for ${e}...`);let o=await this.discovery.discover(e);if(!o)return $(`No OAuth discovery endpoint found for '${e}'.
14
14
  The server must expose one of:
15
15
  - https://${e}/.well-known/oauth-authorization-server (RFC 8414)
16
16
  - https://${e}/.well-known/openid-configuration (OpenID Connect)
17
17
  Verify the hostname is correct and HTTPS is configured.
18
- 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 v(`OAuth metadata for '${e}' is missing required fields: ${r.join(", ")}.
19
- Contact the IDP administrator to ensure these are included in the discovery document.`);let s=yt(o.dpopSigningAlgValuesSupported),i=null;if(s){console.log(" Server supports DPoP (RFC 9449) \u2014 generating key pair...");try{i=ht()}catch(C){return v(`Failed to generate DPoP key pair: ${A(C)}
20
- Ensure your Node.js installation supports EC P-256 curves.`)}}let{redirectUri:a,port:c,waitForCallback:l,close:d}=await Ct(),p=await this.credentialStore.getCredential(e),u=p?.clientId??null,y=p?.clientSecret??null;if(!u&&o.registrationEndpoint){console.log(" Registering dynamic OAuth client (RFC 7591)...");let C=await this.registerClient(o.registrationEndpoint,a);if(!C.success)return d(),v(C.error);u=C.clientId,y=C.clientSecret??null}if(!u)return d(),v(`No OAuth client credentials for '${e}' and the server does not support dynamic client registration (no registration_endpoint in metadata).
18
+ 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 $(`OAuth metadata for '${e}' is missing required fields: ${r.join(", ")}.
19
+ Contact the IDP administrator to ensure these are included in the discovery document.`);let s=Wt(o.dpopSigningAlgValuesSupported),i=null;if(s){console.log(" Server supports DPoP (RFC 9449) \u2014 generating key pair...");try{i=Gt()}catch(R){return $(`Failed to generate DPoP key pair: ${j(R)}
20
+ Ensure your Node.js installation supports EC P-256 curves.`)}}let{redirectUri:a,port:c,waitForCallback:l,close:p}=await en(),d=await this.credentialStore.getCredential(e),u=d?.clientId??null,g=d?.clientSecret??null;if(!u&&o.registrationEndpoint){console.log(" Registering dynamic OAuth client (RFC 7591)...");let R=await this.registerClient(o.registrationEndpoint,a);if(!R.success)return p(),$(R.error);u=R.clientId,g=R.clientSecret??null}if(!u)return p(),$(`No OAuth client credentials for '${e}' and the server does not support dynamic client registration (no registration_endpoint in metadata).
21
21
  You must pre-register a client with your IDP and configure the client_id.
22
22
  Ask your IDP administrator to enable dynamic client registration (RFC 7591),
23
- or add a registration_endpoint to the OAuth metadata.`);let m=bt(),g=wt(m),k=vt(),f=$t(o.authorizationEndpoint,u,a,t,k,g);console.log(` Opening browser for authorization on port ${c}...`),console.log(" If the browser doesn't open, navigate to:"),console.log(` ${f}`),Rt(f);let h=await l();if(d(),!h)return v(`Authorization timed out after 5 minutes.
23
+ or add a registration_endpoint to the OAuth metadata.`);let f=Yt(),y=Jt(f),k=Xt(),m=Qt(o.authorizationEndpoint,u,a,t,k,y);console.log(` Opening browser for authorization on port ${c}...`),console.log(" If the browser doesn't open, navigate to:"),console.log(` ${m}`),nn(m);let b=await l();if(p(),!b)return $(`Authorization timed out after 5 minutes.
24
24
  The browser authorization was not completed in time.
25
- Re-run 'kanonak login ${e}' and complete the browser authorization promptly.`);if(!h.code){let C=h.error?`: ${h.error}`:"";return v(`No authorization code received${C}.
25
+ Re-run 'kanonak login ${e}' and complete the browser authorization promptly.`);if(!b.code){let R=b.error?`: ${b.error}`:"";return $(`No authorization code received${R}.
26
26
  The IDP may have rejected the authorization request.
27
- Check the IDP admin console for error details.`)}if(h.state!==k)return v(`Authorization state mismatch \u2014 possible CSRF attack.
27
+ Check the IDP admin console for error details.`)}if(b.state!==k)return $(`Authorization state mismatch \u2014 possible CSRF attack.
28
28
  The response did not match the expected session.
29
- Re-run 'kanonak login ${e}' to start a fresh authorization flow.`);console.log(" Exchanging authorization code for tokens...");let b=await this.exchangeCode(o.tokenEndpoint,u,y,h.code,a,m,i);if(!b.success)return v(b.error);let w={clientId:u,clientSecret:y,accessToken:b.tokens.accessToken,refreshToken:b.tokens.refreshToken,expiresAt:b.tokens.expiresIn?new Date(Date.now()+b.tokens.expiresIn*1e3).toISOString():null,tokenEndpoint:o.tokenEndpoint,dpopKeyPair:i};return await this.credentialStore.store(e,w),console.log(` Successfully authenticated with ${e}`),s&&console.log(" DPoP proof-of-possession is active"),{success:!0,host:e}}async refresh(e){let t=await this.credentialStore.getCredential(e);if(!t)return v(`No stored credentials for '${e}'. Run 'kanonak login ${e}' to authenticate first.`);if(!t.refreshToken)return v(`No refresh token available for '${e}'.
29
+ Re-run 'kanonak login ${e}' to start a fresh authorization flow.`);console.log(" Exchanging authorization code for tokens...");let h=await this.exchangeCode(o.tokenEndpoint,u,g,b.code,a,f,i);if(!h.success)return $(h.error);let w={clientId:u,clientSecret:g,accessToken:h.tokens.accessToken,refreshToken:h.tokens.refreshToken,expiresAt:h.tokens.expiresIn?new Date(Date.now()+h.tokens.expiresIn*1e3).toISOString():null,tokenEndpoint:o.tokenEndpoint,dpopKeyPair:i};return await this.credentialStore.store(e,w),console.log(` Successfully authenticated with ${e}`),s&&console.log(" DPoP proof-of-possession is active"),{success:!0,host:e}}async refresh(e){let t=await this.credentialStore.getCredential(e);if(!t)return $(`No stored credentials for '${e}'. Run 'kanonak login ${e}' to authenticate first.`);if(!t.refreshToken)return $(`No refresh token available for '${e}'.
30
30
  The authorization server may not issue refresh tokens for this client.
31
- Run 'kanonak login ${e}' to re-authenticate.`);if(!t.clientId)return v(`No client ID in stored credentials for '${e}'.
32
- The stored credential may be corrupted. Run 'kanonak logout ${e}' then 'kanonak login ${e}'.`);let o=t.tokenEndpoint;if(!o){let s=await this.discovery.discover(e);if(!s?.tokenEndpoint)return v(`Cannot find token endpoint for '${e}'.
31
+ Run 'kanonak login ${e}' to re-authenticate.`);if(!t.clientId)return $(`No client ID in stored credentials for '${e}'.
32
+ The stored credential may be corrupted. Run 'kanonak logout ${e}' then 'kanonak login ${e}'.`);let o=t.tokenEndpoint;if(!o){let s=await this.discovery.discover(e);if(!s?.tokenEndpoint)return $(`Cannot find token endpoint for '${e}'.
33
33
  The OAuth discovery endpoint may be unreachable.
34
- Check network connectivity and run 'kanonak login ${e}' to re-authenticate.`);o=s.tokenEndpoint}let r=await this.refreshTokenRequest(o,t.clientId,t.clientSecret,t.refreshToken,t.dpopKeyPair);return r.success?(t.accessToken=r.tokens.accessToken,r.tokens.refreshToken&&(t.refreshToken=r.tokens.refreshToken),t.expiresAt=r.tokens.expiresIn?new Date(Date.now()+r.tokens.expiresIn*1e3).toISOString():null,t.tokenEndpoint=o,await this.credentialStore.store(e,t),{success:!0,host:e}):v(`${r.error}
35
- 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 v(`No stored credentials for '${e}'.
36
- 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(i){return{success:!1,error:`Dynamic client registration request to ${e} failed: ${A(i)}
34
+ Check network connectivity and run 'kanonak login ${e}' to re-authenticate.`);o=s.tokenEndpoint}let r=await this.refreshTokenRequest(o,t.clientId,t.clientSecret,t.refreshToken,t.dpopKeyPair);return r.success?(t.accessToken=r.tokens.accessToken,r.tokens.refreshToken&&(t.refreshToken=r.tokens.refreshToken),t.expiresAt=r.tokens.expiresIn?new Date(Date.now()+r.tokens.expiresIn*1e3).toISOString():null,t.tokenEndpoint=o,await this.credentialStore.store(e,t),{success:!0,host:e}):$(`${r.error}
35
+ 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 $(`No stored credentials for '${e}'.
36
+ 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(i){return{success:!1,error:`Dynamic client registration request to ${e} failed: ${j(i)}
37
37
  Ensure the IDP is reachable and HTTPS is properly configured.
38
- If using a corporate proxy or custom CA, set NODE_EXTRA_CA_CERTS.`}}if(!o.ok){let i=await X(o);return{success:!1,error:`Dynamic client registration (RFC 7591) failed.
38
+ If using a corporate proxy or custom CA, set NODE_EXTRA_CA_CERTS.`}}if(!o.ok){let i=await ce(o);return{success:!1,error:`Dynamic client registration (RFC 7591) failed.
39
39
  Endpoint: ${e}
40
40
  HTTP ${o.status}: ${i}
41
41
  The IDP may not support dynamic registration for public clients.
42
42
  Ask your IDP administrator to enable RFC 7591 support, or pre-register a client manually.`}}let r=await o.json(),s=r.client_id;return s?{success:!0,clientId:s,clientSecret:r.client_secret}:{success:!1,error:`Dynamic client registration response from ${e} did not contain a client_id.
43
- The IDP response may be malformed. Contact your IDP administrator.`}}async exchangeCode(e,t,o,r,s,i,a){let c=new URLSearchParams({grant_type:"authorization_code",client_id:t,code:r,redirect_uri:s,code_verifier:i});o&&c.set("client_secret",o);let l={"Content-Type":"application/x-www-form-urlencoded"};if(a)try{l.DPoP=me(a.privateKey,a.publicKey,"POST",e)}catch(p){return{success:!1,error:`Failed to create DPoP proof for token exchange: ${A(p)}
44
- The stored key pair may be corrupted. Run 'kanonak login' to re-authenticate.`}}let d;try{d=await fetch(e,{method:"POST",headers:l,body:c.toString()})}catch(p){return{success:!1,error:`Token exchange request to ${e} failed: ${A(p)}
45
- Ensure the token endpoint is reachable.`}}if(!d.ok){let p=await X(d),u=kt(p);return{success:!1,error:`Token exchange failed.
43
+ The IDP response may be malformed. Contact your IDP administrator.`}}async exchangeCode(e,t,o,r,s,i,a){let c=new URLSearchParams({grant_type:"authorization_code",client_id:t,code:r,redirect_uri:s,code_verifier:i});o&&c.set("client_secret",o);let l={"Content-Type":"application/x-www-form-urlencoded"};if(a)try{l.DPoP=Ae(a.privateKey,a.publicKey,"POST",e)}catch(d){return{success:!1,error:`Failed to create DPoP proof for token exchange: ${j(d)}
44
+ 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(d){return{success:!1,error:`Token exchange request to ${e} failed: ${j(d)}
45
+ Ensure the token endpoint is reachable.`}}if(!p.ok){let d=await ce(p),u=qt(d);return{success:!1,error:`Token exchange failed.
46
46
  Endpoint: ${e}
47
- HTTP ${d.status}: ${p}`+(u?`
48
- ${u}`:"")}}return{success:!0,tokens:fe(await d.json())}}async refreshTokenRequest(e,t,o,r,s){let i=new URLSearchParams({grant_type:"refresh_token",client_id:t,refresh_token:r});o&&i.set("client_secret",o);let a={"Content-Type":"application/x-www-form-urlencoded"};if(s)try{a.DPoP=me(s.privateKey,s.publicKey,"POST",e)}catch(l){return{success:!1,error:`Failed to create DPoP proof for token refresh: ${A(l)}`}}let c;try{c=await fetch(e,{method:"POST",headers:a,body:i.toString()})}catch(l){return{success:!1,error:`Token refresh request to ${e} failed: ${A(l)}`}}if(!c.ok){let l=await X(c);return{success:!1,error:`Token refresh failed \u2014 HTTP ${c.status}: ${l}`}}return{success:!0,tokens:fe(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 v(n){return{success:!1,error:n}}function fe(n){return{accessToken:n.access_token,refreshToken:n.refresh_token,expiresIn:typeof n.expires_in=="number"?n.expires_in:void 0}}function A(n){return n instanceof Error?n.message:String(n)}async function X(n){try{return await n.text()}catch{return"(could not read response body)"}}function kt(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 bt(){return he(32).toString("base64url")}function wt(n){return gt("sha256").update(n).digest("base64url")}function vt(){return he(16).toString("base64url")}function $t(n,e,t,o,r,s){let i=new URLSearchParams({client_id:e,response_type:"code",redirect_uri:t,scope:o.join(" "),state:r,code_challenge:s,code_challenge_method:"S256"});return`${n}?${i}`}var St=300*1e3;async function Ct(){return new Promise(n=>{let e=mt((r,s)=>{let i=new URL(r.url,"http://localhost"),a=i.searchParams.get("code")??void 0,c=i.searchParams.get("state")??void 0,l=i.searchParams.get("error")??i.searchParams.get("error_description")??void 0,d=l?Pt(l):null,p=d?`<html><body><h1>Authorization failed</h1><p>${d}</p></body></html>`:"<html><body><h1>Authorization successful!</h1><p>You can close this window.</p></body></html>";s.writeHead(200,{"Content-Type":"text/html"}),s.end(p),t({code:a,state:c,error:l})}),t,o=new Promise(r=>{t=r,setTimeout(()=>{r(null),e.close()},St)});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 Pt(n){return n.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}function Rt(n){try{process.platform==="win32"?J("cmd",["/c","start","",n]):process.platform==="darwin"?J("open",[n]):J("xdg-open",[n])}catch{console.log(" Could not open browser automatically. Please navigate to the URL above manually.")}}import{CredentialStore as Dt}from"@kanonak-protocol/sdk";async function ye(n){try{let e=new P,t=new Dt,r=await new I(e,t).authorize(n);r.success?console.log(`
47
+ HTTP ${p.status}: ${d}`+(u?`
48
+ ${u}`:"")}}return{success:!0,tokens:xe(await p.json())}}async refreshTokenRequest(e,t,o,r,s){let i=new URLSearchParams({grant_type:"refresh_token",client_id:t,refresh_token:r});o&&i.set("client_secret",o);let a={"Content-Type":"application/x-www-form-urlencoded"};if(s)try{a.DPoP=Ae(s.privateKey,s.publicKey,"POST",e)}catch(l){return{success:!1,error:`Failed to create DPoP proof for token refresh: ${j(l)}`}}let c;try{c=await fetch(e,{method:"POST",headers:a,body:i.toString()})}catch(l){return{success:!1,error:`Token refresh request to ${e} failed: ${j(l)}`}}if(!c.ok){let l=await ce(c);return{success:!1,error:`Token refresh failed \u2014 HTTP ${c.status}: ${l}`}}return{success:!0,tokens:xe(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 $(n){return{success:!1,error:n}}function xe(n){return{accessToken:n.access_token,refreshToken:n.refresh_token,expiresIn:typeof n.expires_in=="number"?n.expires_in:void 0}}function j(n){return n instanceof Error?n.message:String(n)}async function ce(n){try{return await n.text()}catch{return"(could not read response body)"}}function qt(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 Yt(){return Ee(32).toString("base64url")}function Jt(n){return Vt("sha256").update(n).digest("base64url")}function Xt(){return Ee(16).toString("base64url")}function Qt(n,e,t,o,r,s){let i=new URLSearchParams({client_id:e,response_type:"code",redirect_uri:t,scope:o.join(" "),state:r,code_challenge:s,code_challenge_method:"S256"});return`${n}?${i}`}var Zt=300*1e3;async function en(){return new Promise(n=>{let e=Bt((r,s)=>{let i=new URL(r.url,"http://localhost"),a=i.searchParams.get("code")??void 0,c=i.searchParams.get("state")??void 0,l=i.searchParams.get("error")??i.searchParams.get("error_description")??void 0,p=l?tn(l):null,d=p?`<html><body><h1>Authorization failed</h1><p>${p}</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:a,state:c,error:l})}),t,o=new Promise(r=>{t=r,setTimeout(()=>{r(null),e.close()},Zt)});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 tn(n){return n.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}function nn(n){try{process.platform==="win32"?ae("cmd",["/c","start","",n]):process.platform==="darwin"?ae("open",[n]):ae("xdg-open",[n])}catch{console.log(" Could not open browser automatically. Please navigate to the URL above manually.")}}import{CredentialStore as on}from"@kanonak-protocol/sdk";async function Te(n){try{let e=new x,t=new on,r=await new N(e,t).authorize(n);r.success?console.log(`
49
49
  Authenticated with ${n}.`):(console.error(`
50
50
  Authentication failed:
51
51
  ${r.error}`),process.exit(1))}catch(e){let t=e instanceof Error?e.message:String(e);console.error(`
52
52
  Authentication failed unexpectedly:
53
53
  ${t}`),console.error(`
54
- If this persists, file an issue at https://github.com/kanonak-protocol/typescript/issues`),process.exit(1)}}import{CredentialStore as Tt}from"@kanonak-protocol/sdk";async function ke(n){try{let e=new P,t=new Tt,r=await new I(e,t).logout(n);r.success?console.log(`Logged out from ${n}.`):(console.error(`
54
+ If this persists, file an issue at https://github.com/kanonak-protocol/typescript/issues`),process.exit(1)}}import{CredentialStore as rn}from"@kanonak-protocol/sdk";async function Oe(n){try{let e=new x,t=new rn,r=await new N(e,t).logout(n);r.success?console.log(`Logged out from ${n}.`):(console.error(`
55
55
  Logout failed:
56
56
  ${r.error}`),process.exit(1))}catch(e){let t=e instanceof Error?e.message:String(e);console.error(`
57
57
  Logout failed unexpectedly:
58
- ${t}`),process.exit(1)}}import{Command as Lt}from"commander";import{KanonakParser as Et,PublisherIndex as Ft,CredentialStore as jt,createAuthenticatedFetch as Kt}from"@kanonak-protocol/sdk";import{readFileSync as xt,writeFileSync as At,existsSync as It}from"fs";import{join as _t}from"path";import be from"js-yaml";import{getGlobalCachePath as Ot}from"@kanonak-protocol/sdk";var Nt=`# This file is generated by Kanonak CLI. Do not edit manually.
59
- `;function we(){let n=Ot();return _t(n,"..","capabilities.lock")}function _(){let n=we();if(!It(n))return{version:"1",lastUpdated:new Date().toISOString(),capabilities:{}};let e=xt(n,"utf-8"),t=be.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=be.dump(n,{lineWidth:-1,sortKeys:!1,quotingType:'"'});At(we(),Nt+t,"utf-8")}function ve(){let n=new Lt("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 Ut(e)}),n.command("remove <name>").description("Remove an installed capability").action(async e=>{await Ht(e)}),n.command("list").description("List installed capabilities").action(async()=>{await zt()}),n}async function Ut(n){let e=T(n);e||(console.error(`Invalid package reference: ${n}`),console.error("Expected format: {publisher}/{package}@{version} or {publisher}/{package}"),process.exit(1));let{publisher:t,packageName:o,version:r}=e,s=new $,i=new Et,a=new jt,c=Kt(a),l=new Ft({fetchFn:c}),d=r??await l.getHighestVersion(t,o);d||(console.error(`Could not resolve version for ${t}/${o}`),process.exit(1)),console.log(`Installing capability ${t}/${o}@${d}...`);let p=s.get(t,o,d);if(!p){let g=await l.getPackageUrl(t,o,d),k=await c(g,t);if(!k.ok)throw new Error(`Failed to fetch ${g} (${k.status} ${k.statusText})`);p=await k.text(),s.put(t,o,d,p)}let u=i.parse(p),y=null;for(let[,g]of Object.entries(u.body)){if(!g||typeof g!="object")continue;let k=String(g.type??"");if(k==="Capability"||k.endsWith(".Capability")){y=g.commandName??null;break}}y||(console.error(`Package ${t}/${o}@${d} does not contain a Capability instance.`),process.exit(1));let m=_();m.capabilities[y]={publisher:t,package_:o,version:d,resolved:await l.getPackageUrl(t,o,d),integrity:D(p)},Y(m),console.log(`
60
- Installed capability "${y}".`),console.log(`Run "kanonak ${y} --help" to get started.`)}async function Ht(n){let e=_();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 zt(){let n=_(),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:
61
- `);for(let[t,o]of e)console.log(` ${t} ${o.publisher}/${o.package_}@${o.version}`)}async function $e(n,e){let t=_(),o=[];for(let[r,s]of Object.entries(t.capabilities)){let i=n.get(s.publisher,s.package_,s.version);if(!i){console.error(` WARNING: Cached content missing for capability "${r}" (${s.publisher}/${s.package_}@${s.version})`);continue}try{let a=e.parse(i),c=Vt(a.body,r,s.publisher,s.package_,s.version);c&&o.push(c)}catch(a){console.error(` WARNING: Failed to parse capability "${r}": ${a}`)}}return o}function Vt(n,e,t,o,r){for(let[,s]of Object.entries(n)){if(!s||typeof s!="object")continue;let i=String(s.type??"");if(i!=="Capability"&&!i.endsWith(".Capability"))continue;let a=s.commandName??e,c=s.description??"",l=Mt(s.managesType),d=Wt(s.deploymentTarget),p=qt(s.hasCommand);return{commandName:a,description:c,managesType:l,deploymentTargetName:d,commands:p,publisher:t,package_:o,version:r}}return null}function Mt(n){return typeof n=="string"?Q(n):""}function Wt(n){return typeof n=="string"?Q(n):""}function Se(n){return n==null?[]:Array.isArray(n)?n.filter(e=>typeof e=="object"&&e!==null&&!Array.isArray(e)):typeof n=="object"?Object.entries(n).filter(([,t])=>typeof t=="object"&&t!==null&&!Array.isArray(t)).map(([t,o])=>({__key:t,...o})):[]}function Q(n){if(typeof n!="string")return"";let e=n.indexOf(".");return e===-1?n:n.slice(e+1)}function qt(n){return Se(n).map(e=>({subcommandName:String(e.subcommandName??e.__key??""),description:String(e.description??""),arguments:Gt(e.hasArgument),actionName:Q(e.performs)}))}function Gt(n){return Se(n).map(e=>({argumentName:String(e.argumentName??e.__key??""),required:e.isRequired===!0,isOption:e.isOption===!0,...e.defaultValue!=null?{defaultValue:String(e.defaultValue)}:{}}))}import{Command as Ce}from"commander";var Z={fetchAndDeploy:(n,e,t,o)=>n.add(e,t[0],o),removeDeployed:(n,e,t,o)=>n.remove(e,t[0],o),listDeployed:(n,e,t,o)=>n.list(e,o),updateDeployed:(n,e,t,o)=>n.update(e,t[0],o),searchAvailable:(n,e,t,o)=>n.search(e,o),showInfo:(n,e,t,o)=>n.info(e,t[0],o)};function Pe(n,e,t){for(let o of e){let r=new Ce(o.commandName).description(o.description.trim());for(let s of o.commands){let i=r.command(Bt(s));i.description(s.description);for(let a of s.arguments)if(a.isOption){let c=a.defaultValue!=null?`--${a.argumentName} [value]`:`--${a.argumentName} <value>`;i.option(c,"",a.defaultValue)}i.action(async(...a)=>{let c=Jt(a);await Xt(t,o,s,a,c)})}n.addCommand(r)}}function Bt(n){let e=n.arguments.filter(t=>!t.isOption).map(t=>t.required?`<${t.argumentName}>`:`[${t.argumentName}]`);return[n.subcommandName,...e].join(" ")}function Jt(n){for(let e=n.length-1;e>=0;e--)if(n[e]&&typeof n[e]=="object"&&!(n[e]instanceof Ce))return n[e];return{}}async function Xt(n,e,t,o,r){let s=[];for(let a of o)if(typeof a=="string")s.push(a);else break;t.actionName||(console.error(`Capability subcommand '${t.subcommandName}' has no \`performs\` Action. Every CapabilityCommand must declare a \`performs:\` value pointing at a named Action instance from the capabilities ontology. Known actions: ${Object.keys(Z).join(", ")}.`),process.exit(1));let i=Z[t.actionName];i||(console.error(`Capability subcommand '${t.subcommandName}' references unknown Action '${t.actionName}'. Known actions: ${Object.keys(Z).join(", ")}.`),process.exit(1)),await i(n,e,s,r)}import{PublisherIndex as ee,PublisherConfigResolver as Yt,InMemoryKanonakDocumentRepository as Re,findInstancesByType as De}from"@kanonak-protocol/sdk";var K=class{constructor(e,t,o,r,s){this.fileCache=e;this.parser=t;this.publisherIndex=o;this.fetchFn=r;this.handlerRegistry=s}fileCache;parser;publisherIndex;fetchFn;handlerRegistry;async add(e,t,o){let r=T(t);r||(console.error(`Invalid package reference: ${t}`),console.error("Expected format: {publisher}/{package}@{version} or {publisher}/{package}"),process.exit(1));let{publisher:s,packageName:i,version:a}=r,c=a??await this.publisherIndex.getHighestVersion(s,i);c||(console.error(`Could not resolve version for ${s}/${i}`),process.exit(1));let l=this.fileCache.get(s,i,c);if(!l){let f=await this.publisherIndex.getPackageUrl(s,i,c),h=await this.fetchFn(f,s);if(!h.ok)throw new Error(`Failed to fetch ${f} (${h.status} ${h.statusText})`);l=await h.text(),this.fileCache.put(s,i,c,l)}let d=this.parser.parse(l),p=new Re(this.parser),u=d.metadata.namespace_,y=u?.version?`${u.version.major}.${u.version.minor}.${u.version.patch}`:"0.0.0",m=u?`${u.publisher}/${u.package_}/${y}`:t;await p.saveDocumentAsync(d,m);let g=await De(p,e.managesType);g.length===0&&(console.error(`Package ${s}/${i}@${c} does not contain any ${e.managesType} instances.`),process.exit(1));let k=this.handlerRegistry.get(e.deploymentTargetName);k?await k.deploy(d,g,o):console.log(`Cached ${s}/${i}@${c} (no deployment handler for "${e.deploymentTargetName}")`)}async remove(e,t,o){let r=this.handlerRegistry.get(e.deploymentTargetName);r||(console.error(`No deployment handler registered for "${e.deploymentTargetName}"`),process.exit(1)),await r.undeploy(t,o)}async list(e,t){let o=this.handlerRegistry.get(e.deploymentTargetName);o||(console.error(`No deployment handler registered for "${e.deploymentTargetName}"`),process.exit(1));let r=await o.list(t);if(r.length===0){console.log(`No ${e.managesType} instances installed.`);return}console.log(`Installed ${e.managesType} instances:
62
- `);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 r=this.handlerRegistry.get(e.deploymentTargetName);r||(console.error(`No deployment handler registered for "${e.deploymentTargetName}"`),process.exit(1));let s=await r.list(o),i=t?s.filter(c=>c.name===t):s.filter(c=>c.publisher);if(i.length===0){console.log(t?`Skill "${t}" not found.`:"No managed instances to update.");return}let a=0;for(let c of i){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),a++)}console.log(a===0?"All instances are up to date.":`
63
- Updated ${a} instance(s).`)}async search(e,t){let o=t.publisher??"kanonak.org";console.log(`Searching ${o} for ${e.managesType} instances...
64
- `);let r=new Yt,s=await r.getConfig(o),i=r.resolveIndexUrl(o,s),a=await this.fetchFn(i,o);if(!a.ok){console.error(`Failed to fetch package index from ${o}.`);return}let c=await a.text(),l=ee.parseIndex(c);if(l.size===0){console.error(`No packages found for publisher "${o}".`);return}let d=new Map;for(let[m,g]of l){let k=[...g].sort((f,h)=>{let b=ee.parseVersion(f),w=ee.parseVersion(h);return!b||!w?0:b.major!==w.major?w.major-b.major:b.minor!==w.minor?w.minor-b.minor:w.patch-b.patch});d.set(m,k[0])}let p=new Re(this.parser),u=0;for(let[m,g]of d){let k=this.fileCache.get(o,m,g);if(!k)try{let f=await this.publisherIndex.getPackageUrl(o,m,g),h=await this.fetchFn(f,o);if(!h.ok)continue;k=await h.text(),this.fileCache.put(o,m,g,k)}catch{continue}try{let f=this.parser.parse(k),h=f.metadata.namespace_,b=h?.version?`${h.version.major}.${h.version.minor}.${h.version.patch}`:"0.0.0",w=h?`${h.publisher}/${h.package_}/${b}`:`${o}/${m}/${g}`;await p.saveDocumentAsync(f,w),u++}catch{continue}}let y=await De(p,e.managesType);if(y.length===0){console.log(`No ${e.managesType} instances found across ${u} package(s).`);return}console.log(`Found ${y.length} ${e.managesType} instance(s):
65
- `);for(let m of y){let g=m.entity.description?String(m.entity.description).trim().substring(0,80):"";console.log(` ${m.publisher}/${m.package_}@${m.version}`),console.log(` ${m.entityName}: ${g}`),console.log()}}async info(e,t,o){let r=this.handlerRegistry.get(e.deploymentTargetName);r||(console.error(`No deployment handler registered for "${e.deploymentTargetName}"`),process.exit(1));let i=(await r.list(o)).find(a=>a.name===t);i||(console.error(`${e.managesType} "${t}" is not installed.`),process.exit(1)),console.log(`Name: ${i.name}`),console.log(`Type: ${e.managesType}`),console.log(`Publisher: ${i.publisher||"unmanaged"}`),console.log(`Package: ${i.package_||"n/a"}`),console.log(`Version: ${i.version||"n/a"}`),console.log(`Path: ${i.path}`)}};var U=class{handlers=new Map;register(e,t){this.handlers.set(e,t)}get(e){return this.handlers.get(e)??null}};import{mkdirSync as gn,rmSync as mn,existsSync as V,readdirSync as fn,writeFileSync as hn}from"fs";import{join as M}from"path";var Qt={bash:"Bash",read:"Read",write:"Write",edit:"Edit",glob:"Glob",grep:"Grep","web-search":"Web Search","web-fetch":"Web Fetch"};function Te(n){let e=[];for(let[,t]of Object.entries(n.body)){if(!t||typeof t!="object")continue;let o=String(t.type??"");if(!Zt(o))continue;let r=en(t);r&&e.push(r)}return e}function Zt(n){return n==="Skill"||n.endsWith(".Skill")}function en(n){let e=R(n,"name"),t=L(R(n,"description"));if(!e||!t)return null;let o=[];o.push(`name: ${e}`),o.push(`description: ${t}`);let r=on(R(n,"allowedTools"));r&&o.push(`allowed-tools: ${r}`);let s=R(n,"license");s&&o.push(`license: ${rn(s)}`);let i=R(n,"compatibility");i&&o.push(`compatibility: ${L(i)}`);let a=tn(R(n,"hasSection"))||nn(R(n,"hasResource"),n),c=["---",...o,"---","",a].join(`
66
- `);return{name:e,description:t,skillMd:c}}function tn(n){if(!Array.isArray(n)||n.length===0)return"";let e=[];for(let t of n){if(!t||typeof t!="object")continue;let o=t.title,r=L(t.body);o&&e.push(`## ${o}`),r&&e.push(r)}return e.join(`
58
+ ${t}`),process.exit(1)}}import{Command as xn}from"commander";import{KanonakParser as En,KanonakObjectParser as Tn,PublisherIndex as On,CredentialStore as Un,createAuthenticatedFetch as Ln}from"@kanonak-protocol/sdk";import{readFileSync as sn,writeFileSync as an,existsSync as cn}from"fs";import{join as ln}from"path";import Ue from"js-yaml";import{getGlobalCachePath as pn}from"@kanonak-protocol/sdk";var dn=`# This file is generated by Kanonak CLI. Do not edit manually.
59
+ `;function Le(){let n=pn();return ln(n,"..","capabilities.lock")}function F(){let n=Le();if(!cn(n))return{version:"1",lastUpdated:new Date().toISOString(),capabilities:{}};let e=sn(n,"utf-8"),t=Ue.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 le(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=Ue.dump(n,{lineWidth:-1,sortKeys:!1,quotingType:'"'});an(Le(),dn+t,"utf-8")}var _=class{constructor(e,t){this.doc=e;this.broader=t}doc;broader;async getAllDocumentsAsync(){return[this.doc]}async getDocumentAsync(e){return this.broader.getDocumentAsync(e)}async getDocumentsByNamespaceAsync(e,t){return this.broader.getDocumentsByNamespaceAsync(e,t)}async getHighestCompatibleVersionAsync(e,t){return this.broader.getHighestCompatibleVersionAsync(e,t)}async saveDocumentAsync(){throw new Error("SingleDocumentRepository is read-only")}async deleteDocumentAsync(){throw new Error("SingleDocumentRepository is read-only")}async clearNamespaceAsync(){throw new Error("SingleDocumentRepository is read-only")}async getAllDocumentReferencesAsync(){return[]}async getDocumentContentAsync(e){return this.broader.getDocumentContentAsync(e)}async getDocumentUriAsync(e){return this.broader.getDocumentUriAsync(e)}};import{KanonakObjectParser as bn,EmbeddedKanonak as Be,ReferenceKanonak as ze}from"@kanonak-protocol/sdk";import{SubjectKanonak as je,DefinedKanonak as un,StringStatement as mn,NumberStatement as gn,BooleanStatement as fn,ReferenceStatement as Ne,EmbeddedStatement as zr,ListStatement as yn}from"@kanonak-protocol/sdk";function I(n){return`${n.publisher}/${n.package_}/${n.name}`}function pe(n,e){return n.publisher===e.publisher&&n.package_===e.package_&&n.name===e.name}function hn(n,e){if(!(n instanceof un))return!1;for(let t of n.statement)if(t.predicate?.subject?.name==="type"&&t instanceof Ne){let r=t.object;if(pe(r.subject,e))return!0}return!1}function D(n,e){let t=[];for(let o of n)o instanceof je&&hn(o,e)&&t.push(o);return t}function Fe(n,e){for(let t of n){if(!(t instanceof je)||t.name!==e.name)continue;if((t.namespace||"").startsWith(`${e.publisher}/${e.package_}@`))return t}}function de(n,e){for(let t of n.statement){let o=t.predicate;if(o?.subject&&pe(o.subject,e))return t}}function kn(n,e){let t=de(n,e);if(t&&(t instanceof mn||t instanceof gn||t instanceof fn))return t.object}function P(n,e){let t=kn(n,e);return typeof t=="string"?t:void 0}function H(n,e){let t=de(n,e);if(t instanceof Ne)return t.object.subject}function M(n,e){let t=de(n,e);return t instanceof yn?t.object??[]:[]}var S="kanonak.org",v="capabilities",ue={publisher:S,package_:v,name:"Capability"},Pn={publisher:S,package_:v,name:"commandName"},Ge={publisher:S,package_:v,name:"description"},wn={publisher:S,package_:v,name:"managesType"},Sn={publisher:S,package_:v,name:"deploymentTarget"},vn={publisher:S,package_:v,name:"hasCommand"},$n={publisher:S,package_:v,name:"subcommandName"},Rn={publisher:S,package_:v,name:"performs"},_n={publisher:S,package_:v,name:"hasArgument"},Cn={publisher:S,package_:v,name:"argumentName"},He={publisher:S,package_:v,name:"isRequired"},Me={publisher:S,package_:v,name:"isOption"},Dn={publisher:S,package_:v,name:"defaultValue"};async function We(n,e,t){let o=F(),r=new bn,s=[];for(let[i,a]of Object.entries(o.capabilities)){let c=n.get(a.publisher,a.package_,a.version);if(!c){console.error(` WARNING: Cached content missing for capability "${i}" (${a.publisher}/${a.package_}@${a.version})`);continue}try{let l=e.parse(c),p=new _(l,t),d=await r.parseKanonaks(p),u=In(d,a.publisher,a.package_,a.version);u?s.push(u):console.error(` WARNING: No Capability instance found in "${i}" (${a.publisher}/${a.package_}@${a.version})`)}catch(l){console.error(` WARNING: Failed to parse capability "${i}": ${l}`)}}return s}function In(n,e,t,o){let r=D(n,ue);if(r.length===0)return;let s=r[0],i=P(s,Pn)??"",a=P(s,Ge)??"",c=H(s,wn),l=H(s,Sn),p=[];for(let d of M(s,vn)){let u=Kn(d,n);u&&p.push(u)}return{commandName:i,description:a,managesTypeKey:c?I(c):"",deploymentTargetKey:l?I(l):"",commands:p,publisher:e,package_:t,version:o}}function Kn(n,e){let t;if(n instanceof Be)t=n;else if(n instanceof ze){let c=qe(e,n.subject.publisher,n.subject.package_,n.subject.name);c&&(t=c)}if(!t)return;let o=P(t,$n)??"",r=P(t,Ge)??"",s=H(t,Rn),i=M(t,_n),a=[];for(let c of i){let l=An(c,e);l&&a.push(l)}return{subcommandName:o,description:r,arguments:a,actionKey:s?I(s):""}}function An(n,e){let t;if(n instanceof Be)t=n;else if(n instanceof ze){let c=qe(e,n.subject.publisher,n.subject.package_,n.subject.name);c&&(t=c)}if(!t)return;let o=P(t,Cn)??"",r=P(t,He)==="true"||Ve(t,He)===!0,s=P(t,Me)==="true"||Ve(t,Me)===!0,i=P(t,Dn),a={argumentName:o,required:r,isOption:s};return i!==void 0&&(a.defaultValue=i),a}function Ve(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 qe(n,e,t,o){for(let r of n){if(!("name"in r)||!("namespace"in r))continue;let s=r;if(s.name===o&&!(!s.namespace||typeof s.namespace!="string")&&s.namespace.startsWith(`${e}/${t}@`))return r}}var jn={publisher:S,package_:v,name:"commandName"};function Ye(){let n=new xn("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 Nn(e)}),n.command("remove <name>").description("Remove an installed capability").action(async e=>{await Fn(e)}),n.command("list").description("List installed capabilities").action(async()=>{await Hn()}),n}async function Nn(n){let e=U(n);e||(console.error(`Invalid package reference: ${n}`),console.error("Expected format: {publisher}/{package}@{version} or {publisher}/{package}"),process.exit(1));let{publisher:t,packageName:o,version:r}=e,s=new C,i=new En,a=new Tn,c=new Un,l=Ln(c),p=new On({fetchFn:l}),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 u=s.get(t,o,d);if(!u){let R=await p.getPackageUrl(t,o,d),Y=await l(R,t);if(!Y.ok)throw new Error(`Failed to fetch ${R} (${Y.status} ${Y.statusText})`);u=await Y.text(),s.put(t,o,d,u)}let g=i.parse(u),f=await A(process.cwd(),i),y=new _(g,f),k=await a.parseKanonaks(y),m=D(k,ue);m.length===0&&(console.error(`Package ${t}/${o}@${d} does not contain a ${S}/${v}/Capability instance.`),process.exit(1));let b=m[0],h=P(b,jn);h||(console.error(`Capability instance in ${t}/${o}@${d} has no commandName property.`),process.exit(1));let w=F();w.capabilities[h]={publisher:t,package_:o,version:d,resolved:await p.getPackageUrl(t,o,d),integrity:O(u)},le(w),console.log(`
60
+ Installed capability "${h}".`),console.log(`Run "kanonak ${h} --help" to get started.`)}async function Fn(n){let e=F();e.capabilities[n]||(console.error(`Capability "${n}" is not installed.`),process.exit(1));let t=e.capabilities[n];delete e.capabilities[n],le(e),console.log(`Removed capability "${n}" (${t.publisher}/${t.package_}@${t.version}).`)}async function Hn(){let n=F(),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:
61
+ `);for(let[t,o]of e)console.log(` ${t} ${o.publisher}/${o.package_}@${o.version}`)}import{Command as Je}from"commander";function V(n){return`${S}/${v}/${n}`}var me={[V("fetchAndDeploy")]:(n,e,t,o)=>n.add(e,t[0],o),[V("removeDeployed")]:(n,e,t,o)=>n.remove(e,t[0],o),[V("listDeployed")]:(n,e,t,o)=>n.list(e,o),[V("updateDeployed")]:(n,e,t,o)=>n.update(e,t[0],o),[V("searchAvailable")]:(n,e,t,o)=>n.search(e,o),[V("showInfo")]:(n,e,t,o)=>n.info(e,t[0],o)};function Xe(n,e,t){for(let o of e){let r=new Je(o.commandName).description(o.description.trim());for(let s of o.commands){let i=r.command(Mn(s));i.description(s.description);for(let a of s.arguments)if(a.isOption){let c=a.defaultValue!=null?`--${a.argumentName} [value]`:`--${a.argumentName} <value>`;i.option(c,"",a.defaultValue)}i.action(async(...a)=>{let c=Vn(a);await Bn(t,o,s,a,c)})}n.addCommand(r)}}function Mn(n){let e=n.arguments.filter(t=>!t.isOption).map(t=>t.required?`<${t.argumentName}>`:`[${t.argumentName}]`);return[n.subcommandName,...e].join(" ")}function Vn(n){for(let e=n.length-1;e>=0;e--)if(n[e]&&typeof n[e]=="object"&&!(n[e]instanceof Je))return n[e];return{}}async function Bn(n,e,t,o,r){let s=[];for(let a of o)if(typeof a=="string")s.push(a);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(me).join(", ")}.`),process.exit(1));let i=me[t.actionKey];i||(console.error(`Capability subcommand '${t.subcommandName}' references unknown Action '${t.actionKey}'. Known actions: ${Object.keys(me).join(", ")}.`),process.exit(1)),await i(n,e,s,r)}import{KanonakObjectParser as zn,PublisherIndex as ge,PublisherConfigResolver as Gn}from"@kanonak-protocol/sdk";var X=class{constructor(e,t,o,r,s,i){this.fileCache=e;this.parser=t;this.publisherIndex=o;this.fetchFn=r;this.handlerRegistry=s;this.repository=i}fileCache;parser;publisherIndex;fetchFn;handlerRegistry;repository;objectParser=new zn;async add(e,t,o){let r=U(t);r||(console.error(`Invalid package reference: ${t}`),console.error("Expected format: {publisher}/{package}@{version} or {publisher}/{package}"),process.exit(1));let{publisher:s,packageName:i,version:a}=r,c=a??await this.publisherIndex.getHighestVersion(s,i);c||(console.error(`Could not resolve version for ${s}/${i}`),process.exit(1));let l=this.fileCache.get(s,i,c);if(!l){let k=await this.publisherIndex.getPackageUrl(s,i,c),m=await this.fetchFn(k,s);if(!m.ok)throw new Error(`Failed to fetch ${k} (${m.status} ${m.statusText})`);l=await m.text(),this.fileCache.put(s,i,c,l)}let p=this.parser.parse(l),d=new _(p,this.repository),u=await this.objectParser.parseKanonaks(d),g=Qe(e.managesTypeKey);g||(console.error(`Capability "${e.commandName}" has no resolved managesType.`),process.exit(1));let f=D(u,g);f.length===0&&(console.error(`Package ${s}/${i}@${c} does not contain any ${I(g)} instances.`),process.exit(1));let y=this.handlerRegistry.get(e.deploymentTargetKey);y?await y.deploy({instances:f,allKanonaks:u,repository:this.repository,options:o}):console.log(`Cached ${s}/${i}@${c} (no deployment handler for "${e.deploymentTargetKey}")`)}async remove(e,t,o){await this.requireHandler(e).undeploy(t,{repository:this.repository,options:o})}async list(e,t){let r=await this.requireHandler(e).list({repository:this.repository,options:t}),s=e.managesTypeKey||"managed";if(r.length===0){console.log(`No ${s} instances installed.`);return}console.log(`Installed ${s} instances:
62
+ `);for(let i of r){let a=i.publisher?`${i.publisher}/${i.package_}@${i.version}`:"unmanaged";console.log(` ${i.name} (${a}) ${i.path}`)}}async update(e,t,o){let s=await this.requireHandler(e).list({repository:this.repository,options:o}),i=t?s.filter(c=>c.name===t):s.filter(c=>c.publisher);if(i.length===0){console.log(t?`"${t}" not found.`:"No managed instances to update.");return}let a=0;for(let c of i){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),a++)}console.log(a===0?"All instances are up to date.":`
63
+ Updated ${a} instance(s).`)}async search(e,t){let o=t.publisher??"kanonak.org",r=Qe(e.managesTypeKey);if(!r){console.error("Capability has no resolved managesType; nothing to search for.");return}console.log(`Searching ${o} for ${I(r)} instances...
64
+ `);let s=new Gn,i=await s.getConfig(o),a=s.resolveIndexUrl(o,i),c=await this.fetchFn(a,o);if(!c.ok){console.error(`Failed to fetch package index from ${o}.`);return}let l=await c.text(),p=ge.parseIndex(l);if(p.size===0){console.error(`No packages found for publisher "${o}".`);return}let d=new Map;for(let[f,y]of p){let k=[...y].sort((m,b)=>{let h=ge.parseVersion(m),w=ge.parseVersion(b);return!h||!w?0:h.major!==w.major?w.major-h.major:h.minor!==w.minor?w.minor-h.minor:w.patch-h.patch});d.set(f,k[0])}let u=[],g=0;for(let[f,y]of d){let k=this.fileCache.get(o,f,y);if(!k)try{let m=await this.publisherIndex.getPackageUrl(o,f,y),b=await this.fetchFn(m,o);if(!b.ok)continue;k=await b.text(),this.fileCache.put(o,f,y,k)}catch{continue}try{let m=this.parser.parse(k),b=new _(m,this.repository),h=await this.objectParser.parseKanonaks(b),w=D(h,r);for(let R of w)u.push({publisher:o,package_:f,version:y,subject:R});g++}catch{continue}}if(u.length===0){console.log(`No ${I(r)} instances found across ${g} package(s).`);return}console.log(`Found ${u.length} ${I(r)} instance(s):
65
+ `);for(let f of u)console.log(` ${f.publisher}/${f.package_}@${f.version}`),console.log(` ${f.subject.name}`),console.log()}async info(e,t,o){let i=(await this.requireHandler(e).list({repository:this.repository,options:o})).find(a=>a.name===t);i||(console.error(`"${t}" is not installed.`),process.exit(1)),console.log(`Name: ${i.name}`),console.log(`Type: ${e.managesTypeKey||"n/a"}`),console.log(`Publisher: ${i.publisher||"unmanaged"}`),console.log(`Package: ${i.package_||"n/a"}`),console.log(`Version: ${i.version||"n/a"}`),console.log(`Path: ${i.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 Qe(n){if(!n)return;let e=n.split("/");if(e.length===3)return{publisher:e[0],package_:e[1],name:e[2]}}var Q=class{handlers=new Map;register(e,t){this.handlers.set(e,t)}get(e){return this.handlers.get(e)??null}};import{mkdirSync as So,rmSync as vo,existsSync as te,readdirSync as $o,writeFileSync as Ro}from"fs";import{join as ne}from"path";import{KanonakObjectParser as _o,KanonakParser as Co}from"@kanonak-protocol/sdk";import{SubjectKanonak as Ze,EmbeddedKanonak as Wn,ReferenceKanonak as qn}from"@kanonak-protocol/sdk";var E="kanonak.org",T="agent-skills",Yn="kanonak.org",Jn="core-spdx";var Xn={publisher:E,package_:T,name:"name"},Qn={publisher:E,package_:T,name:"description"},Zn={publisher:E,package_:T,name:"license"},eo={publisher:E,package_:T,name:"compatibility"},to={publisher:E,package_:T,name:"allowedTools"},no={publisher:E,package_:T,name:"hasSection"},oo={publisher:E,package_:T,name:"title"},ro={publisher:E,package_:T,name:"body"},so={publisher:Yn,package_:Jn,name:"spdxId"};async function et(n,e,t,o,r){let s=[],i=new ye(t,o,r);for(let a of e){let c=await io(a,n,i);c&&s.push(c)}return s}async function io(n,e,t){let o=P(n,Xn),r=P(n,Qn);if(!o||!r)return;let s=[];s.push(`name: ${o}`),s.push(`description: ${fe(r)}`);let i=H(n,Zn);if(i){let u=await t.resolveSubject(i,e),g=u?P(u,so):void 0;s.push(`license: ${g??i.name}`)}let a=P(n,eo);a&&s.push(`compatibility: ${fe(a)}`);let c=M(n,to);if(c.length>0){let u=await co(c,e,t);u&&s.push(`allowed-tools: ${u}`)}let l=[];for(let u of M(n,no)){let g=ao(u);g&&l.push(g)}let p=l.join(`
67
66
 
68
- `)}function nn(n,e){if(!Array.isArray(n)||n.length===0)return"";let t=[];for(let o of n){let r=typeof o=="string"?e[o]:o;if(!r||typeof r!="object")continue;let s=String(r.type??""),i=r.title??r.resourceTitle??"";if(i&&t.push(`## ${i}`),s==="ScriptResource"||s.endsWith(".ScriptResource")){let a=r.language??"bash",c=L(r.command);c&&t.push(`\`\`\`${a}
69
- ${c}
70
- \`\`\``)}else if(s==="ReferenceResource"||s.endsWith(".ReferenceResource")){let a=L(r.content);a&&t.push(a)}}return t.join(`
67
+ `),d=["---",...s,"---","",p].join(`
68
+ `);return{name:o,description:r,skillMd:d}}function ao(n){if(!(n instanceof Wn))return"";let e=P(n,oo),t=P(n,ro),o=[];return e&&o.push(`## ${e}`),t&&o.push(fe(t)),o.join(`
71
69
 
72
- `)}function on(n){return Array.isArray(n)?n.map(e=>{let t=String(e);return Qt[t]??sn(t)}).join(", "):""}function rn(n){let e=String(n);return e.includes(".")?e.substring(e.lastIndexOf(".")+1):e}function sn(n){return n.split("-").map(e=>e.charAt(0).toUpperCase()+e.slice(1)).join(" ")}function R(n,e){if(e in n)return n[e];for(let t of Object.keys(n))if(t.endsWith(`.${e}`))return n[t]}function L(n){return typeof n!="string"?"":n.trimEnd()}import{join as xe}from"path";import{homedir as an}from"os";function E(n){let e=n.scope??"project",t=n.client??cn(),o=t?`.${t}`:".agents",r=e==="user"?an():process.cwd();return xe(r,o,"skills")}function H(n,e){return xe(E(e),n)}function cn(){if(process.env.CLAUDE_CODE||process.env.CLAUDE_PROJECT_DIR)return"claude";if(process.env.GEMINI_CLI)return"gemini";if(process.env.CODEX_CLI||process.env.OPENAI_CODEX)return"codex"}import{readFileSync as ln,writeFileSync as dn,existsSync as pn}from"fs";import{join as Ae}from"path";import Ie from"js-yaml";var _e="skills.lock",un=`# This file is generated by Kanonak CLI. Do not edit manually.
73
- `;function z(n){let e=Ae(n,_e);if(!pn(e))return{version:"1",lastUpdated:new Date().toISOString(),skills:{}};let t=ln(e,"utf-8"),o=Ie.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 te(n,e){e.lastUpdated=new Date().toISOString();let t={};for(let s of Object.keys(e.skills).sort())t[s]=e.skills[s];e.skills=t;let o=Ae(n,_e),r=Ie.dump(e,{lineWidth:-1,sortKeys:!1,quotingType:'"'});dn(o,un+r,"utf-8")}var W=class{async deploy(e,t,o){let r=Te(e);if(r.length===0){console.error("No skills could be transformed from the package.");return}let s=E(o),i=z(s),a=e.metadata.namespace_,c=a?.publisher??"",l=a?.package_??"",d=a?.version?`${a.version.major}.${a.version.minor}.${a.version.patch}`:"";for(let p of r){let u=H(p.name,o),y=V(M(u,"SKILL.md"));gn(u,{recursive:!0}),hn(M(u,"SKILL.md"),p.skillMd,"utf-8"),i.skills[p.name]={publisher:c,package_:l,version:d,resolved:a?`kanonak://${c}/${l}@${d}`:"",integrity:D(p.skillMd)},console.log(` ${y?"Updated":"Installed"} skill "${p.name}" \u2192 ${u}`)}te(s,i)}async undeploy(e,t){let o=H(e,t);V(o)||(console.error(`Skill "${e}" is not installed at ${o}`),process.exit(1)),mn(o,{recursive:!0,force:!0});let r=E(t),s=z(r);delete s.skills[e],te(r,s),console.log(`Removed skill "${e}" from ${o}`)}async list(e){let t=E(e),o=z(t),r=[];for(let[s,i]of Object.entries(o.skills))r.push({name:s,publisher:i.publisher,package_:i.package_,version:i.version,path:H(s,e)});if(V(t))try{let s=fn(t,{withFileTypes:!0});for(let i of s){if(!i.isDirectory()||o.skills[i.name])continue;let a=M(t,i.name,"SKILL.md");V(a)&&r.push({name:i.name,publisher:"",package_:"",version:"",path:M(t,i.name)})}}catch{}return r}};var Rn=wn(bn(import.meta.url)),Dn=JSON.parse(kn(vn(Rn,"..","package.json"),"utf-8")),S=new yn;S.name("kanonak").description("Kanonak Protocol CLI - Validate and resolve Kanonak ontology packages").version(Dn.version);S.command("validate <path>").description("Validate .kan.yml file(s). Resolves imports via HTTP from publisher domains.").action(async n=>{await ie(n)});S.command("install [package]").description("Install a package and its dependencies, or install all from kanonak.lock.").action(async n=>{await de(n)});S.command("deps <path>").description("Show resolved dependency tree for a .kan.yml file.").action(async n=>{await ue(n)});S.command("login <publisher>").description("Authenticate with a package publisher using OAuth 2.0.").action(async n=>{await ye(n)});S.command("logout <publisher>").description("Revoke tokens and remove stored credentials for a publisher.").action(async n=>{await ke(n)});S.addCommand(ve());async function Tn(){try{let n=new $,e=new $n,t=new Cn,o=Pn(t),r=new Sn({fetchFn:o}),s=new U;s.register("AgentSkillDeployment",new W);let i=await $e(n,e),a=new K(n,e,r,o,s);Pe(S,i,a)}catch{}}await Tn();S.parse();
70
+ `)}async function co(n,e,t){let o=[];for(let r of n)r instanceof qn&&o.push(r.subject.name);return o.join(" ")}function fe(n){return n.trimEnd()}var ye=class{constructor(e,t,o){this.repository=e;this.parser=t;this.objectParser=o}repository;parser;objectParser;cache=new Map;async resolveSubject(e,t){let o=Fe(t,e);if(o)return o;let r=`${e.publisher}/${e.package_}`,s=this.cache.get(r);if(!s){let i=await this.repository.getDocumentsByNamespaceAsync(e.publisher,e.package_);if(i.length===0)return;let a=i[0],c=new _(a,this.repository);s=await this.objectParser.parseKanonaks(c),this.cache.set(r,s)}for(let i of s)if(i instanceof Ze&&i.name===e.name&&i.namespace&&i.namespace.startsWith(`${e.publisher}/${e.package_}@`))return i;for(let i of s)if(i instanceof Ze&&i.name===e.name)return i}};import{join as he}from"path";import{homedir as tt}from"os";import{KanonakObjectParser as lo}from"@kanonak-protocol/sdk";var B="kanonak.org",z="agent-skills",ot={publisher:B,package_:z,name:"Client"},rt={publisher:B,package_:z,name:"clientId"},po={publisher:B,package_:z,name:"projectSkillDir"},uo={publisher:B,package_:z,name:"userSkillDir"},mo="agents";async function q(n,e){let t=(n.client??go()??mo).toLowerCase(),o=n.scope??"project",r=await fo(t,e);if(!r){let a=await yo(e);throw new Error(`Unknown client "${t}". Known clients: ${a.join(", ")||"(none)"}. Add a Client instance to a package that imports kanonak.org/agent-skills and install that package to make it available.`)}let i=P(r,o==="user"?uo:po);if(!i)throw new Error(`Client "${t}" has no ${o==="user"?"userSkillDir":"projectSkillDir"} declared.`);return ho(i)}async function Z(n,e,t){let o=await q(e,t);return he(o,n)}function go(){if(process.env.CLAUDE_CODE||process.env.CLAUDE_PROJECT_DIR)return"claude-code"}var nt=new WeakMap;async function st(n){let e=nt.get(n);if(e)return e;let t=await n.getDocumentsByNamespaceAsync(B,z);if(t.length===0)throw new Error(`Could not find ${B}/${z} 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,d=l.metadata.namespace_?.version;return!p||!d?0:p.major!==d.major?d.major-p.major:p.minor!==d.minor?d.minor-p.minor:d.patch-p.patch})[0],s=new lo,i=new _(r,n),a=await s.parseKanonaks(i);return nt.set(n,a),a}async function fo(n,e){let t=await st(e),o=D(t,ot);for(let r of o)if(P(r,rt)===n)return r}async function yo(n){let e=await st(n),t=D(e,ot),o=[];for(let r of t){let s=P(r,rt);s&&o.push(s)}return o}function ho(n){return n.startsWith("~/")?he(tt(),n.slice(2)):n==="~"?tt():n.startsWith("/")||/^[A-Za-z]:[\\/]/.test(n)?n:he(process.cwd(),n)}import{readFileSync as ko,writeFileSync as bo,existsSync as Po}from"fs";import{join as it}from"path";import at from"js-yaml";var ct="skills.lock",wo=`# This file is generated by Kanonak CLI. Do not edit manually.
71
+ `;function ee(n){let e=it(n,ct);if(!Po(e))return{version:"1",lastUpdated:new Date().toISOString(),skills:{}};let t=ko(e,"utf-8"),o=at.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 ke(n,e){e.lastUpdated=new Date().toISOString();let t={};for(let s of Object.keys(e.skills).sort())t[s]=e.skills[s];e.skills=t;let o=it(n,ct),r=at.dump(e,{lineWidth:-1,sortKeys:!1,quotingType:'"'});bo(o,wo+r,"utf-8")}var oe=class{parser=new Co;objectParser=new _o;async deploy(e){let{instances:t,allKanonaks:o,repository:r,options:s}=e;if(t.length===0){console.error("No Skill instances to deploy.");return}let i=await et(o,t,r,this.parser,this.objectParser);if(i.length===0){console.error("No skills could be transformed from the package.");return}let a=await q(s,r),c=ee(a),l=t[0].namespace,{publisher:p,package_:d,version:u}=Do(l);for(let g of i){let f=await Z(g.name,s,r),y=te(ne(f,"SKILL.md"));So(f,{recursive:!0}),Ro(ne(f,"SKILL.md"),g.skillMd,"utf-8"),c.skills[g.name]={publisher:p,package_:d,version:u,resolved:p?`kanonak://${p}/${d}@${u}`:"",integrity:O(g.skillMd)},console.log(` ${y?"Updated":"Installed"} skill "${g.name}" \u2192 ${f}`)}ke(a,c)}async undeploy(e,t){let{repository:o,options:r}=t,s=await Z(e,r,o);te(s)||(console.error(`Skill "${e}" is not installed at ${s}`),process.exit(1)),vo(s,{recursive:!0,force:!0});let i=await q(r,o),a=ee(i);delete a.skills[e],ke(i,a),console.log(`Removed skill "${e}" from ${s}`)}async list(e){let{repository:t,options:o}=e,r=await q(o,t),s=ee(r),i=[];for(let[a,c]of Object.entries(s.skills))i.push({name:a,publisher:c.publisher,package_:c.package_,version:c.version,path:await Z(a,o,t)});if(te(r))try{let a=$o(r,{withFileTypes:!0});for(let c of a){if(!c.isDirectory()||s.skills[c.name])continue;let l=ne(r,c.name,"SKILL.md");te(l)&&i.push({name:c.name,publisher:"",package_:"",version:"",path:ne(r,c.name)})}}catch{}return i}};function Do(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 jo=xo(Ao(import.meta.url)),No=JSON.parse(Ko(Eo(jo,"..","package.json"),"utf-8")),K=new Io;K.name("kanonak").description("Kanonak Protocol CLI - Validate and resolve Kanonak ontology packages").version(No.version);K.command("validate <path>").description("Validate .kan.yml file(s). Resolves imports via HTTP from publisher domains.").action(async n=>{await ve(n)});K.command("install [package]").description("Install a package and its dependencies, or install all from kanonak.lock.").action(async n=>{await Ce(n)});K.command("deps <path>").description("Show resolved dependency tree for a .kan.yml file.").action(async n=>{await Ie(n)});K.command("login <publisher>").description("Authenticate with a package publisher using OAuth 2.0.").action(async n=>{await Te(n)});K.command("logout <publisher>").description("Revoke tokens and remove stored credentials for a publisher.").action(async n=>{await Oe(n)});K.addCommand(Ye());async function Fo(){try{let n=new C,e=new To,t=new Uo,o=Lo(t),r=new Oo({fetchFn:o}),s=await A(process.cwd(),e),i=new Q;i.register("kanonak.org/capabilities/AgentSkillDeployment",new oe);let a=await We(n,e,s),c=new X(n,e,r,o,i,s);Xe(K,a,c)}catch{}}await Fo();K.parse();
@@ -1,22 +1,17 @@
1
- import type { KanonakDocument, InstanceSearchResult } from '@kanonak-protocol/sdk';
2
- import type { DeploymentHandler, DeployedInstance } from '../capabilities/DeploymentHandlerRegistry.js';
1
+ import type { DeploymentContext, DeploymentHandler, DeployedInstance, OperationContext } from '../capabilities/DeploymentHandlerRegistry.js';
3
2
  /**
4
- * Deployment handler for AgentSkillDeployment targets.
3
+ * Deployment handler for the `AgentSkillDeployment` DeploymentTarget.
5
4
  *
6
- * Transforms Kanonak Skill instances into SKILL.md files and places them
7
- * in agent discovery directories based on the client and scope options.
5
+ * Transforms `kanonak.org/agent-skills/Skill` instances into SKILL.md
6
+ * files and places them in the directory declared by the named
7
+ * Client instance selected via the `--client` option (defaulting to
8
+ * the "agents" cross-client layout). All path resolution and
9
+ * reference following goes through the SDK object model.
8
10
  */
9
11
  export declare class SkillDeploymentHandler implements DeploymentHandler {
10
- /**
11
- * Deploy skills from a Kanonak document to the local filesystem.
12
- */
13
- deploy(doc: KanonakDocument, instances: InstanceSearchResult[], options: Record<string, string>): Promise<void>;
14
- /**
15
- * Remove a deployed skill by name.
16
- */
17
- undeploy(name: string, options: Record<string, string>): Promise<void>;
18
- /**
19
- * List all deployed skills in the discovery directory.
20
- */
21
- list(options: Record<string, string>): Promise<DeployedInstance[]>;
12
+ private readonly parser;
13
+ private readonly objectParser;
14
+ deploy(context: DeploymentContext): Promise<void>;
15
+ undeploy(name: string, context: OperationContext): Promise<void>;
16
+ list(context: OperationContext): Promise<DeployedInstance[]>;
22
17
  }
@@ -1,27 +1,40 @@
1
+ import type { IKanonakDocumentRepository } from '@kanonak-protocol/sdk';
1
2
  /**
2
3
  * Options for resolving skill discovery paths.
3
4
  */
4
5
  export interface SkillPathOptions {
6
+ /**
7
+ * clientId of a named Client instance in the agent-skills ontology
8
+ * (e.g. "agents", "claude-code"). When omitted, the CLI first tries
9
+ * `detectClient()` on process env vars, then falls back to the
10
+ * "agents" cross-client default.
11
+ */
5
12
  client?: string;
13
+ /** "project" (default) or "user". */
6
14
  scope?: string;
7
15
  }
8
16
  /**
9
- * Resolve the skills directory based on client and scope options.
17
+ * Resolve the skills directory for the requested client and scope.
10
18
  *
11
- * Discovery paths per the agent-skills ontology:
12
- * project + client: {cwd}/.<client>/skills/
13
- * project + none: {cwd}/.agents/skills/
14
- * user + client: ~/.<client>/skills/
15
- * user + none: ~/.agents/skills/
19
+ * This goes through the SDK object model: the agent-skills ontology
20
+ * is parsed, Client instances are looked up by URI, and the matching
21
+ * Client's `projectSkillDir` or `userSkillDir` is read. No hardcoded
22
+ * path templates, no alias string-stripping — the installer adapts
23
+ * to whatever named Client instances exist in the ontology at
24
+ * runtime.
16
25
  */
17
- export declare function resolveSkillsDir(options: SkillPathOptions): string;
26
+ export declare function resolveSkillsDir(options: SkillPathOptions, repository: IKanonakDocumentRepository): Promise<string>;
18
27
  /**
19
- * Resolve the directory for a specific skill.
28
+ * Resolve the directory for a specific skill by name.
20
29
  */
21
- export declare function resolveSkillDir(skillName: string, options: SkillPathOptions): string;
30
+ export declare function resolveSkillDir(skillName: string, options: SkillPathOptions, repository: IKanonakDocumentRepository): Promise<string>;
22
31
  /**
23
32
  * Auto-detect the current AI agent client from environment variables.
33
+ * Returns a clientId matching a named Client instance in the
34
+ * agent-skills ontology, or undefined when nothing is detected.
24
35
  *
25
- * Returns the client name (lowercase) or undefined if not detected.
36
+ * Matches the default Client instances declared in
37
+ * kanonak.org/agent-skills@1.1.0. Extend this mapping when adding
38
+ * new named Client instances with their own env-var signature.
26
39
  */
27
40
  export declare function detectClient(): string | undefined;
@@ -1,6 +1,7 @@
1
- import type { KanonakDocument } from '@kanonak-protocol/sdk';
1
+ import { KanonakParser, KanonakObjectParser, SubjectKanonak, Kanonak } from '@kanonak-protocol/sdk';
2
+ import type { IKanonakDocumentRepository } from '@kanonak-protocol/sdk';
2
3
  /**
3
- * A skill transformed from Kanonak YAML to SKILL.md content.
4
+ * A skill transformed from Kanonak into SKILL.md content.
4
5
  */
5
6
  export interface TransformedSkill {
6
7
  name: string;
@@ -8,13 +9,11 @@ export interface TransformedSkill {
8
9
  skillMd: string;
9
10
  }
10
11
  /**
11
- * Transform a Kanonak document containing Skill instances into SKILL.md content.
12
- *
13
- * Finds all Skill-typed entities in the document body and generates a
14
- * SKILL.md file for each, with YAML frontmatter and markdown body
15
- * assembled from the skill's hasSection entries.
16
- *
17
- * @param doc - A parsed KanonakDocument (from KanonakParser.parse())
18
- * @returns Array of transformed skills with their SKILL.md content
12
+ * Transform every `Skill` instance in a parsed kanonak list into
13
+ * SKILL.md content. References (`license`, `allowedTools`) are
14
+ * followed through the broader repository so the generated
15
+ * frontmatter uses canonical values from the target packages
16
+ * e.g. `Apache-2.0` (the `License.spdxId`) rather than the local
17
+ * entity name `Apache-2-0`.
19
18
  */
20
- export declare function transformKanonakToSkillMd(doc: KanonakDocument): TransformedSkill[];
19
+ export declare function transformSkillsToSkillMd(allKanonaks: Kanonak[], skills: SubjectKanonak[], repository: IKanonakDocumentRepository, parser: KanonakParser, objectParser: KanonakObjectParser): Promise<TransformedSkill[]>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kanonak-protocol/cli",
3
- "version": "1.3.0",
3
+ "version": "1.5.0",
4
4
  "description": "Kanonak Protocol CLI - Validate and resolve Kanonak ontology packages",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -34,8 +34,8 @@
34
34
  "semantic-web"
35
35
  ],
36
36
  "dependencies": {
37
- "@kanonak-protocol/sdk": "^1.3.0",
38
- "@kanonak-protocol/types": "^1.3.0",
37
+ "@kanonak-protocol/sdk": "^1.5.0",
38
+ "@kanonak-protocol/types": "^1.5.0",
39
39
  "commander": "^13.0.0",
40
40
  "js-yaml": "^4.1.1"
41
41
  },