@xera-ai/core 0.4.2 → 0.4.4

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 (35) hide show
  1. package/dist/bin/internal.js +725 -290
  2. package/dist/bin-internal/disputes.d.ts +2 -0
  3. package/dist/bin-internal/disputes.d.ts.map +1 -0
  4. package/dist/bin-internal/doctor.d.ts +1 -1
  5. package/dist/bin-internal/doctor.d.ts.map +1 -1
  6. package/dist/bin-internal/exec.d.ts.map +1 -1
  7. package/dist/bin-internal/graph-record-script.d.ts.map +1 -1
  8. package/dist/bin-internal/graph-render.d.ts +2 -0
  9. package/dist/bin-internal/graph-render.d.ts.map +1 -0
  10. package/dist/bin-internal/index.d.ts.map +1 -1
  11. package/dist/graph/index.d.ts +2 -0
  12. package/dist/graph/index.d.ts.map +1 -1
  13. package/dist/graph/render.d.ts +50 -0
  14. package/dist/graph/render.d.ts.map +1 -0
  15. package/dist/graph/store.d.ts.map +1 -1
  16. package/dist/graph/types.d.ts +1 -0
  17. package/dist/graph/types.d.ts.map +1 -1
  18. package/dist/src/index.js +1 -1
  19. package/package.json +1 -1
  20. package/src/bin-internal/disputes.ts +88 -0
  21. package/src/bin-internal/doctor.ts +13 -1
  22. package/src/bin-internal/exec.ts +3 -0
  23. package/src/bin-internal/graph-record-script.ts +37 -8
  24. package/src/bin-internal/graph-render.ts +70 -0
  25. package/src/bin-internal/index.ts +4 -0
  26. package/src/config/schema.ts +1 -1
  27. package/src/graph/index.ts +2 -0
  28. package/src/graph/render.ts +324 -0
  29. package/src/graph/store.ts +8 -1
  30. package/src/graph/templates/LICENSE-vis-network.txt +176 -0
  31. package/src/graph/templates/graph.css +88 -0
  32. package/src/graph/templates/graph.html.template +31 -0
  33. package/src/graph/templates/graph.js +101 -0
  34. package/src/graph/templates/vis-network.min.js +25000 -0
  35. package/src/graph/types.ts +1 -0
@@ -0,0 +1,2 @@
1
+ export declare function disputesCmd(argv: string[]): Promise<number>;
2
+ //# sourceMappingURL=disputes.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"disputes.d.ts","sourceRoot":"","sources":["../../src/bin-internal/disputes.ts"],"names":[],"mappings":"AAoDA,wBAAsB,WAAW,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAmCjE"}
@@ -1,5 +1,5 @@
1
1
  export interface DoctorOpts {
2
2
  cwd?: string;
3
3
  }
4
- export declare function doctorCmd(_argv: string[], opts?: DoctorOpts): Promise<number>;
4
+ export declare function doctorCmd(argv: string[], opts?: DoctorOpts): Promise<number>;
5
5
  //# sourceMappingURL=doctor.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/bin-internal/doctor.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,UAAU;IACzB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AA8GD,wBAAsB,SAAS,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE,IAAI,GAAE,UAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CAiDvF"}
1
+ {"version":3,"file":"doctor.d.ts","sourceRoot":"","sources":["../../src/bin-internal/doctor.ts"],"names":[],"mappings":"AAOA,MAAM,WAAW,UAAU;IACzB,GAAG,CAAC,EAAE,MAAM,CAAC;CACd;AA8GD,wBAAsB,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,IAAI,GAAE,UAAe,GAAG,OAAO,CAAC,MAAM,CAAC,CA6DtF"}
@@ -1 +1 @@
1
- {"version":3,"file":"exec.d.ts","sourceRoot":"","sources":["../../src/bin-internal/exec.ts"],"names":[],"mappings":"AAWA,wBAAsB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAqH7D"}
1
+ {"version":3,"file":"exec.d.ts","sourceRoot":"","sources":["../../src/bin-internal/exec.ts"],"names":[],"mappings":"AAWA,wBAAsB,OAAO,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAwH7D"}
@@ -1 +1 @@
1
- {"version":3,"file":"graph-record-script.d.ts","sourceRoot":"","sources":["../../src/bin-internal/graph-record-script.ts"],"names":[],"mappings":"AAwGA,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAsFxF"}
1
+ {"version":3,"file":"graph-record-script.d.ts","sourceRoot":"","sources":["../../src/bin-internal/graph-record-script.ts"],"names":[],"mappings":"AAqIA,wBAAsB,gBAAgB,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAsFxF"}
@@ -0,0 +1,2 @@
1
+ export declare function graphRenderCmd(argv: string[]): Promise<number>;
2
+ //# sourceMappingURL=graph-render.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"graph-render.d.ts","sourceRoot":"","sources":["../../src/bin-internal/graph-render.ts"],"names":[],"mappings":"AAkBA,wBAAsB,cAAc,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAmDpE"}
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/bin-internal/index.ts"],"names":[],"mappings":"AAkDA,wBAAsB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAczD"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/bin-internal/index.ts"],"names":[],"mappings":"AAsDA,wBAAsB,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAczD"}
@@ -7,6 +7,8 @@ export { enrichTicket } from './enrich';
7
7
  export type { ImpactEdge, ImpactOpts, ImpactReport, ImpactScenario, } from './impact';
