@builderpackai/cli 0.1.4 → 0.1.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -57,6 +57,56 @@ Install everything:
57
57
  builderpack skills add --all --tool claude,codex
58
58
  ```
59
59
 
60
+ ## Common queries
61
+
62
+ List everything:
63
+
64
+ ```
65
+ builderpack skills list
66
+ ```
67
+
68
+ List by theme:
69
+
70
+ ```
71
+ builderpack skills list --theme gamedev
72
+ ```
73
+
74
+ Install by theme:
75
+
76
+ ```
77
+ builderpack skills add --theme saas --tool claude
78
+ ```
79
+
80
+ Install by skill id:
81
+
82
+ ```
83
+ builderpack skills add --skill og-image-creator --tool codex
84
+ ```
85
+
86
+ Install multiple skills:
87
+
88
+ ```
89
+ builderpack skills add --skill og-image-creator --skill seo-optimizer --tool claude
90
+ ```
91
+
92
+ Dry run (no changes):
93
+
94
+ ```
95
+ builderpack skills add --theme gamedev --tool claude --dry-run
96
+ ```
97
+
98
+ Verbose (see exactly what’s selected and installed):
99
+
100
+ ```
101
+ builderpack skills add --theme gamedev --tool claude --verbose
102
+ ```
103
+
104
+ Selection rules:
105
+
106
+ - `--all` overrides everything.
107
+ - If `--theme` is set, it’s used and `--skill` is ignored.
108
+ - If only `--skill` is set, those ids are used.
109
+
60
110
  ## Global vs project install
61
111
 
62
112
  Default is project-local (puts files in `.claude/skills` or `.codex/skills` in your repo).
package/dist/cli.js CHANGED
@@ -3,7 +3,7 @@ import { homedir, tmpdir } from "os";
3
3
  import { join } from "path";
4
4
  import { mkdirSync, readFileSync, writeFileSync, existsSync, rmSync } from "fs";
5
5
  var getApiBase = () => {
6
- return (process.env.BUILDERPACK_API_BASE?.trim() || "https://builderpack.ai/api/cli/v1").replace(
6
+ return (process.env.BUILDERPACK_API_BASE?.trim() || "https://www.builderpack.ai/api/cli/v1").replace(
7
7
  /\/$/,
8
8
  ""
9
9
  );
@@ -52,33 +52,52 @@ var clearAuth = () => {
52
52
  };
53
53
 
54
54
  // src/http.ts
55
+ var requestJson = async (opts, maxRedirects = 3) => {
56
+ let current = opts;
57
+ for (let i = 0; i <= maxRedirects; i++) {
58
+ const res = await fetch(current.url, {
59
+ method: current.method,
60
+ headers: current.headers,
61
+ body: current.body,
62
+ redirect: "manual"
63
+ });
64
+ if (res.status >= 300 && res.status < 400) {
65
+ const location = res.headers.get("location");
66
+ if (!location) {
67
+ const bodyText = await res.text().catch(() => "");
68
+ throw { status: res.status, bodyText };
69
+ }
70
+ const nextUrl = new URL(location, current.url).toString();
71
+ current = { ...current, url: nextUrl };
72
+ continue;
73
+ }
74
+ if (!res.ok) {
75
+ const bodyText = await res.text().catch(() => "");
76
+ throw { status: res.status, bodyText };
77
+ }
78
+ return await res.json();
79
+ }
80
+ throw { status: 310, bodyText: "Too many redirects" };
81
+ };
55
82
  var httpGetJson = async (url, options) => {
56
- const res = await fetch(url, {
83
+ return requestJson({
57
84
  method: "GET",
85
+ url,
58
86
  headers: {
59
87
  ...options?.bearer ? { Authorization: `Bearer ${options.bearer}` } : {}
60
88
  }
61
89
  });
62
- if (!res.ok) {
63
- const bodyText = await res.text().catch(() => "");
64
- throw { status: res.status, bodyText };
65
- }
66
- return await res.json();
67
90
  };
68
91
  var httpPostJson = async (url, body, options) => {
69
- const res = await fetch(url, {
92
+ return requestJson({
70
93
  method: "POST",
94
+ url,
71
95
  headers: {
72
96
  "Content-Type": "application/json",
73
97
  ...options?.bearer ? { Authorization: `Bearer ${options.bearer}` } : {}
74
98
  },
75
99
  body: JSON.stringify(body)
76
100
  });
77
- if (!res.ok) {
78
- const bodyText = await res.text().catch(() => "");
79
- throw { status: res.status, bodyText };
80
- }
81
- return await res.json();
82
101
  };
83
102
 
84
103
  // src/print.ts
@@ -111,19 +130,37 @@ var tryOpenUrl = (url) => {
111
130
  };
112
131
 
113
132
  // src/auth.ts
133
+ import { createInterface } from "readline";
134
+ var waitForEnter = async () => {
135
+ if (!process.stdin.isTTY || !process.stdout.isTTY) {
136
+ return;
137
+ }
138
+ await new Promise((resolve3) => {
139
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
140
+ rl.question("Press Enter to launch the browser...", () => {
141
+ rl.close();
142
+ resolve3();
143
+ });
144
+ });
145
+ };
114
146
  var commandLogin = async () => {
115
147
  const apiBase = getApiBase();
116
148
  const start = await httpPostJson(`${apiBase}/auth/device/start`, {});
117
149
  log("");
118
150
  log("Builderpack CLI login");
119
151
  log("");
120
- log(`1) Open: ${start.verification_uri}`);
152
+ log(`1) You will open: ${start.verification_uri}`);
121
153
  log(`2) Enter code: ${start.user_code}`);
122
154
  log("");
123
- if (start.verification_uri_complete) {
124
- tryOpenUrl(start.verification_uri_complete);
155
+ const urlToOpen = start.verification_uri_complete || start.verification_uri;
156
+ if (process.stdin.isTTY && process.stdout.isTTY) {
157
+ log("Press Enter to open the browser automatically.");
158
+ log("Then enter the code above and confirm it matches.");
159
+ await waitForEnter();
160
+ tryOpenUrl(urlToOpen);
125
161
  } else {
126
- tryOpenUrl(start.verification_uri);
162
+ log(`Open this URL in a browser when ready: ${urlToOpen}`);
163
+ log("Enter the code above and confirm it matches.");
127
164
  }
128
165
  const deadline = Date.now() + start.expires_in * 1e3;
129
166
  while (Date.now() < deadline) {
@@ -277,11 +314,33 @@ var extractSkillName = (skillMdPath) => {
277
314
  return nameMatch[1].trim().replace(/^["']|["']$/g, "");
278
315
  };
279
316
 
317
+ // src/skills-select.ts
318
+ var resolveSelectedSkills = (opts) => {
319
+ const { catalog, theme, skillArgs, all } = opts;
320
+ if (all) return catalog.skills.map((s) => s.id);
321
+ if (theme) {
322
+ const ids = catalog.themes[theme];
323
+ if (!ids) die(`Unknown theme: ${theme}`);
324
+ return ids;
325
+ }
326
+ if (skillArgs.length > 0) {
327
+ return skillArgs;
328
+ }
329
+ return [];
330
+ };
331
+
280
332
  // src/skills.ts
281
333
  var commandSkillsList = async (args) => {
282
334
  const theme = getFlagValue(args, "--theme");
335
+ const verbose = hasFlag(args, "--verbose");
283
336
  const catalog = await fetchCatalog();
284
337
  const ids = theme && catalog.themes[theme] ? catalog.themes[theme] : catalog.skills.map((s) => s.id);
338
+ if (verbose) {
339
+ const themeInfo = theme ? theme : "all";
340
+ log(`[verbose] theme: ${themeInfo}`);
341
+ log(`[verbose] total skills: ${catalog.skills.length}`);
342
+ log(`[verbose] selected count: ${ids.length}`);
343
+ }
285
344
  for (const id of ids) {
286
345
  const skill = catalog.skills.find((s) => s.id === id);
287
346
  const variants = skill?.variants?.join(",") || "";
@@ -295,6 +354,7 @@ var commandSkillsAdd = async (args) => {
295
354
  const mode = getFlagValue(args, "--mode") || "symlink";
296
355
  const strict = hasFlag(args, "--strict");
297
356
  const dryRun = hasFlag(args, "--dry-run");
357
+ const verbose = hasFlag(args, "--verbose");
298
358
  const toolArg = getFlagValue(args, "--tool") || "claude,codex";
299
359
  const tools = toolArg.split(",").map((t) => t.trim()).filter(Boolean);
300
360
  const invalidTools = tools.filter((t) => t !== "claude" && t !== "codex");
@@ -311,6 +371,16 @@ var commandSkillsAdd = async (args) => {
311
371
  }
312
372
  const repoRoot = scope === "project" ? getRepoRoot() : process.cwd();
313
373
  const canonicalBase = getCanonicalDir(scope, repoRoot);
374
+ if (verbose) {
375
+ log(`[verbose] api base: ${auth.apiBase}`);
376
+ log(`[verbose] scope: ${scope}`);
377
+ log(`[verbose] mode: ${mode}`);
378
+ log(`[verbose] strict: ${strict}`);
379
+ log(`[verbose] dry-run: ${dryRun}`);
380
+ log(`[verbose] tools: ${normalizedTools.join(",")}`);
381
+ log(`[verbose] theme: ${theme ?? "none"}`);
382
+ log(`[verbose] skills: ${selected.join(",")}`);
383
+ }
314
384
  if (scope === "project" && mode === "symlink") {
315
385
  const gitignorePath = join4(repoRoot, ".gitignore");
316
386
  if (existsSync2(gitignorePath)) {
@@ -341,10 +411,17 @@ var commandSkillsAdd = async (args) => {
341
411
  log(`[dry-run] would install ${skillId} (${tool})`);
342
412
  continue;
343
413
  }
414
+ if (verbose) {
415
+ log(`[verbose] request artifact: ${skillId} (${tool})`);
416
+ }
344
417
  const signed = await httpGetJson(
345
418
  `${auth.apiBase}/artifacts/skills/${encodeURIComponent(skillId)}/${encodeURIComponent(tool)}`,
346
419
  { bearer: auth.accessToken }
347
420
  );
421
+ if (verbose) {
422
+ log(`[verbose] signed url expires in: ${signed.expiresIn}s`);
423
+ log(`[verbose] object path: ${signed.objectPath}`);
424
+ }
348
425
  const extractedDir = await downloadAndExtractZip(signed.signedUrl);
349
426
  const resolvedSkillDir = await resolveExtractedSkillRoot(extractedDir);
350
427
  const skillMdPath = join4(resolvedSkillDir, "SKILL.md");
@@ -358,6 +435,10 @@ var commandSkillsAdd = async (args) => {
358
435
  if (!isSafeChildPath(canonicalBase, canonicalDir) || !isSafeChildPath(toolBase, toolDir)) {
359
436
  die(`Unsafe install path for skill: ${skillId}`);
360
437
  }
438
+ if (verbose) {
439
+ log(`[verbose] canonical dir: ${canonicalDir}`);
440
+ log(`[verbose] tool dir: ${toolDir}`);
441
+ }
361
442
  await ensureDir(canonicalBase);
362
443
  await ensureDir(toolBase);
363
444
  if (mode === "copy") {
@@ -397,19 +478,6 @@ var getMultiFlagValues = (args, flag) => {
397
478
  }
398
479
  return out;
399
480
  };
400
- var resolveSelectedSkills = (opts) => {
401
- const { catalog, theme, skillArgs, all } = opts;
402
- if (all) return catalog.skills.map((s) => s.id);
403
- if (theme) {
404
- const ids = catalog.themes[theme];
405
- if (!ids) die(`Unknown theme: ${theme}`);
406
- return ids;
407
- }
408
- if (skillArgs.length > 0) {
409
- return skillArgs;
410
- }
411
- return [];
412
- };
413
481
  var downloadAndExtractZip = async (signedUrl) => {
414
482
  const res = await fetch(signedUrl);
415
483
  if (!res.ok) {
@@ -450,7 +518,7 @@ Usage:
450
518
  builderpack logout
451
519
 
452
520
  builderpack skills list [--theme <name>]
453
- builderpack skills add (--theme <name> | --skill <id>... | --all) [--tool claude,codex] [--global] [--mode symlink|copy] [--strict] [--dry-run]
521
+ builderpack skills add (--theme <name> | --skill <id>... | --all) [--tool claude,codex] [--global] [--mode symlink|copy] [--strict] [--dry-run] [--verbose]
454
522
  `);
