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.
Files changed (133) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +55 -0
  3. package/dist/adapters/route-manifest.d.ts +3 -0
  4. package/dist/adapters/route-manifest.js +98 -0
  5. package/dist/adapters/route-manifest.js.map +1 -0
  6. package/dist/cli.d.ts +3 -0
  7. package/dist/cli.js +93 -0
  8. package/dist/cli.js.map +1 -0
  9. package/dist/commands/doctor.d.ts +4 -0
  10. package/dist/commands/doctor.js +5 -0
  11. package/dist/commands/doctor.js.map +1 -0
  12. package/dist/commands/gc.d.ts +8 -0
  13. package/dist/commands/gc.js +45 -0
  14. package/dist/commands/gc.js.map +1 -0
  15. package/dist/commands/review.d.ts +7 -0
  16. package/dist/commands/review.js +149 -0
  17. package/dist/commands/review.js.map +1 -0
  18. package/dist/commands/run.d.ts +10 -0
  19. package/dist/commands/run.js +168 -0
  20. package/dist/commands/run.js.map +1 -0
  21. package/dist/commands/update.d.ts +11 -0
  22. package/dist/commands/update.js +183 -0
  23. package/dist/commands/update.js.map +1 -0
  24. package/dist/contracts/browser/assertions.d.ts +34 -0
  25. package/dist/contracts/browser/assertions.js +87 -0
  26. package/dist/contracts/browser/assertions.js.map +1 -0
  27. package/dist/contracts/browser/browser-contract.d.ts +13 -0
  28. package/dist/contracts/browser/browser-contract.js +35 -0
  29. package/dist/contracts/browser/browser-contract.js.map +1 -0
  30. package/dist/contracts/browser/console-observer.d.ts +6 -0
  31. package/dist/contracts/browser/console-observer.js +14 -0
  32. package/dist/contracts/browser/console-observer.js.map +1 -0
  33. package/dist/contracts/browser/overflow-check.d.ts +6 -0
  34. package/dist/contracts/browser/overflow-check.js +15 -0
  35. package/dist/contracts/browser/overflow-check.js.map +1 -0
  36. package/dist/contracts/browser/route-runner.d.ts +21 -0
  37. package/dist/contracts/browser/route-runner.js +98 -0
  38. package/dist/contracts/browser/route-runner.js.map +1 -0
  39. package/dist/contracts/component/component-visual-contract.d.ts +30 -0
  40. package/dist/contracts/component/component-visual-contract.js +147 -0
  41. package/dist/contracts/component/component-visual-contract.js.map +1 -0
  42. package/dist/contracts/design/command-adapter.d.ts +17 -0
  43. package/dist/contracts/design/command-adapter.js +60 -0
  44. package/dist/contracts/design/command-adapter.js.map +1 -0
  45. package/dist/contracts/design/design-contract.d.ts +8 -0
  46. package/dist/contracts/design/design-contract.js +149 -0
  47. package/dist/contracts/design/design-contract.js.map +1 -0
  48. package/dist/contracts/visual/baseline-compare.d.ts +19 -0
  49. package/dist/contracts/visual/baseline-compare.js +94 -0
  50. package/dist/contracts/visual/baseline-compare.js.map +1 -0
  51. package/dist/contracts/visual/image-diff.d.ts +27 -0
  52. package/dist/contracts/visual/image-diff.js +58 -0
  53. package/dist/contracts/visual/image-diff.js.map +1 -0
  54. package/dist/contracts/visual/thresholds.d.ts +15 -0
  55. package/dist/contracts/visual/thresholds.js +11 -0
  56. package/dist/contracts/visual/thresholds.js.map +1 -0
  57. package/dist/contracts/visual/visual-contract.d.ts +11 -0
  58. package/dist/contracts/visual/visual-contract.js +32 -0
  59. package/dist/contracts/visual/visual-contract.js.map +1 -0
  60. package/dist/core/artifact-store.d.ts +18 -0
  61. package/dist/core/artifact-store.js +105 -0
  62. package/dist/core/artifact-store.js.map +1 -0
  63. package/dist/core/baseline-store.d.ts +18 -0
  64. package/dist/core/baseline-store.js +56 -0
  65. package/dist/core/baseline-store.js.map +1 -0
  66. package/dist/core/config.d.ts +129 -0
  67. package/dist/core/config.js +159 -0
  68. package/dist/core/config.js.map +1 -0
  69. package/dist/core/define-reflection.d.ts +2 -0
  70. package/dist/core/define-reflection.js +4 -0
  71. package/dist/core/define-reflection.js.map +1 -0
  72. package/dist/core/exit-codes.d.ts +7 -0
  73. package/dist/core/exit-codes.js +9 -0
  74. package/dist/core/exit-codes.js.map +1 -0
  75. package/dist/core/failure-classifier.d.ts +3 -0
  76. package/dist/core/failure-classifier.js +19 -0
  77. package/dist/core/failure-classifier.js.map +1 -0
  78. package/dist/core/gc.d.ts +19 -0
  79. package/dist/core/gc.js +161 -0
  80. package/dist/core/gc.js.map +1 -0
  81. package/dist/core/manifest.d.ts +23 -0
  82. package/dist/core/manifest.js +21 -0
  83. package/dist/core/manifest.js.map +1 -0
  84. package/dist/core/redaction.d.ts +3 -0
  85. package/dist/core/redaction.js +63 -0
  86. package/dist/core/redaction.js.map +1 -0
  87. package/dist/core/report-schema.d.ts +262 -0
  88. package/dist/core/report-schema.js +112 -0
  89. package/dist/core/report-schema.js.map +1 -0
  90. package/dist/core/report-writer.d.ts +4 -0
  91. package/dist/core/report-writer.js +77 -0
  92. package/dist/core/report-writer.js.map +1 -0
  93. package/dist/core/server-manager.d.ts +23 -0
  94. package/dist/core/server-manager.js +64 -0
  95. package/dist/core/server-manager.js.map +1 -0
  96. package/dist/core/target-ir.d.ts +64 -0
  97. package/dist/core/target-ir.js +85 -0
  98. package/dist/core/target-ir.js.map +1 -0
  99. package/dist/index.d.ts +2 -0
  100. package/dist/index.js +2 -0
  101. package/dist/index.js.map +1 -0
  102. package/dist/integrations/playwright/browser-manager.d.ts +2 -0
  103. package/dist/integrations/playwright/browser-manager.js +5 -0
  104. package/dist/integrations/playwright/browser-manager.js.map +1 -0
  105. package/dist/integrations/playwright/context-factory.d.ts +7 -0
  106. package/dist/integrations/playwright/context-factory.js +19 -0
  107. package/dist/integrations/playwright/context-factory.js.map +1 -0
  108. package/dist/integrations/playwright/trace-policy.d.ts +5 -0
  109. package/dist/integrations/playwright/trace-policy.js +7 -0
  110. package/dist/integrations/playwright/trace-policy.js.map +1 -0
  111. package/dist/integrations/storybook/index-json.d.ts +21 -0
  112. package/dist/integrations/storybook/index-json.js +44 -0
  113. package/dist/integrations/storybook/index-json.js.map +1 -0
  114. package/dist/integrations/storybook/server.d.ts +8 -0
  115. package/dist/integrations/storybook/server.js +23 -0
  116. package/dist/integrations/storybook/server.js.map +1 -0
  117. package/dist/integrations/storybook/story-url.d.ts +2 -0
  118. package/dist/integrations/storybook/story-url.js +13 -0
  119. package/dist/integrations/storybook/story-url.js.map +1 -0
  120. package/dist/utils/process.d.ts +9 -0
  121. package/dist/utils/process.js +69 -0
  122. package/dist/utils/process.js.map +1 -0
  123. package/docs/agent-workflows.md +146 -0
  124. package/docs/artifacts-and-gc.md +125 -0
  125. package/docs/browser-contract.md +98 -0
  126. package/docs/ci.md +44 -0
  127. package/docs/configuration.md +210 -0
  128. package/docs/getting-started.md +166 -0
  129. package/docs/plans/reflection-implementation-plan.md +898 -0
  130. package/docs/target-ir-and-adapters.md +111 -0
  131. package/docs/validation-process.md +172 -0
  132. package/docs/visual-contract.md +174 -0
  133. package/package.json +62 -0
