@monoes/monomindcli 2.14.1 → 2.15.0
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/.claude/helpers/control-start.cjs +10 -13
- package/.claude/skills/monodesign/scripts/context.mjs +4 -4
- package/.claude/skills/monodesign/scripts/critique-storage.mjs +1 -1
- package/.claude/skills/monodesign/scripts/detect-csp.mjs +1 -6
- package/.claude/skills/monodesign/scripts/detector/browser/injected/index.mjs +16 -18
- package/.claude/skills/monodesign/scripts/detector/cli/main.mjs +3 -3
- package/.claude/skills/monodesign/scripts/detector/detect-antipatterns-browser.js +67 -47
- package/.claude/skills/monodesign/scripts/detector/engines/regex/detect-text.mjs +6 -6
- package/.claude/skills/monodesign/scripts/detector/engines/static-html/css-cascade.mjs +6 -5
- package/.claude/skills/monodesign/scripts/detector/engines/static-html/detect-html.mjs +6 -6
- package/.claude/skills/monodesign/scripts/detector/fix/index.mjs +3 -3
- package/.claude/skills/monodesign/scripts/detector/node/file-system.mjs +1 -1
- package/.claude/skills/monodesign/scripts/detector/registry/antipatterns.mjs +1 -1
- package/.claude/skills/monodesign/scripts/detector/rules/checks.mjs +24 -25
- package/.claude/skills/monodesign/scripts/detector/shared/color.mjs +2 -2
- package/.claude/skills/monodesign/scripts/detector/shared/constants.mjs +1 -1
- package/.claude/skills/monodesign/scripts/detector/shared/inline-ignores.mjs +2 -2
- package/.claude/skills/monodesign/scripts/hook-admin.mjs +6 -6
- package/.claude/skills/monodesign/scripts/hook-before-edit.mjs +4 -4
- package/.claude/skills/monodesign/scripts/hook-lib.mjs +20 -11
- package/.claude/skills/monodesign/scripts/hook.mjs +1 -1
- package/.claude/skills/monodesign/scripts/lib/design-parser.mjs +9 -42
- package/.claude/skills/monodesign/scripts/lib/is-generated.mjs +1 -1
- package/.claude/skills/monodesign/scripts/lib/monodesign-config.mjs +5 -5
- package/.claude/skills/monodesign/scripts/lib/monodesign-paths.mjs +1 -1
- package/.claude/skills/monodesign/scripts/live/event-validation.mjs +13 -13
- package/.claude/skills/monodesign/scripts/live/manual-apply.mjs +4 -4
- package/.claude/skills/monodesign/scripts/live/manual-edits-buffer.mjs +1 -1
- package/.claude/skills/monodesign/scripts/live/session-store.mjs +5 -5
- package/.claude/skills/monodesign/scripts/live/svelte-component.mjs +13 -13
- package/.claude/skills/monodesign/scripts/live/sveltekit-adapter.mjs +4 -4
- package/.claude/skills/monodesign/scripts/live/ui-core.mjs +1 -1
- package/.claude/skills/monodesign/scripts/live-accept.mjs +24 -24
- package/.claude/skills/monodesign/scripts/live-browser-dom.js +8 -7
- package/.claude/skills/monodesign/scripts/live-browser-session.js +8 -7
- package/.claude/skills/monodesign/scripts/live-browser.js +405 -432
- package/.claude/skills/monodesign/scripts/live-commit-manual-edits.mjs +6 -6
- package/.claude/skills/monodesign/scripts/live-copy-edit-agent.mjs +2 -2
- package/.claude/skills/monodesign/scripts/live-discard-manual-edits.mjs +1 -1
- package/.claude/skills/monodesign/scripts/live-inject.mjs +7 -7
- package/.claude/skills/monodesign/scripts/live-insert.mjs +11 -11
- package/.claude/skills/monodesign/scripts/live-manual-edit-evidence.mjs +4 -4
- package/.claude/skills/monodesign/scripts/live-poll.mjs +5 -5
- package/.claude/skills/monodesign/scripts/live-server.mjs +10 -10
- package/.claude/skills/monodesign/scripts/live-wrap.mjs +31 -41
- package/.claude/skills/monodesign/scripts/live.mjs +5 -5
- package/.claude/skills/monodesign/scripts/palette.mjs +3 -1
- package/.claude/skills/monodesign/scripts/pin.mjs +1 -1
- package/dist/src/commands/doc-filters.d.ts.map +1 -1
- package/dist/src/commands/doc-filters.js +6 -0
- package/dist/src/commands/doc-filters.js.map +1 -1
- package/dist/src/commands/doc-library.d.ts +2 -1
- package/dist/src/commands/doc-library.d.ts.map +1 -1
- package/dist/src/commands/doc-library.js +66 -2
- package/dist/src/commands/doc-library.js.map +1 -1
- package/dist/src/commands/doc.d.ts.map +1 -1
- package/dist/src/commands/doc.js +2 -0
- package/dist/src/commands/doc.js.map +1 -1
- package/dist/src/commands/ui.d.ts.map +1 -1
- package/dist/src/commands/ui.js +60 -0
- package/dist/src/commands/ui.js.map +1 -1
- package/dist/src/knowledge/capture-envelope.d.ts +5 -0
- package/dist/src/knowledge/capture-envelope.d.ts.map +1 -1
- package/dist/src/knowledge/capture-envelope.js +2 -0
- package/dist/src/knowledge/capture-envelope.js.map +1 -1
- package/dist/src/knowledge/document-chunking.d.ts +42 -0
- package/dist/src/knowledge/document-chunking.d.ts.map +1 -0
- package/dist/src/knowledge/document-chunking.js +288 -0
- package/dist/src/knowledge/document-chunking.js.map +1 -0
- package/dist/src/knowledge/document-index.d.ts +124 -0
- package/dist/src/knowledge/document-index.d.ts.map +1 -0
- package/dist/src/knowledge/document-index.js +314 -0
- package/dist/src/knowledge/document-index.js.map +1 -0
- package/dist/src/knowledge/document-ingest.d.ts +23 -0
- package/dist/src/knowledge/document-ingest.d.ts.map +1 -0
- package/dist/src/knowledge/document-ingest.js +368 -0
- package/dist/src/knowledge/document-ingest.js.map +1 -0
- package/dist/src/knowledge/document-pipeline.d.ts +26 -208
- package/dist/src/knowledge/document-pipeline.d.ts.map +1 -1
- package/dist/src/knowledge/document-pipeline.js +25 -1104
- package/dist/src/knowledge/document-pipeline.js.map +1 -1
- package/dist/src/knowledge/document-search.d.ts +27 -0
- package/dist/src/knowledge/document-search.d.ts.map +1 -0
- package/dist/src/knowledge/document-search.js +138 -0
- package/dist/src/knowledge/document-search.js.map +1 -0
- package/dist/src/knowledge/document-store.d.ts +28 -0
- package/dist/src/knowledge/document-store.d.ts.map +1 -0
- package/dist/src/knowledge/document-store.js +61 -0
- package/dist/src/knowledge/document-store.js.map +1 -0
- package/dist/src/knowledge/document-types.d.ts +103 -0
- package/dist/src/knowledge/document-types.d.ts.map +1 -0
- package/dist/src/knowledge/document-types.js +12 -0
- package/dist/src/knowledge/document-types.js.map +1 -0
- package/dist/src/knowledge/highlights.d.ts +168 -0
- package/dist/src/knowledge/highlights.d.ts.map +1 -0
- package/dist/src/knowledge/highlights.js +311 -0
- package/dist/src/knowledge/highlights.js.map +1 -0
- package/dist/src/knowledge/lookup.d.ts +80 -0
- package/dist/src/knowledge/lookup.d.ts.map +1 -0
- package/dist/src/knowledge/lookup.js +156 -0
- package/dist/src/knowledge/lookup.js.map +1 -0
- package/dist/src/knowledge/okf-bundle.d.ts +19 -0
- package/dist/src/knowledge/okf-bundle.d.ts.map +1 -0
- package/dist/src/knowledge/okf-bundle.js +106 -0
- package/dist/src/knowledge/okf-bundle.js.map +1 -0
- package/dist/src/knowledge/profile-store.d.ts +134 -0
- package/dist/src/knowledge/profile-store.d.ts.map +1 -0
- package/dist/src/knowledge/profile-store.js +237 -0
- package/dist/src/knowledge/profile-store.js.map +1 -0
- package/dist/src/orgrt/agent-runner.d.ts +4 -0
- package/dist/src/orgrt/agent-runner.d.ts.map +1 -1
- package/dist/src/orgrt/agent-runner.js +22 -0
- package/dist/src/orgrt/agent-runner.js.map +1 -1
- package/dist/src/orgrt/antigravity-runner.d.ts.map +1 -1
- package/dist/src/orgrt/antigravity-runner.js +2 -1
- package/dist/src/orgrt/antigravity-runner.js.map +1 -1
- package/dist/src/orgrt/authority-mask.d.ts +32 -0
- package/dist/src/orgrt/authority-mask.d.ts.map +1 -0
- package/dist/src/orgrt/authority-mask.js +135 -0
- package/dist/src/orgrt/authority-mask.js.map +1 -0
- package/dist/src/orgrt/codex-runner.d.ts.map +1 -1
- package/dist/src/orgrt/codex-runner.js +2 -1
- package/dist/src/orgrt/codex-runner.js.map +1 -1
- package/dist/src/orgrt/copilot-runner.d.ts.map +1 -1
- package/dist/src/orgrt/copilot-runner.js +2 -1
- package/dist/src/orgrt/copilot-runner.js.map +1 -1
- package/dist/src/orgrt/crush-runner.d.ts.map +1 -1
- package/dist/src/orgrt/crush-runner.js +6 -1
- package/dist/src/orgrt/crush-runner.js.map +1 -1
- package/dist/src/orgrt/daemon.d.ts +4 -0
- package/dist/src/orgrt/daemon.d.ts.map +1 -1
- package/dist/src/orgrt/daemon.js +13 -2
- package/dist/src/orgrt/daemon.js.map +1 -1
- package/dist/src/orgrt/decisions.d.ts +9 -0
- package/dist/src/orgrt/decisions.d.ts.map +1 -1
- package/dist/src/orgrt/decisions.js +32 -5
- package/dist/src/orgrt/decisions.js.map +1 -1
- package/dist/src/orgrt/file-roots.d.ts +2 -1
- package/dist/src/orgrt/file-roots.d.ts.map +1 -1
- package/dist/src/orgrt/file-roots.js +7 -3
- package/dist/src/orgrt/file-roots.js.map +1 -1
- package/dist/src/orgrt/grok-runner.d.ts.map +1 -1
- package/dist/src/orgrt/grok-runner.js +2 -1
- package/dist/src/orgrt/grok-runner.js.map +1 -1
- package/dist/src/orgrt/hermes-runner.d.ts.map +1 -1
- package/dist/src/orgrt/hermes-runner.js +2 -1
- package/dist/src/orgrt/hermes-runner.js.map +1 -1
- package/dist/src/orgrt/inbox.d.ts.map +1 -1
- package/dist/src/orgrt/inbox.js +70 -4
- package/dist/src/orgrt/inbox.js.map +1 -1
- package/dist/src/orgrt/kimicode-runner.d.ts.map +1 -1
- package/dist/src/orgrt/kimicode-runner.js +2 -1
- package/dist/src/orgrt/kimicode-runner.js.map +1 -1
- package/dist/src/orgrt/opencode-runner.d.ts.map +1 -1
- package/dist/src/orgrt/opencode-runner.js +3 -2
- package/dist/src/orgrt/opencode-runner.js.map +1 -1
- package/dist/src/orgrt/pi-rpc-runner.d.ts.map +1 -1
- package/dist/src/orgrt/pi-rpc-runner.js +3 -2
- package/dist/src/orgrt/pi-rpc-runner.js.map +1 -1
- package/dist/src/orgrt/pi-runner.d.ts.map +1 -1
- package/dist/src/orgrt/pi-runner.js +2 -1
- package/dist/src/orgrt/pi-runner.js.map +1 -1
- package/dist/src/orgrt/policy.d.ts.map +1 -1
- package/dist/src/orgrt/policy.js +3 -0
- package/dist/src/orgrt/policy.js.map +1 -1
- package/dist/src/orgrt/qwen-rpc-runner.d.ts.map +1 -1
- package/dist/src/orgrt/qwen-rpc-runner.js +3 -2
- package/dist/src/orgrt/qwen-rpc-runner.js.map +1 -1
- package/dist/src/orgrt/qwen-runner.d.ts.map +1 -1
- package/dist/src/orgrt/qwen-runner.js +2 -1
- package/dist/src/orgrt/qwen-runner.js.map +1 -1
- package/dist/src/orgrt/role-sandbox.d.ts +21 -0
- package/dist/src/orgrt/role-sandbox.d.ts.map +1 -1
- package/dist/src/orgrt/role-sandbox.js +31 -6
- package/dist/src/orgrt/role-sandbox.js.map +1 -1
- package/dist/src/orgrt/session.d.ts.map +1 -1
- package/dist/src/orgrt/session.js +21 -2
- package/dist/src/orgrt/session.js.map +1 -1
- package/dist/src/orgrt/task-dag.d.ts +3 -0
- package/dist/src/orgrt/task-dag.d.ts.map +1 -1
- package/dist/src/orgrt/task-dag.js +1 -0
- package/dist/src/orgrt/task-dag.js.map +1 -1
- package/dist/src/orgrt/types.d.ts +5 -0
- package/dist/src/orgrt/types.d.ts.map +1 -1
- package/dist/src/orgrt/types.js +23 -1
- package/dist/src/orgrt/types.js.map +1 -1
- package/dist/src/ui/dashboard.html +28 -848
- package/dist/src/ui/human-auth.mjs +103 -0
- package/dist/src/ui/org-hil.mjs +86 -37
- package/dist/src/ui/org-runtime.mjs +21 -13
- package/dist/src/ui/routes-org.mjs +49 -445
- package/dist/src/ui/server.mjs +90 -2
- package/dist/tsconfig.tsbuildinfo +1 -1
- package/package.json +6 -6
|
@@ -62,30 +62,30 @@ function validateInsertGenerate(msg) {
|
|
|
62
62
|
|
|
63
63
|
function validateReplaceGenerate(msg) {
|
|
64
64
|
if (!msg.action || !VISUAL_ACTIONS.includes(msg.action)) return 'generate: invalid action';
|
|
65
|
-
if (!msg.element
|
|
65
|
+
if (!msg.element?.outerHTML) return 'generate: missing element context';
|
|
66
66
|
return validateAnnotationFields(msg);
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
function validateManualEditEvent(msg, label) {
|
|
70
|
-
if (!isValidId(msg.id)) return label
|
|
71
|
-
if (!msg.pageUrl || typeof msg.pageUrl !== 'string') return label
|
|
72
|
-
if (!msg.element || typeof msg.element !== 'object') return label
|
|
73
|
-
if (!Array.isArray(msg.ops) || msg.ops.length === 0) return label
|
|
74
|
-
if (msg.ops.length > 100) return label
|
|
70
|
+
if (!isValidId(msg.id)) return `${label}: missing or malformed id`;
|
|
71
|
+
if (!msg.pageUrl || typeof msg.pageUrl !== 'string') return `${label}: missing pageUrl`;
|
|
72
|
+
if (!msg.element || typeof msg.element !== 'object') return `${label}: missing element`;
|
|
73
|
+
if (!Array.isArray(msg.ops) || msg.ops.length === 0) return `${label}: ops must be non-empty array`;
|
|
74
|
+
if (msg.ops.length > 100) return `${label}: too many ops (max 100)`;
|
|
75
75
|
for (const op of msg.ops) {
|
|
76
|
-
if (typeof op.ref !== 'string') return label
|
|
77
|
-
if (typeof op.tag !== 'string') return label
|
|
78
|
-
if (typeof op.originalText !== 'string') return label
|
|
76
|
+
if (typeof op.ref !== 'string') return `${label}: op.ref required`;
|
|
77
|
+
if (typeof op.tag !== 'string') return `${label}: op.tag required`;
|
|
78
|
+
if (typeof op.originalText !== 'string') return `${label}: op.originalText required`;
|
|
79
79
|
if (op.deleted !== true && typeof op.newText !== 'string') {
|
|
80
|
-
return label
|
|
80
|
+
return `${label}: text op requires newText`;
|
|
81
81
|
}
|
|
82
82
|
if (typeof op.newText === 'string') {
|
|
83
83
|
if (op.deleted !== true && op.newText.trim().length === 0) {
|
|
84
|
-
return label
|
|
84
|
+
return `${label}: newText cannot be empty`;
|
|
85
85
|
}
|
|
86
86
|
const forbidden = validateManualEditText(op.newText);
|
|
87
87
|
if (forbidden) {
|
|
88
|
-
return label
|
|
88
|
+
return `${label}: newText cannot contain ${forbidden.join(' ')} (plain text only; ask the AI to insert markup)`;
|
|
89
89
|
}
|
|
90
90
|
}
|
|
91
91
|
}
|
|
@@ -132,6 +132,6 @@ export function validateEvent(msg) {
|
|
|
132
132
|
if (msg.pageUrl !== undefined && typeof msg.pageUrl !== 'string') return 'steer: pageUrl must be string';
|
|
133
133
|
return null;
|
|
134
134
|
default:
|
|
135
|
-
return
|
|
135
|
+
return `Unknown event type: ${msg.type}`;
|
|
136
136
|
}
|
|
137
137
|
}
|
|
@@ -326,7 +326,7 @@ export function writeManualApplyEvidence(eventId, batch, cwd = process.cwd()) {
|
|
|
326
326
|
const dir = manualApplyEvidenceDir(cwd);
|
|
327
327
|
fs.mkdirSync(dir, { recursive: true });
|
|
328
328
|
const evidencePath = path.join(dir, `${eventId}.json`);
|
|
329
|
-
fs.writeFileSync(evidencePath, JSON.stringify(batch, null, 2)
|
|
329
|
+
fs.writeFileSync(evidencePath, `${JSON.stringify(batch, null, 2)}\n`, 'utf-8');
|
|
330
330
|
return evidencePath;
|
|
331
331
|
}
|
|
332
332
|
|
|
@@ -495,7 +495,7 @@ function invalidManualApplyResult(reason, eventId, extra = {}) {
|
|
|
495
495
|
}
|
|
496
496
|
|
|
497
497
|
export function validateManualApplyResultMessage(msg, deferred) {
|
|
498
|
-
|
|
498
|
+
const data = msg?.data;
|
|
499
499
|
const eventId = msg?.id || deferred?.event?.id || 'EVENT_ID';
|
|
500
500
|
if (!data || typeof data !== 'object' || Array.isArray(data)) {
|
|
501
501
|
return invalidManualApplyResult('missing_result_data', eventId);
|
|
@@ -743,7 +743,7 @@ export function writeManualApplyTransaction({ cwd = process.cwd(), pageUrl = nul
|
|
|
743
743
|
}),
|
|
744
744
|
};
|
|
745
745
|
fs.mkdirSync(path.dirname(file), { recursive: true });
|
|
746
|
-
fs.writeFileSync(`${file}.tmp`, JSON.stringify(transaction, null, 2)
|
|
746
|
+
fs.writeFileSync(`${file}.tmp`, `${JSON.stringify(transaction, null, 2)}\n`, 'utf-8');
|
|
747
747
|
fs.renameSync(`${file}.tmp`, file);
|
|
748
748
|
return transaction;
|
|
749
749
|
}
|
|
@@ -935,5 +935,5 @@ export function compactManualLogText(value, max = 200) {
|
|
|
935
935
|
if (typeof value !== 'string') return undefined;
|
|
936
936
|
const normalized = value.replace(/\s+/g, ' ').trim();
|
|
937
937
|
if (normalized.length <= max) return normalized;
|
|
938
|
-
return normalized.slice(0, max)
|
|
938
|
+
return `${normalized.slice(0, max)}... [truncated ${normalized.length - max} chars]`;
|
|
939
939
|
}
|
|
@@ -41,7 +41,7 @@ function readBufferInternal(cwd, { strict }) {
|
|
|
41
41
|
return { version: BUFFER_VERSION, entries: parsed.entries };
|
|
42
42
|
} catch (err) {
|
|
43
43
|
if (strict && err?.code !== 'ENOENT') {
|
|
44
|
-
throw new Error(
|
|
44
|
+
throw new Error(`manual_edit_buffer_unreadable: ${err.message || String(err)}`);
|
|
45
45
|
}
|
|
46
46
|
return { version: BUFFER_VERSION, entries: [] };
|
|
47
47
|
}
|
|
@@ -51,7 +51,7 @@ export function createLiveSessionStore({ cwd = process.cwd(), sessionId } = {})
|
|
|
51
51
|
ts: new Date().toISOString(),
|
|
52
52
|
event: normalized,
|
|
53
53
|
};
|
|
54
|
-
fs.appendFileSync(journalPath, JSON.stringify(entry)
|
|
54
|
+
fs.appendFileSync(journalPath, `${JSON.stringify(entry)}\n`);
|
|
55
55
|
const next = applyEvent(prior.snapshot, entry, prior.diagnostics);
|
|
56
56
|
snapshotCache.set(normalized.id, { snapshot: next, diagnostics: next.diagnostics || [], nextSeq: seq + 1 });
|
|
57
57
|
writeSnapshot(snapshotPath, next);
|
|
@@ -92,15 +92,15 @@ function normalizeEvent(event, fallbackId) {
|
|
|
92
92
|
}
|
|
93
93
|
|
|
94
94
|
function getJournalPath(rootDir, id) {
|
|
95
|
-
return path.join(rootDir, safeSessionId(id)
|
|
95
|
+
return path.join(rootDir, `${safeSessionId(id)}.jsonl`);
|
|
96
96
|
}
|
|
97
97
|
|
|
98
98
|
function getSnapshotPath(rootDir, id) {
|
|
99
|
-
return path.join(rootDir, safeSessionId(id)
|
|
99
|
+
return path.join(rootDir, `${safeSessionId(id)}.snapshot.json`);
|
|
100
100
|
}
|
|
101
101
|
|
|
102
102
|
function safeSessionId(id) {
|
|
103
|
-
if (!/^[A-Za-z0-9_-]{1,128}$/.test(id)) throw new Error(
|
|
103
|
+
if (!/^[A-Za-z0-9_-]{1,128}$/.test(id)) throw new Error(`invalid session id: ${id}`);
|
|
104
104
|
return id;
|
|
105
105
|
}
|
|
106
106
|
|
|
@@ -289,5 +289,5 @@ function upsertArtifact(artifacts, artifact) {
|
|
|
289
289
|
}
|
|
290
290
|
|
|
291
291
|
function writeSnapshot(snapshotPath, snapshot) {
|
|
292
|
-
fs.writeFileSync(snapshotPath, JSON.stringify(snapshot, null, 2)
|
|
292
|
+
fs.writeFileSync(snapshotPath, `${JSON.stringify(snapshot, null, 2)}\n`);
|
|
293
293
|
}
|
|
@@ -73,7 +73,7 @@ export function buildPropContract(expressions) {
|
|
|
73
73
|
|
|
74
74
|
function derivePropName(expr, index) {
|
|
75
75
|
const tail = expr.match(/(?:\.|\[)(\w+)\s*\]?$/);
|
|
76
|
-
if (tail
|
|
76
|
+
if (tail?.[1] && /^[A-Za-z_$][\w$]*$/.test(tail[1])) {
|
|
77
77
|
return tail[1];
|
|
78
78
|
}
|
|
79
79
|
return `prop${index}`;
|
|
@@ -166,7 +166,7 @@ export function scaffoldSvelteComponentSession({
|
|
|
166
166
|
runtimeModule: `/${SVELTE_RUNTIME_FILE}`,
|
|
167
167
|
};
|
|
168
168
|
|
|
169
|
-
fs.writeFileSync(path.join(dir, 'manifest.json'), JSON.stringify(manifest, null, 2)
|
|
169
|
+
fs.writeFileSync(path.join(dir, 'manifest.json'), `${JSON.stringify(manifest, null, 2)}\n`, 'utf-8');
|
|
170
170
|
|
|
171
171
|
for (let n = 1; n <= count; n++) {
|
|
172
172
|
const variantFile = path.join(dir, `v${n}.svelte`);
|
|
@@ -216,7 +216,7 @@ export function scaffoldSvelteComponentInsertSession({
|
|
|
216
216
|
runtimeModule: `/${SVELTE_RUNTIME_FILE}`,
|
|
217
217
|
};
|
|
218
218
|
|
|
219
|
-
fs.writeFileSync(path.join(dir, 'manifest.json'), JSON.stringify(manifest, null, 2)
|
|
219
|
+
fs.writeFileSync(path.join(dir, 'manifest.json'), `${JSON.stringify(manifest, null, 2)}\n`, 'utf-8');
|
|
220
220
|
|
|
221
221
|
for (let n = 1; n <= count; n++) {
|
|
222
222
|
const variantFile = path.join(dir, `v${n}.svelte`);
|
|
@@ -270,14 +270,14 @@ export function resolveSourceFile(sourceFile, cwd = process.cwd()) {
|
|
|
270
270
|
throw new Error('Svelte-component source file escapes project root');
|
|
271
271
|
}
|
|
272
272
|
if (!fs.existsSync(full)) {
|
|
273
|
-
throw new Error(
|
|
273
|
+
throw new Error(`Svelte-component source file not found: ${sourceFile}`);
|
|
274
274
|
}
|
|
275
275
|
return full;
|
|
276
276
|
}
|
|
277
277
|
|
|
278
278
|
function appendCssToSvelteStyle(lines, cssLines) {
|
|
279
279
|
const closeIdx = findLastStyleCloseLine(lines);
|
|
280
|
-
const prepared = ['', ...cssLines.map((line) => (line.trim() === '' ? '' :
|
|
280
|
+
const prepared = ['', ...cssLines.map((line) => (line.trim() === '' ? '' : ` ${line.trimStart()}`))];
|
|
281
281
|
if (closeIdx === -1) {
|
|
282
282
|
return [...lines, '', '<style>', ...prepared.slice(1), '</style>'];
|
|
283
283
|
}
|
|
@@ -436,7 +436,7 @@ function rewriteAcceptedSvelteSelectorPart(selector, variantNum, paramValues, ro
|
|
|
436
436
|
function rewriteParamSelectors(selector, paramValues) {
|
|
437
437
|
let keep = true;
|
|
438
438
|
const next = selector.replace(/\[data-p-([A-Za-z0-9_-]+)(?:=(["'])(.*?)\2)?\]/g, (_match, key, _quote, expected) => {
|
|
439
|
-
if (!paramValues || !Object.
|
|
439
|
+
if (!paramValues || !Object.hasOwn(paramValues, key)) return '';
|
|
440
440
|
const actual = paramValues[key];
|
|
441
441
|
if (expected != null && String(actual) !== String(expected)) {
|
|
442
442
|
keep = false;
|
|
@@ -537,7 +537,7 @@ export function inlineSvelteComponentAccept(manifest, variantNum, paramValues =
|
|
|
537
537
|
const start = Number(manifest.sourceStartLine) - 1;
|
|
538
538
|
const end = Number(manifest.sourceEndLine) - 1;
|
|
539
539
|
if (!Number.isInteger(start) || !Number.isInteger(end) || start < 0 || end < start || end >= sourceLines.length) {
|
|
540
|
-
return { handled: false, error:
|
|
540
|
+
return { handled: false, error: `Invalid source line range for ${manifest.sourceFile}`, ...resultBase };
|
|
541
541
|
}
|
|
542
542
|
|
|
543
543
|
const indent = sourceLines[start].match(/^(\s*)/)?.[1] || '';
|
|
@@ -561,7 +561,7 @@ export function inlineSvelteComponentAccept(manifest, variantNum, paramValues =
|
|
|
561
561
|
try {
|
|
562
562
|
fs.writeFileSync(sourceFile, newLines.join('\n'), 'utf-8');
|
|
563
563
|
} catch (err) {
|
|
564
|
-
return { handled: false, error:
|
|
564
|
+
return { handled: false, error: `Failed to write Svelte source: ${err.message}`, ...resultBase };
|
|
565
565
|
}
|
|
566
566
|
removeSvelteComponentSession(manifest.id, cwd);
|
|
567
567
|
|
|
@@ -596,7 +596,7 @@ function inlineSvelteComponentInsertAccept({
|
|
|
596
596
|
const sourceLines = sourceContent.split('\n');
|
|
597
597
|
const insertIndex = Number(manifest.insertLine) - 1;
|
|
598
598
|
if (!Number.isInteger(insertIndex) || insertIndex < 0 || insertIndex > sourceLines.length) {
|
|
599
|
-
return { handled: false, error:
|
|
599
|
+
return { handled: false, error: `Invalid insert line for ${manifest.sourceFile}`, ...resultBase };
|
|
600
600
|
}
|
|
601
601
|
|
|
602
602
|
const nearbyLine = sourceLines[insertIndex] ?? sourceLines[insertIndex - 1] ?? '';
|
|
@@ -621,7 +621,7 @@ function inlineSvelteComponentInsertAccept({
|
|
|
621
621
|
try {
|
|
622
622
|
fs.writeFileSync(sourceFile, newLines.join('\n'), 'utf-8');
|
|
623
623
|
} catch (err) {
|
|
624
|
-
return { handled: false, error:
|
|
624
|
+
return { handled: false, error: `Failed to write Svelte source: ${err.message}`, ...resultBase };
|
|
625
625
|
}
|
|
626
626
|
removeSvelteComponentSession(manifest.id, cwd);
|
|
627
627
|
|
|
@@ -675,7 +675,7 @@ function mergeOriginalTopLevelAttrs(markup, originalMarkup) {
|
|
|
675
675
|
const nextOpen = variantOpen.prefix
|
|
676
676
|
+ variantOpen.tag
|
|
677
677
|
+ attrs
|
|
678
|
-
+ additions.map((attr) =>
|
|
678
|
+
+ additions.map((attr) => ` ${attr.trim()}`).join('')
|
|
679
679
|
+ variantOpen.close;
|
|
680
680
|
return markup.slice(0, variantOpen.index) + nextOpen + markup.slice(variantOpen.index + variantOpen.raw.length);
|
|
681
681
|
}
|
|
@@ -761,7 +761,7 @@ export function writeDeferredAccept(entry, cwd = process.cwd()) {
|
|
|
761
761
|
const data = readDeferredAccepts(cwd);
|
|
762
762
|
data.accepts = (data.accepts || []).filter((item) => item.id !== entry.id);
|
|
763
763
|
data.accepts.push({ ...entry, createdAt: new Date().toISOString() });
|
|
764
|
-
fs.writeFileSync(file, JSON.stringify(data, null, 2)
|
|
764
|
+
fs.writeFileSync(file, `${JSON.stringify(data, null, 2)}\n`, 'utf-8');
|
|
765
765
|
}
|
|
766
766
|
|
|
767
767
|
export function applyDeferredSvelteComponentAccepts(cwd = process.cwd()) {
|
|
@@ -792,7 +792,7 @@ export function applyDeferredSvelteComponentAccepts(cwd = process.cwd()) {
|
|
|
792
792
|
}
|
|
793
793
|
}
|
|
794
794
|
if (remaining.length > 0) {
|
|
795
|
-
fs.writeFileSync(file, JSON.stringify({ accepts: remaining }, null, 2)
|
|
795
|
+
fs.writeFileSync(file, `${JSON.stringify({ accepts: remaining }, null, 2)}\n`, 'utf-8');
|
|
796
796
|
} else {
|
|
797
797
|
try { fs.rmSync(file, { force: true }); } catch {}
|
|
798
798
|
}
|
|
@@ -103,9 +103,9 @@ export function patchSvelteLayout(content) {
|
|
|
103
103
|
const scriptMatch = out.match(/<script(?:\s[^>]*)?>/i);
|
|
104
104
|
if (scriptMatch) {
|
|
105
105
|
const insertAt = scriptMatch.index + scriptMatch[0].length;
|
|
106
|
-
out = out.slice(0, insertAt)
|
|
106
|
+
out = `${out.slice(0, insertAt)}\n ${SVELTE_ROOT_IMPORT}${out.slice(insertAt)}`;
|
|
107
107
|
} else {
|
|
108
|
-
out = `<script>\n ${SVELTE_ROOT_IMPORT}\n</script>\n\n
|
|
108
|
+
out = `<script>\n ${SVELTE_ROOT_IMPORT}\n</script>\n\n${out}`;
|
|
109
109
|
}
|
|
110
110
|
}
|
|
111
111
|
|
|
@@ -117,7 +117,7 @@ export function patchSvelteLayout(content) {
|
|
|
117
117
|
if (match) {
|
|
118
118
|
out = out.slice(0, match.index) + block + out.slice(match.index);
|
|
119
119
|
} else {
|
|
120
|
-
out = out.replace(/\s*$/,
|
|
120
|
+
out = out.replace(/\s*$/, `\n\n${block}`);
|
|
121
121
|
}
|
|
122
122
|
}
|
|
123
123
|
|
|
@@ -134,7 +134,7 @@ export function unpatchSvelteLayout(content) {
|
|
|
134
134
|
'g',
|
|
135
135
|
);
|
|
136
136
|
out = out.replace(blockRe, '$1');
|
|
137
|
-
out = out.replace(new RegExp(
|
|
137
|
+
out = out.replace(new RegExp(`^\\s*${escapeRegExp(SVELTE_ROOT_IMPORT)}\\s*\\n?`, 'gm'), '');
|
|
138
138
|
out = out.replace(/<script>\s*<\/script>\s*\n?/g, '');
|
|
139
139
|
return out.replace(/\n{3,}/g, '\n\n');
|
|
140
140
|
}
|
|
@@ -140,7 +140,7 @@ export function getLiveUiElementById(id, env = globalThis) {
|
|
|
140
140
|
if (found) return found;
|
|
141
141
|
}
|
|
142
142
|
if (root?.querySelector) {
|
|
143
|
-
const found = root.querySelector(
|
|
143
|
+
const found = root.querySelector(`#${escapeCssIdent(id)}`);
|
|
144
144
|
if (found) return found;
|
|
145
145
|
}
|
|
146
146
|
return doc?.getElementById?.(id) || null;
|
|
@@ -76,7 +76,7 @@ Output (JSON):
|
|
|
76
76
|
const svelteComponentManifest = found ? null : findSvelteComponentManifest(id, process.cwd());
|
|
77
77
|
|
|
78
78
|
if (!found && !svelteComponentManifest) {
|
|
79
|
-
console.log(JSON.stringify({ handled: false, error:
|
|
79
|
+
console.log(JSON.stringify({ handled: false, error: `Session markers not found for id: ${id}` }));
|
|
80
80
|
process.exit(0);
|
|
81
81
|
}
|
|
82
82
|
|
|
@@ -112,7 +112,7 @@ Output (JSON):
|
|
|
112
112
|
};
|
|
113
113
|
}
|
|
114
114
|
if (result.carbonize) {
|
|
115
|
-
result.todo =
|
|
115
|
+
result.todo = `REQUIRED before next poll: carbonize cleanup in ${result.file}. See reference/live.md "Required after accept".`;
|
|
116
116
|
}
|
|
117
117
|
console.log(JSON.stringify({ handled: result.handled !== false, ...result }));
|
|
118
118
|
return;
|
|
@@ -155,7 +155,7 @@ Output (JSON):
|
|
|
155
155
|
// five-step checklist lives in reference/live.md (loaded once per
|
|
156
156
|
// session); repeating it per-event would waste tokens.
|
|
157
157
|
if (result.carbonize) {
|
|
158
|
-
result.todo =
|
|
158
|
+
result.todo = `REQUIRED before next poll: carbonize cleanup in ${relFile}. See reference/live.md "Required after accept".`;
|
|
159
159
|
}
|
|
160
160
|
// Scrub stash entries whose text appeared inside the just-replaced
|
|
161
161
|
// original wrap block. The accept embodies those manual edits (wrap was
|
|
@@ -292,29 +292,29 @@ function buildCarbonizeReplacement({
|
|
|
292
292
|
: 'style="display: contents"';
|
|
293
293
|
|
|
294
294
|
const pushCarbonizeBody = (bodyIndent) => {
|
|
295
|
-
const bodyRestored = reindentContent(restored, indent, bodyIndent
|
|
296
|
-
lines.push(bodyIndent + commentSyntax.open
|
|
297
|
-
lines.push(bodyIndent
|
|
295
|
+
const bodyRestored = reindentContent(restored, indent, `${bodyIndent} `);
|
|
296
|
+
lines.push(`${bodyIndent + commentSyntax.open} monodesign-carbonize-start ${id} ${commentSyntax.close}`);
|
|
297
|
+
lines.push(`${bodyIndent}<style data-monodesign-css="${id}">${isJsx ? '{`' : ''}`);
|
|
298
298
|
for (const cssLine of cssContent) {
|
|
299
299
|
lines.push(bodyIndent + cssLine.trimStart());
|
|
300
300
|
}
|
|
301
301
|
lines.push(bodyIndent + (isJsx ? '`}</style>' : '</style>'));
|
|
302
302
|
if (paramValues && Object.keys(paramValues).length > 0) {
|
|
303
303
|
lines.push(
|
|
304
|
-
bodyIndent + commentSyntax.open
|
|
304
|
+
`${bodyIndent + commentSyntax.open} monodesign-param-values ${id}: ${JSON.stringify(paramValues)} ${commentSyntax.close}`,
|
|
305
305
|
);
|
|
306
306
|
}
|
|
307
|
-
lines.push(bodyIndent + commentSyntax.open
|
|
308
|
-
lines.push(bodyIndent
|
|
307
|
+
lines.push(`${bodyIndent + commentSyntax.open} monodesign-carbonize-end ${id} ${commentSyntax.close}`);
|
|
308
|
+
lines.push(`${bodyIndent}<div data-monodesign-variant="${variantNum}" ${variantStyleAttr}>`);
|
|
309
309
|
lines.push(...bodyRestored);
|
|
310
|
-
lines.push(bodyIndent
|
|
310
|
+
lines.push(`${bodyIndent}</div>`);
|
|
311
311
|
};
|
|
312
312
|
|
|
313
313
|
if (isJsx) {
|
|
314
314
|
const wrapperStyle = 'style={{ display: "contents" }}';
|
|
315
|
-
lines.push(indent
|
|
316
|
-
pushCarbonizeBody(indent
|
|
317
|
-
lines.push(indent
|
|
315
|
+
lines.push(`${indent}<div data-monodesign-carbonize="${id}" ${wrapperStyle}>`);
|
|
316
|
+
pushCarbonizeBody(`${indent} `);
|
|
317
|
+
lines.push(`${indent}</div>`);
|
|
318
318
|
} else {
|
|
319
319
|
pushCarbonizeBody(indent);
|
|
320
320
|
}
|
|
@@ -345,7 +345,7 @@ function handleAccept(id, variantNum, lines, targetFile, paramValues) {
|
|
|
345
345
|
|
|
346
346
|
// Extract the chosen variant's inner content
|
|
347
347
|
const variantContent = extractVariant(lines, block, variantNum);
|
|
348
|
-
if (!variantContent) return { handled: false, error:
|
|
348
|
+
if (!variantContent) return { handled: false, error: `Variant ${variantNum} not found` };
|
|
349
349
|
const originalContent = extractOriginal(lines, block);
|
|
350
350
|
|
|
351
351
|
// Extract CSS block if present
|
|
@@ -382,7 +382,7 @@ function handleAccept(id, variantNum, lines, targetFile, paramValues) {
|
|
|
382
382
|
|
|
383
383
|
function readSourceShadowPreviewMeta(content, id) {
|
|
384
384
|
const escaped = escapeRegExp(id);
|
|
385
|
-
const wrapperRe = new RegExp(
|
|
385
|
+
const wrapperRe = new RegExp(`<[^>]+data-monodesign-variants=(["'])${escaped}\\1[^>]*>`);
|
|
386
386
|
const match = String(content || '').match(wrapperRe);
|
|
387
387
|
if (!match) return null;
|
|
388
388
|
const tag = match[0];
|
|
@@ -395,7 +395,7 @@ function readSourceShadowPreviewMeta(content, id) {
|
|
|
395
395
|
}
|
|
396
396
|
|
|
397
397
|
function readHtmlAttr(tag, name) {
|
|
398
|
-
const match = String(tag || '').match(new RegExp(
|
|
398
|
+
const match = String(tag || '').match(new RegExp(`\\s${escapeRegExp(name)}\\s*=\\s*(["'])(.*?)\\1`));
|
|
399
399
|
if (!match) return null;
|
|
400
400
|
return decodeHtmlAttr(match[2]);
|
|
401
401
|
}
|
|
@@ -419,8 +419,8 @@ function decodeHtmlAttr(value) {
|
|
|
419
419
|
function findMarkerBlock(id, lines) {
|
|
420
420
|
let start = -1;
|
|
421
421
|
let end = -1;
|
|
422
|
-
const startPattern =
|
|
423
|
-
const endPattern =
|
|
422
|
+
const startPattern = `monodesign-variants-start ${id}`;
|
|
423
|
+
const endPattern = `monodesign-variants-end ${id}`;
|
|
424
424
|
|
|
425
425
|
for (let i = 0; i < lines.length; i++) {
|
|
426
426
|
if (start === -1 && lines[i].includes(startPattern)) start = i;
|
|
@@ -504,7 +504,7 @@ function escapeRegExp(value) {
|
|
|
504
504
|
}
|
|
505
505
|
|
|
506
506
|
function isVariantEndMarkerLine(line, id) {
|
|
507
|
-
return new RegExp(
|
|
507
|
+
return new RegExp(`monodesign-variants-end\\s+${escapeRegExp(id)}(?:\\s|--|\\*/|$)`).test(line);
|
|
508
508
|
}
|
|
509
509
|
|
|
510
510
|
function hasVariantWrapperAttr(line, id) {
|
|
@@ -562,7 +562,7 @@ function stripStyleAndJoin(lines, block) {
|
|
|
562
562
|
* Returns the inner string (may be empty), or null if not found.
|
|
563
563
|
*/
|
|
564
564
|
function extractInnerByAttr(text, attrMatch) {
|
|
565
|
-
const openerRe = new RegExp(
|
|
565
|
+
const openerRe = new RegExp(`<([A-Za-z][A-Za-z0-9]*)\\b[^>]*${attrMatch}[^>]*>`);
|
|
566
566
|
const openMatch = text.match(openerRe);
|
|
567
567
|
if (!openMatch) return null;
|
|
568
568
|
|
|
@@ -571,7 +571,7 @@ function extractInnerByAttr(text, attrMatch) {
|
|
|
571
571
|
|
|
572
572
|
// Match any opener or closer of this tag name after innerStart.
|
|
573
573
|
// (Does not match self-closing <TAG … />, which doesn't contribute to depth.)
|
|
574
|
-
const tagRe = new RegExp(
|
|
574
|
+
const tagRe = new RegExp(`<(?:/)?${tagName}\\b[^>]*>`, 'g');
|
|
575
575
|
tagRe.lastIndex = innerStart;
|
|
576
576
|
|
|
577
577
|
let depth = 1;
|
|
@@ -606,7 +606,7 @@ function extractOriginal(lines, block) {
|
|
|
606
606
|
*/
|
|
607
607
|
function extractVariant(lines, block, variantNum) {
|
|
608
608
|
const text = stripStyleAndJoin(lines, block);
|
|
609
|
-
const inner = extractInnerByAttr(text,
|
|
609
|
+
const inner = extractInnerByAttr(text, `data-monodesign-variant="${variantNum}"`);
|
|
610
610
|
if (inner === null) return null;
|
|
611
611
|
const result = inner.split('\n');
|
|
612
612
|
// Collapse a lone empty leading/trailing line (common after string splice).
|
|
@@ -626,7 +626,7 @@ function extractVariant(lines, block, variantNum) {
|
|
|
626
626
|
* the lines between them.
|
|
627
627
|
*/
|
|
628
628
|
function extractCss(lines, block, id) {
|
|
629
|
-
const styleAttr =
|
|
629
|
+
const styleAttr = `data-monodesign-css="${id}"`;
|
|
630
630
|
let inStyle = false;
|
|
631
631
|
const content = [];
|
|
632
632
|
|
|
@@ -747,7 +747,7 @@ function detectCommentSyntax(filePath) {
|
|
|
747
747
|
// ---------------------------------------------------------------------------
|
|
748
748
|
|
|
749
749
|
function findSessionFile(id, cwd) {
|
|
750
|
-
const marker =
|
|
750
|
+
const marker = `monodesign-variants-start ${id}`;
|
|
751
751
|
const searchDirs = ['src', 'app', 'pages', 'components', 'public', 'views', 'templates', '.'];
|
|
752
752
|
const seen = new Set();
|
|
753
753
|
|
|
@@ -5,7 +5,8 @@
|
|
|
5
5
|
* chrome mounting, lookup, focus, and picker helpers without depending on the
|
|
6
6
|
* full overlay UI bundle.
|
|
7
7
|
*/
|
|
8
|
-
(
|
|
8
|
+
((root) => {
|
|
9
|
+
// biome-ignore lint/suspicious/noRedundantUseStrict: served to the page as a classic <script> (not an ES module despite package type=module), so this directive is what enables strict mode
|
|
9
10
|
'use strict';
|
|
10
11
|
if (!root) return;
|
|
11
12
|
|
|
@@ -21,11 +22,11 @@
|
|
|
21
22
|
const tagsToSkip = skipTags || new Set();
|
|
22
23
|
|
|
23
24
|
function own(el) {
|
|
24
|
-
return el && (el.id?.startsWith(prefix) || el.closest?.(
|
|
25
|
+
return el && (el.id?.startsWith(prefix) || el.closest?.(`[id^="${prefix}"]`));
|
|
25
26
|
}
|
|
26
27
|
|
|
27
28
|
function pickable(el) {
|
|
28
|
-
if (
|
|
29
|
+
if (el?.nodeType !== 1) return false;
|
|
29
30
|
if (tagsToSkip.has(String(el.tagName || '').toLowerCase())) return false;
|
|
30
31
|
if (own(el)) return false;
|
|
31
32
|
const r = el.getBoundingClientRect();
|
|
@@ -35,8 +36,8 @@
|
|
|
35
36
|
function desc(el) {
|
|
36
37
|
if (!el) return '';
|
|
37
38
|
let s = el.tagName.toLowerCase();
|
|
38
|
-
if (el.id) s +=
|
|
39
|
-
else if (el.classList.length) s +=
|
|
39
|
+
if (el.id) s += `#${el.id}`;
|
|
40
|
+
else if (el.classList.length) s += `.${[...el.classList].slice(0, 2).join('.')}`;
|
|
40
41
|
return s;
|
|
41
42
|
}
|
|
42
43
|
|
|
@@ -45,7 +46,7 @@
|
|
|
45
46
|
}
|
|
46
47
|
|
|
47
48
|
function makeFrozenAnchor(el) {
|
|
48
|
-
if (!el
|
|
49
|
+
if (!el?.getBoundingClientRect) return null;
|
|
49
50
|
const r = el.getBoundingClientRect();
|
|
50
51
|
if (!rectIsUsableAnchor(r)) return null;
|
|
51
52
|
const rect = {
|
|
@@ -99,7 +100,7 @@
|
|
|
99
100
|
if (found) return found;
|
|
100
101
|
}
|
|
101
102
|
if (uiRoot?.querySelector) {
|
|
102
|
-
const found = uiRoot.querySelector(
|
|
103
|
+
const found = uiRoot.querySelector(`#${cssId(id)}`);
|
|
103
104
|
if (found) return found;
|
|
104
105
|
}
|
|
105
106
|
return doc.getElementById(id);
|
|
@@ -5,16 +5,17 @@
|
|
|
5
5
|
* booting the full overlay UI. Served before live-browser.js and attached to
|
|
6
6
|
* window.__MONODESIGN_LIVE_SESSION__.
|
|
7
7
|
*/
|
|
8
|
-
(
|
|
8
|
+
((root) => {
|
|
9
|
+
// biome-ignore lint/suspicious/noRedundantUseStrict: served to the page as a classic <script> (not an ES module despite package type=module), so this directive is what enables strict mode
|
|
9
10
|
'use strict';
|
|
10
11
|
|
|
11
12
|
function createLiveBrowserSessionState({ prefix, storage, idFactory }) {
|
|
12
13
|
if (!prefix) throw new Error('prefix required');
|
|
13
14
|
const store = storage || root.localStorage;
|
|
14
|
-
const makeId = idFactory ||
|
|
15
|
-
const sessionKey = prefix
|
|
16
|
-
const handledKey = sessionKey
|
|
17
|
-
const scrollKey = sessionKey
|
|
15
|
+
const makeId = idFactory || (() => Math.random().toString(16).slice(2, 10));
|
|
16
|
+
const sessionKey = `${prefix}-session`;
|
|
17
|
+
const handledKey = `${sessionKey}-handled`;
|
|
18
|
+
const scrollKey = `${sessionKey}-scroll`;
|
|
18
19
|
let checkpointRevision = 0;
|
|
19
20
|
const owner = makeId();
|
|
20
21
|
|
|
@@ -43,7 +44,7 @@
|
|
|
43
44
|
}
|
|
44
45
|
|
|
45
46
|
function saveSession(session) {
|
|
46
|
-
if (!session
|
|
47
|
+
if (!session?.id) return;
|
|
47
48
|
const payload = {
|
|
48
49
|
...session,
|
|
49
50
|
checkpointRevision,
|
|
@@ -92,7 +93,7 @@
|
|
|
92
93
|
const raw = safeRead(scrollKey);
|
|
93
94
|
if (raw == null) return null;
|
|
94
95
|
const n = parseFloat(raw);
|
|
95
|
-
return isFinite(n) ? n : null;
|
|
96
|
+
return Number.isFinite(n) ? n : null;
|
|
96
97
|
}
|
|
97
98
|
|
|
98
99
|
function clearScrollY() {
|