@agentpowers/cli 0.1.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/dist/api-client.d.ts +19 -0
- package/dist/api-client.js +132 -0
- package/dist/api-client.js.map +1 -0
- package/dist/auth.d.ts +15 -0
- package/dist/auth.js +81 -0
- package/dist/auth.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +31 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/install.d.ts +2 -0
- package/dist/commands/install.js +44 -0
- package/dist/commands/install.js.map +1 -0
- package/dist/commands/login.d.ts +2 -0
- package/dist/commands/login.js +51 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/search.d.ts +2 -0
- package/dist/commands/search.js +30 -0
- package/dist/commands/search.js.map +1 -0
- package/dist/config.d.ts +10 -0
- package/dist/config.js +15 -0
- package/dist/config.js.map +1 -0
- package/dist/formatters.d.ts +5 -0
- package/dist/formatters.js +76 -0
- package/dist/formatters.js.map +1 -0
- package/dist/index.d.ts +6 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/installer.d.ts +15 -0
- package/dist/installer.js +177 -0
- package/dist/installer.js.map +1 -0
- package/dist/types.d.ts +61 -0
- package/dist/types.js +3 -0
- package/dist/types.js.map +1 -0
- package/package.json +54 -0
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
/** HTTP client for the AgentPowers API. */
|
|
2
|
+
export declare class APIError extends Error {
|
|
3
|
+
readonly statusCode: number;
|
|
4
|
+
readonly code?: string | undefined;
|
|
5
|
+
constructor(message: string, statusCode: number, code?: string | undefined);
|
|
6
|
+
}
|
|
7
|
+
export declare class NetworkError extends Error {
|
|
8
|
+
constructor(message: string);
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Map HTTP status codes to user-friendly messages.
|
|
12
|
+
*/
|
|
13
|
+
export declare function formatAPIError(error: APIError): string;
|
|
14
|
+
export declare function apiGet<T = unknown>(path: string, params?: Record<string, string | number | undefined>, auth?: string | null): Promise<T>;
|
|
15
|
+
export declare function apiPost<T = unknown>(path: string, body?: unknown, auth?: string | null): Promise<T>;
|
|
16
|
+
/**
|
|
17
|
+
* Fire-and-forget installation tracking. Never rejects.
|
|
18
|
+
*/
|
|
19
|
+
export declare function recordInstallation(sourceSlug: string, platform: string, source: string, hostname: string, auth?: string | null): Promise<void>;
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
/** HTTP client for the AgentPowers API. */
|
|
2
|
+
import { API_BASE_URL, TIMEOUT_MS } from "./config.js";
|
|
3
|
+
export class APIError extends Error {
|
|
4
|
+
statusCode;
|
|
5
|
+
code;
|
|
6
|
+
constructor(message, statusCode, code) {
|
|
7
|
+
super(message);
|
|
8
|
+
this.statusCode = statusCode;
|
|
9
|
+
this.code = code;
|
|
10
|
+
this.name = "APIError";
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export class NetworkError extends Error {
|
|
14
|
+
constructor(message) {
|
|
15
|
+
super(message);
|
|
16
|
+
this.name = "NetworkError";
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Extract a human-readable message from the API response body.
|
|
21
|
+
*/
|
|
22
|
+
function parseErrorBody(body) {
|
|
23
|
+
try {
|
|
24
|
+
const json = JSON.parse(body);
|
|
25
|
+
if (typeof json.detail === "string") {
|
|
26
|
+
return { message: json.detail };
|
|
27
|
+
}
|
|
28
|
+
if (json.detail && typeof json.detail === "object") {
|
|
29
|
+
const detail = json.detail;
|
|
30
|
+
return {
|
|
31
|
+
message: typeof detail.detail === "string" ? detail.detail : body,
|
|
32
|
+
code: typeof detail.code === "string" ? detail.code : undefined,
|
|
33
|
+
};
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
catch {
|
|
37
|
+
// Not JSON
|
|
38
|
+
}
|
|
39
|
+
return { message: body };
|
|
40
|
+
}
|
|
41
|
+
/**
|
|
42
|
+
* Map HTTP status codes to user-friendly messages.
|
|
43
|
+
*/
|
|
44
|
+
export function formatAPIError(error) {
|
|
45
|
+
switch (error.statusCode) {
|
|
46
|
+
case 401:
|
|
47
|
+
return "Not logged in. Run `npx @agentpowers/cli login` first.";
|
|
48
|
+
case 403:
|
|
49
|
+
return "Access denied. You may need to purchase this skill first.";
|
|
50
|
+
case 404:
|
|
51
|
+
return "Not found. Check the slug and try again.";
|
|
52
|
+
case 409:
|
|
53
|
+
return error.message || "Conflict — this action has already been taken.";
|
|
54
|
+
case 422:
|
|
55
|
+
return `Invalid request: ${error.message}`;
|
|
56
|
+
case 429:
|
|
57
|
+
return "Too many requests. Please wait a moment and try again.";
|
|
58
|
+
default:
|
|
59
|
+
return error.message || `API error (${error.statusCode})`;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
async function safeFetch(url, init) {
|
|
63
|
+
try {
|
|
64
|
+
return await fetch(url, {
|
|
65
|
+
...init,
|
|
66
|
+
signal: AbortSignal.timeout(TIMEOUT_MS),
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
catch (err) {
|
|
70
|
+
if (err instanceof DOMException && err.name === "TimeoutError") {
|
|
71
|
+
throw new NetworkError("Request timed out. The API may be temporarily unavailable.");
|
|
72
|
+
}
|
|
73
|
+
if (err instanceof TypeError) {
|
|
74
|
+
throw new NetworkError("Could not connect to AgentPowers API. Check your network connection.");
|
|
75
|
+
}
|
|
76
|
+
throw err;
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
export async function apiGet(path, params, auth) {
|
|
80
|
+
const url = new URL(path, API_BASE_URL);
|
|
81
|
+
if (params) {
|
|
82
|
+
for (const [key, value] of Object.entries(params)) {
|
|
83
|
+
if (value !== undefined) {
|
|
84
|
+
url.searchParams.set(key, String(value));
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
const headers = { Accept: "application/json" };
|
|
89
|
+
if (auth) {
|
|
90
|
+
headers["Authorization"] = `Bearer ${auth}`;
|
|
91
|
+
}
|
|
92
|
+
const response = await safeFetch(url.toString(), { headers });
|
|
93
|
+
if (!response.ok) {
|
|
94
|
+
const body = await response.text();
|
|
95
|
+
const { message, code } = parseErrorBody(body);
|
|
96
|
+
throw new APIError(message, response.status, code);
|
|
97
|
+
}
|
|
98
|
+
return (await response.json());
|
|
99
|
+
}
|
|
100
|
+
export async function apiPost(path, body, auth) {
|
|
101
|
+
const url = new URL(path, API_BASE_URL);
|
|
102
|
+
const headers = {
|
|
103
|
+
Accept: "application/json",
|
|
104
|
+
"Content-Type": "application/json",
|
|
105
|
+
};
|
|
106
|
+
if (auth) {
|
|
107
|
+
headers["Authorization"] = `Bearer ${auth}`;
|
|
108
|
+
}
|
|
109
|
+
const response = await safeFetch(url.toString(), {
|
|
110
|
+
method: "POST",
|
|
111
|
+
headers,
|
|
112
|
+
body: body !== undefined ? JSON.stringify(body) : undefined,
|
|
113
|
+
});
|
|
114
|
+
if (!response.ok) {
|
|
115
|
+
const text = await response.text();
|
|
116
|
+
const { message, code } = parseErrorBody(text);
|
|
117
|
+
throw new APIError(message, response.status, code);
|
|
118
|
+
}
|
|
119
|
+
return (await response.json());
|
|
120
|
+
}
|
|
121
|
+
/**
|
|
122
|
+
* Fire-and-forget installation tracking. Never rejects.
|
|
123
|
+
*/
|
|
124
|
+
export async function recordInstallation(sourceSlug, platform, source, hostname, auth) {
|
|
125
|
+
try {
|
|
126
|
+
await apiPost("/v1/installations", { source_slug: sourceSlug, platform, source, hostname }, auth);
|
|
127
|
+
}
|
|
128
|
+
catch {
|
|
129
|
+
// Swallow all errors — tracking must not break install flow
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
//# sourceMappingURL=api-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"api-client.js","sourceRoot":"","sources":["../src/api-client.ts"],"names":[],"mappings":"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"}
|
package/dist/auth.d.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** Auth token management — shared with Python CLI at ~/.agentpowers/auth.json */
|
|
2
|
+
/**
|
|
3
|
+
* Load the auth token from disk. Returns null if missing or expired.
|
|
4
|
+
*/
|
|
5
|
+
export declare function loadAuthToken(): string | null;
|
|
6
|
+
/**
|
|
7
|
+
* Check if the user is currently authenticated.
|
|
8
|
+
*/
|
|
9
|
+
export declare function isAuthenticated(): boolean;
|
|
10
|
+
/**
|
|
11
|
+
* Wait for the auth token file to appear or update.
|
|
12
|
+
* Polls the file every 2 seconds for up to 2 minutes.
|
|
13
|
+
* Returns the token on success, null on timeout.
|
|
14
|
+
*/
|
|
15
|
+
export declare function waitForAuthToken(pollIntervalMs?: number, timeoutMs?: number): Promise<string | null>;
|
package/dist/auth.js
ADDED
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/** Auth token management — shared with Python CLI at ~/.agentpowers/auth.json */
|
|
2
|
+
import { readFileSync, existsSync, watchFile, unwatchFile } from "node:fs";
|
|
3
|
+
import { AUTH_FILE, LOGIN_POLL_INTERVAL_MS, LOGIN_TIMEOUT_MS } from "./config.js";
|
|
4
|
+
/**
|
|
5
|
+
* Load the auth token from disk. Returns null if missing or expired.
|
|
6
|
+
*/
|
|
7
|
+
export function loadAuthToken() {
|
|
8
|
+
if (!existsSync(AUTH_FILE))
|
|
9
|
+
return null;
|
|
10
|
+
try {
|
|
11
|
+
const data = JSON.parse(readFileSync(AUTH_FILE, "utf-8"));
|
|
12
|
+
if (typeof data.token !== "string")
|
|
13
|
+
return null;
|
|
14
|
+
// Check expiration
|
|
15
|
+
if (data.expires_at) {
|
|
16
|
+
const expires = new Date(data.expires_at);
|
|
17
|
+
if (expires.getTime() < Date.now())
|
|
18
|
+
return null;
|
|
19
|
+
}
|
|
20
|
+
return data.token;
|
|
21
|
+
}
|
|
22
|
+
catch {
|
|
23
|
+
return null;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/**
|
|
27
|
+
* Check if the user is currently authenticated.
|
|
28
|
+
*/
|
|
29
|
+
export function isAuthenticated() {
|
|
30
|
+
return loadAuthToken() !== null;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Wait for the auth token file to appear or update.
|
|
34
|
+
* Polls the file every 2 seconds for up to 2 minutes.
|
|
35
|
+
* Returns the token on success, null on timeout.
|
|
36
|
+
*/
|
|
37
|
+
export function waitForAuthToken(pollIntervalMs = LOGIN_POLL_INTERVAL_MS, timeoutMs = LOGIN_TIMEOUT_MS) {
|
|
38
|
+
return new Promise((resolve) => {
|
|
39
|
+
const startTime = Date.now();
|
|
40
|
+
const initialToken = loadAuthToken();
|
|
41
|
+
const checkToken = () => {
|
|
42
|
+
const token = loadAuthToken();
|
|
43
|
+
// Succeed if we have a token that differs from what we started with
|
|
44
|
+
// (or if we had no token before and now we do)
|
|
45
|
+
if (token && token !== initialToken) {
|
|
46
|
+
cleanup();
|
|
47
|
+
resolve(token);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
if (Date.now() - startTime >= timeoutMs) {
|
|
51
|
+
cleanup();
|
|
52
|
+
resolve(null);
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
const interval = setInterval(checkToken, pollIntervalMs);
|
|
57
|
+
// Also watch the file for changes (faster detection)
|
|
58
|
+
let fileWatcherActive = false;
|
|
59
|
+
try {
|
|
60
|
+
watchFile(AUTH_FILE, { interval: 500 }, () => {
|
|
61
|
+
checkToken();
|
|
62
|
+
});
|
|
63
|
+
fileWatcherActive = true;
|
|
64
|
+
}
|
|
65
|
+
catch {
|
|
66
|
+
// watchFile may fail if directory doesn't exist — polling is fine
|
|
67
|
+
}
|
|
68
|
+
const cleanup = () => {
|
|
69
|
+
clearInterval(interval);
|
|
70
|
+
if (fileWatcherActive) {
|
|
71
|
+
try {
|
|
72
|
+
unwatchFile(AUTH_FILE);
|
|
73
|
+
}
|
|
74
|
+
catch {
|
|
75
|
+
// ignore cleanup errors
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
//# sourceMappingURL=auth.js.map
|
package/dist/auth.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"auth.js","sourceRoot":"","sources":["../src/auth.ts"],"names":[],"mappings":"AAAA,iFAAiF;AAEjF,OAAO,EAAE,YAAY,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAC3E,OAAO,EAAE,SAAS,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAGlF;;GAEG;AACH,MAAM,UAAU,aAAa;IAC3B,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC;QAAE,OAAO,IAAI,CAAC;IACxC,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAa,CAAC;QACtE,IAAI,OAAO,IAAI,CAAC,KAAK,KAAK,QAAQ;YAAE,OAAO,IAAI,CAAC;QAEhD,mBAAmB;QACnB,IAAI,IAAI,CAAC,UAAU,EAAE,CAAC;YACpB,MAAM,OAAO,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;YAC1C,IAAI,OAAO,CAAC,OAAO,EAAE,GAAG,IAAI,CAAC,GAAG,EAAE;gBAAE,OAAO,IAAI,CAAC;QAClD,CAAC;QAED,OAAO,IAAI,CAAC,KAAK,CAAC;IACpB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,IAAI,CAAC;IACd,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,eAAe;IAC7B,OAAO,aAAa,EAAE,KAAK,IAAI,CAAC;AAClC,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAC9B,iBAAyB,sBAAsB,EAC/C,YAAoB,gBAAgB;IAEpC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,EAAE;QAC7B,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC7B,MAAM,YAAY,GAAG,aAAa,EAAE,CAAC;QAErC,MAAM,UAAU,GAAG,GAAS,EAAE;YAC5B,MAAM,KAAK,GAAG,aAAa,EAAE,CAAC;YAC9B,oEAAoE;YACpE,+CAA+C;YAC/C,IAAI,KAAK,IAAI,KAAK,KAAK,YAAY,EAAE,CAAC;gBACpC,OAAO,EAAE,CAAC;gBACV,OAAO,CAAC,KAAK,CAAC,CAAC;gBACf,OAAO;YACT,CAAC;YAED,IAAI,IAAI,CAAC,GAAG,EAAE,GAAG,SAAS,IAAI,SAAS,EAAE,CAAC;gBACxC,OAAO,EAAE,CAAC;gBACV,OAAO,CAAC,IAAI,CAAC,CAAC;gBACd,OAAO;YACT,CAAC;QACH,CAAC,CAAC;QAEF,MAAM,QAAQ,GAAG,WAAW,CAAC,UAAU,EAAE,cAAc,CAAC,CAAC;QAEzD,qDAAqD;QACrD,IAAI,iBAAiB,GAAG,KAAK,CAAC;QAC9B,IAAI,CAAC;YACH,SAAS,CAAC,SAAS,EAAE,EAAE,QAAQ,EAAE,GAAG,EAAE,EAAE,GAAG,EAAE;gBAC3C,UAAU,EAAE,CAAC;YACf,CAAC,CAAC,CAAC;YACH,iBAAiB,GAAG,IAAI,CAAC;QAC3B,CAAC;QAAC,MAAM,CAAC;YACP,kEAAkE;QACpE,CAAC;QAED,MAAM,OAAO,GAAG,GAAS,EAAE;YACzB,aAAa,CAAC,QAAQ,CAAC,CAAC;YACxB,IAAI,iBAAiB,EAAE,CAAC;gBACtB,IAAI,CAAC;oBACH,WAAW,CAAC,SAAS,CAAC,CAAC;gBACzB,CAAC;gBAAC,MAAM,CAAC;oBACP,wBAAwB;gBAC1B,CAAC;YACH,CAAC;QACH,CAAC,CAAC;IACJ,CAAC,CAAC,CAAC;AACL,CAAC"}
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/** AgentPowers CLI — search, install, and manage Claude Code skills. */
|
|
3
|
+
import { Command } from "commander";
|
|
4
|
+
import { searchCommand } from "./commands/search.js";
|
|
5
|
+
import { installCommand } from "./commands/install.js";
|
|
6
|
+
import { loginCommand } from "./commands/login.js";
|
|
7
|
+
const program = new Command();
|
|
8
|
+
program
|
|
9
|
+
.name("agentpowers")
|
|
10
|
+
.description("Search, install, and manage Claude Code skills from the AgentPowers marketplace.")
|
|
11
|
+
.version("0.1.0");
|
|
12
|
+
program
|
|
13
|
+
.command("search <query>")
|
|
14
|
+
.description("Search for skills in the marketplace")
|
|
15
|
+
.action(async (query) => {
|
|
16
|
+
await searchCommand(query);
|
|
17
|
+
});
|
|
18
|
+
program
|
|
19
|
+
.command("install <slug>")
|
|
20
|
+
.description("Install a skill by its slug")
|
|
21
|
+
.action(async (slug) => {
|
|
22
|
+
await installCommand(slug);
|
|
23
|
+
});
|
|
24
|
+
program
|
|
25
|
+
.command("login")
|
|
26
|
+
.description("Log in to AgentPowers via your browser")
|
|
27
|
+
.action(async () => {
|
|
28
|
+
await loginCommand();
|
|
29
|
+
});
|
|
30
|
+
program.parse();
|
|
31
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AAEA,wEAAwE;AAExE,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AACrD,OAAO,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACvD,OAAO,EAAE,YAAY,EAAE,MAAM,qBAAqB,CAAC;AAEnD,MAAM,OAAO,GAAG,IAAI,OAAO,EAAE,CAAC;AAE9B,OAAO;KACJ,IAAI,CAAC,aAAa,CAAC;KACnB,WAAW,CAAC,kFAAkF,CAAC;KAC/F,OAAO,CAAC,OAAO,CAAC,CAAC;AAEpB,OAAO;KACJ,OAAO,CAAC,gBAAgB,CAAC;KACzB,WAAW,CAAC,sCAAsC,CAAC;KACnD,MAAM,CAAC,KAAK,EAAE,KAAa,EAAE,EAAE;IAC9B,MAAM,aAAa,CAAC,KAAK,CAAC,CAAC;AAC7B,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,gBAAgB,CAAC;KACzB,WAAW,CAAC,6BAA6B,CAAC;KAC1C,MAAM,CAAC,KAAK,EAAE,IAAY,EAAE,EAAE;IAC7B,MAAM,cAAc,CAAC,IAAI,CAAC,CAAC;AAC7B,CAAC,CAAC,CAAC;AAEL,OAAO;KACJ,OAAO,CAAC,OAAO,CAAC;KAChB,WAAW,CAAC,wCAAwC,CAAC;KACrD,MAAM,CAAC,KAAK,IAAI,EAAE;IACjB,MAAM,YAAY,EAAE,CAAC;AACvB,CAAC,CAAC,CAAC;AAEL,OAAO,CAAC,KAAK,EAAE,CAAC"}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
/** Install command — download and install a skill from the marketplace. */
|
|
2
|
+
import { hostname } from "node:os";
|
|
3
|
+
import { loadAuthToken } from "../auth.js";
|
|
4
|
+
import { apiGet, recordInstallation, APIError, formatAPIError, NetworkError, } from "../api-client.js";
|
|
5
|
+
import { downloadAndExtract, validateSlug } from "../installer.js";
|
|
6
|
+
export async function installCommand(slug) {
|
|
7
|
+
// Validate slug format
|
|
8
|
+
if (!validateSlug(slug)) {
|
|
9
|
+
console.error(`Error: Invalid slug "${slug}". Slugs must be lowercase alphanumeric with hyphens only.`);
|
|
10
|
+
process.exitCode = 1;
|
|
11
|
+
return;
|
|
12
|
+
}
|
|
13
|
+
const token = loadAuthToken();
|
|
14
|
+
try {
|
|
15
|
+
console.log(`Downloading ${slug}...`);
|
|
16
|
+
// Get download URL
|
|
17
|
+
const downloadData = await apiGet(`/v1/skills/${slug}/download`, undefined, token);
|
|
18
|
+
// Download and extract
|
|
19
|
+
const result = await downloadAndExtract(downloadData.url, slug, "agentpowers");
|
|
20
|
+
console.log(`Installed ${slug} to ${result.installDir}`);
|
|
21
|
+
console.log(`Content hash: ${result.contentHash}`);
|
|
22
|
+
// Record installation (fire-and-forget)
|
|
23
|
+
void recordInstallation(slug, "cli", "agentpowers", hostname(), token);
|
|
24
|
+
console.log("\nThe skill is now available in Claude Code.");
|
|
25
|
+
}
|
|
26
|
+
catch (err) {
|
|
27
|
+
if (err instanceof APIError) {
|
|
28
|
+
console.error(`Error: ${formatAPIError(err)}`);
|
|
29
|
+
process.exitCode = 1;
|
|
30
|
+
}
|
|
31
|
+
else if (err instanceof NetworkError) {
|
|
32
|
+
console.error(`Error: ${err.message}`);
|
|
33
|
+
process.exitCode = 1;
|
|
34
|
+
}
|
|
35
|
+
else if (err instanceof Error) {
|
|
36
|
+
console.error(`Error: ${err.message}`);
|
|
37
|
+
process.exitCode = 1;
|
|
38
|
+
}
|
|
39
|
+
else {
|
|
40
|
+
throw err;
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=install.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"install.js","sourceRoot":"","sources":["../../src/commands/install.ts"],"names":[],"mappings":"AAAA,2EAA2E;AAE3E,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EACL,MAAM,EACN,kBAAkB,EAClB,QAAQ,EACR,cAAc,EACd,YAAY,GACb,MAAM,kBAAkB,CAAC;AAC1B,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,MAAM,iBAAiB,CAAC;AAGnE,MAAM,CAAC,KAAK,UAAU,cAAc,CAAC,IAAY;IAC/C,uBAAuB;IACvB,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;QACxB,OAAO,CAAC,KAAK,CACX,wBAAwB,IAAI,4DAA4D,CACzF,CAAC;QACF,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACrB,OAAO;IACT,CAAC;IAED,MAAM,KAAK,GAAG,aAAa,EAAE,CAAC;IAE9B,IAAI,CAAC;QACH,OAAO,CAAC,GAAG,CAAC,eAAe,IAAI,KAAK,CAAC,CAAC;QAEtC,mBAAmB;QACnB,MAAM,YAAY,GAAG,MAAM,MAAM,CAC/B,cAAc,IAAI,WAAW,EAC7B,SAAS,EACT,KAAK,CACN,CAAC;QAEF,uBAAuB;QACvB,MAAM,MAAM,GAAG,MAAM,kBAAkB,CACrC,YAAY,CAAC,GAAG,EAChB,IAAI,EACJ,aAAa,CACd,CAAC;QAEF,OAAO,CAAC,GAAG,CAAC,aAAa,IAAI,OAAO,MAAM,CAAC,UAAU,EAAE,CAAC,CAAC;QACzD,OAAO,CAAC,GAAG,CAAC,iBAAiB,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC;QAEnD,wCAAwC;QACxC,KAAK,kBAAkB,CAAC,IAAI,EAAE,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,EAAE,KAAK,CAAC,CAAC;QAEvE,OAAO,CAAC,GAAG,CAAC,8CAA8C,CAAC,CAAC;IAC9D,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,QAAQ,EAAE,CAAC;YAC5B,OAAO,CAAC,KAAK,CAAC,UAAU,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAC/C,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACvB,CAAC;aAAM,IAAI,GAAG,YAAY,YAAY,EAAE,CAAC;YACvC,OAAO,CAAC,KAAK,CAAC,UAAU,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;YACvC,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACvB,CAAC;aAAM,IAAI,GAAG,YAAY,KAAK,EAAE,CAAC;YAChC,OAAO,CAAC,KAAK,CAAC,UAAU,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;YACvC,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACvB,CAAC;aAAM,CAAC;YACN,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/** Login command — open browser and wait for auth token. */
|
|
2
|
+
import { exec } from "node:child_process";
|
|
3
|
+
import { platform } from "node:os";
|
|
4
|
+
import { mkdirSync } from "node:fs";
|
|
5
|
+
import { isAuthenticated, waitForAuthToken } from "../auth.js";
|
|
6
|
+
import { LOGIN_URL, AUTH_DIR } from "../config.js";
|
|
7
|
+
/**
|
|
8
|
+
* Open a URL in the user's default browser.
|
|
9
|
+
*/
|
|
10
|
+
function openBrowser(url) {
|
|
11
|
+
const os = platform();
|
|
12
|
+
let command;
|
|
13
|
+
if (os === "darwin") {
|
|
14
|
+
command = `open "${url}"`;
|
|
15
|
+
}
|
|
16
|
+
else if (os === "win32") {
|
|
17
|
+
command = `start "" "${url}"`;
|
|
18
|
+
}
|
|
19
|
+
else {
|
|
20
|
+
command = `xdg-open "${url}"`;
|
|
21
|
+
}
|
|
22
|
+
exec(command, (err) => {
|
|
23
|
+
if (err) {
|
|
24
|
+
console.log(`Could not open browser. Please visit: ${url}`);
|
|
25
|
+
}
|
|
26
|
+
});
|
|
27
|
+
}
|
|
28
|
+
export async function loginCommand() {
|
|
29
|
+
// Check if already authenticated
|
|
30
|
+
if (isAuthenticated()) {
|
|
31
|
+
console.log("You are already logged in.");
|
|
32
|
+
console.log("To log in with a different account, delete ~/.agentpowers/auth.json and try again.");
|
|
33
|
+
return;
|
|
34
|
+
}
|
|
35
|
+
// Ensure auth directory exists
|
|
36
|
+
mkdirSync(AUTH_DIR, { recursive: true });
|
|
37
|
+
console.log("Opening browser for login...");
|
|
38
|
+
console.log(`If the browser does not open, visit: ${LOGIN_URL}`);
|
|
39
|
+
console.log("");
|
|
40
|
+
openBrowser(LOGIN_URL);
|
|
41
|
+
console.log("Waiting for authentication...");
|
|
42
|
+
const token = await waitForAuthToken();
|
|
43
|
+
if (token) {
|
|
44
|
+
console.log("Login successful! You are now authenticated.");
|
|
45
|
+
}
|
|
46
|
+
else {
|
|
47
|
+
console.error("Login timed out. Please try again.");
|
|
48
|
+
process.exitCode = 1;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
//# sourceMappingURL=login.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"login.js","sourceRoot":"","sources":["../../src/commands/login.ts"],"names":[],"mappings":"AAAA,4DAA4D;AAE5D,OAAO,EAAE,IAAI,EAAE,MAAM,oBAAoB,CAAC;AAC1C,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AACnC,OAAO,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpC,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAC;AAC/D,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,MAAM,cAAc,CAAC;AAEnD;;GAEG;AACH,SAAS,WAAW,CAAC,GAAW;IAC9B,MAAM,EAAE,GAAG,QAAQ,EAAE,CAAC;IACtB,IAAI,OAAe,CAAC;IACpB,IAAI,EAAE,KAAK,QAAQ,EAAE,CAAC;QACpB,OAAO,GAAG,SAAS,GAAG,GAAG,CAAC;IAC5B,CAAC;SAAM,IAAI,EAAE,KAAK,OAAO,EAAE,CAAC;QAC1B,OAAO,GAAG,aAAa,GAAG,GAAG,CAAC;IAChC,CAAC;SAAM,CAAC;QACN,OAAO,GAAG,aAAa,GAAG,GAAG,CAAC;IAChC,CAAC;IACD,IAAI,CAAC,OAAO,EAAE,CAAC,GAAG,EAAE,EAAE;QACpB,IAAI,GAAG,EAAE,CAAC;YACR,OAAO,CAAC,GAAG,CAAC,yCAAyC,GAAG,EAAE,CAAC,CAAC;QAC9D,CAAC;IACH,CAAC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY;IAChC,iCAAiC;IACjC,IAAI,eAAe,EAAE,EAAE,CAAC;QACtB,OAAO,CAAC,GAAG,CAAC,4BAA4B,CAAC,CAAC;QAC1C,OAAO,CAAC,GAAG,CAAC,oFAAoF,CAAC,CAAC;QAClG,OAAO;IACT,CAAC;IAED,+BAA+B;IAC/B,SAAS,CAAC,QAAQ,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IAEzC,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC;IAC5C,OAAO,CAAC,GAAG,CAAC,wCAAwC,SAAS,EAAE,CAAC,CAAC;IACjE,OAAO,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;IAEhB,WAAW,CAAC,SAAS,CAAC,CAAC;IAEvB,OAAO,CAAC,GAAG,CAAC,+BAA+B,CAAC,CAAC;IAE7C,MAAM,KAAK,GAAG,MAAM,gBAAgB,EAAE,CAAC;IAEvC,IAAI,KAAK,EAAE,CAAC;QACV,OAAO,CAAC,GAAG,CAAC,8CAA8C,CAAC,CAAC;IAC9D,CAAC;SAAM,CAAC;QACN,OAAO,CAAC,KAAK,CAAC,oCAAoC,CAAC,CAAC;QACpD,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;IACvB,CAAC;AACH,CAAC"}
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
/** Search command — query the AgentPowers marketplace. */
|
|
2
|
+
import { apiGet, APIError, formatAPIError, NetworkError } from "../api-client.js";
|
|
3
|
+
import { formatSearchResults } from "../formatters.js";
|
|
4
|
+
export async function searchCommand(query) {
|
|
5
|
+
try {
|
|
6
|
+
const data = await apiGet("/v1/search", { q: query });
|
|
7
|
+
const output = formatSearchResults(data);
|
|
8
|
+
console.log(output);
|
|
9
|
+
// Install hint
|
|
10
|
+
const native = data.agentpowers;
|
|
11
|
+
if (native.items.length > 0) {
|
|
12
|
+
const firstSlug = native.items[0].slug;
|
|
13
|
+
console.log(`Tip: Install a skill with: npx @agentpowers/cli install ${firstSlug}`);
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
catch (err) {
|
|
17
|
+
if (err instanceof APIError) {
|
|
18
|
+
console.error(`Error: ${formatAPIError(err)}`);
|
|
19
|
+
process.exitCode = 1;
|
|
20
|
+
}
|
|
21
|
+
else if (err instanceof NetworkError) {
|
|
22
|
+
console.error(`Error: ${err.message}`);
|
|
23
|
+
process.exitCode = 1;
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
throw err;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
//# sourceMappingURL=search.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"search.js","sourceRoot":"","sources":["../../src/commands/search.ts"],"names":[],"mappings":"AAAA,0DAA0D;AAE1D,OAAO,EAAE,MAAM,EAAE,QAAQ,EAAE,cAAc,EAAE,YAAY,EAAE,MAAM,kBAAkB,CAAC;AAClF,OAAO,EAAE,mBAAmB,EAAE,MAAM,kBAAkB,CAAC;AAGvD,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,KAAa;IAC/C,IAAI,CAAC;QACH,MAAM,IAAI,GAAG,MAAM,MAAM,CAA0B,YAAY,EAAE,EAAE,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC;QAC/E,MAAM,MAAM,GAAG,mBAAmB,CAAC,IAAI,CAAC,CAAC;QACzC,OAAO,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QAEpB,eAAe;QACf,MAAM,MAAM,GAAG,IAAI,CAAC,WAAW,CAAC;QAChC,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAC5B,MAAM,SAAS,GAAG,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC;YACvC,OAAO,CAAC,GAAG,CAAC,2DAA2D,SAAS,EAAE,CAAC,CAAC;QACtF,CAAC;IACH,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAI,GAAG,YAAY,QAAQ,EAAE,CAAC;YAC5B,OAAO,CAAC,KAAK,CAAC,UAAU,cAAc,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;YAC/C,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACvB,CAAC;aAAM,IAAI,GAAG,YAAY,YAAY,EAAE,CAAC;YACvC,OAAO,CAAC,KAAK,CAAC,UAAU,GAAG,CAAC,OAAO,EAAE,CAAC,CAAC;YACvC,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;QACvB,CAAC;aAAM,CAAC;YACN,MAAM,GAAG,CAAC;QACZ,CAAC;IACH,CAAC;AACH,CAAC"}
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/** Configuration constants for the AgentPowers CLI. */
|
|
2
|
+
export declare const API_BASE_URL: string;
|
|
3
|
+
export declare const AUTH_DIR: string;
|
|
4
|
+
export declare const AUTH_FILE: string;
|
|
5
|
+
export declare const PINS_FILE: string;
|
|
6
|
+
export declare const SKILLS_DIR: string;
|
|
7
|
+
export declare const LOGIN_URL = "https://agentpowers.ai/cli-auth";
|
|
8
|
+
export declare const TIMEOUT_MS = 30000;
|
|
9
|
+
export declare const LOGIN_POLL_INTERVAL_MS = 2000;
|
|
10
|
+
export declare const LOGIN_TIMEOUT_MS = 120000;
|
package/dist/config.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** Configuration constants for the AgentPowers CLI. */
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
export const API_BASE_URL = process.env.AGENTPOWERS_API_URL ??
|
|
5
|
+
process.env.AP_API_BASE ??
|
|
6
|
+
"https://api.agentpowers.ai";
|
|
7
|
+
export const AUTH_DIR = join(homedir(), ".agentpowers");
|
|
8
|
+
export const AUTH_FILE = join(AUTH_DIR, "auth.json");
|
|
9
|
+
export const PINS_FILE = join(AUTH_DIR, "pins.json");
|
|
10
|
+
export const SKILLS_DIR = join(homedir(), ".claude", "skills");
|
|
11
|
+
export const LOGIN_URL = "https://agentpowers.ai/cli-auth";
|
|
12
|
+
export const TIMEOUT_MS = 30_000;
|
|
13
|
+
export const LOGIN_POLL_INTERVAL_MS = 2_000;
|
|
14
|
+
export const LOGIN_TIMEOUT_MS = 120_000;
|
|
15
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,uDAAuD;AAEvD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,OAAO,EAAE,MAAM,SAAS,CAAC;AAElC,MAAM,CAAC,MAAM,YAAY,GACvB,OAAO,CAAC,GAAG,CAAC,mBAAmB;IAC/B,OAAO,CAAC,GAAG,CAAC,WAAW;IACvB,4BAA4B,CAAC;AAE/B,MAAM,CAAC,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,cAAc,CAAC,CAAC;AACxD,MAAM,CAAC,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;AACrD,MAAM,CAAC,MAAM,SAAS,GAAG,IAAI,CAAC,QAAQ,EAAE,WAAW,CAAC,CAAC;AACrD,MAAM,CAAC,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,EAAE,EAAE,SAAS,EAAE,QAAQ,CAAC,CAAC;AAC/D,MAAM,CAAC,MAAM,SAAS,GAAG,iCAAiC,CAAC;AAC3D,MAAM,CAAC,MAAM,UAAU,GAAG,MAAM,CAAC;AACjC,MAAM,CAAC,MAAM,sBAAsB,GAAG,KAAK,CAAC;AAC5C,MAAM,CAAC,MAAM,gBAAgB,GAAG,OAAO,CAAC"}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
/** Terminal output formatters for CLI display. */
|
|
2
|
+
import type { SectionedSearchResponse } from "./types.js";
|
|
3
|
+
export declare function formatPrice(priceCents: number): string;
|
|
4
|
+
export declare function formatSecurityStatus(status: string): string;
|
|
5
|
+
export declare function formatSearchResults(data: SectionedSearchResponse): string;
|
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/** Terminal output formatters for CLI display. */
|
|
2
|
+
export function formatPrice(priceCents) {
|
|
3
|
+
if (priceCents === 0)
|
|
4
|
+
return "Free";
|
|
5
|
+
return `$${(priceCents / 100).toFixed(2)}`;
|
|
6
|
+
}
|
|
7
|
+
export function formatSecurityStatus(status) {
|
|
8
|
+
switch (status.toUpperCase()) {
|
|
9
|
+
case "PASS":
|
|
10
|
+
return "Passed";
|
|
11
|
+
case "WARN":
|
|
12
|
+
return "Warnings";
|
|
13
|
+
case "BLOCK":
|
|
14
|
+
return "Blocked";
|
|
15
|
+
default:
|
|
16
|
+
return status;
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function formatNativeItem(item, index) {
|
|
20
|
+
const author = item.author
|
|
21
|
+
? item.author.display_name || item.author.github_username || "Unknown"
|
|
22
|
+
: "Unknown";
|
|
23
|
+
const lines = [
|
|
24
|
+
` ${index}. ${item.title} (${item.slug})`,
|
|
25
|
+
` ${item.description}`,
|
|
26
|
+
` ${formatPrice(item.price_cents)} | v${item.version} | ${formatSecurityStatus(item.security_status)} | ${item.download_count} downloads | by ${author}`,
|
|
27
|
+
"",
|
|
28
|
+
];
|
|
29
|
+
return lines.join("\n");
|
|
30
|
+
}
|
|
31
|
+
function formatExternalItem(item, index) {
|
|
32
|
+
const security = item.ap_security_status
|
|
33
|
+
? formatSecurityStatus(item.ap_security_status)
|
|
34
|
+
: "Not scanned";
|
|
35
|
+
const lines = [
|
|
36
|
+
` ${index}. ${item.title} (${item.slug})`,
|
|
37
|
+
` ${item.description}`,
|
|
38
|
+
` ${formatPrice(item.price_cents)} | ${security} | by ${item.author}`,
|
|
39
|
+
"",
|
|
40
|
+
];
|
|
41
|
+
return lines.join("\n");
|
|
42
|
+
}
|
|
43
|
+
export function formatSearchResults(data) {
|
|
44
|
+
const native = data.agentpowers;
|
|
45
|
+
const externalSources = Object.keys(data).filter((k) => k !== "agentpowers");
|
|
46
|
+
const totalResults = native.total +
|
|
47
|
+
externalSources.reduce((sum, key) => sum + data[key].total, 0);
|
|
48
|
+
if (totalResults === 0) {
|
|
49
|
+
return "No results found.";
|
|
50
|
+
}
|
|
51
|
+
const sections = [];
|
|
52
|
+
let globalIndex = 1;
|
|
53
|
+
// Native AgentPowers results
|
|
54
|
+
if (native.items.length > 0) {
|
|
55
|
+
const lines = [`AgentPowers Marketplace (${native.total} result${native.total === 1 ? "" : "s"})`, ""];
|
|
56
|
+
for (const item of native.items) {
|
|
57
|
+
lines.push(formatNativeItem(item, globalIndex++));
|
|
58
|
+
}
|
|
59
|
+
sections.push(lines.join("\n"));
|
|
60
|
+
}
|
|
61
|
+
// External source results
|
|
62
|
+
for (const source of externalSources) {
|
|
63
|
+
const section = data[source];
|
|
64
|
+
if (section.items.length > 0) {
|
|
65
|
+
const label = source.charAt(0).toUpperCase() + source.slice(1);
|
|
66
|
+
const lines = [`${label} (${section.total} result${section.total === 1 ? "" : "s"})`, ""];
|
|
67
|
+
for (const item of section.items) {
|
|
68
|
+
lines.push(formatExternalItem(item, globalIndex++));
|
|
69
|
+
}
|
|
70
|
+
sections.push(lines.join("\n"));
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
const header = `Found ${totalResults} result${totalResults === 1 ? "" : "s"}:\n`;
|
|
74
|
+
return header + sections.join("\n");
|
|
75
|
+
}
|
|
76
|
+
//# sourceMappingURL=formatters.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"formatters.js","sourceRoot":"","sources":["../src/formatters.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Public API — re-exports for programmatic usage. */
|
|
2
|
+
export { loadAuthToken, isAuthenticated } from "./auth.js";
|
|
3
|
+
export { apiGet, apiPost, APIError, NetworkError, formatAPIError } from "./api-client.js";
|
|
4
|
+
export { downloadAndExtract, validateSlug, getInstallDir } from "./installer.js";
|
|
5
|
+
export { formatSearchResults, formatPrice } from "./formatters.js";
|
|
6
|
+
export type { NativeSearchItem, ExternalSearchItem, SectionedSearchResponse, DownloadResponse, AuthData, } from "./types.js";
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** Public API — re-exports for programmatic usage. */
|
|
2
|
+
export { loadAuthToken, isAuthenticated } from "./auth.js";
|
|
3
|
+
export { apiGet, apiPost, APIError, NetworkError, formatAPIError } from "./api-client.js";
|
|
4
|
+
export { downloadAndExtract, validateSlug, getInstallDir } from "./installer.js";
|
|
5
|
+
export { formatSearchResults, formatPrice } from "./formatters.js";
|
|
6
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,sDAAsD;AAEtD,OAAO,EAAE,aAAa,EAAE,eAAe,EAAE,MAAM,WAAW,CAAC;AAC3D,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,QAAQ,EAAE,YAAY,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAC1F,OAAO,EAAE,kBAAkB,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AACjF,OAAO,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/** Skill installer — download, extract, hash, pin. */
|
|
2
|
+
export declare function validateSlug(slug: string): boolean;
|
|
3
|
+
export declare function hashDirectory(dirPath: string): string;
|
|
4
|
+
export declare function validateArchiveMembers(members: string[], installDir: string): void;
|
|
5
|
+
export declare function getInstallDir(slug: string): string;
|
|
6
|
+
export interface InstallResult {
|
|
7
|
+
installDir: string;
|
|
8
|
+
contentHash: string;
|
|
9
|
+
}
|
|
10
|
+
/**
|
|
11
|
+
* Download a skill package, extract it, compute content hash, and save pin.
|
|
12
|
+
*
|
|
13
|
+
* Supports both HTTP URLs and base64 data URIs (local dev fallback).
|
|
14
|
+
*/
|
|
15
|
+
export declare function downloadAndExtract(url: string, slug: string, source?: string, version?: string | null, securityStatus?: string): Promise<InstallResult>;
|
|
@@ -0,0 +1,177 @@
|
|
|
1
|
+
/** Skill installer — download, extract, hash, pin. */
|
|
2
|
+
import { mkdirSync, rmSync, writeFileSync, unlinkSync, readFileSync, readdirSync, } from "node:fs";
|
|
3
|
+
import { join, relative, normalize, resolve, isAbsolute, dirname } from "node:path";
|
|
4
|
+
import { tmpdir } from "node:os";
|
|
5
|
+
import { execFileSync } from "node:child_process";
|
|
6
|
+
import { randomUUID, createHash } from "node:crypto";
|
|
7
|
+
import { SKILLS_DIR, PINS_FILE } from "./config.js";
|
|
8
|
+
/** Strict slug pattern: lowercase alphanumeric with hyphens. */
|
|
9
|
+
const VALID_SLUG_RE = /^[a-z0-9][a-z0-9-]*$/;
|
|
10
|
+
export function validateSlug(slug) {
|
|
11
|
+
return VALID_SLUG_RE.test(slug);
|
|
12
|
+
}
|
|
13
|
+
// --- Content hashing (matches CLI's content_hasher.py) ---
|
|
14
|
+
const EXCLUDED_NAMES = new Set([".DS_Store", "Thumbs.db", "__pycache__"]);
|
|
15
|
+
const EXCLUDED_SUFFIXES = new Set([".pyc", ".pyo"]);
|
|
16
|
+
function shouldSkip(relativePath) {
|
|
17
|
+
const parts = relativePath.split("/");
|
|
18
|
+
for (const part of parts) {
|
|
19
|
+
if (EXCLUDED_NAMES.has(part))
|
|
20
|
+
return true;
|
|
21
|
+
}
|
|
22
|
+
const lastPart = parts[parts.length - 1];
|
|
23
|
+
for (const suffix of EXCLUDED_SUFFIXES) {
|
|
24
|
+
if (lastPart.endsWith(suffix))
|
|
25
|
+
return true;
|
|
26
|
+
}
|
|
27
|
+
return false;
|
|
28
|
+
}
|
|
29
|
+
function collectFiles(dirPath, basePath) {
|
|
30
|
+
const results = [];
|
|
31
|
+
const entries = readdirSync(dirPath, { withFileTypes: true });
|
|
32
|
+
for (const entry of entries) {
|
|
33
|
+
const fullPath = join(dirPath, entry.name);
|
|
34
|
+
const relPath = relative(basePath, fullPath);
|
|
35
|
+
if (entry.isDirectory()) {
|
|
36
|
+
if (!EXCLUDED_NAMES.has(entry.name)) {
|
|
37
|
+
results.push(...collectFiles(fullPath, basePath));
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
else if (entry.isFile() && !shouldSkip(relPath)) {
|
|
41
|
+
results.push(relPath);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
return results;
|
|
45
|
+
}
|
|
46
|
+
export function hashDirectory(dirPath) {
|
|
47
|
+
const files = collectFiles(dirPath, dirPath).sort();
|
|
48
|
+
const hasher = createHash("sha256");
|
|
49
|
+
for (const relPath of files) {
|
|
50
|
+
hasher.update(relPath, "utf-8");
|
|
51
|
+
hasher.update(readFileSync(join(dirPath, relPath)));
|
|
52
|
+
}
|
|
53
|
+
return `sha256:${hasher.digest("hex")}`;
|
|
54
|
+
}
|
|
55
|
+
// --- Pin management ---
|
|
56
|
+
function loadPins() {
|
|
57
|
+
try {
|
|
58
|
+
return JSON.parse(readFileSync(PINS_FILE, "utf-8"));
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return {};
|
|
62
|
+
}
|
|
63
|
+
}
|
|
64
|
+
function savePin(slug, source, version, contentHash, securityStatus) {
|
|
65
|
+
mkdirSync(dirname(PINS_FILE), { recursive: true });
|
|
66
|
+
const pins = loadPins();
|
|
67
|
+
const now = new Date().toISOString();
|
|
68
|
+
pins[slug] = {
|
|
69
|
+
source,
|
|
70
|
+
version,
|
|
71
|
+
content_hash: contentHash,
|
|
72
|
+
installed_at: now,
|
|
73
|
+
scanned_at: now,
|
|
74
|
+
security_status: securityStatus,
|
|
75
|
+
type: "skill",
|
|
76
|
+
};
|
|
77
|
+
writeFileSync(PINS_FILE, JSON.stringify(pins, null, 2));
|
|
78
|
+
}
|
|
79
|
+
// --- Archive validation ---
|
|
80
|
+
export function validateArchiveMembers(members, installDir) {
|
|
81
|
+
const resolvedInstallDir = resolve(installDir);
|
|
82
|
+
for (const member of members) {
|
|
83
|
+
const normalized = member.replace(/\\/g, "/");
|
|
84
|
+
if (isAbsolute(normalized) || isAbsolute(member)) {
|
|
85
|
+
throw new Error(`Blocked path traversal: absolute path in archive member '${member}'`);
|
|
86
|
+
}
|
|
87
|
+
const parts = normalized.split("/");
|
|
88
|
+
if (parts.includes("..")) {
|
|
89
|
+
throw new Error(`Blocked path traversal: '..' in archive member '${member}'`);
|
|
90
|
+
}
|
|
91
|
+
const target = resolve(installDir, normalize(normalized));
|
|
92
|
+
if (!target.startsWith(resolvedInstallDir)) {
|
|
93
|
+
throw new Error(`Blocked path traversal: '${member}' resolves outside destination directory`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
function safeExtract(tempFile, installDir, isTarball) {
|
|
98
|
+
let memberList;
|
|
99
|
+
if (isTarball) {
|
|
100
|
+
memberList = execFileSync("tar", ["-tzf", tempFile], { encoding: "utf-8" });
|
|
101
|
+
}
|
|
102
|
+
else {
|
|
103
|
+
memberList = execFileSync("zipinfo", ["-1", tempFile], { encoding: "utf-8" });
|
|
104
|
+
}
|
|
105
|
+
const members = memberList
|
|
106
|
+
.split("\n")
|
|
107
|
+
.map((m) => m.trim())
|
|
108
|
+
.filter((m) => m.length > 0);
|
|
109
|
+
validateArchiveMembers(members, installDir);
|
|
110
|
+
if (isTarball) {
|
|
111
|
+
execFileSync("tar", ["-xzf", tempFile, "-C", installDir], { stdio: "pipe" });
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
execFileSync("unzip", ["-o", tempFile, "-d", installDir], { stdio: "pipe" });
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
// --- Data URI handling ---
|
|
118
|
+
function isDataUri(url) {
|
|
119
|
+
return url.startsWith("data:");
|
|
120
|
+
}
|
|
121
|
+
function decodeDataUri(dataUri) {
|
|
122
|
+
const match = dataUri.match(/^data:[^;]*;base64,(.+)$/);
|
|
123
|
+
if (!match) {
|
|
124
|
+
throw new Error("Invalid data URI format — expected base64 encoding.");
|
|
125
|
+
}
|
|
126
|
+
return Buffer.from(match[1], "base64");
|
|
127
|
+
}
|
|
128
|
+
// --- Main install function ---
|
|
129
|
+
export function getInstallDir(slug) {
|
|
130
|
+
return join(SKILLS_DIR, slug);
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Download a skill package, extract it, compute content hash, and save pin.
|
|
134
|
+
*
|
|
135
|
+
* Supports both HTTP URLs and base64 data URIs (local dev fallback).
|
|
136
|
+
*/
|
|
137
|
+
export async function downloadAndExtract(url, slug, source = "agentpowers", version = null, securityStatus = "pass") {
|
|
138
|
+
if (!validateSlug(slug)) {
|
|
139
|
+
throw new Error(`Invalid slug: "${slug}" — slugs must be lowercase alphanumeric with hyphens only.`);
|
|
140
|
+
}
|
|
141
|
+
const installDir = getInstallDir(slug);
|
|
142
|
+
const isTarball = url.includes(".tar.gz") || url.includes(".tgz") || url.startsWith("data:");
|
|
143
|
+
const ext = isTarball ? ".tar.gz" : ".zip";
|
|
144
|
+
const tempFile = join(tmpdir(), `ap-${randomUUID()}${ext}`);
|
|
145
|
+
try {
|
|
146
|
+
let buffer;
|
|
147
|
+
if (isDataUri(url)) {
|
|
148
|
+
buffer = decodeDataUri(url);
|
|
149
|
+
}
|
|
150
|
+
else {
|
|
151
|
+
const response = await fetch(url);
|
|
152
|
+
if (!response.ok) {
|
|
153
|
+
throw new Error(`Download failed: ${response.status} ${response.statusText}`);
|
|
154
|
+
}
|
|
155
|
+
buffer = Buffer.from(await response.arrayBuffer());
|
|
156
|
+
}
|
|
157
|
+
writeFileSync(tempFile, buffer);
|
|
158
|
+
// Clean existing directory for fresh install
|
|
159
|
+
rmSync(installDir, { recursive: true, force: true });
|
|
160
|
+
mkdirSync(installDir, { recursive: true });
|
|
161
|
+
// Validate and extract
|
|
162
|
+
safeExtract(tempFile, installDir, isTarball);
|
|
163
|
+
// Compute content hash and save pin
|
|
164
|
+
const contentHash = hashDirectory(installDir);
|
|
165
|
+
savePin(slug, source, version, contentHash, securityStatus);
|
|
166
|
+
return { installDir, contentHash };
|
|
167
|
+
}
|
|
168
|
+
finally {
|
|
169
|
+
try {
|
|
170
|
+
unlinkSync(tempFile);
|
|
171
|
+
}
|
|
172
|
+
catch {
|
|
173
|
+
// temp file cleanup is best-effort
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
}
|
|
177
|
+
//# sourceMappingURL=installer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"installer.js","sourceRoot":"","sources":["../src/installer.ts"],"names":[],"mappings":"AAAA,sDAAsD;AAEtD,OAAO,EACL,SAAS,EACT,MAAM,EACN,aAAa,EACb,UAAU,EACV,YAAY,EACZ,WAAW,GAEZ,MAAM,SAAS,CAAC;AACjB,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpF,OAAO,EAAW,MAAM,EAAE,MAAM,SAAS,CAAC;AAC1C,OAAO,EAAE,YAAY,EAAE,MAAM,oBAAoB,CAAC;AAClD,OAAO,EAAE,UAAU,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AACrD,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,aAAa,CAAC;AAGpD,gEAAgE;AAChE,MAAM,aAAa,GAAG,sBAAsB,CAAC;AAE7C,MAAM,UAAU,YAAY,CAAC,IAAY;IACvC,OAAO,aAAa,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAClC,CAAC;AAED,4DAA4D;AAE5D,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC,CAAC,WAAW,EAAE,WAAW,EAAE,aAAa,CAAC,CAAC,CAAC;AAC1E,MAAM,iBAAiB,GAAG,IAAI,GAAG,CAAC,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAC;AAEpD,SAAS,UAAU,CAAC,YAAoB;IACtC,MAAM,KAAK,GAAG,YAAY,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;IACtC,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC;YAAE,OAAO,IAAI,CAAC;IAC5C,CAAC;IACD,MAAM,QAAQ,GAAG,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IACzC,KAAK,MAAM,MAAM,IAAI,iBAAiB,EAAE,CAAC;QACvC,IAAI,QAAQ,CAAC,QAAQ,CAAC,MAAM,CAAC;YAAE,OAAO,IAAI,CAAC;IAC7C,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,SAAS,YAAY,CAAC,OAAe,EAAE,QAAgB;IACrD,MAAM,OAAO,GAAa,EAAE,CAAC;IAC7B,MAAM,OAAO,GAAG,WAAW,CAAC,OAAO,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC;IAC9D,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;QAC5B,MAAM,QAAQ,GAAG,IAAI,CAAC,OAAO,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QAC3C,MAAM,OAAO,GAAG,QAAQ,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC;QAC7C,IAAI,KAAK,CAAC,WAAW,EAAE,EAAE,CAAC;YACxB,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;gBACpC,OAAO,CAAC,IAAI,CAAC,GAAG,YAAY,CAAC,QAAQ,EAAE,QAAQ,CAAC,CAAC,CAAC;YACpD,CAAC;QACH,CAAC;aAAM,IAAI,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;YAClD,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;QACxB,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,OAAe;IAC3C,MAAM,KAAK,GAAG,YAAY,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,IAAI,EAAE,CAAC;IACpD,MAAM,MAAM,GAAG,UAAU,CAAC,QAAQ,CAAC,CAAC;IACpC,KAAK,MAAM,OAAO,IAAI,KAAK,EAAE,CAAC;QAC5B,MAAM,CAAC,MAAM,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAChC,MAAM,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC,CAAC,CAAC;IACtD,CAAC;IACD,OAAO,UAAU,MAAM,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;AAC1C,CAAC;AAED,yBAAyB;AAEzB,SAAS,QAAQ;IACf,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,YAAY,CAAC,SAAS,EAAE,OAAO,CAAC,CAAa,CAAC;IAClE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;AACH,CAAC;AAED,SAAS,OAAO,CACd,IAAY,EACZ,MAAc,EACd,OAAsB,EACtB,WAAmB,EACnB,cAAsB;IAEtB,SAAS,CAAC,OAAO,CAAC,SAAS,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;IACnD,MAAM,IAAI,GAAG,QAAQ,EAAE,CAAC;IACxB,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACrC,IAAI,CAAC,IAAI,CAAC,GAAG;QACX,MAAM;QACN,OAAO;QACP,YAAY,EAAE,WAAW;QACzB,YAAY,EAAE,GAAG;QACjB,UAAU,EAAE,GAAG;QACf,eAAe,EAAE,cAAc;QAC/B,IAAI,EAAE,OAAO;KACd,CAAC;IACF,aAAa,CAAC,SAAS,EAAE,IAAI,CAAC,SAAS,CAAC,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAC;AAC1D,CAAC;AAED,6BAA6B;AAE7B,MAAM,UAAU,sBAAsB,CACpC,OAAiB,EACjB,UAAkB;IAElB,MAAM,kBAAkB,GAAG,OAAO,CAAC,UAAU,CAAC,CAAC;IAC/C,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;QAC7B,MAAM,UAAU,GAAG,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,GAAG,CAAC,CAAC;QAC9C,IAAI,UAAU,CAAC,UAAU,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC;YACjD,MAAM,IAAI,KAAK,CACb,4DAA4D,MAAM,GAAG,CACtE,CAAC;QACJ,CAAC;QACD,MAAM,KAAK,GAAG,UAAU,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC;QACpC,IAAI,KAAK,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;YACzB,MAAM,IAAI,KAAK,CACb,mDAAmD,MAAM,GAAG,CAC7D,CAAC;QACJ,CAAC;QACD,MAAM,MAAM,GAAG,OAAO,CAAC,UAAU,EAAE,SAAS,CAAC,UAAU,CAAC,CAAC,CAAC;QAC1D,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,kBAAkB,CAAC,EAAE,CAAC;YAC3C,MAAM,IAAI,KAAK,CACb,4BAA4B,MAAM,0CAA0C,CAC7E,CAAC;QACJ,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,WAAW,CAClB,QAAgB,EAChB,UAAkB,EAClB,SAAkB;IAElB,IAAI,UAAkB,CAAC;IACvB,IAAI,SAAS,EAAE,CAAC;QACd,UAAU,GAAG,YAAY,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,QAAQ,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;IAC9E,CAAC;SAAM,CAAC;QACN,UAAU,GAAG,YAAY,CAAC,SAAS,EAAE,CAAC,IAAI,EAAE,QAAQ,CAAC,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,CAAC,CAAC;IAChF,CAAC;IAED,MAAM,OAAO,GAAG,UAAU;SACvB,KAAK,CAAC,IAAI,CAAC;SACX,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC;SACpB,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAE/B,sBAAsB,CAAC,OAAO,EAAE,UAAU,CAAC,CAAC;IAE5C,IAAI,SAAS,EAAE,CAAC;QACd,YAAY,CAAC,KAAK,EAAE,CAAC,MAAM,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IAC/E,CAAC;SAAM,CAAC;QACN,YAAY,CAAC,OAAO,EAAE,CAAC,IAAI,EAAE,QAAQ,EAAE,IAAI,EAAE,UAAU,CAAC,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC;IAC/E,CAAC;AACH,CAAC;AAED,4BAA4B;AAE5B,SAAS,SAAS,CAAC,GAAW;IAC5B,OAAO,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;AACjC,CAAC;AAED,SAAS,aAAa,CAAC,OAAe;IACpC,MAAM,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC,0BAA0B,CAAC,CAAC;IACxD,IAAI,CAAC,KAAK,EAAE,CAAC;QACX,MAAM,IAAI,KAAK,CAAC,qDAAqD,CAAC,CAAC;IACzE,CAAC;IACD,OAAO,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,QAAQ,CAAC,CAAC;AACzC,CAAC;AAED,gCAAgC;AAEhC,MAAM,UAAU,aAAa,CAAC,IAAY;IACxC,OAAO,IAAI,CAAC,UAAU,EAAE,IAAI,CAAC,CAAC;AAChC,CAAC;AAOD;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,kBAAkB,CACtC,GAAW,EACX,IAAY,EACZ,SAAiB,aAAa,EAC9B,UAAyB,IAAI,EAC7B,iBAAyB,MAAM;IAE/B,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,EAAE,CAAC;QACxB,MAAM,IAAI,KAAK,CACb,kBAAkB,IAAI,6DAA6D,CACpF,CAAC;IACJ,CAAC;IAED,MAAM,UAAU,GAAG,aAAa,CAAC,IAAI,CAAC,CAAC;IACvC,MAAM,SAAS,GAAG,GAAG,CAAC,QAAQ,CAAC,SAAS,CAAC,IAAI,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC,IAAI,GAAG,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC;IAC7F,MAAM,GAAG,GAAG,SAAS,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAC;IAC3C,MAAM,QAAQ,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,MAAM,UAAU,EAAE,GAAG,GAAG,EAAE,CAAC,CAAC;IAE5D,IAAI,CAAC;QACH,IAAI,MAAc,CAAC;QACnB,IAAI,SAAS,CAAC,GAAG,CAAC,EAAE,CAAC;YACnB,MAAM,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC;QAC9B,CAAC;aAAM,CAAC;YACN,MAAM,QAAQ,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,CAAC;YAClC,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;gBACjB,MAAM,IAAI,KAAK,CAAC,oBAAoB,QAAQ,CAAC,MAAM,IAAI,QAAQ,CAAC,UAAU,EAAE,CAAC,CAAC;YAChF,CAAC;YACD,MAAM,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,QAAQ,CAAC,WAAW,EAAE,CAAC,CAAC;QACrD,CAAC;QAED,aAAa,CAAC,QAAQ,EAAE,MAAM,CAAC,CAAC;QAEhC,6CAA6C;QAC7C,MAAM,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;QACrD,SAAS,CAAC,UAAU,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAE3C,uBAAuB;QACvB,WAAW,CAAC,QAAQ,EAAE,UAAU,EAAE,SAAS,CAAC,CAAC;QAE7C,oCAAoC;QACpC,MAAM,WAAW,GAAG,aAAa,CAAC,UAAU,CAAC,CAAC;QAC9C,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,OAAO,EAAE,WAAW,EAAE,cAAc,CAAC,CAAC;QAE5D,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC;IACrC,CAAC;YAAS,CAAC;QACT,IAAI,CAAC;YACH,UAAU,CAAC,QAAQ,CAAC,CAAC;QACvB,CAAC;QAAC,MAAM,CAAC;YACP,mCAAmC;QACrC,CAAC;IACH,CAAC;AACH,CAAC"}
|
package/dist/types.d.ts
ADDED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
/** Type definitions for AgentPowers API responses. */
|
|
2
|
+
export interface NativeSearchItem {
|
|
3
|
+
slug: string;
|
|
4
|
+
title: string;
|
|
5
|
+
description: string;
|
|
6
|
+
category: string;
|
|
7
|
+
type: string;
|
|
8
|
+
price_cents: number;
|
|
9
|
+
currency: string;
|
|
10
|
+
version: string;
|
|
11
|
+
security_status: string;
|
|
12
|
+
download_count: number;
|
|
13
|
+
author: {
|
|
14
|
+
display_name: string | null;
|
|
15
|
+
github_username: string | null;
|
|
16
|
+
} | null;
|
|
17
|
+
}
|
|
18
|
+
export interface ExternalSearchItem {
|
|
19
|
+
slug: string;
|
|
20
|
+
title: string;
|
|
21
|
+
description: string;
|
|
22
|
+
author: string;
|
|
23
|
+
source: string;
|
|
24
|
+
source_url: string;
|
|
25
|
+
source_installs: number | null;
|
|
26
|
+
source_rating: number | null;
|
|
27
|
+
price_cents: number;
|
|
28
|
+
version: string | null;
|
|
29
|
+
ap_security_status: string | null;
|
|
30
|
+
ap_security_score: number | null;
|
|
31
|
+
ap_scanned_at: string | null;
|
|
32
|
+
}
|
|
33
|
+
export interface SearchSection<T> {
|
|
34
|
+
items: T[];
|
|
35
|
+
total: number;
|
|
36
|
+
}
|
|
37
|
+
export interface SectionedSearchResponse {
|
|
38
|
+
agentpowers: SearchSection<NativeSearchItem>;
|
|
39
|
+
[source: string]: SearchSection<NativeSearchItem | ExternalSearchItem>;
|
|
40
|
+
}
|
|
41
|
+
export interface DownloadResponse {
|
|
42
|
+
url: string;
|
|
43
|
+
slug: string;
|
|
44
|
+
}
|
|
45
|
+
export interface AuthData {
|
|
46
|
+
token: string;
|
|
47
|
+
expires_at: string;
|
|
48
|
+
}
|
|
49
|
+
/** Pin entry stored in ~/.agentpowers/pins.json */
|
|
50
|
+
export interface PinEntry {
|
|
51
|
+
source: string;
|
|
52
|
+
version: string | null;
|
|
53
|
+
content_hash: string;
|
|
54
|
+
installed_at: string;
|
|
55
|
+
scanned_at: string;
|
|
56
|
+
security_status: string;
|
|
57
|
+
type?: "skill" | "agent";
|
|
58
|
+
}
|
|
59
|
+
export interface PinsFile {
|
|
60
|
+
[slug: string]: PinEntry;
|
|
61
|
+
}
|
package/dist/types.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.js","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,sDAAsD"}
|
package/package.json
ADDED
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@agentpowers/cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "CLI for the AgentPowers marketplace — search, install, and manage Claude Code skills.",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"bin": {
|
|
9
|
+
"agentpowers": "dist/cli.js"
|
|
10
|
+
},
|
|
11
|
+
"files": [
|
|
12
|
+
"dist"
|
|
13
|
+
],
|
|
14
|
+
"scripts": {
|
|
15
|
+
"build": "tsc",
|
|
16
|
+
"dev": "tsc --watch",
|
|
17
|
+
"test": "vitest run",
|
|
18
|
+
"test:watch": "vitest",
|
|
19
|
+
"test:coverage": "vitest run --coverage",
|
|
20
|
+
"lint": "tsc --noEmit",
|
|
21
|
+
"prepublishOnly": "npm run build"
|
|
22
|
+
},
|
|
23
|
+
"keywords": [
|
|
24
|
+
"claude",
|
|
25
|
+
"claude-code",
|
|
26
|
+
"agentpowers",
|
|
27
|
+
"marketplace",
|
|
28
|
+
"skills",
|
|
29
|
+
"agents",
|
|
30
|
+
"cli",
|
|
31
|
+
"npx"
|
|
32
|
+
],
|
|
33
|
+
"repository": {
|
|
34
|
+
"type": "git",
|
|
35
|
+
"url": "git+https://github.com/AgentPowers-AI/agentpowers-app.git",
|
|
36
|
+
"directory": "agentpowers-npx"
|
|
37
|
+
},
|
|
38
|
+
"homepage": "https://agentpowers.ai",
|
|
39
|
+
"publishConfig": {
|
|
40
|
+
"access": "public"
|
|
41
|
+
},
|
|
42
|
+
"license": "MIT",
|
|
43
|
+
"engines": {
|
|
44
|
+
"node": ">=18.0.0"
|
|
45
|
+
},
|
|
46
|
+
"dependencies": {
|
|
47
|
+
"commander": "^13.0.0"
|
|
48
|
+
},
|
|
49
|
+
"devDependencies": {
|
|
50
|
+
"@types/node": "^22.0.0",
|
|
51
|
+
"typescript": "^5.7.0",
|
|
52
|
+
"vitest": "^3.0.0"
|
|
53
|
+
}
|
|
54
|
+
}
|