@xera-ai/core 0.4.4 → 0.8.0
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 +895 -537
- package/dist/src/index.js +109 -4
- package/package.json +6 -4
- package/src/artifact/status.ts +3 -0
- package/src/bin-internal/auth-setup.ts +116 -0
- package/src/bin-internal/exec.ts +42 -9
- package/src/bin-internal/graph-record.ts +3 -0
- package/src/bin-internal/index.ts +2 -0
- package/src/bin-internal/normalize.ts +13 -1
- package/src/bin-internal/report.ts +94 -2
- package/src/bin-internal/verify-prompts.ts +2 -1
- package/src/classifier/aggregate.ts +3 -0
- package/src/classifier/auth-expired.ts +44 -0
- package/src/classifier/contract-drift.ts +111 -0
- package/src/classifier/rate-limited.ts +25 -0
- package/src/config/schema.ts +51 -8
- package/src/graph/schema.ts +3 -0
- package/src/graph/types.ts +4 -1
- package/src/index.ts +2 -0
- package/src/scrub/index.ts +1 -0
- package/src/scrub/rules.ts +69 -0
- package/dist/adapter/types.d.ts +0 -70
- package/dist/adapter/types.d.ts.map +0 -1
- package/dist/artifact/hash.d.ts +0 -4
- package/dist/artifact/hash.d.ts.map +0 -1
- package/dist/artifact/meta.d.ts +0 -20
- package/dist/artifact/meta.d.ts.map +0 -1
- package/dist/artifact/paths.d.ts +0 -25
- package/dist/artifact/paths.d.ts.map +0 -1
- package/dist/artifact/status.d.ts +0 -75
- package/dist/artifact/status.d.ts.map +0 -1
- package/dist/auth/encrypt.d.ts +0 -4
- package/dist/auth/encrypt.d.ts.map +0 -1
- package/dist/auth/key.d.ts +0 -3
- package/dist/auth/key.d.ts.map +0 -1
- package/dist/auth/refresh.d.ts +0 -9
- package/dist/auth/refresh.d.ts.map +0 -1
- package/dist/auth/state.d.ts +0 -15
- package/dist/auth/state.d.ts.map +0 -1
- package/dist/bin-internal/disputes.d.ts +0 -2
- package/dist/bin-internal/disputes.d.ts.map +0 -1
- package/dist/bin-internal/doctor.d.ts +0 -5
- package/dist/bin-internal/doctor.d.ts.map +0 -1
- package/dist/bin-internal/eval-deterministic.d.ts +0 -5
- package/dist/bin-internal/eval-deterministic.d.ts.map +0 -1
- package/dist/bin-internal/eval-prepare.d.ts +0 -7
- package/dist/bin-internal/eval-prepare.d.ts.map +0 -1
- package/dist/bin-internal/eval-report.d.ts +0 -5
- package/dist/bin-internal/eval-report.d.ts.map +0 -1
- package/dist/bin-internal/exec.d.ts +0 -2
- package/dist/bin-internal/exec.d.ts.map +0 -1
- package/dist/bin-internal/fetch.d.ts +0 -5
- package/dist/bin-internal/fetch.d.ts.map +0 -1
- package/dist/bin-internal/graph-backfill.d.ts +0 -2
- package/dist/bin-internal/graph-backfill.d.ts.map +0 -1
- package/dist/bin-internal/graph-enrich.d.ts +0 -2
- package/dist/bin-internal/graph-enrich.d.ts.map +0 -1
- package/dist/bin-internal/graph-query.d.ts +0 -2
- package/dist/bin-internal/graph-query.d.ts.map +0 -1
- package/dist/bin-internal/graph-record-script.d.ts +0 -2
- package/dist/bin-internal/graph-record-script.d.ts.map +0 -1
- package/dist/bin-internal/graph-record.d.ts +0 -3
- package/dist/bin-internal/graph-record.d.ts.map +0 -1
- package/dist/bin-internal/graph-render.d.ts +0 -2
- package/dist/bin-internal/graph-render.d.ts.map +0 -1
- package/dist/bin-internal/graph-snapshot.d.ts +0 -2
- package/dist/bin-internal/graph-snapshot.d.ts.map +0 -1
- package/dist/bin-internal/heal-prepare.d.ts +0 -19
- package/dist/bin-internal/heal-prepare.d.ts.map +0 -1
- package/dist/bin-internal/impact-prepare.d.ts +0 -2
- package/dist/bin-internal/impact-prepare.d.ts.map +0 -1
- package/dist/bin-internal/index.d.ts +0 -2
- package/dist/bin-internal/index.d.ts.map +0 -1
- package/dist/bin-internal/lint.d.ts +0 -2
- package/dist/bin-internal/lint.d.ts.map +0 -1
- package/dist/bin-internal/normalize.d.ts +0 -2
- package/dist/bin-internal/normalize.d.ts.map +0 -1
- package/dist/bin-internal/post.d.ts +0 -2
- package/dist/bin-internal/post.d.ts.map +0 -1
- package/dist/bin-internal/promote.d.ts +0 -2
- package/dist/bin-internal/promote.d.ts.map +0 -1
- package/dist/bin-internal/report.d.ts +0 -2
- package/dist/bin-internal/report.d.ts.map +0 -1
- package/dist/bin-internal/status-cmd.d.ts +0 -2
- package/dist/bin-internal/status-cmd.d.ts.map +0 -1
- package/dist/bin-internal/typecheck.d.ts +0 -2
- package/dist/bin-internal/typecheck.d.ts.map +0 -1
- package/dist/bin-internal/unlock.d.ts +0 -2
- package/dist/bin-internal/unlock.d.ts.map +0 -1
- package/dist/bin-internal/validate-feature.d.ts +0 -2
- package/dist/bin-internal/validate-feature.d.ts.map +0 -1
- package/dist/bin-internal/verify-prompts.d.ts +0 -7
- package/dist/bin-internal/verify-prompts.d.ts.map +0 -1
- package/dist/classifier/aggregate.d.ts +0 -3
- package/dist/classifier/aggregate.d.ts.map +0 -1
- package/dist/classifier/history.d.ts +0 -13
- package/dist/classifier/history.d.ts.map +0 -1
- package/dist/classifier/types.d.ts +0 -26
- package/dist/classifier/types.d.ts.map +0 -1
- package/dist/config/define.d.ts +0 -3
- package/dist/config/define.d.ts.map +0 -1
- package/dist/config/load.d.ts +0 -3
- package/dist/config/load.d.ts.map +0 -1
- package/dist/config/schema.d.ts +0 -72
- package/dist/config/schema.d.ts.map +0 -1
- package/dist/eval/paths.d.ts +0 -15
- package/dist/eval/paths.d.ts.map +0 -1
- package/dist/eval/run-id.d.ts +0 -6
- package/dist/eval/run-id.d.ts.map +0 -1
- package/dist/eval/types.d.ts +0 -203
- package/dist/eval/types.d.ts.map +0 -1
- package/dist/graph/classify.d.ts +0 -42
- package/dist/graph/classify.d.ts.map +0 -1
- package/dist/graph/cost.d.ts +0 -21
- package/dist/graph/cost.d.ts.map +0 -1
- package/dist/graph/enrich.d.ts +0 -10
- package/dist/graph/enrich.d.ts.map +0 -1
- package/dist/graph/impact.d.ts +0 -31
- package/dist/graph/impact.d.ts.map +0 -1
- package/dist/graph/index.d.ts +0 -17
- package/dist/graph/index.d.ts.map +0 -1
- package/dist/graph/paths.d.ts +0 -10
- package/dist/graph/paths.d.ts.map +0 -1
- package/dist/graph/render.d.ts +0 -50
- package/dist/graph/render.d.ts.map +0 -1
- package/dist/graph/schema.d.ts +0 -180
- package/dist/graph/schema.d.ts.map +0 -1
- package/dist/graph/similarity.d.ts +0 -3
- package/dist/graph/similarity.d.ts.map +0 -1
- package/dist/graph/store.d.ts +0 -14
- package/dist/graph/store.d.ts.map +0 -1
- package/dist/graph/types.d.ts +0 -152
- package/dist/graph/types.d.ts.map +0 -1
- package/dist/graph/ulid.d.ts +0 -2
- package/dist/graph/ulid.d.ts.map +0 -1
- package/dist/index.d.ts +0 -20
- package/dist/index.d.ts.map +0 -1
- package/dist/jira/client.d.ts +0 -11
- package/dist/jira/client.d.ts.map +0 -1
- package/dist/jira/fields.d.ts +0 -7
- package/dist/jira/fields.d.ts.map +0 -1
- package/dist/jira/mcp-backend.d.ts +0 -3
- package/dist/jira/mcp-backend.d.ts.map +0 -1
- package/dist/jira/rest-backend.d.ts +0 -8
- package/dist/jira/rest-backend.d.ts.map +0 -1
- package/dist/jira/retry.d.ts +0 -8
- package/dist/jira/retry.d.ts.map +0 -1
- package/dist/jira/types.d.ts +0 -29
- package/dist/jira/types.d.ts.map +0 -1
- package/dist/lock/file-lock.d.ts +0 -12
- package/dist/lock/file-lock.d.ts.map +0 -1
- package/dist/logging/ndjson-logger.d.ts +0 -11
- package/dist/logging/ndjson-logger.d.ts.map +0 -1
- package/dist/reporter/jira-comment.d.ts +0 -9
- package/dist/reporter/jira-comment.d.ts.map +0 -1
- package/dist/reporter/status-writer.d.ts +0 -14
- package/dist/reporter/status-writer.d.ts.map +0 -1
package/dist/bin/internal.js
CHANGED
|
@@ -19,15 +19,15 @@ var __esm = (fn, res) => () => (fn && (res = fn(fn = 0)), res);
|
|
|
19
19
|
var __require = import.meta.require;
|
|
20
20
|
|
|
21
21
|
// src/graph/paths.ts
|
|
22
|
-
import { join } from "path";
|
|
22
|
+
import { join as join3 } from "path";
|
|
23
23
|
function graphPaths(repoRoot) {
|
|
24
|
-
const eventsDir =
|
|
24
|
+
const eventsDir = join3(repoRoot, ".xera/graph/events");
|
|
25
25
|
return {
|
|
26
26
|
eventsDir,
|
|
27
|
-
snapshotFile:
|
|
28
|
-
costLog:
|
|
29
|
-
eventsMonthDir: (yyyyMm) =>
|
|
30
|
-
eventFile: (ulid, skill, ticketId, yyyyMm) =>
|
|
27
|
+
snapshotFile: join3(repoRoot, ".xera/graph/snapshot.json"),
|
|
28
|
+
costLog: join3(repoRoot, ".xera/cost-log.jsonl"),
|
|
29
|
+
eventsMonthDir: (yyyyMm) => join3(eventsDir, yyyyMm),
|
|
30
|
+
eventFile: (ulid, skill, ticketId, yyyyMm) => join3(eventsDir, yyyyMm, `${ulid}-${skill}-${ticketId}.jsonl`)
|
|
31
31
|
};
|
|
32
32
|
}
|
|
33
33
|
function currentYyyyMm(now = new Date) {
|
|
@@ -41,7 +41,7 @@ var init_paths = () => {};
|
|
|
41
41
|
var SCHEMA_VERSION = 1;
|
|
42
42
|
|
|
43
43
|
// src/graph/schema.ts
|
|
44
|
-
import { z } from "zod";
|
|
44
|
+
import { z as z2 } from "zod";
|
|
45
45
|
function safeParseEvent(value) {
|
|
46
46
|
const r = EventSchema.safeParse(value);
|
|
47
47
|
if (r.success)
|
|
@@ -50,110 +50,113 @@ function safeParseEvent(value) {
|
|
|
50
50
|
}
|
|
51
51
|
var schemaV, iso, ticketFetched, ticketEnriched, scenarioGenerated, pomGenerated, pomPromoted, runCompleted, classification, runClassified, classificationDisputed, edgeDiscovered, base, EventSchema;
|
|
52
52
|
var init_schema = __esm(() => {
|
|
53
|
-
schemaV =
|
|
54
|
-
iso =
|
|
55
|
-
ticketFetched =
|
|
56
|
-
ticketId:
|
|
57
|
-
summary:
|
|
58
|
-
ac:
|
|
59
|
-
jiraLinks:
|
|
60
|
-
ticketId:
|
|
61
|
-
relation:
|
|
53
|
+
schemaV = z2.literal(SCHEMA_VERSION);
|
|
54
|
+
iso = z2.string().datetime({ offset: false });
|
|
55
|
+
ticketFetched = z2.object({
|
|
56
|
+
ticketId: z2.string().regex(/^[A-Z][A-Z0-9]*-\d+$/),
|
|
57
|
+
summary: z2.string(),
|
|
58
|
+
ac: z2.array(z2.string()),
|
|
59
|
+
jiraLinks: z2.array(z2.object({
|
|
60
|
+
ticketId: z2.string().regex(/^[A-Z][A-Z0-9]*-\d+$/),
|
|
61
|
+
relation: z2.enum(["blocks", "duplicates", "relates", "supersedes"])
|
|
62
62
|
})),
|
|
63
|
-
storyHash:
|
|
64
|
-
modifiesAreas:
|
|
63
|
+
storyHash: z2.string(),
|
|
64
|
+
modifiesAreas: z2.array(z2.string().regex(/^[a-z0-9-]+$/))
|
|
65
65
|
}).passthrough();
|
|
66
|
-
ticketEnriched =
|
|
67
|
-
ticketId:
|
|
66
|
+
ticketEnriched = z2.object({
|
|
67
|
+
ticketId: z2.string(),
|
|
68
68
|
enrichedAt: iso,
|
|
69
|
-
similarCount:
|
|
69
|
+
similarCount: z2.number().int().nonnegative()
|
|
70
70
|
}).passthrough();
|
|
71
|
-
scenarioGenerated =
|
|
72
|
-
scenarioId:
|
|
73
|
-
ticketId:
|
|
74
|
-
name:
|
|
75
|
-
gherkin:
|
|
76
|
-
priority:
|
|
77
|
-
featureHash:
|
|
71
|
+
scenarioGenerated = z2.object({
|
|
72
|
+
scenarioId: z2.string(),
|
|
73
|
+
ticketId: z2.string(),
|
|
74
|
+
name: z2.string(),
|
|
75
|
+
gherkin: z2.string(),
|
|
76
|
+
priority: z2.enum(["p0", "p1", "p2"]),
|
|
77
|
+
featureHash: z2.string(),
|
|
78
78
|
generatedAt: iso
|
|
79
79
|
}).passthrough();
|
|
80
|
-
pomGenerated =
|
|
81
|
-
pomId:
|
|
82
|
-
ticketId:
|
|
83
|
-
filePath:
|
|
84
|
-
route:
|
|
85
|
-
locators:
|
|
86
|
-
scope:
|
|
80
|
+
pomGenerated = z2.object({
|
|
81
|
+
pomId: z2.string(),
|
|
82
|
+
ticketId: z2.string(),
|
|
83
|
+
filePath: z2.string(),
|
|
84
|
+
route: z2.string(),
|
|
85
|
+
locators: z2.array(z2.string()),
|
|
86
|
+
scope: z2.enum(["local", "shared"])
|
|
87
87
|
}).passthrough();
|
|
88
|
-
pomPromoted =
|
|
89
|
-
pomId:
|
|
90
|
-
fromPath:
|
|
91
|
-
toPath:
|
|
88
|
+
pomPromoted = z2.object({
|
|
89
|
+
pomId: z2.string(),
|
|
90
|
+
fromPath: z2.string(),
|
|
91
|
+
toPath: z2.string()
|
|
92
92
|
}).passthrough();
|
|
93
|
-
runCompleted =
|
|
94
|
-
scenarioId:
|
|
95
|
-
ticketId:
|
|
96
|
-
runId:
|
|
97
|
-
status:
|
|
98
|
-
traceId:
|
|
99
|
-
runtime:
|
|
93
|
+
runCompleted = z2.object({
|
|
94
|
+
scenarioId: z2.string(),
|
|
95
|
+
ticketId: z2.string(),
|
|
96
|
+
runId: z2.string(),
|
|
97
|
+
status: z2.enum(["pass", "fail"]),
|
|
98
|
+
traceId: z2.string().optional(),
|
|
99
|
+
runtime: z2.number().nonnegative()
|
|
100
100
|
}).passthrough();
|
|
101
|
-
classification =
|
|
101
|
+
classification = z2.enum([
|
|
102
102
|
"REAL_BUG",
|
|
103
103
|
"TEST_BUG",
|
|
104
104
|
"SELECTOR_DRIFT",
|
|
105
105
|
"FLAKY",
|
|
106
106
|
"PASS",
|
|
107
|
-
"TEST_OUTDATED"
|
|
107
|
+
"TEST_OUTDATED",
|
|
108
|
+
"CONTRACT_DRIFT",
|
|
109
|
+
"RATE_LIMITED",
|
|
110
|
+
"AUTH_EXPIRED"
|
|
108
111
|
]);
|
|
109
|
-
runClassified =
|
|
110
|
-
scenarioId:
|
|
111
|
-
runId:
|
|
112
|
+
runClassified = z2.object({
|
|
113
|
+
scenarioId: z2.string(),
|
|
114
|
+
runId: z2.string(),
|
|
112
115
|
classification,
|
|
113
|
-
confidence:
|
|
116
|
+
confidence: z2.enum(["low", "medium", "high"])
|
|
114
117
|
}).passthrough();
|
|
115
|
-
classificationDisputed =
|
|
116
|
-
runId:
|
|
117
|
-
scenarioId:
|
|
118
|
+
classificationDisputed = z2.object({
|
|
119
|
+
runId: z2.string(),
|
|
120
|
+
scenarioId: z2.string(),
|
|
118
121
|
originalClassification: classification,
|
|
119
122
|
disputedTo: classification,
|
|
120
|
-
qaActor:
|
|
121
|
-
qaReason:
|
|
123
|
+
qaActor: z2.string(),
|
|
124
|
+
qaReason: z2.string().optional()
|
|
122
125
|
}).passthrough();
|
|
123
|
-
edgeDiscovered =
|
|
124
|
-
kind:
|
|
125
|
-
from:
|
|
126
|
-
to:
|
|
127
|
-
confidence:
|
|
128
|
-
source:
|
|
126
|
+
edgeDiscovered = z2.object({
|
|
127
|
+
kind: z2.enum(["tests", "uses", "covers", "modifies", "jira-linked", "similar", "ran"]),
|
|
128
|
+
from: z2.string(),
|
|
129
|
+
to: z2.string(),
|
|
130
|
+
confidence: z2.number().min(0).max(1).optional(),
|
|
131
|
+
source: z2.string()
|
|
129
132
|
}).passthrough();
|
|
130
133
|
base = {
|
|
131
|
-
event_id:
|
|
134
|
+
event_id: z2.string().min(20),
|
|
132
135
|
schema_version: schemaV,
|
|
133
136
|
ts: iso,
|
|
134
|
-
actor:
|
|
137
|
+
actor: z2.string()
|
|
135
138
|
};
|
|
136
|
-
EventSchema =
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
139
|
+
EventSchema = z2.discriminatedUnion("type", [
|
|
140
|
+
z2.object({ ...base, type: z2.literal("ticket.fetched"), payload: ticketFetched }),
|
|
141
|
+
z2.object({ ...base, type: z2.literal("ticket.enriched"), payload: ticketEnriched }),
|
|
142
|
+
z2.object({ ...base, type: z2.literal("scenario.generated"), payload: scenarioGenerated }),
|
|
143
|
+
z2.object({ ...base, type: z2.literal("pom.generated"), payload: pomGenerated }),
|
|
144
|
+
z2.object({ ...base, type: z2.literal("pom.promoted"), payload: pomPromoted }),
|
|
145
|
+
z2.object({ ...base, type: z2.literal("run.completed"), payload: runCompleted }),
|
|
146
|
+
z2.object({ ...base, type: z2.literal("run.classified"), payload: runClassified }),
|
|
147
|
+
z2.object({
|
|
145
148
|
...base,
|
|
146
|
-
type:
|
|
149
|
+
type: z2.literal("classification.disputed"),
|
|
147
150
|
payload: classificationDisputed
|
|
148
151
|
}),
|
|
149
|
-
|
|
152
|
+
z2.object({ ...base, type: z2.literal("edge.discovered"), payload: edgeDiscovered })
|
|
150
153
|
]);
|
|
151
154
|
});
|
|
152
155
|
|
|
153
156
|
// src/graph/store.ts
|
|
154
157
|
import { createHash } from "crypto";
|
|
155
158
|
import {
|
|
156
|
-
existsSync,
|
|
159
|
+
existsSync as existsSync3,
|
|
157
160
|
mkdirSync,
|
|
158
161
|
readdirSync,
|
|
159
162
|
readFileSync,
|
|
@@ -180,7 +183,7 @@ function appendEvents(repoRoot, events, opts) {
|
|
|
180
183
|
}
|
|
181
184
|
function loadAllEvents(repoRoot) {
|
|
182
185
|
const paths = graphPaths(repoRoot);
|
|
183
|
-
if (!
|
|
186
|
+
if (!existsSync3(paths.eventsDir))
|
|
184
187
|
return [];
|
|
185
188
|
const files = [];
|
|
186
189
|
for (const monthDir of readdirSync(paths.eventsDir, { withFileTypes: true })) {
|
|
@@ -359,7 +362,7 @@ function writeSnapshot(repoRoot, snap) {
|
|
|
359
362
|
}
|
|
360
363
|
function loadSnapshot(repoRoot) {
|
|
361
364
|
const paths = graphPaths(repoRoot);
|
|
362
|
-
if (!
|
|
365
|
+
if (!existsSync3(paths.snapshotFile))
|
|
363
366
|
return null;
|
|
364
367
|
try {
|
|
365
368
|
return JSON.parse(readFileSync(paths.snapshotFile, "utf8"));
|
|
@@ -437,8 +440,8 @@ __export(exports_graph_record_script, {
|
|
|
437
440
|
recordScriptImpl: () => recordScriptImpl
|
|
438
441
|
});
|
|
439
442
|
import { createHash as createHash2 } from "crypto";
|
|
440
|
-
import { existsSync as
|
|
441
|
-
import { basename, join as
|
|
443
|
+
import { existsSync as existsSync6, readdirSync as readdirSync2, readFileSync as readFileSync4 } from "fs";
|
|
444
|
+
import { basename, join as join5 } from "path";
|
|
442
445
|
function inferPriority(name, gherkin) {
|
|
443
446
|
const haystack = `${name} ${gherkin}`.toLowerCase();
|
|
444
447
|
for (const kw of P0_KEYWORDS) {
|
|
@@ -480,9 +483,9 @@ function parseFeature(text) {
|
|
|
480
483
|
return scenarios;
|
|
481
484
|
}
|
|
482
485
|
function listPomFiles(dir) {
|
|
483
|
-
if (!
|
|
486
|
+
if (!existsSync6(dir))
|
|
484
487
|
return [];
|
|
485
|
-
return readdirSync2(dir).filter((f) => f.endsWith(".ts")).map((f) =>
|
|
488
|
+
return readdirSync2(dir).filter((f) => f.endsWith(".ts")).map((f) => join5(dir, f));
|
|
486
489
|
}
|
|
487
490
|
function extractRoute(pomContent) {
|
|
488
491
|
const m = pomContent.match(/goto\s*\(\s*['"]([^'"]+)['"]/);
|
|
@@ -509,11 +512,11 @@ function extractPomUsage(specContent) {
|
|
|
509
512
|
return [...names];
|
|
510
513
|
}
|
|
511
514
|
async function recordScriptImpl(repoRoot, ticket) {
|
|
512
|
-
const ticketDir =
|
|
513
|
-
const featurePath =
|
|
514
|
-
const specPath =
|
|
515
|
-
const pomDir =
|
|
516
|
-
if (!
|
|
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");
|
|
519
|
+
if (!existsSync6(featurePath)) {
|
|
517
520
|
console.error(`[graph-record script] feature missing`);
|
|
518
521
|
return 1;
|
|
519
522
|
}
|
|
@@ -551,7 +554,7 @@ async function recordScriptImpl(repoRoot, ticket) {
|
|
|
551
554
|
};
|
|
552
555
|
events.push(mk("xera-script", "pom.generated", pg));
|
|
553
556
|
}
|
|
554
|
-
if (
|
|
557
|
+
if (existsSync6(specPath)) {
|
|
555
558
|
const specContent = readFileSync4(specPath, "utf8");
|
|
556
559
|
const usedPoms = extractPomUsage(specContent);
|
|
557
560
|
for (const scenario of scenarios) {
|
|
@@ -619,7 +622,7 @@ var init_graph_record_script = __esm(() => {
|
|
|
619
622
|
];
|
|
620
623
|
});
|
|
621
624
|
|
|
622
|
-
// ../../node_modules
|
|
625
|
+
// ../../node_modules/yaml/dist/nodes/identity.js
|
|
623
626
|
var require_identity = __commonJS((exports) => {
|
|
624
627
|
var ALIAS = Symbol.for("yaml.alias");
|
|
625
628
|
var DOC = Symbol.for("yaml.document");
|
|
@@ -673,7 +676,7 @@ var require_identity = __commonJS((exports) => {
|
|
|
673
676
|
exports.isSeq = isSeq;
|
|
674
677
|
});
|
|
675
678
|
|
|
676
|
-
// ../../node_modules
|
|
679
|
+
// ../../node_modules/yaml/dist/visit.js
|
|
677
680
|
var require_visit = __commonJS((exports) => {
|
|
678
681
|
var identity = require_identity();
|
|
679
682
|
var BREAK = Symbol("break visit");
|
|
@@ -828,7 +831,7 @@ var require_visit = __commonJS((exports) => {
|
|
|
828
831
|
exports.visitAsync = visitAsync;
|
|
829
832
|
});
|
|
830
833
|
|
|
831
|
-
// ../../node_modules
|
|
834
|
+
// ../../node_modules/yaml/dist/doc/directives.js
|
|
832
835
|
var require_directives = __commonJS((exports) => {
|
|
833
836
|
var identity = require_identity();
|
|
834
837
|
var visit = require_visit();
|
|
@@ -980,7 +983,7 @@ var require_directives = __commonJS((exports) => {
|
|
|
980
983
|
exports.Directives = Directives;
|
|
981
984
|
});
|
|
982
985
|
|
|
983
|
-
// ../../node_modules
|
|
986
|
+
// ../../node_modules/yaml/dist/doc/anchors.js
|
|
984
987
|
var require_anchors = __commonJS((exports) => {
|
|
985
988
|
var identity = require_identity();
|
|
986
989
|
var visit = require_visit();
|
|
@@ -1042,7 +1045,7 @@ var require_anchors = __commonJS((exports) => {
|
|
|
1042
1045
|
exports.findNewAnchor = findNewAnchor;
|
|
1043
1046
|
});
|
|
1044
1047
|
|
|
1045
|
-
// ../../node_modules
|
|
1048
|
+
// ../../node_modules/yaml/dist/doc/applyReviver.js
|
|
1046
1049
|
var require_applyReviver = __commonJS((exports) => {
|
|
1047
1050
|
function applyReviver(reviver, obj, key, val) {
|
|
1048
1051
|
if (val && typeof val === "object") {
|
|
@@ -1089,7 +1092,7 @@ var require_applyReviver = __commonJS((exports) => {
|
|
|
1089
1092
|
exports.applyReviver = applyReviver;
|
|
1090
1093
|
});
|
|
1091
1094
|
|
|
1092
|
-
// ../../node_modules
|
|
1095
|
+
// ../../node_modules/yaml/dist/nodes/toJS.js
|
|
1093
1096
|
var require_toJS = __commonJS((exports) => {
|
|
1094
1097
|
var identity = require_identity();
|
|
1095
1098
|
function toJS(value, arg, ctx) {
|
|
@@ -1116,7 +1119,7 @@ var require_toJS = __commonJS((exports) => {
|
|
|
1116
1119
|
exports.toJS = toJS;
|
|
1117
1120
|
});
|
|
1118
1121
|
|
|
1119
|
-
// ../../node_modules
|
|
1122
|
+
// ../../node_modules/yaml/dist/nodes/Node.js
|
|
1120
1123
|
var require_Node = __commonJS((exports) => {
|
|
1121
1124
|
var applyReviver = require_applyReviver();
|
|
1122
1125
|
var identity = require_identity();
|
|
@@ -1153,7 +1156,7 @@ var require_Node = __commonJS((exports) => {
|
|
|
1153
1156
|
exports.NodeBase = NodeBase;
|
|
1154
1157
|
});
|
|
1155
1158
|
|
|
1156
|
-
// ../../node_modules
|
|
1159
|
+
// ../../node_modules/yaml/dist/nodes/Alias.js
|
|
1157
1160
|
var require_Alias = __commonJS((exports) => {
|
|
1158
1161
|
var anchors = require_anchors();
|
|
1159
1162
|
var visit = require_visit();
|
|
@@ -1263,7 +1266,7 @@ var require_Alias = __commonJS((exports) => {
|
|
|
1263
1266
|
exports.Alias = Alias;
|
|
1264
1267
|
});
|
|
1265
1268
|
|
|
1266
|
-
// ../../node_modules
|
|
1269
|
+
// ../../node_modules/yaml/dist/nodes/Scalar.js
|
|
1267
1270
|
var require_Scalar = __commonJS((exports) => {
|
|
1268
1271
|
var identity = require_identity();
|
|
1269
1272
|
var Node = require_Node();
|
|
@@ -1291,7 +1294,7 @@ var require_Scalar = __commonJS((exports) => {
|
|
|
1291
1294
|
exports.isScalarValue = isScalarValue;
|
|
1292
1295
|
});
|
|
1293
1296
|
|
|
1294
|
-
// ../../node_modules
|
|
1297
|
+
// ../../node_modules/yaml/dist/doc/createNode.js
|
|
1295
1298
|
var require_createNode = __commonJS((exports) => {
|
|
1296
1299
|
var Alias = require_Alias();
|
|
1297
1300
|
var identity = require_identity();
|
|
@@ -1363,7 +1366,7 @@ var require_createNode = __commonJS((exports) => {
|
|
|
1363
1366
|
exports.createNode = createNode;
|
|
1364
1367
|
});
|
|
1365
1368
|
|
|
1366
|
-
// ../../node_modules
|
|
1369
|
+
// ../../node_modules/yaml/dist/nodes/Collection.js
|
|
1367
1370
|
var require_Collection = __commonJS((exports) => {
|
|
1368
1371
|
var createNode = require_createNode();
|
|
1369
1372
|
var identity = require_identity();
|
|
@@ -1478,7 +1481,7 @@ var require_Collection = __commonJS((exports) => {
|
|
|
1478
1481
|
exports.isEmptyPath = isEmptyPath;
|
|
1479
1482
|
});
|
|
1480
1483
|
|
|
1481
|
-
// ../../node_modules
|
|
1484
|
+
// ../../node_modules/yaml/dist/stringify/stringifyComment.js
|
|
1482
1485
|
var require_stringifyComment = __commonJS((exports) => {
|
|
1483
1486
|
var stringifyComment = (str) => str.replace(/^(?!$)(?: $)?/gm, "#");
|
|
1484
1487
|
function indentComment(comment, indent) {
|
|
@@ -1495,7 +1498,7 @@ var require_stringifyComment = __commonJS((exports) => {
|
|
|
1495
1498
|
exports.stringifyComment = stringifyComment;
|
|
1496
1499
|
});
|
|
1497
1500
|
|
|
1498
|
-
// ../../node_modules
|
|
1501
|
+
// ../../node_modules/yaml/dist/stringify/foldFlowLines.js
|
|
1499
1502
|
var require_foldFlowLines = __commonJS((exports) => {
|
|
1500
1503
|
var FOLD_FLOW = "flow";
|
|
1501
1504
|
var FOLD_BLOCK = "block";
|
|
@@ -1632,7 +1635,7 @@ ${indent}${text.slice(fold + 1, end2)}`;
|
|
|
1632
1635
|
exports.foldFlowLines = foldFlowLines;
|
|
1633
1636
|
});
|
|
1634
1637
|
|
|
1635
|
-
// ../../node_modules
|
|
1638
|
+
// ../../node_modules/yaml/dist/stringify/stringifyString.js
|
|
1636
1639
|
var require_stringifyString = __commonJS((exports) => {
|
|
1637
1640
|
var Scalar = require_Scalar();
|
|
1638
1641
|
var foldFlowLines = require_foldFlowLines();
|
|
@@ -1930,7 +1933,7 @@ ${indent}`);
|
|
|
1930
1933
|
exports.stringifyString = stringifyString;
|
|
1931
1934
|
});
|
|
1932
1935
|
|
|
1933
|
-
// ../../node_modules
|
|
1936
|
+
// ../../node_modules/yaml/dist/stringify/stringify.js
|
|
1934
1937
|
var require_stringify = __commonJS((exports) => {
|
|
1935
1938
|
var anchors = require_anchors();
|
|
1936
1939
|
var identity = require_identity();
|
|
@@ -2051,7 +2054,7 @@ ${ctx.indent}${str}`;
|
|
|
2051
2054
|
exports.stringify = stringify;
|
|
2052
2055
|
});
|
|
2053
2056
|
|
|
2054
|
-
// ../../node_modules
|
|
2057
|
+
// ../../node_modules/yaml/dist/stringify/stringifyPair.js
|
|
2055
2058
|
var require_stringifyPair = __commonJS((exports) => {
|
|
2056
2059
|
var identity = require_identity();
|
|
2057
2060
|
var Scalar = require_Scalar();
|
|
@@ -2187,7 +2190,7 @@ ${ctx.indent}`;
|
|
|
2187
2190
|
exports.stringifyPair = stringifyPair;
|
|
2188
2191
|
});
|
|
2189
2192
|
|
|
2190
|
-
// ../../node_modules
|
|
2193
|
+
// ../../node_modules/yaml/dist/log.js
|
|
2191
2194
|
var require_log = __commonJS((exports) => {
|
|
2192
2195
|
var node_process = __require("process");
|
|
2193
2196
|
function debug(logLevel, ...messages) {
|
|
@@ -2206,7 +2209,7 @@ var require_log = __commonJS((exports) => {
|
|
|
2206
2209
|
exports.warn = warn;
|
|
2207
2210
|
});
|
|
2208
2211
|
|
|
2209
|
-
// ../../node_modules
|
|
2212
|
+
// ../../node_modules/yaml/dist/schema/yaml-1.1/merge.js
|
|
2210
2213
|
var require_merge = __commonJS((exports) => {
|
|
2211
2214
|
var identity = require_identity();
|
|
2212
2215
|
var Scalar = require_Scalar();
|
|
@@ -2263,7 +2266,7 @@ var require_merge = __commonJS((exports) => {
|
|
|
2263
2266
|
exports.merge = merge;
|
|
2264
2267
|
});
|
|
2265
2268
|
|
|
2266
|
-
// ../../node_modules
|
|
2269
|
+
// ../../node_modules/yaml/dist/nodes/addPairToJSMap.js
|
|
2267
2270
|
var require_addPairToJSMap = __commonJS((exports) => {
|
|
2268
2271
|
var log = require_log();
|
|
2269
2272
|
var merge = require_merge();
|
|
@@ -2324,7 +2327,7 @@ var require_addPairToJSMap = __commonJS((exports) => {
|
|
|
2324
2327
|
exports.addPairToJSMap = addPairToJSMap;
|
|
2325
2328
|
});
|
|
2326
2329
|
|
|
2327
|
-
// ../../node_modules
|
|
2330
|
+
// ../../node_modules/yaml/dist/nodes/Pair.js
|
|
2328
2331
|
var require_Pair = __commonJS((exports) => {
|
|
2329
2332
|
var createNode = require_createNode();
|
|
2330
2333
|
var stringifyPair = require_stringifyPair();
|
|
@@ -2362,7 +2365,7 @@ var require_Pair = __commonJS((exports) => {
|
|
|
2362
2365
|
exports.createPair = createPair;
|
|
2363
2366
|
});
|
|
2364
2367
|
|
|
2365
|
-
// ../../node_modules
|
|
2368
|
+
// ../../node_modules/yaml/dist/stringify/stringifyCollection.js
|
|
2366
2369
|
var require_stringifyCollection = __commonJS((exports) => {
|
|
2367
2370
|
var identity = require_identity();
|
|
2368
2371
|
var stringify = require_stringify();
|
|
@@ -2514,7 +2517,7 @@ ${indent}${end}`;
|
|
|
2514
2517
|
exports.stringifyCollection = stringifyCollection;
|
|
2515
2518
|
});
|
|
2516
2519
|
|
|
2517
|
-
// ../../node_modules
|
|
2520
|
+
// ../../node_modules/yaml/dist/nodes/YAMLMap.js
|
|
2518
2521
|
var require_YAMLMap = __commonJS((exports) => {
|
|
2519
2522
|
var stringifyCollection = require_stringifyCollection();
|
|
2520
2523
|
var addPairToJSMap = require_addPairToJSMap();
|
|
@@ -2641,7 +2644,7 @@ var require_YAMLMap = __commonJS((exports) => {
|
|
|
2641
2644
|
exports.findPair = findPair;
|
|
2642
2645
|
});
|
|
2643
2646
|
|
|
2644
|
-
// ../../node_modules
|
|
2647
|
+
// ../../node_modules/yaml/dist/schema/common/map.js
|
|
2645
2648
|
var require_map = __commonJS((exports) => {
|
|
2646
2649
|
var identity = require_identity();
|
|
2647
2650
|
var YAMLMap = require_YAMLMap();
|
|
@@ -2660,7 +2663,7 @@ var require_map = __commonJS((exports) => {
|
|
|
2660
2663
|
exports.map = map;
|
|
2661
2664
|
});
|
|
2662
2665
|
|
|
2663
|
-
// ../../node_modules
|
|
2666
|
+
// ../../node_modules/yaml/dist/nodes/YAMLSeq.js
|
|
2664
2667
|
var require_YAMLSeq = __commonJS((exports) => {
|
|
2665
2668
|
var createNode = require_createNode();
|
|
2666
2669
|
var stringifyCollection = require_stringifyCollection();
|
|
@@ -2753,7 +2756,7 @@ var require_YAMLSeq = __commonJS((exports) => {
|
|
|
2753
2756
|
exports.YAMLSeq = YAMLSeq;
|
|
2754
2757
|
});
|
|
2755
2758
|
|
|
2756
|
-
// ../../node_modules
|
|
2759
|
+
// ../../node_modules/yaml/dist/schema/common/seq.js
|
|
2757
2760
|
var require_seq = __commonJS((exports) => {
|
|
2758
2761
|
var identity = require_identity();
|
|
2759
2762
|
var YAMLSeq = require_YAMLSeq();
|
|
@@ -2772,7 +2775,7 @@ var require_seq = __commonJS((exports) => {
|
|
|
2772
2775
|
exports.seq = seq;
|
|
2773
2776
|
});
|
|
2774
2777
|
|
|
2775
|
-
// ../../node_modules
|
|
2778
|
+
// ../../node_modules/yaml/dist/schema/common/string.js
|
|
2776
2779
|
var require_string = __commonJS((exports) => {
|
|
2777
2780
|
var stringifyString = require_stringifyString();
|
|
2778
2781
|
var string = {
|
|
@@ -2788,7 +2791,7 @@ var require_string = __commonJS((exports) => {
|
|
|
2788
2791
|
exports.string = string;
|
|
2789
2792
|
});
|
|
2790
2793
|
|
|
2791
|
-
// ../../node_modules
|
|
2794
|
+
// ../../node_modules/yaml/dist/schema/common/null.js
|
|
2792
2795
|
var require_null = __commonJS((exports) => {
|
|
2793
2796
|
var Scalar = require_Scalar();
|
|
2794
2797
|
var nullTag = {
|
|
@@ -2803,7 +2806,7 @@ var require_null = __commonJS((exports) => {
|
|
|
2803
2806
|
exports.nullTag = nullTag;
|
|
2804
2807
|
});
|
|
2805
2808
|
|
|
2806
|
-
// ../../node_modules
|
|
2809
|
+
// ../../node_modules/yaml/dist/schema/core/bool.js
|
|
2807
2810
|
var require_bool = __commonJS((exports) => {
|
|
2808
2811
|
var Scalar = require_Scalar();
|
|
2809
2812
|
var boolTag = {
|
|
@@ -2824,7 +2827,7 @@ var require_bool = __commonJS((exports) => {
|
|
|
2824
2827
|
exports.boolTag = boolTag;
|
|
2825
2828
|
});
|
|
2826
2829
|
|
|
2827
|
-
// ../../node_modules
|
|
2830
|
+
// ../../node_modules/yaml/dist/stringify/stringifyNumber.js
|
|
2828
2831
|
var require_stringifyNumber = __commonJS((exports) => {
|
|
2829
2832
|
function stringifyNumber({ format, minFractionDigits, tag, value }) {
|
|
2830
2833
|
if (typeof value === "bigint")
|
|
@@ -2848,7 +2851,7 @@ var require_stringifyNumber = __commonJS((exports) => {
|
|
|
2848
2851
|
exports.stringifyNumber = stringifyNumber;
|
|
2849
2852
|
});
|
|
2850
2853
|
|
|
2851
|
-
// ../../node_modules
|
|
2854
|
+
// ../../node_modules/yaml/dist/schema/core/float.js
|
|
2852
2855
|
var require_float = __commonJS((exports) => {
|
|
2853
2856
|
var Scalar = require_Scalar();
|
|
2854
2857
|
var stringifyNumber = require_stringifyNumber();
|
|
@@ -2891,7 +2894,7 @@ var require_float = __commonJS((exports) => {
|
|
|
2891
2894
|
exports.floatNaN = floatNaN;
|
|
2892
2895
|
});
|
|
2893
2896
|
|
|
2894
|
-
// ../../node_modules
|
|
2897
|
+
// ../../node_modules/yaml/dist/schema/core/int.js
|
|
2895
2898
|
var require_int = __commonJS((exports) => {
|
|
2896
2899
|
var stringifyNumber = require_stringifyNumber();
|
|
2897
2900
|
var intIdentify = (value) => typeof value === "bigint" || Number.isInteger(value);
|
|
@@ -2933,7 +2936,7 @@ var require_int = __commonJS((exports) => {
|
|
|
2933
2936
|
exports.intOct = intOct;
|
|
2934
2937
|
});
|
|
2935
2938
|
|
|
2936
|
-
// ../../node_modules
|
|
2939
|
+
// ../../node_modules/yaml/dist/schema/core/schema.js
|
|
2937
2940
|
var require_schema = __commonJS((exports) => {
|
|
2938
2941
|
var map = require_map();
|
|
2939
2942
|
var _null = require_null();
|
|
@@ -2958,7 +2961,7 @@ var require_schema = __commonJS((exports) => {
|
|
|
2958
2961
|
exports.schema = schema;
|
|
2959
2962
|
});
|
|
2960
2963
|
|
|
2961
|
-
// ../../node_modules
|
|
2964
|
+
// ../../node_modules/yaml/dist/schema/json/schema.js
|
|
2962
2965
|
var require_schema2 = __commonJS((exports) => {
|
|
2963
2966
|
var Scalar = require_Scalar();
|
|
2964
2967
|
var map = require_map();
|
|
@@ -3022,7 +3025,7 @@ var require_schema2 = __commonJS((exports) => {
|
|
|
3022
3025
|
exports.schema = schema;
|
|
3023
3026
|
});
|
|
3024
3027
|
|
|
3025
|
-
// ../../node_modules
|
|
3028
|
+
// ../../node_modules/yaml/dist/schema/yaml-1.1/binary.js
|
|
3026
3029
|
var require_binary = __commonJS((exports) => {
|
|
3027
3030
|
var node_buffer = __require("buffer");
|
|
3028
3031
|
var Scalar = require_Scalar();
|
|
@@ -3077,7 +3080,7 @@ var require_binary = __commonJS((exports) => {
|
|
|
3077
3080
|
exports.binary = binary;
|
|
3078
3081
|
});
|
|
3079
3082
|
|
|
3080
|
-
// ../../node_modules
|
|
3083
|
+
// ../../node_modules/yaml/dist/schema/yaml-1.1/pairs.js
|
|
3081
3084
|
var require_pairs = __commonJS((exports) => {
|
|
3082
3085
|
var identity = require_identity();
|
|
3083
3086
|
var Pair = require_Pair();
|
|
@@ -3152,7 +3155,7 @@ ${cn.comment}` : item.comment;
|
|
|
3152
3155
|
exports.resolvePairs = resolvePairs;
|
|
3153
3156
|
});
|
|
3154
3157
|
|
|
3155
|
-
// ../../node_modules
|
|
3158
|
+
// ../../node_modules/yaml/dist/schema/yaml-1.1/omap.js
|
|
3156
3159
|
var require_omap = __commonJS((exports) => {
|
|
3157
3160
|
var identity = require_identity();
|
|
3158
3161
|
var toJS = require_toJS();
|
|
@@ -3224,7 +3227,7 @@ var require_omap = __commonJS((exports) => {
|
|
|
3224
3227
|
exports.omap = omap;
|
|
3225
3228
|
});
|
|
3226
3229
|
|
|
3227
|
-
// ../../node_modules
|
|
3230
|
+
// ../../node_modules/yaml/dist/schema/yaml-1.1/bool.js
|
|
3228
3231
|
var require_bool2 = __commonJS((exports) => {
|
|
3229
3232
|
var Scalar = require_Scalar();
|
|
3230
3233
|
function boolStringify({ value, source }, ctx) {
|
|
@@ -3253,7 +3256,7 @@ var require_bool2 = __commonJS((exports) => {
|
|
|
3253
3256
|
exports.trueTag = trueTag;
|
|
3254
3257
|
});
|
|
3255
3258
|
|
|
3256
|
-
// ../../node_modules
|
|
3259
|
+
// ../../node_modules/yaml/dist/schema/yaml-1.1/float.js
|
|
3257
3260
|
var require_float2 = __commonJS((exports) => {
|
|
3258
3261
|
var Scalar = require_Scalar();
|
|
3259
3262
|
var stringifyNumber = require_stringifyNumber();
|
|
@@ -3299,7 +3302,7 @@ var require_float2 = __commonJS((exports) => {
|
|
|
3299
3302
|
exports.floatNaN = floatNaN;
|
|
3300
3303
|
});
|
|
3301
3304
|
|
|
3302
|
-
// ../../node_modules
|
|
3305
|
+
// ../../node_modules/yaml/dist/schema/yaml-1.1/int.js
|
|
3303
3306
|
var require_int2 = __commonJS((exports) => {
|
|
3304
3307
|
var stringifyNumber = require_stringifyNumber();
|
|
3305
3308
|
var intIdentify = (value) => typeof value === "bigint" || Number.isInteger(value);
|
|
@@ -3375,7 +3378,7 @@ var require_int2 = __commonJS((exports) => {
|
|
|
3375
3378
|
exports.intOct = intOct;
|
|
3376
3379
|
});
|
|
3377
3380
|
|
|
3378
|
-
// ../../node_modules
|
|
3381
|
+
// ../../node_modules/yaml/dist/schema/yaml-1.1/set.js
|
|
3379
3382
|
var require_set = __commonJS((exports) => {
|
|
3380
3383
|
var identity = require_identity();
|
|
3381
3384
|
var Pair = require_Pair();
|
|
@@ -3458,7 +3461,7 @@ var require_set = __commonJS((exports) => {
|
|
|
3458
3461
|
exports.set = set;
|
|
3459
3462
|
});
|
|
3460
3463
|
|
|
3461
|
-
// ../../node_modules
|
|
3464
|
+
// ../../node_modules/yaml/dist/schema/yaml-1.1/timestamp.js
|
|
3462
3465
|
var require_timestamp = __commonJS((exports) => {
|
|
3463
3466
|
var stringifyNumber = require_stringifyNumber();
|
|
3464
3467
|
function parseSexagesimal(str, asBigInt) {
|
|
@@ -3540,7 +3543,7 @@ var require_timestamp = __commonJS((exports) => {
|
|
|
3540
3543
|
exports.timestamp = timestamp;
|
|
3541
3544
|
});
|
|
3542
3545
|
|
|
3543
|
-
// ../../node_modules
|
|
3546
|
+
// ../../node_modules/yaml/dist/schema/yaml-1.1/schema.js
|
|
3544
3547
|
var require_schema3 = __commonJS((exports) => {
|
|
3545
3548
|
var map = require_map();
|
|
3546
3549
|
var _null = require_null();
|
|
@@ -3581,7 +3584,7 @@ var require_schema3 = __commonJS((exports) => {
|
|
|
3581
3584
|
exports.schema = schema;
|
|
3582
3585
|
});
|
|
3583
3586
|
|
|
3584
|
-
// ../../node_modules
|
|
3587
|
+
// ../../node_modules/yaml/dist/schema/tags.js
|
|
3585
3588
|
var require_tags = __commonJS((exports) => {
|
|
3586
3589
|
var map = require_map();
|
|
3587
3590
|
var _null = require_null();
|
|
@@ -3672,7 +3675,7 @@ var require_tags = __commonJS((exports) => {
|
|
|
3672
3675
|
exports.getTags = getTags;
|
|
3673
3676
|
});
|
|
3674
3677
|
|
|
3675
|
-
// ../../node_modules
|
|
3678
|
+
// ../../node_modules/yaml/dist/schema/Schema.js
|
|
3676
3679
|
var require_Schema = __commonJS((exports) => {
|
|
3677
3680
|
var identity = require_identity();
|
|
3678
3681
|
var map = require_map();
|
|
@@ -3702,7 +3705,7 @@ var require_Schema = __commonJS((exports) => {
|
|
|
3702
3705
|
exports.Schema = Schema;
|
|
3703
3706
|
});
|
|
3704
3707
|
|
|
3705
|
-
// ../../node_modules
|
|
3708
|
+
// ../../node_modules/yaml/dist/stringify/stringifyDocument.js
|
|
3706
3709
|
var require_stringifyDocument = __commonJS((exports) => {
|
|
3707
3710
|
var identity = require_identity();
|
|
3708
3711
|
var stringify = require_stringify();
|
|
@@ -3782,7 +3785,7 @@ var require_stringifyDocument = __commonJS((exports) => {
|
|
|
3782
3785
|
exports.stringifyDocument = stringifyDocument;
|
|
3783
3786
|
});
|
|
3784
3787
|
|
|
3785
|
-
// ../../node_modules
|
|
3788
|
+
// ../../node_modules/yaml/dist/doc/Document.js
|
|
3786
3789
|
var require_Document = __commonJS((exports) => {
|
|
3787
3790
|
var Alias = require_Alias();
|
|
3788
3791
|
var Collection = require_Collection();
|
|
@@ -4017,7 +4020,7 @@ var require_Document = __commonJS((exports) => {
|
|
|
4017
4020
|
exports.Document = Document;
|
|
4018
4021
|
});
|
|
4019
4022
|
|
|
4020
|
-
// ../../node_modules
|
|
4023
|
+
// ../../node_modules/yaml/dist/errors.js
|
|
4021
4024
|
var require_errors = __commonJS((exports) => {
|
|
4022
4025
|
class YAMLError extends Error {
|
|
4023
4026
|
constructor(name, pos, code, message) {
|
|
@@ -4082,7 +4085,7 @@ ${pointer}
|
|
|
4082
4085
|
exports.prettifyError = prettifyError;
|
|
4083
4086
|
});
|
|
4084
4087
|
|
|
4085
|
-
// ../../node_modules
|
|
4088
|
+
// ../../node_modules/yaml/dist/compose/resolve-props.js
|
|
4086
4089
|
var require_resolve_props = __commonJS((exports) => {
|
|
4087
4090
|
function resolveProps(tokens, { flow, indicator, next, offset, onError, parentIndent, startOnNewline }) {
|
|
4088
4091
|
let spaceBefore = false;
|
|
@@ -4212,7 +4215,7 @@ var require_resolve_props = __commonJS((exports) => {
|
|
|
4212
4215
|
exports.resolveProps = resolveProps;
|
|
4213
4216
|
});
|
|
4214
4217
|
|
|
4215
|
-
// ../../node_modules
|
|
4218
|
+
// ../../node_modules/yaml/dist/compose/util-contains-newline.js
|
|
4216
4219
|
var require_util_contains_newline = __commonJS((exports) => {
|
|
4217
4220
|
function containsNewline(key) {
|
|
4218
4221
|
if (!key)
|
|
@@ -4252,7 +4255,7 @@ var require_util_contains_newline = __commonJS((exports) => {
|
|
|
4252
4255
|
exports.containsNewline = containsNewline;
|
|
4253
4256
|
});
|
|
4254
4257
|
|
|
4255
|
-
// ../../node_modules
|
|
4258
|
+
// ../../node_modules/yaml/dist/compose/util-flow-indent-check.js
|
|
4256
4259
|
var require_util_flow_indent_check = __commonJS((exports) => {
|
|
4257
4260
|
var utilContainsNewline = require_util_contains_newline();
|
|
4258
4261
|
function flowIndentCheck(indent, fc, onError) {
|
|
@@ -4267,7 +4270,7 @@ var require_util_flow_indent_check = __commonJS((exports) => {
|
|
|
4267
4270
|
exports.flowIndentCheck = flowIndentCheck;
|
|
4268
4271
|
});
|
|
4269
4272
|
|
|
4270
|
-
// ../../node_modules
|
|
4273
|
+
// ../../node_modules/yaml/dist/compose/util-map-includes.js
|
|
4271
4274
|
var require_util_map_includes = __commonJS((exports) => {
|
|
4272
4275
|
var identity = require_identity();
|
|
4273
4276
|
function mapIncludes(ctx, items, search) {
|
|
@@ -4280,7 +4283,7 @@ var require_util_map_includes = __commonJS((exports) => {
|
|
|
4280
4283
|
exports.mapIncludes = mapIncludes;
|
|
4281
4284
|
});
|
|
4282
4285
|
|
|
4283
|
-
// ../../node_modules
|
|
4286
|
+
// ../../node_modules/yaml/dist/compose/resolve-block-map.js
|
|
4284
4287
|
var require_resolve_block_map = __commonJS((exports) => {
|
|
4285
4288
|
var Pair = require_Pair();
|
|
4286
4289
|
var YAMLMap = require_YAMLMap();
|
|
@@ -4387,7 +4390,7 @@ var require_resolve_block_map = __commonJS((exports) => {
|
|
|
4387
4390
|
exports.resolveBlockMap = resolveBlockMap;
|
|
4388
4391
|
});
|
|
4389
4392
|
|
|
4390
|
-
// ../../node_modules
|
|
4393
|
+
// ../../node_modules/yaml/dist/compose/resolve-block-seq.js
|
|
4391
4394
|
var require_resolve_block_seq = __commonJS((exports) => {
|
|
4392
4395
|
var YAMLSeq = require_YAMLSeq();
|
|
4393
4396
|
var resolveProps = require_resolve_props();
|
|
@@ -4435,7 +4438,7 @@ var require_resolve_block_seq = __commonJS((exports) => {
|
|
|
4435
4438
|
exports.resolveBlockSeq = resolveBlockSeq;
|
|
4436
4439
|
});
|
|
4437
4440
|
|
|
4438
|
-
// ../../node_modules
|
|
4441
|
+
// ../../node_modules/yaml/dist/compose/resolve-end.js
|
|
4439
4442
|
var require_resolve_end = __commonJS((exports) => {
|
|
4440
4443
|
function resolveEnd(end, offset, reqSpace, onError) {
|
|
4441
4444
|
let comment = "";
|
|
@@ -4475,7 +4478,7 @@ var require_resolve_end = __commonJS((exports) => {
|
|
|
4475
4478
|
exports.resolveEnd = resolveEnd;
|
|
4476
4479
|
});
|
|
4477
4480
|
|
|
4478
|
-
// ../../node_modules
|
|
4481
|
+
// ../../node_modules/yaml/dist/compose/resolve-flow-collection.js
|
|
4479
4482
|
var require_resolve_flow_collection = __commonJS((exports) => {
|
|
4480
4483
|
var identity = require_identity();
|
|
4481
4484
|
var Pair = require_Pair();
|
|
@@ -4666,7 +4669,7 @@ var require_resolve_flow_collection = __commonJS((exports) => {
|
|
|
4666
4669
|
exports.resolveFlowCollection = resolveFlowCollection;
|
|
4667
4670
|
});
|
|
4668
4671
|
|
|
4669
|
-
// ../../node_modules
|
|
4672
|
+
// ../../node_modules/yaml/dist/compose/compose-collection.js
|
|
4670
4673
|
var require_compose_collection = __commonJS((exports) => {
|
|
4671
4674
|
var identity = require_identity();
|
|
4672
4675
|
var Scalar = require_Scalar();
|
|
@@ -4728,7 +4731,7 @@ var require_compose_collection = __commonJS((exports) => {
|
|
|
4728
4731
|
exports.composeCollection = composeCollection;
|
|
4729
4732
|
});
|
|
4730
4733
|
|
|
4731
|
-
// ../../node_modules
|
|
4734
|
+
// ../../node_modules/yaml/dist/compose/resolve-block-scalar.js
|
|
4732
4735
|
var require_resolve_block_scalar = __commonJS((exports) => {
|
|
4733
4736
|
var Scalar = require_Scalar();
|
|
4734
4737
|
function resolveBlockScalar(ctx, scalar, onError) {
|
|
@@ -4921,7 +4924,7 @@ var require_resolve_block_scalar = __commonJS((exports) => {
|
|
|
4921
4924
|
exports.resolveBlockScalar = resolveBlockScalar;
|
|
4922
4925
|
});
|
|
4923
4926
|
|
|
4924
|
-
// ../../node_modules
|
|
4927
|
+
// ../../node_modules/yaml/dist/compose/resolve-flow-scalar.js
|
|
4925
4928
|
var require_resolve_flow_scalar = __commonJS((exports) => {
|
|
4926
4929
|
var Scalar = require_Scalar();
|
|
4927
4930
|
var resolveEnd = require_resolve_end();
|
|
@@ -5138,7 +5141,7 @@ var require_resolve_flow_scalar = __commonJS((exports) => {
|
|
|
5138
5141
|
exports.resolveFlowScalar = resolveFlowScalar;
|
|
5139
5142
|
});
|
|
5140
5143
|
|
|
5141
|
-
// ../../node_modules
|
|
5144
|
+
// ../../node_modules/yaml/dist/compose/compose-scalar.js
|
|
5142
5145
|
var require_compose_scalar = __commonJS((exports) => {
|
|
5143
5146
|
var identity = require_identity();
|
|
5144
5147
|
var Scalar = require_Scalar();
|
|
@@ -5216,7 +5219,7 @@ var require_compose_scalar = __commonJS((exports) => {
|
|
|
5216
5219
|
exports.composeScalar = composeScalar;
|
|
5217
5220
|
});
|
|
5218
5221
|
|
|
5219
|
-
// ../../node_modules
|
|
5222
|
+
// ../../node_modules/yaml/dist/compose/util-empty-scalar-position.js
|
|
5220
5223
|
var require_util_empty_scalar_position = __commonJS((exports) => {
|
|
5221
5224
|
function emptyScalarPosition(offset, before, pos) {
|
|
5222
5225
|
if (before) {
|
|
@@ -5243,7 +5246,7 @@ var require_util_empty_scalar_position = __commonJS((exports) => {
|
|
|
5243
5246
|
exports.emptyScalarPosition = emptyScalarPosition;
|
|
5244
5247
|
});
|
|
5245
5248
|
|
|
5246
|
-
// ../../node_modules
|
|
5249
|
+
// ../../node_modules/yaml/dist/compose/compose-node.js
|
|
5247
5250
|
var require_compose_node = __commonJS((exports) => {
|
|
5248
5251
|
var Alias = require_Alias();
|
|
5249
5252
|
var identity = require_identity();
|
|
@@ -5346,7 +5349,7 @@ var require_compose_node = __commonJS((exports) => {
|
|
|
5346
5349
|
exports.composeNode = composeNode;
|
|
5347
5350
|
});
|
|
5348
5351
|
|
|
5349
|
-
// ../../node_modules
|
|
5352
|
+
// ../../node_modules/yaml/dist/compose/compose-doc.js
|
|
5350
5353
|
var require_compose_doc = __commonJS((exports) => {
|
|
5351
5354
|
var Document = require_Document();
|
|
5352
5355
|
var composeNode = require_compose_node();
|
|
@@ -5386,7 +5389,7 @@ var require_compose_doc = __commonJS((exports) => {
|
|
|
5386
5389
|
exports.composeDoc = composeDoc;
|
|
5387
5390
|
});
|
|
5388
5391
|
|
|
5389
|
-
// ../../node_modules
|
|
5392
|
+
// ../../node_modules/yaml/dist/compose/composer.js
|
|
5390
5393
|
var require_composer = __commonJS((exports) => {
|
|
5391
5394
|
var node_process = __require("process");
|
|
5392
5395
|
var directives = require_directives();
|
|
@@ -5577,7 +5580,7 @@ ${end.comment}` : end.comment;
|
|
|
5577
5580
|
exports.Composer = Composer;
|
|
5578
5581
|
});
|
|
5579
5582
|
|
|
5580
|
-
// ../../node_modules
|
|
5583
|
+
// ../../node_modules/yaml/dist/parse/cst-scalar.js
|
|
5581
5584
|
var require_cst_scalar = __commonJS((exports) => {
|
|
5582
5585
|
var resolveBlockScalar = require_resolve_block_scalar();
|
|
5583
5586
|
var resolveFlowScalar = require_resolve_flow_scalar();
|
|
@@ -5767,7 +5770,7 @@ var require_cst_scalar = __commonJS((exports) => {
|
|
|
5767
5770
|
exports.setScalarValue = setScalarValue;
|
|
5768
5771
|
});
|
|
5769
5772
|
|
|
5770
|
-
// ../../node_modules
|
|
5773
|
+
// ../../node_modules/yaml/dist/parse/cst-stringify.js
|
|
5771
5774
|
var require_cst_stringify = __commonJS((exports) => {
|
|
5772
5775
|
var stringify = (cst) => ("type" in cst) ? stringifyToken(cst) : stringifyItem(cst);
|
|
5773
5776
|
function stringifyToken(token) {
|
|
@@ -5825,7 +5828,7 @@ var require_cst_stringify = __commonJS((exports) => {
|
|
|
5825
5828
|
exports.stringify = stringify;
|
|
5826
5829
|
});
|
|
5827
5830
|
|
|
5828
|
-
// ../../node_modules
|
|
5831
|
+
// ../../node_modules/yaml/dist/parse/cst-visit.js
|
|
5829
5832
|
var require_cst_visit = __commonJS((exports) => {
|
|
5830
5833
|
var BREAK = Symbol("break visit");
|
|
5831
5834
|
var SKIP = Symbol("skip children");
|
|
@@ -5884,7 +5887,7 @@ var require_cst_visit = __commonJS((exports) => {
|
|
|
5884
5887
|
exports.visit = visit;
|
|
5885
5888
|
});
|
|
5886
5889
|
|
|
5887
|
-
// ../../node_modules
|
|
5890
|
+
// ../../node_modules/yaml/dist/parse/cst.js
|
|
5888
5891
|
var require_cst = __commonJS((exports) => {
|
|
5889
5892
|
var cstScalar = require_cst_scalar();
|
|
5890
5893
|
var cstStringify = require_cst_stringify();
|
|
@@ -5985,7 +5988,7 @@ var require_cst = __commonJS((exports) => {
|
|
|
5985
5988
|
exports.tokenType = tokenType;
|
|
5986
5989
|
});
|
|
5987
5990
|
|
|
5988
|
-
// ../../node_modules
|
|
5991
|
+
// ../../node_modules/yaml/dist/parse/lexer.js
|
|
5989
5992
|
var require_lexer = __commonJS((exports) => {
|
|
5990
5993
|
var cst = require_cst();
|
|
5991
5994
|
function isEmpty(ch) {
|
|
@@ -6582,7 +6585,7 @@ var require_lexer = __commonJS((exports) => {
|
|
|
6582
6585
|
exports.Lexer = Lexer;
|
|
6583
6586
|
});
|
|
6584
6587
|
|
|
6585
|
-
// ../../node_modules
|
|
6588
|
+
// ../../node_modules/yaml/dist/parse/line-counter.js
|
|
6586
6589
|
var require_line_counter = __commonJS((exports) => {
|
|
6587
6590
|
class LineCounter {
|
|
6588
6591
|
constructor() {
|
|
@@ -6610,7 +6613,7 @@ var require_line_counter = __commonJS((exports) => {
|
|
|
6610
6613
|
exports.LineCounter = LineCounter;
|
|
6611
6614
|
});
|
|
6612
6615
|
|
|
6613
|
-
// ../../node_modules
|
|
6616
|
+
// ../../node_modules/yaml/dist/parse/parser.js
|
|
6614
6617
|
var require_parser = __commonJS((exports) => {
|
|
6615
6618
|
var node_process = __require("process");
|
|
6616
6619
|
var cst = require_cst();
|
|
@@ -7466,7 +7469,7 @@ var require_parser = __commonJS((exports) => {
|
|
|
7466
7469
|
exports.Parser = Parser;
|
|
7467
7470
|
});
|
|
7468
7471
|
|
|
7469
|
-
// ../../node_modules
|
|
7472
|
+
// ../../node_modules/yaml/dist/public-api.js
|
|
7470
7473
|
var require_public_api = __commonJS((exports) => {
|
|
7471
7474
|
var composer = require_composer();
|
|
7472
7475
|
var Document = require_Document();
|
|
@@ -7560,7 +7563,7 @@ var require_public_api = __commonJS((exports) => {
|
|
|
7560
7563
|
exports.stringify = stringify;
|
|
7561
7564
|
});
|
|
7562
7565
|
|
|
7563
|
-
// ../../node_modules
|
|
7566
|
+
// ../../node_modules/yaml/dist/index.js
|
|
7564
7567
|
var composer, Document, Schema, errors, Alias, identity, Pair, Scalar, YAMLMap, YAMLSeq, cst, lexer, lineCounter, parser, publicApi, visit, $Composer, $Document, $Schema, $YAMLError, $YAMLParseError, $YAMLWarning, $Alias, $isAlias, $isCollection, $isDocument, $isMap, $isNode, $isPair, $isScalar, $isSeq, $Pair, $Scalar, $YAMLMap, $YAMLSeq, $Lexer, $LineCounter, $Parser, $parse, $parseAllDocuments, $parseDocument, $stringify, $visit, $visitAsync;
|
|
7565
7568
|
var init_dist = __esm(() => {
|
|
7566
7569
|
composer = require_composer();
|
|
@@ -7616,8 +7619,8 @@ __export(exports_graph_record, {
|
|
|
7616
7619
|
graphRecordCmd: () => graphRecordCmd
|
|
7617
7620
|
});
|
|
7618
7621
|
import { createHash as createHash3 } from "crypto";
|
|
7619
|
-
import { existsSync as
|
|
7620
|
-
import { basename as basename2, join as
|
|
7622
|
+
import { existsSync as existsSync7, readFileSync as readFileSync5 } from "fs";
|
|
7623
|
+
import { basename as basename2, join as join6 } from "path";
|
|
7621
7624
|
function nowIso2() {
|
|
7622
7625
|
return new Date().toISOString();
|
|
7623
7626
|
}
|
|
@@ -7641,8 +7644,8 @@ function makeEvent(actor, type, payload) {
|
|
|
7641
7644
|
};
|
|
7642
7645
|
}
|
|
7643
7646
|
function readStoryFrontmatter(repoRoot, ticket) {
|
|
7644
|
-
const path =
|
|
7645
|
-
if (!
|
|
7647
|
+
const path = join6(repoRoot, ".xera", ticket, "story.md");
|
|
7648
|
+
if (!existsSync7(path))
|
|
7646
7649
|
return null;
|
|
7647
7650
|
const raw = readFileSync5(path, "utf8");
|
|
7648
7651
|
const m = raw.match(/^---\n([\s\S]*?)\n---/);
|
|
@@ -7651,8 +7654,8 @@ function readStoryFrontmatter(repoRoot, ticket) {
|
|
|
7651
7654
|
return $parse(m[1]);
|
|
7652
7655
|
}
|
|
7653
7656
|
function readGraphInput(repoRoot, ticket) {
|
|
7654
|
-
const path =
|
|
7655
|
-
if (!
|
|
7657
|
+
const path = join6(repoRoot, ".xera", ticket, "graph-input.json");
|
|
7658
|
+
if (!existsSync7(path))
|
|
7656
7659
|
return { modifiesAreas: [] };
|
|
7657
7660
|
try {
|
|
7658
7661
|
return JSON.parse(readFileSync5(path, "utf8"));
|
|
@@ -7703,8 +7706,8 @@ async function recordScript(repoRoot, ticket) {
|
|
|
7703
7706
|
return recordScriptImpl2(repoRoot, ticket);
|
|
7704
7707
|
}
|
|
7705
7708
|
async function recordExec(repoRoot, ticket, runId) {
|
|
7706
|
-
const reporterPath =
|
|
7707
|
-
if (!
|
|
7709
|
+
const reporterPath = join6(repoRoot, ".xera", ticket, "runs", runId, "reporter.json");
|
|
7710
|
+
if (!existsSync7(reporterPath)) {
|
|
7708
7711
|
console.error(`[graph-record exec] reporter.json missing`);
|
|
7709
7712
|
return 1;
|
|
7710
7713
|
}
|
|
@@ -7726,8 +7729,8 @@ async function recordExec(repoRoot, ticket, runId) {
|
|
|
7726
7729
|
return 0;
|
|
7727
7730
|
}
|
|
7728
7731
|
async function recordClassify(repoRoot, ticket, runId) {
|
|
7729
|
-
const classifyPath =
|
|
7730
|
-
if (!
|
|
7732
|
+
const classifyPath = join6(repoRoot, ".xera", ticket, "runs", runId, "classifier-output.json");
|
|
7733
|
+
if (!existsSync7(classifyPath)) {
|
|
7731
7734
|
console.error(`[graph-record classify] classifier-output.json missing`);
|
|
7732
7735
|
return 1;
|
|
7733
7736
|
}
|
|
@@ -7834,7 +7837,10 @@ async function graphRecordCmd(argv) {
|
|
|
7834
7837
|
"SELECTOR_DRIFT",
|
|
7835
7838
|
"FLAKY",
|
|
7836
7839
|
"PASS",
|
|
7837
|
-
"TEST_OUTDATED"
|
|
7840
|
+
"TEST_OUTDATED",
|
|
7841
|
+
"CONTRACT_DRIFT",
|
|
7842
|
+
"RATE_LIMITED",
|
|
7843
|
+
"AUTH_EXPIRED"
|
|
7838
7844
|
];
|
|
7839
7845
|
if (!validClass.includes(from) || !validClass.includes(to)) {
|
|
7840
7846
|
console.error(`[graph-record dispute] --from and --to must be one of: ${validClass.join(", ")}`);
|
|
@@ -7869,11 +7875,11 @@ var exports_graph_backfill = {};
|
|
|
7869
7875
|
__export(exports_graph_backfill, {
|
|
7870
7876
|
graphBackfillCmd: () => graphBackfillCmd
|
|
7871
7877
|
});
|
|
7872
|
-
import { existsSync as
|
|
7873
|
-
import { join as
|
|
7878
|
+
import { existsSync as existsSync8, readdirSync as readdirSync3 } from "fs";
|
|
7879
|
+
import { join as join7 } from "path";
|
|
7874
7880
|
async function backfillTicket(repoRoot, ticket, dryRun) {
|
|
7875
|
-
const storyPath =
|
|
7876
|
-
if (!
|
|
7881
|
+
const storyPath = join7(repoRoot, ".xera", ticket, "story.md");
|
|
7882
|
+
if (!existsSync8(storyPath))
|
|
7877
7883
|
return 0;
|
|
7878
7884
|
const { recordFetch: recordFetch2 } = await Promise.resolve().then(() => (init_graph_record(), exports_graph_record));
|
|
7879
7885
|
if (dryRun) {
|
|
@@ -7887,8 +7893,8 @@ async function backfillTicket(repoRoot, ticket, dryRun) {
|
|
|
7887
7893
|
async function graphBackfillCmd(argv) {
|
|
7888
7894
|
const dryRun = argv.includes("--dry-run");
|
|
7889
7895
|
const repoRoot = process.cwd();
|
|
7890
|
-
const xeraDir =
|
|
7891
|
-
if (!
|
|
7896
|
+
const xeraDir = join7(repoRoot, ".xera");
|
|
7897
|
+
if (!existsSync8(xeraDir)) {
|
|
7892
7898
|
console.log("[backfill] no .xera/ directory");
|
|
7893
7899
|
return 0;
|
|
7894
7900
|
}
|
|
@@ -7914,6 +7920,212 @@ var init_graph_backfill = __esm(() => {
|
|
|
7914
7920
|
init_graph_record_script();
|
|
7915
7921
|
});
|
|
7916
7922
|
|
|
7923
|
+
// src/bin-internal/auth-setup.ts
|
|
7924
|
+
import { existsSync as existsSync2 } from "fs";
|
|
7925
|
+
import { join as join2 } from "path";
|
|
7926
|
+
import { pathToFileURL as pathToFileURL2 } from "url";
|
|
7927
|
+
|
|
7928
|
+
// src/config/load.ts
|
|
7929
|
+
import { existsSync } from "fs";
|
|
7930
|
+
import { join } from "path";
|
|
7931
|
+
import { pathToFileURL } from "url";
|
|
7932
|
+
|
|
7933
|
+
// src/config/schema.ts
|
|
7934
|
+
import { z } from "zod";
|
|
7935
|
+
var AuthRoleSchema = z.object({
|
|
7936
|
+
envEmail: z.string().min(1),
|
|
7937
|
+
envPassword: z.string().min(1)
|
|
7938
|
+
});
|
|
7939
|
+
var AuthSchema = z.object({
|
|
7940
|
+
strategy: z.enum(["storageState", "apiToken", "none"]).default("none"),
|
|
7941
|
+
ttl: z.string().default("8h"),
|
|
7942
|
+
refreshBuffer: z.string().default("30m"),
|
|
7943
|
+
setupScript: z.string().optional(),
|
|
7944
|
+
roles: z.record(z.string(), AuthRoleSchema).default({})
|
|
7945
|
+
});
|
|
7946
|
+
var WebSchema = z.object({
|
|
7947
|
+
baseUrl: z.record(z.string(), z.string().url()).refine((m) => Object.keys(m).length > 0, {
|
|
7948
|
+
message: "baseUrl must have at least one environment"
|
|
7949
|
+
}),
|
|
7950
|
+
defaultEnv: z.string(),
|
|
7951
|
+
auth: AuthSchema.prefault({}),
|
|
7952
|
+
testData: z.object({
|
|
7953
|
+
users: z.record(z.string(), z.object({ fromAuth: z.string() })).default({})
|
|
7954
|
+
}).prefault({})
|
|
7955
|
+
}).refine((w) => w.baseUrl[w.defaultEnv] !== undefined, {
|
|
7956
|
+
message: "defaultEnv must exist in baseUrl map",
|
|
7957
|
+
path: ["defaultEnv"]
|
|
7958
|
+
});
|
|
7959
|
+
var HttpAuthRoleSchema = z.object({
|
|
7960
|
+
tokenEnv: z.string().optional(),
|
|
7961
|
+
userEnv: z.string().optional(),
|
|
7962
|
+
passEnv: z.string().optional(),
|
|
7963
|
+
tokenUrl: z.string().url().optional(),
|
|
7964
|
+
clientIdEnv: z.string().optional(),
|
|
7965
|
+
clientSecretEnv: z.string().optional(),
|
|
7966
|
+
scope: z.string().optional()
|
|
7967
|
+
});
|
|
7968
|
+
var HttpAuthSchema = z.object({
|
|
7969
|
+
strategy: z.enum(["bearer", "apiKey", "basic", "oauth-cc", "custom", "none"]).default("none"),
|
|
7970
|
+
ttl: z.string().default("8h"),
|
|
7971
|
+
refreshBuffer: z.string().default("30m"),
|
|
7972
|
+
roles: z.record(z.string(), HttpAuthRoleSchema).default({})
|
|
7973
|
+
});
|
|
7974
|
+
var HttpSchema = z.object({
|
|
7975
|
+
baseUrl: z.record(z.string(), z.string().url()).refine((m) => Object.keys(m).length > 0, {
|
|
7976
|
+
message: "baseUrl must have at least one environment"
|
|
7977
|
+
}),
|
|
7978
|
+
defaultEnv: z.string(),
|
|
7979
|
+
spec: z.string().optional(),
|
|
7980
|
+
auth: HttpAuthSchema.prefault({})
|
|
7981
|
+
}).refine((h) => h.baseUrl[h.defaultEnv] !== undefined, {
|
|
7982
|
+
message: "defaultEnv must exist in baseUrl map",
|
|
7983
|
+
path: ["defaultEnv"]
|
|
7984
|
+
});
|
|
7985
|
+
var JiraSchema = z.object({
|
|
7986
|
+
baseUrl: z.string().url(),
|
|
7987
|
+
projectKeys: z.array(z.string().min(1)).min(1),
|
|
7988
|
+
fields: z.object({
|
|
7989
|
+
story: z.string().min(1),
|
|
7990
|
+
acceptanceCriteria: z.string().optional(),
|
|
7991
|
+
attachments: z.string().default("attachment")
|
|
7992
|
+
})
|
|
7993
|
+
});
|
|
7994
|
+
var AISchema = z.object({
|
|
7995
|
+
livePageSnapshot: z.boolean().default(true),
|
|
7996
|
+
confidenceThreshold: z.enum(["low", "medium", "high"]).default("medium"),
|
|
7997
|
+
maxRetries: z.object({
|
|
7998
|
+
typecheck: z.number().int().min(0).max(5).default(2),
|
|
7999
|
+
lint: z.number().int().min(0).max(5).default(2),
|
|
8000
|
+
validateFeature: z.number().int().min(0).max(5).default(2)
|
|
8001
|
+
}).prefault({})
|
|
8002
|
+
}).prefault({});
|
|
8003
|
+
var ReportingSchema = z.object({
|
|
8004
|
+
language: z.enum(["en", "vi"]).default("en"),
|
|
8005
|
+
postToJira: z.boolean().default(true),
|
|
8006
|
+
transition: z.object({
|
|
8007
|
+
onPass: z.string().nullable().default(null),
|
|
8008
|
+
onFail: z.string().nullable().default(null)
|
|
8009
|
+
}).prefault({}),
|
|
8010
|
+
artifactLinks: z.enum(["git", "local"]).default("git")
|
|
8011
|
+
}).prefault({});
|
|
8012
|
+
var RunSchema = z.object({
|
|
8013
|
+
autoImpact: z.object({
|
|
8014
|
+
enabled: z.boolean().default(true),
|
|
8015
|
+
threshold: z.number().nonnegative().default(8)
|
|
8016
|
+
}).prefault({})
|
|
8017
|
+
}).prefault({});
|
|
8018
|
+
var XeraConfigSchema = z.object({
|
|
8019
|
+
jira: JiraSchema,
|
|
8020
|
+
web: WebSchema.optional(),
|
|
8021
|
+
http: HttpSchema.optional(),
|
|
8022
|
+
ai: AISchema,
|
|
8023
|
+
reporting: ReportingSchema,
|
|
8024
|
+
run: RunSchema.prefault({}),
|
|
8025
|
+
adapters: z.array(z.enum(["web", "http"])).min(1).default(["web"])
|
|
8026
|
+
}).refine((c) => c.web !== undefined || c.http !== undefined, {
|
|
8027
|
+
message: "At least one of `web` or `http` must be configured"
|
|
8028
|
+
}).refine((c) => c.adapters.every((a) => (a === "web" ? c.web : c.http) !== undefined), {
|
|
8029
|
+
message: "Every adapter in `adapters` must have a corresponding config block",
|
|
8030
|
+
path: ["adapters"]
|
|
8031
|
+
});
|
|
8032
|
+
|
|
8033
|
+
// src/config/load.ts
|
|
8034
|
+
async function loadConfig(cwd) {
|
|
8035
|
+
const path = join(cwd, "xera.config.ts");
|
|
8036
|
+
if (!existsSync(path)) {
|
|
8037
|
+
throw new Error(`xera.config.ts not found in ${cwd}`);
|
|
8038
|
+
}
|
|
8039
|
+
const mod = await import(pathToFileURL(path).href);
|
|
8040
|
+
const raw = mod.default ?? mod;
|
|
8041
|
+
return XeraConfigSchema.parse(raw);
|
|
8042
|
+
}
|
|
8043
|
+
|
|
8044
|
+
// src/bin-internal/auth-setup.ts
|
|
8045
|
+
function parseOpts(argv) {
|
|
8046
|
+
const opts = { shape: "all" };
|
|
8047
|
+
for (let i = 0;i < argv.length; i++) {
|
|
8048
|
+
const a = argv[i];
|
|
8049
|
+
const next = argv[i + 1];
|
|
8050
|
+
if (a === "--role" && next) {
|
|
8051
|
+
opts.role = next;
|
|
8052
|
+
i++;
|
|
8053
|
+
} else if (a === "--shape" && next) {
|
|
8054
|
+
if (next === "web" || next === "http" || next === "all")
|
|
8055
|
+
opts.shape = next;
|
|
8056
|
+
i++;
|
|
8057
|
+
}
|
|
8058
|
+
}
|
|
8059
|
+
return opts;
|
|
8060
|
+
}
|
|
8061
|
+
async function authSetupCmd(argv) {
|
|
8062
|
+
const opts = parseOpts(argv);
|
|
8063
|
+
const cwd = process.cwd();
|
|
8064
|
+
const config = await loadConfig(cwd);
|
|
8065
|
+
const authSetupScript = join2(cwd, "shared", "auth-setup.ts");
|
|
8066
|
+
if (!existsSync2(authSetupScript)) {
|
|
8067
|
+
console.error(`[xera:auth-setup] auth-setup.ts not found at ${authSetupScript}. Run 'bunx @xera-ai/cli init' first.`);
|
|
8068
|
+
return 1;
|
|
8069
|
+
}
|
|
8070
|
+
const mod = await import(pathToFileURL2(authSetupScript).href);
|
|
8071
|
+
let exitCode = 0;
|
|
8072
|
+
if ((opts.shape === "all" || opts.shape === "web") && config.web && typeof mod.web === "function") {
|
|
8073
|
+
const { runAuthSetup } = await import("@xera-ai/web");
|
|
8074
|
+
const { chromium } = await import("@playwright/test");
|
|
8075
|
+
const browser = await chromium.launch();
|
|
8076
|
+
try {
|
|
8077
|
+
for (const [roleName, roleCreds] of Object.entries(config.web.auth.roles)) {
|
|
8078
|
+
if (opts.role && roleName !== opts.role)
|
|
8079
|
+
continue;
|
|
8080
|
+
const email = process.env[roleCreds.envEmail];
|
|
8081
|
+
const password = process.env[roleCreds.envPassword];
|
|
8082
|
+
if (!email || !password) {
|
|
8083
|
+
console.error(`[xera:auth-setup] missing env vars ${roleCreds.envEmail} / ${roleCreds.envPassword} for role '${roleName}'`);
|
|
8084
|
+
exitCode = 1;
|
|
8085
|
+
continue;
|
|
8086
|
+
}
|
|
8087
|
+
try {
|
|
8088
|
+
await runAuthSetup({
|
|
8089
|
+
role: roleName,
|
|
8090
|
+
creds: { email, password },
|
|
8091
|
+
setupScriptPath: authSetupScript,
|
|
8092
|
+
authDir: join2(cwd, ".xera", ".auth"),
|
|
8093
|
+
browser
|
|
8094
|
+
});
|
|
8095
|
+
console.log(`[xera:auth-setup] \u2713 ${roleName}.json (web)`);
|
|
8096
|
+
} catch (e) {
|
|
8097
|
+
console.error(`[xera:auth-setup] \u2717 web/${roleName}: ${e.message}`);
|
|
8098
|
+
exitCode = 1;
|
|
8099
|
+
}
|
|
8100
|
+
}
|
|
8101
|
+
} finally {
|
|
8102
|
+
await browser.close();
|
|
8103
|
+
}
|
|
8104
|
+
}
|
|
8105
|
+
if ((opts.shape === "all" || opts.shape === "http") && config.http && typeof mod.http === "function") {
|
|
8106
|
+
globalThis.__XERA_HTTP_CONFIG__ = config.http;
|
|
8107
|
+
const { runHttpAuthSetup } = await import("@xera-ai/http");
|
|
8108
|
+
for (const roleName of Object.keys(config.http.auth.roles)) {
|
|
8109
|
+
if (opts.role && roleName !== opts.role)
|
|
8110
|
+
continue;
|
|
8111
|
+
try {
|
|
8112
|
+
await runHttpAuthSetup({
|
|
8113
|
+
authDir: join2(cwd, ".xera", ".auth"),
|
|
8114
|
+
role: roleName,
|
|
8115
|
+
config: config.http,
|
|
8116
|
+
setupFn: mod.http,
|
|
8117
|
+
creds: { email: "", password: "" }
|
|
8118
|
+
});
|
|
8119
|
+
console.log(`[xera:auth-setup] \u2713 http/${roleName}.json`);
|
|
8120
|
+
} catch (e) {
|
|
8121
|
+
console.error(`[xera:auth-setup] \u2717 http/${roleName}: ${e.message}`);
|
|
8122
|
+
exitCode = 1;
|
|
8123
|
+
}
|
|
8124
|
+
}
|
|
8125
|
+
}
|
|
8126
|
+
return exitCode;
|
|
8127
|
+
}
|
|
8128
|
+
|
|
7917
8129
|
// src/bin-internal/disputes.ts
|
|
7918
8130
|
init_store();
|
|
7919
8131
|
function parseDuration(s) {
|
|
@@ -7990,16 +8202,16 @@ async function disputesCmd(argv) {
|
|
|
7990
8202
|
}
|
|
7991
8203
|
|
|
7992
8204
|
// src/bin-internal/doctor.ts
|
|
7993
|
-
import { existsSync as
|
|
7994
|
-
import { join as
|
|
8205
|
+
import { existsSync as existsSync9, readdirSync as readdirSync4, readFileSync as readFileSync6 } from "fs";
|
|
8206
|
+
import { join as join8 } from "path";
|
|
7995
8207
|
|
|
7996
8208
|
// src/graph/cost.ts
|
|
7997
|
-
import { appendFileSync, existsSync as
|
|
8209
|
+
import { appendFileSync, existsSync as existsSync4, mkdirSync as mkdirSync2, readFileSync as readFileSync2 } from "fs";
|
|
7998
8210
|
init_paths();
|
|
7999
8211
|
function summarizeCost(repoRoot, daysBack) {
|
|
8000
8212
|
const paths = graphPaths(repoRoot);
|
|
8001
8213
|
const result = { totalCalls: 0, totalUsd: 0, bySkill: {}, windowDays: daysBack };
|
|
8002
|
-
if (!
|
|
8214
|
+
if (!existsSync4(paths.costLog))
|
|
8003
8215
|
return result;
|
|
8004
8216
|
const cutoff = Date.now() - daysBack * 86400 * 1000;
|
|
8005
8217
|
for (const line of readFileSync2(paths.costLog, "utf8").split(`
|
|
@@ -8029,11 +8241,12 @@ function summarizeCost(repoRoot, daysBack) {
|
|
|
8029
8241
|
init_store();
|
|
8030
8242
|
|
|
8031
8243
|
// src/bin-internal/verify-prompts.ts
|
|
8032
|
-
import { existsSync as
|
|
8033
|
-
import { join as
|
|
8244
|
+
import { existsSync as existsSync5, readFileSync as readFileSync3 } from "fs";
|
|
8245
|
+
import { join as join4 } from "path";
|
|
8034
8246
|
var IN_SCOPE_PROMPTS = [
|
|
8035
8247
|
"feature-from-story.md",
|
|
8036
|
-
"script-from-feature.md",
|
|
8248
|
+
"script-from-feature-web.md",
|
|
8249
|
+
"script-from-feature-http.md",
|
|
8037
8250
|
"heal-locator.md",
|
|
8038
8251
|
"extract-areas.md",
|
|
8039
8252
|
"similarity-match.md",
|
|
@@ -8042,11 +8255,11 @@ var IN_SCOPE_PROMPTS = [
|
|
|
8042
8255
|
var REQUIRED_SECTION_HEADING = "## Handling untrusted input";
|
|
8043
8256
|
var REQUIRED_KEYWORDS = ["UNTRUSTED", "injection-follow", "<XR_"];
|
|
8044
8257
|
function verifyPrompts(repoRoot) {
|
|
8045
|
-
const promptsDir =
|
|
8258
|
+
const promptsDir = join4(repoRoot, "packages/prompts");
|
|
8046
8259
|
const results = [];
|
|
8047
8260
|
for (const filename of IN_SCOPE_PROMPTS) {
|
|
8048
|
-
const path =
|
|
8049
|
-
if (!
|
|
8261
|
+
const path = join4(promptsDir, filename);
|
|
8262
|
+
if (!existsSync5(path)) {
|
|
8050
8263
|
results.push({
|
|
8051
8264
|
ok: false,
|
|
8052
8265
|
message: `${filename}: file missing at packages/prompts/${filename}`
|
|
@@ -8101,8 +8314,8 @@ function frontmatterField(content, field) {
|
|
|
8101
8314
|
return m?.[1] ?? null;
|
|
8102
8315
|
}
|
|
8103
8316
|
function checkGoldenEvalDir(repoRoot) {
|
|
8104
|
-
const root =
|
|
8105
|
-
if (!
|
|
8317
|
+
const root = join8(repoRoot, "fixtures/golden-eval");
|
|
8318
|
+
if (!existsSync9(root))
|
|
8106
8319
|
return [{ ok: false, message: "fixtures/golden-eval/ does not exist" }];
|
|
8107
8320
|
const dirs = readdirSync4(root, { withFileTypes: true }).filter((e) => e.isDirectory() && !e.name.startsWith("."));
|
|
8108
8321
|
const results = [];
|
|
@@ -8113,9 +8326,9 @@ function checkGoldenEvalDir(repoRoot) {
|
|
|
8113
8326
|
});
|
|
8114
8327
|
}
|
|
8115
8328
|
for (const entry of dirs) {
|
|
8116
|
-
const dir =
|
|
8117
|
-
const metaPath =
|
|
8118
|
-
if (!
|
|
8329
|
+
const dir = join8(root, entry.name);
|
|
8330
|
+
const metaPath = join8(dir, "meta.json");
|
|
8331
|
+
if (!existsSync9(metaPath)) {
|
|
8119
8332
|
results.push({ ok: false, message: `${entry.name}: meta.json missing` });
|
|
8120
8333
|
continue;
|
|
8121
8334
|
}
|
|
@@ -8132,12 +8345,12 @@ function checkGoldenEvalDir(repoRoot) {
|
|
|
8132
8345
|
const stages = Array.isArray(meta.stages) ? meta.stages : [];
|
|
8133
8346
|
if (stages.length === 0)
|
|
8134
8347
|
results.push({ ok: false, message: `${entry.name}: meta.stages is empty` });
|
|
8135
|
-
if (!
|
|
8348
|
+
if (!existsSync9(join8(dir, "story.md")))
|
|
8136
8349
|
results.push({ ok: false, message: `${entry.name}: story.md missing` });
|
|
8137
8350
|
for (const stage of stages) {
|
|
8138
8351
|
const required = REQUIRED_FILES_PER_STAGE[stage] ?? [];
|
|
8139
8352
|
for (const rel of required) {
|
|
8140
|
-
if (!
|
|
8353
|
+
if (!existsSync9(join8(dir, rel))) {
|
|
8141
8354
|
results.push({
|
|
8142
8355
|
ok: false,
|
|
8143
8356
|
message: `${meta.id ?? entry.name}: stage "${stage}" declared but ${rel} missing`
|
|
@@ -8149,8 +8362,8 @@ function checkGoldenEvalDir(repoRoot) {
|
|
|
8149
8362
|
return results;
|
|
8150
8363
|
}
|
|
8151
8364
|
function checkRubricPrompt(repoRoot) {
|
|
8152
|
-
const path =
|
|
8153
|
-
if (!
|
|
8365
|
+
const path = join8(repoRoot, "packages/prompts/eval-rubric.md");
|
|
8366
|
+
if (!existsSync9(path))
|
|
8154
8367
|
return [{ ok: false, message: "packages/prompts/eval-rubric.md missing" }];
|
|
8155
8368
|
const text = readFileSync6(path, "utf8");
|
|
8156
8369
|
const id = frontmatterField(text, "id");
|
|
@@ -8162,8 +8375,8 @@ function checkRubricPrompt(repoRoot) {
|
|
|
8162
8375
|
return [];
|
|
8163
8376
|
}
|
|
8164
8377
|
function checkEvalSkill(repoRoot) {
|
|
8165
|
-
const path =
|
|
8166
|
-
if (!
|
|
8378
|
+
const path = join8(repoRoot, "packages/skills/xera-eval.md");
|
|
8379
|
+
if (!existsSync9(path))
|
|
8167
8380
|
return [{ ok: false, message: "packages/skills/xera-eval.md missing" }];
|
|
8168
8381
|
const text = readFileSync6(path, "utf8");
|
|
8169
8382
|
if (!frontmatterField(text, "name"))
|
|
@@ -8174,8 +8387,8 @@ function checkPromptInjectionPreamble(repoRoot) {
|
|
|
8174
8387
|
return verifyPrompts(repoRoot);
|
|
8175
8388
|
}
|
|
8176
8389
|
function checkRootScripts(repoRoot) {
|
|
8177
|
-
const path =
|
|
8178
|
-
if (!
|
|
8390
|
+
const path = join8(repoRoot, "package.json");
|
|
8391
|
+
if (!existsSync9(path))
|
|
8179
8392
|
return [{ ok: false, message: "root package.json missing" }];
|
|
8180
8393
|
const pkg = JSON.parse(readFileSync6(path, "utf8"));
|
|
8181
8394
|
const scripts = pkg.scripts ?? {};
|
|
@@ -8202,8 +8415,8 @@ async function doctorCmd(argv, opts = {}) {
|
|
|
8202
8415
|
if (top)
|
|
8203
8416
|
console.log(` Top skill: ${top[0]} (${top[1].calls} calls, $${top[1].usd.toFixed(2)})`);
|
|
8204
8417
|
}
|
|
8205
|
-
const xeraDir =
|
|
8206
|
-
if (
|
|
8418
|
+
const xeraDir = join8(repoRoot, ".xera");
|
|
8419
|
+
if (existsSync9(xeraDir)) {
|
|
8207
8420
|
const ticketDirs = readdirSync4(xeraDir, { withFileTypes: true }).filter((e) => e.isDirectory() && /^[A-Z]+-\d+$/.test(e.name));
|
|
8208
8421
|
if (ticketDirs.length > 0) {
|
|
8209
8422
|
const events = loadAllEvents(repoRoot);
|
|
@@ -8238,111 +8451,111 @@ async function doctorCmd(argv, opts = {}) {
|
|
|
8238
8451
|
}
|
|
8239
8452
|
|
|
8240
8453
|
// src/bin-internal/eval-deterministic.ts
|
|
8241
|
-
import { existsSync as
|
|
8242
|
-
import { join as
|
|
8454
|
+
import { existsSync as existsSync10, readFileSync as readFileSync7, writeFileSync as writeFileSync2 } from "fs";
|
|
8455
|
+
import { join as join10 } from "path";
|
|
8243
8456
|
import { validateGherkin } from "@xera-ai/web";
|
|
8244
8457
|
|
|
8245
8458
|
// src/eval/paths.ts
|
|
8246
|
-
import { join as
|
|
8459
|
+
import { join as join9 } from "path";
|
|
8247
8460
|
function resolveEvalPaths(cwd, runId) {
|
|
8248
|
-
const root =
|
|
8461
|
+
const root = join9(cwd, ".xera", "eval", runId);
|
|
8249
8462
|
return {
|
|
8250
8463
|
root,
|
|
8251
|
-
manifest:
|
|
8252
|
-
lock:
|
|
8253
|
-
deterministicScores:
|
|
8254
|
-
judgeScores:
|
|
8255
|
-
report:
|
|
8256
|
-
summary:
|
|
8257
|
-
inputsDir:
|
|
8258
|
-
actualDir:
|
|
8259
|
-
ticketInputsDir: (ticket) =>
|
|
8260
|
-
ticketActualDir: (ticket) =>
|
|
8464
|
+
manifest: join9(root, "manifest.json"),
|
|
8465
|
+
lock: join9(root, ".lock"),
|
|
8466
|
+
deterministicScores: join9(root, "deterministic-scores.json"),
|
|
8467
|
+
judgeScores: join9(root, "judge-scores.json"),
|
|
8468
|
+
report: join9(root, "report.md"),
|
|
8469
|
+
summary: join9(root, "summary.json"),
|
|
8470
|
+
inputsDir: join9(root, "inputs"),
|
|
8471
|
+
actualDir: join9(root, "actual"),
|
|
8472
|
+
ticketInputsDir: (ticket) => join9(root, "inputs", ticket),
|
|
8473
|
+
ticketActualDir: (ticket) => join9(root, "actual", ticket)
|
|
8261
8474
|
};
|
|
8262
8475
|
}
|
|
8263
8476
|
|
|
8264
8477
|
// src/eval/types.ts
|
|
8265
|
-
import { z as
|
|
8478
|
+
import { z as z3 } from "zod";
|
|
8266
8479
|
var STAGES = ["feature-from-story", "script-from-feature", "diagnose-failure"];
|
|
8267
|
-
var StageSchema =
|
|
8268
|
-
var VerdictSchema =
|
|
8269
|
-
var PromptVersionsSchema =
|
|
8270
|
-
"feature-from-story":
|
|
8271
|
-
"script-from-feature":
|
|
8272
|
-
"diagnose-failure":
|
|
8273
|
-
"eval-rubric":
|
|
8480
|
+
var StageSchema = z3.enum(STAGES);
|
|
8481
|
+
var VerdictSchema = z3.enum(["PASS", "FAIL", "NA"]);
|
|
8482
|
+
var PromptVersionsSchema = z3.object({
|
|
8483
|
+
"feature-from-story": z3.string(),
|
|
8484
|
+
"script-from-feature": z3.string(),
|
|
8485
|
+
"diagnose-failure": z3.string(),
|
|
8486
|
+
"eval-rubric": z3.string()
|
|
8274
8487
|
});
|
|
8275
|
-
var ManifestSchema =
|
|
8276
|
-
run_id:
|
|
8277
|
-
started_at:
|
|
8278
|
-
git_sha:
|
|
8279
|
-
tickets:
|
|
8280
|
-
stages:
|
|
8281
|
-
ticket_stages:
|
|
8488
|
+
var ManifestSchema = z3.object({
|
|
8489
|
+
run_id: z3.string(),
|
|
8490
|
+
started_at: z3.string(),
|
|
8491
|
+
git_sha: z3.string(),
|
|
8492
|
+
tickets: z3.array(z3.string()).min(1),
|
|
8493
|
+
stages: z3.array(StageSchema).min(1),
|
|
8494
|
+
ticket_stages: z3.record(z3.string(), z3.array(StageSchema).min(1)),
|
|
8282
8495
|
prompt_versions: PromptVersionsSchema,
|
|
8283
|
-
flags:
|
|
8284
|
-
force:
|
|
8496
|
+
flags: z3.object({
|
|
8497
|
+
force: z3.boolean(),
|
|
8285
8498
|
only_prompt: StageSchema.nullable(),
|
|
8286
|
-
only_ticket:
|
|
8287
|
-
judge_only:
|
|
8499
|
+
only_ticket: z3.string().nullable(),
|
|
8500
|
+
judge_only: z3.boolean()
|
|
8288
8501
|
})
|
|
8289
8502
|
});
|
|
8290
|
-
var DimensionSchema =
|
|
8291
|
-
name:
|
|
8503
|
+
var DimensionSchema = z3.object({
|
|
8504
|
+
name: z3.string(),
|
|
8292
8505
|
verdict: VerdictSchema,
|
|
8293
|
-
notes:
|
|
8506
|
+
notes: z3.string()
|
|
8294
8507
|
});
|
|
8295
|
-
var JudgmentSchema =
|
|
8508
|
+
var JudgmentSchema = z3.object({
|
|
8296
8509
|
stage: StageSchema,
|
|
8297
|
-
ticket:
|
|
8298
|
-
dimensions:
|
|
8510
|
+
ticket: z3.string(),
|
|
8511
|
+
dimensions: z3.array(DimensionSchema).min(1)
|
|
8299
8512
|
});
|
|
8300
|
-
var JudgeScoresSchema =
|
|
8301
|
-
run_id:
|
|
8302
|
-
judgments:
|
|
8513
|
+
var JudgeScoresSchema = z3.object({
|
|
8514
|
+
run_id: z3.string(),
|
|
8515
|
+
judgments: z3.array(JudgmentSchema)
|
|
8303
8516
|
});
|
|
8304
|
-
var DeterministicEntrySchema =
|
|
8305
|
-
ticket:
|
|
8517
|
+
var DeterministicEntrySchema = z3.object({
|
|
8518
|
+
ticket: z3.string(),
|
|
8306
8519
|
stage: StageSchema,
|
|
8307
|
-
passed:
|
|
8308
|
-
checks:
|
|
8309
|
-
error:
|
|
8520
|
+
passed: z3.boolean(),
|
|
8521
|
+
checks: z3.array(z3.string()),
|
|
8522
|
+
error: z3.string().optional()
|
|
8310
8523
|
});
|
|
8311
|
-
var DeterministicScoresSchema =
|
|
8312
|
-
run_id:
|
|
8313
|
-
entries:
|
|
8524
|
+
var DeterministicScoresSchema = z3.object({
|
|
8525
|
+
run_id: z3.string(),
|
|
8526
|
+
entries: z3.array(DeterministicEntrySchema)
|
|
8314
8527
|
});
|
|
8315
|
-
var ResultSchema =
|
|
8316
|
-
ticket:
|
|
8528
|
+
var ResultSchema = z3.object({
|
|
8529
|
+
ticket: z3.string(),
|
|
8317
8530
|
stage: StageSchema,
|
|
8318
|
-
deterministic:
|
|
8319
|
-
passed:
|
|
8320
|
-
checks:
|
|
8321
|
-
error:
|
|
8531
|
+
deterministic: z3.object({
|
|
8532
|
+
passed: z3.boolean(),
|
|
8533
|
+
checks: z3.array(z3.string()),
|
|
8534
|
+
error: z3.string().optional()
|
|
8322
8535
|
}),
|
|
8323
|
-
judge:
|
|
8324
|
-
passed:
|
|
8325
|
-
dimensions:
|
|
8326
|
-
score:
|
|
8536
|
+
judge: z3.object({
|
|
8537
|
+
passed: z3.boolean(),
|
|
8538
|
+
dimensions: z3.array(DimensionSchema),
|
|
8539
|
+
score: z3.number().min(0).max(1)
|
|
8327
8540
|
}).nullable(),
|
|
8328
|
-
skipped:
|
|
8541
|
+
skipped: z3.boolean().optional()
|
|
8329
8542
|
});
|
|
8330
|
-
var SummarySchema =
|
|
8331
|
-
run_id:
|
|
8332
|
-
git_sha:
|
|
8543
|
+
var SummarySchema = z3.object({
|
|
8544
|
+
run_id: z3.string(),
|
|
8545
|
+
git_sha: z3.string(),
|
|
8333
8546
|
prompt_versions: PromptVersionsSchema,
|
|
8334
|
-
results:
|
|
8335
|
-
overall:
|
|
8336
|
-
passed:
|
|
8337
|
-
failed:
|
|
8338
|
-
total:
|
|
8339
|
-
score:
|
|
8547
|
+
results: z3.array(ResultSchema),
|
|
8548
|
+
overall: z3.object({
|
|
8549
|
+
passed: z3.number().int().nonnegative(),
|
|
8550
|
+
failed: z3.number().int().nonnegative(),
|
|
8551
|
+
total: z3.number().int().nonnegative(),
|
|
8552
|
+
score: z3.number().min(0).max(1)
|
|
8340
8553
|
})
|
|
8341
8554
|
});
|
|
8342
8555
|
|
|
8343
8556
|
// src/bin-internal/eval-deterministic.ts
|
|
8344
8557
|
function checkFeatureFromStory(actualFeaturePath) {
|
|
8345
|
-
if (!
|
|
8558
|
+
if (!existsSync10(actualFeaturePath)) {
|
|
8346
8559
|
return { passed: false, checks: ["validate-feature"], error: "actual missing: test.feature" };
|
|
8347
8560
|
}
|
|
8348
8561
|
try {
|
|
@@ -8359,23 +8572,23 @@ function checkFeatureFromStory(actualFeaturePath) {
|
|
|
8359
8572
|
}
|
|
8360
8573
|
}
|
|
8361
8574
|
function checkScriptFromFeature(actualTicketDir) {
|
|
8362
|
-
const specPath =
|
|
8363
|
-
if (!
|
|
8575
|
+
const specPath = join10(actualTicketDir, "spec.ts");
|
|
8576
|
+
if (!existsSync10(specPath)) {
|
|
8364
8577
|
return { passed: false, checks: ["file-presence"], error: "actual missing: spec.ts" };
|
|
8365
8578
|
}
|
|
8366
8579
|
return { passed: true, checks: ["file-presence"] };
|
|
8367
8580
|
}
|
|
8368
8581
|
function checkDiagnoseFailure(inputsTicketDir, actualTicketDir) {
|
|
8369
|
-
const inputPath =
|
|
8370
|
-
const actualPath =
|
|
8371
|
-
if (!
|
|
8582
|
+
const inputPath = join10(inputsTicketDir, "classifier-input.json");
|
|
8583
|
+
const actualPath = join10(actualTicketDir, "classification.json");
|
|
8584
|
+
if (!existsSync10(actualPath)) {
|
|
8372
8585
|
return {
|
|
8373
8586
|
passed: false,
|
|
8374
8587
|
checks: ["bucket-match"],
|
|
8375
8588
|
error: "actual missing: classification.json"
|
|
8376
8589
|
};
|
|
8377
8590
|
}
|
|
8378
|
-
if (!
|
|
8591
|
+
if (!existsSync10(inputPath)) {
|
|
8379
8592
|
return {
|
|
8380
8593
|
passed: false,
|
|
8381
8594
|
checks: ["bucket-match"],
|
|
@@ -8413,7 +8626,7 @@ async function evalDeterministicCmd(argv, opts = {}) {
|
|
|
8413
8626
|
return 1;
|
|
8414
8627
|
}
|
|
8415
8628
|
const paths = resolveEvalPaths(cwd, runId);
|
|
8416
|
-
if (!
|
|
8629
|
+
if (!existsSync10(paths.manifest)) {
|
|
8417
8630
|
console.error(`[xera:eval-deterministic] missing manifest.json at ${paths.manifest}`);
|
|
8418
8631
|
return 1;
|
|
8419
8632
|
}
|
|
@@ -8425,7 +8638,7 @@ async function evalDeterministicCmd(argv, opts = {}) {
|
|
|
8425
8638
|
const actualDir = paths.ticketActualDir(ticket);
|
|
8426
8639
|
let result;
|
|
8427
8640
|
if (stage === "feature-from-story") {
|
|
8428
|
-
result = checkFeatureFromStory(
|
|
8641
|
+
result = checkFeatureFromStory(join10(actualDir, "test.feature"));
|
|
8429
8642
|
} else if (stage === "script-from-feature") {
|
|
8430
8643
|
result = checkScriptFromFeature(actualDir);
|
|
8431
8644
|
} else {
|
|
@@ -8452,13 +8665,13 @@ async function evalDeterministicCmd(argv, opts = {}) {
|
|
|
8452
8665
|
// src/bin-internal/eval-prepare.ts
|
|
8453
8666
|
import {
|
|
8454
8667
|
copyFileSync,
|
|
8455
|
-
existsSync as
|
|
8668
|
+
existsSync as existsSync12,
|
|
8456
8669
|
mkdirSync as mkdirSync4,
|
|
8457
8670
|
readdirSync as readdirSync5,
|
|
8458
8671
|
readFileSync as readFileSync9,
|
|
8459
8672
|
writeFileSync as writeFileSync4
|
|
8460
8673
|
} from "fs";
|
|
8461
|
-
import { join as
|
|
8674
|
+
import { join as join11 } from "path";
|
|
8462
8675
|
|
|
8463
8676
|
// src/eval/run-id.ts
|
|
8464
8677
|
import { execSync } from "child_process";
|
|
@@ -8483,11 +8696,11 @@ function generateRunId(opts = {}) {
|
|
|
8483
8696
|
}
|
|
8484
8697
|
|
|
8485
8698
|
// src/lock/file-lock.ts
|
|
8486
|
-
import { existsSync as
|
|
8699
|
+
import { existsSync as existsSync11, mkdirSync as mkdirSync3, readFileSync as readFileSync8, unlinkSync, writeFileSync as writeFileSync3 } from "fs";
|
|
8487
8700
|
import { hostname } from "os";
|
|
8488
8701
|
import { dirname as dirname2 } from "path";
|
|
8489
8702
|
function acquireLock(path, runId) {
|
|
8490
|
-
if (
|
|
8703
|
+
if (existsSync11(path))
|
|
8491
8704
|
return false;
|
|
8492
8705
|
mkdirSync3(dirname2(path), { recursive: true });
|
|
8493
8706
|
const data = {
|
|
@@ -8504,11 +8717,11 @@ function acquireLock(path, runId) {
|
|
|
8504
8717
|
}
|
|
8505
8718
|
}
|
|
8506
8719
|
function releaseLock(path) {
|
|
8507
|
-
if (
|
|
8720
|
+
if (existsSync11(path))
|
|
8508
8721
|
unlinkSync(path);
|
|
8509
8722
|
}
|
|
8510
8723
|
function readLock(path) {
|
|
8511
|
-
if (!
|
|
8724
|
+
if (!existsSync11(path))
|
|
8512
8725
|
return null;
|
|
8513
8726
|
return JSON.parse(readFileSync8(path, "utf8"));
|
|
8514
8727
|
}
|
|
@@ -8551,16 +8764,16 @@ function parseFlags2(argv) {
|
|
|
8551
8764
|
return flags;
|
|
8552
8765
|
}
|
|
8553
8766
|
function readPromptVersion(repoRoot, name) {
|
|
8554
|
-
const path =
|
|
8555
|
-
if (!
|
|
8767
|
+
const path = join11(repoRoot, "packages/prompts", `${name}.md`);
|
|
8768
|
+
if (!existsSync12(path))
|
|
8556
8769
|
return "0.0.0";
|
|
8557
8770
|
const text = readFileSync9(path, "utf8");
|
|
8558
8771
|
const m = /^version:\s*(\S+)\s*$/m.exec(text);
|
|
8559
8772
|
return m?.[1] ?? "0.0.0";
|
|
8560
8773
|
}
|
|
8561
8774
|
function discoverEvalTickets(repoRoot) {
|
|
8562
|
-
const root =
|
|
8563
|
-
if (!
|
|
8775
|
+
const root = join11(repoRoot, "fixtures/golden-eval");
|
|
8776
|
+
if (!existsSync12(root))
|
|
8564
8777
|
return [];
|
|
8565
8778
|
const out = [];
|
|
8566
8779
|
for (const entry of readdirSync5(root, { withFileTypes: true })) {
|
|
@@ -8568,9 +8781,9 @@ function discoverEvalTickets(repoRoot) {
|
|
|
8568
8781
|
continue;
|
|
8569
8782
|
if (entry.name === "README.md" || entry.name.startsWith("."))
|
|
8570
8783
|
continue;
|
|
8571
|
-
const dir =
|
|
8572
|
-
const metaPath =
|
|
8573
|
-
if (!
|
|
8784
|
+
const dir = join11(root, entry.name);
|
|
8785
|
+
const metaPath = join11(dir, "meta.json");
|
|
8786
|
+
if (!existsSync12(metaPath))
|
|
8574
8787
|
continue;
|
|
8575
8788
|
const meta = JSON.parse(readFileSync9(metaPath, "utf8"));
|
|
8576
8789
|
out.push({ id: meta.id, dir, stages: meta.stages });
|
|
@@ -8578,14 +8791,14 @@ function discoverEvalTickets(repoRoot) {
|
|
|
8578
8791
|
return out.sort((a, b) => a.id.localeCompare(b.id));
|
|
8579
8792
|
}
|
|
8580
8793
|
function discoverClassifierTickets(repoRoot) {
|
|
8581
|
-
const root =
|
|
8582
|
-
if (!
|
|
8794
|
+
const root = join11(repoRoot, "fixtures/golden-tickets");
|
|
8795
|
+
if (!existsSync12(root))
|
|
8583
8796
|
return [];
|
|
8584
8797
|
const out = [];
|
|
8585
8798
|
for (const entry of readdirSync5(root, { withFileTypes: true })) {
|
|
8586
8799
|
if (!entry.isFile() || !entry.name.endsWith(".json"))
|
|
8587
8800
|
continue;
|
|
8588
|
-
const path =
|
|
8801
|
+
const path = join11(root, entry.name);
|
|
8589
8802
|
const data = JSON.parse(readFileSync9(path, "utf8"));
|
|
8590
8803
|
if (typeof data.ticket === "string")
|
|
8591
8804
|
out.push({ id: data.ticket, path });
|
|
@@ -8645,7 +8858,7 @@ async function evalPrepareCmd(argv, opts = {}) {
|
|
|
8645
8858
|
...opts.getGitSha ? { getGitSha: opts.getGitSha } : {}
|
|
8646
8859
|
});
|
|
8647
8860
|
const paths = resolveEvalPaths(repoRoot, runId);
|
|
8648
|
-
if (
|
|
8861
|
+
if (existsSync12(paths.root) && !flags.force) {
|
|
8649
8862
|
console.error(`[xera:eval-prepare] run dir already exists: ${paths.root}. Pass --force to re-run.`);
|
|
8650
8863
|
return 1;
|
|
8651
8864
|
}
|
|
@@ -8657,13 +8870,13 @@ async function evalPrepareCmd(argv, opts = {}) {
|
|
|
8657
8870
|
const evalT = evalTickets.find((t) => t.id === ticket);
|
|
8658
8871
|
const classT = classifierTickets.find((t) => t.id === ticket);
|
|
8659
8872
|
if (evalT) {
|
|
8660
|
-
copyFileSync(
|
|
8661
|
-
const featurePath =
|
|
8662
|
-
if (
|
|
8663
|
-
copyFileSync(featurePath,
|
|
8873
|
+
copyFileSync(join11(evalT.dir, "story.md"), join11(ticketInputs, "story.md"));
|
|
8874
|
+
const featurePath = join11(evalT.dir, "golden/test.feature");
|
|
8875
|
+
if (existsSync12(featurePath))
|
|
8876
|
+
copyFileSync(featurePath, join11(ticketInputs, "test.feature"));
|
|
8664
8877
|
}
|
|
8665
8878
|
if (classT) {
|
|
8666
|
-
copyFileSync(classT.path,
|
|
8879
|
+
copyFileSync(classT.path, join11(ticketInputs, "classifier-input.json"));
|
|
8667
8880
|
}
|
|
8668
8881
|
}
|
|
8669
8882
|
const now = (opts.now ?? (() => new Date))();
|
|
@@ -8699,7 +8912,7 @@ async function evalPrepareCmd(argv, opts = {}) {
|
|
|
8699
8912
|
}
|
|
8700
8913
|
|
|
8701
8914
|
// src/bin-internal/eval-report.ts
|
|
8702
|
-
import { existsSync as
|
|
8915
|
+
import { existsSync as existsSync13, readFileSync as readFileSync10, writeFileSync as writeFileSync5 } from "fs";
|
|
8703
8916
|
function scoreJudgment(j) {
|
|
8704
8917
|
const nonNa = j.dimensions.filter((d) => d.verdict !== "NA");
|
|
8705
8918
|
if (nonNa.length === 0)
|
|
@@ -8754,7 +8967,7 @@ async function evalReportCmd(argv, opts = {}) {
|
|
|
8754
8967
|
return 1;
|
|
8755
8968
|
}
|
|
8756
8969
|
const paths = resolveEvalPaths(cwd, runId);
|
|
8757
|
-
if (!
|
|
8970
|
+
if (!existsSync13(paths.manifest)) {
|
|
8758
8971
|
console.error(`[xera:eval-report] missing manifest.json at ${paths.manifest}`);
|
|
8759
8972
|
return 1;
|
|
8760
8973
|
}
|
|
@@ -8841,40 +9054,77 @@ async function evalReportCmd(argv, opts = {}) {
|
|
|
8841
9054
|
}
|
|
8842
9055
|
|
|
8843
9056
|
// src/bin-internal/exec.ts
|
|
8844
|
-
import { existsSync as
|
|
8845
|
-
import { join as
|
|
9057
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync8 } from "fs";
|
|
9058
|
+
import { join as join14 } from "path";
|
|
8846
9059
|
import { chromium } from "@playwright/test";
|
|
8847
9060
|
import { runAuthSetup, runPlaywright, stagePlaywrightState } from "@xera-ai/web";
|
|
8848
9061
|
|
|
9062
|
+
// src/artifact/meta.ts
|
|
9063
|
+
import { existsSync as existsSync14, mkdirSync as mkdirSync5, readFileSync as readFileSync11, writeFileSync as writeFileSync6 } from "fs";
|
|
9064
|
+
import { dirname as dirname3 } from "path";
|
|
9065
|
+
import { z as z4 } from "zod";
|
|
9066
|
+
var MetaJsonSchema = z4.object({
|
|
9067
|
+
ticket: z4.string(),
|
|
9068
|
+
adapter: z4.string(),
|
|
9069
|
+
xera_version: z4.string(),
|
|
9070
|
+
prompts_version: z4.string(),
|
|
9071
|
+
fetched_at: z4.string().optional(),
|
|
9072
|
+
story_hash: z4.string().optional(),
|
|
9073
|
+
feature_generated_at: z4.string().optional(),
|
|
9074
|
+
feature_generated_from_story_hash: z4.string().optional(),
|
|
9075
|
+
feature_hash: z4.string().optional(),
|
|
9076
|
+
script_generated_at: z4.string().optional(),
|
|
9077
|
+
script_generated_from_feature_hash: z4.string().optional(),
|
|
9078
|
+
script_warnings: z4.array(z4.string()).optional()
|
|
9079
|
+
});
|
|
9080
|
+
function readMeta(path) {
|
|
9081
|
+
if (!existsSync14(path))
|
|
9082
|
+
return null;
|
|
9083
|
+
return MetaJsonSchema.parse(JSON.parse(readFileSync11(path, "utf8")));
|
|
9084
|
+
}
|
|
9085
|
+
function writeMeta(path, meta) {
|
|
9086
|
+
mkdirSync5(dirname3(path), { recursive: true });
|
|
9087
|
+
writeFileSync6(path, JSON.stringify(meta, null, 2));
|
|
9088
|
+
}
|
|
9089
|
+
function updateMeta(path, patch) {
|
|
9090
|
+
const existing = readMeta(path);
|
|
9091
|
+
if (!existing) {
|
|
9092
|
+
throw new Error(`meta.json not found at ${path}; cannot update`);
|
|
9093
|
+
}
|
|
9094
|
+
const next = { ...existing, ...patch };
|
|
9095
|
+
writeMeta(path, next);
|
|
9096
|
+
return next;
|
|
9097
|
+
}
|
|
9098
|
+
|
|
8849
9099
|
// src/artifact/paths.ts
|
|
8850
|
-
import { join as
|
|
9100
|
+
import { join as join12 } from "path";
|
|
8851
9101
|
var TICKET_RE = /^[A-Z][A-Z0-9_]*-\d+$|^SAMPLE-\d+$/;
|
|
8852
9102
|
function resolveArtifactPaths(repoRoot, ticket) {
|
|
8853
9103
|
if (!TICKET_RE.test(ticket)) {
|
|
8854
9104
|
throw new Error(`Invalid ticket key: "${ticket}" (expected e.g. JIRA-123 or SAMPLE-001)`);
|
|
8855
9105
|
}
|
|
8856
|
-
const ticketDir =
|
|
9106
|
+
const ticketDir = join12(repoRoot, ".xera", ticket);
|
|
8857
9107
|
return {
|
|
8858
9108
|
ticketDir,
|
|
8859
|
-
storyPath:
|
|
8860
|
-
featurePath:
|
|
8861
|
-
specPath:
|
|
8862
|
-
pageObjectsDir:
|
|
8863
|
-
runsDir:
|
|
8864
|
-
metaPath:
|
|
8865
|
-
statusPath:
|
|
8866
|
-
logPath:
|
|
8867
|
-
lockPath:
|
|
8868
|
-
authDir:
|
|
9109
|
+
storyPath: join12(ticketDir, "story.md"),
|
|
9110
|
+
featurePath: join12(ticketDir, "test.feature"),
|
|
9111
|
+
specPath: join12(ticketDir, "spec.ts"),
|
|
9112
|
+
pageObjectsDir: join12(ticketDir, "page-objects"),
|
|
9113
|
+
runsDir: join12(ticketDir, "runs"),
|
|
9114
|
+
metaPath: join12(ticketDir, "meta.json"),
|
|
9115
|
+
statusPath: join12(ticketDir, "status.json"),
|
|
9116
|
+
logPath: join12(ticketDir, "xera.log"),
|
|
9117
|
+
lockPath: join12(ticketDir, ".lock"),
|
|
9118
|
+
authDir: join12(repoRoot, ".xera", ".auth"),
|
|
8869
9119
|
runPath: (runId) => {
|
|
8870
|
-
const runDir =
|
|
9120
|
+
const runDir = join12(ticketDir, "runs", runId);
|
|
8871
9121
|
return {
|
|
8872
9122
|
runDir,
|
|
8873
|
-
reportJsonPath:
|
|
8874
|
-
tracePath:
|
|
8875
|
-
normalizedPath:
|
|
8876
|
-
screenshotsDir:
|
|
8877
|
-
videoDir:
|
|
9123
|
+
reportJsonPath: join12(runDir, "report.json"),
|
|
9124
|
+
tracePath: join12(runDir, "trace.zip"),
|
|
9125
|
+
normalizedPath: join12(runDir, "normalized.json"),
|
|
9126
|
+
screenshotsDir: join12(runDir, "screenshots"),
|
|
9127
|
+
videoDir: join12(runDir, "videos")
|
|
8878
9128
|
};
|
|
8879
9129
|
}
|
|
8880
9130
|
};
|
|
@@ -8912,9 +9162,9 @@ function needsRefresh(entry, policy, now = new Date) {
|
|
|
8912
9162
|
}
|
|
8913
9163
|
|
|
8914
9164
|
// src/auth/state.ts
|
|
8915
|
-
import { existsSync as
|
|
8916
|
-
import { join as
|
|
8917
|
-
import { z as
|
|
9165
|
+
import { existsSync as existsSync15, mkdirSync as mkdirSync6, readFileSync as readFileSync12, writeFileSync as writeFileSync7 } from "fs";
|
|
9166
|
+
import { join as join13 } from "path";
|
|
9167
|
+
import { z as z5 } from "zod";
|
|
8918
9168
|
|
|
8919
9169
|
// src/auth/encrypt.ts
|
|
8920
9170
|
import { createCipheriv, createDecipheriv, randomBytes } from "crypto";
|
|
@@ -8971,123 +9221,39 @@ function resolveAuthKey() {
|
|
|
8971
9221
|
}
|
|
8972
9222
|
|
|
8973
9223
|
// src/auth/state.ts
|
|
8974
|
-
var AuthStateEntrySchema =
|
|
8975
|
-
role:
|
|
8976
|
-
strategy:
|
|
8977
|
-
created_at:
|
|
8978
|
-
expires_at:
|
|
8979
|
-
payload:
|
|
9224
|
+
var AuthStateEntrySchema = z5.object({
|
|
9225
|
+
role: z5.string(),
|
|
9226
|
+
strategy: z5.enum(["storageState", "apiToken"]),
|
|
9227
|
+
created_at: z5.string(),
|
|
9228
|
+
expires_at: z5.string(),
|
|
9229
|
+
payload: z5.record(z5.string(), z5.unknown())
|
|
8980
9230
|
});
|
|
8981
9231
|
function pathFor(authDir, role) {
|
|
8982
|
-
return
|
|
9232
|
+
return join13(authDir, `${role}.json`);
|
|
8983
9233
|
}
|
|
8984
9234
|
function writeAuthState(authDir, entry) {
|
|
8985
|
-
|
|
9235
|
+
mkdirSync6(authDir, { recursive: true });
|
|
8986
9236
|
const ct = encrypt(JSON.stringify(entry), resolveAuthKey());
|
|
8987
|
-
|
|
9237
|
+
writeFileSync7(pathFor(authDir, entry.role), ct);
|
|
8988
9238
|
}
|
|
8989
9239
|
function readAuthState(authDir, role) {
|
|
8990
9240
|
const p = pathFor(authDir, role);
|
|
8991
|
-
if (!
|
|
9241
|
+
if (!existsSync15(p))
|
|
8992
9242
|
return null;
|
|
8993
|
-
const txt =
|
|
9243
|
+
const txt = readFileSync12(p, "utf8");
|
|
8994
9244
|
const plain = decrypt(txt, resolveAuthKey());
|
|
8995
9245
|
return AuthStateEntrySchema.parse(JSON.parse(plain));
|
|
8996
9246
|
}
|
|
8997
9247
|
|
|
8998
|
-
// src/config/load.ts
|
|
8999
|
-
import { existsSync as existsSync13 } from "fs";
|
|
9000
|
-
import { join as join12 } from "path";
|
|
9001
|
-
import { pathToFileURL } from "url";
|
|
9002
|
-
|
|
9003
|
-
// src/config/schema.ts
|
|
9004
|
-
import { z as z4 } from "zod";
|
|
9005
|
-
var AuthRoleSchema = z4.object({
|
|
9006
|
-
envEmail: z4.string().min(1),
|
|
9007
|
-
envPassword: z4.string().min(1)
|
|
9008
|
-
});
|
|
9009
|
-
var AuthSchema = z4.object({
|
|
9010
|
-
strategy: z4.enum(["storageState", "apiToken", "none"]).default("none"),
|
|
9011
|
-
ttl: z4.string().default("8h"),
|
|
9012
|
-
refreshBuffer: z4.string().default("30m"),
|
|
9013
|
-
setupScript: z4.string().optional(),
|
|
9014
|
-
roles: z4.record(z4.string(), AuthRoleSchema).default({})
|
|
9015
|
-
});
|
|
9016
|
-
var WebSchema = z4.object({
|
|
9017
|
-
baseUrl: z4.record(z4.string(), z4.string().url()).refine((m) => Object.keys(m).length > 0, {
|
|
9018
|
-
message: "baseUrl must have at least one environment"
|
|
9019
|
-
}),
|
|
9020
|
-
defaultEnv: z4.string(),
|
|
9021
|
-
auth: AuthSchema.prefault({}),
|
|
9022
|
-
testData: z4.object({
|
|
9023
|
-
users: z4.record(z4.string(), z4.object({ fromAuth: z4.string() })).default({})
|
|
9024
|
-
}).prefault({})
|
|
9025
|
-
}).refine((w) => w.baseUrl[w.defaultEnv] !== undefined, {
|
|
9026
|
-
message: "defaultEnv must exist in baseUrl map",
|
|
9027
|
-
path: ["defaultEnv"]
|
|
9028
|
-
});
|
|
9029
|
-
var JiraSchema = z4.object({
|
|
9030
|
-
baseUrl: z4.string().url(),
|
|
9031
|
-
projectKeys: z4.array(z4.string().min(1)).min(1),
|
|
9032
|
-
fields: z4.object({
|
|
9033
|
-
story: z4.string().min(1),
|
|
9034
|
-
acceptanceCriteria: z4.string().optional(),
|
|
9035
|
-
attachments: z4.string().default("attachment")
|
|
9036
|
-
})
|
|
9037
|
-
});
|
|
9038
|
-
var AISchema = z4.object({
|
|
9039
|
-
livePageSnapshot: z4.boolean().default(true),
|
|
9040
|
-
confidenceThreshold: z4.enum(["low", "medium", "high"]).default("medium"),
|
|
9041
|
-
maxRetries: z4.object({
|
|
9042
|
-
typecheck: z4.number().int().min(0).max(5).default(2),
|
|
9043
|
-
lint: z4.number().int().min(0).max(5).default(2),
|
|
9044
|
-
validateFeature: z4.number().int().min(0).max(5).default(2)
|
|
9045
|
-
}).prefault({})
|
|
9046
|
-
}).prefault({});
|
|
9047
|
-
var ReportingSchema = z4.object({
|
|
9048
|
-
language: z4.enum(["en", "vi"]).default("en"),
|
|
9049
|
-
postToJira: z4.boolean().default(true),
|
|
9050
|
-
transition: z4.object({
|
|
9051
|
-
onPass: z4.string().nullable().default(null),
|
|
9052
|
-
onFail: z4.string().nullable().default(null)
|
|
9053
|
-
}).prefault({}),
|
|
9054
|
-
artifactLinks: z4.enum(["git", "local"]).default("git")
|
|
9055
|
-
}).prefault({});
|
|
9056
|
-
var RunSchema = z4.object({
|
|
9057
|
-
autoImpact: z4.object({
|
|
9058
|
-
enabled: z4.boolean().default(true),
|
|
9059
|
-
threshold: z4.number().nonnegative().default(8)
|
|
9060
|
-
}).prefault({})
|
|
9061
|
-
}).prefault({});
|
|
9062
|
-
var XeraConfigSchema = z4.object({
|
|
9063
|
-
jira: JiraSchema,
|
|
9064
|
-
web: WebSchema,
|
|
9065
|
-
ai: AISchema,
|
|
9066
|
-
reporting: ReportingSchema,
|
|
9067
|
-
run: RunSchema.prefault({}),
|
|
9068
|
-
adapters: z4.array(z4.string().min(1)).min(1).default(["web"])
|
|
9069
|
-
});
|
|
9070
|
-
|
|
9071
|
-
// src/config/load.ts
|
|
9072
|
-
async function loadConfig(cwd) {
|
|
9073
|
-
const path = join12(cwd, "xera.config.ts");
|
|
9074
|
-
if (!existsSync13(path)) {
|
|
9075
|
-
throw new Error(`xera.config.ts not found in ${cwd}`);
|
|
9076
|
-
}
|
|
9077
|
-
const mod = await import(pathToFileURL(path).href);
|
|
9078
|
-
const raw = mod.default ?? mod;
|
|
9079
|
-
return XeraConfigSchema.parse(raw);
|
|
9080
|
-
}
|
|
9081
|
-
|
|
9082
9248
|
// src/logging/ndjson-logger.ts
|
|
9083
|
-
import { appendFileSync as appendFileSync2, existsSync as
|
|
9084
|
-
import { dirname as
|
|
9249
|
+
import { appendFileSync as appendFileSync2, existsSync as existsSync16, mkdirSync as mkdirSync7, readFileSync as readFileSync13 } from "fs";
|
|
9250
|
+
import { dirname as dirname4 } from "path";
|
|
9085
9251
|
|
|
9086
9252
|
class NdjsonLogger {
|
|
9087
9253
|
path;
|
|
9088
9254
|
constructor(path) {
|
|
9089
9255
|
this.path = path;
|
|
9090
|
-
|
|
9256
|
+
mkdirSync7(dirname4(path), { recursive: true });
|
|
9091
9257
|
}
|
|
9092
9258
|
log(payload) {
|
|
9093
9259
|
const entry = { ts: new Date().toISOString(), ...payload };
|
|
@@ -9095,9 +9261,9 @@ class NdjsonLogger {
|
|
|
9095
9261
|
`);
|
|
9096
9262
|
}
|
|
9097
9263
|
static readAll(path) {
|
|
9098
|
-
if (!
|
|
9264
|
+
if (!existsSync16(path))
|
|
9099
9265
|
return [];
|
|
9100
|
-
const txt =
|
|
9266
|
+
const txt = readFileSync13(path, "utf8").trim();
|
|
9101
9267
|
if (!txt)
|
|
9102
9268
|
return [];
|
|
9103
9269
|
return txt.split(`
|
|
@@ -9132,14 +9298,41 @@ async function execCmd(argv) {
|
|
|
9132
9298
|
}
|
|
9133
9299
|
const t0 = Date.now();
|
|
9134
9300
|
try {
|
|
9135
|
-
|
|
9301
|
+
const meta = readMeta(paths.metaPath);
|
|
9302
|
+
const adapter = meta?.adapter ?? "web";
|
|
9303
|
+
if (adapter === "http") {
|
|
9304
|
+
if (!config.http) {
|
|
9305
|
+
throw new Error("http adapter requires http config block");
|
|
9306
|
+
}
|
|
9307
|
+
const env = process.env["XERA_ENV"] ?? config.http.defaultEnv;
|
|
9308
|
+
const { HttpAdapter } = await import("@xera-ai/http");
|
|
9309
|
+
const result = await HttpAdapter.execute({
|
|
9310
|
+
ticketDir: paths.ticketDir,
|
|
9311
|
+
config,
|
|
9312
|
+
runId,
|
|
9313
|
+
env
|
|
9314
|
+
});
|
|
9315
|
+
log.log({
|
|
9316
|
+
step: "exec.complete",
|
|
9317
|
+
runId,
|
|
9318
|
+
outcome: result.outcome,
|
|
9319
|
+
elapsedMs: Date.now() - t0
|
|
9320
|
+
});
|
|
9321
|
+
console.log(`[xera:exec] runId=${runId} outcome=${result.outcome}`);
|
|
9322
|
+
return result.outcome === "PASS" ? 0 : 3;
|
|
9323
|
+
}
|
|
9324
|
+
if (!config.web) {
|
|
9325
|
+
throw new Error("web adapter requires web config block");
|
|
9326
|
+
}
|
|
9327
|
+
const webConfig = config.web;
|
|
9328
|
+
if (webConfig.auth.strategy === "storageState" && webConfig.auth.setupScript) {
|
|
9136
9329
|
const browser = await chromium.launch();
|
|
9137
9330
|
try {
|
|
9138
|
-
for (const [roleName, roleCreds] of Object.entries(
|
|
9331
|
+
for (const [roleName, roleCreds] of Object.entries(webConfig.auth.roles)) {
|
|
9139
9332
|
const entry = readAuthState(paths.authDir, roleName);
|
|
9140
9333
|
if (needsRefresh(entry, {
|
|
9141
|
-
ttl:
|
|
9142
|
-
refreshBuffer:
|
|
9334
|
+
ttl: webConfig.auth.ttl,
|
|
9335
|
+
refreshBuffer: webConfig.auth.refreshBuffer
|
|
9143
9336
|
})) {
|
|
9144
9337
|
const email = process.env[roleCreds.envEmail];
|
|
9145
9338
|
const password = process.env[roleCreds.envPassword];
|
|
@@ -9150,7 +9343,7 @@ async function execCmd(argv) {
|
|
|
9150
9343
|
await runAuthSetup({
|
|
9151
9344
|
role: roleName,
|
|
9152
9345
|
creds: { email, password },
|
|
9153
|
-
setupScriptPath:
|
|
9346
|
+
setupScriptPath: join14(cwd, webConfig.auth.setupScript),
|
|
9154
9347
|
authDir: paths.authDir,
|
|
9155
9348
|
browser
|
|
9156
9349
|
});
|
|
@@ -9161,23 +9354,23 @@ async function execCmd(argv) {
|
|
|
9161
9354
|
await browser.close();
|
|
9162
9355
|
}
|
|
9163
9356
|
}
|
|
9164
|
-
if (
|
|
9165
|
-
for (const roleName of Object.keys(
|
|
9357
|
+
if (webConfig.auth.strategy === "storageState") {
|
|
9358
|
+
for (const roleName of Object.keys(webConfig.auth.roles)) {
|
|
9166
9359
|
if (readAuthState(paths.authDir, roleName)) {
|
|
9167
9360
|
stagePlaywrightState(paths.authDir, roleName);
|
|
9168
9361
|
}
|
|
9169
9362
|
}
|
|
9170
9363
|
}
|
|
9171
|
-
const cfgPath =
|
|
9172
|
-
if (!
|
|
9364
|
+
const cfgPath = join14(cwd, "playwright.config.ts");
|
|
9365
|
+
if (!existsSync17(cfgPath)) {
|
|
9173
9366
|
console.error(`[xera:exec] missing ${cfgPath}. Run \`xera init\` to scaffold it, then re-run.`);
|
|
9174
9367
|
return 1;
|
|
9175
9368
|
}
|
|
9176
9369
|
const runDir = paths.runPath(runId).runDir;
|
|
9177
|
-
|
|
9178
|
-
const envName = process.env.XERA_ENV ??
|
|
9179
|
-
const baseURL =
|
|
9180
|
-
const reportJsonPath =
|
|
9370
|
+
mkdirSync8(runDir, { recursive: true });
|
|
9371
|
+
const envName = process.env.XERA_ENV ?? webConfig.defaultEnv;
|
|
9372
|
+
const baseURL = webConfig.baseUrl[envName] ?? webConfig.baseUrl[webConfig.defaultEnv];
|
|
9373
|
+
const reportJsonPath = join14(runDir, "report.json");
|
|
9181
9374
|
log.log({ step: "exec.start", runId, env: envName, baseURL });
|
|
9182
9375
|
const r = await runPlaywright({
|
|
9183
9376
|
specPath: paths.specPath,
|
|
@@ -9204,83 +9397,46 @@ import { dirname as dirname5 } from "path";
|
|
|
9204
9397
|
|
|
9205
9398
|
// src/artifact/hash.ts
|
|
9206
9399
|
import { createHash as createHash4 } from "crypto";
|
|
9207
|
-
import { existsSync as
|
|
9400
|
+
import { existsSync as existsSync18, readFileSync as readFileSync14 } from "fs";
|
|
9208
9401
|
function hashString(s) {
|
|
9209
9402
|
return `sha256:${createHash4("sha256").update(s).digest("hex")}`;
|
|
9210
9403
|
}
|
|
9211
9404
|
function hashFile(path) {
|
|
9212
|
-
return hashString(
|
|
9405
|
+
return hashString(readFileSync14(path, "utf8"));
|
|
9213
9406
|
}
|
|
9214
9407
|
function hashFileIfExists(path) {
|
|
9215
|
-
if (!
|
|
9408
|
+
if (!existsSync18(path))
|
|
9216
9409
|
return null;
|
|
9217
9410
|
return hashFile(path);
|
|
9218
9411
|
}
|
|
9219
9412
|
|
|
9220
|
-
// src/artifact/meta.ts
|
|
9221
|
-
import { existsSync as existsSync17, mkdirSync as mkdirSync8, readFileSync as readFileSync14, writeFileSync as writeFileSync7 } from "fs";
|
|
9222
|
-
import { dirname as dirname4 } from "path";
|
|
9223
|
-
import { z as z5 } from "zod";
|
|
9224
|
-
var MetaJsonSchema = z5.object({
|
|
9225
|
-
ticket: z5.string(),
|
|
9226
|
-
adapter: z5.string(),
|
|
9227
|
-
xera_version: z5.string(),
|
|
9228
|
-
prompts_version: z5.string(),
|
|
9229
|
-
fetched_at: z5.string().optional(),
|
|
9230
|
-
story_hash: z5.string().optional(),
|
|
9231
|
-
feature_generated_at: z5.string().optional(),
|
|
9232
|
-
feature_generated_from_story_hash: z5.string().optional(),
|
|
9233
|
-
feature_hash: z5.string().optional(),
|
|
9234
|
-
script_generated_at: z5.string().optional(),
|
|
9235
|
-
script_generated_from_feature_hash: z5.string().optional(),
|
|
9236
|
-
script_warnings: z5.array(z5.string()).optional()
|
|
9237
|
-
});
|
|
9238
|
-
function readMeta(path) {
|
|
9239
|
-
if (!existsSync17(path))
|
|
9240
|
-
return null;
|
|
9241
|
-
return MetaJsonSchema.parse(JSON.parse(readFileSync14(path, "utf8")));
|
|
9242
|
-
}
|
|
9243
|
-
function writeMeta(path, meta) {
|
|
9244
|
-
mkdirSync8(dirname4(path), { recursive: true });
|
|
9245
|
-
writeFileSync7(path, JSON.stringify(meta, null, 2));
|
|
9246
|
-
}
|
|
9247
|
-
function updateMeta(path, patch) {
|
|
9248
|
-
const existing = readMeta(path);
|
|
9249
|
-
if (!existing) {
|
|
9250
|
-
throw new Error(`meta.json not found at ${path}; cannot update`);
|
|
9251
|
-
}
|
|
9252
|
-
const next = { ...existing, ...patch };
|
|
9253
|
-
writeMeta(path, next);
|
|
9254
|
-
return next;
|
|
9255
|
-
}
|
|
9256
|
-
|
|
9257
9413
|
// src/jira/mcp-backend.ts
|
|
9258
|
-
import { existsSync as
|
|
9414
|
+
import { existsSync as existsSync19, mkdirSync as mkdirSync9, readFileSync as readFileSync15, writeFileSync as writeFileSync8 } from "fs";
|
|
9259
9415
|
import { tmpdir } from "os";
|
|
9260
|
-
import { join as
|
|
9416
|
+
import { join as join15 } from "path";
|
|
9261
9417
|
var MCP_ENV = "XERA_MCP_JIRA";
|
|
9262
9418
|
async function createMcpBackend(_baseUrl) {
|
|
9263
9419
|
if (process.env[MCP_ENV] !== "1")
|
|
9264
9420
|
return null;
|
|
9265
|
-
const tmpDir =
|
|
9421
|
+
const tmpDir = join15(tmpdir(), "xera-mcp");
|
|
9266
9422
|
mkdirSync9(tmpDir, { recursive: true });
|
|
9267
9423
|
return {
|
|
9268
9424
|
backend: "mcp",
|
|
9269
9425
|
async fetchTicket(key, _fields) {
|
|
9270
|
-
const cachePath =
|
|
9271
|
-
if (!
|
|
9426
|
+
const cachePath = join15(tmpDir, `${key}.json`);
|
|
9427
|
+
if (!existsSync19(cachePath)) {
|
|
9272
9428
|
throw new Error(`MCP-mode fetch requires the skill to first call mcp__atlassian__getJiraIssue and write ${cachePath}. ` + `If you are running this directly, unset ${MCP_ENV} to use REST.`);
|
|
9273
9429
|
}
|
|
9274
9430
|
const parsed = JSON.parse(readFileSync15(cachePath, "utf8"));
|
|
9275
9431
|
return parsed;
|
|
9276
9432
|
},
|
|
9277
9433
|
async postComment(key, body) {
|
|
9278
|
-
const outPath =
|
|
9434
|
+
const outPath = join15(tmpDir, `${key}.comment.json`);
|
|
9279
9435
|
writeFileSync8(outPath, JSON.stringify({ key, body }));
|
|
9280
9436
|
return { id: "mcp-pending" };
|
|
9281
9437
|
},
|
|
9282
9438
|
async transitionStatus(key, statusName) {
|
|
9283
|
-
const outPath =
|
|
9439
|
+
const outPath = join15(tmpDir, `${key}.transition.json`);
|
|
9284
9440
|
writeFileSync8(outPath, JSON.stringify({ key, statusName }));
|
|
9285
9441
|
},
|
|
9286
9442
|
async listFields(_sampleKey) {
|
|
@@ -9455,8 +9611,8 @@ init_graph_backfill();
|
|
|
9455
9611
|
// src/graph/enrich.ts
|
|
9456
9612
|
init_store();
|
|
9457
9613
|
init_ulid();
|
|
9458
|
-
import { existsSync as
|
|
9459
|
-
import { join as
|
|
9614
|
+
import { existsSync as existsSync20, readFileSync as readFileSync16 } from "fs";
|
|
9615
|
+
import { join as join16 } from "path";
|
|
9460
9616
|
import { z as z6 } from "zod";
|
|
9461
9617
|
var MAX_SIMILAR_EDGES = 10;
|
|
9462
9618
|
var MIN_CONFIDENCE = 0.7;
|
|
@@ -9478,8 +9634,8 @@ var mk2 = (actor, type, payload) => ({
|
|
|
9478
9634
|
payload
|
|
9479
9635
|
});
|
|
9480
9636
|
async function enrichTicket(repoRoot, ticketId, opts) {
|
|
9481
|
-
const inputPath =
|
|
9482
|
-
if (!
|
|
9637
|
+
const inputPath = join16(repoRoot, ".xera", ticketId, "enrichment-input.json");
|
|
9638
|
+
if (!existsSync20(inputPath)) {
|
|
9483
9639
|
throw new Error(`enrichment-input.json not found at ${inputPath}`);
|
|
9484
9640
|
}
|
|
9485
9641
|
const raw = JSON.parse(readFileSync16(inputPath, "utf8"));
|
|
@@ -9592,11 +9748,11 @@ init_graph_record();
|
|
|
9592
9748
|
|
|
9593
9749
|
// src/bin-internal/graph-render.ts
|
|
9594
9750
|
import { mkdirSync as mkdirSync11, renameSync as renameSync2, writeFileSync as writeFileSync10 } from "fs";
|
|
9595
|
-
import { dirname as dirname7, join as
|
|
9751
|
+
import { dirname as dirname7, join as join18 } from "path";
|
|
9596
9752
|
|
|
9597
9753
|
// src/graph/render.ts
|
|
9598
9754
|
import { readFileSync as readFileSync17 } from "fs";
|
|
9599
|
-
import { dirname as dirname6, join as
|
|
9755
|
+
import { dirname as dirname6, join as join17 } from "path";
|
|
9600
9756
|
import { fileURLToPath } from "url";
|
|
9601
9757
|
var COLORS = {
|
|
9602
9758
|
ticket: "#3B82F6",
|
|
@@ -9815,9 +9971,9 @@ function transformForVisNetwork(snap, opts) {
|
|
|
9815
9971
|
}
|
|
9816
9972
|
var __filename2 = fileURLToPath(import.meta.url);
|
|
9817
9973
|
var __dirname2 = dirname6(__filename2);
|
|
9818
|
-
var TEMPLATES_DIR =
|
|
9974
|
+
var TEMPLATES_DIR = join17(__dirname2, "templates");
|
|
9819
9975
|
function loadTemplate(name) {
|
|
9820
|
-
return readFileSync17(
|
|
9976
|
+
return readFileSync17(join17(TEMPLATES_DIR, name), "utf8");
|
|
9821
9977
|
}
|
|
9822
9978
|
function statsToHuman(s) {
|
|
9823
9979
|
return `${s.tickets} tickets \xB7 ${s.scenarios} scenarios \xB7 ${s.poms} POMs \xB7 ${s.edges} edges`;
|
|
@@ -9863,7 +10019,7 @@ async function graphRenderCmd(argv) {
|
|
|
9863
10019
|
depth = parseDepth(argv[++i]);
|
|
9864
10020
|
}
|
|
9865
10021
|
const repoRoot = process.cwd();
|
|
9866
|
-
const finalPath = outPath ??
|
|
10022
|
+
const finalPath = outPath ?? join18(repoRoot, ".xera/graph.html");
|
|
9867
10023
|
const snap = deriveSnapshot(loadAllEvents(repoRoot));
|
|
9868
10024
|
const totalNodeCount = Object.keys(snap.tickets).length + Object.keys(snap.scenarios).length + Object.keys(snap.poms).length + Object.keys(snap.areas).length;
|
|
9869
10025
|
const performanceMode = decidePerformanceMode(totalNodeCount);
|
|
@@ -9915,11 +10071,11 @@ async function graphSnapshotCmd(argv) {
|
|
|
9915
10071
|
}
|
|
9916
10072
|
|
|
9917
10073
|
// src/bin-internal/heal-prepare.ts
|
|
9918
|
-
import { existsSync as
|
|
9919
|
-
import { join as
|
|
10074
|
+
import { existsSync as existsSync21, readdirSync as readdirSync6, readFileSync as readFileSync18, writeFileSync as writeFileSync11 } from "fs";
|
|
10075
|
+
import { join as join19 } from "path";
|
|
9920
10076
|
import { scrubFreeText } from "@xera-ai/web";
|
|
9921
10077
|
|
|
9922
|
-
// ../../node_modules
|
|
10078
|
+
// ../../node_modules/fflate/esm/index.mjs
|
|
9923
10079
|
import { createRequire } from "module";
|
|
9924
10080
|
var require2 = createRequire("/");
|
|
9925
10081
|
var _a;
|
|
@@ -10344,7 +10500,7 @@ function classifyKind(raw) {
|
|
|
10344
10500
|
return "other";
|
|
10345
10501
|
}
|
|
10346
10502
|
function extractDomSnapshot(tracePath) {
|
|
10347
|
-
if (!
|
|
10503
|
+
if (!existsSync21(tracePath))
|
|
10348
10504
|
return "";
|
|
10349
10505
|
const buf = readFileSync18(tracePath);
|
|
10350
10506
|
const entries = unzipSync(buf);
|
|
@@ -10394,12 +10550,12 @@ function extractDomSnapshot(tracePath) {
|
|
|
10394
10550
|
return scrubFreeText(html);
|
|
10395
10551
|
}
|
|
10396
10552
|
function findPomLine(ticketDir, rawLocator) {
|
|
10397
|
-
const pomDir =
|
|
10553
|
+
const pomDir = join19(ticketDir, "page-objects");
|
|
10398
10554
|
const candidates = [];
|
|
10399
|
-
if (
|
|
10555
|
+
if (existsSync21(pomDir)) {
|
|
10400
10556
|
for (const name of readdirSync6(pomDir)) {
|
|
10401
10557
|
if (name.endsWith(".ts"))
|
|
10402
|
-
candidates.push(
|
|
10558
|
+
candidates.push(join19(pomDir, name));
|
|
10403
10559
|
}
|
|
10404
10560
|
}
|
|
10405
10561
|
for (const file of candidates) {
|
|
@@ -10441,13 +10597,13 @@ function findGherkinStep(featureText, rawLocator) {
|
|
|
10441
10597
|
}
|
|
10442
10598
|
function healPrepare(repoRoot, ticket, runId, scenarioName) {
|
|
10443
10599
|
const paths = resolveArtifactPaths(repoRoot, ticket);
|
|
10444
|
-
const classifierPath =
|
|
10600
|
+
const classifierPath = join19(paths.ticketDir, "classifier-input.json");
|
|
10445
10601
|
const classifier = JSON.parse(readFileSync18(classifierPath, "utf8"));
|
|
10446
10602
|
const cls = classifier.scenarios.find((s) => s.name === scenarioName);
|
|
10447
10603
|
if (!cls)
|
|
10448
10604
|
throw new Error(`scenario not found in classifier-input: "${scenarioName}"`);
|
|
10449
|
-
const runDir =
|
|
10450
|
-
const normalized = JSON.parse(readFileSync18(
|
|
10605
|
+
const runDir = join19(paths.runsDir, runId);
|
|
10606
|
+
const normalized = JSON.parse(readFileSync18(join19(runDir, "normalized.json"), "utf8"));
|
|
10451
10607
|
const normSc = normalized.scenarios.find((s) => s.name === scenarioName);
|
|
10452
10608
|
if (!normSc?.failure)
|
|
10453
10609
|
throw new Error(`no failure recorded for scenario "${scenarioName}"`);
|
|
@@ -10460,7 +10616,7 @@ function healPrepare(repoRoot, ticket, runId, scenarioName) {
|
|
|
10460
10616
|
const pomLoc = findPomLine(paths.ticketDir, raw);
|
|
10461
10617
|
const featureText = readFileSync18(paths.featurePath, "utf8");
|
|
10462
10618
|
const gherkinStep = findGherkinStep(featureText, raw);
|
|
10463
|
-
const domSnapshotAtFailure = extractDomSnapshot(
|
|
10619
|
+
const domSnapshotAtFailure = extractDomSnapshot(join19(runDir, "trace.zip"));
|
|
10464
10620
|
return {
|
|
10465
10621
|
ticket,
|
|
10466
10622
|
runId,
|
|
@@ -10480,7 +10636,7 @@ async function healPrepareCmd(argv) {
|
|
|
10480
10636
|
try {
|
|
10481
10637
|
const result = healPrepare(process.cwd(), ticket, runId, scenarioName);
|
|
10482
10638
|
const paths = resolveArtifactPaths(process.cwd(), ticket);
|
|
10483
|
-
const outPath =
|
|
10639
|
+
const outPath = join19(paths.runsDir, runId, "heal-input.json");
|
|
10484
10640
|
writeFileSync11(outPath, JSON.stringify(result, null, 2));
|
|
10485
10641
|
console.log(`[xera:heal-prepare] wrote ${outPath}`);
|
|
10486
10642
|
return 0;
|
|
@@ -10492,7 +10648,7 @@ async function healPrepareCmd(argv) {
|
|
|
10492
10648
|
|
|
10493
10649
|
// src/bin-internal/impact-prepare.ts
|
|
10494
10650
|
import { mkdirSync as mkdirSync12, writeFileSync as writeFileSync12 } from "fs";
|
|
10495
|
-
import { join as
|
|
10651
|
+
import { join as join20 } from "path";
|
|
10496
10652
|
|
|
10497
10653
|
// src/graph/impact.ts
|
|
10498
10654
|
var PRIORITY_WEIGHT = { p0: 3, p1: 2, p2: 1 };
|
|
@@ -10742,11 +10898,11 @@ async function impactPrepareCmd(argv) {
|
|
|
10742
10898
|
scenarios,
|
|
10743
10899
|
generatedAt: new Date().toISOString()
|
|
10744
10900
|
};
|
|
10745
|
-
const impactDir =
|
|
10901
|
+
const impactDir = join20(repoRoot, ".xera/impact");
|
|
10746
10902
|
mkdirSync12(impactDir, { recursive: true });
|
|
10747
|
-
writeFileSync12(
|
|
10903
|
+
writeFileSync12(join20(impactDir, `${ticket}.json`), JSON.stringify(report, null, 2));
|
|
10748
10904
|
if (!quiet) {
|
|
10749
|
-
writeFileSync12(
|
|
10905
|
+
writeFileSync12(join20(impactDir, `${ticket}.md`), renderImpactMarkdown(report));
|
|
10750
10906
|
}
|
|
10751
10907
|
return 0;
|
|
10752
10908
|
}
|
|
@@ -10771,9 +10927,8 @@ async function lintCmd(argv) {
|
|
|
10771
10927
|
}
|
|
10772
10928
|
|
|
10773
10929
|
// src/bin-internal/normalize.ts
|
|
10774
|
-
import { existsSync as
|
|
10775
|
-
import { join as
|
|
10776
|
-
import { normalizeRun } from "@xera-ai/web";
|
|
10930
|
+
import { existsSync as existsSync22, readdirSync as readdirSync7 } from "fs";
|
|
10931
|
+
import { join as join21 } from "path";
|
|
10777
10932
|
async function normalizeCmd(argv) {
|
|
10778
10933
|
const ticket = argv[0];
|
|
10779
10934
|
if (!ticket) {
|
|
@@ -10787,22 +10942,31 @@ async function normalizeCmd(argv) {
|
|
|
10787
10942
|
console.error("[xera:normalize] no run found");
|
|
10788
10943
|
return 1;
|
|
10789
10944
|
}
|
|
10790
|
-
const runDir =
|
|
10791
|
-
if (!
|
|
10945
|
+
const runDir = join21(paths.runsDir, runId);
|
|
10946
|
+
if (!existsSync22(runDir)) {
|
|
10792
10947
|
console.error(`[xera:normalize] runs/${runId} missing`);
|
|
10793
10948
|
return 1;
|
|
10794
10949
|
}
|
|
10950
|
+
const meta = readMeta(paths.metaPath);
|
|
10951
|
+
const adapter = meta?.adapter ?? "web";
|
|
10952
|
+
if (adapter === "http") {
|
|
10953
|
+
const { normalizeHttpRun } = await import("@xera-ai/http");
|
|
10954
|
+
await normalizeHttpRun({ runId, runDir });
|
|
10955
|
+
console.log(`[xera:normalize] wrote normalized.json (http)`);
|
|
10956
|
+
return 0;
|
|
10957
|
+
}
|
|
10958
|
+
const { normalizeRun } = await import("@xera-ai/web");
|
|
10795
10959
|
const r = await normalizeRun({ runId, runDir });
|
|
10796
10960
|
console.log(`[xera:normalize] wrote normalized.json (scrubbed_fields_count=${r.scrubbed_fields_count})`);
|
|
10797
10961
|
return 0;
|
|
10798
10962
|
}
|
|
10799
10963
|
|
|
10800
10964
|
// src/bin-internal/post.ts
|
|
10801
|
-
import { existsSync as
|
|
10802
|
-
import { join as
|
|
10965
|
+
import { existsSync as existsSync24, readFileSync as readFileSync20 } from "fs";
|
|
10966
|
+
import { join as join22 } from "path";
|
|
10803
10967
|
|
|
10804
10968
|
// src/artifact/status.ts
|
|
10805
|
-
import { existsSync as
|
|
10969
|
+
import { existsSync as existsSync23, mkdirSync as mkdirSync13, readFileSync as readFileSync19, writeFileSync as writeFileSync13 } from "fs";
|
|
10806
10970
|
import { dirname as dirname8 } from "path";
|
|
10807
10971
|
import { z as z7 } from "zod";
|
|
10808
10972
|
var ClassificationEnum = z7.enum([
|
|
@@ -10811,7 +10975,10 @@ var ClassificationEnum = z7.enum([
|
|
|
10811
10975
|
"SELECTOR_DRIFT",
|
|
10812
10976
|
"FLAKY",
|
|
10813
10977
|
"TEST_BUG",
|
|
10814
|
-
"TEST_OUTDATED"
|
|
10978
|
+
"TEST_OUTDATED",
|
|
10979
|
+
"CONTRACT_DRIFT",
|
|
10980
|
+
"RATE_LIMITED",
|
|
10981
|
+
"AUTH_EXPIRED"
|
|
10815
10982
|
]);
|
|
10816
10983
|
var ResultEnum = z7.enum(["PASS", "FAIL"]);
|
|
10817
10984
|
var ConfidenceEnum = z7.enum(["low", "medium", "high"]);
|
|
@@ -10837,7 +11004,7 @@ var StatusJsonSchema = z7.object({
|
|
|
10837
11004
|
});
|
|
10838
11005
|
var HISTORY_CAP = 20;
|
|
10839
11006
|
function readStatus(path) {
|
|
10840
|
-
if (!
|
|
11007
|
+
if (!existsSync23(path))
|
|
10841
11008
|
return null;
|
|
10842
11009
|
return StatusJsonSchema.parse(JSON.parse(readFileSync19(path, "utf8")));
|
|
10843
11010
|
}
|
|
@@ -10869,8 +11036,8 @@ async function postCmd(argv) {
|
|
|
10869
11036
|
return 0;
|
|
10870
11037
|
}
|
|
10871
11038
|
const paths = resolveArtifactPaths(cwd, ticket);
|
|
10872
|
-
const draftPath =
|
|
10873
|
-
if (!
|
|
11039
|
+
const draftPath = join22(paths.ticketDir, "jira-comment.draft.md");
|
|
11040
|
+
if (!existsSync24(draftPath)) {
|
|
10874
11041
|
console.error(`[xera:post] no draft at ${draftPath}; run \`xera-internal report\` first.`);
|
|
10875
11042
|
return 1;
|
|
10876
11043
|
}
|
|
@@ -10902,12 +11069,15 @@ async function promoteCmd(argv) {
|
|
|
10902
11069
|
}
|
|
10903
11070
|
|
|
10904
11071
|
// src/bin-internal/report.ts
|
|
10905
|
-
import { existsSync as
|
|
10906
|
-
import { join as
|
|
11072
|
+
import { existsSync as existsSync26, readFileSync as readFileSync21, writeFileSync as writeFileSync14 } from "fs";
|
|
11073
|
+
import { join as join23 } from "path";
|
|
10907
11074
|
|
|
10908
11075
|
// src/classifier/aggregate.ts
|
|
10909
11076
|
var CLASS_PRIORITY = [
|
|
10910
11077
|
"REAL_BUG",
|
|
11078
|
+
"CONTRACT_DRIFT",
|
|
11079
|
+
"AUTH_EXPIRED",
|
|
11080
|
+
"RATE_LIMITED",
|
|
10911
11081
|
"TEST_OUTDATED",
|
|
10912
11082
|
"TEST_BUG",
|
|
10913
11083
|
"SELECTOR_DRIFT",
|
|
@@ -10934,6 +11104,134 @@ function aggregateScenarios(scenarios) {
|
|
|
10934
11104
|
return { overall: chosen, overallConfidence: minConf, scenarios };
|
|
10935
11105
|
}
|
|
10936
11106
|
|
|
11107
|
+
// src/classifier/auth-expired.ts
|
|
11108
|
+
function jwtExpPast(jwt, now) {
|
|
11109
|
+
const parts = jwt.split(".");
|
|
11110
|
+
if (parts.length !== 3)
|
|
11111
|
+
return false;
|
|
11112
|
+
try {
|
|
11113
|
+
const payloadB64 = parts[1];
|
|
11114
|
+
if (!payloadB64)
|
|
11115
|
+
return false;
|
|
11116
|
+
const payload = JSON.parse(Buffer.from(payloadB64, "base64url").toString("utf8"));
|
|
11117
|
+
return typeof payload.exp === "number" && payload.exp * 1000 < now;
|
|
11118
|
+
} catch {
|
|
11119
|
+
return false;
|
|
11120
|
+
}
|
|
11121
|
+
}
|
|
11122
|
+
function classifyAuthExpired(input) {
|
|
11123
|
+
const has401 = input.calls.some((c) => c.status === 401);
|
|
11124
|
+
if (!has401)
|
|
11125
|
+
return null;
|
|
11126
|
+
const now = Date.now();
|
|
11127
|
+
for (const [role, entry] of Object.entries(input.authFiles)) {
|
|
11128
|
+
const fileExpired = new Date(entry.expires_at).getTime() < now;
|
|
11129
|
+
const jwtExpired = entry.type === "bearer" && jwtExpPast(entry.token, now);
|
|
11130
|
+
if (fileExpired || jwtExpired) {
|
|
11131
|
+
return {
|
|
11132
|
+
class: "AUTH_EXPIRED",
|
|
11133
|
+
rationale: `HTTP 401 captured; auth file for role '${role}' is past expiry. Run: bun run xera:auth-setup --role ${role}`
|
|
11134
|
+
};
|
|
11135
|
+
}
|
|
11136
|
+
}
|
|
11137
|
+
return null;
|
|
11138
|
+
}
|
|
11139
|
+
|
|
11140
|
+
// src/classifier/contract-drift.ts
|
|
11141
|
+
function matchPath(specPaths, actualUrl) {
|
|
11142
|
+
const path = actualUrl.split("?")[0] ?? actualUrl;
|
|
11143
|
+
for (const tmpl of specPaths) {
|
|
11144
|
+
const re = new RegExp(`^${tmpl.replace(/\{[^}]+\}/g, "[^/]+")}$`);
|
|
11145
|
+
if (re.test(path))
|
|
11146
|
+
return tmpl;
|
|
11147
|
+
}
|
|
11148
|
+
return null;
|
|
11149
|
+
}
|
|
11150
|
+
function matchesSchema(body, schema) {
|
|
11151
|
+
if (!schema)
|
|
11152
|
+
return true;
|
|
11153
|
+
if (schema.type === "object") {
|
|
11154
|
+
if (typeof body !== "object" || body === null || Array.isArray(body))
|
|
11155
|
+
return false;
|
|
11156
|
+
const obj = body;
|
|
11157
|
+
for (const req of schema.required ?? []) {
|
|
11158
|
+
if (!(req in obj))
|
|
11159
|
+
return false;
|
|
11160
|
+
}
|
|
11161
|
+
return true;
|
|
11162
|
+
}
|
|
11163
|
+
if (schema.type === "array")
|
|
11164
|
+
return Array.isArray(body);
|
|
11165
|
+
if (schema.type === "string")
|
|
11166
|
+
return typeof body === "string";
|
|
11167
|
+
if (schema.type === "integer" || schema.type === "number")
|
|
11168
|
+
return typeof body === "number";
|
|
11169
|
+
if (schema.type === "boolean")
|
|
11170
|
+
return typeof body === "boolean";
|
|
11171
|
+
if (schema.type === "null")
|
|
11172
|
+
return body === null;
|
|
11173
|
+
return true;
|
|
11174
|
+
}
|
|
11175
|
+
var VERBS = ["get", "post", "put", "patch", "delete"];
|
|
11176
|
+
function isVerb(s) {
|
|
11177
|
+
return VERBS.includes(s);
|
|
11178
|
+
}
|
|
11179
|
+
function classifyContractDrift(input) {
|
|
11180
|
+
if (input.openapi === null)
|
|
11181
|
+
return null;
|
|
11182
|
+
const specPaths = Object.keys(input.openapi.paths);
|
|
11183
|
+
for (const call of input.calls) {
|
|
11184
|
+
const tmpl = matchPath(specPaths, call.url);
|
|
11185
|
+
if (!tmpl) {
|
|
11186
|
+
return {
|
|
11187
|
+
class: "CONTRACT_DRIFT",
|
|
11188
|
+
rationale: `Endpoint ${call.method} ${call.url} not found in OpenAPI`
|
|
11189
|
+
};
|
|
11190
|
+
}
|
|
11191
|
+
const methodLower = call.method.toLowerCase();
|
|
11192
|
+
if (!isVerb(methodLower)) {
|
|
11193
|
+
return {
|
|
11194
|
+
class: "CONTRACT_DRIFT",
|
|
11195
|
+
rationale: `Method ${call.method} not supported by classifier for ${tmpl}`
|
|
11196
|
+
};
|
|
11197
|
+
}
|
|
11198
|
+
const pathItem = input.openapi.paths[tmpl];
|
|
11199
|
+
const op = pathItem?.[methodLower];
|
|
11200
|
+
if (!op) {
|
|
11201
|
+
return {
|
|
11202
|
+
class: "CONTRACT_DRIFT",
|
|
11203
|
+
rationale: `${call.method} not defined for ${tmpl} in OpenAPI`
|
|
11204
|
+
};
|
|
11205
|
+
}
|
|
11206
|
+
const respDef = op.responses?.[String(call.status)];
|
|
11207
|
+
if (!respDef) {
|
|
11208
|
+
return {
|
|
11209
|
+
class: "CONTRACT_DRIFT",
|
|
11210
|
+
rationale: `Status ${call.status} not enumerated for ${call.method} ${tmpl} in OpenAPI`
|
|
11211
|
+
};
|
|
11212
|
+
}
|
|
11213
|
+
const schema = respDef.content?.["application/json"]?.schema;
|
|
11214
|
+
if (!matchesSchema(call.respBody, schema)) {
|
|
11215
|
+
return {
|
|
11216
|
+
class: "CONTRACT_DRIFT",
|
|
11217
|
+
rationale: `Response body for ${call.method} ${tmpl} (${call.status}) does not match OpenAPI schema`
|
|
11218
|
+
};
|
|
11219
|
+
}
|
|
11220
|
+
}
|
|
11221
|
+
return null;
|
|
11222
|
+
}
|
|
11223
|
+
|
|
11224
|
+
// src/classifier/rate-limited.ts
|
|
11225
|
+
function classifyRateLimited(input) {
|
|
11226
|
+
const hit = input.calls.find((c) => c.status === 429);
|
|
11227
|
+
if (!hit)
|
|
11228
|
+
return null;
|
|
11229
|
+
return {
|
|
11230
|
+
class: "RATE_LIMITED",
|
|
11231
|
+
rationale: `Captured HTTP 429 on ${hit.method} ${hit.url}`
|
|
11232
|
+
};
|
|
11233
|
+
}
|
|
11234
|
+
|
|
10937
11235
|
// src/graph/classify.ts
|
|
10938
11236
|
var DEFAULT_THRESHOLD = 0.7;
|
|
10939
11237
|
var SHORT_CIRCUIT = ["FLAKY", "PASS"];
|
|
@@ -11038,11 +11336,11 @@ xera v${input.xeraVersion} \u2022 prompts v${input.promptsVersion}`;
|
|
|
11038
11336
|
}
|
|
11039
11337
|
|
|
11040
11338
|
// src/reporter/status-writer.ts
|
|
11041
|
-
import { existsSync as
|
|
11339
|
+
import { existsSync as existsSync25 } from "fs";
|
|
11042
11340
|
function writeStatusFromClassification(path, input) {
|
|
11043
11341
|
const result = input.classification.overall === "PASS" ? "PASS" : "FAIL";
|
|
11044
11342
|
const entry = { ts: input.runTs, result, class: input.classification.overall };
|
|
11045
|
-
if (!
|
|
11343
|
+
if (!existsSync25(path)) {
|
|
11046
11344
|
writeStatus(path, {
|
|
11047
11345
|
ticket: input.ticket,
|
|
11048
11346
|
lastRun: input.runTs,
|
|
@@ -11074,11 +11372,70 @@ async function reportCmd(argv) {
|
|
|
11074
11372
|
console.error("[xera:report] usage: report <TICKET> --input=<classifier-output.json>");
|
|
11075
11373
|
return 1;
|
|
11076
11374
|
}
|
|
11077
|
-
const
|
|
11375
|
+
const cwd = process.cwd();
|
|
11376
|
+
const paths = resolveArtifactPaths(cwd, ticket);
|
|
11078
11377
|
const input = JSON.parse(readFileSync21(inputArg.slice("--input=".length), "utf8"));
|
|
11079
|
-
|
|
11080
|
-
const
|
|
11081
|
-
|
|
11378
|
+
let httpRuleOverride = null;
|
|
11379
|
+
const meta = readMeta(paths.metaPath);
|
|
11380
|
+
if (meta?.adapter === "http") {
|
|
11381
|
+
const config = await loadConfig(cwd);
|
|
11382
|
+
if (config.http) {
|
|
11383
|
+
const normalizedPath = join23(paths.ticketDir, "runs", input.runId, "normalized.json");
|
|
11384
|
+
if (existsSync26(normalizedPath)) {
|
|
11385
|
+
const norm = JSON.parse(readFileSync21(normalizedPath, "utf8"));
|
|
11386
|
+
const calls = norm.http?.calls ?? [];
|
|
11387
|
+
const rate = classifyRateLimited({ calls });
|
|
11388
|
+
if (rate)
|
|
11389
|
+
httpRuleOverride = rate;
|
|
11390
|
+
if (!httpRuleOverride) {
|
|
11391
|
+
const authFiles = {};
|
|
11392
|
+
const httpAuthDir = join23(cwd, ".xera", ".auth", "http");
|
|
11393
|
+
for (const role of Object.keys(config.http.auth.roles)) {
|
|
11394
|
+
const entry = readAuthState(httpAuthDir, role);
|
|
11395
|
+
if (entry) {
|
|
11396
|
+
const p = entry.payload;
|
|
11397
|
+
if (typeof p.token === "string" && typeof p.type === "string") {
|
|
11398
|
+
authFiles[role] = {
|
|
11399
|
+
token: p.token,
|
|
11400
|
+
type: p.type,
|
|
11401
|
+
expires_at: entry.expires_at
|
|
11402
|
+
};
|
|
11403
|
+
}
|
|
11404
|
+
}
|
|
11405
|
+
}
|
|
11406
|
+
const authExp = classifyAuthExpired({ calls, authFiles });
|
|
11407
|
+
if (authExp)
|
|
11408
|
+
httpRuleOverride = authExp;
|
|
11409
|
+
}
|
|
11410
|
+
if (!httpRuleOverride && config.http.spec) {
|
|
11411
|
+
const { loadOpenApi } = await import("@xera-ai/http");
|
|
11412
|
+
const openapi = await loadOpenApi(config.http.spec);
|
|
11413
|
+
if (openapi) {
|
|
11414
|
+
const drift = classifyContractDrift({
|
|
11415
|
+
calls: calls.map((c) => ({
|
|
11416
|
+
method: c.method,
|
|
11417
|
+
url: c.url,
|
|
11418
|
+
status: c.status,
|
|
11419
|
+
respBody: c.respBody
|
|
11420
|
+
})),
|
|
11421
|
+
openapi
|
|
11422
|
+
});
|
|
11423
|
+
if (drift)
|
|
11424
|
+
httpRuleOverride = drift;
|
|
11425
|
+
}
|
|
11426
|
+
}
|
|
11427
|
+
}
|
|
11428
|
+
}
|
|
11429
|
+
}
|
|
11430
|
+
const scenariosForAggregation = httpRuleOverride ? input.scenarios.map((s) => s.outcome === "FAIL" ? {
|
|
11431
|
+
...s,
|
|
11432
|
+
class: httpRuleOverride.class,
|
|
11433
|
+
rationale: httpRuleOverride.rationale,
|
|
11434
|
+
confidence: "high"
|
|
11435
|
+
} : s) : input.scenarios;
|
|
11436
|
+
const aggregated = aggregateScenarios(scenariosForAggregation);
|
|
11437
|
+
const decisionsPath = join23(paths.ticketDir, "runs", input.runId, "outdated-decisions.json");
|
|
11438
|
+
const decisions = existsSync26(decisionsPath) ? JSON.parse(readFileSync21(decisionsPath, "utf8")) : {};
|
|
11082
11439
|
const graph = deriveSnapshot(loadAllEvents(process.cwd()));
|
|
11083
11440
|
const normalizeScenarioName = (name) => name.trim().toLowerCase().replace(/\s+/g, " ");
|
|
11084
11441
|
const scenarioIdByName = {};
|
|
@@ -11126,7 +11483,7 @@ async function reportCmd(argv) {
|
|
|
11126
11483
|
xeraVersion: "0.1.0",
|
|
11127
11484
|
promptsVersion: "1.0.0"
|
|
11128
11485
|
});
|
|
11129
|
-
const draftPath =
|
|
11486
|
+
const draftPath = join23(paths.ticketDir, "jira-comment.draft.md");
|
|
11130
11487
|
writeFileSync14(draftPath, md);
|
|
11131
11488
|
console.log(`[xera:report] wrote status.json and ${draftPath}`);
|
|
11132
11489
|
return 0;
|
|
@@ -11194,7 +11551,7 @@ async function unlockCmd(argv) {
|
|
|
11194
11551
|
}
|
|
11195
11552
|
|
|
11196
11553
|
// src/bin-internal/validate-feature.ts
|
|
11197
|
-
import { existsSync as
|
|
11554
|
+
import { existsSync as existsSync27, readFileSync as readFileSync22 } from "fs";
|
|
11198
11555
|
import { validateGherkin as validateGherkin2 } from "@xera-ai/web";
|
|
11199
11556
|
async function validateFeatureCmd(argv) {
|
|
11200
11557
|
const ticket = argv[0];
|
|
@@ -11203,7 +11560,7 @@ async function validateFeatureCmd(argv) {
|
|
|
11203
11560
|
return 1;
|
|
11204
11561
|
}
|
|
11205
11562
|
const paths = resolveArtifactPaths(process.cwd(), ticket);
|
|
11206
|
-
if (!
|
|
11563
|
+
if (!existsSync27(paths.featurePath)) {
|
|
11207
11564
|
console.error(`[xera:validate-feature] missing ${paths.featurePath}`);
|
|
11208
11565
|
return 1;
|
|
11209
11566
|
}
|
|
@@ -11219,6 +11576,7 @@ async function validateFeatureCmd(argv) {
|
|
|
11219
11576
|
|
|
11220
11577
|
// src/bin-internal/index.ts
|
|
11221
11578
|
var COMMANDS = {
|
|
11579
|
+
"auth-setup": authSetupCmd,
|
|
11222
11580
|
disputes: disputesCmd,
|
|
11223
11581
|
doctor: doctorCmd,
|
|
11224
11582
|
"eval-deterministic": evalDeterministicCmd,
|