@anytio/pspm 0.1.0 → 0.2.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/CHANGELOG.md +221 -0
- package/CLI_GUIDE.md +465 -0
- package/LICENSE +176 -109
- package/README.md +41 -96
- package/bin/pspm.js +2 -0
- package/dist/index.js +989 -686
- package/dist/index.js.map +1 -1
- package/package.json +70 -67
package/dist/index.js
CHANGED
|
@@ -1,113 +1,15 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
import { checkbox } from '@inquirer/prompts';
|
|
12
|
-
import { createInterface } from 'readline';
|
|
13
|
-
import http from 'http';
|
|
14
|
-
import open from 'open';
|
|
15
|
-
import { exec as exec$1 } from 'child_process';
|
|
16
|
-
import { promisify } from 'util';
|
|
17
|
-
|
|
18
|
-
function calculateIntegrity(data) {
|
|
19
|
-
const hash = createHash("sha256").update(data).digest("base64");
|
|
20
|
-
return `sha256-${hash}`;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
|
-
// ../../packages/shared/pspm-types/src/manifest.ts
|
|
24
|
-
var DEFAULT_SKILL_FILES = [
|
|
25
|
-
"SKILL.md",
|
|
26
|
-
"runtime",
|
|
27
|
-
"scripts",
|
|
28
|
-
"data"
|
|
29
|
-
];
|
|
30
|
-
var PSPM_SCHEMA_URL = "https://pspm.dev/schema/v1/pspm.json";
|
|
31
|
-
function validateManifest(manifest) {
|
|
32
|
-
if (!manifest.name) {
|
|
33
|
-
return { valid: false, error: "Manifest must have a 'name' field" };
|
|
34
|
-
}
|
|
35
|
-
if (!manifest.version) {
|
|
36
|
-
return { valid: false, error: "Manifest must have a 'version' field" };
|
|
37
|
-
}
|
|
38
|
-
if (!/^[a-z][a-z0-9_-]*$/.test(manifest.name)) {
|
|
39
|
-
return {
|
|
40
|
-
valid: false,
|
|
41
|
-
error: "Name must start with a lowercase letter and contain only lowercase letters, numbers, hyphens, and underscores"
|
|
42
|
-
};
|
|
43
|
-
}
|
|
44
|
-
if (!/^\d+\.\d+\.\d+/.test(manifest.version)) {
|
|
45
|
-
return {
|
|
46
|
-
valid: false,
|
|
47
|
-
error: "Version must be a valid semantic version (e.g., 1.0.0)"
|
|
48
|
-
};
|
|
49
|
-
}
|
|
50
|
-
return { valid: true };
|
|
51
|
-
}
|
|
52
|
-
|
|
53
|
-
// ../../packages/shared/pspm-types/src/specifier.ts
|
|
54
|
-
var SPECIFIER_PATTERN = /^@user\/([a-zA-Z0-9_-]+)\/([a-z][a-z0-9_-]*)(?:@(.+))?$/;
|
|
55
|
-
function parseSkillSpecifier(specifier) {
|
|
56
|
-
const match = specifier.match(SPECIFIER_PATTERN);
|
|
57
|
-
if (!match) {
|
|
58
|
-
return null;
|
|
59
|
-
}
|
|
60
|
-
return {
|
|
61
|
-
username: match[1],
|
|
62
|
-
name: match[2],
|
|
63
|
-
versionRange: match[3]
|
|
64
|
-
};
|
|
65
|
-
}
|
|
66
|
-
var GITHUB_SPECIFIER_PATTERN = /^github:([a-zA-Z0-9_-]+)\/([a-zA-Z0-9_.-]+)(\/[^@]+)?(?:@(.+))?$/;
|
|
67
|
-
function parseGitHubSpecifier(specifier) {
|
|
68
|
-
const match = specifier.match(GITHUB_SPECIFIER_PATTERN);
|
|
69
|
-
if (!match) {
|
|
70
|
-
return null;
|
|
71
|
-
}
|
|
72
|
-
const [, owner, repo, pathWithSlash, ref] = match;
|
|
73
|
-
return {
|
|
74
|
-
owner,
|
|
75
|
-
repo,
|
|
76
|
-
// Remove leading slash from path
|
|
77
|
-
path: pathWithSlash ? pathWithSlash.slice(1) : void 0,
|
|
78
|
-
ref: ref || void 0
|
|
79
|
-
};
|
|
80
|
-
}
|
|
81
|
-
function formatGitHubSpecifier(spec) {
|
|
82
|
-
let result = `github:${spec.owner}/${spec.repo}`;
|
|
83
|
-
if (spec.path) {
|
|
84
|
-
result += `/${spec.path}`;
|
|
85
|
-
}
|
|
86
|
-
if (spec.ref) {
|
|
87
|
-
result += `@${spec.ref}`;
|
|
88
|
-
}
|
|
89
|
-
return result;
|
|
90
|
-
}
|
|
91
|
-
function getGitHubSkillName(spec) {
|
|
92
|
-
if (spec.path) {
|
|
93
|
-
const segments = spec.path.split("/").filter(Boolean);
|
|
94
|
-
return segments[segments.length - 1];
|
|
95
|
-
}
|
|
96
|
-
return spec.repo;
|
|
97
|
-
}
|
|
98
|
-
function isGitHubSpecifier(specifier) {
|
|
99
|
-
return specifier.startsWith("github:");
|
|
100
|
-
}
|
|
101
|
-
function resolveVersion(range, availableVersions) {
|
|
102
|
-
const sorted = availableVersions.filter((v) => semver.valid(v)).sort((a, b) => semver.rcompare(a, b));
|
|
103
|
-
if (!range || range === "latest" || range === "*") {
|
|
104
|
-
return sorted[0] ?? null;
|
|
105
|
-
}
|
|
106
|
-
return semver.maxSatisfying(sorted, range);
|
|
107
|
-
}
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
4
|
+
var __esm = (fn, res) => function __init() {
|
|
5
|
+
return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
|
|
6
|
+
};
|
|
7
|
+
var __export = (target, all) => {
|
|
8
|
+
for (var name in all)
|
|
9
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
10
|
+
};
|
|
108
11
|
|
|
109
|
-
//
|
|
110
|
-
var config = null;
|
|
12
|
+
// src/sdk/fetcher.ts
|
|
111
13
|
function configure(options) {
|
|
112
14
|
config = options;
|
|
113
15
|
}
|
|
@@ -146,84 +48,87 @@ async function customFetch(url, options) {
|
|
|
146
48
|
headers: response.headers
|
|
147
49
|
};
|
|
148
50
|
}
|
|
51
|
+
var config;
|
|
52
|
+
var init_fetcher = __esm({
|
|
53
|
+
"src/sdk/fetcher.ts"() {
|
|
54
|
+
"use strict";
|
|
55
|
+
config = null;
|
|
56
|
+
}
|
|
57
|
+
});
|
|
149
58
|
|
|
150
|
-
//
|
|
151
|
-
var getMeUrl
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
getMeUrl()
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
}
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
};
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
{
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
|
|
215
|
-
|
|
216
|
-
|
|
217
|
-
|
|
218
|
-
|
|
219
|
-
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
method: "DELETE"
|
|
224
|
-
}
|
|
225
|
-
);
|
|
226
|
-
};
|
|
59
|
+
// src/sdk/generated/index.ts
|
|
60
|
+
var getMeUrl, me, getListSkillVersionsUrl, listSkillVersions, getGetSkillVersionUrl, getSkillVersion, getPublishSkillUrl, publishSkill, getDeleteSkillUrl, deleteSkill, getDeleteSkillVersionUrl, deleteSkillVersion;
|
|
61
|
+
var init_generated = __esm({
|
|
62
|
+
"src/sdk/generated/index.ts"() {
|
|
63
|
+
"use strict";
|
|
64
|
+
init_fetcher();
|
|
65
|
+
getMeUrl = () => {
|
|
66
|
+
return "/api/skills/me";
|
|
67
|
+
};
|
|
68
|
+
me = async (options) => {
|
|
69
|
+
return customFetch(getMeUrl(), {
|
|
70
|
+
...options,
|
|
71
|
+
method: "GET"
|
|
72
|
+
});
|
|
73
|
+
};
|
|
74
|
+
getListSkillVersionsUrl = (username, name) => {
|
|
75
|
+
return `/api/skills/@user/${username}/${name}/versions`;
|
|
76
|
+
};
|
|
77
|
+
listSkillVersions = async (username, name, options) => {
|
|
78
|
+
return customFetch(
|
|
79
|
+
getListSkillVersionsUrl(username, name),
|
|
80
|
+
{
|
|
81
|
+
...options,
|
|
82
|
+
method: "GET"
|
|
83
|
+
}
|
|
84
|
+
);
|
|
85
|
+
};
|
|
86
|
+
getGetSkillVersionUrl = (username, name, version2) => {
|
|
87
|
+
return `/api/skills/@user/${username}/${name}/${version2}`;
|
|
88
|
+
};
|
|
89
|
+
getSkillVersion = async (username, name, version2, options) => {
|
|
90
|
+
return customFetch(
|
|
91
|
+
getGetSkillVersionUrl(username, name, version2),
|
|
92
|
+
{
|
|
93
|
+
...options,
|
|
94
|
+
method: "GET"
|
|
95
|
+
}
|
|
96
|
+
);
|
|
97
|
+
};
|
|
98
|
+
getPublishSkillUrl = () => {
|
|
99
|
+
return "/api/skills/publish";
|
|
100
|
+
};
|
|
101
|
+
publishSkill = async (publishSkillInput, options) => {
|
|
102
|
+
return customFetch(getPublishSkillUrl(), {
|
|
103
|
+
...options,
|
|
104
|
+
method: "POST",
|
|
105
|
+
headers: { "Content-Type": "application/json", ...options?.headers },
|
|
106
|
+
body: JSON.stringify(publishSkillInput)
|
|
107
|
+
});
|
|
108
|
+
};
|
|
109
|
+
getDeleteSkillUrl = (name) => {
|
|
110
|
+
return `/api/skills/${name}`;
|
|
111
|
+
};
|
|
112
|
+
deleteSkill = async (name, options) => {
|
|
113
|
+
return customFetch(getDeleteSkillUrl(name), {
|
|
114
|
+
...options,
|
|
115
|
+
method: "DELETE"
|
|
116
|
+
});
|
|
117
|
+
};
|
|
118
|
+
getDeleteSkillVersionUrl = (name, version2) => {
|
|
119
|
+
return `/api/skills/${name}/${version2}`;
|
|
120
|
+
};
|
|
121
|
+
deleteSkillVersion = async (name, version2, options) => {
|
|
122
|
+
return customFetch(
|
|
123
|
+
getDeleteSkillVersionUrl(name, version2),
|
|
124
|
+
{
|
|
125
|
+
...options,
|
|
126
|
+
method: "DELETE"
|
|
127
|
+
}
|
|
128
|
+
);
|
|
129
|
+
};
|
|
130
|
+
}
|
|
131
|
+
});
|
|
227
132
|
|
|
228
133
|
// src/api-client.ts
|
|
229
134
|
function registryUrlToBaseUrl(registryUrl) {
|
|
@@ -345,28 +250,21 @@ async function changeSkillAccess(skillName, input) {
|
|
|
345
250
|
};
|
|
346
251
|
}
|
|
347
252
|
}
|
|
253
|
+
var init_api_client = __esm({
|
|
254
|
+
"src/api-client.ts"() {
|
|
255
|
+
"use strict";
|
|
256
|
+
init_fetcher();
|
|
257
|
+
init_generated();
|
|
258
|
+
}
|
|
259
|
+
});
|
|
348
260
|
|
|
349
261
|
// src/errors.ts
|
|
350
|
-
var ConfigError = class extends Error {
|
|
351
|
-
constructor(message) {
|
|
352
|
-
super(message);
|
|
353
|
-
this.name = "ConfigError";
|
|
354
|
-
}
|
|
355
|
-
};
|
|
356
|
-
var NotLoggedInError = class extends ConfigError {
|
|
357
|
-
constructor() {
|
|
358
|
-
super(
|
|
359
|
-
"Not logged in. Run 'pspm login --api-key <key>' first, or set PSPM_API_KEY env var."
|
|
360
|
-
);
|
|
361
|
-
this.name = "NotLoggedInError";
|
|
362
|
-
}
|
|
363
|
-
};
|
|
364
262
|
function extractApiErrorMessage(response, fallbackMessage) {
|
|
365
263
|
const errorData = response.data;
|
|
366
264
|
if (process.env.PSPM_DEBUG) {
|
|
367
265
|
console.log(`[debug] API response status: ${response.status}`);
|
|
368
266
|
console.log(
|
|
369
|
-
|
|
267
|
+
"[debug] API response data:",
|
|
370
268
|
JSON.stringify(errorData, null, 2)
|
|
371
269
|
);
|
|
372
270
|
}
|
|
@@ -395,9 +293,32 @@ ${issueMessages}`;
|
|
|
395
293
|
}
|
|
396
294
|
return errorMessage;
|
|
397
295
|
}
|
|
296
|
+
var ConfigError, NotLoggedInError;
|
|
297
|
+
var init_errors = __esm({
|
|
298
|
+
"src/errors.ts"() {
|
|
299
|
+
"use strict";
|
|
300
|
+
ConfigError = class extends Error {
|
|
301
|
+
constructor(message) {
|
|
302
|
+
super(message);
|
|
303
|
+
this.name = "ConfigError";
|
|
304
|
+
}
|
|
305
|
+
};
|
|
306
|
+
NotLoggedInError = class extends ConfigError {
|
|
307
|
+
constructor() {
|
|
308
|
+
super(
|
|
309
|
+
"Not logged in. Run 'pspm login --api-key <key>' first, or set PSPM_API_KEY env var."
|
|
310
|
+
);
|
|
311
|
+
this.name = "NotLoggedInError";
|
|
312
|
+
}
|
|
313
|
+
};
|
|
314
|
+
}
|
|
315
|
+
});
|
|
398
316
|
|
|
399
317
|
// src/config.ts
|
|
400
|
-
|
|
318
|
+
import { mkdir, readFile, stat, unlink, writeFile } from "fs/promises";
|
|
319
|
+
import { homedir } from "os";
|
|
320
|
+
import { dirname, join } from "path";
|
|
321
|
+
import * as ini from "ini";
|
|
401
322
|
function getConfigPath() {
|
|
402
323
|
return join(homedir(), ".pspmrc");
|
|
403
324
|
}
|
|
@@ -431,7 +352,7 @@ async function readUserConfig() {
|
|
|
431
352
|
const content = await readFile(configPath, "utf-8");
|
|
432
353
|
const parsed = ini.parse(content);
|
|
433
354
|
if (process.env.PSPM_DEBUG) {
|
|
434
|
-
console.log(
|
|
355
|
+
console.log("[config] Parsed config:", JSON.stringify(parsed, null, 2));
|
|
435
356
|
}
|
|
436
357
|
const scopedRegistries = {};
|
|
437
358
|
for (const key of Object.keys(parsed)) {
|
|
@@ -592,7 +513,7 @@ async function resolveConfig() {
|
|
|
592
513
|
apiKey = process.env.PSPM_API_KEY;
|
|
593
514
|
}
|
|
594
515
|
if (process.env.PSPM_DEBUG) {
|
|
595
|
-
console.log(
|
|
516
|
+
console.log("[config] Resolved config:");
|
|
596
517
|
console.log(`[config] registryUrl: ${registryUrl}`);
|
|
597
518
|
console.log(`[config] apiKey: ${apiKey ? "***" : "(not set)"}`);
|
|
598
519
|
console.log(`[config] username: ${username || "(not set)"}`);
|
|
@@ -636,8 +557,8 @@ async function setCredentials(authToken, username, registry) {
|
|
|
636
557
|
}
|
|
637
558
|
async function clearCredentials() {
|
|
638
559
|
const config2 = await readUserConfig();
|
|
639
|
-
|
|
640
|
-
|
|
560
|
+
config2.authToken = void 0;
|
|
561
|
+
config2.username = void 0;
|
|
641
562
|
await writeUserConfig(config2);
|
|
642
563
|
}
|
|
643
564
|
async function isLoggedIn() {
|
|
@@ -652,7 +573,7 @@ async function requireApiKey() {
|
|
|
652
573
|
const resolved = await resolveConfig();
|
|
653
574
|
if (!resolved.apiKey) {
|
|
654
575
|
if (process.env.PSPM_DEBUG) {
|
|
655
|
-
console.log(
|
|
576
|
+
console.log("[config] requireApiKey: No API key found");
|
|
656
577
|
}
|
|
657
578
|
throw new NotLoggedInError();
|
|
658
579
|
}
|
|
@@ -667,131 +588,146 @@ async function getRegistryUrl() {
|
|
|
667
588
|
const resolved = await resolveConfig();
|
|
668
589
|
return resolved.registryUrl;
|
|
669
590
|
}
|
|
591
|
+
var DEFAULT_REGISTRY_URL;
|
|
592
|
+
var init_config = __esm({
|
|
593
|
+
"src/config.ts"() {
|
|
594
|
+
"use strict";
|
|
595
|
+
init_errors();
|
|
596
|
+
DEFAULT_REGISTRY_URL = "https://pspm.dev";
|
|
597
|
+
}
|
|
598
|
+
});
|
|
670
599
|
|
|
671
|
-
// src/
|
|
672
|
-
|
|
673
|
-
|
|
674
|
-
|
|
675
|
-
|
|
676
|
-
|
|
677
|
-
|
|
678
|
-
|
|
679
|
-
|
|
680
|
-
|
|
681
|
-
|
|
682
|
-
|
|
683
|
-
|
|
684
|
-
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
`Error: Invalid skill specifier "${specifier}". Use format: @user/{username}/{name}`
|
|
691
|
-
);
|
|
692
|
-
process.exit(1);
|
|
693
|
-
}
|
|
694
|
-
packageName = parsed.name;
|
|
695
|
-
} else {
|
|
696
|
-
const { readFile: readFile7 } = await import('fs/promises');
|
|
697
|
-
const { join: join13 } = await import('path');
|
|
698
|
-
let manifest = null;
|
|
699
|
-
try {
|
|
700
|
-
const content = await readFile7(
|
|
701
|
-
join13(process.cwd(), "pspm.json"),
|
|
702
|
-
"utf-8"
|
|
703
|
-
);
|
|
704
|
-
manifest = JSON.parse(content);
|
|
705
|
-
} catch {
|
|
706
|
-
try {
|
|
707
|
-
const content = await readFile7(
|
|
708
|
-
join13(process.cwd(), "package.json"),
|
|
709
|
-
"utf-8"
|
|
710
|
-
);
|
|
711
|
-
manifest = JSON.parse(content);
|
|
712
|
-
} catch {
|
|
713
|
-
console.error(
|
|
714
|
-
"Error: No pspm.json or package.json found in current directory"
|
|
715
|
-
);
|
|
716
|
-
console.error(
|
|
717
|
-
"Either run this command in a package directory or specify a package name"
|
|
718
|
-
);
|
|
719
|
-
process.exit(1);
|
|
720
|
-
}
|
|
721
|
-
}
|
|
722
|
-
if (!manifest?.name) {
|
|
723
|
-
console.error("Error: Package manifest is missing 'name' field");
|
|
724
|
-
process.exit(1);
|
|
725
|
-
}
|
|
726
|
-
packageName = manifest.name;
|
|
727
|
-
}
|
|
728
|
-
configure2({ registryUrl, apiKey });
|
|
729
|
-
console.log(`Setting ${packageName} to ${visibility}...`);
|
|
730
|
-
const response = await changeSkillAccess(packageName, { visibility });
|
|
731
|
-
if (response.status !== 200 || !response.data) {
|
|
732
|
-
const errorMessage = response.error ?? "Failed to change visibility";
|
|
733
|
-
console.error(`Error: ${errorMessage}`);
|
|
734
|
-
process.exit(1);
|
|
735
|
-
}
|
|
736
|
-
const result = response.data;
|
|
737
|
-
console.log(
|
|
738
|
-
`+ @user/${result.username}/${result.name} is now ${result.visibility}`
|
|
739
|
-
);
|
|
740
|
-
if (visibility === "public") {
|
|
741
|
-
console.log("");
|
|
742
|
-
console.log(
|
|
743
|
-
"Note: This action is irreversible. Public packages cannot be made private."
|
|
744
|
-
);
|
|
745
|
-
}
|
|
746
|
-
} catch (error) {
|
|
747
|
-
const message = error instanceof Error ? error.message : "Unknown error";
|
|
748
|
-
console.error(`Error: ${message}`);
|
|
749
|
-
process.exit(1);
|
|
600
|
+
// src/lib/integrity.ts
|
|
601
|
+
import { createHash } from "crypto";
|
|
602
|
+
function calculateIntegrity(data) {
|
|
603
|
+
const hash = createHash("sha256").update(data).digest("base64");
|
|
604
|
+
return `sha256-${hash}`;
|
|
605
|
+
}
|
|
606
|
+
var init_integrity = __esm({
|
|
607
|
+
"src/lib/integrity.ts"() {
|
|
608
|
+
"use strict";
|
|
609
|
+
}
|
|
610
|
+
});
|
|
611
|
+
|
|
612
|
+
// src/lib/manifest.ts
|
|
613
|
+
function validateManifest(manifest) {
|
|
614
|
+
if (!manifest.name) {
|
|
615
|
+
return { valid: false, error: "Manifest must have a 'name' field" };
|
|
616
|
+
}
|
|
617
|
+
if (!manifest.version) {
|
|
618
|
+
return { valid: false, error: "Manifest must have a 'version' field" };
|
|
750
619
|
}
|
|
620
|
+
if (!/^[a-z][a-z0-9_-]*$/.test(manifest.name)) {
|
|
621
|
+
return {
|
|
622
|
+
valid: false,
|
|
623
|
+
error: "Name must start with a lowercase letter and contain only lowercase letters, numbers, hyphens, and underscores"
|
|
624
|
+
};
|
|
625
|
+
}
|
|
626
|
+
if (!/^\d+\.\d+\.\d+/.test(manifest.version)) {
|
|
627
|
+
return {
|
|
628
|
+
valid: false,
|
|
629
|
+
error: "Version must be a valid semantic version (e.g., 1.0.0)"
|
|
630
|
+
};
|
|
631
|
+
}
|
|
632
|
+
return { valid: true };
|
|
751
633
|
}
|
|
752
|
-
var
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
758
|
-
|
|
759
|
-
|
|
760
|
-
|
|
761
|
-
|
|
762
|
-
|
|
763
|
-
skillsDir: ".cursor/skills"
|
|
764
|
-
},
|
|
765
|
-
gemini: {
|
|
766
|
-
displayName: "Gemini CLI",
|
|
767
|
-
skillsDir: ".gemini/skills"
|
|
768
|
-
},
|
|
769
|
-
kiro: {
|
|
770
|
-
displayName: "Kiro CLI",
|
|
771
|
-
skillsDir: ".kiro/skills"
|
|
772
|
-
},
|
|
773
|
-
opencode: {
|
|
774
|
-
displayName: "OpenCode",
|
|
775
|
-
skillsDir: ".opencode/skills"
|
|
634
|
+
var DEFAULT_SKILL_FILES, PSPM_SCHEMA_URL;
|
|
635
|
+
var init_manifest = __esm({
|
|
636
|
+
"src/lib/manifest.ts"() {
|
|
637
|
+
"use strict";
|
|
638
|
+
DEFAULT_SKILL_FILES = [
|
|
639
|
+
"SKILL.md",
|
|
640
|
+
"runtime",
|
|
641
|
+
"scripts",
|
|
642
|
+
"data"
|
|
643
|
+
];
|
|
644
|
+
PSPM_SCHEMA_URL = "https://pspm.dev/schema/v1/pspm.json";
|
|
776
645
|
}
|
|
777
|
-
};
|
|
778
|
-
|
|
779
|
-
|
|
780
|
-
|
|
781
|
-
|
|
782
|
-
|
|
783
|
-
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
|
|
788
|
-
|
|
789
|
-
|
|
790
|
-
|
|
791
|
-
|
|
792
|
-
|
|
793
|
-
|
|
794
|
-
|
|
646
|
+
});
|
|
647
|
+
|
|
648
|
+
// src/lib/specifier.ts
|
|
649
|
+
function parseSkillSpecifier(specifier) {
|
|
650
|
+
const match = specifier.match(SPECIFIER_PATTERN);
|
|
651
|
+
if (!match) {
|
|
652
|
+
return null;
|
|
653
|
+
}
|
|
654
|
+
return {
|
|
655
|
+
username: match[1],
|
|
656
|
+
name: match[2],
|
|
657
|
+
versionRange: match[3]
|
|
658
|
+
};
|
|
659
|
+
}
|
|
660
|
+
function parseGitHubSpecifier(specifier) {
|
|
661
|
+
const match = specifier.match(GITHUB_SPECIFIER_PATTERN);
|
|
662
|
+
if (!match) {
|
|
663
|
+
return null;
|
|
664
|
+
}
|
|
665
|
+
const [, owner, repo, pathWithSlash, ref] = match;
|
|
666
|
+
return {
|
|
667
|
+
owner,
|
|
668
|
+
repo,
|
|
669
|
+
// Remove leading slash from path
|
|
670
|
+
path: pathWithSlash ? pathWithSlash.slice(1) : void 0,
|
|
671
|
+
ref: ref || void 0
|
|
672
|
+
};
|
|
673
|
+
}
|
|
674
|
+
function formatGitHubSpecifier(spec) {
|
|
675
|
+
let result = `github:${spec.owner}/${spec.repo}`;
|
|
676
|
+
if (spec.path) {
|
|
677
|
+
result += `/${spec.path}`;
|
|
678
|
+
}
|
|
679
|
+
if (spec.ref) {
|
|
680
|
+
result += `@${spec.ref}`;
|
|
681
|
+
}
|
|
682
|
+
return result;
|
|
683
|
+
}
|
|
684
|
+
function getGitHubSkillName(spec) {
|
|
685
|
+
if (spec.path) {
|
|
686
|
+
const segments = spec.path.split("/").filter(Boolean);
|
|
687
|
+
return segments[segments.length - 1];
|
|
688
|
+
}
|
|
689
|
+
return spec.repo;
|
|
690
|
+
}
|
|
691
|
+
function isGitHubSpecifier(specifier) {
|
|
692
|
+
return specifier.startsWith("github:");
|
|
693
|
+
}
|
|
694
|
+
var SPECIFIER_PATTERN, GITHUB_SPECIFIER_PATTERN;
|
|
695
|
+
var init_specifier = __esm({
|
|
696
|
+
"src/lib/specifier.ts"() {
|
|
697
|
+
"use strict";
|
|
698
|
+
SPECIFIER_PATTERN = /^@user\/([a-zA-Z0-9_-]+)\/([a-z][a-z0-9_-]*)(?:@(.+))?$/;
|
|
699
|
+
GITHUB_SPECIFIER_PATTERN = /^github:([a-zA-Z0-9_-]+)\/([a-zA-Z0-9_.-]+)(\/[^@]+)?(?:@(.+))?$/;
|
|
700
|
+
}
|
|
701
|
+
});
|
|
702
|
+
|
|
703
|
+
// src/lib/version.ts
|
|
704
|
+
import * as semver from "semver";
|
|
705
|
+
function resolveVersion(range, availableVersions) {
|
|
706
|
+
const sorted = availableVersions.filter((v) => semver.valid(v)).sort((a, b) => semver.rcompare(a, b));
|
|
707
|
+
if (!range || range === "latest" || range === "*") {
|
|
708
|
+
return sorted[0] ?? null;
|
|
709
|
+
}
|
|
710
|
+
return semver.maxSatisfying(sorted, range);
|
|
711
|
+
}
|
|
712
|
+
var init_version = __esm({
|
|
713
|
+
"src/lib/version.ts"() {
|
|
714
|
+
"use strict";
|
|
715
|
+
}
|
|
716
|
+
});
|
|
717
|
+
|
|
718
|
+
// src/lib/index.ts
|
|
719
|
+
var init_lib = __esm({
|
|
720
|
+
"src/lib/index.ts"() {
|
|
721
|
+
"use strict";
|
|
722
|
+
init_integrity();
|
|
723
|
+
init_manifest();
|
|
724
|
+
init_specifier();
|
|
725
|
+
init_version();
|
|
726
|
+
}
|
|
727
|
+
});
|
|
728
|
+
|
|
729
|
+
// src/agents.ts
|
|
730
|
+
import { checkbox } from "@inquirer/prompts";
|
|
795
731
|
function resolveAgentConfig(name, overrides) {
|
|
796
732
|
if (overrides?.[name]) {
|
|
797
733
|
return overrides[name];
|
|
@@ -803,7 +739,7 @@ function resolveAgentConfig(name, overrides) {
|
|
|
803
739
|
}
|
|
804
740
|
function parseAgentArg(agentArg) {
|
|
805
741
|
if (!agentArg) {
|
|
806
|
-
return [
|
|
742
|
+
return [...ALL_AGENTS];
|
|
807
743
|
}
|
|
808
744
|
if (agentArg === "none") {
|
|
809
745
|
return ["none"];
|
|
@@ -831,35 +767,58 @@ async function promptForAgents() {
|
|
|
831
767
|
}
|
|
832
768
|
return selected;
|
|
833
769
|
}
|
|
834
|
-
var
|
|
835
|
-
|
|
836
|
-
|
|
837
|
-
|
|
838
|
-
|
|
839
|
-
|
|
840
|
-
|
|
841
|
-
|
|
842
|
-
|
|
843
|
-
|
|
844
|
-
|
|
845
|
-
|
|
846
|
-
|
|
847
|
-
|
|
848
|
-
|
|
849
|
-
|
|
850
|
-
|
|
851
|
-
|
|
852
|
-
|
|
853
|
-
|
|
854
|
-
|
|
855
|
-
|
|
856
|
-
|
|
857
|
-
|
|
858
|
-
|
|
859
|
-
|
|
860
|
-
|
|
770
|
+
var AGENT_INFO, DEFAULT_AGENT_CONFIGS, ALL_AGENTS;
|
|
771
|
+
var init_agents = __esm({
|
|
772
|
+
"src/agents.ts"() {
|
|
773
|
+
"use strict";
|
|
774
|
+
AGENT_INFO = {
|
|
775
|
+
"claude-code": {
|
|
776
|
+
displayName: "Claude Code",
|
|
777
|
+
skillsDir: ".claude/skills"
|
|
778
|
+
},
|
|
779
|
+
codex: {
|
|
780
|
+
displayName: "Codex",
|
|
781
|
+
skillsDir: ".codex/skills"
|
|
782
|
+
},
|
|
783
|
+
cursor: {
|
|
784
|
+
displayName: "Cursor",
|
|
785
|
+
skillsDir: ".cursor/skills"
|
|
786
|
+
},
|
|
787
|
+
gemini: {
|
|
788
|
+
displayName: "Gemini CLI",
|
|
789
|
+
skillsDir: ".gemini/skills"
|
|
790
|
+
},
|
|
791
|
+
kiro: {
|
|
792
|
+
displayName: "Kiro CLI",
|
|
793
|
+
skillsDir: ".kiro/skills"
|
|
794
|
+
},
|
|
795
|
+
opencode: {
|
|
796
|
+
displayName: "OpenCode",
|
|
797
|
+
skillsDir: ".opencode/skills"
|
|
798
|
+
}
|
|
799
|
+
};
|
|
800
|
+
DEFAULT_AGENT_CONFIGS = {
|
|
801
|
+
"claude-code": { skillsDir: AGENT_INFO["claude-code"].skillsDir },
|
|
802
|
+
codex: { skillsDir: AGENT_INFO.codex.skillsDir },
|
|
803
|
+
cursor: { skillsDir: AGENT_INFO.cursor.skillsDir },
|
|
804
|
+
gemini: { skillsDir: AGENT_INFO.gemini.skillsDir },
|
|
805
|
+
kiro: { skillsDir: AGENT_INFO.kiro.skillsDir },
|
|
806
|
+
opencode: { skillsDir: AGENT_INFO.opencode.skillsDir }
|
|
807
|
+
};
|
|
808
|
+
ALL_AGENTS = [
|
|
809
|
+
"claude-code",
|
|
810
|
+
"codex",
|
|
811
|
+
"cursor",
|
|
812
|
+
"gemini",
|
|
813
|
+
"kiro",
|
|
814
|
+
"opencode"
|
|
815
|
+
];
|
|
861
816
|
}
|
|
862
|
-
};
|
|
817
|
+
});
|
|
818
|
+
|
|
819
|
+
// src/github.ts
|
|
820
|
+
import { cp, lstat, mkdir as mkdir2, readdir, rm, writeFile as writeFile2 } from "fs/promises";
|
|
821
|
+
import { join as join2 } from "path";
|
|
863
822
|
function getGitHubHeaders() {
|
|
864
823
|
const headers = {
|
|
865
824
|
Accept: "application/vnd.github+json",
|
|
@@ -874,7 +833,8 @@ function getGitHubHeaders() {
|
|
|
874
833
|
}
|
|
875
834
|
async function resolveGitHubRef(owner, repo, ref) {
|
|
876
835
|
const headers = getGitHubHeaders();
|
|
877
|
-
|
|
836
|
+
let resolvedRef = ref;
|
|
837
|
+
if (!resolvedRef || resolvedRef === "latest") {
|
|
878
838
|
const repoUrl = `https://api.github.com/repos/${owner}/${repo}`;
|
|
879
839
|
const repoResponse = await fetch(repoUrl, { headers });
|
|
880
840
|
if (repoResponse.status === 404) {
|
|
@@ -890,9 +850,9 @@ async function resolveGitHubRef(owner, repo, ref) {
|
|
|
890
850
|
throw new Error(`GitHub API error: ${repoResponse.status}`);
|
|
891
851
|
}
|
|
892
852
|
const repoData = await repoResponse.json();
|
|
893
|
-
|
|
853
|
+
resolvedRef = repoData.default_branch;
|
|
894
854
|
}
|
|
895
|
-
const commitUrl = `https://api.github.com/repos/${owner}/${repo}/commits/${
|
|
855
|
+
const commitUrl = `https://api.github.com/repos/${owner}/${repo}/commits/${resolvedRef}`;
|
|
896
856
|
const commitResponse = await fetch(commitUrl, { headers });
|
|
897
857
|
if (commitResponse.status === 404) {
|
|
898
858
|
throw new GitHubNotFoundError({ owner, repo, ref });
|
|
@@ -934,14 +894,14 @@ async function downloadGitHubPackage(spec) {
|
|
|
934
894
|
return { buffer, commit, integrity };
|
|
935
895
|
}
|
|
936
896
|
async function extractGitHubPackage(spec, buffer, skillsDir) {
|
|
937
|
-
const destPath = spec.path ?
|
|
938
|
-
const tempDir =
|
|
939
|
-
await
|
|
940
|
-
const tempFile =
|
|
897
|
+
const destPath = spec.path ? join2(skillsDir, "_github", spec.owner, spec.repo, spec.path) : join2(skillsDir, "_github", spec.owner, spec.repo);
|
|
898
|
+
const tempDir = join2(skillsDir, "_github", ".temp", `${Date.now()}`);
|
|
899
|
+
await mkdir2(tempDir, { recursive: true });
|
|
900
|
+
const tempFile = join2(tempDir, "archive.tgz");
|
|
941
901
|
try {
|
|
942
|
-
await
|
|
943
|
-
const { exec: exec2 } = await import(
|
|
944
|
-
const { promisify: promisify2 } = await import(
|
|
902
|
+
await writeFile2(tempFile, buffer);
|
|
903
|
+
const { exec: exec2 } = await import("child_process");
|
|
904
|
+
const { promisify: promisify2 } = await import("util");
|
|
945
905
|
const execAsync = promisify2(exec2);
|
|
946
906
|
await execAsync(`tar -xzf "${tempFile}" -C "${tempDir}"`);
|
|
947
907
|
const entries = await readdir(tempDir);
|
|
@@ -951,15 +911,15 @@ async function extractGitHubPackage(spec, buffer, skillsDir) {
|
|
|
951
911
|
if (!extractedDir) {
|
|
952
912
|
throw new Error("Failed to find extracted directory in tarball");
|
|
953
913
|
}
|
|
954
|
-
const sourcePath =
|
|
955
|
-
const copySource = spec.path ?
|
|
914
|
+
const sourcePath = join2(tempDir, extractedDir);
|
|
915
|
+
const copySource = spec.path ? join2(sourcePath, spec.path) : sourcePath;
|
|
956
916
|
if (spec.path) {
|
|
957
917
|
const pathExists = await lstat(copySource).catch(() => null);
|
|
958
918
|
if (!pathExists) {
|
|
959
919
|
const rootEntries = await readdir(sourcePath);
|
|
960
920
|
const dirs = [];
|
|
961
921
|
for (const entry of rootEntries) {
|
|
962
|
-
const stat7 = await lstat(
|
|
922
|
+
const stat7 = await lstat(join2(sourcePath, entry)).catch(() => null);
|
|
963
923
|
if (stat7?.isDirectory() && !entry.startsWith(".")) {
|
|
964
924
|
dirs.push(entry);
|
|
965
925
|
}
|
|
@@ -968,7 +928,7 @@ async function extractGitHubPackage(spec, buffer, skillsDir) {
|
|
|
968
928
|
}
|
|
969
929
|
}
|
|
970
930
|
await rm(destPath, { recursive: true, force: true });
|
|
971
|
-
await
|
|
931
|
+
await mkdir2(destPath, { recursive: true });
|
|
972
932
|
await cp(copySource, destPath, { recursive: true });
|
|
973
933
|
return spec.path ? `.pspm/skills/_github/${spec.owner}/${spec.repo}/${spec.path}` : `.pspm/skills/_github/${spec.owner}/${spec.repo}`;
|
|
974
934
|
} finally {
|
|
@@ -982,13 +942,54 @@ function getGitHubDisplayName(spec, commit) {
|
|
|
982
942
|
}
|
|
983
943
|
if (spec.ref || commit) {
|
|
984
944
|
const ref = spec.ref || "HEAD";
|
|
985
|
-
|
|
945
|
+
const shortCommit = commit ? commit.slice(0, 7) : "";
|
|
946
|
+
name += ` (${ref}${shortCommit ? `@${shortCommit}` : ""})`;
|
|
986
947
|
}
|
|
987
948
|
return name;
|
|
988
949
|
}
|
|
950
|
+
var GitHubRateLimitError, GitHubNotFoundError, GitHubPathNotFoundError;
|
|
951
|
+
var init_github = __esm({
|
|
952
|
+
"src/github.ts"() {
|
|
953
|
+
"use strict";
|
|
954
|
+
init_lib();
|
|
955
|
+
GitHubRateLimitError = class extends Error {
|
|
956
|
+
constructor() {
|
|
957
|
+
super(
|
|
958
|
+
"GitHub API rate limit exceeded. Set GITHUB_TOKEN environment variable for higher limits."
|
|
959
|
+
);
|
|
960
|
+
this.name = "GitHubRateLimitError";
|
|
961
|
+
}
|
|
962
|
+
};
|
|
963
|
+
GitHubNotFoundError = class extends Error {
|
|
964
|
+
constructor(spec) {
|
|
965
|
+
const path = spec.path ? `/${spec.path}` : "";
|
|
966
|
+
const ref = spec.ref ? `@${spec.ref}` : "";
|
|
967
|
+
super(
|
|
968
|
+
`GitHub repository not found: ${spec.owner}/${spec.repo}${path}${ref}`
|
|
969
|
+
);
|
|
970
|
+
this.name = "GitHubNotFoundError";
|
|
971
|
+
}
|
|
972
|
+
};
|
|
973
|
+
GitHubPathNotFoundError = class extends Error {
|
|
974
|
+
constructor(spec, availablePaths) {
|
|
975
|
+
const pathInfo = availablePaths?.length ? `
|
|
976
|
+
Available paths in repository root:
|
|
977
|
+
${availablePaths.join("\n ")}` : "";
|
|
978
|
+
super(
|
|
979
|
+
`Path "${spec.path}" not found in ${spec.owner}/${spec.repo}${pathInfo}`
|
|
980
|
+
);
|
|
981
|
+
this.name = "GitHubPathNotFoundError";
|
|
982
|
+
}
|
|
983
|
+
};
|
|
984
|
+
}
|
|
985
|
+
});
|
|
986
|
+
|
|
987
|
+
// src/lockfile.ts
|
|
988
|
+
import { mkdir as mkdir3, readFile as readFile2, stat as stat2, writeFile as writeFile3 } from "fs/promises";
|
|
989
|
+
import { dirname as dirname2 } from "path";
|
|
989
990
|
async function hasLegacyLockfile() {
|
|
990
991
|
try {
|
|
991
|
-
await
|
|
992
|
+
await stat2(getLegacyLockfilePath());
|
|
992
993
|
return true;
|
|
993
994
|
} catch {
|
|
994
995
|
return false;
|
|
@@ -998,26 +999,26 @@ async function migrateLockfileIfNeeded() {
|
|
|
998
999
|
const legacyPath = getLegacyLockfilePath();
|
|
999
1000
|
const newPath = getLockfilePath();
|
|
1000
1001
|
try {
|
|
1001
|
-
await
|
|
1002
|
+
await stat2(legacyPath);
|
|
1002
1003
|
} catch {
|
|
1003
1004
|
return false;
|
|
1004
1005
|
}
|
|
1005
1006
|
try {
|
|
1006
|
-
await
|
|
1007
|
+
await stat2(newPath);
|
|
1007
1008
|
return false;
|
|
1008
1009
|
} catch {
|
|
1009
1010
|
}
|
|
1010
1011
|
try {
|
|
1011
|
-
const content = await
|
|
1012
|
+
const content = await readFile2(legacyPath, "utf-8");
|
|
1012
1013
|
const oldLockfile = JSON.parse(content);
|
|
1013
1014
|
const newLockfile = {
|
|
1014
1015
|
lockfileVersion: 2,
|
|
1015
1016
|
registryUrl: oldLockfile.registryUrl,
|
|
1016
1017
|
packages: oldLockfile.skills ?? {}
|
|
1017
1018
|
};
|
|
1018
|
-
await
|
|
1019
|
+
await writeFile3(newPath, `${JSON.stringify(newLockfile, null, 2)}
|
|
1019
1020
|
`);
|
|
1020
|
-
console.log(
|
|
1021
|
+
console.log("Migrated lockfile: skill-lock.json \u2192 pspm-lock.json");
|
|
1021
1022
|
return true;
|
|
1022
1023
|
} catch {
|
|
1023
1024
|
return false;
|
|
@@ -1026,7 +1027,7 @@ async function migrateLockfileIfNeeded() {
|
|
|
1026
1027
|
async function readLockfile() {
|
|
1027
1028
|
const lockfilePath = getLockfilePath();
|
|
1028
1029
|
try {
|
|
1029
|
-
const content = await
|
|
1030
|
+
const content = await readFile2(lockfilePath, "utf-8");
|
|
1030
1031
|
const lockfile = JSON.parse(content);
|
|
1031
1032
|
if (lockfile.lockfileVersion === 1 && lockfile.skills && !lockfile.packages) {
|
|
1032
1033
|
return {
|
|
@@ -1039,7 +1040,7 @@ async function readLockfile() {
|
|
|
1039
1040
|
} catch {
|
|
1040
1041
|
if (await hasLegacyLockfile()) {
|
|
1041
1042
|
try {
|
|
1042
|
-
const content = await
|
|
1043
|
+
const content = await readFile2(getLegacyLockfilePath(), "utf-8");
|
|
1043
1044
|
const legacyLockfile = JSON.parse(content);
|
|
1044
1045
|
return {
|
|
1045
1046
|
lockfileVersion: 2,
|
|
@@ -1055,7 +1056,7 @@ async function readLockfile() {
|
|
|
1055
1056
|
}
|
|
1056
1057
|
async function writeLockfile(lockfile) {
|
|
1057
1058
|
const lockfilePath = getLockfilePath();
|
|
1058
|
-
await
|
|
1059
|
+
await mkdir3(dirname2(lockfilePath), { recursive: true });
|
|
1059
1060
|
const normalized = {
|
|
1060
1061
|
lockfileVersion: 3,
|
|
1061
1062
|
registryUrl: lockfile.registryUrl,
|
|
@@ -1064,7 +1065,7 @@ async function writeLockfile(lockfile) {
|
|
|
1064
1065
|
if (lockfile.githubPackages && Object.keys(lockfile.githubPackages).length > 0) {
|
|
1065
1066
|
normalized.githubPackages = lockfile.githubPackages;
|
|
1066
1067
|
}
|
|
1067
|
-
await
|
|
1068
|
+
await writeFile3(lockfilePath, `${JSON.stringify(normalized, null, 2)}
|
|
1068
1069
|
`);
|
|
1069
1070
|
}
|
|
1070
1071
|
async function createEmptyLockfile() {
|
|
@@ -1143,12 +1144,22 @@ async function listLockfileGitHubPackages() {
|
|
|
1143
1144
|
entry
|
|
1144
1145
|
}));
|
|
1145
1146
|
}
|
|
1147
|
+
var init_lockfile = __esm({
|
|
1148
|
+
"src/lockfile.ts"() {
|
|
1149
|
+
"use strict";
|
|
1150
|
+
init_config();
|
|
1151
|
+
}
|
|
1152
|
+
});
|
|
1153
|
+
|
|
1154
|
+
// src/manifest.ts
|
|
1155
|
+
import { readFile as readFile3, writeFile as writeFile4 } from "fs/promises";
|
|
1156
|
+
import { join as join3 } from "path";
|
|
1146
1157
|
function getManifestPath() {
|
|
1147
|
-
return
|
|
1158
|
+
return join3(process.cwd(), "pspm.json");
|
|
1148
1159
|
}
|
|
1149
1160
|
async function readManifest() {
|
|
1150
1161
|
try {
|
|
1151
|
-
const content = await
|
|
1162
|
+
const content = await readFile3(getManifestPath(), "utf-8");
|
|
1152
1163
|
return JSON.parse(content);
|
|
1153
1164
|
} catch {
|
|
1154
1165
|
return null;
|
|
@@ -1156,7 +1167,7 @@ async function readManifest() {
|
|
|
1156
1167
|
}
|
|
1157
1168
|
async function writeManifest(manifest) {
|
|
1158
1169
|
const content = JSON.stringify(manifest, null, 2);
|
|
1159
|
-
await
|
|
1170
|
+
await writeFile4(getManifestPath(), `${content}
|
|
1160
1171
|
`);
|
|
1161
1172
|
}
|
|
1162
1173
|
async function createMinimalManifest() {
|
|
@@ -1214,6 +1225,15 @@ async function removeGitHubDependency(specifier) {
|
|
|
1214
1225
|
await writeManifest(manifest);
|
|
1215
1226
|
return true;
|
|
1216
1227
|
}
|
|
1228
|
+
var init_manifest2 = __esm({
|
|
1229
|
+
"src/manifest.ts"() {
|
|
1230
|
+
"use strict";
|
|
1231
|
+
}
|
|
1232
|
+
});
|
|
1233
|
+
|
|
1234
|
+
// src/symlinks.ts
|
|
1235
|
+
import { lstat as lstat2, mkdir as mkdir4, readlink, rm as rm2, symlink } from "fs/promises";
|
|
1236
|
+
import { dirname as dirname3, join as join4, relative } from "path";
|
|
1217
1237
|
async function createAgentSymlinks(skills, options) {
|
|
1218
1238
|
const { agents, projectRoot, agentConfigs } = options;
|
|
1219
1239
|
if (agents.length === 1 && agents[0] === "none") {
|
|
@@ -1225,26 +1245,26 @@ async function createAgentSymlinks(skills, options) {
|
|
|
1225
1245
|
console.warn(`Warning: Unknown agent "${agentName}", skipping symlinks`);
|
|
1226
1246
|
continue;
|
|
1227
1247
|
}
|
|
1228
|
-
const agentSkillsDir =
|
|
1229
|
-
await
|
|
1248
|
+
const agentSkillsDir = join4(projectRoot, config2.skillsDir);
|
|
1249
|
+
await mkdir4(agentSkillsDir, { recursive: true });
|
|
1230
1250
|
for (const skill of skills) {
|
|
1231
|
-
const symlinkPath =
|
|
1232
|
-
const targetPath =
|
|
1233
|
-
const relativeTarget = relative(
|
|
1251
|
+
const symlinkPath = join4(agentSkillsDir, skill.name);
|
|
1252
|
+
const targetPath = join4(projectRoot, skill.sourcePath);
|
|
1253
|
+
const relativeTarget = relative(dirname3(symlinkPath), targetPath);
|
|
1234
1254
|
await createSymlink(symlinkPath, relativeTarget, skill.name);
|
|
1235
1255
|
}
|
|
1236
1256
|
}
|
|
1237
1257
|
}
|
|
1238
1258
|
async function createSymlink(symlinkPath, target, skillName) {
|
|
1239
1259
|
try {
|
|
1240
|
-
const stats = await
|
|
1260
|
+
const stats = await lstat2(symlinkPath).catch(() => null);
|
|
1241
1261
|
if (stats) {
|
|
1242
1262
|
if (stats.isSymbolicLink()) {
|
|
1243
1263
|
const existingTarget = await readlink(symlinkPath);
|
|
1244
1264
|
if (existingTarget === target) {
|
|
1245
1265
|
return;
|
|
1246
1266
|
}
|
|
1247
|
-
await
|
|
1267
|
+
await rm2(symlinkPath);
|
|
1248
1268
|
} else {
|
|
1249
1269
|
console.warn(
|
|
1250
1270
|
`Warning: File exists at symlink path for "${skillName}", skipping: ${symlinkPath}`
|
|
@@ -1270,11 +1290,11 @@ async function removeAgentSymlinks(skillName, options) {
|
|
|
1270
1290
|
if (!config2) {
|
|
1271
1291
|
continue;
|
|
1272
1292
|
}
|
|
1273
|
-
const symlinkPath =
|
|
1293
|
+
const symlinkPath = join4(projectRoot, config2.skillsDir, skillName);
|
|
1274
1294
|
try {
|
|
1275
|
-
const stats = await
|
|
1295
|
+
const stats = await lstat2(symlinkPath).catch(() => null);
|
|
1276
1296
|
if (stats?.isSymbolicLink()) {
|
|
1277
|
-
await
|
|
1297
|
+
await rm2(symlinkPath);
|
|
1278
1298
|
}
|
|
1279
1299
|
} catch {
|
|
1280
1300
|
}
|
|
@@ -1294,20 +1314,61 @@ async function getLinkedAgents(skillName, agents, projectRoot, agentConfigs) {
|
|
|
1294
1314
|
for (const agentName of agents) {
|
|
1295
1315
|
const config2 = resolveAgentConfig(agentName, agentConfigs);
|
|
1296
1316
|
if (!config2) continue;
|
|
1297
|
-
const symlinkPath =
|
|
1317
|
+
const symlinkPath = join4(projectRoot, config2.skillsDir, skillName);
|
|
1298
1318
|
try {
|
|
1299
|
-
const stats = await
|
|
1319
|
+
const stats = await lstat2(symlinkPath);
|
|
1300
1320
|
if (stats.isSymbolicLink()) {
|
|
1301
1321
|
linkedAgents.push(agentName);
|
|
1302
1322
|
}
|
|
1303
1323
|
} catch {
|
|
1304
1324
|
}
|
|
1305
1325
|
}
|
|
1306
|
-
return linkedAgents;
|
|
1307
|
-
}
|
|
1308
|
-
|
|
1309
|
-
|
|
1310
|
-
|
|
1326
|
+
return linkedAgents;
|
|
1327
|
+
}
|
|
1328
|
+
var init_symlinks = __esm({
|
|
1329
|
+
"src/symlinks.ts"() {
|
|
1330
|
+
"use strict";
|
|
1331
|
+
init_agents();
|
|
1332
|
+
}
|
|
1333
|
+
});
|
|
1334
|
+
|
|
1335
|
+
// src/commands/add.ts
|
|
1336
|
+
var add_exports = {};
|
|
1337
|
+
__export(add_exports, {
|
|
1338
|
+
add: () => add
|
|
1339
|
+
});
|
|
1340
|
+
import { mkdir as mkdir5, rm as rm3 } from "fs/promises";
|
|
1341
|
+
import { join as join5 } from "path";
|
|
1342
|
+
async function add(specifiers, options) {
|
|
1343
|
+
console.log("Resolving packages...\n");
|
|
1344
|
+
const resolvedPackages = [];
|
|
1345
|
+
const validationErrors = [];
|
|
1346
|
+
for (const specifier of specifiers) {
|
|
1347
|
+
try {
|
|
1348
|
+
if (isGitHubSpecifier(specifier)) {
|
|
1349
|
+
const resolved = await validateGitHubPackage(specifier);
|
|
1350
|
+
resolvedPackages.push(resolved);
|
|
1351
|
+
} else {
|
|
1352
|
+
const resolved = await validateRegistryPackage(specifier);
|
|
1353
|
+
resolvedPackages.push(resolved);
|
|
1354
|
+
}
|
|
1355
|
+
} catch (error) {
|
|
1356
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
1357
|
+
validationErrors.push({ specifier, error: message });
|
|
1358
|
+
console.error(`Failed to resolve ${specifier}: ${message}
|
|
1359
|
+
`);
|
|
1360
|
+
}
|
|
1361
|
+
}
|
|
1362
|
+
if (resolvedPackages.length === 0) {
|
|
1363
|
+
console.error("No packages could be resolved.");
|
|
1364
|
+
process.exit(1);
|
|
1365
|
+
}
|
|
1366
|
+
if (validationErrors.length > 0) {
|
|
1367
|
+
console.log(
|
|
1368
|
+
`Resolved ${resolvedPackages.length} of ${specifiers.length} packages.
|
|
1369
|
+
`
|
|
1370
|
+
);
|
|
1371
|
+
}
|
|
1311
1372
|
let agents;
|
|
1312
1373
|
const manifest = await readManifest();
|
|
1313
1374
|
if (options.agent) {
|
|
@@ -1319,216 +1380,359 @@ async function add(specifier, options) {
|
|
|
1319
1380
|
} else {
|
|
1320
1381
|
console.log("No pspm.json found. Let's set up your project.\n");
|
|
1321
1382
|
agents = await promptForAgents();
|
|
1383
|
+
console.log();
|
|
1322
1384
|
}
|
|
1323
|
-
|
|
1324
|
-
|
|
1325
|
-
|
|
1326
|
-
|
|
1385
|
+
const results = [];
|
|
1386
|
+
for (const resolved of resolvedPackages) {
|
|
1387
|
+
try {
|
|
1388
|
+
if (resolved.type === "github") {
|
|
1389
|
+
await installGitHubPackage(resolved, {
|
|
1390
|
+
...options,
|
|
1391
|
+
resolvedAgents: agents
|
|
1392
|
+
});
|
|
1393
|
+
} else {
|
|
1394
|
+
await installRegistryPackage(resolved, {
|
|
1395
|
+
...options,
|
|
1396
|
+
resolvedAgents: agents
|
|
1397
|
+
});
|
|
1398
|
+
}
|
|
1399
|
+
results.push({ specifier: resolved.specifier, success: true });
|
|
1400
|
+
} catch (error) {
|
|
1401
|
+
const message = error instanceof Error ? error.message : "Unknown error";
|
|
1402
|
+
results.push({
|
|
1403
|
+
specifier: resolved.specifier,
|
|
1404
|
+
success: false,
|
|
1405
|
+
error: message
|
|
1406
|
+
});
|
|
1407
|
+
console.error(`Failed to install ${resolved.specifier}: ${message}
|
|
1408
|
+
`);
|
|
1409
|
+
}
|
|
1410
|
+
}
|
|
1411
|
+
if (specifiers.length > 1) {
|
|
1412
|
+
const succeeded = results.filter((r) => r.success).length;
|
|
1413
|
+
const failed = results.filter((r) => !r.success).length + validationErrors.length;
|
|
1414
|
+
console.log(`
|
|
1415
|
+
Summary: ${succeeded} added, ${failed} failed`);
|
|
1416
|
+
if (failed > 0) {
|
|
1417
|
+
process.exit(1);
|
|
1418
|
+
}
|
|
1327
1419
|
}
|
|
1328
1420
|
}
|
|
1329
|
-
async function
|
|
1330
|
-
|
|
1331
|
-
|
|
1332
|
-
|
|
1333
|
-
|
|
1334
|
-
|
|
1335
|
-
|
|
1336
|
-
|
|
1337
|
-
|
|
1421
|
+
async function validateRegistryPackage(specifier) {
|
|
1422
|
+
const config2 = await resolveConfig();
|
|
1423
|
+
const registryUrl = config2.registryUrl;
|
|
1424
|
+
const apiKey = getTokenForRegistry(config2, registryUrl);
|
|
1425
|
+
const parsed = parseSkillSpecifier(specifier);
|
|
1426
|
+
if (!parsed) {
|
|
1427
|
+
throw new Error(
|
|
1428
|
+
`Invalid skill specifier "${specifier}". Use format: @user/{username}/{name}[@{version}]`
|
|
1429
|
+
);
|
|
1430
|
+
}
|
|
1431
|
+
const { username, name, versionRange } = parsed;
|
|
1432
|
+
configure2({ registryUrl, apiKey: apiKey ?? "" });
|
|
1433
|
+
console.log(`Resolving ${specifier}...`);
|
|
1434
|
+
const versionsResponse = await listSkillVersions(username, name);
|
|
1435
|
+
if (versionsResponse.status !== 200) {
|
|
1436
|
+
if (versionsResponse.status === 401) {
|
|
1437
|
+
if (!apiKey) {
|
|
1438
|
+
throw new Error(
|
|
1439
|
+
`Package @user/${username}/${name} requires authentication. Please run 'pspm login' to authenticate`
|
|
1440
|
+
);
|
|
1441
|
+
}
|
|
1442
|
+
throw new Error(
|
|
1443
|
+
`Access denied to @user/${username}/${name}. You may not have permission to access this private package.`
|
|
1338
1444
|
);
|
|
1445
|
+
}
|
|
1446
|
+
const errorMessage = extractApiErrorMessage(
|
|
1447
|
+
versionsResponse,
|
|
1448
|
+
`Skill @user/${username}/${name} not found`
|
|
1449
|
+
);
|
|
1450
|
+
throw new Error(errorMessage);
|
|
1451
|
+
}
|
|
1452
|
+
const versions = versionsResponse.data;
|
|
1453
|
+
if (versions.length === 0) {
|
|
1454
|
+
throw new Error(`Skill @user/${username}/${name} not found`);
|
|
1455
|
+
}
|
|
1456
|
+
const versionStrings = versions.map((v) => v.version);
|
|
1457
|
+
const resolvedVersion = resolveVersion(versionRange || "*", versionStrings);
|
|
1458
|
+
if (!resolvedVersion) {
|
|
1459
|
+
throw new Error(
|
|
1460
|
+
`No version matching "${versionRange || "latest"}" found for @user/${username}/${name}. Available versions: ${versionStrings.join(", ")}`
|
|
1461
|
+
);
|
|
1462
|
+
}
|
|
1463
|
+
const versionResponse = await getSkillVersion(
|
|
1464
|
+
username,
|
|
1465
|
+
name,
|
|
1466
|
+
resolvedVersion
|
|
1467
|
+
);
|
|
1468
|
+
if (versionResponse.status !== 200 || !versionResponse.data) {
|
|
1469
|
+
const errorMessage = extractApiErrorMessage(
|
|
1470
|
+
versionResponse,
|
|
1471
|
+
`Version ${resolvedVersion} not found`
|
|
1472
|
+
);
|
|
1473
|
+
throw new Error(errorMessage);
|
|
1474
|
+
}
|
|
1475
|
+
console.log(`Resolved @user/${username}/${name}@${resolvedVersion}`);
|
|
1476
|
+
return {
|
|
1477
|
+
type: "registry",
|
|
1478
|
+
specifier,
|
|
1479
|
+
username,
|
|
1480
|
+
name,
|
|
1481
|
+
versionRange,
|
|
1482
|
+
resolvedVersion,
|
|
1483
|
+
versionInfo: {
|
|
1484
|
+
downloadUrl: versionResponse.data.downloadUrl,
|
|
1485
|
+
checksum: versionResponse.data.checksum
|
|
1486
|
+
}
|
|
1487
|
+
};
|
|
1488
|
+
}
|
|
1489
|
+
async function validateGitHubPackage(specifier) {
|
|
1490
|
+
const parsed = parseGitHubSpecifier(specifier);
|
|
1491
|
+
if (!parsed) {
|
|
1492
|
+
throw new Error(
|
|
1493
|
+
`Invalid GitHub specifier "${specifier}". Use format: github:{owner}/{repo}[/{path}][@{ref}]`
|
|
1494
|
+
);
|
|
1495
|
+
}
|
|
1496
|
+
const ref = parsed.ref || "HEAD";
|
|
1497
|
+
console.log(`Resolving ${getGitHubDisplayName(parsed)}...`);
|
|
1498
|
+
const result = await downloadGitHubPackage(parsed);
|
|
1499
|
+
console.log(`Resolved ${specifier} (${ref}@${result.commit.slice(0, 7)})`);
|
|
1500
|
+
return {
|
|
1501
|
+
type: "github",
|
|
1502
|
+
specifier,
|
|
1503
|
+
parsed,
|
|
1504
|
+
ref,
|
|
1505
|
+
downloadResult: result
|
|
1506
|
+
};
|
|
1507
|
+
}
|
|
1508
|
+
async function installRegistryPackage(resolved, options) {
|
|
1509
|
+
const { username, name, versionRange, resolvedVersion, versionInfo } = resolved;
|
|
1510
|
+
console.log(`Installing @user/${username}/${name}@${resolvedVersion}...`);
|
|
1511
|
+
const config2 = await resolveConfig();
|
|
1512
|
+
const apiKey = getTokenForRegistry(config2, config2.registryUrl);
|
|
1513
|
+
const isPresignedUrl = versionInfo.downloadUrl.includes(".r2.cloudflarestorage.com") || versionInfo.downloadUrl.includes("X-Amz-Signature");
|
|
1514
|
+
const downloadHeaders = {};
|
|
1515
|
+
if (!isPresignedUrl && apiKey) {
|
|
1516
|
+
downloadHeaders.Authorization = `Bearer ${apiKey}`;
|
|
1517
|
+
}
|
|
1518
|
+
const tarballResponse = await fetch(versionInfo.downloadUrl, {
|
|
1519
|
+
headers: downloadHeaders,
|
|
1520
|
+
redirect: "follow"
|
|
1521
|
+
});
|
|
1522
|
+
if (!tarballResponse.ok) {
|
|
1523
|
+
throw new Error(`Failed to download tarball (${tarballResponse.status})`);
|
|
1524
|
+
}
|
|
1525
|
+
const tarballBuffer = Buffer.from(await tarballResponse.arrayBuffer());
|
|
1526
|
+
const integrity = calculateIntegrity(tarballBuffer);
|
|
1527
|
+
const expectedIntegrity = `sha256-${Buffer.from(versionInfo.checksum, "hex").toString("base64")}`;
|
|
1528
|
+
if (integrity !== expectedIntegrity) {
|
|
1529
|
+
throw new Error("Checksum verification failed");
|
|
1530
|
+
}
|
|
1531
|
+
const skillsDir = getSkillsDir();
|
|
1532
|
+
const destDir = join5(skillsDir, username, name);
|
|
1533
|
+
await mkdir5(destDir, { recursive: true });
|
|
1534
|
+
const { writeFile: writeFile8 } = await import("fs/promises");
|
|
1535
|
+
const tempFile = join5(destDir, ".temp.tgz");
|
|
1536
|
+
await writeFile8(tempFile, tarballBuffer);
|
|
1537
|
+
const { exec: exec2 } = await import("child_process");
|
|
1538
|
+
const { promisify: promisify2 } = await import("util");
|
|
1539
|
+
const execAsync = promisify2(exec2);
|
|
1540
|
+
try {
|
|
1541
|
+
await rm3(destDir, { recursive: true, force: true });
|
|
1542
|
+
await mkdir5(destDir, { recursive: true });
|
|
1543
|
+
await writeFile8(tempFile, tarballBuffer);
|
|
1544
|
+
await execAsync(
|
|
1545
|
+
`tar -xzf "${tempFile}" -C "${destDir}" --strip-components=1`
|
|
1546
|
+
);
|
|
1547
|
+
} finally {
|
|
1548
|
+
await rm3(tempFile, { force: true });
|
|
1549
|
+
}
|
|
1550
|
+
const fullName = `@user/${username}/${name}`;
|
|
1551
|
+
await addToLockfile(fullName, {
|
|
1552
|
+
version: resolvedVersion,
|
|
1553
|
+
resolved: versionInfo.downloadUrl,
|
|
1554
|
+
integrity
|
|
1555
|
+
});
|
|
1556
|
+
const dependencyRange = versionRange || `^${resolvedVersion}`;
|
|
1557
|
+
await addDependency(fullName, dependencyRange);
|
|
1558
|
+
const agents = options.resolvedAgents;
|
|
1559
|
+
if (agents[0] !== "none") {
|
|
1560
|
+
const skillManifest = await readManifest();
|
|
1561
|
+
const skillInfo = {
|
|
1562
|
+
name,
|
|
1563
|
+
sourcePath: getRegistrySkillPath(username, name)
|
|
1564
|
+
};
|
|
1565
|
+
await createAgentSymlinks([skillInfo], {
|
|
1566
|
+
agents,
|
|
1567
|
+
projectRoot: process.cwd(),
|
|
1568
|
+
agentConfigs: skillManifest?.agents
|
|
1569
|
+
});
|
|
1570
|
+
}
|
|
1571
|
+
console.log(`Installed @user/${username}/${name}@${resolvedVersion}`);
|
|
1572
|
+
console.log(`Location: ${destDir}`);
|
|
1573
|
+
}
|
|
1574
|
+
async function installGitHubPackage(resolved, options) {
|
|
1575
|
+
const { specifier, parsed, ref, downloadResult } = resolved;
|
|
1576
|
+
console.log(
|
|
1577
|
+
`Installing ${specifier} (${ref}@${downloadResult.commit.slice(0, 7)})...`
|
|
1578
|
+
);
|
|
1579
|
+
const skillsDir = getSkillsDir();
|
|
1580
|
+
const destPath = await extractGitHubPackage(
|
|
1581
|
+
parsed,
|
|
1582
|
+
downloadResult.buffer,
|
|
1583
|
+
skillsDir
|
|
1584
|
+
);
|
|
1585
|
+
const lockfileSpecifier = formatGitHubSpecifier({
|
|
1586
|
+
owner: parsed.owner,
|
|
1587
|
+
repo: parsed.repo,
|
|
1588
|
+
path: parsed.path
|
|
1589
|
+
// Don't include ref in the specifier key, it's stored in gitRef
|
|
1590
|
+
});
|
|
1591
|
+
const entry = {
|
|
1592
|
+
version: downloadResult.commit.slice(0, 7),
|
|
1593
|
+
resolved: `https://github.com/${parsed.owner}/${parsed.repo}`,
|
|
1594
|
+
integrity: downloadResult.integrity,
|
|
1595
|
+
gitCommit: downloadResult.commit,
|
|
1596
|
+
gitRef: ref
|
|
1597
|
+
};
|
|
1598
|
+
await addGitHubToLockfile(lockfileSpecifier, entry);
|
|
1599
|
+
await addGitHubDependency(lockfileSpecifier, ref);
|
|
1600
|
+
const agents = options.resolvedAgents;
|
|
1601
|
+
if (agents[0] !== "none") {
|
|
1602
|
+
const manifest = await readManifest();
|
|
1603
|
+
const skillName = getGitHubSkillName(parsed);
|
|
1604
|
+
const skillInfo = {
|
|
1605
|
+
name: skillName,
|
|
1606
|
+
sourcePath: getGitHubSkillPath(parsed.owner, parsed.repo, parsed.path)
|
|
1607
|
+
};
|
|
1608
|
+
await createAgentSymlinks([skillInfo], {
|
|
1609
|
+
agents,
|
|
1610
|
+
projectRoot: process.cwd(),
|
|
1611
|
+
agentConfigs: manifest?.agents
|
|
1612
|
+
});
|
|
1613
|
+
}
|
|
1614
|
+
console.log(
|
|
1615
|
+
`Installed ${specifier} (${ref}@${downloadResult.commit.slice(0, 7)})`
|
|
1616
|
+
);
|
|
1617
|
+
console.log(`Location: ${destPath}`);
|
|
1618
|
+
}
|
|
1619
|
+
var init_add = __esm({
|
|
1620
|
+
"src/commands/add.ts"() {
|
|
1621
|
+
"use strict";
|
|
1622
|
+
init_agents();
|
|
1623
|
+
init_api_client();
|
|
1624
|
+
init_config();
|
|
1625
|
+
init_errors();
|
|
1626
|
+
init_github();
|
|
1627
|
+
init_lib();
|
|
1628
|
+
init_lockfile();
|
|
1629
|
+
init_manifest2();
|
|
1630
|
+
init_symlinks();
|
|
1631
|
+
}
|
|
1632
|
+
});
|
|
1633
|
+
|
|
1634
|
+
// src/index.ts
|
|
1635
|
+
import { readFileSync } from "fs";
|
|
1636
|
+
import { dirname as dirname4, join as join12 } from "path";
|
|
1637
|
+
import { fileURLToPath } from "url";
|
|
1638
|
+
import { Command } from "commander";
|
|
1639
|
+
|
|
1640
|
+
// src/commands/access.ts
|
|
1641
|
+
init_api_client();
|
|
1642
|
+
init_config();
|
|
1643
|
+
init_lib();
|
|
1644
|
+
async function access(specifier, options) {
|
|
1645
|
+
try {
|
|
1646
|
+
const apiKey = await requireApiKey();
|
|
1647
|
+
const registryUrl = await getRegistryUrl();
|
|
1648
|
+
if (options.public && options.private) {
|
|
1649
|
+
console.error("Error: Cannot specify both --public and --private");
|
|
1339
1650
|
process.exit(1);
|
|
1340
1651
|
}
|
|
1341
|
-
|
|
1342
|
-
|
|
1343
|
-
|
|
1344
|
-
|
|
1345
|
-
|
|
1346
|
-
|
|
1347
|
-
|
|
1652
|
+
if (!options.public && !options.private) {
|
|
1653
|
+
console.error("Error: Must specify either --public or --private");
|
|
1654
|
+
process.exit(1);
|
|
1655
|
+
}
|
|
1656
|
+
const visibility = options.public ? "public" : "private";
|
|
1657
|
+
let packageName;
|
|
1658
|
+
if (specifier) {
|
|
1659
|
+
const parsed = parseSkillSpecifier(specifier);
|
|
1660
|
+
if (!parsed) {
|
|
1661
|
+
console.error(
|
|
1662
|
+
`Error: Invalid skill specifier "${specifier}". Use format: @user/{username}/{name}`
|
|
1663
|
+
);
|
|
1664
|
+
process.exit(1);
|
|
1665
|
+
}
|
|
1666
|
+
packageName = parsed.name;
|
|
1667
|
+
} else {
|
|
1668
|
+
const { readFile: readFile7 } = await import("fs/promises");
|
|
1669
|
+
const { join: join13 } = await import("path");
|
|
1670
|
+
let manifest = null;
|
|
1671
|
+
try {
|
|
1672
|
+
const content = await readFile7(
|
|
1673
|
+
join13(process.cwd(), "pspm.json"),
|
|
1674
|
+
"utf-8"
|
|
1675
|
+
);
|
|
1676
|
+
manifest = JSON.parse(content);
|
|
1677
|
+
} catch {
|
|
1678
|
+
try {
|
|
1679
|
+
const content = await readFile7(
|
|
1680
|
+
join13(process.cwd(), "package.json"),
|
|
1681
|
+
"utf-8"
|
|
1682
|
+
);
|
|
1683
|
+
manifest = JSON.parse(content);
|
|
1684
|
+
} catch {
|
|
1348
1685
|
console.error(
|
|
1349
|
-
|
|
1686
|
+
"Error: No pspm.json or package.json found in current directory"
|
|
1350
1687
|
);
|
|
1351
|
-
console.error("Please run 'pspm login' to authenticate");
|
|
1352
|
-
} else {
|
|
1353
1688
|
console.error(
|
|
1354
|
-
|
|
1689
|
+
"Either run this command in a package directory or specify a package name"
|
|
1355
1690
|
);
|
|
1691
|
+
process.exit(1);
|
|
1356
1692
|
}
|
|
1693
|
+
}
|
|
1694
|
+
if (!manifest?.name) {
|
|
1695
|
+
console.error("Error: Package manifest is missing 'name' field");
|
|
1357
1696
|
process.exit(1);
|
|
1358
1697
|
}
|
|
1359
|
-
|
|
1360
|
-
versionsResponse,
|
|
1361
|
-
`Skill @user/${username}/${name} not found`
|
|
1362
|
-
);
|
|
1363
|
-
console.error(`Error: ${errorMessage}`);
|
|
1364
|
-
process.exit(1);
|
|
1365
|
-
}
|
|
1366
|
-
const versions = versionsResponse.data;
|
|
1367
|
-
if (versions.length === 0) {
|
|
1368
|
-
console.error(`Error: Skill @user/${username}/${name} not found`);
|
|
1369
|
-
process.exit(1);
|
|
1370
|
-
}
|
|
1371
|
-
const versionStrings = versions.map((v) => v.version);
|
|
1372
|
-
const resolved = resolveVersion(versionRange || "*", versionStrings);
|
|
1373
|
-
if (!resolved) {
|
|
1374
|
-
console.error(
|
|
1375
|
-
`Error: No version matching "${versionRange || "latest"}" found for @user/${username}/${name}`
|
|
1376
|
-
);
|
|
1377
|
-
console.error(`Available versions: ${versionStrings.join(", ")}`);
|
|
1378
|
-
process.exit(1);
|
|
1698
|
+
packageName = manifest.name;
|
|
1379
1699
|
}
|
|
1380
|
-
|
|
1381
|
-
|
|
1382
|
-
|
|
1383
|
-
|
|
1384
|
-
|
|
1385
|
-
`Version ${resolved} not found`
|
|
1386
|
-
);
|
|
1700
|
+
configure2({ registryUrl, apiKey });
|
|
1701
|
+
console.log(`Setting ${packageName} to ${visibility}...`);
|
|
1702
|
+
const response = await changeSkillAccess(packageName, { visibility });
|
|
1703
|
+
if (response.status !== 200 || !response.data) {
|
|
1704
|
+
const errorMessage = response.error ?? "Failed to change visibility";
|
|
1387
1705
|
console.error(`Error: ${errorMessage}`);
|
|
1388
1706
|
process.exit(1);
|
|
1389
1707
|
}
|
|
1390
|
-
const
|
|
1391
|
-
|
|
1392
|
-
|
|
1393
|
-
|
|
1394
|
-
|
|
1395
|
-
|
|
1396
|
-
|
|
1397
|
-
|
|
1398
|
-
redirect: "follow"
|
|
1399
|
-
});
|
|
1400
|
-
if (!tarballResponse.ok) {
|
|
1401
|
-
console.error(
|
|
1402
|
-
`Error: Failed to download tarball (${tarballResponse.status})`
|
|
1403
|
-
);
|
|
1404
|
-
process.exit(1);
|
|
1405
|
-
}
|
|
1406
|
-
const tarballBuffer = Buffer.from(await tarballResponse.arrayBuffer());
|
|
1407
|
-
const integrity = calculateIntegrity(tarballBuffer);
|
|
1408
|
-
const expectedIntegrity = `sha256-${Buffer.from(versionInfo.checksum, "hex").toString("base64")}`;
|
|
1409
|
-
if (integrity !== expectedIntegrity) {
|
|
1410
|
-
console.error("Error: Checksum verification failed");
|
|
1411
|
-
process.exit(1);
|
|
1412
|
-
}
|
|
1413
|
-
const skillsDir = getSkillsDir();
|
|
1414
|
-
const destDir = join(skillsDir, username, name);
|
|
1415
|
-
await mkdir(destDir, { recursive: true });
|
|
1416
|
-
const { writeFile: writeFile8 } = await import('fs/promises');
|
|
1417
|
-
const tempFile = join(destDir, ".temp.tgz");
|
|
1418
|
-
await writeFile8(tempFile, tarballBuffer);
|
|
1419
|
-
const { exec: exec2 } = await import('child_process');
|
|
1420
|
-
const { promisify: promisify2 } = await import('util');
|
|
1421
|
-
const execAsync = promisify2(exec2);
|
|
1422
|
-
try {
|
|
1423
|
-
await rm(destDir, { recursive: true, force: true });
|
|
1424
|
-
await mkdir(destDir, { recursive: true });
|
|
1425
|
-
await writeFile8(tempFile, tarballBuffer);
|
|
1426
|
-
await execAsync(
|
|
1427
|
-
`tar -xzf "${tempFile}" -C "${destDir}" --strip-components=1`
|
|
1708
|
+
const result = response.data;
|
|
1709
|
+
console.log(
|
|
1710
|
+
`+ @user/${result.username}/${result.name} is now ${result.visibility}`
|
|
1711
|
+
);
|
|
1712
|
+
if (visibility === "public") {
|
|
1713
|
+
console.log("");
|
|
1714
|
+
console.log(
|
|
1715
|
+
"Note: This action is irreversible. Public packages cannot be made private."
|
|
1428
1716
|
);
|
|
1429
|
-
} finally {
|
|
1430
|
-
await rm(tempFile, { force: true });
|
|
1431
|
-
}
|
|
1432
|
-
const fullName = `@user/${username}/${name}`;
|
|
1433
|
-
await addToLockfile(fullName, {
|
|
1434
|
-
version: resolved,
|
|
1435
|
-
resolved: versionInfo.downloadUrl,
|
|
1436
|
-
integrity
|
|
1437
|
-
});
|
|
1438
|
-
const dependencyRange = versionRange || `^${resolved}`;
|
|
1439
|
-
await addDependency(fullName, dependencyRange);
|
|
1440
|
-
const agents = options.resolvedAgents;
|
|
1441
|
-
if (agents[0] !== "none") {
|
|
1442
|
-
const skillManifest = await readManifest();
|
|
1443
|
-
const skillInfo = {
|
|
1444
|
-
name,
|
|
1445
|
-
sourcePath: getRegistrySkillPath(username, name)
|
|
1446
|
-
};
|
|
1447
|
-
await createAgentSymlinks([skillInfo], {
|
|
1448
|
-
agents,
|
|
1449
|
-
projectRoot: process.cwd(),
|
|
1450
|
-
agentConfigs: skillManifest?.agents
|
|
1451
|
-
});
|
|
1452
1717
|
}
|
|
1453
|
-
console.log(`Installed @user/${username}/${name}@${resolved}`);
|
|
1454
|
-
console.log(`Location: ${destDir}`);
|
|
1455
1718
|
} catch (error) {
|
|
1456
1719
|
const message = error instanceof Error ? error.message : "Unknown error";
|
|
1457
1720
|
console.error(`Error: ${message}`);
|
|
1458
1721
|
process.exit(1);
|
|
1459
1722
|
}
|
|
1460
1723
|
}
|
|
1461
|
-
|
|
1462
|
-
|
|
1463
|
-
|
|
1464
|
-
|
|
1465
|
-
|
|
1466
|
-
|
|
1467
|
-
|
|
1468
|
-
process.exit(1);
|
|
1469
|
-
}
|
|
1470
|
-
const ref = parsed.ref || "HEAD";
|
|
1471
|
-
console.log(`Resolving ${getGitHubDisplayName(parsed)}...`);
|
|
1472
|
-
const result = await downloadGitHubPackage(parsed);
|
|
1473
|
-
console.log(
|
|
1474
|
-
`Installing ${specifier} (${ref}@${result.commit.slice(0, 7)})...`
|
|
1475
|
-
);
|
|
1476
|
-
const skillsDir = getSkillsDir();
|
|
1477
|
-
const destPath = await extractGitHubPackage(
|
|
1478
|
-
parsed,
|
|
1479
|
-
result.buffer,
|
|
1480
|
-
skillsDir
|
|
1481
|
-
);
|
|
1482
|
-
const lockfileSpecifier = formatGitHubSpecifier({
|
|
1483
|
-
owner: parsed.owner,
|
|
1484
|
-
repo: parsed.repo,
|
|
1485
|
-
path: parsed.path
|
|
1486
|
-
// Don't include ref in the specifier key, it's stored in gitRef
|
|
1487
|
-
});
|
|
1488
|
-
const entry = {
|
|
1489
|
-
version: result.commit.slice(0, 7),
|
|
1490
|
-
resolved: `https://github.com/${parsed.owner}/${parsed.repo}`,
|
|
1491
|
-
integrity: result.integrity,
|
|
1492
|
-
gitCommit: result.commit,
|
|
1493
|
-
gitRef: ref
|
|
1494
|
-
};
|
|
1495
|
-
await addGitHubToLockfile(lockfileSpecifier, entry);
|
|
1496
|
-
await addGitHubDependency(lockfileSpecifier, ref);
|
|
1497
|
-
const agents = options.resolvedAgents;
|
|
1498
|
-
if (agents[0] !== "none") {
|
|
1499
|
-
const manifest = await readManifest();
|
|
1500
|
-
const skillName = getGitHubSkillName(parsed);
|
|
1501
|
-
const skillInfo = {
|
|
1502
|
-
name: skillName,
|
|
1503
|
-
sourcePath: getGitHubSkillPath(parsed.owner, parsed.repo, parsed.path)
|
|
1504
|
-
};
|
|
1505
|
-
await createAgentSymlinks([skillInfo], {
|
|
1506
|
-
agents,
|
|
1507
|
-
projectRoot: process.cwd(),
|
|
1508
|
-
agentConfigs: manifest?.agents
|
|
1509
|
-
});
|
|
1510
|
-
}
|
|
1511
|
-
console.log(`Installed ${specifier} (${ref}@${result.commit.slice(0, 7)})`);
|
|
1512
|
-
console.log(`Location: ${destPath}`);
|
|
1513
|
-
} catch (error) {
|
|
1514
|
-
if (error instanceof GitHubRateLimitError) {
|
|
1515
|
-
console.error(`Error: ${error.message}`);
|
|
1516
|
-
} else if (error instanceof GitHubPathNotFoundError) {
|
|
1517
|
-
console.error(`Error: ${error.message}`);
|
|
1518
|
-
} else if (error instanceof GitHubNotFoundError) {
|
|
1519
|
-
console.error(`Error: ${error.message}`);
|
|
1520
|
-
} else {
|
|
1521
|
-
const message = error instanceof Error ? error.message : "Unknown error";
|
|
1522
|
-
console.error(`Error: ${message}`);
|
|
1523
|
-
}
|
|
1524
|
-
process.exit(1);
|
|
1525
|
-
}
|
|
1526
|
-
}
|
|
1724
|
+
|
|
1725
|
+
// src/commands/index.ts
|
|
1726
|
+
init_add();
|
|
1727
|
+
|
|
1728
|
+
// src/commands/config/init.ts
|
|
1729
|
+
import { stat as stat3, writeFile as writeFile5 } from "fs/promises";
|
|
1730
|
+
import { join as join6 } from "path";
|
|
1527
1731
|
async function configInit(options) {
|
|
1528
1732
|
try {
|
|
1529
|
-
const configPath =
|
|
1733
|
+
const configPath = join6(process.cwd(), ".pspmrc");
|
|
1530
1734
|
try {
|
|
1531
|
-
await
|
|
1735
|
+
await stat3(configPath);
|
|
1532
1736
|
console.error("Error: .pspmrc already exists in this directory.");
|
|
1533
1737
|
process.exit(1);
|
|
1534
1738
|
} catch {
|
|
@@ -1541,7 +1745,7 @@ async function configInit(options) {
|
|
|
1541
1745
|
lines.push("; registry = https://custom-registry.example.com");
|
|
1542
1746
|
}
|
|
1543
1747
|
lines.push("");
|
|
1544
|
-
await
|
|
1748
|
+
await writeFile5(configPath, lines.join("\n"));
|
|
1545
1749
|
console.log("Created .pspmrc");
|
|
1546
1750
|
console.log("");
|
|
1547
1751
|
console.log("Contents:");
|
|
@@ -1556,6 +1760,7 @@ async function configInit(options) {
|
|
|
1556
1760
|
}
|
|
1557
1761
|
|
|
1558
1762
|
// src/commands/config/show.ts
|
|
1763
|
+
init_config();
|
|
1559
1764
|
async function configShow() {
|
|
1560
1765
|
try {
|
|
1561
1766
|
const resolved = await resolveConfig();
|
|
@@ -1585,6 +1790,9 @@ async function configShow() {
|
|
|
1585
1790
|
}
|
|
1586
1791
|
|
|
1587
1792
|
// src/commands/deprecate.ts
|
|
1793
|
+
init_api_client();
|
|
1794
|
+
init_config();
|
|
1795
|
+
init_lib();
|
|
1588
1796
|
async function deprecate(specifier, message, options) {
|
|
1589
1797
|
try {
|
|
1590
1798
|
const apiKey = await requireApiKey();
|
|
@@ -1647,6 +1855,12 @@ async function deprecate(specifier, message, options) {
|
|
|
1647
1855
|
process.exit(1);
|
|
1648
1856
|
}
|
|
1649
1857
|
}
|
|
1858
|
+
|
|
1859
|
+
// src/commands/init.ts
|
|
1860
|
+
init_lib();
|
|
1861
|
+
import { readFile as readFile4, stat as stat4, writeFile as writeFile6 } from "fs/promises";
|
|
1862
|
+
import { basename, join as join7 } from "path";
|
|
1863
|
+
import { createInterface } from "readline";
|
|
1650
1864
|
function prompt(rl, question, defaultValue) {
|
|
1651
1865
|
return new Promise((resolve) => {
|
|
1652
1866
|
const displayDefault = defaultValue ? ` (${defaultValue})` : "";
|
|
@@ -1657,8 +1871,8 @@ function prompt(rl, question, defaultValue) {
|
|
|
1657
1871
|
}
|
|
1658
1872
|
async function readExistingPackageJson() {
|
|
1659
1873
|
try {
|
|
1660
|
-
const content = await
|
|
1661
|
-
|
|
1874
|
+
const content = await readFile4(
|
|
1875
|
+
join7(process.cwd(), "package.json"),
|
|
1662
1876
|
"utf-8"
|
|
1663
1877
|
);
|
|
1664
1878
|
const pkg = JSON.parse(content);
|
|
@@ -1675,8 +1889,8 @@ async function readExistingPackageJson() {
|
|
|
1675
1889
|
}
|
|
1676
1890
|
async function getGitAuthor() {
|
|
1677
1891
|
try {
|
|
1678
|
-
const { exec: exec2 } = await import(
|
|
1679
|
-
const { promisify: promisify2 } = await import(
|
|
1892
|
+
const { exec: exec2 } = await import("child_process");
|
|
1893
|
+
const { promisify: promisify2 } = await import("util");
|
|
1680
1894
|
const execAsync = promisify2(exec2);
|
|
1681
1895
|
const [nameResult, emailResult] = await Promise.all([
|
|
1682
1896
|
execAsync("git config user.name").catch(() => ({ stdout: "" })),
|
|
@@ -1707,10 +1921,10 @@ function isValidVersion(version2) {
|
|
|
1707
1921
|
}
|
|
1708
1922
|
async function init(options) {
|
|
1709
1923
|
try {
|
|
1710
|
-
const pspmJsonPath =
|
|
1924
|
+
const pspmJsonPath = join7(process.cwd(), "pspm.json");
|
|
1711
1925
|
let exists = false;
|
|
1712
1926
|
try {
|
|
1713
|
-
await
|
|
1927
|
+
await stat4(pspmJsonPath);
|
|
1714
1928
|
exists = true;
|
|
1715
1929
|
} catch {
|
|
1716
1930
|
}
|
|
@@ -1821,9 +2035,9 @@ async function init(options) {
|
|
|
1821
2035
|
throw error;
|
|
1822
2036
|
}
|
|
1823
2037
|
}
|
|
1824
|
-
if (!manifest.description)
|
|
1825
|
-
if (!manifest.author)
|
|
1826
|
-
if (manifest.capabilities?.length === 0)
|
|
2038
|
+
if (!manifest.description) manifest.description = void 0;
|
|
2039
|
+
if (!manifest.author) manifest.author = void 0;
|
|
2040
|
+
if (manifest.capabilities?.length === 0) manifest.capabilities = void 0;
|
|
1827
2041
|
const content = JSON.stringify(manifest, null, 2);
|
|
1828
2042
|
console.log("");
|
|
1829
2043
|
console.log(`About to write to ${pspmJsonPath}:`);
|
|
@@ -1842,10 +2056,10 @@ async function init(options) {
|
|
|
1842
2056
|
process.exit(0);
|
|
1843
2057
|
}
|
|
1844
2058
|
}
|
|
1845
|
-
await
|
|
2059
|
+
await writeFile6(pspmJsonPath, `${content}
|
|
1846
2060
|
`);
|
|
1847
2061
|
try {
|
|
1848
|
-
await
|
|
2062
|
+
await stat4(join7(process.cwd(), "SKILL.md"));
|
|
1849
2063
|
} catch {
|
|
1850
2064
|
console.log(
|
|
1851
2065
|
"Note: Create a SKILL.md file with your skill's prompt content."
|
|
@@ -1862,6 +2076,20 @@ async function init(options) {
|
|
|
1862
2076
|
process.exit(1);
|
|
1863
2077
|
}
|
|
1864
2078
|
}
|
|
2079
|
+
|
|
2080
|
+
// src/commands/install.ts
|
|
2081
|
+
init_agents();
|
|
2082
|
+
init_api_client();
|
|
2083
|
+
init_config();
|
|
2084
|
+
init_errors();
|
|
2085
|
+
init_github();
|
|
2086
|
+
init_lib();
|
|
2087
|
+
init_lockfile();
|
|
2088
|
+
init_manifest2();
|
|
2089
|
+
init_symlinks();
|
|
2090
|
+
import { createHash as createHash2 } from "crypto";
|
|
2091
|
+
import { mkdir as mkdir6, readFile as readFile5, rm as rm4, writeFile as writeFile7 } from "fs/promises";
|
|
2092
|
+
import { join as join8 } from "path";
|
|
1865
2093
|
function getCacheFilePath(cacheDir, integrity) {
|
|
1866
2094
|
const match = integrity.match(/^sha256-(.+)$/);
|
|
1867
2095
|
if (!match) {
|
|
@@ -1869,15 +2097,15 @@ function getCacheFilePath(cacheDir, integrity) {
|
|
|
1869
2097
|
}
|
|
1870
2098
|
const base64Hash = match[1];
|
|
1871
2099
|
const hexHash = Buffer.from(base64Hash, "base64").toString("hex");
|
|
1872
|
-
return
|
|
2100
|
+
return join8(cacheDir, `sha256-${hexHash}.tgz`);
|
|
1873
2101
|
}
|
|
1874
2102
|
async function readFromCache(cacheDir, integrity) {
|
|
1875
2103
|
try {
|
|
1876
2104
|
const cachePath = getCacheFilePath(cacheDir, integrity);
|
|
1877
|
-
const data = await
|
|
1878
|
-
const actualIntegrity = `sha256-${
|
|
2105
|
+
const data = await readFile5(cachePath);
|
|
2106
|
+
const actualIntegrity = `sha256-${createHash2("sha256").update(data).digest("base64")}`;
|
|
1879
2107
|
if (actualIntegrity !== integrity) {
|
|
1880
|
-
await
|
|
2108
|
+
await rm4(cachePath, { force: true });
|
|
1881
2109
|
return null;
|
|
1882
2110
|
}
|
|
1883
2111
|
return data;
|
|
@@ -1887,32 +2115,31 @@ async function readFromCache(cacheDir, integrity) {
|
|
|
1887
2115
|
}
|
|
1888
2116
|
async function writeToCache(cacheDir, integrity, data) {
|
|
1889
2117
|
try {
|
|
1890
|
-
await
|
|
2118
|
+
await mkdir6(cacheDir, { recursive: true });
|
|
1891
2119
|
const cachePath = getCacheFilePath(cacheDir, integrity);
|
|
1892
|
-
await
|
|
2120
|
+
await writeFile7(cachePath, data);
|
|
1893
2121
|
} catch {
|
|
1894
2122
|
}
|
|
1895
2123
|
}
|
|
1896
|
-
async function install(options) {
|
|
2124
|
+
async function install(specifiers, options) {
|
|
2125
|
+
if (specifiers.length > 0) {
|
|
2126
|
+
const { add: add2 } = await Promise.resolve().then(() => (init_add(), add_exports));
|
|
2127
|
+
await add2(specifiers, {
|
|
2128
|
+
save: true,
|
|
2129
|
+
agent: options.agent,
|
|
2130
|
+
yes: options.yes
|
|
2131
|
+
});
|
|
2132
|
+
return;
|
|
2133
|
+
}
|
|
2134
|
+
await installFromLockfile(options);
|
|
2135
|
+
}
|
|
2136
|
+
async function installFromLockfile(options) {
|
|
1897
2137
|
try {
|
|
1898
2138
|
const config2 = await resolveConfig();
|
|
1899
2139
|
const registryUrl = config2.registryUrl;
|
|
1900
2140
|
const apiKey = getTokenForRegistry(config2, registryUrl);
|
|
1901
2141
|
const skillsDir = options.dir || getSkillsDir();
|
|
1902
2142
|
const cacheDir = getCacheDir();
|
|
1903
|
-
const manifest = await readManifest();
|
|
1904
|
-
const agentConfigs = manifest?.agents;
|
|
1905
|
-
let agents;
|
|
1906
|
-
if (options.agent) {
|
|
1907
|
-
agents = parseAgentArg(options.agent);
|
|
1908
|
-
} else if (manifest) {
|
|
1909
|
-
agents = parseAgentArg(void 0);
|
|
1910
|
-
} else if (options.yes) {
|
|
1911
|
-
agents = parseAgentArg(void 0);
|
|
1912
|
-
} else {
|
|
1913
|
-
console.log("No pspm.json found. Let's set up your project.\n");
|
|
1914
|
-
agents = await promptForAgents();
|
|
1915
|
-
}
|
|
1916
2143
|
await migrateLockfileIfNeeded();
|
|
1917
2144
|
let lockfile = await readLockfile();
|
|
1918
2145
|
const manifestDeps = await getDependencies();
|
|
@@ -2069,6 +2296,20 @@ Resolving ${missingGitHubDeps.length} GitHub dependency(ies)...
|
|
|
2069
2296
|
}
|
|
2070
2297
|
lockfile = await readLockfile();
|
|
2071
2298
|
}
|
|
2299
|
+
const manifest = await readManifest();
|
|
2300
|
+
const agentConfigs = manifest?.agents;
|
|
2301
|
+
let agents;
|
|
2302
|
+
if (options.agent) {
|
|
2303
|
+
agents = parseAgentArg(options.agent);
|
|
2304
|
+
} else if (manifest) {
|
|
2305
|
+
agents = parseAgentArg(void 0);
|
|
2306
|
+
} else if (options.yes) {
|
|
2307
|
+
agents = parseAgentArg(void 0);
|
|
2308
|
+
} else {
|
|
2309
|
+
console.log("\nNo pspm.json found. Let's set up your project.\n");
|
|
2310
|
+
agents = await promptForAgents();
|
|
2311
|
+
console.log();
|
|
2312
|
+
}
|
|
2072
2313
|
const packages = lockfile?.packages ?? lockfile?.skills ?? {};
|
|
2073
2314
|
const packageCount = Object.keys(packages).length;
|
|
2074
2315
|
if (packageCount > 0) {
|
|
@@ -2119,7 +2360,7 @@ Installing ${packageCount} registry skill(s)...
|
|
|
2119
2360
|
continue;
|
|
2120
2361
|
}
|
|
2121
2362
|
tarballBuffer = Buffer.from(await response.arrayBuffer());
|
|
2122
|
-
const actualIntegrity = `sha256-${
|
|
2363
|
+
const actualIntegrity = `sha256-${createHash2("sha256").update(tarballBuffer).digest("base64")}`;
|
|
2123
2364
|
if (actualIntegrity !== entry.integrity) {
|
|
2124
2365
|
console.error(
|
|
2125
2366
|
` Error: Checksum verification failed for ${fullName}`
|
|
@@ -2131,20 +2372,20 @@ Installing ${packageCount} registry skill(s)...
|
|
|
2131
2372
|
}
|
|
2132
2373
|
await writeToCache(cacheDir, entry.integrity, tarballBuffer);
|
|
2133
2374
|
}
|
|
2134
|
-
const destDir =
|
|
2135
|
-
await
|
|
2136
|
-
await
|
|
2137
|
-
const tempFile =
|
|
2138
|
-
await
|
|
2139
|
-
const { exec: exec2 } = await import(
|
|
2140
|
-
const { promisify: promisify2 } = await import(
|
|
2375
|
+
const destDir = join8(skillsDir, username, name);
|
|
2376
|
+
await rm4(destDir, { recursive: true, force: true });
|
|
2377
|
+
await mkdir6(destDir, { recursive: true });
|
|
2378
|
+
const tempFile = join8(destDir, ".temp.tgz");
|
|
2379
|
+
await writeFile7(tempFile, tarballBuffer);
|
|
2380
|
+
const { exec: exec2 } = await import("child_process");
|
|
2381
|
+
const { promisify: promisify2 } = await import("util");
|
|
2141
2382
|
const execAsync = promisify2(exec2);
|
|
2142
2383
|
try {
|
|
2143
2384
|
await execAsync(
|
|
2144
2385
|
`tar -xzf "${tempFile}" -C "${destDir}" --strip-components=1`
|
|
2145
2386
|
);
|
|
2146
2387
|
} finally {
|
|
2147
|
-
await
|
|
2388
|
+
await rm4(tempFile, { force: true });
|
|
2148
2389
|
}
|
|
2149
2390
|
console.log(
|
|
2150
2391
|
` Installed to ${destDir}${fromCache ? " (from cache)" : ""}`
|
|
@@ -2257,6 +2498,11 @@ All ${totalCount} skill(s) installed.`);
|
|
|
2257
2498
|
}
|
|
2258
2499
|
|
|
2259
2500
|
// src/commands/link.ts
|
|
2501
|
+
init_agents();
|
|
2502
|
+
init_lib();
|
|
2503
|
+
init_lockfile();
|
|
2504
|
+
init_manifest2();
|
|
2505
|
+
init_symlinks();
|
|
2260
2506
|
async function link(options) {
|
|
2261
2507
|
try {
|
|
2262
2508
|
const manifest = await readManifest();
|
|
@@ -2327,6 +2573,15 @@ async function link(options) {
|
|
|
2327
2573
|
process.exit(1);
|
|
2328
2574
|
}
|
|
2329
2575
|
}
|
|
2576
|
+
|
|
2577
|
+
// src/commands/list.ts
|
|
2578
|
+
init_agents();
|
|
2579
|
+
init_lib();
|
|
2580
|
+
init_lockfile();
|
|
2581
|
+
init_manifest2();
|
|
2582
|
+
init_symlinks();
|
|
2583
|
+
import { access as access2 } from "fs/promises";
|
|
2584
|
+
import { join as join9 } from "path";
|
|
2330
2585
|
async function list(options) {
|
|
2331
2586
|
try {
|
|
2332
2587
|
const registrySkills = await listLockfileSkills();
|
|
@@ -2341,10 +2596,10 @@ async function list(options) {
|
|
|
2341
2596
|
if (!match) continue;
|
|
2342
2597
|
const [, username, skillName] = match;
|
|
2343
2598
|
const sourcePath = getRegistrySkillPath(username, skillName);
|
|
2344
|
-
const absolutePath =
|
|
2599
|
+
const absolutePath = join9(projectRoot, sourcePath);
|
|
2345
2600
|
let status = "installed";
|
|
2346
2601
|
try {
|
|
2347
|
-
await
|
|
2602
|
+
await access2(absolutePath);
|
|
2348
2603
|
} catch {
|
|
2349
2604
|
status = "missing";
|
|
2350
2605
|
}
|
|
@@ -2374,10 +2629,10 @@ async function list(options) {
|
|
|
2374
2629
|
parsed.repo,
|
|
2375
2630
|
parsed.path
|
|
2376
2631
|
);
|
|
2377
|
-
const absolutePath =
|
|
2632
|
+
const absolutePath = join9(projectRoot, sourcePath);
|
|
2378
2633
|
let status = "installed";
|
|
2379
2634
|
try {
|
|
2380
|
-
await
|
|
2635
|
+
await access2(absolutePath);
|
|
2381
2636
|
} catch {
|
|
2382
2637
|
status = "missing";
|
|
2383
2638
|
}
|
|
@@ -2440,13 +2695,21 @@ Total: ${skills.length} skill(s) (${parts.join(", ")})`);
|
|
|
2440
2695
|
process.exit(1);
|
|
2441
2696
|
}
|
|
2442
2697
|
}
|
|
2698
|
+
|
|
2699
|
+
// src/commands/login.ts
|
|
2700
|
+
init_api_client();
|
|
2701
|
+
init_config();
|
|
2702
|
+
import { randomBytes } from "crypto";
|
|
2703
|
+
import http from "http";
|
|
2704
|
+
import { URL as URL2 } from "url";
|
|
2705
|
+
import open from "open";
|
|
2443
2706
|
var DEFAULT_WEB_APP_URL = "https://pspm.dev";
|
|
2444
2707
|
function getWebAppUrl(registryUrl) {
|
|
2445
2708
|
if (process.env.PSPM_WEB_URL) {
|
|
2446
2709
|
return process.env.PSPM_WEB_URL.replace(/\/$/, "");
|
|
2447
2710
|
}
|
|
2448
2711
|
try {
|
|
2449
|
-
const url = new
|
|
2712
|
+
const url = new URL2(registryUrl);
|
|
2450
2713
|
return `${url.protocol}//${url.host}`;
|
|
2451
2714
|
} catch {
|
|
2452
2715
|
return DEFAULT_WEB_APP_URL;
|
|
@@ -2454,7 +2717,7 @@ function getWebAppUrl(registryUrl) {
|
|
|
2454
2717
|
}
|
|
2455
2718
|
function getServerUrl(registryUrl) {
|
|
2456
2719
|
try {
|
|
2457
|
-
const url = new
|
|
2720
|
+
const url = new URL2(registryUrl);
|
|
2458
2721
|
return `${url.protocol}//${url.host}`;
|
|
2459
2722
|
} catch {
|
|
2460
2723
|
return DEFAULT_WEB_APP_URL;
|
|
@@ -2486,7 +2749,7 @@ function startCallbackServer(expectedState) {
|
|
|
2486
2749
|
rejectToken = reject;
|
|
2487
2750
|
});
|
|
2488
2751
|
const server = http.createServer((req, res) => {
|
|
2489
|
-
const url = new
|
|
2752
|
+
const url = new URL2(req.url || "/", "http://localhost");
|
|
2490
2753
|
if (url.pathname === "/callback") {
|
|
2491
2754
|
const token = url.searchParams.get("token");
|
|
2492
2755
|
const state = url.searchParams.get("state");
|
|
@@ -2573,7 +2836,7 @@ async function browserLogin() {
|
|
|
2573
2836
|
console.log("Starting browser-based login...");
|
|
2574
2837
|
const { port, tokenPromise, cleanup } = await startCallbackServer(state);
|
|
2575
2838
|
const loginUrl = `${webAppUrl}/cli/login?port=${port}&state=${encodeURIComponent(state)}`;
|
|
2576
|
-
console.log(
|
|
2839
|
+
console.log("Opening browser to authenticate...");
|
|
2577
2840
|
console.log(`If the browser doesn't open, visit: ${loginUrl}`);
|
|
2578
2841
|
try {
|
|
2579
2842
|
await open(loginUrl);
|
|
@@ -2617,6 +2880,7 @@ async function login(options) {
|
|
|
2617
2880
|
}
|
|
2618
2881
|
|
|
2619
2882
|
// src/commands/logout.ts
|
|
2883
|
+
init_config();
|
|
2620
2884
|
async function logout() {
|
|
2621
2885
|
try {
|
|
2622
2886
|
const loggedIn = await isLoggedIn();
|
|
@@ -2632,6 +2896,11 @@ async function logout() {
|
|
|
2632
2896
|
process.exit(1);
|
|
2633
2897
|
}
|
|
2634
2898
|
}
|
|
2899
|
+
|
|
2900
|
+
// src/commands/migrate.ts
|
|
2901
|
+
init_config();
|
|
2902
|
+
init_lockfile();
|
|
2903
|
+
import { mkdir as mkdir7, readdir as readdir2, rename, rm as rm5, stat as stat5 } from "fs/promises";
|
|
2635
2904
|
async function migrate(options) {
|
|
2636
2905
|
try {
|
|
2637
2906
|
const legacySkillsDir = getLegacySkillsDir();
|
|
@@ -2642,26 +2911,26 @@ async function migrate(options) {
|
|
|
2642
2911
|
let migrationNeeded = false;
|
|
2643
2912
|
const actions = [];
|
|
2644
2913
|
try {
|
|
2645
|
-
const legacyStats = await
|
|
2914
|
+
const legacyStats = await stat5(legacySkillsDir);
|
|
2646
2915
|
if (legacyStats.isDirectory()) {
|
|
2647
|
-
const contents = await
|
|
2916
|
+
const contents = await readdir2(legacySkillsDir);
|
|
2648
2917
|
if (contents.length > 0) {
|
|
2649
2918
|
migrationNeeded = true;
|
|
2650
|
-
actions.push(
|
|
2919
|
+
actions.push("Move .skills/ \u2192 .pspm/skills/");
|
|
2651
2920
|
}
|
|
2652
2921
|
}
|
|
2653
2922
|
} catch {
|
|
2654
2923
|
}
|
|
2655
2924
|
try {
|
|
2656
|
-
await
|
|
2925
|
+
await stat5(legacyLockfilePath);
|
|
2657
2926
|
try {
|
|
2658
|
-
await
|
|
2927
|
+
await stat5(newLockfilePath);
|
|
2659
2928
|
actions.push(
|
|
2660
|
-
|
|
2929
|
+
"Note: Both skill-lock.json and pspm-lock.json exist. Manual merge may be needed."
|
|
2661
2930
|
);
|
|
2662
2931
|
} catch {
|
|
2663
2932
|
migrationNeeded = true;
|
|
2664
|
-
actions.push(
|
|
2933
|
+
actions.push("Migrate skill-lock.json \u2192 pspm-lock.json");
|
|
2665
2934
|
}
|
|
2666
2935
|
} catch {
|
|
2667
2936
|
}
|
|
@@ -2687,21 +2956,21 @@ async function migrate(options) {
|
|
|
2687
2956
|
console.log(" \u2713 Migrated skill-lock.json \u2192 pspm-lock.json");
|
|
2688
2957
|
}
|
|
2689
2958
|
try {
|
|
2690
|
-
const legacyStats = await
|
|
2959
|
+
const legacyStats = await stat5(legacySkillsDir);
|
|
2691
2960
|
if (legacyStats.isDirectory()) {
|
|
2692
|
-
const contents = await
|
|
2961
|
+
const contents = await readdir2(legacySkillsDir);
|
|
2693
2962
|
if (contents.length > 0) {
|
|
2694
|
-
await
|
|
2963
|
+
await mkdir7(pspmDir, { recursive: true });
|
|
2695
2964
|
try {
|
|
2696
|
-
const newStats = await
|
|
2965
|
+
const newStats = await stat5(newSkillsDir);
|
|
2697
2966
|
if (newStats.isDirectory()) {
|
|
2698
|
-
const newContents = await
|
|
2967
|
+
const newContents = await readdir2(newSkillsDir);
|
|
2699
2968
|
if (newContents.length > 0) {
|
|
2700
2969
|
console.log(
|
|
2701
2970
|
" ! Both .skills/ and .pspm/skills/ have content. Manual merge required."
|
|
2702
2971
|
);
|
|
2703
2972
|
} else {
|
|
2704
|
-
await
|
|
2973
|
+
await rm5(newSkillsDir, { recursive: true, force: true });
|
|
2705
2974
|
await rename(legacySkillsDir, newSkillsDir);
|
|
2706
2975
|
console.log(" \u2713 Moved .skills/ \u2192 .pspm/skills/");
|
|
2707
2976
|
}
|
|
@@ -2731,19 +3000,30 @@ async function migrate(options) {
|
|
|
2731
3000
|
process.exit(1);
|
|
2732
3001
|
}
|
|
2733
3002
|
}
|
|
2734
|
-
|
|
3003
|
+
|
|
3004
|
+
// src/commands/publish.ts
|
|
3005
|
+
init_api_client();
|
|
3006
|
+
init_config();
|
|
3007
|
+
init_errors();
|
|
3008
|
+
init_lib();
|
|
3009
|
+
import { exec as execCb } from "child_process";
|
|
3010
|
+
import { createHash as createHash3 } from "crypto";
|
|
3011
|
+
import { readdir as readdir3, readFile as readFile6, stat as stat6 } from "fs/promises";
|
|
3012
|
+
import { join as join10, relative as relative2 } from "path";
|
|
3013
|
+
import { promisify } from "util";
|
|
3014
|
+
var exec = promisify(execCb);
|
|
2735
3015
|
async function detectManifest() {
|
|
2736
3016
|
const cwd = process.cwd();
|
|
2737
|
-
const pspmJsonPath =
|
|
3017
|
+
const pspmJsonPath = join10(cwd, "pspm.json");
|
|
2738
3018
|
try {
|
|
2739
|
-
const content = await
|
|
3019
|
+
const content = await readFile6(pspmJsonPath, "utf-8");
|
|
2740
3020
|
const manifest = JSON.parse(content);
|
|
2741
3021
|
return { type: "pspm.json", manifest, path: pspmJsonPath };
|
|
2742
3022
|
} catch {
|
|
2743
3023
|
}
|
|
2744
|
-
const packageJsonPath =
|
|
3024
|
+
const packageJsonPath = join10(cwd, "package.json");
|
|
2745
3025
|
try {
|
|
2746
|
-
const content = await
|
|
3026
|
+
const content = await readFile6(packageJsonPath, "utf-8");
|
|
2747
3027
|
const packageJson2 = JSON.parse(content);
|
|
2748
3028
|
const manifest = {
|
|
2749
3029
|
name: packageJson2.name,
|
|
@@ -2766,10 +3046,10 @@ function formatBytes(bytes) {
|
|
|
2766
3046
|
async function getFilesWithSizes(dir, baseDir) {
|
|
2767
3047
|
const results = [];
|
|
2768
3048
|
try {
|
|
2769
|
-
const entries = await
|
|
3049
|
+
const entries = await readdir3(dir, { withFileTypes: true });
|
|
2770
3050
|
for (const entry of entries) {
|
|
2771
|
-
const fullPath =
|
|
2772
|
-
const relativePath =
|
|
3051
|
+
const fullPath = join10(dir, entry.name);
|
|
3052
|
+
const relativePath = relative2(baseDir, fullPath);
|
|
2773
3053
|
if (entry.name === "node_modules" || entry.name === ".git") {
|
|
2774
3054
|
continue;
|
|
2775
3055
|
}
|
|
@@ -2777,7 +3057,7 @@ async function getFilesWithSizes(dir, baseDir) {
|
|
|
2777
3057
|
const subFiles = await getFilesWithSizes(fullPath, baseDir);
|
|
2778
3058
|
results.push(...subFiles);
|
|
2779
3059
|
} else {
|
|
2780
|
-
const fileStat = await
|
|
3060
|
+
const fileStat = await stat6(fullPath);
|
|
2781
3061
|
results.push({ path: relativePath, size: fileStat.size });
|
|
2782
3062
|
}
|
|
2783
3063
|
}
|
|
@@ -2810,7 +3090,7 @@ async function publishCommand(options) {
|
|
|
2810
3090
|
files: manifest.files
|
|
2811
3091
|
};
|
|
2812
3092
|
if (options.bump) {
|
|
2813
|
-
const semver2 = await import(
|
|
3093
|
+
const semver2 = await import("semver");
|
|
2814
3094
|
const newVersion = semver2.default.inc(packageJson2.version, options.bump);
|
|
2815
3095
|
if (!newVersion) {
|
|
2816
3096
|
console.error(
|
|
@@ -2823,7 +3103,7 @@ async function publishCommand(options) {
|
|
|
2823
3103
|
}
|
|
2824
3104
|
const safeName = packageJson2.name.replace(/[@/]/g, "-").replace(/^-+/, "");
|
|
2825
3105
|
const tarballName = `${safeName}-${packageJson2.version}.tgz`;
|
|
2826
|
-
const tempDir =
|
|
3106
|
+
const tempDir = join10(process.cwd(), ".pspm-publish");
|
|
2827
3107
|
try {
|
|
2828
3108
|
await exec(`rm -rf "${tempDir}" && mkdir -p "${tempDir}"`);
|
|
2829
3109
|
const files = packageJson2.files || [...DEFAULT_SKILL_FILES];
|
|
@@ -2839,7 +3119,7 @@ async function publishCommand(options) {
|
|
|
2839
3119
|
if (detection.type === "pspm.json") {
|
|
2840
3120
|
await exec(`cp pspm.json "${tempDir}/package/"`);
|
|
2841
3121
|
try {
|
|
2842
|
-
await
|
|
3122
|
+
await stat6(join10(process.cwd(), "package.json"));
|
|
2843
3123
|
await exec(
|
|
2844
3124
|
`cp package.json "${tempDir}/package/" 2>/dev/null || true`
|
|
2845
3125
|
);
|
|
@@ -2848,30 +3128,30 @@ async function publishCommand(options) {
|
|
|
2848
3128
|
} else {
|
|
2849
3129
|
await exec(`cp package.json "${tempDir}/package/"`);
|
|
2850
3130
|
}
|
|
2851
|
-
const packageDir =
|
|
3131
|
+
const packageDir = join10(tempDir, "package");
|
|
2852
3132
|
const tarballContents = await getFilesWithSizes(packageDir, packageDir);
|
|
2853
3133
|
const unpackedSize = tarballContents.reduce((acc, f) => acc + f.size, 0);
|
|
2854
|
-
const tarballPath =
|
|
3134
|
+
const tarballPath = join10(tempDir, tarballName);
|
|
2855
3135
|
await exec(
|
|
2856
3136
|
`tar -czf "${tarballPath}" -C "${tempDir}" --exclude='node_modules' --exclude='.git' package`
|
|
2857
3137
|
);
|
|
2858
|
-
const tarballBuffer = await
|
|
3138
|
+
const tarballBuffer = await readFile6(tarballPath);
|
|
2859
3139
|
const tarballBase64 = tarballBuffer.toString("base64");
|
|
2860
3140
|
const tarballSize = tarballBuffer.length;
|
|
2861
|
-
const shasum =
|
|
2862
|
-
const integrityHash =
|
|
3141
|
+
const shasum = createHash3("sha1").update(tarballBuffer).digest("hex");
|
|
3142
|
+
const integrityHash = createHash3("sha512").update(tarballBuffer).digest("base64");
|
|
2863
3143
|
const integrity = `sha512-${integrityHash}`;
|
|
2864
3144
|
console.log("");
|
|
2865
|
-
console.log(
|
|
3145
|
+
console.log("pspm notice");
|
|
2866
3146
|
console.log(`pspm notice \u{1F4E6} ${packageJson2.name}@${packageJson2.version}`);
|
|
2867
|
-
console.log(
|
|
3147
|
+
console.log("pspm notice Tarball Contents");
|
|
2868
3148
|
tarballContents.sort((a, b) => b.size - a.size);
|
|
2869
3149
|
for (const file of tarballContents) {
|
|
2870
3150
|
console.log(
|
|
2871
3151
|
`pspm notice ${formatBytes(file.size).padStart(8)} ${file.path}`
|
|
2872
3152
|
);
|
|
2873
3153
|
}
|
|
2874
|
-
console.log(
|
|
3154
|
+
console.log("pspm notice Tarball Details");
|
|
2875
3155
|
console.log(`pspm notice name: ${packageJson2.name}`);
|
|
2876
3156
|
console.log(`pspm notice version: ${packageJson2.version}`);
|
|
2877
3157
|
console.log(`pspm notice filename: ${tarballName}`);
|
|
@@ -2882,7 +3162,7 @@ async function publishCommand(options) {
|
|
|
2882
3162
|
`pspm notice integrity: ${integrity.substring(0, 50)}...`
|
|
2883
3163
|
);
|
|
2884
3164
|
console.log(`pspm notice total files: ${tarballContents.length}`);
|
|
2885
|
-
console.log(
|
|
3165
|
+
console.log("pspm notice");
|
|
2886
3166
|
console.log(`pspm notice Publishing to ${registryUrl} with tag latest`);
|
|
2887
3167
|
configure2({ registryUrl, apiKey });
|
|
2888
3168
|
const response = await publishSkill({
|
|
@@ -2892,7 +3172,7 @@ async function publishCommand(options) {
|
|
|
2892
3172
|
if (response.status !== 200) {
|
|
2893
3173
|
const errorMessage = extractApiErrorMessage(response, "Publish failed");
|
|
2894
3174
|
if (errorMessage.includes("must be greater than") || errorMessage.includes("already exists")) {
|
|
2895
|
-
console.error(
|
|
3175
|
+
console.error("pspm error code E403");
|
|
2896
3176
|
console.error(
|
|
2897
3177
|
`pspm error 403 403 Forbidden - You cannot publish over the previously published versions: ${packageJson2.version}.`
|
|
2898
3178
|
);
|
|
@@ -2936,6 +3216,16 @@ Setting visibility to ${options.access}...`);
|
|
|
2936
3216
|
process.exit(1);
|
|
2937
3217
|
}
|
|
2938
3218
|
}
|
|
3219
|
+
|
|
3220
|
+
// src/commands/remove.ts
|
|
3221
|
+
init_agents();
|
|
3222
|
+
init_config();
|
|
3223
|
+
init_lib();
|
|
3224
|
+
init_lockfile();
|
|
3225
|
+
init_manifest2();
|
|
3226
|
+
init_symlinks();
|
|
3227
|
+
import { rm as rm6 } from "fs/promises";
|
|
3228
|
+
import { join as join11 } from "path";
|
|
2939
3229
|
async function remove(nameOrSpecifier) {
|
|
2940
3230
|
try {
|
|
2941
3231
|
const manifest = await readManifest();
|
|
@@ -2976,9 +3266,9 @@ async function removeRegistry(specifier, agents, agentConfigs) {
|
|
|
2976
3266
|
agentConfigs
|
|
2977
3267
|
});
|
|
2978
3268
|
const skillsDir = getSkillsDir();
|
|
2979
|
-
const destDir =
|
|
3269
|
+
const destDir = join11(skillsDir, username, name);
|
|
2980
3270
|
try {
|
|
2981
|
-
await
|
|
3271
|
+
await rm6(destDir, { recursive: true, force: true });
|
|
2982
3272
|
} catch {
|
|
2983
3273
|
}
|
|
2984
3274
|
console.log(`Removed ${fullName}`);
|
|
@@ -3005,9 +3295,9 @@ async function removeGitHub(specifier, agents, agentConfigs) {
|
|
|
3005
3295
|
});
|
|
3006
3296
|
const skillsDir = getSkillsDir();
|
|
3007
3297
|
const destPath = getGitHubSkillPath(parsed.owner, parsed.repo, parsed.path);
|
|
3008
|
-
const destDir =
|
|
3298
|
+
const destDir = join11(skillsDir, "..", destPath);
|
|
3009
3299
|
try {
|
|
3010
|
-
await
|
|
3300
|
+
await rm6(destDir, { recursive: true, force: true });
|
|
3011
3301
|
} catch {
|
|
3012
3302
|
}
|
|
3013
3303
|
console.log(`Removed ${lockfileKey}`);
|
|
@@ -3037,6 +3327,10 @@ async function removeByShortName(shortName, agents, agentConfigs) {
|
|
|
3037
3327
|
}
|
|
3038
3328
|
|
|
3039
3329
|
// src/commands/unpublish.ts
|
|
3330
|
+
init_api_client();
|
|
3331
|
+
init_config();
|
|
3332
|
+
init_errors();
|
|
3333
|
+
init_lib();
|
|
3040
3334
|
async function unpublish(specifier, options) {
|
|
3041
3335
|
try {
|
|
3042
3336
|
const apiKey = await requireApiKey();
|
|
@@ -3095,6 +3389,12 @@ async function unpublish(specifier, options) {
|
|
|
3095
3389
|
}
|
|
3096
3390
|
|
|
3097
3391
|
// src/commands/update.ts
|
|
3392
|
+
init_api_client();
|
|
3393
|
+
init_config();
|
|
3394
|
+
init_errors();
|
|
3395
|
+
init_lib();
|
|
3396
|
+
init_lockfile();
|
|
3397
|
+
init_add();
|
|
3098
3398
|
async function update(options) {
|
|
3099
3399
|
try {
|
|
3100
3400
|
const apiKey = await requireApiKey();
|
|
@@ -3156,7 +3456,7 @@ async function update(options) {
|
|
|
3156
3456
|
if (!match) continue;
|
|
3157
3457
|
const [, username, skillName] = match;
|
|
3158
3458
|
const specifier = `@user/${username}/${skillName}@${latest}`;
|
|
3159
|
-
await add(specifier, {});
|
|
3459
|
+
await add([specifier], {});
|
|
3160
3460
|
}
|
|
3161
3461
|
console.log("\nAll skills updated.");
|
|
3162
3462
|
} catch (error) {
|
|
@@ -3167,6 +3467,8 @@ async function update(options) {
|
|
|
3167
3467
|
}
|
|
3168
3468
|
|
|
3169
3469
|
// src/commands/whoami.ts
|
|
3470
|
+
init_api_client();
|
|
3471
|
+
init_config();
|
|
3170
3472
|
async function whoami() {
|
|
3171
3473
|
try {
|
|
3172
3474
|
const resolved = await resolveConfig();
|
|
@@ -3192,13 +3494,13 @@ async function whoami() {
|
|
|
3192
3494
|
}
|
|
3193
3495
|
|
|
3194
3496
|
// src/index.ts
|
|
3195
|
-
var __dirname
|
|
3497
|
+
var __dirname = dirname4(fileURLToPath(import.meta.url));
|
|
3196
3498
|
var packageJson = JSON.parse(
|
|
3197
|
-
readFileSync(
|
|
3499
|
+
readFileSync(join12(__dirname, "..", "package.json"), "utf-8")
|
|
3198
3500
|
);
|
|
3199
3501
|
var version = packageJson.version;
|
|
3200
3502
|
var program = new Command();
|
|
3201
|
-
program.name("pspm").description("Prompt Skill Package Manager for
|
|
3503
|
+
program.name("pspm").description("Prompt Skill Package Manager for AI coding agents").version(version);
|
|
3202
3504
|
var configCmd = program.command("config").description("Manage PSPM configuration");
|
|
3203
3505
|
configCmd.command("show").description("Show resolved configuration").action(async () => {
|
|
3204
3506
|
await configShow();
|
|
@@ -3234,13 +3536,13 @@ program.command("migrate").description(
|
|
|
3234
3536
|
).option("--dry-run", "Show what would be migrated without making changes").action(async (options) => {
|
|
3235
3537
|
await migrate({ dryRun: options.dryRun });
|
|
3236
3538
|
});
|
|
3237
|
-
program.command("add <
|
|
3238
|
-
"Add
|
|
3539
|
+
program.command("add <specifiers...>").description(
|
|
3540
|
+
"Add one or more skills (e.g., @user/bsheng/vite_slides@^2.0.0 or github:owner/repo/path@ref)"
|
|
3239
3541
|
).option("--save", "Save to lockfile (default)").option(
|
|
3240
3542
|
"--agent <agents>",
|
|
3241
|
-
'Comma-separated agents for symlinks (default:
|
|
3242
|
-
).option("-y, --yes", "Skip agent selection prompt and use defaults").action(async (
|
|
3243
|
-
await add(
|
|
3543
|
+
'Comma-separated agents for symlinks (default: all agents, use "none" to skip)'
|
|
3544
|
+
).option("-y, --yes", "Skip agent selection prompt and use defaults").action(async (specifiers, options) => {
|
|
3545
|
+
await add(specifiers, {
|
|
3244
3546
|
save: options.save ?? true,
|
|
3245
3547
|
agent: options.agent,
|
|
3246
3548
|
yes: options.yes
|
|
@@ -3252,11 +3554,13 @@ program.command("remove <name>").alias("rm").description("Remove an installed sk
|
|
|
3252
3554
|
program.command("list").alias("ls").description("List installed skills").option("--json", "Output as JSON").action(async (options) => {
|
|
3253
3555
|
await list({ json: options.json });
|
|
3254
3556
|
});
|
|
3255
|
-
program.command("install").alias("i").description(
|
|
3557
|
+
program.command("install [specifiers...]").alias("i").description(
|
|
3558
|
+
"Install skills from lockfile, or add and install specific packages"
|
|
3559
|
+
).option("--frozen-lockfile", "Fail if lockfile is missing or outdated").option("--dir <path>", "Install skills to a specific directory").option(
|
|
3256
3560
|
"--agent <agents>",
|
|
3257
|
-
'Comma-separated agents for symlinks (default:
|
|
3258
|
-
).option("-y, --yes", "Skip agent selection prompt and use defaults").action(async (options) => {
|
|
3259
|
-
await install({
|
|
3561
|
+
'Comma-separated agents for symlinks (default: all agents, use "none" to skip)'
|
|
3562
|
+
).option("-y, --yes", "Skip agent selection prompt and use defaults").action(async (specifiers, options) => {
|
|
3563
|
+
await install(specifiers, {
|
|
3260
3564
|
frozenLockfile: options.frozenLockfile,
|
|
3261
3565
|
dir: options.dir,
|
|
3262
3566
|
agent: options.agent,
|
|
@@ -3265,7 +3569,7 @@ program.command("install").alias("i").description("Install all skills from lockf
|
|
|
3265
3569
|
});
|
|
3266
3570
|
program.command("link").description("Recreate agent symlinks without reinstalling").option(
|
|
3267
3571
|
"--agent <agents>",
|
|
3268
|
-
'Comma-separated agents for symlinks (default:
|
|
3572
|
+
'Comma-separated agents for symlinks (default: all agents, use "none" to skip)'
|
|
3269
3573
|
).option("-y, --yes", "Skip agent selection prompt and use defaults").action(async (options) => {
|
|
3270
3574
|
await link({ agent: options.agent, yes: options.yes });
|
|
3271
3575
|
});
|
|
@@ -3296,5 +3600,4 @@ program.command("deprecate <specifier> [message]").description(
|
|
|
3296
3600
|
await deprecate(specifier, message, { undo: options.undo });
|
|
3297
3601
|
});
|
|
3298
3602
|
program.parse();
|
|
3299
|
-
//# sourceMappingURL=index.js.map
|
|
3300
3603
|
//# sourceMappingURL=index.js.map
|