@monoes/monodesign 1.2.18 → 1.2.22

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 (104) hide show
  1. package/README.md +3 -3
  2. package/cli/engine/design-system-checks.mjs +381 -0
  3. package/cli/engine/design-system-parse.mjs +433 -0
  4. package/cli/engine/design-system.mjs +20 -736
  5. package/cli/engine/detect-antipatterns-browser.js +12 -1
  6. package/cli/engine/engines/regex/detect-text-matchers.mjs +371 -0
  7. package/cli/engine/engines/regex/detect-text-run.mjs +186 -0
  8. package/cli/engine/engines/regex/detect-text.mjs +11 -523
  9. package/cli/engine/engines/static-html/css-cascade-color.mjs +219 -0
  10. package/cli/engine/engines/static-html/css-cascade-static-data.mjs +138 -0
  11. package/cli/engine/engines/static-html/css-cascade-static-dom.mjs +132 -0
  12. package/cli/engine/engines/static-html/css-cascade-static-parse.mjs +393 -0
  13. package/cli/engine/engines/static-html/css-cascade.mjs +24 -837
  14. package/cli/engine/registry/antipatterns-provider.mjs +60 -0
  15. package/cli/engine/registry/antipatterns-quality.mjs +218 -0
  16. package/cli/engine/registry/antipatterns-slop.mjs +226 -0
  17. package/cli/engine/registry/antipatterns.mjs +7 -494
  18. package/cli/engine/rules/checks-background.mjs +155 -0
  19. package/cli/engine/rules/checks-css-values.mjs +137 -0
  20. package/cli/engine/rules/checks-dom-effects.mjs +243 -0
  21. package/cli/engine/rules/checks-dom.mjs +148 -0
  22. package/cli/engine/rules/checks-element.mjs +286 -0
  23. package/cli/engine/rules/checks-html.mjs +204 -0
  24. package/cli/engine/rules/checks-overflow.mjs +263 -0
  25. package/cli/engine/rules/checks-page.mjs +465 -0
  26. package/cli/engine/rules/checks-pure.mjs +453 -0
  27. package/cli/engine/rules/checks-quality.mjs +447 -0
  28. package/cli/engine/rules/checks-stylesheet.mjs +324 -0
  29. package/cli/engine/rules/checks.mjs +98 -2939
  30. package/cli/lib/monodesign-config-consent.mjs +93 -0
  31. package/cli/lib/monodesign-config-core.mjs +37 -0
  32. package/cli/lib/monodesign-config-detection.mjs +133 -0
  33. package/cli/lib/monodesign-config-filter.mjs +198 -0
  34. package/cli/lib/monodesign-config-ignore-value.mjs +212 -0
  35. package/cli/lib/monodesign-config.mjs +21 -623
  36. package/package.json +2 -2
  37. package/skill/scripts/context-fields.mjs +65 -0
  38. package/skill/scripts/context-resolve.mjs +425 -0
  39. package/skill/scripts/context-update.mjs +151 -0
  40. package/skill/scripts/context-utils.mjs +68 -0
  41. package/skill/scripts/context-workspace.mjs +245 -0
  42. package/skill/scripts/context.mjs +17 -891
  43. package/skill/scripts/hook-admin-config.mjs +152 -0
  44. package/skill/scripts/hook-admin-ignore.mjs +131 -0
  45. package/skill/scripts/hook-admin-manifest.mjs +292 -0
  46. package/skill/scripts/hook-admin.mjs +8 -541
  47. package/skill/scripts/hook-before-edit-shell.mjs +184 -0
  48. package/skill/scripts/hook-before-edit.mjs +9 -165
  49. package/skill/scripts/hook-lib-cache.mjs +145 -0
  50. package/skill/scripts/hook-lib-config.mjs +292 -0
  51. package/skill/scripts/hook-lib-detector.mjs +72 -0
  52. package/skill/scripts/hook-lib-events.mjs +182 -0
  53. package/skill/scripts/hook-lib-findings.mjs +201 -0
  54. package/skill/scripts/hook-lib-ignore.mjs +205 -0
  55. package/skill/scripts/hook-lib-render.mjs +273 -0
  56. package/skill/scripts/hook-lib-run.mjs +281 -0
  57. package/skill/scripts/hook-lib-scan-targets.mjs +128 -0
  58. package/skill/scripts/hook-lib.mjs +71 -1747
  59. package/skill/scripts/lib/design-parser-colors.mjs +182 -0
  60. package/skill/scripts/lib/design-parser-extract.mjs +333 -0
  61. package/skill/scripts/lib/design-parser-sections.mjs +214 -0
  62. package/skill/scripts/lib/design-parser-yaml.mjs +135 -0
  63. package/skill/scripts/lib/design-parser.mjs +10 -783
  64. package/skill/scripts/live/manual-apply-chunk.mjs +151 -0
  65. package/skill/scripts/live/manual-apply-compact.mjs +122 -0
  66. package/skill/scripts/live/manual-apply-evidence.mjs +115 -0
  67. package/skill/scripts/live/manual-apply-log.mjs +179 -0
  68. package/skill/scripts/live/manual-apply-transaction.mjs +122 -0
  69. package/skill/scripts/live/manual-apply.mjs +65 -640
  70. package/skill/scripts/live/svelte-component-accept.mjs +248 -0
  71. package/skill/scripts/live/svelte-component-css.mjs +230 -0
  72. package/skill/scripts/live/svelte-component-markup.mjs +104 -0
  73. package/skill/scripts/live/svelte-component-scaffold.mjs +118 -0
  74. package/skill/scripts/live/svelte-component-session.mjs +158 -0
  75. package/skill/scripts/live/svelte-component.mjs +32 -792
  76. package/skill/scripts/live-accept-mutate.mjs +152 -0
  77. package/skill/scripts/live-accept-parse.mjs +370 -0
  78. package/skill/scripts/live-accept-scrub.mjs +59 -0
  79. package/skill/scripts/live-accept-search.mjs +58 -0
  80. package/skill/scripts/live-accept.mjs +15 -631
  81. package/skill/scripts/live-commit-manual-edits-paths.mjs +27 -0
  82. package/skill/scripts/live-commit-manual-edits-repair.mjs +166 -0
  83. package/skill/scripts/live-commit-manual-edits-rollback.mjs +231 -0
  84. package/skill/scripts/live-commit-manual-edits-utils.mjs +167 -0
  85. package/skill/scripts/live-commit-manual-edits-verify.mjs +356 -0
  86. package/skill/scripts/live-commit-manual-edits.mjs +24 -881
  87. package/skill/scripts/live-copy-edit-agent.mjs +16 -551
  88. package/skill/scripts/live-copy-edit-compact.mjs +137 -0
  89. package/skill/scripts/live-copy-edit-post-apply.mjs +175 -0
  90. package/skill/scripts/live-copy-edit-runners.mjs +297 -0
  91. package/skill/scripts/live-inject-csp.mjs +132 -0
  92. package/skill/scripts/live-inject-files.mjs +229 -0
  93. package/skill/scripts/live-inject-tag.mjs +114 -0
  94. package/skill/scripts/live-inject.mjs +13 -440
  95. package/skill/scripts/live-server-poll.mjs +232 -0
  96. package/skill/scripts/live-server-routes.mjs +449 -0
  97. package/skill/scripts/live-server-state.mjs +361 -0
  98. package/skill/scripts/live-server.mjs +10 -946
  99. package/skill/scripts/live-wrap-css.mjs +132 -0
  100. package/skill/scripts/live-wrap-manual-edit.mjs +153 -0
  101. package/skill/scripts/live-wrap-search.mjs +247 -0
  102. package/skill/scripts/live-wrap.mjs +21 -484
  103. package/skill/scripts/palette-seeds.mjs +401 -0
  104. package/skill/scripts/palette.mjs +1 -395
