@inerrata-corporation/errata 2.0.2-dev.161 → 2.0.2-dev.169

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 (2) hide show
  1. package/errata.mjs +79 -14
  2. package/package.json +1 -1
package/errata.mjs CHANGED
@@ -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()}`);
@@ -50904,13 +50907,51 @@ function generalizeRouteForSync(edge2, level) {
50904
50907
  navFailures: 0
50905
50908
  };
50906
50909
  }
50910
+ function buildBucketTokenAnchors(languages, packages = []) {
50911
+ const anchors = {};
50912
+ const langTokens = /* @__PURE__ */ new Set();
50913
+ for (const l of languages) {
50914
+ const t = canonicalizeToken(String(l));
50915
+ if (!t || t.includes(":") && !t.startsWith("lang:")) continue;
50916
+ langTokens.add(t);
50917
+ anchors[t] = t.startsWith("lang:") ? t : `lang:${t}`;
50918
+ }
50919
+ const versionless = (purl) => purl.replace(/@[^/@]+$/, "");
50920
+ const conflicted = /* @__PURE__ */ new Set();
50921
+ for (const p of packages) {
50922
+ const t = canonicalizeToken(p.name);
50923
+ if (!t || !p.purl || langTokens.has(t) || conflicted.has(t)) continue;
50924
+ const existing = anchors[t];
50925
+ if (existing === void 0) {
50926
+ anchors[t] = p.purl;
50927
+ } else if (versionless(existing) !== versionless(p.purl)) {
50928
+ delete anchors[t];
50929
+ conflicted.add(t);
50930
+ }
50931
+ }
50932
+ return anchors;
50933
+ }
50934
+ function witnessedAnchor(routes, tokenAnchors) {
50935
+ const weight = /* @__PURE__ */ new Map();
50936
+ for (const e of routes) {
50937
+ const perContext = e.attrs["perContext"] ?? {};
50938
+ for (const [bucket, c] of Object.entries(perContext)) {
50939
+ if (!bucket.startsWith("stack:") || !c || !(c.confirmed > 0)) continue;
50940
+ const anchor = tokenAnchors[bucket.slice("stack:".length)];
50941
+ if (anchor) weight.set(anchor, (weight.get(anchor) ?? 0) + c.confirmed);
50942
+ }
50943
+ }
50944
+ return [...weight.entries()].sort((a, b) => b[1] - a[1] || (a[0] < b[0] ? -1 : 1))[0]?.[0];
50945
+ }
50907
50946
  function buildTriageIngest(shared, daemonVersion, ignorePatterns = [], level = 2, opts = {}) {
50908
50947
  const lang = opts.primaryLanguage?.trim().toLowerCase();
50909
- const claim = lang ? { anchorVisibility: "public", anchor: `lang:${lang}` } : {};
50948
+ const fallbackAnchor = lang ? `lang:${lang}` : void 0;
50949
+ const tokenAnchors = opts.tokenAnchors ?? {};
50950
+ const claimOf = (anchor) => anchor ? { anchorVisibility: "public", anchor } : {};
50910
50951
  const nodes = [];
50911
50952
  const edges = [];
50912
50953
  const seenIds = /* @__PURE__ */ new Set();
50913
- const shareEndpoint = (id) => {
50954
+ const shareEndpoint = (id, anchor) => {
50914
50955
  if (seenIds.has(id)) return;
50915
50956
  const n = shared.getNode(id);
50916
50957
  if (!n) return;
@@ -50920,12 +50961,13 @@ function buildTriageIngest(shared, daemonVersion, ignorePatterns = [], level = 2
50920
50961
  description: generalize(n.description, { level }).text,
50921
50962
  embedding: [],
50922
50963
  attrs: { scope: {} },
50923
- ...claim
50964
+ ...claimOf(anchor ?? fallbackAnchor)
50924
50965
  });
50925
50966
  };
50926
50967
  for (const tri of shared.findNodesByLabel("Triage")) {
50927
50968
  const routes = shared.outEdges(tri.id, ["CONFIRMS", "INDICATES", "ROUTES_TO"]).filter((e) => isSyncableRoute(e, shared, tri, ignorePatterns));
50928
50969
  if (routes.length === 0) continue;
50970
+ const triAnchor = witnessedAnchor(routes, tokenAnchors);
50929
50971
  if (!seenIds.has(tri.id)) {
50930
50972
  seenIds.add(tri.id);
50931
50973
  const statement = String(tri.attrs["statement"] ?? "");
@@ -50937,18 +50979,18 @@ function buildTriageIngest(shared, daemonVersion, ignorePatterns = [], level = 2
50937
50979
  ...statement ? { statement: generalize(statement, { level }).text } : {},
50938
50980
  ...tri.attrs["perContextSeen"] ? { perContextSeen: tri.attrs["perContextSeen"] } : {}
50939
50981
  },
50940
- ...claim
50982
+ ...claimOf(triAnchor ?? fallbackAnchor)
50941
50983
  });
50942
50984
  }
50943
50985
  for (const tb of shared.inEdges(tri.id, ["TRIAGED_BY"])) {
50944
- shareEndpoint(tb.from);
50986
+ shareEndpoint(tb.from, triAnchor);
50945
50987
  edges.push({ ...tb, navSuccesses: 0, navFailures: 0 });
50946
50988
  }
50947
50989
  for (const e of routes) {
50948
50990
  if (!(e.type === "CONFIRMS" || e.type === "ROUTES_TO" && e.attrs["provisional"] === false)) {
50949
50991
  throw new Error(`buildTriageIngest: refusing to sync non-router route ${e.id} \u2014 C7 invariant violated`);
50950
50992
  }
50951
- shareEndpoint(e.to);
50993
+ shareEndpoint(e.to, witnessedAnchor([e], tokenAnchors));
50952
50994
  edges.push(generalizeRouteForSync(e, level));
50953
50995
  }
50954
50996
  }
@@ -51319,8 +51361,8 @@ function readSkillManifest(manifestPath) {
51319
51361
  return [];
51320
51362
  }
51321
51363
  }
51322
- async function syncSkills(paths, client, seed, pins = []) {
51323
- const res = await client.getSkills(void 0, seed);
51364
+ async function syncSkills(paths, client, seed, pins = [], techSeed) {
51365
+ const res = await client.getSkills(void 0, seed, techSeed);
51324
51366
  const staleDaemon = res.staleDaemon && res.latestDaemonVersion ? { latest: res.latestDaemonVersion } : void 0;
51325
51367
  mkdirSync6(paths.skillsDir, { recursive: true });
51326
51368
  if (res.skills.length === 0 && pins.length === 0) {
@@ -51997,7 +52039,7 @@ function startLoopLagMonitor(thresholdMs = 1e3) {
51997
52039
  }
51998
52040
 
51999
52041
  // src/engine.ts
52000
- var DAEMON_VERSION = true ? "2.0.2-dev.161" : "2.0.0-alpha.0";
52042
+ var DAEMON_VERSION = true ? "2.0.2-dev.169" : "2.0.0-alpha.0";
52001
52043
  var IGNORED_PATH = /[\\/](?:\.git|node_modules|\.errata|\.claude|\.codex|\.cursor|\.turbo|\.next|dist|coverage|test-results|playwright-report|__pycache__)(?:[\\/]|$)/;
52002
52044
  var IGNORED_NOISE = /castalia\.db|eventlog\.sqlite|turn-cursors/;
52003
52045
  var GIT_OP_MUTE_MS = 4e3;
@@ -53061,7 +53103,20 @@ function createWorkspaceEngine(opts) {
53061
53103
  return typeof cloudId === "string" && cloudId !== p.id ? [p.id, cloudId] : [p.id];
53062
53104
  });
53063
53105
  const pins = profile?.projectId ? await cloud.getSkillPins(profile.projectId).then((r) => r.pins).catch(() => []) : [];
53064
- const result = await syncSkills(paths, cloud, skillSeed, pins);
53106
+ const anchorMap = buildBucketTokenAnchors(
53107
+ profile.languages ?? [],
53108
+ loadConfig().consent.contributePackages ? store.findNodesByLabel("Package").map((p) => ({
53109
+ name: String(p.attrs["name"] ?? ""),
53110
+ purl: String(p.attrs["purl"] ?? p.id)
53111
+ })) : []
53112
+ );
53113
+ const stackTokens = new Set((profile.stack ?? []).map((t) => canonicalizeToken(String(t))).filter(Boolean));
53114
+ const techSeed = [
53115
+ ...new Set(
53116
+ Object.entries(anchorMap).filter(([tok, a]) => a.startsWith("lang:") || stackTokens.has(tok)).map(([, a]) => a)
53117
+ )
53118
+ ].slice(0, 24);
53119
+ const result = await syncSkills(paths, cloud, skillSeed, pins, techSeed);
53065
53120
  try {
53066
53121
  const inputs = emitInputsFromManifest(paths.configDir, paths.skillsManifest);
53067
53122
  emitAndProjectSkills(opts.workspaceRoot, inputs);
@@ -55018,11 +55073,21 @@ async function startMultiDaemon(opts = {}) {
55018
55073
  return { uploaded: res.accepted };
55019
55074
  },
55020
55075
  async syncTriagePublic() {
55021
- if (!loadConfig().consent.sync) return { uploaded: 0, skipped: "consent-off" };
55076
+ const cfg2 = loadConfig();
55077
+ if (!cfg2.consent.sync) return { uploaded: 0, skipped: "consent-off" };
55022
55078
  const ignore = loadClaimIgnorePatterns(globalDir());
55023
55079
  const primaryLanguage = machineDominantLanguage();
55080
+ const languages = records.flatMap((r) => r.engine.profile.languages ?? []);
55081
+ const packages = cfg2.consent.contributePackages ? records.flatMap(
55082
+ (r) => r.engine.store.findNodesByLabel("Package").map((p) => ({
55083
+ name: String(p.attrs["name"] ?? ""),
55084
+ purl: String(p.attrs["purl"] ?? p.id)
55085
+ }))
55086
+ ) : [];
55087
+ const tokenAnchors = buildBucketTokenAnchors(languages, packages);
55024
55088
  const payload = buildTriageIngest(sharedStore, DAEMON_VERSION, ignore, 2, {
55025
- ...primaryLanguage ? { primaryLanguage } : {}
55089
+ ...primaryLanguage ? { primaryLanguage } : {},
55090
+ tokenAnchors
55026
55091
  });
55027
55092
  if (!payload) return { uploaded: 0 };
55028
55093
  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.161",
3
+ "version": "2.0.2-dev.169",
4
4
  "description": "errata - local-first observation engine for AI coding agents",
5
5
  "type": "module",
6
6
  "bin": {