@skillsmith/cli 0.4.2 → 0.5.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/.tsbuildinfo +1 -1
- package/dist/src/commands/audit.d.ts +19 -0
- package/dist/src/commands/audit.d.ts.map +1 -0
- package/dist/src/commands/audit.js +134 -0
- package/dist/src/commands/audit.js.map +1 -0
- package/dist/src/commands/audit.test.d.ts +8 -0
- package/dist/src/commands/audit.test.d.ts.map +1 -0
- package/dist/src/commands/audit.test.js +97 -0
- package/dist/src/commands/audit.test.js.map +1 -0
- package/dist/src/commands/author/init.d.ts.map +1 -1
- package/dist/src/commands/author/init.js +4 -9
- package/dist/src/commands/author/init.js.map +1 -1
- package/dist/src/commands/create.d.ts +42 -0
- package/dist/src/commands/create.d.ts.map +1 -0
- package/dist/src/commands/create.js +325 -0
- package/dist/src/commands/create.js.map +1 -0
- package/dist/src/commands/diff.d.ts +17 -0
- package/dist/src/commands/diff.d.ts.map +1 -0
- package/dist/src/commands/diff.js +191 -0
- package/dist/src/commands/diff.js.map +1 -0
- package/dist/src/commands/diff.test.d.ts +6 -0
- package/dist/src/commands/diff.test.d.ts.map +1 -0
- package/dist/src/commands/diff.test.js +275 -0
- package/dist/src/commands/diff.test.js.map +1 -0
- package/dist/src/commands/index.d.ts +4 -0
- package/dist/src/commands/index.d.ts.map +1 -1
- package/dist/src/commands/index.js +7 -0
- package/dist/src/commands/index.js.map +1 -1
- package/dist/src/commands/manage.d.ts.map +1 -1
- package/dist/src/commands/manage.js +18 -10
- package/dist/src/commands/manage.js.map +1 -1
- package/dist/src/commands/pin.d.ts +24 -0
- package/dist/src/commands/pin.d.ts.map +1 -0
- package/dist/src/commands/pin.js +123 -0
- package/dist/src/commands/pin.js.map +1 -0
- package/dist/src/commands/pin.test.d.ts +6 -0
- package/dist/src/commands/pin.test.d.ts.map +1 -0
- package/dist/src/commands/pin.test.js +206 -0
- package/dist/src/commands/pin.test.js.map +1 -0
- package/dist/src/commands/search.d.ts.map +1 -1
- package/dist/src/commands/search.js +3 -3
- package/dist/src/commands/search.js.map +1 -1
- package/dist/src/commands/sync.d.ts.map +1 -1
- package/dist/src/commands/sync.js +7 -6
- package/dist/src/commands/sync.js.map +1 -1
- package/dist/src/import.js +2 -2
- package/dist/src/import.js.map +1 -1
- package/dist/src/index.js +9 -1
- package/dist/src/index.js.map +1 -1
- package/dist/src/templates/changelog.md.template.d.ts +8 -0
- package/dist/src/templates/changelog.md.template.d.ts.map +1 -0
- package/dist/src/templates/changelog.md.template.js +19 -0
- package/dist/src/templates/changelog.md.template.js.map +1 -0
- package/dist/src/templates/index.d.ts +1 -0
- package/dist/src/templates/index.d.ts.map +1 -1
- package/dist/src/templates/index.js +1 -0
- package/dist/src/templates/index.js.map +1 -1
- package/dist/src/templates/skill.md.template.d.ts +1 -1
- package/dist/src/templates/skill.md.template.d.ts.map +1 -1
- package/dist/src/templates/skill.md.template.js +1 -3
- package/dist/src/templates/skill.md.template.js.map +1 -1
- package/dist/src/utils/license-validation.js +1 -1
- package/dist/src/utils/license-validation.js.map +1 -1
- package/dist/src/utils/manifest.d.ts +46 -0
- package/dist/src/utils/manifest.d.ts.map +1 -0
- package/dist/src/utils/manifest.js +55 -0
- package/dist/src/utils/manifest.js.map +1 -0
- package/dist/src/utils/require-tier.d.ts +38 -0
- package/dist/src/utils/require-tier.d.ts.map +1 -0
- package/dist/src/utils/require-tier.js +74 -0
- package/dist/src/utils/require-tier.js.map +1 -0
- package/dist/src/utils/skill-name.d.ts +19 -0
- package/dist/src/utils/skill-name.d.ts.map +1 -0
- package/dist/src/utils/skill-name.js +26 -0
- package/dist/src/utils/skill-name.js.map +1 -0
- package/dist/src/utils/skills-directory.d.ts +12 -3
- package/dist/src/utils/skills-directory.d.ts.map +1 -1
- package/dist/src/utils/skills-directory.js +62 -7
- package/dist/src/utils/skills-directory.js.map +1 -1
- package/dist/tests/create.test.d.ts +5 -0
- package/dist/tests/create.test.d.ts.map +1 -0
- package/dist/tests/create.test.js +449 -0
- package/dist/tests/create.test.js.map +1 -0
- package/package.json +2 -2
|
@@ -3,6 +3,6 @@
|
|
|
3
3
|
*
|
|
4
4
|
* Template for new skill SKILL.md files with YAML frontmatter.
|
|
5
5
|
*/
|
|
6
|
-
export declare const SKILL_MD_TEMPLATE = "---\nname: {{name}}\ndescription: {{description}}\nauthor: {{author}}\nversion: 1.0.0\ncategory: {{category}}\ntags:\n - claude-skill\n - {{category}}\nlicense: MIT\ncreated: {{date}}\n---\n\n# {{name}}\n\n{{description}}
|
|
6
|
+
export declare const SKILL_MD_TEMPLATE = "---\nname: {{name}}\ndescription: {{description}}\nauthor: {{author}}\nversion: 1.0.0\ncategory: {{category}}\ntags:\n - claude-skill\n - {{category}}\nlicense: MIT\ncreated: {{date}}\n---\n\n# {{name}}\n\n{{description}}{{behavioralClassification}}## Features\n\n- Feature 1: Description of feature\n- Feature 2: Description of feature\n- Feature 3: Description of feature\n\n## Installation\n\n```bash\nskillsmith install {{name}}\n```\n\nOr manually:\n\n```bash\ncp -r . ~/.claude/skills/{{name}}\n```\n\n## Usage\n\n### Basic Usage\n\nDescribe how to use the skill with examples.\n\n### Commands\n\n| Command | Description |\n|---------|-------------|\n| `/example` | Description of example command |\n\n### Trigger Phrases\n\nThe skill responds to:\n- \"example phrase 1\"\n- \"example phrase 2\"\n\n## Configuration\n\n| Setting | Default | Description |\n|---------|---------|-------------|\n| `setting1` | `value` | Description |\n\n## Scripts\n\n### example.js\n\nLocated in `scripts/example.js`:\n\n```javascript\n// Your automation script here\n```\n\n## Resources\n\nFiles in the `resources/` directory:\n- `resource1.txt` - Description\n\n## Dependencies\n\nThis skill requires:\n- No external dependencies\n\n## Contributing\n\nContributions welcome! Please submit pull requests.\n\n## License\n\nMIT License - see LICENSE file for details.\n\n## Changelog\n\n### 1.0.0 ({{date}})\n- Initial release\n";
|
|
7
7
|
export default SKILL_MD_TEMPLATE;
|
|
8
8
|
//# sourceMappingURL=skill.md.template.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skill.md.template.d.ts","sourceRoot":"","sources":["../../../src/templates/skill.md.template.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,eAAO,MAAM,iBAAiB,
|
|
1
|
+
{"version":3,"file":"skill.md.template.d.ts","sourceRoot":"","sources":["../../../src/templates/skill.md.template.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,eAAO,MAAM,iBAAiB,84CAyF7B,CAAA;AAED,eAAe,iBAAiB,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skill.md.template.js","sourceRoot":"","sources":["../../../src/templates/skill.md.template.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,CAAC,MAAM,iBAAiB,GAAG
|
|
1
|
+
{"version":3,"file":"skill.md.template.js","sourceRoot":"","sources":["../../../src/templates/skill.md.template.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,MAAM,CAAC,MAAM,iBAAiB,GAAG;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAyFhC,CAAA;AAED,eAAe,iBAAiB,CAAA"}
|
|
@@ -62,7 +62,7 @@ export function decodeLicenseKey(licenseKey) {
|
|
|
62
62
|
const decoded = Buffer.from(licenseKey, 'base64').toString('utf-8');
|
|
63
63
|
const payload = JSON.parse(decoded);
|
|
64
64
|
// Validate required fields
|
|
65
|
-
if (!payload.tier || !['team', 'enterprise'].includes(payload.tier)) {
|
|
65
|
+
if (!payload.tier || !['individual', 'team', 'enterprise'].includes(payload.tier)) {
|
|
66
66
|
return null;
|
|
67
67
|
}
|
|
68
68
|
if (!payload.expiresAt || isNaN(Date.parse(payload.expiresAt))) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"license-validation.js","sourceRoot":"","sources":["../../../src/utils/license-validation.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,EAAE,aAAa,EAAE,MAAM,oBAAoB,CAAA;AAElD,uEAAuE;AACvE,IAAI,wBAAwB,GAAkD,SAAS,CAAA;AAEvF;;;;;GAKG;AACH,MAAM,CAAC,KAAK,UAAU,0BAA0B;IAC9C,yCAAyC;IACzC,IAAI,wBAAwB,KAAK,SAAS,EAAE,CAAC;QAC3C,OAAO,wBAAwB,CAAA;IACjC,CAAC;IAED,IAAI,CAAC;QACH,oFAAoF;QACpF,gEAAgE;QAChE,MAAM,WAAW,GAAG,wBAAwB,CAAA;QAC5C,MAAM,UAAU,GAAG,CAAC,MAAM,MAAM,CAAC,yBAAyB,CAAC,WAAW,CAAC,CAGtE,CAAA;QAED,IAAI,UAAU,CAAC,kBAAkB,CAAC,EAAE,CAAC;YACnC,MAAM,cAAc,GAAG,UAAU,CAAC,kBAAkB,CAAyC,CAAA;YAC7F,wBAAwB,GAAG,IAAI,cAAc,EAAE,CAAA;YAC/C,OAAO,wBAAwB,CAAA;QACjC,CAAC;QAED,wBAAwB,GAAG,IAAI,CAAA;QAC/B,OAAO,IAAI,CAAA;IACb,CAAC;IAAC,MAAM,CAAC;QACP,0EAA0E;QAC1E,wBAAwB,GAAG,IAAI,CAAA;QAC/B,OAAO,IAAI,CAAA;IACb,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,8BAA8B;IAC5C,wBAAwB,GAAG,SAAS,CAAA;AACtC,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,gBAAgB,CAAC,UAAkB;IACjD,IAAI,CAAC;QACH,0CAA0C;QAC1C,yEAAyE;QACzE,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAA;QACnE,MAAM,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAmB,CAAA;QAErD,2BAA2B;QAC3B,IAAI,CAAC,OAAO,CAAC,IAAI,IAAI,CAAC,CAAC,MAAM,EAAE,YAAY,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,EAAE,CAAC;
|
|
1
|
+
{"version":3,"file":"license-validation.js","sourceRoot":"","sources":["../../../src/utils/license-validation.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Thin manifest reader for the Skillsmith CLI
|
|
3
|
+
* @module @skillsmith/cli/utils/manifest
|
|
4
|
+
* @see SMI-skill-version-tracking Wave 2
|
|
5
|
+
*
|
|
6
|
+
* Reads (and optionally writes) the ~/.skillsmith/manifest.json file.
|
|
7
|
+
* This mirrors the SkillManifest types defined in
|
|
8
|
+
* @skillsmith/mcp-server/tools/install.types without creating a cross-package
|
|
9
|
+
* dependency on mcp-server.
|
|
10
|
+
*
|
|
11
|
+
* The CLI owns its own read path; write operations (pin/unpin) use
|
|
12
|
+
* updateManifestEntry below which does an atomic temp-file rename.
|
|
13
|
+
*/
|
|
14
|
+
export interface SkillManifestEntry {
|
|
15
|
+
id: string;
|
|
16
|
+
name: string;
|
|
17
|
+
version: string;
|
|
18
|
+
source: string;
|
|
19
|
+
installPath: string;
|
|
20
|
+
installedAt: string;
|
|
21
|
+
lastUpdated: string;
|
|
22
|
+
originalContentHash?: string;
|
|
23
|
+
contentHash?: string;
|
|
24
|
+
/** Wave 2: pinned content hash (8-char truncation of full SHA-256) */
|
|
25
|
+
pinnedVersion?: string;
|
|
26
|
+
updatePolicy?: 'auto' | 'manual' | 'never';
|
|
27
|
+
}
|
|
28
|
+
export interface SkillManifest {
|
|
29
|
+
version: string;
|
|
30
|
+
installedSkills: Record<string, SkillManifestEntry>;
|
|
31
|
+
}
|
|
32
|
+
export declare const MANIFEST_PATH: string;
|
|
33
|
+
/**
|
|
34
|
+
* Load the manifest from disk.
|
|
35
|
+
* Returns an empty manifest if the file does not exist.
|
|
36
|
+
*/
|
|
37
|
+
export declare function loadManifest(): Promise<SkillManifest>;
|
|
38
|
+
/**
|
|
39
|
+
* Save the manifest atomically (temp file → rename).
|
|
40
|
+
*/
|
|
41
|
+
export declare function saveManifest(manifest: SkillManifest): Promise<void>;
|
|
42
|
+
/**
|
|
43
|
+
* Load the manifest, apply an update function, and save atomically.
|
|
44
|
+
*/
|
|
45
|
+
export declare function updateManifestEntry(updateFn: (manifest: SkillManifest) => SkillManifest): Promise<void>;
|
|
46
|
+
//# sourceMappingURL=manifest.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.d.ts","sourceRoot":"","sources":["../../../src/utils/manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAUH,MAAM,WAAW,kBAAkB;IACjC,EAAE,EAAE,MAAM,CAAA;IACV,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,CAAA;IACf,MAAM,EAAE,MAAM,CAAA;IACd,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,MAAM,CAAA;IACnB,WAAW,EAAE,MAAM,CAAA;IACnB,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,sEAAsE;IACtE,aAAa,CAAC,EAAE,MAAM,CAAA;IACtB,YAAY,CAAC,EAAE,MAAM,GAAG,QAAQ,GAAG,OAAO,CAAA;CAC3C;AAED,MAAM,WAAW,aAAa;IAC5B,OAAO,EAAE,MAAM,CAAA;IACf,eAAe,EAAE,MAAM,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAA;CACpD;AAOD,eAAO,MAAM,aAAa,QAAwC,CAAA;AAMlE;;;GAGG;AACH,wBAAsB,YAAY,IAAI,OAAO,CAAC,aAAa,CAAC,CAO3D;AAED;;GAEG;AACH,wBAAsB,YAAY,CAAC,QAAQ,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAKzE;AAED;;GAEG;AACH,wBAAsB,mBAAmB,CACvC,QAAQ,EAAE,CAAC,QAAQ,EAAE,aAAa,KAAK,aAAa,GACnD,OAAO,CAAC,IAAI,CAAC,CAIf"}
|
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview Thin manifest reader for the Skillsmith CLI
|
|
3
|
+
* @module @skillsmith/cli/utils/manifest
|
|
4
|
+
* @see SMI-skill-version-tracking Wave 2
|
|
5
|
+
*
|
|
6
|
+
* Reads (and optionally writes) the ~/.skillsmith/manifest.json file.
|
|
7
|
+
* This mirrors the SkillManifest types defined in
|
|
8
|
+
* @skillsmith/mcp-server/tools/install.types without creating a cross-package
|
|
9
|
+
* dependency on mcp-server.
|
|
10
|
+
*
|
|
11
|
+
* The CLI owns its own read path; write operations (pin/unpin) use
|
|
12
|
+
* updateManifestEntry below which does an atomic temp-file rename.
|
|
13
|
+
*/
|
|
14
|
+
import { readFile, writeFile, mkdir, rename } from 'fs/promises';
|
|
15
|
+
import { join, dirname } from 'path';
|
|
16
|
+
import { homedir } from 'os';
|
|
17
|
+
// ============================================================================
|
|
18
|
+
// Paths
|
|
19
|
+
// ============================================================================
|
|
20
|
+
const SKILLSMITH_DIR = join(homedir(), '.skillsmith');
|
|
21
|
+
export const MANIFEST_PATH = join(SKILLSMITH_DIR, 'manifest.json');
|
|
22
|
+
// ============================================================================
|
|
23
|
+
// Read / Write
|
|
24
|
+
// ============================================================================
|
|
25
|
+
/**
|
|
26
|
+
* Load the manifest from disk.
|
|
27
|
+
* Returns an empty manifest if the file does not exist.
|
|
28
|
+
*/
|
|
29
|
+
export async function loadManifest() {
|
|
30
|
+
try {
|
|
31
|
+
const content = await readFile(MANIFEST_PATH, 'utf-8');
|
|
32
|
+
return JSON.parse(content);
|
|
33
|
+
}
|
|
34
|
+
catch {
|
|
35
|
+
return { version: '1.0.0', installedSkills: {} };
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Save the manifest atomically (temp file → rename).
|
|
40
|
+
*/
|
|
41
|
+
export async function saveManifest(manifest) {
|
|
42
|
+
await mkdir(dirname(MANIFEST_PATH), { recursive: true });
|
|
43
|
+
const tmpPath = `${MANIFEST_PATH}.tmp.${process.pid}`;
|
|
44
|
+
await writeFile(tmpPath, JSON.stringify(manifest, null, 2));
|
|
45
|
+
await rename(tmpPath, MANIFEST_PATH);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Load the manifest, apply an update function, and save atomically.
|
|
49
|
+
*/
|
|
50
|
+
export async function updateManifestEntry(updateFn) {
|
|
51
|
+
const manifest = await loadManifest();
|
|
52
|
+
const updated = updateFn(manifest);
|
|
53
|
+
await saveManifest(updated);
|
|
54
|
+
}
|
|
55
|
+
//# sourceMappingURL=manifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../../src/utils/manifest.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,aAAa,CAAA;AAChE,OAAO,EAAE,IAAI,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AACpC,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAA;AA0B5B,+EAA+E;AAC/E,QAAQ;AACR,+EAA+E;AAE/E,MAAM,cAAc,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,aAAa,CAAC,CAAA;AACrD,MAAM,CAAC,MAAM,aAAa,GAAG,IAAI,CAAC,cAAc,EAAE,eAAe,CAAC,CAAA;AAElE,+EAA+E;AAC/E,eAAe;AACf,+EAA+E;AAE/E;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,IAAI,CAAC;QACH,MAAM,OAAO,GAAG,MAAM,QAAQ,CAAC,aAAa,EAAE,OAAO,CAAC,CAAA;QACtD,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAkB,CAAA;IAC7C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,eAAe,EAAE,EAAE,EAAE,CAAA;IAClD,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,QAAuB;IACxD,MAAM,KAAK,CAAC,OAAO,CAAC,aAAa,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAA;IACxD,MAAM,OAAO,GAAG,GAAG,aAAa,QAAQ,OAAO,CAAC,GAAG,EAAE,CAAA;IACrD,MAAM,SAAS,CAAC,OAAO,EAAE,IAAI,CAAC,SAAS,CAAC,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAA;IAC3D,MAAM,MAAM,CAAC,OAAO,EAAE,aAAa,CAAC,CAAA;AACtC,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,mBAAmB,CACvC,QAAoD;IAEpD,MAAM,QAAQ,GAAG,MAAM,YAAY,EAAE,CAAA;IACrC,MAAM,OAAO,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAA;IAClC,MAAM,YAAY,CAAC,OAAO,CAAC,CAAA;AAC7B,CAAC"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview requireTier — CLI license tier gate helper
|
|
3
|
+
* @module @skillsmith/cli/utils/require-tier
|
|
4
|
+
* @see SMI-skill-version-tracking Wave 1
|
|
5
|
+
*
|
|
6
|
+
* Throws a user-friendly error when the current license tier is below
|
|
7
|
+
* the minimum required for a CLI command or flag.
|
|
8
|
+
*
|
|
9
|
+
* Security properties:
|
|
10
|
+
* - Fail-secure: key present + validation failure → block, never fall back
|
|
11
|
+
* to community to silently allow access
|
|
12
|
+
* - SKILLSMITH_SKIP_LICENSE_CHECK=true is a CI/dev escape hatch only; it
|
|
13
|
+
* must use bracket notation per TypeScript/ESLint index-signature rules
|
|
14
|
+
* - SKILLSMITH_LICENSE_KEY is read from env but never logged
|
|
15
|
+
*/
|
|
16
|
+
import type { LicenseTier } from './license-types.js';
|
|
17
|
+
/**
|
|
18
|
+
* Throw if the current license tier is below minimumTier.
|
|
19
|
+
*
|
|
20
|
+
* Call this at the top of any CLI command or action that requires a paid tier.
|
|
21
|
+
*
|
|
22
|
+
* @param minimumTier - Minimum tier required to use the feature
|
|
23
|
+
* @throws Error with an upgrade prompt when the tier requirement is not met
|
|
24
|
+
* @throws Error when a license key is present but fails validation (fail-secure)
|
|
25
|
+
*
|
|
26
|
+
* @example
|
|
27
|
+
* ```typescript
|
|
28
|
+
* export function createOutdatedCommand(): Command {
|
|
29
|
+
* return new Command('outdated')
|
|
30
|
+
* .action(async () => {
|
|
31
|
+
* await requireTier('individual')
|
|
32
|
+
* // ... rest of command
|
|
33
|
+
* })
|
|
34
|
+
* }
|
|
35
|
+
* ```
|
|
36
|
+
*/
|
|
37
|
+
export declare function requireTier(minimumTier: LicenseTier): Promise<void>;
|
|
38
|
+
//# sourceMappingURL=require-tier.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"require-tier.d.ts","sourceRoot":"","sources":["../../../src/utils/require-tier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAGH,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,oBAAoB,CAAA;AAkBrD;;;;;;;;;;;;;;;;;;;GAmBG;AACH,wBAAsB,WAAW,CAAC,WAAW,EAAE,WAAW,GAAG,OAAO,CAAC,IAAI,CAAC,CA8BzE"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @fileoverview requireTier — CLI license tier gate helper
|
|
3
|
+
* @module @skillsmith/cli/utils/require-tier
|
|
4
|
+
* @see SMI-skill-version-tracking Wave 1
|
|
5
|
+
*
|
|
6
|
+
* Throws a user-friendly error when the current license tier is below
|
|
7
|
+
* the minimum required for a CLI command or flag.
|
|
8
|
+
*
|
|
9
|
+
* Security properties:
|
|
10
|
+
* - Fail-secure: key present + validation failure → block, never fall back
|
|
11
|
+
* to community to silently allow access
|
|
12
|
+
* - SKILLSMITH_SKIP_LICENSE_CHECK=true is a CI/dev escape hatch only; it
|
|
13
|
+
* must use bracket notation per TypeScript/ESLint index-signature rules
|
|
14
|
+
* - SKILLSMITH_LICENSE_KEY is read from env but never logged
|
|
15
|
+
*/
|
|
16
|
+
import { getLicenseStatus } from './license-validation.js';
|
|
17
|
+
/**
|
|
18
|
+
* Ordered license tiers, lowest to highest.
|
|
19
|
+
* Used for tier comparison arithmetic.
|
|
20
|
+
*/
|
|
21
|
+
const TIER_ORDER = ['community', 'individual', 'team', 'enterprise'];
|
|
22
|
+
/**
|
|
23
|
+
* Prices for use in upgrade messages
|
|
24
|
+
*/
|
|
25
|
+
const TIER_PRICING = {
|
|
26
|
+
community: '$0/month',
|
|
27
|
+
individual: '$9.99/month',
|
|
28
|
+
team: '$25/user/month',
|
|
29
|
+
enterprise: '$55/user/month',
|
|
30
|
+
};
|
|
31
|
+
/**
|
|
32
|
+
* Throw if the current license tier is below minimumTier.
|
|
33
|
+
*
|
|
34
|
+
* Call this at the top of any CLI command or action that requires a paid tier.
|
|
35
|
+
*
|
|
36
|
+
* @param minimumTier - Minimum tier required to use the feature
|
|
37
|
+
* @throws Error with an upgrade prompt when the tier requirement is not met
|
|
38
|
+
* @throws Error when a license key is present but fails validation (fail-secure)
|
|
39
|
+
*
|
|
40
|
+
* @example
|
|
41
|
+
* ```typescript
|
|
42
|
+
* export function createOutdatedCommand(): Command {
|
|
43
|
+
* return new Command('outdated')
|
|
44
|
+
* .action(async () => {
|
|
45
|
+
* await requireTier('individual')
|
|
46
|
+
* // ... rest of command
|
|
47
|
+
* })
|
|
48
|
+
* }
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
export async function requireTier(minimumTier) {
|
|
52
|
+
// CI / dev escape hatch — must use bracket notation (TS index-signature rule)
|
|
53
|
+
if (process.env['SKILLSMITH_SKIP_LICENSE_CHECK'] === 'true') {
|
|
54
|
+
return;
|
|
55
|
+
}
|
|
56
|
+
const status = await getLicenseStatus();
|
|
57
|
+
// Fail-secure: key present + validation failure → block
|
|
58
|
+
// Never silently fall back to community when a key was supplied
|
|
59
|
+
const hasKey = Boolean(process.env['SKILLSMITH_LICENSE_KEY']);
|
|
60
|
+
if (hasKey && !status.valid) {
|
|
61
|
+
throw new Error(`License validation failed. ` +
|
|
62
|
+
`Please check your SKILLSMITH_LICENSE_KEY or visit https://skillsmith.app/account to manage your license.`);
|
|
63
|
+
}
|
|
64
|
+
const currentTier = (status.tier ?? 'community');
|
|
65
|
+
const currentIndex = TIER_ORDER.indexOf(currentTier);
|
|
66
|
+
const requiredIndex = TIER_ORDER.indexOf(minimumTier);
|
|
67
|
+
if (currentIndex < requiredIndex) {
|
|
68
|
+
const pricing = TIER_PRICING[minimumTier];
|
|
69
|
+
throw new Error(`This feature requires ${minimumTier} tier or higher (${pricing}). ` +
|
|
70
|
+
`You are currently on the ${currentTier} tier. ` +
|
|
71
|
+
`Upgrade at https://skillsmith.app/upgrade?tier=${minimumTier}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=require-tier.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"require-tier.js","sourceRoot":"","sources":["../../../src/utils/require-tier.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAEH,OAAO,EAAE,gBAAgB,EAAE,MAAM,yBAAyB,CAAA;AAG1D;;;GAGG;AACH,MAAM,UAAU,GAAkB,CAAC,WAAW,EAAE,YAAY,EAAE,MAAM,EAAE,YAAY,CAAC,CAAA;AAEnF;;GAEG;AACH,MAAM,YAAY,GAAgC;IAChD,SAAS,EAAE,UAAU;IACrB,UAAU,EAAE,aAAa;IACzB,IAAI,EAAE,gBAAgB;IACtB,UAAU,EAAE,gBAAgB;CAC7B,CAAA;AAED;;;;;;;;;;;;;;;;;;;GAmBG;AACH,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,WAAwB;IACxD,8EAA8E;IAC9E,IAAI,OAAO,CAAC,GAAG,CAAC,+BAA+B,CAAC,KAAK,MAAM,EAAE,CAAC;QAC5D,OAAM;IACR,CAAC;IAED,MAAM,MAAM,GAAG,MAAM,gBAAgB,EAAE,CAAA;IAEvC,wDAAwD;IACxD,gEAAgE;IAChE,MAAM,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC,CAAA;IAC7D,IAAI,MAAM,IAAI,CAAC,MAAM,CAAC,KAAK,EAAE,CAAC;QAC5B,MAAM,IAAI,KAAK,CACb,6BAA6B;YAC3B,0GAA0G,CAC7G,CAAA;IACH,CAAC;IAED,MAAM,WAAW,GAAG,CAAC,MAAM,CAAC,IAAI,IAAI,WAAW,CAAgB,CAAA;IAC/D,MAAM,YAAY,GAAG,UAAU,CAAC,OAAO,CAAC,WAAW,CAAC,CAAA;IACpD,MAAM,aAAa,GAAG,UAAU,CAAC,OAAO,CAAC,WAAW,CAAC,CAAA;IAErD,IAAI,YAAY,GAAG,aAAa,EAAE,CAAC;QACjC,MAAM,OAAO,GAAG,YAAY,CAAC,WAAW,CAAC,CAAA;QACzC,MAAM,IAAI,KAAK,CACb,yBAAyB,WAAW,oBAAoB,OAAO,KAAK;YAClE,4BAA4B,WAAW,SAAS;YAChD,kDAAkD,WAAW,EAAE,CAClE,CAAA;IACH,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared skill name validation utilities.
|
|
3
|
+
*
|
|
4
|
+
* Used by both `skillsmith author init` and `skillsmith create` to enforce
|
|
5
|
+
* a consistent, registry-safe naming convention across all scaffolding paths.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Valid skill names: lowercase letters, digits, and hyphens only.
|
|
9
|
+
* Must start with a lowercase letter.
|
|
10
|
+
* Matches the Skillsmith registry slug format.
|
|
11
|
+
*/
|
|
12
|
+
export declare const VALID_SKILL_NAME_RE: RegExp;
|
|
13
|
+
/**
|
|
14
|
+
* Validate a skill name against the canonical Skillsmith naming convention.
|
|
15
|
+
*
|
|
16
|
+
* @returns `true` if valid, or a string error message if invalid.
|
|
17
|
+
*/
|
|
18
|
+
export declare function validateSkillName(name: string): true | string;
|
|
19
|
+
//# sourceMappingURL=skill-name.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-name.d.ts","sourceRoot":"","sources":["../../../src/utils/skill-name.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;GAIG;AACH,eAAO,MAAM,mBAAmB,QAAsB,CAAA;AAEtD;;;;GAIG;AACH,wBAAgB,iBAAiB,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,GAAG,MAAM,CAM7D"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared skill name validation utilities.
|
|
3
|
+
*
|
|
4
|
+
* Used by both `skillsmith author init` and `skillsmith create` to enforce
|
|
5
|
+
* a consistent, registry-safe naming convention across all scaffolding paths.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Valid skill names: lowercase letters, digits, and hyphens only.
|
|
9
|
+
* Must start with a lowercase letter.
|
|
10
|
+
* Matches the Skillsmith registry slug format.
|
|
11
|
+
*/
|
|
12
|
+
export const VALID_SKILL_NAME_RE = /^[a-z][a-z0-9-]*$/;
|
|
13
|
+
/**
|
|
14
|
+
* Validate a skill name against the canonical Skillsmith naming convention.
|
|
15
|
+
*
|
|
16
|
+
* @returns `true` if valid, or a string error message if invalid.
|
|
17
|
+
*/
|
|
18
|
+
export function validateSkillName(name) {
|
|
19
|
+
if (!name.trim())
|
|
20
|
+
return 'Skill name is required';
|
|
21
|
+
if (!VALID_SKILL_NAME_RE.test(name)) {
|
|
22
|
+
return 'Skill name must start with a lowercase letter and contain only lowercase letters, digits, and hyphens (e.g. my-skill)';
|
|
23
|
+
}
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=skill-name.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skill-name.js","sourceRoot":"","sources":["../../../src/utils/skill-name.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH;;;;GAIG;AACH,MAAM,CAAC,MAAM,mBAAmB,GAAG,mBAAmB,CAAA;AAEtD;;;;GAIG;AACH,MAAM,UAAU,iBAAiB,CAAC,IAAY;IAC5C,IAAI,CAAC,IAAI,CAAC,IAAI,EAAE;QAAE,OAAO,wBAAwB,CAAA;IACjD,IAAI,CAAC,mBAAmB,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QACpC,OAAO,uHAAuH,CAAA;IAChI,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC"}
|
|
@@ -12,14 +12,23 @@ export interface InstalledSkill {
|
|
|
12
12
|
hasUpdates: boolean;
|
|
13
13
|
}
|
|
14
14
|
/**
|
|
15
|
-
* Get skills from a specific directory
|
|
15
|
+
* Get skills from a specific directory.
|
|
16
|
+
*
|
|
17
|
+
* When dbPath is provided, opens the skill_versions table to determine
|
|
18
|
+
* whether a newer content hash has been recorded since the skill was installed.
|
|
19
|
+
* Falls back to hasUpdates: false when the database is unavailable.
|
|
20
|
+
*
|
|
21
|
+
* @param skillsDir Directory to scan for installed skills
|
|
22
|
+
* @param dbPath Optional path to the Skillsmith SQLite database
|
|
16
23
|
*/
|
|
17
|
-
export declare function getSkillsFromDirectory(skillsDir: string): Promise<InstalledSkill[]>;
|
|
24
|
+
export declare function getSkillsFromDirectory(skillsDir: string, dbPath?: string): Promise<InstalledSkill[]>;
|
|
18
25
|
/**
|
|
19
26
|
* Get list of installed skills from both global (~/.claude/skills) and
|
|
20
27
|
* local (.claude/skills) directories.
|
|
21
28
|
*
|
|
22
29
|
* SMI-1630: Local skills take precedence over global skills with the same name.
|
|
30
|
+
*
|
|
31
|
+
* @param dbPath Optional path to the Skillsmith SQLite database for update detection
|
|
23
32
|
*/
|
|
24
|
-
export declare function getInstalledSkills(): Promise<InstalledSkill[]>;
|
|
33
|
+
export declare function getInstalledSkills(dbPath?: string): Promise<InstalledSkill[]>;
|
|
25
34
|
//# sourceMappingURL=skills-directory.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skills-directory.d.ts","sourceRoot":"","sources":["../../../src/utils/skills-directory.ts"],"names":[],"mappings":"AAAA;;;GAGG;
|
|
1
|
+
{"version":3,"file":"skills-directory.d.ts","sourceRoot":"","sources":["../../../src/utils/skills-directory.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAMH,OAAO,EAIL,KAAK,SAAS,EACf,MAAM,kBAAkB,CAAA;AAGzB,MAAM,WAAW,cAAc;IAC7B,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,EAAE,MAAM,GAAG,IAAI,CAAA;IACtB,SAAS,EAAE,SAAS,CAAA;IACpB,WAAW,EAAE,MAAM,CAAA;IACnB,UAAU,EAAE,OAAO,CAAA;CACpB;AAoBD;;;;;;;;;GASG;AACH,wBAAsB,sBAAsB,CAC1C,SAAS,EAAE,MAAM,EACjB,MAAM,CAAC,EAAE,MAAM,GACd,OAAO,CAAC,cAAc,EAAE,CAAC,CAgG3B;AAED;;;;;;;GAOG;AACH,wBAAsB,kBAAkB,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,OAAO,CAAC,cAAc,EAAE,CAAC,CAsBnF"}
|
|
@@ -3,9 +3,11 @@
|
|
|
3
3
|
* from the global and local ~/.claude/skills directories.
|
|
4
4
|
*/
|
|
5
5
|
import { readdir, readFile, stat } from 'fs/promises';
|
|
6
|
+
import { createHash } from 'crypto';
|
|
6
7
|
import { join } from 'path';
|
|
7
8
|
import { homedir } from 'os';
|
|
8
|
-
import { SkillParser } from '@skillsmith/core';
|
|
9
|
+
import { SkillParser, createDatabase, SkillVersionRepository, } from '@skillsmith/core';
|
|
10
|
+
import { DEFAULT_DB_PATH } from '../config.js';
|
|
9
11
|
/**
|
|
10
12
|
* SMI-1630: Search both global and local skill directories
|
|
11
13
|
*
|
|
@@ -23,10 +25,31 @@ function getLocalSkillsDir() {
|
|
|
23
25
|
return join(process.cwd(), '.claude', 'skills');
|
|
24
26
|
}
|
|
25
27
|
/**
|
|
26
|
-
* Get skills from a specific directory
|
|
28
|
+
* Get skills from a specific directory.
|
|
29
|
+
*
|
|
30
|
+
* When dbPath is provided, opens the skill_versions table to determine
|
|
31
|
+
* whether a newer content hash has been recorded since the skill was installed.
|
|
32
|
+
* Falls back to hasUpdates: false when the database is unavailable.
|
|
33
|
+
*
|
|
34
|
+
* @param skillsDir Directory to scan for installed skills
|
|
35
|
+
* @param dbPath Optional path to the Skillsmith SQLite database
|
|
27
36
|
*/
|
|
28
|
-
export async function getSkillsFromDirectory(skillsDir) {
|
|
37
|
+
export async function getSkillsFromDirectory(skillsDir, dbPath) {
|
|
29
38
|
const skills = [];
|
|
39
|
+
// Open the version repository if a db path was provided
|
|
40
|
+
let versionRepo = null;
|
|
41
|
+
let dbConn = null;
|
|
42
|
+
if (dbPath) {
|
|
43
|
+
try {
|
|
44
|
+
dbConn = createDatabase(dbPath);
|
|
45
|
+
versionRepo = new SkillVersionRepository(dbConn);
|
|
46
|
+
}
|
|
47
|
+
catch {
|
|
48
|
+
// DB not available yet — fall back to hasUpdates: false
|
|
49
|
+
versionRepo = null;
|
|
50
|
+
dbConn = null;
|
|
51
|
+
}
|
|
52
|
+
}
|
|
30
53
|
try {
|
|
31
54
|
const entries = await readdir(skillsDir, { withFileTypes: true });
|
|
32
55
|
for (const entry of entries) {
|
|
@@ -38,13 +61,39 @@ export async function getSkillsFromDirectory(skillsDir) {
|
|
|
38
61
|
const content = await readFile(skillMdPath, 'utf-8');
|
|
39
62
|
const parser = new SkillParser();
|
|
40
63
|
const parsed = parser.parse(content);
|
|
64
|
+
// Determine hasUpdates by comparing the current SKILL.md hash to the
|
|
65
|
+
// most-recently recorded hash in skill_versions for this skill id.
|
|
66
|
+
let hasUpdates = false;
|
|
67
|
+
if (versionRepo && parsed) {
|
|
68
|
+
try {
|
|
69
|
+
const parsedAny = parsed;
|
|
70
|
+
const skillId = parsedAny['id'] ?? entry.name;
|
|
71
|
+
const latestVersion = await versionRepo.getLatestVersion(skillId);
|
|
72
|
+
if (latestVersion) {
|
|
73
|
+
const currentHash = createHash('sha256').update(content, 'utf8').digest('hex');
|
|
74
|
+
const storedHash = parsedAny['contentHash'] ??
|
|
75
|
+
parsedAny['originalContentHash'] ??
|
|
76
|
+
'';
|
|
77
|
+
// hasUpdates = latest recorded hash differs from what we have locally
|
|
78
|
+
hasUpdates = storedHash !== '' && latestVersion.content_hash !== storedHash;
|
|
79
|
+
// If we have no stored hash, compare against current content hash
|
|
80
|
+
if (!storedHash) {
|
|
81
|
+
hasUpdates = latestVersion.content_hash !== currentHash;
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
catch {
|
|
86
|
+
// Version check failed — safe to ignore, fall back to false
|
|
87
|
+
hasUpdates = false;
|
|
88
|
+
}
|
|
89
|
+
}
|
|
41
90
|
skills.push({
|
|
42
91
|
name: parsed?.name || entry.name,
|
|
43
92
|
path: skillPath,
|
|
44
93
|
version: parsed?.version || null,
|
|
45
94
|
trustTier: parsed ? parser.inferTrustTier(parsed) : 'unknown',
|
|
46
95
|
installDate: skillMdStat.mtime.toISOString().split('T')[0] || 'Unknown',
|
|
47
|
-
hasUpdates
|
|
96
|
+
hasUpdates,
|
|
48
97
|
});
|
|
49
98
|
}
|
|
50
99
|
catch (error) {
|
|
@@ -73,6 +122,9 @@ export async function getSkillsFromDirectory(skillsDir) {
|
|
|
73
122
|
throw error;
|
|
74
123
|
}
|
|
75
124
|
}
|
|
125
|
+
finally {
|
|
126
|
+
dbConn?.close();
|
|
127
|
+
}
|
|
76
128
|
return skills;
|
|
77
129
|
}
|
|
78
130
|
/**
|
|
@@ -80,12 +132,15 @@ export async function getSkillsFromDirectory(skillsDir) {
|
|
|
80
132
|
* local (.claude/skills) directories.
|
|
81
133
|
*
|
|
82
134
|
* SMI-1630: Local skills take precedence over global skills with the same name.
|
|
135
|
+
*
|
|
136
|
+
* @param dbPath Optional path to the Skillsmith SQLite database for update detection
|
|
83
137
|
*/
|
|
84
|
-
export async function getInstalledSkills() {
|
|
138
|
+
export async function getInstalledSkills(dbPath) {
|
|
139
|
+
const resolvedDbPath = dbPath ?? DEFAULT_DB_PATH;
|
|
85
140
|
// Get skills from both directories
|
|
86
141
|
const [globalSkills, localSkills] = await Promise.all([
|
|
87
|
-
getSkillsFromDirectory(GLOBAL_SKILLS_DIR),
|
|
88
|
-
getSkillsFromDirectory(getLocalSkillsDir()),
|
|
142
|
+
getSkillsFromDirectory(GLOBAL_SKILLS_DIR, resolvedDbPath),
|
|
143
|
+
getSkillsFromDirectory(getLocalSkillsDir(), resolvedDbPath),
|
|
89
144
|
]);
|
|
90
145
|
// Create a map for deduplication, local skills take precedence
|
|
91
146
|
const skillMap = new Map();
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"skills-directory.js","sourceRoot":"","sources":["../../../src/utils/skills-directory.ts"],"names":[],"mappings":"AAAA;;;GAGG;AAEH,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AACrD,OAAO,EAAE,IAAI,EAAE,MAAM,MAAM,CAAA;AAC3B,OAAO,EAAE,OAAO,EAAE,MAAM,IAAI,CAAA;AAC5B,OAAO,
|
|
1
|
+
{"version":3,"file":"skills-directory.js","sourceRoot":"","sources":["../../../src/utils/skills-directory.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"create.test.d.ts","sourceRoot":"","sources":["../../tests/create.test.ts"],"names":[],"mappings":"AAAA;;GAEG"}
|