lynkeus 0.2.0 → 0.4.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/lib/cases/ahead.d.ts +31 -0
- package/lib/cases/ahead.js +90 -0
- package/lib/cases/fixtures.d.ts +12 -0
- package/lib/cases/fixtures.js +32 -0
- package/lib/cases/flakes.d.ts +28 -0
- package/lib/cases/flakes.js +61 -0
- package/lib/cases/format.d.ts +5 -0
- package/lib/cases/format.js +30 -4
- package/lib/cases/portClaim.d.ts +10 -0
- package/lib/cases/portClaim.js +55 -0
- package/lib/cases/runfile.d.ts +24 -0
- package/lib/cases/runfile.js +108 -0
- package/lib/cases/runner.d.ts +82 -3
- package/lib/cases/runner.js +394 -40
- package/lib/cases/templates.d.ts +2 -2
- package/lib/cases/templates.js +14 -4
- package/lib/cases/traces.d.ts +58 -0
- package/lib/cases/traces.js +250 -0
- package/lib/cli.js +28 -7
- package/lib/commands/cases.js +411 -42
- package/lib/commands/check.d.ts +6 -0
- package/lib/commands/check.js +8 -3
- package/lib/commands/doctor.js +8 -2
- package/lib/commands/drive.js +32 -8
- package/lib/commands/headless.js +132 -8
- package/lib/commands/init.d.ts +29 -0
- package/lib/commands/init.js +295 -33
- package/lib/commands/report.d.ts +97 -0
- package/lib/commands/report.js +228 -0
- package/lib/config.d.ts +26 -1
- package/lib/config.js +30 -0
- package/lib/device/agentVersion.d.ts +7 -0
- package/lib/device/agentVersion.js +12 -0
- package/lib/device/devices.d.ts +5 -0
- package/lib/device/devices.js +27 -0
- package/lib/device/driver.js +2 -2
- package/lib/flow/runner.js +33 -1
- package/lib/flow/types.d.ts +2 -1
- package/lib/knowledge/contrast.d.ts +45 -0
- package/lib/knowledge/contrast.js +114 -0
- package/lib/knowledge/errors.js +1 -1
- package/lib/knowledge/lint.d.ts +2 -0
- package/lib/knowledge/lint.js +13 -3
- package/lib/mcp/server.js +31 -2
- package/lib/registry.d.ts +5 -0
- package/lib/targets.d.ts +10 -1
- package/lib/targets.js +16 -3
- package/package.json +10 -6
- package/src/cases/ahead.ts +111 -0
- package/src/cases/fixtures.ts +37 -0
- package/src/cases/flakes.ts +67 -0
- package/src/cases/format.ts +31 -6
- package/src/cases/portClaim.ts +52 -0
- package/src/cases/runfile.ts +119 -0
- package/src/cases/runner.ts +454 -46
- package/src/cases/templates.ts +14 -4
- package/src/cases/traces.ts +298 -0
- package/src/cli.ts +29 -7
- package/src/commands/cases.ts +428 -41
- package/src/commands/check.ts +11 -4
- package/src/commands/doctor.ts +9 -2
- package/src/commands/drive.ts +31 -8
- package/src/commands/headless.ts +143 -8
- package/src/commands/init.ts +338 -30
- package/src/commands/report.ts +272 -0
- package/src/config.ts +39 -2
- package/src/device/agentVersion.ts +15 -0
- package/src/device/devices.ts +28 -0
- package/src/device/driver.ts +2 -2
- package/src/flow/runner.ts +35 -1
- package/src/flow/types.ts +2 -2
- package/src/knowledge/contrast.ts +135 -0
- package/src/knowledge/errors.ts +1 -1
- package/src/knowledge/lint.ts +15 -4
- package/src/mcp/server.ts +31 -2
- package/src/registry.ts +2 -0
- package/src/targets.ts +17 -3
- package/lib/__tests__/args.test.d.ts +0 -1
- package/lib/__tests__/args.test.js +0 -69
- package/lib/__tests__/check.test.d.ts +0 -1
- package/lib/__tests__/check.test.js +0 -60
- package/lib/__tests__/init.test.d.ts +0 -1
- package/lib/__tests__/init.test.js +0 -42
- package/lib/__tests__/record.test.d.ts +0 -1
- package/lib/__tests__/record.test.js +0 -44
- package/lib/__tests__/snapshot.test.d.ts +0 -1
- package/lib/__tests__/snapshot.test.js +0 -47
- package/lib/__tests__/targets.test.d.ts +0 -1
- package/lib/__tests__/targets.test.js +0 -127
- package/lib/cases/__tests__/format.test.d.ts +0 -1
- package/lib/cases/__tests__/format.test.js +0 -61
- package/lib/cases/__tests__/runner.test.d.ts +0 -1
- package/lib/cases/__tests__/runner.test.js +0 -188
- package/lib/knowledge/__tests__/edges.test.d.ts +0 -1
- package/lib/knowledge/__tests__/edges.test.js +0 -25
- package/lib/knowledge/__tests__/events.test.d.ts +0 -1
- package/lib/knowledge/__tests__/events.test.js +0 -39
- package/lib/knowledge/__tests__/extract.test.d.ts +0 -1
- package/lib/knowledge/__tests__/extract.test.js +0 -69
- package/lib/knowledge/__tests__/frontier.test.d.ts +0 -1
- package/lib/knowledge/__tests__/frontier.test.js +0 -57
- package/lib/knowledge/__tests__/funnels.test.d.ts +0 -1
- package/lib/knowledge/__tests__/funnels.test.js +0 -40
- package/lib/knowledge/__tests__/lint.test.d.ts +0 -1
- package/lib/knowledge/__tests__/lint.test.js +0 -53
- package/lib/knowledge/__tests__/perf.test.d.ts +0 -1
- package/lib/knowledge/__tests__/perf.test.js +0 -34
- package/lib/knowledge/__tests__/plan.test.d.ts +0 -1
- package/lib/knowledge/__tests__/plan.test.js +0 -35
- package/lib/knowledge/__tests__/query.test.d.ts +0 -1
- package/lib/knowledge/__tests__/query.test.js +0 -55
- package/lib/knowledge/__tests__/screens.test.d.ts +0 -1
- package/lib/knowledge/__tests__/screens.test.js +0 -30
- package/lib/knowledge/__tests__/why.test.d.ts +0 -1
- package/lib/knowledge/__tests__/why.test.js +0 -28
- package/src/__tests__/args.test.ts +0 -82
- package/src/__tests__/check.test.ts +0 -71
- package/src/__tests__/init.test.ts +0 -52
- package/src/__tests__/record.test.ts +0 -49
- package/src/__tests__/snapshot.test.ts +0 -51
- package/src/__tests__/targets.test.ts +0 -132
- package/src/cases/__tests__/format.test.ts +0 -76
- package/src/cases/__tests__/runner.test.ts +0 -230
- package/src/knowledge/__tests__/edges.test.ts +0 -34
- package/src/knowledge/__tests__/events.test.ts +0 -45
- package/src/knowledge/__tests__/extract.test.ts +0 -88
- package/src/knowledge/__tests__/frontier.test.ts +0 -77
- package/src/knowledge/__tests__/funnels.test.ts +0 -58
- package/src/knowledge/__tests__/lint.test.ts +0 -66
- package/src/knowledge/__tests__/perf.test.ts +0 -41
- package/src/knowledge/__tests__/plan.test.ts +0 -52
- package/src/knowledge/__tests__/query.test.ts +0 -74
- package/src/knowledge/__tests__/screens.test.ts +0 -37
- package/src/knowledge/__tests__/why.test.ts +0 -40
|
@@ -0,0 +1,119 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Writes a run of cases as the directory `lynkeus-protocol` describes: run.json
|
|
3
|
+
* and cases.jsonl. The manifest is written at the start and again at the end,
|
|
4
|
+
* so a run that was cut short still says when it began and what it ran on.
|
|
5
|
+
*/
|
|
6
|
+
import { execFileSync } from 'node:child_process';
|
|
7
|
+
import fs from 'node:fs';
|
|
8
|
+
import path from 'node:path';
|
|
9
|
+
|
|
10
|
+
import { RUN_SCHEMA, type RunCase, type RunManifest, type RunStep } from 'lynkeus-protocol';
|
|
11
|
+
|
|
12
|
+
import type { Case } from './format.js';
|
|
13
|
+
import type { CaseReport } from './runner.js';
|
|
14
|
+
|
|
15
|
+
export type Attempt = { report: CaseReport; attempt: number; startedAt: Date };
|
|
16
|
+
|
|
17
|
+
/** Paths in the run file are relative to its directory, so the directory can move. */
|
|
18
|
+
const within = (dir: string | undefined, file: string | undefined) => (file ? (dir ? path.relative(dir, file) : file) : undefined);
|
|
19
|
+
|
|
20
|
+
export const toRunCase = (c: Case, { report, attempt, startedAt }: Attempt, root: string, dir?: string): RunCase => {
|
|
21
|
+
const steps: RunStep[] = report.steps.map((s, index) => {
|
|
22
|
+
// The runner numbers an event's step from 1, in the order the steps ran.
|
|
23
|
+
const told = (report.events ?? [])
|
|
24
|
+
.filter((e) => e.step === index + 1)
|
|
25
|
+
.map((e) => ({ origin: 'app' as const, name: e.name, ...(e.props ? { props: e.props } : {}), ...(e.route ? { route: e.route } : {}) }));
|
|
26
|
+
const sent = (s.sent ?? []).map((e) => ({ origin: 'app' as const, provider: e.provider, name: e.name, ...(e.props ? { props: e.props } : {}) }));
|
|
27
|
+
const events = [...told, ...sent];
|
|
28
|
+
const screenshot = within(dir, s.screenshot);
|
|
29
|
+
return {
|
|
30
|
+
step: s.step,
|
|
31
|
+
status: s.status,
|
|
32
|
+
ms: s.ms,
|
|
33
|
+
...(s.error ? { error: s.error } : {}),
|
|
34
|
+
section: index < c.setup.length ? 'setup' : 'steps',
|
|
35
|
+
...(events.length > 0 ? { events } : {}),
|
|
36
|
+
...(screenshot ? { screenshot } : {}),
|
|
37
|
+
...(s.videoS !== undefined ? { videoS: s.videoS } : {}),
|
|
38
|
+
...(s.backend?.length ? { backend: s.backend } : {}),
|
|
39
|
+
};
|
|
40
|
+
});
|
|
41
|
+
const description = typeof c.meta.description === 'string' ? c.meta.description : undefined;
|
|
42
|
+
const video = within(dir, report.video);
|
|
43
|
+
return {
|
|
44
|
+
id: report.id,
|
|
45
|
+
...(report.title ? { title: report.title } : {}),
|
|
46
|
+
...(description ? { description } : {}),
|
|
47
|
+
file: path.relative(root, path.resolve(root, report.file)),
|
|
48
|
+
attempt,
|
|
49
|
+
result: report.result,
|
|
50
|
+
startedAt: startedAt.toISOString(),
|
|
51
|
+
ms: report.ms,
|
|
52
|
+
steps,
|
|
53
|
+
...(report.diagnosis ? { diagnosis: report.diagnosis } : {}),
|
|
54
|
+
...(report.evidence ? { evidence: report.evidence } : {}),
|
|
55
|
+
...(video ? { video } : {}),
|
|
56
|
+
};
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
/** The branch and commit the run was made from, so a report can say which code it tested. */
|
|
60
|
+
const gitOf = (root: string): RunManifest['git'] => {
|
|
61
|
+
const ask = (...args: string[]) => {
|
|
62
|
+
try {
|
|
63
|
+
return execFileSync('git', args, { cwd: root, encoding: 'utf8', stdio: ['ignore', 'pipe', 'ignore'] }).trim() || undefined;
|
|
64
|
+
} catch {
|
|
65
|
+
return undefined;
|
|
66
|
+
}
|
|
67
|
+
};
|
|
68
|
+
const commit = ask('rev-parse', '--short', 'HEAD');
|
|
69
|
+
if (!commit) return undefined;
|
|
70
|
+
const branch = process.env.GITHUB_HEAD_REF || process.env.GITHUB_REF_NAME || ask('rev-parse', '--abbrev-ref', 'HEAD');
|
|
71
|
+
return { commit, ...(branch && branch !== 'HEAD' ? { branch } : {}) };
|
|
72
|
+
};
|
|
73
|
+
|
|
74
|
+
export class RunFile {
|
|
75
|
+
private readonly manifest: RunManifest;
|
|
76
|
+
private readonly last = new Map<string, { result: RunCase['result']; attempt: number }>();
|
|
77
|
+
|
|
78
|
+
constructor(
|
|
79
|
+
private readonly dir: string,
|
|
80
|
+
private readonly root: string,
|
|
81
|
+
startedAt = new Date(),
|
|
82
|
+
) {
|
|
83
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
84
|
+
fs.writeFileSync(path.join(dir, 'cases.jsonl'), '');
|
|
85
|
+
const git = gitOf(root);
|
|
86
|
+
this.manifest = { schema: RUN_SCHEMA, startedAt: startedAt.toISOString(), ...(git ? { git } : {}) };
|
|
87
|
+
this.save();
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/** Where a case's frames and film go: one folder per attempt. */
|
|
91
|
+
evidenceDir(id: string, attempt: number): string {
|
|
92
|
+
return path.join(this.dir, `${id.replace(/[^\w.=-]+/g, '_')}${attempt > 1 ? `.${attempt}` : ''}`);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
add(c: Case, attempt: Attempt): void {
|
|
96
|
+
const line = toRunCase(c, attempt, this.root, this.dir);
|
|
97
|
+
fs.appendFileSync(path.join(this.dir, 'cases.jsonl'), `${JSON.stringify(line)}\n`);
|
|
98
|
+
this.last.set(line.id, { result: line.result, attempt: line.attempt });
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
finish(app: { platform?: string; native?: boolean } = {}, finishedAt = new Date()): void {
|
|
102
|
+
const cases = [...this.last.values()];
|
|
103
|
+
this.manifest.finishedAt = finishedAt.toISOString();
|
|
104
|
+
if (app.platform) this.manifest.platform = app.platform;
|
|
105
|
+
if (app.native !== undefined) this.manifest.native = app.native;
|
|
106
|
+
this.manifest.totals = {
|
|
107
|
+
cases: cases.length,
|
|
108
|
+
passed: cases.filter((c) => c.result === 'passed').length,
|
|
109
|
+
failed: cases.filter((c) => c.result === 'failed').length,
|
|
110
|
+
unsupported: cases.filter((c) => c.result === 'unsupported').length,
|
|
111
|
+
retried: cases.filter((c) => c.attempt > 1).length,
|
|
112
|
+
};
|
|
113
|
+
this.save();
|
|
114
|
+
}
|
|
115
|
+
|
|
116
|
+
private save(): void {
|
|
117
|
+
fs.writeFileSync(path.join(this.dir, 'run.json'), `${JSON.stringify(this.manifest, null, 2)}\n`);
|
|
118
|
+
}
|
|
119
|
+
}
|