@synkro-sh/cli 1.7.43 → 1.7.45
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/bootstrap.js +47 -12
- package/dist/bootstrap.js.map +1 -1
- package/package.json +1 -1
package/dist/bootstrap.js
CHANGED
|
@@ -4826,7 +4826,7 @@ function writeConfigEnv(opts) {
|
|
|
4826
4826
|
`SYNKRO_CREDENTIALS_PATH=${shellQuoteSingle(credsPath)}`,
|
|
4827
4827
|
`SYNKRO_TIER=${shellQuoteSingle(safeTier)}`,
|
|
4828
4828
|
`SYNKRO_INFERENCE=${shellQuoteSingle(safeInference)}`,
|
|
4829
|
-
`SYNKRO_VERSION=${shellQuoteSingle("1.7.
|
|
4829
|
+
`SYNKRO_VERSION=${shellQuoteSingle("1.7.45")}`
|
|
4830
4830
|
];
|
|
4831
4831
|
if (safeSynkroBin) lines.push(`SYNKRO_CLI_BIN=${shellQuoteSingle(safeSynkroBin)}`);
|
|
4832
4832
|
if (safeUserId) lines.push(`SYNKRO_USER_ID=${shellQuoteSingle(safeUserId)}`);
|
|
@@ -6106,7 +6106,10 @@ async function syncSkillFiles() {
|
|
|
6106
6106
|
console.log(` indexing ${tasks.length} skill file${tasks.length === 1 ? "" : "s"} \u2014 comparing against existing ruleset (this may take a few seconds)...`);
|
|
6107
6107
|
await ingestSkillTasks(tasks, mcpPort);
|
|
6108
6108
|
}
|
|
6109
|
-
function
|
|
6109
|
+
function normSkillName(name) {
|
|
6110
|
+
return name.toLowerCase().replace(/\.mdx?$/, "");
|
|
6111
|
+
}
|
|
6112
|
+
function discoverSkillFiles(repoRoot, excludeHashes, ingestedHashes, ingestedNames) {
|
|
6110
6113
|
const roots = [];
|
|
6111
6114
|
const add = (p) => {
|
|
6112
6115
|
try {
|
|
@@ -6137,7 +6140,8 @@ function discoverSkillFiles(repoRoot, excludeHashes) {
|
|
|
6137
6140
|
const hash = createHash("sha256").update(content).digest("hex");
|
|
6138
6141
|
if (seen.has(hash) || excludeHashes.has(hash)) return;
|
|
6139
6142
|
seen.add(hash);
|
|
6140
|
-
|
|
6143
|
+
const ingested = ingestedHashes.has(hash) || ingestedNames.has(normSkillName(name));
|
|
6144
|
+
out.push({ source: `skill:${name}`, content, name, hash, ingested });
|
|
6141
6145
|
};
|
|
6142
6146
|
for (const root of roots) {
|
|
6143
6147
|
let entries = [];
|
|
@@ -6170,19 +6174,29 @@ function discoverySetHash(found) {
|
|
|
6170
6174
|
}
|
|
6171
6175
|
async function promptSkillDiscovery(found) {
|
|
6172
6176
|
if (!process.stdin.isTTY || found.length === 0) return [];
|
|
6177
|
+
const selectableIdx = found.map((s, i) => s.ingested ? -1 : i).filter((i) => i >= 0);
|
|
6178
|
+
if (selectableIdx.length === 0) return [];
|
|
6173
6179
|
const rl = createInterface3({ input: process.stdin, output: process.stdout });
|
|
6174
6180
|
const ask3 = (q) => new Promise((res) => rl.question(q, (a) => res(a.trim())));
|
|
6175
6181
|
try {
|
|
6176
6182
|
console.log(`
|
|
6177
6183
|
Found ${found.length} skill${found.length === 1 ? "" : "s"} in your Claude Code / skills.sh folders:`);
|
|
6178
|
-
found.forEach((s, i) => console.log(` ${i + 1}. ${s.name}`));
|
|
6179
|
-
console.log("Ingest
|
|
6184
|
+
found.forEach((s, i) => console.log(` ${i + 1}. ${s.name}${s.ingested ? " \u2014 already ingested (not selectable)" : ""}`));
|
|
6185
|
+
console.log("Ingest the uningested skills as enforceable rules? Each is security-vetted first \u2014 anything");
|
|
6180
6186
|
console.log("malicious (prompt injection, guardrail-weakening, secret exfil) is blocked and reported.");
|
|
6181
|
-
const a = (await ask3(
|
|
6187
|
+
const a = (await ask3(`Ingest [all] (${selectableIdx.length} uningested) / type numbers (e.g. 1,3) / [skip]: `)).toLowerCase();
|
|
6182
6188
|
if (a === "skip" || a === "n" || a === "no" || a === "s") return [];
|
|
6183
|
-
if (a === "" || a === "all" || a === "y" || a === "yes" || a === "a") return
|
|
6189
|
+
if (a === "" || a === "all" || a === "y" || a === "yes" || a === "a") return selectableIdx;
|
|
6184
6190
|
const picks = a.split(/[\s,]+/).map((x) => parseInt(x, 10) - 1).filter((i) => Number.isInteger(i) && i >= 0 && i < found.length);
|
|
6185
|
-
|
|
6191
|
+
const valid = [];
|
|
6192
|
+
for (const i of [...new Set(picks)]) {
|
|
6193
|
+
if (found[i].ingested) {
|
|
6194
|
+
console.log(` \xB7 ${found[i].name} is already ingested \u2014 skipped`);
|
|
6195
|
+
continue;
|
|
6196
|
+
}
|
|
6197
|
+
valid.push(i);
|
|
6198
|
+
}
|
|
6199
|
+
return valid;
|
|
6186
6200
|
} finally {
|
|
6187
6201
|
rl.close();
|
|
6188
6202
|
}
|
|
@@ -6191,6 +6205,7 @@ async function discoverAndIngestSkills() {
|
|
|
6191
6205
|
try {
|
|
6192
6206
|
const sf = readFullSynkroFile();
|
|
6193
6207
|
const repoRoot = sf?._repoRoot || detectGitRepo2();
|
|
6208
|
+
const mcpPort = process.env.SYNKRO_MCP_PORT || "18931";
|
|
6194
6209
|
const excludeHashes = /* @__PURE__ */ new Set();
|
|
6195
6210
|
if (sf?.skills?.length) {
|
|
6196
6211
|
for (const fp of resolveSkillPaths(sf.skills, sf._repoRoot)) {
|
|
@@ -6200,9 +6215,30 @@ async function discoverAndIngestSkills() {
|
|
|
6200
6215
|
}
|
|
6201
6216
|
}
|
|
6202
6217
|
}
|
|
6203
|
-
const
|
|
6218
|
+
const ingestedHashes = /* @__PURE__ */ new Set();
|
|
6219
|
+
const ingestedNames = /* @__PURE__ */ new Set();
|
|
6220
|
+
try {
|
|
6221
|
+
const resp = await fetch(`http://127.0.0.1:${mcpPort}/api/local/skills?status=active`, { signal: AbortSignal.timeout(5e3) });
|
|
6222
|
+
if (resp.ok) {
|
|
6223
|
+
const { skills } = await resp.json();
|
|
6224
|
+
for (const s of skills || []) {
|
|
6225
|
+
if (s.content_hash) ingestedHashes.add(s.content_hash);
|
|
6226
|
+
if (s.name) ingestedNames.add(normSkillName(String(s.name)));
|
|
6227
|
+
}
|
|
6228
|
+
}
|
|
6229
|
+
} catch {
|
|
6230
|
+
}
|
|
6231
|
+
const found = discoverSkillFiles(repoRoot, excludeHashes, ingestedHashes, ingestedNames);
|
|
6204
6232
|
if (found.length === 0) return;
|
|
6205
|
-
const
|
|
6233
|
+
const selectable = found.filter((f) => !f.ingested);
|
|
6234
|
+
if (selectable.length === 0) {
|
|
6235
|
+
const names = found.map((f) => f.name);
|
|
6236
|
+
const shown = names.slice(0, 5).join(", ") + (names.length > 5 ? `, +${names.length - 5} more` : "");
|
|
6237
|
+
console.log(`
|
|
6238
|
+
\u2713 ${found.length} skill${found.length === 1 ? "" : "s"} already ingested (${shown}) \u2014 nothing new to add.`);
|
|
6239
|
+
return;
|
|
6240
|
+
}
|
|
6241
|
+
const setHash = discoverySetHash(selectable);
|
|
6206
6242
|
let prev = "";
|
|
6207
6243
|
try {
|
|
6208
6244
|
prev = readFileSync11(SKILLS_DISCOVERED_PATH, "utf-8").trim();
|
|
@@ -6218,7 +6254,6 @@ async function discoverAndIngestSkills() {
|
|
|
6218
6254
|
console.log(" Skipped \u2014 you can ingest skills anytime from the Synkro dashboard or via the MCP tool.");
|
|
6219
6255
|
return;
|
|
6220
6256
|
}
|
|
6221
|
-
const mcpPort = process.env.SYNKRO_MCP_PORT || "18931";
|
|
6222
6257
|
console.log(` Ingesting ${picks.length} skill${picks.length === 1 ? "" : "s"} (security-vetting each first)\u2026`);
|
|
6223
6258
|
const summary = await ingestSkillTasks(picks.map((i) => ({ source: found[i].source, content: found[i].content })), mcpPort);
|
|
6224
6259
|
const parts = [`${summary.ingested} ingested (${summary.rules} rule${summary.rules === 1 ? "" : "s"})`];
|
|
@@ -9043,7 +9078,7 @@ var args = process.argv.slice(2);
|
|
|
9043
9078
|
var cmd = args[0] || "";
|
|
9044
9079
|
var subArgs = args.slice(1);
|
|
9045
9080
|
function printVersion() {
|
|
9046
|
-
console.log("1.7.
|
|
9081
|
+
console.log("1.7.45");
|
|
9047
9082
|
}
|
|
9048
9083
|
function printHelp2() {
|
|
9049
9084
|
console.log(`Synkro CLI \u2014 runtime safety for AI coding agents
|