@xera-ai/core 0.9.2 → 0.9.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.
- package/dist/bin/internal.js +118 -98
- package/dist/bin/templates/LICENSE-vis-network.txt +176 -0
- package/dist/bin/templates/graph.css +88 -0
- package/dist/bin/templates/graph.html.template +31 -0
- package/dist/bin/templates/graph.js +101 -0
- package/dist/bin/templates/vis-network.min.js +25000 -0
- package/dist/src/index.js +44 -36
- package/package.json +4 -4
- package/src/bin-internal/graph-backfill.ts +2 -2
- package/src/bin-internal/graph-record-script.ts +11 -3
- package/src/bin-internal/graph-record.ts +12 -10
package/dist/bin/internal.js
CHANGED
|
@@ -513,9 +513,9 @@ function extractPomUsage(specContent) {
|
|
|
513
513
|
}
|
|
514
514
|
async function recordScriptImpl(repoRoot, ticket) {
|
|
515
515
|
const ticketDir = join5(repoRoot, ".xera", ticket);
|
|
516
|
-
const featurePath = join5(ticketDir, "feature", `${ticket}.feature`);
|
|
517
|
-
const specPath = join5(ticketDir, "tests", `${ticket}.spec.ts`);
|
|
518
|
-
const pomDir = join5(ticketDir, "poms");
|
|
516
|
+
const featurePath = existsSync6(join5(ticketDir, "test.feature")) ? join5(ticketDir, "test.feature") : join5(ticketDir, "feature", `${ticket}.feature`);
|
|
517
|
+
const specPath = existsSync6(join5(ticketDir, "spec.ts")) ? join5(ticketDir, "spec.ts") : join5(ticketDir, "tests", `${ticket}.spec.ts`);
|
|
518
|
+
const pomDir = existsSync6(join5(ticketDir, "page-objects")) ? join5(ticketDir, "page-objects") : join5(ticketDir, "poms");
|
|
519
519
|
if (!existsSync6(featurePath)) {
|
|
520
520
|
console.error(`[graph-record script] feature missing`);
|
|
521
521
|
return 1;
|
|
@@ -7612,6 +7612,46 @@ var init_dist = __esm(() => {
|
|
|
7612
7612
|
$visitAsync = visit.visitAsync;
|
|
7613
7613
|
});
|
|
7614
7614
|
|
|
7615
|
+
// src/artifact/paths.ts
|
|
7616
|
+
import { join as join6 } from "path";
|
|
7617
|
+
function resolveArtifactPaths(repoRoot, ticket) {
|
|
7618
|
+
if (!TICKET_RE.test(ticket)) {
|
|
7619
|
+
throw new Error(`Invalid ticket key: "${ticket}" (expected e.g. JIRA-123 or SAMPLE-001)`);
|
|
7620
|
+
}
|
|
7621
|
+
const ticketDir = join6(repoRoot, ".xera", ticket);
|
|
7622
|
+
return {
|
|
7623
|
+
ticketDir,
|
|
7624
|
+
storyPath: join6(ticketDir, "story.md"),
|
|
7625
|
+
featurePath: join6(ticketDir, "test.feature"),
|
|
7626
|
+
specPath: join6(ticketDir, "spec.ts"),
|
|
7627
|
+
pageObjectsDir: join6(ticketDir, "page-objects"),
|
|
7628
|
+
runsDir: join6(ticketDir, "runs"),
|
|
7629
|
+
metaPath: join6(ticketDir, "meta.json"),
|
|
7630
|
+
statusPath: join6(ticketDir, "status.json"),
|
|
7631
|
+
logPath: join6(ticketDir, "xera.log"),
|
|
7632
|
+
lockPath: join6(ticketDir, ".lock"),
|
|
7633
|
+
authDir: join6(repoRoot, ".xera", ".auth"),
|
|
7634
|
+
runPath: (runId) => {
|
|
7635
|
+
const runDir = join6(ticketDir, "runs", runId);
|
|
7636
|
+
return {
|
|
7637
|
+
runDir,
|
|
7638
|
+
reportJsonPath: join6(runDir, "report.json"),
|
|
7639
|
+
tracePath: join6(runDir, "trace.zip"),
|
|
7640
|
+
normalizedPath: join6(runDir, "normalized.json"),
|
|
7641
|
+
screenshotsDir: join6(runDir, "screenshots"),
|
|
7642
|
+
videoDir: join6(runDir, "videos")
|
|
7643
|
+
};
|
|
7644
|
+
}
|
|
7645
|
+
};
|
|
7646
|
+
}
|
|
7647
|
+
function generateRunId(now = new Date) {
|
|
7648
|
+
return now.toISOString().replace(/[:.]/g, "-").replace("Z", "");
|
|
7649
|
+
}
|
|
7650
|
+
var TICKET_RE;
|
|
7651
|
+
var init_paths2 = __esm(() => {
|
|
7652
|
+
TICKET_RE = /^[A-Z][A-Z0-9_]*-\d+$|^SAMPLE-\d+$/;
|
|
7653
|
+
});
|
|
7654
|
+
|
|
7615
7655
|
// src/bin-internal/graph-record.ts
|
|
7616
7656
|
var exports_graph_record = {};
|
|
7617
7657
|
__export(exports_graph_record, {
|
|
@@ -7620,7 +7660,7 @@ __export(exports_graph_record, {
|
|
|
7620
7660
|
});
|
|
7621
7661
|
import { createHash as createHash3 } from "crypto";
|
|
7622
7662
|
import { existsSync as existsSync7, readFileSync as readFileSync5 } from "fs";
|
|
7623
|
-
import { basename as basename2, join as
|
|
7663
|
+
import { basename as basename2, join as join7 } from "path";
|
|
7624
7664
|
function nowIso2() {
|
|
7625
7665
|
return new Date().toISOString();
|
|
7626
7666
|
}
|
|
@@ -7644,7 +7684,7 @@ function makeEvent(actor, type, payload) {
|
|
|
7644
7684
|
};
|
|
7645
7685
|
}
|
|
7646
7686
|
function readStoryFrontmatter(repoRoot, ticket) {
|
|
7647
|
-
const path =
|
|
7687
|
+
const path = join7(repoRoot, ".xera", ticket, "story.md");
|
|
7648
7688
|
if (!existsSync7(path))
|
|
7649
7689
|
return null;
|
|
7650
7690
|
const raw = readFileSync5(path, "utf8");
|
|
@@ -7654,7 +7694,7 @@ function readStoryFrontmatter(repoRoot, ticket) {
|
|
|
7654
7694
|
return $parse(m[1]);
|
|
7655
7695
|
}
|
|
7656
7696
|
function readGraphInput(repoRoot, ticket) {
|
|
7657
|
-
const path =
|
|
7697
|
+
const path = join7(repoRoot, ".xera", ticket, "graph-input.json");
|
|
7658
7698
|
if (!existsSync7(path))
|
|
7659
7699
|
return { modifiesAreas: [] };
|
|
7660
7700
|
try {
|
|
@@ -7706,32 +7746,33 @@ async function recordScript(repoRoot, ticket) {
|
|
|
7706
7746
|
return recordScriptImpl2(repoRoot, ticket);
|
|
7707
7747
|
}
|
|
7708
7748
|
async function recordExec(repoRoot, ticket, runId) {
|
|
7709
|
-
const
|
|
7710
|
-
if (!existsSync7(
|
|
7711
|
-
console.error(`[graph-record exec]
|
|
7749
|
+
const { normalizedPath } = resolveArtifactPaths(repoRoot, ticket).runPath(runId);
|
|
7750
|
+
if (!existsSync7(normalizedPath)) {
|
|
7751
|
+
console.error(`[graph-record exec] normalized.json missing`);
|
|
7712
7752
|
return 1;
|
|
7713
7753
|
}
|
|
7714
|
-
const data = JSON.parse(readFileSync5(
|
|
7754
|
+
const data = JSON.parse(readFileSync5(normalizedPath, "utf8"));
|
|
7715
7755
|
const events = [];
|
|
7716
7756
|
for (const s of data.scenarios) {
|
|
7757
|
+
if (s.outcome === "SKIPPED")
|
|
7758
|
+
continue;
|
|
7717
7759
|
const p = {
|
|
7718
7760
|
scenarioId: scenarioId(ticket, s.name),
|
|
7719
7761
|
ticketId: ticket,
|
|
7720
7762
|
runId,
|
|
7721
|
-
status: s.
|
|
7722
|
-
runtime:
|
|
7763
|
+
status: s.outcome === "PASS" ? "pass" : "fail",
|
|
7764
|
+
runtime: 0
|
|
7723
7765
|
};
|
|
7724
|
-
if (s.traceId)
|
|
7725
|
-
p.traceId = s.traceId;
|
|
7726
7766
|
events.push(makeEvent("xera-exec", "run.completed", p));
|
|
7727
7767
|
}
|
|
7728
7768
|
appendEvents(repoRoot, events, { skill: "xera-exec", ticketId: ticket });
|
|
7729
7769
|
return 0;
|
|
7730
7770
|
}
|
|
7731
7771
|
async function recordClassify(repoRoot, ticket, runId) {
|
|
7732
|
-
const
|
|
7772
|
+
const { ticketDir } = resolveArtifactPaths(repoRoot, ticket);
|
|
7773
|
+
const classifyPath = join7(ticketDir, "classifier-input.json");
|
|
7733
7774
|
if (!existsSync7(classifyPath)) {
|
|
7734
|
-
console.error(`[graph-record classify] classifier-
|
|
7775
|
+
console.error(`[graph-record classify] classifier-input.json missing`);
|
|
7735
7776
|
return 1;
|
|
7736
7777
|
}
|
|
7737
7778
|
const data = JSON.parse(readFileSync5(classifyPath, "utf8"));
|
|
@@ -7866,6 +7907,7 @@ async function graphRecordCmd(argv) {
|
|
|
7866
7907
|
}
|
|
7867
7908
|
var init_graph_record = __esm(() => {
|
|
7868
7909
|
init_dist();
|
|
7910
|
+
init_paths2();
|
|
7869
7911
|
init_store();
|
|
7870
7912
|
init_ulid();
|
|
7871
7913
|
});
|
|
@@ -7876,9 +7918,9 @@ __export(exports_graph_backfill, {
|
|
|
7876
7918
|
graphBackfillCmd: () => graphBackfillCmd
|
|
7877
7919
|
});
|
|
7878
7920
|
import { existsSync as existsSync8, readdirSync as readdirSync3 } from "fs";
|
|
7879
|
-
import { join as
|
|
7921
|
+
import { join as join8 } from "path";
|
|
7880
7922
|
async function backfillTicket(repoRoot, ticket, dryRun) {
|
|
7881
|
-
const storyPath =
|
|
7923
|
+
const storyPath = join8(repoRoot, ".xera", ticket, "story.md");
|
|
7882
7924
|
if (!existsSync8(storyPath))
|
|
7883
7925
|
return 0;
|
|
7884
7926
|
const { recordFetch: recordFetch2 } = await Promise.resolve().then(() => (init_graph_record(), exports_graph_record));
|
|
@@ -7886,14 +7928,14 @@ async function backfillTicket(repoRoot, ticket, dryRun) {
|
|
|
7886
7928
|
console.log(`[backfill dry-run] would backfill ${ticket}`);
|
|
7887
7929
|
return 0;
|
|
7888
7930
|
}
|
|
7889
|
-
await recordScriptImpl(repoRoot, ticket);
|
|
7890
7931
|
await recordFetch2(repoRoot, ticket);
|
|
7932
|
+
await recordScriptImpl(repoRoot, ticket);
|
|
7891
7933
|
return 0;
|
|
7892
7934
|
}
|
|
7893
7935
|
async function graphBackfillCmd(argv) {
|
|
7894
7936
|
const dryRun = argv.includes("--dry-run");
|
|
7895
7937
|
const repoRoot = process.cwd();
|
|
7896
|
-
const xeraDir =
|
|
7938
|
+
const xeraDir = join8(repoRoot, ".xera");
|
|
7897
7939
|
if (!existsSync8(xeraDir)) {
|
|
7898
7940
|
console.log("[backfill] no .xera/ directory");
|
|
7899
7941
|
return 0;
|
|
@@ -8203,7 +8245,7 @@ async function disputesCmd(argv) {
|
|
|
8203
8245
|
|
|
8204
8246
|
// src/bin-internal/doctor.ts
|
|
8205
8247
|
import { existsSync as existsSync9, readdirSync as readdirSync4, readFileSync as readFileSync6 } from "fs";
|
|
8206
|
-
import { join as
|
|
8248
|
+
import { join as join9 } from "path";
|
|
8207
8249
|
|
|
8208
8250
|
// src/graph/cost.ts
|
|
8209
8251
|
import { appendFileSync, existsSync as existsSync4, mkdirSync as mkdirSync2, readFileSync as readFileSync2 } from "fs";
|
|
@@ -8314,7 +8356,7 @@ function frontmatterField(content, field) {
|
|
|
8314
8356
|
return m?.[1] ?? null;
|
|
8315
8357
|
}
|
|
8316
8358
|
function checkGoldenEvalDir(repoRoot) {
|
|
8317
|
-
const root =
|
|
8359
|
+
const root = join9(repoRoot, "fixtures/golden-eval");
|
|
8318
8360
|
if (!existsSync9(root))
|
|
8319
8361
|
return [{ ok: false, message: "fixtures/golden-eval/ does not exist" }];
|
|
8320
8362
|
const dirs = readdirSync4(root, { withFileTypes: true }).filter((e) => e.isDirectory() && !e.name.startsWith("."));
|
|
@@ -8326,8 +8368,8 @@ function checkGoldenEvalDir(repoRoot) {
|
|
|
8326
8368
|
});
|
|
8327
8369
|
}
|
|
8328
8370
|
for (const entry of dirs) {
|
|
8329
|
-
const dir =
|
|
8330
|
-
const metaPath =
|
|
8371
|
+
const dir = join9(root, entry.name);
|
|
8372
|
+
const metaPath = join9(dir, "meta.json");
|
|
8331
8373
|
if (!existsSync9(metaPath)) {
|
|
8332
8374
|
results.push({ ok: false, message: `${entry.name}: meta.json missing` });
|
|
8333
8375
|
continue;
|
|
@@ -8345,12 +8387,12 @@ function checkGoldenEvalDir(repoRoot) {
|
|
|
8345
8387
|
const stages = Array.isArray(meta.stages) ? meta.stages : [];
|
|
8346
8388
|
if (stages.length === 0)
|
|
8347
8389
|
results.push({ ok: false, message: `${entry.name}: meta.stages is empty` });
|
|
8348
|
-
if (!existsSync9(
|
|
8390
|
+
if (!existsSync9(join9(dir, "story.md")))
|
|
8349
8391
|
results.push({ ok: false, message: `${entry.name}: story.md missing` });
|
|
8350
8392
|
for (const stage of stages) {
|
|
8351
8393
|
const required = REQUIRED_FILES_PER_STAGE[stage] ?? [];
|
|
8352
8394
|
for (const rel of required) {
|
|
8353
|
-
if (!existsSync9(
|
|
8395
|
+
if (!existsSync9(join9(dir, rel))) {
|
|
8354
8396
|
results.push({
|
|
8355
8397
|
ok: false,
|
|
8356
8398
|
message: `${meta.id ?? entry.name}: stage "${stage}" declared but ${rel} missing`
|
|
@@ -8362,7 +8404,7 @@ function checkGoldenEvalDir(repoRoot) {
|
|
|
8362
8404
|
return results;
|
|
8363
8405
|
}
|
|
8364
8406
|
function checkRubricPrompt(repoRoot) {
|
|
8365
|
-
const path =
|
|
8407
|
+
const path = join9(repoRoot, "packages/prompts/eval-rubric.md");
|
|
8366
8408
|
if (!existsSync9(path))
|
|
8367
8409
|
return [{ ok: false, message: "packages/prompts/eval-rubric.md missing" }];
|
|
8368
8410
|
const text = readFileSync6(path, "utf8");
|
|
@@ -8375,7 +8417,7 @@ function checkRubricPrompt(repoRoot) {
|
|
|
8375
8417
|
return [];
|
|
8376
8418
|
}
|
|
8377
8419
|
function checkEvalSkill(repoRoot) {
|
|
8378
|
-
const path =
|
|
8420
|
+
const path = join9(repoRoot, "packages/skills/xera-eval.md");
|
|
8379
8421
|
if (!existsSync9(path))
|
|
8380
8422
|
return [{ ok: false, message: "packages/skills/xera-eval.md missing" }];
|
|
8381
8423
|
const text = readFileSync6(path, "utf8");
|
|
@@ -8387,7 +8429,7 @@ function checkPromptInjectionPreamble(repoRoot) {
|
|
|
8387
8429
|
return verifyPrompts(repoRoot);
|
|
8388
8430
|
}
|
|
8389
8431
|
function checkRootScripts(repoRoot) {
|
|
8390
|
-
const path =
|
|
8432
|
+
const path = join9(repoRoot, "package.json");
|
|
8391
8433
|
if (!existsSync9(path))
|
|
8392
8434
|
return [{ ok: false, message: "root package.json missing" }];
|
|
8393
8435
|
const pkg = JSON.parse(readFileSync6(path, "utf8"));
|
|
@@ -8396,7 +8438,7 @@ function checkRootScripts(repoRoot) {
|
|
|
8396
8438
|
return missing.map((s) => ({ ok: false, message: `root package.json missing script: ${s}` }));
|
|
8397
8439
|
}
|
|
8398
8440
|
function isXeraMonorepo(repoRoot) {
|
|
8399
|
-
return existsSync9(
|
|
8441
|
+
return existsSync9(join9(repoRoot, "packages/skills")) && existsSync9(join9(repoRoot, "packages/prompts"));
|
|
8400
8442
|
}
|
|
8401
8443
|
async function doctorCmd(argv, opts = {}) {
|
|
8402
8444
|
const repoRoot = opts.cwd ?? process.cwd();
|
|
@@ -8418,7 +8460,7 @@ async function doctorCmd(argv, opts = {}) {
|
|
|
8418
8460
|
if (top)
|
|
8419
8461
|
console.log(` Top skill: ${top[0]} (${top[1].calls} calls, $${top[1].usd.toFixed(2)})`);
|
|
8420
8462
|
}
|
|
8421
|
-
const xeraDir =
|
|
8463
|
+
const xeraDir = join9(repoRoot, ".xera");
|
|
8422
8464
|
if (existsSync9(xeraDir)) {
|
|
8423
8465
|
const ticketDirs = readdirSync4(xeraDir, { withFileTypes: true }).filter((e) => e.isDirectory() && /^[A-Z]+-\d+$/.test(e.name));
|
|
8424
8466
|
if (ticketDirs.length > 0) {
|
|
@@ -8455,25 +8497,25 @@ async function doctorCmd(argv, opts = {}) {
|
|
|
8455
8497
|
|
|
8456
8498
|
// src/bin-internal/eval-deterministic.ts
|
|
8457
8499
|
import { existsSync as existsSync10, readFileSync as readFileSync7, writeFileSync as writeFileSync2 } from "fs";
|
|
8458
|
-
import { join as
|
|
8500
|
+
import { join as join11 } from "path";
|
|
8459
8501
|
import { validateGherkin } from "@xera-ai/web";
|
|
8460
8502
|
|
|
8461
8503
|
// src/eval/paths.ts
|
|
8462
|
-
import { join as
|
|
8504
|
+
import { join as join10 } from "path";
|
|
8463
8505
|
function resolveEvalPaths(cwd, runId) {
|
|
8464
|
-
const root =
|
|
8506
|
+
const root = join10(cwd, ".xera", "eval", runId);
|
|
8465
8507
|
return {
|
|
8466
8508
|
root,
|
|
8467
|
-
manifest:
|
|
8468
|
-
lock:
|
|
8469
|
-
deterministicScores:
|
|
8470
|
-
judgeScores:
|
|
8471
|
-
report:
|
|
8472
|
-
summary:
|
|
8473
|
-
inputsDir:
|
|
8474
|
-
actualDir:
|
|
8475
|
-
ticketInputsDir: (ticket) =>
|
|
8476
|
-
ticketActualDir: (ticket) =>
|
|
8509
|
+
manifest: join10(root, "manifest.json"),
|
|
8510
|
+
lock: join10(root, ".lock"),
|
|
8511
|
+
deterministicScores: join10(root, "deterministic-scores.json"),
|
|
8512
|
+
judgeScores: join10(root, "judge-scores.json"),
|
|
8513
|
+
report: join10(root, "report.md"),
|
|
8514
|
+
summary: join10(root, "summary.json"),
|
|
8515
|
+
inputsDir: join10(root, "inputs"),
|
|
8516
|
+
actualDir: join10(root, "actual"),
|
|
8517
|
+
ticketInputsDir: (ticket) => join10(root, "inputs", ticket),
|
|
8518
|
+
ticketActualDir: (ticket) => join10(root, "actual", ticket)
|
|
8477
8519
|
};
|
|
8478
8520
|
}
|
|
8479
8521
|
|
|
@@ -8575,15 +8617,15 @@ function checkFeatureFromStory(actualFeaturePath) {
|
|
|
8575
8617
|
}
|
|
8576
8618
|
}
|
|
8577
8619
|
function checkScriptFromFeature(actualTicketDir) {
|
|
8578
|
-
const specPath =
|
|
8620
|
+
const specPath = join11(actualTicketDir, "spec.ts");
|
|
8579
8621
|
if (!existsSync10(specPath)) {
|
|
8580
8622
|
return { passed: false, checks: ["file-presence"], error: "actual missing: spec.ts" };
|
|
8581
8623
|
}
|
|
8582
8624
|
return { passed: true, checks: ["file-presence"] };
|
|
8583
8625
|
}
|
|
8584
8626
|
function checkDiagnoseFailure(inputsTicketDir, actualTicketDir) {
|
|
8585
|
-
const inputPath =
|
|
8586
|
-
const actualPath =
|
|
8627
|
+
const inputPath = join11(inputsTicketDir, "classifier-input.json");
|
|
8628
|
+
const actualPath = join11(actualTicketDir, "classification.json");
|
|
8587
8629
|
if (!existsSync10(actualPath)) {
|
|
8588
8630
|
return {
|
|
8589
8631
|
passed: false,
|
|
@@ -8641,7 +8683,7 @@ async function evalDeterministicCmd(argv, opts = {}) {
|
|
|
8641
8683
|
const actualDir = paths.ticketActualDir(ticket);
|
|
8642
8684
|
let result;
|
|
8643
8685
|
if (stage === "feature-from-story") {
|
|
8644
|
-
result = checkFeatureFromStory(
|
|
8686
|
+
result = checkFeatureFromStory(join11(actualDir, "test.feature"));
|
|
8645
8687
|
} else if (stage === "script-from-feature") {
|
|
8646
8688
|
result = checkScriptFromFeature(actualDir);
|
|
8647
8689
|
} else {
|
|
@@ -8674,7 +8716,7 @@ import {
|
|
|
8674
8716
|
readFileSync as readFileSync9,
|
|
8675
8717
|
writeFileSync as writeFileSync4
|
|
8676
8718
|
} from "fs";
|
|
8677
|
-
import { join as
|
|
8719
|
+
import { join as join12 } from "path";
|
|
8678
8720
|
|
|
8679
8721
|
// src/eval/run-id.ts
|
|
8680
8722
|
import { execSync } from "child_process";
|
|
@@ -8688,7 +8730,7 @@ function defaultGetGitSha() {
|
|
|
8688
8730
|
function pad(n) {
|
|
8689
8731
|
return n.toString().padStart(2, "0");
|
|
8690
8732
|
}
|
|
8691
|
-
function
|
|
8733
|
+
function generateRunId2(opts = {}) {
|
|
8692
8734
|
const getGitSha = opts.getGitSha ?? defaultGetGitSha;
|
|
8693
8735
|
const now = (opts.now ?? (() => new Date))();
|
|
8694
8736
|
const date = `${now.getUTCFullYear()}${pad(now.getUTCMonth() + 1)}${pad(now.getUTCDate())}`;
|
|
@@ -8767,7 +8809,7 @@ function parseFlags2(argv) {
|
|
|
8767
8809
|
return flags;
|
|
8768
8810
|
}
|
|
8769
8811
|
function readPromptVersion(repoRoot, name) {
|
|
8770
|
-
const path =
|
|
8812
|
+
const path = join12(repoRoot, "packages/prompts", `${name}.md`);
|
|
8771
8813
|
if (!existsSync12(path))
|
|
8772
8814
|
return "0.0.0";
|
|
8773
8815
|
const text = readFileSync9(path, "utf8");
|
|
@@ -8775,7 +8817,7 @@ function readPromptVersion(repoRoot, name) {
|
|
|
8775
8817
|
return m?.[1] ?? "0.0.0";
|
|
8776
8818
|
}
|
|
8777
8819
|
function discoverEvalTickets(repoRoot) {
|
|
8778
|
-
const root =
|
|
8820
|
+
const root = join12(repoRoot, "fixtures/golden-eval");
|
|
8779
8821
|
if (!existsSync12(root))
|
|
8780
8822
|
return [];
|
|
8781
8823
|
const out = [];
|
|
@@ -8784,8 +8826,8 @@ function discoverEvalTickets(repoRoot) {
|
|
|
8784
8826
|
continue;
|
|
8785
8827
|
if (entry.name === "README.md" || entry.name.startsWith("."))
|
|
8786
8828
|
continue;
|
|
8787
|
-
const dir =
|
|
8788
|
-
const metaPath =
|
|
8829
|
+
const dir = join12(root, entry.name);
|
|
8830
|
+
const metaPath = join12(dir, "meta.json");
|
|
8789
8831
|
if (!existsSync12(metaPath))
|
|
8790
8832
|
continue;
|
|
8791
8833
|
const meta = JSON.parse(readFileSync9(metaPath, "utf8"));
|
|
@@ -8794,14 +8836,14 @@ function discoverEvalTickets(repoRoot) {
|
|
|
8794
8836
|
return out.sort((a, b) => a.id.localeCompare(b.id));
|
|
8795
8837
|
}
|
|
8796
8838
|
function discoverClassifierTickets(repoRoot) {
|
|
8797
|
-
const root =
|
|
8839
|
+
const root = join12(repoRoot, "fixtures/golden-tickets");
|
|
8798
8840
|
if (!existsSync12(root))
|
|
8799
8841
|
return [];
|
|
8800
8842
|
const out = [];
|
|
8801
8843
|
for (const entry of readdirSync5(root, { withFileTypes: true })) {
|
|
8802
8844
|
if (!entry.isFile() || !entry.name.endsWith(".json"))
|
|
8803
8845
|
continue;
|
|
8804
|
-
const path =
|
|
8846
|
+
const path = join12(root, entry.name);
|
|
8805
8847
|
const data = JSON.parse(readFileSync9(path, "utf8"));
|
|
8806
8848
|
if (typeof data.ticket === "string")
|
|
8807
8849
|
out.push({ id: data.ticket, path });
|
|
@@ -8856,7 +8898,7 @@ async function evalPrepareCmd(argv, opts = {}) {
|
|
|
8856
8898
|
console.error("[xera:eval-prepare] No tickets applicable to requested stages.");
|
|
8857
8899
|
return 1;
|
|
8858
8900
|
}
|
|
8859
|
-
const runId =
|
|
8901
|
+
const runId = generateRunId2({
|
|
8860
8902
|
...opts.now ? { now: opts.now } : {},
|
|
8861
8903
|
...opts.getGitSha ? { getGitSha: opts.getGitSha } : {}
|
|
8862
8904
|
});
|
|
@@ -8873,13 +8915,13 @@ async function evalPrepareCmd(argv, opts = {}) {
|
|
|
8873
8915
|
const evalT = evalTickets.find((t) => t.id === ticket);
|
|
8874
8916
|
const classT = classifierTickets.find((t) => t.id === ticket);
|
|
8875
8917
|
if (evalT) {
|
|
8876
|
-
copyFileSync(
|
|
8877
|
-
const featurePath =
|
|
8918
|
+
copyFileSync(join12(evalT.dir, "story.md"), join12(ticketInputs, "story.md"));
|
|
8919
|
+
const featurePath = join12(evalT.dir, "golden/test.feature");
|
|
8878
8920
|
if (existsSync12(featurePath))
|
|
8879
|
-
copyFileSync(featurePath,
|
|
8921
|
+
copyFileSync(featurePath, join12(ticketInputs, "test.feature"));
|
|
8880
8922
|
}
|
|
8881
8923
|
if (classT) {
|
|
8882
|
-
copyFileSync(classT.path,
|
|
8924
|
+
copyFileSync(classT.path, join12(ticketInputs, "classifier-input.json"));
|
|
8883
8925
|
}
|
|
8884
8926
|
}
|
|
8885
8927
|
const now = (opts.now ?? (() => new Date))();
|
|
@@ -9099,42 +9141,8 @@ function updateMeta(path, patch) {
|
|
|
9099
9141
|
return next;
|
|
9100
9142
|
}
|
|
9101
9143
|
|
|
9102
|
-
// src/
|
|
9103
|
-
|
|
9104
|
-
var TICKET_RE = /^[A-Z][A-Z0-9_]*-\d+$|^SAMPLE-\d+$/;
|
|
9105
|
-
function resolveArtifactPaths(repoRoot, ticket) {
|
|
9106
|
-
if (!TICKET_RE.test(ticket)) {
|
|
9107
|
-
throw new Error(`Invalid ticket key: "${ticket}" (expected e.g. JIRA-123 or SAMPLE-001)`);
|
|
9108
|
-
}
|
|
9109
|
-
const ticketDir = join12(repoRoot, ".xera", ticket);
|
|
9110
|
-
return {
|
|
9111
|
-
ticketDir,
|
|
9112
|
-
storyPath: join12(ticketDir, "story.md"),
|
|
9113
|
-
featurePath: join12(ticketDir, "test.feature"),
|
|
9114
|
-
specPath: join12(ticketDir, "spec.ts"),
|
|
9115
|
-
pageObjectsDir: join12(ticketDir, "page-objects"),
|
|
9116
|
-
runsDir: join12(ticketDir, "runs"),
|
|
9117
|
-
metaPath: join12(ticketDir, "meta.json"),
|
|
9118
|
-
statusPath: join12(ticketDir, "status.json"),
|
|
9119
|
-
logPath: join12(ticketDir, "xera.log"),
|
|
9120
|
-
lockPath: join12(ticketDir, ".lock"),
|
|
9121
|
-
authDir: join12(repoRoot, ".xera", ".auth"),
|
|
9122
|
-
runPath: (runId) => {
|
|
9123
|
-
const runDir = join12(ticketDir, "runs", runId);
|
|
9124
|
-
return {
|
|
9125
|
-
runDir,
|
|
9126
|
-
reportJsonPath: join12(runDir, "report.json"),
|
|
9127
|
-
tracePath: join12(runDir, "trace.zip"),
|
|
9128
|
-
normalizedPath: join12(runDir, "normalized.json"),
|
|
9129
|
-
screenshotsDir: join12(runDir, "screenshots"),
|
|
9130
|
-
videoDir: join12(runDir, "videos")
|
|
9131
|
-
};
|
|
9132
|
-
}
|
|
9133
|
-
};
|
|
9134
|
-
}
|
|
9135
|
-
function generateRunId2(now = new Date) {
|
|
9136
|
-
return now.toISOString().replace(/[:.]/g, "-").replace("Z", "");
|
|
9137
|
-
}
|
|
9144
|
+
// src/bin-internal/exec.ts
|
|
9145
|
+
init_paths2();
|
|
9138
9146
|
|
|
9139
9147
|
// src/auth/refresh.ts
|
|
9140
9148
|
var RE = /^(\d+)([hms])$/;
|
|
@@ -9286,7 +9294,7 @@ async function execCmd(argv) {
|
|
|
9286
9294
|
const cwd = process.cwd();
|
|
9287
9295
|
const config = await loadConfig(cwd);
|
|
9288
9296
|
const paths = resolveArtifactPaths(cwd, ticket);
|
|
9289
|
-
const runId =
|
|
9297
|
+
const runId = generateRunId();
|
|
9290
9298
|
const log = new NdjsonLogger(paths.logPath);
|
|
9291
9299
|
if (!acquireLock(paths.lockPath, runId)) {
|
|
9292
9300
|
if (isLockStale(paths.lockPath)) {
|
|
@@ -9413,6 +9421,9 @@ function hashFileIfExists(path) {
|
|
|
9413
9421
|
return hashFile(path);
|
|
9414
9422
|
}
|
|
9415
9423
|
|
|
9424
|
+
// src/bin-internal/fetch.ts
|
|
9425
|
+
init_paths2();
|
|
9426
|
+
|
|
9416
9427
|
// src/jira/mcp-backend.ts
|
|
9417
9428
|
import { existsSync as existsSync19, mkdirSync as mkdirSync9, readFileSync as readFileSync15, writeFileSync as writeFileSync8 } from "fs";
|
|
9418
9429
|
import { tmpdir } from "os";
|
|
@@ -10526,6 +10537,7 @@ function unzipSync(data, opts) {
|
|
|
10526
10537
|
}
|
|
10527
10538
|
|
|
10528
10539
|
// src/bin-internal/heal-prepare.ts
|
|
10540
|
+
init_paths2();
|
|
10529
10541
|
var LOCATOR_LINE_RE = /^Locator:\s*(.+)$/m;
|
|
10530
10542
|
function classifyKind(raw) {
|
|
10531
10543
|
if (/^getByRole\b/.test(raw))
|
|
@@ -10949,6 +10961,7 @@ async function impactPrepareCmd(argv) {
|
|
|
10949
10961
|
}
|
|
10950
10962
|
|
|
10951
10963
|
// src/bin-internal/lint.ts
|
|
10964
|
+
init_paths2();
|
|
10952
10965
|
import { lintTicket } from "@xera-ai/web";
|
|
10953
10966
|
async function lintCmd(argv) {
|
|
10954
10967
|
const ticket = argv[0];
|
|
@@ -10970,6 +10983,7 @@ async function lintCmd(argv) {
|
|
|
10970
10983
|
// src/bin-internal/normalize.ts
|
|
10971
10984
|
import { existsSync as existsSync22, readdirSync as readdirSync7 } from "fs";
|
|
10972
10985
|
import { join as join21 } from "path";
|
|
10986
|
+
init_paths2();
|
|
10973
10987
|
async function normalizeCmd(argv) {
|
|
10974
10988
|
const ticket = argv[0];
|
|
10975
10989
|
if (!ticket) {
|
|
@@ -11003,6 +11017,7 @@ async function normalizeCmd(argv) {
|
|
|
11003
11017
|
}
|
|
11004
11018
|
|
|
11005
11019
|
// src/bin-internal/post.ts
|
|
11020
|
+
init_paths2();
|
|
11006
11021
|
import { existsSync as existsSync24, readFileSync as readFileSync20 } from "fs";
|
|
11007
11022
|
import { join as join22 } from "path";
|
|
11008
11023
|
|
|
@@ -11112,6 +11127,7 @@ async function promoteCmd(argv) {
|
|
|
11112
11127
|
// src/bin-internal/report.ts
|
|
11113
11128
|
import { existsSync as existsSync26, readFileSync as readFileSync21, writeFileSync as writeFileSync14 } from "fs";
|
|
11114
11129
|
import { join as join23 } from "path";
|
|
11130
|
+
init_paths2();
|
|
11115
11131
|
|
|
11116
11132
|
// src/classifier/aggregate.ts
|
|
11117
11133
|
var CLASS_PRIORITY = [
|
|
@@ -11531,6 +11547,7 @@ async function reportCmd(argv) {
|
|
|
11531
11547
|
}
|
|
11532
11548
|
|
|
11533
11549
|
// src/bin-internal/status-cmd.ts
|
|
11550
|
+
init_paths2();
|
|
11534
11551
|
async function statusCmd(argv) {
|
|
11535
11552
|
const ticket = argv[0];
|
|
11536
11553
|
if (!ticket) {
|
|
@@ -11550,6 +11567,7 @@ async function statusCmd(argv) {
|
|
|
11550
11567
|
}
|
|
11551
11568
|
|
|
11552
11569
|
// src/bin-internal/typecheck.ts
|
|
11570
|
+
init_paths2();
|
|
11553
11571
|
import { typecheckTicket } from "@xera-ai/web";
|
|
11554
11572
|
async function typecheckCmd(argv) {
|
|
11555
11573
|
const ticket = argv[0];
|
|
@@ -11569,6 +11587,7 @@ async function typecheckCmd(argv) {
|
|
|
11569
11587
|
}
|
|
11570
11588
|
|
|
11571
11589
|
// src/bin-internal/unlock.ts
|
|
11590
|
+
init_paths2();
|
|
11572
11591
|
async function unlockCmd(argv) {
|
|
11573
11592
|
const ticket = argv[0];
|
|
11574
11593
|
if (!ticket) {
|
|
@@ -11592,6 +11611,7 @@ async function unlockCmd(argv) {
|
|
|
11592
11611
|
}
|
|
11593
11612
|
|
|
11594
11613
|
// src/bin-internal/validate-feature.ts
|
|
11614
|
+
init_paths2();
|
|
11595
11615
|
import { existsSync as existsSync27, readFileSync as readFileSync22 } from "fs";
|
|
11596
11616
|
import { validateGherkin as validateGherkin2 } from "@xera-ai/web";
|
|
11597
11617
|
async function validateFeatureCmd(argv) {
|