@iamsaroj/replicax 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (3) hide show
  1. package/README.md +5 -5
  2. package/dist/index.js +38 -34
  3. package/package.json +1 -1
package/README.md CHANGED
@@ -10,11 +10,11 @@
10
10
  None of your business code. None of your secrets. Just the setup.
11
11
  </p>
12
12
 
13
- [![npm](https://img.shields.io/badge/npm-%40iamsaroj%2Freplicax-CB3837?style=for-the-badge&logo=npm&logoColor=white)](https://www.npmjs.com/package/@iamsaroj/replicax)
14
- [![Node](https://img.shields.io/badge/Node-%E2%89%A5%2020-339933?style=for-the-badge&logo=node.js&logoColor=white)](https://nodejs.org)
15
- [![TypeScript](https://img.shields.io/badge/TypeScript-5-3178C6?style=for-the-badge&logo=typescript&logoColor=white)](https://www.typescriptlang.org)
16
- ![ESM](https://img.shields.io/badge/Module-ESM-F7DF1E?style=for-the-badge&logo=javascript&logoColor=black)
17
- [![License](https://img.shields.io/badge/License-MIT-3FB950?style=for-the-badge)](LICENSE)
13
+ [![npm](https://img.shields.io/badge/npm-%40iamsaroj%2Freplicax-CB3837?style=flat-square&logo=npm&logoColor=white)](https://www.npmjs.com/package/@iamsaroj/replicax)
14
+ [![Node](https://img.shields.io/badge/Node-%E2%89%A5%2020-339933?style=flat-square&logo=node.js&logoColor=white)](https://nodejs.org)
15
+ [![TypeScript](https://img.shields.io/badge/TypeScript-5-3178C6?style=flat-square&logo=typescript&logoColor=white)](https://www.typescriptlang.org)
16
+ ![ESM](https://img.shields.io/badge/Module-ESM-F7DF1E?style=flat-square&logo=javascript&logoColor=black)
17
+ [![License](https://img.shields.io/badge/License-MIT-3FB950?style=flat-square)](LICENSE)
18
18
 
19
19
  <sub>
20
20
  <a href="#quick-start"><b>Quick start</b></a> &nbsp;•&nbsp;
package/dist/index.js CHANGED
@@ -129,15 +129,19 @@ var SECRET_GUARD_GLOBS = [
129
129
  "**/*.key",
130
130
  "**/*.p12",
131
131
  "**/*.pfx",
132
+ "**/*.p8",
132
133
  "**/*.cert",
133
134
  "**/*.crt",
134
135
  "**/*.keystore",
135
136
  "**/*.jks",
137
+ "**/*.ppk",
136
138
  "**/id_rsa*",
137
139
  "**/id_dsa*",
138
140
  "**/id_ecdsa*",
139
141
  "**/id_ed25519*",
140
142
  "**/.netrc",
143
+ "**/.pgpass",
144
+ "**/.htpasswd",
141
145
  "**/secrets.*",
142
146
  "**/*.secret",
143
147
  "**/*.secrets"
@@ -454,7 +458,7 @@ function detectFramework(pkg) {
454
458
  [has("svelte"), "svelte"],
455
459
  [has("solid-js"), "solid"],
456
460
  [has("react"), "react"],
457
- [has("@fastify/fastify") || has("fastify"), "fastify"],
461
+ [has("fastify"), "fastify"],
458
462
  [has("koa"), "koa"],
459
463
  [has("express"), "express"]
460
464
  ];
@@ -953,25 +957,31 @@ var SKILL_TARGETS = [
953
957
  {
954
958
  id: "claude",
955
959
  label: "Claude Code",
956
- entryPath: (slug2) => `.claude/skills/${slug2}/SKILL.md`,
960
+ entryPath: (slug) => `.claude/skills/${slug}/SKILL.md`,
957
961
  note: "Claude Code loads skills from .claude/skills/<name>/SKILL.md"
958
962
  },
959
963
  {
960
964
  id: "codex",
961
965
  label: "OpenAI Codex CLI",
962
- entryPath: (slug2) => `.codex/skills/${slug2}/SKILL.md`,
966
+ entryPath: (slug) => `.codex/skills/${slug}/SKILL.md`,
963
967
  note: "Codex CLI loads project skills from .codex/skills/<name>/SKILL.md"
964
968
  },
965
969
  {
966
970
  id: "antigravity",
967
971
  label: "Google Antigravity",
968
- entryPath: (slug2) => `.agents/skills/${slug2}.md`,
972
+ entryPath: (slug) => `.agents/skills/${slug}.md`,
969
973
  note: "Antigravity discovers skills under .agents/skills/"
970
974
  }
971
975
  ];
972
976
  var SKILL_TARGET_BY_ID = new Map(SKILL_TARGETS.map((t) => [t.id, t]));
973
977
  var SKILL_TARGET_IDS = SKILL_TARGETS.map((t) => t.id);
974
978
 
979
+ // src/utils/slug.ts
980
+ function slugify(input, fallback = "project") {
981
+ const slug = input.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
982
+ return slug || fallback;
983
+ }
984
+
975
985
  // src/core/skill-generator.ts
976
986
  var FRAMEWORK_LABELS = {
977
987
  next: "Next.js",
@@ -1004,10 +1014,6 @@ var PRIMARY_SCRIPTS = [
1004
1014
  "format:check",
1005
1015
  "typecheck"
1006
1016
  ];
1007
- function slugify(input) {
1008
- const slug2 = input.trim().toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "");
1009
- return slug2 || "project";
1010
- }
1011
1017
  function installCommand(pm) {
1012
1018
  switch (pm) {
1013
1019
  case "yarn":
@@ -1110,7 +1116,7 @@ function conventionLines(args, scripts) {
1110
1116
  }
1111
1117
  function buildSkill(args) {
1112
1118
  const { name, metadata, tooling, structure, pkg } = args;
1113
- const slug2 = slugify(name);
1119
+ const slug = slugify(name);
1114
1120
  const pm = metadata.packageManager;
1115
1121
  const framework = FRAMEWORK_LABELS[metadata.framework] ?? metadata.framework;
1116
1122
  const language = metadata.language === "typescript" ? "TypeScript" : "JavaScript";
@@ -1118,7 +1124,7 @@ function buildSkill(args) {
1118
1124
  const description = `${name} project: ${framework}/${language} setup, build/test commands, and tooling conventions. Use this skill when working in or scaffolding this codebase.`;
1119
1125
  const lines = [];
1120
1126
  lines.push("---");
1121
- lines.push(`name: ${slug2}`);
1127
+ lines.push(`name: ${slug}`);
1122
1128
  lines.push(`description: ${yamlString(description)}`);
1123
1129
  lines.push("---");
1124
1130
  lines.push("");
@@ -1176,7 +1182,7 @@ function buildSkill(args) {
1176
1182
  lines.push(`- ${line}`);
1177
1183
  }
1178
1184
  lines.push("");
1179
- return { slug: slug2, content: lines.join("\n") };
1185
+ return { slug, content: lines.join("\n") };
1180
1186
  }
1181
1187
 
1182
1188
  // src/core/ai/cli.ts
@@ -1576,24 +1582,24 @@ function tokenFromEnv() {
1576
1582
  const token = process.env.GITHUB_TOKEN || process.env.GH_TOKEN;
1577
1583
  return token?.trim() || void 0;
1578
1584
  }
1579
- function httpError(status, slug2, hasToken) {
1585
+ function httpError(status, slug, hasToken) {
1580
1586
  if (status === 404) {
1581
- return new ReplicaxError(`Repository not found: ${slug2}.`, [
1587
+ return new ReplicaxError(`Repository not found: ${slug}.`, [
1582
1588
  "Check the owner/repo spelling and the branch/tag/commit name.",
1583
1589
  hasToken ? "If it is private, make sure your token can access it." : "If it is private, set GITHUB_TOKEN (or GH_TOKEN) with repo access."
1584
1590
  ]);
1585
1591
  }
1586
1592
  if (status === 401) {
1587
- return new ReplicaxError(`GitHub rejected the credentials for ${slug2}.`, [
1593
+ return new ReplicaxError(`GitHub rejected the credentials for ${slug}.`, [
1588
1594
  "Check that GITHUB_TOKEN (or GH_TOKEN) is valid and not expired."
1589
1595
  ]);
1590
1596
  }
1591
1597
  if (status === 403 || status === 429) {
1592
- return new ReplicaxError(`GitHub rate limit hit while fetching ${slug2}.`, [
1598
+ return new ReplicaxError(`GitHub rate limit hit while fetching ${slug}.`, [
1593
1599
  hasToken ? "Wait a moment and try again." : "Set GITHUB_TOKEN (or GH_TOKEN) to raise the limit, then retry."
1594
1600
  ]);
1595
1601
  }
1596
- return new ReplicaxError(`GitHub returned HTTP ${status} for ${slug2}.`);
1602
+ return new ReplicaxError(`GitHub returned HTTP ${status} for ${slug}.`);
1597
1603
  }
1598
1604
  async function firstSubdir(dir) {
1599
1605
  const entries = await fs7.readdir(dir, { withFileTypes: true });
@@ -1603,7 +1609,7 @@ async function firstSubdir(dir) {
1603
1609
  return null;
1604
1610
  }
1605
1611
  async function downloadRepo(ref) {
1606
- const slug2 = `${ref.owner}/${ref.repo}`;
1612
+ const slug = `${ref.owner}/${ref.repo}`;
1607
1613
  const url = `https://api.github.com/repos/${ref.owner}/${ref.repo}/tarball` + (ref.ref ? `/${encodeURIComponent(ref.ref)}` : "");
1608
1614
  const token = tokenFromEnv();
1609
1615
  const headers = {
@@ -1620,7 +1626,7 @@ async function downloadRepo(ref) {
1620
1626
  ]);
1621
1627
  }
1622
1628
  if (!res.ok) {
1623
- throw httpError(res.status, slug2, Boolean(token));
1629
+ throw httpError(res.status, slug, Boolean(token));
1624
1630
  }
1625
1631
  const tmpRoot = await fs7.mkdtemp(path8.join(os.tmpdir(), "replicax-extract-"));
1626
1632
  const cleanup = () => fs7.remove(tmpRoot);
@@ -1632,7 +1638,7 @@ async function downloadRepo(ref) {
1632
1638
  await tarExtract({ file: tarPath, cwd: extractDir, strip: 0 });
1633
1639
  const repoRoot = await firstSubdir(extractDir);
1634
1640
  if (!repoRoot) {
1635
- throw new ReplicaxError(`The downloaded archive for ${slug2} was empty.`);
1641
+ throw new ReplicaxError(`The downloaded archive for ${slug} was empty.`);
1636
1642
  }
1637
1643
  return { dir: repoRoot, cleanup };
1638
1644
  } catch (err) {
@@ -2038,6 +2044,15 @@ function printList(title, items, marker) {
2038
2044
 
2039
2045
  // src/commands/inspect.ts
2040
2046
  import Table from "cli-table3";
2047
+
2048
+ // src/utils/format.ts
2049
+ function formatBytes(bytes) {
2050
+ if (bytes < 1024) return `${bytes} B`;
2051
+ if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
2052
+ return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
2053
+ }
2054
+
2055
+ // src/commands/inspect.ts
2041
2056
  var SECTIONS = ["profile", "tooling", "structure", "metadata"];
2042
2057
  async function inspectCommand(options) {
2043
2058
  const dir = options.profile ? await resolveProfileDir(options.profile) : profileDir(process.cwd());
@@ -2110,11 +2125,6 @@ function printStructure(bundle) {
2110
2125
  logger.out(renderTree(structure.directories, structure.root));
2111
2126
  logger.out("");
2112
2127
  }
2113
- function formatBytes(bytes) {
2114
- if (bytes < 1024) return `${bytes} B`;
2115
- if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
2116
- return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
2117
- }
2118
2128
 
2119
2129
  // src/commands/validate.ts
2120
2130
  async function validateCommand(options) {
@@ -2200,30 +2210,24 @@ async function findProfileRoot(dir) {
2200
2210
  }
2201
2211
 
2202
2212
  // src/commands/export.ts
2203
- function slug(name) {
2204
- return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "") || "profile";
2205
- }
2206
2213
  async function exportCommand(options) {
2207
2214
  const dir = options.profile ? await resolveProfileDir(options.profile) : profileDir(process.cwd());
2208
2215
  if (!await profileExists(dir)) {
2209
2216
  throw new ReplicaxError("No ReplicaX profile found to export.", ["Run `replicax init` first."]);
2210
2217
  }
2211
2218
  const bundle = await loadBundle(dir);
2212
- const outPath = path13.resolve(options.out ?? `${slug(bundle.profile.name)}.replicax.tar.gz`);
2219
+ const outPath = path13.resolve(
2220
+ options.out ?? `${slugify(bundle.profile.name, "profile")}.replicax.tar.gz`
2221
+ );
2213
2222
  const spinner = ora5({ text: "Packaging profile\u2026" }).start();
2214
2223
  await exportProfile(dir, outPath);
2215
2224
  spinner.stop();
2216
2225
  const { size } = await fs11.stat(outPath);
2217
2226
  logger.success(
2218
- `Exported "${bundle.profile.name}" \u2192 ${path13.relative(process.cwd(), outPath)} (${formatBytes2(size)})`
2227
+ `Exported "${bundle.profile.name}" \u2192 ${path13.relative(process.cwd(), outPath)} (${formatBytes(size)})`
2219
2228
  );
2220
2229
  logger.hint("Share it, then `replicax import <file>` elsewhere.");
2221
2230
  }
2222
- function formatBytes2(bytes) {
2223
- if (bytes < 1024) return `${bytes} B`;
2224
- if (bytes < 1024 * 1024) return `${(bytes / 1024).toFixed(1)} KB`;
2225
- return `${(bytes / (1024 * 1024)).toFixed(1)} MB`;
2226
- }
2227
2231
 
2228
2232
  // src/commands/import.ts
2229
2233
  import fs12 from "fs-extra";
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@iamsaroj/replicax",
3
- "version": "0.0.2",
3
+ "version": "0.0.3",
4
4
  "description": "Copy the setup, not the code. Extract a project's tooling, structure, and conventions and recreate them in new projects.",
5
5
  "type": "module",
6
6
  "license": "MIT",