monomind 2.5.2 → 2.5.4
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/README.md +1 -1
- package/package.json +1 -1
- package/packages/@monomind/cli/.claude/agents/github/repo-architect.md +3 -3
- package/packages/@monomind/cli/.claude/agents/github/sync-coordinator.md +2 -2
- package/packages/@monomind/cli/.claude/agents/specialists/integration-architect.md +4 -4
- package/packages/@monomind/cli/.claude/commands/github/repo-architect.md +4 -4
- package/packages/@monomind/cli/.claude/commands/github/sync-coordinator.md +2 -2
- package/packages/@monomind/cli/.claude/helpers/event-logger.cjs +2 -2
- package/packages/@monomind/cli/.claude/helpers/extras-registry.json +1 -1
- package/packages/@monomind/cli/.claude/helpers/handlers/agent-start-handler.cjs +2 -2
- package/packages/@monomind/cli/.claude/helpers/handlers/edit-handler.cjs +2 -2
- package/packages/@monomind/cli/.claude/helpers/handlers/gates-handler.cjs +6 -1
- package/packages/@monomind/cli/.claude/helpers/handlers/route-handler.cjs +1 -1
- package/packages/@monomind/cli/.claude/helpers/handlers/session-handler.cjs +1 -1
- package/packages/@monomind/cli/.claude/helpers/handlers/session-restore-handler.cjs +11 -11
- package/packages/@monomind/cli/.claude/helpers/handlers/task-handler.cjs +2 -2
- package/packages/@monomind/cli/.claude/helpers/hook-handler.cjs +8 -8
- package/packages/@monomind/cli/.claude/skills/mastermind-techport/SKILL.md +1 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/SKILL.md +2 -2
- package/packages/@monomind/cli/.claude/skills/monodesign/reference/antipatterns-catalog.md +47 -2
- package/packages/@monomind/cli/.claude/skills/monodesign/reference/critique.md +1 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/reference/live.md +0 -8
- package/packages/@monomind/cli/.claude/skills/monodesign/reference/polish.md +2 -2
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/context-signals.mjs +39 -6
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/context.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/critique-storage.mjs +175 -2
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/detect-csp.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/detect.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/detector/browser/injected/index.mjs +25 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/detector/cli/main.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/detector/design-system.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/detector/detect-antipatterns-browser.js +356 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/detector/detect-antipatterns.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/detector/engines/browser/detect-url.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/detector/engines/browser/drivers.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/detector/engines/regex/detect-text.mjs +63 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/detector/engines/static-html/css-cascade.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/detector/engines/static-html/detect-html.mjs +19 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/detector/engines/visual/screenshot-contrast.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/detector/findings.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/detector/fix/css-regions.mjs +181 -0
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/detector/fix/fixers.mjs +373 -0
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/detector/fix/index.mjs +426 -0
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/detector/node/file-system.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/detector/profile/profiler.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/detector/registry/antipatterns.mjs +49 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/detector/rules/checks.mjs +292 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/detector/shared/color.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/detector/shared/constants.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/detector/shared/fonts.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/detector/shared/inline-ignores.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/detector/shared/page.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/hook-admin.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/hook-before-edit.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/hook-lib.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/hook.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/lib/design-parser.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/lib/is-generated.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/lib/monodesign-config.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/lib/monodesign-paths.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/lib/provider.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/lib/target-args.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live/browser-script-parts.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live/completion.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live/event-validation.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live/insert-ui.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live/manual-apply.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live/manual-edit-routes.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live/manual-edits-buffer.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live/session-store.mjs +5 -2
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live/svelte-component.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live/sveltekit-adapter.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live/ui-core.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live/vocabulary.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live-accept.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live-browser-dom.js +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live-browser-session.js +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live-browser.js +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live-commit-manual-edits.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live-complete.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live-copy-edit-agent.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live-discard-manual-edits.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live-inject.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live-insert.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live-manual-edit-evidence.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live-poll.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live-resume.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live-server.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live-status.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live-target.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live-wrap.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/live.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/modern-screenshot.umd.js +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/palette.mjs +0 -1
- package/packages/@monomind/cli/.claude/skills/monodesign/scripts/pin.mjs +0 -1
- package/packages/@monomind/cli/README.md +1 -1
- package/packages/@monomind/cli/dist/src/commands/design-detect.js +62 -1
- package/packages/@monomind/cli/dist/src/commands/design-palette.d.ts +0 -1
- package/packages/@monomind/cli/dist/src/commands/design-palette.js +0 -1
- package/packages/@monomind/cli/dist/src/commands/doctor-project-checks.d.ts +1 -1
- package/packages/@monomind/cli/dist/src/commands/doctor-project-checks.js +1 -1
- package/packages/@monomind/cli/dist/src/commands/hooks-workers.d.ts +1 -1
- package/packages/@monomind/cli/dist/src/commands/hooks-workers.js +8 -8
- package/packages/@monomind/cli/dist/src/commands/init.js +2 -2
- package/packages/@monomind/cli/dist/src/index.d.ts +1 -1
- package/packages/@monomind/cli/dist/src/index.js +3 -3
- package/packages/@monomind/cli/dist/src/init/claudemd-generator.js +5 -5
- package/packages/@monomind/cli/dist/src/init/executor.js +3 -3
- package/packages/@monomind/cli/dist/src/knowledge/document-pipeline.js +3 -1
- package/packages/@monomind/cli/dist/src/mcp-server.js +2 -2
- package/packages/@monomind/cli/dist/src/mcp-tools/hooks-intelligence.d.ts +1 -1
- package/packages/@monomind/cli/dist/src/mcp-tools/hooks-intelligence.js +1 -1
- package/packages/@monomind/cli/dist/src/mcp-tools/hooks-routing.js +2 -2
- package/packages/@monomind/cli/dist/src/mcp-tools/hooks-tools.js +1 -1
- package/packages/@monomind/cli/dist/src/memory/memory-kg.d.ts +5 -4
- package/packages/@monomind/cli/dist/src/memory/memory-kg.js +5 -4
- package/packages/@monomind/cli/dist/src/routing/embed-worker.js +1 -1
- package/packages/@monomind/cli/dist/src/routing/llm-caller.js +1 -1
- package/packages/@monomind/cli/dist/src/routing/route-layer-factory.js +1 -1
- package/packages/@monomind/cli/dist/src/ui/dashboard.html +22 -20
- package/packages/@monomind/cli/dist/src/update/checker.js +3 -3
- package/packages/@monomind/cli/package.json +5 -5
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// Pattern adapted from impeccable (Apache-2.0) — rebranded for monomind
|
|
3
2
|
/**
|
|
4
3
|
* Context-signals gatherer for the bare Monodesign invocation
|
|
5
4
|
* (no-argument) path. Collects cheap, deterministic signals about the current
|
|
@@ -24,6 +23,7 @@ import { fileURLToPath } from 'node:url';
|
|
|
24
23
|
import { execFileSync } from 'node:child_process';
|
|
25
24
|
import { loadContext, extractRegister, extractPlatform } from './context.mjs';
|
|
26
25
|
import { getCritiqueDir } from './lib/monodesign-paths.mjs';
|
|
26
|
+
import { readTrend, extractIssueLines, trendDirection } from './critique-storage.mjs';
|
|
27
27
|
|
|
28
28
|
/** Is there code here at all, or just context files / an empty repo? */
|
|
29
29
|
function hasCode(cwd) {
|
|
@@ -37,7 +37,10 @@ function hasCode(cwd) {
|
|
|
37
37
|
/**
|
|
38
38
|
* The most recent critique snapshot across all targets. Filenames are
|
|
39
39
|
* timestamp-prefixed (`<iso>__<slug>.md`), so a lexical sort is chronological.
|
|
40
|
-
* Parses the small frontmatter for score + P0/P1 counts
|
|
40
|
+
* Parses the small frontmatter for score + P0/P1 counts, plus two "design
|
|
41
|
+
* health" extras: the score trend for the same slug (last 3 runs, with a
|
|
42
|
+
* direction) and the open [P0] issue titles from the snapshot body — enough
|
|
43
|
+
* for a session to start design-health-aware without an LLM pass.
|
|
41
44
|
*/
|
|
42
45
|
function latestCritique(cwd) {
|
|
43
46
|
try {
|
|
@@ -56,13 +59,43 @@ function latestCritique(cwd) {
|
|
|
56
59
|
const n = Number(v);
|
|
57
60
|
return Number.isFinite(n) ? n : null;
|
|
58
61
|
};
|
|
62
|
+
const slug = get('slug');
|
|
63
|
+
// Trend across the last 3 runs for the same slug. Frontmatter written by
|
|
64
|
+
// critique-storage carries `total_score`; older/hand-written snapshots may
|
|
65
|
+
// carry `score` — accept either. Best-effort: never let this probe throw.
|
|
66
|
+
let trend = null;
|
|
67
|
+
try {
|
|
68
|
+
if (slug) {
|
|
69
|
+
const rows = readTrend(slug, { limit: 3, cwd });
|
|
70
|
+
const scores = rows
|
|
71
|
+
.map((r) => num(r.total_score ?? r.score))
|
|
72
|
+
.filter((n) => n !== null);
|
|
73
|
+
if (scores.length) trend = { scores, direction: trendDirection(scores) };
|
|
74
|
+
}
|
|
75
|
+
} catch { /* trend stays null */ }
|
|
76
|
+
let openP0 = [];
|
|
77
|
+
try {
|
|
78
|
+
openP0 = extractIssueLines(text).p0;
|
|
79
|
+
} catch { /* openP0 stays empty */ }
|
|
80
|
+
// Frontmatter key fallbacks: context fixtures use score/p0/p1, the
|
|
81
|
+
// critique flow's MONODESIGN_CRITIQUE_META uses total_score/p0_count/
|
|
82
|
+
// p1_count. `get` returns null for missing keys; keep null (not 0).
|
|
83
|
+
const numKey = (...keys) => {
|
|
84
|
+
for (const k of keys) {
|
|
85
|
+
const v = get(k);
|
|
86
|
+
if (v !== null) return num(v);
|
|
87
|
+
}
|
|
88
|
+
return null;
|
|
89
|
+
};
|
|
59
90
|
return {
|
|
60
|
-
slug
|
|
61
|
-
score:
|
|
62
|
-
p0:
|
|
63
|
-
p1:
|
|
91
|
+
slug,
|
|
92
|
+
score: numKey('score', 'total_score'),
|
|
93
|
+
p0: numKey('p0', 'p0_count'),
|
|
94
|
+
p1: numKey('p1', 'p1_count'),
|
|
64
95
|
timestamp: get('timestamp'),
|
|
65
96
|
file: path.relative(cwd, path.join(dir, newest)),
|
|
97
|
+
trend,
|
|
98
|
+
openP0,
|
|
66
99
|
};
|
|
67
100
|
} catch {
|
|
68
101
|
return null;
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// Pattern adapted from impeccable (Apache-2.0) — rebranded for monomind
|
|
3
2
|
/**
|
|
4
3
|
* Critique persistence helper.
|
|
5
4
|
*
|
|
@@ -19,6 +18,13 @@
|
|
|
19
18
|
* node critique-storage.mjs write <slug> <snapshot-body-file>
|
|
20
19
|
* node critique-storage.mjs latest <slug>
|
|
21
20
|
* node critique-storage.mjs trend <slug> [limit]
|
|
21
|
+
* node critique-storage.mjs recall <slug> [limit]
|
|
22
|
+
*
|
|
23
|
+
* `write` also best-effort mirrors a compact record of the snapshot into
|
|
24
|
+
* monomind's persistent memory (namespace `design-critique`) so design
|
|
25
|
+
* health survives across sessions. The mirror is fire-and-forget: if the
|
|
26
|
+
* monomind CLI is not installed it is skipped silently, and it can be
|
|
27
|
+
* disabled outright with MONODESIGN_NO_MEMORY=1.
|
|
22
28
|
*
|
|
23
29
|
* Note: there is intentionally no `ignore` subcommand. ignore.md is a plain
|
|
24
30
|
* markdown file; the model reads it directly with its file-read tool. This
|
|
@@ -28,6 +34,7 @@
|
|
|
28
34
|
|
|
29
35
|
import fs from 'node:fs';
|
|
30
36
|
import path from 'node:path';
|
|
37
|
+
import { spawnSync } from 'node:child_process';
|
|
31
38
|
import { fileURLToPath, pathToFileURL } from 'node:url';
|
|
32
39
|
import { getCritiqueDir } from './lib/monodesign-paths.mjs';
|
|
33
40
|
|
|
@@ -179,6 +186,164 @@ export function readTrend(slug, { limit = 5, cwd = process.cwd() } = {}) {
|
|
|
179
186
|
return slice.map((file) => parseFrontmatter(fs.readFileSync(file, 'utf-8')));
|
|
180
187
|
}
|
|
181
188
|
|
|
189
|
+
// ---- Monomind memory mirror --------------------------------------------
|
|
190
|
+
|
|
191
|
+
const asFiniteNumber = (v) => {
|
|
192
|
+
const n = Number(v);
|
|
193
|
+
return Number.isFinite(n) ? n : null;
|
|
194
|
+
};
|
|
195
|
+
|
|
196
|
+
/**
|
|
197
|
+
* Locate a locally installed monomind CLI bin by climbing from `cwd`.
|
|
198
|
+
* Returns null when none is installed — the caller then tries
|
|
199
|
+
* `npx --no-install`, which also fails fast (and silently) when absent.
|
|
200
|
+
*/
|
|
201
|
+
function resolveMonomindBin(cwd) {
|
|
202
|
+
const name = process.platform === 'win32' ? 'monomind.cmd' : 'monomind';
|
|
203
|
+
let dir = path.resolve(cwd);
|
|
204
|
+
for (;;) {
|
|
205
|
+
const bin = path.join(dir, 'node_modules', '.bin', name);
|
|
206
|
+
try {
|
|
207
|
+
fs.accessSync(bin, fs.constants.X_OK);
|
|
208
|
+
return bin;
|
|
209
|
+
} catch { /* keep climbing */ }
|
|
210
|
+
const parent = path.dirname(dir);
|
|
211
|
+
if (parent === dir) return null;
|
|
212
|
+
dir = parent;
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
|
|
216
|
+
/**
|
|
217
|
+
* Best-effort mirror of a snapshot's structured metadata into monomind's
|
|
218
|
+
* persistent memory (namespace `design-critique`, key `<project>-<slug>`,
|
|
219
|
+
* upserted), so design health is queryable across sessions via
|
|
220
|
+
* `monomind memory search`. Never throws and never fails the critique flow:
|
|
221
|
+
* if the monomind CLI is unavailable the call is skipped silently.
|
|
222
|
+
* Kill-switch: MONODESIGN_NO_MEMORY=1.
|
|
223
|
+
*/
|
|
224
|
+
export function mirrorToMemory({ slug, meta = {}, filePath, cwd = process.cwd(), now = new Date(), env = process.env }) {
|
|
225
|
+
if (!slug) return { mirrored: false, reason: 'no-slug' };
|
|
226
|
+
if (env.MONODESIGN_NO_MEMORY === '1') return { mirrored: false, reason: 'disabled' };
|
|
227
|
+
try {
|
|
228
|
+
const record = {
|
|
229
|
+
score: asFiniteNumber(meta.total_score ?? meta.score),
|
|
230
|
+
p0: asFiniteNumber(meta.p0_count ?? meta.p0),
|
|
231
|
+
p1: asFiniteNumber(meta.p1_count ?? meta.p1),
|
|
232
|
+
date: now.toISOString(),
|
|
233
|
+
slug,
|
|
234
|
+
path: filePath ? path.relative(cwd, filePath) : null,
|
|
235
|
+
};
|
|
236
|
+
const project = kebab(path.basename(path.resolve(cwd))) || 'project';
|
|
237
|
+
const key = `${project}-${slug}`;
|
|
238
|
+
const argv = [
|
|
239
|
+
'memory', 'store',
|
|
240
|
+
'--key', key,
|
|
241
|
+
'--value', JSON.stringify(record),
|
|
242
|
+
'--namespace', 'design-critique',
|
|
243
|
+
'--upsert',
|
|
244
|
+
];
|
|
245
|
+
const bin = resolveMonomindBin(cwd);
|
|
246
|
+
const opts = { cwd, env, stdio: 'ignore', timeout: 15000 };
|
|
247
|
+
const run = bin
|
|
248
|
+
? spawnSync(bin, argv, opts)
|
|
249
|
+
: spawnSync('npx', ['--no-install', 'monomind', ...argv], { ...opts, shell: process.platform === 'win32' });
|
|
250
|
+
if (run.error || run.status !== 0) return { mirrored: false, reason: 'cli-unavailable' };
|
|
251
|
+
return { mirrored: true, key };
|
|
252
|
+
} catch {
|
|
253
|
+
return { mirrored: false, reason: 'error' };
|
|
254
|
+
}
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
// ---- Recall (latest + trend + open items, one compact block) -----------
|
|
258
|
+
|
|
259
|
+
/**
|
|
260
|
+
* Extract open issue titles tagged [P0] / [P1] from a snapshot body.
|
|
261
|
+
* Matches the critique report's "**[P?] What**: ..." lines, but tolerates
|
|
262
|
+
* loose formatting: any line containing `[P0]`/`[P1]` counts, with the
|
|
263
|
+
* title taken from the text after the tag (markdown emphasis stripped).
|
|
264
|
+
*/
|
|
265
|
+
export function extractIssueLines(body, { max = 8 } = {}) {
|
|
266
|
+
const issues = { p0: [], p1: [] };
|
|
267
|
+
if (!body || typeof body !== 'string') return issues;
|
|
268
|
+
// Drop frontmatter so metadata lines never masquerade as issues.
|
|
269
|
+
const text = body.replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/, '');
|
|
270
|
+
for (const line of text.split(/\r?\n/)) {
|
|
271
|
+
const m = line.match(/\[(P0|P1)\]\s*(.*)/i);
|
|
272
|
+
if (!m) continue;
|
|
273
|
+
let title = m[2];
|
|
274
|
+
// "**[P0] Title**: explanation" → keep just the title.
|
|
275
|
+
const boldColon = title.indexOf('**:');
|
|
276
|
+
if (boldColon !== -1) title = title.slice(0, boldColon);
|
|
277
|
+
title = title.replace(/\*+/g, '').replace(/^[-–—\s]+/, '').replace(/[:\s]+$/, '').trim();
|
|
278
|
+
if (!title) continue;
|
|
279
|
+
const bucket = m[1].toUpperCase() === 'P0' ? issues.p0 : issues.p1;
|
|
280
|
+
if (bucket.length < max && !bucket.includes(title)) bucket.push(title);
|
|
281
|
+
}
|
|
282
|
+
return issues;
|
|
283
|
+
}
|
|
284
|
+
|
|
285
|
+
/**
|
|
286
|
+
* Direction of the last (up to) 3 finite scores: improving | declining |
|
|
287
|
+
* flat, or null when fewer than 2 scores exist.
|
|
288
|
+
*/
|
|
289
|
+
export function trendDirection(scores) {
|
|
290
|
+
const s = (scores || []).map(asFiniteNumber).filter((n) => n !== null).slice(-3);
|
|
291
|
+
if (s.length < 2) return null;
|
|
292
|
+
if (s[s.length - 1] > s[0]) return 'improving';
|
|
293
|
+
if (s[s.length - 1] < s[0]) return 'declining';
|
|
294
|
+
return 'flat';
|
|
295
|
+
}
|
|
296
|
+
|
|
297
|
+
/**
|
|
298
|
+
* Combined latest + trend + open-issue view for `slug`, or null when no
|
|
299
|
+
* snapshot exists. This backs the `recall` subcommand that polish/critique
|
|
300
|
+
* consume instead of separate latest+trend calls.
|
|
301
|
+
*/
|
|
302
|
+
export function readRecall(slug, { limit = 5, cwd = process.cwd() } = {}) {
|
|
303
|
+
const latest = readLatestSnapshot(slug, { cwd });
|
|
304
|
+
if (!latest) return null;
|
|
305
|
+
const trend = readTrend(slug, { limit, cwd });
|
|
306
|
+
const scores = trend.map((t) => asFiniteNumber(t.total_score ?? t.score));
|
|
307
|
+
return {
|
|
308
|
+
slug,
|
|
309
|
+
latest,
|
|
310
|
+
trend,
|
|
311
|
+
scores,
|
|
312
|
+
direction: trendDirection(scores),
|
|
313
|
+
issues: extractIssueLines(latest.body),
|
|
314
|
+
};
|
|
315
|
+
}
|
|
316
|
+
|
|
317
|
+
/** Render a recall result as a compact markdown block. */
|
|
318
|
+
export function formatRecall(recall, { cwd = process.cwd() } = {}) {
|
|
319
|
+
const { slug, latest, trend, scores, direction, issues } = recall;
|
|
320
|
+
const meta = latest.meta;
|
|
321
|
+
const score = asFiniteNumber(meta.total_score ?? meta.score);
|
|
322
|
+
const p0 = asFiniteNumber(meta.p0_count ?? meta.p0);
|
|
323
|
+
const p1 = asFiniteNumber(meta.p1_count ?? meta.p1);
|
|
324
|
+
const lines = [`## Design health: \`${slug}\``];
|
|
325
|
+
lines.push(
|
|
326
|
+
`- Latest score: ${score !== null ? `${score}/40` : 'n/a'}`
|
|
327
|
+
+ ` (P0: ${p0 ?? '?'}, P1: ${p1 ?? '?'})`
|
|
328
|
+
+ (meta.timestamp ? ` — ${meta.timestamp}` : ''),
|
|
329
|
+
);
|
|
330
|
+
const arrows = scores.map((n) => (n === null ? '?' : n)).join(' → ');
|
|
331
|
+
lines.push(`- Trend (last ${trend.length}): ${arrows}${direction ? ` (${direction})` : ''}`);
|
|
332
|
+
if (issues.p0.length) {
|
|
333
|
+
lines.push('- Open P0:');
|
|
334
|
+
for (const t of issues.p0) lines.push(` - ${t}`);
|
|
335
|
+
}
|
|
336
|
+
if (issues.p1.length) {
|
|
337
|
+
lines.push('- Open P1:');
|
|
338
|
+
for (const t of issues.p1) lines.push(` - ${t}`);
|
|
339
|
+
}
|
|
340
|
+
if (!issues.p0.length && !issues.p1.length) {
|
|
341
|
+
lines.push('- No open P0/P1 lines found in the latest snapshot.');
|
|
342
|
+
}
|
|
343
|
+
lines.push(`- Snapshot: ${path.relative(cwd, latest.path)}`);
|
|
344
|
+
return lines.join('\n');
|
|
345
|
+
}
|
|
346
|
+
|
|
182
347
|
// ---- CLI ---------------------------------------------------------------
|
|
183
348
|
|
|
184
349
|
function main(argv) {
|
|
@@ -203,6 +368,8 @@ function main(argv) {
|
|
|
203
368
|
try { meta = JSON.parse(metaArg); } catch { /* ignore */ }
|
|
204
369
|
}
|
|
205
370
|
const out = writeSnapshot({ slug, meta, body: raw });
|
|
371
|
+
// Best-effort cross-session mirror; must never break the critique flow.
|
|
372
|
+
mirrorToMemory({ slug, meta, filePath: out });
|
|
206
373
|
process.stdout.write(`${out}\n`);
|
|
207
374
|
return;
|
|
208
375
|
}
|
|
@@ -217,8 +384,14 @@ function main(argv) {
|
|
|
217
384
|
process.stdout.write(JSON.stringify(rows, null, 2) + '\n');
|
|
218
385
|
return;
|
|
219
386
|
}
|
|
387
|
+
case 'recall': {
|
|
388
|
+
const recall = readRecall(args[0], { limit: args[1] ? Number(args[1]) : 5 });
|
|
389
|
+
if (!recall) { process.exit(2); }
|
|
390
|
+
process.stdout.write(`${formatRecall(recall)}\n`);
|
|
391
|
+
return;
|
|
392
|
+
}
|
|
220
393
|
default:
|
|
221
|
-
process.stderr.write('usage: critique-storage.mjs <slug|write|latest|trend> [args]\n');
|
|
394
|
+
process.stderr.write('usage: critique-storage.mjs <slug|write|latest|trend|recall> [args]\n');
|
|
222
395
|
process.exit(1);
|
|
223
396
|
}
|
|
224
397
|
}
|
package/packages/@monomind/cli/.claude/skills/monodesign/scripts/detector/browser/injected/index.mjs
CHANGED
|
@@ -1,4 +1,3 @@
|
|
|
1
|
-
// Pattern adapted from impeccable (Apache-2.0) — rebranded for monomind
|
|
2
1
|
const IS_BROWSER = typeof window !== 'undefined';
|
|
3
2
|
|
|
4
3
|
// ─── Section 7: Browser UI (IS_BROWSER only) ────────────────────────────────
|
|
@@ -1489,6 +1488,8 @@ if (IS_BROWSER) {
|
|
|
1489
1488
|
...checkElementClippedOverflowDOM(el).map(f => ({ type: f.id, detail: f.snippet })),
|
|
1490
1489
|
...checkElementGptBorderShadowDOM(el).map(f => ({ type: f.id, detail: f.snippet })),
|
|
1491
1490
|
...checkElementTextOverflowDOM(el).map(f => ({ type: f.id, detail: f.snippet })),
|
|
1491
|
+
...checkElementImageDimensionsDOM(el).map(f => ({ type: f.id, detail: f.snippet })),
|
|
1492
|
+
...checkElementSmallTouchTargetDOM(el).map(f => ({ type: f.id, detail: f.snippet })),
|
|
1492
1493
|
...checkElementDesignSystemDOM(el, designSystem, designSeen),
|
|
1493
1494
|
].filter(f => _ruleOk(f.type));
|
|
1494
1495
|
|
|
@@ -1548,6 +1549,29 @@ if (IS_BROWSER) {
|
|
|
1548
1549
|
addBrowserFindings(groupMap, document.body, creamFindings);
|
|
1549
1550
|
}
|
|
1550
1551
|
|
|
1552
|
+
// Stylesheet-level accessibility rules (focus-visible, hover-only,
|
|
1553
|
+
// dark-scheme). Serialize every same-origin stylesheet to CSS text and
|
|
1554
|
+
// run the shared analyzers — cross-origin sheets throw on cssRules access
|
|
1555
|
+
// and are skipped.
|
|
1556
|
+
let stylesheetCssText = '';
|
|
1557
|
+
for (const sheet of Array.from(document.styleSheets || [])) {
|
|
1558
|
+
let rules;
|
|
1559
|
+
try { rules = sheet.cssRules; } catch { continue; }
|
|
1560
|
+
if (!rules) continue;
|
|
1561
|
+
for (const rule of Array.from(rules)) {
|
|
1562
|
+
try { stylesheetCssText += rule.cssText + '\n'; } catch { /* ignore */ }
|
|
1563
|
+
}
|
|
1564
|
+
}
|
|
1565
|
+
const stylesheetFindings = [
|
|
1566
|
+
...checkFocusVisible(stylesheetCssText),
|
|
1567
|
+
...checkHoverOnlyAffordance(stylesheetCssText),
|
|
1568
|
+
...checkDarkSchemeContrast(stylesheetCssText),
|
|
1569
|
+
].map(f => ({ type: f.id, detail: f.snippet })).filter(f => _ruleOk(f.type));
|
|
1570
|
+
if (stylesheetFindings.length > 0) {
|
|
1571
|
+
pageLevelFindings.push(...stylesheetFindings);
|
|
1572
|
+
addBrowserFindings(groupMap, document.body, stylesheetFindings);
|
|
1573
|
+
}
|
|
1574
|
+
|
|
1551
1575
|
// Regex-on-HTML checks (shared with Node)
|
|
1552
1576
|
// Clone the document and strip monodesign-live overlay nodes before the
|
|
1553
1577
|
// regex scan, so the inspector's own inline styles (transitions on top/
|