@xera-ai/core 0.11.0 → 0.11.2

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
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xera-ai/core",
3
- "version": "0.11.0",
3
+ "version": "0.11.2",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -31,8 +31,8 @@
31
31
  },
32
32
  "dependencies": {
33
33
  "zod": "4.4.3",
34
- "@xera-ai/web": "^0.11.0",
35
- "@xera-ai/http": "^0.11.0",
34
+ "@xera-ai/web": "^0.11.2",
35
+ "@xera-ai/http": "^0.11.2",
36
36
  "@playwright/test": "1.60.0",
37
37
  "dotenv": "^16.0.0",
38
38
  "fflate": "0.8.3",
@@ -1,4 +1,4 @@
1
- import { existsSync, readFileSync } from 'node:fs';
1
+ import { existsSync, readFileSync, unlinkSync } from 'node:fs';
2
2
  import { join } from 'node:path';
3
3
  import { z } from 'zod';
4
4
  import { appendEvents, deriveSnapshot, loadAllEvents } from './store';
@@ -50,6 +50,22 @@ export async function enrichTicket(
50
50
  ticketId: string,
51
51
  opts: EnrichOptions,
52
52
  ): Promise<EnrichResult> {
53
+ // Check the graph snapshot first so a missing ticket surfaces as the
54
+ // actionable "fetch it first" error instead of a confusing
55
+ // "enrichment-input.json not found" — the input file may live under
56
+ // .xera/<CANDIDATE>/, a directory that doesn't exist until the
57
+ // candidate has been fetched.
58
+ const snapshot = deriveSnapshot(loadAllEvents(repoRoot));
59
+ if (!snapshot.tickets[ticketId]) {
60
+ throw new Error(
61
+ `ticket ${ticketId} not in graph; fetch it first with \`/xera-fetch ${ticketId}\``,
62
+ );
63
+ }
64
+
65
+ if (snapshot.tickets[ticketId]!.enrichedAt && !opts.force) {
66
+ return { ticketId, similarCount: 0, enrichedAt: snapshot.tickets[ticketId]!.enrichedAt! };
67
+ }
68
+
53
69
  const inputPath = join(repoRoot, '.xera', ticketId, 'enrichment-input.json');
54
70
  if (!existsSync(inputPath)) {
55
71
  throw new Error(`enrichment-input.json not found at ${inputPath}`);
@@ -61,15 +77,6 @@ export async function enrichTicket(
61
77
  throw new Error(`invalid enrichment-input.json: ${parsed.error.message}`);
62
78
  }
63
79
 
64
- const snapshot = deriveSnapshot(loadAllEvents(repoRoot));
65
- if (!snapshot.tickets[ticketId]) {
66
- throw new Error(`ticket ${ticketId} not in graph; run /xera-fetch first`);
67
- }
68
-
69
- if (snapshot.tickets[ticketId]!.enrichedAt && !opts.force) {
70
- return { ticketId, similarCount: 0, enrichedAt: snapshot.tickets[ticketId]!.enrichedAt! };
71
- }
72
-
73
80
  const validated = parsed.data.similar
74
81
  .map((s) => ({ ...s, confidence: Math.max(0, Math.min(1, s.confidence)) }))
75
82
  .filter((s) => s.confidence >= MIN_CONFIDENCE)
@@ -99,5 +106,13 @@ export async function enrichTicket(
99
106
 
100
107
  appendEvents(repoRoot, events, { skill: 'graph-enrich', ticketId });
101
108
 
109
+ // Consumed — remove so a stale file can't accidentally re-drive enrich
110
+ // on a later invocation outside the /xera-report skill flow.
111
+ try {
112
+ unlinkSync(inputPath);
113
+ } catch {
114
+ // Best-effort cleanup; ignore if already gone.
115
+ }
116
+
102
117
  return { ticketId, similarCount: validated.length, enrichedAt };
103
118
  }