@synkro-sh/cli 1.7.44 → 1.7.46

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 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.44")}`
4829
+ `SYNKRO_VERSION=${shellQuoteSingle("1.7.46")}`
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 discoverSkillFiles(repoRoot, excludeHashes, excludeNames) {
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 {
@@ -6135,9 +6138,10 @@ function discoverSkillFiles(repoRoot, excludeHashes, excludeNames) {
6135
6138
  }
6136
6139
  if (!content.trim()) return;
6137
6140
  const hash = createHash("sha256").update(content).digest("hex");
6138
- if (seen.has(hash) || excludeHashes.has(hash) || excludeNames?.has(name.toLowerCase())) return;
6141
+ if (seen.has(hash) || excludeHashes.has(hash)) return;
6139
6142
  seen.add(hash);
6140
- out.push({ source: `skill:${name}`, content, name, hash });
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 into Synkro as enforceable rules? Each is security-vetted first \u2014 anything");
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("Ingest [all] / type numbers (e.g. 1,3) / [skip]: ")).toLowerCase();
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 found.map((_, i) => i);
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
- return [...new Set(picks)];
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
  }
@@ -6201,21 +6215,30 @@ async function discoverAndIngestSkills() {
6201
6215
  }
6202
6216
  }
6203
6217
  }
6204
- const excludeNames = /* @__PURE__ */ new Set();
6218
+ const ingestedHashes = /* @__PURE__ */ new Set();
6219
+ const ingestedNames = /* @__PURE__ */ new Set();
6205
6220
  try {
6206
6221
  const resp = await fetch(`http://127.0.0.1:${mcpPort}/api/local/skills?status=active`, { signal: AbortSignal.timeout(5e3) });
6207
6222
  if (resp.ok) {
6208
6223
  const { skills } = await resp.json();
6209
6224
  for (const s of skills || []) {
6210
- if (s.content_hash) excludeHashes.add(s.content_hash);
6211
- else if (s.name) excludeNames.add(String(s.name).toLowerCase());
6225
+ if (s.content_hash) ingestedHashes.add(s.content_hash);
6226
+ if (s.name) ingestedNames.add(normSkillName(String(s.name)));
6212
6227
  }
6213
6228
  }
6214
6229
  } catch {
6215
6230
  }
6216
- const found = discoverSkillFiles(repoRoot, excludeHashes, excludeNames);
6231
+ const found = discoverSkillFiles(repoRoot, excludeHashes, ingestedHashes, ingestedNames);
6217
6232
  if (found.length === 0) return;
6218
- const setHash = discoverySetHash(found);
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);
6219
6242
  let prev = "";
6220
6243
  try {
6221
6244
  prev = readFileSync11(SKILLS_DISCOVERED_PATH, "utf-8").trim();
@@ -9055,7 +9078,7 @@ var args = process.argv.slice(2);
9055
9078
  var cmd = args[0] || "";
9056
9079
  var subArgs = args.slice(1);
9057
9080
  function printVersion() {
9058
- console.log("1.7.44");
9081
+ console.log("1.7.46");
9059
9082
  }
9060
9083
  function printHelp2() {
9061
9084
  console.log(`Synkro CLI \u2014 runtime safety for AI coding agents