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
|
@@ -0,0 +1,85 @@
|
|
|
1
|
+
export function compileReflectionTargets(config) {
|
|
2
|
+
const targets = [];
|
|
3
|
+
const browser = config.contracts.browser;
|
|
4
|
+
if (browser && browser.enabled !== false) {
|
|
5
|
+
for (const route of browser.routes) {
|
|
6
|
+
targets.push({
|
|
7
|
+
id: route.id,
|
|
8
|
+
family: 'browser-route',
|
|
9
|
+
source: 'reflection-config',
|
|
10
|
+
runModes: ['smoke', 'full'],
|
|
11
|
+
blocking: browser.blocking ?? true,
|
|
12
|
+
route: {
|
|
13
|
+
path: route.path,
|
|
14
|
+
...(route.name ? { name: route.name } : {}),
|
|
15
|
+
viewports: route.viewports,
|
|
16
|
+
expects: route.expects
|
|
17
|
+
},
|
|
18
|
+
browser: {
|
|
19
|
+
baseUrl: browser.baseUrl,
|
|
20
|
+
maskSelectors: browser.maskSelectors ?? []
|
|
21
|
+
}
|
|
22
|
+
});
|
|
23
|
+
}
|
|
24
|
+
for (const visualCase of browser.visualSmoke ?? []) {
|
|
25
|
+
targets.push({
|
|
26
|
+
id: visualCase.id,
|
|
27
|
+
family: 'route-visual',
|
|
28
|
+
source: 'reflection-config',
|
|
29
|
+
runModes: ['smoke', 'full'],
|
|
30
|
+
blocking: visualCase.blocking === true || visualCase.strict === true,
|
|
31
|
+
route: {
|
|
32
|
+
path: visualCase.route
|
|
33
|
+
},
|
|
34
|
+
visual: {
|
|
35
|
+
viewport: visualCase.viewport,
|
|
36
|
+
baseline: visualCase.baseline,
|
|
37
|
+
...(visualCase.baselineRoot ? { baselineRoot: visualCase.baselineRoot } : {}),
|
|
38
|
+
...(visualCase.threshold !== undefined ? { threshold: visualCase.threshold } : {})
|
|
39
|
+
}
|
|
40
|
+
});
|
|
41
|
+
}
|
|
42
|
+
}
|
|
43
|
+
const component = config.contracts.component;
|
|
44
|
+
if (component && component.enabled !== false) {
|
|
45
|
+
for (const componentCase of component.cases) {
|
|
46
|
+
targets.push({
|
|
47
|
+
id: componentCase.id,
|
|
48
|
+
family: 'component-visual',
|
|
49
|
+
source: 'reflection-config',
|
|
50
|
+
runModes: ['visual', 'full'],
|
|
51
|
+
blocking: componentCase.blocking === true || componentCase.strict === true,
|
|
52
|
+
story: {
|
|
53
|
+
storyId: componentCase.storyId,
|
|
54
|
+
statePolicy: componentCase.browserState ? 'browser-forced-with-stabilization' : 'story-controlled',
|
|
55
|
+
...(componentCase.stateNote ? { stateNote: componentCase.stateNote } : {}),
|
|
56
|
+
...(componentCase.browserState ? { browserState: componentCase.browserState } : {})
|
|
57
|
+
},
|
|
58
|
+
visual: {
|
|
59
|
+
viewport: componentCase.viewport ?? 'component',
|
|
60
|
+
baseline: componentCase.baseline,
|
|
61
|
+
...(componentCase.baselineRoot ? { baselineRoot: componentCase.baselineRoot } : {}),
|
|
62
|
+
...(componentCase.threshold !== undefined ? { threshold: componentCase.threshold } : {})
|
|
63
|
+
}
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
const design = config.contracts.design;
|
|
68
|
+
if (design && design.enabled !== false) {
|
|
69
|
+
for (const designCommand of design.commands) {
|
|
70
|
+
targets.push({
|
|
71
|
+
id: designCommand.id,
|
|
72
|
+
family: 'design-command',
|
|
73
|
+
source: 'reflection-config',
|
|
74
|
+
runModes: ['design', 'full'],
|
|
75
|
+
blocking: designCommand.blocking ?? true,
|
|
76
|
+
command: {
|
|
77
|
+
command: designCommand.command,
|
|
78
|
+
...(designCommand.cwd ? { cwd: designCommand.cwd } : {})
|
|
79
|
+
}
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
return { project: config.project, targets };
|
|
84
|
+
}
|
|
85
|
+
//# sourceMappingURL=target-ir.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"target-ir.js","sourceRoot":"","sources":["../../src/core/target-ir.ts"],"names":[],"mappings":"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"}
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,gBAAgB,EAAE,MAAM,6BAA6B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"browser-manager.js","sourceRoot":"","sources":["../../../src/integrations/playwright/browser-manager.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAgB,MAAM,YAAY,CAAC;AAEpD,MAAM,CAAC,KAAK,UAAU,aAAa;IACjC,OAAO,QAAQ,CAAC,MAAM,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,CAAC,CAAC;AAC7C,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { Browser, BrowserContext } from 'playwright';
|
|
2
|
+
export type ViewportName = 'desktop' | 'mobile' | 'tablet' | 'component';
|
|
3
|
+
export declare function resolveViewport(viewport: string): {
|
|
4
|
+
width: number;
|
|
5
|
+
height: number;
|
|
6
|
+
};
|
|
7
|
+
export declare function createBrowserContext(browser: Browser, viewport: string): Promise<BrowserContext>;
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
const viewportPresets = {
|
|
2
|
+
desktop: { width: 1440, height: 900 },
|
|
3
|
+
mobile: { width: 390, height: 844 },
|
|
4
|
+
tablet: { width: 820, height: 1180 },
|
|
5
|
+
component: { width: 390, height: 220 }
|
|
6
|
+
};
|
|
7
|
+
export function resolveViewport(viewport) {
|
|
8
|
+
return viewportPresets[viewport] ?? viewportPresets.desktop;
|
|
9
|
+
}
|
|
10
|
+
export async function createBrowserContext(browser, viewport) {
|
|
11
|
+
return browser.newContext({
|
|
12
|
+
viewport: resolveViewport(viewport),
|
|
13
|
+
deviceScaleFactor: 1,
|
|
14
|
+
locale: 'en-US',
|
|
15
|
+
timezoneId: 'Europe/Stockholm',
|
|
16
|
+
colorScheme: 'light'
|
|
17
|
+
});
|
|
18
|
+
}
|
|
19
|
+
//# sourceMappingURL=context-factory.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"context-factory.js","sourceRoot":"","sources":["../../../src/integrations/playwright/context-factory.ts"],"names":[],"mappings":"AAIA,MAAM,eAAe,GAA4D;IAC/E,OAAO,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE;IACrC,MAAM,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE;IACnC,MAAM,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,IAAI,EAAE;IACpC,SAAS,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,EAAE,GAAG,EAAE;CACvC,CAAC;AAEF,MAAM,UAAU,eAAe,CAAC,QAAgB;IAC9C,OAAO,eAAe,CAAC,QAAwB,CAAC,IAAI,eAAe,CAAC,OAAO,CAAC;AAC9E,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,oBAAoB,CAAC,OAAgB,EAAE,QAAgB;IAC3E,OAAO,OAAO,CAAC,UAAU,CAAC;QACxB,QAAQ,EAAE,eAAe,CAAC,QAAQ,CAAC;QACnC,iBAAiB,EAAE,CAAC;QACpB,MAAM,EAAE,OAAO;QACf,UAAU,EAAE,kBAAkB;QAC9B,WAAW,EAAE,OAAO;KACrB,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"trace-policy.js","sourceRoot":"","sources":["../../../src/integrations/playwright/trace-policy.ts"],"names":[],"mappings":"AAKA,MAAM,UAAU,iBAAiB,CAAC,YAAkC,EAAE;IACpE,OAAO;QACL,KAAK,EAAE,SAAS,CAAC,KAAK,IAAI,KAAK;QAC/B,KAAK,EAAE,SAAS,CAAC,KAAK,IAAI,KAAK;KAChC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
declare const StorybookEntrySchema: z.ZodObject<{
|
|
3
|
+
id: z.ZodString;
|
|
4
|
+
title: z.ZodString;
|
|
5
|
+
name: z.ZodString;
|
|
6
|
+
type: z.ZodString;
|
|
7
|
+
importPath: z.ZodOptional<z.ZodString>;
|
|
8
|
+
}, z.core.$strip>;
|
|
9
|
+
declare const StorybookIndexSchema: z.ZodObject<{
|
|
10
|
+
entries: z.ZodRecord<z.ZodString, z.ZodObject<{
|
|
11
|
+
id: z.ZodString;
|
|
12
|
+
title: z.ZodString;
|
|
13
|
+
name: z.ZodString;
|
|
14
|
+
type: z.ZodString;
|
|
15
|
+
importPath: z.ZodOptional<z.ZodString>;
|
|
16
|
+
}, z.core.$strip>>;
|
|
17
|
+
}, z.core.$strip>;
|
|
18
|
+
export type StorybookEntry = z.output<typeof StorybookEntrySchema>;
|
|
19
|
+
export type StorybookIndex = z.output<typeof StorybookIndexSchema>;
|
|
20
|
+
export declare function loadStorybookIndex(baseUrl: string): Promise<StorybookIndex>;
|
|
21
|
+
export {};
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
const StorybookEntrySchema = z.object({
|
|
3
|
+
id: z.string().min(1),
|
|
4
|
+
title: z.string().min(1),
|
|
5
|
+
name: z.string().min(1),
|
|
6
|
+
type: z.string().min(1),
|
|
7
|
+
importPath: z.string().optional()
|
|
8
|
+
});
|
|
9
|
+
const StorybookIndexSchema = z.object({
|
|
10
|
+
entries: z.record(z.string(), StorybookEntrySchema)
|
|
11
|
+
});
|
|
12
|
+
export async function loadStorybookIndex(baseUrl) {
|
|
13
|
+
const indexUrl = new URL('index.json', normalizeBaseUrl(baseUrl));
|
|
14
|
+
let response;
|
|
15
|
+
try {
|
|
16
|
+
response = await fetch(indexUrl, { cache: 'no-store' });
|
|
17
|
+
}
|
|
18
|
+
catch (error) {
|
|
19
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
20
|
+
throw new Error(`Reflection Storybook setup/config error: failed to load ${indexUrl.toString()}: ${message}`);
|
|
21
|
+
}
|
|
22
|
+
if (!response.ok) {
|
|
23
|
+
await response.body?.cancel();
|
|
24
|
+
throw new Error(`Reflection Storybook setup/config error: failed to load ${indexUrl.toString()}: HTTP ${response.status}`);
|
|
25
|
+
}
|
|
26
|
+
let payload;
|
|
27
|
+
try {
|
|
28
|
+
payload = await response.json();
|
|
29
|
+
}
|
|
30
|
+
catch (error) {
|
|
31
|
+
const message = error instanceof Error ? error.message : String(error);
|
|
32
|
+
throw new Error(`Reflection Storybook setup/config error: invalid JSON from ${indexUrl.toString()}: ${message}`);
|
|
33
|
+
}
|
|
34
|
+
const parsed = StorybookIndexSchema.safeParse(payload);
|
|
35
|
+
if (!parsed.success) {
|
|
36
|
+
const details = parsed.error.issues.map((issue) => `${issue.path.join('.') || 'index'}: ${issue.message}`).join('; ');
|
|
37
|
+
throw new Error(`Reflection Storybook setup/config error: invalid ${indexUrl.toString()}: ${details}`);
|
|
38
|
+
}
|
|
39
|
+
return parsed.data;
|
|
40
|
+
}
|
|
41
|
+
function normalizeBaseUrl(baseUrl) {
|
|
42
|
+
return baseUrl.endsWith('/') ? baseUrl : `${baseUrl}/`;
|
|
43
|
+
}
|
|
44
|
+
//# sourceMappingURL=index-json.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index-json.js","sourceRoot":"","sources":["../../../src/integrations/storybook/index-json.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { type ManagedServer, type ServerConfig, type StartManagedServerOptions } from '../../core/server-manager.js';
|
|
2
|
+
import { type StorybookIndex } from './index-json.js';
|
|
3
|
+
export type StorybookServer = {
|
|
4
|
+
baseUrl: string;
|
|
5
|
+
index: StorybookIndex;
|
|
6
|
+
server: ManagedServer;
|
|
7
|
+
};
|
|
8
|
+
export declare function startStorybookServer(config: ServerConfig, options?: StartManagedServerOptions): Promise<StorybookServer>;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { startManagedServer } from '../../core/server-manager.js';
|
|
2
|
+
import { loadStorybookIndex } from './index-json.js';
|
|
3
|
+
export async function startStorybookServer(config, options = {}) {
|
|
4
|
+
const server = await startManagedServer({
|
|
5
|
+
...config,
|
|
6
|
+
readyUrl: storybookIndexUrl(config.readyUrl)
|
|
7
|
+
}, options);
|
|
8
|
+
try {
|
|
9
|
+
return {
|
|
10
|
+
baseUrl: config.readyUrl,
|
|
11
|
+
index: await loadStorybookIndex(config.readyUrl),
|
|
12
|
+
server
|
|
13
|
+
};
|
|
14
|
+
}
|
|
15
|
+
catch (error) {
|
|
16
|
+
await server.stop();
|
|
17
|
+
throw error;
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
function storybookIndexUrl(baseUrl) {
|
|
21
|
+
return new URL('index.json', baseUrl.endsWith('/') ? baseUrl : `${baseUrl}/`).toString();
|
|
22
|
+
}
|
|
23
|
+
//# sourceMappingURL=server.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../../src/integrations/storybook/server.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,kBAAkB,EAAyE,MAAM,8BAA8B,CAAC;AACzI,OAAO,EAAE,kBAAkB,EAAuB,MAAM,iBAAiB,CAAC;AAQ1E,MAAM,CAAC,KAAK,UAAU,oBAAoB,CACxC,MAAoB,EACpB,UAAqC,EAAE;IAEvC,MAAM,MAAM,GAAG,MAAM,kBAAkB,CACrC;QACE,GAAG,MAAM;QACT,QAAQ,EAAE,iBAAiB,CAAC,MAAM,CAAC,QAAQ,CAAC;KAC7C,EACD,OAAO,CACR,CAAC;IAEF,IAAI,CAAC;QACH,OAAO;YACL,OAAO,EAAE,MAAM,CAAC,QAAQ;YACxB,KAAK,EAAE,MAAM,kBAAkB,CAAC,MAAM,CAAC,QAAQ,CAAC;YAChD,MAAM;SACP,CAAC;IACJ,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,MAAM,MAAM,CAAC,IAAI,EAAE,CAAC;QACpB,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,SAAS,iBAAiB,CAAC,OAAe;IACxC,OAAO,IAAI,GAAG,CAAC,YAAY,EAAE,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,GAAG,CAAC,CAAC,QAAQ,EAAE,CAAC;AAC3F,CAAC"}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export function resolveStoryUrl(index, baseUrl, storyId) {
|
|
2
|
+
const entry = index.entries[storyId];
|
|
3
|
+
if (!entry || entry.type !== 'story') {
|
|
4
|
+
throw new Error(`Reflection Storybook setup/config error: storyId "${storyId}" was not found or is not a story in ${new URL('index.json', normalizeBaseUrl(baseUrl)).toString()}`);
|
|
5
|
+
}
|
|
6
|
+
const url = new URL('iframe.html', normalizeBaseUrl(baseUrl));
|
|
7
|
+
url.searchParams.set('id', entry.id);
|
|
8
|
+
return url.toString();
|
|
9
|
+
}
|
|
10
|
+
function normalizeBaseUrl(baseUrl) {
|
|
11
|
+
return baseUrl.endsWith('/') ? baseUrl : `${baseUrl}/`;
|
|
12
|
+
}
|
|
13
|
+
//# sourceMappingURL=story-url.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"story-url.js","sourceRoot":"","sources":["../../../src/integrations/storybook/story-url.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,eAAe,CAAC,KAAqB,EAAE,OAAe,EAAE,OAAe;IACrF,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACrC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,IAAI,KAAK,OAAO,EAAE,CAAC;QACrC,MAAM,IAAI,KAAK,CACb,qDAAqD,OAAO,wCAAwC,IAAI,GAAG,CACzG,YAAY,EACZ,gBAAgB,CAAC,OAAO,CAAC,CAC1B,CAAC,QAAQ,EAAE,EAAE,CACf,CAAC;IACJ,CAAC;IAED,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,aAAa,EAAE,gBAAgB,CAAC,OAAO,CAAC,CAAC,CAAC;IAC9D,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC;IACrC,OAAO,GAAG,CAAC,QAAQ,EAAE,CAAC;AACxB,CAAC;AAED,SAAS,gBAAgB,CAAC,OAAe;IACvC,OAAO,OAAO,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,GAAG,OAAO,GAAG,CAAC;AACzD,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
export type ManagedProcessOptions = {
|
|
2
|
+
cwd?: string;
|
|
3
|
+
logPath?: string;
|
|
4
|
+
};
|
|
5
|
+
export type ManagedProcess = {
|
|
6
|
+
pid: number | undefined;
|
|
7
|
+
stop: () => Promise<void>;
|
|
8
|
+
};
|
|
9
|
+
export declare function spawnManagedProcess(command: string, options?: ManagedProcessOptions): Promise<ManagedProcess>;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { spawn } from 'node:child_process';
|
|
2
|
+
import { createWriteStream } from 'node:fs';
|
|
3
|
+
import { mkdir } from 'node:fs/promises';
|
|
4
|
+
import { dirname } from 'node:path';
|
|
5
|
+
import { createRedactionTransform } from '../core/redaction.js';
|
|
6
|
+
export async function spawnManagedProcess(command, options = {}) {
|
|
7
|
+
let logStream;
|
|
8
|
+
if (options.logPath) {
|
|
9
|
+
await mkdir(dirname(options.logPath), { recursive: true });
|
|
10
|
+
logStream = createWriteStream(options.logPath, { flags: 'a' });
|
|
11
|
+
}
|
|
12
|
+
const spawnOptions = {
|
|
13
|
+
detached: true,
|
|
14
|
+
shell: true,
|
|
15
|
+
stdio: 'pipe'
|
|
16
|
+
};
|
|
17
|
+
if (options.cwd) {
|
|
18
|
+
spawnOptions.cwd = options.cwd;
|
|
19
|
+
}
|
|
20
|
+
const child = spawn(command, spawnOptions);
|
|
21
|
+
child.stdin?.end();
|
|
22
|
+
if (logStream) {
|
|
23
|
+
child.stdout?.pipe(createRedactionTransform()).pipe(logStream, { end: false });
|
|
24
|
+
child.stderr?.pipe(createRedactionTransform()).pipe(logStream, { end: false });
|
|
25
|
+
}
|
|
26
|
+
return {
|
|
27
|
+
pid: child.pid,
|
|
28
|
+
stop: () => stopChildProcess(child, logStream)
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
async function stopChildProcess(child, logStream) {
|
|
32
|
+
if (child.exitCode !== null || child.signalCode !== null) {
|
|
33
|
+
await closeLogStream(logStream);
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
await new Promise((resolve) => {
|
|
37
|
+
const timeout = setTimeout(() => {
|
|
38
|
+
if (child.exitCode === null && child.signalCode === null) {
|
|
39
|
+
killProcessGroup(child, 'SIGKILL');
|
|
40
|
+
}
|
|
41
|
+
}, 1_000);
|
|
42
|
+
child.once('close', () => {
|
|
43
|
+
clearTimeout(timeout);
|
|
44
|
+
resolve();
|
|
45
|
+
});
|
|
46
|
+
killProcessGroup(child, 'SIGTERM');
|
|
47
|
+
});
|
|
48
|
+
await closeLogStream(logStream);
|
|
49
|
+
}
|
|
50
|
+
function killProcessGroup(child, signal) {
|
|
51
|
+
if (!child.pid) {
|
|
52
|
+
return;
|
|
53
|
+
}
|
|
54
|
+
try {
|
|
55
|
+
process.kill(-child.pid, signal);
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
child.kill(signal);
|
|
59
|
+
}
|
|
60
|
+
}
|
|
61
|
+
async function closeLogStream(logStream) {
|
|
62
|
+
if (!logStream || logStream.closed || logStream.destroyed) {
|
|
63
|
+
return;
|
|
64
|
+
}
|
|
65
|
+
await new Promise((resolve) => {
|
|
66
|
+
logStream.end(resolve);
|
|
67
|
+
});
|
|
68
|
+
}
|
|
69
|
+
//# sourceMappingURL=process.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"process.js","sourceRoot":"","sources":["../../src/utils/process.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAoD,MAAM,oBAAoB,CAAC;AAC7F,OAAO,EAAE,iBAAiB,EAAoB,MAAM,SAAS,CAAC;AAC9D,OAAO,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AACzC,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,wBAAwB,EAAE,MAAM,sBAAsB,CAAC;AAYhE,MAAM,CAAC,KAAK,UAAU,mBAAmB,CAAC,OAAe,EAAE,UAAiC,EAAE;IAC5F,IAAI,SAAkC,CAAC;IACvC,IAAI,OAAO,CAAC,OAAO,EAAE,CAAC;QACpB,MAAM,KAAK,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAC3D,SAAS,GAAG,iBAAiB,CAAC,OAAO,CAAC,OAAO,EAAE,EAAE,KAAK,EAAE,GAAG,EAAE,CAAC,CAAC;IACjE,CAAC;IAED,MAAM,YAAY,GAA6B;QAC7C,QAAQ,EAAE,IAAI;QACd,KAAK,EAAE,IAAI;QACX,KAAK,EAAE,MAAM;KACd,CAAC;IACF,IAAI,OAAO,CAAC,GAAG,EAAE,CAAC;QAChB,YAAY,CAAC,GAAG,GAAG,OAAO,CAAC,GAAG,CAAC;IACjC,CAAC;IAED,MAAM,KAAK,GAAG,KAAK,CAAC,OAAO,EAAE,YAAY,CAAC,CAAC;IAC3C,KAAK,CAAC,KAAK,EAAE,GAAG,EAAE,CAAC;IAEnB,IAAI,SAAS,EAAE,CAAC;QACd,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,wBAAwB,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC;QAC/E,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,wBAAwB,EAAE,CAAC,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC,CAAC;IACjF,CAAC;IAED,OAAO;QACL,GAAG,EAAE,KAAK,CAAC,GAAG;QACd,IAAI,EAAE,GAAG,EAAE,CAAC,gBAAgB,CAAC,KAAK,EAAE,SAAS,CAAC;KAC/C,CAAC;AACJ,CAAC;AAED,KAAK,UAAU,gBAAgB,CAAC,KAAmB,EAAE,SAAuB;IAC1E,IAAI,KAAK,CAAC,QAAQ,KAAK,IAAI,IAAI,KAAK,CAAC,UAAU,KAAK,IAAI,EAAE,CAAC;QACzD,MAAM,cAAc,CAAC,SAAS,CAAC,CAAC;QAChC,OAAO;IACT,CAAC;IAED,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;QAClC,MAAM,OAAO,GAAG,UAAU,CAAC,GAAG,EAAE;YAC9B,IAAI,KAAK,CAAC,QAAQ,KAAK,IAAI,IAAI,KAAK,CAAC,UAAU,KAAK,IAAI,EAAE,CAAC;gBACzD,gBAAgB,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;YACrC,CAAC;QACH,CAAC,EAAE,KAAK,CAAC,CAAC;QAEV,KAAK,CAAC,IAAI,CAAC,OAAO,EAAE,GAAG,EAAE;YACvB,YAAY,CAAC,OAAO,CAAC,CAAC;YACtB,OAAO,EAAE,CAAC;QACZ,CAAC,CAAC,CAAC;QAEH,gBAAgB,CAAC,KAAK,EAAE,SAAS,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,MAAM,cAAc,CAAC,SAAS,CAAC,CAAC;AAClC,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAmB,EAAE,MAAsB;IACnE,IAAI,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC;QACf,OAAO;IACT,CAAC;IAED,IAAI,CAAC;QACH,OAAO,CAAC,IAAI,CAAC,CAAC,KAAK,CAAC,GAAG,EAAE,MAAM,CAAC,CAAC;IACnC,CAAC;IAAC,MAAM,CAAC;QACP,KAAK,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACrB,CAAC;AACH,CAAC;AAED,KAAK,UAAU,cAAc,CAAC,SAAuB;IACnD,IAAI,CAAC,SAAS,IAAI,SAAS,CAAC,MAAM,IAAI,SAAS,CAAC,SAAS,EAAE,CAAC;QAC1D,OAAO;IACT,CAAC;IAED,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;QAClC,SAAS,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC;IACzB,CAAC,CAAC,CAAC;AACL,CAAC"}
|
|
@@ -0,0 +1,146 @@
|
|
|
1
|
+
# Agent workflows
|
|
2
|
+
|
|
3
|
+
Reflection is meant to give agents an evidence gate for rendered UI work. Agents should use it to observe and report, not to silently heal visual changes.
|
|
4
|
+
|
|
5
|
+
## Core agent loop
|
|
6
|
+
|
|
7
|
+
Before claiming frontend work is complete:
|
|
8
|
+
|
|
9
|
+
```bash
|
|
10
|
+
reflection doctor
|
|
11
|
+
reflection run --config reflection.config.ts --mode smoke
|
|
12
|
+
reflection review --json
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
`reflection doctor` is currently a lightweight setup check. Treat `reflection run --config ...` as the command that exercises project contracts.
|
|
16
|
+
|
|
17
|
+
If the project uses a non-default config path or report root, pass it explicitly:
|
|
18
|
+
|
|
19
|
+
```bash
|
|
20
|
+
reflection doctor
|
|
21
|
+
reflection run --config path/to/reflection.config.ts --mode smoke --report-dir .reflection
|
|
22
|
+
reflection review --report-dir .reflection --json
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
## How to interpret review JSON
|
|
26
|
+
|
|
27
|
+
Treat the review summary as the handoff contract:
|
|
28
|
+
|
|
29
|
+
- `status: "pass"` — validation passed.
|
|
30
|
+
- `status: "pass-with-review"` — blocking checks passed, but the agent must summarize review items and artifact paths.
|
|
31
|
+
- `status: "fail"` — blocking failures must be fixed before completion.
|
|
32
|
+
- Tool/configuration errors mean the validation did not complete; report the blocker and fix setup when in scope.
|
|
33
|
+
|
|
34
|
+
A good completion message includes:
|
|
35
|
+
|
|
36
|
+
- commands run;
|
|
37
|
+
- status;
|
|
38
|
+
- report path;
|
|
39
|
+
- blocking failures, if any;
|
|
40
|
+
- review items, if any;
|
|
41
|
+
- artifact paths for changed/failing UI;
|
|
42
|
+
- whether any baseline update was dry-run only or human-approved non-dry.
|
|
43
|
+
|
|
44
|
+
## Baseline update policy for agents
|
|
45
|
+
|
|
46
|
+
Agents may propose a baseline update only with a dry run:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
reflection update --route <routeId> --from-run latest --dry-run
|
|
50
|
+
reflection update --case <routeVisualCaseId> --from-run latest --dry-run
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
`reflection update` currently targets route-level `visualSmoke` baselines. Component visual baseline promotion is still a manual review/copy step.
|
|
54
|
+
|
|
55
|
+
Do not run non-dry `reflection update` unless the human explicitly approves that exact target.
|
|
56
|
+
|
|
57
|
+
Never run `reflection update` in CI.
|
|
58
|
+
|
|
59
|
+
After a human-approved non-dry update:
|
|
60
|
+
|
|
61
|
+
1. Inspect the git diff.
|
|
62
|
+
2. Report exactly which baseline files changed.
|
|
63
|
+
3. Re-run `reflection run` and `reflection review --json` if the task requires proof that the new baseline now passes.
|
|
64
|
+
|
|
65
|
+
## Handling `pass-with-review`
|
|
66
|
+
|
|
67
|
+
`pass-with-review` is useful. It means the functional/browser contract did not block, but some artifact needs human attention.
|
|
68
|
+
|
|
69
|
+
For visual diffs, include:
|
|
70
|
+
|
|
71
|
+
- check id;
|
|
72
|
+
- target route/story and viewport;
|
|
73
|
+
- expected image path;
|
|
74
|
+
- actual image path;
|
|
75
|
+
- diff image path;
|
|
76
|
+
- threshold metadata if present;
|
|
77
|
+
- whether the case is review-only or strict/blocking.
|
|
78
|
+
|
|
79
|
+
Do not hide review items behind "tests passed". The review item is the reason Reflection exists.
|
|
80
|
+
|
|
81
|
+
## Suggested agent-file section
|
|
82
|
+
|
|
83
|
+
Repository agent files should include a short pointer, not a copy of this whole guide.
|
|
84
|
+
|
|
85
|
+
Supported files to update, in order of preference:
|
|
86
|
+
|
|
87
|
+
- existing `AGENTS.md`;
|
|
88
|
+
- existing `CLAUDE.md`;
|
|
89
|
+
- existing `.github/copilot-instructions.md`;
|
|
90
|
+
- existing `copilot-instructions.md`;
|
|
91
|
+
- create `AGENTS.md` only if none exists.
|
|
92
|
+
|
|
93
|
+
Suggested section:
|
|
94
|
+
|
|
95
|
+
````md
|
|
96
|
+
## Reflection validation
|
|
97
|
+
|
|
98
|
+
Use Reflection as the UI evidence gate before claiming frontend work is complete.
|
|
99
|
+
|
|
100
|
+
Run:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
reflection doctor
|
|
104
|
+
reflection run --config reflection.config.ts --mode smoke
|
|
105
|
+
reflection review --json
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
Rules:
|
|
109
|
+
|
|
110
|
+
- Treat blocking failures as task blockers.
|
|
111
|
+
- Summarize review items with artifact paths for the human.
|
|
112
|
+
- Use `reflection update --route <routeId> --from-run latest --dry-run` only to propose intentional visual changes.
|
|
113
|
+
- Do not run non-dry `reflection update` unless the human explicitly approves it.
|
|
114
|
+
- Never run `reflection update` in CI.
|
|
115
|
+
|
|
116
|
+
Full protocol: `docs/validation-process.md`.
|
|
117
|
+
````
|
|
118
|
+
|
|
119
|
+
## CI workflow
|
|
120
|
+
|
|
121
|
+
CI should run Reflection and upload artifacts, but never update baselines:
|
|
122
|
+
|
|
123
|
+
```bash
|
|
124
|
+
reflection doctor
|
|
125
|
+
reflection run --ci --config reflection.config.ts --mode smoke
|
|
126
|
+
reflection review --report-dir artifacts/reflection --json
|
|
127
|
+
```
|
|
128
|
+
|
|
129
|
+
`reflection run --ci` writes to `artifacts/reflection` by default, so pass the same report root to `review`.
|
|
130
|
+
|
|
131
|
+
Upload the report root even on failure:
|
|
132
|
+
|
|
133
|
+
```text
|
|
134
|
+
artifacts/reflection/**
|
|
135
|
+
```
|
|
136
|
+
|
|
137
|
+
See `docs/ci.md` for current CI-specific defaults and exit codes.
|
|
138
|
+
|
|
139
|
+
## Common mistakes
|
|
140
|
+
|
|
141
|
+
- Treating generated evidence screenshots as baselines.
|
|
142
|
+
- Running non-dry `reflection update` without human approval.
|
|
143
|
+
- Ignoring `pass-with-review` because the shell exit code is `0`.
|
|
144
|
+
- Deleting run artifacts before reporting the artifact paths.
|
|
145
|
+
- Copying long Reflection instructions into multiple agent files and letting them drift.
|
|
146
|
+
- Forgetting `--report-dir` when reviewing a CI or custom-root run.
|