@xera-ai/core 0.11.1 → 0.11.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.
@@ -10910,7 +10910,7 @@ init_graph_backfill();
10910
10910
  // src/graph/enrich.ts
10911
10911
  init_store();
10912
10912
  init_ulid();
10913
- import { existsSync as existsSync22, readFileSync as readFileSync19 } from "fs";
10913
+ import { existsSync as existsSync22, readFileSync as readFileSync19, unlinkSync as unlinkSync2 } from "fs";
10914
10914
  import { join as join21 } from "path";
10915
10915
  import { z as z8 } from "zod";
10916
10916
  var MAX_SIMILAR_EDGES = 10;
@@ -10933,6 +10933,13 @@ var mk2 = (actor, type, payload) => ({
10933
10933
  payload
10934
10934
  });
10935
10935
  async function enrichTicket(repoRoot, ticketId, opts) {
10936
+ const snapshot = deriveSnapshot(loadAllEvents(repoRoot));
10937
+ if (!snapshot.tickets[ticketId]) {
10938
+ throw new Error(`ticket ${ticketId} not in graph; fetch it first with \`/xera-fetch ${ticketId}\``);
10939
+ }
10940
+ if (snapshot.tickets[ticketId].enrichedAt && !opts.force) {
10941
+ return { ticketId, similarCount: 0, enrichedAt: snapshot.tickets[ticketId].enrichedAt };
10942
+ }
10936
10943
  const inputPath = join21(repoRoot, ".xera", ticketId, "enrichment-input.json");
10937
10944
  if (!existsSync22(inputPath)) {
10938
10945
  throw new Error(`enrichment-input.json not found at ${inputPath}`);
@@ -10942,13 +10949,6 @@ async function enrichTicket(repoRoot, ticketId, opts) {
10942
10949
  if (!parsed.success) {
10943
10950
  throw new Error(`invalid enrichment-input.json: ${parsed.error.message}`);
10944
10951
  }
10945
- const snapshot = deriveSnapshot(loadAllEvents(repoRoot));
10946
- if (!snapshot.tickets[ticketId]) {
10947
- throw new Error(`ticket ${ticketId} not in graph; run /xera-fetch first`);
10948
- }
10949
- if (snapshot.tickets[ticketId].enrichedAt && !opts.force) {
10950
- return { ticketId, similarCount: 0, enrichedAt: snapshot.tickets[ticketId].enrichedAt };
10951
- }
10952
10952
  const validated = parsed.data.similar.map((s) => ({ ...s, confidence: Math.max(0, Math.min(1, s.confidence)) })).filter((s) => s.confidence >= MIN_CONFIDENCE).filter((s) => snapshot.tickets[s.ticketId] !== undefined).filter((s) => s.ticketId !== ticketId).slice(0, MAX_SIMILAR_EDGES);
10953
10953
  const events = [];
10954
10954
  for (const s of validated) {
@@ -10969,6 +10969,9 @@ async function enrichTicket(repoRoot, ticketId, opts) {
10969
10969
  };
10970
10970
  events.push(mk2("graph-enrich", "ticket.enriched", enrichedPayload));
10971
10971
  appendEvents(repoRoot, events, { skill: "graph-enrich", ticketId });
10972
+ try {
10973
+ unlinkSync2(inputPath);
10974
+ } catch {}
10972
10975
  return { ticketId, similarCount: validated.length, enrichedAt };
10973
10976
  }
10974
10977
 
@@ -11287,7 +11290,7 @@ function renderHtml(input) {
11287
11290
  const coverageTabButton = input.coverage ? '<button data-tab="coverage">Coverage</button>' : "";
11288
11291
  const coverageTabPanel = input.coverage ? loadTemplate("coverage-panel.html.fragment") : "";
11289
11292
  const coverageJson = input.coverage ? JSON.stringify(input.coverage) : "null";
11290
- return template.replace("{{CSS}}", () => css).replace("{{STATS}}", () => statsHuman).replace("{{GENERATED_AT}}", () => input.generatedAt).replace("{{VIS_NETWORK_JS}}", () => visNetwork).replace("{{GRAPH_DATA}}", () => graphJson).replace("{{INTERACTION_JS}}", () => js).replace("{{COVERAGE_TAB_BUTTON}}", () => coverageTabButton).replace("{{COVERAGE_TAB_PANEL}}", () => coverageTabPanel).replace("{{COVERAGE_DATA}}", () => coverageJson);
11293
+ return template.replace("{{CSS}}", () => css).replace("{{STATS}}", () => statsHuman).replace(/\{\{GENERATED_AT\}\}/g, () => input.generatedAt).replace("{{VIS_NETWORK_JS}}", () => visNetwork).replace("{{GRAPH_DATA}}", () => graphJson).replace("{{INTERACTION_JS}}", () => js).replace("{{COVERAGE_TAB_BUTTON}}", () => coverageTabButton).replace("{{COVERAGE_TAB_PANEL}}", () => coverageTabPanel).replace("{{COVERAGE_DATA}}", () => coverageJson);
11291
11294
  }
11292
11295
 
11293
11296
  // src/bin-internal/graph-render.ts
@@ -5,7 +5,6 @@
5
5
  <button data-subtab="trend">Trend</button>
6
6
  </nav>
7
7
  <div data-subpanel="map" class="active">
8
- <p class="subpanel-hint">Area nodes are colored by status. Red = UNCOVERED, amber = STALE, green = COVERED. Other nodes neutral.</p>
9
8
  <main id="coverage-map-canvas"></main>
10
9
  </div>
11
10
  <div data-subpanel="list" hidden>
@@ -17,4 +16,14 @@
17
16
  <p class="subpanel-hint">UNCOVERED + STALE area count over time (one point per day, latest snapshot wins).</p>
18
17
  <div id="coverage-trend-svg"></div>
19
18
  </div>
19
+ <aside id="cov-drawer" class="cov-drawer hidden" aria-hidden="true">
20
+ <header class="cov-drawer-head">
21
+ <div class="cov-drawer-head-text">
22
+ <span id="cov-drawer-status" class="cov-drawer-status"></span>
23
+ <h3 id="cov-drawer-title"></h3>
24
+ </div>
25
+ <button id="cov-drawer-close" aria-label="Close" type="button">&times;</button>
26
+ </header>
27
+ <div class="cov-drawer-body" id="cov-drawer-body"></div>
28
+ </aside>
20
29
  </section>