reflection-check 0.0.1
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/LICENSE +21 -0
- package/README.md +55 -0
- package/dist/adapters/route-manifest.d.ts +3 -0
- package/dist/adapters/route-manifest.js +98 -0
- package/dist/adapters/route-manifest.js.map +1 -0
- package/dist/cli.d.ts +3 -0
- package/dist/cli.js +93 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/doctor.d.ts +4 -0
- package/dist/commands/doctor.js +5 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/gc.d.ts +8 -0
- package/dist/commands/gc.js +45 -0
- package/dist/commands/gc.js.map +1 -0
- package/dist/commands/review.d.ts +7 -0
- package/dist/commands/review.js +149 -0
- package/dist/commands/review.js.map +1 -0
- package/dist/commands/run.d.ts +10 -0
- package/dist/commands/run.js +168 -0
- package/dist/commands/run.js.map +1 -0
- package/dist/commands/update.d.ts +11 -0
- package/dist/commands/update.js +183 -0
- package/dist/commands/update.js.map +1 -0
- package/dist/contracts/browser/assertions.d.ts +34 -0
- package/dist/contracts/browser/assertions.js +87 -0
- package/dist/contracts/browser/assertions.js.map +1 -0
- package/dist/contracts/browser/browser-contract.d.ts +13 -0
- package/dist/contracts/browser/browser-contract.js +35 -0
- package/dist/contracts/browser/browser-contract.js.map +1 -0
- package/dist/contracts/browser/console-observer.d.ts +6 -0
- package/dist/contracts/browser/console-observer.js +14 -0
- package/dist/contracts/browser/console-observer.js.map +1 -0
- package/dist/contracts/browser/overflow-check.d.ts +6 -0
- package/dist/contracts/browser/overflow-check.js +15 -0
- package/dist/contracts/browser/overflow-check.js.map +1 -0
- package/dist/contracts/browser/route-runner.d.ts +21 -0
- package/dist/contracts/browser/route-runner.js +98 -0
- package/dist/contracts/browser/route-runner.js.map +1 -0
- package/dist/contracts/component/component-visual-contract.d.ts +30 -0
- package/dist/contracts/component/component-visual-contract.js +147 -0
- package/dist/contracts/component/component-visual-contract.js.map +1 -0
- package/dist/contracts/design/command-adapter.d.ts +17 -0
- package/dist/contracts/design/command-adapter.js +60 -0
- package/dist/contracts/design/command-adapter.js.map +1 -0
- package/dist/contracts/design/design-contract.d.ts +8 -0
- package/dist/contracts/design/design-contract.js +149 -0
- package/dist/contracts/design/design-contract.js.map +1 -0
- package/dist/contracts/visual/baseline-compare.d.ts +19 -0
- package/dist/contracts/visual/baseline-compare.js +94 -0
- package/dist/contracts/visual/baseline-compare.js.map +1 -0
- package/dist/contracts/visual/image-diff.d.ts +27 -0
- package/dist/contracts/visual/image-diff.js +58 -0
- package/dist/contracts/visual/image-diff.js.map +1 -0
- package/dist/contracts/visual/thresholds.d.ts +15 -0
- package/dist/contracts/visual/thresholds.js +11 -0
- package/dist/contracts/visual/thresholds.js.map +1 -0
- package/dist/contracts/visual/visual-contract.d.ts +11 -0
- package/dist/contracts/visual/visual-contract.js +32 -0
- package/dist/contracts/visual/visual-contract.js.map +1 -0
- package/dist/core/artifact-store.d.ts +18 -0
- package/dist/core/artifact-store.js +105 -0
- package/dist/core/artifact-store.js.map +1 -0
- package/dist/core/baseline-store.d.ts +18 -0
- package/dist/core/baseline-store.js +56 -0
- package/dist/core/baseline-store.js.map +1 -0
- package/dist/core/config.d.ts +129 -0
- package/dist/core/config.js +159 -0
- package/dist/core/config.js.map +1 -0
- package/dist/core/define-reflection.d.ts +2 -0
- package/dist/core/define-reflection.js +4 -0
- package/dist/core/define-reflection.js.map +1 -0
- package/dist/core/exit-codes.d.ts +7 -0
- package/dist/core/exit-codes.js +9 -0
- package/dist/core/exit-codes.js.map +1 -0
- package/dist/core/failure-classifier.d.ts +3 -0
- package/dist/core/failure-classifier.js +19 -0
- package/dist/core/failure-classifier.js.map +1 -0
- package/dist/core/gc.d.ts +19 -0
- package/dist/core/gc.js +161 -0
- package/dist/core/gc.js.map +1 -0
- package/dist/core/manifest.d.ts +23 -0
- package/dist/core/manifest.js +21 -0
- package/dist/core/manifest.js.map +1 -0
- package/dist/core/redaction.d.ts +3 -0
- package/dist/core/redaction.js +63 -0
- package/dist/core/redaction.js.map +1 -0
- package/dist/core/report-schema.d.ts +262 -0
- package/dist/core/report-schema.js +112 -0
- package/dist/core/report-schema.js.map +1 -0
- package/dist/core/report-writer.d.ts +4 -0
- package/dist/core/report-writer.js +77 -0
- package/dist/core/report-writer.js.map +1 -0
- package/dist/core/server-manager.d.ts +23 -0
- package/dist/core/server-manager.js +64 -0
- package/dist/core/server-manager.js.map +1 -0
- package/dist/core/target-ir.d.ts +64 -0
- package/dist/core/target-ir.js +85 -0
- package/dist/core/target-ir.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +2 -0
- package/dist/index.js.map +1 -0
- package/dist/integrations/playwright/browser-manager.d.ts +2 -0
- package/dist/integrations/playwright/browser-manager.js +5 -0
- package/dist/integrations/playwright/browser-manager.js.map +1 -0
- package/dist/integrations/playwright/context-factory.d.ts +7 -0
- package/dist/integrations/playwright/context-factory.js +19 -0
- package/dist/integrations/playwright/context-factory.js.map +1 -0
- package/dist/integrations/playwright/trace-policy.d.ts +5 -0
- package/dist/integrations/playwright/trace-policy.js +7 -0
- package/dist/integrations/playwright/trace-policy.js.map +1 -0
- package/dist/integrations/storybook/index-json.d.ts +21 -0
- package/dist/integrations/storybook/index-json.js +44 -0
- package/dist/integrations/storybook/index-json.js.map +1 -0
- package/dist/integrations/storybook/server.d.ts +8 -0
- package/dist/integrations/storybook/server.js +23 -0
- package/dist/integrations/storybook/server.js.map +1 -0
- package/dist/integrations/storybook/story-url.d.ts +2 -0
- package/dist/integrations/storybook/story-url.js +13 -0
- package/dist/integrations/storybook/story-url.js.map +1 -0
- package/dist/utils/process.d.ts +9 -0
- package/dist/utils/process.js +69 -0
- package/dist/utils/process.js.map +1 -0
- package/docs/agent-workflows.md +146 -0
- package/docs/artifacts-and-gc.md +125 -0
- package/docs/browser-contract.md +98 -0
- package/docs/ci.md +44 -0
- package/docs/configuration.md +210 -0
- package/docs/getting-started.md +166 -0
- package/docs/plans/reflection-implementation-plan.md +898 -0
- package/docs/target-ir-and-adapters.md +111 -0
- package/docs/validation-process.md +172 -0
- package/docs/visual-contract.md +174 -0
- package/package.json +62 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Niklas Westman
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
# Reflection
|
|
2
|
+
|
|
3
|
+
Reflection is a CLI for evidence-backed rendered UI validation.
|
|
4
|
+
|
|
5
|
+
It answers three practical questions for frontend changes:
|
|
6
|
+
|
|
7
|
+
```text
|
|
8
|
+
Does the UI still work?
|
|
9
|
+
Does it still match the design system contract?
|
|
10
|
+
Did anything visible change unexpectedly?
|
|
11
|
+
```
|
|
12
|
+
|
|
13
|
+
Current status: Reflection now has the core local validation loop: config → browser route check → screenshot/visual evidence → report → review → explicit baseline update.
|
|
14
|
+
|
|
15
|
+
## Documentation
|
|
16
|
+
|
|
17
|
+
- [`docs/getting-started.md`](docs/getting-started.md) — add Reflection to a new repo and run the local loop.
|
|
18
|
+
- [`docs/configuration.md`](docs/configuration.md) — supported config shape, run modes, browser/design/component contracts.
|
|
19
|
+
- [`docs/browser-contract.md`](docs/browser-contract.md) — rendered route expectations and screenshot evidence.
|
|
20
|
+
- [`docs/visual-contract.md`](docs/visual-contract.md) — route/component baselines, review-only diffs, and baseline update policy.
|
|
21
|
+
- [`docs/artifacts-and-gc.md`](docs/artifacts-and-gc.md) — report bundle layout, artifact roots, and safe garbage collection.
|
|
22
|
+
- [`docs/agent-workflows.md`](docs/agent-workflows.md) — agent completion loop and baseline-update rules.
|
|
23
|
+
- [`docs/validation-process.md`](docs/validation-process.md) — canonical operating guide for agents and CI.
|
|
24
|
+
- [`docs/ci.md`](docs/ci.md) — CI defaults and exit codes.
|
|
25
|
+
- [`docs/target-ir-and-adapters.md`](docs/target-ir-and-adapters.md) — internal target inventory and adapter seam.
|
|
26
|
+
|
|
27
|
+
## Command surface
|
|
28
|
+
|
|
29
|
+
```bash
|
|
30
|
+
reflection run
|
|
31
|
+
reflection review
|
|
32
|
+
reflection update
|
|
33
|
+
reflection doctor
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
## Install
|
|
37
|
+
|
|
38
|
+
```bash
|
|
39
|
+
pnpm add -D reflection-check
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
Use the package root helper in `reflection.config.ts`:
|
|
43
|
+
|
|
44
|
+
```ts
|
|
45
|
+
import { defineReflection } from 'reflection-check';
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
## Local development
|
|
49
|
+
|
|
50
|
+
```bash
|
|
51
|
+
pnpm install
|
|
52
|
+
pnpm typecheck
|
|
53
|
+
pnpm test
|
|
54
|
+
pnpm build
|
|
55
|
+
```
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import { z } from 'zod';
|
|
3
|
+
const RouteManifestExpectationSchema = z.union([
|
|
4
|
+
z.object({ urlIncludes: z.string() }).strict(),
|
|
5
|
+
z.object({ urlEquals: z.string() }).strict(),
|
|
6
|
+
z.object({ role: z.string(), name: z.string().optional() }).strict(),
|
|
7
|
+
z.object({ label: z.string() }).strict(),
|
|
8
|
+
z.object({ text: z.string() }).strict(),
|
|
9
|
+
z.object({ noText: z.string() }).strict(),
|
|
10
|
+
z.object({ selector: z.string() }).strict(),
|
|
11
|
+
z.object({ elementVisible: z.string() }).strict(),
|
|
12
|
+
z.object({ elementNotVisible: z.string() }).strict(),
|
|
13
|
+
z.object({ noHorizontalOverflow: z.literal(true) }).strict(),
|
|
14
|
+
z.object({ noConsoleErrors: z.literal(true) }).strict(),
|
|
15
|
+
z.object({ screenshot: z.string() }).strict()
|
|
16
|
+
]);
|
|
17
|
+
const RouteManifestRouteSchema = z
|
|
18
|
+
.object({
|
|
19
|
+
id: z.string().min(1),
|
|
20
|
+
name: z.string().min(1).optional(),
|
|
21
|
+
path: z.string().min(1),
|
|
22
|
+
viewports: z.array(z.string().min(1)).default(['desktop']),
|
|
23
|
+
expects: z.array(RouteManifestExpectationSchema).default([]),
|
|
24
|
+
blocking: z.boolean().optional()
|
|
25
|
+
})
|
|
26
|
+
.strict();
|
|
27
|
+
const RouteManifestSchema = z
|
|
28
|
+
.object({
|
|
29
|
+
project: z.string().min(1),
|
|
30
|
+
baseUrl: z.string().url(),
|
|
31
|
+
maskSelectors: z.array(z.string().min(1)).default([]),
|
|
32
|
+
routes: z.array(RouteManifestRouteSchema).default([])
|
|
33
|
+
})
|
|
34
|
+
.strict()
|
|
35
|
+
.superRefine((manifest, context) => {
|
|
36
|
+
const seen = new Set();
|
|
37
|
+
for (const [index, route] of manifest.routes.entries()) {
|
|
38
|
+
if (seen.has(route.id)) {
|
|
39
|
+
context.addIssue({
|
|
40
|
+
code: z.ZodIssueCode.custom,
|
|
41
|
+
path: ['routes', index, 'id'],
|
|
42
|
+
message: `duplicate route id "${route.id}"`
|
|
43
|
+
});
|
|
44
|
+
}
|
|
45
|
+
seen.add(route.id);
|
|
46
|
+
}
|
|
47
|
+
});
|
|
48
|
+
export async function loadRouteManifestTargets(manifestPath) {
|
|
49
|
+
let raw;
|
|
50
|
+
try {
|
|
51
|
+
raw = await readFile(manifestPath, 'utf8');
|
|
52
|
+
}
|
|
53
|
+
catch (error) {
|
|
54
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
55
|
+
throw new Error(`Route manifest not found: ${manifestPath}: ${message}`);
|
|
56
|
+
}
|
|
57
|
+
try {
|
|
58
|
+
return parseRouteManifestTargets(JSON.parse(raw));
|
|
59
|
+
}
|
|
60
|
+
catch (error) {
|
|
61
|
+
if (error instanceof SyntaxError) {
|
|
62
|
+
throw new Error(`Invalid route manifest JSON: ${manifestPath}: ${error.message}`);
|
|
63
|
+
}
|
|
64
|
+
throw error;
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
export function parseRouteManifestTargets(input) {
|
|
68
|
+
const manifest = parseRouteManifest(input);
|
|
69
|
+
return {
|
|
70
|
+
project: manifest.project,
|
|
71
|
+
targets: manifest.routes.map((route) => ({
|
|
72
|
+
id: route.id,
|
|
73
|
+
family: 'browser-route',
|
|
74
|
+
source: 'adapter',
|
|
75
|
+
runModes: ['smoke', 'full'],
|
|
76
|
+
blocking: route.blocking ?? true,
|
|
77
|
+
route: {
|
|
78
|
+
path: route.path,
|
|
79
|
+
...(route.name !== undefined ? { name: route.name } : {}),
|
|
80
|
+
viewports: route.viewports,
|
|
81
|
+
expects: route.expects
|
|
82
|
+
},
|
|
83
|
+
browser: {
|
|
84
|
+
baseUrl: manifest.baseUrl,
|
|
85
|
+
maskSelectors: manifest.maskSelectors
|
|
86
|
+
}
|
|
87
|
+
}))
|
|
88
|
+
};
|
|
89
|
+
}
|
|
90
|
+
function parseRouteManifest(input) {
|
|
91
|
+
const parsed = RouteManifestSchema.safeParse(input);
|
|
92
|
+
if (!parsed.success) {
|
|
93
|
+
const details = parsed.error.issues.map((issue) => `${issue.path.join('.') || 'manifest'}: ${issue.message}`).join('; ');
|
|
94
|
+
throw new Error(`Invalid route manifest: ${details}`);
|
|
95
|
+
}
|
|
96
|
+
return parsed.data;
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=route-manifest.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"route-manifest.js","sourceRoot":"","sources":["../../src/adapters/route-manifest.ts"],"names":[],"mappings":"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"}
|
package/dist/cli.d.ts
ADDED
package/dist/cli.js
ADDED
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { realpathSync } from 'node:fs';
|
|
3
|
+
import { fileURLToPath } from 'node:url';
|
|
4
|
+
import { Command, CommanderError } from 'commander';
|
|
5
|
+
import { doctorCommand } from './commands/doctor.js';
|
|
6
|
+
import { gcCommand } from './commands/gc.js';
|
|
7
|
+
import { reviewCommand } from './commands/review.js';
|
|
8
|
+
import { runCommand } from './commands/run.js';
|
|
9
|
+
import { updateCommand } from './commands/update.js';
|
|
10
|
+
import { ExitCode } from './core/exit-codes.js';
|
|
11
|
+
export function createCli() {
|
|
12
|
+
const program = new Command();
|
|
13
|
+
program
|
|
14
|
+
.name('reflection')
|
|
15
|
+
.description('Evidence-backed rendered UI validation.')
|
|
16
|
+
.version('0.0.1')
|
|
17
|
+
.configureOutput({
|
|
18
|
+
outputError: (message, write) => write(message)
|
|
19
|
+
});
|
|
20
|
+
program
|
|
21
|
+
.command('run')
|
|
22
|
+
.description('Check the UI contract for this project.')
|
|
23
|
+
.option('--config <path>', 'Path to reflection.config.ts')
|
|
24
|
+
.option('--mode <mode>', 'Run mode: smoke, design, visual, full', 'smoke')
|
|
25
|
+
.option('--ci', 'Run with CI defaults')
|
|
26
|
+
.option('--report-dir <path>', 'Artifact/report root directory')
|
|
27
|
+
.option('--workers [count]', 'Worker count for browser/visual checks')
|
|
28
|
+
.action(async (options) => {
|
|
29
|
+
await runCommand(options);
|
|
30
|
+
});
|
|
31
|
+
program
|
|
32
|
+
.command('review')
|
|
33
|
+
.description('Show what passed, failed, changed visually, and where the evidence is.')
|
|
34
|
+
.option('--latest', 'Review the latest run')
|
|
35
|
+
.option('--run <runId>', 'Review a specific run id')
|
|
36
|
+
.option('--json', 'Emit a stable JSON summary')
|
|
37
|
+
.option('--report-dir <path>', 'Artifact/report root directory')
|
|
38
|
+
.action(async (options) => {
|
|
39
|
+
await reviewCommand(options);
|
|
40
|
+
});
|
|
41
|
+
program
|
|
42
|
+
.command('update')
|
|
43
|
+
.description('Accept intentional visual changes by updating targeted baselines.')
|
|
44
|
+
.option('--config <path>', 'Path to reflection.config.ts')
|
|
45
|
+
.option('--report-dir <path>', 'Artifact/report root directory')
|
|
46
|
+
.option('--from-run <runId>', 'Run id to promote from, or latest', 'latest')
|
|
47
|
+
.option('--route <routeId>', 'Update visual baselines for a specific route id')
|
|
48
|
+
.option('--case <caseId>', 'Update a specific visual baseline case id')
|
|
49
|
+
.option('--all', 'Update all visual baselines from the selected run')
|
|
50
|
+
.option('--dry-run', 'Show planned baseline updates without writing')
|
|
51
|
+
.option('--ci', 'Refuse updates under CI mode')
|
|
52
|
+
.action(async (options) => {
|
|
53
|
+
await updateCommand(options);
|
|
54
|
+
});
|
|
55
|
+
program
|
|
56
|
+
.command('gc')
|
|
57
|
+
.description('Clean up old Reflection run artifacts without touching baselines.')
|
|
58
|
+
.option('--report-dir <path>', 'Artifact/report root directory')
|
|
59
|
+
.option('--dry-run', 'List eligible run directories without deleting them')
|
|
60
|
+
.option('--delete', 'Delete eligible run directories')
|
|
61
|
+
.action(async (options) => {
|
|
62
|
+
await gcCommand(options);
|
|
63
|
+
});
|
|
64
|
+
program
|
|
65
|
+
.command('doctor')
|
|
66
|
+
.description('Check whether Reflection can run correctly in this project.')
|
|
67
|
+
.option('--config <path>', 'Path to reflection.config.ts')
|
|
68
|
+
.action(async (options) => {
|
|
69
|
+
await doctorCommand(options);
|
|
70
|
+
});
|
|
71
|
+
return program;
|
|
72
|
+
}
|
|
73
|
+
async function main() {
|
|
74
|
+
const program = createCli();
|
|
75
|
+
try {
|
|
76
|
+
await program.parseAsync(process.argv);
|
|
77
|
+
}
|
|
78
|
+
catch (error) {
|
|
79
|
+
if (error instanceof CommanderError) {
|
|
80
|
+
if (error.message) {
|
|
81
|
+
console.error(error.message);
|
|
82
|
+
}
|
|
83
|
+
process.exit(error.exitCode);
|
|
84
|
+
}
|
|
85
|
+
console.error(error instanceof Error ? error.message : String(error));
|
|
86
|
+
process.exit(ExitCode.ToolOrConfigError);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
const executedPath = process.argv[1] ? realpathSync(fileURLToPath(import.meta.url)) === realpathSync(process.argv[1]) : false;
|
|
90
|
+
if (executedPath) {
|
|
91
|
+
void main();
|
|
92
|
+
}
|
|
93
|
+
//# sourceMappingURL=cli.js.map
|
package/dist/cli.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAIA,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,WAAiC,EAAE;IACrE,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,CAAC;IACjC,OAAO,CAAC,GAAG,CAAC,qGAAqG,CAAC,CAAC;AACrH,CAAC"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type GcPlan } from '../core/gc.js';
|
|
2
|
+
export type GcCommandOptions = {
|
|
3
|
+
reportDir?: string;
|
|
4
|
+
dryRun?: boolean;
|
|
5
|
+
delete?: boolean;
|
|
6
|
+
};
|
|
7
|
+
export declare function gcCommand(options?: GcCommandOptions): Promise<void>;
|
|
8
|
+
export declare function renderGcSummary(plan: GcPlan): string;
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { CommanderError } from 'commander';
|
|
2
|
+
import { collectGarbage } from '../core/gc.js';
|
|
3
|
+
import { ExitCode } from '../core/exit-codes.js';
|
|
4
|
+
export async function gcCommand(options = {}) {
|
|
5
|
+
try {
|
|
6
|
+
if (options.dryRun === true && options.delete === true) {
|
|
7
|
+
throw new CommanderError(ExitCode.InvalidUsage, 'reflection.gc', 'Use either --dry-run or --delete, not both.');
|
|
8
|
+
}
|
|
9
|
+
const plan = await collectGarbage({ ...(options.reportDir !== undefined ? { reportDir: options.reportDir } : {}), dryRun: options.delete !== true });
|
|
10
|
+
console.log(renderGcSummary(plan));
|
|
11
|
+
}
|
|
12
|
+
catch (error) {
|
|
13
|
+
if (error instanceof CommanderError) {
|
|
14
|
+
throw error;
|
|
15
|
+
}
|
|
16
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
17
|
+
throw new CommanderError(ExitCode.ToolOrConfigError, 'reflection.gc', message);
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export function renderGcSummary(plan) {
|
|
21
|
+
const lines = ['Reflection GC', '', `Dry run: ${plan.dryRun ? 'yes' : 'no'}`, `Runs directory: ${plan.runsDir}`, ''];
|
|
22
|
+
if (plan.eligible.length === 0) {
|
|
23
|
+
lines.push(plan.dryRun ? 'No eligible run directories would be deleted.' : 'No eligible run directories were deleted.');
|
|
24
|
+
}
|
|
25
|
+
else {
|
|
26
|
+
lines.push(plan.dryRun ? 'Would delete:' : 'Eligible:');
|
|
27
|
+
for (const run of plan.eligible) {
|
|
28
|
+
lines.push(`- ${run.runId}: ${run.path}`);
|
|
29
|
+
}
|
|
30
|
+
}
|
|
31
|
+
if (plan.deleted.length > 0) {
|
|
32
|
+
lines.push('', 'Deleted:');
|
|
33
|
+
for (const run of plan.deleted) {
|
|
34
|
+
lines.push(`- ${run.runId}: ${run.path}`);
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
if (plan.skipped.length > 0) {
|
|
38
|
+
lines.push('', 'Skipped:');
|
|
39
|
+
for (const run of plan.skipped) {
|
|
40
|
+
lines.push(`- ${run.runId}: ${run.reason}`);
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
return lines.join('\n');
|
|
44
|
+
}
|
|
45
|
+
//# sourceMappingURL=gc.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"gc.js","sourceRoot":"","sources":["../../src/commands/gc.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
import { readFile, realpath } from 'node:fs/promises';
|
|
2
|
+
import { dirname, isAbsolute, relative, resolve } from 'node:path';
|
|
3
|
+
import { CommanderError } from 'commander';
|
|
4
|
+
import { ExitCode } from '../core/exit-codes.js';
|
|
5
|
+
import { validateReport } from '../core/report-schema.js';
|
|
6
|
+
export async function reviewCommand(options = {}) {
|
|
7
|
+
try {
|
|
8
|
+
if (options.latest === true && options.run !== undefined) {
|
|
9
|
+
throw new Error('Use either --latest or --run, not both.');
|
|
10
|
+
}
|
|
11
|
+
const rootDir = resolve(options.reportDir ?? '.reflection');
|
|
12
|
+
const runsDir = resolve(rootDir, 'runs');
|
|
13
|
+
const runId = options.run ?? (await readLatestRunId(rootDir));
|
|
14
|
+
assertSafeRunId(runId);
|
|
15
|
+
const runDir = resolve(runsDir, runId);
|
|
16
|
+
ensureInside(runsDir, runDir);
|
|
17
|
+
await ensureRealPathInside(runsDir, runDir);
|
|
18
|
+
const reportPath = resolve(runDir, 'report.json');
|
|
19
|
+
ensureInside(runDir, reportPath);
|
|
20
|
+
await ensureRealPathInside(runDir, reportPath);
|
|
21
|
+
const report = validateReport(JSON.parse(await readFile(reportPath, 'utf8')));
|
|
22
|
+
if (report.runId !== runId) {
|
|
23
|
+
throw new Error(`Report run id mismatch: expected ${runId}, found ${report.runId}`);
|
|
24
|
+
}
|
|
25
|
+
const summary = createReviewSummary(report, reportPath, dirname(reportPath));
|
|
26
|
+
if (options.json === true) {
|
|
27
|
+
console.log(JSON.stringify(summary, null, 2));
|
|
28
|
+
return;
|
|
29
|
+
}
|
|
30
|
+
console.log(renderReview(summary));
|
|
31
|
+
}
|
|
32
|
+
catch (error) {
|
|
33
|
+
if (error instanceof CommanderError) {
|
|
34
|
+
throw error;
|
|
35
|
+
}
|
|
36
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
37
|
+
throw new CommanderError(ExitCode.ToolOrConfigError, 'reflection.review', message);
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
async function readLatestRunId(rootDir) {
|
|
41
|
+
const runsDir = resolve(rootDir, 'runs');
|
|
42
|
+
const latestPath = resolve(runsDir, 'latest');
|
|
43
|
+
ensureInside(runsDir, latestPath);
|
|
44
|
+
await ensureRealPathInside(runsDir, latestPath);
|
|
45
|
+
const value = (await readFile(latestPath, 'utf8')).trim();
|
|
46
|
+
if (value.length === 0) {
|
|
47
|
+
throw new Error(`Latest Reflection run pointer is empty: ${latestPath}`);
|
|
48
|
+
}
|
|
49
|
+
return value;
|
|
50
|
+
}
|
|
51
|
+
function createReviewSummary(report, reportPath, runDir) {
|
|
52
|
+
const blockingFailures = report.checks.filter(isBlockingFailure).map(toReviewCheck);
|
|
53
|
+
const reviewItems = report.checks.filter(isReviewItem).map(toReviewCheck);
|
|
54
|
+
return {
|
|
55
|
+
runId: report.runId,
|
|
56
|
+
project: report.project,
|
|
57
|
+
status: report.status,
|
|
58
|
+
reportPath,
|
|
59
|
+
blockingFailures,
|
|
60
|
+
reviewItems,
|
|
61
|
+
artifactPaths: collectArtifactPaths(report, runDir),
|
|
62
|
+
suggestedNextSteps: report.suggestedNextSteps.map((step) => step.summary)
|
|
63
|
+
};
|
|
64
|
+
}
|
|
65
|
+
function renderReview(summary) {
|
|
66
|
+
const lines = [];
|
|
67
|
+
lines.push('Reflection review');
|
|
68
|
+
lines.push('');
|
|
69
|
+
lines.push(`Project: ${summary.project}`);
|
|
70
|
+
lines.push(`Run: ${summary.runId}`);
|
|
71
|
+
lines.push(`Status: ${summary.status}`);
|
|
72
|
+
lines.push(`Report: ${summary.reportPath}`);
|
|
73
|
+
if (summary.blockingFailures.length > 0) {
|
|
74
|
+
lines.push('');
|
|
75
|
+
lines.push('Blocking:');
|
|
76
|
+
for (const item of summary.blockingFailures) {
|
|
77
|
+
lines.push(`- ${item.id} — ${item.summary}`);
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
if (summary.reviewItems.length > 0) {
|
|
81
|
+
lines.push('');
|
|
82
|
+
lines.push('Review:');
|
|
83
|
+
for (const item of summary.reviewItems) {
|
|
84
|
+
lines.push(`- ${item.id} — ${item.summary}`);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
if (summary.artifactPaths.length > 0) {
|
|
88
|
+
lines.push('');
|
|
89
|
+
lines.push('Artifacts:');
|
|
90
|
+
for (const artifactPath of summary.artifactPaths) {
|
|
91
|
+
lines.push(`- ${artifactPath}`);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
if (summary.suggestedNextSteps.length > 0) {
|
|
95
|
+
lines.push('');
|
|
96
|
+
lines.push('Next:');
|
|
97
|
+
for (const step of summary.suggestedNextSteps) {
|
|
98
|
+
lines.push(`- ${step}`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return lines.join('\n');
|
|
102
|
+
}
|
|
103
|
+
function isBlockingFailure(check) {
|
|
104
|
+
return check.severity === 'blocking' && (check.status === 'fail' || check.status === 'error');
|
|
105
|
+
}
|
|
106
|
+
function isReviewItem(check) {
|
|
107
|
+
return check.severity === 'review' && (check.status === 'warn' || check.status === 'fail');
|
|
108
|
+
}
|
|
109
|
+
function toReviewCheck(check) {
|
|
110
|
+
return {
|
|
111
|
+
id: check.id,
|
|
112
|
+
summary: check.summary,
|
|
113
|
+
target: check.target,
|
|
114
|
+
status: check.status
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
function collectArtifactPaths(report, runDir) {
|
|
118
|
+
const paths = new Set();
|
|
119
|
+
const addArtifact = (artifact) => {
|
|
120
|
+
assertSafeArtifactPath(artifact.path, runDir);
|
|
121
|
+
paths.add(artifact.path);
|
|
122
|
+
};
|
|
123
|
+
report.artifacts.forEach(addArtifact);
|
|
124
|
+
report.checks.flatMap((check) => check.artifacts).forEach(addArtifact);
|
|
125
|
+
return [...paths];
|
|
126
|
+
}
|
|
127
|
+
function assertSafeArtifactPath(artifactPath, runDir) {
|
|
128
|
+
if (isAbsolute(artifactPath)) {
|
|
129
|
+
throw new Error(`Invalid absolute artifact path in report: ${artifactPath}`);
|
|
130
|
+
}
|
|
131
|
+
const resolvedArtifactPath = resolve(runDir, artifactPath);
|
|
132
|
+
ensureInside(runDir, resolvedArtifactPath, `Refusing to emit artifact path outside Reflection run directory: ${artifactPath}`);
|
|
133
|
+
}
|
|
134
|
+
function assertSafeRunId(runId) {
|
|
135
|
+
if (!/^[A-Za-z0-9._:-]+$/.test(runId) || isAbsolute(runId) || runId.split(/[\\/]/).includes('..')) {
|
|
136
|
+
throw new Error(`Invalid Reflection run id: ${runId}`);
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
async function ensureRealPathInside(parent, child) {
|
|
140
|
+
const [realParent, realChild] = await Promise.all([realpath(parent), realpath(child)]);
|
|
141
|
+
ensureInside(realParent, realChild, `Refusing to read report outside Reflection runs directory: ${child}`);
|
|
142
|
+
}
|
|
143
|
+
function ensureInside(parent, child, message) {
|
|
144
|
+
const relation = relative(parent, child);
|
|
145
|
+
if (relation.startsWith('..') || isAbsolute(relation)) {
|
|
146
|
+
throw new Error(message ?? `Refusing to read report outside Reflection runs directory: ${child}`);
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
//# sourceMappingURL=review.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review.js","sourceRoot":"","sources":["../../src/commands/review.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { type RunMode } from '../core/config.js';
|
|
2
|
+
export type RunCommandOptions = {
|
|
3
|
+
config?: string;
|
|
4
|
+
mode: string;
|
|
5
|
+
ci?: boolean;
|
|
6
|
+
reportDir?: string;
|
|
7
|
+
workers?: string | number | boolean;
|
|
8
|
+
};
|
|
9
|
+
export declare function parseRunMode(value: string): RunMode;
|
|
10
|
+
export declare function runCommand(options: RunCommandOptions): Promise<void>;
|