synskill 0.1.5 → 0.1.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 +69 -69
- package/bin/synskill.js +83 -16
- package/package.json +33 -33
package/README.md
CHANGED
|
@@ -1,69 +1,69 @@
|
|
|
1
|
-
# synskill
|
|
2
|
-
|
|
3
|
-
`synskill` is a public npm CLI that installs skills from a private Git repository you already have access to.
|
|
4
|
-
|
|
5
|
-
## Usage
|
|
6
|
-
|
|
7
|
-
```bash
|
|
8
|
-
npx synskill
|
|
9
|
-
```
|
|
10
|
-
|
|
11
|
-
## Install A Skill
|
|
12
|
-
|
|
13
|
-
Install one skill directly into the current repo:
|
|
14
|
-
|
|
15
|
-
```bash
|
|
16
|
-
npx synskill <skill-name> --project
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
Examples:
|
|
20
|
-
|
|
21
|
-
```bash
|
|
22
|
-
npx synskill pr-review --project
|
|
23
|
-
npx synskill bootstrap-device-repo --project
|
|
24
|
-
npx synskill skill-creator --global
|
|
25
|
-
```
|
|
26
|
-
|
|
27
|
-
Omit `--project` for a global install. Add `--copy` if you want copies instead of symlinks.
|
|
28
|
-
|
|
29
|
-
## Requirements
|
|
30
|
-
|
|
31
|
-
- Node.js 18 or newer
|
|
32
|
-
- Git available in `PATH`
|
|
33
|
-
- Access to the private repository that contains your skills
|
|
34
|
-
|
|
35
|
-
## Common Commands
|
|
36
|
-
|
|
37
|
-
```bash
|
|
38
|
-
npx synskill
|
|
39
|
-
npx synskill pr-review --project
|
|
40
|
-
npx synskill install pr-review --project
|
|
41
|
-
npx synskill add pr-review --project
|
|
42
|
-
npx synskill list
|
|
43
|
-
npx synskill skill-creator --global
|
|
44
|
-
npx synskill install --skills my-skill --project
|
|
45
|
-
npx synskill install --skills my-skill --project --copy
|
|
46
|
-
npx synskill update
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
## Private Repo Override
|
|
50
|
-
|
|
51
|
-
```bash
|
|
52
|
-
npx synskill --repo-url <git-url>
|
|
53
|
-
```
|
|
54
|
-
|
|
55
|
-
or:
|
|
56
|
-
|
|
57
|
-
```bash
|
|
58
|
-
SKILLS_REPO_URL=<git-url> npx synskill
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
## Notes
|
|
62
|
-
|
|
63
|
-
- The CLI keeps a local cache of the private skills repository to make repeated runs fast.
|
|
64
|
-
- You can install a specific skill directly with `npx synskill install <skill-name>` or `npx synskill <skill-name>`.
|
|
65
|
-
- `skill-creator` is fetched on demand from `https://github.com/anthropics/skills/tree/main/skills/skill-creator` so it stays on the upstream latest version without being stored in this repo.
|
|
66
|
-
- `skill-creator` is explicit-install only and does not appear in the default interactive skills list.
|
|
67
|
-
- By default it symlinks each selected target directly to the source skill directory; use `--copy` to write independent copies instead.
|
|
68
|
-
- `update` forces a cache refresh.
|
|
69
|
-
- `--no-pull` uses the existing cache without refreshing it.
|
|
1
|
+
# synskill
|
|
2
|
+
|
|
3
|
+
`synskill` is a public npm CLI that installs skills from a private Git repository you already have access to.
|
|
4
|
+
|
|
5
|
+
## Usage
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npx synskill
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
## Install A Skill
|
|
12
|
+
|
|
13
|
+
Install one skill directly into the current repo:
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npx synskill <skill-name> --project
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
Examples:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
npx synskill pr-review --project
|
|
23
|
+
npx synskill bootstrap-device-repo --project
|
|
24
|
+
npx synskill skill-creator --global
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
Omit `--project` for a global install. Add `--copy` if you want copies instead of symlinks.
|
|
28
|
+
|
|
29
|
+
## Requirements
|
|
30
|
+
|
|
31
|
+
- Node.js 18 or newer
|
|
32
|
+
- Git available in `PATH`
|
|
33
|
+
- Access to the private repository that contains your skills
|
|
34
|
+
|
|
35
|
+
## Common Commands
|
|
36
|
+
|
|
37
|
+
```bash
|
|
38
|
+
npx synskill
|
|
39
|
+
npx synskill pr-review --project
|
|
40
|
+
npx synskill install pr-review --project
|
|
41
|
+
npx synskill add pr-review --project
|
|
42
|
+
npx synskill list
|
|
43
|
+
npx synskill skill-creator --global
|
|
44
|
+
npx synskill install --skills my-skill --project
|
|
45
|
+
npx synskill install --skills my-skill --project --copy
|
|
46
|
+
npx synskill update
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
## Private Repo Override
|
|
50
|
+
|
|
51
|
+
```bash
|
|
52
|
+
npx synskill --repo-url <git-url>
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
or:
|
|
56
|
+
|
|
57
|
+
```bash
|
|
58
|
+
SKILLS_REPO_URL=<git-url> npx synskill
|
|
59
|
+
```
|
|
60
|
+
|
|
61
|
+
## Notes
|
|
62
|
+
|
|
63
|
+
- The CLI keeps a local cache of the private skills repository to make repeated runs fast.
|
|
64
|
+
- You can install a specific skill directly with `npx synskill install <skill-name>` or `npx synskill <skill-name>`.
|
|
65
|
+
- `skill-creator` is fetched on demand from `https://github.com/anthropics/skills/tree/main/skills/skill-creator` so it stays on the upstream latest version without being stored in this repo.
|
|
66
|
+
- `skill-creator` is explicit-install only and does not appear in the default interactive skills list.
|
|
67
|
+
- By default it symlinks each selected target directly to the source skill directory; use `--copy` to write independent copies instead.
|
|
68
|
+
- `update` forces a cache refresh.
|
|
69
|
+
- `--no-pull` uses the existing cache without refreshing it.
|
package/bin/synskill.js
CHANGED
|
@@ -180,6 +180,7 @@ var require_constants = __commonJS({
|
|
|
180
180
|
folder: ".claude"
|
|
181
181
|
}
|
|
182
182
|
];
|
|
183
|
+
var DEFAULT_TARGET_KEYS2 = INSTALL_TARGETS2.map((target) => target.key);
|
|
183
184
|
function userHome() {
|
|
184
185
|
return process.env.USERPROFILE || os.homedir();
|
|
185
186
|
}
|
|
@@ -203,6 +204,7 @@ var require_constants = __commonJS({
|
|
|
203
204
|
CLI_NAME: CLI_NAME2,
|
|
204
205
|
DEFAULT_BRANCH: DEFAULT_BRANCH2,
|
|
205
206
|
DEFAULT_REPO_URL: DEFAULT_REPO_URL2,
|
|
207
|
+
DEFAULT_TARGET_KEYS: DEFAULT_TARGET_KEYS2,
|
|
206
208
|
INSTALL_TARGETS: INSTALL_TARGETS2,
|
|
207
209
|
LEGACY_CACHE_DIR_NAMES,
|
|
208
210
|
LEGACY_CACHE_METADATA_NAMES,
|
|
@@ -419,6 +421,30 @@ var require_git = __commonJS({
|
|
|
419
421
|
});
|
|
420
422
|
}
|
|
421
423
|
}
|
|
424
|
+
function sshToHttpsUrl(url) {
|
|
425
|
+
if (!url || typeof url !== "string") {
|
|
426
|
+
return null;
|
|
427
|
+
}
|
|
428
|
+
const scpMatch = url.match(/^git@([^:]+):(.+)$/);
|
|
429
|
+
if (scpMatch) {
|
|
430
|
+
const host = scpMatch[1];
|
|
431
|
+
const repoPath = scpMatch[2].replace(/\.git$/, "");
|
|
432
|
+
return `https://${host}/${repoPath}.git`;
|
|
433
|
+
}
|
|
434
|
+
const sshMatch = url.match(/^ssh:\/\/git@([^/]+)\/(.+)$/);
|
|
435
|
+
if (sshMatch) {
|
|
436
|
+
const host = sshMatch[1];
|
|
437
|
+
const repoPath = sshMatch[2].replace(/\.git$/, "");
|
|
438
|
+
return `https://${host}/${repoPath}.git`;
|
|
439
|
+
}
|
|
440
|
+
return null;
|
|
441
|
+
}
|
|
442
|
+
function isSshUrl(url) {
|
|
443
|
+
if (!url || typeof url !== "string") {
|
|
444
|
+
return false;
|
|
445
|
+
}
|
|
446
|
+
return url.startsWith("git@") || url.startsWith("ssh://");
|
|
447
|
+
}
|
|
422
448
|
function formatGitAccessError2(repoUrl, error) {
|
|
423
449
|
const repoLabel = repoUrl && repoUrl !== DEFAULT_REPO_URL2 ? repoUrl : "the private repository";
|
|
424
450
|
if (!(error instanceof GitCommandError)) {
|
|
@@ -451,7 +477,9 @@ ${error.message}`;
|
|
|
451
477
|
GitCommandError,
|
|
452
478
|
formatGitAccessError: formatGitAccessError2,
|
|
453
479
|
getInheritedGitConfigArgs,
|
|
480
|
+
isSshUrl,
|
|
454
481
|
runGit,
|
|
482
|
+
sshToHttpsUrl,
|
|
455
483
|
syncInheritedGitConfig
|
|
456
484
|
};
|
|
457
485
|
}
|
|
@@ -1443,7 +1471,7 @@ var require_search_multiselect = __commonJS({
|
|
|
1443
1471
|
var require_prompts = __commonJS({
|
|
1444
1472
|
"src/prompts.js"(exports2, module2) {
|
|
1445
1473
|
"use strict";
|
|
1446
|
-
var { INSTALL_TARGETS: INSTALL_TARGETS2 } = require_constants();
|
|
1474
|
+
var { DEFAULT_TARGET_KEYS: DEFAULT_TARGET_KEYS2, INSTALL_TARGETS: INSTALL_TARGETS2 } = require_constants();
|
|
1447
1475
|
var { splitRepositoryField } = require_skill_catalog();
|
|
1448
1476
|
var {
|
|
1449
1477
|
cancelSymbol: cancelSymbol2,
|
|
@@ -1476,7 +1504,7 @@ var require_prompts = __commonJS({
|
|
|
1476
1504
|
label: target.name,
|
|
1477
1505
|
hint: `${target.folder}/skills`
|
|
1478
1506
|
})),
|
|
1479
|
-
initialValues:
|
|
1507
|
+
initialValues: [...DEFAULT_TARGET_KEYS2],
|
|
1480
1508
|
required: true,
|
|
1481
1509
|
instructions: "Use arrows to move, space to toggle, a for all, then press enter to confirm."
|
|
1482
1510
|
});
|
|
@@ -1618,7 +1646,7 @@ var require_repo_cache = __commonJS({
|
|
|
1618
1646
|
LEGACY_REPO_PACKAGE_NAMES,
|
|
1619
1647
|
PRIVATE_REPO_ENV_VAR: PRIVATE_REPO_ENV_VAR2
|
|
1620
1648
|
} = require_constants();
|
|
1621
|
-
var { GitCommandError, formatGitAccessError: formatGitAccessError2, runGit, syncInheritedGitConfig } = require_git();
|
|
1649
|
+
var { GitCommandError, formatGitAccessError: formatGitAccessError2, runGit, syncInheritedGitConfig, isSshUrl, sshToHttpsUrl } = require_git();
|
|
1622
1650
|
function getConfiguredRepoUrl2(options = {}, env = process.env) {
|
|
1623
1651
|
return options.repoUrl || env[PRIVATE_REPO_ENV_VAR2] || env[LEGACY_PRIVATE_REPO_ENV_VAR] || DEFAULT_REPO_URL2;
|
|
1624
1652
|
}
|
|
@@ -1792,27 +1820,65 @@ Using the existing local cache at ${cacheDir}.`
|
|
|
1792
1820
|
};
|
|
1793
1821
|
}
|
|
1794
1822
|
function cloneRepo(cacheDir, repoUrl, branch, gitConfigContextCwd) {
|
|
1795
|
-
|
|
1796
|
-
repoUrl,
|
|
1797
|
-
|
|
1798
|
-
|
|
1823
|
+
try {
|
|
1824
|
+
runGit(["clone", "--depth", "1", "--branch", branch, repoUrl, cacheDir], {
|
|
1825
|
+
repoUrl,
|
|
1826
|
+
gitConfigContextCwd
|
|
1827
|
+
});
|
|
1828
|
+
} catch (error) {
|
|
1829
|
+
if (error instanceof GitCommandError && error.isAuthError && isSshUrl(repoUrl)) {
|
|
1830
|
+
const httpsUrl = sshToHttpsUrl(repoUrl);
|
|
1831
|
+
if (httpsUrl) {
|
|
1832
|
+
runGit(["clone", "--depth", "1", "--branch", branch, httpsUrl, cacheDir], {
|
|
1833
|
+
repoUrl: httpsUrl,
|
|
1834
|
+
gitConfigContextCwd
|
|
1835
|
+
});
|
|
1836
|
+
syncInheritedGitConfig(cacheDir, gitConfigContextCwd);
|
|
1837
|
+
return;
|
|
1838
|
+
}
|
|
1839
|
+
}
|
|
1840
|
+
throw error;
|
|
1841
|
+
}
|
|
1799
1842
|
syncInheritedGitConfig(cacheDir, gitConfigContextCwd);
|
|
1800
1843
|
}
|
|
1801
1844
|
function refreshRepo(cacheDir, repoUrl, branch, gitConfigContextCwd) {
|
|
1802
1845
|
syncInheritedGitConfig(cacheDir, gitConfigContextCwd);
|
|
1803
|
-
|
|
1804
|
-
|
|
1805
|
-
|
|
1806
|
-
|
|
1807
|
-
|
|
1846
|
+
const currentRemote = readOriginUrl(cacheDir);
|
|
1847
|
+
const effectiveUrl = currentRemote || repoUrl;
|
|
1848
|
+
try {
|
|
1849
|
+
runGit(["fetch", "--depth", "1", "origin", branch], {
|
|
1850
|
+
cwd: cacheDir,
|
|
1851
|
+
repoUrl: effectiveUrl,
|
|
1852
|
+
gitConfigContextCwd
|
|
1853
|
+
});
|
|
1854
|
+
} catch (error) {
|
|
1855
|
+
if (error instanceof GitCommandError && error.isAuthError && isSshUrl(effectiveUrl)) {
|
|
1856
|
+
const httpsUrl = sshToHttpsUrl(effectiveUrl);
|
|
1857
|
+
if (httpsUrl) {
|
|
1858
|
+
try {
|
|
1859
|
+
runGit(["remote", "set-url", "origin", httpsUrl], { cwd: cacheDir });
|
|
1860
|
+
} catch {
|
|
1861
|
+
}
|
|
1862
|
+
runGit(["fetch", "--depth", "1", "origin", branch], {
|
|
1863
|
+
cwd: cacheDir,
|
|
1864
|
+
repoUrl: httpsUrl,
|
|
1865
|
+
gitConfigContextCwd
|
|
1866
|
+
});
|
|
1867
|
+
} else {
|
|
1868
|
+
throw error;
|
|
1869
|
+
}
|
|
1870
|
+
} else {
|
|
1871
|
+
throw error;
|
|
1872
|
+
}
|
|
1873
|
+
}
|
|
1808
1874
|
runGit(["reset", "--hard", "FETCH_HEAD"], {
|
|
1809
1875
|
cwd: cacheDir,
|
|
1810
|
-
repoUrl,
|
|
1876
|
+
repoUrl: effectiveUrl,
|
|
1811
1877
|
gitConfigContextCwd
|
|
1812
1878
|
});
|
|
1813
1879
|
runGit(["clean", "-fd", "-e", path2.basename(getCacheMetadataPath(cacheDir))], {
|
|
1814
1880
|
cwd: cacheDir,
|
|
1815
|
-
repoUrl,
|
|
1881
|
+
repoUrl: effectiveUrl,
|
|
1816
1882
|
gitConfigContextCwd
|
|
1817
1883
|
});
|
|
1818
1884
|
}
|
|
@@ -1882,6 +1948,7 @@ var {
|
|
|
1882
1948
|
CLI_NAME,
|
|
1883
1949
|
DEFAULT_BRANCH,
|
|
1884
1950
|
DEFAULT_REPO_URL,
|
|
1951
|
+
DEFAULT_TARGET_KEYS,
|
|
1885
1952
|
INSTALL_TARGETS,
|
|
1886
1953
|
PRIVATE_REPO_ENV_VAR
|
|
1887
1954
|
} = require_constants();
|
|
@@ -1922,7 +1989,7 @@ function usage() {
|
|
|
1922
1989
|
console.log(" --copy Copy files instead of symlinking targets to the source skill directory");
|
|
1923
1990
|
console.log(" --force Overwrite existing skills");
|
|
1924
1991
|
console.log(" --no-pull Use the local cache as-is");
|
|
1925
|
-
console.log(" --yes, -y Skip prompts (defaults to all skills + global +
|
|
1992
|
+
console.log(" --yes, -y Skip prompts (defaults to all skills + global + all install targets)");
|
|
1926
1993
|
console.log(" --filter <text> Filter skills by name, description, or repository");
|
|
1927
1994
|
console.log(" --details Show full descriptions");
|
|
1928
1995
|
console.log(" --repo-url <git-url> Override the private skills repo URL");
|
|
@@ -2125,7 +2192,7 @@ async function resolveTargetKeys(options, interactive) {
|
|
|
2125
2192
|
return [];
|
|
2126
2193
|
}
|
|
2127
2194
|
if (options.yes || !interactive) {
|
|
2128
|
-
return [
|
|
2195
|
+
return [...DEFAULT_TARGET_KEYS];
|
|
2129
2196
|
}
|
|
2130
2197
|
const selected = await promptForTargets();
|
|
2131
2198
|
if (selected === cancelSymbol) {
|
package/package.json
CHANGED
|
@@ -1,33 +1,33 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "synskill",
|
|
3
|
-
"version": "0.1.
|
|
4
|
-
"private": false,
|
|
5
|
-
"description": "CLI installer for private agent skills.",
|
|
6
|
-
"license": "UNLICENSED",
|
|
7
|
-
"files": [
|
|
8
|
-
"bin",
|
|
9
|
-
"README.md"
|
|
10
|
-
],
|
|
11
|
-
"scripts": {
|
|
12
|
-
"build": "node scripts/bundle-cli.js",
|
|
13
|
-
"synskill": "node src/synskill.js",
|
|
14
|
-
"test": "node
|
|
15
|
-
"prepack": "node scripts/manage-pack-readme.js prepack",
|
|
16
|
-
"postpack": "node scripts/manage-pack-readme.js postpack",
|
|
17
|
-
"prepublishOnly": "npm run build && npm test"
|
|
18
|
-
},
|
|
19
|
-
"bin": {
|
|
20
|
-
"synskill": "bin/synskill.js"
|
|
21
|
-
},
|
|
22
|
-
"engines": {
|
|
23
|
-
"node": ">=18"
|
|
24
|
-
},
|
|
25
|
-
"devDependencies": {
|
|
26
|
-
"@clack/prompts": "^0.11.0",
|
|
27
|
-
"esbuild": "^0.20.2",
|
|
28
|
-
"picocolors": "^1.1.1"
|
|
29
|
-
},
|
|
30
|
-
"dependencies": {
|
|
31
|
-
"markdown-it": "^14.1.1"
|
|
32
|
-
}
|
|
33
|
-
}
|
|
1
|
+
{
|
|
2
|
+
"name": "synskill",
|
|
3
|
+
"version": "0.1.7",
|
|
4
|
+
"private": false,
|
|
5
|
+
"description": "CLI installer for private agent skills.",
|
|
6
|
+
"license": "UNLICENSED",
|
|
7
|
+
"files": [
|
|
8
|
+
"bin",
|
|
9
|
+
"README.md"
|
|
10
|
+
],
|
|
11
|
+
"scripts": {
|
|
12
|
+
"build": "node scripts/bundle-cli.js",
|
|
13
|
+
"synskill": "node src/synskill.js",
|
|
14
|
+
"test": "node scripts/run-tests.js",
|
|
15
|
+
"prepack": "node scripts/manage-pack-readme.js prepack",
|
|
16
|
+
"postpack": "node scripts/manage-pack-readme.js postpack",
|
|
17
|
+
"prepublishOnly": "npm run build && npm test"
|
|
18
|
+
},
|
|
19
|
+
"bin": {
|
|
20
|
+
"synskill": "bin/synskill.js"
|
|
21
|
+
},
|
|
22
|
+
"engines": {
|
|
23
|
+
"node": ">=18"
|
|
24
|
+
},
|
|
25
|
+
"devDependencies": {
|
|
26
|
+
"@clack/prompts": "^0.11.0",
|
|
27
|
+
"esbuild": "^0.20.2",
|
|
28
|
+
"picocolors": "^1.1.1"
|
|
29
|
+
},
|
|
30
|
+
"dependencies": {
|
|
31
|
+
"markdown-it": "^14.1.1"
|
|
32
|
+
}
|
|
33
|
+
}
|