@cremini/skillpack 1.0.5 → 1.0.7
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 +5 -5
- package/dist/cli.js +100 -56
- package/package.json +3 -10
- package/runtime/server/package-lock.json +4649 -0
- /package/runtime/{scripts/start.bat → start.bat} +0 -0
- /package/runtime/{scripts/start.sh → start.sh} +0 -0
package/README.md
CHANGED
|
@@ -27,14 +27,14 @@ Step-by-Step
|
|
|
27
27
|
3. Add prompts to orchestrate and organize skills you added to accomplish tasks
|
|
28
28
|
4. (Optional) bundle the result as a zip
|
|
29
29
|
|
|
30
|
-
### Initialize
|
|
30
|
+
### Initialize with Configuration
|
|
31
31
|
|
|
32
32
|
```bash
|
|
33
33
|
npx @cremini/skillpack init --config ./skillpack.json
|
|
34
34
|
npx @cremini/skillpack init commic_explainer --config https://raw.githubusercontent.com/CreminiAI/skillpack/refs/heads/main/examples/commic_explainer.json
|
|
35
35
|
```
|
|
36
36
|
|
|
37
|
-
|
|
37
|
+
Bootstrap a SkillPack using a local file or remote URL.
|
|
38
38
|
|
|
39
39
|
### Step-by-Step Commands
|
|
40
40
|
|
|
@@ -73,11 +73,11 @@ The extracted archive looks like this:
|
|
|
73
73
|
skillpack/
|
|
74
74
|
├── skillpack.json # Pack configuration
|
|
75
75
|
├── skills/ # Collected SKILL.md files
|
|
76
|
-
├── server/ #
|
|
77
|
-
├── web/ #
|
|
76
|
+
├── server/ # Runtime backend
|
|
77
|
+
├── web/ # Runtime web UI
|
|
78
78
|
├── start.sh # One-click launcher for macOS/Linux
|
|
79
79
|
├── start.bat # One-click launcher for Windows
|
|
80
|
-
└── README.md
|
|
80
|
+
└── README.md # Runtime guide
|
|
81
81
|
```
|
|
82
82
|
|
|
83
83
|
### Run the Skill Pack
|
package/dist/cli.js
CHANGED
|
@@ -5,8 +5,8 @@ import { Command } from "commander";
|
|
|
5
5
|
import chalk8 from "chalk";
|
|
6
6
|
|
|
7
7
|
// src/commands/create.ts
|
|
8
|
-
import
|
|
9
|
-
import
|
|
8
|
+
import fs5 from "fs";
|
|
9
|
+
import path5 from "path";
|
|
10
10
|
import inquirer from "inquirer";
|
|
11
11
|
import chalk3 from "chalk";
|
|
12
12
|
|
|
@@ -114,11 +114,10 @@ function configExists(workDir) {
|
|
|
114
114
|
}
|
|
115
115
|
|
|
116
116
|
// src/core/bundler.ts
|
|
117
|
-
import
|
|
118
|
-
import
|
|
117
|
+
import fs4 from "fs";
|
|
118
|
+
import path4 from "path";
|
|
119
119
|
import archiver from "archiver";
|
|
120
120
|
import chalk2 from "chalk";
|
|
121
|
-
import { fileURLToPath } from "url";
|
|
122
121
|
|
|
123
122
|
// src/core/skill-manager.ts
|
|
124
123
|
import { spawnSync } from "child_process";
|
|
@@ -313,25 +312,98 @@ function removeSkill(workDir, skillName) {
|
|
|
313
312
|
return true;
|
|
314
313
|
}
|
|
315
314
|
|
|
316
|
-
// src/core/
|
|
315
|
+
// src/core/runtime-template.ts
|
|
316
|
+
import fs3 from "fs";
|
|
317
|
+
import path3 from "path";
|
|
318
|
+
import { fileURLToPath } from "url";
|
|
317
319
|
var __dirname = path3.dirname(fileURLToPath(import.meta.url));
|
|
318
320
|
function getRuntimeDir() {
|
|
319
321
|
const projectRoot = path3.resolve(__dirname, "..");
|
|
320
322
|
return path3.join(projectRoot, "runtime");
|
|
321
323
|
}
|
|
324
|
+
function assertRuntimeDirExists(runtimeDir) {
|
|
325
|
+
if (!fs3.existsSync(runtimeDir)) {
|
|
326
|
+
throw new Error(`Runtime directory not found: ${runtimeDir}`);
|
|
327
|
+
}
|
|
328
|
+
}
|
|
329
|
+
function collectRuntimeTemplateEntries(runtimeDir) {
|
|
330
|
+
assertRuntimeDirExists(runtimeDir);
|
|
331
|
+
const entries = [];
|
|
332
|
+
function visit(currentDir, relativeDir = "") {
|
|
333
|
+
const dirEntries = fs3.readdirSync(currentDir, { withFileTypes: true });
|
|
334
|
+
for (const dirEntry of dirEntries) {
|
|
335
|
+
if (dirEntry.name === "node_modules") {
|
|
336
|
+
continue;
|
|
337
|
+
}
|
|
338
|
+
const absolutePath = path3.join(currentDir, dirEntry.name);
|
|
339
|
+
const relativePath = relativeDir ? path3.posix.join(relativeDir, dirEntry.name) : dirEntry.name;
|
|
340
|
+
const stats = fs3.statSync(absolutePath);
|
|
341
|
+
if (dirEntry.isDirectory()) {
|
|
342
|
+
entries.push({
|
|
343
|
+
absolutePath,
|
|
344
|
+
relativePath,
|
|
345
|
+
stats,
|
|
346
|
+
type: "directory"
|
|
347
|
+
});
|
|
348
|
+
visit(absolutePath, relativePath);
|
|
349
|
+
continue;
|
|
350
|
+
}
|
|
351
|
+
if (dirEntry.isFile()) {
|
|
352
|
+
entries.push({
|
|
353
|
+
absolutePath,
|
|
354
|
+
relativePath,
|
|
355
|
+
stats,
|
|
356
|
+
type: "file"
|
|
357
|
+
});
|
|
358
|
+
}
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
visit(runtimeDir);
|
|
362
|
+
return entries;
|
|
363
|
+
}
|
|
364
|
+
function copyRuntimeTemplate(runtimeDir, workDir) {
|
|
365
|
+
const entries = collectRuntimeTemplateEntries(runtimeDir);
|
|
366
|
+
for (const entry of entries) {
|
|
367
|
+
const destinationPath = path3.join(workDir, entry.relativePath);
|
|
368
|
+
if (entry.type === "directory") {
|
|
369
|
+
fs3.mkdirSync(destinationPath, { recursive: true });
|
|
370
|
+
continue;
|
|
371
|
+
}
|
|
372
|
+
fs3.mkdirSync(path3.dirname(destinationPath), { recursive: true });
|
|
373
|
+
fs3.copyFileSync(entry.absolutePath, destinationPath);
|
|
374
|
+
fs3.chmodSync(destinationPath, entry.stats.mode);
|
|
375
|
+
}
|
|
376
|
+
}
|
|
377
|
+
function addRuntimeFiles(archive, runtimeDir, prefix) {
|
|
378
|
+
const entries = collectRuntimeTemplateEntries(runtimeDir);
|
|
379
|
+
for (const entry of entries) {
|
|
380
|
+
const archivePath = `${prefix}/${entry.relativePath}`;
|
|
381
|
+
if (entry.type === "directory") {
|
|
382
|
+
archive.append("", {
|
|
383
|
+
name: `${archivePath}/`,
|
|
384
|
+
mode: entry.stats.mode
|
|
385
|
+
});
|
|
386
|
+
continue;
|
|
387
|
+
}
|
|
388
|
+
archive.file(entry.absolutePath, {
|
|
389
|
+
name: archivePath,
|
|
390
|
+
mode: entry.stats.mode
|
|
391
|
+
});
|
|
392
|
+
}
|
|
393
|
+
}
|
|
394
|
+
|
|
395
|
+
// src/core/bundler.ts
|
|
322
396
|
async function bundle(workDir) {
|
|
323
397
|
const config = loadConfig(workDir);
|
|
324
398
|
const zipName = `${config.name}.zip`;
|
|
325
|
-
const zipPath =
|
|
399
|
+
const zipPath = path4.join(workDir, zipName);
|
|
326
400
|
const runtimeDir = getRuntimeDir();
|
|
327
|
-
|
|
328
|
-
throw new Error(`Runtime directory not found: ${runtimeDir}`);
|
|
329
|
-
}
|
|
401
|
+
assertRuntimeDirExists(runtimeDir);
|
|
330
402
|
installConfiguredSkills(workDir, config);
|
|
331
403
|
syncSkillDescriptions(workDir, config);
|
|
332
404
|
saveConfig(workDir, config);
|
|
333
405
|
console.log(chalk2.blue(`Packaging ${config.name}...`));
|
|
334
|
-
const output =
|
|
406
|
+
const output = fs4.createWriteStream(zipPath);
|
|
335
407
|
const archive = archiver("zip", { zlib: { level: 9 } });
|
|
336
408
|
return new Promise((resolve, reject) => {
|
|
337
409
|
output.on("close", () => {
|
|
@@ -348,55 +420,23 @@ async function bundle(workDir) {
|
|
|
348
420
|
archive.file(getPackPath(workDir), {
|
|
349
421
|
name: `${prefix}/${PACK_FILE}`
|
|
350
422
|
});
|
|
351
|
-
const skillsDir =
|
|
352
|
-
if (
|
|
423
|
+
const skillsDir = path4.join(workDir, "skills");
|
|
424
|
+
if (fs4.existsSync(skillsDir)) {
|
|
353
425
|
archive.directory(skillsDir, `${prefix}/skills`);
|
|
354
426
|
}
|
|
355
427
|
addRuntimeFiles(archive, runtimeDir, prefix);
|
|
356
428
|
archive.finalize();
|
|
357
429
|
});
|
|
358
430
|
}
|
|
359
|
-
function addRuntimeFiles(archive, runtimeDir, prefix) {
|
|
360
|
-
const serverDir = path3.join(runtimeDir, "server");
|
|
361
|
-
if (fs3.existsSync(serverDir)) {
|
|
362
|
-
archive.glob(
|
|
363
|
-
"**/*",
|
|
364
|
-
{
|
|
365
|
-
cwd: serverDir,
|
|
366
|
-
ignore: ["node_modules/**"]
|
|
367
|
-
},
|
|
368
|
-
{ prefix: `${prefix}/server` }
|
|
369
|
-
);
|
|
370
|
-
}
|
|
371
|
-
const webDir = path3.join(runtimeDir, "web");
|
|
372
|
-
if (fs3.existsSync(webDir)) {
|
|
373
|
-
archive.directory(webDir, `${prefix}/web`);
|
|
374
|
-
}
|
|
375
|
-
const scriptsDir = path3.join(runtimeDir, "scripts");
|
|
376
|
-
if (fs3.existsSync(scriptsDir)) {
|
|
377
|
-
const startSh = path3.join(scriptsDir, "start.sh");
|
|
378
|
-
if (fs3.existsSync(startSh)) {
|
|
379
|
-
archive.file(startSh, { name: `${prefix}/start.sh`, mode: 493 });
|
|
380
|
-
}
|
|
381
|
-
const startBat = path3.join(scriptsDir, "start.bat");
|
|
382
|
-
if (fs3.existsSync(startBat)) {
|
|
383
|
-
archive.file(startBat, { name: `${prefix}/start.bat` });
|
|
384
|
-
}
|
|
385
|
-
}
|
|
386
|
-
const readme = path3.join(runtimeDir, "README.md");
|
|
387
|
-
if (fs3.existsSync(readme)) {
|
|
388
|
-
archive.file(readme, { name: `${prefix}/README.md` });
|
|
389
|
-
}
|
|
390
|
-
}
|
|
391
431
|
|
|
392
432
|
// src/commands/create.ts
|
|
393
433
|
function parseSkillNames(value) {
|
|
394
434
|
return value.split(",").map((name) => name.trim()).filter(Boolean);
|
|
395
435
|
}
|
|
396
436
|
async function createCommand(directory) {
|
|
397
|
-
const workDir = directory ?
|
|
437
|
+
const workDir = directory ? path5.resolve(directory) : process.cwd();
|
|
398
438
|
if (directory) {
|
|
399
|
-
|
|
439
|
+
fs5.mkdirSync(workDir, { recursive: true });
|
|
400
440
|
}
|
|
401
441
|
if (configExists(workDir)) {
|
|
402
442
|
const { overwrite } = await inquirer.prompt([
|
|
@@ -515,8 +555,8 @@ async function createCommand(directory) {
|
|
|
515
555
|
}
|
|
516
556
|
|
|
517
557
|
// src/commands/init.ts
|
|
518
|
-
import
|
|
519
|
-
import
|
|
558
|
+
import fs6 from "fs";
|
|
559
|
+
import path6 from "path";
|
|
520
560
|
import inquirer2 from "inquirer";
|
|
521
561
|
import chalk4 from "chalk";
|
|
522
562
|
function isHttpUrl(value) {
|
|
@@ -536,17 +576,17 @@ async function readConfigSource(source) {
|
|
|
536
576
|
}
|
|
537
577
|
raw = await response.text();
|
|
538
578
|
} else {
|
|
539
|
-
const filePath =
|
|
540
|
-
raw =
|
|
579
|
+
const filePath = path6.resolve(source);
|
|
580
|
+
raw = fs6.readFileSync(filePath, "utf-8");
|
|
541
581
|
}
|
|
542
582
|
const parsed = JSON.parse(raw);
|
|
543
583
|
validateConfigShape(parsed, source);
|
|
544
584
|
return parsed;
|
|
545
585
|
}
|
|
546
586
|
async function initCommand(directory, options) {
|
|
547
|
-
const workDir = directory ?
|
|
587
|
+
const workDir = directory ? path6.resolve(directory) : process.cwd();
|
|
548
588
|
if (directory) {
|
|
549
|
-
|
|
589
|
+
fs6.mkdirSync(workDir, { recursive: true });
|
|
550
590
|
}
|
|
551
591
|
if (configExists(workDir)) {
|
|
552
592
|
const { overwrite } = await inquirer2.prompt([
|
|
@@ -569,12 +609,14 @@ async function initCommand(directory, options) {
|
|
|
569
609
|
`));
|
|
570
610
|
installConfiguredSkills(workDir, config);
|
|
571
611
|
refreshDescriptionsAndSave(workDir, config);
|
|
612
|
+
copyRuntimeTemplate(getRuntimeDir(), workDir);
|
|
572
613
|
if (options.bundle) {
|
|
573
614
|
await bundle(workDir);
|
|
574
615
|
}
|
|
575
616
|
console.log(chalk4.green(`
|
|
576
617
|
${PACK_FILE} saved
|
|
577
618
|
`));
|
|
619
|
+
console.log(chalk4.green(" Runtime template expanded.\n"));
|
|
578
620
|
console.log(chalk4.green(" Initialization complete.\n"));
|
|
579
621
|
if (!options.bundle) {
|
|
580
622
|
console.log(
|
|
@@ -706,16 +748,18 @@ function registerPromptsCommand(program2) {
|
|
|
706
748
|
}
|
|
707
749
|
|
|
708
750
|
// src/cli.ts
|
|
709
|
-
import
|
|
751
|
+
import fs7 from "fs";
|
|
710
752
|
var packageJson = JSON.parse(
|
|
711
|
-
|
|
753
|
+
fs7.readFileSync(new URL("../package.json", import.meta.url), "utf-8")
|
|
712
754
|
);
|
|
713
755
|
var program = new Command();
|
|
714
756
|
program.name("skillpack").description("Assemble, package, and run Agent Skills packs").version(packageJson.version);
|
|
715
757
|
program.command("create [directory]").description("Create a skills pack interactively").action(async (directory) => {
|
|
716
758
|
await createCommand(directory);
|
|
717
759
|
});
|
|
718
|
-
program.command("init [directory]").description(
|
|
760
|
+
program.command("init [directory]").description(
|
|
761
|
+
"Initialize a skills pack from a local config file or URL and expand runtime files"
|
|
762
|
+
).requiredOption("--config <path-or-url>", "Path or URL to a skillpack.json file").option("--bundle", "Bundle as a zip after initialization").action(
|
|
719
763
|
async (directory, options) => {
|
|
720
764
|
await initCommand(directory, options);
|
|
721
765
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@cremini/skillpack",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.7",
|
|
4
4
|
"description": "Turn Skills into a Standalone App with UI",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"repository": {
|
|
@@ -16,14 +16,7 @@
|
|
|
16
16
|
},
|
|
17
17
|
"files": [
|
|
18
18
|
"dist",
|
|
19
|
-
"runtime
|
|
20
|
-
"runtime/scripts",
|
|
21
|
-
"runtime/server/chat-proxy.js",
|
|
22
|
-
"runtime/server/index.js",
|
|
23
|
-
"runtime/server/package.json",
|
|
24
|
-
"runtime/server/routes.js",
|
|
25
|
-
"runtime/server/skills-loader.js",
|
|
26
|
-
"runtime/web",
|
|
19
|
+
"runtime",
|
|
27
20
|
"README.md",
|
|
28
21
|
"LICENSE"
|
|
29
22
|
],
|
|
@@ -61,4 +54,4 @@
|
|
|
61
54
|
"tsup": "^8.5.1",
|
|
62
55
|
"typescript": "^5.9.3"
|
|
63
56
|
}
|
|
64
|
-
}
|
|
57
|
+
}
|