455
523
  };
456
524
  var main = async () => {
@@ -489,7 +557,7 @@ var main = async () => {
489
557
 
490
558
  Usage:
491
559
  builderpack skills list [--theme <name>]
492
- builderpack skills add (--theme <name> | --skill <id>... | --all) [--tool claude,codex] [--global] [--mode symlink|copy] [--strict] [--dry-run]
560
+ builderpack skills add (--theme <name> | --skill <id>... | --all) [--tool claude,codex] [--global] [--mode symlink|copy] [--strict] [--dry-run] [--verbose]
493
561
  `);
494
562
  return;
495
563
  }
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/config.ts","../src/http.ts","../src/print.ts","../src/open.ts","../src/auth.ts","../src/skills.ts","../src/catalog.ts","../src/fsx.ts","../src/paths.ts","../src/skill-md.ts","../src/cli.ts"],"sourcesContent":["import { homedir, tmpdir } from \"os\"\nimport { join } from \"path\"\nimport { mkdirSync, readFileSync, writeFileSync, existsSync, rmSync } from \"fs\"\n\nexport type BuilderpackAuth = {\n apiBase: string\n accessToken: string\n}\n\nexport const getApiBase = (): string => {\n return (process.env.BUILDERPACK_API_BASE?.trim() || \"https://builderpack.ai/api/cli/v1\").replace(\n /\\/$/,\n \"\"\n )\n}\n\nexport const getConfigDir = (): string => {\n const xdg = process.env.XDG_CONFIG_HOME?.trim()\n if (xdg) return join(xdg, \"builderpack\")\n\n if (process.platform === \"win32\") {\n const appData = process.env.APPDATA?.trim()\n if (appData) return join(appData, \"builderpack\")\n }\n\n return join(homedir(), \".config\", \"builderpack\")\n}\n\nexport const getAuthPath = (): string => {\n return join(getConfigDir(), \"auth.json\")\n}\n\nexport const loadAuth = (): BuilderpackAuth | null => {\n const p = getAuthPath()\n if (!existsSync(p)) return null\n try {\n const parsed = JSON.parse(readFileSync(p, \"utf8\")) as Partial<BuilderpackAuth>\n if (!parsed?.accessToken || !parsed?.apiBase) return null\n return { apiBase: parsed.apiBase, accessToken: parsed.accessToken }\n } catch {\n return null\n }\n}\n\nexport const requireAuth = (): BuilderpackAuth => {\n const auth = loadAuth()\n if (!auth) {\n throw new Error(\"Not logged in. Run: builderpack login\")\n }\n return auth\n}\n\nexport const saveAuth = (auth: BuilderpackAuth): void => {\n const dir = getConfigDir()\n mkdirSync(dir, { recursive: true })\n writeFileSync(getAuthPath(), JSON.stringify(auth, null, 2), \"utf8\")\n}\n\nexport const clearAuth = (): void => {\n const p = getAuthPath()\n try {\n rmSync(p)\n } catch {\n // ignore\n }\n}\n\nexport const getTempDir = (): string => {\n return join(tmpdir(), \"builderpack\")\n}\n","export type HttpError = {\n status: number\n bodyText: string\n}\n\nexport const httpGetJson = async <T>(\n url: string,\n options?: { bearer?: string }\n): Promise<T> => {\n const res = await fetch(url, {\n method: \"GET\",\n headers: {\n ...(options?.bearer ? { Authorization: `Bearer ${options.bearer}` } : {}),\n },\n })\n\n if (!res.ok) {\n const bodyText = await res.text().catch(() => \"\")\n throw { status: res.status, bodyText } satisfies HttpError\n }\n\n return (await res.json()) as T\n}\n\nexport const httpPostJson = async <T>(\n url: string,\n body: unknown,\n options?: { bearer?: string }\n): Promise<T> => {\n const res = await fetch(url, {\n method: \"POST\",\n headers: {\n \"Content-Type\": \"application/json\",\n ...(options?.bearer ? { Authorization: `Bearer ${options.bearer}` } : {}),\n },\n body: JSON.stringify(body),\n })\n\n if (!res.ok) {\n const bodyText = await res.text().catch(() => \"\")\n throw { status: res.status, bodyText } satisfies HttpError\n }\n\n return (await res.json()) as T\n}\n\n","export const die = (message: string, code: number = 1): never => {\n process.stderr.write(message + \"\\n\")\n process.exit(code)\n}\n\nexport const log = (message: string): void => {\n process.stdout.write(message + \"\\n\")\n}\n\nexport const warn = (message: string): void => {\n process.stderr.write(message + \"\\n\")\n}\n\n","import { spawnSync } from \"child_process\"\n\nexport const tryOpenUrl = (url: string): void => {\n try {\n if (process.platform === \"darwin\") {\n spawnSync(\"open\", [url], { stdio: \"ignore\" })\n return\n }\n\n if (process.platform === \"win32\") {\n spawnSync(\"cmd\", [\"/c\", \"start\", \"\", url], { stdio: \"ignore\" })\n return\n }\n\n spawnSync(\"xdg-open\", [url], { stdio: \"ignore\" })\n } catch {\n // ignore\n }\n}\n\n","import { getApiBase, requireAuth, saveAuth, clearAuth } from \"./config\"\nimport { httpGetJson, httpPostJson } from \"./http\"\nimport { die, log } from \"./print\"\nimport { tryOpenUrl } from \"./open\"\n\ntype DeviceStartResponse = {\n device_code: string\n user_code: string\n verification_uri: string\n verification_uri_complete?: string\n expires_in: number\n interval: number\n}\n\ntype DeviceTokenResponse = {\n access_token: string\n expires_in: number\n}\n\ntype MeResponse = {\n email: string\n entitlements: { claude: boolean; codex: boolean; adk: boolean; allInOne: boolean }\n}\n\nexport const commandLogin = async (): Promise<void> => {\n const apiBase = getApiBase()\n const start = await httpPostJson<DeviceStartResponse>(`${apiBase}/auth/device/start`, {})\n\n log(\"\")\n log(\"Builderpack CLI login\")\n log(\"\")\n log(`1) Open: ${start.verification_uri}`)\n log(`2) Enter code: ${start.user_code}`)\n log(\"\")\n\n if (start.verification_uri_complete) {\n tryOpenUrl(start.verification_uri_complete)\n } else {\n tryOpenUrl(start.verification_uri)\n }\n\n const deadline = Date.now() + start.expires_in * 1000\n while (Date.now() < deadline) {\n try {\n const token = await httpPostJson<DeviceTokenResponse>(`${apiBase}/auth/device/token`, {\n device_code: start.device_code,\n })\n\n saveAuth({ apiBase, accessToken: token.access_token })\n log(\"Logged in. You can now run: builderpack skills add ...\")\n return\n } catch (e: any) {\n const status = typeof e?.status === \"number\" ? e.status : 0\n if (status === 428) {\n await new Promise((r) => setTimeout(r, Math.max(1, start.interval) * 1000))\n continue\n }\n if (status === 410) {\n die(\"Login expired. Run: builderpack login\")\n }\n // Other error; keep retrying a couple times then bail\n await new Promise((r) => setTimeout(r, Math.max(1, start.interval) * 1000))\n continue\n }\n }\n\n die(\"Login expired. Run: builderpack login\")\n}\n\nexport const commandWhoami = async (): Promise<void> => {\n const auth = requireAuth()\n const me = await httpGetJson<MeResponse>(`${auth.apiBase}/me`, { bearer: auth.accessToken })\n log(JSON.stringify(me, null, 2))\n}\n\nexport const commandLogout = (): void => {\n clearAuth()\n log(\"Logged out.\")\n}\n","import { mkdtemp, writeFile, readdir } from \"fs/promises\"\nimport { existsSync, readFileSync } from \"fs\"\nimport { join } from \"path\"\nimport { tmpdir } from \"os\"\nimport AdmZip from \"adm-zip\"\nimport { requireAuth } from \"./config\"\nimport { fetchCatalog, type CatalogV1 } from \"./catalog\"\nimport { httpGetJson } from \"./http\"\nimport { die, log, warn } from \"./print\"\nimport { copyDir, createSymlink, ensureDir, fileExists, removePath } from \"./fsx\"\nimport { getCanonicalDir, getRepoRoot, getToolSkillsDir, isSafeChildPath } from \"./paths\"\nimport { extractSkillName } from \"./skill-md\"\n\ntype Variant = \"claude\" | \"codex\"\n\ntype SignedUrlResponse = {\n signedUrl: string\n expiresIn: number\n objectPath: string\n}\n\nexport const commandSkillsList = async (args: string[]): Promise<void> => {\n const theme = getFlagValue(args, \"--theme\")\n const catalog = await fetchCatalog()\n\n const ids =\n theme && catalog.themes[theme]\n ? catalog.themes[theme]\n : catalog.skills.map((s) => s.id)\n\n for (const id of ids) {\n const skill = catalog.skills.find((s) => s.id === id)\n const variants = skill?.variants?.join(\",\") || \"\"\n log(`${id}${variants ? ` (${variants})` : \"\"}`)\n }\n}\n\nexport const commandSkillsAdd = async (args: string[]): Promise<void> => {\n const auth = requireAuth()\n\n const catalog = await fetchCatalog()\n\n const scope = hasFlag(args, \"--global\") ? \"global\" : \"project\"\n const mode = (getFlagValue(args, \"--mode\") || \"symlink\") as \"symlink\" | \"copy\"\n const strict = hasFlag(args, \"--strict\")\n const dryRun = hasFlag(args, \"--dry-run\")\n\n const toolArg = getFlagValue(args, \"--tool\") || \"claude,codex\"\n const tools = toolArg\n .split(\",\")\n .map((t) => t.trim())\n .filter(Boolean)\n\n const invalidTools = tools.filter((t) => t !== \"claude\" && t !== \"codex\")\n if (invalidTools.length > 0) {\n die(`Invalid --tool value(s): ${invalidTools.join(\", \")} (expected claude,codex)`)\n }\n\n const normalizedTools = tools as Variant[]\n\n const theme = getFlagValue(args, \"--theme\")\n const skillArgs = getMultiFlagValues(args, \"--skill\")\n const all = hasFlag(args, \"--all\")\n\n const selected = resolveSelectedSkills({ catalog, theme, skillArgs, all })\n if (selected.length === 0) {\n die(\"No skills selected. Use --theme <name>, --skill <id>, or --all\")\n }\n\n const repoRoot = scope === \"project\" ? getRepoRoot() : process.cwd()\n const canonicalBase = getCanonicalDir(scope, repoRoot)\n\n if (scope === \"project\" && mode === \"symlink\") {\n const gitignorePath = join(repoRoot, \".gitignore\")\n if (existsSync(gitignorePath)) {\n try {\n const content = readFileSync(gitignorePath, \"utf8\")\n if (!content.includes(\".builderpack/\")) {\n warn(\"Note: consider adding `.builderpack/` to your repo .gitignore\")\n }\n } catch {\n // ignore\n }\n }\n }\n\n for (const skillId of selected) {\n const skill = catalog.skills.find((s) => s.id === skillId)\n if (!skill) {\n if (strict) die(`Unknown skill: ${skillId}`)\n warn(`Skipping unknown skill: ${skillId}`)\n continue\n }\n\n for (const tool of normalizedTools) {\n if (!skill.variants.includes(tool)) {\n const msg = `Skipping ${skillId} for ${tool}: variant not available`\n if (strict) die(msg)\n warn(msg)\n continue\n }\n\n if (dryRun) {\n log(`[dry-run] would install ${skillId} (${tool})`)\n continue\n }\n\n const signed = await httpGetJson<SignedUrlResponse>(\n `${auth.apiBase}/artifacts/skills/${encodeURIComponent(skillId)}/${encodeURIComponent(tool)}`,\n { bearer: auth.accessToken }\n )\n\n const extractedDir = await downloadAndExtractZip(signed.signedUrl)\n const resolvedSkillDir = await resolveExtractedSkillRoot(extractedDir)\n\n const skillMdPath = join(resolvedSkillDir, \"SKILL.md\")\n const skillName = (await fileExists(skillMdPath)) ? extractSkillName(skillMdPath) : null\n if (skillName !== skillId) {\n die(`Invalid payload for ${skillId}: SKILL.md name is ${skillName ?? \"missing\"}`)\n }\n\n const canonicalDir = join(canonicalBase, skillId)\n const toolBase = getToolSkillsDir(tool, scope, repoRoot)\n const toolDir = join(toolBase, skillId)\n\n if (!isSafeChildPath(canonicalBase, canonicalDir) || !isSafeChildPath(toolBase, toolDir)) {\n die(`Unsafe install path for skill: ${skillId}`)\n }\n\n await ensureDir(canonicalBase)\n await ensureDir(toolBase)\n\n if (mode === \"copy\") {\n await removePath(toolDir)\n await copyDir(resolvedSkillDir, toolDir)\n log(`Installed ${skillId} (${tool}) -> ${toolDir}`)\n continue\n }\n\n await removePath(canonicalDir)\n await copyDir(resolvedSkillDir, canonicalDir)\n\n const symlinkOk = await createSymlink(canonicalDir, toolDir)\n if (!symlinkOk) {\n await removePath(toolDir)\n await copyDir(resolvedSkillDir, toolDir)\n warn(`Symlink failed; copied ${skillId} (${tool}) -> ${toolDir}`)\n } else {\n log(`Installed ${skillId} (${tool}) -> ${toolDir}`)\n }\n }\n }\n}\n\nconst hasFlag = (args: string[], flag: string): boolean => args.includes(flag)\n\nconst getFlagValue = (args: string[], flag: string): string | null => {\n const idx = args.indexOf(flag)\n if (idx === -1) return null\n const v = args[idx + 1]\n if (!v || v.startsWith(\"-\")) return null\n return v\n}\n\nconst getMultiFlagValues = (args: string[], flag: string): string[] => {\n const out: string[] = []\n for (let i = 0; i < args.length; i++) {\n if (args[i] === flag) {\n const v = args[i + 1]\n if (v && !v.startsWith(\"-\")) out.push(v)\n }\n }\n return out\n}\n\nconst resolveSelectedSkills = (opts: {\n catalog: CatalogV1\n theme: string | null\n skillArgs: string[]\n all: boolean\n}): string[] => {\n const { catalog, theme, skillArgs, all } = opts\n\n if (all) return catalog.skills.map((s) => s.id)\n\n if (theme) {\n const ids = catalog.themes[theme]\n if (!ids) die(`Unknown theme: ${theme}`)\n return ids\n }\n\n if (skillArgs.length > 0) {\n return skillArgs\n }\n\n return []\n}\n\nconst downloadAndExtractZip = async (signedUrl: string): Promise<string> => {\n const res = await fetch(signedUrl)\n if (!res.ok) {\n die(`Failed to download artifact (HTTP ${res.status})`)\n }\n\n const tmpBase = await mkdtemp(join(tmpdir(), \"builderpack-\"))\n const zipPath = join(tmpBase, \"artifact.zip\")\n\n const buf = Buffer.from(await res.arrayBuffer())\n await writeFile(zipPath, buf)\n\n const zip = new AdmZip(zipPath)\n const outDir = join(tmpBase, \"out\")\n zip.extractAllTo(outDir, true)\n return outDir\n}\n\nconst resolveExtractedSkillRoot = async (dir: string): Promise<string> => {\n const direct = join(dir, \"SKILL.md\")\n if (await fileExists(direct)) return dir\n\n // Heuristic: if there is exactly one top-level directory and it contains SKILL.md, use it\n const entries = await readdir(dir, { withFileTypes: true })\n const dirs = entries.filter((e) => e.isDirectory()).map((e) => e.name)\n if (dirs.length === 1) {\n const nested = join(dir, dirs[0], \"SKILL.md\")\n if (await fileExists(nested)) return join(dir, dirs[0])\n }\n\n die(\"Invalid artifact zip: missing SKILL.md at root\")\n throw new Error(\"unreachable\")\n}\n","import { requireAuth } from \"./config\"\nimport { httpGetJson } from \"./http\"\n\nexport type CatalogV1 = {\n version: 1\n themes: Record<string, string[]>\n skills: Array<{ id: string; variants: Array<\"claude\" | \"codex\">; themes: string[] }>\n}\n\ntype CatalogResponse = { catalog: CatalogV1; entitlements: unknown }\n\nexport const fetchCatalog = async (): Promise<CatalogV1> => {\n const auth = requireAuth()\n\n const res = await httpGetJson<CatalogResponse>(`${auth.apiBase}/catalog`, { bearer: auth.accessToken })\n return res.catalog\n}\n","import { mkdir, rm, readdir, stat, copyFile, symlink, readlink } from \"fs/promises\"\nimport { dirname, join, relative, resolve } from \"path\"\n\nexport const ensureDir = async (path: string): Promise<void> => {\n await mkdir(path, { recursive: true })\n}\n\nexport const removePath = async (path: string): Promise<void> => {\n await rm(path, { recursive: true, force: true })\n}\n\nexport const copyDir = async (src: string, dest: string): Promise<void> => {\n await ensureDir(dest)\n const entries = await readdir(src, { withFileTypes: true })\n await Promise.all(\n entries.map(async (entry) => {\n const s = join(src, entry.name)\n const d = join(dest, entry.name)\n if (entry.isDirectory()) {\n await copyDir(s, d)\n return\n }\n if (entry.isFile()) {\n await ensureDir(dirname(d))\n await copyFile(s, d)\n }\n })\n )\n}\n\nexport const createSymlink = async (target: string, linkPath: string): Promise<boolean> => {\n try {\n const resolvedTarget = resolve(target)\n const resolvedLinkPath = resolve(linkPath)\n if (resolvedTarget === resolvedLinkPath) return true\n\n // if existing link already points correctly, keep it\n try {\n const existing = await readlink(linkPath)\n const resolvedExisting = resolve(dirname(linkPath), existing)\n if (resolvedExisting === resolvedTarget) return true\n } catch {\n // ignore\n }\n\n await removePath(linkPath)\n await ensureDir(dirname(linkPath))\n\n const rel = relative(dirname(linkPath), target)\n const type = process.platform === \"win32\" ? \"junction\" : undefined\n await symlink(rel, linkPath, type as any)\n return true\n } catch {\n return false\n }\n}\n\nexport const fileExists = async (path: string): Promise<boolean> => {\n try {\n const s = await stat(path)\n return s.isFile()\n } catch {\n return false\n }\n}\n\n","import { spawnSync } from \"child_process\"\nimport { homedir } from \"os\"\nimport { join, resolve } from \"path\"\n\nexport type InstallScope = \"project\" | \"global\"\nexport type ToolVariant = \"claude\" | \"codex\"\n\nexport const getRepoRoot = (): string => {\n const out = spawnSync(\"git\", [\"rev-parse\", \"--show-toplevel\"], { encoding: \"utf8\" })\n if (out.status === 0 && out.stdout) {\n return out.stdout.trim()\n }\n return process.cwd()\n}\n\nexport const getCanonicalDir = (scope: InstallScope, repoRoot: string): string => {\n if (scope === \"global\") {\n return join(homedir(), \".builderpack\", \"store\", \"skills\")\n }\n return join(repoRoot, \".builderpack\", \"store\", \"skills\")\n}\n\nexport const getToolSkillsDir = (\n tool: ToolVariant,\n scope: InstallScope,\n repoRoot: string\n): string => {\n if (scope === \"project\") {\n if (tool === \"claude\") return join(repoRoot, \".claude\", \"skills\")\n return join(repoRoot, \".codex\", \"skills\")\n }\n\n if (tool === \"claude\") {\n const base = process.env.CLAUDE_CONFIG_DIR?.trim() || join(homedir(), \".claude\")\n return join(base, \"skills\")\n }\n\n const codexHome = process.env.CODEX_HOME?.trim() || join(homedir(), \".codex\")\n return join(codexHome, \"skills\")\n}\n\nexport const isSafeChildPath = (baseDir: string, childPath: string): boolean => {\n const base = resolve(baseDir)\n const target = resolve(childPath)\n return target === base || target.startsWith(base + \"/\") || target.startsWith(base + \"\\\\\")\n}\n\n","import { readFileSync } from \"fs\"\n\nexport const extractSkillName = (skillMdPath: string): string | null => {\n const content = readFileSync(skillMdPath, \"utf8\")\n const match = content.match(/^\\s*---\\s*\\n([\\s\\S]*?)\\n---\\s*\\n/)\n if (!match) return null\n const fm = match[1]\n const nameMatch = fm.match(/^\\s*name\\s*:\\s*(.+?)\\s*$/m)\n if (!nameMatch) return null\n return nameMatch[1].trim().replace(/^[\"']|[\"']$/g, \"\")\n}\n\n","import { commandLogin, commandLogout, commandWhoami } from \"./auth\"\nimport { commandSkillsAdd, commandSkillsList } from \"./skills\"\nimport { die, log } from \"./print\"\nimport { readFileSync } from \"fs\"\nimport { join, dirname } from \"path\"\nimport { fileURLToPath } from \"url\"\n\nconst showHelp = (): void => {\n log(`builderpack\n\nUsage:\n builderpack login\n builderpack whoami\n builderpack logout\n\n builderpack skills list [--theme <name>]\n builderpack skills add (--theme <name> | --skill <id>... | --all) [--tool claude,codex] [--global] [--mode symlink|copy] [--strict] [--dry-run]\n`)\n}\n\nconst main = async (): Promise<void> => {\n const [, , ...argv] = process.argv\n const [cmd, sub, ...rest] = argv\n\n if (!cmd || cmd === \"--help\" || cmd === \"-h\") {\n showHelp()\n return\n }\n\n if (cmd === \"--version\" || cmd === \"-v\") {\n try {\n const here = dirname(fileURLToPath(import.meta.url))\n const pkgPath = join(here, \"..\", \"package.json\")\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf8\")) as { version?: string }\n log(pkg.version || \"0.0.0\")\n } catch {\n log(\"0.0.0\")\n }\n return\n }\n\n if (cmd === \"login\") {\n await commandLogin()\n return\n }\n if (cmd === \"whoami\") {\n await commandWhoami()\n return\n }\n if (cmd === \"logout\") {\n commandLogout()\n return\n }\n\n if (cmd === \"skills\") {\n if (!sub || sub === \"--help\" || sub === \"-h\") {\n log(`builderpack skills\n\nUsage:\n builderpack skills list [--theme <name>]\n builderpack skills add (--theme <name> | --skill <id>... | --all) [--tool claude,codex] [--global] [--mode symlink|copy] [--strict] [--dry-run]\n`)\n return\n }\n\n if (sub === \"list\") {\n await commandSkillsList(rest)\n return\n }\n\n if (sub === \"add\") {\n await commandSkillsAdd(rest)\n return\n }\n\n die(`Unknown skills command: ${sub}`)\n }\n\n die(`Unknown command: ${cmd}`)\n}\n\nmain().catch((err) => {\n // eslint-disable-next-line no-console\n console.error(err)\n process.exitCode = 1\n})\n"],"mappings":"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","names":["readdir","existsSync","readFileSync","join","tmpdir","join","spawnSync","homedir","join","resolve","readFileSync","join","existsSync","readFileSync","tmpdir","readdir","readFileSync","join","dirname"]}
1
+ {"version":3,"sources":["../src/config.ts","../src/http.ts","../src/print.ts","../src/open.ts","../src/auth.ts","../src/skills.ts","../src/catalog.ts","../src/fsx.ts","../src/paths.ts","../src/skill-md.ts","../src/skills-select.ts","../src/cli.ts"],"sourcesContent":["import { homedir, tmpdir } from \"os\"\nimport { join } from \"path\"\nimport { mkdirSync, readFileSync, writeFileSync, existsSync, rmSync } from \"fs\"\n\nexport type BuilderpackAuth = {\n apiBase: string\n accessToken: string\n}\n\nexport const getApiBase = (): string => {\n return (process.env.BUILDERPACK_API_BASE?.trim() || \"https://www.builderpack.ai/api/cli/v1\").replace(\n /\\/$/,\n \"\"\n )\n}\n\nexport const getConfigDir = (): string => {\n const xdg = process.env.XDG_CONFIG_HOME?.trim()\n if (xdg) return join(xdg, \"builderpack\")\n\n if (process.platform === \"win32\") {\n const appData = process.env.APPDATA?.trim()\n if (appData) return join(appData, \"builderpack\")\n }\n\n return join(homedir(), \".config\", \"builderpack\")\n}\n\nexport const getAuthPath = (): string => {\n return join(getConfigDir(), \"auth.json\")\n}\n\nexport const loadAuth = (): BuilderpackAuth | null => {\n const p = getAuthPath()\n if (!existsSync(p)) return null\n try {\n const parsed = JSON.parse(readFileSync(p, \"utf8\")) as Partial<BuilderpackAuth>\n if (!parsed?.accessToken || !parsed?.apiBase) return null\n return { apiBase: parsed.apiBase, accessToken: parsed.accessToken }\n } catch {\n return null\n }\n}\n\nexport const requireAuth = (): BuilderpackAuth => {\n const auth = loadAuth()\n if (!auth) {\n throw new Error(\"Not logged in. Run: builderpack login\")\n }\n return auth\n}\n\nexport const saveAuth = (auth: BuilderpackAuth): void => {\n const dir = getConfigDir()\n mkdirSync(dir, { recursive: true })\n writeFileSync(getAuthPath(), JSON.stringify(auth, null, 2), \"utf8\")\n}\n\nexport const clearAuth = (): void => {\n const p = getAuthPath()\n try {\n rmSync(p)\n } catch {\n // ignore\n }\n}\n\nexport const getTempDir = (): string => {\n return join(tmpdir(), \"builderpack\")\n}\n","export type HttpError = {\n status: number\n bodyText: string\n}\n\ntype RequestOptions = {\n method: \"GET\" | \"POST\"\n url: string\n headers: Record<string, string>\n body?: string\n}\n\nconst requestJson = async <T>(\n opts: RequestOptions,\n maxRedirects: number = 3\n): Promise<T> => {\n let current = opts\n for (let i = 0; i <= maxRedirects; i++) {\n const res = await fetch(current.url, {\n method: current.method,\n headers: current.headers,\n body: current.body,\n redirect: \"manual\",\n })\n\n if (res.status >= 300 && res.status < 400) {\n const location = res.headers.get(\"location\")\n if (!location) {\n const bodyText = await res.text().catch(() => \"\")\n throw { status: res.status, bodyText } satisfies HttpError\n }\n const nextUrl = new URL(location, current.url).toString()\n current = { ...current, url: nextUrl }\n continue\n }\n\n if (!res.ok) {\n const bodyText = await res.text().catch(() => \"\")\n throw { status: res.status, bodyText } satisfies HttpError\n }\n\n return (await res.json()) as T\n }\n\n throw { status: 310, bodyText: \"Too many redirects\" } satisfies HttpError\n}\n\nexport const httpGetJson = async <T>(\n url: string,\n options?: { bearer?: string }\n): Promise<T> => {\n return requestJson<T>({\n method: \"GET\",\n url,\n headers: {\n ...(options?.bearer ? { Authorization: `Bearer ${options.bearer}` } : {}),\n },\n })\n}\n\nexport const httpPostJson = async <T>(\n url: string,\n body: unknown,\n options?: { bearer?: string }\n): Promise<T> => {\n return requestJson<T>({\n method: \"POST\",\n url,\n headers: {\n \"Content-Type\": \"application/json\",\n ...(options?.bearer ? { Authorization: `Bearer ${options.bearer}` } : {}),\n },\n body: JSON.stringify(body),\n })\n}\n","export const die = (message: string, code: number = 1): never => {\n process.stderr.write(message + \"\\n\")\n process.exit(code)\n}\n\nexport const log = (message: string): void => {\n process.stdout.write(message + \"\\n\")\n}\n\nexport const warn = (message: string): void => {\n process.stderr.write(message + \"\\n\")\n}\n\n","import { spawnSync } from \"child_process\"\n\nexport const tryOpenUrl = (url: string): void => {\n try {\n if (process.platform === \"darwin\") {\n spawnSync(\"open\", [url], { stdio: \"ignore\" })\n return\n }\n\n if (process.platform === \"win32\") {\n spawnSync(\"cmd\", [\"/c\", \"start\", \"\", url], { stdio: \"ignore\" })\n return\n }\n\n spawnSync(\"xdg-open\", [url], { stdio: \"ignore\" })\n } catch {\n // ignore\n }\n}\n\n","import { getApiBase, requireAuth, saveAuth, clearAuth } from \"./config\"\nimport { httpGetJson, httpPostJson } from \"./http\"\nimport { die, log } from \"./print\"\nimport { tryOpenUrl } from \"./open\"\nimport { createInterface } from \"readline\"\n\nconst waitForEnter = async (): Promise<void> => {\n if (!process.stdin.isTTY || !process.stdout.isTTY) {\n return\n }\n\n await new Promise<void>((resolve) => {\n const rl = createInterface({ input: process.stdin, output: process.stdout })\n rl.question(\"Press Enter to launch the browser...\", () => {\n rl.close()\n resolve()\n })\n })\n}\n\ntype DeviceStartResponse = {\n device_code: string\n user_code: string\n verification_uri: string\n verification_uri_complete?: string\n expires_in: number\n interval: number\n}\n\ntype DeviceTokenResponse = {\n access_token: string\n expires_in: number\n}\n\ntype MeResponse = {\n email: string\n entitlements: { claude: boolean; codex: boolean; adk: boolean; allInOne: boolean }\n}\n\nexport const commandLogin = async (): Promise<void> => {\n const apiBase = getApiBase()\n const start = await httpPostJson<DeviceStartResponse>(`${apiBase}/auth/device/start`, {})\n\n log(\"\")\n log(\"Builderpack CLI login\")\n log(\"\")\n log(`1) You will open: ${start.verification_uri}`)\n log(`2) Enter code: ${start.user_code}`)\n log(\"\")\n\n const urlToOpen = start.verification_uri_complete || start.verification_uri\n if (process.stdin.isTTY && process.stdout.isTTY) {\n log(\"Press Enter to open the browser automatically.\")\n log(\"Then enter the code above and confirm it matches.\")\n await waitForEnter()\n tryOpenUrl(urlToOpen)\n } else {\n // Non-interactive environment; don't auto-launch a browser.\n log(`Open this URL in a browser when ready: ${urlToOpen}`)\n log(\"Enter the code above and confirm it matches.\")\n }\n\n const deadline = Date.now() + start.expires_in * 1000\n while (Date.now() < deadline) {\n try {\n const token = await httpPostJson<DeviceTokenResponse>(`${apiBase}/auth/device/token`, {\n device_code: start.device_code,\n })\n\n saveAuth({ apiBase, accessToken: token.access_token })\n log(\"Logged in. You can now run: builderpack skills add ...\")\n return\n } catch (e: any) {\n const status = typeof e?.status === \"number\" ? e.status : 0\n if (status === 428) {\n await new Promise((r) => setTimeout(r, Math.max(1, start.interval) * 1000))\n continue\n }\n if (status === 410) {\n die(\"Login expired. Run: builderpack login\")\n }\n // Other error; keep retrying a couple times then bail\n await new Promise((r) => setTimeout(r, Math.max(1, start.interval) * 1000))\n continue\n }\n }\n\n die(\"Login expired. Run: builderpack login\")\n}\n\nexport const commandWhoami = async (): Promise<void> => {\n const auth = requireAuth()\n const me = await httpGetJson<MeResponse>(`${auth.apiBase}/me`, { bearer: auth.accessToken })\n log(JSON.stringify(me, null, 2))\n}\n\nexport const commandLogout = (): void => {\n clearAuth()\n log(\"Logged out.\")\n}\n","import { mkdtemp, writeFile, readdir } from \"fs/promises\"\nimport { existsSync, readFileSync } from \"fs\"\nimport { join } from \"path\"\nimport { tmpdir } from \"os\"\nimport AdmZip from \"adm-zip\"\nimport { requireAuth } from \"./config\"\nimport { fetchCatalog, type CatalogV1 } from \"./catalog\"\nimport { httpGetJson } from \"./http\"\nimport { die, log, warn } from \"./print\"\nimport { copyDir, createSymlink, ensureDir, fileExists, removePath } from \"./fsx\"\nimport { getCanonicalDir, getRepoRoot, getToolSkillsDir, isSafeChildPath } from \"./paths\"\nimport { extractSkillName } from \"./skill-md\"\nimport { resolveSelectedSkills } from \"./skills-select\"\n\ntype Variant = \"claude\" | \"codex\"\n\ntype SignedUrlResponse = {\n signedUrl: string\n expiresIn: number\n objectPath: string\n}\n\nexport const commandSkillsList = async (args: string[]): Promise<void> => {\n const theme = getFlagValue(args, \"--theme\")\n const verbose = hasFlag(args, \"--verbose\")\n const catalog = await fetchCatalog()\n\n const ids =\n theme && catalog.themes[theme]\n ? catalog.themes[theme]\n : catalog.skills.map((s) => s.id)\n\n if (verbose) {\n const themeInfo = theme ? theme : \"all\"\n log(`[verbose] theme: ${themeInfo}`)\n log(`[verbose] total skills: ${catalog.skills.length}`)\n log(`[verbose] selected count: ${ids.length}`)\n }\n\n for (const id of ids) {\n const skill = catalog.skills.find((s) => s.id === id)\n const variants = skill?.variants?.join(\",\") || \"\"\n log(`${id}${variants ? ` (${variants})` : \"\"}`)\n }\n}\n\nexport const commandSkillsAdd = async (args: string[]): Promise<void> => {\n const auth = requireAuth()\n\n const catalog = await fetchCatalog()\n\n const scope = hasFlag(args, \"--global\") ? \"global\" : \"project\"\n const mode = (getFlagValue(args, \"--mode\") || \"symlink\") as \"symlink\" | \"copy\"\n const strict = hasFlag(args, \"--strict\")\n const dryRun = hasFlag(args, \"--dry-run\")\n const verbose = hasFlag(args, \"--verbose\")\n\n const toolArg = getFlagValue(args, \"--tool\") || \"claude,codex\"\n const tools = toolArg\n .split(\",\")\n .map((t) => t.trim())\n .filter(Boolean)\n\n const invalidTools = tools.filter((t) => t !== \"claude\" && t !== \"codex\")\n if (invalidTools.length > 0) {\n die(`Invalid --tool value(s): ${invalidTools.join(\", \")} (expected claude,codex)`)\n }\n\n const normalizedTools = tools as Variant[]\n\n const theme = getFlagValue(args, \"--theme\")\n const skillArgs = getMultiFlagValues(args, \"--skill\")\n const all = hasFlag(args, \"--all\")\n\n const selected = resolveSelectedSkills({ catalog, theme, skillArgs, all })\n if (selected.length === 0) {\n die(\"No skills selected. Use --theme <name>, --skill <id>, or --all\")\n }\n\n const repoRoot = scope === \"project\" ? getRepoRoot() : process.cwd()\n const canonicalBase = getCanonicalDir(scope, repoRoot)\n\n if (verbose) {\n log(`[verbose] api base: ${auth.apiBase}`)\n log(`[verbose] scope: ${scope}`)\n log(`[verbose] mode: ${mode}`)\n log(`[verbose] strict: ${strict}`)\n log(`[verbose] dry-run: ${dryRun}`)\n log(`[verbose] tools: ${normalizedTools.join(\",\")}`)\n log(`[verbose] theme: ${theme ?? \"none\"}`)\n log(`[verbose] skills: ${selected.join(\",\")}`)\n }\n\n if (scope === \"project\" && mode === \"symlink\") {\n const gitignorePath = join(repoRoot, \".gitignore\")\n if (existsSync(gitignorePath)) {\n try {\n const content = readFileSync(gitignorePath, \"utf8\")\n if (!content.includes(\".builderpack/\")) {\n warn(\"Note: consider adding `.builderpack/` to your repo .gitignore\")\n }\n } catch {\n // ignore\n }\n }\n }\n\n for (const skillId of selected) {\n const skill = catalog.skills.find((s) => s.id === skillId)\n if (!skill) {\n if (strict) die(`Unknown skill: ${skillId}`)\n warn(`Skipping unknown skill: ${skillId}`)\n continue\n }\n\n for (const tool of normalizedTools) {\n if (!skill.variants.includes(tool)) {\n const msg = `Skipping ${skillId} for ${tool}: variant not available`\n if (strict) die(msg)\n warn(msg)\n continue\n }\n\n if (dryRun) {\n log(`[dry-run] would install ${skillId} (${tool})`)\n continue\n }\n\n if (verbose) {\n log(`[verbose] request artifact: ${skillId} (${tool})`)\n }\n const signed = await httpGetJson<SignedUrlResponse>(\n `${auth.apiBase}/artifacts/skills/${encodeURIComponent(skillId)}/${encodeURIComponent(tool)}`,\n { bearer: auth.accessToken }\n )\n\n if (verbose) {\n log(`[verbose] signed url expires in: ${signed.expiresIn}s`)\n log(`[verbose] object path: ${signed.objectPath}`)\n }\n const extractedDir = await downloadAndExtractZip(signed.signedUrl)\n const resolvedSkillDir = await resolveExtractedSkillRoot(extractedDir)\n\n const skillMdPath = join(resolvedSkillDir, \"SKILL.md\")\n const skillName = (await fileExists(skillMdPath)) ? extractSkillName(skillMdPath) : null\n if (skillName !== skillId) {\n die(`Invalid payload for ${skillId}: SKILL.md name is ${skillName ?? \"missing\"}`)\n }\n\n const canonicalDir = join(canonicalBase, skillId)\n const toolBase = getToolSkillsDir(tool, scope, repoRoot)\n const toolDir = join(toolBase, skillId)\n\n if (!isSafeChildPath(canonicalBase, canonicalDir) || !isSafeChildPath(toolBase, toolDir)) {\n die(`Unsafe install path for skill: ${skillId}`)\n }\n\n if (verbose) {\n log(`[verbose] canonical dir: ${canonicalDir}`)\n log(`[verbose] tool dir: ${toolDir}`)\n }\n\n await ensureDir(canonicalBase)\n await ensureDir(toolBase)\n\n if (mode === \"copy\") {\n await removePath(toolDir)\n await copyDir(resolvedSkillDir, toolDir)\n log(`Installed ${skillId} (${tool}) -> ${toolDir}`)\n continue\n }\n\n await removePath(canonicalDir)\n await copyDir(resolvedSkillDir, canonicalDir)\n\n const symlinkOk = await createSymlink(canonicalDir, toolDir)\n if (!symlinkOk) {\n await removePath(toolDir)\n await copyDir(resolvedSkillDir, toolDir)\n warn(`Symlink failed; copied ${skillId} (${tool}) -> ${toolDir}`)\n } else {\n log(`Installed ${skillId} (${tool}) -> ${toolDir}`)\n }\n }\n }\n}\n\nconst hasFlag = (args: string[], flag: string): boolean => args.includes(flag)\n\nconst getFlagValue = (args: string[], flag: string): string | null => {\n const idx = args.indexOf(flag)\n if (idx === -1) return null\n const v = args[idx + 1]\n if (!v || v.startsWith(\"-\")) return null\n return v\n}\n\nconst getMultiFlagValues = (args: string[], flag: string): string[] => {\n const out: string[] = []\n for (let i = 0; i < args.length; i++) {\n if (args[i] === flag) {\n const v = args[i + 1]\n if (v && !v.startsWith(\"-\")) out.push(v)\n }\n }\n return out\n}\n\nconst downloadAndExtractZip = async (signedUrl: string): Promise<string> => {\n const res = await fetch(signedUrl)\n if (!res.ok) {\n die(`Failed to download artifact (HTTP ${res.status})`)\n }\n\n const tmpBase = await mkdtemp(join(tmpdir(), \"builderpack-\"))\n const zipPath = join(tmpBase, \"artifact.zip\")\n\n const buf = Buffer.from(await res.arrayBuffer())\n await writeFile(zipPath, buf)\n\n const zip = new AdmZip(zipPath)\n const outDir = join(tmpBase, \"out\")\n zip.extractAllTo(outDir, true)\n return outDir\n}\n\nconst resolveExtractedSkillRoot = async (dir: string): Promise<string> => {\n const direct = join(dir, \"SKILL.md\")\n if (await fileExists(direct)) return dir\n\n // Heuristic: if there is exactly one top-level directory and it contains SKILL.md, use it\n const entries = await readdir(dir, { withFileTypes: true })\n const dirs = entries.filter((e) => e.isDirectory()).map((e) => e.name)\n if (dirs.length === 1) {\n const nested = join(dir, dirs[0], \"SKILL.md\")\n if (await fileExists(nested)) return join(dir, dirs[0])\n }\n\n die(\"Invalid artifact zip: missing SKILL.md at root\")\n throw new Error(\"unreachable\")\n}\n","import { requireAuth } from \"./config\"\nimport { httpGetJson } from \"./http\"\n\nexport type CatalogV1 = {\n version: 1\n themes: Record<string, string[]>\n skills: Array<{ id: string; variants: Array<\"claude\" | \"codex\">; themes: string[] }>\n}\n\ntype CatalogResponse = { catalog: CatalogV1; entitlements: unknown }\n\nexport const fetchCatalog = async (): Promise<CatalogV1> => {\n const auth = requireAuth()\n\n const res = await httpGetJson<CatalogResponse>(`${auth.apiBase}/catalog`, { bearer: auth.accessToken })\n return res.catalog\n}\n","import { mkdir, rm, readdir, stat, copyFile, symlink, readlink } from \"fs/promises\"\nimport { dirname, join, relative, resolve } from \"path\"\n\nexport const ensureDir = async (path: string): Promise<void> => {\n await mkdir(path, { recursive: true })\n}\n\nexport const removePath = async (path: string): Promise<void> => {\n await rm(path, { recursive: true, force: true })\n}\n\nexport const copyDir = async (src: string, dest: string): Promise<void> => {\n await ensureDir(dest)\n const entries = await readdir(src, { withFileTypes: true })\n await Promise.all(\n entries.map(async (entry) => {\n const s = join(src, entry.name)\n const d = join(dest, entry.name)\n if (entry.isDirectory()) {\n await copyDir(s, d)\n return\n }\n if (entry.isFile()) {\n await ensureDir(dirname(d))\n await copyFile(s, d)\n }\n })\n )\n}\n\nexport const createSymlink = async (target: string, linkPath: string): Promise<boolean> => {\n try {\n const resolvedTarget = resolve(target)\n const resolvedLinkPath = resolve(linkPath)\n if (resolvedTarget === resolvedLinkPath) return true\n\n // if existing link already points correctly, keep it\n try {\n const existing = await readlink(linkPath)\n const resolvedExisting = resolve(dirname(linkPath), existing)\n if (resolvedExisting === resolvedTarget) return true\n } catch {\n // ignore\n }\n\n await removePath(linkPath)\n await ensureDir(dirname(linkPath))\n\n const rel = relative(dirname(linkPath), target)\n const type = process.platform === \"win32\" ? \"junction\" : undefined\n await symlink(rel, linkPath, type as any)\n return true\n } catch {\n return false\n }\n}\n\nexport const fileExists = async (path: string): Promise<boolean> => {\n try {\n const s = await stat(path)\n return s.isFile()\n } catch {\n return false\n }\n}\n\n","import { spawnSync } from \"child_process\"\nimport { homedir } from \"os\"\nimport { join, resolve } from \"path\"\n\nexport type InstallScope = \"project\" | \"global\"\nexport type ToolVariant = \"claude\" | \"codex\"\n\nexport const getRepoRoot = (): string => {\n const out = spawnSync(\"git\", [\"rev-parse\", \"--show-toplevel\"], { encoding: \"utf8\" })\n if (out.status === 0 && out.stdout) {\n return out.stdout.trim()\n }\n return process.cwd()\n}\n\nexport const getCanonicalDir = (scope: InstallScope, repoRoot: string): string => {\n if (scope === \"global\") {\n return join(homedir(), \".builderpack\", \"store\", \"skills\")\n }\n return join(repoRoot, \".builderpack\", \"store\", \"skills\")\n}\n\nexport const getToolSkillsDir = (\n tool: ToolVariant,\n scope: InstallScope,\n repoRoot: string\n): string => {\n if (scope === \"project\") {\n if (tool === \"claude\") return join(repoRoot, \".claude\", \"skills\")\n return join(repoRoot, \".codex\", \"skills\")\n }\n\n if (tool === \"claude\") {\n const base = process.env.CLAUDE_CONFIG_DIR?.trim() || join(homedir(), \".claude\")\n return join(base, \"skills\")\n }\n\n const codexHome = process.env.CODEX_HOME?.trim() || join(homedir(), \".codex\")\n return join(codexHome, \"skills\")\n}\n\nexport const isSafeChildPath = (baseDir: string, childPath: string): boolean => {\n const base = resolve(baseDir)\n const target = resolve(childPath)\n return target === base || target.startsWith(base + \"/\") || target.startsWith(base + \"\\\\\")\n}\n\n","import { readFileSync } from \"fs\"\n\nexport const extractSkillName = (skillMdPath: string): string | null => {\n const content = readFileSync(skillMdPath, \"utf8\")\n const match = content.match(/^\\s*---\\s*\\n([\\s\\S]*?)\\n---\\s*\\n/)\n if (!match) return null\n const fm = match[1]\n const nameMatch = fm.match(/^\\s*name\\s*:\\s*(.+?)\\s*$/m)\n if (!nameMatch) return null\n return nameMatch[1].trim().replace(/^[\"']|[\"']$/g, \"\")\n}\n\n","import { type CatalogV1 } from \"./catalog\"\nimport { die } from \"./print\"\n\nexport const resolveSelectedSkills = (opts: {\n catalog: CatalogV1\n theme: string | null\n skillArgs: string[]\n all: boolean\n}): string[] => {\n const { catalog, theme, skillArgs, all } = opts\n\n if (all) return catalog.skills.map((s) => s.id)\n\n if (theme) {\n const ids = catalog.themes[theme]\n if (!ids) die(`Unknown theme: ${theme}`)\n return ids\n }\n\n if (skillArgs.length > 0) {\n return skillArgs\n }\n\n return []\n}\n","import { commandLogin, commandLogout, commandWhoami } from \"./auth\"\nimport { commandSkillsAdd, commandSkillsList } from \"./skills\"\nimport { die, log } from \"./print\"\nimport { readFileSync } from \"fs\"\nimport { join, dirname } from \"path\"\nimport { fileURLToPath } from \"url\"\n\nconst showHelp = (): void => {\n log(`builderpack\n\nUsage:\n builderpack login\n builderpack whoami\n builderpack logout\n\n builderpack skills list [--theme <name>]\n builderpack skills add (--theme <name> | --skill <id>... | --all) [--tool claude,codex] [--global] [--mode symlink|copy] [--strict] [--dry-run] [--verbose]\n`)\n}\n\nconst main = async (): Promise<void> => {\n const [, , ...argv] = process.argv\n const [cmd, sub, ...rest] = argv\n\n if (!cmd || cmd === \"--help\" || cmd === \"-h\") {\n showHelp()\n return\n }\n\n if (cmd === \"--version\" || cmd === \"-v\") {\n try {\n const here = dirname(fileURLToPath(import.meta.url))\n const pkgPath = join(here, \"..\", \"package.json\")\n const pkg = JSON.parse(readFileSync(pkgPath, \"utf8\")) as { version?: string }\n log(pkg.version || \"0.0.0\")\n } catch {\n log(\"0.0.0\")\n }\n return\n }\n\n if (cmd === \"login\") {\n await commandLogin()\n return\n }\n if (cmd === \"whoami\") {\n await commandWhoami()\n return\n }\n if (cmd === \"logout\") {\n commandLogout()\n return\n }\n\n if (cmd === \"skills\") {\n if (!sub || sub === \"--help\" || sub === \"-h\") {\n log(`builderpack skills\n\nUsage:\n builderpack skills list [--theme <name>]\n builderpack skills add (--theme <name> | --skill <id>... | --all) [--tool claude,codex] [--global] [--mode symlink|copy] [--strict] [--dry-run] [--verbose]\n`)\n return\n }\n\n if (sub === \"list\") {\n await commandSkillsList(rest)\n return\n }\n\n if (sub === \"add\") {\n await commandSkillsAdd(rest)\n return\n }\n\n die(`Unknown skills command: ${sub}`)\n }\n\n die(`Unknown command: ${cmd}`)\n}\n\nmain().catch((err) => {\n // eslint-disable-next-line no-console\n console.error(err)\n process.exitCode = 1\n})\n"],"mappings":"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","names":["resolve","readdir","existsSync","readFileSync","join","tmpdir","join","spawnSync","homedir","join","resolve","readFileSync","join","existsSync","readFileSync","tmpdir","readdir","readFileSync","join","dirname"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@builderpackai/cli",
3
- "version": "0.1.4",
3
+ "version": "0.1.6",
4
4
  "description": "Builderpack CLI (skills installer)",
5
5
  "type": "module",
6
6
  "bin": {
@@ -18,7 +18,8 @@
18
18
  "package:skills": "node --import tsx scripts/package-skills.ts",
19
19
  "upload:catalog": "supabase --experimental --workdir web storage cp ../catalog/v1.json ss:///builderpack-cli/catalog/v1.json",
20
20
  "release": "node scripts/release.js",
21
- "type-check": "tsc --noEmit"
21
+ "type-check": "tsc --noEmit",
22
+ "test": "node --import tsx --test tests/**/*.test.ts"
22
23
  },
23
24
  "dependencies": {
24
25
  "adm-zip": "^0.5.16"