mastermind-md 0.1.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/skills/master/SKILL.md +10 -0
- package/.claude/skills/mastermind/SKILL.md +61 -0
- package/.claude/skills/mastermind/reference/demo.md +35 -0
- package/LICENSE +21 -0
- package/README.md +135 -0
- package/assets/agent/global.md +12 -0
- package/bin/mastermind.js +17 -0
- package/dist/cli/index.js +1284 -0
- package/dist/cli/index.js.map +1 -0
- package/dist/server/index.js +1752 -0
- package/dist/server/index.js.map +1 -0
- package/dist/ui/assets/FindBar-CSKdPrxm.js +1 -0
- package/dist/ui/assets/RenameDialog-C6yP_6D8.js +1 -0
- package/dist/ui/assets/SettingsPanel-C6-wwvJr.js +1 -0
- package/dist/ui/assets/SourceEditor-DN44HaIZ.js +37 -0
- package/dist/ui/assets/TranslatedView-G29rKesM.js +1 -0
- package/dist/ui/assets/index-Bhf9eUP2.css +1 -0
- package/dist/ui/assets/index-cMAuoyhV.js +99 -0
- package/dist/ui/assets/jsx-runtime-BrnrUjgG.js +1 -0
- package/dist/ui/assets/react-DoK4WR2u.js +1 -0
- package/dist/ui/index.html +16 -0
- package/package.json +91 -0
- package/themes/carbon/theme.json +11 -0
- package/themes/carbon/tokens.css +67 -0
- package/themes/cobalt/theme.json +11 -0
- package/themes/cobalt/tokens.css +67 -0
- package/themes/fonts/BricolageGrotesque-Variable.woff2 +0 -0
- package/themes/fonts/CrimsonPro-Variable.woff2 +0 -0
- package/themes/fonts/Fraunces-Variable.woff2 +0 -0
- package/themes/fonts/GeistSans-Variable.woff2 +0 -0
- package/themes/fonts/HankenGrotesk-Variable.woff2 +0 -0
- package/themes/fonts/Inter-Variable.woff2 +0 -0
- package/themes/fonts/JetBrainsMono-Variable.woff2 +0 -0
- package/themes/fonts/Lora-Variable.woff2 +0 -0
- package/themes/fonts/Manrope-Variable.woff2 +0 -0
- package/themes/fonts/Newsreader-Variable.woff2 +0 -0
- package/themes/fonts/Outfit-Variable.woff2 +0 -0
- package/themes/fonts/SpaceGrotesk-Variable.woff2 +0 -0
- package/themes/fonts/SplineSansMono-Variable.woff2 +0 -0
- package/themes/fonts/UbuntuSansMono-Variable.woff2 +0 -0
- package/themes/grid/fonts/GeistMono-Variable.woff2 +0 -0
- package/themes/grid/fonts/SchibstedGrotesk-Variable.woff2 +0 -0
- package/themes/grid/theme.json +11 -0
- package/themes/grid/tokens.css +67 -0
- package/themes/nacht/theme.json +11 -0
- package/themes/nacht/tokens.css +67 -0
- package/themes/rose/theme.json +11 -0
- package/themes/rose/tokens.css +67 -0
- package/themes/sepia/theme.json +11 -0
- package/themes/sepia/tokens.css +67 -0
- package/themes/slate/theme.json +11 -0
- package/themes/slate/tokens.css +67 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/cli/index.ts","../../package.json","../../src/server/paths.ts","../../src/server/statefile.ts","../../src/cli/daemon.ts","../../src/cli/http.ts","../../src/cli/sse.ts","../../src/cli/wait.ts","../../src/server/config.ts","../../src/shared/constants.ts","../../src/shared/critic/scanner.ts","../../src/shared/markdown/processor.ts","../../src/shared/markdown/exclusions.ts","../../src/shared/blocks.ts","../../src/shared/languages.ts","../../src/shared/translate-direction.ts","../../src/server/translate/cache.ts","../../src/server/translate/pretranslate.ts","../../src/cli/config-edit.ts","../../src/cli/browser-open.ts","../../src/cli/install-agents.ts"],"sourcesContent":["import { Command } from 'commander'\nimport { spawn } from 'node:child_process'\nimport fs from 'node:fs'\nimport path from 'node:path'\nimport os from 'node:os'\nimport pkg from '../../package.json'\nimport type { CreateSessionResponse, CreateWorkspaceResponse, MastermindConfig, ServerState } from '../shared/types'\nimport { pkgRoot, serverLogPath } from '../server/paths'\nimport { readServerState } from '../server/statefile'\nimport { CliError, ensureServer } from './daemon'\nimport { getJson, postJson, postNoContent, probeHealth, putJson, requestShutdown, sleep } from './http'\nimport { serveAssist, waitForHandback } from './wait'\nimport { type ConfigPatch, readConfig, updateConfig } from '../server/config'\nimport { planPretranslate, writePretranslations } from '../server/translate/pretranslate'\nimport { type Assignment, applyAssignments, getDotted, parseAssignment } from './config-edit'\nimport { browserOpenArgs } from './browser-open'\nimport { AGENT_TARGETS, removeMarkedBlock, skillFile, stripFrontmatter, upsertMarkedBlock } from './install-agents'\n\nconst program = new Command()\n\nfunction die(code: number, message: string): never {\n process.stderr.write(`mastermind: ${message}\\n`)\n process.exit(code)\n}\n\nfunction parsePort(value: string | undefined): number | undefined {\n if (value === undefined) return undefined\n const n = Number(value)\n if (!Number.isInteger(n) || n < 1 || n > 65535) die(2, `invalid port: ${value}`)\n return n\n}\n\nasync function openBrowser(url: string, override?: string): Promise<void> {\n if (process.platform !== 'darwin') return\n const args = browserOpenArgs(url, override, readConfig().browser)\n if (args.length === 1) {\n // system default browser — fire and forget\n spawn('open', args, { stdio: 'ignore', detached: true }).unref()\n return\n }\n // a specific app (`-a <name>`): detect \"no such application\" and fall back to the default\n const ok = await new Promise<boolean>((resolve) => {\n const child = spawn('open', args, { stdio: 'ignore' })\n child.on('error', () => resolve(false))\n child.on('exit', (code) => resolve(code === 0))\n })\n if (!ok) {\n process.stderr.write(`mastermind: couldn't open ${args[1]} — using the default browser\\n`)\n spawn('open', [url], { stdio: 'ignore', detached: true }).unref()\n }\n}\n\nasync function createSession(port: number, filePath: string): Promise<CreateSessionResponse> {\n return postJson<CreateSessionResponse>(port, '/api/sessions', { path: filePath })\n}\n\nasync function createWorkspace(port: number, dir: string): Promise<CreateWorkspaceResponse> {\n return postJson<CreateWorkspaceResponse>(port, '/api/workspaces', { root: dir })\n}\n\nprogram\n .name('mastermind')\n .description('Local-first markdown review for humans and AI agents — the file is the protocol')\n .version(pkg.version)\n .option('--port <n>', 'port override (default 5173 or next free)')\n\nprogram\n .command('open')\n .argument('<file>', 'markdown file to open')\n .option('--wait', 'block until the user clicks \"Save & hand back\", then exit 0')\n .option('--serve-assist', 'answer translation/suggestion requests for this session (on by default with --wait)')\n .option('--no-assist', 'with --wait, review only — do not serve the assist channel (translation/suggestions)')\n .option('--no-browser', 'print the URL without opening a browser tab')\n .option('--in <browser>', 'open in a specific browser app, e.g. \"Google Chrome\" (overrides the configured default)')\n .description('start the server if not running and open a browser tab for this file')\n .action(async (file: string, opts: { wait?: boolean; serveAssist?: boolean; assist: boolean; browser: boolean; in?: string }) => {\n const pinnedPort = parsePort(program.opts<{ port?: string }>().port)\n const abs = path.resolve(file)\n let st: fs.Stats\n try {\n st = fs.statSync(abs)\n } catch {\n die(2, `file not found: ${abs}`)\n }\n if (!st.isFile()) die(2, `not a file: ${abs}`)\n\n const port = await ensureServer({ pinnedPort })\n const session = await createSession(port, abs)\n process.stdout.write(`${session.url}\\n`)\n if (opts.browser) await openBrowser(session.url, opts.in)\n\n // A --wait review serves the agent-channel by default: it lights up the reading-language\n // toggle and lets Mastermind pre-translate the document while the user reads (opt out with\n // --no-assist). Plain `open` stays fire-and-forget; --serve-assist makes it block-and-serve.\n const serve = !!opts.serveAssist || (!!opts.wait && opts.assist)\n if (opts.wait) {\n await waitForHandback(port, session.sessionId, { serveAssist: serve })\n } else if (serve) {\n await serveAssist(port, session.sessionId)\n }\n process.exit(0)\n })\n\nprogram\n .command('workspace')\n .alias('ws')\n .argument('[dir]', 'directory to browse (default: current directory)')\n .option('--no-browser', 'print the URL without opening a browser tab')\n .description('open a file-tree workspace rooted at a directory')\n .action(async (dirArg: string | undefined, opts: { browser: boolean }) => {\n const pinnedPort = parsePort(program.opts<{ port?: string }>().port)\n const abs = path.resolve(dirArg ?? process.cwd())\n let st: fs.Stats\n try {\n st = fs.statSync(abs)\n } catch {\n die(2, `directory not found: ${abs}`)\n }\n if (!st.isDirectory()) die(2, `not a directory: ${abs}`)\n\n const port = await ensureServer({ pinnedPort })\n const ws = await createWorkspace(port, abs)\n process.stdout.write(`${ws.url}\\n`)\n if (opts.browser) await openBrowser(ws.url)\n process.exit(0)\n })\n\nprogram\n .command('assist')\n .argument('<file>', 'markdown file under review')\n .description('listen for translation/suggestion requests and stream them as JSON lines (agent-channel)')\n .action(async (file: string) => {\n const pinnedPort = parsePort(program.opts<{ port?: string }>().port)\n const abs = path.resolve(file)\n if (!fs.existsSync(abs)) die(2, `file not found: ${abs}`)\n const port = await ensureServer({ pinnedPort })\n const session = await createSession(port, abs)\n await serveAssist(port, session.sessionId)\n })\n\nprogram\n .command('assist-result')\n .argument('<id>', 'the request id from the assist-request line')\n .option('--blocks <json>', 'translate result: JSON [{hash,text}]')\n .option('--markup <md>', 'suggest result: the selection rewritten with CriticMarkup')\n .description('deliver an agent-channel result back to Mastermind')\n .action(async (id: string, opts: { blocks?: string; markup?: string }) => {\n const state = readServerState()\n if (!state) die(1, 'no daemon running')\n let payload: unknown\n if (opts.blocks !== undefined) {\n let blocks: unknown\n try {\n blocks = JSON.parse(opts.blocks)\n } catch {\n die(2, '--blocks must be valid JSON')\n }\n payload = { kind: 'translate', blocks }\n } else if (opts.markup !== undefined) {\n payload = { kind: 'suggest', markup: opts.markup }\n } else {\n die(2, 'provide --blocks or --markup')\n }\n try {\n await postNoContent(state.port, `/api/assist/${id}/result`, payload)\n process.exit(0)\n } catch (err) {\n die(1, `result rejected: ${err instanceof Error ? err.message : String(err)}`)\n }\n })\n\nprogram\n .command('assist-error')\n .argument('<id>', 'the request id')\n .option('--reason <text>', 'why the request could not be fulfilled')\n .description('decline an agent-channel request')\n .action(async (id: string, opts: { reason?: string }) => {\n const state = readServerState()\n if (!state) die(1, 'no daemon running')\n try {\n await postNoContent(state.port, `/api/assist/${id}/error`, { reason: opts.reason ?? 'declined' })\n process.exit(0)\n } catch (err) {\n die(1, `error rejected: ${err instanceof Error ? err.message : String(err)}`)\n }\n })\n\nprogram\n .command('new')\n .argument('[path]', 'optional path for the new draft')\n .option('--no-browser', 'print the URL without opening a browser tab')\n .description('create a blank draft and open it (prompts for a name on first save)')\n .action(async (pathArg: string | undefined, opts: { browser: boolean }) => {\n const pinnedPort = parsePort(program.opts<{ port?: string }>().port)\n const port = await ensureServer({ pinnedPort })\n let session: CreateSessionResponse\n if (pathArg) {\n const abs = path.resolve(pathArg)\n if (!fs.existsSync(abs)) {\n fs.mkdirSync(path.dirname(abs), { recursive: true })\n fs.writeFileSync(abs, '', { flag: 'wx' })\n }\n session = await postJson<CreateSessionResponse>(port, '/api/sessions', { path: abs })\n } else {\n session = await postJson<CreateSessionResponse>(port, '/api/sessions', { draft: true, dir: process.cwd() })\n }\n process.stdout.write(`${session.url}\\n`)\n if (opts.browser) await openBrowser(session.url)\n process.exit(0)\n })\n\nprogram\n .command('status')\n .description('show daemon status')\n .action(async () => {\n const state: ServerState | null = readServerState()\n if (!state) {\n process.stdout.write('mastermind: no daemon registered\\n')\n process.exit(0)\n }\n const probe = await probeHealth(state.port)\n if (probe === 'free' || probe === 'foreign') {\n process.stdout.write(\n `mastermind: statefile names pid ${state.pid} on port ${state.port}, but no healthy daemon answered (${probe})\\n`,\n )\n process.exit(1)\n }\n const uptime = Math.round((Date.now() - probe.startedAt) / 1000)\n process.stdout.write(\n `mastermind v${probe.version} — pid ${probe.pid}, http://127.0.0.1:${state.port}, up ${uptime}s\\nlog: ${serverLogPath()}\\n`,\n )\n process.exit(0)\n })\n\nprogram\n .command('stop')\n .description('shut the daemon down')\n .action(async () => {\n const state = readServerState()\n if (!state) {\n process.stdout.write('mastermind: no daemon registered\\n')\n process.exit(0)\n }\n await requestShutdown(state.port)\n const until = Date.now() + 4000\n while (Date.now() < until) {\n if ((await probeHealth(state.port)) === 'free') {\n process.stdout.write('mastermind: daemon stopped\\n')\n process.exit(0)\n }\n await sleep(100)\n }\n die(1, `daemon did not stop — check ${serverLogPath()}`)\n })\n\nasync function readStdin(): Promise<string> {\n const chunks: Buffer[] = []\n for await (const chunk of process.stdin) chunks.push(chunk as Buffer)\n return Buffer.concat(chunks).toString('utf8')\n}\n\nprogram\n .command('translate-blocks')\n .argument('<file>', 'markdown file to pre-translate')\n .option('--save', 'read translated [{hash,text}] JSON from stdin and write it to the on-disk cache')\n .description(\"offline pre-translate: emit the blocks to translate, or (--save) cache the agent's translations\")\n .action(async (file: string, opts: { save?: boolean }) => {\n const abs = path.resolve(file)\n let source: string\n try {\n source = fs.readFileSync(abs, 'utf8')\n } catch {\n die(2, `file not found: ${abs}`)\n }\n const { langPair } = readConfig()\n if (opts.save) {\n let entries: { hash: string; text: string }[]\n try {\n const parsed: unknown = JSON.parse(await readStdin())\n if (!Array.isArray(parsed)) throw new Error('expected a JSON array')\n const ok = parsed.every(\n (e) =>\n e !== null &&\n typeof e === 'object' &&\n typeof (e as { hash?: unknown }).hash === 'string' &&\n typeof (e as { text?: unknown }).text === 'string',\n )\n if (!ok) throw new Error('each element must be { hash: string, text: string }')\n entries = parsed as { hash: string; text: string }[]\n } catch (err) {\n die(2, `--save expects [{hash,text}] JSON on stdin: ${err instanceof Error ? err.message : String(err)}`)\n }\n const res = await writePretranslations(abs, source, langPair, entries)\n const skips: string[] = []\n if (res.skippedUnknownHash) skips.push(`${res.skippedUnknownHash} stale/unknown-hash`)\n if (res.skippedMarkMismatch) skips.push(`${res.skippedMarkMismatch} mismatched-CriticMarkup`)\n process.stdout.write(\n `mastermind: cached ${res.written} block(s) → ${res.cachePath}${skips.length ? ` (skipped ${skips.join(', ')})` : ''}\\n`,\n )\n process.exit(0)\n }\n process.stdout.write(`${JSON.stringify(await planPretranslate(abs, source, langPair))}\\n`)\n process.exit(0)\n })\n\n/** Port of a live, healthy daemon, or null when none runs (config edits then go straight to disk). */\nasync function liveDaemonPort(): Promise<number | null> {\n const state = readServerState()\n if (!state) return null\n const probe = await probeHealth(state.port)\n return typeof probe === 'object' ? state.port : null\n}\n\nconst configCmd = program.command('config').description('read or write Mastermind preferences')\n\nconfigCmd\n .command('get [key]')\n .description('print the whole config as JSON, or one dotted key (e.g. langPair.a)')\n .action((key: string | undefined) => {\n const cfg = readConfig() as unknown as Record<string, unknown>\n if (key === undefined) {\n process.stdout.write(`${JSON.stringify(cfg, null, 2)}\\n`)\n } else {\n const v = getDotted(cfg, key)\n if (v === undefined) die(2, `unknown config key: ${key}`)\n process.stdout.write(`${typeof v === 'string' ? v : JSON.stringify(v)}\\n`)\n }\n process.exit(0)\n })\n\nconfigCmd\n .command('set <assignments...>')\n .description('set dotted key=value pairs, e.g. langPair.a=English theme=nacht browser=\"Google Chrome\"')\n .action(async (raw: string[]) => {\n let assignments: Assignment[]\n try {\n assignments = raw.map(parseAssignment)\n } catch (err) {\n die(2, err instanceof Error ? err.message : String(err))\n }\n const port = await liveDaemonPort()\n // Read current config (via the daemon if up, else the file) so a dotted edit like\n // langPair.a doesn't clobber its sibling in the shallow server-side merge.\n const current = port ? await getJson<MastermindConfig>(port, '/api/config') : readConfig()\n let patch: Record<string, unknown>\n try {\n patch = applyAssignments(current, assignments).patch\n } catch (err) {\n die(2, err instanceof Error ? err.message : String(err))\n }\n try {\n // Daemon up → PUT so the change persists AND broadcasts config-changed to open tabs;\n // daemon down → write the file directly (no tabs to notify).\n if (port) await putJson<MastermindConfig>(port, '/api/config', patch)\n else updateConfig(patch as ConfigPatch)\n } catch (err) {\n die(1, `config set failed: ${err instanceof Error ? err.message : String(err)}`)\n }\n process.stdout.write(`mastermind: set ${assignments.map((a) => a.key).join(', ')}\\n`)\n process.exit(0)\n })\n\nconst MM_DESC =\n 'Visualize and review a Markdown file in Mastermind — /mastermind [setup|demo|<file>]. Always pre-translates the doc into both reading languages first.'\nconst MASTER_DESC = 'Alias of /mastermind: translate a file into both reading languages, then open it in Mastermind.'\n\nfunction readCanonical(rel: string): string {\n return fs.readFileSync(path.join(pkgRoot, rel), 'utf8')\n}\n\nfunction installAgents(opts: { all: boolean; global: boolean }): void {\n const home = os.homedir()\n const mmBody = stripFrontmatter(readCanonical('.claude/skills/mastermind/SKILL.md'))\n const masterBody = stripFrontmatter(readCanonical('.claude/skills/master/SKILL.md'))\n const demo = readCanonical('.claude/skills/mastermind/reference/demo.md')\n const globalBody = readCanonical('assets/agent/global.md')\n\n const done: string[] = []\n for (const t of AGENT_TARGETS) {\n const base = path.join(home, t.dir)\n if (!opts.all && !fs.existsSync(base)) continue\n const mmDir = path.join(base, 'skills', 'mastermind')\n fs.mkdirSync(path.join(mmDir, 'reference'), { recursive: true })\n fs.writeFileSync(path.join(mmDir, 'SKILL.md'), skillFile(t, 'mastermind', MM_DESC, mmBody, pkg.version))\n fs.writeFileSync(path.join(mmDir, 'reference', 'demo.md'), demo)\n const masterDir = path.join(base, 'skills', 'master')\n fs.mkdirSync(masterDir, { recursive: true })\n fs.writeFileSync(path.join(masterDir, 'SKILL.md'), skillFile(t, 'master', MASTER_DESC, masterBody, pkg.version))\n let note = ` ${t.id}: skills/{mastermind,master}`\n if (opts.global && t.globalFile) {\n const gf = path.join(base, t.globalFile)\n const existing = fs.existsSync(gf) ? fs.readFileSync(gf, 'utf8') : ''\n fs.writeFileSync(gf, upsertMarkedBlock(existing, globalBody))\n note += ` + global (${t.globalFile})`\n } else if (opts.global && !t.globalFile) {\n note += ` + global skipped (no known memory file for ${t.id}; see AGENT_SETUP.md)`\n }\n done.push(`${note} → ${base}`)\n }\n if (done.length === 0) {\n process.stdout.write(\n 'mastermind: no agent config dirs found (~/.claude, ~/.cursor, ~/.gemini, ~/.agents). Re-run with --all to create them.\\n',\n )\n return\n }\n process.stdout.write(`mastermind: installed for ${done.length} agent(s):\\n${done.join('\\n')}\\n`)\n if (opts.global) process.stdout.write(' (undo the global block + skills with `mastermind uninstall-agents`)\\n')\n}\n\nfunction uninstallAgents(): void {\n const home = os.homedir()\n const removed: string[] = []\n for (const t of AGENT_TARGETS) {\n const base = path.join(home, t.dir)\n for (const name of ['mastermind', 'master']) {\n const dir = path.join(base, 'skills', name)\n if (fs.existsSync(dir)) {\n fs.rmSync(dir, { recursive: true, force: true })\n removed.push(` ${t.id}: skills/${name}`)\n }\n }\n if (t.globalFile) {\n const gf = path.join(base, t.globalFile)\n if (fs.existsSync(gf)) fs.writeFileSync(gf, removeMarkedBlock(fs.readFileSync(gf, 'utf8')))\n }\n }\n process.stdout.write(removed.length ? `mastermind: removed:\\n${removed.join('\\n')}\\n` : 'mastermind: nothing to remove\\n')\n}\n\nprogram\n .command('install-agents')\n .option('--all', 'install for every supported agent, creating its config dir if absent')\n .option('--no-global', 'install the skills only — skip the always-translate-first / plan→visualize global instruction block')\n .description('install the mastermind + master skills (and a global instruction block) for your coding agents')\n .action((opts: { all?: boolean; global: boolean }) => {\n installAgents({ all: !!opts.all, global: opts.global })\n process.exit(0)\n })\n\nprogram\n .command('uninstall-agents')\n .description('remove the mastermind/master skills and the global instruction block this tool installed')\n .action(() => {\n uninstallAgents()\n process.exit(0)\n })\n\nprogram.parseAsync().catch((err: unknown) => {\n if (err instanceof CliError) die(err.exitCode, err.message)\n die(1, err instanceof Error ? err.message : String(err))\n})\n","{\n \"name\": \"mastermind-md\",\n \"version\": \"0.1.0\",\n \"type\": \"module\",\n \"description\": \"Review Markdown with your coding agent — local-first, CriticMarkup review loop, bilingual, the file is the protocol\",\n \"license\": \"MIT\",\n \"author\": \"Kevin Ding <kevincentding@gmail.com>\",\n \"homepage\": \"https://github.com/Jingquank/Mastermind#readme\",\n \"repository\": {\n \"type\": \"git\",\n \"url\": \"git+https://github.com/Jingquank/Mastermind.git\"\n },\n \"bugs\": {\n \"url\": \"https://github.com/Jingquank/Mastermind/issues\"\n },\n \"keywords\": [\n \"markdown\",\n \"review\",\n \"criticmarkup\",\n \"ai-agents\",\n \"claude\",\n \"cli\",\n \"bilingual\",\n \"local-first\"\n ],\n \"engines\": {\n \"node\": \">=20\"\n },\n \"bin\": {\n \"mastermind\": \"bin/mastermind.js\",\n \"mastermind-md\": \"bin/mastermind.js\"\n },\n \"files\": [\n \"dist/\",\n \"bin/\",\n \"themes/\",\n \".claude/skills/\",\n \"assets/agent/\",\n \"README.md\",\n \"LICENSE\"\n ],\n \"scripts\": {\n \"build\": \"rm -rf dist && vite build && tsup\",\n \"dev\": \"concurrently -k \\\"MASTERMIND_PORT=5199 tsx watch src/server/index.ts\\\" \\\"vite\\\"\",\n \"test\": \"vitest run\",\n \"test:watch\": \"vitest\",\n \"typecheck\": \"tsc -p tsconfig.json && tsc -p tsconfig.node.json\",\n \"prepare\": \"npm run build\",\n \"prepack\": \"npm run build\"\n },\n \"dependencies\": {\n \"@codemirror/lang-markdown\": \"^6.5.0\",\n \"@codemirror/language\": \"^6.12.3\",\n \"@codemirror/state\": \"^6.6.0\",\n \"@codemirror/view\": \"^6.43.1\",\n \"@hono/node-server\": \"^2.0.4\",\n \"@lezer/highlight\": \"^1.2.3\",\n \"@radix-ui/react-icons\": \"^1.3.2\",\n \"chokidar\": \"^5.0.0\",\n \"codemirror\": \"^6.0.2\",\n \"commander\": \"^15.0.0\",\n \"diff\": \"^9.0.0\",\n \"hono\": \"^4.12.25\",\n \"mdast-util-to-markdown\": \"^2.1.2\",\n \"radix-ui\": \"^1.5.0\",\n \"react\": \"^19.2.7\",\n \"react-dom\": \"^19.2.7\",\n \"remark-gfm\": \"^4.0.1\",\n \"remark-parse\": \"^11.0.0\",\n \"remark-stringify\": \"^11.0.0\",\n \"slot-text\": \"^0.2.2\",\n \"unified\": \"^11.0.5\",\n \"unist-util-visit\": \"^5.1.0\",\n \"zustand\": \"^5.0.14\"\n },\n \"devDependencies\": {\n \"@types/mdast\": \"^4.0.4\",\n \"@types/node\": \"^25.9.3\",\n \"@types/react\": \"^19.2.17\",\n \"@types/react-dom\": \"^19.2.3\",\n \"@types/unist\": \"^3.0.3\",\n \"@vitejs/plugin-react\": \"^6.0.2\",\n \"concurrently\": \"^10.0.3\",\n \"jsdom\": \"^29.1.1\",\n \"tsup\": \"^8.5.1\",\n \"tsx\": \"^4.22.4\",\n \"typescript\": \"^6.0.3\",\n \"vite\": \"^8.0.16\",\n \"vitest\": \"^4.1.8\"\n }\n}\n","import { fileURLToPath } from 'node:url'\nimport path from 'node:path'\nimport os from 'node:os'\nimport fs from 'node:fs'\n\n/**\n * Package root, resolved relative to this module. Works from both the bundled\n * output (dist/cli/*, dist/server/*) and tsx dev runs (src/server/*) — all sit\n * exactly two levels below the repo root.\n */\nexport const pkgRoot = fileURLToPath(new URL('../../', import.meta.url))\n\nexport const uiDir = path.join(pkgRoot, 'dist', 'ui')\nexport const themesDir = path.join(pkgRoot, 'themes')\n\nexport function configDir(): string {\n return process.env.MASTERMIND_CONFIG_DIR ?? path.join(os.homedir(), '.config', 'mastermind')\n}\n\nexport function ensureConfigDir(): string {\n const dir = configDir()\n fs.mkdirSync(dir, { recursive: true })\n return dir\n}\n\nexport function stateFilePath(): string {\n return path.join(configDir(), 'server.json')\n}\n\nexport function serverLogPath(): string {\n return path.join(configDir(), 'server.log')\n}\n\nexport function configFilePath(): string {\n return path.join(configDir(), 'config.json')\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\nimport type { ServerState } from '../shared/types'\nimport { ensureConfigDir, stateFilePath } from './paths'\n\nexport function readServerState(): ServerState | null {\n try {\n const raw = fs.readFileSync(stateFilePath(), 'utf8')\n const parsed: unknown = JSON.parse(raw)\n if (\n typeof parsed === 'object' &&\n parsed !== null &&\n typeof (parsed as ServerState).port === 'number' &&\n typeof (parsed as ServerState).pid === 'number' &&\n typeof (parsed as ServerState).version === 'string' &&\n typeof (parsed as ServerState).startedAt === 'number'\n ) {\n return parsed as ServerState\n }\n return null\n } catch {\n return null\n }\n}\n\n/** Atomic write: tmp file + rename, so a concurrent reader never sees a torn file. */\nexport function writeServerState(state: ServerState): void {\n const dir = ensureConfigDir()\n const tmp = path.join(dir, `.server.json.${process.pid}.tmp`)\n fs.writeFileSync(tmp, JSON.stringify(state, null, 2))\n fs.renameSync(tmp, stateFilePath())\n}\n\n/**\n * Remove the statefile. When `onlyIfPid` is given, leave it alone unless it\n * still names that pid — a newer daemon may have already replaced it.\n */\nexport function clearServerState(onlyIfPid?: number): void {\n if (onlyIfPid !== undefined) {\n const current = readServerState()\n if (current && current.pid !== onlyIfPid) return\n }\n try {\n fs.unlinkSync(stateFilePath())\n } catch {\n /* already gone */\n }\n}\n\nexport function pidIsAlive(pid: number): boolean {\n try {\n process.kill(pid, 0)\n return true\n } catch {\n return false\n }\n}\n","import { spawn } from 'node:child_process'\nimport fs from 'node:fs'\nimport { fileURLToPath } from 'node:url'\nimport pkg from '../../package.json'\nimport { ensureConfigDir, pkgRoot, serverLogPath } from '../server/paths'\nimport { clearServerState, pidIsAlive, readServerState } from '../server/statefile'\nimport { probeHealth, requestShutdown, sleep } from './http'\n\nconst serverEntry = fileURLToPath(new URL('../server/index.js', import.meta.url))\n\nexport class CliError extends Error {\n constructor(\n message: string,\n public exitCode: number,\n ) {\n super(message)\n }\n}\n\nfunction spawnDaemon(opts: { port?: number; pinned: boolean }): void {\n ensureConfigDir()\n const logPath = serverLogPath()\n try {\n const st = fs.statSync(logPath)\n if (st.size > 5 * 1024 * 1024) fs.renameSync(logPath, `${logPath}.1`)\n } catch {\n /* no log yet */\n }\n const logFd = fs.openSync(logPath, 'a')\n const child = spawn(process.execPath, [serverEntry], {\n detached: true,\n stdio: ['ignore', logFd, logFd],\n cwd: pkgRoot,\n env: {\n ...process.env,\n MASTERMIND_PORT: opts.port !== undefined ? String(opts.port) : '',\n MASTERMIND_PINNED: opts.pinned ? '1' : '',\n },\n })\n child.unref()\n fs.closeSync(logFd)\n}\n\nasync function awaitReady(deadlineMs: number): Promise<number> {\n const until = Date.now() + deadlineMs\n while (Date.now() < until) {\n const state = readServerState()\n if (state && state.version === pkg.version) {\n const probe = await probeHealth(state.port)\n if (probe !== 'free' && probe !== 'foreign' && probe.version === pkg.version) return state.port\n }\n await sleep(120)\n }\n throw new CliError(`daemon did not become ready — check ${serverLogPath()}`, 1)\n}\n\nasync function shutdownAndWait(port: number): Promise<void> {\n await requestShutdown(port)\n const until = Date.now() + 4000\n while (Date.now() < until) {\n if ((await probeHealth(port)) === 'free') return\n await sleep(100)\n }\n}\n\n/**\n * Make sure a daemon of OUR version is running; return its port.\n * Handles: reuse, stale statefile recovery, version-skew restart, pinned ports.\n */\nexport async function ensureServer(opts: { pinnedPort?: number } = {}): Promise<number> {\n const pinned = opts.pinnedPort\n\n const state = readServerState()\n if (state) {\n const probe = await probeHealth(state.port)\n if (probe !== 'free' && probe !== 'foreign') {\n // healthy mastermind\n if (probe.version !== pkg.version) {\n process.stderr.write(`mastermind: restarting daemon (v${probe.version} → v${pkg.version})\\n`)\n await shutdownAndWait(state.port)\n } else if (pinned !== undefined && state.port !== pinned) {\n process.stderr.write(`mastermind: daemon already running on port ${state.port}; reusing it (ignoring --port ${pinned})\\n`)\n return state.port\n } else {\n return state.port\n }\n } else {\n // stale or hung — recover\n if (pidIsAlive(state.pid)) {\n process.stderr.write(`mastermind: unresponsive daemon (pid ${state.pid}) — abandoning it\\n`)\n }\n clearServerState(state.pid)\n }\n }\n\n if (pinned !== undefined) {\n const probe = await probeHealth(pinned)\n if (probe === 'foreign') {\n throw new CliError(`port ${pinned} is in use by something that isn't mastermind`, 2)\n }\n if (probe !== 'free') {\n // healthy mastermind not in the statefile (e.g. statefile was deleted)\n if (probe.version === pkg.version) return pinned\n await shutdownAndWait(pinned)\n }\n spawnDaemon({ port: pinned, pinned: true })\n } else {\n spawnDaemon({ pinned: false })\n }\n\n return awaitReady(6000)\n}\n","import type { HealthResponse } from '../shared/types'\n\nexport type HealthProbe = HealthResponse | 'free' | 'foreign'\n\nfunction isConnRefused(err: unknown): boolean {\n const cause = (err as { cause?: unknown }).cause\n if (!cause) return false\n const code = (cause as NodeJS.ErrnoException).code\n if (code === 'ECONNREFUSED') return true\n const errors = (cause as { errors?: NodeJS.ErrnoException[] }).errors\n return Array.isArray(errors) && errors.some((e) => e.code === 'ECONNREFUSED')\n}\n\n/**\n * Probe a port: a healthy mastermind daemon, nothing at all ('free'), or\n * something else / hung ('foreign').\n */\nexport async function probeHealth(port: number): Promise<HealthProbe> {\n try {\n const res = await fetch(`http://127.0.0.1:${port}/api/health`, { signal: AbortSignal.timeout(1500) })\n if (!res.ok) return 'foreign'\n const j = (await res.json()) as Partial<HealthResponse>\n if (j.ok === true && typeof j.pid === 'number' && typeof j.version === 'string') {\n return j as HealthResponse\n }\n return 'foreign'\n } catch (err) {\n return isConnRefused(err) ? 'free' : 'foreign'\n }\n}\n\nexport async function postJson<T>(port: number, pathName: string, body: unknown): Promise<T> {\n const res = await fetch(`http://127.0.0.1:${port}${pathName}`, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(body),\n signal: AbortSignal.timeout(5000),\n })\n if (!res.ok) {\n let detail = `${res.status}`\n try {\n const j = (await res.json()) as { error?: string }\n if (j.error) detail = j.error\n } catch {\n /* not json */\n }\n throw new Error(detail)\n }\n return (await res.json()) as T\n}\n\n/** POST that tolerates a 204/empty body (used by assist-result / assist-error). */\nexport async function postNoContent(port: number, pathName: string, body: unknown): Promise<void> {\n const res = await fetch(`http://127.0.0.1:${port}${pathName}`, {\n method: 'POST',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(body),\n signal: AbortSignal.timeout(5000),\n })\n if (!res.ok) {\n let detail = `${res.status}`\n try {\n const j = (await res.json()) as { error?: string }\n if (j.error) detail = j.error\n } catch {\n /* not json */\n }\n throw new Error(detail)\n }\n}\n\nexport async function getJson<T>(port: number, pathName: string): Promise<T> {\n const res = await fetch(`http://127.0.0.1:${port}${pathName}`, { signal: AbortSignal.timeout(5000) })\n if (!res.ok) throw new Error(`${res.status}`)\n return (await res.json()) as T\n}\n\nexport async function putJson<T>(port: number, pathName: string, body: unknown): Promise<T> {\n const res = await fetch(`http://127.0.0.1:${port}${pathName}`, {\n method: 'PUT',\n headers: { 'content-type': 'application/json' },\n body: JSON.stringify(body),\n signal: AbortSignal.timeout(5000),\n })\n if (!res.ok) {\n let detail = `${res.status}`\n try {\n const j = (await res.json()) as { error?: string }\n if (j.error) detail = j.error\n } catch {\n /* not json */\n }\n throw new Error(detail)\n }\n return (await res.json()) as T\n}\n\nexport async function requestShutdown(port: number): Promise<void> {\n try {\n await fetch(`http://127.0.0.1:${port}/api/admin/shutdown`, {\n method: 'POST',\n signal: AbortSignal.timeout(1500),\n })\n } catch {\n /* it may die mid-response; that's fine */\n }\n}\n\nexport function sleep(ms: number): Promise<void> {\n return new Promise((r) => setTimeout(r, ms))\n}\n","export interface SseRecord {\n event: string\n data: string\n}\n\n/** Minimal SSE client over fetch (Node has no EventSource). Shared by wait + assist. */\nexport async function* sseRecords(url: string, signal?: AbortSignal): AsyncGenerator<SseRecord> {\n const res = await fetch(url, { headers: { accept: 'text/event-stream' }, signal })\n if (!res.ok || !res.body) throw new Error(`sse connect failed: ${res.status}`)\n const decoder = new TextDecoder()\n let buf = ''\n for await (const chunk of res.body) {\n buf += decoder.decode(chunk as Uint8Array, { stream: true })\n let idx: number\n while ((idx = buf.indexOf('\\n\\n')) !== -1) {\n const record = buf.slice(0, idx)\n buf = buf.slice(idx + 2)\n if (record.startsWith(':')) continue // comment/ping\n let event = 'message'\n let data = ''\n for (const line of record.split('\\n')) {\n if (line.startsWith('event:')) event = line.slice(6).trim()\n else if (line.startsWith('data:')) data += line.slice(5).trim()\n }\n yield { event, data }\n }\n }\n}\n","import type { ReviewCounts, SessionCloseReason } from '../shared/types'\nimport { probeHealth, sleep } from './http'\nimport { sseRecords } from './sse'\n\nconst CLOSE_MESSAGES: Record<SessionCloseReason, string> = {\n 'tabs-closed': 'tab closed without hand-back',\n 'never-opened': 'browser never connected',\n shutdown: 'server shut down',\n}\n\n/** Emit any requests queued before this listener attached (startup race). */\nasync function drainAssistPending(port: number, sessionId: string): Promise<void> {\n try {\n const res = await fetch(`http://127.0.0.1:${port}/api/assist/pending?sessionId=${sessionId}`, {\n signal: AbortSignal.timeout(2000),\n })\n if (!res.ok) return\n const { requests } = (await res.json()) as { requests: unknown[] }\n for (const req of requests) process.stdout.write(`mastermind-assist: ${JSON.stringify(req)}\\n`)\n } catch {\n /* best effort */\n }\n}\n\n/**\n * Standalone assist listener: attaches assist-capable, drains pending, and\n * prints one `mastermind-assist: {json}` line per request. The agent answers\n * with `mastermind assist-result|assist-error`. Runs until the session closes.\n */\nexport async function serveAssist(port: number, sessionId: string): Promise<never> {\n process.on('SIGINT', () => process.exit(130))\n process.on('SIGTERM', () => process.exit(143))\n process.stderr.write('mastermind: assist listener ready — answer with `mastermind assist-result|assist-error`\\n')\n\n let attempts = 0\n for (;;) {\n try {\n await drainAssistPending(port, sessionId)\n const url = `http://127.0.0.1:${port}/api/sessions/${sessionId}/events?role=cli&assist=1`\n for await (const evt of sseRecords(url)) {\n attempts = 0\n if (evt.event === 'assist-request') {\n process.stdout.write(`mastermind-assist: ${evt.data}\\n`)\n } else if (evt.event === 'session-closed') {\n const { reason } = JSON.parse(evt.data) as { reason: SessionCloseReason }\n process.stderr.write(`mastermind: ${CLOSE_MESSAGES[reason] ?? reason}\\n`)\n process.exit(0)\n }\n }\n } catch {\n /* connection dropped — retry as long as the daemon is alive */\n }\n attempts++\n // Only give up if the daemon is truly gone; otherwise keep the listener alive\n // across transient drops (a dropped SSE used to silently kill translation).\n if ((await probeHealth(port)) === 'free') {\n process.stderr.write('mastermind: daemon is gone\\n')\n process.exit(1)\n }\n await sleep(Math.min(1000 * attempts, 10000)) // capped backoff\n }\n}\n\n/**\n * The --wait state machine. Blocks until hand-back (prints the summary line,\n * exit 0), the session dies (exit 1), or the daemon vanishes after retries\n * (exit 1). SIGINT/SIGTERM exit 130/143. `file-deleted` is NOT terminal —\n * the user can still hand back, which recreates the file.\n */\nexport async function waitForHandback(\n port: number,\n sessionId: string,\n opts: { serveAssist?: boolean } = {},\n): Promise<never> {\n process.on('SIGINT', () => process.exit(130))\n process.on('SIGTERM', () => process.exit(143))\n\n let attempts = 0\n for (;;) {\n try {\n const q = opts.serveAssist ? 'role=cli&assist=1' : 'role=cli'\n const url = `http://127.0.0.1:${port}/api/sessions/${sessionId}/events?${q}`\n if (opts.serveAssist) await drainAssistPending(port, sessionId)\n for await (const evt of sseRecords(url)) {\n attempts = 0\n if (evt.event === 'handback') {\n const payload = JSON.parse(evt.data) as { summaryLine: string; counts: ReviewCounts }\n process.stdout.write(`${payload.summaryLine}\\n`)\n process.exit(0)\n }\n if (evt.event === 'session-closed') {\n const { reason } = JSON.parse(evt.data) as { reason: SessionCloseReason }\n process.stderr.write(`mastermind: ${CLOSE_MESSAGES[reason] ?? reason}\\n`)\n process.exit(1)\n }\n if (opts.serveAssist && evt.event === 'assist-request') {\n process.stdout.write(`mastermind-assist: ${evt.data}\\n`)\n }\n // ping / file-changed / file-deleted / config-changed: keep waiting\n }\n } catch {\n /* connection dropped — fall through to retry */\n }\n attempts++\n if (attempts > 3) {\n process.stderr.write('mastermind: lost connection to the daemon\\n')\n process.exit(1)\n }\n await sleep(1000 * attempts)\n const probe = await probeHealth(port)\n if (probe === 'free' || probe === 'foreign') {\n process.stderr.write('mastermind: daemon is gone\\n')\n process.exit(1)\n }\n const sessionAlive = await fetch(`http://127.0.0.1:${port}/api/sessions/${sessionId}`, {\n signal: AbortSignal.timeout(2000),\n })\n .then((r) => r.ok)\n .catch(() => false)\n if (!sessionAlive) {\n process.stderr.write('mastermind: session is gone\\n')\n process.exit(1)\n }\n }\n}\n","import fs from 'node:fs'\nimport path from 'node:path'\nimport { DEFAULT_AUTHOR_TAG } from '../shared/constants'\nimport type { ClientConfig, MastermindConfig } from '../shared/types'\nimport { configFilePath, ensureConfigDir } from './paths'\n\nexport const DEFAULT_CONFIG: MastermindConfig = {\n version: 1,\n theme: 'grid',\n fontSize: 16,\n lineHeight: 1.6,\n contentWidth: 736,\n authorTag: DEFAULT_AUTHOR_TAG,\n typeSet: 'grid',\n monoFont: 'geist',\n codeTheme: 'none',\n uiLang: 'en',\n langPair: { a: 'English', b: 'Simplified Chinese' },\n browser: '',\n grain: {},\n}\n\nexport function readConfig(): MastermindConfig {\n try {\n const raw = fs.readFileSync(configFilePath(), 'utf8')\n const parsed = JSON.parse(raw) as Partial<MastermindConfig>\n return { ...DEFAULT_CONFIG, ...parsed, version: 1 }\n } catch {\n return { ...DEFAULT_CONFIG }\n }\n}\n\nfunction persist(config: MastermindConfig): void {\n const dir = ensureConfigDir()\n const tmp = path.join(dir, `.config.json.${process.pid}.tmp`)\n fs.writeFileSync(tmp, JSON.stringify(config, null, 2))\n fs.renameSync(tmp, configFilePath())\n}\n\nexport type ConfigPatch = Partial<Omit<MastermindConfig, 'version'>>\n\nexport function updateConfig(patch: ConfigPatch): MastermindConfig {\n const next: MastermindConfig = { ...readConfig(), ...patch, version: 1 }\n persist(next)\n return next\n}\n\n/** The browser sees the whole config — there are no secrets to redact. */\nexport function redactConfig(config: MastermindConfig): ClientConfig {\n return config\n}\n","export const APP_NAME = 'mastermind'\n\n/** Default port per spec (\"5173 or next free\"); server.json is the sole port authority. */\nexport const DEFAULT_PORT = 5173\nexport const PORT_SCAN_LIMIT = 20\n\nexport const SSE_PING_INTERVAL_MS = 15_000\nexport const SESSION_CLOSE_GRACE_MS = 30_000\nexport const SESSION_NEVER_OPENED_MS = 120_000\nexport const DAEMON_IDLE_EXIT_MS = 30 * 60_000\n\n/** Until the settings panel (M9) makes it configurable. */\nexport const DEFAULT_AUTHOR_TAG = 'ke'\n\n/** How long an agent-channel request waits for the agent to answer. */\nexport const ASSIST_TIMEOUT_MS = 120_000\n","import type { CommentEntry, CriticKind, CriticSpan, Range, ReviewCountsDetail, ReviewItem } from './types'\n\nconst OPENERS: ReadonlyArray<readonly [string, CriticKind]> = [\n ['{++', 'ins'],\n ['{--', 'del'],\n ['{~~', 'sub'],\n ['{==', 'highlight'],\n ['{>>', 'comment'],\n]\n\nconst CLOSERS: Record<CriticKind, string> = {\n ins: '++}',\n del: '--}',\n sub: '~~}',\n highlight: '==}',\n comment: '<<}',\n}\n\n/** Start offsets of blank-line breaks (a span may not cross one). */\nfunction blankBreaks(text: string): number[] {\n const out: number[] = []\n const re = /\\r?\\n[ \\t]*\\r?\\n/g\n let m: RegExpExecArray | null\n while ((m = re.exec(text)) !== null) {\n out.push(m.index)\n re.lastIndex = m.index + 1 // overlapping blank runs all count\n }\n return out\n}\n\nfunction makeExcludeLookup(exclude: readonly Range[]): (pos: number) => Range | null {\n const sorted = [...exclude].sort((a, b) => a.start - b.start)\n return (pos: number) => {\n let lo = 0\n let hi = sorted.length - 1\n while (lo <= hi) {\n const mid = (lo + hi) >> 1\n const r = sorted[mid]!\n if (pos < r.start) hi = mid - 1\n else if (pos >= r.end) lo = mid + 1\n else return r\n }\n return null\n }\n}\n\nfunction escapedAt(text: string, bracePos: number): boolean {\n let backslashes = 0\n while (bracePos - 1 - backslashes >= 0 && text[bracePos - 1 - backslashes] === '\\\\') backslashes++\n return backslashes % 2 === 1\n}\n\n/**\n * Scan raw text for CriticMarkup spans.\n *\n * Rules: delimiters must not sit inside `exclude` ranges (code, html); span\n * content may contain newlines but never a blank line; `\\{` defeats an\n * opener; marks do not nest — the first valid closer wins.\n */\nexport function scan(text: string, exclude: readonly Range[] = []): CriticSpan[] {\n const spans: CriticSpan[] = []\n const breaks = blankBreaks(text)\n const excludeAt = makeExcludeLookup(exclude)\n let breakIdx = 0\n\n const findToken = (token: string, from: number, limit: number): number => {\n let k = from\n while (k < limit) {\n const j = text.indexOf(token, k)\n if (j === -1 || j >= limit) return -1\n const ex = excludeAt(j)\n if (ex) {\n k = ex.end\n continue\n }\n return j\n }\n return -1\n }\n\n let i = 0\n while (i < text.length) {\n const brace = text.indexOf('{', i)\n if (brace === -1) break\n i = brace\n\n const ex = excludeAt(i)\n if (ex) {\n i = ex.end\n continue\n }\n if (escapedAt(text, i)) {\n i += 1\n continue\n }\n\n const opener = OPENERS.find(([tok]) => text.startsWith(tok, i))\n if (!opener) {\n i += 1\n continue\n }\n const kind = opener[1]\n const innerStart = i + 3\n\n while (breakIdx < breaks.length && breaks[breakIdx]! < innerStart) breakIdx++\n const limit = breakIdx < breaks.length ? breaks[breakIdx]! : text.length\n\n if (kind === 'sub') {\n const firstCloser = findToken(CLOSERS.sub, innerStart, limit)\n const sep = findToken('~>', innerStart, limit)\n if (firstCloser === -1 || sep === -1 || sep >= firstCloser) {\n i += 1\n continue\n }\n spans.push({\n kind,\n start: i,\n end: firstCloser + 3,\n innerStart,\n innerEnd: firstCloser,\n oldStart: innerStart,\n oldEnd: sep,\n newStart: sep + 2,\n newEnd: firstCloser,\n })\n i = firstCloser + 3\n continue\n }\n\n const closer = findToken(CLOSERS[kind], innerStart, limit)\n if (closer === -1) {\n i += 1\n continue\n }\n spans.push({ kind, start: i, end: closer + 3, innerStart, innerEnd: closer })\n i = closer + 3\n }\n return spans\n}\n\nconst AUTHOR_RE = /^\\s*@([^\\s:@]{1,64}):\\s?/\n\n/**\n * Drop container prefixes (`> `, continuation indent) from a raw multi-line\n * span slice — they're markdown plumbing, not content.\n */\nexport function stripLinePrefixes(s: string): string {\n return s.replace(/\\n[ \\t]*(?:>[ \\t]?)*/g, '\\n')\n}\n\nexport function parseAuthor(content: string): { author: string | null; body: string } {\n const m = AUTHOR_RE.exec(content)\n if (!m) return { author: null, body: content }\n return { author: m[1]!, body: content.slice(m[0].length) }\n}\n\nfunction toEntry(span: CriticSpan, text: string): CommentEntry {\n const { author, body } = parseAuthor(stripLinePrefixes(text.slice(span.innerStart, span.innerEnd)))\n return { span, author, body }\n}\n\n/**\n * Group scanned spans into review items: ins/del/sub → suggestions;\n * `{==x==}{>>c<<}` → anchored thread; consecutive comments → one thread;\n * highlights without a trailing comment → standalone highlights.\n * Adjacency means zero characters between marks.\n */\nexport function group(spans: readonly CriticSpan[], text: string): ReviewItem[] {\n const items: ReviewItem[] = []\n let i = 0\n while (i < spans.length) {\n const s = spans[i]!\n if (s.kind === 'ins' || s.kind === 'del' || s.kind === 'sub') {\n items.push({ type: 'suggestion', span: s })\n i++\n continue\n }\n if (s.kind === 'highlight') {\n const next = spans[i + 1]\n if (!(next && next.kind === 'comment' && next.start === s.end)) {\n items.push({ type: 'highlight', span: s })\n i++\n continue\n }\n const comments: CommentEntry[] = []\n let j = i + 1\n let expectedStart = s.end\n while (spans[j] && spans[j]!.kind === 'comment' && spans[j]!.start === expectedStart) {\n comments.push(toEntry(spans[j]!, text))\n expectedStart = spans[j]!.end\n j++\n }\n items.push({ type: 'thread', anchor: s, comments, start: s.start, end: expectedStart })\n i = j\n continue\n }\n // orphan comment / thread start\n const comments: CommentEntry[] = [toEntry(s, text)]\n let j = i + 1\n let expectedStart = s.end\n while (spans[j] && spans[j]!.kind === 'comment' && spans[j]!.start === expectedStart) {\n comments.push(toEntry(spans[j]!, text))\n expectedStart = spans[j]!.end\n j++\n }\n items.push({ type: 'thread', anchor: null, comments, start: s.start, end: expectedStart })\n i = j\n }\n return items\n}\n\n/**\n * Counts for the review summary. Comments count every comment mark; edits\n * count ins+del+sub; highlights count only standalone highlights (an anchored\n * comment's highlight is the comment's anchor, not a separate annotation).\n */\nexport function reviewCounts(items: readonly ReviewItem[]): ReviewCountsDetail {\n let comments = 0\n let edits = 0\n let highlights = 0\n for (const item of items) {\n if (item.type === 'suggestion') edits++\n else if (item.type === 'highlight') highlights++\n else comments += item.comments.length\n }\n return { comments, edits, highlights }\n}\n","import type { Root } from 'mdast'\nimport remarkGfm from 'remark-gfm'\nimport remarkParse from 'remark-parse'\nimport { unified } from 'unified'\n\nconst processor = unified().use(remarkParse).use(remarkGfm).freeze()\n\n/** Parse markdown (GFM) to mdast with position offsets intact. */\nexport function parseMarkdown(text: string): Root {\n const tree = processor.parse(text)\n return processor.runSync(tree) as Root\n}\n","import type { Node, Parent } from 'unist'\nimport type { Range } from '../critic/types'\nimport { parseMarkdown } from './processor'\n\nconst EXCLUDED_TYPES = new Set(['code', 'inlineCode', 'html'])\n\n/**\n * Ranges the CriticMarkup scanner must treat as opaque: fenced/indented code,\n * inline code, and raw HTML — one notion of \"code\", derived from a plain\n * remark parse of the same text so it can never drift from rendering.\n */\nexport function codeRanges(text: string): Range[] {\n const tree = parseMarkdown(text)\n const out: Range[] = []\n const visit = (node: Node): void => {\n const start = node.position?.start?.offset\n const end = node.position?.end?.offset\n if (EXCLUDED_TYPES.has(node.type) && start !== undefined && end !== undefined) {\n out.push({ start, end })\n return\n }\n const children = (node as Parent).children\n if (children) for (const child of children) visit(child)\n }\n visit(tree)\n return out.sort((a, b) => a.start - b.start)\n}\n","import type { ListItem, RootContent } from 'mdast'\nimport { scan } from './critic/scanner'\nimport { codeRanges } from './markdown/exclusions'\nimport { parseMarkdown } from './markdown/processor'\n\nexport interface SourceBlock {\n hash: string\n text: string\n start: number\n end: number\n kind: string\n /** code/html blocks are never translated */\n translatable: boolean\n}\n\nconst UNTRANSLATABLE = new Set(['code', 'html', 'thematicBreak', 'definition'])\n\n/** sha-256 via WebCrypto — identical hashes in the browser and the daemon. */\nexport async function hashBlock(kind: string, text: string): Promise<string> {\n const data = new TextEncoder().encode(`${kind}\u0000${text}`)\n const digest = await globalThis.crypto.subtle.digest('SHA-256', data)\n return [...new Uint8Array(digest)].map((b) => b.toString(16).padStart(2, '0')).join('')\n}\n\n/**\n * Translation granularity: top-level blocks, with list items individually\n * (editing one item re-translates only that item). Block slices are raw\n * source — CriticMarkup travels through translation inside them.\n */\nexport async function segmentBlocks(text: string): Promise<SourceBlock[]> {\n const tree = parseMarkdown(text)\n const out: SourceBlock[] = []\n\n const push = async (node: RootContent | ListItem, kind: string): Promise<void> => {\n const start = node.position?.start?.offset\n const end = node.position?.end?.offset\n if (start === undefined || end === undefined || end <= start) return\n const slice = text.slice(start, end)\n out.push({\n hash: await hashBlock(kind, slice),\n text: slice,\n start,\n end,\n kind,\n translatable: !UNTRANSLATABLE.has(kind),\n })\n }\n\n for (const node of tree.children) {\n if (node.type === 'list') {\n for (const item of node.children) await push(item, 'listItem')\n continue\n }\n await push(node, node.type)\n }\n return out\n}\n\n/**\n * A translated block is acceptable only when its CriticMarkup structure\n * matches the original: same mark kinds, same order. Inner text may change\n * (it was translated); the syntax may not.\n */\nexport function validateTranslatedBlock(original: string, translated: string): boolean {\n const kinds = (t: string): string =>\n scan(t, codeRanges(t))\n .map((s) => s.kind)\n .join(',')\n return kinds(original) === kinds(translated)\n}\n\n/** Cheap doc-language heuristic for picking the toggle direction. */\nexport function detectDocScript(text: string): 'cjk' | 'latin' {\n const sample = text.slice(0, 4000)\n let cjk = 0\n let letters = 0\n for (const ch of sample) {\n const code = ch.codePointAt(0)!\n if (code >= 0x4e00 && code <= 0x9fff) cjk++\n if ((code >= 0x41 && code <= 0x7a) || (code >= 0x4e00 && code <= 0x9fff)) letters++\n }\n return letters > 0 && cjk / letters > 0.25 ? 'cjk' : 'latin'\n}\n","/**\n * The curated language list backing the reading-pair picker. Browser-safe and\n * isomorphic — imported by the settings combobox (UI) *and* the translation\n * direction heuristic (`pickTarget` in the translate store), so both agree on\n * what counts as a CJK-script language.\n *\n * Stored config values are the human `name` (\"English\", \"Simplified Chinese\").\n * Lookups also match legacy BCP-47 codes (\"en\", \"zh-CN\") and endonyms so old\n * configs and free-typed custom languages still resolve. The agent LLM is the\n * only translation backend, so any string works as a language — the list is a\n * convenience, not a constraint (see the \"custom language\" fallback).\n */\nexport interface Language {\n /** BCP-47-ish code — kept for back-compat matching of legacy stored values. */\n code: string\n /** English display name — the canonical value stored in config. */\n name: string\n /** Endonym, shown muted beside the English name. */\n native: string\n /** True for CJK-script languages; drives translation-direction detection. */\n cjk?: boolean\n}\n\n/** ~30 common languages. Order is rough frequency, not alphabetical. */\nexport const LANGUAGES: Language[] = [\n { code: 'en', name: 'English', native: 'English' },\n { code: 'zh-CN', name: 'Simplified Chinese', native: '简体中文', cjk: true },\n { code: 'zh-TW', name: 'Traditional Chinese', native: '繁體中文', cjk: true },\n { code: 'ja', name: 'Japanese', native: '日本語', cjk: true },\n { code: 'ko', name: 'Korean', native: '한국어', cjk: true },\n { code: 'es', name: 'Spanish', native: 'Español' },\n { code: 'fr', name: 'French', native: 'Français' },\n { code: 'de', name: 'German', native: 'Deutsch' },\n { code: 'it', name: 'Italian', native: 'Italiano' },\n { code: 'pt', name: 'Portuguese', native: 'Português' },\n { code: 'ru', name: 'Russian', native: 'Русский' },\n { code: 'ar', name: 'Arabic', native: 'العربية' },\n { code: 'hi', name: 'Hindi', native: 'हिन्दी' },\n { code: 'bn', name: 'Bengali', native: 'বাংলা' },\n { code: 'pa', name: 'Punjabi', native: 'ਪੰਜਾਬੀ' },\n { code: 'id', name: 'Indonesian', native: 'Bahasa Indonesia' },\n { code: 'ms', name: 'Malay', native: 'Bahasa Melayu' },\n { code: 'vi', name: 'Vietnamese', native: 'Tiếng Việt' },\n { code: 'th', name: 'Thai', native: 'ไทย' },\n { code: 'tr', name: 'Turkish', native: 'Türkçe' },\n { code: 'nl', name: 'Dutch', native: 'Nederlands' },\n { code: 'pl', name: 'Polish', native: 'Polski' },\n { code: 'uk', name: 'Ukrainian', native: 'Українська' },\n { code: 'sv', name: 'Swedish', native: 'Svenska' },\n { code: 'fi', name: 'Finnish', native: 'Suomi' },\n { code: 'el', name: 'Greek', native: 'Ελληνικά' },\n { code: 'he', name: 'Hebrew', native: 'עברית' },\n { code: 'fa', name: 'Persian', native: 'فارسی' },\n { code: 'cs', name: 'Czech', native: 'Čeština' },\n { code: 'ro', name: 'Romanian', native: 'Română' },\n { code: 'hu', name: 'Hungarian', native: 'Magyar' },\n]\n\nconst norm = (s: string): string => s.trim().toLowerCase()\n\n/** Resolve a stored value (English name, legacy code, or endonym) to its entry. */\nexport function findLanguage(value: string): Language | undefined {\n const v = norm(value)\n if (!v) return undefined\n return LANGUAGES.find((l) => norm(l.name) === v || norm(l.code) === v || norm(l.native) === v)\n}\n\n/** Display parts for a stored value; `custom` is true for anything off-list. */\nexport function langLabel(value: string): { name: string; native?: string; custom: boolean } {\n const hit = findLanguage(value)\n if (hit) return { name: hit.name, native: hit.native, custom: false }\n return { name: value, custom: true }\n}\n\n/**\n * Whether a stored language value is CJK-script — the signal `pickTarget` uses\n * to decide which side of the pair is the source for a CJK document. Known\n * languages use their `cjk` flag; custom values fall back to legacy codes,\n * common endonym prefixes, and the presence of CJK characters.\n */\nexport function isCjkLang(value: string): boolean {\n const hit = findLanguage(value)\n if (hit) return !!hit.cjk\n return (\n /^(zh|ja|ko|cjk|中文|日本|한국)/i.test(value.trim()) ||\n /[一-鿿-ヿ가-]/.test(value)\n )\n}\n\n/** Filter the list for the combobox search (matches name, endonym, or code). */\nexport function searchLanguages(query: string): Language[] {\n const q = norm(query)\n if (!q) return LANGUAGES\n return LANGUAGES.filter((l) => norm(l.name).includes(q) || norm(l.native).includes(q) || norm(l.code).includes(q))\n}\n","/**\n * Reading-pair translation direction — picks which side of the `langPair` is the\n * source vs. target for a given document, from a CJK-script heuristic.\n *\n * Isomorphic / browser-safe so BOTH the browser (translate toggle) and the CLI\n * (offline `translate-blocks` pre-translate) compute the SAME target-language\n * string — that parity is what makes a CLI-written translation cache a hit when\n * the browser later asks for it.\n */\n\nimport { detectDocScript } from './blocks'\nimport { isCjkLang } from './languages'\n\nexport function pickTarget(source: string, pair: { a: string; b: string }): { sourceLang: string; targetLang: string } {\n const docIsCjk = detectDocScript(source) === 'cjk'\n const aIsCjk = isCjkLang(pair.a)\n if (docIsCjk) {\n return aIsCjk ? { sourceLang: pair.a, targetLang: pair.b } : { sourceLang: pair.b, targetLang: pair.a }\n }\n return aIsCjk ? { sourceLang: pair.b, targetLang: pair.a } : { sourceLang: pair.a, targetLang: pair.b }\n}\n\nexport function previewTargetLang(source: string, pair: { a: string; b: string }): string {\n return pickTarget(source, pair).targetLang\n}\n","import path from 'node:path'\nimport fs from 'node:fs/promises'\n\n/**\n * On-disk translation cache. Translations are keyed by content hash (sha-256 of\n * the block) and target language, so they survive reloads and unrelated edits —\n * an unchanged block stays translated without re-asking the agent. Lives next to\n * the document under `.mastermind/translations/`, the same sibling dir the rest\n * of Mastermind's on-disk state uses (and which the workspace tree hides).\n */\nexport function cacheFile(realPath: string, targetLang: string): string {\n // targetLang is a language code (en, zh-CN, …); sanitize anyway for the filename.\n const safeLang = targetLang.replace(/[^a-zA-Z0-9_-]/g, '_') || 'x'\n return path.join(path.dirname(realPath), '.mastermind', 'translations', `${path.basename(realPath)}.${safeLang}.json`)\n}\n\n/** The cached `{ blockHash: translatedText }` map, or `{}` if none/unreadable. */\nexport async function loadCache(realPath: string, targetLang: string): Promise<Record<string, string>> {\n try {\n const raw = await fs.readFile(cacheFile(realPath, targetLang), 'utf8')\n const parsed: unknown = JSON.parse(raw)\n return parsed && typeof parsed === 'object' ? (parsed as Record<string, string>) : {}\n } catch {\n return {}\n }\n}\n\n/**\n * Merge fresh translations into the on-disk cache (read-modify-write). Best-effort:\n * a disk failure never breaks translation, it just doesn't persist. Content-addressed,\n * so superseded block versions linger harmlessly until pruned by a future cleanup.\n */\nexport async function saveCache(realPath: string, targetLang: string, entries: Record<string, string>): Promise<void> {\n if (Object.keys(entries).length === 0) return\n const file = cacheFile(realPath, targetLang)\n try {\n await fs.mkdir(path.dirname(file), { recursive: true })\n const merged = { ...(await loadCache(realPath, targetLang)), ...entries }\n await fs.writeFile(file, JSON.stringify(merged))\n } catch {\n // best-effort: the in-memory translation still works even if the cache can't persist\n }\n}\n","/**\n * Offline pre-translate — the engine behind `mastermind translate-blocks`.\n *\n * The agent (any agent) translates a document's blocks up front and writes them\n * straight into the on-disk translation cache, so Mastermind's toggle is warm on\n * open with NO live serve loop: `translateBlocks` finds every block already cached\n * (`loadCache`) and asks no one. This is the \"always translate first\" guardrail,\n * realized as a pure file op.\n *\n * Parity is everything: the blocks are segmented with the same isomorphic\n * `segmentBlocks`/`hashBlock` the browser uses, and the target language is chosen\n * with the same `pickTarget` — so the cache the CLI writes is exactly the cache the\n * browser later reads.\n */\n\nimport { segmentBlocks, validateTranslatedBlock } from '../../shared/blocks'\nimport { pickTarget } from '../../shared/translate-direction'\nimport { cacheFile, loadCache, saveCache } from './cache'\n\nexport interface PretranslatePlan {\n sourceLang: string\n targetLang: string\n cachePath: string\n /** translatable blocks not yet in the cache — what the agent must translate */\n blocks: { hash: string; text: string }[]\n}\n\n/** Segment a doc and list the translatable blocks still missing from the target-language cache. */\nexport async function planPretranslate(\n realPath: string,\n source: string,\n langPair: { a: string; b: string },\n): Promise<PretranslatePlan> {\n const { sourceLang, targetLang } = pickTarget(source, langPair)\n const cached = await loadCache(realPath, targetLang)\n const blocks = (await segmentBlocks(source))\n .filter((b) => b.translatable && cached[b.hash] === undefined)\n .map((b) => ({ hash: b.hash, text: b.text }))\n return { sourceLang, targetLang, cachePath: cacheFile(realPath, targetLang), blocks }\n}\n\nexport interface PretranslateWriteResult {\n targetLang: string\n cachePath: string\n written: number\n /** total dropped = unknown-hash + CriticMarkup-mismatch */\n skipped: number\n /** dropped because the hash isn't in the current document (stale plan / the doc changed) */\n skippedUnknownHash: number\n /** dropped because the translation's CriticMarkup structure didn't match the source */\n skippedMarkMismatch: number\n}\n\n/**\n * Validate agent translations against the source's CriticMarkup structure, then write the\n * valid ones to the on-disk cache (same path/format `loadCache` reads). A translation that\n * adds/drops/reorders marks is rejected, never cached — the engine's invariant, enforced here.\n */\nexport async function writePretranslations(\n realPath: string,\n source: string,\n langPair: { a: string; b: string },\n entries: { hash: string; text: string }[],\n): Promise<PretranslateWriteResult> {\n const { targetLang } = pickTarget(source, langPair)\n const originals = new Map((await segmentBlocks(source)).map((b) => [b.hash, b.text]))\n const valid: Record<string, string> = {}\n let skippedUnknownHash = 0\n let skippedMarkMismatch = 0\n for (const { hash, text } of entries) {\n const original = originals.get(hash)\n if (original === undefined) skippedUnknownHash++\n else if (!validateTranslatedBlock(original, text)) skippedMarkMismatch++\n else valid[hash] = text\n }\n await saveCache(realPath, targetLang, valid)\n return {\n targetLang,\n cachePath: cacheFile(realPath, targetLang),\n written: Object.keys(valid).length,\n skipped: skippedUnknownHash + skippedMarkMismatch,\n skippedUnknownHash,\n skippedMarkMismatch,\n }\n}\n","/**\n * Pure helpers for `mastermind config set/get` — extracted so they can be unit-tested\n * without spawning the CLI (the entrypoint runs `program.parseAsync()` at import).\n *\n * The server merges config patches SHALLOWLY at the top level (`{ ...readConfig(), ...patch }`),\n * so a dotted edit like `langPair.a=…` must be applied onto a copy of the *current* config and\n * the WHOLE top-level key sent back — otherwise `langPair.b` (or a `grain.<theme>` sibling) is\n * silently dropped. These helpers also validate input so a malformed value can never persist\n * `NaN`/`null` or pollute the config with unknown keys.\n */\n\nimport type { MastermindConfig } from '../shared/types'\n\n/** Writable top-level config keys (everything in MastermindConfig except the fixed `version`). */\nconst CONFIG_KEYS: ReadonlySet<string> = new Set([\n 'theme',\n 'fontSize',\n 'lineHeight',\n 'contentWidth',\n 'authorTag',\n 'typeSet',\n 'monoFont',\n 'codeTheme',\n 'uiLang',\n 'langPair',\n 'browser',\n 'grain',\n])\n\nconst NUMERIC_KEYS: ReadonlySet<string> = new Set(['fontSize', 'lineHeight', 'contentWidth'])\n\nexport interface Assignment {\n key: string\n value: string\n}\n\n/** Split `key=value` on the first `=`. Throws on a missing/leading `=`. */\nexport function parseAssignment(arg: string): Assignment {\n const eq = arg.indexOf('=')\n if (eq < 1) throw new Error(`expected key=value, got: ${arg}`)\n return { key: arg.slice(0, eq), value: arg.slice(eq + 1) }\n}\n\n/** Coerce a string value for a key: numeric keys → a finite number (throws on NaN), else the string. */\nexport function coerceConfigValue(key: string, value: string): unknown {\n if (!NUMERIC_KEYS.has(key.split('.')[0]!)) return value\n const n = Number(value)\n if (value.trim() === '' || !Number.isFinite(n) || n <= 0) {\n throw new Error(`${key} must be a positive number, got: ${value === '' ? '(empty)' : value}`)\n }\n return n\n}\n\nfunction setDotted(obj: Record<string, unknown>, dotted: string, value: unknown): void {\n const parts = dotted.split('.')\n let cur = obj\n for (let i = 0; i < parts.length - 1; i++) {\n const k = parts[i]!\n const existing = cur[k]\n if (existing === undefined || existing === null) cur[k] = {}\n else if (typeof existing !== 'object') {\n throw new Error(`cannot set ${dotted}: ${parts.slice(0, i + 1).join('.')} is not a nested object`)\n }\n cur = cur[k] as Record<string, unknown>\n }\n cur[parts[parts.length - 1]!] = value\n}\n\nexport function getDotted(obj: Record<string, unknown>, dotted: string): unknown {\n return dotted\n .split('.')\n .reduce<unknown>((acc, k) => (acc == null ? undefined : (acc as Record<string, unknown>)[k]), obj)\n}\n\n/**\n * Apply `key=value` assignments onto a COPY of `current`, validating each, and return the\n * patch of touched TOP-LEVEL keys (full values, so the shallow server merge preserves siblings).\n * Throws on an unknown key, a non-finite numeric, or dotting into a scalar field.\n */\nexport function applyAssignments(current: MastermindConfig, assignments: Assignment[]): { patch: Record<string, unknown> } {\n const next = structuredClone(current) as unknown as Record<string, unknown>\n for (const { key, value } of assignments) {\n const top = key.split('.')[0]!\n if (!CONFIG_KEYS.has(top)) throw new Error(`unknown config key: ${top}`)\n setDotted(next, key, coerceConfigValue(key, value))\n }\n const patch: Record<string, unknown> = {}\n for (const top of new Set(assignments.map((a) => a.key.split('.')[0]!))) patch[top] = next[top]\n return { patch }\n}\n","/**\n * Pure `open` argv construction for the browser launcher — extracted so the\n * override/trim/system-default logic can be unit-tested (openBrowser itself is\n * darwin-gated and spawns a process).\n */\n\n/**\n * Build the macOS `open` argv for a URL.\n * - a non-empty `--in` override or configured browser → `['-a', <app>, url]`\n * - otherwise (empty/whitespace) → `[url]` (the system default browser)\n * The override wins over the configured default; an explicit empty override means \"system default\".\n */\nexport function browserOpenArgs(url: string, override: string | undefined, configBrowser: string): string[] {\n const app = (override ?? configBrowser).trim()\n return app ? ['-a', app, url] : [url]\n}\n","/**\n * Pure helpers for `mastermind install-agents` / `uninstall-agents` — the multi-agent\n * provisioning of the `mastermind`/`master` skills + a global instruction block.\n *\n * Kept pure (no fs) so the marker handling and per-agent frontmatter are unit-testable; the\n * CLI command does the filesystem work with these.\n */\n\nexport const MM_BEGIN = '<!-- mastermind:begin -->'\nexport const MM_END = '<!-- mastermind:end -->'\n\nexport interface AgentTarget {\n id: 'claude' | 'cursor' | 'gemini' | 'agents'\n /** config dir relative to the user's home, e.g. '.claude' */\n dir: string\n /** global-memory file in that dir to append the instruction block to, or null if unknown */\n globalFile: string | null\n /** include a `version:` field in skill frontmatter */\n version: boolean\n /** include a `license:` field in skill frontmatter */\n license: boolean\n}\n\n/** The agents we know how to provision, with the frontmatter quirks the drill confirmed. */\nexport const AGENT_TARGETS: AgentTarget[] = [\n { id: 'claude', dir: '.claude', globalFile: 'CLAUDE.md', version: false, license: false },\n { id: 'cursor', dir: '.cursor', globalFile: null, version: true, license: true },\n { id: 'gemini', dir: '.gemini', globalFile: 'GEMINI.md', version: true, license: false },\n { id: 'agents', dir: '.agents', globalFile: null, version: false, license: false },\n]\n\nfunction escapeRe(s: string): string {\n return s.replace(/[.*+?^${}()|[\\]\\\\]/g, '\\\\$&')\n}\n\n/** Strip a leading `---\\n…\\n---\\n` YAML frontmatter block, returning the body. */\nexport function stripFrontmatter(md: string): string {\n if (!md.startsWith('---\\n')) return md\n const end = md.indexOf('\\n---', 4)\n if (end === -1) return md\n const after = md.indexOf('\\n', end + 1)\n return after === -1 ? '' : md.slice(after + 1).replace(/^\\n+/, '')\n}\n\n/** Build SKILL.md frontmatter for a target agent (single-line description). */\nexport function skillFile(t: AgentTarget, name: string, description: string, body: string, version: string): string {\n const lines = ['---', `name: ${name}`, `description: ${description.replace(/\\n+/g, ' ').trim()}`]\n if (t.version) lines.push(`version: ${version}`)\n if (t.license) lines.push('license: Apache-2.0')\n lines.push('---', '')\n return `${lines.join('\\n')}\\n${body.trim()}\\n`\n}\n\n/** The marker-wrapped instruction block. */\nexport function wrapGlobalBlock(body: string): string {\n return `${MM_BEGIN}\\n${body.trim()}\\n${MM_END}`\n}\n\n/** Insert or replace the marker-wrapped block in a global-memory file (idempotent). */\nexport function upsertMarkedBlock(existing: string, body: string): string {\n const block = wrapGlobalBlock(body)\n const re = new RegExp(`${escapeRe(MM_BEGIN)}[\\\\s\\\\S]*?${escapeRe(MM_END)}`)\n if (re.test(existing)) return existing.replace(re, block)\n if (existing.trim() === '') return `${block}\\n`\n return `${existing.replace(/\\n*$/, '')}\\n\\n${block}\\n`\n}\n\n/** Remove the marker-wrapped block (idempotent — a no-op if absent). */\nexport function removeMarkedBlock(existing: string): string {\n const re = new RegExp(`\\\\n*${escapeRe(MM_BEGIN)}[\\\\s\\\\S]*?${escapeRe(MM_END)}\\\\n*`, 'g')\n return existing.replace(re, '\\n').replace(/^\\n+/, '').replace(/\\n{3,}/g, '\\n\\n')\n}\n"],"mappings":"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","names":["spawn","fs","path","os","fs","path","fs","fs","fs","fileURLToPath","fileURLToPath","fs","fs","path","fs","path","path","fs","spawn","path","fs","os"]}
|