@newlandnpt/pep-cli 0.3.1 → 0.4.1
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 +58 -0
- package/dist/pep.cjs +153 -55
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -83,6 +83,64 @@ departments to use now.
|
|
|
83
83
|
back to `production` and publish immediately once that endpoint is live**: the issuer is baked in
|
|
84
84
|
at build time, so releases already out in the wild cannot be repointed.
|
|
85
85
|
|
|
86
|
+
## Skills
|
|
87
|
+
|
|
88
|
+
```powershell
|
|
89
|
+
pep skills add https://git.newlandpayment.com/group/sub/project # or group/sub/project[@ref]
|
|
90
|
+
pep skills list
|
|
91
|
+
pep skills update # all of them
|
|
92
|
+
pep skills update group/sub/project # just this one
|
|
93
|
+
pep skills add group/sub/project -p # into THIS project
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
PEP fetches the repository with its own read-only service account, so no GitLab credential ever
|
|
97
|
+
reaches the machine. Only repositories on the platform's own GitLab host are accepted. One
|
|
98
|
+
repository may hold several skills: every directory containing a `SKILL.md` becomes one, and
|
|
99
|
+
`update` reports which of them actually changed rather than just that the repository moved.
|
|
100
|
+
|
|
101
|
+
### Where skills are installed
|
|
102
|
+
|
|
103
|
+
| Scope | Flag | Canonical copy | Linked into |
|
|
104
|
+
| ----------- | ----------- | ------------------------- | -------------------------- |
|
|
105
|
+
| **Personal**| (default) | `~/.agents/skills/` | `~/.claude/skills/` |
|
|
106
|
+
| **Project** | `-p`, `--project` | `./.agents/skills/` | `./.claude/skills/` |
|
|
107
|
+
| **Raw** | `--dir <p>` | `<p>/` | nothing — linking skipped |
|
|
108
|
+
|
|
109
|
+
`~/.agents/skills` is the cross-agent convention that Codex, Cursor, Amp and ~20 others read
|
|
110
|
+
directly; Claude Code keeps its own directory, so each skill is also linked there — one copy on
|
|
111
|
+
disk, updated in one place. The project paths are the same two names rooted at the current
|
|
112
|
+
directory, matching what `npx skills` installs at project scope.
|
|
113
|
+
|
|
114
|
+
Personal is the default because the project directories get committed: whether a synced skill
|
|
115
|
+
counts as a change, and whether to gitignore it, is a question every repository would otherwise
|
|
116
|
+
have to answer. Use `-p` when the skills genuinely belong to one repository.
|
|
117
|
+
|
|
118
|
+
**The location is remembered per repository.** `pep skills update` refreshes each repository where
|
|
119
|
+
it already lives, and never moves anything.
|
|
120
|
+
|
|
121
|
+
On `update`, `-p` and `--dir` **narrow the run** rather than relocate — the same meaning they have
|
|
122
|
+
in `npx skills`:
|
|
123
|
+
|
|
124
|
+
```powershell
|
|
125
|
+
pep skills update # every repository, each where it lives
|
|
126
|
+
pep skills update -p # only the ones installed in this project
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
If the current project has none, `update -p` says so and does nothing. **To move a repository, add
|
|
130
|
+
it again with the new flag** — `add` is where the location is decided, and the copy in the old
|
|
131
|
+
location is then removed:
|
|
132
|
+
|
|
133
|
+
```powershell
|
|
134
|
+
pep skills add group/sub/project -p # move it into this project
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
`pep skills list` prints each repository with the directory it lives in, which is what `-p` matches
|
|
138
|
+
against.
|
|
139
|
+
|
|
140
|
+
Deleting a skill folder by hand is fine — `pep skills update` notices it is missing and writes it
|
|
141
|
+
again. It checks the disk, not just its own ledger, so it cannot report "already up to date" about
|
|
142
|
+
files that are no longer there.
|
|
143
|
+
|
|
86
144
|
`pep auth token` writes only the access token to stdout, so agents can use it without parsing status
|
|
87
145
|
text. Refresh occurs automatically shortly before expiry and the rotated refresh token replaces the old
|
|
88
146
|
credential atomically.
|
package/dist/pep.cjs
CHANGED
|
@@ -51,6 +51,15 @@ function defaultSkillsDirectory() {
|
|
|
51
51
|
function claudeSkillsDirectory() {
|
|
52
52
|
return (0, import_node_path.join)((0, import_node_os.homedir)(), ".claude", "skills");
|
|
53
53
|
}
|
|
54
|
+
function userSkillsTarget() {
|
|
55
|
+
return { directory: defaultSkillsDirectory(), linkInto: claudeSkillsDirectory() };
|
|
56
|
+
}
|
|
57
|
+
function projectSkillsTarget(cwd = process.cwd()) {
|
|
58
|
+
return {
|
|
59
|
+
directory: (0, import_node_path.join)(cwd, ".agents", "skills"),
|
|
60
|
+
linkInto: (0, import_node_path.join)(cwd, ".claude", "skills")
|
|
61
|
+
};
|
|
62
|
+
}
|
|
54
63
|
function isCliConfig(value) {
|
|
55
64
|
if (typeof value !== "object" || value === null) return false;
|
|
56
65
|
const candidate = value;
|
|
@@ -82,6 +91,16 @@ function fileConfigStore(path = configPath()) {
|
|
|
82
91
|
};
|
|
83
92
|
}
|
|
84
93
|
function isSkillsState(value) {
|
|
94
|
+
if (typeof value !== "object" || value === null) return false;
|
|
95
|
+
const candidate = value;
|
|
96
|
+
if (candidate.version !== 4) return false;
|
|
97
|
+
return isPackageMap(candidate.packages, (skills, pkg) => {
|
|
98
|
+
if (typeof pkg.directory !== "string") return false;
|
|
99
|
+
if (pkg.linkedInto !== void 0 && typeof pkg.linkedInto !== "string") return false;
|
|
100
|
+
return isStringMap(skills);
|
|
101
|
+
});
|
|
102
|
+
}
|
|
103
|
+
function isSkillsStateV3(value) {
|
|
85
104
|
if (typeof value !== "object" || value === null) return false;
|
|
86
105
|
const candidate = value;
|
|
87
106
|
if (candidate.version !== 3) return false;
|
|
@@ -110,7 +129,7 @@ function isPackageMap(value, skillsOk) {
|
|
|
110
129
|
return Object.values(value).every((one) => {
|
|
111
130
|
if (typeof one !== "object" || one === null || Array.isArray(one)) return false;
|
|
112
131
|
const pkg = one;
|
|
113
|
-
return skillsOk(pkg.skills) && (pkg.commit === void 0 || typeof pkg.commit === "string");
|
|
132
|
+
return skillsOk(pkg.skills, pkg) && (pkg.commit === void 0 || typeof pkg.commit === "string");
|
|
114
133
|
});
|
|
115
134
|
}
|
|
116
135
|
function isStringMap(value) {
|
|
@@ -118,29 +137,34 @@ function isStringMap(value) {
|
|
|
118
137
|
return Object.values(value).every((one) => typeof one === "string");
|
|
119
138
|
}
|
|
120
139
|
function migrateSkillsState(old) {
|
|
121
|
-
const
|
|
122
|
-
version: 3,
|
|
140
|
+
const where = {
|
|
123
141
|
directory: old.directory,
|
|
124
142
|
...old.linkedInto !== void 0 ? { linkedInto: old.linkedInto } : {}
|
|
125
143
|
};
|
|
126
144
|
const unknownHashes = (names) => Object.fromEntries(names.map((name) => [name, ""]));
|
|
127
145
|
if (old.version === 1) {
|
|
128
146
|
return {
|
|
129
|
-
|
|
147
|
+
version: 4,
|
|
130
148
|
packages: {
|
|
131
149
|
[LEGACY_PACKAGE]: {
|
|
132
150
|
...old.commit !== void 0 ? { commit: old.commit } : {},
|
|
151
|
+
...where,
|
|
133
152
|
skills: unknownHashes(old.skills)
|
|
134
153
|
}
|
|
135
154
|
}
|
|
136
155
|
};
|
|
137
156
|
}
|
|
138
157
|
return {
|
|
139
|
-
|
|
158
|
+
version: 4,
|
|
140
159
|
packages: Object.fromEntries(
|
|
141
160
|
Object.entries(old.packages).map(([source, pkg]) => [
|
|
142
161
|
source,
|
|
143
|
-
{
|
|
162
|
+
{
|
|
163
|
+
...pkg.commit !== void 0 ? { commit: pkg.commit } : {},
|
|
164
|
+
...where,
|
|
165
|
+
// v2 的 `skills` 是名字数组(哈希未知),v3 的已经是「名字 → 真哈希」。
|
|
166
|
+
skills: Array.isArray(pkg.skills) ? unknownHashes(pkg.skills) : pkg.skills
|
|
167
|
+
}
|
|
144
168
|
])
|
|
145
169
|
)
|
|
146
170
|
};
|
|
@@ -151,7 +175,8 @@ function fileSkillsStateStore(path = skillsStatePath()) {
|
|
|
151
175
|
try {
|
|
152
176
|
const parsed = JSON.parse(await (0, import_promises.readFile)(path, "utf8"));
|
|
153
177
|
if (isSkillsState(parsed)) return parsed;
|
|
154
|
-
if (
|
|
178
|
+
if (isSkillsStateV3(parsed) || isSkillsStateV2(parsed) || isSkillsStateV1(parsed))
|
|
179
|
+
return migrateSkillsState(parsed);
|
|
155
180
|
return null;
|
|
156
181
|
} catch (error) {
|
|
157
182
|
if (error.code === "ENOENT") return null;
|
|
@@ -1170,6 +1195,15 @@ function hashSkill(files) {
|
|
|
1170
1195
|
}
|
|
1171
1196
|
return hash.digest("hex").slice(0, 32);
|
|
1172
1197
|
}
|
|
1198
|
+
async function allPresent(directory, skills, linkedInto) {
|
|
1199
|
+
for (const skill of skills) {
|
|
1200
|
+
if (!await (0, import_promises4.stat)((0, import_node_path4.join)(directory, skill)).catch(() => null)) return false;
|
|
1201
|
+
if (linkedInto !== void 0 && !await (0, import_promises4.stat)((0, import_node_path4.join)(linkedInto, skill)).catch(() => null)) {
|
|
1202
|
+
return false;
|
|
1203
|
+
}
|
|
1204
|
+
}
|
|
1205
|
+
return true;
|
|
1206
|
+
}
|
|
1173
1207
|
async function updateSkills(dependencies) {
|
|
1174
1208
|
const doFetch = dependencies.fetch ?? globalThis.fetch;
|
|
1175
1209
|
const name = dependencies.source;
|
|
@@ -1185,7 +1219,9 @@ async function updateSkills(dependencies) {
|
|
|
1185
1219
|
const commit = response.headers.get("x-skills-commit") ?? void 0;
|
|
1186
1220
|
const state = await dependencies.stateStore.read();
|
|
1187
1221
|
const previous = state?.packages[name];
|
|
1188
|
-
|
|
1222
|
+
const sameTarget = previous?.directory === dependencies.directory && previous?.linkedInto === dependencies.linkInto;
|
|
1223
|
+
const intact = sameTarget && previous !== void 0 && await allPresent(previous.directory, Object.keys(previous.skills), previous.linkedInto);
|
|
1224
|
+
if (commit !== void 0 && commit === previous?.commit && intact) {
|
|
1189
1225
|
await response.body?.cancel();
|
|
1190
1226
|
return { status: "unchanged", name, commit };
|
|
1191
1227
|
}
|
|
@@ -1208,6 +1244,16 @@ async function updateSkills(dependencies) {
|
|
|
1208
1244
|
if (before !== void 0 && before !== "" && before === hash) unchanged.push(skill);
|
|
1209
1245
|
else updated.push(skill);
|
|
1210
1246
|
}
|
|
1247
|
+
const removed = Object.keys(previous?.skills ?? {}).filter((skill) => !skills.includes(skill));
|
|
1248
|
+
if (previous !== void 0) {
|
|
1249
|
+
const stale = sameTarget ? removed : Object.keys(previous.skills);
|
|
1250
|
+
for (const skill of stale) {
|
|
1251
|
+
await (0, import_promises4.rm)((0, import_node_path4.join)(previous.directory, skill), { recursive: true, force: true });
|
|
1252
|
+
if (previous.linkedInto !== void 0) {
|
|
1253
|
+
await (0, import_promises4.rm)((0, import_node_path4.join)(previous.linkedInto, skill), { recursive: true, force: true });
|
|
1254
|
+
}
|
|
1255
|
+
}
|
|
1256
|
+
}
|
|
1211
1257
|
for (const skill of skills) {
|
|
1212
1258
|
await (0, import_promises4.rm)((0, import_node_path4.join)(dependencies.directory, skill), { recursive: true, force: true });
|
|
1213
1259
|
}
|
|
@@ -1226,24 +1272,18 @@ async function updateSkills(dependencies) {
|
|
|
1226
1272
|
if (how === "copied") copiedCount += 1;
|
|
1227
1273
|
}
|
|
1228
1274
|
}
|
|
1229
|
-
const removed = Object.keys(previous?.skills ?? {}).filter((skill) => !skills.includes(skill));
|
|
1230
|
-
for (const skill of removed) {
|
|
1231
|
-
await (0, import_promises4.rm)((0, import_node_path4.join)(state?.directory ?? dependencies.directory, skill), {
|
|
1232
|
-
recursive: true,
|
|
1233
|
-
force: true
|
|
1234
|
-
});
|
|
1235
|
-
if (state?.linkedInto !== void 0) {
|
|
1236
|
-
await (0, import_promises4.rm)((0, import_node_path4.join)(state.linkedInto, skill), { recursive: true, force: true });
|
|
1237
|
-
}
|
|
1238
|
-
}
|
|
1239
1275
|
await dependencies.stateStore.write({
|
|
1240
|
-
version:
|
|
1241
|
-
directory: dependencies.directory,
|
|
1242
|
-
...dependencies.linkInto !== void 0 ? { linkedInto: dependencies.linkInto } : {},
|
|
1276
|
+
version: 4,
|
|
1243
1277
|
packages: {
|
|
1244
1278
|
// 别的包的账原样留着 —— 装 B 不该把 A 的记录抹掉,那会让 A 铺的目录从此没人清理。
|
|
1279
|
+
// v4 起每个包各记各的落点,所以这一份合并不会再把别人的落点带歪。
|
|
1245
1280
|
...state?.packages ?? {},
|
|
1246
|
-
[name]: {
|
|
1281
|
+
[name]: {
|
|
1282
|
+
...commit ? { commit } : {},
|
|
1283
|
+
directory: dependencies.directory,
|
|
1284
|
+
...dependencies.linkInto !== void 0 ? { linkedInto: dependencies.linkInto } : {},
|
|
1285
|
+
skills: hashes
|
|
1286
|
+
}
|
|
1247
1287
|
}
|
|
1248
1288
|
});
|
|
1249
1289
|
return {
|
|
@@ -1260,13 +1300,9 @@ async function updateSkills(dependencies) {
|
|
|
1260
1300
|
...commit ? { commit } : {}
|
|
1261
1301
|
};
|
|
1262
1302
|
}
|
|
1263
|
-
async function installedPackages(store) {
|
|
1264
|
-
const state = await store.read();
|
|
1265
|
-
return Object.keys(state?.packages ?? {}).sort();
|
|
1266
|
-
}
|
|
1267
1303
|
|
|
1268
1304
|
// src/cli.ts
|
|
1269
|
-
var VERSION = "0.
|
|
1305
|
+
var VERSION = false ? "0.0.0-dev" : "0.4.1";
|
|
1270
1306
|
function usage() {
|
|
1271
1307
|
return `PEP CLI ${VERSION}
|
|
1272
1308
|
|
|
@@ -1276,8 +1312,8 @@ Usage:
|
|
|
1276
1312
|
pep auth token
|
|
1277
1313
|
pep auth logout
|
|
1278
1314
|
pep skills list
|
|
1279
|
-
pep skills add <repo-url | group/project[@ref]> [--dir <path>]
|
|
1280
|
-
pep skills update [<repo>...] [--dir <path>]
|
|
1315
|
+
pep skills add <repo-url | group/project[@ref]> [-p | --dir <path>]
|
|
1316
|
+
pep skills update [<repo>...] [-p | --dir <path>]
|
|
1281
1317
|
pep docs list [--docs-url <url>]
|
|
1282
1318
|
pep docs get <path> [--docs-url <url>]
|
|
1283
1319
|
pep nexus setup
|
|
@@ -1309,9 +1345,21 @@ directly. Claude Code keeps its own directory, so each skill is also linked into
|
|
|
1309
1345
|
${claudeSkillsDirectory()} \u2014 one copy on disk, updated in one place. Where links are not
|
|
1310
1346
|
available the skill is copied instead and the run says so.
|
|
1311
1347
|
|
|
1348
|
+
-p, --project installs into the CURRENT PROJECT instead: ./.agents/skills plus the same link into
|
|
1349
|
+
./.claude/skills. Use it when the skills belong to one repository and should be committed with
|
|
1350
|
+
it; note both directories then show up in git status, which is why the personal location is the
|
|
1351
|
+
default.
|
|
1352
|
+
|
|
1312
1353
|
--dir <path> writes to that path ONLY and skips the linking, for an agent that reads neither
|
|
1313
|
-
directory.
|
|
1314
|
-
|
|
1354
|
+
directory.
|
|
1355
|
+
|
|
1356
|
+
Where a repository was installed is remembered, so \`pep skills update\` refreshes each one where
|
|
1357
|
+
it already lives and never moves anything. On update, -p and --dir instead NARROW the run to the
|
|
1358
|
+
repositories installed there: \`pep skills update -p\` refreshes only this project's, and reports
|
|
1359
|
+
nothing to do when the project has none. To move a repository, add it again with the new flag \u2014
|
|
1360
|
+
add is where the location is decided, and the copy in the old location is then removed.
|
|
1361
|
+
Deleting a skill folder by hand is fine: update notices it is gone and writes it again.
|
|
1362
|
+
Either way update only touches skills it wrote itself; anything you put there by hand is left alone.
|
|
1315
1363
|
|
|
1316
1364
|
\`pep docs list\` prints the documents this account can read (path + description); feed a path
|
|
1317
1365
|
straight to \`pep docs get\` to print that document as markdown on stdout. The documentation
|
|
@@ -1359,6 +1407,16 @@ function repeatedOption(args, name) {
|
|
|
1359
1407
|
args.splice(index, 2);
|
|
1360
1408
|
}
|
|
1361
1409
|
}
|
|
1410
|
+
function flag(args, ...names) {
|
|
1411
|
+
let found = false;
|
|
1412
|
+
for (const name of names) {
|
|
1413
|
+
for (let index = args.indexOf(name); index !== -1; index = args.indexOf(name)) {
|
|
1414
|
+
args.splice(index, 1);
|
|
1415
|
+
found = true;
|
|
1416
|
+
}
|
|
1417
|
+
}
|
|
1418
|
+
return found;
|
|
1419
|
+
}
|
|
1362
1420
|
function option(args, name) {
|
|
1363
1421
|
const index = args.indexOf(name);
|
|
1364
1422
|
if (index === -1) return void 0;
|
|
@@ -1383,6 +1441,33 @@ async function loginConfig(args, store = fileConfigStore()) {
|
|
|
1383
1441
|
...saved?.docsUrl !== void 0 ? { docsUrl: saved.docsUrl } : {}
|
|
1384
1442
|
};
|
|
1385
1443
|
}
|
|
1444
|
+
function parseSkillsArgs(command, args, cwd) {
|
|
1445
|
+
const explicitDirectory = command === "list" ? void 0 : option(args, "--dir");
|
|
1446
|
+
const project = command === "list" ? false : flag(args, "--project", "-p");
|
|
1447
|
+
if (explicitDirectory !== void 0 && project) {
|
|
1448
|
+
throw new Error("--dir and --project/-p cannot be used together: they name different places.");
|
|
1449
|
+
}
|
|
1450
|
+
const unknownOption = args.find((one) => one.startsWith("-"));
|
|
1451
|
+
if (unknownOption) throw new Error(`Unknown option: ${unknownOption}`);
|
|
1452
|
+
const requested = command === "add" ? args.shift() : void 0;
|
|
1453
|
+
if (command === "add" && !requested) {
|
|
1454
|
+
throw new Error("pep skills add needs a repository: a full https URL, or <group>/<project>.");
|
|
1455
|
+
}
|
|
1456
|
+
const named = command === "update" ? [...args] : [];
|
|
1457
|
+
if (command !== "update" && args.length > 0) {
|
|
1458
|
+
throw new Error(`Unexpected argument: ${args[0]}`);
|
|
1459
|
+
}
|
|
1460
|
+
const chosenTarget = explicitDirectory !== void 0 ? { directory: explicitDirectory } : project ? projectSkillsTarget(cwd) : void 0;
|
|
1461
|
+
return { ...requested !== void 0 ? { requested } : {}, named, ...chosenTarget ? { chosenTarget } : {} };
|
|
1462
|
+
}
|
|
1463
|
+
function targetForSource(chosen, recorded) {
|
|
1464
|
+
if (chosen) return chosen;
|
|
1465
|
+
if (!recorded) return userSkillsTarget();
|
|
1466
|
+
return {
|
|
1467
|
+
directory: recorded.directory,
|
|
1468
|
+
...recorded.linkedInto !== void 0 ? { linkInto: recorded.linkedInto } : {}
|
|
1469
|
+
};
|
|
1470
|
+
}
|
|
1386
1471
|
async function main() {
|
|
1387
1472
|
const args = process.argv.slice(2);
|
|
1388
1473
|
if (args.length === 0 || args.includes("--help") || args.includes("-h")) {
|
|
@@ -1472,31 +1557,39 @@ ${usage()}`);
|
|
|
1472
1557
|
|
|
1473
1558
|
${usage()}`);
|
|
1474
1559
|
}
|
|
1475
|
-
const requested
|
|
1476
|
-
const named = command === "update" ? args.filter((one) => !one.startsWith("--")) : [];
|
|
1477
|
-
for (const one of named) args.splice(args.indexOf(one), 1);
|
|
1478
|
-
if (command === "add" && !requested) {
|
|
1479
|
-
throw new Error("pep skills add needs a repository: a full https URL, or <group>/<project>.");
|
|
1480
|
-
}
|
|
1481
|
-
const explicitDirectory = command === "list" ? void 0 : option(args, "--dir");
|
|
1482
|
-
const directory = explicitDirectory ?? defaultSkillsDirectory();
|
|
1483
|
-
if (args.length > 0) throw new Error(`Unknown option: ${args[0]}`);
|
|
1560
|
+
const { requested, named, chosenTarget } = parseSkillsArgs(command, args);
|
|
1484
1561
|
const authorization = await auth.currentAuthorization();
|
|
1485
1562
|
const remote = { issuer: authorization.issuer, accessToken: authorization.accessToken };
|
|
1486
1563
|
if (command === "list") {
|
|
1487
|
-
const
|
|
1488
|
-
|
|
1564
|
+
const listed = await fileSkillsStateStore().read();
|
|
1565
|
+
const packages = Object.entries(listed?.packages ?? {}).sort(
|
|
1566
|
+
([a], [b]) => a.localeCompare(b)
|
|
1567
|
+
);
|
|
1568
|
+
if (packages.length === 0) {
|
|
1489
1569
|
console.error("Nothing added yet. Run `pep skills add <repo>`.");
|
|
1490
1570
|
return;
|
|
1491
1571
|
}
|
|
1492
|
-
for (const
|
|
1493
|
-
console.error("\n`pep skills update` refreshes all of them.");
|
|
1572
|
+
for (const [source, pkg] of packages) console.log(`${source} ${pkg.directory}`);
|
|
1573
|
+
console.error("\n`pep skills update` refreshes all of them, each where it lives.");
|
|
1494
1574
|
return;
|
|
1495
1575
|
}
|
|
1496
1576
|
const stateStore = fileSkillsStateStore();
|
|
1497
|
-
const
|
|
1498
|
-
const
|
|
1499
|
-
|
|
1577
|
+
const state = await stateStore.read();
|
|
1578
|
+
const installed = Object.keys(state?.packages ?? {}).sort();
|
|
1579
|
+
const run2 = async (source, target) => reportUpdate(
|
|
1580
|
+
await updateSkills({
|
|
1581
|
+
...remote,
|
|
1582
|
+
source,
|
|
1583
|
+
directory: target.directory,
|
|
1584
|
+
...target.linkInto !== void 0 ? { linkInto: target.linkInto } : {},
|
|
1585
|
+
stateStore
|
|
1586
|
+
})
|
|
1587
|
+
);
|
|
1588
|
+
if (command === "add") {
|
|
1589
|
+
await run2(requested, targetForSource(chosenTarget, state?.packages[requested]));
|
|
1590
|
+
return;
|
|
1591
|
+
}
|
|
1592
|
+
if (installed.length === 0) {
|
|
1500
1593
|
console.error("Nothing added yet. Run `pep skills add <repo>`.");
|
|
1501
1594
|
return;
|
|
1502
1595
|
}
|
|
@@ -1506,15 +1599,20 @@ ${usage()}`);
|
|
|
1506
1599
|
`Not added yet: ${unknown.join(" ")}. Run \`pep skills add <repo>\` first, or \`pep skills list\` to see what is.`
|
|
1507
1600
|
);
|
|
1508
1601
|
}
|
|
1602
|
+
const wanted = named.length > 0 ? named : installed;
|
|
1603
|
+
const targets = chosenTarget ? wanted.filter((one) => state?.packages[one]?.directory === chosenTarget.directory) : wanted;
|
|
1604
|
+
if (targets.length === 0) {
|
|
1605
|
+
console.error(`No skills are installed in ${chosenTarget?.directory}.`);
|
|
1606
|
+
console.error("`pep skills update` (no flag) refreshes every repository where it lives;");
|
|
1607
|
+
console.error("`pep skills add <repo> -p` installs one into this project.");
|
|
1608
|
+
return;
|
|
1609
|
+
}
|
|
1610
|
+
const skipped = wanted.filter((one) => !targets.includes(one));
|
|
1611
|
+
if (skipped.length > 0) {
|
|
1612
|
+
console.error(`Not installed in ${chosenTarget?.directory}, skipped: ${skipped.join(" ")}`);
|
|
1613
|
+
}
|
|
1509
1614
|
for (const source of targets) {
|
|
1510
|
-
|
|
1511
|
-
...remote,
|
|
1512
|
-
source,
|
|
1513
|
-
directory,
|
|
1514
|
-
...explicitDirectory === void 0 ? { linkInto: claudeSkillsDirectory() } : {},
|
|
1515
|
-
stateStore
|
|
1516
|
-
});
|
|
1517
|
-
reportUpdate(result);
|
|
1615
|
+
await run2(source, targetForSource(void 0, state?.packages[source]));
|
|
1518
1616
|
}
|
|
1519
1617
|
return;
|
|
1520
1618
|
}
|