@inerrata-corporation/errata 2.0.2-dev.165 → 2.0.2-dev.174

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.
@@ -15415,7 +15415,7 @@ var init_canonicalize = __esm({
15415
15415
 
15416
15416
  // ../../packages/shared/src/nlp/triage-canon.ts
15417
15417
  function canonicalizeToken(t) {
15418
- const base = t.trim().toLowerCase().replace(/[@\s].*$/, "");
15418
+ const base = t.trim().toLowerCase().replace(/(?!^)@.*$|\s.*$/, "");
15419
15419
  if (!base) return "";
15420
15420
  return resolveCanonicalId(base) ?? base;
15421
15421
  }
package/errata.mjs CHANGED
@@ -15887,7 +15887,7 @@ var init_canonicalize = __esm({
15887
15887
 
15888
15888
  // ../../packages/shared/src/nlp/triage-canon.ts
15889
15889
  function canonicalizeToken(t) {
15890
- const base = t.trim().toLowerCase().replace(/[@\s].*$/, "");
15890
+ const base = t.trim().toLowerCase().replace(/(?!^)@.*$|\s.*$/, "");
15891
15891
  if (!base) return "";
15892
15892
  return resolveCanonicalId(base) ?? base;
15893
15893
  }
@@ -22203,10 +22203,13 @@ var init_client = __esm({
22203
22203
  }
22204
22204
  /** Pull cloud-induced skills + the session-bootstrap prime payload. `seed` is the
22205
22205
  * canonical ids of the agent's recent problems — the cloud ranks the skills whose
22206
- * motifs those problems match first (the rest are baseline). */
22207
- async getSkills(context = "daemon skill sync", seed) {
22206
+ * motifs those problems match first (the rest are baseline). `techSeed`
22207
+ * (CL-tech-bridge) is the workspace's spine tech ids (`lang:<slug>`, purls)
22208
+ * a secondary relevance signal that also covers the zero-problem cold start. */
22209
+ async getSkills(context = "daemon skill sync", seed, techSeed) {
22208
22210
  const qs = new URLSearchParams({ context });
22209
22211
  if (seed && seed.length > 0) qs.set("seed", seed.join(","));
22212
+ if (techSeed && techSeed.length > 0) qs.set("techSeed", techSeed.join(","));
22210
22213
  if (this.daemonVersion) qs.set("daemonVersion", this.daemonVersion);
22211
22214
  if (this.daemonChannel) qs.set("daemonChannel", this.daemonChannel);
22212
22215
  return this.json("GET", `/v2/skills?${qs.toString()}`);
@@ -50879,11 +50882,17 @@ function isSyncableRoute(edge2, shared, triage, ignorePatterns = []) {
50879
50882
  ].join(" ").toLowerCase();
50880
50883
  return !ignorePatterns.some((p) => blob.includes(p));
50881
50884
  }
50882
- function generalizeRouteForSync(edge2, level) {
50885
+ var isScopedBucket = (bucket) => bucket.startsWith("stack:@");
50886
+ function filterScopedBucketKeys(rec, includeScopedBuckets) {
50887
+ if (includeScopedBuckets) return rec;
50888
+ return Object.fromEntries(Object.entries(rec).filter(([k]) => !isScopedBucket(k)));
50889
+ }
50890
+ function generalizeRouteForSync(edge2, level, includeScopedBuckets = false) {
50883
50891
  const disc = edge2.attrs["discriminator"];
50884
50892
  const local = edge2.attrs["perContext"] ?? {};
50885
50893
  const perContext = {};
50886
50894
  for (const [b, c] of Object.entries(local)) {
50895
+ if (!includeScopedBuckets && isScopedBucket(b)) continue;
50887
50896
  const independent = c.independent ?? c.contributors?.length;
50888
50897
  const inferredIndependent = c.inferredIndependent ?? c.inferredContributors?.length;
50889
50898
  perContext[b] = {
@@ -50944,6 +50953,7 @@ function buildTriageIngest(shared, daemonVersion, ignorePatterns = [], level = 2
50944
50953
  const lang = opts.primaryLanguage?.trim().toLowerCase();
50945
50954
  const fallbackAnchor = lang ? `lang:${lang}` : void 0;
50946
50955
  const tokenAnchors = opts.tokenAnchors ?? {};
50956
+ const includeScopedBuckets = opts.includeScopedBuckets === true;
50947
50957
  const claimOf = (anchor) => anchor ? { anchorVisibility: "public", anchor } : {};
50948
50958
  const nodes = [];
50949
50959
  const edges = [];
@@ -50974,7 +50984,12 @@ function buildTriageIngest(shared, daemonVersion, ignorePatterns = [], level = 2
50974
50984
  embedding: [],
50975
50985
  attrs: {
50976
50986
  ...statement ? { statement: generalize(statement, { level }).text } : {},
50977
- ...tri.attrs["perContextSeen"] ? { perContextSeen: tri.attrs["perContextSeen"] } : {}
50987
+ ...tri.attrs["perContextSeen"] ? {
50988
+ perContextSeen: filterScopedBucketKeys(
50989
+ tri.attrs["perContextSeen"],
50990
+ includeScopedBuckets
50991
+ )
50992
+ } : {}
50978
50993
  },
50979
50994
  ...claimOf(triAnchor ?? fallbackAnchor)
50980
50995
  });
@@ -50988,7 +51003,7 @@ function buildTriageIngest(shared, daemonVersion, ignorePatterns = [], level = 2
50988
51003
  throw new Error(`buildTriageIngest: refusing to sync non-router route ${e.id} \u2014 C7 invariant violated`);
50989
51004
  }
50990
51005
  shareEndpoint(e.to, witnessedAnchor([e], tokenAnchors));
50991
- edges.push(generalizeRouteForSync(e, level));
51006
+ edges.push(generalizeRouteForSync(e, level, includeScopedBuckets));
50992
51007
  }
50993
51008
  }
50994
51009
  if (edges.length === 0) return null;
@@ -51358,8 +51373,8 @@ function readSkillManifest(manifestPath) {
51358
51373
  return [];
51359
51374
  }
51360
51375
  }
51361
- async function syncSkills(paths, client, seed, pins = []) {
51362
- const res = await client.getSkills(void 0, seed);
51376
+ async function syncSkills(paths, client, seed, pins = [], techSeed) {
51377
+ const res = await client.getSkills(void 0, seed, techSeed);
51363
51378
  const staleDaemon = res.staleDaemon && res.latestDaemonVersion ? { latest: res.latestDaemonVersion } : void 0;
51364
51379
  mkdirSync6(paths.skillsDir, { recursive: true });
51365
51380
  if (res.skills.length === 0 && pins.length === 0) {
@@ -52036,7 +52051,7 @@ function startLoopLagMonitor(thresholdMs = 1e3) {
52036
52051
  }
52037
52052
 
52038
52053
  // src/engine.ts
52039
- var DAEMON_VERSION = true ? "2.0.2-dev.165" : "2.0.0-alpha.0";
52054
+ var DAEMON_VERSION = true ? "2.0.2-dev.174" : "2.0.0-alpha.0";
52040
52055
  var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
52041
52056
  var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
52042
52057
  var GIT_OP_MUTE_MS = 4e3;
@@ -53100,7 +53115,20 @@ function createWorkspaceEngine(opts) {
53100
53115
  return typeof cloudId === "string" && cloudId !== p.id ? [p.id, cloudId] : [p.id];
53101
53116
  });
53102
53117
  const pins = profile?.projectId ? await cloud.getSkillPins(profile.projectId).then((r) => r.pins).catch(() => []) : [];
53103
- const result = await syncSkills(paths, cloud, skillSeed, pins);
53118
+ const anchorMap = buildBucketTokenAnchors(
53119
+ profile.languages ?? [],
53120
+ loadConfig().consent.contributePackages ? store.findNodesByLabel("Package").map((p) => ({
53121
+ name: String(p.attrs["name"] ?? ""),
53122
+ purl: String(p.attrs["purl"] ?? p.id)
53123
+ })) : []
53124
+ );
53125
+ const stackTokens = new Set((profile.stack ?? []).map((t) => canonicalizeToken(String(t))).filter(Boolean));
53126
+ const techSeed = [
53127
+ ...new Set(
53128
+ Object.entries(anchorMap).filter(([tok, a]) => a.startsWith("lang:") || stackTokens.has(tok)).map(([, a]) => a)
53129
+ )
53130
+ ].slice(0, 24);
53131
+ const result = await syncSkills(paths, cloud, skillSeed, pins, techSeed);
53104
53132
  try {
53105
53133
  const inputs = emitInputsFromManifest(paths.configDir, paths.skillsManifest);
53106
53134
  emitAndProjectSkills(opts.workspaceRoot, inputs);
@@ -55071,7 +55099,9 @@ async function startMultiDaemon(opts = {}) {
55071
55099
  const tokenAnchors = buildBucketTokenAnchors(languages, packages);
55072
55100
  const payload = buildTriageIngest(sharedStore, DAEMON_VERSION, ignore, 2, {
55073
55101
  ...primaryLanguage ? { primaryLanguage } : {},
55074
- tokenAnchors
55102
+ tokenAnchors,
55103
+ // Scoped bucket keys carry package names — same consent as the purls.
55104
+ includeScopedBuckets: cfg2.consent.contributePackages
55075
55105
  });
55076
55106
  if (!payload) return { uploaded: 0 };
55077
55107
  const res = await cloudNow().ingest(payload);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@inerrata-corporation/errata",
3
- "version": "2.0.2-dev.165",
3
+ "version": "2.0.2-dev.174",
4
4
  "description": "errata - local-first observation engine for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {