@multiplayer-app/sandbox 0.0.31 → 0.0.32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agents/html-generator.agent.d.ts +3 -1
- package/dist/agents/html-generator.agent.d.ts.map +1 -1
- package/dist/agents/html-generator.agent.js +90 -4
- package/dist/agents/html-generator.agent.js.map +1 -1
- package/dist/agents/markdown-generator.agent.d.ts.map +1 -1
- package/dist/agents/markdown-generator.agent.js +5 -10
- package/dist/agents/markdown-generator.agent.js.map +1 -1
- package/dist/agents/shared/app-vm.tools.d.ts +4 -0
- package/dist/agents/shared/app-vm.tools.d.ts.map +1 -0
- package/dist/agents/shared/app-vm.tools.js +105 -0
- package/dist/agents/shared/app-vm.tools.js.map +1 -0
- package/dist/agents/shared/build-plan.tools.d.ts +5 -0
- package/dist/agents/shared/build-plan.tools.d.ts.map +1 -0
- package/dist/agents/shared/build-plan.tools.js +176 -0
- package/dist/agents/shared/build-plan.tools.js.map +1 -0
- package/dist/agents/shared/session-quality-report.tool.d.ts +7 -0
- package/dist/agents/shared/session-quality-report.tool.d.ts.map +1 -0
- package/dist/agents/shared/session-quality-report.tool.js +97 -0
- package/dist/agents/shared/session-quality-report.tool.js.map +1 -0
- package/dist/agents/shared/session-vm-bridge.d.ts +49 -0
- package/dist/agents/shared/session-vm-bridge.d.ts.map +1 -0
- package/dist/agents/shared/session-vm-bridge.js +9 -0
- package/dist/agents/shared/session-vm-bridge.js.map +1 -0
- package/dist/agents/skills/a11y.skill.d.ts +3 -0
- package/dist/agents/skills/a11y.skill.d.ts.map +1 -0
- package/dist/agents/skills/a11y.skill.js +23 -0
- package/dist/agents/skills/a11y.skill.js.map +1 -0
- package/dist/agents/skills/account-skill-loader.d.ts +13 -0
- package/dist/agents/skills/account-skill-loader.d.ts.map +1 -0
- package/dist/agents/skills/account-skill-loader.js +42 -0
- package/dist/agents/skills/account-skill-loader.js.map +1 -0
- package/dist/agents/skills/app-scaffold.skill.d.ts +3 -0
- package/dist/agents/skills/app-scaffold.skill.d.ts.map +1 -0
- package/dist/agents/skills/app-scaffold.skill.js +30 -0
- package/dist/agents/skills/app-scaffold.skill.js.map +1 -0
- package/dist/agents/skills/copywriting.skill.d.ts +3 -0
- package/dist/agents/skills/copywriting.skill.d.ts.map +1 -0
- package/dist/agents/skills/copywriting.skill.js +35 -0
- package/dist/agents/skills/copywriting.skill.js.map +1 -0
- package/dist/agents/skills/custom-skill-repository.d.ts +40 -0
- package/dist/agents/skills/custom-skill-repository.d.ts.map +1 -0
- package/dist/agents/skills/custom-skill-repository.js +3 -0
- package/dist/agents/skills/custom-skill-repository.js.map +1 -0
- package/dist/agents/skills/data-viz.skill.d.ts +3 -0
- package/dist/agents/skills/data-viz.skill.d.ts.map +1 -0
- package/dist/agents/skills/data-viz.skill.js +42 -0
- package/dist/agents/skills/data-viz.skill.js.map +1 -0
- package/dist/agents/skills/designer.skill.d.ts +3 -0
- package/dist/agents/skills/designer.skill.d.ts.map +1 -0
- package/dist/agents/skills/designer.skill.js +139 -0
- package/dist/agents/skills/designer.skill.js.map +1 -0
- package/dist/agents/skills/forms.skill.d.ts +3 -0
- package/dist/agents/skills/forms.skill.d.ts.map +1 -0
- package/dist/agents/skills/forms.skill.js +37 -0
- package/dist/agents/skills/forms.skill.js.map +1 -0
- package/dist/agents/skills/index.d.ts +6 -0
- package/dist/agents/skills/index.d.ts.map +1 -0
- package/dist/agents/skills/index.js +18 -0
- package/dist/agents/skills/index.js.map +1 -0
- package/dist/agents/skills/interactions.skill.d.ts +3 -0
- package/dist/agents/skills/interactions.skill.d.ts.map +1 -0
- package/dist/agents/skills/interactions.skill.js +31 -0
- package/dist/agents/skills/interactions.skill.js.map +1 -0
- package/dist/agents/skills/registry.d.ts +23 -0
- package/dist/agents/skills/registry.d.ts.map +1 -0
- package/dist/agents/skills/registry.js +75 -0
- package/dist/agents/skills/registry.js.map +1 -0
- package/dist/agents/skills/skill-injection.d.ts +52 -0
- package/dist/agents/skills/skill-injection.d.ts.map +1 -0
- package/dist/agents/skills/skill-injection.js +210 -0
- package/dist/agents/skills/skill-injection.js.map +1 -0
- package/dist/agents/skills/types.d.ts +12 -0
- package/dist/agents/skills/types.d.ts.map +1 -0
- package/dist/agents/skills/types.js +3 -0
- package/dist/agents/skills/types.js.map +1 -0
- package/dist/builder-api-config.d.ts +7 -0
- package/dist/builder-api-config.d.ts.map +1 -1
- package/dist/builder-api-config.js.map +1 -1
- package/dist/context.d.ts +7 -0
- package/dist/context.d.ts.map +1 -1
- package/dist/context.js +19 -0
- package/dist/context.js.map +1 -1
- package/dist/create-builder-api.d.ts +2 -3
- package/dist/create-builder-api.d.ts.map +1 -1
- package/dist/create-builder-api.js +18 -0
- package/dist/create-builder-api.js.map +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +2 -1
- package/dist/index.js.map +1 -1
- package/dist/lib/library/list-library-items.d.ts +2 -2
- package/dist/lib/library/list-library-items.d.ts.map +1 -1
- package/dist/lib/library/list-library-items.js +49 -7
- package/dist/lib/library/list-library-items.js.map +1 -1
- package/dist/lib/object-storage/index.d.ts +3 -0
- package/dist/lib/object-storage/index.d.ts.map +1 -0
- package/dist/lib/object-storage/index.js +19 -0
- package/dist/lib/object-storage/index.js.map +1 -0
- package/dist/lib/object-storage/keys.d.ts +10 -0
- package/dist/lib/object-storage/keys.d.ts.map +1 -0
- package/dist/lib/object-storage/keys.js +51 -0
- package/dist/lib/object-storage/keys.js.map +1 -0
- package/dist/lib/object-storage/s3-object-store.d.ts +14 -0
- package/dist/lib/object-storage/s3-object-store.d.ts.map +1 -0
- package/dist/lib/object-storage/s3-object-store.js +64 -0
- package/dist/lib/object-storage/s3-object-store.js.map +1 -0
- package/dist/lib/session-pages/artifact-quality-audit.d.ts +16 -0
- package/dist/lib/session-pages/artifact-quality-audit.d.ts.map +1 -0
- package/dist/lib/session-pages/artifact-quality-audit.js +293 -0
- package/dist/lib/session-pages/artifact-quality-audit.js.map +1 -0
- package/dist/lib/session-pages/artifact-storage.d.ts +3 -0
- package/dist/lib/session-pages/artifact-storage.d.ts.map +1 -1
- package/dist/lib/session-pages/artifact-storage.js +94 -85
- package/dist/lib/session-pages/artifact-storage.js.map +1 -1
- package/dist/lib/session-pages/audit-session-html.d.ts +23 -0
- package/dist/lib/session-pages/audit-session-html.d.ts.map +1 -0
- package/dist/lib/session-pages/audit-session-html.js +82 -0
- package/dist/lib/session-pages/audit-session-html.js.map +1 -0
- package/dist/lib/session-pages/contrast-check.d.ts +25 -0
- package/dist/lib/session-pages/contrast-check.d.ts.map +1 -0
- package/dist/lib/session-pages/contrast-check.js +290 -0
- package/dist/lib/session-pages/contrast-check.js.map +1 -0
- package/dist/lib/session-pages/deferred-quality-rules.d.ts +7 -0
- package/dist/lib/session-pages/deferred-quality-rules.d.ts.map +1 -0
- package/dist/lib/session-pages/deferred-quality-rules.js +25 -0
- package/dist/lib/session-pages/deferred-quality-rules.js.map +1 -0
- package/dist/lib/session-pages/delete-session-artifact.d.ts.map +1 -1
- package/dist/lib/session-pages/delete-session-artifact.js +12 -41
- package/dist/lib/session-pages/delete-session-artifact.js.map +1 -1
- package/dist/lib/session-pages/delete-session-artifacts.d.ts +0 -6
- package/dist/lib/session-pages/delete-session-artifacts.d.ts.map +1 -1
- package/dist/lib/session-pages/delete-session-artifacts.js +51 -15
- package/dist/lib/session-pages/delete-session-artifacts.js.map +1 -1
- package/dist/lib/session-pages/list-session-artifacts.d.ts.map +1 -1
- package/dist/lib/session-pages/list-session-artifacts.js +48 -48
- package/dist/lib/session-pages/list-session-artifacts.js.map +1 -1
- package/dist/lib/session-pages/read-session-artifacts.d.ts.map +1 -1
- package/dist/lib/session-pages/read-session-artifacts.js +4 -26
- package/dist/lib/session-pages/read-session-artifacts.js.map +1 -1
- package/dist/lib/session-pages/resolve-session-account-id.d.ts +3 -0
- package/dist/lib/session-pages/resolve-session-account-id.d.ts.map +1 -0
- package/dist/lib/session-pages/resolve-session-account-id.js +31 -0
- package/dist/lib/session-pages/resolve-session-account-id.js.map +1 -0
- package/dist/lib/session-pages/write-session-artifacts.d.ts +0 -2
- package/dist/lib/session-pages/write-session-artifacts.d.ts.map +1 -1
- package/dist/lib/session-pages/write-session-artifacts.js +8 -0
- package/dist/lib/session-pages/write-session-artifacts.js.map +1 -1
- package/dist/lib/session-plans/build-plan.d.ts +64 -0
- package/dist/lib/session-plans/build-plan.d.ts.map +1 -0
- package/dist/lib/session-plans/build-plan.js +134 -0
- package/dist/lib/session-plans/build-plan.js.map +1 -0
- package/dist/lib/yjs-pending/flush-lock.d.ts +6 -0
- package/dist/lib/yjs-pending/flush-lock.d.ts.map +1 -0
- package/dist/lib/yjs-pending/flush-lock.js +43 -0
- package/dist/lib/yjs-pending/flush-lock.js.map +1 -0
- package/dist/lib/yjs-pending/flush-worker.d.ts +5 -0
- package/dist/lib/yjs-pending/flush-worker.d.ts.map +1 -0
- package/dist/lib/yjs-pending/flush-worker.js +75 -0
- package/dist/lib/yjs-pending/flush-worker.js.map +1 -0
- package/dist/lib/yjs-pending/yjs-pending-updates-repository.d.ts +22 -0
- package/dist/lib/yjs-pending/yjs-pending-updates-repository.d.ts.map +1 -0
- package/dist/lib/yjs-pending/yjs-pending-updates-repository.js +3 -0
- package/dist/lib/yjs-pending/yjs-pending-updates-repository.js.map +1 -0
- package/dist/lib/yjs-pending/yjs-persistence.d.ts +23 -0
- package/dist/lib/yjs-pending/yjs-persistence.d.ts.map +1 -0
- package/dist/lib/yjs-pending/yjs-persistence.js +222 -0
- package/dist/lib/yjs-pending/yjs-persistence.js.map +1 -0
- package/dist/realtime/reset-session-artifact-y-docs.d.ts.map +1 -1
- package/dist/realtime/reset-session-artifact-y-docs.js +1 -6
- package/dist/realtime/reset-session-artifact-y-docs.js.map +1 -1
- package/dist/realtime/session-artifact-y-socket-io.d.ts +0 -5
- package/dist/realtime/session-artifact-y-socket-io.d.ts.map +1 -1
- package/dist/realtime/session-artifact-y-socket-io.js +5 -69
- package/dist/realtime/session-artifact-y-socket-io.js.map +1 -1
- package/dist/realtime/session-artifact-yjs-store.d.ts +3 -35
- package/dist/realtime/session-artifact-yjs-store.d.ts.map +1 -1
- package/dist/realtime/session-artifact-yjs-store.js +75 -235
- package/dist/realtime/session-artifact-yjs-store.js.map +1 -1
- package/dist/routes/sessions.d.ts.map +1 -1
- package/dist/routes/sessions.js +26 -6
- package/dist/routes/sessions.js.map +1 -1
- package/dist/routes/skills.d.ts +2 -0
- package/dist/routes/skills.d.ts.map +1 -0
- package/dist/routes/skills.js +140 -0
- package/dist/routes/skills.js.map +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,293 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.auditHtmlArtifact = auditHtmlArtifact;
|
|
4
|
+
const contrast_check_1 = require("./contrast-check");
|
|
5
|
+
function extractStyles(html) {
|
|
6
|
+
var _a, _b;
|
|
7
|
+
const closed = [...html.matchAll(/<style[^>]*>([\s\S]*?)<\/style>/gi)].map((m) => m[1]);
|
|
8
|
+
if (closed.length > 0)
|
|
9
|
+
return closed.join('\n');
|
|
10
|
+
// Unclosed <style> swallows the rest of the document — still treat that
|
|
11
|
+
// trailing text as the stylesheet so the other rules stay meaningful.
|
|
12
|
+
return (_b = (_a = html.match(/<style[^>]*>([\s\S]*)$/i)) === null || _a === void 0 ? void 0 : _a[1]) !== null && _b !== void 0 ? _b : '';
|
|
13
|
+
}
|
|
14
|
+
function extractScripts(html) {
|
|
15
|
+
return [...html.matchAll(/<script[^>]*>([\s\S]*?)<\/script>/gi)].map((m) => m[1]).join('\n');
|
|
16
|
+
}
|
|
17
|
+
/** Legacy Pico-era classes usable without a page-level definition (kept for
|
|
18
|
+
* auditing older documents that still link Pico). */
|
|
19
|
+
const FRAMEWORK_CLASSES = new Set([
|
|
20
|
+
'container',
|
|
21
|
+
'container-fluid',
|
|
22
|
+
'grid',
|
|
23
|
+
'secondary',
|
|
24
|
+
'contrast',
|
|
25
|
+
'outline',
|
|
26
|
+
]);
|
|
27
|
+
/** Pages on the Tailwind shell style themselves via utility classes, so the
|
|
28
|
+
* undefined-class and thin-CSS heuristics do not apply. */
|
|
29
|
+
function usesTailwind(html) {
|
|
30
|
+
return /cdn\.tailwindcss\.com|tailwindcss/i.test(html);
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Static quality audit for generated HTML pages. Deterministic counterpart to
|
|
34
|
+
* the generation skill guides: flags the failure modes they warn about so
|
|
35
|
+
* subagents can fix them before publishing.
|
|
36
|
+
*/
|
|
37
|
+
function auditHtmlArtifact(html) {
|
|
38
|
+
var _a, _b, _c, _d, _e, _f;
|
|
39
|
+
const findings = [];
|
|
40
|
+
const styles = extractStyles(html);
|
|
41
|
+
const scripts = extractScripts(html);
|
|
42
|
+
const openStyleTags = ((_a = html.match(/<style[^>]*>/gi)) !== null && _a !== void 0 ? _a : []).length;
|
|
43
|
+
const closeStyleTags = ((_b = html.match(/<\/style>/gi)) !== null && _b !== void 0 ? _b : []).length;
|
|
44
|
+
const hasUnclosedStyle = openStyleTags > closeStyleTags;
|
|
45
|
+
if (hasUnclosedStyle) {
|
|
46
|
+
findings.push({
|
|
47
|
+
rule: 'unclosed-style',
|
|
48
|
+
severity: 'error',
|
|
49
|
+
message: '<style> tag is never closed — everything after it is swallowed as CSS. Add the missing </style> first; other style checks are skipped until it is fixed.',
|
|
50
|
+
});
|
|
51
|
+
}
|
|
52
|
+
const openScriptTags = ((_c = html.match(/<script[^>]*>/gi)) !== null && _c !== void 0 ? _c : []).length;
|
|
53
|
+
const closeScriptTags = ((_d = html.match(/<\/script>/gi)) !== null && _d !== void 0 ? _d : []).length;
|
|
54
|
+
if (openScriptTags > closeScriptTags) {
|
|
55
|
+
findings.push({
|
|
56
|
+
rule: 'unclosed-script',
|
|
57
|
+
severity: 'error',
|
|
58
|
+
message: '<script> tag is never closed — everything after it is swallowed as JavaScript. Add the missing </script>.',
|
|
59
|
+
});
|
|
60
|
+
}
|
|
61
|
+
// Legacy Pico-based pages: Pico is (nearly) classless — it styles bare
|
|
62
|
+
// elements and ships no utility classes, so any class the markup references
|
|
63
|
+
// does nothing unless the page's own <style> defines it. Tailwind pages are
|
|
64
|
+
// exempt (utilities ARE the styling). Also skipped while a <style> tag is
|
|
65
|
+
// unclosed — that breakage makes class detection unreliable.
|
|
66
|
+
const tailwind = usesTailwind(html);
|
|
67
|
+
if (!hasUnclosedStyle && !tailwind) {
|
|
68
|
+
const referencedClasses = new Set();
|
|
69
|
+
for (const match of html.matchAll(/class=["']([^"']+)["']/gi)) {
|
|
70
|
+
for (const token of match[1].split(/\s+/)) {
|
|
71
|
+
if (token)
|
|
72
|
+
referencedClasses.add(token);
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
const undefinedClasses = [...referencedClasses].filter((token) => !FRAMEWORK_CLASSES.has(token) && !styles.includes(`.${token}`) && !scripts.includes(token));
|
|
76
|
+
if (undefinedClasses.length > 0) {
|
|
77
|
+
findings.push({
|
|
78
|
+
rule: 'undefined-classes',
|
|
79
|
+
severity: 'error',
|
|
80
|
+
message: `These classes have no CSS — the base stylesheet (Pico) has no utility classes, so a class does nothing until your <style> defines it. Add a rule for each of: ${undefinedClasses
|
|
81
|
+
.slice(0, 12)
|
|
82
|
+
.join(', ')}${undefinedClasses.length > 12 ? ` +${undefinedClasses.length - 12} more` : ''} — or delete the class attribute.`,
|
|
83
|
+
});
|
|
84
|
+
}
|
|
85
|
+
}
|
|
86
|
+
// Advisory: native form submits are legitimate scriptless buttons, so this
|
|
87
|
+
// cannot be a hard invariant — but a page full of dead toggles usually is.
|
|
88
|
+
// Checks INLINE script content: src-only tags (e.g. the Tailwind CDN loader)
|
|
89
|
+
// don't count as page behavior.
|
|
90
|
+
if (/<button[\s>]/i.test(html) && scripts.trim().length === 0) {
|
|
91
|
+
findings.push({
|
|
92
|
+
rule: 'static-controls',
|
|
93
|
+
severity: 'warning',
|
|
94
|
+
message: '<button> elements present but the page has no <script> — interactive controls (toggles, filters, tabs) must actually work.',
|
|
95
|
+
});
|
|
96
|
+
}
|
|
97
|
+
// Advisory only: fragment titles are auto-derived from the first <h1> at
|
|
98
|
+
// wrap time, so this now fires only for pages with neither.
|
|
99
|
+
const titleMatch = html.match(/<title[^>]*>([^<]*)<\/title>/i);
|
|
100
|
+
if (titleMatch && /^(page|document|untitled)?$/i.test(titleMatch[1].trim())) {
|
|
101
|
+
findings.push({
|
|
102
|
+
rule: 'generic-title',
|
|
103
|
+
severity: 'warning',
|
|
104
|
+
message: 'Document title is missing or generic — pass a meaningful `title` (or add an <h1>, which the server uses to derive one).',
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
const markupOnly = html
|
|
108
|
+
.replace(/<style[\s\S]*?<\/style>/gi, '')
|
|
109
|
+
.replace(/<script[\s\S]*?<\/script>/gi, '');
|
|
110
|
+
// Class-strategy dark mode: dark: variants do nothing unless the page opts
|
|
111
|
+
// in with a .dark ancestor. Half-implemented dark mode (dark text variants
|
|
112
|
+
// on light backgrounds) was a severe real-world contrast failure.
|
|
113
|
+
if (tailwind && /class=["'][^"']*\bdark:/.test(html) && !/class=["'][^"']*\bdark\b(?!:)/.test(html)) {
|
|
114
|
+
findings.push({
|
|
115
|
+
rule: 'inert-dark-variants',
|
|
116
|
+
severity: 'warning',
|
|
117
|
+
message: 'dark: utility variants found but the page never enables the dark class — they have no effect. Style your color scheme explicitly (per the design brief) and remove the dark: variants.',
|
|
118
|
+
});
|
|
119
|
+
}
|
|
120
|
+
// CSS variables referenced but never defined render as transparent/initial —
|
|
121
|
+
// invisible buttons, black text on dark heroes. Always an authoring error.
|
|
122
|
+
const referencedVars = new Set([...html.matchAll(/var\((--[a-zA-Z0-9_-]+)/g)].map((match) => match[1]));
|
|
123
|
+
const undefinedVars = [...referencedVars].filter((name) => !new RegExp(`${name}\\s*:`).test(html));
|
|
124
|
+
if (undefinedVars.length > 0) {
|
|
125
|
+
findings.push({
|
|
126
|
+
rule: 'undefined-css-variable',
|
|
127
|
+
severity: 'error',
|
|
128
|
+
message: `CSS variables referenced but never defined: ${undefinedVars.join(', ')} — elements using them render transparent or inherit the wrong color. Define them in a :root block in your <style> (e.g. :root { ${undefinedVars[0]}: #0ea5e9 }).`,
|
|
129
|
+
});
|
|
130
|
+
}
|
|
131
|
+
// WCAG contrast: static analysis over Tailwind color utilities. This is a
|
|
132
|
+
// heuristic: it cannot reliably resolve every CSS cascade, overlay,
|
|
133
|
+
// pseudo-element, or runtime class. Findings are therefore always advisory.
|
|
134
|
+
// Treating an inferred contrast pair as a transactional publish error caused
|
|
135
|
+
// valid dark/gradient pages to regenerate the complete document repeatedly.
|
|
136
|
+
// Accessibility still matters, but it belongs in the targeted consistency
|
|
137
|
+
// pass (or a browser-backed check), not in the atomic file-write gate.
|
|
138
|
+
if (!hasUnclosedStyle && tailwind) {
|
|
139
|
+
try {
|
|
140
|
+
for (const issue of (0, contrast_check_1.checkContrast)(html).slice(0, 5)) {
|
|
141
|
+
findings.push({
|
|
142
|
+
rule: issue.severity === 'error' ? 'unreadable-contrast' : 'low-contrast',
|
|
143
|
+
severity: 'warning',
|
|
144
|
+
message: `WCAG contrast ${issue.ratio}:1 — "${issue.textToken}" on "${issue.bgToken}" (e.g. "${issue.snippet}"). ${issue.severity === 'error' ? 'This text is effectively invisible.' : 'Below the 4.5:1 AA minimum.'} Static analysis only; verify the rendered state and pick a text color readable on that background.`,
|
|
145
|
+
});
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
catch (_g) {
|
|
149
|
+
// Contrast analysis is best-effort — never break the audit on it.
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
// Distinctive web fonts are required — the shell no longer injects Inter.
|
|
153
|
+
// Google Fonts link OR an explicit font-family in <style> satisfies this.
|
|
154
|
+
if (!/fonts\.googleapis\.com/i.test(html) &&
|
|
155
|
+
!/font-family\s*:/i.test(styles) &&
|
|
156
|
+
!/<link[^>]+fonts\.(?:googleapis|gstatic)\.com/i.test(html)) {
|
|
157
|
+
findings.push({
|
|
158
|
+
rule: 'missing-web-font',
|
|
159
|
+
severity: 'error',
|
|
160
|
+
message: 'No web font loaded — add the design-brief Google Font pairing (<link href="https://fonts.googleapis.com/css2?family=…"> plus font-family on body). Never rely on system/Inter defaults.',
|
|
161
|
+
});
|
|
162
|
+
}
|
|
163
|
+
const emojiMatches = ((_e = markupOnly.match(/\p{Extended_Pictographic}/gu)) !== null && _e !== void 0 ? _e : []).filter((char) => !'©®™°†‡§¶'.includes(char));
|
|
164
|
+
if (emojiMatches.length > 0) {
|
|
165
|
+
findings.push({
|
|
166
|
+
rule: 'emoji-icons',
|
|
167
|
+
severity: 'error',
|
|
168
|
+
message: `${emojiMatches.length} emoji character(s) in the markup (${[...new Set(emojiMatches)]
|
|
169
|
+
.slice(0, 6)
|
|
170
|
+
.join(' ')}) — emoji are not icons; use inline SVG icons (Lucide/Heroicons, stroke="currentColor") unless the user explicitly asked for emoji content.`,
|
|
171
|
+
});
|
|
172
|
+
}
|
|
173
|
+
const markupLength = markupOnly.length;
|
|
174
|
+
if (!tailwind && markupLength > 1500 && styles.length < 1200) {
|
|
175
|
+
findings.push({
|
|
176
|
+
rule: 'thin-styling',
|
|
177
|
+
severity: 'warning',
|
|
178
|
+
message: `Only ${styles.length} chars of CSS for ${markupLength} chars of markup — this reads as an unstyled page. Build the full design system: layout container, cards, spacing scale, hover/focus states.`,
|
|
179
|
+
});
|
|
180
|
+
}
|
|
181
|
+
// Web-font hosts are the one sanctioned external dependency (the designer
|
|
182
|
+
// guide mandates a Google Fonts pairing) — everything else remote is a 404
|
|
183
|
+
// waiting to happen.
|
|
184
|
+
const externalStyleUrl = /url\(\s*["']?https?:\/\/(?!fonts\.googleapis\.com|fonts\.gstatic\.com)/i;
|
|
185
|
+
if (/<img[^>]+src=["']https?:/i.test(html) || externalStyleUrl.test(styles)) {
|
|
186
|
+
findings.push({
|
|
187
|
+
rule: 'external-image',
|
|
188
|
+
severity: 'error',
|
|
189
|
+
message: 'External image/asset URLs can 404 — replace with inline SVG, CSS gradients, or data: URIs (Google Fonts imports are allowed).',
|
|
190
|
+
});
|
|
191
|
+
}
|
|
192
|
+
if (/lorem\s+ipsum/i.test(html)) {
|
|
193
|
+
findings.push({
|
|
194
|
+
rule: 'placeholder-copy',
|
|
195
|
+
severity: 'error',
|
|
196
|
+
message: 'Lorem ipsum found — write realistic, domain-appropriate content instead.',
|
|
197
|
+
});
|
|
198
|
+
}
|
|
199
|
+
if (/\b(?:Item|Feature|Card|Product)\s+[0-9]\b/.test(html)) {
|
|
200
|
+
findings.push({
|
|
201
|
+
rule: 'generic-sample-data',
|
|
202
|
+
severity: 'error',
|
|
203
|
+
message: 'Generic sample data ("Item 1"…) found — use realistic, internally consistent examples.',
|
|
204
|
+
});
|
|
205
|
+
}
|
|
206
|
+
// Generic marketing filler — ships as "AI template" even when layout is fine.
|
|
207
|
+
if (/\bwelcome\s+to\s+(?:our|the)\b/i.test(markupOnly)) {
|
|
208
|
+
findings.push({
|
|
209
|
+
rule: 'template-copy',
|
|
210
|
+
severity: 'error',
|
|
211
|
+
message: 'Template copy ("Welcome to our/the…") found — lead with the product outcome instead.',
|
|
212
|
+
});
|
|
213
|
+
}
|
|
214
|
+
if (/\b(?:revolutionary|seamless|cutting-edge|unleash(?:ing)?|empower(?:ing)?)\b/i.test(markupOnly)) {
|
|
215
|
+
findings.push({
|
|
216
|
+
rule: 'template-copy',
|
|
217
|
+
severity: 'error',
|
|
218
|
+
message: 'Banned template adjectives found (revolutionary/seamless/cutting-edge/unleash/empower) — use concrete, domain-specific language.',
|
|
219
|
+
});
|
|
220
|
+
}
|
|
221
|
+
// Inter is the default AI-page tell — designer skill and design brief forbid it.
|
|
222
|
+
if (/family=Inter\b|font-family:\s*['"]?Inter\b/i.test(html)) {
|
|
223
|
+
findings.push({
|
|
224
|
+
rule: 'generic-font',
|
|
225
|
+
severity: 'error',
|
|
226
|
+
message: 'Inter font detected — replace with the design-brief pairing (Manrope/Sora/Fraunces/Outfit/…).',
|
|
227
|
+
});
|
|
228
|
+
}
|
|
229
|
+
// Indigo/violet gradient walls are the strongest "AI SaaS template" signal.
|
|
230
|
+
if (/(?:from|via|to)-(?:indigo|violet|purple)-\d{2,3}|(?:bg|text|border)-(?:indigo|violet)-[56]00/i.test(markupOnly)) {
|
|
231
|
+
findings.push({
|
|
232
|
+
rule: 'ai-palette-cliche',
|
|
233
|
+
severity: 'warning',
|
|
234
|
+
message: 'Indigo/violet palette utilities detected — unless the design brief explicitly chose indigo, switch to the brief accent hex for a topic-fit look.',
|
|
235
|
+
});
|
|
236
|
+
}
|
|
237
|
+
if (/\son(?:click|change|input|submit|mouseover|keydown|load)\s*=/i.test(html)) {
|
|
238
|
+
findings.push({
|
|
239
|
+
rule: 'inline-handler',
|
|
240
|
+
severity: 'warning',
|
|
241
|
+
message: 'Inline event handler attributes found — wire behavior with addEventListener instead.',
|
|
242
|
+
});
|
|
243
|
+
}
|
|
244
|
+
if (/(?:animation|transition)\s*:/i.test(styles) && !/prefers-reduced-motion/i.test(html)) {
|
|
245
|
+
findings.push({
|
|
246
|
+
rule: 'missing-reduced-motion',
|
|
247
|
+
severity: 'warning',
|
|
248
|
+
message: 'Animations/transitions without a prefers-reduced-motion guard.',
|
|
249
|
+
});
|
|
250
|
+
}
|
|
251
|
+
if (/(?:background(?:-color)?|(?<![a-z-])color)\s*:\s*(?:#(?:fff(?:fff)?|000(?:000)?)\b|white\b|black\b)/i.test(styles)) {
|
|
252
|
+
findings.push({
|
|
253
|
+
rule: 'hard-coded-scheme-color',
|
|
254
|
+
severity: 'warning',
|
|
255
|
+
message: 'Hard-coded black/white colors break light/dark schemes — use your design-token CSS variables (with color-mix) or dark-mode variants instead.',
|
|
256
|
+
});
|
|
257
|
+
}
|
|
258
|
+
const h1Count = ((_f = html.match(/<h1[\s>]/gi)) !== null && _f !== void 0 ? _f : []).length;
|
|
259
|
+
if (h1Count === 0) {
|
|
260
|
+
findings.push({
|
|
261
|
+
rule: 'missing-h1',
|
|
262
|
+
severity: 'error',
|
|
263
|
+
message: 'Page has no <h1> — add one clear page headline.',
|
|
264
|
+
});
|
|
265
|
+
}
|
|
266
|
+
else if (h1Count > 1) {
|
|
267
|
+
findings.push({
|
|
268
|
+
rule: 'multiple-h1',
|
|
269
|
+
severity: 'warning',
|
|
270
|
+
message: `Page has ${h1Count} <h1> elements — keep one and demote the rest.`,
|
|
271
|
+
});
|
|
272
|
+
}
|
|
273
|
+
if (/href=["']#["']/.test(html)) {
|
|
274
|
+
findings.push({
|
|
275
|
+
rule: 'dead-link',
|
|
276
|
+
severity: 'warning',
|
|
277
|
+
message: 'href="#" links found — prefer real section ids, index.html, or <button> for actions.',
|
|
278
|
+
});
|
|
279
|
+
}
|
|
280
|
+
const hasVisibleInputs = /<(?:input(?![^>]*type=["']hidden)|select|textarea)[\s>]/i.test(html);
|
|
281
|
+
if (hasVisibleInputs && !/<label[\s>]/i.test(html) && !/aria-label(?:ledby)?=/i.test(html)) {
|
|
282
|
+
findings.push({
|
|
283
|
+
rule: 'unlabeled-inputs',
|
|
284
|
+
severity: 'error',
|
|
285
|
+
message: 'Form controls without any <label> or aria-label — every control needs an accessible name.',
|
|
286
|
+
});
|
|
287
|
+
}
|
|
288
|
+
return {
|
|
289
|
+
clean: findings.length === 0,
|
|
290
|
+
findings,
|
|
291
|
+
};
|
|
292
|
+
}
|
|
293
|
+
//# sourceMappingURL=artifact-quality-audit.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"artifact-quality-audit.js","sourceRoot":"","sources":["../../../src/lib/session-pages/artifact-quality-audit.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { sessionArtifactsPrefix, isSessionArtifactUserFacingKey, relativeSessionArtifactPath } from '../object-storage/keys';
|
|
1
2
|
export declare function writeArtifactLatestState(sessionId: string, artifactPath: string, state: Uint8Array): Promise<void>;
|
|
2
3
|
export declare function readArtifactLatestState(sessionId: string, artifactPath: string): Promise<Uint8Array | null>;
|
|
3
4
|
export declare function writeArtifactContentSnapshot(sessionId: string, artifactPath: string, content: string): Promise<void>;
|
|
@@ -5,4 +6,6 @@ export declare function readArtifactContentSnapshot(sessionId: string, artifactP
|
|
|
5
6
|
export declare function writeArtifactNamedSnapshot(sessionId: string, artifactPath: string, content: string, at?: Date): Promise<string>;
|
|
6
7
|
export declare function listArtifactSnapshotPaths(sessionId: string, artifactPath: string): Promise<string[]>;
|
|
7
8
|
export declare function deleteArtifactStorageFiles(sessionId: string, artifactPath: string): Promise<void>;
|
|
9
|
+
export declare function sessionArtifactExistsOnStorage(sessionId: string, artifactPath: string): Promise<boolean>;
|
|
10
|
+
export { isSessionArtifactUserFacingKey, relativeSessionArtifactPath, sessionArtifactsPrefix };
|
|
8
11
|
//# sourceMappingURL=artifact-storage.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"artifact-storage.d.ts","sourceRoot":"","sources":["../../../src/lib/session-pages/artifact-storage.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"artifact-storage.d.ts","sourceRoot":"","sources":["../../../src/lib/session-pages/artifact-storage.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,sBAAsB,EACtB,8BAA8B,EAC9B,2BAA2B,EAC5B,MAAM,wBAAwB,CAAA;AAS/B,wBAAsB,wBAAwB,CAC5C,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,UAAU,GAChB,OAAO,CAAC,IAAI,CAAC,CAGf;AAED,wBAAsB,uBAAuB,CAC3C,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC,CAG5B;AAED,wBAAsB,4BAA4B,CAChD,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,IAAI,CAAC,CAGf;AAED,wBAAsB,2BAA2B,CAC/C,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,MAAM,GAAG,IAAI,CAAC,CAGxB;AAED,wBAAsB,0BAA0B,CAC9C,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,EACpB,OAAO,EAAE,MAAM,EACf,EAAE,GAAE,IAAiB,GACpB,OAAO,CAAC,MAAM,CAAC,CAKjB;AAED,wBAAsB,yBAAyB,CAC7C,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,MAAM,EAAE,CAAC,CAQnB;AAED,wBAAsB,0BAA0B,CAC9C,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,IAAI,CAAC,CA6Bf;AAED,wBAAsB,8BAA8B,CAClD,SAAS,EAAE,MAAM,EACjB,YAAY,EAAE,MAAM,GACnB,OAAO,CAAC,OAAO,CAAC,CAUlB;AAED,OAAO,EAAE,8BAA8B,EAAE,2BAA2B,EAAE,sBAAsB,EAAE,CAAA"}
|
|
@@ -1,8 +1,39 @@
|
|
|
1
1
|
"use strict";
|
|
2
|
-
var
|
|
3
|
-
|
|
4
|
-
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
5
35
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.sessionArtifactsPrefix = exports.relativeSessionArtifactPath = exports.isSessionArtifactUserFacingKey = void 0;
|
|
6
37
|
exports.writeArtifactLatestState = writeArtifactLatestState;
|
|
7
38
|
exports.readArtifactLatestState = readArtifactLatestState;
|
|
8
39
|
exports.writeArtifactContentSnapshot = writeArtifactContentSnapshot;
|
|
@@ -10,104 +41,82 @@ exports.readArtifactContentSnapshot = readArtifactContentSnapshot;
|
|
|
10
41
|
exports.writeArtifactNamedSnapshot = writeArtifactNamedSnapshot;
|
|
11
42
|
exports.listArtifactSnapshotPaths = listArtifactSnapshotPaths;
|
|
12
43
|
exports.deleteArtifactStorageFiles = deleteArtifactStorageFiles;
|
|
13
|
-
|
|
14
|
-
const
|
|
44
|
+
exports.sessionArtifactExistsOnStorage = sessionArtifactExistsOnStorage;
|
|
45
|
+
const keys_1 = require("../object-storage/keys");
|
|
46
|
+
Object.defineProperty(exports, "sessionArtifactsPrefix", { enumerable: true, get: function () { return keys_1.sessionArtifactsPrefix; } });
|
|
47
|
+
Object.defineProperty(exports, "isSessionArtifactUserFacingKey", { enumerable: true, get: function () { return keys_1.isSessionArtifactUserFacingKey; } });
|
|
48
|
+
Object.defineProperty(exports, "relativeSessionArtifactPath", { enumerable: true, get: function () { return keys_1.relativeSessionArtifactPath; } });
|
|
49
|
+
const s3 = __importStar(require("../object-storage/s3-object-store"));
|
|
50
|
+
const context_1 = require("../../context");
|
|
51
|
+
const session_artifact_document_id_1 = require("../../realtime/session-artifact-document-id");
|
|
52
|
+
const flush_lock_1 = require("../yjs-pending/flush-lock");
|
|
15
53
|
const artifact_storage_paths_1 = require("./artifact-storage-paths");
|
|
16
54
|
const paths_1 = require("./paths");
|
|
55
|
+
const resolve_session_account_id_1 = require("./resolve-session-account-id");
|
|
17
56
|
async function writeArtifactLatestState(sessionId, artifactPath, state) {
|
|
18
|
-
const
|
|
19
|
-
|
|
20
|
-
await promises_1.default.mkdir(node_path_1.default.dirname(absolutePath), { recursive: true });
|
|
21
|
-
await promises_1.default.writeFile(absolutePath, Buffer.from(state));
|
|
57
|
+
const accountId = await (0, resolve_session_account_id_1.resolveSessionAccountId)(sessionId);
|
|
58
|
+
await s3.putBytes((0, keys_1.sessionArtifactLatestStateKey)(accountId, sessionId, artifactPath), state);
|
|
22
59
|
}
|
|
23
60
|
async function readArtifactLatestState(sessionId, artifactPath) {
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
const data = await promises_1.default.readFile(absolutePath);
|
|
27
|
-
return new Uint8Array(data);
|
|
28
|
-
}
|
|
29
|
-
catch (error) {
|
|
30
|
-
if (error.code === 'ENOENT') {
|
|
31
|
-
return null;
|
|
32
|
-
}
|
|
33
|
-
throw error;
|
|
34
|
-
}
|
|
61
|
+
const accountId = await (0, resolve_session_account_id_1.resolveSessionAccountId)(sessionId);
|
|
62
|
+
return s3.getBytes((0, keys_1.sessionArtifactLatestStateKey)(accountId, sessionId, artifactPath));
|
|
35
63
|
}
|
|
36
64
|
async function writeArtifactContentSnapshot(sessionId, artifactPath, content) {
|
|
37
|
-
const
|
|
38
|
-
await
|
|
39
|
-
await promises_1.default.writeFile(absolutePath, content, 'utf8');
|
|
65
|
+
const accountId = await (0, resolve_session_account_id_1.resolveSessionAccountId)(sessionId);
|
|
66
|
+
await s3.putString((0, keys_1.sessionArtifactContentKey)(accountId, sessionId, artifactPath), content);
|
|
40
67
|
}
|
|
41
68
|
async function readArtifactContentSnapshot(sessionId, artifactPath) {
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
return await promises_1.default.readFile(absolutePath, 'utf8');
|
|
45
|
-
}
|
|
46
|
-
catch (error) {
|
|
47
|
-
if (error.code === 'ENOENT') {
|
|
48
|
-
return null;
|
|
49
|
-
}
|
|
50
|
-
throw error;
|
|
51
|
-
}
|
|
69
|
+
const accountId = await (0, resolve_session_account_id_1.resolveSessionAccountId)(sessionId);
|
|
70
|
+
return s3.getString((0, keys_1.sessionArtifactContentKey)(accountId, sessionId, artifactPath));
|
|
52
71
|
}
|
|
53
72
|
async function writeArtifactNamedSnapshot(sessionId, artifactPath, content, at = new Date()) {
|
|
54
|
-
const
|
|
55
|
-
const
|
|
56
|
-
await
|
|
57
|
-
|
|
58
|
-
return relativePath;
|
|
59
|
-
}
|
|
60
|
-
async function walkFiles(dir, root, onFile) {
|
|
61
|
-
let entries;
|
|
62
|
-
try {
|
|
63
|
-
entries = await promises_1.default.readdir(dir, { withFileTypes: true });
|
|
64
|
-
}
|
|
65
|
-
catch (error) {
|
|
66
|
-
if (error.code === 'ENOENT') {
|
|
67
|
-
return;
|
|
68
|
-
}
|
|
69
|
-
throw error;
|
|
70
|
-
}
|
|
71
|
-
for (const entry of entries) {
|
|
72
|
-
const absolute = node_path_1.default.join(dir, entry.name);
|
|
73
|
-
if (entry.isDirectory()) {
|
|
74
|
-
await walkFiles(absolute, root, onFile);
|
|
75
|
-
continue;
|
|
76
|
-
}
|
|
77
|
-
if (!entry.isFile()) {
|
|
78
|
-
continue;
|
|
79
|
-
}
|
|
80
|
-
const relative = node_path_1.default.relative(root, absolute).split(node_path_1.default.sep).join('/');
|
|
81
|
-
await onFile(relative);
|
|
82
|
-
}
|
|
73
|
+
const accountId = await (0, resolve_session_account_id_1.resolveSessionAccountId)(sessionId);
|
|
74
|
+
const key = (0, keys_1.sessionArtifactNamedSnapshotKey)(accountId, sessionId, artifactPath, at);
|
|
75
|
+
await s3.putString(key, content);
|
|
76
|
+
return key;
|
|
83
77
|
}
|
|
84
78
|
async function listArtifactSnapshotPaths(sessionId, artifactPath) {
|
|
85
|
-
const
|
|
79
|
+
const accountId = await (0, resolve_session_account_id_1.resolveSessionAccountId)(sessionId);
|
|
80
|
+
const prefix = (0, keys_1.sessionArtifactsPrefix)(accountId, sessionId);
|
|
86
81
|
const normalized = (0, paths_1.normalizeArtifactPath)(artifactPath);
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
}
|
|
92
|
-
});
|
|
93
|
-
return snapshots.sort((a, b) => a.localeCompare(b));
|
|
82
|
+
return (await s3.listKeysByPrefix(prefix))
|
|
83
|
+
.map((o) => (0, keys_1.relativeSessionArtifactPath)(prefix, o.key))
|
|
84
|
+
.filter((relative) => (0, artifact_storage_paths_1.isSnapshotForArtifact)(relative, normalized))
|
|
85
|
+
.sort();
|
|
94
86
|
}
|
|
95
87
|
async function deleteArtifactStorageFiles(sessionId, artifactPath) {
|
|
88
|
+
const accountId = await (0, resolve_session_account_id_1.resolveSessionAccountId)(sessionId);
|
|
89
|
+
const normalized = (0, paths_1.normalizeArtifactPath)(artifactPath);
|
|
90
|
+
const documentId = (0, session_artifact_document_id_1.buildSessionArtifactDocumentId)(sessionId, normalized);
|
|
91
|
+
const prefix = (0, keys_1.sessionArtifactsPrefix)(accountId, sessionId);
|
|
92
|
+
const objects = await s3.listKeysByPrefix(prefix);
|
|
93
|
+
const run = async () => {
|
|
94
|
+
await (0, context_1.getYjsPendingUpdatesRepository)().deleteByDocumentId(documentId);
|
|
95
|
+
await Promise.all(objects
|
|
96
|
+
.filter((o) => {
|
|
97
|
+
const relative = (0, keys_1.relativeSessionArtifactPath)(prefix, o.key);
|
|
98
|
+
return (relative === normalized ||
|
|
99
|
+
relative === `${normalized}.latest.state` ||
|
|
100
|
+
(0, artifact_storage_paths_1.isSnapshotForArtifact)(relative, normalized));
|
|
101
|
+
})
|
|
102
|
+
.map((o) => s3.deleteObject(o.key)));
|
|
103
|
+
};
|
|
104
|
+
const redis = (0, context_1.getSharedRedisClient)();
|
|
105
|
+
if (redis) {
|
|
106
|
+
await (0, flush_lock_1.withFlushLock)(redis, documentId, run);
|
|
107
|
+
return;
|
|
108
|
+
}
|
|
109
|
+
await run();
|
|
110
|
+
}
|
|
111
|
+
async function sessionArtifactExistsOnStorage(sessionId, artifactPath) {
|
|
112
|
+
const accountId = await (0, resolve_session_account_id_1.resolveSessionAccountId)(sessionId);
|
|
96
113
|
const normalized = (0, paths_1.normalizeArtifactPath)(artifactPath);
|
|
97
|
-
const
|
|
98
|
-
|
|
99
|
-
(0,
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
await promises_1.default.unlink(absolutePath);
|
|
105
|
-
}
|
|
106
|
-
catch (error) {
|
|
107
|
-
if (error.code !== 'ENOENT') {
|
|
108
|
-
throw error;
|
|
109
|
-
}
|
|
110
|
-
}
|
|
111
|
-
}));
|
|
114
|
+
const documentId = (0, session_artifact_document_id_1.buildSessionArtifactDocumentId)(sessionId, normalized);
|
|
115
|
+
const [content, latest, pendingCount] = await Promise.all([
|
|
116
|
+
s3.objectExists((0, keys_1.sessionArtifactContentKey)(accountId, sessionId, normalized)),
|
|
117
|
+
s3.objectExists((0, keys_1.sessionArtifactLatestStateKey)(accountId, sessionId, normalized)),
|
|
118
|
+
(0, context_1.getYjsPendingUpdatesRepository)().countByDocumentId(documentId),
|
|
119
|
+
]);
|
|
120
|
+
return content || latest || pendingCount > 0;
|
|
112
121
|
}
|
|
113
122
|
//# sourceMappingURL=artifact-storage.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"artifact-storage.js","sourceRoot":"","sources":["../../../src/lib/session-pages/artifact-storage.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"artifact-storage.js","sourceRoot":"","sources":["../../../src/lib/session-pages/artifact-storage.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { type QualityFinding } from './artifact-quality-audit';
|
|
2
|
+
export interface SessionQualityIssue {
|
|
3
|
+
path: string;
|
|
4
|
+
findings: QualityFinding[];
|
|
5
|
+
}
|
|
6
|
+
export interface SessionQualityReport {
|
|
7
|
+
issues: SessionQualityIssue[];
|
|
8
|
+
/** Actionable findings only (excludes deferred heuristics like contrast). */
|
|
9
|
+
actionableIssues: SessionQualityIssue[];
|
|
10
|
+
/** Flat lines suitable for plan.openAdvisories / tool output (actionable only). */
|
|
11
|
+
advisoryLines: string[];
|
|
12
|
+
errorCount: number;
|
|
13
|
+
warningCount: number;
|
|
14
|
+
deferredWarningCount: number;
|
|
15
|
+
}
|
|
16
|
+
/**
|
|
17
|
+
* Re-audit every HTML artifact in the session. Used by the consistency pass
|
|
18
|
+
* to prove polish work actually cleared quality findings.
|
|
19
|
+
*/
|
|
20
|
+
export declare function auditSessionHtmlArtifacts(sessionId: string): Promise<SessionQualityReport>;
|
|
21
|
+
/** Compact path → finding lines for openAdvisories storage (actionable only). */
|
|
22
|
+
export declare function sessionQualityToAdvisoryLines(report: SessionQualityReport): string[];
|
|
23
|
+
//# sourceMappingURL=audit-session-html.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"audit-session-html.d.ts","sourceRoot":"","sources":["../../../src/lib/session-pages/audit-session-html.ts"],"names":[],"mappings":"AAAA,OAAO,EAAqB,KAAK,cAAc,EAAE,MAAM,0BAA0B,CAAA;AAKjF,MAAM,WAAW,mBAAmB;IAClC,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,cAAc,EAAE,CAAA;CAC3B;AAED,MAAM,WAAW,oBAAoB;IACnC,MAAM,EAAE,mBAAmB,EAAE,CAAA;IAC7B,6EAA6E;IAC7E,gBAAgB,EAAE,mBAAmB,EAAE,CAAA;IACvC,mFAAmF;IACnF,aAAa,EAAE,MAAM,EAAE,CAAA;IACvB,UAAU,EAAE,MAAM,CAAA;IAClB,YAAY,EAAE,MAAM,CAAA;IACpB,oBAAoB,EAAE,MAAM,CAAA;CAC7B;AAED;;;GAGG;AACH,wBAAsB,yBAAyB,CAAC,SAAS,EAAE,MAAM,GAAG,OAAO,CAAC,oBAAoB,CAAC,CAuEhG;AAED,iFAAiF;AACjF,wBAAgB,6BAA6B,CAAC,MAAM,EAAE,oBAAoB,GAAG,MAAM,EAAE,CAIpF"}
|