8
8
  export { renderImpactMarkdown, riskScore, walkImpact, } from './impact';
9
9
  export { currentYyyyMm, graphPaths } from './paths';
10
+ export type { GraphStats, RenderHtmlInput, RenderOpts, VisEdge, VisNode } from './render';
11
+ export { renderHtml, transformForVisNetwork } from './render';
10
12
  export { EventSchema, safeParseEvent } from './schema';
11
13
  export { buildSimilarityPrompt } from './similarity';
12
14
  export { appendEvents, computeEventsHash, deriveSnapshot, isSnapshotStale, loadAllEvents, loadSnapshot, writeSnapshot, } from './store';
@@ -1 +1 @@
1
- {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/graph/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,EACb,cAAc,EACd,cAAc,EACd,gBAAgB,GACjB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACnD,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,YAAY,EACV,UAAU,EACV,UAAU,EACV,YAAY,EACZ,cAAc,GACf,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,oBAAoB,EACpB,SAAS,EACT,UAAU,GACX,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AACvD,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EACL,YAAY,EACZ,iBAAiB,EACjB,cAAc,EACd,eAAe,EACf,aAAa,EACb,YAAY,EACZ,aAAa,GACd,MAAM,SAAS,CAAC;AACjB,cAAc,SAAS,CAAC;AACxB,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC"}
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/graph/index.ts"],"names":[],"mappings":"AAAA,YAAY,EACV,iBAAiB,EACjB,gBAAgB,EAChB,aAAa,EACb,cAAc,EACd,cAAc,EACd,gBAAgB,GACjB,MAAM,YAAY,CAAC;AACpB,OAAO,EACL,qBAAqB,EACrB,oBAAoB,GACrB,MAAM,YAAY,CAAC;AACpB,YAAY,EAAE,WAAW,EAAE,UAAU,EAAE,MAAM,QAAQ,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAC;AACnD,YAAY,EAAE,aAAa,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AAC5D,OAAO,EAAE,YAAY,EAAE,MAAM,UAAU,CAAC;AACxC,YAAY,EACV,UAAU,EACV,UAAU,EACV,YAAY,EACZ,cAAc,GACf,MAAM,UAAU,CAAC;AAClB,OAAO,EACL,oBAAoB,EACpB,SAAS,EACT,UAAU,GACX,MAAM,UAAU,CAAC;AAClB,OAAO,EAAE,aAAa,EAAE,UAAU,EAAE,MAAM,SAAS,CAAC;AACpD,YAAY,EAAE,UAAU,EAAE,eAAe,EAAE,UAAU,EAAE,OAAO,EAAE,OAAO,EAAE,MAAM,UAAU,CAAC;AAC1F,OAAO,EAAE,UAAU,EAAE,sBAAsB,EAAE,MAAM,UAAU,CAAC;AAC9D,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,UAAU,CAAC;AACvD,OAAO,EAAE,qBAAqB,EAAE,MAAM,cAAc,CAAC;AACrD,OAAO,EACL,YAAY,EACZ,iBAAiB,EACjB,cAAc,EACd,eAAe,EACf,aAAa,EACb,YAAY,EACZ,aAAa,GACd,MAAM,SAAS,CAAC;AACjB,cAAc,SAAS,CAAC;AACxB,OAAO,EAAE,IAAI,EAAE,MAAM,QAAQ,CAAC"}
@@ -0,0 +1,50 @@
1
+ import type { Snapshot } from './types';
2
+ export interface VisNode {
3
+ id: string;
4
+ label: string;
5
+ group: 'Ticket' | 'Scenario' | 'POM' | 'SUTArea' | 'Failure';
6
+ color?: string;
7
+ shape?: string;
8
+ size?: number;
9
+ title?: string;
10
+ borderWidth?: number;
11
+ }
12
+ export interface VisEdge {
13
+ id?: string;
14
+ from: string;
15
+ to: string;
16
+ label?: string;
17
+ color?: string;
18
+ dashes?: boolean;
19
+ width?: number;
20
+ arrows?: string;
21
+ }
22
+ export interface GraphStats {
23
+ tickets: number;
24
+ scenarios: number;
25
+ poms: number;
26
+ areas: number;
27
+ failures: number;
28
+ edges: number;
29
+ }
30
+ export interface RenderOpts {
31
+ since?: string;
32
+ ticketId?: string;
33
+ depth?: 1 | 2 | 3;
34
+ performanceMode?: 'full' | 'ticket-only' | 'text-fallback';
35
+ }
36
+ export declare function transformForVisNetwork(snap: Snapshot, opts: RenderOpts): {
37
+ nodes: VisNode[];
38
+ edges: VisEdge[];
39
+ stats: GraphStats;
40
+ };
41
+ export interface RenderHtmlInput {
42
+ data: {
43
+ nodes: VisNode[];
44
+ edges: VisEdge[];
45
+ };
46
+ stats: GraphStats;
47
+ generatedAt: string;
48
+ }
49
+ export declare function renderHtml(input: RenderHtmlInput): string;
50
+ //# sourceMappingURL=render.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"render.d.ts","sourceRoot":"","sources":["../../src/graph/render.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAc,QAAQ,EAAE,MAAM,SAAS,CAAC;AAEpD,MAAM,WAAW,OAAO;IACtB,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,EAAE,MAAM,CAAC;IACd,KAAK,EAAE,QAAQ,GAAG,UAAU,GAAG,KAAK,GAAG,SAAS,GAAG,SAAS,CAAC;IAC7D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAED,MAAM,WAAW,OAAO;IACtB,EAAE,CAAC,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,MAAM,CAAC;IACX,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED,MAAM,WAAW,UAAU;IACzB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,MAAM,CAAC;CACf;AAED,MAAM,WAAW,UAAU;IACzB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IAClB,eAAe,CAAC,EAAE,MAAM,GAAG,aAAa,GAAG,eAAe,CAAC;CAC5D;AAmKD,wBAAgB,sBAAsB,CACpC,IAAI,EAAE,QAAQ,EACd,IAAI,EAAE,UAAU,GACf;IACD,KAAK,EAAE,OAAO,EAAE,CAAC;IACjB,KAAK,EAAE,OAAO,EAAE,CAAC;IACjB,KAAK,EAAE,UAAU,CAAC;CACnB,CA4EA;AAcD,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE;QAAE,KAAK,EAAE,OAAO,EAAE,CAAC;QAAC,KAAK,EAAE,OAAO,EAAE,CAAA;KAAE,CAAC;IAC7C,KAAK,EAAE,UAAU,CAAC;IAClB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED,wBAAgB,UAAU,CAAC,KAAK,EAAE,eAAe,GAAG,MAAM,CAgBzD"}
@@ -1 +1 @@
1
- {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/graph/store.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAEV,KAAK,EAIL,QAAQ,EAET,MAAM,SAAS,CAAC;AAGjB,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,IAAI,CAAC;CACZ;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,aAAa,GAAG,MAAM,CAa3F;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,KAAK,EAAE,CAyCvD;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,CAIzD;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,QAAQ,CAgHxD;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,GAAG,IAAI,CAMpE;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAQ9D;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAKzD"}
1
+ {"version":3,"file":"store.d.ts","sourceRoot":"","sources":["../../src/graph/store.ts"],"names":[],"mappings":"AAYA,OAAO,KAAK,EAEV,KAAK,EAIL,QAAQ,EAET,MAAM,SAAS,CAAC;AAGjB,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAC;IACd,QAAQ,EAAE,MAAM,CAAC;IACjB,GAAG,CAAC,EAAE,IAAI,CAAC;CACZ;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,aAAa,GAAG,MAAM,CAa3F;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,GAAG,KAAK,EAAE,CAyCvD;AAED,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,MAAM,CAIzD;AAED,wBAAgB,cAAc,CAAC,MAAM,EAAE,KAAK,EAAE,GAAG,QAAQ,CAuHxD;AAED,wBAAgB,aAAa,CAAC,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,QAAQ,GAAG,IAAI,CAMpE;AAED,wBAAgB,YAAY,CAAC,QAAQ,EAAE,MAAM,GAAG,QAAQ,GAAG,IAAI,CAQ9D;AAED,wBAAgB,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAKzD"}
@@ -127,6 +127,7 @@ export interface FailureNode {
127
127
  runId: string;
128
128
  traceId?: string;
129
129
  ts: string;
130
+ disputed?: boolean;
130
131
  }
131
132
  export interface EdgeRecord {
132
133
  kind: EdgeKind;
@@ -1 +1 @@
1
- {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/graph/types.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/graph/types.ts"],"names":[],"mappings":"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"}
package/dist/src/index.js CHANGED
@@ -327,7 +327,7 @@ var ReportingSchema = z4.object({
327
327
  var RunSchema = z4.object({
328
328
  autoImpact: z4.object({
329
329
  enabled: z4.boolean().default(true),
330
- threshold: z4.number().nonnegative().default(6)
330
+ threshold: z4.number().nonnegative().default(8)
331
331
  }).prefault({})
332
332
  }).prefault({});
333
333
  var XeraConfigSchema = z4.object({
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@xera-ai/core",
3
- "version": "0.4.2",
3
+ "version": "0.4.4",
4
4
  "type": "module",
5
5
  "main": "./dist/index.js",
6
6
  "types": "./dist/index.d.ts",
@@ -0,0 +1,88 @@
1
+ import { loadAllEvents } from '../graph/store';
2
+ import type { ClassificationDisputedPayload, Event } from '../graph/types';
3
+
4
+ function parseDuration(s: string): number {
5
+ // accepts "7d", "30d", "1h", "5m" — returns ms; returns 0 for invalid input
6
+ const match = s.match(/^(\d+)([dhm])$/);
7
+ if (!match) return 0;
8
+ const n = Number.parseInt(match[1]!, 10);
9
+ const unit = match[2]!;
10
+ if (unit === 'd') return n * 86400 * 1000;
11
+ if (unit === 'h') return n * 3600 * 1000;
12
+ if (unit === 'm') return n * 60 * 1000;
13
+ return 0;
14
+ }
15
+
16
+ interface DisputeRow {
17
+ ts: string;
18
+ runId: string;
19
+ scenarioId: string;
20
+ originalClassification: string;
21
+ disputedTo: string;
22
+ qaActor: string;
23
+ qaReason?: string;
24
+ }
25
+
26
+ function eventToRow(e: Event & { type: 'classification.disputed' }): DisputeRow {
27
+ const p = e.payload as ClassificationDisputedPayload;
28
+ const row: DisputeRow = {
29
+ ts: e.ts,
30
+ runId: p.runId,
31
+ scenarioId: p.scenarioId,
32
+ originalClassification: p.originalClassification,
33
+ disputedTo: p.disputedTo,
34
+ qaActor: p.qaActor,
35
+ };
36
+ if (p.qaReason) row.qaReason = p.qaReason;
37
+ return row;
38
+ }
39
+
40
+ function renderText(rows: DisputeRow[]): string {
41
+ if (rows.length === 0) return 'No disputes recorded.\n';
42
+ const lines: string[] = [];
43
+ lines.push(`${rows.length} dispute(s):`);
44
+ for (const r of rows) {
45
+ lines.push(
46
+ ` ${r.ts} | ${r.scenarioId} | ${r.originalClassification} → ${r.disputedTo} | ${r.qaActor}`,
47
+ );
48
+ if (r.qaReason) lines.push(` reason: ${r.qaReason}`);
49
+ }
50
+ return `${lines.join('\n')}\n`;
51
+ }
52
+
53
+ export async function disputesCmd(argv: string[]): Promise<number> {
54
+ let since: string | undefined;
55
+ let format: 'text' | 'json' = 'text';
56
+ for (let i = 0; i < argv.length; i++) {
57
+ if (argv[i] === '--since') {
58
+ since = argv[++i];
59
+ } else if (argv[i] === '--format') {
60
+ const v = argv[++i];
61
+ if (v === 'json' || v === 'text') format = v;
62
+ }
63
+ }
64
+
65
+ const repoRoot = process.cwd();
66
+ const events = loadAllEvents(repoRoot);
67
+ const disputes = events.filter(
68
+ (e): e is Event & { type: 'classification.disputed' } => e.type === 'classification.disputed',
69
+ );
70
+
71
+ let cutoffMs: number | undefined;
72
+ if (since) {
73
+ const sinceMs = parseDuration(since);
74
+ if (sinceMs > 0) cutoffMs = Date.now() - sinceMs;
75
+ }
76
+
77
+ const rows = disputes
78
+ .filter((e) => cutoffMs === undefined || Date.parse(e.ts) >= cutoffMs)
79
+ .map(eventToRow)
80
+ .sort((a, b) => (a.ts < b.ts ? 1 : -1));
81
+
82
+ if (format === 'json') {
83
+ process.stdout.write(JSON.stringify(rows, null, 2));
84
+ } else {
85
+ process.stdout.write(renderText(rows));
86
+ }
87
+ return 0;
88
+ }
@@ -117,8 +117,9 @@ function checkRootScripts(repoRoot: string): CheckResult[] {
117
117
  return missing.map((s) => ({ ok: false, message: `root package.json missing script: ${s}` }));
118
118
  }
119
119
 
120
- export async function doctorCmd(_argv: string[], opts: DoctorOpts = {}): Promise<number> {
120
+ export async function doctorCmd(argv: string[], opts: DoctorOpts = {}): Promise<number> {
121
121
  const repoRoot = opts.cwd ?? process.cwd();
122
+ const autoEnrich = argv.includes('--auto-enrich');
122
123
  const results: CheckResult[] = [
123
124
  ...checkGoldenEvalDir(repoRoot),
124
125
  ...checkRubricPrompt(repoRoot),
@@ -156,6 +157,17 @@ export async function doctorCmd(_argv: string[], opts: DoctorOpts = {}): Promise
156
157
  console.log(` These won't participate in v0.6.1+ features (TEST_OUTDATED, /xera-impact).`);
157
158
  console.log(` Run: bun run xera:graph-backfill`);
158
159
  console.log(` (Use --dry-run to preview.)`);
160
+ if (autoEnrich) {
161
+ console.log('[doctor] --auto-enrich: running backfill for unbackfilled tickets...');
162
+ // Lazy import to avoid circular deps
163
+ const { graphBackfillCmd } = await import('./graph-backfill');
164
+ const exitCode = await graphBackfillCmd([]);
165
+ if (exitCode === 0) {
166
+ console.log(`[doctor] auto-enrich: backfilled ${unbackfilled.length} tickets`);
167
+ } else {
168
+ console.error('[doctor] auto-enrich: backfill failed');
169
+ }
170
+ }
159
171
  }
160
172
  }
161
173
  }
@@ -15,6 +15,8 @@ export async function execCmd(argv: string[]): Promise<number> {
15
15
  console.error('[xera:exec] usage: exec <TICKET>');
16
16
  return 1;
17
17
  }
18
+ const grepIdx = argv.indexOf('--grep');
19
+ const grep = grepIdx > -1 ? argv[grepIdx + 1] : undefined;
18
20
  const cwd = process.cwd();
19
21
  const config = await loadConfig(cwd);
20
22
  const paths = resolveArtifactPaths(cwd, ticket);
@@ -117,6 +119,7 @@ export async function execCmd(argv: string[]): Promise<number> {
117
119
  // path to read.
118
120
  PLAYWRIGHT_JSON_OUTPUT_NAME: reportJsonPath,
119
121
  },
122
+ ...(grep && { grep }),
120
123
  });
121
124
  log.log({ step: 'exec.done', runId, exit: r.exitCode, ms: Date.now() - t0 });
122
125
 
@@ -30,18 +30,49 @@ const mk = <T extends Event['type']>(
30
30
  payload,
31
31
  }) as Event;
32
32
 
33
+ const P0_KEYWORDS = [
34
+ 'log in',
35
+ 'login',
36
+ 'sign in',
37
+ 'signin',
38
+ 'sign up',
39
+ 'signup',
40
+ 'auth',
41
+ 'authentic',
42
+ 'payment',
43
+ 'pay ',
44
+ 'checkout',
45
+ 'purchase',
46
+ 'charge',
47
+ 'password',
48
+ 'credential',
49
+ 'admin',
50
+ 'permission',
51
+ 'role',
52
+ 'must ',
53
+ 'critical',
54
+ ];
55
+
56
+ function inferPriority(name: string, gherkin: string): 'p0' | 'p1' {
57
+ const haystack = `${name} ${gherkin}`.toLowerCase();
58
+ for (const kw of P0_KEYWORDS) {
59
+ if (haystack.includes(kw)) return 'p0';
60
+ }
61
+ return 'p1';
62
+ }
63
+
33
64
  function parseFeature(
34
65
  text: string,
35
66
  ): Array<{ name: string; priority: 'p0' | 'p1' | 'p2'; gherkin: string }> {
36
67
  const scenarios: Array<{ name: string; priority: 'p0' | 'p1' | 'p2'; gherkin: string }> = [];
37
68
  const lines = text.split('\n');
38
- let currentTagPriority: 'p0' | 'p1' | 'p2' = 'p1';
69
+ let explicitTag: 'p0' | 'p1' | 'p2' | null = null;
39
70
  let i = 0;
40
71
  while (i < lines.length) {
41
72
  const line = lines[i]!.trim();
42
73
  if (line.startsWith('@')) {
43
74
  const tag = line.slice(1).split(/\s+/)[0]!.toLowerCase();
44
- if (tag === 'p0' || tag === 'p1' || tag === 'p2') currentTagPriority = tag;
75
+ if (tag === 'p0' || tag === 'p1' || tag === 'p2') explicitTag = tag;
45
76
  i++;
46
77
  continue;
47
78
  }
@@ -55,12 +86,10 @@ function parseFeature(
55
86
  !lines[i]!.trim().startsWith('@')
56
87
  )
57
88
  i++;
58
- scenarios.push({
59
- name,
60
- priority: currentTagPriority,
61
- gherkin: lines.slice(start, i).join('\n'),
62
- });
63
- currentTagPriority = 'p1';
89
+ const gherkin = lines.slice(start, i).join('\n');
90
+ const priority = explicitTag !== null ? explicitTag : inferPriority(name, gherkin);
91
+ scenarios.push({ name, priority, gherkin });
92
+ explicitTag = null;
64
93
  continue;
65
94
  }
66
95
  i++;
@@ -0,0 +1,70 @@
1
+ import { mkdirSync, renameSync, writeFileSync } from 'node:fs';
2
+ import { dirname, join } from 'node:path';
3
+ import type { RenderOpts } from '../graph/render';
4
+ import { renderHtml, transformForVisNetwork } from '../graph/render';
5
+ import { deriveSnapshot, loadAllEvents } from '../graph/store';
6
+
7
+ function parseDepth(s: string | undefined): 1 | 2 | 3 {
8
+ const n = s ? Number.parseInt(s, 10) : 2;
9
+ if (n === 1 || n === 3) return n;
10
+ return 2;
11
+ }
12
+
13
+ function decidePerformanceMode(nodeCount: number): 'full' | 'ticket-only' | 'text-fallback' {
14
+ if (nodeCount > 2000) return 'text-fallback';
15
+ if (nodeCount > 500) return 'ticket-only';
16
+ return 'full';
17
+ }
18
+
19
+ export async function graphRenderCmd(argv: string[]): Promise<number> {
20
+ let outPath: string | undefined;
21
+ let ticketId: string | undefined;
22
+ let since: string | undefined;
23
+ let depth: 1 | 2 | 3 = 2;
24
+
25
+ for (let i = 0; i < argv.length; i++) {
26
+ if (argv[i] === '--out') outPath = argv[++i];
27
+ else if (argv[i] === '--ticket') ticketId = argv[++i];
28
+ else if (argv[i] === '--since') since = argv[++i];
29
+ else if (argv[i] === '--depth') depth = parseDepth(argv[++i]);
30
+ }
31
+
32
+ const repoRoot = process.cwd();
33
+ const finalPath = outPath ?? join(repoRoot, '.xera/graph.html');
34
+
35
+ const snap = deriveSnapshot(loadAllEvents(repoRoot));
36
+ const totalNodeCount =
37
+ Object.keys(snap.tickets).length +
38
+ Object.keys(snap.scenarios).length +
39
+ Object.keys(snap.poms).length +
40
+ Object.keys(snap.areas).length;
41
+ const performanceMode = decidePerformanceMode(totalNodeCount);
42
+
43
+ if (performanceMode === 'text-fallback') {
44
+ const txtPath = finalPath.replace(/\.html$/, '.txt');
45
+ mkdirSync(dirname(txtPath), { recursive: true });
46
+ writeFileSync(
47
+ txtPath,
48
+ `Graph too large for HTML viewer (${totalNodeCount} nodes). Use 'xera:graph-query --format text' instead.\n`,
49
+ );
50
+ console.log(`[graph-render] graph too large (${totalNodeCount} nodes); wrote ${txtPath}`);
51
+ return 0;
52
+ }
53
+
54
+ const opts: RenderOpts = { depth, performanceMode };
55
+ if (ticketId) opts.ticketId = ticketId;
56
+ if (since) opts.since = since;
57
+
58
+ const data = transformForVisNetwork(snap, opts);
59
+ const html = renderHtml({ data, stats: data.stats, generatedAt: new Date().toISOString() });
60
+
61
+ mkdirSync(dirname(finalPath), { recursive: true });
62
+ const tmpPath = `${finalPath}.tmp`;
63
+ writeFileSync(tmpPath, html);
64
+ renameSync(tmpPath, finalPath);
65
+
66
+ console.log(
67
+ `[graph-render] wrote ${finalPath} (${data.stats.tickets} tickets · ${data.stats.scenarios} scenarios · ${html.length} bytes)`,
68
+ );
69
+ return 0;
70
+ }
@@ -1,3 +1,4 @@
1
+ import { disputesCmd } from './disputes';
1
2
  import { doctorCmd } from './doctor';
2
3
  import { evalDeterministicCmd } from './eval-deterministic';
3
4
  import { evalPrepareCmd } from './eval-prepare';
@@ -8,6 +9,7 @@ import { graphBackfillCmd } from './graph-backfill';
8
9
  import { graphEnrichCmd } from './graph-enrich';
9
10
  import { graphQueryCmd } from './graph-query';
10
11
  import { graphRecordCmd } from './graph-record';
12
+ import { graphRenderCmd } from './graph-render';
11
13
  import { graphSnapshotCmd } from './graph-snapshot';
12
14
  import { healPrepareCmd } from './heal-prepare';
13
15
  import { impactPrepareCmd } from './impact-prepare';
@@ -23,6 +25,7 @@ import { validateFeatureCmd } from './validate-feature';
23
25
  import { verifyPromptsCmd } from './verify-prompts';
24
26
 
25
27
  const COMMANDS: Record<string, (argv: string[]) => Promise<number>> = {
28
+ disputes: disputesCmd,
26
29
  doctor: doctorCmd,
27
30
  'eval-deterministic': evalDeterministicCmd,
28
31
  'eval-prepare': evalPrepareCmd,
@@ -31,6 +34,7 @@ const COMMANDS: Record<string, (argv: string[]) => Promise<number>> = {
31
34
  fetch: fetchCmd,
32
35
  'graph-backfill': graphBackfillCmd,
33
36
  'graph-enrich': graphEnrichCmd,
37
+ 'graph-render': graphRenderCmd,
34
38
  'graph-query': graphQueryCmd,
35
39
  'graph-record': graphRecordCmd,
36
40
  'graph-snapshot': graphSnapshotCmd,
@@ -74,7 +74,7 @@ const RunSchema = z
74
74
  autoImpact: z
75
75
  .object({
76
76
  enabled: z.boolean().default(true),
77
- threshold: z.number().nonnegative().default(6.0),
77
+ threshold: z.number().nonnegative().default(8.0),
78
78
  })
79
79
  .prefault({}),
80
80
  })
@@ -26,6 +26,8 @@ export {
26
26
  walkImpact,
27
27
  } from './impact';
28
28
  export { currentYyyyMm, graphPaths } from './paths';
29
+ export type { GraphStats, RenderHtmlInput, RenderOpts, VisEdge, VisNode } from './render';
30
+ export { renderHtml, transformForVisNetwork } from './render';
29
31
  export { EventSchema, safeParseEvent } from './schema';
30
32
  export { buildSimilarityPrompt } from './similarity';
31
33
  export {