@knolo/cli 5.2.0 → 5.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +75 -29
- package/bin/knolo.mjs +9 -6
- package/bin/registry/artifacts.mjs +21 -5
- package/bin/registry/commands.mjs +850 -87
- package/bin/registry/errors.mjs +3 -1
- package/bin/registry/http.mjs +72 -18
- package/bin/registry/lockfile.mjs +16 -5
- package/bin/registry/manifest.mjs +6 -0
- package/package.json +3 -2
package/README.md
CHANGED
|
@@ -47,10 +47,56 @@ An explicit `--registry` value takes precedence over `KNOLO_HUB_URL`. In
|
|
|
47
47
|
development mode (`NODE_ENV=development`), the default is
|
|
48
48
|
`http://localhost:3000`; otherwise the default is `https://hub.knolo.dev`.
|
|
49
49
|
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
50
|
+
Hub writes use a dashboard token as an HTTP Bearer credential. GitHub sign-in
|
|
51
|
+
is needed only to mint that token at
|
|
52
|
+
`https://hub.knolo.dev/dashboard/tokens`; `knolo login` is local-only and does
|
|
53
|
+
not call a Hub login or token-minting endpoint:
|
|
54
|
+
|
|
55
|
+
```bash
|
|
56
|
+
knolo login --token kno_…
|
|
57
|
+
# write requests use: Authorization: Bearer kno_…
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
`knolo publish` uploads bytes with `@vercel/blob` to the public store, waits
|
|
61
|
+
for verification, creates an attested draft, and releases it. Set
|
|
62
|
+
`PACKS_READ_WRITE_TOKEN` from the production `knolo-hub` Vercel environment
|
|
63
|
+
before publishing; do not substitute `BLOB_READ_WRITE_TOKEN`:
|
|
64
|
+
|
|
65
|
+
```bash
|
|
66
|
+
cd /path/to/knolo-hub
|
|
67
|
+
npx vercel env pull /tmp/knolo-env-prod --environment=production --yes
|
|
68
|
+
export PACKS_READ_WRITE_TOKEN="$(awk -F= '$1 == "PACKS_READ_WRITE_TOKEN" {sub(/^[^=]*=/, ""); gsub(/^\"|\"$/, ""); print; exit}' /tmp/knolo-env-prod)"
|
|
69
|
+
|
|
70
|
+
knolo publish ./dist/knowledge.knolo \
|
|
71
|
+
--slug refund-policy --version 1.2.0 --license Apache-2.0
|
|
72
|
+
knolo yank acme/refund-policy@1.2.0
|
|
73
|
+
```
|
|
74
|
+
|
|
75
|
+
The upload uses pathname `sha256/<64-lowercase-hex>.knolo`, public access,
|
|
76
|
+
`addRandomSuffix: false`, `application/octet-stream`, and a one-year cache.
|
|
77
|
+
Only public Blob URLs are accepted because Hub verification fetches the
|
|
78
|
+
artifact itself. The CLI never sends the `kno_…` token to Blob, in a query
|
|
79
|
+
string, cookie, or pack bytes. A 401 usually means the `Bearer` word is
|
|
80
|
+
missing or the token was revoked; it does not mean the Hub write API requires
|
|
81
|
+
a GitHub browser session.
|
|
82
|
+
|
|
83
|
+
The older `@knolo/cli@5.2.0` publish/yank command was an unimplemented stub;
|
|
84
|
+
current versions use the live Hub HTTP sequence. For a direct smoke test of a
|
|
85
|
+
stored credential, request the account endpoint with the same header:
|
|
86
|
+
|
|
87
|
+
```bash
|
|
88
|
+
curl -sS \
|
|
89
|
+
-H "Authorization: Bearer kno_…" \
|
|
90
|
+
-H "Accept: application/json" \
|
|
91
|
+
https://hub.knolo.dev/api/v1/account
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Do not use `POST /api/v1/tokens` as a CLI login endpoint; it is for the
|
|
95
|
+
dashboard/GitHub session that mints tokens.
|
|
96
|
+
|
|
97
|
+
Hub pack installation remains available without credentials and only happens
|
|
98
|
+
after its manifest, Blob bytes, digest, size, and local Knowledge Image
|
|
99
|
+
structure have all been verified:
|
|
54
100
|
|
|
55
101
|
```bash
|
|
56
102
|
knolo add acme/refund-policy@1.2.0
|
|
@@ -127,11 +173,11 @@ curl -sS "http://127.0.0.1:8787/search?q=billing&k=5"
|
|
|
127
173
|
|
|
128
174
|
These commands stay local-first:
|
|
129
175
|
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
176
|
+
- No hosted service
|
|
177
|
+
- No vector database
|
|
178
|
+
- Lexical retrieval by default
|
|
179
|
+
- Controller-only pack mutation; 2 MiB pack limit
|
|
180
|
+
- Pack state survives canister upgrades
|
|
135
181
|
|
|
136
182
|
---
|
|
137
183
|
|
|
@@ -152,8 +198,8 @@ knolo.config.ts
|
|
|
152
198
|
|
|
153
199
|
```ts
|
|
154
200
|
export default {
|
|
155
|
-
input:
|
|
156
|
-
output:
|
|
201
|
+
input: './knowledge',
|
|
202
|
+
output: './dist/knowledge.knolo',
|
|
157
203
|
};
|
|
158
204
|
```
|
|
159
205
|
|
|
@@ -161,12 +207,12 @@ export default {
|
|
|
161
207
|
|
|
162
208
|
## 🧱 What the CLI Does
|
|
163
209
|
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
210
|
+
- Parses structured documents
|
|
211
|
+
- Normalizes metadata
|
|
212
|
+
- Indexes namespaces
|
|
213
|
+
- Extracts agent routing profiles
|
|
214
|
+
- Validates agent registry
|
|
215
|
+
- Generates compact `.knolo` bundle
|
|
170
216
|
|
|
171
217
|
All builds are deterministic.
|
|
172
218
|
|
|
@@ -176,11 +222,11 @@ All builds are deterministic.
|
|
|
176
222
|
|
|
177
223
|
Current v4 features include:
|
|
178
224
|
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
225
|
+
- Routing profile extraction
|
|
226
|
+
- Tool policy validation
|
|
227
|
+
- Mount-time registry validation
|
|
228
|
+
- Deterministic selection logic
|
|
229
|
+
- Pack manifests, analyzer identities, retrieval plans, receipts, and evidence spans
|
|
184
230
|
|
|
185
231
|
---
|
|
186
232
|
|
|
@@ -188,16 +234,16 @@ Current v4 features include:
|
|
|
188
234
|
|
|
189
235
|
KnoLo intentionally avoids:
|
|
190
236
|
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
237
|
+
- Vector databases
|
|
238
|
+
- Similarity search
|
|
239
|
+
- External inference APIs
|
|
194
240
|
|
|
195
241
|
This ensures:
|
|
196
242
|
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
243
|
+
- Reproducibility
|
|
244
|
+
- Security
|
|
245
|
+
- Low memory usage
|
|
246
|
+
- Predictable results
|
|
201
247
|
|
|
202
248
|
---
|
|
203
249
|
|
package/bin/knolo.mjs
CHANGED
|
@@ -20,7 +20,7 @@ import path from 'node:path';
|
|
|
20
20
|
import process from 'node:process';
|
|
21
21
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
22
22
|
import { createRequire } from 'node:module';
|
|
23
|
-
import { isHubAddInvocation, runHubAdd, runHubInfo, runHubLogin, runHubLogout,
|
|
23
|
+
import { isHubAddInvocation, runHubAdd, runHubInfo, runHubLogin, runHubLogout, runHubPublish, runHubSearch, runHubWhoami, runHubYank } from './registry/commands.mjs';
|
|
24
24
|
|
|
25
25
|
const __dirname = path.dirname(fileURLToPath(import.meta.url));
|
|
26
26
|
const require = createRequire(import.meta.url);
|
|
@@ -34,7 +34,7 @@ const DEFAULT_CONFIG = {
|
|
|
34
34
|
};
|
|
35
35
|
const SUPPORTED_EXTENSIONS = new Set(['.md', '.txt', '.json']);
|
|
36
36
|
const SKIP_DIRS = new Set(['node_modules', 'dist', '.git', '.dfx', '.cargo-target']);
|
|
37
|
-
const SUBCOMMANDS = new Set(['init', 'add', 'build', 'query', 'inspect', 'migrate', 'verify', 'explain', 'diff', 'dev', 'v5', 'search', 'info', 'login', 'whoami', 'logout', 'publish', 'semantic:index', 'semantic:inspect', 'semantic:validate']);
|
|
37
|
+
const SUBCOMMANDS = new Set(['init', 'add', 'build', 'query', 'inspect', 'migrate', 'verify', 'explain', 'diff', 'dev', 'v5', 'search', 'info', 'login', 'whoami', 'logout', 'publish', 'yank', 'semantic:index', 'semantic:inspect', 'semantic:validate']);
|
|
38
38
|
const ICP_SUBCOMMANDS = new Set(['init', 'build-pack', 'upload', 'query', 'health', 'info', 'clear']);
|
|
39
39
|
const ICP_TEMPLATE_CANDIDATES = [
|
|
40
40
|
path.resolve(__dirname, '../templates/icp-knowledge-canister'),
|
|
@@ -86,7 +86,8 @@ Commands:
|
|
|
86
86
|
login Store a Hub token locally
|
|
87
87
|
whoami Show the stored Hub token prefix
|
|
88
88
|
logout Remove the stored Hub token
|
|
89
|
-
publish Publish
|
|
89
|
+
publish Publish a pack with a Hub Bearer token
|
|
90
|
+
yank <pack>@<version> Yank a released pack with a Hub Bearer token
|
|
90
91
|
build Build a .knolo pack from configured sources
|
|
91
92
|
query <question> Query a built pack and print top hits
|
|
92
93
|
inspect <pack> Inspect pack format, sections, and manifest
|
|
@@ -111,10 +112,11 @@ function printCommandHelp(command) {
|
|
|
111
112
|
add: 'Usage: knolo add <name> <path> | <publisher>/<slug>[@<version>] [--out <path>] [--force] [--json] [--registry <url>]',
|
|
112
113
|
search: 'Usage: knolo search <query> [--format V4|V5] [--license <id>] [--official] [--agents] [--json] [--registry <url>]',
|
|
113
114
|
info: 'Usage: knolo info <publisher>/<slug> [--json] [--registry <url>]',
|
|
114
|
-
login: 'Usage: knolo login [--token kno_…] [--stdin] [--registry <url>]',
|
|
115
|
+
login: 'Usage: knolo login [--token kno_…] [--stdin] [--registry <url>]\n\nStores the raw token locally. Hub write calls send Authorization: Bearer kno_….\nMint tokens at https://hub.knolo.dev/dashboard/tokens; login does not call POST /api/v1/tokens.',
|
|
115
116
|
whoami: 'Usage: knolo whoami',
|
|
116
117
|
logout: 'Usage: knolo logout',
|
|
117
|
-
publish: 'Usage: knolo publish <pack.knolo>
|
|
118
|
+
publish: 'Usage: knolo publish <pack.knolo> --slug <slug> --version <version> --license <SPDX> [--publisher <handle>] [--readme <text>] [--sources <text>] [--intended-use <text>] [--json] [--registry <url>]\n\nUses the stored token as Authorization: Bearer kno_…. Uploads go directly to a public Blob URL; Hub verifies before release.\nOlder @knolo/cli 5.2.0 builds were unimplemented; Hub has always accepted Bearer CLI tokens.',
|
|
119
|
+
yank: 'Usage: knolo yank <publisher>/<slug>@<version> [--json] [--registry <url>]\n\nUses the stored token as Authorization: Bearer kno_…. Yank is owner-only and leaves the public Blob in place.',
|
|
118
120
|
build: 'Usage: knolo build',
|
|
119
121
|
query: 'Usage: knolo query <question> [--pack <path>] [--k <number>] [--receipt <file>] [--json]',
|
|
120
122
|
inspect: 'Usage: knolo inspect <pack.knolo>',
|
|
@@ -1195,7 +1197,8 @@ async function main() {
|
|
|
1195
1197
|
if (command === 'login') return await runHubLogin(commandArgs);
|
|
1196
1198
|
if (command === 'whoami') return await runHubWhoami(commandArgs);
|
|
1197
1199
|
if (command === 'logout') return await runHubLogout(commandArgs);
|
|
1198
|
-
if (command === 'publish') return
|
|
1200
|
+
if (command === 'publish') return runHubPublish(commandArgs);
|
|
1201
|
+
if (command === 'yank') return runHubYank(commandArgs);
|
|
1199
1202
|
|
|
1200
1203
|
const core = await loadCore();
|
|
1201
1204
|
if (command === 'build') return await cmdBuild(core);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { createHash, randomUUID } from 'node:crypto';
|
|
2
2
|
import { createWriteStream } from 'node:fs';
|
|
3
|
-
import { chmod, mkdir, readFile, rename, unlink } from 'node:fs/promises';
|
|
3
|
+
import { chmod, copyFile, mkdir, readFile, rename, unlink } from 'node:fs/promises';
|
|
4
4
|
import path from 'node:path';
|
|
5
5
|
import { Readable } from 'node:stream';
|
|
6
6
|
|
|
@@ -86,11 +86,27 @@ export async function readArtifact(tempPath) {
|
|
|
86
86
|
}
|
|
87
87
|
|
|
88
88
|
export async function installCachedArtifact(tempPath, cachePath) {
|
|
89
|
+
const stagedPath = await stageCachedArtifact(tempPath, cachePath);
|
|
90
|
+
try {
|
|
91
|
+
await rename(stagedPath, cachePath);
|
|
92
|
+
await chmod(cachePath, 0o644);
|
|
93
|
+
return cachePath;
|
|
94
|
+
} finally {
|
|
95
|
+
await unlink(stagedPath).catch(() => {});
|
|
96
|
+
}
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
export async function stageCachedArtifact(sourcePath, cachePath) {
|
|
89
100
|
await mkdir(path.dirname(cachePath), { recursive: true });
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
101
|
+
const stagedPath = `${cachePath}.tmp-${process.pid}-${randomUUID()}`;
|
|
102
|
+
try {
|
|
103
|
+
await copyFile(sourcePath, stagedPath);
|
|
104
|
+
await chmod(stagedPath, 0o644);
|
|
105
|
+
return stagedPath;
|
|
106
|
+
} catch (error) {
|
|
107
|
+
await unlink(stagedPath).catch(() => {});
|
|
108
|
+
throw error;
|
|
109
|
+
}
|
|
94
110
|
}
|
|
95
111
|
|
|
96
112
|
async function writeChunk(stream, chunk) {
|