@cremini/skillpack 1.0.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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 Finpeak Inc
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,91 @@
1
+ # SkillPack - Pack AI Skills into Standalone Apps
2
+
3
+ Go to [skillpack.sh](https://skillpack.sh) to pack skills and try existing skill packs.
4
+
5
+ One command to orchestrate [Skills](https://skills.sh), tools, mcps into a standalone app users can download and use on their own computer!
6
+
7
+ ```bash
8
+ npx @cremini/skillpack create
9
+ ```
10
+
11
+ If skills, tools, and MCPs are like LEGO pieces, a skill pack is the master piece that assembles them into a complete solution.
12
+
13
+ Each Skill Pack should organize different skills to address a well-defined problem or complete specific tasks. For example, research a company by gathering information from various sources and create a PowerPoint presentation based on the findings.
14
+
15
+ ## Quick Start
16
+
17
+ ### Create a Skill Pack Interactively
18
+
19
+ ```bash
20
+ npx @cremini/skillpack create
21
+ ```
22
+
23
+ Step-by-Step
24
+
25
+ 1. Set the Pack name and description
26
+ 2. Add skills from a GitHub repos, URLs, or local paths
27
+ 3. Add prompts to orchestrate and organize skills you added to accomplish tasks
28
+ 4. (Optional) bundle the result as a zip
29
+
30
+ ### Step-by-Step Commands
31
+
32
+ ```bash
33
+ # Add skills
34
+ npx @cremini/skillpack skills add vercel-labs/agent-skills --skill frontend-design
35
+ npx @cremini/skillpack skills add ./my-local-skills
36
+
37
+ # Manage prompts
38
+ npx @cremini/skillpack prompts add "Collect company data using Skill A, create charts from the data using Skill B, and compile the results into a PowerPoint using Skill C"
39
+ npx @cremini/skillpack prompts list
40
+
41
+ # Package the current app
42
+ npx @cremini/skillpack build
43
+ ```
44
+
45
+ ## Commands
46
+
47
+ | Command | Description |
48
+ | ------------------------ | ------------------------------------- |
49
+ | `create` | Create a skill pack interactively |
50
+ | `skills add <source>` | Add a skill |
51
+ | `skills remove <name>` | Remove a skill |
52
+ | `skills list` | List installed skills |
53
+ | `prompts add <text>` | Add a prompt |
54
+ | `prompts remove <index>` | Remove a prompt |
55
+ | `prompts list` | List all prompts |
56
+ | `build` | Package the skill pack as a zip file |
57
+
58
+ ## Zip Output
59
+
60
+ The extracted archive looks like this:
61
+
62
+ ```text
63
+ skillpack/
64
+ ├── app.json # App configuration
65
+ ├── skills/ # Collected SKILL.md files
66
+ ├── server/ # Express backend
67
+ ├── web/ # Web chat UI
68
+ ├── start.sh # One-click launcher for macOS/Linux
69
+ ├── start.bat # One-click launcher for Windows
70
+ └── README.md
71
+ ```
72
+
73
+ ### Run the Skill Pack
74
+
75
+ ```bash
76
+ # macOS / Linux
77
+ chmod +x start.sh && ./start.sh
78
+
79
+ # Windows
80
+ start.bat
81
+ ```
82
+
83
+ Then open [http://127.0.0.1:26313](http://127.0.0.1:26313), enter your API key, and start working and having fun!!!
84
+
85
+ ## Development
86
+
87
+ For development details, see [Development Guide](docs/development.md).
88
+
89
+ ## License
90
+
91
+ MIT
package/dist/cli.js ADDED
@@ -0,0 +1,492 @@
1
+ #!/usr/bin/env node
2
+
3
+ // src/cli.ts
4
+ import { Command } from "commander";
5
+ import chalk7 from "chalk";
6
+
7
+ // src/commands/create.ts
8
+ import inquirer from "inquirer";
9
+ import chalk3 from "chalk";
10
+
11
+ // src/core/pack-config.ts
12
+ import fs from "fs";
13
+ import path from "path";
14
+ var PACK_FILE = "app.json";
15
+ function getPackPath(workDir) {
16
+ return path.join(workDir, PACK_FILE);
17
+ }
18
+ function createDefaultConfig(name, description) {
19
+ return {
20
+ name,
21
+ description,
22
+ version: "1.0.0",
23
+ prompts: [],
24
+ skills: []
25
+ };
26
+ }
27
+ function loadConfig(workDir) {
28
+ const filePath = getPackPath(workDir);
29
+ if (!fs.existsSync(filePath)) {
30
+ throw new Error(
31
+ `Could not find ${PACK_FILE}. Run npx @cremini/skillpack create first or work in a directory that contains app.json`
32
+ );
33
+ }
34
+ const raw = fs.readFileSync(filePath, "utf-8");
35
+ return JSON.parse(raw);
36
+ }
37
+ function saveConfig(workDir, config) {
38
+ const filePath = getPackPath(workDir);
39
+ fs.writeFileSync(filePath, JSON.stringify(config, null, 2) + "\n", "utf-8");
40
+ }
41
+ function configExists(workDir) {
42
+ return fs.existsSync(getPackPath(workDir));
43
+ }
44
+
45
+ // src/core/bundler.ts
46
+ import fs3 from "fs";
47
+ import path3 from "path";
48
+ import archiver from "archiver";
49
+ import chalk2 from "chalk";
50
+ import { fileURLToPath } from "url";
51
+
52
+ // src/core/skill-manager.ts
53
+ import { execSync } from "child_process";
54
+ import fs2 from "fs";
55
+ import path2 from "path";
56
+ import chalk from "chalk";
57
+ var SKILLS_DIR = "skills";
58
+ function getSkillsDir(workDir) {
59
+ return path2.join(workDir, SKILLS_DIR);
60
+ }
61
+ async function installPendingSkills(workDir, config) {
62
+ const pendingSkills = config.skills.filter((s) => s.installSource);
63
+ if (pendingSkills.length === 0) {
64
+ return;
65
+ }
66
+ console.log(chalk.blue(`
67
+ Installing pending skills...`));
68
+ const skillsDir = getSkillsDir(workDir);
69
+ fs2.mkdirSync(skillsDir, { recursive: true });
70
+ for (const skill of pendingSkills) {
71
+ let addCmd = `npx -y skills add ${skill.installSource} --agent openclaw --copy -y`;
72
+ if (skill.specificSkills && skill.specificSkills.length > 0) {
73
+ for (const name of skill.specificSkills) {
74
+ addCmd += ` --skill "${name}"`;
75
+ }
76
+ }
77
+ console.log(chalk.dim(`> ${addCmd}`));
78
+ try {
79
+ execSync(addCmd, { encoding: "utf-8", cwd: workDir, stdio: "inherit" });
80
+ } catch (err) {
81
+ console.error(chalk.red(`Failed to install skill: ${err}`));
82
+ }
83
+ }
84
+ config.skills = scanInstalledSkills(workDir);
85
+ saveConfig(workDir, config);
86
+ console.log(chalk.green(` Skill installation complete.
87
+ `));
88
+ }
89
+ function scanInstalledSkills(workDir) {
90
+ const results = [];
91
+ const skillsDir = getSkillsDir(workDir);
92
+ if (!fs2.existsSync(skillsDir)) {
93
+ return results;
94
+ }
95
+ function findSkillFiles(dir) {
96
+ const entries = fs2.readdirSync(dir, { withFileTypes: true });
97
+ for (const entry of entries) {
98
+ const fullPath = path2.join(dir, entry.name);
99
+ if (entry.isDirectory()) {
100
+ findSkillFiles(fullPath);
101
+ } else if (entry.name === "SKILL.md") {
102
+ const skill = parseSkillMd(fullPath, workDir);
103
+ if (skill) {
104
+ results.push(skill);
105
+ }
106
+ }
107
+ }
108
+ }
109
+ findSkillFiles(skillsDir);
110
+ return results;
111
+ }
112
+ function parseSkillMd(filePath, workDir) {
113
+ try {
114
+ const content = fs2.readFileSync(filePath, "utf-8");
115
+ const frontmatterMatch = content.match(/^---\s*\n([\s\S]*?)\n---/);
116
+ if (!frontmatterMatch) return null;
117
+ const frontmatter = frontmatterMatch[1];
118
+ const nameMatch = frontmatter.match(/^name:\s*(.+)$/m);
119
+ const descMatch = frontmatter.match(/^description:\s*(.+)$/m);
120
+ if (!nameMatch) return null;
121
+ return {
122
+ name: nameMatch[1].trim(),
123
+ source: path2.relative(workDir, path2.dirname(filePath)),
124
+ description: descMatch ? descMatch[1].trim() : ""
125
+ };
126
+ } catch {
127
+ return null;
128
+ }
129
+ }
130
+ function removeSkill(workDir, skillName) {
131
+ const config = loadConfig(workDir);
132
+ const idx = config.skills.findIndex(
133
+ (s) => s.name.toLowerCase() === skillName.toLowerCase()
134
+ );
135
+ if (idx === -1) {
136
+ console.log(chalk.yellow(`Skill not found: ${skillName}`));
137
+ return false;
138
+ }
139
+ const skillDir = path2.join(workDir, config.skills[idx].source);
140
+ if (fs2.existsSync(skillDir)) {
141
+ fs2.rmSync(skillDir, { recursive: true });
142
+ }
143
+ config.skills.splice(idx, 1);
144
+ saveConfig(workDir, config);
145
+ console.log(chalk.green(`Removed skill: ${skillName}`));
146
+ return true;
147
+ }
148
+
149
+ // src/core/bundler.ts
150
+ var __dirname = path3.dirname(fileURLToPath(import.meta.url));
151
+ function getRuntimeDir() {
152
+ const projectRoot = path3.resolve(__dirname, "..");
153
+ return path3.join(projectRoot, "runtime");
154
+ }
155
+ async function bundle(workDir) {
156
+ const config = loadConfig(workDir);
157
+ const zipName = `${config.name}.zip`;
158
+ const zipPath = path3.join(workDir, zipName);
159
+ const runtimeDir = getRuntimeDir();
160
+ if (!fs3.existsSync(runtimeDir)) {
161
+ throw new Error(`Runtime directory not found: ${runtimeDir}`);
162
+ }
163
+ await installPendingSkills(workDir, config);
164
+ console.log(chalk2.blue(`Packaging ${config.name}...`));
165
+ const output = fs3.createWriteStream(zipPath);
166
+ const archive = archiver("zip", { zlib: { level: 9 } });
167
+ return new Promise((resolve, reject) => {
168
+ output.on("close", () => {
169
+ console.log(
170
+ chalk2.green(
171
+ `Packaging complete: ${zipName} (${(archive.pointer() / 1024).toFixed(1)} KB)`
172
+ )
173
+ );
174
+ resolve(zipPath);
175
+ });
176
+ archive.on("error", (err) => reject(err));
177
+ archive.pipe(output);
178
+ const prefix = config.name;
179
+ archive.file(path3.join(workDir, "app.json"), {
180
+ name: `${prefix}/app.json`
181
+ });
182
+ const skillsDir = path3.join(workDir, "skills");
183
+ if (fs3.existsSync(skillsDir)) {
184
+ archive.directory(skillsDir, `${prefix}/skills`);
185
+ }
186
+ addRuntimeFiles(archive, runtimeDir, prefix);
187
+ archive.finalize();
188
+ });
189
+ }
190
+ function addRuntimeFiles(archive, runtimeDir, prefix) {
191
+ const serverDir = path3.join(runtimeDir, "server");
192
+ if (fs3.existsSync(serverDir)) {
193
+ archive.glob(
194
+ "**/*",
195
+ {
196
+ cwd: serverDir,
197
+ ignore: ["node_modules/**"]
198
+ },
199
+ { prefix: `${prefix}/server` }
200
+ );
201
+ }
202
+ const webDir = path3.join(runtimeDir, "web");
203
+ if (fs3.existsSync(webDir)) {
204
+ archive.directory(webDir, `${prefix}/web`);
205
+ }
206
+ const scriptsDir = path3.join(runtimeDir, "scripts");
207
+ if (fs3.existsSync(scriptsDir)) {
208
+ const startSh = path3.join(scriptsDir, "start.sh");
209
+ if (fs3.existsSync(startSh)) {
210
+ archive.file(startSh, { name: `${prefix}/start.sh`, mode: 493 });
211
+ }
212
+ const startBat = path3.join(scriptsDir, "start.bat");
213
+ if (fs3.existsSync(startBat)) {
214
+ archive.file(startBat, { name: `${prefix}/start.bat` });
215
+ }
216
+ }
217
+ const readme = path3.join(runtimeDir, "README.md");
218
+ if (fs3.existsSync(readme)) {
219
+ archive.file(readme, { name: `${prefix}/README.md` });
220
+ }
221
+ }
222
+
223
+ // src/commands/create.ts
224
+ import fs4 from "fs";
225
+ import path4 from "path";
226
+ async function createCommand(directory) {
227
+ const workDir = directory ? path4.resolve(directory) : process.cwd();
228
+ if (directory) {
229
+ fs4.mkdirSync(workDir, { recursive: true });
230
+ }
231
+ if (configExists(workDir)) {
232
+ const { overwrite } = await inquirer.prompt([
233
+ {
234
+ type: "confirm",
235
+ name: "overwrite",
236
+ message: "An app.json file already exists in this directory. Overwrite it?",
237
+ default: false
238
+ }
239
+ ]);
240
+ if (!overwrite) {
241
+ console.log(chalk3.yellow("Cancelled"));
242
+ return;
243
+ }
244
+ }
245
+ console.log(chalk3.blue("\n Create a new Skill App\n"));
246
+ const { name, description } = await inquirer.prompt([
247
+ {
248
+ type: "input",
249
+ name: "name",
250
+ message: "App name:",
251
+ validate: (v) => v.trim() ? true : "Name is required"
252
+ },
253
+ {
254
+ type: "input",
255
+ name: "description",
256
+ message: "Description:",
257
+ default: "A skill App, powered by SkillPack.sh"
258
+ }
259
+ ]);
260
+ const config = createDefaultConfig(name.trim(), description.trim());
261
+ console.log(
262
+ chalk3.blue("\n Add Skills (enter a skill source, leave blank to skip)\n")
263
+ );
264
+ console.log(
265
+ chalk3.dim(
266
+ " Supported formats: owner/repo, GitHub URL, local path, or a full npx skills add command"
267
+ )
268
+ );
269
+ console.log(chalk3.dim(" Example: vercel-labs/agent-skills"));
270
+ console.log(
271
+ chalk3.dim(
272
+ " Example: npx skills add https://github.com/vercel-labs/skills --skill find-skillsclear\n"
273
+ )
274
+ );
275
+ while (true) {
276
+ const { source } = await inquirer.prompt([
277
+ {
278
+ type: "input",
279
+ name: "source",
280
+ message: "Skill source (leave blank to skip):"
281
+ }
282
+ ]);
283
+ if (!source.trim()) break;
284
+ let parsedSource = source.trim();
285
+ let parsedSpecificSkill;
286
+ const skillMatch = parsedSource.match(/(.*?)\s+--skill\s+([^\s]+)(.*)/);
287
+ if (skillMatch) {
288
+ parsedSpecificSkill = skillMatch[2];
289
+ parsedSource = `${skillMatch[1]} ${skillMatch[3]}`.trim();
290
+ }
291
+ const npxMatch = parsedSource.match(/^npx\s+[^\s]+\s+add\s+(.+)$/);
292
+ if (npxMatch) {
293
+ parsedSource = npxMatch[1].trim();
294
+ }
295
+ if (!parsedSource) continue;
296
+ let specificSkill = parsedSpecificSkill;
297
+ if (specificSkill !== void 0) {
298
+ console.log(chalk3.dim(` Auto-detected skill source: ${parsedSource}`));
299
+ console.log(
300
+ chalk3.dim(` Auto-detected specific skill: ${specificSkill}`)
301
+ );
302
+ } else {
303
+ if (parsedSource !== source.trim()) {
304
+ console.log(chalk3.dim(` Auto-detected skill source: ${parsedSource}`));
305
+ }
306
+ const answer = await inquirer.prompt([
307
+ {
308
+ type: "input",
309
+ name: "specificSkill",
310
+ message: "Specific skill name (leave blank to install all):"
311
+ }
312
+ ]);
313
+ specificSkill = answer.specificSkill;
314
+ }
315
+ const skillNames = specificSkill && specificSkill.trim() ? [specificSkill.trim()] : void 0;
316
+ config.skills.push({
317
+ name: skillNames ? skillNames.join(", ") : parsedSource,
318
+ source: parsedSource,
319
+ description: "Pending installation",
320
+ installSource: parsedSource,
321
+ specificSkills: skillNames
322
+ });
323
+ }
324
+ console.log(chalk3.blue("\n Add Prompts\n"));
325
+ console.log(
326
+ chalk3.blue(
327
+ "Use a prompt to explain how you will organize the skills you added to complete the task\n"
328
+ )
329
+ );
330
+ let promptIndex = 1;
331
+ while (true) {
332
+ const isFirst = promptIndex === 1;
333
+ const { prompt } = await inquirer.prompt([
334
+ {
335
+ type: "input",
336
+ name: "prompt",
337
+ message: isFirst ? `Prompt #${promptIndex} (required):` : `Prompt #${promptIndex} (leave blank to finish):`,
338
+ validate: isFirst ? (v) => v.trim() ? true : "The first Prompt cannot be empty" : void 0
339
+ }
340
+ ]);
341
+ if (!isFirst && !prompt.trim()) break;
342
+ config.prompts.push(prompt.trim());
343
+ promptIndex++;
344
+ }
345
+ saveConfig(workDir, config);
346
+ console.log(chalk3.green("\n app.json saved\n"));
347
+ const { shouldBundle } = await inquirer.prompt([
348
+ {
349
+ type: "confirm",
350
+ name: "shouldBundle",
351
+ message: "Bundle as a zip now?",
352
+ default: true
353
+ }
354
+ ]);
355
+ if (shouldBundle) {
356
+ await bundle(workDir);
357
+ }
358
+ console.log(chalk3.green("\n Done!"));
359
+ if (!shouldBundle) {
360
+ console.log(
361
+ chalk3.dim(" Run npx @cremini/skillpack build to create the zip\n")
362
+ );
363
+ }
364
+ }
365
+
366
+ // src/commands/skills-cmd.ts
367
+ import chalk4 from "chalk";
368
+ function registerSkillsCommand(program2) {
369
+ const skills = program2.command("skills").description("Manage skills in the app");
370
+ skills.command("add <source>").description("Add a skill from a git repo, URL, or local path").option("-s, --skill <names...>", "Specify skill name(s)").action(async (source, opts) => {
371
+ const workDir = process.cwd();
372
+ const config = loadConfig(workDir);
373
+ config.skills.push({
374
+ name: opts.skill ? opts.skill.join(", ") : source,
375
+ source,
376
+ description: "Pending installation",
377
+ installSource: source,
378
+ specificSkills: opts.skill && opts.skill.length > 0 ? opts.skill : void 0
379
+ });
380
+ saveConfig(workDir, config);
381
+ console.log(
382
+ chalk4.green(
383
+ `Skill list updated (${config.skills.length} total). Skills will be installed during build.`
384
+ )
385
+ );
386
+ });
387
+ skills.command("remove <name>").description("Remove a skill").action((name) => {
388
+ removeSkill(process.cwd(), name);
389
+ });
390
+ skills.command("list").description("List installed skills").action(() => {
391
+ const config = loadConfig(process.cwd());
392
+ if (config.skills.length === 0) {
393
+ console.log(chalk4.dim(" No skills installed"));
394
+ return;
395
+ }
396
+ console.log(chalk4.blue(`
397
+ ${config.name} Skills:
398
+ `));
399
+ for (const skill of config.skills) {
400
+ console.log(` ${chalk4.green("\u25CF")} ${chalk4.bold(skill.name)}`);
401
+ if (skill.description) {
402
+ console.log(` ${chalk4.dim(skill.description)}`);
403
+ }
404
+ }
405
+ console.log();
406
+ });
407
+ }
408
+
409
+ // src/commands/prompts-cmd.ts
410
+ import chalk6 from "chalk";
411
+
412
+ // src/core/prompts.ts
413
+ import chalk5 from "chalk";
414
+ function addPrompt(workDir, text) {
415
+ const config = loadConfig(workDir);
416
+ config.prompts.push(text);
417
+ saveConfig(workDir, config);
418
+ console.log(chalk5.green(`Added Prompt #${config.prompts.length}`));
419
+ }
420
+ function removePrompt(workDir, index) {
421
+ const config = loadConfig(workDir);
422
+ const idx = index - 1;
423
+ if (idx < 0 || idx >= config.prompts.length) {
424
+ console.log(
425
+ chalk5.yellow(`Invalid index: ${index} (${config.prompts.length} total)`)
426
+ );
427
+ return false;
428
+ }
429
+ const removed = config.prompts.splice(idx, 1)[0];
430
+ saveConfig(workDir, config);
431
+ console.log(
432
+ chalk5.green(`Removed Prompt #${index}: "${removed.substring(0, 50)}..."`)
433
+ );
434
+ return true;
435
+ }
436
+ function listPrompts(workDir) {
437
+ const config = loadConfig(workDir);
438
+ return config.prompts;
439
+ }
440
+
441
+ // src/commands/prompts-cmd.ts
442
+ function registerPromptsCommand(program2) {
443
+ const prompts = program2.command("prompts").description("Manage prompts");
444
+ prompts.command("add <text>").description("Add a prompt").action((text) => {
445
+ addPrompt(process.cwd(), text);
446
+ });
447
+ prompts.command("remove <index>").description("Remove a prompt by number, starting from 1").action((index) => {
448
+ const num = parseInt(index, 10);
449
+ if (isNaN(num)) {
450
+ console.log(chalk6.red("Enter a valid numeric index"));
451
+ return;
452
+ }
453
+ removePrompt(process.cwd(), num);
454
+ });
455
+ prompts.command("list").description("List all prompts").action(() => {
456
+ const prompts2 = listPrompts(process.cwd());
457
+ if (prompts2.length === 0) {
458
+ console.log(chalk6.dim(" No prompts yet"));
459
+ return;
460
+ }
461
+ console.log(chalk6.blue("\n Prompts:\n"));
462
+ prompts2.forEach((u, i) => {
463
+ const marker = i === 0 ? chalk6.green("\u2605") : chalk6.dim("\u25CF");
464
+ const label = i === 0 ? chalk6.dim(" (default)") : "";
465
+ const display = u.length > 80 ? u.substring(0, 80) + "..." : u;
466
+ console.log(` ${marker} #${i + 1}${label} ${display}`);
467
+ });
468
+ console.log();
469
+ });
470
+ }
471
+
472
+ // src/cli.ts
473
+ import fs5 from "fs";
474
+ var packageJson = JSON.parse(
475
+ fs5.readFileSync(new URL("../package.json", import.meta.url), "utf-8")
476
+ );
477
+ var program = new Command();
478
+ program.name("skillpack").description("Assemble, package, and run Agent Skills packs").version(packageJson.version);
479
+ program.command("create [directory]").description("Create a skills pack interactively").action(async (directory) => {
480
+ await createCommand(directory);
481
+ });
482
+ registerSkillsCommand(program);
483
+ registerPromptsCommand(program);
484
+ program.command("build").description("Package the current pack as a zip file").action(async () => {
485
+ try {
486
+ await bundle(process.cwd());
487
+ } catch (err) {
488
+ console.error(chalk7.red(`Packaging failed: ${err}`));
489
+ process.exit(1);
490
+ }
491
+ });
492
+ program.parse();
package/package.json ADDED
@@ -0,0 +1,64 @@
1
+ {
2
+ "name": "@cremini/skillpack",
3
+ "version": "1.0.2",
4
+ "description": "Turn Skills into a Standalone App with UI",
5
+ "type": "module",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "git+https://github.com/FinpeakInc/skillpack.git"
9
+ },
10
+ "bugs": {
11
+ "url": "https://github.com/FinpeakInc/skillpack/issues"
12
+ },
13
+ "homepage": "https://github.com/FinpeakInc/skillpack#readme",
14
+ "bin": {
15
+ "skillpack": "dist/cli.js"
16
+ },
17
+ "files": [
18
+ "dist",
19
+ "runtime/README.md",
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",
27
+ "README.md",
28
+ "LICENSE"
29
+ ],
30
+ "engines": {
31
+ "node": ">=20"
32
+ },
33
+ "scripts": {
34
+ "build": "tsup",
35
+ "dev": "tsup --watch",
36
+ "check": "tsc --noEmit",
37
+ "format": "prettier --write .",
38
+ "create": "node dist/cli.js create",
39
+ "verify-release": "npm run check && npm run build && npm pack --dry-run",
40
+ "prepublishOnly": "npm run verify-release"
41
+ },
42
+ "keywords": [
43
+ "skills",
44
+ "agent",
45
+ "ai",
46
+ "cli"
47
+ ],
48
+ "author": "Finpeak Inc",
49
+ "license": "MIT",
50
+ "dependencies": {
51
+ "archiver": "^7.0.1",
52
+ "chalk": "^5.6.2",
53
+ "commander": "^14.0.3",
54
+ "inquirer": "^13.3.0"
55
+ },
56
+ "devDependencies": {
57
+ "@types/archiver": "^7.0.0",
58
+ "@types/inquirer": "^9.0.9",
59
+ "@types/node": "^25.5.0",
60
+ "prettier": "^3.8.1",
61
+ "tsup": "^8.5.1",
62
+ "typescript": "^5.9.3"
63
+ }
64
+ }