@grimoire-cc/cli 0.1.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/dist/bin.d.ts ADDED
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ export {};
3
+ //# sourceMappingURL=bin.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.d.ts","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":""}
package/dist/bin.js ADDED
@@ -0,0 +1,68 @@
1
+ #!/usr/bin/env node
2
+ import { defineCommand, runMain } from 'citty';
3
+ import { runAdd } from './commands/add.js';
4
+ import { runLogs } from './commands/logs.js';
5
+ const addCommand = defineCommand({
6
+ meta: {
7
+ name: 'add',
8
+ description: 'Install agents and skills from a pack into your project',
9
+ },
10
+ args: {
11
+ pack: {
12
+ type: 'positional',
13
+ description: 'Pack name (npm package)',
14
+ required: true,
15
+ },
16
+ pick: {
17
+ type: 'string',
18
+ description: 'Pick specific item by name, or use bare --pick for interactive selection',
19
+ },
20
+ },
21
+ async run({ args }) {
22
+ await runAdd(args.pack, args.pick, process.cwd());
23
+ },
24
+ });
25
+ const logsCommand = defineCommand({
26
+ meta: {
27
+ name: 'logs',
28
+ description: 'Open skill-router log viewer in the browser',
29
+ },
30
+ args: {
31
+ file: {
32
+ type: 'string',
33
+ description: 'Custom log file path (default: .claude/logs/skill-router.log)',
34
+ },
35
+ port: {
36
+ type: 'string',
37
+ description: 'Port to serve on (default: OS-assigned)',
38
+ },
39
+ },
40
+ async run({ args }) {
41
+ const server = await runLogs(process.cwd(), {
42
+ logFile: args.file || undefined,
43
+ port: args.port ? Number(args.port) : undefined,
44
+ });
45
+ const addr = server.address();
46
+ if (addr && typeof addr === 'object') {
47
+ console.log(`Log viewer running at http://127.0.0.1:${addr.port}`);
48
+ console.log('Press Ctrl+C to stop');
49
+ }
50
+ process.on('SIGINT', () => {
51
+ server.close();
52
+ process.exit(0);
53
+ });
54
+ },
55
+ });
56
+ const main = defineCommand({
57
+ meta: {
58
+ name: 'grimoire',
59
+ version: '0.1.0',
60
+ description: 'CLI tool for installing Grimoire agent and skill packs',
61
+ },
62
+ subCommands: {
63
+ add: addCommand,
64
+ logs: logsCommand,
65
+ },
66
+ });
67
+ runMain(main);
68
+ //# sourceMappingURL=bin.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"bin.js","sourceRoot":"","sources":["../src/bin.ts"],"names":[],"mappings":";AACA,OAAO,EAAE,aAAa,EAAE,OAAO,EAAE,MAAM,OAAO,CAAC;AAC/C,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAE7C,MAAM,UAAU,GAAG,aAAa,CAAC;IAC/B,IAAI,EAAE;QACJ,IAAI,EAAE,KAAK;QACX,WAAW,EAAE,yDAAyD;KACvE;IACD,IAAI,EAAE;QACJ,IAAI,EAAE;YACJ,IAAI,EAAE,YAAY;YAClB,WAAW,EAAE,yBAAyB;YACtC,QAAQ,EAAE,IAAI;SACf;QACD,IAAI,EAAE;YACJ,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE,0EAA0E;SACxF;KACF;IACD,KAAK,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE;QAChB,MAAM,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC;IACpD,CAAC;CACF,CAAC,CAAC;AAEH,MAAM,WAAW,GAAG,aAAa,CAAC;IAChC,IAAI,EAAE;QACJ,IAAI,EAAE,MAAM;QACZ,WAAW,EAAE,6CAA6C;KAC3D;IACD,IAAI,EAAE;QACJ,IAAI,EAAE;YACJ,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE,+DAA+D;SAC7E;QACD,IAAI,EAAE;YACJ,IAAI,EAAE,QAAQ;YACd,WAAW,EAAE,yCAAyC;SACvD;KACF;IACD,KAAK,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE;QAChB,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE;YAC1C,OAAO,EAAE,IAAI,CAAC,IAAI,IAAI,SAAS;YAC/B,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS;SAChD,CAAC,CAAC;QAEH,MAAM,IAAI,GAAG,MAAM,CAAC,OAAO,EAAE,CAAC;QAC9B,IAAI,IAAI,IAAI,OAAO,IAAI,KAAK,QAAQ,EAAE,CAAC;YACrC,OAAO,CAAC,GAAG,CAAC,0CAA0C,IAAI,CAAC,IAAI,EAAE,CAAC,CAAC;YACnE,OAAO,CAAC,GAAG,CAAC,sBAAsB,CAAC,CAAC;QACtC,CAAC;QAED,OAAO,CAAC,EAAE,CAAC,QAAQ,EAAE,GAAG,EAAE;YACxB,MAAM,CAAC,KAAK,EAAE,CAAC;YACf,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;QAClB,CAAC,CAAC,CAAC;IACL,CAAC;CACF,CAAC,CAAC;AAEH,MAAM,IAAI,GAAG,aAAa,CAAC;IACzB,IAAI,EAAE;QACJ,IAAI,EAAE,UAAU;QAChB,OAAO,EAAE,OAAO;QAChB,WAAW,EAAE,wDAAwD;KACtE;IACD,WAAW,EAAE;QACX,GAAG,EAAE,UAAU;QACf,IAAI,EAAE,WAAW;KAClB;CACF,CAAC,CAAC;AAEH,OAAO,CAAC,IAAI,CAAC,CAAC"}
@@ -0,0 +1,12 @@
1
+ import type { InstallSummary } from '../types.js';
2
+ /**
3
+ * Runs the `add` command: resolves a pack, loads its manifest, determines which items
4
+ * to install, copies them, and prints a summary.
5
+ *
6
+ * @param packageName - npm package name to install from
7
+ * @param pick - undefined = all, "" = interactive, "name" = specific item
8
+ * @param cwd - Target project directory (defaults to process.cwd())
9
+ * @returns The install summary
10
+ */
11
+ export declare function runAdd(packageName: string, pick: string | undefined, cwd?: string | undefined): Promise<InstallSummary>;
12
+ //# sourceMappingURL=add.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add.d.ts","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAe,cAAc,EAAgB,MAAM,aAAa,CAAC;AAE7E;;;;;;;;GAQG;AACH,wBAAsB,MAAM,CAC1B,WAAW,EAAE,MAAM,EACnB,IAAI,EAAE,MAAM,GAAG,SAAS,EACxB,GAAG,CAAC,EAAE,MAAM,GAAG,SAAS,GACvB,OAAO,CAAC,cAAc,CAAC,CAmBzB"}
@@ -0,0 +1,62 @@
1
+ import { resolvePackDir } from '../resolve.js';
2
+ import { loadManifest } from '../manifest.js';
3
+ import { copyItems } from '../copy.js';
4
+ import { printSummary } from '../summary.js';
5
+ import { promptForItems } from '../prompt.js';
6
+ /**
7
+ * Runs the `add` command: resolves a pack, loads its manifest, determines which items
8
+ * to install, copies them, and prints a summary.
9
+ *
10
+ * @param packageName - npm package name to install from
11
+ * @param pick - undefined = all, "" = interactive, "name" = specific item
12
+ * @param cwd - Target project directory (defaults to process.cwd())
13
+ * @returns The install summary
14
+ */
15
+ export async function runAdd(packageName, pick, cwd) {
16
+ const projectDir = cwd ?? process.cwd();
17
+ const packDir = resolvePackDir(packageName, projectDir);
18
+ const manifest = loadManifest(packDir);
19
+ const allItems = manifestToItems(manifest);
20
+ const selectedItems = await selectItems(allItems, manifest, pick);
21
+ const results = copyItems(selectedItems, packDir, projectDir);
22
+ const summary = {
23
+ packName: manifest.name,
24
+ packVersion: manifest.version,
25
+ results,
26
+ };
27
+ printSummary(summary);
28
+ return summary;
29
+ }
30
+ function manifestToItems(manifest) {
31
+ const agents = manifest.agents.map((agent) => ({
32
+ type: 'agent',
33
+ name: agent.name,
34
+ sourcePath: agent.path,
35
+ description: agent.description,
36
+ }));
37
+ const skills = manifest.skills.map((skill) => ({
38
+ type: 'skill',
39
+ name: skill.name,
40
+ sourcePath: skill.path,
41
+ description: skill.description,
42
+ }));
43
+ return [...agents, ...skills];
44
+ }
45
+ async function selectItems(allItems, manifest, pick) {
46
+ // No --pick: install everything
47
+ if (pick === undefined) {
48
+ return allItems;
49
+ }
50
+ // Bare --pick (empty string): interactive prompt
51
+ if (pick === '') {
52
+ return promptForItems(manifest);
53
+ }
54
+ // --pick=<name>: find specific item
55
+ const found = allItems.filter((item) => item.name === pick);
56
+ if (found.length === 0) {
57
+ const available = allItems.map((i) => i.name).join(', ');
58
+ throw new Error(`Item not found: "${pick}". Available items: ${available}`);
59
+ }
60
+ return found;
61
+ }
62
+ //# sourceMappingURL=add.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"add.js","sourceRoot":"","sources":["../../src/commands/add.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,eAAe,CAAC;AAC/C,OAAO,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AACvC,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAG9C;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,MAAM,CAC1B,WAAmB,EACnB,IAAwB,EACxB,GAAwB;IAExB,MAAM,UAAU,GAAG,GAAG,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;IACxC,MAAM,OAAO,GAAG,cAAc,CAAC,WAAW,EAAE,UAAU,CAAC,CAAC;IACxD,MAAM,QAAQ,GAAG,YAAY,CAAC,OAAO,CAAC,CAAC;IAEvC,MAAM,QAAQ,GAAG,eAAe,CAAC,QAAQ,CAAC,CAAC;IAC3C,MAAM,aAAa,GAAG,MAAM,WAAW,CAAC,QAAQ,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAC;IAElE,MAAM,OAAO,GAAG,SAAS,CAAC,aAAa,EAAE,OAAO,EAAE,UAAU,CAAC,CAAC;IAE9D,MAAM,OAAO,GAAmB;QAC9B,QAAQ,EAAE,QAAQ,CAAC,IAAI;QACvB,WAAW,EAAE,QAAQ,CAAC,OAAO;QAC7B,OAAO;KACR,CAAC;IAEF,YAAY,CAAC,OAAO,CAAC,CAAC;IAEtB,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,SAAS,eAAe,CAAC,QAAsB;IAC7C,MAAM,MAAM,GAAkB,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAC5D,IAAI,EAAE,OAAgB;QACtB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,UAAU,EAAE,KAAK,CAAC,IAAI;QACtB,WAAW,EAAE,KAAK,CAAC,WAAW;KAC/B,CAAC,CAAC,CAAC;IAEJ,MAAM,MAAM,GAAkB,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC;QAC5D,IAAI,EAAE,OAAgB;QACtB,IAAI,EAAE,KAAK,CAAC,IAAI;QAChB,UAAU,EAAE,KAAK,CAAC,IAAI;QACtB,WAAW,EAAE,KAAK,CAAC,WAAW;KAC/B,CAAC,CAAC,CAAC;IAEJ,OAAO,CAAC,GAAG,MAAM,EAAE,GAAG,MAAM,CAAC,CAAC;AAChC,CAAC;AAED,KAAK,UAAU,WAAW,CACxB,QAAgC,EAChC,QAAsB,EACtB,IAAwB;IAExB,gCAAgC;IAChC,IAAI,IAAI,KAAK,SAAS,EAAE,CAAC;QACvB,OAAO,QAAQ,CAAC;IAClB,CAAC;IAED,iDAAiD;IACjD,IAAI,IAAI,KAAK,EAAE,EAAE,CAAC;QAChB,OAAO,cAAc,CAAC,QAAQ,CAAC,CAAC;IAClC,CAAC;IAED,oCAAoC;IACpC,MAAM,KAAK,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC;IAC5D,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACvB,MAAM,SAAS,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACzD,MAAM,IAAI,KAAK,CACb,oBAAoB,IAAI,uBAAuB,SAAS,EAAE,CAC3D,CAAC;IACJ,CAAC;IAED,OAAO,KAAK,CAAC;AACf,CAAC"}
@@ -0,0 +1,8 @@
1
+ import { type Server } from 'node:http';
2
+ export interface LogsOptions {
3
+ readonly logFile?: string | undefined;
4
+ readonly port?: number | undefined;
5
+ readonly open?: boolean;
6
+ }
7
+ export declare function runLogs(cwd: string, options?: LogsOptions): Promise<Server>;
8
+ //# sourceMappingURL=logs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logs.d.ts","sourceRoot":"","sources":["../../src/commands/logs.ts"],"names":[],"mappings":"AAAA,OAAO,EAAgB,KAAK,MAAM,EAAE,MAAM,WAAW,CAAC;AAKtD,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACtC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;IACnC,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;CACzB;AAKD,wBAAsB,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,GAAE,WAAgB,GAAG,OAAO,CAAC,MAAM,CAAC,CAyHrF"}
@@ -0,0 +1,128 @@
1
+ import { createServer } from 'node:http';
2
+ import { readFileSync, accessSync, constants, statSync, openSync, readSync, closeSync } from 'node:fs';
3
+ import { resolve } from 'node:path';
4
+ import { exec } from 'node:child_process';
5
+ const DEFAULT_LOG_PATH = '.claude/logs/skill-router.log';
6
+ const DEFAULT_MANIFEST_PATH = '.claude/skills-manifest.json';
7
+ export async function runLogs(cwd, options = {}) {
8
+ const logFilePath = options.logFile
9
+ ? resolve(cwd, options.logFile)
10
+ : resolve(cwd, DEFAULT_LOG_PATH);
11
+ // Validate log file exists up front
12
+ try {
13
+ accessSync(logFilePath, constants.R_OK);
14
+ }
15
+ catch {
16
+ throw new Error(`Log file not found: ${logFilePath}`);
17
+ }
18
+ const htmlPath = resolve(import.meta.dirname, '..', 'static', 'log-viewer.html');
19
+ const html = readFileSync(htmlPath, 'utf-8');
20
+ const server = createServer((req, res) => {
21
+ if (req.url === '/' || req.url === '/index.html') {
22
+ res.writeHead(200, { 'Content-Type': 'text/html; charset=utf-8' });
23
+ res.end(html);
24
+ return;
25
+ }
26
+ if (req.url === '/api/logs') {
27
+ try {
28
+ const logData = readFileSync(logFilePath, 'utf-8');
29
+ res.writeHead(200, { 'Content-Type': 'application/x-ndjson' });
30
+ res.end(logData);
31
+ }
32
+ catch {
33
+ res.writeHead(500, { 'Content-Type': 'text/plain' });
34
+ res.end('Failed to read log file');
35
+ }
36
+ return;
37
+ }
38
+ if (req.url === '/api/manifest') {
39
+ const manifestPath = resolve(cwd, DEFAULT_MANIFEST_PATH);
40
+ try {
41
+ const data = readFileSync(manifestPath, 'utf-8');
42
+ res.writeHead(200, { 'Content-Type': 'application/json' });
43
+ res.end(data);
44
+ }
45
+ catch {
46
+ res.writeHead(404, { 'Content-Type': 'text/plain' });
47
+ res.end('Manifest not found');
48
+ }
49
+ return;
50
+ }
51
+ if (req.url === '/api/logs/stream') {
52
+ res.writeHead(200, {
53
+ 'Content-Type': 'text/event-stream',
54
+ 'Cache-Control': 'no-cache',
55
+ 'Connection': 'keep-alive',
56
+ });
57
+ let offset = 0;
58
+ const sendChunk = (text) => {
59
+ if (!text.trim())
60
+ return;
61
+ const encoded = text.split('\n').map(l => `data: ${l}`).join('\n');
62
+ res.write(`${encoded}\n\n`);
63
+ };
64
+ // Send initial content
65
+ try {
66
+ const content = readFileSync(logFilePath, 'utf-8');
67
+ offset = Buffer.byteLength(content, 'utf-8');
68
+ sendChunk(content);
69
+ }
70
+ catch { /* file may be empty */ }
71
+ // Poll for new data
72
+ const watcher = setInterval(() => {
73
+ try {
74
+ const stat = statSync(logFilePath);
75
+ if (stat.size > offset) {
76
+ const fd = openSync(logFilePath, 'r');
77
+ const buf = Buffer.alloc(stat.size - offset);
78
+ readSync(fd, buf, 0, buf.length, offset);
79
+ closeSync(fd);
80
+ offset = stat.size;
81
+ sendChunk(buf.toString('utf-8'));
82
+ }
83
+ else if (stat.size < offset) {
84
+ // File was truncated — reset
85
+ res.write('event: reset\ndata: \n\n');
86
+ const content = readFileSync(logFilePath, 'utf-8');
87
+ offset = Buffer.byteLength(content, 'utf-8');
88
+ if (content.trim())
89
+ sendChunk(content);
90
+ }
91
+ }
92
+ catch { /* file temporarily unavailable */ }
93
+ }, 1000);
94
+ const heartbeat = setInterval(() => {
95
+ res.write(':heartbeat\n\n');
96
+ }, 15000);
97
+ req.on('close', () => {
98
+ clearInterval(watcher);
99
+ clearInterval(heartbeat);
100
+ });
101
+ return;
102
+ }
103
+ res.writeHead(404, { 'Content-Type': 'text/plain' });
104
+ res.end('Not found');
105
+ });
106
+ const port = options.port ?? 0;
107
+ const shouldOpen = options.open ?? true;
108
+ return new Promise((resolve, reject) => {
109
+ server.on('error', reject);
110
+ server.listen(port, '127.0.0.1', () => {
111
+ const addr = server.address();
112
+ if (addr && typeof addr === 'object') {
113
+ const url = `http://127.0.0.1:${addr.port}`;
114
+ if (shouldOpen) {
115
+ openBrowser(url);
116
+ }
117
+ }
118
+ resolve(server);
119
+ });
120
+ });
121
+ }
122
+ function openBrowser(url) {
123
+ const cmd = process.platform === 'darwin' ? 'open' :
124
+ process.platform === 'win32' ? 'start' :
125
+ 'xdg-open';
126
+ exec(`${cmd} ${url}`);
127
+ }
128
+ //# sourceMappingURL=logs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"logs.js","sourceRoot":"","sources":["../../src/commands/logs.ts"],"names":[],"mappings":"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"}
package/dist/copy.d.ts ADDED
@@ -0,0 +1,19 @@
1
+ import type { InstallItem, InstallResult } from './types.js';
2
+ interface CopyResult {
3
+ readonly destinationPath: string;
4
+ readonly overwritten: boolean;
5
+ }
6
+ /**
7
+ * Copies a single agent .md file from a pack into the project's .claude/agents/ directory.
8
+ */
9
+ export declare function copyAgent(packDir: string, relativePath: string, projectDir: string): CopyResult;
10
+ /**
11
+ * Copies a skill directory recursively from a pack into the project's .claude/skills/ directory.
12
+ */
13
+ export declare function copySkill(packDir: string, relativePath: string, projectDir: string): CopyResult;
14
+ /**
15
+ * Copies a list of install items (agents and skills) into the project directory.
16
+ */
17
+ export declare function copyItems(items: readonly InstallItem[], packDir: string, projectDir: string): readonly InstallResult[];
18
+ export {};
19
+ //# sourceMappingURL=copy.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copy.d.ts","sourceRoot":"","sources":["../src/copy.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,WAAW,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAE7D,UAAU,UAAU;IAClB,QAAQ,CAAC,eAAe,EAAE,MAAM,CAAC;IACjC,QAAQ,CAAC,WAAW,EAAE,OAAO,CAAC;CAC/B;AAED;;GAEG;AACH,wBAAgB,SAAS,CACvB,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,GACjB,UAAU,CAkBZ;AAED;;GAEG;AACH,wBAAgB,SAAS,CACvB,OAAO,EAAE,MAAM,EACf,YAAY,EAAE,MAAM,EACpB,UAAU,EAAE,MAAM,GACjB,UAAU,CAkBZ;AAED;;GAEG;AACH,wBAAgB,SAAS,CACvB,KAAK,EAAE,SAAS,WAAW,EAAE,EAC7B,OAAO,EAAE,MAAM,EACf,UAAU,EAAE,MAAM,GACjB,SAAS,aAAa,EAAE,CAa1B"}
package/dist/copy.js ADDED
@@ -0,0 +1,58 @@
1
+ import { cpSync, existsSync, mkdirSync, statSync } from 'fs';
2
+ import { basename, dirname, join, resolve } from 'path';
3
+ /**
4
+ * Copies a single agent .md file from a pack into the project's .claude/agents/ directory.
5
+ */
6
+ export function copyAgent(packDir, relativePath, projectDir) {
7
+ validateNoTraversal(packDir, relativePath);
8
+ const sourcePath = join(packDir, relativePath);
9
+ if (!existsSync(sourcePath)) {
10
+ throw new Error(`Agent source not found: ${sourcePath}`);
11
+ }
12
+ const fileName = basename(relativePath);
13
+ const destDir = join(projectDir, '.claude', 'agents');
14
+ mkdirSync(destDir, { recursive: true });
15
+ const destPath = join(destDir, fileName);
16
+ const overwritten = existsSync(destPath);
17
+ cpSync(sourcePath, destPath, { force: true });
18
+ return { destinationPath: destPath, overwritten };
19
+ }
20
+ /**
21
+ * Copies a skill directory recursively from a pack into the project's .claude/skills/ directory.
22
+ */
23
+ export function copySkill(packDir, relativePath, projectDir) {
24
+ validateNoTraversal(packDir, relativePath);
25
+ const sourcePath = join(packDir, relativePath);
26
+ if (!existsSync(sourcePath)) {
27
+ throw new Error(`Skill source not found: ${sourcePath}`);
28
+ }
29
+ const dirName = basename(relativePath);
30
+ const destDir = join(projectDir, '.claude', 'skills');
31
+ mkdirSync(destDir, { recursive: true });
32
+ const destPath = join(destDir, dirName);
33
+ const overwritten = existsSync(destPath);
34
+ cpSync(sourcePath, destPath, { recursive: true, force: true });
35
+ return { destinationPath: destPath, overwritten };
36
+ }
37
+ /**
38
+ * Copies a list of install items (agents and skills) into the project directory.
39
+ */
40
+ export function copyItems(items, packDir, projectDir) {
41
+ return items.map((item) => {
42
+ const copyResult = item.type === 'agent'
43
+ ? copyAgent(packDir, item.sourcePath, projectDir)
44
+ : copySkill(packDir, item.sourcePath, projectDir);
45
+ return {
46
+ item,
47
+ destinationPath: copyResult.destinationPath,
48
+ overwritten: copyResult.overwritten,
49
+ };
50
+ });
51
+ }
52
+ function validateNoTraversal(packDir, relativePath) {
53
+ const resolved = resolve(packDir, relativePath);
54
+ if (!resolved.startsWith(resolve(packDir))) {
55
+ throw new Error(`Path traversal detected: "${relativePath}" escapes pack root`);
56
+ }
57
+ }
58
+ //# sourceMappingURL=copy.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"copy.js","sourceRoot":"","sources":["../src/copy.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ export { loadManifest } from './manifest.js';
2
+ export { resolvePackDir } from './resolve.js';
3
+ export { copyAgent, copySkill, copyItems } from './copy.js';
4
+ export { printSummary } from './summary.js';
5
+ export { promptForItems } from './prompt.js';
6
+ export { runAdd } from './commands/add.js';
7
+ export { runLogs } from './commands/logs.js';
8
+ export type { LogsOptions } from './commands/logs.js';
9
+ export type { PackSkillTriggers, PackAgentEntry, PackSkillEntry, PackManifest, InstallItem, InstallResult, InstallSummary, } from './types.js';
10
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC;AAC7C,YAAY,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAC;AACtD,YAAY,EACV,iBAAiB,EACjB,cAAc,EACd,cAAc,EACd,YAAY,EACZ,WAAW,EACX,aAAa,EACb,cAAc,GACf,MAAM,YAAY,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,8 @@
1
+ export { loadManifest } from './manifest.js';
2
+ export { resolvePackDir } from './resolve.js';
3
+ export { copyAgent, copySkill, copyItems } from './copy.js';
4
+ export { printSummary } from './summary.js';
5
+ export { promptForItems } from './prompt.js';
6
+ export { runAdd } from './commands/add.js';
7
+ export { runLogs } from './commands/logs.js';
8
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,cAAc,EAAE,MAAM,cAAc,CAAC;AAC9C,OAAO,EAAE,SAAS,EAAE,SAAS,EAAE,SAAS,EAAE,MAAM,WAAW,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAC7C,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,OAAO,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,10 @@
1
+ import type { PackManifest } from './types.js';
2
+ /**
3
+ * Loads and validates a claudify pack manifest from a directory.
4
+ *
5
+ * @param packDir - Absolute path to the pack's root directory
6
+ * @returns Validated PackManifest
7
+ * @throws Error if file not found, invalid JSON, or schema validation fails
8
+ */
9
+ export declare function loadManifest(packDir: string): PackManifest;
10
+ //# sourceMappingURL=manifest.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,YAAY,EAAqD,MAAM,YAAY,CAAC;AAElG;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,OAAO,EAAE,MAAM,GAAG,YAAY,CAuD1D"}
@@ -0,0 +1,118 @@
1
+ import { readFileSync } from 'fs';
2
+ import { join } from 'path';
3
+ /**
4
+ * Loads and validates a claudify pack manifest from a directory.
5
+ *
6
+ * @param packDir - Absolute path to the pack's root directory
7
+ * @returns Validated PackManifest
8
+ * @throws Error if file not found, invalid JSON, or schema validation fails
9
+ */
10
+ export function loadManifest(packDir) {
11
+ const manifestPath = join(packDir, 'claudify.json');
12
+ let content;
13
+ try {
14
+ content = readFileSync(manifestPath, 'utf-8');
15
+ }
16
+ catch (error) {
17
+ const message = error instanceof Error ? error.message : String(error);
18
+ throw new Error(`Manifest file not found: ${manifestPath} - ${message}`);
19
+ }
20
+ let data;
21
+ try {
22
+ data = JSON.parse(content);
23
+ }
24
+ catch (error) {
25
+ const message = error instanceof Error ? error.message : String(error);
26
+ throw new Error(`Failed to parse manifest JSON: ${message}`);
27
+ }
28
+ if (!data || typeof data !== 'object') {
29
+ throw new Error('Manifest must be an object');
30
+ }
31
+ const raw = data;
32
+ if (!raw['name'] || typeof raw['name'] !== 'string') {
33
+ throw new Error('Manifest must have a "name" string field');
34
+ }
35
+ if (!raw['version'] || typeof raw['version'] !== 'string') {
36
+ throw new Error('Manifest must have a "version" string field');
37
+ }
38
+ if (!Array.isArray(raw['agents'])) {
39
+ throw new Error('Manifest must have an "agents" array field');
40
+ }
41
+ if (!Array.isArray(raw['skills'])) {
42
+ throw new Error('Manifest must have a "skills" array field');
43
+ }
44
+ const agents = raw['agents'].map((entry, i) => validateAgentEntry(entry, i));
45
+ const skills = raw['skills'].map((entry, i) => validateSkillEntry(entry, i));
46
+ return {
47
+ name: raw['name'],
48
+ version: raw['version'],
49
+ agents,
50
+ skills,
51
+ };
52
+ }
53
+ function validateAgentEntry(entry, index) {
54
+ if (!entry || typeof entry !== 'object') {
55
+ throw new Error(`Agent entry [${index}] must be an object`);
56
+ }
57
+ const raw = entry;
58
+ if (!raw['name'] || typeof raw['name'] !== 'string') {
59
+ throw new Error(`Agent entry [${index}] must have a "name" string field`);
60
+ }
61
+ if (!raw['path'] || typeof raw['path'] !== 'string') {
62
+ throw new Error(`Agent entry [${index}] must have a "path" string field`);
63
+ }
64
+ if (!raw['description'] || typeof raw['description'] !== 'string') {
65
+ throw new Error(`Agent entry [${index}] must have a "description" string field`);
66
+ }
67
+ return {
68
+ name: raw['name'],
69
+ path: raw['path'],
70
+ description: raw['description'],
71
+ };
72
+ }
73
+ function validateSkillEntry(entry, index) {
74
+ if (!entry || typeof entry !== 'object') {
75
+ throw new Error(`Skill entry [${index}] must be an object`);
76
+ }
77
+ const raw = entry;
78
+ if (!raw['name'] || typeof raw['name'] !== 'string') {
79
+ throw new Error(`Skill entry [${index}] must have a "name" string field`);
80
+ }
81
+ if (!raw['path'] || typeof raw['path'] !== 'string') {
82
+ throw new Error(`Skill entry [${index}] must have a "path" string field`);
83
+ }
84
+ if (!raw['description'] || typeof raw['description'] !== 'string') {
85
+ throw new Error(`Skill entry [${index}] must have a "description" string field`);
86
+ }
87
+ const triggers = raw['triggers'] != null
88
+ ? validateTriggers(raw['triggers'], index)
89
+ : undefined;
90
+ return {
91
+ name: raw['name'],
92
+ path: raw['path'],
93
+ description: raw['description'],
94
+ triggers,
95
+ };
96
+ }
97
+ function validateTriggers(triggers, skillIndex) {
98
+ if (typeof triggers !== 'object' || triggers === null) {
99
+ throw new Error(`Skill entry [${skillIndex}] triggers must be an object`);
100
+ }
101
+ const raw = triggers;
102
+ return {
103
+ keywords: asStringArray(raw['keywords']),
104
+ file_extensions: asStringArray(raw['file_extensions']),
105
+ patterns: asStringArray(raw['patterns']),
106
+ file_paths: asStringArray(raw['file_paths']),
107
+ };
108
+ }
109
+ function asStringArray(value) {
110
+ if (value === undefined || value === null) {
111
+ return [];
112
+ }
113
+ if (!Array.isArray(value)) {
114
+ return [];
115
+ }
116
+ return value;
117
+ }
118
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../src/manifest.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,8 @@
1
+ import type { PackManifest, InstallItem } from './types.js';
2
+ /**
3
+ * Displays an interactive multiselect prompt for the user to pick items from a pack manifest.
4
+ *
5
+ * @returns The selected install items, or empty array if cancelled
6
+ */
7
+ export declare function promptForItems(manifest: PackManifest): Promise<readonly InstallItem[]>;
8
+ //# sourceMappingURL=prompt.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"prompt.d.ts","sourceRoot":"","sources":["../src/prompt.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,YAAY,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAE5D;;;;GAIG;AACH,wBAAsB,cAAc,CAAC,QAAQ,EAAE,YAAY,GAAG,OAAO,CAAC,SAAS,WAAW,EAAE,CAAC,CAkB5F"}
package/dist/prompt.js ADDED
@@ -0,0 +1,45 @@
1
+ import * as clack from '@clack/prompts';
2
+ /**
3
+ * Displays an interactive multiselect prompt for the user to pick items from a pack manifest.
4
+ *
5
+ * @returns The selected install items, or empty array if cancelled
6
+ */
7
+ export async function promptForItems(manifest) {
8
+ clack.intro(`Pick items from ${manifest.name}`);
9
+ const options = buildOptions(manifest);
10
+ const selected = await clack.multiselect({
11
+ message: 'Select items to install:',
12
+ options,
13
+ required: false,
14
+ });
15
+ if (clack.isCancel(selected)) {
16
+ clack.cancel('Installation cancelled.');
17
+ return [];
18
+ }
19
+ clack.outro('Selection complete.');
20
+ return selected;
21
+ }
22
+ function buildOptions(manifest) {
23
+ const agentOptions = manifest.agents.map((agent) => ({
24
+ label: `[agent] ${agent.name}`,
25
+ value: {
26
+ type: 'agent',
27
+ name: agent.name,
28
+ sourcePath: agent.path,
29
+ description: agent.description,
30
+ },
31
+ hint: agent.description,
32
+ }));
33
+ const skillOptions = manifest.skills.map((skill) => ({
34
+ label: `[skill] ${skill.name}`,
35
+ value: {
36
+ type: 'skill',
37
+ name: skill.name,
38
+ sourcePath: skill.path,
39
+ description: skill.description,
40
+ },
41
+ hint: skill.description,
42
+ }));
43
+ return [...agentOptions, ...skillOptions];
44
+ }
45
+ //# sourceMappingURL=prompt.js.map