@newlandnpt/pep-cli 0.1.1 → 0.1.3

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.
Files changed (2) hide show
  1. package/dist/pep.cjs +78 -19
  2. package/package.json +1 -1
package/dist/pep.cjs CHANGED
@@ -38,6 +38,9 @@ function skillsStatePath() {
38
38
  return (0, import_node_path.join)(configDirectory(), "skills.json");
39
39
  }
40
40
  function defaultSkillsDirectory() {
41
+ return (0, import_node_path.join)((0, import_node_os.homedir)(), ".agents", "skills");
42
+ }
43
+ function claudeSkillsDirectory() {
41
44
  return (0, import_node_path.join)((0, import_node_os.homedir)(), ".claude", "skills");
42
45
  }
43
46
  function isCliConfig(value) {
@@ -73,7 +76,8 @@ function fileConfigStore(path = configPath()) {
73
76
  function isSkillsState(value) {
74
77
  if (typeof value !== "object" || value === null) return false;
75
78
  const candidate = value;
76
- return candidate.version === 1 && typeof candidate.directory === "string" && Array.isArray(candidate.skills) && candidate.skills.every((one) => typeof one === "string") && (candidate.commit === void 0 || typeof candidate.commit === "string");
79
+ return candidate.version === 1 && typeof candidate.directory === "string" && Array.isArray(candidate.skills) && candidate.skills.every((one) => typeof one === "string") && (candidate.commit === void 0 || typeof candidate.commit === "string") && // 可选:0.1.1 及更早写下的 skills.json 没有这个键,读它们不该报「状态损坏」。
80
+ (candidate.linkedInto === void 0 || typeof candidate.linkedInto === "string");
77
81
  }
78
82
  function fileSkillsStateStore(path = skillsStatePath()) {
79
83
  return {
@@ -192,12 +196,12 @@ async function waitForAuthorizationCallback(args) {
192
196
  throw new Error("CLI redirect URI must be an http://localhost URL with an explicit port.");
193
197
  }
194
198
  let server;
195
- return new Promise((resolve, reject) => {
199
+ return new Promise((resolve2, reject) => {
196
200
  const finish = (error, code) => {
197
201
  clearTimeout(timeout);
198
202
  server?.close();
199
203
  if (error) reject(error);
200
- else resolve(code);
204
+ else resolve2(code);
201
205
  };
202
206
  const timeout = setTimeout(
203
207
  () => finish(new Error("Login timed out while waiting for the browser callback.")),
@@ -240,7 +244,7 @@ async function waitForAuthorizationCallback(args) {
240
244
  function openBrowser(url) {
241
245
  const command = process.platform === "win32" ? "rundll32.exe" : process.platform === "darwin" ? "open" : "xdg-open";
242
246
  const commandArgs = process.platform === "win32" ? ["url.dll,FileProtocolHandler", url] : [url];
243
- return new Promise((resolve, reject) => {
247
+ return new Promise((resolve2, reject) => {
244
248
  const child = (0, import_node_child_process.spawn)(command, commandArgs, {
245
249
  detached: true,
246
250
  stdio: "ignore",
@@ -249,7 +253,7 @@ function openBrowser(url) {
249
253
  child.once("error", reject);
250
254
  child.once("spawn", () => {
251
255
  child.unref();
252
- resolve();
256
+ resolve2();
253
257
  });
254
258
  });
255
259
  }
@@ -360,7 +364,7 @@ var REFRESH_EARLY_MS = 60 * 1e3;
360
364
  var LOCK_STALE_MS = 30 * 1e3;
361
365
  var LOCK_WAIT_MS = 10 * 1e3;
362
366
  async function delay(milliseconds) {
363
- await new Promise((resolve) => setTimeout(resolve, milliseconds));
367
+ await new Promise((resolve2) => setTimeout(resolve2, milliseconds));
364
368
  }
365
369
  async function withAuthorizationLock(path, action) {
366
370
  await (0, import_promises2.mkdir)((0, import_node_path2.dirname)(path), { recursive: true });
@@ -554,7 +558,7 @@ function encodedPowerShell(script) {
554
558
  return Buffer.from(script, "utf16le").toString("base64");
555
559
  }
556
560
  async function runPowerShell(script, input) {
557
- return new Promise((resolve, reject) => {
561
+ return new Promise((resolve2, reject) => {
558
562
  const child = (0, import_node_child_process2.spawn)(
559
563
  "powershell.exe",
560
564
  [
@@ -577,7 +581,7 @@ async function runPowerShell(script, input) {
577
581
  );
578
582
  child.once("close", (code) => {
579
583
  clearTimeout(timeout);
580
- if (code === 0) resolve(stdout.trim());
584
+ if (code === 0) resolve2(stdout.trim());
581
585
  else
582
586
  reject(
583
587
  new Error(
@@ -627,7 +631,7 @@ $raw = [Console]::In.ReadToEnd()
627
631
  }
628
632
  var SECURITY_NOT_FOUND = 44;
629
633
  async function runSecurity(args) {
630
- return new Promise((resolve, reject) => {
634
+ return new Promise((resolve2, reject) => {
631
635
  const child = (0, import_node_child_process2.spawn)("/usr/bin/security", [...args], {
632
636
  stdio: ["ignore", "pipe", "pipe"]
633
637
  });
@@ -642,7 +646,7 @@ async function runSecurity(args) {
642
646
  );
643
647
  child.once("close", (code) => {
644
648
  clearTimeout(timeout);
645
- resolve({ code: code ?? -1, stdout, stderr });
649
+ resolve2({ code: code ?? -1, stdout, stderr });
646
650
  });
647
651
  });
648
652
  }
@@ -763,6 +767,7 @@ async function fetchDocContent(dependencies, path) {
763
767
 
764
768
  // src/skills-service.ts
765
769
  var import_promises3 = require("node:fs/promises");
770
+ var import_node_os2 = require("node:os");
766
771
  var import_node_path3 = require("node:path");
767
772
  var import_node_zlib = require("node:zlib");
768
773
 
@@ -852,11 +857,11 @@ function planSkillFiles(entries) {
852
857
  );
853
858
  }
854
859
  const withoutRoot = segments.slice(1);
855
- const relative = withoutRoot[0] === SKILLS_SEGMENT ? withoutRoot.slice(1) : withoutRoot;
856
- if (relative.length < 2) continue;
860
+ const relative2 = withoutRoot[0] === SKILLS_SEGMENT ? withoutRoot.slice(1) : withoutRoot;
861
+ if (relative2.length < 2) continue;
857
862
  files.push({
858
- skill: relative[0],
859
- path: relative.slice(1).join("/"),
863
+ skill: relative2[0],
864
+ path: relative2.slice(1).join("/"),
860
865
  data: entry.data
861
866
  });
862
867
  }
@@ -876,6 +881,31 @@ function describeFailure2(status) {
876
881
  }
877
882
  return `PEP answered ${status}.`;
878
883
  }
884
+ async function physicalDir(path) {
885
+ const absolute = (0, import_node_path3.resolve)(path);
886
+ try {
887
+ return (0, import_node_path3.join)(await (0, import_promises3.realpath)((0, import_node_path3.dirname)(absolute)), (0, import_node_path3.basename)(absolute));
888
+ } catch {
889
+ return absolute;
890
+ }
891
+ }
892
+ async function linkSkill(canonicalSkillDir, linkPath) {
893
+ await (0, import_promises3.rm)(linkPath, { recursive: true, force: true });
894
+ const linkDir = (0, import_node_path3.dirname)(linkPath);
895
+ await (0, import_promises3.mkdir)(linkDir, { recursive: true });
896
+ try {
897
+ const junction = (0, import_node_os2.platform)() === "win32";
898
+ await (0, import_promises3.symlink)(
899
+ junction ? canonicalSkillDir : (0, import_node_path3.relative)(await physicalDir(linkDir), canonicalSkillDir),
900
+ linkPath,
901
+ junction ? "junction" : void 0
902
+ );
903
+ return "linked";
904
+ } catch {
905
+ await (0, import_promises3.cp)(canonicalSkillDir, linkPath, { recursive: true });
906
+ return "copied";
907
+ }
908
+ }
879
909
  async function syncSkills(dependencies) {
880
910
  const doFetch = dependencies.fetch ?? globalThis.fetch;
881
911
  const response = await doFetch(`${dependencies.issuer}${ARCHIVE_PATH}`, {
@@ -909,6 +939,16 @@ async function syncSkills(dependencies) {
909
939
  await (0, import_promises3.mkdir)((0, import_node_path3.dirname)(target), { recursive: true });
910
940
  await (0, import_promises3.writeFile)(target, file.data);
911
941
  }
942
+ let copiedCount = 0;
943
+ if (dependencies.linkInto !== void 0) {
944
+ for (const skill of skills) {
945
+ const how = await linkSkill(
946
+ (0, import_node_path3.join)(dependencies.directory, skill),
947
+ (0, import_node_path3.join)(dependencies.linkInto, skill)
948
+ );
949
+ if (how === "copied") copiedCount += 1;
950
+ }
951
+ }
912
952
  const removed = (previous?.skills ?? []).filter(
913
953
  (skill) => !skills.includes(skill)
914
954
  );
@@ -917,11 +957,15 @@ async function syncSkills(dependencies) {
917
957
  recursive: true,
918
958
  force: true
919
959
  });
960
+ if (previous?.linkedInto !== void 0) {
961
+ await (0, import_promises3.rm)((0, import_node_path3.join)(previous.linkedInto, skill), { recursive: true, force: true });
962
+ }
920
963
  }
921
964
  const state = {
922
965
  version: 1,
923
966
  skills,
924
967
  directory: dependencies.directory,
968
+ ...dependencies.linkInto !== void 0 ? { linkedInto: dependencies.linkInto } : {},
925
969
  ...commit ? { commit } : {}
926
970
  };
927
971
  await dependencies.stateStore.write(state);
@@ -931,12 +975,14 @@ async function syncSkills(dependencies) {
931
975
  fileCount: files.length,
932
976
  removed,
933
977
  directory: dependencies.directory,
978
+ ...dependencies.linkInto !== void 0 ? { linkedInto: dependencies.linkInto } : {},
979
+ ...copiedCount > 0 ? { copiedCount } : {},
934
980
  ...commit ? { commit } : {}
935
981
  };
936
982
  }
937
983
 
938
984
  // src/cli.ts
939
- var VERSION = "0.1.1";
985
+ var VERSION = "0.1.3";
940
986
  function usage() {
941
987
  return `PEP CLI ${VERSION}
942
988
 
@@ -956,9 +1002,15 @@ one. It defaults to the docs platform \u2014 a token minted without it is reject
956
1002
  resource server, and their answer looks exactly like "this token does not exist".
957
1003
  Use \`pep auth token\` when another agent needs a fresh bearer token.
958
1004
 
959
- \`pep skills sync\` fetches the latest skills from PEP and writes them where Claude Code
960
- looks for them (${defaultSkillsDirectory()} unless --dir says otherwise). It only touches
961
- skills it wrote itself; anything you put there by hand is left alone.
1005
+ \`pep skills sync\` fetches the latest skills from PEP and writes them to the shared agent
1006
+ directory (${defaultSkillsDirectory()}), which Codex, Cursor, Amp and ~20 other agents read
1007
+ directly. Claude Code keeps its own directory, so each skill is also linked into
1008
+ ${claudeSkillsDirectory()} \u2014 one copy on disk, updated in one place. Where links are not
1009
+ available the skill is copied instead and the run says so.
1010
+
1011
+ --dir <path> writes to that path ONLY and skips the linking, for an agent that reads neither
1012
+ directory. Either way sync only touches skills it wrote itself; anything you put there by
1013
+ hand is left alone.
962
1014
 
963
1015
  \`pep docs list\` prints the documents this account can read (path + description); feed a path
964
1016
  straight to \`pep docs get\` to print that document as markdown on stdout. The documentation
@@ -1056,13 +1108,15 @@ ${usage()}`);
1056
1108
  if (command !== "sync") throw new Error(`Unknown skills command.
1057
1109
 
1058
1110
  ${usage()}`);
1059
- const directory = option(args, "--dir") ?? defaultSkillsDirectory();
1111
+ const explicitDirectory = option(args, "--dir");
1112
+ const directory = explicitDirectory ?? defaultSkillsDirectory();
1060
1113
  if (args.length > 0) throw new Error(`Unknown option: ${args[0]}`);
1061
1114
  const authorization = await auth.currentAuthorization();
1062
1115
  const result = await syncSkills({
1063
1116
  issuer: authorization.issuer,
1064
1117
  accessToken: authorization.accessToken,
1065
1118
  directory,
1119
+ ...explicitDirectory === void 0 ? { linkInto: claudeSkillsDirectory() } : {},
1066
1120
  stateStore: fileSkillsStateStore()
1067
1121
  });
1068
1122
  if (result.status === "unchanged") {
@@ -1072,6 +1126,11 @@ ${usage()}`);
1072
1126
  console.log(
1073
1127
  `Wrote ${result.fileCount} file(s) across ${result.skills.length} skill(s) to ${result.directory}`
1074
1128
  );
1129
+ if (result.linkedInto !== void 0) {
1130
+ console.log(
1131
+ result.copiedCount === void 0 ? `Linked into ${result.linkedInto} for Claude Code` : `Linked into ${result.linkedInto} for Claude Code (${result.copiedCount} copied instead \u2014 links unavailable here)`
1132
+ );
1133
+ }
1075
1134
  if (result.commit) console.log(`Commit: ${result.commit}`);
1076
1135
  if (result.removed.length > 0)
1077
1136
  console.log(`Removed (gone upstream): ${result.removed.join(" ")}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@newlandnpt/pep-cli",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "description": "PEP CLI —— 凭 PEP 身份读取 Newland 开发者文档与 agent skills",
5
5
  "license": "UNLICENSED",
6
6
  "type": "module",