@skillerr/cli 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Bharat Dudeja
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,65 @@
1
+ # `@skillerr/cli`
2
+
3
+ CLI implementation for the [Open `.skill` Protocol](https://github.com/dot-skill/dot-skill).
4
+
5
+ **Public install:** [`skillerr`](https://www.npmjs.com/package/skillerr) · **Bin:** `skill`
6
+
7
+ Users install `skillerr` (depends on this package). This package is the internal implementation.
8
+
9
+ ## Install (public)
10
+
11
+ ```bash
12
+ npm i -g skillerr
13
+ ```
14
+
15
+ Node ≥ 20. Set `SKILL_HOST` when creating (`cursor`, `ollama`, `claude`, …).
16
+
17
+ ## Quickstart
18
+
19
+ ### Create
20
+
21
+ ```bash
22
+ export SKILL_HOST=cursor
23
+ skill init --title "Demo"
24
+ skill journey --summary "Redacted human+AI work; secrets as refs."
25
+ skill propose --json '[{"title":"Tone","body":"Keep answers short.","type":"decision"}]'
26
+ skill status
27
+ skill checkpoint
28
+ skill compile -m "Demo" --approve --mint
29
+ ```
30
+
31
+ ### Ingest / run
32
+
33
+ ```bash
34
+ skill inspect ./file.skill
35
+ skill validate ./file.skill
36
+ skill verify-trust ./file.skill
37
+ skill load ./file.skill
38
+ skill run ./file.skill
39
+ ```
40
+
41
+ ### Multi-skill identify
42
+
43
+ ```bash
44
+ skill agent-guide
45
+ skill extract ./journey.json -o ./extraction # or: skill segment …
46
+ # one workspace per selected candidate → contract-check → compile
47
+ ```
48
+
49
+ ```bash
50
+ skill --help
51
+ ```
52
+
53
+ ## Related
54
+
55
+ - [`skillerr`](https://www.npmjs.com/package/skillerr) — public install
56
+ - [`@skillerr/protocol`](https://www.npmjs.com/package/@skillerr/protocol)
57
+ - [`@skillerr/core`](https://www.npmjs.com/package/@skillerr/core)
58
+ - [`@skillerr/runtime`](https://www.npmjs.com/package/@skillerr/runtime)
59
+ - [`@skillerr/workspace`](https://www.npmjs.com/package/@skillerr/workspace)
60
+
61
+ Docs: [Agent](https://github.com/dot-skill/dot-skill/blob/main/docs/AGENT.md) · [Protocol](https://github.com/dot-skill/dot-skill/blob/main/docs/PROTOCOL.md)
62
+
63
+ ## License
64
+
65
+ MIT
package/dist/cli.d.ts ADDED
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * skill — Open .skill Protocol CLI
4
+ *
5
+ * AI agents create; humans review. Continuity drafts for handoff; release for mint.
6
+ *
7
+ * npm i -g skillerr # or: npx -y skillerr --help
8
+ * export SKILL_HOST=cursor
9
+ * skill init --title "…"
10
+ * skill propose --json '[…]'
11
+ * skill journey --summary "…"
12
+ * skill checkpoint # continuity draft (partial OK)
13
+ * skill compile -m "…" --mint # release (complete or refuse)
14
+ * skill inspect ./file.skill # ingest: inspect before run
15
+ * skill load ./file.skill # resume handoff in another AI
16
+ */
17
+ export {};
package/dist/cli.js ADDED
@@ -0,0 +1,610 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * skill — Open .skill Protocol CLI
4
+ *
5
+ * AI agents create; humans review. Continuity drafts for handoff; release for mint.
6
+ *
7
+ * npm i -g skillerr # or: npx -y skillerr --help
8
+ * export SKILL_HOST=cursor
9
+ * skill init --title "…"
10
+ * skill propose --json '[…]'
11
+ * skill journey --summary "…"
12
+ * skill checkpoint # continuity draft (partial OK)
13
+ * skill compile -m "…" --mint # release (complete or refuse)
14
+ * skill inspect ./file.skill # ingest: inspect before run
15
+ * skill load ./file.skill # resume handoff in another AI
16
+ */
17
+ import { readFileSync } from "node:fs";
18
+ import { mkdir, readFile, writeFile } from "node:fs/promises";
19
+ import { join, resolve } from "node:path";
20
+ import { inspectSkill, inspectTrustView, migrateLegacySkill, toSkillMdAdapter, unpackSkill, validatePackageBytes, mintSkillPackage, verifyMintTrust, compileRecipeToSkill, compileSkillSource, approveCompilation, redactSecrets, CompileRefusalError, } from "@skillerr/core";
21
+ import { runSkillArchive } from "@skillerr/runtime";
22
+ import { lookup, list, verify as registryVerify, publish as registryPublish } from "@skillerr/registry";
23
+ import { agentCreateGuide, assessSkillContract, explainContractAssessment, extractSkillCandidates, formatAgentGuide, isValidAgentHost, scaffoldSkillContract, } from "@skillerr/protocol";
24
+ import { initWorkspace, requireWorkspace, proposeSection, proposeMany, stage, unstage, status, compileWorkspace, checkpoint, discardSection, loadHead, loadSkillHandoff, setJourney, requireAgentHost, } from "@skillerr/workspace";
25
+ function loadPackageVersion() {
26
+ const metadata = JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8"));
27
+ if (typeof metadata.version !== "string" || metadata.version.length === 0) {
28
+ throw new Error("Invalid @skillerr/cli package version metadata");
29
+ }
30
+ return metadata.version;
31
+ }
32
+ const VERSION = loadPackageVersion();
33
+ function usage(exitCode = 1) {
34
+ console.log(`skill — Open .skill Protocol CLI v${VERSION}
35
+
36
+ Easily create, inspect, and run portable .skill packages.
37
+ Agents create; humans approve releases.
38
+
39
+ Create:
40
+ skill init [--title name]
41
+ skill status Completeness + staged sections
42
+ skill propose --title T --body B Requires SKILL_HOST
43
+ skill propose --json '[...]'
44
+ skill journey --summary "…" Redacted human+AI journey (no secrets)
45
+ skill add [id...] Stage (default: ALL)
46
+ skill unstage [id...] | skill review | skill discard <id>
47
+ skill checkpoint [-m msg] Continuity handoff (partial OK)
48
+ skill compile -m "msg" [--approve] [--mint] [--profile release|continuity]
49
+ Release refuses if incomplete
50
+ skill load <file.skill> Resume continuity in another AI
51
+ skill mint [--host name] Seal release (host required)
52
+
53
+ Multi-skill identify:
54
+ skill agent-guide [--json] Exact create/identify protocol steps
55
+ skill extract <journey.json> [-o dir] [--profile release|continuity]
56
+ Candidate SkillContract/source scaffolds
57
+ skill segment … Alias of extract
58
+
59
+ Ingest / run:
60
+ skill inspect <file.skill> [--trust] TrustView (no compile / no model body)
61
+ skill validate <file.skill> Structure + hash integrity
62
+ skill unpack <file.skill>
63
+ skill verify-trust <file.skill> [--profile minted] [--allow-development-issuer]
64
+ skill run <file.skill> [--mode execute] [--allow-untrusted]
65
+ Dry-run by default; execute refuses
66
+ unsigned/dev seals without --allow-untrusted
67
+ skill pack <source.json> [-o out.skill] [--approve] [--profile release]
68
+ skill contract-template 0.5 authoring contract scaffold
69
+ skill contract-check <contract.json> Completeness + fixes
70
+ skill registry list|lookup <digest> Optional local transparency log
71
+
72
+ Env:
73
+ SKILL_HOST (required to create) SKILL_PROVIDER SKILL_MODEL
74
+ SKILL_DEPLOYMENT SKILL_ENDPOINT SKILL_ACTOR
75
+ SKILL_AGENT_RUNTIME SKILL_AGENT_VERSION SKILL_SESSION_ID
76
+ SKILL_AGENT_INVOCATION Agent runtime marker (anti env-only spoof)
77
+ SKILL_INPUT_TOKENS SKILL_OUTPUT_TOKENS
78
+
79
+ Notes:
80
+ SKILL_HOST alone never yields verified_issuer trust. Public-dev HMAC is
81
+ development-only. human/cli/shell/manual hosts are denylisted for mint.
82
+
83
+ Install: npm i -g skillerr → skill --help
84
+ Docs: https://skillerr.com
85
+ `);
86
+ process.exit(exitCode);
87
+ }
88
+ function flag(args, name) {
89
+ return args.includes(name);
90
+ }
91
+ function opt(args, name) {
92
+ const i = args.indexOf(name);
93
+ return i >= 0 ? args[i + 1] : undefined;
94
+ }
95
+ async function main() {
96
+ const argv = process.argv.slice(2);
97
+ const cmd = argv[0];
98
+ const rest = argv.slice(1);
99
+ if (!cmd || cmd === "-h" || cmd === "--help")
100
+ usage(0);
101
+ if (cmd === "-V" || cmd === "--version") {
102
+ console.log(VERSION);
103
+ return;
104
+ }
105
+ switch (cmd) {
106
+ case "agent-guide": {
107
+ if (flag(rest, "--json")) {
108
+ console.log(JSON.stringify(agentCreateGuide(), null, 2));
109
+ }
110
+ else {
111
+ console.log(formatAgentGuide());
112
+ }
113
+ break;
114
+ }
115
+ case "extract":
116
+ case "segment": {
117
+ const file = rest.find((a) => !a.startsWith("-"));
118
+ if (!file) {
119
+ console.error("Usage: skill extract <journey.json> [-o dir] [--profile release|continuity]\n" +
120
+ " journey.json: { summary, candidates|topics: [...] }\n" +
121
+ " See: skill agent-guide");
122
+ process.exit(2);
123
+ }
124
+ const profile = opt(rest, "--profile") ?? "release";
125
+ const outDir = opt(rest, "-o") ?? opt(rest, "--out");
126
+ const raw = JSON.parse(await readFile(resolve(file), "utf8"));
127
+ const report = extractSkillCandidates(raw, {
128
+ profile,
129
+ host: process.env.SKILL_HOST,
130
+ });
131
+ if (outDir) {
132
+ const root = resolve(outDir);
133
+ await mkdir(root, { recursive: true });
134
+ await writeFile(join(root, "extraction.json"), `${JSON.stringify(report, null, 2)}\n`);
135
+ for (const scaffold of report.scaffolds) {
136
+ const dir = join(root, "candidates", scaffold.workspace_slug);
137
+ await mkdir(dir, { recursive: true });
138
+ await writeFile(join(dir, "contract.json"), `${JSON.stringify(scaffold.contract_scaffold, null, 2)}\n`);
139
+ await writeFile(join(dir, "source.json"), `${JSON.stringify(scaffold.source_scaffold, null, 2)}\n`);
140
+ await writeFile(join(dir, "assessment.json"), `${JSON.stringify({
141
+ candidate: scaffold.candidate,
142
+ missing: scaffold.missing,
143
+ next_steps: scaffold.next_steps,
144
+ }, null, 2)}\n`);
145
+ }
146
+ }
147
+ console.log(JSON.stringify({
148
+ ok: true,
149
+ written: outDir ? resolve(outDir) : null,
150
+ ...report,
151
+ note: "Scaffolds are intentionally incomplete. Complete each SkillContract, one workspace per candidate, then contract-check / status before release compile.",
152
+ }, null, 2));
153
+ // Non-zero if any candidate is incomplete (expected for fresh extract).
154
+ process.exit(report.scaffolds.every((s) => s.candidate.assessment.complete) ? 0 : 2);
155
+ break;
156
+ }
157
+ case "contract-template": {
158
+ console.log(JSON.stringify(scaffoldSkillContract(), null, 2));
159
+ break;
160
+ }
161
+ case "contract-check": {
162
+ const file = rest[0];
163
+ if (!file)
164
+ usage();
165
+ const profile = opt(rest, "--profile") ?? "release";
166
+ const parsed = JSON.parse(await readFile(resolve(file), "utf8"));
167
+ const contract = parsed && typeof parsed === "object" && "kind" in parsed && parsed.kind === "skill_source"
168
+ ? parsed.contract
169
+ : parsed;
170
+ const assessment = assessSkillContract(contract, profile);
171
+ console.log(JSON.stringify({
172
+ assessment,
173
+ explanation: explainContractAssessment(assessment),
174
+ }, null, 2));
175
+ process.exit(assessment.complete ? 0 : 2);
176
+ break;
177
+ }
178
+ case "init": {
179
+ const title = opt(rest, "--title");
180
+ const { root, created } = await initWorkspace(process.cwd(), { title });
181
+ console.log(JSON.stringify({
182
+ ok: true,
183
+ created,
184
+ root,
185
+ hint: created
186
+ ? "Set SKILL_HOST, then: skill propose … → skill checkpoint | skill compile -m \"…\" --mint"
187
+ : "Already a skill workspace",
188
+ }, null, 2));
189
+ break;
190
+ }
191
+ case "status": {
192
+ const root = requireWorkspace();
193
+ const st = await status(root);
194
+ console.log(JSON.stringify({
195
+ root: st.root,
196
+ title: st.title,
197
+ agent_host_ok: st.agent_host_ok,
198
+ journey_summary: st.journey_summary,
199
+ completeness: st.completeness,
200
+ staged: st.staged.map((i) => ({ id: i.id, type: i.type, title: i.title })),
201
+ unstaged: st.unstaged.map((i) => ({ id: i.id, type: i.type, title: i.title })),
202
+ head: st.head,
203
+ }, null, 2));
204
+ break;
205
+ }
206
+ case "propose": {
207
+ requireAgentHost();
208
+ const root = requireWorkspace();
209
+ const json = opt(rest, "--json");
210
+ if (json) {
211
+ const items = JSON.parse(json);
212
+ const made = await proposeMany(root, items);
213
+ console.log(JSON.stringify({ ok: true, count: made.length, ids: made.map((m) => m.id) }, null, 2));
214
+ break;
215
+ }
216
+ const title = opt(rest, "--title");
217
+ const body = opt(rest, "--body");
218
+ const type = opt(rest, "--type");
219
+ if (!title || !body) {
220
+ console.error("Usage: skill propose --title T --body B [--type decision]");
221
+ console.error(' or: skill propose --json \'[{"title":"…","body":"…"}]\'');
222
+ process.exit(2);
223
+ }
224
+ const section = await proposeSection(root, { title, body, type });
225
+ console.log(JSON.stringify({ ok: true, section }, null, 2));
226
+ break;
227
+ }
228
+ case "journey": {
229
+ const root = requireWorkspace();
230
+ const summary = opt(rest, "--summary");
231
+ if (!summary) {
232
+ console.error("Usage: skill journey --summary \"Redacted human+AI journey…\"");
233
+ process.exit(2);
234
+ }
235
+ const open = opt(rest, "--open");
236
+ const config = await setJourney(root, {
237
+ summary,
238
+ open_questions: open ? open.split("|") : undefined,
239
+ });
240
+ console.log(JSON.stringify({ ok: true, journey_summary: config.journey_summary }, null, 2));
241
+ break;
242
+ }
243
+ case "add": {
244
+ const root = requireWorkspace();
245
+ const ids = rest.filter((a) => !a.startsWith("-"));
246
+ const index = await stage(root, ids.length ? ids : "all");
247
+ console.log(JSON.stringify({ ok: true, staged: index.staged }, null, 2));
248
+ break;
249
+ }
250
+ case "unstage": {
251
+ const root = requireWorkspace();
252
+ const ids = rest.filter((a) => !a.startsWith("-"));
253
+ const index = await unstage(root, ids.length ? ids : "all");
254
+ console.log(JSON.stringify({ ok: true, staged: index.staged }, null, 2));
255
+ break;
256
+ }
257
+ case "review": {
258
+ const root = requireWorkspace();
259
+ const st = await status(root);
260
+ console.log(JSON.stringify({
261
+ staged: st.staged.map((i) => ({
262
+ id: i.id,
263
+ type: i.type,
264
+ title: i.title,
265
+ body: i.body,
266
+ source: i.source,
267
+ })),
268
+ }, null, 2));
269
+ break;
270
+ }
271
+ case "discard": {
272
+ const root = requireWorkspace();
273
+ const id = rest[0];
274
+ if (!id)
275
+ usage();
276
+ await discardSection(root, id);
277
+ console.log(JSON.stringify({ ok: true, discarded: id }, null, 2));
278
+ break;
279
+ }
280
+ case "checkpoint": {
281
+ const root = requireWorkspace();
282
+ try {
283
+ const result = await checkpoint(root, {
284
+ message: opt(rest, "-m") ?? opt(rest, "--message"),
285
+ summary: opt(rest, "--summary"),
286
+ input_tokens: opt(rest, "--input-tokens")
287
+ ? Number(opt(rest, "--input-tokens"))
288
+ : undefined,
289
+ output_tokens: opt(rest, "--output-tokens")
290
+ ? Number(opt(rest, "--output-tokens"))
291
+ : undefined,
292
+ });
293
+ console.log(JSON.stringify({
294
+ ok: true,
295
+ profile: "continuity",
296
+ package_path: result.package_path,
297
+ package_digest: result.package_digest,
298
+ skill_id: result.compile.files.manifest.id,
299
+ completeness: result.compile.completeness,
300
+ hint: "Hand this .skill to another AI via: skill load <path>",
301
+ }, null, 2));
302
+ }
303
+ catch (e) {
304
+ if (e instanceof CompileRefusalError) {
305
+ console.log(JSON.stringify({
306
+ ok: false,
307
+ kind: "compile_refused",
308
+ profile: e.profile,
309
+ missing: e.missing,
310
+ hints: e.hints,
311
+ }, null, 2));
312
+ process.exit(2);
313
+ }
314
+ throw e;
315
+ }
316
+ break;
317
+ }
318
+ case "compile":
319
+ case "bake": {
320
+ if (cmd === "bake") {
321
+ console.error("note: `bake` is a legacy alias; the protocol command is `skill compile`");
322
+ }
323
+ const root = requireWorkspace();
324
+ const profile = opt(rest, "--profile") ?? "release";
325
+ try {
326
+ const result = await compileWorkspace(root, {
327
+ message: opt(rest, "-m") ?? opt(rest, "--message"),
328
+ title: opt(rest, "--title"),
329
+ summary: opt(rest, "--summary"),
330
+ add_all: !flag(rest, "--no-all"),
331
+ approve: flag(rest, "--approve"),
332
+ mint: flag(rest, "--mint"),
333
+ profile,
334
+ host: opt(rest, "--host"),
335
+ agent_runtime: process.env.SKILL_AGENT_RUNTIME ?? "@skillerr/cli",
336
+ agent_version: process.env.SKILL_AGENT_VERSION ??
337
+ (process.env.SKILL_AGENT_RUNTIME ? "unknown" : VERSION),
338
+ input_tokens: opt(rest, "--input-tokens")
339
+ ? Number(opt(rest, "--input-tokens"))
340
+ : undefined,
341
+ output_tokens: opt(rest, "--output-tokens")
342
+ ? Number(opt(rest, "--output-tokens"))
343
+ : undefined,
344
+ });
345
+ console.log(JSON.stringify({
346
+ ok: true,
347
+ profile: result.profile,
348
+ package_path: result.package_path,
349
+ package_digest: result.package_digest,
350
+ skill_id: result.compile.files.manifest.id,
351
+ minted: result.minted,
352
+ completeness: result.compile.completeness,
353
+ pending_approvals: result.compile.pending_approvals,
354
+ generation_usage: result.compile.files.provenance?.generation_usage,
355
+ }, null, 2));
356
+ }
357
+ catch (e) {
358
+ if (e instanceof CompileRefusalError) {
359
+ console.log(JSON.stringify({
360
+ ok: false,
361
+ kind: "compile_refused",
362
+ profile: e.profile,
363
+ missing: e.missing,
364
+ hints: e.hints,
365
+ message: "Skill generation stopped. Complete missing parts with the AI agent, then compile again.",
366
+ }, null, 2));
367
+ process.exit(2);
368
+ }
369
+ throw e;
370
+ }
371
+ break;
372
+ }
373
+ case "load": {
374
+ const file = rest[0];
375
+ if (!file)
376
+ usage();
377
+ const handoff = await loadSkillHandoff(resolve(file));
378
+ console.log(JSON.stringify({
379
+ ok: true,
380
+ handoff,
381
+ agent_prompt: "Resume from this .skill continuity package. Honor journey, knowledge, open_questions, and typed inputs. Do not invent missing private data.",
382
+ }, null, 2));
383
+ break;
384
+ }
385
+ case "mint": {
386
+ requireAgentHost(opt(rest, "--host"));
387
+ const root = requireWorkspace();
388
+ const head = await loadHead(root);
389
+ const file = rest.find((a) => a.endsWith(".skill")) ?? head.package_path;
390
+ if (!file)
391
+ throw new Error("No package to mint. Run skill compile first.");
392
+ const bytes = new Uint8Array(await readFile(resolve(file)));
393
+ const unpacked = unpackSkill(bytes);
394
+ if (unpacked.raw.manifest.compile_profile === "continuity") {
395
+ throw new Error("Cannot mint continuity draft. Recompile with --profile release first.");
396
+ }
397
+ const { packageBytes, files, attestation } = mintSkillPackage(unpacked.raw, {
398
+ host: requireAgentHost(opt(rest, "--host")),
399
+ provider: process.env.SKILL_PROVIDER,
400
+ model: process.env.SKILL_MODEL,
401
+ deployment: process.env.SKILL_DEPLOYMENT ?? "unknown",
402
+ endpoint: process.env.SKILL_ENDPOINT
403
+ ? redactSecrets(process.env.SKILL_ENDPOINT)
404
+ : undefined,
405
+ agent_runtime: process.env.SKILL_AGENT_RUNTIME ?? "@skillerr/cli",
406
+ agent_version: process.env.SKILL_AGENT_VERSION ??
407
+ (process.env.SKILL_AGENT_RUNTIME ? "unknown" : VERSION),
408
+ });
409
+ const out = opt(rest, "-o") ?? file;
410
+ await writeFile(resolve(out), packageBytes);
411
+ console.log(JSON.stringify({
412
+ ok: true,
413
+ out,
414
+ mint_status: files.manifest.mint?.mint_status,
415
+ content_id: files.manifest.mint?.content_id,
416
+ package_digest: files.manifest.package_digest,
417
+ generation_usage: attestation.generation_usage,
418
+ }, null, 2));
419
+ break;
420
+ }
421
+ case "publish": {
422
+ console.error("Publish is not part of the open .skill happy path.\n" +
423
+ "Share the .skill file (git, chat, drive). Optional local log: skill registry publish <file>\n" +
424
+ "Hosted registries are product concerns, not this protocol.");
425
+ process.exit(2);
426
+ break;
427
+ }
428
+ case "inspect": {
429
+ const file = rest[0];
430
+ if (!file)
431
+ usage();
432
+ const bytes = new Uint8Array(await readFile(resolve(file)));
433
+ if (flag(rest, "--trust")) {
434
+ console.log(JSON.stringify(inspectTrustView(bytes), null, 2));
435
+ }
436
+ else {
437
+ console.log(JSON.stringify(inspectSkill(bytes), null, 2));
438
+ }
439
+ break;
440
+ }
441
+ case "validate": {
442
+ const file = rest[0];
443
+ if (!file)
444
+ usage();
445
+ const result = validatePackageBytes(new Uint8Array(await readFile(resolve(file))));
446
+ console.log(JSON.stringify(result, null, 2));
447
+ process.exit(result.ok ? 0 : 2);
448
+ break;
449
+ }
450
+ case "unpack": {
451
+ const file = rest[0];
452
+ if (!file)
453
+ usage();
454
+ const u = unpackSkill(new Uint8Array(await readFile(resolve(file))));
455
+ console.log(JSON.stringify({
456
+ manifest: u.manifest,
457
+ workflow: u.workflow,
458
+ knowledge: u.knowledge,
459
+ journey: u.raw.provenance?.journey,
460
+ generation_usage: u.raw.provenance?.generation_usage,
461
+ }, null, 2));
462
+ break;
463
+ }
464
+ case "pack": {
465
+ const file = rest[0];
466
+ if (!file)
467
+ usage();
468
+ requireAgentHost(opt(rest, "--host"));
469
+ const approve = flag(rest, "--approve");
470
+ const profile = opt(rest, "--profile") ?? "release";
471
+ const out = opt(rest, "-o") ?? "out.skill";
472
+ const raw = JSON.parse(await readFile(resolve(file), "utf8"));
473
+ let compiled;
474
+ try {
475
+ if (raw.kind === "skill_source") {
476
+ compiled = compileSkillSource(raw, {
477
+ profile,
478
+ approve_inferred_inputs: approve,
479
+ approve_permissions: approve,
480
+ });
481
+ }
482
+ else {
483
+ const recipe = raw;
484
+ if (!recipe.provenance.hosts.length || !isValidAgentHost(recipe.provenance.hosts[0])) {
485
+ recipe.provenance.hosts = [requireAgentHost(opt(rest, "--host"))];
486
+ }
487
+ compiled = compileRecipeToSkill(recipe, {
488
+ profile,
489
+ approve_inferred_inputs: approve,
490
+ approve_permissions: approve,
491
+ host: requireAgentHost(opt(rest, "--host")),
492
+ });
493
+ }
494
+ if (approve)
495
+ compiled = approveCompilation(compiled, { inputs: ["*"], permissions: true });
496
+ }
497
+ catch (e) {
498
+ if (e instanceof CompileRefusalError) {
499
+ console.log(JSON.stringify({ ok: false, kind: "compile_refused", missing: e.missing, hints: e.hints }, null, 2));
500
+ process.exit(2);
501
+ }
502
+ throw e;
503
+ }
504
+ await writeFile(resolve(out), compiled.packageBytes);
505
+ console.log(JSON.stringify({
506
+ out,
507
+ skill_id: compiled.files.manifest.id,
508
+ package_digest: compiled.files.manifest.package_digest,
509
+ completeness: compiled.completeness,
510
+ }, null, 2));
511
+ break;
512
+ }
513
+ case "run": {
514
+ const file = rest[0];
515
+ if (!file)
516
+ usage();
517
+ const mode = (opt(rest, "--mode") ?? "dry_run");
518
+ const inputs = {};
519
+ for (let i = 0; i < rest.length; i++) {
520
+ if (rest[i] === "--input" && rest[i + 1]) {
521
+ const [k, ...v] = rest[i + 1].split("=");
522
+ inputs[k] = v.join("=");
523
+ }
524
+ }
525
+ const run = await runSkillArchive(new Uint8Array(await readFile(resolve(file))), { host: process.env.SKILL_HOST ?? "runtime" }, {
526
+ mode,
527
+ inputs,
528
+ allow_untrusted: flag(rest, "--allow-untrusted"),
529
+ allow_development_issuer: flag(rest, "--allow-development-issuer"),
530
+ });
531
+ console.log(JSON.stringify(run, null, 2));
532
+ process.exit(run.status === "succeeded" || run.status === "paused" ? 0 : 2);
533
+ break;
534
+ }
535
+ case "verify-trust": {
536
+ const file = rest[0];
537
+ if (!file)
538
+ usage();
539
+ const profile = (opt(rest, "--profile") ?? "minted");
540
+ console.log(JSON.stringify(verifyMintTrust(new Uint8Array(await readFile(resolve(file))), profile, {
541
+ allow_development_issuer: flag(rest, "--allow-development-issuer"),
542
+ allow_self_reported: flag(rest, "--allow-self-reported"),
543
+ }), null, 2));
544
+ break;
545
+ }
546
+ case "registry": {
547
+ const sub = rest[0];
548
+ if (sub === "list") {
549
+ console.log(JSON.stringify(await list(undefined, Number(opt(rest, "--limit") ?? 50)), null, 2));
550
+ }
551
+ else if (sub === "lookup") {
552
+ const digest = rest[1];
553
+ if (!digest)
554
+ usage();
555
+ console.log(JSON.stringify(await lookup(digest), null, 2));
556
+ }
557
+ else if (sub === "verify") {
558
+ const file = rest[1];
559
+ if (!file)
560
+ usage();
561
+ console.log(JSON.stringify(await registryVerify(new Uint8Array(await readFile(resolve(file)))), null, 2));
562
+ }
563
+ else if (sub === "publish") {
564
+ const file = rest[1];
565
+ if (!file)
566
+ usage();
567
+ const bytes = new Uint8Array(await readFile(resolve(file)));
568
+ const digest = unpackSkill(bytes).manifest.package_digest;
569
+ console.log(JSON.stringify({
570
+ ...(await registryPublish(digest, { path: file })),
571
+ note: "Local transparency log only — not a public marketplace.",
572
+ }, null, 2));
573
+ }
574
+ else
575
+ usage();
576
+ break;
577
+ }
578
+ case "migrate-legacy": {
579
+ const file = rest[0];
580
+ if (!file)
581
+ usage();
582
+ const out = opt(rest, "-o") ?? "migrated.skill";
583
+ const legacy = JSON.parse(await readFile(resolve(file), "utf8"));
584
+ const { packageBytes, files } = migrateLegacySkill(legacy);
585
+ await writeFile(resolve(out), packageBytes);
586
+ console.log(JSON.stringify({ out, skill_id: files.manifest.id }, null, 2));
587
+ break;
588
+ }
589
+ case "to-skill-md": {
590
+ const file = rest[0];
591
+ if (!file)
592
+ usage();
593
+ const out = opt(rest, "-o") ?? "SKILL.md";
594
+ const md = toSkillMdAdapter(unpackSkill(new Uint8Array(await readFile(resolve(file)))).raw);
595
+ await writeFile(resolve(out), md, "utf8");
596
+ console.log(JSON.stringify({ out, warning: "Lossy adapter — markdown is never the source of truth." }, null, 2));
597
+ break;
598
+ }
599
+ case "help":
600
+ usage();
601
+ break;
602
+ default:
603
+ console.error(`Unknown command: ${cmd}\n`);
604
+ usage();
605
+ }
606
+ }
607
+ main().catch((e) => {
608
+ console.error(e instanceof Error ? e.message : e);
609
+ process.exit(1);
610
+ });
package/package.json ADDED
@@ -0,0 +1,63 @@
1
+ {
2
+ "name": "@skillerr/cli",
3
+ "version": "0.6.0",
4
+ "description": "CLI implementation for portable .skill packages (install skillerr for the skill bin)",
5
+ "license": "MIT",
6
+ "author": {
7
+ "name": "Bharat Dudeja",
8
+ "url": "https://github.com/bharatdudeja13-cmd"
9
+ },
10
+ "keywords": [
11
+ "skill",
12
+ "skillerr",
13
+ ".skill",
14
+ "ai-agents",
15
+ "agent-skills",
16
+ "cli",
17
+ "protocol"
18
+ ],
19
+ "type": "module",
20
+ "bin": {
21
+ "skill": "./dist/cli.js",
22
+ "skillerr": "./dist/cli.js"
23
+ },
24
+ "main": "./dist/cli.js",
25
+ "publishConfig": {
26
+ "access": "public",
27
+ "provenance": true
28
+ },
29
+ "repository": {
30
+ "type": "git",
31
+ "url": "https://github.com/dot-skill/dot-skill.git",
32
+ "directory": "packages/cli"
33
+ },
34
+ "homepage": "https://skillerr.com",
35
+ "bugs": {
36
+ "url": "https://github.com/dot-skill/dot-skill/issues"
37
+ },
38
+ "files": [
39
+ "dist/cli.js",
40
+ "dist/cli.d.ts",
41
+ "README.md",
42
+ "LICENSE"
43
+ ],
44
+ "scripts": {
45
+ "build": "rm -rf dist && tsc -p tsconfig.json",
46
+ "prepack": "npm run build",
47
+ "test": "node --test dist/conformance.test.js"
48
+ },
49
+ "dependencies": {
50
+ "@skillerr/core": "^0.6.0",
51
+ "@skillerr/protocol": "^0.6.0",
52
+ "@skillerr/registry": "^0.6.0",
53
+ "@skillerr/runtime": "^0.6.0",
54
+ "@skillerr/workspace": "^0.6.0"
55
+ },
56
+ "devDependencies": {
57
+ "@types/node": "^22.15.21",
58
+ "typescript": "^5.8.3"
59
+ },
60
+ "engines": {
61
+ "node": ">=20"
62
+ }
63
+ }