Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
44 changes: 0 additions & 44 deletions contracts/animTokens.js

This file was deleted.

6 changes: 6 additions & 0 deletions core/diffusionController.ts
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,12 @@ export function createDiffusionController(
policy?: ActiveRegionPolicy,
getLMAdapter?: () => LMAdapter | null | undefined,
) {
// ⟢ Orchestrates the three-stage pipeline:
// 1) Noise: cheap, deterministic fixes within a short window behind caret
// 2) Context: sentence-scale repairs; may plan LM corrections
// 3) Tone: optional rephrasing within caret-safe pre-caret range
// The controller also renders the active region and applies LM streaming diffs
// with strict caret-safety. UndoIsolation groups system edits separately.
// Safari/older browsers: Intl.Segmenter may be missing or partial. Provide a fallback.
let seg: Intl.Segmenter | null = null;
try {
Expand Down
14 changes: 7 additions & 7 deletions core/lm/types.generated.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,12 @@
/* Auto-generated by doc2code — do not edit by hand */

export interface LMStreamParams {
text: string;
caret: number;
active_region: { start: number; end: number };
settings?: Record<string, unknown>;
}

export interface AnimTokens {
waveSpeed: number;
waveSpread: number;
Expand All @@ -13,10 +20,3 @@ export const DEFAULT_SYMBOLS = [
'\u2800','\u2802','\u2804','\u2806','\u2810','\u2812','\u2814','\u2816',
'\u2820','\u2822','\u2824','\u2826','\u2830','\u2832','\u2834','\u2836',
] as const;

export interface LMStreamParams {
text: string;
caret: number;
active_region: { start: number; end: number };
settings?: Record<string, unknown>;
}
2 changes: 1 addition & 1 deletion demo/mt-braille-animation-v1/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width,initial-scale=1,viewport-fit=cover" />
<title>Mind Type — Braille Flicker</title>
<meta name="mt-version" content="0.2.0-alpha" />
<meta name="mt-version" content="0.5.0" />
<meta name="mt-last-updated" content="" />
<link rel="stylesheet" href="../_shared/header.css" />
<link rel="stylesheet" href="./styles.css" />
Expand Down
56 changes: 26 additions & 30 deletions docs/traceability.json
Original file line number Diff line number Diff line change
Expand Up @@ -198,35 +198,6 @@
"types": [],
"source": "docs/02-implementation/02-Implementation.md"
},
"CONTRACT-DOT-MATRIX-WAVE": {
"kind": "CONTRACT",
"title": "Dot-matrix wave animation tokens",
"modules": [
"contracts/animTokens.ts",
"demo/dot-matrix-wave/main.js"
],
"acceptance": [],
"tests": [],
"invariants": [
{
"Preserve layout": "no per-char DOM mutations; overlay only"
},
{
"Reduced-motion": "static correction highlight, no rAF"
}
],
"types": [
{
"name": "AnimTokens",
"ts": "export interface AnimTokens {\n waveSpeed: number;\n waveSpread: number;\n waveMix: number; // 0..100\n symbolSet: string[];\n autoplay: boolean;\n playhead: number; // 0..100\n}\n"
},
{
"name": "DEFAULT_SYMBOLS",
"ts": "export const DEFAULT_SYMBOLS = [\n '\\u2800','\\u2802','\\u2804','\\u2806','\\u2810','\\u2812','\\u2814','\\u2816',\n '\\u2820','\\u2822','\\u2824','\\u2826','\\u2830','\\u2832','\\u2834','\\u2836',\n] as const;\n"
}
],
"source": "docs/06-guides/dot-matrix-wave.md"
},
"CONTRACT-ACTIVE-REGION": {
"kind": "CONTRACT",
"title": "Active region policy (render vs context ranges)",
Expand Down Expand Up @@ -258,7 +229,7 @@
"types": [
{
"name": "LMStreamParams",
"ts": "export interface LMStreamParams {\n text: string;\n caret: number;\n active_region: { start: number; end: number };\n settings?: Record<string, unknown>;\n}\n"
"ts": "export interface LMStreamParams {\n text: string;\n caret: number;\n active_region: { start: number; end: number };\n settings?: Record<string, unknown>;\n}"
}
],
"source": "docs/06-guides/06-03-reference/lm-behavior.md"
Expand All @@ -282,5 +253,30 @@
],
"types": [],
"source": "docs/06-guides/06-03-reference/lm-stream.md"
},
"CONTRACT-DOT-MATRIX-WAVE": {
"kind": "CONTRACT",
"title": "Dot-matrix wave animation tokens",
"modules": [
"contracts/animTokens.ts",
"demo/dot-matrix-wave/main.js"
],
"acceptance": [],
"tests": [],
"invariants": [
"Preserve layout: no per-char DOM mutations; overlay only",
"Reduced-motion: static correction highlight, no rAF"
],
"types": [
{
"name": "AnimTokens",
"ts": "export interface AnimTokens {\n waveSpeed: number;\n waveSpread: number;\n waveMix: number; // 0..100\n symbolSet: string[];\n autoplay: boolean;\n playhead: number; // 0..100\n}"
},
{
"name": "DEFAULT_SYMBOLS",
"ts": "export const DEFAULT_SYMBOLS = [\n '\\u2800','\\u2802','\\u2804','\\u2806','\\u2810','\\u2812','\\u2814','\\u2816',\n '\\u2820','\\u2822','\\u2824','\\u2826','\\u2830','\\u2832','\\u2834','\\u2836',\n] as const;"
}
],
"source": "docs/06-guides/dot-matrix-wave.md"
}
}
4 changes: 4 additions & 0 deletions engines/contextTransformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -118,6 +118,10 @@ export async function contextTransform(
lmAdapter?: LMAdapter,
contextManager?: LMContextManager,
): Promise<TransformResult> {
// ⟢ Builds a sentence-aware window and proposes caret-safe diffs.
// - Deterministic repairs first (cheap, predictable)
// - Optional LM pass uses policy-driven band selection and confidence gating
// - Never edits at/after caret; proposals are clamped to pre-caret span
const { text, caret } = input;
// Enhanced diagnostic logging for LM-501
const diagnosticId = `ctx-${Date.now().toString(36)}-${Math.random().toString(36).slice(2, 6)}`;
Expand Down
3 changes: 3 additions & 0 deletions engines/noiseTransformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -330,6 +330,9 @@ const RULES: NoiseRule[] = [
export function noiseTransform(input: NoiseInput): NoiseResult {
const { text, caret } = input;

// ⟢ Fast path: run a small set of rules in priority order and return
// the rightmost safe diff behind the caret. This keeps the UI snappy
// and avoids changing text near the user's current typing position.
console.log('[Noise] Processing:', { text, caret });

// Safety check: never edit at or after the caret
Expand Down
3 changes: 3 additions & 0 deletions engines/toneTransformer.ts
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,9 @@ export function planAdjustments(
text: string,
caret: number,
): ToneProposal[] {
// ⟢ Produces caret-safe style adjustments (pre-caret only).
// Professional → expand contractions; Casual → introduce a few.
// Keeps changes minimal and explainable; LM can later refine phrasing.
if (target === 'None') return [];
// Operate on last sentences before the caret only (caret-safe)
const upto = caret;
Expand Down
152 changes: 146 additions & 6 deletions scripts/doc2code.cjs
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,7 @@
const fs = require('fs');
const path = require('path');
// ⟢ Deps
const fg = require('fast-glob');
const yaml = require('js-yaml');
// NOTE: Avoid external deps to keep scripts runnable without install

const REPO_ROOT = path.resolve(__dirname, '..');
const DOCS_DIR = path.join(REPO_ROOT, 'docs');
Expand All @@ -40,7 +39,7 @@ function extractSpecBlocks(markdownText, filePath) {
const kind = m[1].trim();
const body = m[2];
try {
const data = yaml.load(body);
const data = parseSpecYaml(body);
if (!data || typeof data !== 'object') continue;
data.__kind = kind;
data.__source = filePath;
Expand All @@ -55,11 +54,152 @@ function extractSpecBlocks(markdownText, filePath) {
return blocks;
}

/**
* Minimal YAML parser for SPEC blocks. Supports a safe subset:
* - key: value (scalars)
* - key: (array) with indented dash items (- item)
* - key: (array of objects) started with '- name:' style
* - special handling for 'ts: |' multiline blocks indented under a list item
*/
function parseSpecYaml(body) {
const lines = body
.replace(/^[\r\n]+|[\r\n]+$/g, '')
.split(/\r?\n/);
let i = 0;
const root = {};
let currentKey = null;
let currentArray = null;
let inMultiline = false;
let multilineIndent = 0;
let multilineTarget = null; // {obj, key}

function indentOf(s) {
let n = 0;
while (n < s.length && s[n] === ' ') n++;
return n;
}

function setScalar(obj, key, value) {
if (value === 'true') return (obj[key] = true);
if (value === 'false') return (obj[key] = false);
if (value === 'null') return (obj[key] = null);
// number?
if (/^-?\d+(?:\.\d+)?$/.test(value)) return (obj[key] = Number(value));
return (obj[key] = value);
}

while (i < lines.length) {
const raw = lines[i];
const line = raw.replace(/\t/g, ' ');
i++;
if (!line.trim()) continue;

if (inMultiline) {
const ind = indentOf(line);
if (ind < multilineIndent) {
// end block
inMultiline = false;
multilineIndent = 0;
multilineTarget = null;
// fallthrough to normal processing of this line
} else {
const text = line.slice(multilineIndent);
multilineTarget.obj[multilineTarget.key] += (multilineTarget.obj[multilineTarget.key]
? '\n'
: '') + text;
continue;
}
}

const ind = indentOf(line);
const trimmed = line.slice(ind);

// Top-level key
if (ind === 0 && /:\s*/.test(trimmed) && !trimmed.startsWith('- ')) {
const [k, rest] = trimmed.split(/:\s*/, 2);
currentKey = k.trim();
if (rest === '') {
// key: (will expect list or map)
root[currentKey] = undefined;
currentArray = null;
} else {
setScalar(root, currentKey, rest.trim());
currentArray = null;
}
continue;
}

// Array items under currentKey
if (currentKey && ind > 0 && trimmed.startsWith('- ')) {
if (!Array.isArray(root[currentKey])) root[currentKey] = [];
currentArray = root[currentKey];
const afterDash = trimmed.slice(2);
// Object item like: "name: Foo" or scalar item
if (/^\w+\s*:/.test(afterDash)) {
const obj = {};
currentArray.push(obj);
// parse in-line first k:v
const [k, rest] = afterDash.split(/:\s*/, 2);
setScalar(obj, k.trim(), (rest || '').trim());
// Now parse following indented object lines
const baseIndent = ind + 2; // indent after '- '
while (i < lines.length) {
const peekRaw = lines[i];
const peek = peekRaw.replace(/\t/g, ' ');
const pind = indentOf(peek);
if (pind <= ind) break;
i++;
const ptrim = peek.slice(pind);
if (!/:\s*/.test(ptrim)) continue;
const [pk, prest] = ptrim.split(/:\s*/, 2);
const key = pk.trim();
const val = (prest || '').trim();
if (val === '|') {
// multiline block begins; consume subsequent lines with greater indent
obj[key] = '';
inMultiline = true;
multilineIndent = pind + 2; // expect additional indent for block content
multilineTarget = { obj, key };
break;
} else {
setScalar(obj, key, val);
}
}
} else {
// Scalar list item
currentArray.push(afterDash.trim());
}
continue;
}
}

return root;
}

function readAllSpecs() {
const files = fg.sync(['docs/**/*.md'], { cwd: REPO_ROOT, dot: false });
const docsRoot = path.join(REPO_ROOT, 'docs');
/**
* Recursively collect markdown files under docs/ using only fs APIs.
*/
function walkMarkdownFiles(dirAbs, out) {
const entries = fs.readdirSync(dirAbs, { withFileTypes: true });
for (const entry of entries) {
if (entry.name.startsWith('.')) continue; // skip dotfiles
const childAbs = path.join(dirAbs, entry.name);
if (entry.isDirectory()) {
walkMarkdownFiles(childAbs, out);
} else if (entry.isFile() && entry.name.toLowerCase().endsWith('.md')) {
out.push(childAbs);
}
}
}
const fileAbsPaths = [];
if (fs.existsSync(docsRoot)) {
walkMarkdownFiles(docsRoot, fileAbsPaths);
}
const specs = [];
for (const rel of files) {
const abs = path.join(REPO_ROOT, rel);
for (const abs of fileAbsPaths) {
const rel = path.relative(REPO_ROOT, abs).split(path.sep).join('/');
const md = fs.readFileSync(abs, 'utf8');
const blocks = extractSpecBlocks(md, rel);
specs.push(...blocks);
Expand Down
1 change: 1 addition & 0 deletions ui/highlighter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ interface MinimalGlobal {
}

export function renderHighlight(_range: { start: number; end: number; text?: string }) {
// ⟢ Host-agnostic event to visualize applied changes (e.g., underline, flash)
const g = globalThis as unknown as MinimalGlobal;
if (g.dispatchEvent && g.CustomEvent) {
const event = new g.CustomEvent('mindtype:highlight', {
Expand Down
Loading
Loading