@aikdna/kdna-cli 0.25.1 → 0.26.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.
Files changed (3) hide show
  1. package/README.md +37 -0
  2. package/package.json +2 -2
  3. package/src/cli.js +31 -0
package/README.md CHANGED
@@ -11,6 +11,11 @@ handled by KDNA Studio CLI and Studio Core.
11
11
  KDNA Core v1 does not require a public registry, marketplace, quality badge, or
12
12
  signature system. The current first-run path uses local `.kdna` files.
13
13
 
14
+ Authorization and runtime-load decisions are defined in `aikdna/kdna`, not in
15
+ this repository. `kdna plan-load` is the CLI diagnostic surface for that
16
+ contract and MUST call the LoadPlan API from `@aikdna/kdna-core` instead of
17
+ deriving authorization state directly from manifest fields.
18
+
14
19
  ## Install
15
20
 
16
21
  ```bash
@@ -23,6 +28,7 @@ npm install -g @aikdna/kdna-cli
23
28
  kdna demo minimal ./minimal
24
29
  kdna inspect ./minimal
25
30
  kdna validate ./minimal
31
+ kdna plan-load ./minimal --json
26
32
  kdna pack ./minimal ./minimal.kdna
27
33
  kdna validate ./minimal.kdna
28
34
  kdna load ./minimal.kdna --profile=compact --as=prompt
@@ -49,6 +55,9 @@ Successful validation returns:
49
55
  | `kdna demo minimal <dir>` | Create a minimal v1 source directory |
50
56
  | `kdna inspect <path>` | Inspect a v1 source dir or `.kdna` container |
51
57
  | `kdna validate <path>` | Validate format, schema, payload, checksums, and load contract |
58
+ | `kdna plan-load <path> --json` | Return the Core LoadPlan before runtime load |
59
+ | `kdna plan-load <path> --json --has-password` | Diagnose password-authorized load state |
60
+ | `kdna plan-load <path> --json --entitlement-status active` | Diagnose receipt/entitlement load state |
52
61
  | `kdna pack <source-dir> <output.kdna>` | Pack a v1 source directory |
53
62
  | `kdna unpack <input.kdna> <output-dir>` | Unpack a v1 container |
54
63
  | `kdna load <path> --profile=<index|compact|scenario|full> --as=<json|prompt>` | Render judgment context for agents or tools |
@@ -79,10 +88,38 @@ New integrations should use the v1 Core route:
79
88
  source or Studio project
80
89
  → v1 .kdna container
81
90
  → kdna validate
91
+ → kdna plan-load
82
92
  → kdna load
83
93
  → agent/runtime context
84
94
  ```
85
95
 
96
+ ## Runtime Authorization Contract
97
+
98
+ The source of truth is `aikdna/kdna`:
99
+
100
+ - `specs/kdna-authorization-contract.md`
101
+ - `schema/load-plan.schema.json`
102
+ - `conformance/authorization/cases.json`
103
+ - `conformance/authorization/goldens/*.loadplan.json`
104
+
105
+ This CLI is a diagnostic control plane. It may display, validate, and transport
106
+ LoadPlan results, but it must not define access modes, entitlement profiles,
107
+ issue codes, crypto profiles, or fail-closed policy independently.
108
+
109
+ Current local authorization path:
110
+
111
+ ```bash
112
+ kdna validate ./asset.kdna --json
113
+ kdna plan-load ./asset.kdna --json
114
+ kdna plan-load ./asset.kdna --json --has-password
115
+ kdna plan-load ./asset.kdna --json --entitlement-status active
116
+ kdna load ./asset.kdna --profile=compact --as=prompt
117
+ ```
118
+
119
+ `plan-load` requires a version of `@aikdna/kdna-core` that exports the LoadPlan
120
+ v1 API. Until that dependency is released and installed, the command fails with
121
+ a version-gate error instead of falling back to duplicated CLI-side parsing.
122
+
86
123
  ## Development
87
124
 