@@ -0,0 +1,214 @@
1
+ // DESIGN.md body splitting: canonical H2 sections, subsections, paragraphs
2
+ // and bullets. Split out of design-parser.mjs (file-size sweep — pure move,
3
+ // no behaviour change).
4
+
5
+ import { CANONICAL_SECTIONS } from './design-parser-yaml.mjs';
6
+
7
+ const HEX_RE = /#[0-9a-fA-F]{3,8}\b/g;
8
+ const OKLCH_RE = /oklch\([^)]+\)/gi;
9
+
10
+ // ---------- Section splitting ----------
11
+
12
+ function splitSections(md) {
13
+ const lines = md.split(/\r?\n/);
14
+ let title = null;
15
+ const sections = {};
16
+ let current = null;
17
+
18
+ for (const raw of lines) {
19
+ const line = raw.trimEnd();
20
+
21
+ if (!title && line.startsWith('# ') && !line.startsWith('## ')) {
22
+ title = line.replace(/^#\s+/, '').trim();
23
+ continue;
24
+ }
25
+
26
+ const h2 = line.match(/^##\s+(?:\d+\.\s*)?([^:\n]+?)(?::\s*(.+))?$/);
27
+ if (h2) {
28
+ const rawName = normalizeApostrophes(h2[1].trim());
29
+ const subtitle = h2[2] ? h2[2].trim() : null;
30
+ const canonical = matchCanonicalSection(rawName);
31
+ if (canonical) {
32
+ current = { name: canonical, subtitle, lines: [] };
33
+ sections[canonical] = current;
34
+ continue;
35
+ }
36
+ // non-canonical H2 — ignore but stop feeding into current
37
+ current = null;
38
+ continue;
39
+ }
40
+
41
+ if (current) current.lines.push(raw);
42
+ }
43
+
44
+ return { title, sections };
45
+ }
46
+
47
+ function normalizeApostrophes(s) {
48
+ return s.replace(/[\u2018\u2019]/g, "'");
49
+ }
50
+
51
+ function matchCanonicalSection(name) {
52
+ const normalized = normalizeApostrophes(name).toLowerCase();
53
+ // Exact match first
54
+ for (const c of CANONICAL_SECTIONS) {
55
+ if (normalizeApostrophes(c).toLowerCase() === normalized) return c;
56
+ }
57
+ // Keyword-contained match: "Overview & Creative North Star" -> "Overview",
58
+ // "Elevation & Depth" -> "Elevation", etc.
59
+ for (const c of CANONICAL_SECTIONS) {
60
+ const key = normalizeApostrophes(c).toLowerCase();
61
+ const pattern = new RegExp(`\\b${key.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')}\\b`);
62
+ if (pattern.test(normalized)) return c;
63
+ }
64
+ return null;
65
+ }
66
+
67
+ // ---------- Subsection splitting (inside a canonical section) ----------
68
+
69
+ function splitSubsections(lines) {
70
+ const subs = [];
71
+ let current = { name: null, lines: [] };
72
+ subs.push(current);
73
+
74
+ for (const raw of lines) {
75
+ const h3 = raw.match(/^###\s+(.+?)\s*$/);
76
+ if (h3) {
77
+ current = { name: h3[1].trim(), lines: [] };
78
+ subs.push(current);
79
+ continue;
80
+ }
81
+ current.lines.push(raw);
82
+ }
83
+
84
+ return subs;
85
+ }
86
+
87
+ // ---------- Generic helpers ----------
88
+
89
+ function collectParagraphs(lines) {
90
+ const paragraphs = [];
91
+ let buf = [];
92
+ const flush = () => {
93
+ if (buf.length) {
94
+ paragraphs.push(buf.join(' ').trim());
95
+ buf = [];
96
+ }
97
+ };
98
+ for (const raw of lines) {
99
+ const trimmed = raw.trim();
100
+ if (trimmed === '') { flush(); continue; }
101
+ // Horizontal rules (---, ***) and headings/bullets end a paragraph.
102
+ if (/^(?:-{3,}|\*{3,}|_{3,})$/.test(trimmed)) { flush(); continue; }
103
+ if (raw.startsWith('#') || raw.match(/^[-*]\s/)) { flush(); continue; }
104
+ buf.push(trimmed);
105
+ }
106
+ flush();
107
+ return paragraphs.filter(Boolean);
108
+ }
109
+
110
+ function collectBullets(lines) {
111
+ const bullets = [];
112
+ let current = null;
113
+ for (const raw of lines) {
114
+ const m = raw.match(/^\s*[-*]\s+(.+)$/);
115
+ if (m) {
116
+ if (current) bullets.push(current);
117
+ current = m[1];
118
+ continue;
119
+ }
120
+ // continuation of a bullet (indented line)
121
+ if (current && raw.match(/^\s{2,}\S/)) {
122
+ current += ` ${raw.trim()}`;
123
+ continue;
124
+ }
125
+ // blank line ends a bullet
126
+ if (raw.trim() === '' && current) {
127
+ bullets.push(current);
128
+ current = null;
129
+ }
130
+ }
131
+ if (current) bullets.push(current);
132
+ return bullets;
133
+ }
134
+
135
+ function stripBold(s) {
136
+ return s.replace(/\*\*(.+?)\*\*/g, '$1');
137
+ }
138
+
139
+ function extractNamedRules(lines) {
140
+ const rules = [];
141
+ const seen = new Set();
142
+
143
+ // Style A (Monodesign): "**The X Rule.** body body body" — can span lines.
144
+ const joined = lines.join('\n');
145
+ const inlineStart = /\*\*(The [^*]+?Rule)\.\*\*/g;
146
+ const inlineMatches = [];
147
+ let m;
148
+ while ((m = inlineStart.exec(joined)) !== null) {
149
+ inlineMatches.push({ name: m[1], start: m.index, end: inlineStart.lastIndex });
150
+ }
151
+ for (let i = 0; i < inlineMatches.length; i++) {
152
+ const mm = inlineMatches[i];
153
+ const bodyEnd = i + 1 < inlineMatches.length ? inlineMatches[i + 1].start : joined.length;
154
+ const body = joined
155
+ .slice(mm.end, bodyEnd)
156
+ .replace(/\n##[^\n]*$/s, '')
157
+ .replace(/\n###[^\n]*$/s, '')
158
+ .trim();
159
+ const name = stripBold(mm.name).trim();
160
+ seen.add(name.toLowerCase());
161
+ rules.push({ name, body: stripBold(body) });
162
+ }
163
+
164
+ // Style B (Stitch): `### The "X" Rule` or `### The X Fallback`, body is the
165
+ // bullets/paragraphs until the next heading. Accept Rule / Fallback / Principle.
166
+ for (let i = 0; i < lines.length; i++) {
167
+ const h3 = lines[i].match(/^###\s+(.+?)\s*$/);
168
+ if (!h3) continue;
169
+ const headerName = stripBold(h3[1]).replace(/["“”]/g, '').trim();
170
+ if (!/^The\b.*\b(Rule|Fallback|Principle)\b/i.test(headerName)) continue;
171
+ if (seen.has(headerName.toLowerCase())) continue;
172
+
173
+ const bodyLines = [];
174
+ for (let j = i + 1; j < lines.length; j++) {
175
+ if (/^##\s|^###\s/.test(lines[j])) break;
176
+ bodyLines.push(lines[j]);
177
+ }
178
+ const body = stripBold(bodyLines.join('\n').replace(/\n+/g, ' ')).trim();
179
+ if (body) {
180
+ seen.add(headerName.toLowerCase());
181
+ rules.push({ name: headerName, body });
182
+ }
183
+ }
184
+
185
+ // Style C (Stitch bullet form): "* **The Layering Principle:** body"
186
+ // Colon/period lives inside the bold, so match "**...**" then inspect.
187
+ for (const b of collectBullets(lines)) {
188
+ const mm = b.match(/^\*\*([^*]+?)\*\*\s*(.+)$/);
189
+ if (!mm) continue;
190
+ const nameRaw = mm[1].replace(/[.:]\s*$/, '').replace(/["“”]/g, '').trim();
191
+ if (!/^The\b.+\b(Rule|Fallback|Principle)$/i.test(nameRaw)) continue;
192
+ if (seen.has(nameRaw.toLowerCase())) continue;
193
+ seen.add(nameRaw.toLowerCase());
194
+ rules.push({ name: nameRaw, body: stripBold(mm[2]).trim() });
195
+ }
196
+
197
+ return rules;
198
+ }
199
+
200
+ // ---------- Per-section extractors ----------
201
+
202
+
203
+ export {
204
+ HEX_RE,
205
+ OKLCH_RE,
206
+ splitSections,
207
+ normalizeApostrophes,
208
+ matchCanonicalSection,
209
+ splitSubsections,
210
+ collectParagraphs,
211
+ collectBullets,
212
+ stripBold,
213
+ extractNamedRules,
214
+ };
@@ -0,0 +1,135 @@
1
+ // DESIGN.md frontmatter (Stitch YAML subset) parsing. Split out of
2
+ // design-parser.mjs (file-size sweep — pure move, no behaviour change).
3
+
4
+ const CANONICAL_SECTIONS = [
5
+ 'Overview',
6
+ 'Colors',
7
+ 'Typography',
8
+ 'Elevation',
9
+ 'Components',
10
+ "Do's and Don'ts",
11
+ ];
12
+
13
+ // ---------- Frontmatter (Stitch YAML subset) ----------
14
+
15
+ function parseFrontmatter(md) {
16
+ const lines = md.split(/\r?\n/);
17
+ if (lines[0]?.trim() !== '---') return { frontmatter: null, body: md };
18
+
19
+ let end = -1;
20
+ for (let i = 1; i < lines.length; i++) {
21
+ if (lines[i].trim() === '---') { end = i; break; }
22
+ }
23
+ if (end === -1) return { frontmatter: null, body: md };
24
+
25
+ const yaml = lines.slice(1, end).join('\n');
26
+ const body = lines.slice(end + 1).join('\n');
27
+ try {
28
+ return { frontmatter: parseYamlSubset(yaml), body };
29
+ } catch {
30
+ return { frontmatter: null, body: md };
31
+ }
32
+ }
33
+
34
+ // Minimal YAML reader for the Stitch frontmatter subset: scalar maps with
35
+ // one level of nested objects (typography roles, components). Indent-based,
36
+ // 2-space convention. No arrays, no anchors, no multi-line scalars — Stitch's
37
+ // schema doesn't need them and accepting them would require a real YAML
38
+ // dependency we don't want to vendor.
39
+ function parseYamlSubset(yaml) {
40
+ const lines = yaml.split(/\r?\n/);
41
+ const root = {};
42
+ const stack = [{ indent: -1, obj: root }];
43
+
44
+ for (const raw of lines) {
45
+ // Skip blanks and line-only comments. Don't strip inline comments:
46
+ // unquoted hex values start with `#` and can't be safely distinguished
47
+ // from a comment after whitespace.
48
+ if (!raw.trim() || /^\s*#/.test(raw)) continue;
49
+
50
+ const indent = raw.match(/^\s*/)[0].length;
51
+ const content = raw.slice(indent);
52
+
53
+ const colonIdx = findTopLevelColon(content);
54
+ if (colonIdx === -1) continue;
55
+
56
+ while (stack.length > 1 && stack[stack.length - 1].indent >= indent) {
57
+ stack.pop();
58
+ }
59
+
60
+ const key = unquoteYamlKey(content.slice(0, colonIdx).trim());
61
+ const rest = stripInlineYamlComment(content.slice(colonIdx + 1).trim());
62
+ const parent = stack[stack.length - 1].obj;
63
+
64
+ if (rest === '') {
65
+ const obj = {};
66
+ parent[key] = obj;
67
+ stack.push({ indent, obj });
68
+ } else {
69
+ parent[key] = parseScalar(rest);
70
+ }
71
+ }
72
+
73
+ return root;
74
+ }
75
+
76
+ function findTopLevelColon(s) {
77
+ let inQuote = null;
78
+ for (let i = 0; i < s.length; i++) {
79
+ const ch = s[i];
80
+ if (inQuote) {
81
+ if (ch === inQuote && s[i - 1] !== '\\') inQuote = null;
82
+ } else if (ch === '"' || ch === "'") {
83
+ inQuote = ch;
84
+ } else if (ch === ':') {
85
+ return i;
86
+ }
87
+ }
88
+ return -1;
89
+ }
90
+
91
+ function unquoteYamlKey(key) {
92
+ if ((key.startsWith('"') && key.endsWith('"')) || (key.startsWith("'") && key.endsWith("'"))) {
93
+ return key.slice(1, -1);
94
+ }
95
+ return key;
96
+ }
97
+
98
+ function stripInlineYamlComment(s) {
99
+ let inQuote = null;
100
+ for (let i = 0; i < s.length; i++) {
101
+ const ch = s[i];
102
+ if (inQuote) {
103
+ if (ch === inQuote && s[i - 1] !== '\\') inQuote = null;
104
+ } else if (ch === '"' || ch === "'") {
105
+ inQuote = ch;
106
+ } else if (ch === '#' && i > 0 && /\s/.test(s[i - 1])) {
107
+ return s.slice(0, i).trimEnd();
108
+ }
109
+ }
110
+ return s;
111
+ }
112
+
113
+ function parseScalar(raw) {
114
+ const s = raw.trim();
115
+ if ((s.startsWith('"') && s.endsWith('"')) || (s.startsWith("'") && s.endsWith("'"))) {
116
+ return s.slice(1, -1);
117
+ }
118
+ if (s === 'true') return true;
119
+ if (s === 'false') return false;
120
+ if (s === 'null' || s === '~') return null;
121
+ if (/^-?\d+$/.test(s)) return Number(s);
122
+ if (/^-?\d*\.\d+$/.test(s)) return Number(s);
123
+ return s;
124
+ }
125
+
126
+
127
+ export {
128
+ CANONICAL_SECTIONS,
129
+ parseFrontmatter,
130
+ parseYamlSubset,
131
+ findTopLevelColon,
132
+ unquoteYamlKey,
133
+ stripInlineYamlComment,
134
+ parseScalar,
135
+ };