@@ -0,0 +1,159 @@
1
+ import { access } from 'node:fs/promises';
2
+ import { extname, resolve } from 'node:path';
3
+ import { pathToFileURL } from 'node:url';
4
+ import { createJiti } from 'jiti';
5
+ import { z } from 'zod';
6
+ export const runModes = ['smoke', 'design', 'visual', 'full'];
7
+ const BrowserExpectationSchema = z.union([
8
+ z.object({ urlIncludes: z.string() }),
9
+ z.object({ urlEquals: z.string() }),
10
+ z.object({ role: z.string(), name: z.string().optional() }),
11
+ z.object({ label: z.string() }),
12
+ z.object({ text: z.string() }),
13
+ z.object({ noText: z.string() }),
14
+ z.object({ selector: z.string() }),
15
+ z.object({ elementVisible: z.string() }),
16
+ z.object({ elementNotVisible: z.string() }),
17
+ z.object({ noHorizontalOverflow: z.literal(true) }),
18
+ z.object({ noConsoleErrors: z.literal(true) }),
19
+ z.object({ screenshot: z.string() })
20
+ ]);
21
+ const VisualThresholdSchema = z.object({
22
+ maxDiffPixels: z.number().int().nonnegative().optional(),
23
+ maxDiffPixelRatio: z.number().min(0).max(1).optional()
24
+ });
25
+ const RouteVisualSmokeCaseSchema = z.object({
26
+ id: z.string().min(1),
27
+ route: z.string().min(1),
28
+ viewport: z.string().min(1),
29
+ baseline: z.string().min(1),
30
+ baselineRoot: z.string().optional(),
31
+ threshold: VisualThresholdSchema.optional(),
32
+ blocking: z.boolean().optional(),
33
+ strict: z.boolean().optional()
34
+ });
35
+ const BrowserRouteSchema = z.object({
36
+ id: z.string().min(1),
37
+ name: z.string().optional(),
38
+ path: z.string().min(1),
39
+ viewports: z.array(z.string().min(1)).default(['desktop']),
40
+ expects: z.array(BrowserExpectationSchema).default([])
41
+ });
42
+ const BrowserContractSchema = z.object({
43
+ enabled: z.boolean().default(true),
44
+ blocking: z.boolean().default(true),
45
+ baseUrl: z.string().url(),
46
+ server: z
47
+ .object({
48
+ command: z.string(),
49
+ readyUrl: z.string().url(),
50
+ reuseExisting: z.boolean().default(true),
51
+ timeoutMs: z.number().int().positive().default(60_000)
52
+ })
53
+ .optional(),
54
+ routes: z.array(BrowserRouteSchema).default([]),
55
+ maskSelectors: z.array(z.string().min(1)).default([]),
56
+ visualSmoke: z.array(RouteVisualSmokeCaseSchema).default([])
57
+ });
58
+ const DesignCommandSchema = z.object({
59
+ id: z.string().min(1),
60
+ command: z.string().min(1),
61
+ cwd: z.string().min(1).optional(),
62
+ blocking: z.boolean().optional()
63
+ });
64
+ const DesignContractSchema = z.object({
65
+ enabled: z.boolean().default(true),
66
+ commands: z.array(DesignCommandSchema).default([])
67
+ });
68
+ const ComponentBrowserStateSchema = z
69
+ .object({
70
+ kind: z.enum(['hover', 'focus']),
71
+ selector: z.string().min(1),
72
+ animationStabilization: z.object({
73
+ disableAnimations: z.boolean().optional(),
74
+ waitMs: z.number().int().nonnegative().max(5_000).optional()
75
+ })
76
+ })
77
+ .superRefine((value, context) => {
78
+ if (value.animationStabilization.disableAnimations !== true && (value.animationStabilization.waitMs ?? 0) <= 0) {
79
+ context.addIssue({
80
+ code: z.ZodIssueCode.custom,
81
+ path: ['animationStabilization'],
82
+ message: 'browser-forced pseudo states require effective animation stabilization'
83
+ });
84
+ }
85
+ });
86
+ const ComponentVisualCaseSchema = z.object({
87
+ id: z.string().min(1),
88
+ storyId: z.string().min(1),
89
+ viewport: z.string().min(1).default('component'),
90
+ baseline: z.string().min(1),
91
+ baselineRoot: z.string().optional(),
92
+ threshold: VisualThresholdSchema.optional(),
93
+ blocking: z.boolean().optional(),
94
+ strict: z.boolean().optional(),
95
+ stateNote: z.string().min(1).optional(),
96
+ browserState: ComponentBrowserStateSchema.optional()
97
+ });
98
+ const ComponentContractSchema = z.object({
99
+ enabled: z.boolean().default(true),
100
+ storybook: z.object({
101
+ command: z.string(),
102
+ readyUrl: z.string().url(),
103
+ reuseExisting: z.boolean().default(true),
104
+ timeoutMs: z.number().int().positive().default(60_000)
105
+ }),
106
+ cases: z.array(ComponentVisualCaseSchema).default([])
107
+ });
108
+ const ReflectionConfigSchema = z.object({
109
+ project: z.string().min(1),
110
+ run: z
111
+ .object({
112
+ defaultMode: z.enum(runModes).default('smoke'),
113
+ ciMode: z.enum(runModes).default('smoke')
114
+ })
115
+ .default({ defaultMode: 'smoke', ciMode: 'smoke' }),
116
+ contracts: z.object({
117
+ browser: BrowserContractSchema.optional(),
118
+ design: DesignContractSchema.optional(),
119
+ component: ComponentContractSchema.optional(),
120
+ visual: z.unknown().optional()
121
+ })
122
+ });
123
+ export function isRunMode(value) {
124
+ return runModes.includes(value);
125
+ }
126
+ export function validateReflectionConfig(input) {
127
+ const parsed = ReflectionConfigSchema.safeParse(input);
128
+ if (!parsed.success) {
129
+ const details = parsed.error.issues.map((issue) => `${issue.path.join('.') || 'config'}: ${issue.message}`).join('; ');
130
+ throw new Error(`Invalid Reflection config: ${details}`);
131
+ }
132
+ return parsed.data;
133
+ }
134
+ export async function loadReflectionConfig(configPath) {
135
+ const resolvedConfigPath = resolve(configPath);
136
+ try {
137
+ await access(resolvedConfigPath);
138
+ }
139
+ catch {
140
+ throw new Error(`Reflection config not found: ${configPath}`);
141
+ }
142
+ const module = await importConfigModule(resolvedConfigPath);
143
+ if (!('default' in module)) {
144
+ throw new Error(`Reflection config must use a default export: ${configPath}`);
145
+ }
146
+ return validateReflectionConfig(module.default);
147
+ }
148
+ async function importConfigModule(configPath) {
149
+ const extension = extname(configPath);
150
+ if (extension === '.ts' || extension === '.mts' || extension === '.cts') {
151
+ const jiti = createJiti(import.meta.url, { moduleCache: false });
152
+ const config = await jiti.import(configPath, { default: true });
153
+ return { default: config };
154
+ }
155
+ const configUrl = pathToFileURL(configPath);
156
+ configUrl.searchParams.set('reflectionLoad', Date.now().toString());
157
+ return (await import(configUrl.href));
158
+ }
159
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/core/config.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,2 @@
1
+ import type { ReflectionConfigInput } from './config.js';
2
+ export declare function defineReflection(config: ReflectionConfigInput): ReflectionConfigInput;
@@ -0,0 +1,4 @@
1
+ export function defineReflection(config) {
2
+ return config;
3
+ }
4
+ //# sourceMappingURL=define-reflection.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"define-reflection.js","sourceRoot":"","sources":["../../src/core/define-reflection.ts"],"names":[],"mappings":"AAEA,MAAM,UAAU,gBAAgB,CAAC,MAA6B;IAC5D,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,7 @@
1
+ export declare enum ExitCode {
2
+ Success = 0,
3
+ BlockingFailure = 1,
4
+ ToolOrConfigError = 2,
5
+ InvalidUsage = 64,
6
+ MissingDependency = 69
7
+ }
@@ -0,0 +1,9 @@
1
+ export var ExitCode;
2
+ (function (ExitCode) {
3
+ ExitCode[ExitCode["Success"] = 0] = "Success";
4
+ ExitCode[ExitCode["BlockingFailure"] = 1] = "BlockingFailure";
5
+ ExitCode[ExitCode["ToolOrConfigError"] = 2] = "ToolOrConfigError";
6
+ ExitCode[ExitCode["InvalidUsage"] = 64] = "InvalidUsage";
7
+ ExitCode[ExitCode["MissingDependency"] = 69] = "MissingDependency";
8
+ })(ExitCode || (ExitCode = {}));
9
+ //# sourceMappingURL=exit-codes.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"exit-codes.js","sourceRoot":"","sources":["../../src/core/exit-codes.ts"],"names":[],"mappings":"AAAA,MAAM,CAAN,IAAY,QAMX;AAND,WAAY,QAAQ;IAClB,6CAAW,CAAA;IACX,6DAAmB,CAAA;IACnB,iEAAqB,CAAA;IACrB,wDAAiB,CAAA;IACjB,kEAAsB,CAAA;AACxB,CAAC,EANW,QAAQ,KAAR,QAAQ,QAMnB"}
@@ -0,0 +1,3 @@
1
+ import type { CheckResult } from './report-schema.js';
2
+ export type FailureClass = 'route-failure' | 'auth-gate-failure' | 'dom-contract-failure' | 'accessibility-contract-failure' | 'layout-overflow' | 'console-error' | 'network-error' | 'visual-diff' | 'component-drift' | 'environment-mismatch' | 'missing-baseline' | 'flaky-unstable-screenshot' | 'artifact-redaction-warning' | 'tool-error';
3
+ export declare function classifyFailure(check: CheckResult): FailureClass | undefined;
@@ -0,0 +1,19 @@
1
+ export function classifyFailure(check) {
2
+ if (check.status !== 'fail' && check.status !== 'error') {
3
+ return undefined;
4
+ }
5
+ if (check.metadata.failureClass && typeof check.metadata.failureClass === 'string') {
6
+ return check.metadata.failureClass;
7
+ }
8
+ if (check.status === 'error') {
9
+ return 'tool-error';
10
+ }
11
+ if (check.suite === 'visual') {
12
+ return 'visual-diff';
13
+ }
14
+ if (check.suite === 'environment') {
15
+ return 'environment-mismatch';
16
+ }
17
+ return 'dom-contract-failure';
18
+ }
19
+ //# sourceMappingURL=failure-classifier.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"failure-classifier.js","sourceRoot":"","sources":["../../src/core/failure-classifier.ts"],"names":[],"mappings":"AAkBA,MAAM,UAAU,eAAe,CAAC,KAAkB;IAChD,IAAI,KAAK,CAAC,MAAM,KAAK,MAAM,IAAI,KAAK,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC;QACxD,OAAO,SAAS,CAAC;IACnB,CAAC;IAED,IAAI,KAAK,CAAC,QAAQ,CAAC,YAAY,IAAI,OAAO,KAAK,CAAC,QAAQ,CAAC,YAAY,KAAK,QAAQ,EAAE,CAAC;QACnF,OAAO,KAAK,CAAC,QAAQ,CAAC,YAA4B,CAAC;IACrD,CAAC;IAED,IAAI,KAAK,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC;QAC7B,OAAO,YAAY,CAAC;IACtB,CAAC;IAED,IAAI,KAAK,CAAC,KAAK,KAAK,QAAQ,EAAE,CAAC;QAC7B,OAAO,aAAa,CAAC;IACvB,CAAC;IAED,IAAI,KAAK,CAAC,KAAK,KAAK,aAAa,EAAE,CAAC;QAClC,OAAO,sBAAsB,CAAC;IAChC,CAAC;IAED,OAAO,sBAAsB,CAAC;AAChC,CAAC"}
@@ -0,0 +1,19 @@
1
+ export type GcRun = {
2
+ runId: string;
3
+ path: string;
4
+ };
5
+ export type GcSkippedRun = GcRun & {
6
+ reason: string;
7
+ };
8
+ export type GcPlan = {
9
+ reportDir: string;
10
+ runsDir: string;
11
+ dryRun: boolean;
12
+ eligible: GcRun[];
13
+ skipped: GcSkippedRun[];
14
+ deleted: GcRun[];
15
+ };
16
+ export declare function collectGarbage(options?: {
17
+ reportDir?: string;
18
+ dryRun?: boolean;
19
+ }): Promise<GcPlan>;
@@ -0,0 +1,161 @@
1
+ import { lstat, readdir, readFile, realpath, rm } from 'node:fs/promises';
2
+ import { isAbsolute, relative, resolve } from 'node:path';
3
+ import { z } from 'zod';
4
+ const RunManifestSchema = z.object({
5
+ schemaVersion: z.literal(1),
6
+ runId: z.string().min(1),
7
+ createdAt: z.string().datetime(),
8
+ project: z.string().min(1),
9
+ status: z.enum(['pass', 'fail', 'pass-with-review', 'error']),
10
+ mode: z.enum(['smoke', 'design', 'visual', 'full']),
11
+ ci: z.boolean(),
12
+ retention: z.object({ pinned: z.boolean() }),
13
+ files: z.array(z.object({
14
+ path: z.string().min(1),
15
+ type: z.enum(['report', 'screenshot', 'image', 'visual-diff', 'trace', 'video', 'log', 'metadata']),
16
+ bytes: z.number().int().nonnegative().optional(),
17
+ sha256: z.string().regex(/^[a-f0-9]{64}$/).optional()
18
+ }))
19
+ });
20
+ export async function collectGarbage(options = {}) {
21
+ const reportDir = resolve(options.reportDir ?? '.reflection');
22
+ const runsDir = resolve(reportDir, 'runs');
23
+ ensureInside(reportDir, runsDir);
24
+ const dryRun = options.dryRun !== false;
25
+ const plan = { reportDir, runsDir, dryRun, eligible: [], skipped: [], deleted: [] };
26
+ const realReportDir = await realpath(reportDir);
27
+ const realRunsDir = await inspectRunsDirectory(runsDir, realReportDir);
28
+ if (realRunsDir === undefined) {
29
+ return plan;
30
+ }
31
+ let entries;
32
+ try {
33
+ entries = await readdir(runsDir, { withFileTypes: true });
34
+ }
35
+ catch (error) {
36
+ if (isNodeError(error, 'ENOENT')) {
37
+ return plan;
38
+ }
39
+ throw error;
40
+ }
41
+ for (const entry of entries) {
42
+ if (entry.name === 'latest') {
43
+ continue;
44
+ }
45
+ const runDir = resolve(runsDir, entry.name);
46
+ ensureInside(runsDir, runDir);
47
+ const entryStats = await lstat(runDir);
48
+ if (!entryStats.isDirectory() && !entryStats.isSymbolicLink()) {
49
+ plan.skipped.push({ runId: entry.name, path: runDir, reason: 'not a run directory' });
50
+ continue;
51
+ }
52
+ const safetyIssue = await getRunSafetyIssue({ realRunsDir, runDir });
53
+ if (safetyIssue) {
54
+ plan.skipped.push({ runId: entry.name, path: runDir, reason: safetyIssue });
55
+ continue;
56
+ }
57
+ const manifestResult = await readRunManifest(runDir);
58
+ if (!manifestResult.ok) {
59
+ plan.skipped.push({ runId: entry.name, path: runDir, reason: manifestResult.reason });
60
+ continue;
61
+ }
62
+ if (manifestResult.manifest.runId !== entry.name) {
63
+ plan.skipped.push({ runId: entry.name, path: runDir, reason: `manifest runId mismatch: ${manifestResult.manifest.runId}` });
64
+ continue;
65
+ }
66
+ if (manifestResult.manifest.retention.pinned) {
67
+ plan.skipped.push({ runId: entry.name, path: runDir, reason: 'run is pinned' });
68
+ continue;
69
+ }
70
+ plan.eligible.push({ runId: entry.name, path: runDir });
71
+ }
72
+ if (!dryRun) {
73
+ for (const run of plan.eligible) {
74
+ const safetyIssue = await getRunSafetyIssue({ realRunsDir, runDir: run.path });
75
+ if (safetyIssue) {
76
+ plan.skipped.push({ ...run, reason: `became unsafe before deletion: ${safetyIssue}` });
77
+ continue;
78
+ }
79
+ await rm(run.path, { recursive: true, force: false });
80
+ plan.deleted.push(run);
81
+ }
82
+ }
83
+ return plan;
84
+ }
85
+ async function inspectRunsDirectory(runsDir, realReportDir) {
86
+ try {
87
+ const stats = await lstat(runsDir);
88
+ if (stats.isSymbolicLink()) {
89
+ throw new Error(`Refusing to garbage collect through a symlinked runs directory: ${runsDir}`);
90
+ }
91
+ if (!stats.isDirectory()) {
92
+ throw new Error(`Reflection runs path is not a directory: ${runsDir}`);
93
+ }
94
+ }
95
+ catch (error) {
96
+ if (isNodeError(error, 'ENOENT')) {
97
+ return undefined;
98
+ }
99
+ throw error;
100
+ }
101
+ const realRunsDir = await realpath(runsDir);
102
+ if (!isInside(realReportDir, realRunsDir)) {
103
+ throw new Error(`Reflection runs directory resolves outside the artifact root: ${realRunsDir}`);
104
+ }
105
+ return realRunsDir;
106
+ }
107
+ async function getRunSafetyIssue(input) {
108
+ try {
109
+ const stats = await lstat(input.runDir);
110
+ if (stats.isSymbolicLink()) {
111
+ const realRunDir = await realpath(input.runDir);
112
+ if (!isInside(input.realRunsDir, realRunDir)) {
113
+ return `run directory resolves outside the runs directory: ${realRunDir}`;
114
+ }
115
+ return 'run directory is a symlink';
116
+ }
117
+ const realRunDir = await realpath(input.runDir);
118
+ if (!isInside(input.realRunsDir, realRunDir)) {
119
+ return `run directory resolves outside the runs directory: ${realRunDir}`;
120
+ }
121
+ }
122
+ catch (error) {
123
+ if (isNodeError(error, 'ENOENT')) {
124
+ return 'run directory disappeared before GC could inspect it';
125
+ }
126
+ throw error;
127
+ }
128
+ return undefined;
129
+ }
130
+ async function readRunManifest(runDir) {
131
+ try {
132
+ const raw = await readFile(resolve(runDir, 'manifest.json'), 'utf8');
133
+ const parsed = RunManifestSchema.safeParse(JSON.parse(raw));
134
+ if (!parsed.success) {
135
+ return { ok: false, reason: `invalid manifest: ${parsed.error.issues.map((issue) => issue.path.join('.') || 'manifest').join(', ')}` };
136
+ }
137
+ return { ok: true, manifest: parsed.data };
138
+ }
139
+ catch (error) {
140
+ if (isNodeError(error, 'ENOENT')) {
141
+ return { ok: false, reason: 'missing manifest' };
142
+ }
143
+ if (error instanceof SyntaxError) {
144
+ return { ok: false, reason: 'invalid manifest JSON' };
145
+ }
146
+ throw error;
147
+ }
148
+ }
149
+ function ensureInside(parent, child) {
150
+ if (!isInside(parent, child)) {
151
+ throw new Error(`Refusing to garbage collect outside the artifact root: ${child}`);
152
+ }
153
+ }
154
+ function isInside(parent, child) {
155
+ const relation = relative(parent, child);
156
+ return relation === '' || (!relation.startsWith('..') && !isAbsolute(relation));
157
+ }
158
+ function isNodeError(error, code) {
159
+ return error instanceof Error && 'code' in error && error.code === code;
160
+ }
161
+ //# sourceMappingURL=gc.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"gc.js","sourceRoot":"","sources":["../../src/core/gc.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,23 @@
1
+ import type { ArtifactRef, ReflectionReport } from './report-schema.js';
2
+ export type RunManifest = {
3
+ schemaVersion: 1;
4
+ runId: string;
5
+ createdAt: string;
6
+ project: string;
7
+ status: ReflectionReport['status'];
8
+ mode: ReflectionReport['mode'];
9
+ ci: boolean;
10
+ retention: {
11
+ pinned: boolean;
12
+ };
13
+ files: Array<{
14
+ path: string;
15
+ type: ArtifactRef['type'];
16
+ bytes?: number;
17
+ sha256?: string;
18
+ }>;
19
+ };
20
+ export declare function createRunManifest(input: {
21
+ report: ReflectionReport;
22
+ files: ArtifactRef[];
23
+ }): RunManifest;
@@ -0,0 +1,21 @@
1
+ export function createRunManifest(input) {
2
+ return {
3
+ schemaVersion: 1,
4
+ runId: input.report.runId,
5
+ createdAt: input.report.finishedAt,
6
+ project: input.report.project,
7
+ status: input.report.status,
8
+ mode: input.report.mode,
9
+ ci: input.report.ci,
10
+ retention: {
11
+ pinned: false
12
+ },
13
+ files: input.files.map((file) => ({
14
+ path: file.path,
15
+ type: file.type,
16
+ ...(file.bytes !== undefined ? { bytes: file.bytes } : {}),
17
+ ...(file.sha256 !== undefined ? { sha256: file.sha256 } : {})
18
+ }))
19
+ };
20
+ }
21
+ //# sourceMappingURL=manifest.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"manifest.js","sourceRoot":"","sources":["../../src/core/manifest.ts"],"names":[],"mappings":"AAqBA,MAAM,UAAU,iBAAiB,CAAC,KAAyD;IACzF,OAAO;QACL,aAAa,EAAE,CAAC;QAChB,KAAK,EAAE,KAAK,CAAC,MAAM,CAAC,KAAK;QACzB,SAAS,EAAE,KAAK,CAAC,MAAM,CAAC,UAAU;QAClC,OAAO,EAAE,KAAK,CAAC,MAAM,CAAC,OAAO;QAC7B,MAAM,EAAE,KAAK,CAAC,MAAM,CAAC,MAAM;QAC3B,IAAI,EAAE,KAAK,CAAC,MAAM,CAAC,IAAI;QACvB,EAAE,EAAE,KAAK,CAAC,MAAM,CAAC,EAAE;QACnB,SAAS,EAAE;YACT,MAAM,EAAE,KAAK;SACd;QACD,KAAK,EAAE,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YAChC,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,IAAI,EAAE,IAAI,CAAC,IAAI;YACf,GAAG,CAAC,IAAI,CAAC,KAAK,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC1D,GAAG,CAAC,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;SAC9D,CAAC,CAAC;KACJ,CAAC;AACJ,CAAC"}
@@ -0,0 +1,3 @@
1
+ import { Transform } from 'node:stream';
2
+ export declare function redactSensitiveText(text: string): string;
3
+ export declare function createRedactionTransform(): Transform;
@@ -0,0 +1,63 @@
1
+ import { Transform } from 'node:stream';
2
+ const REDACTION = '[REDACTED]';
3
+ const streamingTailLength = 4096;
4
+ const sensitiveHeaderNames = ['authorization', 'cookie', 'set-cookie', 'x-api-key', 'api[-_]?key', 'access[-_]?token'];
5
+ const sensitiveFieldStartPattern = new RegExp(`["']?(?:${sensitiveHeaderNames.join('|')})["']?\\s*[:=]`, 'i');
6
+ const incompleteSensitiveFieldPattern = new RegExp(`(["']?(?:${sensitiveHeaderNames.join('|')})["']?\\s*[:=]\\s*["']?)[\\s\\S]*`, 'i');
7
+ const doubleQuotedValuePattern = new RegExp(`("(?:${sensitiveHeaderNames.join('|')})"\\s*:\\s*")(?:\\\\.|[^"\\\\\\r\\n])*(")`, 'gi');
8
+ const singleQuotedValuePattern = new RegExp(`('(?:${sensitiveHeaderNames.join('|')})'\\s*:\\s*')(?:\\\\.|[^'\\\\\\r\\n])*(')`, 'gi');
9
+ const headerLinePatterns = [
10
+ /\b(authorization\s*[:=]\s*)[^\r\n]+/gi,
11
+ /\b(cookie\s*[:=]\s*)[^\r\n]+/gi,
12
+ /\b(set-cookie\s*[:=]\s*)[^\r\n]+/gi,
13
+ /\b(x-api-key\s*[:=]\s*)[^\r\n]+/gi,
14
+ /\b(api[-_]?key\s*[:=]\s*)[^\s&\r\n]+/gi,
15
+ /\b(access[-_]?token\s*[:=]\s*)[^\s&\r\n]+/gi
16
+ ];
17
+ export function redactSensitiveText(text) {
18
+ const redactedDoubleQuotedValues = text.replace(doubleQuotedValuePattern, `$1${REDACTION}$2`);
19
+ const redactedQuotedValues = redactedDoubleQuotedValues.replace(singleQuotedValuePattern, `$1${REDACTION}$2`);
20
+ return headerLinePatterns.reduce((value, pattern) => value.replace(pattern, `$1${REDACTION}`), redactedQuotedValues);
21
+ }
22
+ export function createRedactionTransform() {
23
+ let pending = '';
24
+ let suppressingSensitiveLine = false;
25
+ return new Transform({
26
+ transform(chunk, _encoding, callback) {
27
+ let text = chunk.toString();
28
+ if (suppressingSensitiveLine) {
29
+ const lineBreak = text.indexOf('\n');
30
+ if (lineBreak === -1) {
31
+ callback();
32
+ return;
33
+ }
34
+ text = text.slice(lineBreak + 1);
35
+ suppressingSensitiveLine = false;
36
+ }
37
+ pending += text;
38
+ const lastLineBreak = pending.lastIndexOf('\n');
39
+ if (lastLineBreak === -1 && pending.length <= streamingTailLength) {
40
+ callback();
41
+ return;
42
+ }
43
+ if (lastLineBreak === -1 && sensitiveFieldStartPattern.test(pending)) {
44
+ const redacted = redactIncompleteSensitiveLine(pending);
45
+ pending = '';
46
+ suppressingSensitiveLine = true;
47
+ callback(null, redacted);
48
+ return;
49
+ }
50
+ const flushThrough = lastLineBreak === -1 ? Math.max(0, pending.length - streamingTailLength) : lastLineBreak + 1;
51
+ const ready = pending.slice(0, flushThrough);
52
+ pending = pending.slice(flushThrough);
53
+ callback(null, redactSensitiveText(ready));
54
+ },
55
+ flush(callback) {
56
+ callback(null, suppressingSensitiveLine ? '' : redactSensitiveText(pending));
57
+ }
58
+ });
59
+ }
60
+ function redactIncompleteSensitiveLine(text) {
61
+ return text.replace(incompleteSensitiveFieldPattern, `$1${REDACTION}`);
62
+ }
63
+ //# sourceMappingURL=redaction.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"redaction.js","sourceRoot":"","sources":["../../src/core/redaction.ts"],"names":[],"mappings":"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"}