@newlandnpt/pep-cli 0.4.0 → 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/README.md +18 -0
- package/dist/pep.cjs +43 -10
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -137,6 +137,24 @@ pep skills add group/sub/project -p # move it into this project
|
|
|
137
137
|
`pep skills list` prints each repository with the directory it lives in, which is what `-p` matches
|
|
138
138
|
against.
|
|
139
139
|
|
|
140
|
+
### Deleting a skill
|
|
141
|
+
|
|
142
|
+
Delete a skill folder by hand and it **stays deleted**. `update` refreshes what is still on disk
|
|
143
|
+
and leaves the rest alone, naming them so the run is not silent:
|
|
144
|
+
|
|
145
|
+
```
|
|
146
|
+
group/sub/project: updated b
|
|
147
|
+
deleted locally, left alone: a
|
|
148
|
+
(`pep skills add group/sub/project` puts them back)
|
|
149
|
+
```
|
|
150
|
+
|
|
151
|
+
`add` is the command that installs, so that is what brings a deleted skill back. This split is
|
|
152
|
+
deliberate: `update` means "bring what I have up to date", not "refill everything the repository
|
|
153
|
+
offers".
|
|
154
|
+
|
|
155
|
+
Skills that are **new upstream** are still installed by `update` — the test is "was mine and is now
|
|
156
|
+
gone", not "is absent".
|
|
157
|
+
|
|
140
158
|
`pep auth token` writes only the access token to stdout, so agents can use it without parsing status
|
|
141
159
|
text. Refresh occurs automatically shortly before expiry and the rotated refresh token replaces the old
|
|
142
160
|
credential atomically.
|
package/dist/pep.cjs
CHANGED
|
@@ -1195,6 +1195,18 @@ function hashSkill(files) {
|
|
|
1195
1195
|
}
|
|
1196
1196
|
return hash.digest("hex").slice(0, 32);
|
|
1197
1197
|
}
|
|
1198
|
+
function pickSkipped(previous, skipped) {
|
|
1199
|
+
return Object.fromEntries(
|
|
1200
|
+
skipped.map((skill) => [skill, previous?.skills[skill] ?? ""])
|
|
1201
|
+
);
|
|
1202
|
+
}
|
|
1203
|
+
async function missingSkills(directory, skills) {
|
|
1204
|
+
const gone = /* @__PURE__ */ new Set();
|
|
1205
|
+
for (const skill of skills) {
|
|
1206
|
+
if (!await (0, import_promises4.stat)((0, import_node_path4.join)(directory, skill)).catch(() => null)) gone.add(skill);
|
|
1207
|
+
}
|
|
1208
|
+
return gone;
|
|
1209
|
+
}
|
|
1198
1210
|
async function updateSkills(dependencies) {
|
|
1199
1211
|
const doFetch = dependencies.fetch ?? globalThis.fetch;
|
|
1200
1212
|
const name = dependencies.source;
|
|
@@ -1211,7 +1223,9 @@ async function updateSkills(dependencies) {
|
|
|
1211
1223
|
const state = await dependencies.stateStore.read();
|
|
1212
1224
|
const previous = state?.packages[name];
|
|
1213
1225
|
const sameTarget = previous?.directory === dependencies.directory && previous?.linkedInto === dependencies.linkInto;
|
|
1214
|
-
|
|
1226
|
+
const gone = previous !== void 0 && sameTarget ? await missingSkills(previous.directory, Object.keys(previous.skills)) : /* @__PURE__ */ new Set();
|
|
1227
|
+
const nothingToRestore = !dependencies.restoreMissing || gone.size === 0;
|
|
1228
|
+
if (commit !== void 0 && commit === previous?.commit && sameTarget && nothingToRestore) {
|
|
1215
1229
|
await response.body?.cancel();
|
|
1216
1230
|
return { status: "unchanged", name, commit };
|
|
1217
1231
|
}
|
|
@@ -1223,7 +1237,9 @@ async function updateSkills(dependencies) {
|
|
|
1223
1237
|
if (group) group.push(file);
|
|
1224
1238
|
else bySkill.set(file.skill, [file]);
|
|
1225
1239
|
}
|
|
1226
|
-
const
|
|
1240
|
+
const inArchive = [...bySkill.keys()].sort();
|
|
1241
|
+
const skipped = dependencies.restoreMissing ? [] : inArchive.filter((skill) => gone.has(skill));
|
|
1242
|
+
const skills = inArchive.filter((skill) => !skipped.includes(skill));
|
|
1227
1243
|
const hashes = {};
|
|
1228
1244
|
const updated = [];
|
|
1229
1245
|
const unchanged = [];
|
|
@@ -1231,10 +1247,11 @@ async function updateSkills(dependencies) {
|
|
|
1231
1247
|
const hash = hashSkill(bySkill.get(skill));
|
|
1232
1248
|
hashes[skill] = hash;
|
|
1233
1249
|
const before = previous?.skills[skill];
|
|
1234
|
-
if (
|
|
1250
|
+
if (gone.has(skill)) updated.push(skill);
|
|
1251
|
+
else if (before !== void 0 && before !== "" && before === hash) unchanged.push(skill);
|
|
1235
1252
|
else updated.push(skill);
|
|
1236
1253
|
}
|
|
1237
|
-
const removed = Object.keys(previous?.skills ?? {}).filter((skill) => !
|
|
1254
|
+
const removed = Object.keys(previous?.skills ?? {}).filter((skill) => !inArchive.includes(skill));
|
|
1238
1255
|
if (previous !== void 0) {
|
|
1239
1256
|
const stale = sameTarget ? removed : Object.keys(previous.skills);
|
|
1240
1257
|
for (const skill of stale) {
|
|
@@ -1248,6 +1265,7 @@ async function updateSkills(dependencies) {
|
|
|
1248
1265
|
await (0, import_promises4.rm)((0, import_node_path4.join)(dependencies.directory, skill), { recursive: true, force: true });
|
|
1249
1266
|
}
|
|
1250
1267
|
for (const file of files) {
|
|
1268
|
+
if (skipped.includes(file.skill)) continue;
|
|
1251
1269
|
const target = (0, import_node_path4.join)(dependencies.directory, file.skill, ...file.path.split("/"));
|
|
1252
1270
|
await (0, import_promises4.mkdir)((0, import_node_path4.dirname)(target), { recursive: true });
|
|
1253
1271
|
await (0, import_promises4.writeFile)(target, file.data);
|
|
@@ -1272,7 +1290,9 @@ async function updateSkills(dependencies) {
|
|
|
1272
1290
|
...commit ? { commit } : {},
|
|
1273
1291
|
directory: dependencies.directory,
|
|
1274
1292
|
...dependencies.linkInto !== void 0 ? { linkedInto: dependencies.linkInto } : {},
|
|
1275
|
-
|
|
1293
|
+
// 跳过的那些**原样留着上次的哈希** —— 账上仍然认它是这个包的(将来 add 能补回来,
|
|
1294
|
+
// 上游删掉时也还清得动),只是这次没去碰它。
|
|
1295
|
+
skills: { ...pickSkipped(previous, skipped), ...hashes }
|
|
1276
1296
|
}
|
|
1277
1297
|
}
|
|
1278
1298
|
});
|
|
@@ -1282,8 +1302,9 @@ async function updateSkills(dependencies) {
|
|
|
1282
1302
|
updated,
|
|
1283
1303
|
unchanged,
|
|
1284
1304
|
skills,
|
|
1285
|
-
fileCount: files.length,
|
|
1305
|
+
fileCount: files.filter((one) => !skipped.includes(one.skill)).length,
|
|
1286
1306
|
removed,
|
|
1307
|
+
skipped,
|
|
1287
1308
|
directory: dependencies.directory,
|
|
1288
1309
|
...dependencies.linkInto !== void 0 ? { linkedInto: dependencies.linkInto } : {},
|
|
1289
1310
|
...copiedCount > 0 ? { copiedCount } : {},
|
|
@@ -1292,7 +1313,7 @@ async function updateSkills(dependencies) {
|
|
|
1292
1313
|
}
|
|
1293
1314
|
|
|
1294
1315
|
// src/cli.ts
|
|
1295
|
-
var VERSION = false ? "0.0.0-dev" : "0.
|
|
1316
|
+
var VERSION = false ? "0.0.0-dev" : "0.5.0";
|
|
1296
1317
|
function usage() {
|
|
1297
1318
|
return `PEP CLI ${VERSION}
|
|
1298
1319
|
|
|
@@ -1348,7 +1369,10 @@ it already lives and never moves anything. On update, -p and --dir instead NARRO
|
|
|
1348
1369
|
repositories installed there: \`pep skills update -p\` refreshes only this project's, and reports
|
|
1349
1370
|
nothing to do when the project has none. To move a repository, add it again with the new flag \u2014
|
|
1350
1371
|
add is where the location is decided, and the copy in the old location is then removed.
|
|
1351
|
-
|
|
1372
|
+
Delete a skill folder by hand and update LEAVES IT DELETED \u2014 it refreshes what is still there and
|
|
1373
|
+
reports the ones it left alone. Run \`pep skills add <repo>\` to put them back; add is the command
|
|
1374
|
+
that installs. Either way update only touches skills it wrote itself; anything you put there by
|
|
1375
|
+
hand is left alone.
|
|
1352
1376
|
|
|
1353
1377
|
\`pep docs list\` prints the documents this account can read (path + description); feed a path
|
|
1354
1378
|
straight to \`pep docs get\` to print that document as markdown on stdout. The documentation
|
|
@@ -1375,6 +1399,10 @@ function reportUpdate(result) {
|
|
|
1375
1399
|
if (result.unchanged.length > 0) {
|
|
1376
1400
|
console.log(` unchanged: ${result.unchanged.join(" ")}`);
|
|
1377
1401
|
}
|
|
1402
|
+
if (result.skipped.length > 0) {
|
|
1403
|
+
console.log(` deleted locally, left alone: ${result.skipped.join(" ")}`);
|
|
1404
|
+
console.log(` (\`pep skills add ${result.name}\` puts them back)`);
|
|
1405
|
+
}
|
|
1378
1406
|
console.log(` ${result.fileCount} file(s) in ${result.directory}`);
|
|
1379
1407
|
if (result.linkedInto !== void 0) {
|
|
1380
1408
|
console.log(
|
|
@@ -1565,17 +1593,22 @@ ${usage()}`);
|
|
|
1565
1593
|
const stateStore = fileSkillsStateStore();
|
|
1566
1594
|
const state = await stateStore.read();
|
|
1567
1595
|
const installed = Object.keys(state?.packages ?? {}).sort();
|
|
1568
|
-
const run2 = async (source, target) => reportUpdate(
|
|
1596
|
+
const run2 = async (source, target, restoreMissing = false) => reportUpdate(
|
|
1569
1597
|
await updateSkills({
|
|
1570
1598
|
...remote,
|
|
1571
1599
|
source,
|
|
1572
1600
|
directory: target.directory,
|
|
1573
1601
|
...target.linkInto !== void 0 ? { linkInto: target.linkInto } : {},
|
|
1602
|
+
...restoreMissing ? { restoreMissing: true } : {},
|
|
1574
1603
|
stateStore
|
|
1575
1604
|
})
|
|
1576
1605
|
);
|
|
1577
1606
|
if (command === "add") {
|
|
1578
|
-
await run2(
|
|
1607
|
+
await run2(
|
|
1608
|
+
requested,
|
|
1609
|
+
targetForSource(chosenTarget, state?.packages[requested]),
|
|
1610
|
+
true
|
|
1611
|
+
);
|
|
1579
1612
|
return;
|
|
1580
1613
|
}
|
|
1581
1614
|
if (installed.length === 0) {
|