@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.
- package/README.md +5 -5
- package/dist/index.js +38 -34
- 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
|
-
[](https://www.npmjs.com/package/@iamsaroj/replicax)
|
|
14
|
+
[](https://nodejs.org)
|
|
15
|
+
[](https://www.typescriptlang.org)
|
|
16
|
+

|
|
17
|
+
[](LICENSE)
|
|
18
18
|
|
|
19
19
|
<sub>
|
|
20
20
|
<a href="#quick-start"><b>Quick start</b></a> •
|
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("
|
|
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: (
|
|
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: (
|
|
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: (
|
|
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
|
|
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: ${
|
|
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
|
|
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,
|
|
1585
|
+
function httpError(status, slug, hasToken) {
|
|
1580
1586
|
if (status === 404) {
|
|
1581
|
-
return new ReplicaxError(`Repository not found: ${
|
|
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 ${
|
|
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 ${
|
|
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 ${
|
|
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
|
|
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,
|
|
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 ${
|
|
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(
|
|
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)} (${
|
|
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