88
125
  ```bash
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aikdna/kdna-cli",
3
- "version": "0.25.1",
3
+ "version": "0.26.0",
4
4
  "description": "KDNA CLI — runtime control plane for verifying, installing, loading, comparing, publishing, and auditing existing .kdna assets.",
5
5
  "type": "commonjs",
6
6
  "bin": {
@@ -55,7 +55,7 @@
55
55
  "node": ">=18"
56
56
  },
57
57
  "dependencies": {
58
- "@aikdna/kdna-core": "^0.11.0"
58
+ "@aikdna/kdna-core": "^0.12.0"
59
59
  },
60
60
  "optionalDependencies": {
61
61
  "ajv": "^8.20.0",
package/src/cli.js CHANGED
@@ -89,6 +89,8 @@ Start here:
89
89
  Core v1:
90
90
  inspect <path> Inspect v1 source dir or .kdna container
91
91
  validate <path> Validate v1 source dir or .kdna container
92
+ plan-load <path> Return a LoadPlan before runtime load
93
+ Add --has-password or --entitlement-status for diagnostics
92
94
  pack <src> <out> Deterministic pack into .kdna container
93
95
  unpack <in> <out> Extract .kdna container
94
96
 
@@ -109,6 +111,8 @@ function showHelpAdvanced() {
109
111
  Core v1:
110
112
  inspect <path> Inspect v1 source dir or .kdna container
111
113
  validate <path> Validate v1 source dir or .kdna container
114
+ plan-load <path> [--has-password] [--entitlement-status <status>]
115
+ Return a LoadPlan before runtime load
112
116
  pack <src> <out> Deterministic pack into .kdna container
113
117
  unpack <in> <out> Extract .kdna container
114
118
  demo minimal <dir> [--force] Create a minimal v1 fixture
@@ -271,6 +275,33 @@ switch (cmd) {
271
275
  );
272
276
  break;
273
277
  }
278
+ case 'plan-load': {
279
+ const v1Target = args.filter((a) => !a.startsWith('--'))[1];
280
+ if (!v1Target) error('Usage: kdna plan-load <path> [--json] [--has-password] [--entitlement-status <status>]', EXIT.INPUT_ERROR);
281
+ const core = require('@aikdna/kdna-core');
282
+ const abs = require('node:path').resolve(v1Target);
283
+ if (!(core.isV1SourceDir(abs) || core.detectContainerFormat(abs) === 'v1')) {
284
+ error('plan-load requires a KDNA Core v1 source dir or .kdna container', EXIT.INPUT_ERROR);
285
+ }
286
+ if (typeof core.planLoad !== 'function') {
287
+ error(
288
+ 'kdna plan-load requires @aikdna/kdna-core with the LoadPlan v1 API. Update @aikdna/kdna-core before enabling runtime authorization diagnostics.',
289
+ EXIT.PROVIDER_ERROR,
290
+ );
291
+ }
292
+ const entitlementStatusIndex = args.indexOf('--entitlement-status');
293
+ const entitlementStatus = entitlementStatusIndex >= 0 ? args[entitlementStatusIndex + 1] : null;
294
+ const allowedEntitlementStatuses = new Set(['active', 'expired', 'revoked', 'offline_grace']);
295
+ if (entitlementStatusIndex >= 0 && !allowedEntitlementStatuses.has(entitlementStatus)) {
296
+ error('Invalid --entitlement-status. Use active, expired, revoked, or offline_grace.', EXIT.INPUT_ERROR);
297
+ }
298
+ const plan = core.planLoad(v1Target, {
299
+ hasPassword: args.includes('--has-password'),
300
+ entitlement: entitlementStatus ? { status: entitlementStatus } : undefined,
301
+ });
302
+ console.log(JSON.stringify(plan, null, 2));
303
+ process.exit(plan.state === 'invalid' ? 1 : 0);
304
+ }
274
305
  case 'pack': {
275
306
  const v1Target = args.filter((a) => !a.startsWith('--'))[1];
276
307
  if (v1Target) {