@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.
@@ -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
@@ -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
@@ -0,0 +1,3 @@
1
+ #!/usr/bin/env node
2
+ /** AgentPowers CLI — search, install, and manage Claude Code skills. */
3
+ export {};
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
@@ -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,2 @@
1
+ /** Install command — download and install a skill from the marketplace. */
2
+ export declare function installCommand(slug: string): Promise<void>;
@@ -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,2 @@
1
+ /** Login command — open browser and wait for auth token. */
2
+ export declare function loginCommand(): Promise<void>;
@@ -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,2 @@
1
+ /** Search command — query the AgentPowers marketplace. */
2
+ export declare function searchCommand(query: string): Promise<void>;
@@ -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"}
@@ -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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"}
@@ -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":"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"}
@@ -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,3 @@
1
+ /** Type definitions for AgentPowers API responses. */
2
+ export {};
3
+ //# sourceMappingURL=types.js.map
@@ -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
+ }