@vortex-os/base 0.0.1 → 0.2.3

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/dist/index.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,MAAM,CAAC,MAAM,mBAAmB,GAAG,OAAgB,CAAC;AAWpD,MAAM,CAAC,MAAM,cAAc,GAAwB;IACjD,OAAO,EAAE,mBAAmB;IAC5B,SAAS,EAAE,WAAW;IACtB,iBAAiB,EAAE,OAAO;IAC1B,eAAe,EACb,yEAAyE;IAC3E,UAAU,EAAE,2CAA2C;CACxD,CAAC"}
1
+ {"version":3,"sources":["../../core/src/index.ts","../../core/src/types.ts","../../core/src/frontmatter.ts","../../core/src/privacy.ts","../../core/src/paths.ts","../../core/src/config.ts","../../modules/slash-commands/src/index.ts","../../modules/slash-commands/src/registry.ts","../../modules/slash-commands/src/runner.ts","../../modules/memory-system/src/index.ts","../../modules/memory-system/src/types.ts","../../modules/memory-system/src/store.ts","../../modules/memory-system/src/memory-index.ts","../../modules/memory-system/src/sync.ts","../../modules/data-lint/src/index.ts","../../modules/data-lint/src/runner.ts","../../modules/data-lint/src/rules/require-frontmatter.ts","../../modules/data-lint/src/rules/privacy-valid.ts","../../modules/data-lint/src/rules/wiki-link-resolves.ts","../../modules/ai-coding-pitfalls/src/index.ts","../../modules/ai-coding-pitfalls/src/catalog.ts","../../modules/tool-rules/src/index.ts","../../modules/tool-rules/src/catalog.ts","../../modules/report-generator/src/index.ts","../../node_modules/marked/src/defaults.ts","../../node_modules/marked/src/rules.ts","../../node_modules/marked/src/helpers.ts","../../node_modules/marked/src/Tokenizer.ts","../../node_modules/marked/src/Lexer.ts","../../node_modules/marked/src/Renderer.ts","../../node_modules/marked/src/TextRenderer.ts","../../node_modules/marked/src/Parser.ts","../../node_modules/marked/src/Hooks.ts","../../node_modules/marked/src/Instance.ts","../../node_modules/marked/src/marked.ts","../../modules/report-generator/src/filter.ts","../../modules/report-generator/src/template.ts","../../modules/report-generator/src/renderer.ts","../../modules/worklog/src/index.ts","../../modules/worklog/src/store.ts","../../modules/worklog/src/append.ts","../../modules/decision-log/src/index.ts","../../modules/decision-log/src/store.ts","../../modules/decision-log/src/template.ts","../../modules/index-generator/src/index.ts","../../modules/index-generator/src/scan.ts","../../modules/index-generator/src/render.ts","../../modules/index-generator/src/nested.ts","../../modules/runbooks/src/index.ts","../../modules/runbooks/src/store.ts","../../modules/link-rewriter/src/index.ts","../../modules/link-rewriter/src/extract.ts","../../modules/link-rewriter/src/resolve.ts","../../modules/link-rewriter/src/checker.ts","../../modules/link-rewriter/src/rewrite.ts","../../modules/proactive-curator/src/index.ts","../../modules/proactive-curator/src/fingerprint.ts","../../modules/proactive-curator/src/decline-store.ts","../../modules/proactive-curator/src/insight-proposer.ts","../../modules/proactive-curator/src/hub-proposer.ts","../../modules/proactive-curator/src/ambient-tracker.ts","../../modules/proactive-curator/src/ambient-recaller.ts","../../modules/proactive-curator/src/adapters/shared.ts","../../modules/proactive-curator/src/adapters/claude-code.ts","../../modules/proactive-curator/src/adapters/codex.ts","../../modules/proactive-curator/src/adapters/gemini.ts","../../modules/proactive-curator/src/adapters/claude-desktop.ts","../../plugins/session-rituals/src/index.ts","../../plugins/session-rituals/src/commands/curate.ts","../../plugins/session-rituals/src/commands/recall.ts","../../plugins/session-rituals/src/commands/decision.ts","../../plugins/session-rituals/src/commands/reindex.ts","../../plugins/session-rituals/src/commands/session-start.ts","../../plugins/session-rituals/src/commands/log.ts","../../plugins/session-rituals/src/commands/vortex.ts","../../plugins/session-rituals/src/ensure-hooks.ts","../../plugins/session-rituals/src/agenda.ts","../../plugins/session-rituals/src/commands/agenda.ts","../../plugins/session-rituals/src/registry.ts","../../plugins/session-rituals/src/ambient-recall.ts","../../plugins/session-rituals/src/session-start-report.ts","../../plugins/session-rituals/src/worklog-write.ts","../../plugins/session-rituals/src/catch-up.ts"],"sourcesContent":["export { Privacy } from \"./types.js\";\nexport type { FrontmatterDoc, ModuleContext } from \"./types.js\";\nexport { parseFrontmatter, serializeFrontmatter } from \"./frontmatter.js\";\nexport { isVisibleAt, maxPrivacy, normalizePrivacy } from \"./privacy.js\";\nexport { makeContext, moduleDir } from \"./paths.js\";\nexport { loadVortexConfig, resolveEnvironment, vortexConfigPath } from \"./config.js\";\nexport type { AutoRecordConfig, EnvironmentRule, VortexConfig } from \"./config.js\";\n","/**\n * Three-tier privacy classification used across VortEX.\n *\n * - `public` — safe to share with anyone, including in published repositories.\n * - `internal` — visible to the operator and their organization; not for public release.\n * - `personal` — personal data; never shared, never published.\n */\nexport const Privacy = {\n Public: \"public\",\n Internal: \"internal\",\n Personal: \"personal\",\n} as const;\n\nexport type Privacy = (typeof Privacy)[keyof typeof Privacy];\n\n/**\n * Parsed markdown document with separated YAML frontmatter and body.\n */\nexport interface FrontmatterDoc<T = Record<string, unknown>> {\n frontmatter: T & { privacy?: Privacy };\n body: string;\n}\n\n/**\n * Resolved paths for a VortEX repository root.\n *\n * Every module receives a `ModuleContext` from the host (CLI, plugin runtime,\n * or test harness) and resolves its own paths against it. Modules must not\n * derive paths by string manipulation against an assumed layout.\n */\nexport interface ModuleContext {\n repoRoot: string;\n agentDir: string;\n dataDir: string;\n modulesDir: string;\n pluginsDir: string;\n}\n","import { parse as parseYaml, stringify as stringifyYaml } from \"yaml\";\nimport type { FrontmatterDoc, Privacy } from \"./types.js\";\n\nconst FENCE = /^---\\r?\\n([\\s\\S]*?)\\r?\\n---\\r?\\n?/;\nconst BOM = \"\";\n\n/**\n * Parse a markdown source into its YAML frontmatter and body. If no frontmatter\n * fence is present, returns an empty frontmatter object and the source unchanged.\n *\n * A leading UTF-8 BOM is stripped before matching. Windows-authored files\n * frequently begin with ``, which would otherwise prevent the fence\n * regex from anchoring to `---` at byte 0.\n */\nexport function parseFrontmatter<T = Record<string, unknown>>(\n source: string,\n): FrontmatterDoc<T> {\n const cleaned = source.startsWith(BOM) ? source.slice(1) : source;\n const match = cleaned.match(FENCE);\n if (!match) {\n return {\n frontmatter: {} as T & { privacy?: Privacy },\n body: cleaned,\n };\n }\n const yaml = match[1] ?? \"\";\n const body = cleaned.slice(match[0].length);\n let parsed: T & { privacy?: Privacy };\n try {\n parsed = (parseYaml(yaml) ?? {}) as T & { privacy?: Privacy };\n } catch {\n // The fence was present but its YAML body did not parse — often the\n // result of copy/paste artifacts (a stray `---` mid-document, headings\n // accidentally pasted inside the fence). Treat as no frontmatter so\n // callers can still read the body; the fence content is discarded.\n parsed = {} as T & { privacy?: Privacy };\n }\n return { frontmatter: parsed, body };\n}\n\n/**\n * Serialize a `FrontmatterDoc` back into markdown text. If the frontmatter is\n * empty, the body is returned unchanged (no empty fence is emitted).\n */\nexport function serializeFrontmatter<T = Record<string, unknown>>(\n doc: FrontmatterDoc<T>,\n): string {\n const keys = Object.keys(doc.frontmatter ?? {});\n if (keys.length === 0) return doc.body;\n const yaml = stringifyYaml(doc.frontmatter).trimEnd();\n return `---\\n${yaml}\\n---\\n${doc.body}`;\n}\n","import type { Privacy } from \"./types.js\";\n\nconst ORDER: Record<Privacy, number> = {\n public: 0,\n internal: 1,\n personal: 2,\n};\n\n/**\n * Returns true if a document with `docPrivacy` is visible to a viewer authorized\n * at `viewerPrivacy`. Viewers see content at or below their own level.\n *\n * - `public` viewer sees → public only\n * - `internal` viewer sees → public + internal\n * - `personal` viewer sees → all three\n */\nexport function isVisibleAt(docPrivacy: Privacy, viewerPrivacy: Privacy): boolean {\n return ORDER[docPrivacy] <= ORDER[viewerPrivacy];\n}\n\n/**\n * Returns the more-restrictive of two privacy levels.\n * Useful when combining content from multiple sources for sharing.\n */\nexport function maxPrivacy(a: Privacy, b: Privacy): Privacy {\n return ORDER[a] >= ORDER[b] ? a : b;\n}\n\n/**\n * Coerce an unknown value (e.g. user input or untyped frontmatter) into a\n * valid `Privacy`. Falls back to `internal` by default — the safest default\n * for unclassified content.\n */\nexport function normalizePrivacy(value: unknown, fallback: Privacy = \"internal\"): Privacy {\n if (value === \"public\" || value === \"internal\" || value === \"personal\") {\n return value;\n }\n return fallback;\n}\n","import { resolve, join } from \"node:path\";\nimport type { ModuleContext } from \"./types.js\";\n\n/**\n * Build a `ModuleContext` for the given VortEX repository root. The root is\n * resolved to an absolute path; standard subdirectories are derived by\n * convention and are not guaranteed to exist on disk.\n */\nexport function makeContext(repoRoot: string): ModuleContext {\n const root = resolve(repoRoot);\n return {\n repoRoot: root,\n agentDir: join(root, \".agent\"),\n dataDir: join(root, \"data\"),\n modulesDir: join(root, \"modules\"),\n pluginsDir: join(root, \"plugins\"),\n };\n}\n\n/**\n * Resolve the directory of a named module within the repository.\n */\nexport function moduleDir(ctx: ModuleContext, moduleName: string): string {\n return join(ctx.modulesDir, moduleName);\n}\n","import { existsSync, readFileSync } from \"node:fs\";\nimport { join } from \"node:path\";\nimport type { ModuleContext } from \"./types.js\";\n\n/**\n * Instance configuration for VortEX, read from `<agentDir>/vortex.json`.\n *\n * The config exists to give the user control over the **auto-maintained**\n * operational behaviors (see `AGENT.md` → \"Default behaviors\") without\n * touching code: toggle any auto-record off, and declare how this machine's\n * environment is detected. A fresh instance has no config file — everything\n * is on, no environment — so the framework works out of the box and the file\n * is purely opt-in tuning.\n */\n\n/** Which auto-maintained operational records are enabled. Default: all on. */\nexport interface AutoRecordConfig {\n readonly sessionStart: boolean;\n readonly worklog: boolean;\n readonly decision: boolean;\n readonly ambientRecall: boolean;\n /**\n * Catch-up: at session start, ingest conversation transcripts that have not\n * been archived yet (the host's own machine only). Text is stored\n * immediately; vectorization is deferred to recall/rebuild so start stays\n * fast. Off → no automatic ingest; the archive only grows when explicitly\n * rebuilt.\n */\n readonly archive: boolean;\n}\n\n/**\n * One environment label plus the signal that selects it. Rules are evaluated\n * in order; the first match wins. Generalizes the operator's home/work\n * `Test-Path` pattern into a portable, declarative form.\n */\nexport interface EnvironmentRule {\n readonly label: string;\n /** Match when this absolute path exists on the machine. */\n readonly pathExists?: string;\n /** Match when the OS hostname equals this (case-insensitive). */\n readonly hostname?: string;\n /**\n * Match when an environment variable is set. A bare string matches on\n * presence; the object form additionally requires a specific value.\n */\n readonly envVar?: string | { readonly name: string; readonly equals?: string };\n}\n\nexport interface VortexConfig {\n readonly autoRecord: AutoRecordConfig;\n readonly environments: readonly EnvironmentRule[];\n}\n\nconst DEFAULT_CONFIG: VortexConfig = {\n autoRecord: { sessionStart: true, worklog: true, decision: true, ambientRecall: true, archive: true },\n environments: [],\n};\n\n/** Path of the instance config file: `<agentDir>/vortex.json`. */\nexport function vortexConfigPath(ctx: ModuleContext): string {\n return join(ctx.agentDir, \"vortex.json\");\n}\n\n/**\n * Load the instance config, merged over defaults. A missing, unreadable, or\n * invalid file yields defaults (everything on, no environments) rather than\n * throwing — config is opt-in tuning, never a prerequisite.\n */\nexport function loadVortexConfig(ctx: ModuleContext): VortexConfig {\n const path = vortexConfigPath(ctx);\n if (!existsSync(path)) return DEFAULT_CONFIG;\n try {\n const raw = JSON.parse(readFileSync(path, \"utf8\")) as Partial<VortexConfig>;\n return {\n autoRecord: { ...DEFAULT_CONFIG.autoRecord, ...(raw.autoRecord ?? {}) },\n environments: Array.isArray(raw.environments) ? raw.environments : [],\n };\n } catch {\n return DEFAULT_CONFIG;\n }\n}\n\n/**\n * Resolve the active environment label from the config rules (first match\n * wins), or null when none match. Pure — the caller injects the signals\n * (hostname, env vars, a path-existence probe) so this stays testable and\n * free of direct OS access.\n */\nexport function resolveEnvironment(\n config: VortexConfig,\n signals: {\n readonly hostname?: string;\n readonly env?: Record<string, string | undefined>;\n readonly pathExists?: (p: string) => boolean;\n },\n): string | null {\n const host = signals.hostname?.toLowerCase();\n const env = signals.env ?? {};\n const pathExists = signals.pathExists ?? (() => false);\n for (const rule of config.environments) {\n if (rule.pathExists && pathExists(rule.pathExists)) return rule.label;\n if (rule.hostname && host && rule.hostname.toLowerCase() === host) return rule.label;\n if (rule.envVar) {\n if (typeof rule.envVar === \"string\") {\n if (env[rule.envVar] !== undefined) return rule.label;\n } else {\n const v = env[rule.envVar.name];\n if (v !== undefined && (rule.envVar.equals === undefined || v === rule.envVar.equals)) {\n return rule.label;\n }\n }\n }\n }\n return null;\n}\n","export type { Command, CommandArg, CommandInput } from \"./types.js\";\nexport { CommandRegistry } from \"./registry.js\";\nexport { runSlash, CommandNotFoundError } from \"./runner.js\";\nexport type { RunOptions } from \"./runner.js\";\n","import type { Command } from \"./types.js\";\n\n/**\n * Holds registered commands and looks them up by name.\n *\n * Names are matched exactly. Registering two commands with the same name\n * is an error — the second call throws. Callers that want to override an\n * existing command must `unregister` first.\n */\nexport class CommandRegistry {\n private readonly commands = new Map<string, Command>();\n\n register(command: Command): void {\n if (this.commands.has(command.name)) {\n throw new Error(`Command \"${command.name}\" is already registered`);\n }\n this.commands.set(command.name, command);\n }\n\n unregister(name: string): boolean {\n return this.commands.delete(name);\n }\n\n has(name: string): boolean {\n return this.commands.has(name);\n }\n\n get(name: string): Command | undefined {\n return this.commands.get(name);\n }\n\n list(): readonly Command[] {\n return Array.from(this.commands.values());\n }\n}\n","import type { ModuleContext } from \"@vortex-os/core\";\nimport type { CommandRegistry } from \"./registry.js\";\nimport type { CommandArg, CommandInput } from \"./types.js\";\n\nexport interface RunOptions {\n readonly registry: CommandRegistry;\n readonly context: ModuleContext;\n}\n\n/**\n * Thrown by `runSlash` when the requested command name does not exist\n * in the registry. The unknown name is exposed for caller diagnostics.\n */\nexport class CommandNotFoundError extends Error {\n readonly commandName: string;\n\n constructor(commandName: string) {\n super(`Unknown command: ${commandName}`);\n this.name = \"CommandNotFoundError\";\n this.commandName = commandName;\n }\n}\n\n/**\n * Parse an input string and dispatch the matching command.\n *\n * Accepted forms (leading slash optional):\n * \"name\"\n * \"/name\"\n * \"name arg1 arg2 ...\"\n *\n * Returns whatever the command's handler returns (awaited if it is async).\n */\nexport async function runSlash(\n input: string,\n { registry, context }: RunOptions,\n): Promise<unknown> {\n const trimmed = input.trim().replace(/^\\//, \"\");\n if (trimmed.length === 0) {\n throw new Error(\"Empty command input\");\n }\n\n const tokens = trimmed.split(/\\s+/);\n const name = tokens[0] ?? \"\";\n const tail = tokens.slice(1);\n\n const command = registry.get(name);\n if (!command) {\n throw new CommandNotFoundError(name);\n }\n\n const args = parseArgs(tail, command.args);\n const rest = tail.join(\" \");\n const ci: CommandInput = {\n raw: trimmed,\n args,\n rest,\n context,\n };\n return command.handler(ci);\n}\n\nfunction parseArgs(\n tokens: readonly string[],\n schema: readonly CommandArg[] | undefined,\n): Record<string, string> {\n const out: Record<string, string> = {};\n if (!schema) return out;\n for (let i = 0; i < schema.length; i += 1) {\n const arg = schema[i];\n const value = tokens[i];\n if (arg && value !== undefined) {\n out[arg.name] = value;\n }\n }\n return out;\n}\n","export { MemoryType } from \"./types.js\";\nexport type { Memory, MemoryFrontmatter } from \"./types.js\";\nexport { MemoryStore } from \"./store.js\";\nexport { writeMemoryIndex } from \"./memory-index.js\";\nexport type { WriteMemoryIndexOptions } from \"./memory-index.js\";\nexport { diffStores } from \"./sync.js\";\nexport type { SyncDiff } from \"./sync.js\";\n","/**\n * Canonical memory categories.\n *\n * - `user` — facts about the operator (role, preferences, working style).\n * - `feedback` — corrections and validated approaches from the operator.\n * - `project` — ongoing work context (goals, deadlines, stakeholders).\n * - `reference` — pointers to external systems (dashboards, repos, channels).\n *\n * Hosts may extend the set, but stability of these four is preserved.\n */\nexport const MemoryType = {\n User: \"user\",\n Feedback: \"feedback\",\n Project: \"project\",\n Reference: \"reference\",\n} as const;\n\nexport type MemoryType = (typeof MemoryType)[keyof typeof MemoryType];\n\n/**\n * Frontmatter required on every memory file.\n *\n * `name` should match the file id (filename without `.md`). `description`\n * is a single-line summary used in the generated index. `type` places the\n * memory in one of the canonical categories. Additional keys (e.g.\n * `originSessionId`, `created`, custom tags) are tolerated and preserved\n * on round-trip but are not required.\n */\nexport interface MemoryFrontmatter {\n name: string;\n description: string;\n type: MemoryType;\n [key: string]: unknown;\n}\n\n/**\n * A parsed memory document, ready to be written back or rendered.\n *\n * `id` is the filename stem (no `.md`); it is the address by which the\n * store retrieves and overwrites the memory.\n */\nexport interface Memory {\n id: string;\n frontmatter: MemoryFrontmatter;\n body: string;\n}\n","import { readdir, readFile, writeFile, mkdir, unlink, stat } from \"node:fs/promises\";\nimport { join, basename, extname } from \"node:path\";\nimport { parseFrontmatter, serializeFrontmatter } from \"@vortex-os/core\";\nimport type { Memory, MemoryFrontmatter } from \"./types.js\";\n\n/**\n * A directory-backed memory store.\n *\n * Each memory lives in a single `.md` file. The `MEMORY.md` (generated index)\n * and `_INDEX.md` (Obsidian-friendly index) files are excluded — they are\n * derived views, not memories themselves.\n */\nexport class MemoryStore {\n constructor(readonly dir: string) {}\n\n /** Ensure the backing directory exists. Safe to call repeatedly. */\n async ensure(): Promise<void> {\n await mkdir(this.dir, { recursive: true });\n }\n\n /** List memory ids (filename stems), sorted lexicographically. */\n async list(): Promise<readonly string[]> {\n try {\n const entries = await readdir(this.dir);\n return entries\n .filter((e) => e.endsWith(\".md\") && e !== \"MEMORY.md\" && e !== \"_INDEX.md\")\n .map((e) => basename(e, extname(e)))\n .sort();\n } catch (e) {\n if ((e as NodeJS.ErrnoException).code === \"ENOENT\") return [];\n throw e;\n }\n }\n\n /** Read a memory by id. Throws if the file does not exist. */\n async read(id: string): Promise<Memory> {\n const raw = await readFile(this.pathFor(id), \"utf8\");\n const { frontmatter, body } = parseFrontmatter<MemoryFrontmatter>(raw);\n return { id, frontmatter, body };\n }\n\n /** Write (or overwrite) a memory. Ensures the directory exists first. */\n async write(memory: Memory): Promise<void> {\n await this.ensure();\n const source = serializeFrontmatter({\n frontmatter: memory.frontmatter,\n body: memory.body,\n });\n await writeFile(this.pathFor(memory.id), source, \"utf8\");\n }\n\n /** Delete a memory. Returns false if it did not exist. */\n async delete(id: string): Promise<boolean> {\n try {\n await unlink(this.pathFor(id));\n return true;\n } catch (e) {\n if ((e as NodeJS.ErrnoException).code === \"ENOENT\") return false;\n throw e;\n }\n }\n\n /** Test whether a memory exists by id. */\n async has(id: string): Promise<boolean> {\n try {\n await stat(this.pathFor(id));\n return true;\n } catch {\n return false;\n }\n }\n\n /** Absolute path of a memory file (file may not exist). */\n pathFor(id: string): string {\n return join(this.dir, `${id}.md`);\n }\n}\n","import { writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport type { MemoryStore } from \"./store.js\";\n\nexport interface WriteMemoryIndexOptions {\n /** Top-level heading. Defaults to \"Memory Index\". */\n title?: string;\n /** Optional text placed above the heading (e.g. an HTML comment). */\n preamble?: string;\n}\n\n/**\n * Render a `MEMORY.md` index from the entries currently in `store` and\n * write it to `<store.dir>/MEMORY.md`. Existing `MEMORY.md` is overwritten.\n *\n * The index is a flat bullet list: one line per memory, linking to the\n * memory file and including the memory's `description`.\n */\nexport async function writeMemoryIndex(\n store: MemoryStore,\n options: WriteMemoryIndexOptions = {},\n): Promise<void> {\n const ids = await store.list();\n const lines: string[] = [];\n if (options.preamble) {\n lines.push(options.preamble, \"\");\n }\n lines.push(`# ${options.title ?? \"Memory Index\"}`, \"\");\n for (const id of ids) {\n const memory = await store.read(id);\n lines.push(\n `- [${memory.frontmatter.name}](${id}.md) — ${memory.frontmatter.description}`,\n );\n }\n await writeFile(join(store.dir, \"MEMORY.md\"), `${lines.join(\"\\n\")}\\n`, \"utf8\");\n}\n","import { readFile } from \"node:fs/promises\";\nimport type { MemoryStore } from \"./store.js\";\n\n/**\n * Difference between two memory stores. All three lists may be empty,\n * which means the stores are in sync.\n */\nexport interface SyncDiff {\n /** Ids present in `a` but not in `b`. */\n onlyInA: readonly string[];\n /** Ids present in `b` but not in `a`. */\n onlyInB: readonly string[];\n /** Ids present in both but whose raw file contents differ. */\n changed: readonly string[];\n}\n\n/**\n * Compute the diff between two memory stores. Neither store is modified.\n *\n * `changed` is determined by exact byte comparison of the underlying\n * `.md` files. Frontmatter ordering or whitespace differences therefore\n * count as a change — callers that want semantic equality should\n * re-serialize through `parseFrontmatter` / `serializeFrontmatter` before\n * comparing.\n */\nexport async function diffStores(\n a: MemoryStore,\n b: MemoryStore,\n): Promise<SyncDiff> {\n const [idsA, idsB] = await Promise.all([a.list(), b.list()]);\n const setA = new Set(idsA);\n const setB = new Set(idsB);\n\n const onlyInA = idsA.filter((id) => !setB.has(id));\n const onlyInB = idsB.filter((id) => !setA.has(id));\n const both = idsA.filter((id) => setB.has(id));\n\n const changed: string[] = [];\n for (const id of both) {\n const [contentA, contentB] = await Promise.all([\n readFile(a.pathFor(id), \"utf8\"),\n readFile(b.pathFor(id), \"utf8\"),\n ]);\n if (contentA !== contentB) {\n changed.push(id);\n }\n }\n\n return { onlyInA, onlyInB, changed };\n}\n","export type { Severity, LintFinding, LintRule, LintInput, LintReport } from \"./types.js\";\nexport { lintDirectory } from \"./runner.js\";\nexport type { LintOptions } from \"./runner.js\";\nexport { requireFrontmatter } from \"./rules/require-frontmatter.js\";\nexport type { RequireFrontmatterOptions } from \"./rules/require-frontmatter.js\";\nexport { privacyValid } from \"./rules/privacy-valid.js\";\nexport { wikiLinkResolves } from \"./rules/wiki-link-resolves.js\";\nexport type { WikiLinkResolvesOptions } from \"./rules/wiki-link-resolves.js\";\n","import { readdir, readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport type { LintFinding, LintReport, LintRule } from \"./types.js\";\n\nexport interface LintOptions {\n /** Directory to scan recursively. */\n readonly dir: string;\n /** Rules to apply to every file. */\n readonly rules: readonly LintRule[];\n /** File extensions to include. Defaults to `[\".md\"]`. */\n readonly extensions?: readonly string[];\n}\n\n/**\n * Recursively scan `dir` for files with the configured extensions and run\n * every rule against each file. Findings from all rules are aggregated into\n * a single `LintReport`. Order of findings within the report is not\n * guaranteed beyond \"file by file, rule by rule\".\n */\nexport async function lintDirectory(options: LintOptions): Promise<LintReport> {\n const start = Date.now();\n const extensions = options.extensions ?? [\".md\"];\n const files = await collectFiles(options.dir, extensions);\n const findings: LintFinding[] = [];\n\n for (const file of files) {\n const content = await readFile(file, \"utf8\");\n for (const rule of options.rules) {\n const result = await rule.check({ file, content });\n for (const f of result) findings.push(f);\n }\n }\n\n return {\n findings,\n filesScanned: files.length,\n rulesRun: options.rules.length,\n durationMs: Date.now() - start,\n };\n}\n\nasync function collectFiles(\n dir: string,\n extensions: readonly string[],\n): Promise<string[]> {\n const out: string[] = [];\n const stack: string[] = [dir];\n while (stack.length > 0) {\n const current = stack.pop();\n if (current === undefined) break;\n let entries;\n try {\n entries = await readdir(current, { withFileTypes: true });\n } catch (e) {\n if ((e as NodeJS.ErrnoException).code === \"ENOENT\") continue;\n throw e;\n }\n for (const entry of entries) {\n const full = join(current, entry.name);\n if (entry.isDirectory()) {\n stack.push(full);\n } else if (\n entry.isFile() &&\n extensions.some((ext) => entry.name.endsWith(ext))\n ) {\n out.push(full);\n }\n }\n }\n return out.sort();\n}\n","import { parseFrontmatter } from \"@vortex-os/core\";\nimport type { LintFinding, LintRule } from \"../types.js\";\n\nexport interface RequireFrontmatterOptions {\n /** Frontmatter keys that must be present and non-empty. */\n readonly required: readonly string[];\n}\n\n/**\n * Rule that ensures the listed frontmatter keys are present and non-empty.\n * Empty string, null, and undefined values all fail the check; `0`, `false`,\n * and structured values (arrays, objects) pass as long as they exist.\n */\nexport function requireFrontmatter(options: RequireFrontmatterOptions): LintRule {\n return {\n id: \"require-frontmatter\",\n description: `Ensure required frontmatter keys are present: ${options.required.join(\", \")}`,\n check({ file, content }) {\n const findings: LintFinding[] = [];\n const { frontmatter } = parseFrontmatter<Record<string, unknown>>(content);\n for (const key of options.required) {\n const value = frontmatter[key];\n if (value === undefined || value === null || value === \"\") {\n findings.push({\n rule: \"require-frontmatter\",\n severity: \"error\",\n file,\n message: `Missing required frontmatter key: \"${key}\"`,\n });\n }\n }\n return findings;\n },\n };\n}\n","import { parseFrontmatter } from \"@vortex-os/core\";\nimport type { LintFinding, LintRule } from \"../types.js\";\n\nconst CANONICAL = new Set([\"public\", \"internal\", \"personal\"]);\n\n/**\n * Rule that ensures, if a `privacy` frontmatter field is present, its value\n * is one of the canonical three: `public`, `internal`, `personal`.\n * Documents without any `privacy` field pass.\n */\nexport function privacyValid(): LintRule {\n return {\n id: \"privacy-valid\",\n description: \"Ensure frontmatter privacy is one of public/internal/personal\",\n check({ file, content }) {\n const findings: LintFinding[] = [];\n const { frontmatter } = parseFrontmatter<{ privacy?: unknown }>(content);\n if (frontmatter.privacy === undefined) return findings;\n if (typeof frontmatter.privacy !== \"string\" || !CANONICAL.has(frontmatter.privacy)) {\n findings.push({\n rule: \"privacy-valid\",\n severity: \"error\",\n file,\n message: `Invalid privacy value: ${JSON.stringify(frontmatter.privacy)}. Expected one of: public, internal, personal.`,\n });\n }\n return findings;\n },\n };\n}\n","import { readdir } from \"node:fs/promises\";\nimport { basename, extname, join } from \"node:path\";\nimport type { LintFinding, LintRule } from \"../types.js\";\n\nconst WIKI_LINK = /\\[\\[([^\\]|#]+)(?:[|#][^\\]]*)?\\]\\]/g;\n\nexport interface WikiLinkResolvesOptions {\n /** Directory under which valid link targets live. Searched recursively. */\n readonly searchRoot: string;\n /** Target file extensions. Defaults to `[\".md\"]`. */\n readonly extensions?: readonly string[];\n}\n\n/**\n * Rule that checks wiki-style links `[[target]]` resolve to an existing\n * file under `searchRoot` (by basename match, recursive). Aliases\n * (`[[target|alias]]`) and anchors (`[[target#section]]`) are stripped\n * before lookup.\n *\n * The target index is built lazily on the first invocation and cached for\n * the lifetime of the rule instance.\n */\nexport function wikiLinkResolves(options: WikiLinkResolvesOptions): LintRule {\n let cache: Set<string> | undefined;\n const extensions = options.extensions ?? [\".md\"];\n\n async function buildIndex(): Promise<Set<string>> {\n if (cache) return cache;\n const out = new Set<string>();\n const stack: string[] = [options.searchRoot];\n while (stack.length > 0) {\n const current = stack.pop();\n if (current === undefined) break;\n let entries;\n try {\n entries = await readdir(current, { withFileTypes: true });\n } catch {\n continue;\n }\n for (const entry of entries) {\n const full = join(current, entry.name);\n if (entry.isDirectory()) {\n stack.push(full);\n } else if (\n entry.isFile() &&\n extensions.some((ext) => entry.name.endsWith(ext))\n ) {\n out.add(basename(entry.name, extname(entry.name)));\n }\n }\n }\n cache = out;\n return out;\n }\n\n return {\n id: \"wiki-link-resolves\",\n description: \"Check [[wiki links]] resolve to an existing file by basename\",\n async check({ file, content }) {\n const findings: LintFinding[] = [];\n const index = await buildIndex();\n const lines = content.split(\"\\n\");\n lines.forEach((line, idx) => {\n for (const match of line.matchAll(WIKI_LINK)) {\n const target = match[1]?.trim();\n if (target && !index.has(target)) {\n findings.push({\n rule: \"wiki-link-resolves\",\n severity: \"warning\",\n file,\n line: idx + 1,\n message: `Unresolved wiki link: [[${target}]]`,\n });\n }\n }\n });\n return findings;\n },\n };\n}\n","export type { Pitfall, PitfallFrontmatter, PitfallSeverity } from \"./types.js\";\nexport { PitfallCatalog } from \"./catalog.js\";\n","import { readdir, readFile } from \"node:fs/promises\";\nimport { basename, extname, join } from \"node:path\";\nimport { parseFrontmatter } from \"@vortex-os/core\";\nimport type { Pitfall, PitfallFrontmatter } from \"./types.js\";\n\n/**\n * Directory-backed pitfall catalog. One `.md` file per pitfall.\n *\n * The catalog reads all `.md` files in `dir` on each query (no caching).\n * Callers that need cached behavior should wrap or call `list()` once and\n * reuse the result.\n */\nexport class PitfallCatalog {\n constructor(readonly dir: string) {}\n\n /** Load every pitfall in the directory, sorted by id. */\n async list(): Promise<readonly Pitfall[]> {\n const files = await this.entries();\n const out: Pitfall[] = [];\n for (const file of files) {\n out.push(await this.loadFile(file));\n }\n return out.sort((a, b) => a.id.localeCompare(b.id));\n }\n\n /** Load a single pitfall by id. Returns `undefined` if not found. */\n async get(id: string): Promise<Pitfall | undefined> {\n const all = await this.list();\n return all.find((p) => p.id === id);\n }\n\n /** Return only pitfalls matching the given category. */\n async filterByCategory(category: string): Promise<readonly Pitfall[]> {\n const all = await this.list();\n return all.filter((p) => p.category === category);\n }\n\n private async entries(): Promise<string[]> {\n try {\n const names = await readdir(this.dir);\n return names\n .filter((n) => n.endsWith(\".md\"))\n .map((n) => join(this.dir, n));\n } catch (e) {\n if ((e as NodeJS.ErrnoException).code === \"ENOENT\") return [];\n throw e;\n }\n }\n\n private async loadFile(path: string): Promise<Pitfall> {\n const raw = await readFile(path, \"utf8\");\n const { frontmatter, body } = parseFrontmatter<PitfallFrontmatter>(raw);\n const idFromFile = basename(path, extname(path));\n return {\n id: frontmatter.id ?? idFromFile,\n title: frontmatter.title,\n category: frontmatter.category,\n severity: frontmatter.severity,\n signal: frontmatter.signal,\n cause: frontmatter.cause,\n mitigation: frontmatter.mitigation,\n body: body.trimStart(),\n };\n }\n}\n","export type { ToolRule, ToolRuleFrontmatter, ToolRuleSeverity } from \"./types.js\";\nexport { ToolRuleCatalog } from \"./catalog.js\";\n","import { readdir, readFile } from \"node:fs/promises\";\nimport { basename, extname, join } from \"node:path\";\nimport { parseFrontmatter } from \"@vortex-os/core\";\nimport type { ToolRule, ToolRuleFrontmatter, ToolRuleSeverity } from \"./types.js\";\n\n/**\n * Directory-backed tool-rule catalog. One `.md` file per rule.\n *\n * The catalog reads all `.md` files in `dir` on each query (no caching).\n */\nexport class ToolRuleCatalog {\n constructor(readonly dir: string) {}\n\n /** Load every rule in the directory, sorted by id. */\n async list(): Promise<readonly ToolRule[]> {\n const files = await this.entries();\n const out: ToolRule[] = [];\n for (const file of files) {\n out.push(await this.loadFile(file));\n }\n return out.sort((a, b) => a.id.localeCompare(b.id));\n }\n\n /** Load a single rule by id. Returns `undefined` if not found. */\n async get(id: string): Promise<ToolRule | undefined> {\n const all = await this.list();\n return all.find((r) => r.id === id);\n }\n\n /** Return only rules whose `scope` matches exactly. */\n async filterByScope(scope: string): Promise<readonly ToolRule[]> {\n const all = await this.list();\n return all.filter((r) => r.scope === scope);\n }\n\n /** Return only rules whose `severity` matches. */\n async filterBySeverity(severity: ToolRuleSeverity): Promise<readonly ToolRule[]> {\n const all = await this.list();\n return all.filter((r) => r.severity === severity);\n }\n\n private async entries(): Promise<string[]> {\n try {\n const names = await readdir(this.dir);\n return names\n .filter((n) => n.endsWith(\".md\"))\n .map((n) => join(this.dir, n));\n } catch (e) {\n if ((e as NodeJS.ErrnoException).code === \"ENOENT\") return [];\n throw e;\n }\n }\n\n private async loadFile(path: string): Promise<ToolRule> {\n const raw = await readFile(path, \"utf8\");\n const { frontmatter, body } = parseFrontmatter<ToolRuleFrontmatter>(raw);\n const idFromFile = basename(path, extname(path));\n return {\n id: frontmatter.id ?? idFromFile,\n title: frontmatter.title,\n scope: frontmatter.scope,\n severity: frontmatter.severity,\n condition: frontmatter.condition,\n action: frontmatter.action,\n body: body.trimStart(),\n };\n }\n}\n","export type { RenderOptions, RenderResult, RenderWarning, WarningKind } from \"./types.js\";\nexport { renderHtml } from \"./renderer.js\";\nexport { stripPrivateSections } from \"./filter.js\";\nexport type { StripResult } from \"./filter.js\";\nexport { applyTemplate, DEFAULT_TEMPLATE } from \"./template.js\";\n","import type { MarkedOptions } from './MarkedOptions.ts';\n\n/**\n * Gets the original marked default options.\n */\nexport function _getDefaults<ParserOutput = string, RendererOutput = string>(): MarkedOptions<ParserOutput, RendererOutput> {\n return {\n async: false,\n breaks: false,\n extensions: null,\n gfm: true,\n hooks: null,\n pedantic: false,\n renderer: null,\n silent: false,\n tokenizer: null,\n walkTokens: null,\n };\n}\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\nexport let _defaults: MarkedOptions<any, any> = _getDefaults();\n\nexport function changeDefaults<ParserOutput = string, RendererOutput = string>(newDefaults: MarkedOptions<ParserOutput, RendererOutput>) {\n _defaults = newDefaults;\n}\n","const noopTest = { exec: () => null } as unknown as RegExp;\n\nfunction edit(regex: string | RegExp, opt = '') {\n let source = typeof regex === 'string' ? regex : regex.source;\n const obj = {\n replace: (name: string | RegExp, val: string | RegExp) => {\n let valSource = typeof val === 'string' ? val : val.source;\n valSource = valSource.replace(other.caret, '$1');\n source = source.replace(name, valSource);\n return obj;\n },\n getRegex: () => {\n return new RegExp(source, opt);\n },\n };\n return obj;\n}\n\nconst supportsLookbehind = (() => {\ntry {\n // eslint-disable-next-line prefer-regex-literals\n return !!new RegExp('(?<=1)(?<!1)');\n} catch {\n // See browser support here:\n // https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Regular_expressions/Lookbehind_assertion\n return false;\n}\n})();\n\nexport const other = {\n codeRemoveIndent: /^(?: {1,4}| {0,3}\\t)/gm,\n outputLinkReplace: /\\\\([\\[\\]])/g,\n indentCodeCompensation: /^(\\s+)(?:```)/,\n beginningSpace: /^\\s+/,\n endingHash: /#$/,\n startingSpaceChar: /^ /,\n endingSpaceChar: / $/,\n nonSpaceChar: /[^ ]/,\n newLineCharGlobal: /\\n/g,\n tabCharGlobal: /\\t/g,\n multipleSpaceGlobal: /\\s+/g,\n blankLine: /^[ \\t]*$/,\n doubleBlankLine: /\\n[ \\t]*\\n[ \\t]*$/,\n blockquoteStart: /^ {0,3}>/,\n blockquoteSetextReplace: /\\n {0,3}((?:=+|-+) *)(?=\\n|$)/g,\n blockquoteSetextReplace2: /^ {0,3}>[ \\t]?/gm,\n listReplaceTabs: /^\\t+/,\n listReplaceNesting: /^ {1,4}(?=( {4})*[^ ])/g,\n listIsTask: /^\\[[ xX]\\] /,\n listReplaceTask: /^\\[[ xX]\\] +/,\n anyLine: /\\n.*\\n/,\n hrefBrackets: /^<(.*)>$/,\n tableDelimiter: /[:|]/,\n tableAlignChars: /^\\||\\| *$/g,\n tableRowBlankLine: /\\n[ \\t]*$/,\n tableAlignRight: /^ *-+: *$/,\n tableAlignCenter: /^ *:-+: *$/,\n tableAlignLeft: /^ *:-+ *$/,\n startATag: /^<a /i,\n endATag: /^<\\/a>/i,\n startPreScriptTag: /^<(pre|code|kbd|script)(\\s|>)/i,\n endPreScriptTag: /^<\\/(pre|code|kbd|script)(\\s|>)/i,\n startAngleBracket: /^</,\n endAngleBracket: />$/,\n pedanticHrefTitle: /^([^'\"]*[^\\s])\\s+(['\"])(.*)\\2/,\n unicodeAlphaNumeric: /[\\p{L}\\p{N}]/u,\n escapeTest: /[&<>\"']/,\n escapeReplace: /[&<>\"']/g,\n escapeTestNoEncode: /[<>\"']|&(?!(#\\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\\w+);)/,\n escapeReplaceNoEncode: /[<>\"']|&(?!(#\\d{1,7}|#[Xx][a-fA-F0-9]{1,6}|\\w+);)/g,\n unescapeTest: /&(#(?:\\d+)|(?:#x[0-9A-Fa-f]+)|(?:\\w+));?/ig,\n caret: /(^|[^\\[])\\^/g,\n percentDecode: /%25/g,\n findPipe: /\\|/g,\n splitPipe: / \\|/,\n slashPipe: /\\\\\\|/g,\n carriageReturn: /\\r\\n|\\r/g,\n spaceLine: /^ +$/gm,\n notSpaceStart: /^\\S*/,\n endingNewline: /\\n$/,\n listItemRegex: (bull: string) => new RegExp(`^( {0,3}${bull})((?:[\\t ][^\\\\n]*)?(?:\\\\n|$))`),\n nextBulletRegex: (indent: number) => new RegExp(`^ {0,${Math.min(3, indent - 1)}}(?:[*+-]|\\\\d{1,9}[.)])((?:[ \\t][^\\\\n]*)?(?:\\\\n|$))`),\n hrRegex: (indent: number) => new RegExp(`^ {0,${Math.min(3, indent - 1)}}((?:- *){3,}|(?:_ *){3,}|(?:\\\\* *){3,})(?:\\\\n+|$)`),\n fencesBeginRegex: (indent: number) => new RegExp(`^ {0,${Math.min(3, indent - 1)}}(?:\\`\\`\\`|~~~)`),\n headingBeginRegex: (indent: number) => new RegExp(`^ {0,${Math.min(3, indent - 1)}}#`),\n htmlBeginRegex: (indent: number) => new RegExp(`^ {0,${Math.min(3, indent - 1)}}<(?:[a-z].*>|!--)`, 'i'),\n};\n\n/**\n * Block-Level Grammar\n */\n\nconst newline = /^(?:[ \\t]*(?:\\n|$))+/;\nconst blockCode = /^((?: {4}| {0,3}\\t)[^\\n]+(?:\\n(?:[ \\t]*(?:\\n|$))*)?)+/;\nconst fences = /^ {0,3}(`{3,}(?=[^`\\n]*(?:\\n|$))|~{3,})([^\\n]*)(?:\\n|$)(?:|([\\s\\S]*?)(?:\\n|$))(?: {0,3}\\1[~`]* *(?=\\n|$)|$)/;\nconst hr = /^ {0,3}((?:-[\\t ]*){3,}|(?:_[ \\t]*){3,}|(?:\\*[ \\t]*){3,})(?:\\n+|$)/;\nconst heading = /^ {0,3}(#{1,6})(?=\\s|$)(.*)(?:\\n+|$)/;\nconst bullet = /(?:[*+-]|\\d{1,9}[.)])/;\nconst lheadingCore = /^(?!bull |blockCode|fences|blockquote|heading|html|table)((?:.|\\n(?!\\s*?\\n|bull |blockCode|fences|blockquote|heading|html|table))+?)\\n {0,3}(=+|-+) *(?:\\n+|$)/;\nconst lheading = edit(lheadingCore)\n .replace(/bull/g, bullet) // lists can interrupt\n .replace(/blockCode/g, /(?: {4}| {0,3}\\t)/) // indented code blocks can interrupt\n .replace(/fences/g, / {0,3}(?:`{3,}|~{3,})/) // fenced code blocks can interrupt\n .replace(/blockquote/g, / {0,3}>/) // blockquote can interrupt\n .replace(/heading/g, / {0,3}#{1,6}/) // ATX heading can interrupt\n .replace(/html/g, / {0,3}<[^\\n>]+>\\n/) // block html can interrupt\n .replace(/\\|table/g, '') // table not in commonmark\n .getRegex();\nconst lheadingGfm = edit(lheadingCore)\n .replace(/bull/g, bullet) // lists can interrupt\n .replace(/blockCode/g, /(?: {4}| {0,3}\\t)/) // indented code blocks can interrupt\n .replace(/fences/g, / {0,3}(?:`{3,}|~{3,})/) // fenced code blocks can interrupt\n .replace(/blockquote/g, / {0,3}>/) // blockquote can interrupt\n .replace(/heading/g, / {0,3}#{1,6}/) // ATX heading can interrupt\n .replace(/html/g, / {0,3}<[^\\n>]+>\\n/) // block html can interrupt\n .replace(/table/g, / {0,3}\\|?(?:[:\\- ]*\\|)+[\\:\\- ]*\\n/) // table can interrupt\n .getRegex();\nconst _paragraph = /^([^\\n]+(?:\\n(?!hr|heading|lheading|blockquote|fences|list|html|table| +\\n)[^\\n]+)*)/;\nconst blockText = /^[^\\n]+/;\nconst _blockLabel = /(?!\\s*\\])(?:\\\\[\\s\\S]|[^\\[\\]\\\\])+/;\nconst def = edit(/^ {0,3}\\[(label)\\]: *(?:\\n[ \\t]*)?([^<\\s][^\\s]*|<.*?>)(?:(?: +(?:\\n[ \\t]*)?| *\\n[ \\t]*)(title))? *(?:\\n+|$)/)\n .replace('label', _blockLabel)\n .replace('title', /(?:\"(?:\\\\\"?|[^\"\\\\])*\"|'[^'\\n]*(?:\\n[^'\\n]+)*\\n?'|\\([^()]*\\))/)\n .getRegex();\n\nconst list = edit(/^( {0,3}bull)([ \\t][^\\n]+?)?(?:\\n|$)/)\n .replace(/bull/g, bullet)\n .getRegex();\n\nconst _tag = 'address|article|aside|base|basefont|blockquote|body|caption'\n + '|center|col|colgroup|dd|details|dialog|dir|div|dl|dt|fieldset|figcaption'\n + '|figure|footer|form|frame|frameset|h[1-6]|head|header|hr|html|iframe'\n + '|legend|li|link|main|menu|menuitem|meta|nav|noframes|ol|optgroup|option'\n + '|p|param|search|section|summary|table|tbody|td|tfoot|th|thead|title'\n + '|tr|track|ul';\nconst _comment = /<!--(?:-?>|[\\s\\S]*?(?:-->|$))/;\nconst html = edit(\n '^ {0,3}(?:' // optional indentation\n+ '<(script|pre|style|textarea)[\\\\s>][\\\\s\\\\S]*?(?:</\\\\1>[^\\\\n]*\\\\n+|$)' // (1)\n+ '|comment[^\\\\n]*(\\\\n+|$)' // (2)\n+ '|<\\\\?[\\\\s\\\\S]*?(?:\\\\?>\\\\n*|$)' // (3)\n+ '|<![A-Z][\\\\s\\\\S]*?(?:>\\\\n*|$)' // (4)\n+ '|<!\\\\[CDATA\\\\[[\\\\s\\\\S]*?(?:\\\\]\\\\]>\\\\n*|$)' // (5)\n+ '|</?(tag)(?: +|\\\\n|/?>)[\\\\s\\\\S]*?(?:(?:\\\\n[ \\t]*)+\\\\n|$)' // (6)\n+ '|<(?!script|pre|style|textarea)([a-z][\\\\w-]*)(?:attribute)*? */?>(?=[ \\\\t]*(?:\\\\n|$))[\\\\s\\\\S]*?(?:(?:\\\\n[ \\t]*)+\\\\n|$)' // (7) open tag\n+ '|</(?!script|pre|style|textarea)[a-z][\\\\w-]*\\\\s*>(?=[ \\\\t]*(?:\\\\n|$))[\\\\s\\\\S]*?(?:(?:\\\\n[ \\t]*)+\\\\n|$)' // (7) closing tag\n+ ')', 'i')\n .replace('comment', _comment)\n .replace('tag', _tag)\n .replace('attribute', / +[a-zA-Z:_][\\w.:-]*(?: *= *\"[^\"\\n]*\"| *= *'[^'\\n]*'| *= *[^\\s\"'=<>`]+)?/)\n .getRegex();\n\nconst paragraph = edit(_paragraph)\n .replace('hr', hr)\n .replace('heading', ' {0,3}#{1,6}(?:\\\\s|$)')\n .replace('|lheading', '') // setext headings don't interrupt commonmark paragraphs\n .replace('|table', '')\n .replace('blockquote', ' {0,3}>')\n .replace('fences', ' {0,3}(?:`{3,}(?=[^`\\\\n]*\\\\n)|~{3,})[^\\\\n]*\\\\n')\n .replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt\n .replace('html', '</?(?:tag)(?: +|\\\\n|/?>)|<(?:script|pre|style|textarea|!--)')\n .replace('tag', _tag) // pars can be interrupted by type (6) html blocks\n .getRegex();\n\nconst blockquote = edit(/^( {0,3}> ?(paragraph|[^\\n]*)(?:\\n|$))+/)\n .replace('paragraph', paragraph)\n .getRegex();\n\n/**\n * Normal Block Grammar\n */\n\nconst blockNormal = {\n blockquote,\n code: blockCode,\n def,\n fences,\n heading,\n hr,\n html,\n lheading,\n list,\n newline,\n paragraph,\n table: noopTest,\n text: blockText,\n};\n\ntype BlockKeys = keyof typeof blockNormal;\n\n/**\n * GFM Block Grammar\n */\n\nconst gfmTable = edit(\n '^ *([^\\\\n ].*)\\\\n' // Header\n+ ' {0,3}((?:\\\\| *)?:?-+:? *(?:\\\\| *:?-+:? *)*(?:\\\\| *)?)' // Align\n+ '(?:\\\\n((?:(?! *\\\\n|hr|heading|blockquote|code|fences|list|html).*(?:\\\\n|$))*)\\\\n*|$)') // Cells\n .replace('hr', hr)\n .replace('heading', ' {0,3}#{1,6}(?:\\\\s|$)')\n .replace('blockquote', ' {0,3}>')\n .replace('code', '(?: {4}| {0,3}\\t)[^\\\\n]')\n .replace('fences', ' {0,3}(?:`{3,}(?=[^`\\\\n]*\\\\n)|~{3,})[^\\\\n]*\\\\n')\n .replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt\n .replace('html', '</?(?:tag)(?: +|\\\\n|/?>)|<(?:script|pre|style|textarea|!--)')\n .replace('tag', _tag) // tables can be interrupted by type (6) html blocks\n .getRegex();\n\nconst blockGfm: Record<BlockKeys, RegExp> = {\n ...blockNormal,\n lheading: lheadingGfm,\n table: gfmTable,\n paragraph: edit(_paragraph)\n .replace('hr', hr)\n .replace('heading', ' {0,3}#{1,6}(?:\\\\s|$)')\n .replace('|lheading', '') // setext headings don't interrupt commonmark paragraphs\n .replace('table', gfmTable) // interrupt paragraphs with table\n .replace('blockquote', ' {0,3}>')\n .replace('fences', ' {0,3}(?:`{3,}(?=[^`\\\\n]*\\\\n)|~{3,})[^\\\\n]*\\\\n')\n .replace('list', ' {0,3}(?:[*+-]|1[.)]) ') // only lists starting from 1 can interrupt\n .replace('html', '</?(?:tag)(?: +|\\\\n|/?>)|<(?:script|pre|style|textarea|!--)')\n .replace('tag', _tag) // pars can be interrupted by type (6) html blocks\n .getRegex(),\n};\n\n/**\n * Pedantic grammar (original John Gruber's loose markdown specification)\n */\n\nconst blockPedantic: Record<BlockKeys, RegExp> = {\n ...blockNormal,\n html: edit(\n '^ *(?:comment *(?:\\\\n|\\\\s*$)'\n + '|<(tag)[\\\\s\\\\S]+?</\\\\1> *(?:\\\\n{2,}|\\\\s*$)' // closed tag\n + '|<tag(?:\"[^\"]*\"|\\'[^\\']*\\'|\\\\s[^\\'\"/>\\\\s]*)*?/?> *(?:\\\\n{2,}|\\\\s*$))')\n .replace('comment', _comment)\n .replace(/tag/g, '(?!(?:'\n + 'a|em|strong|small|s|cite|q|dfn|abbr|data|time|code|var|samp|kbd|sub'\n + '|sup|i|b|u|mark|ruby|rt|rp|bdi|bdo|span|br|wbr|ins|del|img)'\n + '\\\\b)\\\\w+(?!:|[^\\\\w\\\\s@]*@)\\\\b')\n .getRegex(),\n def: /^ *\\[([^\\]]+)\\]: *<?([^\\s>]+)>?(?: +([\"(][^\\n]+[\")]))? *(?:\\n+|$)/,\n heading: /^(#{1,6})(.*)(?:\\n+|$)/,\n fences: noopTest, // fences not supported\n lheading: /^(.+?)\\n {0,3}(=+|-+) *(?:\\n+|$)/,\n paragraph: edit(_paragraph)\n .replace('hr', hr)\n .replace('heading', ' *#{1,6} *[^\\n]')\n .replace('lheading', lheading)\n .replace('|table', '')\n .replace('blockquote', ' {0,3}>')\n .replace('|fences', '')\n .replace('|list', '')\n .replace('|html', '')\n .replace('|tag', '')\n .getRegex(),\n};\n\n/**\n * Inline-Level Grammar\n */\n\nconst escape = /^\\\\([!\"#$%&'()*+,\\-./:;<=>?@\\[\\]\\\\^_`{|}~])/;\nconst inlineCode = /^(`+)([^`]|[^`][\\s\\S]*?[^`])\\1(?!`)/;\nconst br = /^( {2,}|\\\\)\\n(?!\\s*$)/;\nconst inlineText = /^(`+|[^`])(?:(?= {2,}\\n)|[\\s\\S]*?(?:(?=[\\\\<!\\[`*_]|\\b_|$)|[^ ](?= {2,}\\n)))/;\n\n// list of unicode punctuation marks, plus any missing characters from CommonMark spec\nconst _punctuation = /[\\p{P}\\p{S}]/u;\nconst _punctuationOrSpace = /[\\s\\p{P}\\p{S}]/u;\nconst _notPunctuationOrSpace = /[^\\s\\p{P}\\p{S}]/u;\nconst punctuation = edit(/^((?![*_])punctSpace)/, 'u')\n .replace(/punctSpace/g, _punctuationOrSpace).getRegex();\n\n// GFM allows ~ inside strong and em for strikethrough\nconst _punctuationGfmStrongEm = /(?!~)[\\p{P}\\p{S}]/u;\nconst _punctuationOrSpaceGfmStrongEm = /(?!~)[\\s\\p{P}\\p{S}]/u;\nconst _notPunctuationOrSpaceGfmStrongEm = /(?:[^\\s\\p{P}\\p{S}]|~)/u;\n\n// sequences em should skip over [title](link), `code`, <html>\nconst blockSkip = edit(/link|precode-code|html/, 'g')\n .replace('link', /\\[(?:[^\\[\\]`]|(?<a>`+)[^`]+\\k<a>(?!`))*?\\]\\((?:\\\\[\\s\\S]|[^\\\\\\(\\)]|\\((?:\\\\[\\s\\S]|[^\\\\\\(\\)])*\\))*\\)/)\n .replace('precode-', supportsLookbehind ? '(?<!`)()' : '(^^|[^`])')\n .replace('code', /(?<b>`+)[^`]+\\k<b>(?!`)/)\n .replace('html', /<(?! )[^<>]*?>/)\n .getRegex();\n\nconst emStrongLDelimCore = /^(?:\\*+(?:((?!\\*)punct)|[^\\s*]))|^_+(?:((?!_)punct)|([^\\s_]))/;\n\nconst emStrongLDelim = edit(emStrongLDelimCore, 'u')\n .replace(/punct/g, _punctuation)\n .getRegex();\n\nconst emStrongLDelimGfm = edit(emStrongLDelimCore, 'u')\n .replace(/punct/g, _punctuationGfmStrongEm)\n .getRegex();\n\nconst emStrongRDelimAstCore =\n '^[^_*]*?__[^_*]*?\\\\*[^_*]*?(?=__)' // Skip orphan inside strong\n+ '|[^*]+(?=[^*])' // Consume to delim\n+ '|(?!\\\\*)punct(\\\\*+)(?=[\\\\s]|$)' // (1) #*** can only be a Right Delimiter\n+ '|notPunctSpace(\\\\*+)(?!\\\\*)(?=punctSpace|$)' // (2) a***#, a*** can only be a Right Delimiter\n+ '|(?!\\\\*)punctSpace(\\\\*+)(?=notPunctSpace)' // (3) #***a, ***a can only be Left Delimiter\n+ '|[\\\\s](\\\\*+)(?!\\\\*)(?=punct)' // (4) ***# can only be Left Delimiter\n+ '|(?!\\\\*)punct(\\\\*+)(?!\\\\*)(?=punct)' // (5) #***# can be either Left or Right Delimiter\n+ '|notPunctSpace(\\\\*+)(?=notPunctSpace)'; // (6) a***a can be either Left or Right Delimiter\n\nconst emStrongRDelimAst = edit(emStrongRDelimAstCore, 'gu')\n .replace(/notPunctSpace/g, _notPunctuationOrSpace)\n .replace(/punctSpace/g, _punctuationOrSpace)\n .replace(/punct/g, _punctuation)\n .getRegex();\n\nconst emStrongRDelimAstGfm = edit(emStrongRDelimAstCore, 'gu')\n .replace(/notPunctSpace/g, _notPunctuationOrSpaceGfmStrongEm)\n .replace(/punctSpace/g, _punctuationOrSpaceGfmStrongEm)\n .replace(/punct/g, _punctuationGfmStrongEm)\n .getRegex();\n\n// (6) Not allowed for _\nconst emStrongRDelimUnd = edit(\n '^[^_*]*?\\\\*\\\\*[^_*]*?_[^_*]*?(?=\\\\*\\\\*)' // Skip orphan inside strong\n+ '|[^_]+(?=[^_])' // Consume to delim\n+ '|(?!_)punct(_+)(?=[\\\\s]|$)' // (1) #___ can only be a Right Delimiter\n+ '|notPunctSpace(_+)(?!_)(?=punctSpace|$)' // (2) a___#, a___ can only be a Right Delimiter\n+ '|(?!_)punctSpace(_+)(?=notPunctSpace)' // (3) #___a, ___a can only be Left Delimiter\n+ '|[\\\\s](_+)(?!_)(?=punct)' // (4) ___# can only be Left Delimiter\n+ '|(?!_)punct(_+)(?!_)(?=punct)', 'gu') // (5) #___# can be either Left or Right Delimiter\n .replace(/notPunctSpace/g, _notPunctuationOrSpace)\n .replace(/punctSpace/g, _punctuationOrSpace)\n .replace(/punct/g, _punctuation)\n .getRegex();\n\nconst anyPunctuation = edit(/\\\\(punct)/, 'gu')\n .replace(/punct/g, _punctuation)\n .getRegex();\n\nconst autolink = edit(/^<(scheme:[^\\s\\x00-\\x1f<>]*|email)>/)\n .replace('scheme', /[a-zA-Z][a-zA-Z0-9+.-]{1,31}/)\n .replace('email', /[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+(@)[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?(?:\\.[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?)+(?![-_])/)\n .getRegex();\n\nconst _inlineComment = edit(_comment).replace('(?:-->|$)', '-->').getRegex();\nconst tag = edit(\n '^comment'\n + '|^</[a-zA-Z][\\\\w:-]*\\\\s*>' // self-closing tag\n + '|^<[a-zA-Z][\\\\w-]*(?:attribute)*?\\\\s*/?>' // open tag\n + '|^<\\\\?[\\\\s\\\\S]*?\\\\?>' // processing instruction, e.g. <?php ?>\n + '|^<![a-zA-Z]+\\\\s[\\\\s\\\\S]*?>' // declaration, e.g. <!DOCTYPE html>\n + '|^<!\\\\[CDATA\\\\[[\\\\s\\\\S]*?\\\\]\\\\]>') // CDATA section\n .replace('comment', _inlineComment)\n .replace('attribute', /\\s+[a-zA-Z:_][\\w.:-]*(?:\\s*=\\s*\"[^\"]*\"|\\s*=\\s*'[^']*'|\\s*=\\s*[^\\s\"'=<>`]+)?/)\n .getRegex();\n\nconst _inlineLabel = /(?:\\[(?:\\\\[\\s\\S]|[^\\[\\]\\\\])*\\]|\\\\[\\s\\S]|`+[^`]*?`+(?!`)|[^\\[\\]\\\\`])*?/;\n\nconst link = edit(/^!?\\[(label)\\]\\(\\s*(href)(?:(?:[ \\t]*(?:\\n[ \\t]*)?)(title))?\\s*\\)/)\n .replace('label', _inlineLabel)\n .replace('href', /<(?:\\\\.|[^\\n<>\\\\])+>|[^ \\t\\n\\x00-\\x1f]*/)\n .replace('title', /\"(?:\\\\\"?|[^\"\\\\])*\"|'(?:\\\\'?|[^'\\\\])*'|\\((?:\\\\\\)?|[^)\\\\])*\\)/)\n .getRegex();\n\nconst reflink = edit(/^!?\\[(label)\\]\\[(ref)\\]/)\n .replace('label', _inlineLabel)\n .replace('ref', _blockLabel)\n .getRegex();\n\nconst nolink = edit(/^!?\\[(ref)\\](?:\\[\\])?/)\n .replace('ref', _blockLabel)\n .getRegex();\n\nconst reflinkSearch = edit('reflink|nolink(?!\\\\()', 'g')\n .replace('reflink', reflink)\n .replace('nolink', nolink)\n .getRegex();\n\nconst _caseInsensitiveProtocol = /[hH][tT][tT][pP][sS]?|[fF][tT][pP]/;\n\n/**\n * Normal Inline Grammar\n */\n\nconst inlineNormal = {\n _backpedal: noopTest, // only used for GFM url\n anyPunctuation,\n autolink,\n blockSkip,\n br,\n code: inlineCode,\n del: noopTest,\n emStrongLDelim,\n emStrongRDelimAst,\n emStrongRDelimUnd,\n escape,\n link,\n nolink,\n punctuation,\n reflink,\n reflinkSearch,\n tag,\n text: inlineText,\n url: noopTest,\n};\n\ntype InlineKeys = keyof typeof inlineNormal;\n\n/**\n * Pedantic Inline Grammar\n */\n\nconst inlinePedantic: Record<InlineKeys, RegExp> = {\n ...inlineNormal,\n link: edit(/^!?\\[(label)\\]\\((.*?)\\)/)\n .replace('label', _inlineLabel)\n .getRegex(),\n reflink: edit(/^!?\\[(label)\\]\\s*\\[([^\\]]*)\\]/)\n .replace('label', _inlineLabel)\n .getRegex(),\n};\n\n/**\n * GFM Inline Grammar\n */\n\nconst inlineGfm: Record<InlineKeys, RegExp> = {\n ...inlineNormal,\n emStrongRDelimAst: emStrongRDelimAstGfm,\n emStrongLDelim: emStrongLDelimGfm,\n url: edit(/^((?:protocol):\\/\\/|www\\.)(?:[a-zA-Z0-9\\-]+\\.?)+[^\\s<]*|^email/)\n .replace('protocol', _caseInsensitiveProtocol)\n .replace('email', /[A-Za-z0-9._+-]+(@)[a-zA-Z0-9-_]+(?:\\.[a-zA-Z0-9-_]*[a-zA-Z0-9])+(?![-_])/)\n .getRegex(),\n _backpedal: /(?:[^?!.,:;*_'\"~()&]+|\\([^)]*\\)|&(?![a-zA-Z0-9]+;$)|[?!.,:;*_'\"~)]+(?!$))+/,\n del: /^(~~?)(?=[^\\s~])((?:\\\\[\\s\\S]|[^\\\\])*?(?:\\\\[\\s\\S]|[^\\s~\\\\]))\\1(?=[^~]|$)/,\n text: edit(/^([`~]+|[^`~])(?:(?= {2,}\\n)|(?=[a-zA-Z0-9.!#$%&'*+\\/=?_`{\\|}~-]+@)|[\\s\\S]*?(?:(?=[\\\\<!\\[`*~_]|\\b_|protocol:\\/\\/|www\\.|$)|[^ ](?= {2,}\\n)|[^a-zA-Z0-9.!#$%&'*+\\/=?_`{\\|}~-](?=[a-zA-Z0-9.!#$%&'*+\\/=?_`{\\|}~-]+@)))/)\n .replace('protocol', _caseInsensitiveProtocol)\n .getRegex(),\n};\n\n/**\n * GFM + Line Breaks Inline Grammar\n */\n\nconst inlineBreaks: Record<InlineKeys, RegExp> = {\n ...inlineGfm,\n br: edit(br).replace('{2,}', '*').getRegex(),\n text: edit(inlineGfm.text)\n .replace('\\\\b_', '\\\\b_| {2,}\\\\n')\n .replace(/\\{2,\\}/g, '*')\n .getRegex(),\n};\n\n/**\n * exports\n */\n\nexport const block = {\n normal: blockNormal,\n gfm: blockGfm,\n pedantic: blockPedantic,\n};\n\nexport const inline = {\n normal: inlineNormal,\n gfm: inlineGfm,\n breaks: inlineBreaks,\n pedantic: inlinePedantic,\n};\n\nexport interface Rules {\n other: typeof other\n block: Record<BlockKeys, RegExp>\n inline: Record<InlineKeys, RegExp>\n}\n","import { other } from './rules.ts';\n\n/**\n * Helpers\n */\nconst escapeReplacements: { [index: string]: string } = {\n '&': '&amp;',\n '<': '&lt;',\n '>': '&gt;',\n '\"': '&quot;',\n \"'\": '&#39;',\n};\nconst getEscapeReplacement = (ch: string) => escapeReplacements[ch];\n\nexport function escape(html: string, encode?: boolean) {\n if (encode) {\n if (other.escapeTest.test(html)) {\n return html.replace(other.escapeReplace, getEscapeReplacement);\n }\n } else {\n if (other.escapeTestNoEncode.test(html)) {\n return html.replace(other.escapeReplaceNoEncode, getEscapeReplacement);\n }\n }\n\n return html;\n}\n\nexport function unescape(html: string) {\n // explicitly match decimal, hex, and named HTML entities\n return html.replace(other.unescapeTest, (_, n) => {\n n = n.toLowerCase();\n if (n === 'colon') return ':';\n if (n.charAt(0) === '#') {\n return n.charAt(1) === 'x'\n ? String.fromCharCode(parseInt(n.substring(2), 16))\n : String.fromCharCode(+n.substring(1));\n }\n return '';\n });\n}\n\nexport function cleanUrl(href: string) {\n try {\n href = encodeURI(href).replace(other.percentDecode, '%');\n } catch {\n return null;\n }\n return href;\n}\n\nexport function splitCells(tableRow: string, count?: number) {\n // ensure that every cell-delimiting pipe has a space\n // before it to distinguish it from an escaped pipe\n const row = tableRow.replace(other.findPipe, (match, offset, str) => {\n let escaped = false;\n let curr = offset;\n while (--curr >= 0 && str[curr] === '\\\\') escaped = !escaped;\n if (escaped) {\n // odd number of slashes means | is escaped\n // so we leave it alone\n return '|';\n } else {\n // add space before unescaped |\n return ' |';\n }\n }),\n cells = row.split(other.splitPipe);\n let i = 0;\n\n // First/last cell in a row cannot be empty if it has no leading/trailing pipe\n if (!cells[0].trim()) {\n cells.shift();\n }\n if (cells.length > 0 && !cells.at(-1)?.trim()) {\n cells.pop();\n }\n\n if (count) {\n if (cells.length > count) {\n cells.splice(count);\n } else {\n while (cells.length < count) cells.push('');\n }\n }\n\n for (; i < cells.length; i++) {\n // leading or trailing whitespace is ignored per the gfm spec\n cells[i] = cells[i].trim().replace(other.slashPipe, '|');\n }\n return cells;\n}\n\n/**\n * Remove trailing 'c's. Equivalent to str.replace(/c*$/, '').\n * /c*$/ is vulnerable to REDOS.\n *\n * @param str\n * @param c\n * @param invert Remove suffix of non-c chars instead. Default falsey.\n */\nexport function rtrim(str: string, c: string, invert?: boolean) {\n const l = str.length;\n if (l === 0) {\n return '';\n }\n\n // Length of suffix matching the invert condition.\n let suffLen = 0;\n\n // Step left until we fail to match the invert condition.\n while (suffLen < l) {\n const currChar = str.charAt(l - suffLen - 1);\n if (currChar === c && !invert) {\n suffLen++;\n } else if (currChar !== c && invert) {\n suffLen++;\n } else {\n break;\n }\n }\n\n return str.slice(0, l - suffLen);\n}\n\nexport function findClosingBracket(str: string, b: string) {\n if (str.indexOf(b[1]) === -1) {\n return -1;\n }\n\n let level = 0;\n for (let i = 0; i < str.length; i++) {\n if (str[i] === '\\\\') {\n i++;\n } else if (str[i] === b[0]) {\n level++;\n } else if (str[i] === b[1]) {\n level--;\n if (level < 0) {\n return i;\n }\n }\n }\n if (level > 0) {\n return -2;\n }\n\n return -1;\n}\n","import { _defaults } from './defaults.ts';\nimport {\n rtrim,\n splitCells,\n findClosingBracket,\n} from './helpers.ts';\nimport type { Rules } from './rules.ts';\nimport type { _Lexer } from './Lexer.ts';\nimport type { Links, Tokens, Token } from './Tokens.ts';\nimport type { MarkedOptions } from './MarkedOptions.ts';\n\nfunction outputLink(cap: string[], link: Pick<Tokens.Link, 'href' | 'title'>, raw: string, lexer: _Lexer, rules: Rules): Tokens.Link | Tokens.Image {\n const href = link.href;\n const title = link.title || null;\n const text = cap[1].replace(rules.other.outputLinkReplace, '$1');\n\n lexer.state.inLink = true;\n const token: Tokens.Link | Tokens.Image = {\n type: cap[0].charAt(0) === '!' ? 'image' : 'link',\n raw,\n href,\n title,\n text,\n tokens: lexer.inlineTokens(text),\n };\n lexer.state.inLink = false;\n return token;\n}\n\nfunction indentCodeCompensation(raw: string, text: string, rules: Rules) {\n const matchIndentToCode = raw.match(rules.other.indentCodeCompensation);\n\n if (matchIndentToCode === null) {\n return text;\n }\n\n const indentToCode = matchIndentToCode[1];\n\n return text\n .split('\\n')\n .map(node => {\n const matchIndentInNode = node.match(rules.other.beginningSpace);\n if (matchIndentInNode === null) {\n return node;\n }\n\n const [indentInNode] = matchIndentInNode;\n\n if (indentInNode.length >= indentToCode.length) {\n return node.slice(indentToCode.length);\n }\n\n return node;\n })\n .join('\\n');\n}\n\n/**\n * Tokenizer\n */\nexport class _Tokenizer<ParserOutput = string, RendererOutput = string> {\n options: MarkedOptions<ParserOutput, RendererOutput>;\n rules!: Rules; // set by the lexer\n lexer!: _Lexer<ParserOutput, RendererOutput>; // set by the lexer\n\n constructor(options?: MarkedOptions<ParserOutput, RendererOutput>) {\n this.options = options || _defaults;\n }\n\n space(src: string): Tokens.Space | undefined {\n const cap = this.rules.block.newline.exec(src);\n if (cap && cap[0].length > 0) {\n return {\n type: 'space',\n raw: cap[0],\n };\n }\n }\n\n code(src: string): Tokens.Code | undefined {\n const cap = this.rules.block.code.exec(src);\n if (cap) {\n const text = cap[0].replace(this.rules.other.codeRemoveIndent, '');\n return {\n type: 'code',\n raw: cap[0],\n codeBlockStyle: 'indented',\n text: !this.options.pedantic\n ? rtrim(text, '\\n')\n : text,\n };\n }\n }\n\n fences(src: string): Tokens.Code | undefined {\n const cap = this.rules.block.fences.exec(src);\n if (cap) {\n const raw = cap[0];\n const text = indentCodeCompensation(raw, cap[3] || '', this.rules);\n\n return {\n type: 'code',\n raw,\n lang: cap[2] ? cap[2].trim().replace(this.rules.inline.anyPunctuation, '$1') : cap[2],\n text,\n };\n }\n }\n\n heading(src: string): Tokens.Heading | undefined {\n const cap = this.rules.block.heading.exec(src);\n if (cap) {\n let text = cap[2].trim();\n\n // remove trailing #s\n if (this.rules.other.endingHash.test(text)) {\n const trimmed = rtrim(text, '#');\n if (this.options.pedantic) {\n text = trimmed.trim();\n } else if (!trimmed || this.rules.other.endingSpaceChar.test(trimmed)) {\n // CommonMark requires space before trailing #s\n text = trimmed.trim();\n }\n }\n\n return {\n type: 'heading',\n raw: cap[0],\n depth: cap[1].length,\n text,\n tokens: this.lexer.inline(text),\n };\n }\n }\n\n hr(src: string): Tokens.Hr | undefined {\n const cap = this.rules.block.hr.exec(src);\n if (cap) {\n return {\n type: 'hr',\n raw: rtrim(cap[0], '\\n'),\n };\n }\n }\n\n blockquote(src: string): Tokens.Blockquote | undefined {\n const cap = this.rules.block.blockquote.exec(src);\n if (cap) {\n let lines = rtrim(cap[0], '\\n').split('\\n');\n let raw = '';\n let text = '';\n const tokens: Token[] = [];\n\n while (lines.length > 0) {\n let inBlockquote = false;\n const currentLines = [];\n\n let i;\n for (i = 0; i < lines.length; i++) {\n // get lines up to a continuation\n if (this.rules.other.blockquoteStart.test(lines[i])) {\n currentLines.push(lines[i]);\n inBlockquote = true;\n } else if (!inBlockquote) {\n currentLines.push(lines[i]);\n } else {\n break;\n }\n }\n lines = lines.slice(i);\n\n const currentRaw = currentLines.join('\\n');\n const currentText = currentRaw\n // precede setext continuation with 4 spaces so it isn't a setext\n .replace(this.rules.other.blockquoteSetextReplace, '\\n $1')\n .replace(this.rules.other.blockquoteSetextReplace2, '');\n raw = raw ? `${raw}\\n${currentRaw}` : currentRaw;\n text = text ? `${text}\\n${currentText}` : currentText;\n\n // parse blockquote lines as top level tokens\n // merge paragraphs if this is a continuation\n const top = this.lexer.state.top;\n this.lexer.state.top = true;\n this.lexer.blockTokens(currentText, tokens, true);\n this.lexer.state.top = top;\n\n // if there is no continuation then we are done\n if (lines.length === 0) {\n break;\n }\n\n const lastToken = tokens.at(-1);\n\n if (lastToken?.type === 'code') {\n // blockquote continuation cannot be preceded by a code block\n break;\n } else if (lastToken?.type === 'blockquote') {\n // include continuation in nested blockquote\n const oldToken = lastToken as Tokens.Blockquote;\n const newText = oldToken.raw + '\\n' + lines.join('\\n');\n const newToken = this.blockquote(newText)!;\n tokens[tokens.length - 1] = newToken;\n\n raw = raw.substring(0, raw.length - oldToken.raw.length) + newToken.raw;\n text = text.substring(0, text.length - oldToken.text.length) + newToken.text;\n break;\n } else if (lastToken?.type === 'list') {\n // include continuation in nested list\n const oldToken = lastToken as Tokens.List;\n const newText = oldToken.raw + '\\n' + lines.join('\\n');\n const newToken = this.list(newText)!;\n tokens[tokens.length - 1] = newToken;\n\n raw = raw.substring(0, raw.length - lastToken.raw.length) + newToken.raw;\n text = text.substring(0, text.length - oldToken.raw.length) + newToken.raw;\n lines = newText.substring(tokens.at(-1)!.raw.length).split('\\n');\n continue;\n }\n }\n\n return {\n type: 'blockquote',\n raw,\n tokens,\n text,\n };\n }\n }\n\n list(src: string): Tokens.List | undefined {\n let cap = this.rules.block.list.exec(src);\n if (cap) {\n let bull = cap[1].trim();\n const isordered = bull.length > 1;\n\n const list: Tokens.List = {\n type: 'list',\n raw: '',\n ordered: isordered,\n start: isordered ? +bull.slice(0, -1) : '',\n loose: false,\n items: [],\n };\n\n bull = isordered ? `\\\\d{1,9}\\\\${bull.slice(-1)}` : `\\\\${bull}`;\n\n if (this.options.pedantic) {\n bull = isordered ? bull : '[*+-]';\n }\n\n // Get next list item\n const itemRegex = this.rules.other.listItemRegex(bull);\n let endsWithBlankLine = false;\n // Check if current bullet point can start a new List Item\n while (src) {\n let endEarly = false;\n let raw = '';\n let itemContents = '';\n if (!(cap = itemRegex.exec(src))) {\n break;\n }\n\n if (this.rules.block.hr.test(src)) { // End list if bullet was actually HR (possibly move into itemRegex?)\n break;\n }\n\n raw = cap[0];\n src = src.substring(raw.length);\n\n let line = cap[2].split('\\n', 1)[0].replace(this.rules.other.listReplaceTabs, (t: string) => ' '.repeat(3 * t.length));\n let nextLine = src.split('\\n', 1)[0];\n let blankLine = !line.trim();\n\n let indent = 0;\n if (this.options.pedantic) {\n indent = 2;\n itemContents = line.trimStart();\n } else if (blankLine) {\n indent = cap[1].length + 1;\n } else {\n indent = cap[2].search(this.rules.other.nonSpaceChar); // Find first non-space char\n indent = indent > 4 ? 1 : indent; // Treat indented code blocks (> 4 spaces) as having only 1 indent\n itemContents = line.slice(indent);\n indent += cap[1].length;\n }\n\n if (blankLine && this.rules.other.blankLine.test(nextLine)) { // Items begin with at most one blank line\n raw += nextLine + '\\n';\n src = src.substring(nextLine.length + 1);\n endEarly = true;\n }\n\n if (!endEarly) {\n const nextBulletRegex = this.rules.other.nextBulletRegex(indent);\n const hrRegex = this.rules.other.hrRegex(indent);\n const fencesBeginRegex = this.rules.other.fencesBeginRegex(indent);\n const headingBeginRegex = this.rules.other.headingBeginRegex(indent);\n const htmlBeginRegex = this.rules.other.htmlBeginRegex(indent);\n\n // Check if following lines should be included in List Item\n while (src) {\n const rawLine = src.split('\\n', 1)[0];\n let nextLineWithoutTabs;\n nextLine = rawLine;\n\n // Re-align to follow commonmark nesting rules\n if (this.options.pedantic) {\n nextLine = nextLine.replace(this.rules.other.listReplaceNesting, ' ');\n nextLineWithoutTabs = nextLine;\n } else {\n nextLineWithoutTabs = nextLine.replace(this.rules.other.tabCharGlobal, ' ');\n }\n\n // End list item if found code fences\n if (fencesBeginRegex.test(nextLine)) {\n break;\n }\n\n // End list item if found start of new heading\n if (headingBeginRegex.test(nextLine)) {\n break;\n }\n\n // End list item if found start of html block\n if (htmlBeginRegex.test(nextLine)) {\n break;\n }\n\n // End list item if found start of new bullet\n if (nextBulletRegex.test(nextLine)) {\n break;\n }\n\n // Horizontal rule found\n if (hrRegex.test(nextLine)) {\n break;\n }\n\n if (nextLineWithoutTabs.search(this.rules.other.nonSpaceChar) >= indent || !nextLine.trim()) { // Dedent if possible\n itemContents += '\\n' + nextLineWithoutTabs.slice(indent);\n } else {\n // not enough indentation\n if (blankLine) {\n break;\n }\n\n // paragraph continuation unless last line was a different block level element\n if (line.replace(this.rules.other.tabCharGlobal, ' ').search(this.rules.other.nonSpaceChar) >= 4) { // indented code block\n break;\n }\n if (fencesBeginRegex.test(line)) {\n break;\n }\n if (headingBeginRegex.test(line)) {\n break;\n }\n if (hrRegex.test(line)) {\n break;\n }\n\n itemContents += '\\n' + nextLine;\n }\n\n if (!blankLine && !nextLine.trim()) { // Check if current line is blank\n blankLine = true;\n }\n\n raw += rawLine + '\\n';\n src = src.substring(rawLine.length + 1);\n line = nextLineWithoutTabs.slice(indent);\n }\n }\n\n if (!list.loose) {\n // If the previous item ended with a blank line, the list is loose\n if (endsWithBlankLine) {\n list.loose = true;\n } else if (this.rules.other.doubleBlankLine.test(raw)) {\n endsWithBlankLine = true;\n }\n }\n\n let istask: RegExpExecArray | null = null;\n let ischecked: boolean | undefined;\n // Check for task list items\n if (this.options.gfm) {\n istask = this.rules.other.listIsTask.exec(itemContents);\n if (istask) {\n ischecked = istask[0] !== '[ ] ';\n itemContents = itemContents.replace(this.rules.other.listReplaceTask, '');\n }\n }\n\n list.items.push({\n type: 'list_item',\n raw,\n task: !!istask,\n checked: ischecked,\n loose: false,\n text: itemContents,\n tokens: [],\n });\n\n list.raw += raw;\n }\n\n // Do not consume newlines at end of final item. Alternatively, make itemRegex *start* with any newlines to simplify/speed up endsWithBlankLine logic\n const lastItem = list.items.at(-1);\n if (lastItem) {\n lastItem.raw = lastItem.raw.trimEnd();\n lastItem.text = lastItem.text.trimEnd();\n } else {\n // not a list since there were no items\n return;\n }\n list.raw = list.raw.trimEnd();\n\n // Item child tokens handled here at end because we needed to have the final item to trim it first\n for (let i = 0; i < list.items.length; i++) {\n this.lexer.state.top = false;\n list.items[i].tokens = this.lexer.blockTokens(list.items[i].text, []);\n\n if (!list.loose) {\n // Check if list should be loose\n const spacers = list.items[i].tokens.filter(t => t.type === 'space');\n const hasMultipleLineBreaks = spacers.length > 0 && spacers.some(t => this.rules.other.anyLine.test(t.raw));\n\n list.loose = hasMultipleLineBreaks;\n }\n }\n\n // Set all items to loose if list is loose\n if (list.loose) {\n for (let i = 0; i < list.items.length; i++) {\n list.items[i].loose = true;\n }\n }\n\n return list;\n }\n }\n\n html(src: string): Tokens.HTML | undefined {\n const cap = this.rules.block.html.exec(src);\n if (cap) {\n const token: Tokens.HTML = {\n type: 'html',\n block: true,\n raw: cap[0],\n pre: cap[1] === 'pre' || cap[1] === 'script' || cap[1] === 'style',\n text: cap[0],\n };\n return token;\n }\n }\n\n def(src: string): Tokens.Def | undefined {\n const cap = this.rules.block.def.exec(src);\n if (cap) {\n const tag = cap[1].toLowerCase().replace(this.rules.other.multipleSpaceGlobal, ' ');\n const href = cap[2] ? cap[2].replace(this.rules.other.hrefBrackets, '$1').replace(this.rules.inline.anyPunctuation, '$1') : '';\n const title = cap[3] ? cap[3].substring(1, cap[3].length - 1).replace(this.rules.inline.anyPunctuation, '$1') : cap[3];\n return {\n type: 'def',\n tag,\n raw: cap[0],\n href,\n title,\n };\n }\n }\n\n table(src: string): Tokens.Table | undefined {\n const cap = this.rules.block.table.exec(src);\n if (!cap) {\n return;\n }\n\n if (!this.rules.other.tableDelimiter.test(cap[2])) {\n // delimiter row must have a pipe (|) or colon (:) otherwise it is a setext heading\n return;\n }\n\n const headers = splitCells(cap[1]);\n const aligns = cap[2].replace(this.rules.other.tableAlignChars, '').split('|');\n const rows = cap[3]?.trim() ? cap[3].replace(this.rules.other.tableRowBlankLine, '').split('\\n') : [];\n\n const item: Tokens.Table = {\n type: 'table',\n raw: cap[0],\n header: [],\n align: [],\n rows: [],\n };\n\n if (headers.length !== aligns.length) {\n // header and align columns must be equal, rows can be different.\n return;\n }\n\n for (const align of aligns) {\n if (this.rules.other.tableAlignRight.test(align)) {\n item.align.push('right');\n } else if (this.rules.other.tableAlignCenter.test(align)) {\n item.align.push('center');\n } else if (this.rules.other.tableAlignLeft.test(align)) {\n item.align.push('left');\n } else {\n item.align.push(null);\n }\n }\n\n for (let i = 0; i < headers.length; i++) {\n item.header.push({\n text: headers[i],\n tokens: this.lexer.inline(headers[i]),\n header: true,\n align: item.align[i],\n });\n }\n\n for (const row of rows) {\n item.rows.push(splitCells(row, item.header.length).map((cell, i) => {\n return {\n text: cell,\n tokens: this.lexer.inline(cell),\n header: false,\n align: item.align[i],\n };\n }));\n }\n\n return item;\n }\n\n lheading(src: string): Tokens.Heading | undefined {\n const cap = this.rules.block.lheading.exec(src);\n if (cap) {\n return {\n type: 'heading',\n raw: cap[0],\n depth: cap[2].charAt(0) === '=' ? 1 : 2,\n text: cap[1],\n tokens: this.lexer.inline(cap[1]),\n };\n }\n }\n\n paragraph(src: string): Tokens.Paragraph | undefined {\n const cap = this.rules.block.paragraph.exec(src);\n if (cap) {\n const text = cap[1].charAt(cap[1].length - 1) === '\\n'\n ? cap[1].slice(0, -1)\n : cap[1];\n return {\n type: 'paragraph',\n raw: cap[0],\n text,\n tokens: this.lexer.inline(text),\n };\n }\n }\n\n text(src: string): Tokens.Text | undefined {\n const cap = this.rules.block.text.exec(src);\n if (cap) {\n return {\n type: 'text',\n raw: cap[0],\n text: cap[0],\n tokens: this.lexer.inline(cap[0]),\n };\n }\n }\n\n escape(src: string): Tokens.Escape | undefined {\n const cap = this.rules.inline.escape.exec(src);\n if (cap) {\n return {\n type: 'escape',\n raw: cap[0],\n text: cap[1],\n };\n }\n }\n\n tag(src: string): Tokens.Tag | undefined {\n const cap = this.rules.inline.tag.exec(src);\n if (cap) {\n if (!this.lexer.state.inLink && this.rules.other.startATag.test(cap[0])) {\n this.lexer.state.inLink = true;\n } else if (this.lexer.state.inLink && this.rules.other.endATag.test(cap[0])) {\n this.lexer.state.inLink = false;\n }\n if (!this.lexer.state.inRawBlock && this.rules.other.startPreScriptTag.test(cap[0])) {\n this.lexer.state.inRawBlock = true;\n } else if (this.lexer.state.inRawBlock && this.rules.other.endPreScriptTag.test(cap[0])) {\n this.lexer.state.inRawBlock = false;\n }\n\n return {\n type: 'html',\n raw: cap[0],\n inLink: this.lexer.state.inLink,\n inRawBlock: this.lexer.state.inRawBlock,\n block: false,\n text: cap[0],\n };\n }\n }\n\n link(src: string): Tokens.Link | Tokens.Image | undefined {\n const cap = this.rules.inline.link.exec(src);\n if (cap) {\n const trimmedUrl = cap[2].trim();\n if (!this.options.pedantic && this.rules.other.startAngleBracket.test(trimmedUrl)) {\n // commonmark requires matching angle brackets\n if (!(this.rules.other.endAngleBracket.test(trimmedUrl))) {\n return;\n }\n\n // ending angle bracket cannot be escaped\n const rtrimSlash = rtrim(trimmedUrl.slice(0, -1), '\\\\');\n if ((trimmedUrl.length - rtrimSlash.length) % 2 === 0) {\n return;\n }\n } else {\n // find closing parenthesis\n const lastParenIndex = findClosingBracket(cap[2], '()');\n if (lastParenIndex === -2) {\n // more open parens than closed\n return;\n }\n\n if (lastParenIndex > -1) {\n const start = cap[0].indexOf('!') === 0 ? 5 : 4;\n const linkLen = start + cap[1].length + lastParenIndex;\n cap[2] = cap[2].substring(0, lastParenIndex);\n cap[0] = cap[0].substring(0, linkLen).trim();\n cap[3] = '';\n }\n }\n let href = cap[2];\n let title = '';\n if (this.options.pedantic) {\n // split pedantic href and title\n const link = this.rules.other.pedanticHrefTitle.exec(href);\n\n if (link) {\n href = link[1];\n title = link[3];\n }\n } else {\n title = cap[3] ? cap[3].slice(1, -1) : '';\n }\n\n href = href.trim();\n if (this.rules.other.startAngleBracket.test(href)) {\n if (this.options.pedantic && !(this.rules.other.endAngleBracket.test(trimmedUrl))) {\n // pedantic allows starting angle bracket without ending angle bracket\n href = href.slice(1);\n } else {\n href = href.slice(1, -1);\n }\n }\n return outputLink(cap, {\n href: href ? href.replace(this.rules.inline.anyPunctuation, '$1') : href,\n title: title ? title.replace(this.rules.inline.anyPunctuation, '$1') : title,\n }, cap[0], this.lexer, this.rules);\n }\n }\n\n reflink(src: string, links: Links): Tokens.Link | Tokens.Image | Tokens.Text | undefined {\n let cap;\n if ((cap = this.rules.inline.reflink.exec(src))\n || (cap = this.rules.inline.nolink.exec(src))) {\n const linkString = (cap[2] || cap[1]).replace(this.rules.other.multipleSpaceGlobal, ' ');\n const link = links[linkString.toLowerCase()];\n if (!link) {\n const text = cap[0].charAt(0);\n return {\n type: 'text',\n raw: text,\n text,\n };\n }\n return outputLink(cap, link, cap[0], this.lexer, this.rules);\n }\n }\n\n emStrong(src: string, maskedSrc: string, prevChar = ''): Tokens.Em | Tokens.Strong | undefined {\n let match = this.rules.inline.emStrongLDelim.exec(src);\n if (!match) return;\n\n // _ can't be between two alphanumerics. \\p{L}\\p{N} includes non-english alphabet/numbers as well\n if (match[3] && prevChar.match(this.rules.other.unicodeAlphaNumeric)) return;\n\n const nextChar = match[1] || match[2] || '';\n\n if (!nextChar || !prevChar || this.rules.inline.punctuation.exec(prevChar)) {\n // unicode Regex counts emoji as 1 char; spread into array for proper count (used multiple times below)\n const lLength = [...match[0]].length - 1;\n let rDelim, rLength, delimTotal = lLength, midDelimTotal = 0;\n\n const endReg = match[0][0] === '*' ? this.rules.inline.emStrongRDelimAst : this.rules.inline.emStrongRDelimUnd;\n endReg.lastIndex = 0;\n\n // Clip maskedSrc to same section of string as src (move to lexer?)\n maskedSrc = maskedSrc.slice(-1 * src.length + lLength);\n\n while ((match = endReg.exec(maskedSrc)) != null) {\n rDelim = match[1] || match[2] || match[3] || match[4] || match[5] || match[6];\n\n if (!rDelim) continue; // skip single * in __abc*abc__\n\n rLength = [...rDelim].length;\n\n if (match[3] || match[4]) { // found another Left Delim\n delimTotal += rLength;\n continue;\n } else if (match[5] || match[6]) { // either Left or Right Delim\n if (lLength % 3 && !((lLength + rLength) % 3)) {\n midDelimTotal += rLength;\n continue; // CommonMark Emphasis Rules 9-10\n }\n }\n\n delimTotal -= rLength;\n\n if (delimTotal > 0) continue; // Haven't found enough closing delimiters\n\n // Remove extra characters. *a*** -> *a*\n rLength = Math.min(rLength, rLength + delimTotal + midDelimTotal);\n // char length can be >1 for unicode characters;\n const lastCharLength = [...match[0]][0].length;\n const raw = src.slice(0, lLength + match.index + lastCharLength + rLength);\n\n // Create `em` if smallest delimiter has odd char count. *a***\n if (Math.min(lLength, rLength) % 2) {\n const text = raw.slice(1, -1);\n return {\n type: 'em',\n raw,\n text,\n tokens: this.lexer.inlineTokens(text),\n };\n }\n\n // Create 'strong' if smallest delimiter has even char count. **a***\n const text = raw.slice(2, -2);\n return {\n type: 'strong',\n raw,\n text,\n tokens: this.lexer.inlineTokens(text),\n };\n }\n }\n }\n\n codespan(src: string): Tokens.Codespan | undefined {\n const cap = this.rules.inline.code.exec(src);\n if (cap) {\n let text = cap[2].replace(this.rules.other.newLineCharGlobal, ' ');\n const hasNonSpaceChars = this.rules.other.nonSpaceChar.test(text);\n const hasSpaceCharsOnBothEnds = this.rules.other.startingSpaceChar.test(text) && this.rules.other.endingSpaceChar.test(text);\n if (hasNonSpaceChars && hasSpaceCharsOnBothEnds) {\n text = text.substring(1, text.length - 1);\n }\n return {\n type: 'codespan',\n raw: cap[0],\n text,\n };\n }\n }\n\n br(src: string): Tokens.Br | undefined {\n const cap = this.rules.inline.br.exec(src);\n if (cap) {\n return {\n type: 'br',\n raw: cap[0],\n };\n }\n }\n\n del(src: string): Tokens.Del | undefined {\n const cap = this.rules.inline.del.exec(src);\n if (cap) {\n return {\n type: 'del',\n raw: cap[0],\n text: cap[2],\n tokens: this.lexer.inlineTokens(cap[2]),\n };\n }\n }\n\n autolink(src: string): Tokens.Link | undefined {\n const cap = this.rules.inline.autolink.exec(src);\n if (cap) {\n let text, href;\n if (cap[2] === '@') {\n text = cap[1];\n href = 'mailto:' + text;\n } else {\n text = cap[1];\n href = text;\n }\n\n return {\n type: 'link',\n raw: cap[0],\n text,\n href,\n tokens: [\n {\n type: 'text',\n raw: text,\n text,\n },\n ],\n };\n }\n }\n\n url(src: string): Tokens.Link | undefined {\n let cap;\n if (cap = this.rules.inline.url.exec(src)) {\n let text, href;\n if (cap[2] === '@') {\n text = cap[0];\n href = 'mailto:' + text;\n } else {\n // do extended autolink path validation\n let prevCapZero;\n do {\n prevCapZero = cap[0];\n cap[0] = this.rules.inline._backpedal.exec(cap[0])?.[0] ?? '';\n } while (prevCapZero !== cap[0]);\n text = cap[0];\n if (cap[1] === 'www.') {\n href = 'http://' + cap[0];\n } else {\n href = cap[0];\n }\n }\n return {\n type: 'link',\n raw: cap[0],\n text,\n href,\n tokens: [\n {\n type: 'text',\n raw: text,\n text,\n },\n ],\n };\n }\n }\n\n inlineText(src: string): Tokens.Text | undefined {\n const cap = this.rules.inline.text.exec(src);\n if (cap) {\n const escaped = this.lexer.state.inRawBlock;\n return {\n type: 'text',\n raw: cap[0],\n text: cap[0],\n escaped,\n };\n }\n }\n}\n","import { _Tokenizer } from './Tokenizer.ts';\nimport { _defaults } from './defaults.ts';\nimport { other, block, inline } from './rules.ts';\nimport type { Token, TokensList, Tokens } from './Tokens.ts';\nimport type { MarkedOptions } from './MarkedOptions.ts';\n\n/**\n * Block Lexer\n */\nexport class _Lexer<ParserOutput = string, RendererOutput = string> {\n tokens: TokensList;\n options: MarkedOptions<ParserOutput, RendererOutput>;\n state: {\n inLink: boolean;\n inRawBlock: boolean;\n top: boolean;\n };\n\n private tokenizer: _Tokenizer<ParserOutput, RendererOutput>;\n private inlineQueue: { src: string, tokens: Token[] }[];\n\n constructor(options?: MarkedOptions<ParserOutput, RendererOutput>) {\n // TokenList cannot be created in one go\n this.tokens = [] as unknown as TokensList;\n this.tokens.links = Object.create(null);\n this.options = options || _defaults;\n this.options.tokenizer = this.options.tokenizer || new _Tokenizer<ParserOutput, RendererOutput>();\n this.tokenizer = this.options.tokenizer;\n this.tokenizer.options = this.options;\n this.tokenizer.lexer = this;\n this.inlineQueue = [];\n this.state = {\n inLink: false,\n inRawBlock: false,\n top: true,\n };\n\n const rules = {\n other,\n block: block.normal,\n inline: inline.normal,\n };\n\n if (this.options.pedantic) {\n rules.block = block.pedantic;\n rules.inline = inline.pedantic;\n } else if (this.options.gfm) {\n rules.block = block.gfm;\n if (this.options.breaks) {\n rules.inline = inline.breaks;\n } else {\n rules.inline = inline.gfm;\n }\n }\n this.tokenizer.rules = rules;\n }\n\n /**\n * Expose Rules\n */\n static get rules() {\n return {\n block,\n inline,\n };\n }\n\n /**\n * Static Lex Method\n */\n static lex<ParserOutput = string, RendererOutput = string>(src: string, options?: MarkedOptions<ParserOutput, RendererOutput>) {\n const lexer = new _Lexer<ParserOutput, RendererOutput>(options);\n return lexer.lex(src);\n }\n\n /**\n * Static Lex Inline Method\n */\n static lexInline<ParserOutput = string, RendererOutput = string>(src: string, options?: MarkedOptions<ParserOutput, RendererOutput>) {\n const lexer = new _Lexer<ParserOutput, RendererOutput>(options);\n return lexer.inlineTokens(src);\n }\n\n /**\n * Preprocessing\n */\n lex(src: string) {\n src = src.replace(other.carriageReturn, '\\n');\n\n this.blockTokens(src, this.tokens);\n\n for (let i = 0; i < this.inlineQueue.length; i++) {\n const next = this.inlineQueue[i];\n this.inlineTokens(next.src, next.tokens);\n }\n this.inlineQueue = [];\n\n return this.tokens;\n }\n\n /**\n * Lexing\n */\n blockTokens(src: string, tokens?: Token[], lastParagraphClipped?: boolean): Token[];\n blockTokens(src: string, tokens?: TokensList, lastParagraphClipped?: boolean): TokensList;\n blockTokens(src: string, tokens: Token[] = [], lastParagraphClipped = false) {\n if (this.options.pedantic) {\n src = src.replace(other.tabCharGlobal, ' ').replace(other.spaceLine, '');\n }\n\n while (src) {\n let token: Tokens.Generic | undefined;\n\n if (this.options.extensions?.block?.some((extTokenizer) => {\n if (token = extTokenizer.call({ lexer: this }, src, tokens)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n return true;\n }\n return false;\n })) {\n continue;\n }\n\n // newline\n if (token = this.tokenizer.space(src)) {\n src = src.substring(token.raw.length);\n const lastToken = tokens.at(-1);\n if (token.raw.length === 1 && lastToken !== undefined) {\n // if there's a single \\n as a spacer, it's terminating the last line,\n // so move it there so that we don't get unnecessary paragraph tags\n lastToken.raw += '\\n';\n } else {\n tokens.push(token);\n }\n continue;\n }\n\n // code\n if (token = this.tokenizer.code(src)) {\n src = src.substring(token.raw.length);\n const lastToken = tokens.at(-1);\n // An indented code block cannot interrupt a paragraph.\n if (lastToken?.type === 'paragraph' || lastToken?.type === 'text') {\n lastToken.raw += (lastToken.raw.endsWith('\\n') ? '' : '\\n') + token.raw;\n lastToken.text += '\\n' + token.text;\n this.inlineQueue.at(-1)!.src = lastToken.text;\n } else {\n tokens.push(token);\n }\n continue;\n }\n\n // fences\n if (token = this.tokenizer.fences(src)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n }\n\n // heading\n if (token = this.tokenizer.heading(src)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n }\n\n // hr\n if (token = this.tokenizer.hr(src)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n }\n\n // blockquote\n if (token = this.tokenizer.blockquote(src)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n }\n\n // list\n if (token = this.tokenizer.list(src)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n }\n\n // html\n if (token = this.tokenizer.html(src)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n }\n\n // def\n if (token = this.tokenizer.def(src)) {\n src = src.substring(token.raw.length);\n const lastToken = tokens.at(-1);\n if (lastToken?.type === 'paragraph' || lastToken?.type === 'text') {\n lastToken.raw += (lastToken.raw.endsWith('\\n') ? '' : '\\n') + token.raw;\n lastToken.text += '\\n' + token.raw;\n this.inlineQueue.at(-1)!.src = lastToken.text;\n } else if (!this.tokens.links[token.tag]) {\n this.tokens.links[token.tag] = {\n href: token.href,\n title: token.title,\n };\n tokens.push(token);\n }\n continue;\n }\n\n // table (gfm)\n if (token = this.tokenizer.table(src)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n }\n\n // lheading\n if (token = this.tokenizer.lheading(src)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n }\n\n // top-level paragraph\n // prevent paragraph consuming extensions by clipping 'src' to extension start\n let cutSrc = src;\n if (this.options.extensions?.startBlock) {\n let startIndex = Infinity;\n const tempSrc = src.slice(1);\n let tempStart;\n this.options.extensions.startBlock.forEach((getStartIndex) => {\n tempStart = getStartIndex.call({ lexer: this }, tempSrc);\n if (typeof tempStart === 'number' && tempStart >= 0) {\n startIndex = Math.min(startIndex, tempStart);\n }\n });\n if (startIndex < Infinity && startIndex >= 0) {\n cutSrc = src.substring(0, startIndex + 1);\n }\n }\n if (this.state.top && (token = this.tokenizer.paragraph(cutSrc))) {\n const lastToken = tokens.at(-1);\n if (lastParagraphClipped && lastToken?.type === 'paragraph') {\n lastToken.raw += (lastToken.raw.endsWith('\\n') ? '' : '\\n') + token.raw;\n lastToken.text += '\\n' + token.text;\n this.inlineQueue.pop();\n this.inlineQueue.at(-1)!.src = lastToken.text;\n } else {\n tokens.push(token);\n }\n lastParagraphClipped = cutSrc.length !== src.length;\n src = src.substring(token.raw.length);\n continue;\n }\n\n // text\n if (token = this.tokenizer.text(src)) {\n src = src.substring(token.raw.length);\n const lastToken = tokens.at(-1);\n if (lastToken?.type === 'text') {\n lastToken.raw += (lastToken.raw.endsWith('\\n') ? '' : '\\n') + token.raw;\n lastToken.text += '\\n' + token.text;\n this.inlineQueue.pop();\n this.inlineQueue.at(-1)!.src = lastToken.text;\n } else {\n tokens.push(token);\n }\n continue;\n }\n\n if (src) {\n const errMsg = 'Infinite loop on byte: ' + src.charCodeAt(0);\n if (this.options.silent) {\n console.error(errMsg);\n break;\n } else {\n throw new Error(errMsg);\n }\n }\n }\n\n this.state.top = true;\n return tokens;\n }\n\n inline(src: string, tokens: Token[] = []) {\n this.inlineQueue.push({ src, tokens });\n return tokens;\n }\n\n /**\n * Lexing/Compiling\n */\n inlineTokens(src: string, tokens: Token[] = []): Token[] {\n // String with links masked to avoid interference with em and strong\n let maskedSrc = src;\n let match: RegExpExecArray | null = null;\n\n // Mask out reflinks\n if (this.tokens.links) {\n const links = Object.keys(this.tokens.links);\n if (links.length > 0) {\n while ((match = this.tokenizer.rules.inline.reflinkSearch.exec(maskedSrc)) != null) {\n if (links.includes(match[0].slice(match[0].lastIndexOf('[') + 1, -1))) {\n maskedSrc = maskedSrc.slice(0, match.index)\n + '[' + 'a'.repeat(match[0].length - 2) + ']'\n + maskedSrc.slice(this.tokenizer.rules.inline.reflinkSearch.lastIndex);\n }\n }\n }\n }\n\n // Mask out escaped characters\n while ((match = this.tokenizer.rules.inline.anyPunctuation.exec(maskedSrc)) != null) {\n maskedSrc = maskedSrc.slice(0, match.index) + '++' + maskedSrc.slice(this.tokenizer.rules.inline.anyPunctuation.lastIndex);\n }\n\n // Mask out other blocks\n let offset;\n while ((match = this.tokenizer.rules.inline.blockSkip.exec(maskedSrc)) != null) {\n offset = match[2] ? match[2].length : 0;\n maskedSrc = maskedSrc.slice(0, match.index + offset) + '[' + 'a'.repeat(match[0].length - offset - 2) + ']' + maskedSrc.slice(this.tokenizer.rules.inline.blockSkip.lastIndex);\n }\n\n // Mask out blocks from extensions\n maskedSrc = this.options.hooks?.emStrongMask?.call({ lexer: this }, maskedSrc) ?? maskedSrc;\n\n let keepPrevChar = false;\n let prevChar = '';\n while (src) {\n if (!keepPrevChar) {\n prevChar = '';\n }\n keepPrevChar = false;\n\n let token: Tokens.Generic | undefined;\n\n // extensions\n if (this.options.extensions?.inline?.some((extTokenizer) => {\n if (token = extTokenizer.call({ lexer: this }, src, tokens)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n return true;\n }\n return false;\n })) {\n continue;\n }\n\n // escape\n if (token = this.tokenizer.escape(src)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n }\n\n // tag\n if (token = this.tokenizer.tag(src)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n }\n\n // link\n if (token = this.tokenizer.link(src)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n }\n\n // reflink, nolink\n if (token = this.tokenizer.reflink(src, this.tokens.links)) {\n src = src.substring(token.raw.length);\n const lastToken = tokens.at(-1);\n if (token.type === 'text' && lastToken?.type === 'text') {\n lastToken.raw += token.raw;\n lastToken.text += token.text;\n } else {\n tokens.push(token);\n }\n continue;\n }\n\n // em & strong\n if (token = this.tokenizer.emStrong(src, maskedSrc, prevChar)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n }\n\n // code\n if (token = this.tokenizer.codespan(src)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n }\n\n // br\n if (token = this.tokenizer.br(src)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n }\n\n // del (gfm)\n if (token = this.tokenizer.del(src)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n }\n\n // autolink\n if (token = this.tokenizer.autolink(src)) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n }\n\n // url (gfm)\n if (!this.state.inLink && (token = this.tokenizer.url(src))) {\n src = src.substring(token.raw.length);\n tokens.push(token);\n continue;\n }\n\n // text\n // prevent inlineText consuming extensions by clipping 'src' to extension start\n let cutSrc = src;\n if (this.options.extensions?.startInline) {\n let startIndex = Infinity;\n const tempSrc = src.slice(1);\n let tempStart;\n this.options.extensions.startInline.forEach((getStartIndex) => {\n tempStart = getStartIndex.call({ lexer: this }, tempSrc);\n if (typeof tempStart === 'number' && tempStart >= 0) {\n startIndex = Math.min(startIndex, tempStart);\n }\n });\n if (startIndex < Infinity && startIndex >= 0) {\n cutSrc = src.substring(0, startIndex + 1);\n }\n }\n if (token = this.tokenizer.inlineText(cutSrc)) {\n src = src.substring(token.raw.length);\n if (token.raw.slice(-1) !== '_') { // Track prevChar before string of ____ started\n prevChar = token.raw.slice(-1);\n }\n keepPrevChar = true;\n const lastToken = tokens.at(-1);\n if (lastToken?.type === 'text') {\n lastToken.raw += token.raw;\n lastToken.text += token.text;\n } else {\n tokens.push(token);\n }\n continue;\n }\n\n if (src) {\n const errMsg = 'Infinite loop on byte: ' + src.charCodeAt(0);\n if (this.options.silent) {\n console.error(errMsg);\n break;\n } else {\n throw new Error(errMsg);\n }\n }\n }\n\n return tokens;\n }\n}\n","import { _defaults } from './defaults.ts';\nimport {\n cleanUrl,\n escape,\n} from './helpers.ts';\nimport { other } from './rules.ts';\nimport type { MarkedOptions } from './MarkedOptions.ts';\nimport type { Tokens } from './Tokens.ts';\nimport type { _Parser } from './Parser.ts';\n\n/**\n * Renderer\n */\nexport class _Renderer<ParserOutput = string, RendererOutput = string> {\n options: MarkedOptions<ParserOutput, RendererOutput>;\n parser!: _Parser<ParserOutput, RendererOutput>; // set by the parser\n constructor(options?: MarkedOptions<ParserOutput, RendererOutput>) {\n this.options = options || _defaults;\n }\n\n space(token: Tokens.Space): RendererOutput {\n return '' as RendererOutput;\n }\n\n code({ text, lang, escaped }: Tokens.Code): RendererOutput {\n const langString = (lang || '').match(other.notSpaceStart)?.[0];\n\n const code = text.replace(other.endingNewline, '') + '\\n';\n\n if (!langString) {\n return '<pre><code>'\n + (escaped ? code : escape(code, true))\n + '</code></pre>\\n' as RendererOutput;\n }\n\n return '<pre><code class=\"language-'\n + escape(langString)\n + '\">'\n + (escaped ? code : escape(code, true))\n + '</code></pre>\\n' as RendererOutput;\n }\n\n blockquote({ tokens }: Tokens.Blockquote): RendererOutput {\n const body = this.parser.parse(tokens);\n return `<blockquote>\\n${body}</blockquote>\\n` as RendererOutput;\n }\n\n html({ text }: Tokens.HTML | Tokens.Tag): RendererOutput {\n return text as RendererOutput;\n }\n\n def(token: Tokens.Def): RendererOutput {\n return '' as RendererOutput;\n }\n\n heading({ tokens, depth }: Tokens.Heading): RendererOutput {\n return `<h${depth}>${this.parser.parseInline(tokens)}</h${depth}>\\n` as RendererOutput;\n }\n\n hr(token: Tokens.Hr): RendererOutput {\n return '<hr>\\n' as RendererOutput;\n }\n\n list(token: Tokens.List): RendererOutput {\n const ordered = token.ordered;\n const start = token.start;\n\n let body = '';\n for (let j = 0; j < token.items.length; j++) {\n const item = token.items[j];\n body += this.listitem(item);\n }\n\n const type = ordered ? 'ol' : 'ul';\n const startAttr = (ordered && start !== 1) ? (' start=\"' + start + '\"') : '';\n return '<' + type + startAttr + '>\\n' + body + '</' + type + '>\\n' as RendererOutput;\n }\n\n listitem(item: Tokens.ListItem): RendererOutput {\n let itemBody = '';\n if (item.task) {\n const checkbox = this.checkbox({ checked: !!item.checked });\n if (item.loose) {\n if (item.tokens[0]?.type === 'paragraph') {\n item.tokens[0].text = checkbox + ' ' + item.tokens[0].text;\n if (item.tokens[0].tokens && item.tokens[0].tokens.length > 0 && item.tokens[0].tokens[0].type === 'text') {\n item.tokens[0].tokens[0].text = checkbox + ' ' + escape(item.tokens[0].tokens[0].text);\n item.tokens[0].tokens[0].escaped = true;\n }\n } else {\n item.tokens.unshift({\n type: 'text',\n raw: checkbox + ' ',\n text: checkbox + ' ',\n escaped: true,\n });\n }\n } else {\n itemBody += checkbox + ' ';\n }\n }\n\n itemBody += this.parser.parse(item.tokens, !!item.loose);\n\n return `<li>${itemBody}</li>\\n` as RendererOutput;\n }\n\n checkbox({ checked }: Tokens.Checkbox): RendererOutput {\n return '<input '\n + (checked ? 'checked=\"\" ' : '')\n + 'disabled=\"\" type=\"checkbox\">' as RendererOutput;\n }\n\n paragraph({ tokens }: Tokens.Paragraph): RendererOutput {\n return `<p>${this.parser.parseInline(tokens)}</p>\\n` as RendererOutput;\n }\n\n table(token: Tokens.Table): RendererOutput {\n let header = '';\n\n // header\n let cell = '';\n for (let j = 0; j < token.header.length; j++) {\n cell += this.tablecell(token.header[j]);\n }\n header += this.tablerow({ text: cell as ParserOutput });\n\n let body = '';\n for (let j = 0; j < token.rows.length; j++) {\n const row = token.rows[j];\n\n cell = '';\n for (let k = 0; k < row.length; k++) {\n cell += this.tablecell(row[k]);\n }\n\n body += this.tablerow({ text: cell as ParserOutput });\n }\n if (body) body = `<tbody>${body}</tbody>`;\n\n return '<table>\\n'\n + '<thead>\\n'\n + header\n + '</thead>\\n'\n + body\n + '</table>\\n' as RendererOutput;\n }\n\n tablerow({ text }: Tokens.TableRow<ParserOutput>): RendererOutput {\n return `<tr>\\n${text}</tr>\\n` as RendererOutput;\n }\n\n tablecell(token: Tokens.TableCell): RendererOutput {\n const content = this.parser.parseInline(token.tokens);\n const type = token.header ? 'th' : 'td';\n const tag = token.align\n ? `<${type} align=\"${token.align}\">`\n : `<${type}>`;\n return tag + content + `</${type}>\\n` as RendererOutput;\n }\n\n /**\n * span level renderer\n */\n strong({ tokens }: Tokens.Strong): RendererOutput {\n return `<strong>${this.parser.parseInline(tokens)}</strong>` as RendererOutput;\n }\n\n em({ tokens }: Tokens.Em): RendererOutput {\n return `<em>${this.parser.parseInline(tokens)}</em>` as RendererOutput;\n }\n\n codespan({ text }: Tokens.Codespan): RendererOutput {\n return `<code>${escape(text, true)}</code>` as RendererOutput;\n }\n\n br(token: Tokens.Br): RendererOutput {\n return '<br>' as RendererOutput;\n }\n\n del({ tokens }: Tokens.Del): RendererOutput {\n return `<del>${this.parser.parseInline(tokens)}</del>` as RendererOutput;\n }\n\n link({ href, title, tokens }: Tokens.Link): RendererOutput {\n const text = this.parser.parseInline(tokens) as string;\n const cleanHref = cleanUrl(href);\n if (cleanHref === null) {\n return text as RendererOutput;\n }\n href = cleanHref;\n let out = '<a href=\"' + href + '\"';\n if (title) {\n out += ' title=\"' + (escape(title)) + '\"';\n }\n out += '>' + text + '</a>';\n return out as RendererOutput;\n }\n\n image({ href, title, text, tokens }: Tokens.Image): RendererOutput {\n if (tokens) {\n text = this.parser.parseInline(tokens, this.parser.textRenderer) as string;\n }\n const cleanHref = cleanUrl(href);\n if (cleanHref === null) {\n return escape(text) as RendererOutput;\n }\n href = cleanHref;\n\n let out = `<img src=\"${href}\" alt=\"${text}\"`;\n if (title) {\n out += ` title=\"${escape(title)}\"`;\n }\n out += '>';\n return out as RendererOutput;\n }\n\n text(token: Tokens.Text | Tokens.Escape): RendererOutput {\n return 'tokens' in token && token.tokens\n ? this.parser.parseInline(token.tokens) as unknown as RendererOutput\n : ('escaped' in token && token.escaped ? token.text as RendererOutput : escape(token.text) as RendererOutput);\n }\n}\n","import type { Tokens } from './Tokens.ts';\n\n/**\n * TextRenderer\n * returns only the textual part of the token\n */\nexport class _TextRenderer<RendererOutput = string> {\n // no need for block level renderers\n strong({ text }: Tokens.Strong): RendererOutput {\n return text as RendererOutput;\n }\n\n em({ text }: Tokens.Em): RendererOutput {\n return text as RendererOutput;\n }\n\n codespan({ text }: Tokens.Codespan): RendererOutput {\n return text as RendererOutput;\n }\n\n del({ text }: Tokens.Del): RendererOutput {\n return text as RendererOutput;\n }\n\n html({ text }: Tokens.HTML | Tokens.Tag): RendererOutput {\n return text as RendererOutput;\n }\n\n text({ text }: Tokens.Text | Tokens.Escape | Tokens.Tag): RendererOutput {\n return text as RendererOutput;\n }\n\n link({ text }: Tokens.Link): RendererOutput {\n return '' + text as RendererOutput;\n }\n\n image({ text }: Tokens.Image): RendererOutput {\n return '' + text as RendererOutput;\n }\n\n br(): RendererOutput {\n return '' as RendererOutput;\n }\n}\n","import { _Renderer } from './Renderer.ts';\nimport { _TextRenderer } from './TextRenderer.ts';\nimport { _defaults } from './defaults.ts';\nimport type { MarkedToken, Token, Tokens } from './Tokens.ts';\nimport type { MarkedOptions } from './MarkedOptions.ts';\n\n/**\n * Parsing & Compiling\n */\nexport class _Parser<ParserOutput = string, RendererOutput = string> {\n options: MarkedOptions<ParserOutput, RendererOutput>;\n renderer: _Renderer<ParserOutput, RendererOutput>;\n textRenderer: _TextRenderer<RendererOutput>;\n constructor(options?: MarkedOptions<ParserOutput, RendererOutput>) {\n this.options = options || _defaults;\n this.options.renderer = this.options.renderer || new _Renderer<ParserOutput, RendererOutput>();\n this.renderer = this.options.renderer;\n this.renderer.options = this.options;\n this.renderer.parser = this;\n this.textRenderer = new _TextRenderer<RendererOutput>();\n }\n\n /**\n * Static Parse Method\n */\n static parse<ParserOutput = string, RendererOutput = string>(tokens: Token[], options?: MarkedOptions<ParserOutput, RendererOutput>) {\n const parser = new _Parser<ParserOutput, RendererOutput>(options);\n return parser.parse(tokens);\n }\n\n /**\n * Static Parse Inline Method\n */\n static parseInline<ParserOutput = string, RendererOutput = string>(tokens: Token[], options?: MarkedOptions<ParserOutput, RendererOutput>) {\n const parser = new _Parser<ParserOutput, RendererOutput>(options);\n return parser.parseInline(tokens);\n }\n\n /**\n * Parse Loop\n */\n parse(tokens: Token[], top = true): ParserOutput {\n let out = '';\n\n for (let i = 0; i < tokens.length; i++) {\n const anyToken = tokens[i];\n\n // Run any renderer extensions\n if (this.options.extensions?.renderers?.[anyToken.type]) {\n const genericToken = anyToken as Tokens.Generic;\n const ret = this.options.extensions.renderers[genericToken.type].call({ parser: this }, genericToken);\n if (ret !== false || !['space', 'hr', 'heading', 'code', 'table', 'blockquote', 'list', 'html', 'def', 'paragraph', 'text'].includes(genericToken.type)) {\n out += ret || '';\n continue;\n }\n }\n\n const token = anyToken as MarkedToken;\n\n switch (token.type) {\n case 'space': {\n out += this.renderer.space(token);\n continue;\n }\n case 'hr': {\n out += this.renderer.hr(token);\n continue;\n }\n case 'heading': {\n out += this.renderer.heading(token);\n continue;\n }\n case 'code': {\n out += this.renderer.code(token);\n continue;\n }\n case 'table': {\n out += this.renderer.table(token);\n continue;\n }\n case 'blockquote': {\n out += this.renderer.blockquote(token);\n continue;\n }\n case 'list': {\n out += this.renderer.list(token);\n continue;\n }\n case 'html': {\n out += this.renderer.html(token);\n continue;\n }\n case 'def': {\n out += this.renderer.def(token);\n continue;\n }\n case 'paragraph': {\n out += this.renderer.paragraph(token);\n continue;\n }\n case 'text': {\n let textToken = token;\n let body = this.renderer.text(textToken) as string;\n while (i + 1 < tokens.length && tokens[i + 1].type === 'text') {\n textToken = tokens[++i] as Tokens.Text;\n body += ('\\n' + this.renderer.text(textToken));\n }\n if (top) {\n out += this.renderer.paragraph({\n type: 'paragraph',\n raw: body,\n text: body,\n tokens: [{ type: 'text', raw: body, text: body, escaped: true }],\n });\n } else {\n out += body;\n }\n continue;\n }\n\n default: {\n const errMsg = 'Token with \"' + token.type + '\" type was not found.';\n if (this.options.silent) {\n console.error(errMsg);\n return '' as ParserOutput;\n } else {\n throw new Error(errMsg);\n }\n }\n }\n }\n\n return out as ParserOutput;\n }\n\n /**\n * Parse Inline Tokens\n */\n parseInline(tokens: Token[], renderer: _Renderer<ParserOutput, RendererOutput> | _TextRenderer<RendererOutput> = this.renderer): ParserOutput {\n let out = '';\n\n for (let i = 0; i < tokens.length; i++) {\n const anyToken = tokens[i];\n\n // Run any renderer extensions\n if (this.options.extensions?.renderers?.[anyToken.type]) {\n const ret = this.options.extensions.renderers[anyToken.type].call({ parser: this }, anyToken);\n if (ret !== false || !['escape', 'html', 'link', 'image', 'strong', 'em', 'codespan', 'br', 'del', 'text'].includes(anyToken.type)) {\n out += ret || '';\n continue;\n }\n }\n\n const token = anyToken as MarkedToken;\n\n switch (token.type) {\n case 'escape': {\n out += renderer.text(token);\n break;\n }\n case 'html': {\n out += renderer.html(token);\n break;\n }\n case 'link': {\n out += renderer.link(token);\n break;\n }\n case 'image': {\n out += renderer.image(token);\n break;\n }\n case 'strong': {\n out += renderer.strong(token);\n break;\n }\n case 'em': {\n out += renderer.em(token);\n break;\n }\n case 'codespan': {\n out += renderer.codespan(token);\n break;\n }\n case 'br': {\n out += renderer.br(token);\n break;\n }\n case 'del': {\n out += renderer.del(token);\n break;\n }\n case 'text': {\n out += renderer.text(token);\n break;\n }\n default: {\n const errMsg = 'Token with \"' + token.type + '\" type was not found.';\n if (this.options.silent) {\n console.error(errMsg);\n return '' as ParserOutput;\n } else {\n throw new Error(errMsg);\n }\n }\n }\n }\n return out as ParserOutput;\n }\n}\n","import { _defaults } from './defaults.ts';\nimport { _Lexer } from './Lexer.ts';\nimport { _Parser } from './Parser.ts';\nimport type { MarkedOptions } from './MarkedOptions.ts';\nimport type { Token, TokensList } from './Tokens.ts';\n\nexport class _Hooks<ParserOutput = string, RendererOutput = string> {\n options: MarkedOptions<ParserOutput, RendererOutput>;\n block?: boolean;\n\n constructor(options?: MarkedOptions<ParserOutput, RendererOutput>) {\n this.options = options || _defaults;\n }\n\n static passThroughHooks = new Set([\n 'preprocess',\n 'postprocess',\n 'processAllTokens',\n 'emStrongMask',\n ]);\n\n static passThroughHooksRespectAsync = new Set([\n 'preprocess',\n 'postprocess',\n 'processAllTokens',\n ]);\n\n /**\n * Process markdown before marked\n */\n preprocess(markdown: string) {\n return markdown;\n }\n\n /**\n * Process HTML after marked is finished\n */\n postprocess(html: ParserOutput) {\n return html;\n }\n\n /**\n * Process all tokens before walk tokens\n */\n processAllTokens(tokens: Token[] | TokensList) {\n return tokens;\n }\n\n /**\n * Mask contents that should not be interpreted as em/strong delimiters\n */\n emStrongMask(src: string) {\n return src;\n }\n\n /**\n * Provide function to tokenize markdown\n */\n provideLexer() {\n return this.block ? _Lexer.lex : _Lexer.lexInline;\n }\n\n /**\n * Provide function to parse tokens\n */\n provideParser() {\n return this.block ? _Parser.parse<ParserOutput, RendererOutput> : _Parser.parseInline<ParserOutput, RendererOutput>;\n }\n}\n","import { _getDefaults } from './defaults.ts';\nimport { _Lexer } from './Lexer.ts';\nimport { _Parser } from './Parser.ts';\nimport { _Hooks } from './Hooks.ts';\nimport { _Renderer } from './Renderer.ts';\nimport { _Tokenizer } from './Tokenizer.ts';\nimport { _TextRenderer } from './TextRenderer.ts';\nimport { escape } from './helpers.ts';\nimport type { MarkedExtension, MarkedOptions } from './MarkedOptions.ts';\nimport type { Token, Tokens, TokensList } from './Tokens.ts';\n\nexport type MaybePromise = void | Promise<void>;\n\ntype UnknownFunction = (...args: unknown[]) => unknown;\ntype GenericRendererFunction = (...args: unknown[]) => string | false;\n\nexport class Marked<ParserOutput = string, RendererOutput = string> {\n defaults = _getDefaults<ParserOutput, RendererOutput>();\n options = this.setOptions;\n\n parse = this.parseMarkdown(true);\n parseInline = this.parseMarkdown(false);\n\n Parser = _Parser<ParserOutput, RendererOutput>;\n Renderer = _Renderer<ParserOutput, RendererOutput>;\n TextRenderer = _TextRenderer<RendererOutput>;\n Lexer = _Lexer;\n Tokenizer = _Tokenizer<ParserOutput, RendererOutput>;\n Hooks = _Hooks<ParserOutput, RendererOutput>;\n\n constructor(...args: MarkedExtension<ParserOutput, RendererOutput>[]) {\n this.use(...args);\n }\n\n /**\n * Run callback for every token\n */\n walkTokens(tokens: Token[] | TokensList, callback: (token: Token) => MaybePromise | MaybePromise[]) {\n let values: MaybePromise[] = [];\n for (const token of tokens) {\n values = values.concat(callback.call(this, token));\n switch (token.type) {\n case 'table': {\n const tableToken = token as Tokens.Table;\n for (const cell of tableToken.header) {\n values = values.concat(this.walkTokens(cell.tokens, callback));\n }\n for (const row of tableToken.rows) {\n for (const cell of row) {\n values = values.concat(this.walkTokens(cell.tokens, callback));\n }\n }\n break;\n }\n case 'list': {\n const listToken = token as Tokens.List;\n values = values.concat(this.walkTokens(listToken.items, callback));\n break;\n }\n default: {\n const genericToken = token as Tokens.Generic;\n if (this.defaults.extensions?.childTokens?.[genericToken.type]) {\n this.defaults.extensions.childTokens[genericToken.type].forEach((childTokens) => {\n const tokens = genericToken[childTokens].flat(Infinity) as Token[] | TokensList;\n values = values.concat(this.walkTokens(tokens, callback));\n });\n } else if (genericToken.tokens) {\n values = values.concat(this.walkTokens(genericToken.tokens, callback));\n }\n }\n }\n }\n return values;\n }\n\n use(...args: MarkedExtension<ParserOutput, RendererOutput>[]) {\n const extensions: MarkedOptions<ParserOutput, RendererOutput>['extensions'] = this.defaults.extensions || { renderers: {}, childTokens: {} };\n\n args.forEach((pack) => {\n // copy options to new object\n const opts = { ...pack } as MarkedOptions<ParserOutput, RendererOutput>;\n\n // set async to true if it was set to true before\n opts.async = this.defaults.async || opts.async || false;\n\n // ==-- Parse \"addon\" extensions --== //\n if (pack.extensions) {\n pack.extensions.forEach((ext) => {\n if (!ext.name) {\n throw new Error('extension name required');\n }\n if ('renderer' in ext) { // Renderer extensions\n const prevRenderer = extensions.renderers[ext.name];\n if (prevRenderer) {\n // Replace extension with func to run new extension but fall back if false\n extensions.renderers[ext.name] = function(...args) {\n let ret = ext.renderer.apply(this, args);\n if (ret === false) {\n ret = prevRenderer.apply(this, args);\n }\n return ret;\n };\n } else {\n extensions.renderers[ext.name] = ext.renderer;\n }\n }\n if ('tokenizer' in ext) { // Tokenizer Extensions\n if (!ext.level || (ext.level !== 'block' && ext.level !== 'inline')) {\n throw new Error(\"extension level must be 'block' or 'inline'\");\n }\n const extLevel = extensions[ext.level];\n if (extLevel) {\n extLevel.unshift(ext.tokenizer);\n } else {\n extensions[ext.level] = [ext.tokenizer];\n }\n if (ext.start) { // Function to check for start of token\n if (ext.level === 'block') {\n if (extensions.startBlock) {\n extensions.startBlock.push(ext.start);\n } else {\n extensions.startBlock = [ext.start];\n }\n } else if (ext.level === 'inline') {\n if (extensions.startInline) {\n extensions.startInline.push(ext.start);\n } else {\n extensions.startInline = [ext.start];\n }\n }\n }\n }\n if ('childTokens' in ext && ext.childTokens) { // Child tokens to be visited by walkTokens\n extensions.childTokens[ext.name] = ext.childTokens;\n }\n });\n opts.extensions = extensions;\n }\n\n // ==-- Parse \"overwrite\" extensions --== //\n if (pack.renderer) {\n const renderer = this.defaults.renderer || new _Renderer<ParserOutput, RendererOutput>(this.defaults);\n for (const prop in pack.renderer) {\n if (!(prop in renderer)) {\n throw new Error(`renderer '${prop}' does not exist`);\n }\n if (['options', 'parser'].includes(prop)) {\n // ignore options property\n continue;\n }\n const rendererProp = prop as Exclude<keyof _Renderer<ParserOutput, RendererOutput>, 'options' | 'parser'>;\n const rendererFunc = pack.renderer[rendererProp] as GenericRendererFunction;\n const prevRenderer = renderer[rendererProp] as GenericRendererFunction;\n // Replace renderer with func to run extension, but fall back if false\n renderer[rendererProp] = (...args: unknown[]) => {\n let ret = rendererFunc.apply(renderer, args);\n if (ret === false) {\n ret = prevRenderer.apply(renderer, args);\n }\n return (ret || '') as RendererOutput;\n };\n }\n opts.renderer = renderer;\n }\n if (pack.tokenizer) {\n const tokenizer = this.defaults.tokenizer || new _Tokenizer<ParserOutput, RendererOutput>(this.defaults);\n for (const prop in pack.tokenizer) {\n if (!(prop in tokenizer)) {\n throw new Error(`tokenizer '${prop}' does not exist`);\n }\n if (['options', 'rules', 'lexer'].includes(prop)) {\n // ignore options, rules, and lexer properties\n continue;\n }\n const tokenizerProp = prop as Exclude<keyof _Tokenizer<ParserOutput, RendererOutput>, 'options' | 'rules' | 'lexer'>;\n const tokenizerFunc = pack.tokenizer[tokenizerProp] as UnknownFunction;\n const prevTokenizer = tokenizer[tokenizerProp] as UnknownFunction;\n // Replace tokenizer with func to run extension, but fall back if false\n // @ts-expect-error cannot type tokenizer function dynamically\n tokenizer[tokenizerProp] = (...args: unknown[]) => {\n let ret = tokenizerFunc.apply(tokenizer, args);\n if (ret === false) {\n ret = prevTokenizer.apply(tokenizer, args);\n }\n return ret;\n };\n }\n opts.tokenizer = tokenizer;\n }\n\n // ==-- Parse Hooks extensions --== //\n if (pack.hooks) {\n const hooks = this.defaults.hooks || new _Hooks<ParserOutput, RendererOutput>();\n for (const prop in pack.hooks) {\n if (!(prop in hooks)) {\n throw new Error(`hook '${prop}' does not exist`);\n }\n if (['options', 'block'].includes(prop)) {\n // ignore options and block properties\n continue;\n }\n const hooksProp = prop as Exclude<keyof _Hooks<ParserOutput, RendererOutput>, 'options' | 'block'>;\n const hooksFunc = pack.hooks[hooksProp] as UnknownFunction;\n const prevHook = hooks[hooksProp] as UnknownFunction;\n if (_Hooks.passThroughHooks.has(prop)) {\n // @ts-expect-error cannot type hook function dynamically\n hooks[hooksProp] = (arg: unknown) => {\n if (this.defaults.async && _Hooks.passThroughHooksRespectAsync.has(prop)) {\n return (async() => {\n const ret = await hooksFunc.call(hooks, arg);\n return prevHook.call(hooks, ret);\n })();\n }\n\n const ret = hooksFunc.call(hooks, arg);\n return prevHook.call(hooks, ret);\n };\n } else {\n // @ts-expect-error cannot type hook function dynamically\n hooks[hooksProp] = (...args: unknown[]) => {\n if (this.defaults.async) {\n return (async() => {\n let ret = await hooksFunc.apply(hooks, args);\n if (ret === false) {\n ret = await prevHook.apply(hooks, args);\n }\n return ret;\n })();\n }\n\n let ret = hooksFunc.apply(hooks, args);\n if (ret === false) {\n ret = prevHook.apply(hooks, args);\n }\n return ret;\n };\n }\n }\n opts.hooks = hooks;\n }\n\n // ==-- Parse WalkTokens extensions --== //\n if (pack.walkTokens) {\n const walkTokens = this.defaults.walkTokens;\n const packWalktokens = pack.walkTokens;\n opts.walkTokens = function(token) {\n let values: MaybePromise[] = [];\n values.push(packWalktokens.call(this, token));\n if (walkTokens) {\n values = values.concat(walkTokens.call(this, token));\n }\n return values;\n };\n }\n\n this.defaults = { ...this.defaults, ...opts };\n });\n\n return this;\n }\n\n setOptions(opt: MarkedOptions<ParserOutput, RendererOutput>) {\n this.defaults = { ...this.defaults, ...opt };\n return this;\n }\n\n lexer(src: string, options?: MarkedOptions<ParserOutput, RendererOutput>) {\n return _Lexer.lex(src, options ?? this.defaults);\n }\n\n parser(tokens: Token[], options?: MarkedOptions<ParserOutput, RendererOutput>) {\n return _Parser.parse<ParserOutput, RendererOutput>(tokens, options ?? this.defaults);\n }\n\n private parseMarkdown(blockType: boolean) {\n type overloadedParse = {\n (src: string, options: MarkedOptions<ParserOutput, RendererOutput> & { async: true }): Promise<ParserOutput>;\n (src: string, options: MarkedOptions<ParserOutput, RendererOutput> & { async: false }): ParserOutput;\n (src: string, options?: MarkedOptions<ParserOutput, RendererOutput> | null): ParserOutput | Promise<ParserOutput>;\n };\n\n // eslint-disable-next-line @typescript-eslint/no-explicit-any\n const parse: overloadedParse = (src: string, options?: MarkedOptions<ParserOutput, RendererOutput> | null): any => {\n const origOpt = { ...options };\n const opt = { ...this.defaults, ...origOpt };\n\n const throwError = this.onError(!!opt.silent, !!opt.async);\n\n // throw error if an extension set async to true but parse was called with async: false\n if (this.defaults.async === true && origOpt.async === false) {\n return throwError(new Error('marked(): The async option was set to true by an extension. Remove async: false from the parse options object to return a Promise.'));\n }\n\n // throw error in case of non string input\n if (typeof src === 'undefined' || src === null) {\n return throwError(new Error('marked(): input parameter is undefined or null'));\n }\n if (typeof src !== 'string') {\n return throwError(new Error('marked(): input parameter is of type '\n + Object.prototype.toString.call(src) + ', string expected'));\n }\n\n if (opt.hooks) {\n opt.hooks.options = opt;\n opt.hooks.block = blockType;\n }\n\n if (opt.async) {\n return (async() => {\n const processedSrc = opt.hooks ? await opt.hooks.preprocess(src) : src;\n const lexer = opt.hooks ? await opt.hooks.provideLexer() : (blockType ? _Lexer.lex : _Lexer.lexInline);\n const tokens = await lexer(processedSrc, opt);\n const processedTokens = opt.hooks ? await opt.hooks.processAllTokens(tokens) : tokens;\n if (opt.walkTokens) {\n await Promise.all(this.walkTokens(processedTokens, opt.walkTokens));\n }\n const parser = opt.hooks ? await opt.hooks.provideParser() : (blockType ? _Parser.parse : _Parser.parseInline);\n const html = await parser(processedTokens, opt);\n return opt.hooks ? await opt.hooks.postprocess(html) : html;\n })().catch(throwError);\n }\n\n try {\n if (opt.hooks) {\n src = opt.hooks.preprocess(src) as string;\n }\n const lexer = opt.hooks ? opt.hooks.provideLexer() : (blockType ? _Lexer.lex : _Lexer.lexInline);\n let tokens = lexer(src, opt);\n if (opt.hooks) {\n tokens = opt.hooks.processAllTokens(tokens);\n }\n if (opt.walkTokens) {\n this.walkTokens(tokens, opt.walkTokens);\n }\n const parser = opt.hooks ? opt.hooks.provideParser() : (blockType ? _Parser.parse : _Parser.parseInline);\n let html = parser(tokens, opt);\n if (opt.hooks) {\n html = opt.hooks.postprocess(html);\n }\n return html;\n } catch(e) {\n return throwError(e as Error);\n }\n };\n\n return parse;\n }\n\n private onError(silent: boolean, async: boolean) {\n return (e: Error): string | Promise<string> => {\n e.message += '\\nPlease report this to https://github.com/markedjs/marked.';\n\n if (silent) {\n const msg = '<p>An error occurred:</p><pre>'\n + escape(e.message + '', true)\n + '</pre>';\n if (async) {\n return Promise.resolve(msg);\n }\n return msg;\n }\n\n if (async) {\n return Promise.reject(e);\n }\n throw e;\n };\n }\n}\n","import { _Lexer } from './Lexer.ts';\nimport { _Parser } from './Parser.ts';\nimport { _Tokenizer } from './Tokenizer.ts';\nimport { _Renderer } from './Renderer.ts';\nimport { _TextRenderer } from './TextRenderer.ts';\nimport { _Hooks } from './Hooks.ts';\nimport { Marked } from './Instance.ts';\nimport {\n _getDefaults,\n changeDefaults,\n _defaults,\n} from './defaults.ts';\nimport type { MarkedExtension, MarkedOptions } from './MarkedOptions.ts';\nimport type { Token, TokensList } from './Tokens.ts';\nimport type { MaybePromise } from './Instance.ts';\n\nconst markedInstance = new Marked();\n\n/**\n * Compiles markdown to HTML asynchronously.\n *\n * @param src String of markdown source to be compiled\n * @param options Hash of options, having async: true\n * @return Promise of string of compiled HTML\n */\nexport function marked(src: string, options: MarkedOptions & { async: true }): Promise<string>;\n\n/**\n * Compiles markdown to HTML.\n *\n * @param src String of markdown source to be compiled\n * @param options Optional hash of options\n * @return String of compiled HTML. Will be a Promise of string if async is set to true by any extensions.\n */\nexport function marked(src: string, options: MarkedOptions & { async: false }): string;\nexport function marked(src: string, options: MarkedOptions & { async: true }): Promise<string>;\nexport function marked(src: string, options?: MarkedOptions | null): string | Promise<string>;\nexport function marked(src: string, opt?: MarkedOptions | null): string | Promise<string> {\n return markedInstance.parse(src, opt);\n}\n\n/**\n * Sets the default options.\n *\n * @param options Hash of options\n */\nmarked.options =\nmarked.setOptions = function(options: MarkedOptions) {\n markedInstance.setOptions(options);\n marked.defaults = markedInstance.defaults;\n changeDefaults(marked.defaults);\n return marked;\n};\n\n/**\n * Gets the original marked default options.\n */\nmarked.getDefaults = _getDefaults;\n\nmarked.defaults = _defaults;\n\n/**\n * Use Extension\n */\n\nmarked.use = function(...args: MarkedExtension[]) {\n markedInstance.use(...args);\n marked.defaults = markedInstance.defaults;\n changeDefaults(marked.defaults);\n return marked;\n};\n\n/**\n * Run callback for every token\n */\n\nmarked.walkTokens = function(tokens: Token[] | TokensList, callback: (token: Token) => MaybePromise | MaybePromise[]) {\n return markedInstance.walkTokens(tokens, callback);\n};\n\n/**\n * Compiles markdown to HTML without enclosing `p` tag.\n *\n * @param src String of markdown source to be compiled\n * @param options Hash of options\n * @return String of compiled HTML\n */\nmarked.parseInline = markedInstance.parseInline;\n\n/**\n * Expose\n */\nmarked.Parser = _Parser;\nmarked.parser = _Parser.parse;\nmarked.Renderer = _Renderer;\nmarked.TextRenderer = _TextRenderer;\nmarked.Lexer = _Lexer;\nmarked.lexer = _Lexer.lex;\nmarked.Tokenizer = _Tokenizer;\nmarked.Hooks = _Hooks;\nmarked.parse = marked;\n\nexport const options = marked.options;\nexport const setOptions = marked.setOptions;\nexport const use = marked.use;\nexport const walkTokens = marked.walkTokens;\nexport const parseInline = marked.parseInline;\nexport const parse = marked;\nexport const parser = _Parser.parse;\nexport const lexer = _Lexer.lex;\nexport { _defaults as defaults, _getDefaults as getDefaults } from './defaults.ts';\nexport { _Lexer as Lexer } from './Lexer.ts';\nexport { _Parser as Parser } from './Parser.ts';\nexport { _Tokenizer as Tokenizer } from './Tokenizer.ts';\nexport { _Renderer as Renderer } from './Renderer.ts';\nexport { _TextRenderer as TextRenderer } from './TextRenderer.ts';\nexport { _Hooks as Hooks } from './Hooks.ts';\nexport { Marked } from './Instance.ts';\nexport type * from './MarkedOptions.ts';\nexport type * from './Tokens.ts';\n","import { isVisibleAt, normalizePrivacy } from \"@vortex-os/core\";\nimport type { Privacy } from \"@vortex-os/core\";\nimport type { RenderWarning } from \"./types.js\";\n\nconst SECTION_PATTERN =\n /<!--\\s*vortex:privacy\\s+(\\w+)\\s*-->([\\s\\S]*?)<!--\\s*\\/vortex:privacy\\s*-->/g;\n\nexport interface StripResult {\n readonly content: string;\n readonly warnings: readonly RenderWarning[];\n}\n\n/**\n * Remove section blocks whose declared privacy exceeds the target.\n *\n * Each section is delimited by `<!-- vortex:privacy LEVEL -->` and\n * `<!-- /vortex:privacy -->`. Sections at or below target privacy keep\n * their body (markers themselves are removed). Sections above target are\n * stripped entirely and a `section-stripped` warning is reported.\n *\n * Sections do not nest; the parser does not support nesting.\n */\nexport function stripPrivateSections(\n content: string,\n targetPrivacy: Privacy,\n): StripResult {\n const warnings: RenderWarning[] = [];\n const out = content.replace(SECTION_PATTERN, (_match, levelRaw: string, body: string) => {\n const sectionPrivacy = normalizePrivacy(levelRaw);\n if (isVisibleAt(sectionPrivacy, targetPrivacy)) {\n return body;\n }\n warnings.push({\n kind: \"section-stripped\",\n reason: `Stripped section with privacy=${sectionPrivacy} (above target ${targetPrivacy})`,\n });\n return \"\";\n });\n return { content: out, warnings };\n}\n","/**\n * Minimal default template. Hosts that want styling, navigation, or\n * additional metadata should pass a custom `template` to `renderHtml`.\n */\nexport const DEFAULT_TEMPLATE = `<!DOCTYPE html>\n<html lang=\"en\">\n<head>\n<meta charset=\"utf-8\">\n<title>{{title}}</title>\n</head>\n<body>\n{{content}}\n</body>\n</html>\n`;\n\n/**\n * Replace `{{name}}` placeholders in a template string with values from\n * `vars`. Missing keys are replaced with the empty string.\n */\nexport function applyTemplate(\n template: string,\n vars: Readonly<Record<string, string>>,\n): string {\n return template.replace(/\\{\\{(\\w+)\\}\\}/g, (_match, key: string) => {\n return vars[key] ?? \"\";\n });\n}\n","import { marked } from \"marked\";\nimport { isVisibleAt, normalizePrivacy, parseFrontmatter } from \"@vortex-os/core\";\nimport type { Privacy } from \"@vortex-os/core\";\nimport { stripPrivateSections } from \"./filter.js\";\nimport { applyTemplate, DEFAULT_TEMPLATE } from \"./template.js\";\nimport type { RenderOptions, RenderResult } from \"./types.js\";\n\n/**\n * Render a markdown source to HTML, applying document-level and\n * section-level privacy filtering before conversion.\n *\n * If the document's own privacy exceeds the target, an empty result is\n * returned with a `document-not-visible` warning and no body conversion\n * is performed.\n */\nexport async function renderHtml(\n source: string,\n options: RenderOptions,\n): Promise<RenderResult> {\n const { frontmatter, body } = parseFrontmatter<{\n privacy?: unknown;\n title?: unknown;\n }>(source);\n const documentPrivacy: Privacy = normalizePrivacy(frontmatter.privacy);\n\n if (!isVisibleAt(documentPrivacy, options.targetPrivacy)) {\n return {\n html: \"\",\n documentPrivacy,\n visible: false,\n warnings: [\n {\n kind: \"document-not-visible\",\n reason: `Document privacy is ${documentPrivacy}; viewer target is ${options.targetPrivacy}.`,\n },\n ],\n };\n }\n\n const stripped = stripPrivateSections(body, options.targetPrivacy);\n const inner = (await Promise.resolve(\n marked.parse(stripped.content, { gfm: true, breaks: false }),\n )) as string;\n const title =\n options.title ?? (typeof frontmatter.title === \"string\" ? frontmatter.title : \"\");\n const template = options.template ?? DEFAULT_TEMPLATE;\n const html = applyTemplate(template, { title, content: inner });\n\n return {\n html,\n documentPrivacy,\n visible: true,\n warnings: stripped.warnings,\n };\n}\n","export type { WorklogEntry, WorklogFrontmatter } from \"./types.js\";\r\nexport { WorklogStore } from \"./store.js\";\r\nexport { appendSection } from \"./append.js\";\r\n","import { readdir, readFile, stat } from \"node:fs/promises\";\r\nimport { join } from \"node:path\";\r\nimport { parseFrontmatter } from \"@vortex-os/core\";\r\nimport type { WorklogEntry, WorklogFrontmatter } from \"./types.js\";\r\n\r\nconst FILENAME_PATTERN = /^(\\d{4}-\\d{2}-\\d{2})-(.+)\\.md$/;\r\nconst MONTH_PATTERN = /^\\d{2}$/;\r\nconst YEAR_PATTERN = /^\\d{4}$/;\r\n\r\n/**\r\n * Directory-backed worklog store. Expected layout: `<rootDir>/YYYY/MM/YYYY-MM-DD-keyword.md`.\r\n *\r\n * The store treats missing subdirectories as empty, never as errors —\r\n * a brand-new month with no entries returns an empty list, not a throw.\r\n */\r\nexport class WorklogStore {\r\n constructor(readonly rootDir: string) {}\r\n\r\n /** All entries across all years and months, sorted by date ascending. */\r\n async list(): Promise<readonly WorklogEntry[]> {\r\n const years = await this.listSubdirs(this.rootDir, YEAR_PATTERN);\r\n const entries: WorklogEntry[] = [];\r\n for (const year of years) {\r\n const yearDir = join(this.rootDir, year);\r\n const months = await this.listSubdirs(yearDir, MONTH_PATTERN);\r\n for (const month of months) {\r\n entries.push(...(await this.entriesIn(join(yearDir, month))));\r\n }\r\n }\r\n return entries.sort((a, b) =>\r\n a.date === b.date ? a.keyword.localeCompare(b.keyword) : a.date.localeCompare(b.date),\r\n );\r\n }\r\n\r\n /** Entries within one calendar month. */\r\n async listByMonth(year: number, month: number): Promise<readonly WorklogEntry[]> {\r\n const monthDir = join(\r\n this.rootDir,\r\n String(year).padStart(4, \"0\"),\r\n String(month).padStart(2, \"0\"),\r\n );\r\n const entries = await this.entriesIn(monthDir);\r\n return entries.sort((a, b) =>\r\n a.date === b.date ? a.keyword.localeCompare(b.keyword) : a.date.localeCompare(b.date),\r\n );\r\n }\r\n\r\n /**\r\n * The first entry matching `date` (`YYYY-MM-DD`). If multiple files exist\r\n * for that date with different keywords, the lexicographically-first one\r\n * is returned. Use `list()` when all are needed.\r\n */\r\n async get(date: string): Promise<WorklogEntry | undefined> {\r\n const [year, month] = date.split(\"-\");\r\n if (!year || !month) return undefined;\r\n const monthDir = join(this.rootDir, year, month);\r\n const entries = (await this.entriesIn(monthDir))\r\n .filter((e) => e.date === date)\r\n .sort((a, b) => a.keyword.localeCompare(b.keyword));\r\n return entries[0];\r\n }\r\n\r\n /** Most recent entry by date (descending), then keyword (descending). */\r\n async getLatest(): Promise<WorklogEntry | undefined> {\r\n const all = await this.list();\r\n if (all.length === 0) return undefined;\r\n return all[all.length - 1];\r\n }\r\n\r\n /** Resolve the file path for a given (date, keyword), without creating it. */\r\n pathFor(date: string, keyword: string): string {\r\n const [year, month] = date.split(\"-\");\r\n if (!year || !month) {\r\n throw new Error(`Invalid date: ${date} (expected YYYY-MM-DD)`);\r\n }\r\n return join(this.rootDir, year, month, `${date}-${keyword}.md`);\r\n }\r\n\r\n private async listSubdirs(dir: string, pattern: RegExp): Promise<readonly string[]> {\r\n try {\r\n const entries = await readdir(dir, { withFileTypes: true });\r\n return entries\r\n .filter((e) => e.isDirectory() && pattern.test(e.name))\r\n .map((e) => e.name)\r\n .sort();\r\n } catch (e) {\r\n if ((e as NodeJS.ErrnoException).code === \"ENOENT\") return [];\r\n throw e;\r\n }\r\n }\r\n\r\n private async entriesIn(monthDir: string): Promise<WorklogEntry[]> {\r\n let names: string[];\r\n try {\r\n names = await readdir(monthDir);\r\n } catch (e) {\r\n if ((e as NodeJS.ErrnoException).code === \"ENOENT\") return [];\r\n throw e;\r\n }\r\n const out: WorklogEntry[] = [];\r\n for (const name of names) {\r\n const match = name.match(FILENAME_PATTERN);\r\n if (!match) continue;\r\n const path = join(monthDir, name);\r\n try {\r\n const info = await stat(path);\r\n if (!info.isFile()) continue;\r\n } catch {\r\n continue;\r\n }\r\n const raw = await readFile(path, \"utf8\");\r\n const { frontmatter, body } = parseFrontmatter<WorklogFrontmatter>(raw);\r\n const date = match[1] ?? \"\";\r\n const keyword = match[2] ?? \"\";\r\n out.push({ date, keyword, path, frontmatter, body });\r\n }\r\n return out;\r\n }\r\n}\r\n","import { readFile, writeFile } from \"node:fs/promises\";\r\nimport type { WorklogEntry } from \"./types.js\";\r\n\r\n/**\r\n * Append a new section to the end of an existing worklog entry's file.\r\n *\r\n * The resulting markdown adds two leading blank lines, then `## <title>`,\r\n * then a blank line, then the body. The entry's frontmatter is not touched.\r\n *\r\n * Returns the updated raw markdown that was written.\r\n */\r\nexport async function appendSection(\r\n entry: WorklogEntry,\r\n title: string,\r\n body: string,\r\n): Promise<string> {\r\n const original = await readFile(entry.path, \"utf8\");\r\n const trimmed = original.replace(/\\s+$/u, \"\");\r\n const section = `## ${title}\\n\\n${body.trimEnd()}\\n`;\r\n const next = `${trimmed}\\n\\n${section}`;\r\n await writeFile(entry.path, next, \"utf8\");\r\n return next;\r\n}\r\n","export type {\n DecisionEntry,\n DecisionFilter,\n DecisionLogFrontmatter,\n DecisionTemplateInput,\n} from \"./types.js\";\nexport { DecisionStore } from \"./store.js\";\nexport { renderTemplate } from \"./template.js\";\n","import { readdir, readFile, stat } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { parseFrontmatter } from \"@vortex-os/core\";\nimport type {\n DecisionEntry,\n DecisionFilter,\n DecisionLogFrontmatter,\n} from \"./types.js\";\n\nconst FILENAME_PATTERN = /^(\\d{4}-\\d{2}-\\d{2})-(.+)\\.md$/;\n\n/**\n * Directory-backed Decision-Log store. Expected layout is flat —\n * `<rootDir>/YYYY-MM-DD-<slug>.md`, no year/month subdirectories.\n *\n * Non-entry files at the root (README, _TEMPLATE, anything not matching\n * the date-prefix pattern) are silently ignored.\n *\n * A missing root directory returns an empty list rather than throwing,\n * so a brand-new template clone with no entries is a normal state.\n */\nexport class DecisionStore {\n constructor(readonly rootDir: string) {}\n\n /** All entries, sorted by date ascending, then slug ascending. */\n async list(): Promise<readonly DecisionEntry[]> {\n let names: string[];\n try {\n names = await readdir(this.rootDir);\n } catch (e) {\n if ((e as NodeJS.ErrnoException).code === \"ENOENT\") return [];\n throw e;\n }\n const out: DecisionEntry[] = [];\n for (const name of names) {\n const match = name.match(FILENAME_PATTERN);\n if (!match) continue;\n const path = join(this.rootDir, name);\n try {\n const info = await stat(path);\n if (!info.isFile()) continue;\n } catch {\n continue;\n }\n const raw = await readFile(path, \"utf8\");\n const { frontmatter, body } =\n parseFrontmatter<DecisionLogFrontmatter>(raw);\n const date = match[1] ?? \"\";\n const slug = match[2] ?? \"\";\n out.push({ date, slug, path, frontmatter, body });\n }\n return out.sort((a, b) =>\n a.date === b.date\n ? a.slug.localeCompare(b.slug)\n : a.date.localeCompare(b.date),\n );\n }\n\n /**\n * Entries whose filename starts with `date` (`YYYY-MM-DD`). Multiple\n * decisions on the same day are returned in slug-ascending order.\n */\n async getByDate(date: string): Promise<readonly DecisionEntry[]> {\n const all = await this.list();\n return all.filter((e) => e.date === date);\n }\n\n /**\n * The first entry matching `date` and (optionally) `slug`. When no slug is\n * provided and multiple entries share the date, the lexicographically-first\n * one is returned.\n */\n async get(date: string, slug?: string): Promise<DecisionEntry | undefined> {\n const matches = await this.getByDate(date);\n if (slug === undefined) return matches[0];\n return matches.find((e) => e.slug === slug);\n }\n\n /** Most recent entry by date (descending), then slug (descending). */\n async getLatest(): Promise<DecisionEntry | undefined> {\n const all = await this.list();\n if (all.length === 0) return undefined;\n return all[all.length - 1];\n }\n\n /**\n * Subset of entries matching the given criteria. Empty/undefined fields\n * are ignored. Returns entries in the same order as {@link list}.\n */\n async filter(criteria: DecisionFilter): Promise<readonly DecisionEntry[]> {\n const all = await this.list();\n return all.filter((e) => {\n if (criteria.status !== undefined && e.frontmatter.status !== criteria.status) {\n return false;\n }\n if (criteria.tag !== undefined) {\n const tags = e.frontmatter.tags ?? [];\n if (!tags.includes(criteria.tag)) return false;\n }\n if (criteria.fromDate !== undefined && e.date < criteria.fromDate) {\n return false;\n }\n if (criteria.toDate !== undefined && e.date > criteria.toDate) {\n return false;\n }\n return true;\n });\n }\n\n /** Resolve the file path for a given (date, slug), without creating it. */\n pathFor(date: string, slug: string): string {\n if (!/^\\d{4}-\\d{2}-\\d{2}$/.test(date)) {\n throw new Error(`Invalid date: ${date} (expected YYYY-MM-DD)`);\n }\n return join(this.rootDir, `${date}-${slug}.md`);\n }\n}\n","import type { DecisionTemplateInput } from \"./types.js\";\n\n/**\n * Render a new Decision-Log entry body using an obsidian-style template\n * convention. Caller is responsible for writing the result to disk via\n * {@link DecisionStore.pathFor}.\n *\n * The output deliberately mirrors a human-authored template so the\n * shape stays consistent whether the entry was created by hand or by\n * this helper.\n */\nexport function renderTemplate(input: DecisionTemplateInput): string {\n const tags = [\"decision-log\", ...(input.tags ?? [])];\n const tagsLine = tags.map((t) => `\"${t}\"`).join(\", \");\n const area = input.area ?? \"work / personal / other\";\n\n return [\n \"---\",\n \"type: decision-log\",\n \"status: active\",\n \"privacy: personal\",\n `created: ${input.date}`,\n `updated: ${input.date}`,\n `tags: [${tagsLine}]`,\n \"---\",\n \"\",\n `# ${input.title}`,\n \"\",\n `- **Date**: ${input.date}`,\n `- **Area**: ${area}`,\n \"- **Tag**: #decision-log\",\n \"\",\n \"## Context\",\n \"\",\n \"{What problem prompted this decision? Why was a choice required? 2-3 sentences.}\",\n \"\",\n \"## Options\",\n \"\",\n \"| Option | Content | Pros | Cons |\",\n \"|--------|---------|------|------|\",\n \"| A | | | |\",\n \"| B | | | |\",\n \"| C | | | |\",\n \"\",\n \"## Chosen: {A/B/C}\",\n \"\",\n \"## Why this one\",\n \"\",\n \"{The core section. The real reasoning behind the choice, candidly.}\",\n \"\",\n \"## Principle (patterns emerge when this repeats)\",\n \"\",\n \"> {One sentence: the judgment criterion this decision exposed.}\",\n \"\",\n \"## Result (optional)\",\n \"\",\n \"{Fill in only for verifiable decisions. Delete the section for taste/preference records.}\",\n \"\",\n ].join(\"\\n\");\n}\n","export type {\n IndexEntry,\n RenderIndexInput,\n ScanOptions,\n} from \"./types.js\";\nexport { scanDirectory } from \"./scan.js\";\nexport { renderIndex } from \"./render.js\";\nexport { findIndexableDirs } from \"./nested.js\";\n","import { readdir, readFile, stat } from \"node:fs/promises\";\nimport { basename, extname, join, relative } from \"node:path\";\nimport { parseFrontmatter } from \"@vortex-os/core\";\nimport type { IndexEntry, ScanOptions } from \"./types.js\";\n\nconst RESERVED_FILES: ReadonlySet<string> = new Set([\"README.md\", \"_INDEX.md\"]);\nconst H1_PATTERN = /^#\\s+(.+?)\\s*$/m;\n\n/**\n * Scan a directory of markdown notes and produce one {@link IndexEntry}\n * per file, sorted by `relPath` ascending.\n *\n * - Files whose names are `README.md` or `_INDEX.md` are always skipped.\n * - Hidden entries (name starting with `.` or `_`, except `_TEMPLATE` which\n * is still surfaced but can be excluded via `skipPrefixes: [\"_TEMPLATE\"]`)\n * are not descended into when `recursive: true`.\n * - A missing directory returns an empty list rather than throwing.\n */\nexport async function scanDirectory(\n rootDir: string,\n opts: ScanOptions = {},\n): Promise<readonly IndexEntry[]> {\n const skipFilenames = new Set([\n ...RESERVED_FILES,\n ...(opts.skipFilenames ?? []),\n ]);\n const skipPrefixes = opts.skipPrefixes ?? [];\n const recursive = opts.recursive ?? false;\n\n const out: IndexEntry[] = [];\n await walk(rootDir, rootDir, recursive, skipFilenames, skipPrefixes, out);\n return out.sort((a, b) => a.relPath.localeCompare(b.relPath));\n}\n\nasync function walk(\n rootDir: string,\n currentDir: string,\n recursive: boolean,\n skipFilenames: ReadonlySet<string>,\n skipPrefixes: readonly string[],\n out: IndexEntry[],\n): Promise<void> {\n let entries;\n try {\n entries = await readdir(currentDir, { withFileTypes: true });\n } catch (e) {\n if ((e as NodeJS.ErrnoException).code === \"ENOENT\") return;\n throw e;\n }\n\n for (const dirent of entries) {\n const name = dirent.name;\n if (dirent.isDirectory()) {\n if (!recursive) continue;\n if (name.startsWith(\".\") || name.startsWith(\"_\")) continue;\n await walk(\n rootDir,\n join(currentDir, name),\n recursive,\n skipFilenames,\n skipPrefixes,\n out,\n );\n continue;\n }\n if (!dirent.isFile()) continue;\n if (extname(name) !== \".md\") continue;\n if (skipFilenames.has(name)) continue;\n\n const nameNoExt = basename(name, \".md\");\n if (skipPrefixes.some((p) => nameNoExt.startsWith(p))) continue;\n\n const fullPath = join(currentDir, name);\n let info;\n try {\n info = await stat(fullPath);\n if (!info.isFile()) continue;\n } catch {\n continue;\n }\n const raw = await readFile(fullPath, \"utf8\");\n const { frontmatter, body } = parseFrontmatter<Record<string, unknown>>(raw);\n const title = extractTitle(body) ?? nameNoExt;\n const description = extractDescription(frontmatter, body);\n const type = stringField(frontmatter, \"type\");\n const updated =\n stringField(frontmatter, \"updated\") ?? stringField(frontmatter, \"created\");\n\n out.push({\n relPath: relative(rootDir, fullPath).split(/[\\\\/]/).join(\"/\"),\n name: nameNoExt,\n title,\n description,\n type,\n updated,\n });\n }\n}\n\nfunction extractTitle(body: string): string | undefined {\n const m = body.match(H1_PATTERN);\n if (!m) return undefined;\n return m[1]?.trim();\n}\n\nfunction extractDescription(\n frontmatter: Record<string, unknown>,\n body: string,\n): string | undefined {\n const fm = stringField(frontmatter, \"description\");\n if (fm) return fm;\n // First non-empty, non-heading, non-blockquote paragraph.\n const lines = body.split(/\\r?\\n/);\n for (const line of lines) {\n const trimmed = line.trim();\n if (!trimmed) continue;\n if (trimmed.startsWith(\"#\")) continue;\n if (trimmed.startsWith(\">\")) continue;\n if (trimmed.startsWith(\"-\") || trimmed.startsWith(\"*\")) continue;\n return trimmed.length > 160 ? `${trimmed.slice(0, 157)}...` : trimmed;\n }\n return undefined;\n}\n\nfunction stringField(\n obj: Record<string, unknown>,\n key: string,\n): string | undefined {\n const v = obj[key];\n return typeof v === \"string\" && v.length > 0 ? v : undefined;\n}\n","import type { RenderIndexInput } from \"./types.js\";\n\n/**\n * Render an `_INDEX.md` body from a {@link RenderIndexInput}.\n *\n * Output shape:\n *\n * ---\n * type: index\n * status: active\n * privacy: <privacy>\n * updated: <updated>\n * tags: [index, <extraTags...>]\n * ---\n *\n * # <title>\n *\n * > <description>\n *\n * ## 항목 (<count>)\n *\n * | 파일 | 설명 | 갱신 |\n * |---|---|---|\n * | [[<name>]] | <description or title> | <updated> |\n * ...\n *\n * ## 관련 (only if `related` is non-empty)\n *\n * - [[<related[0]>]]\n * ...\n *\n * Caller is responsible for writing this body to disk. The renderer never\n * touches the filesystem.\n */\nexport function renderIndex(input: RenderIndexInput): string {\n const updated = input.updated ?? today();\n const privacy = input.privacy ?? \"internal\";\n const tags = [\"index\", ...(input.extraTags ?? [])];\n const tagsLine = tags.map((t) => `\"${t}\"`).join(\", \");\n\n const lines: string[] = [\n \"---\",\n \"type: index\",\n \"status: active\",\n `privacy: ${privacy}`,\n `updated: ${updated}`,\n `tags: [${tagsLine}]`,\n \"---\",\n \"\",\n `# ${input.title}`,\n \"\",\n ];\n\n if (input.description && input.description.length > 0) {\n lines.push(`> ${input.description}`, \"\");\n }\n\n lines.push(`## 항목 (${input.entries.length})`, \"\");\n\n if (input.entries.length === 0) {\n lines.push(\"(비어 있음)\", \"\");\n } else {\n lines.push(\"| 파일 | 설명 | 갱신 |\", \"|---|---|---|\");\n for (const e of input.entries) {\n const desc = sanitizeCell(e.description ?? e.title);\n const upd = e.updated ?? \"—\";\n lines.push(`| [[${e.name}]] | ${desc} | ${upd} |`);\n }\n lines.push(\"\");\n }\n\n if (input.related && input.related.length > 0) {\n lines.push(\"## 관련\", \"\");\n for (const r of input.related) {\n lines.push(`- [[${r}]]`);\n }\n lines.push(\"\");\n }\n\n return lines.join(\"\\n\");\n}\n\nfunction sanitizeCell(s: string): string {\n // Markdown tables: pipe must be escaped, newlines collapse to spaces.\n return s.replace(/\\|/g, \"\\\\|\").replace(/\\r?\\n/g, \" \").trim();\n}\n\nfunction today(): string {\n const d = new Date();\n const y = d.getFullYear();\n const m = String(d.getMonth() + 1).padStart(2, \"0\");\n const day = String(d.getDate()).padStart(2, \"0\");\n return `${y}-${m}-${day}`;\n}\n","import { readdir, stat } from \"node:fs/promises\";\nimport { extname, join } from \"node:path\";\n\n/**\n * Walk a directory tree and return every subdirectory that contains at\n * least `minEntries` markdown files at its top level. The root directory\n * itself is included if it qualifies.\n *\n * \"At its top level\" means `.md` files **directly inside** the directory\n * (not in its subdirectories) — this is what an `_INDEX.md` in that\n * directory would index.\n *\n * `README.md` and `_INDEX.md` files are not counted (they are not\n * indexable entries). `.md` files starting with prefixes in `skipPrefixes`\n * are also not counted.\n *\n * Hidden directories (`.foo`) are not descended into. `_foo` directories\n * are descended into — they may legitimately contain content\n * (`_HUB-*.md`, `_INDEX.md` of subdirectories).\n *\n * A missing root directory returns an empty list rather than throwing.\n *\n * Use case — splitting a giant flat `_INDEX.md` into per-folder\n * indexes: scan a tree, find the meaningful directories, write an\n * `_INDEX.md` in each.\n */\nexport async function findIndexableDirs(\n rootDir: string,\n options: {\n minEntries?: number;\n skipPrefixes?: readonly string[];\n } = {},\n): Promise<readonly string[]> {\n const minEntries = options.minEntries ?? 1;\n const skipPrefixes = options.skipPrefixes ?? [];\n const out: string[] = [];\n await walk(rootDir, minEntries, skipPrefixes, out);\n return out;\n}\n\nasync function walk(\n dir: string,\n minEntries: number,\n skipPrefixes: readonly string[],\n out: string[],\n): Promise<void> {\n let entries;\n try {\n entries = await readdir(dir, { withFileTypes: true });\n } catch (e) {\n if ((e as NodeJS.ErrnoException).code === \"ENOENT\") return;\n throw e;\n }\n\n let mdCount = 0;\n const subdirs: string[] = [];\n for (const dirent of entries) {\n if (dirent.isDirectory()) {\n if (dirent.name.startsWith(\".\")) continue;\n subdirs.push(dirent.name);\n continue;\n }\n if (!dirent.isFile()) continue;\n if (extname(dirent.name) !== \".md\") continue;\n if (dirent.name === \"README.md\" || dirent.name === \"_INDEX.md\") continue;\n const nameNoExt = dirent.name.slice(0, -3);\n if (skipPrefixes.some((p) => nameNoExt.startsWith(p))) continue;\n // Confirm it's a regular file (not a symlink to a directory, etc.).\n try {\n const info = await stat(join(dir, dirent.name));\n if (!info.isFile()) continue;\n } catch {\n continue;\n }\n mdCount++;\n }\n\n if (mdCount >= minEntries) {\n out.push(dir);\n }\n\n for (const name of subdirs) {\n await walk(join(dir, name), minEntries, skipPrefixes, out);\n }\n}\n","export type {\n RunbookEntry,\n RunbookFilter,\n RunbookFrontmatter,\n} from \"./types.js\";\nexport { RunbookStore } from \"./store.js\";\n","import { readdir, readFile, stat } from \"node:fs/promises\";\nimport { extname, join } from \"node:path\";\nimport { parseFrontmatter } from \"@vortex-os/core\";\nimport type {\n RunbookEntry,\n RunbookFilter,\n RunbookFrontmatter,\n} from \"./types.js\";\n\nconst RESERVED_FILES: ReadonlySet<string> = new Set([\"README.md\", \"_INDEX.md\"]);\n\n/**\n * Directory-backed runbook store. Expected layout is flat —\n * `<rootDir>/<slug>.md`, no subdirectories.\n *\n * Non-entry files at the root (README, _INDEX, anything not ending in `.md`)\n * are silently ignored. A missing root directory returns an empty list\n * rather than throwing.\n */\nexport class RunbookStore {\n constructor(readonly rootDir: string) {}\n\n /** All entries, sorted by slug ascending. */\n async list(): Promise<readonly RunbookEntry[]> {\n let names: string[];\n try {\n names = await readdir(this.rootDir);\n } catch (e) {\n if ((e as NodeJS.ErrnoException).code === \"ENOENT\") return [];\n throw e;\n }\n const out: RunbookEntry[] = [];\n for (const name of names) {\n if (extname(name) !== \".md\") continue;\n if (RESERVED_FILES.has(name)) continue;\n const path = join(this.rootDir, name);\n try {\n const info = await stat(path);\n if (!info.isFile()) continue;\n } catch {\n continue;\n }\n const raw = await readFile(path, \"utf8\");\n const { frontmatter, body } =\n parseFrontmatter<RunbookFrontmatter>(raw);\n const slug = name.slice(0, -3);\n out.push({ slug, path, frontmatter, body });\n }\n return out.sort((a, b) => a.slug.localeCompare(b.slug));\n }\n\n /** A single entry by slug, or undefined if not found. */\n async get(slug: string): Promise<RunbookEntry | undefined> {\n const all = await this.list();\n return all.find((e) => e.slug === slug);\n }\n\n /**\n * Subset of entries matching the given criteria. Empty/undefined fields\n * are ignored. Returns entries in the same order as {@link list}.\n */\n async filter(criteria: RunbookFilter): Promise<readonly RunbookEntry[]> {\n const all = await this.list();\n return all.filter((e) => {\n if (criteria.status !== undefined && e.frontmatter.status !== criteria.status) {\n return false;\n }\n if (criteria.tag !== undefined) {\n const tags = e.frontmatter.tags ?? [];\n if (!tags.includes(criteria.tag)) return false;\n }\n if (\n criteria.incidentType !== undefined &&\n e.frontmatter[\"incident-type\"] !== criteria.incidentType\n ) {\n return false;\n }\n return true;\n });\n }\n\n /**\n * Entries whose `last_tested` is older than `staleAfterDays` from the\n * given reference date (default: today). Entries without a `last_tested`\n * field are treated as \"never tested\" and are always returned.\n *\n * This is the practical reason runbooks are a module rather than plain\n * data — periodic reverification is a real operational need.\n */\n async getStaleByLastTested(\n staleAfterDays: number,\n referenceDate?: Date,\n ): Promise<readonly RunbookEntry[]> {\n if (!Number.isFinite(staleAfterDays) || staleAfterDays < 0) {\n throw new Error(`Invalid staleAfterDays: ${staleAfterDays}`);\n }\n const now = referenceDate ?? new Date();\n const threshold = now.getTime() - staleAfterDays * 86_400_000;\n const all = await this.list();\n return all.filter((e) => {\n const lt = e.frontmatter.last_tested;\n if (!lt) return true;\n const parsed = parseIsoDate(lt);\n if (parsed === undefined) return true;\n return parsed < threshold;\n });\n }\n}\n\nfunction parseIsoDate(s: string): number | undefined {\n if (!/^\\d{4}-\\d{2}-\\d{2}$/.test(s)) return undefined;\n const t = Date.parse(`${s}T00:00:00Z`);\n return Number.isNaN(t) ? undefined : t;\n}\n","export type {\n BrokenLink,\n LinkCheckResult,\n WikiLink,\n} from \"./types.js\";\nexport { extractWikiLinks } from \"./extract.js\";\nexport {\n buildFileIndex,\n resolveLink,\n toRel,\n} from \"./resolve.js\";\nexport type {\n BuildIndexOptions,\n FileIndex,\n ResolveOpts,\n ResolveOutcome,\n} from \"./resolve.js\";\nexport { checkDirectory, topBrokenTargets } from \"./checker.js\";\nexport type { CheckDirectoryOptions } from \"./checker.js\";\nexport { rewriteBody, rewriteDirectory } from \"./rewrite.js\";\nexport type {\n FileRewrite,\n RedirectionMap,\n RewriteOptions,\n RewriteResult,\n} from \"./rewrite.js\";\n","import type { WikiLink } from \"./types.js\";\n\n/**\n * Match a single wiki link including optional anchor and alias.\n *\n * `[[name]]` / `[[name|alias]]` / `[[name#anchor]]` / `[[name#anchor|alias]]`\n *\n * The name part disallows `|`, `#`, and `]` so the components separate\n * cleanly even when several links appear on one line.\n */\nconst WIKI_LINK_PATTERN = /\\[\\[([^\\]|#\\n]+?)(?:#([^\\]|\\n]+?))?(?:\\|([^\\]\\n]+?))?\\]\\]/g;\n\n/**\n * Extract every wiki link from a markdown body. Returns links in\n * document order; duplicates are preserved (callers can dedupe if they\n * want, but a broken link in two places is still two repairs).\n *\n * Code fences and inline code spans are not stripped — this module\n * treats markdown as text. Hosts that need to ignore links inside\n * code blocks should pre-filter the body.\n */\nexport function extractWikiLinks(body: string): readonly WikiLink[] {\n const out: WikiLink[] = [];\n for (const match of body.matchAll(WIKI_LINK_PATTERN)) {\n const name = match[1]?.trim();\n if (!name) continue;\n const anchor = match[2]?.trim();\n const alias = match[3]?.trim();\n out.push({\n name,\n anchor: anchor || undefined,\n alias: alias || undefined,\n raw: match[0],\n });\n }\n return out;\n}\n","import { readdir, stat } from \"node:fs/promises\";\nimport {\n basename,\n dirname,\n extname,\n isAbsolute,\n join,\n relative,\n resolve as pathResolve,\n} from \"node:path\";\n\n/**\n * Filesystem index of every `.md` file under a root.\n *\n * Provides two lookup paths:\n *\n * - `byBasename` — `name` (no `.md`) → list of absolute paths. Used for\n * bare wiki links like `[[Foo]]`, which Obsidian resolves by filename\n * anywhere in the vault.\n * - `byRelPath` — forward-slash relative path (no `.md`) → absolute path.\n * Used for path-aware wiki links like `[[Projects/Home/Foo]]` or\n * `[[../Foo]]`, where the operator wrote a path on purpose to\n * disambiguate.\n *\n * `rootDir` is retained so resolvers can interpret root-relative paths.\n */\nexport interface FileIndex {\n readonly byBasename: ReadonlyMap<string, readonly string[]>;\n readonly byRelPath: ReadonlyMap<string, string>;\n /**\n * Optional lowercase rel-path → absolute-path map for case-insensitive\n * fallback. Present only when {@link buildFileIndex} was called with\n * `caseInsensitive: true`. If two rel-paths collide after lowercasing,\n * the first walker-visited path wins; the conflict is silent (rare in\n * a well-organized tree).\n */\n readonly byRelPathLower?: ReadonlyMap<string, string>;\n readonly rootDir: string;\n}\n\n/**\n * Options for {@link buildFileIndex}.\n */\nexport interface BuildIndexOptions {\n /**\n * Build an additional lowercase `byRelPathLower` map so {@link resolveLink}\n * can fall back to case-insensitive matching when the exact-case path\n * lookup fails. Useful when the operator's wiki-link convention uses\n * different casing than the on-disk layout (a frequent situation when\n * content is migrated from one vault into another with renamed roots,\n * e.g. `[[Projects/Home/foo]]` vs `data/projects/home/foo.md`).\n *\n * Default: false. Bare-name lookup is unaffected — Obsidian historically\n * treats bare names case-sensitively, and we keep that.\n */\n caseInsensitive?: boolean;\n /**\n * Extra file extensions (besides `.md`) to include in the index. Each\n * extension must include the leading dot, e.g. `[\".hwp\", \".docx\", \".pdf\"]`.\n *\n * `.md` files are always indexed with the extension stripped from their\n * key — `[[Foo]]` matches `Foo.md`. Files with one of the additional\n * extensions are indexed with the extension *kept*, so they only match\n * when the operator writes the full filename — `[[Foo.hwp]]` matches\n * `Foo.hwp`. This avoids surprise collisions where `[[Foo]]` would\n * suddenly match a non-markdown file.\n *\n * Default: `[]` (only `.md` is indexed; preserves v1 behavior).\n *\n * Note: only `.md` files are scanned for wiki links by\n * {@link import(\"./checker.js\").checkDirectory} and rewritten by\n * {@link import(\"./rewrite.js\").rewriteDirectory}. Additional extensions\n * affect *resolution targets* (what a wiki link can point at), not\n * *scan sources* (what a wiki link can appear in).\n */\n additionalExtensions?: readonly string[];\n}\n\n/**\n * Walk `rootDir` recursively and build a {@link FileIndex} of every `.md`\n * file (plus any `additionalExtensions` requested).\n *\n * Hidden directories (`.foo`) are skipped. `_foo` directories ARE indexed —\n * Obsidian wiki links can target any markdown file regardless of underscore\n * prefix, so we mirror that. A missing root returns an empty index.\n */\nexport async function buildFileIndex(\n rootDir: string,\n options: BuildIndexOptions = {},\n): Promise<FileIndex> {\n const byBasename = new Map<string, string[]>();\n const byRelPath = new Map<string, string>();\n const additional = new Set(options.additionalExtensions ?? []);\n await walk(rootDir, rootDir, byBasename, byRelPath, additional);\n if (options.caseInsensitive) {\n const byRelPathLower = new Map<string, string>();\n for (const [rel, abs] of byRelPath) {\n const lower = rel.toLowerCase();\n if (!byRelPathLower.has(lower)) byRelPathLower.set(lower, abs);\n }\n return { byBasename, byRelPath, byRelPathLower, rootDir };\n }\n return { byBasename, byRelPath, rootDir };\n}\n\nasync function walk(\n rootDir: string,\n dir: string,\n byBasename: Map<string, string[]>,\n byRelPath: Map<string, string>,\n additionalExts: ReadonlySet<string>,\n): Promise<void> {\n let entries;\n try {\n entries = await readdir(dir, { withFileTypes: true });\n } catch (e) {\n if ((e as NodeJS.ErrnoException).code === \"ENOENT\") return;\n throw e;\n }\n for (const dirent of entries) {\n const name = dirent.name;\n if (dirent.isDirectory()) {\n if (name.startsWith(\".\")) continue;\n await walk(rootDir, join(dir, name), byBasename, byRelPath, additionalExts);\n continue;\n }\n if (!dirent.isFile()) continue;\n const ext = extname(name);\n const isMd = ext === \".md\";\n if (!isMd && !additionalExts.has(ext)) continue;\n const path = join(dir, name);\n try {\n const info = await stat(path);\n if (!info.isFile()) continue;\n } catch {\n continue;\n }\n // `.md` strips its extension from keys; non-md files keep it so a\n // bare `[[Foo]]` cannot accidentally resolve to `Foo.hwp`.\n const key = isMd ? basename(name, \".md\") : name;\n const list = byBasename.get(key);\n if (list) {\n list.push(path);\n } else {\n byBasename.set(key, [path]);\n }\n const relRaw = relative(rootDir, path).split(/[\\\\/]/).join(\"/\");\n const rel = isMd ? relRaw.replace(/\\.md$/, \"\") : relRaw;\n byRelPath.set(rel, path);\n }\n}\n\n/**\n * Resolution outcome for a single wiki link.\n *\n * - `unique`: one and only one file matched.\n * - `not-found`: no file matched.\n * - `ambiguous`: multiple files share the basename (only possible for\n * bare-name links; path-aware links always resolve uniquely or fail).\n */\nexport type ResolveOutcome =\n | { kind: \"unique\"; path: string }\n | { kind: \"not-found\" }\n | { kind: \"ambiguous\"; candidates: readonly string[] };\n\n/**\n * Optional hints that turn on path-aware resolution.\n *\n * - `sourcePath` — absolute path of the file the link was found in.\n * Required to resolve `../foo`-style relative links.\n *\n * When neither hint is set, behavior collapses to bare-name lookup\n * (basename only), matching the original v1 semantics.\n */\nexport interface ResolveOpts {\n sourcePath?: string;\n}\n\n/**\n * Look up a wiki link in the index. Three cases:\n *\n * 1. **Bare name** (`[[Foo]]`) — basename lookup only. Returns `unique`\n * if exactly one `Foo.md` exists, `ambiguous` if multiple, `not-found`\n * otherwise.\n * 2. **Root-relative path** (`[[Projects/Foo]]`) — exact rel-path lookup\n * against the index. Always `unique` or `not-found`.\n * 3. **Source-relative path** (`[[../Foo]]`, `[[./Foo]]`) — resolved\n * against `dirname(sourcePath)` first, then looked up by rel-path.\n * Requires `opts.sourcePath`; without it, returns `not-found`.\n *\n * Trailing `.md` in the link name is stripped before matching.\n */\nexport function resolveLink(\n name: string,\n index: FileIndex,\n opts: ResolveOpts = {},\n): ResolveOutcome {\n // Strip any explicit .md extension the operator may have typed.\n const stripped = name.replace(/\\.md$/u, \"\");\n\n if (!stripped.includes(\"/\") && !stripped.includes(\"\\\\\")) {\n // Case 1: bare name → basename lookup.\n const list = index.byBasename.get(stripped);\n if (!list || list.length === 0) return { kind: \"not-found\" };\n if (list.length === 1) return { kind: \"unique\", path: list[0]! };\n return { kind: \"ambiguous\", candidates: list };\n }\n\n const normalized = stripped.replace(/\\\\/g, \"/\");\n\n if (normalized.startsWith(\"../\") || normalized.startsWith(\"./\")) {\n // Case 3: source-relative path. Need a base to resolve from.\n if (!opts.sourcePath) return { kind: \"not-found\" };\n const baseDir = dirname(opts.sourcePath);\n const absolute = pathResolve(baseDir, normalized);\n const rel = relative(index.rootDir, absolute)\n .split(/[\\\\/]/)\n .join(\"/\");\n // Guard: if the relative path climbs above rootDir, the link cannot\n // resolve within this index.\n if (rel.startsWith(\"..\") || isAbsolute(rel)) {\n return { kind: \"not-found\" };\n }\n return lookupRelPath(rel, index);\n }\n\n // Case 2: root-relative path.\n return lookupRelPath(normalized, index);\n}\n\n/**\n * Look up a rel-path with optional case-insensitive fallback.\n */\nfunction lookupRelPath(rel: string, index: FileIndex): ResolveOutcome {\n const exact = index.byRelPath.get(rel);\n if (exact) return { kind: \"unique\", path: exact };\n if (index.byRelPathLower) {\n const fallback = index.byRelPathLower.get(rel.toLowerCase());\n if (fallback) return { kind: \"unique\", path: fallback };\n }\n return { kind: \"not-found\" };\n}\n\n/**\n * Reduce an absolute path to one relative to `rootDir`, using forward\n * slashes. Useful for reporting.\n */\nexport function toRel(path: string, rootDir: string): string {\n return relative(rootDir, path).split(/[\\\\/]/).join(\"/\");\n}\n","import { readFile } from \"node:fs/promises\";\nimport { extname } from \"node:path\";\nimport { parseFrontmatter } from \"@vortex-os/core\";\nimport { extractWikiLinks } from \"./extract.js\";\nimport { buildFileIndex, resolveLink } from \"./resolve.js\";\nimport type { BuildIndexOptions } from \"./resolve.js\";\nimport type { BrokenLink, LinkCheckResult } from \"./types.js\";\n\n/**\n * Options for {@link checkDirectory}.\n */\nexport interface CheckDirectoryOptions extends BuildIndexOptions {}\n\n/**\n * Scan every `.md` file under `rootDir`, extract wiki links, and\n * report which ones cannot be resolved (or resolve to multiple files).\n *\n * This is read-only — it does not modify any file. The function returns\n * a structured result so hosts can decide whether to log, fail a build,\n * propose rewrites, etc.\n *\n * Pass `caseInsensitive: true` when wiki-link casing may differ from\n * the on-disk path (e.g. content migrated from a vault with different\n * directory naming conventions).\n */\nexport async function checkDirectory(\n rootDir: string,\n options: CheckDirectoryOptions = {},\n): Promise<LinkCheckResult> {\n const index = await buildFileIndex(rootDir, options);\n const broken: BrokenLink[] = [];\n const ambiguous: BrokenLink[] = [];\n\n let filesScanned = 0;\n let totalLinks = 0;\n let resolved = 0;\n\n for (const paths of index.byBasename.values()) {\n for (const path of paths) {\n // Only markdown files carry wiki-link text. Non-md entries in the\n // index (when `additionalExtensions` is set) are resolution targets,\n // not scan sources.\n if (extname(path) !== \".md\") continue;\n filesScanned++;\n const raw = await readFile(path, \"utf8\");\n const { body } = parseFrontmatter(raw);\n const links = extractWikiLinks(body);\n totalLinks += links.length;\n for (const link of links) {\n const outcome = resolveLink(link.name, index, { sourcePath: path });\n if (outcome.kind === \"unique\") {\n resolved++;\n } else if (outcome.kind === \"not-found\") {\n broken.push({ sourcePath: path, link, reason: \"not-found\" });\n } else {\n ambiguous.push({\n sourcePath: path,\n link,\n reason: \"ambiguous\",\n candidates: outcome.candidates,\n });\n }\n }\n }\n }\n\n return { filesScanned, totalLinks, resolved, broken, ambiguous };\n}\n\n/**\n * Group broken links by target name and return counts in descending order.\n * Useful for quickly identifying the most-cited missing pages.\n */\nexport function topBrokenTargets(\n broken: readonly BrokenLink[],\n limit = 20,\n): readonly { readonly name: string; readonly count: number }[] {\n const counts = new Map<string, number>();\n for (const b of broken) {\n counts.set(b.link.name, (counts.get(b.link.name) ?? 0) + 1);\n }\n return [...counts.entries()]\n .map(([name, count]) => ({ name, count }))\n .sort((a, b) => b.count - a.count || a.name.localeCompare(b.name))\n .slice(0, limit);\n}\n","import { readFile, writeFile } from \"node:fs/promises\";\nimport { extname } from \"node:path\";\nimport { extractWikiLinks } from \"./extract.js\";\nimport { buildFileIndex } from \"./resolve.js\";\n\n/**\n * Map of wiki-link names to replace.\n *\n * Both keys and values are the `name` portion of a wiki link — what\n * appears between `[[` and the optional `#anchor` / `|alias`. Anchors\n * and aliases on the original link are preserved automatically.\n *\n * Examples:\n * { \"API-Tokens\": \"secrets/api-tokens\" }\n * [[API-Tokens]] → [[secrets/api-tokens]]\n * [[API-Tokens|토큰]] → [[secrets/api-tokens|토큰]]\n * [[API-Tokens#A|토큰]] → [[secrets/api-tokens#A|토큰]]\n *\n * Use the exact name string the operator wrote — no normalization is\n * applied. If the same broken target appears with different spellings\n * (e.g. case differences), provide one entry per spelling.\n */\nexport type RedirectionMap = ReadonlyMap<string, string>;\n\n/**\n * Options for {@link rewriteDirectory}.\n */\nexport interface RewriteOptions {\n /**\n * The redirection map driving the rewrite. Links whose name is not\n * a key in this map are left untouched.\n */\n redirections: RedirectionMap;\n /**\n * When true, do not write any files. The result still describes the\n * rewrites that would happen — useful for showing the operator what\n * a redirection map will do before it does it.\n */\n dryRun?: boolean;\n}\n\n/**\n * Per-file detail of a rewrite operation.\n */\nexport interface FileRewrite {\n readonly sourcePath: string;\n readonly rewrites: readonly { readonly from: string; readonly to: string }[];\n}\n\n/**\n * Aggregate result of {@link rewriteDirectory}.\n */\nexport interface RewriteResult {\n readonly filesScanned: number;\n /** Files whose body was changed (or would be changed under dry-run). */\n readonly filesChanged: number;\n /** Total number of link replacements (may exceed `filesChanged`). */\n readonly rewritesApplied: number;\n /** Links matching a redirection key but ultimately not replaced — currently always 0; reserved for future skip reasons. */\n readonly skipped: number;\n readonly details: readonly FileRewrite[];\n readonly dryRun: boolean;\n}\n\n/**\n * Walk every `.md` file under `rootDir`, replace wiki links whose name\n * is a key in `redirections`, and write the changed files back to disk\n * (or describe what would change when `dryRun: true`).\n *\n * Only the link `name` is replaced. Anchors (`#Section`) and aliases\n * (`|display`) carry over verbatim onto the replacement link. The\n * surrounding markdown body is untouched.\n *\n * Rewriting is deterministic and order-independent — within a file,\n * every occurrence of every mapped key is replaced exactly once per\n * occurrence, with no chaining (the replacement is not re-scanned for\n * further matches).\n */\nexport async function rewriteDirectory(\n rootDir: string,\n opts: RewriteOptions,\n): Promise<RewriteResult> {\n const { redirections, dryRun = false } = opts;\n const index = await buildFileIndex(rootDir);\n\n let filesScanned = 0;\n let filesChanged = 0;\n let rewritesApplied = 0;\n const details: FileRewrite[] = [];\n\n for (const paths of index.byBasename.values()) {\n for (const path of paths) {\n // Only markdown files have rewritable wiki-link bodies. Non-md\n // entries in the index (when callers asked for `additionalExtensions`\n // upstream) are resolution targets, not rewrite sources.\n if (extname(path) !== \".md\") continue;\n filesScanned++;\n const raw = await readFile(path, \"utf8\");\n const { newBody, fileRewrites } = rewriteBody(raw, redirections);\n if (fileRewrites.length === 0) continue;\n filesChanged++;\n rewritesApplied += fileRewrites.length;\n details.push({ sourcePath: path, rewrites: fileRewrites });\n if (!dryRun) {\n await writeFile(path, newBody, \"utf8\");\n }\n }\n }\n\n return {\n filesScanned,\n filesChanged,\n rewritesApplied,\n skipped: 0,\n details,\n dryRun,\n };\n}\n\n/**\n * Pure transformation: take a markdown body, return the body with all\n * `[[…]]` links whose name appears in `redirections` rewritten. Exported\n * for testing and for callers that need to rewrite an in-memory string.\n *\n * The transformation does not touch markdown outside `[[…]]` patterns.\n */\nexport function rewriteBody(\n body: string,\n redirections: RedirectionMap,\n): { newBody: string; fileRewrites: { from: string; to: string }[] } {\n const fileRewrites: { from: string; to: string }[] = [];\n // Reconstruct each match piece-by-piece so we keep the same anchor/\n // alias the operator wrote.\n const links = extractWikiLinks(body);\n if (links.length === 0) return { newBody: body, fileRewrites };\n\n let out = \"\";\n let cursor = 0;\n\n // We need positional info: walk the body with the same regex used in\n // extract.ts so we know where each match starts and ends.\n const pattern = /\\[\\[([^\\]|#\\n]+?)(?:#([^\\]|\\n]+?))?(?:\\|([^\\]\\n]+?))?\\]\\]/g;\n let m: RegExpExecArray | null;\n while ((m = pattern.exec(body)) !== null) {\n const [whole, rawName, rawAnchor, rawAlias] = m;\n const name = (rawName ?? \"\").trim();\n const target = redirections.get(name);\n if (!target) continue;\n\n // Found a replacement. Emit everything up to this match unchanged…\n out += body.slice(cursor, m.index);\n // …then build the replacement preserving anchor and alias.\n let replacement = `[[${target}`;\n if (rawAnchor) replacement += `#${rawAnchor}`;\n if (rawAlias) replacement += `|${rawAlias}`;\n replacement += \"]]\";\n out += replacement;\n cursor = m.index + whole.length;\n fileRewrites.push({ from: whole, to: replacement });\n }\n\n // Tail: everything after the last replacement (or the whole body if\n // nothing matched).\n out += body.slice(cursor);\n return { newBody: out, fileRewrites };\n}\n","export type {\n AcceptResult,\n Proposal,\n ProposalAction,\n Proposer,\n ProposerContext,\n} from \"./proposer.js\";\n\nexport type { ExpectedShape, LLMJudge } from \"./llm-judge.js\";\n\nexport type { FingerprintInput } from \"./fingerprint.js\";\nexport { computeFingerprint } from \"./fingerprint.js\";\n\nexport type { DeclinedEntry, ProposalKind } from \"./decline-store.js\";\nexport {\n loadDeclinedFingerprints,\n recordAcceptance,\n recordDecline,\n resetDeclined,\n} from \"./decline-store.js\";\n\nexport type {\n InsightInput,\n InsightProposal,\n InsightProposerOptions,\n TopicTreeSnapshot,\n TurnRecord,\n} from \"./insight-proposer.js\";\nexport { InsightProposer } from \"./insight-proposer.js\";\n\nexport type {\n HubInput,\n HubProposal,\n HubProposerOptions,\n} from \"./hub-proposer.js\";\nexport { HubProposer } from \"./hub-proposer.js\";\n\nexport { AmbientBackpressure, TurnBuffer } from \"./ambient-tracker.js\";\n\nexport { AmbientRecaller, deriveQueryFromTurns } from \"./ambient-recaller.js\";\nexport type {\n AmbientRecallHit,\n AmbientRecallResult,\n AmbientRecallerOptions,\n RecallFn,\n RecallSuggestion,\n} from \"./ambient-recaller.js\";\n\n// Shared adapter base — host authors can build their own adapter from these\n// without subclassing (frame + parse + error family).\nexport type { InjectedInvoker } from \"./adapters/shared.js\";\nexport {\n InjectedLLMJudge,\n LLMJudgeError,\n frameForJudge,\n parseJudgeResponse,\n} from \"./adapters/shared.js\";\n\n// First-party host adapters (one per sessionArchive host).\nexport type { ClaudeCodeSubAgentInvoker } from \"./adapters/claude-code.js\";\nexport {\n ClaudeCodeLLMJudge,\n ClaudeCodeLLMJudgeError,\n} from \"./adapters/claude-code.js\";\nexport type { CodexCompletionInvoker } from \"./adapters/codex.js\";\nexport { CodexLLMJudge, CodexLLMJudgeError } from \"./adapters/codex.js\";\nexport type { GeminiMcpInvoker } from \"./adapters/gemini.js\";\nexport { GeminiLLMJudge, GeminiLLMJudgeError } from \"./adapters/gemini.js\";\nexport type { ClaudeDesktopInvoker } from \"./adapters/claude-desktop.js\";\nexport {\n ClaudeDesktopLLMJudge,\n ClaudeDesktopLLMJudgeError,\n} from \"./adapters/claude-desktop.js\";\n","import { createHash } from \"node:crypto\";\nimport type { ProposalAction } from \"./proposer.js\";\n\n/**\n * Input to {@link computeFingerprint}. Two shapes — one per surface — share\n * a single function so the decline store can carry both kinds of\n * fingerprints in the same lookup set.\n *\n * The action-aware fingerprint is the load-bearing design choice: declining\n * an `append-section` proposal for topic X does *not* prevent a later\n * `create-file` proposal for the same topic from surfacing. The LLM's\n * placement decision is part of the fingerprint, so a shifted decision is\n * a new proposal.\n */\nexport type FingerprintInput =\n | {\n readonly kind: \"capture-insight\";\n readonly turnIds: readonly string[];\n readonly topic: string;\n readonly actionKind: ProposalAction[\"kind\"];\n readonly targetPath: string;\n }\n | {\n readonly kind: \"create-hub\";\n readonly topic: string;\n readonly sourceDocs: readonly string[];\n readonly actionKind: ProposalAction[\"kind\"];\n readonly targetPath: string;\n };\n\n/**\n * Compute a stable 16-hex-char fingerprint for a proposal. Stable means:\n * identical logical input — regardless of source ordering of array fields or\n * path separator style — produces an identical fingerprint, so the decline\n * lookup is reliable across machines (work / home) and across path-separator\n * regimes (Windows backslash vs POSIX slash).\n *\n * SHA-256 truncated to 16 hex chars (64 bits) is enough collision resistance\n * for a per-instance decline set; the full hash adds storage with no\n * practical benefit at this scale.\n */\nexport function computeFingerprint(input: FingerprintInput): string {\n const normalized = normalizeForHash(input);\n return createHash(\"sha256\").update(normalized).digest(\"hex\").slice(0, 16);\n}\n\nfunction normalizeForHash(input: FingerprintInput): string {\n if (input.kind === \"capture-insight\") {\n return JSON.stringify({\n kind: \"capture-insight\",\n turnIds: [...input.turnIds].sort(),\n topic: normalizeTopic(input.topic),\n actionKind: input.actionKind,\n targetPath: normalizePath(input.targetPath),\n });\n }\n return JSON.stringify({\n kind: \"create-hub\",\n topic: normalizeTopic(input.topic),\n sourceDocs: [...input.sourceDocs].map(normalizePath).sort(),\n actionKind: input.actionKind,\n targetPath: normalizePath(input.targetPath),\n });\n}\n\nfunction normalizeTopic(t: string): string {\n return t.trim().toLowerCase();\n}\n\nfunction normalizePath(p: string): string {\n return p.replace(/\\\\/g, \"/\");\n}\n","import { existsSync } from \"node:fs\";\nimport { appendFile, mkdir, readFile, writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport type { ProposalAction } from \"./proposer.js\";\n\n/**\n * Persistence layer for declined and accepted proposals.\n *\n * Two artifacts live under `<cwd>/data/_proactive-curator/`:\n *\n * - `declined.json` — keyed by proposal kind + fingerprint. Entries expire\n * after a configurable number of days (default 30) so a one-time decline\n * does not silence the same topic forever. The expiry check happens both\n * at read time (filtered out of the active set) and at write time\n * (purged from disk).\n * - `accepted.log` — append-only JSON-lines audit trail. Informational\n * only — the actual file write is the proposal's `onAccept` side effect;\n * this lets the operator audit *what was accepted and when*.\n *\n * All operations are functional — no in-memory state — so a process can\n * call any function at any time without coordinating with previous calls.\n * Concurrent writes from the same process are rare in a slash-command\n * workflow; we accept last-write-wins.\n */\n\nconst STORE_DIR = \"data/_proactive-curator\";\nconst DECLINED_FILE = \"declined.json\";\nconst ACCEPTED_LOG = \"accepted.log\";\nconst DEFAULT_EXPIRY_DAYS = 30;\n\nexport type ProposalKind = \"capture-insight\" | \"create-hub\";\n\nexport interface DeclinedEntry {\n /** ISO-8601 timestamp of when the user declined. */\n readonly declinedAt: string;\n /** Topic slug at decline time (for the audit trail; not part of the fingerprint). */\n readonly topic: string;\n /** ISO-8601 timestamp after which this entry is eligible for re-evaluation. */\n readonly expiresAt: string;\n /** The action the user declined — `create-file`, `append-section`, etc. */\n readonly actionKind: ProposalAction[\"kind\"];\n /** Target path the declined action would have written/touched (data-relative). */\n readonly targetPath: string;\n /** Hub proposals only — the source-doc cluster that triggered this proposal. */\n readonly sourceDocs?: readonly string[];\n}\n\ninterface DeclinedFile {\n \"capture-insight\": Record<string, DeclinedEntry>;\n \"create-hub\": Record<string, DeclinedEntry>;\n}\n\n/**\n * Load the active (un-expired) declined fingerprints. The returned set is\n * what {@link ProposerContext.declinedFingerprints} carries during\n * `evaluate()` so the proposer can do its decline check without filesystem\n * access at evaluation time.\n *\n * Missing or corrupt store files return an empty set rather than throwing —\n * a first-run instance simply has nothing declined.\n */\nexport async function loadDeclinedFingerprints(\n cwd: string,\n now: Date,\n): Promise<ReadonlySet<string>> {\n const parsed = await readDeclinedFile(cwd);\n if (!parsed) return new Set();\n const active = new Set<string>();\n const nowMs = now.getTime();\n for (const kind of [\"capture-insight\", \"create-hub\"] as const) {\n const entries = parsed[kind] ?? {};\n for (const [fp, entry] of Object.entries(entries)) {\n if (isActive(entry, nowMs)) active.add(fp);\n }\n }\n return active;\n}\n\n/**\n * Persist a decline. Purges expired entries from disk in the same write so\n * the store does not grow unbounded.\n */\nexport async function recordDecline(\n cwd: string,\n args: {\n readonly kind: ProposalKind;\n readonly fingerprint: string;\n readonly topic: string;\n readonly actionKind: ProposalAction[\"kind\"];\n readonly targetPath: string;\n readonly sourceDocs?: readonly string[];\n readonly now: Date;\n readonly expiryDays?: number;\n },\n): Promise<void> {\n await ensureStoreDir(cwd);\n const existing = (await readDeclinedFile(cwd)) ?? emptyDeclinedFile();\n const expiryDays = args.expiryDays ?? DEFAULT_EXPIRY_DAYS;\n const expiresAt = new Date(\n args.now.getTime() + expiryDays * 24 * 60 * 60 * 1000,\n ).toISOString();\n\n const updated: DeclinedFile = {\n \"capture-insight\": purgeExpired(existing[\"capture-insight\"], args.now),\n \"create-hub\": purgeExpired(existing[\"create-hub\"], args.now),\n };\n const entry: DeclinedEntry = {\n declinedAt: args.now.toISOString(),\n topic: args.topic,\n expiresAt,\n actionKind: args.actionKind,\n targetPath: args.targetPath,\n ...(args.sourceDocs ? { sourceDocs: args.sourceDocs } : {}),\n };\n updated[args.kind] = { ...updated[args.kind], [args.fingerprint]: entry };\n\n await writeFile(\n join(cwd, STORE_DIR, DECLINED_FILE),\n JSON.stringify(updated, null, 2) + \"\\n\",\n \"utf8\",\n );\n}\n\n/**\n * Append an acceptance record to the audit trail. Newline-delimited JSON so\n * the file is grep-friendly and tail-friendly without a parser.\n */\nexport async function recordAcceptance(\n cwd: string,\n args: {\n readonly kind: ProposalKind;\n readonly fingerprint: string;\n readonly topic: string;\n readonly actionKind: ProposalAction[\"kind\"];\n readonly writtenPath: string;\n readonly now: Date;\n },\n): Promise<void> {\n await ensureStoreDir(cwd);\n const line = JSON.stringify({\n acceptedAt: args.now.toISOString(),\n kind: args.kind,\n fingerprint: args.fingerprint,\n topic: args.topic,\n actionKind: args.actionKind,\n writtenPath: args.writtenPath,\n });\n await appendFile(join(cwd, STORE_DIR, ACCEPTED_LOG), line + \"\\n\", \"utf8\");\n}\n\n/**\n * Clear declined entries. Optional `kind` argument scopes the reset to\n * just one surface. Called by `/curate --reset-declined` (sub-phase c).\n * Missing store file is a no-op — nothing to reset.\n */\nexport async function resetDeclined(\n cwd: string,\n kind?: ProposalKind,\n): Promise<void> {\n const file = join(cwd, STORE_DIR, DECLINED_FILE);\n if (!existsSync(file)) return;\n if (kind === undefined) {\n await writeFile(file, JSON.stringify(emptyDeclinedFile(), null, 2) + \"\\n\", \"utf8\");\n return;\n }\n const parsed = (await readDeclinedFile(cwd)) ?? emptyDeclinedFile();\n parsed[kind] = {};\n await writeFile(file, JSON.stringify(parsed, null, 2) + \"\\n\", \"utf8\");\n}\n\nfunction isActive(entry: DeclinedEntry, nowMs: number): boolean {\n const expiresMs = new Date(entry.expiresAt).getTime();\n return Number.isFinite(expiresMs) && expiresMs > nowMs;\n}\n\nfunction purgeExpired(\n entries: Record<string, DeclinedEntry> | undefined,\n now: Date,\n): Record<string, DeclinedEntry> {\n if (!entries) return {};\n const out: Record<string, DeclinedEntry> = {};\n const nowMs = now.getTime();\n for (const [fp, entry] of Object.entries(entries)) {\n if (isActive(entry, nowMs)) out[fp] = entry;\n }\n return out;\n}\n\nasync function readDeclinedFile(cwd: string): Promise<DeclinedFile | null> {\n const file = join(cwd, STORE_DIR, DECLINED_FILE);\n if (!existsSync(file)) return null;\n try {\n const raw = await readFile(file, \"utf8\");\n const parsed = JSON.parse(raw) as Partial<DeclinedFile>;\n return {\n \"capture-insight\": parsed[\"capture-insight\"] ?? {},\n \"create-hub\": parsed[\"create-hub\"] ?? {},\n };\n } catch {\n return null;\n }\n}\n\nfunction emptyDeclinedFile(): DeclinedFile {\n return { \"capture-insight\": {}, \"create-hub\": {} };\n}\n\nasync function ensureStoreDir(cwd: string): Promise<void> {\n await mkdir(join(cwd, STORE_DIR), { recursive: true });\n}\n","import { existsSync } from \"node:fs\";\nimport { appendFile, mkdir, readFile, readdir, writeFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport { parseFrontmatter } from \"@vortex-os/core\";\nimport {\n type DeclinedEntry,\n recordAcceptance,\n recordDecline,\n} from \"./decline-store.js\";\nimport { computeFingerprint } from \"./fingerprint.js\";\nimport type { ExpectedShape, LLMJudge } from \"./llm-judge.js\";\nimport type {\n AcceptResult,\n Proposal,\n ProposalAction,\n Proposer,\n ProposerContext,\n} from \"./proposer.js\";\n\n/**\n * In-session insight capture surface.\n *\n * Trigger logic (6 steps — design.md `Surface ①` for the full rationale):\n *\n * 1. **Token-count safety net.** Below `minTokensAccumulated`, return null.\n * 2. **LLM capture decision.** Ask the LLM whether the recent turns contain\n * a worth-capturing insight; if yes, get a 3-5 sentence summary plus a\n * 1-3 word topic.\n * 3. **Topic-tree scan.** Walk `data/` excluding reserved system-meta\n * directories. The result feeds the next LLM call as the placement\n * context — *which existing topic folders does this insight relate to,\n * and which files already discuss the topic?*\n * 4. **LLM placement decision.** With the summary, topic, and tree\n * snapshot in hand, ask the LLM to pick one of four actions:\n * `create-folder`, `create-file`, `append-section`, `update-file`.\n * Preference order is wired into the prompt — extend before create.\n * 5. **Decline check.** Fingerprint the proposal (turn IDs + topic +\n * action kind + target path) and short-circuit if the fingerprint is\n * in the decline set.\n * 6. **Emit.** Return a `Proposal` whose `onAccept` applies the action\n * and whose `onDecline` records the decline.\n *\n * `evaluate()` makes two LLM round-trips for a successful proposal and\n * exactly one for a *\"no, nothing to capture right now\"* outcome. The\n * second call is skipped when the first says no, which is the common case.\n */\n\nconst SYSTEM_META_DIRS = new Set([\n \"worklog\",\n \"decision-log\",\n \"runbooks\",\n \"hubs\",\n \"_memory\",\n \"_templates\",\n \"_proactive-curator\",\n]);\n\nexport interface InsightProposerOptions {\n /** Below this token count the proposer never asks the LLM. */\n readonly minTokensAccumulated: number;\n /** Below this turn count the proposer never asks the LLM. */\n readonly minTurnsBeforeFirstCheck: number;\n /**\n * Cap on how many topic folders to surface to the placement LLM call.\n * Large instance trees will exceed any practical LLM context budget;\n * truncation keeps the call tractable. Default 100.\n */\n readonly maxTreeEntries?: number;\n /** Days after which a decline becomes eligible for re-evaluation. */\n readonly declineExpiryDays?: number;\n}\n\nexport interface TurnRecord {\n readonly turnId: string;\n readonly role: \"user\" | \"assistant\" | \"system\";\n readonly content: string;\n}\n\nexport interface InsightInput {\n readonly recentTurns: readonly TurnRecord[];\n readonly accumulatedTokens: number;\n}\n\nexport interface InsightProposal extends Proposal {\n readonly kind: \"capture-insight\";\n}\n\ninterface CaptureDecision {\n readonly verdict: \"yes\" | \"no\";\n readonly summary?: string;\n readonly topic?: string;\n}\n\ninterface PlacementDecision {\n readonly actionKind: ProposalAction[\"kind\"];\n readonly rationale: string;\n readonly folderPath?: string;\n readonly filename?: string;\n readonly filePath?: string;\n readonly sectionHeader?: string;\n readonly reason?: string;\n}\n\ninterface TopicFile {\n readonly path: string;\n readonly filename: string;\n readonly frontmatterTopic?: string;\n readonly tags?: readonly string[];\n}\n\ninterface TopicFolderSnapshot {\n readonly path: string;\n readonly files: readonly TopicFile[];\n}\n\nexport interface TopicTreeSnapshot {\n readonly folders: readonly TopicFolderSnapshot[];\n /** True when the scan was truncated by `maxTreeEntries`. */\n readonly truncated: boolean;\n}\n\nexport class InsightProposer implements Proposer<InsightInput, InsightProposal> {\n readonly kind = \"capture-insight\";\n\n constructor(private readonly options: InsightProposerOptions) {}\n\n async evaluate(\n input: InsightInput,\n ctx: ProposerContext,\n ): Promise<InsightProposal | null> {\n if (input.accumulatedTokens < this.options.minTokensAccumulated) return null;\n if (input.recentTurns.length < this.options.minTurnsBeforeFirstCheck) return null;\n\n const capture = await askCaptureDecision(ctx.llm, input.recentTurns);\n if (capture.verdict === \"no\" || !capture.summary || !capture.topic) return null;\n\n const tree = await scanTopicTree(\n ctx.cwd,\n this.options.maxTreeEntries ?? 100,\n );\n\n const placement = await askPlacementDecision(\n ctx.llm,\n capture.summary,\n capture.topic,\n tree,\n );\n if (!placement) return null;\n\n const action = buildAction(\n placement,\n capture.summary,\n capture.topic,\n ctx.now,\n );\n if (!action) return null;\n\n const targetPath = targetPathFromAction(action);\n const fingerprint = computeFingerprint({\n kind: \"capture-insight\",\n turnIds: input.recentTurns.map((t) => t.turnId),\n topic: capture.topic,\n actionKind: action.kind,\n targetPath,\n });\n if (ctx.declinedFingerprints.has(fingerprint)) return null;\n\n const sourceRefs = input.recentTurns.map((t) => t.turnId);\n const declineExpiryDays = this.options.declineExpiryDays;\n\n return {\n kind: \"capture-insight\",\n fingerprint,\n action,\n preview: capture.summary,\n rationale: placement.rationale,\n sourceRefs,\n onAccept: async () => {\n const writtenPath = await applyAction(ctx.cwd, action);\n await recordAcceptance(ctx.cwd, {\n kind: \"capture-insight\",\n fingerprint,\n topic: capture.topic!,\n actionKind: action.kind,\n writtenPath,\n now: ctx.now,\n });\n return {\n writtenPath,\n actionApplied: action.kind,\n nextActionHint: nextActionHintFor(action),\n } satisfies AcceptResult;\n },\n onDecline: async () => {\n await recordDecline(ctx.cwd, {\n kind: \"capture-insight\",\n fingerprint,\n topic: capture.topic!,\n actionKind: action.kind,\n targetPath,\n now: ctx.now,\n ...(declineExpiryDays !== undefined ? { expiryDays: declineExpiryDays } : {}),\n });\n },\n };\n }\n}\n\nasync function askCaptureDecision(\n llm: LLMJudge,\n turns: readonly TurnRecord[],\n): Promise<CaptureDecision> {\n const prompt = renderCapturePrompt(turns);\n const expected: ExpectedShape = {\n shape: \"json\",\n schema: {\n verdict: \"yes|no\",\n summary: \"string (required when verdict=yes)\",\n topic: \"string (required when verdict=yes, 1-3 words)\",\n },\n };\n const raw = await llm.ask(prompt, expected);\n return normalizeCaptureDecision(raw);\n}\n\nfunction renderCapturePrompt(turns: readonly TurnRecord[]): string {\n const transcript = turns\n .map((t) => `[${t.role}] ${t.content}`)\n .join(\"\\n\\n\");\n return [\n \"You are reviewing a conversation snippet to decide whether anything in it deserves to be captured as a standalone note.\",\n \"\",\n \"Capture only if the recent turns produced an insight, decision, or piece of structured thought that would be lost if the session ended right now. Routine status updates, command output, or trivial back-and-forth do not qualify.\",\n \"\",\n \"Return JSON:\",\n ` { \"verdict\": \"yes\" | \"no\", \"summary\": \"3-5 sentences if verdict=yes\", \"topic\": \"1-3 words if verdict=yes\" }`,\n \"\",\n \"Recent turns:\",\n transcript,\n ].join(\"\\n\");\n}\n\nfunction normalizeCaptureDecision(raw: unknown): CaptureDecision {\n if (typeof raw !== \"object\" || raw === null) return { verdict: \"no\" };\n const obj = raw as Record<string, unknown>;\n if (obj.verdict !== \"yes\") return { verdict: \"no\" };\n const summary = typeof obj.summary === \"string\" ? obj.summary.trim() : \"\";\n const topic = typeof obj.topic === \"string\" ? obj.topic.trim() : \"\";\n if (!summary || !topic) return { verdict: \"no\" };\n return { verdict: \"yes\", summary, topic };\n}\n\nasync function askPlacementDecision(\n llm: LLMJudge,\n summary: string,\n topic: string,\n tree: TopicTreeSnapshot,\n): Promise<PlacementDecision | null> {\n const prompt = renderPlacementPrompt(summary, topic, tree);\n const expected: ExpectedShape = {\n shape: \"json\",\n schema: {\n actionKind: \"create-folder|create-file|append-section|update-file\",\n rationale: \"string (one line)\",\n folderPath: \"string (create-folder, create-file)\",\n filename: \"string (create-folder, create-file)\",\n filePath: \"string (append-section, update-file)\",\n sectionHeader: \"string (append-section)\",\n reason: \"string (update-file)\",\n },\n };\n const raw = await llm.ask(prompt, expected);\n return normalizePlacementDecision(raw);\n}\n\nfunction renderPlacementPrompt(\n summary: string,\n topic: string,\n tree: TopicTreeSnapshot,\n): string {\n const treeText = tree.folders.length === 0\n ? \"(no existing topic folders)\"\n : tree.folders\n .map((f) => {\n const fileLines = f.files\n .map((file) => ` - ${file.filename}${file.frontmatterTopic ? ` [topic: ${file.frontmatterTopic}]` : \"\"}`)\n .join(\"\\n\");\n return ` ${f.path}/\\n${fileLines}`;\n })\n .join(\"\\n\");\n const truncationNote = tree.truncated\n ? \"\\n\\n(Tree snapshot truncated — additional folders exist but are omitted for brevity.)\"\n : \"\";\n return [\n \"You are deciding where to place a captured insight in the user's existing topic tree.\",\n \"\",\n `Insight topic: ${topic}`,\n `Insight summary: ${summary}`,\n \"\",\n \"Existing topic tree (data-relative paths, system-meta dirs excluded):\",\n treeText + truncationNote,\n \"\",\n \"Pick one placement action. Preference order — extend existing structure before adding new:\",\n \" 1. append-section — an existing file is the right home; add a `## <sectionHeader>` section to it.\",\n \" 2. create-file — a topic folder exists; add a new sibling file alongside its current contents.\",\n \" 3. create-folder — the topic is genuinely new; create a folder and seed it with the first file.\",\n \" 4. update-file — an existing file needs in-place revision (rare; prefer append).\",\n \"\",\n \"Return JSON:\",\n ` { \"actionKind\": \"append-section\", \"rationale\": \"one line why\", \"filePath\": \"<data-relative path>\", \"sectionHeader\": \"<section title without leading ##>\" }`,\n ` { \"actionKind\": \"create-file\", \"rationale\": \"one line why\", \"folderPath\": \"<data-relative folder>\", \"filename\": \"<slug>.md\" }`,\n ` { \"actionKind\": \"create-folder\", \"rationale\": \"one line why\", \"folderPath\": \"<data-relative folder>\", \"filename\": \"<slug>.md\" }`,\n ` { \"actionKind\": \"update-file\", \"rationale\": \"one line why\", \"filePath\": \"<data-relative path>\", \"reason\": \"what needs revising\" }`,\n \"\",\n \"Paths must be relative to data/. Do not propose paths inside system-meta directories (worklog/, decision-log/, runbooks/, hubs/, _memory/, _templates/, _proactive-curator/, or any other _* directory).\",\n ].join(\"\\n\");\n}\n\nfunction normalizePlacementDecision(raw: unknown): PlacementDecision | null {\n if (typeof raw !== \"object\" || raw === null) return null;\n const obj = raw as Record<string, unknown>;\n const actionKind = String(obj.actionKind ?? \"\");\n const rationale = typeof obj.rationale === \"string\" ? obj.rationale.trim() : \"\";\n if (!rationale) return null;\n switch (actionKind) {\n case \"create-folder\":\n case \"create-file\": {\n const folderPath = typeof obj.folderPath === \"string\" ? obj.folderPath.trim() : \"\";\n const filename = typeof obj.filename === \"string\" ? obj.filename.trim() : \"\";\n if (!folderPath || !filename) return null;\n if (isSystemMetaPath(folderPath)) return null;\n return { actionKind: actionKind as \"create-folder\" | \"create-file\", rationale, folderPath, filename };\n }\n case \"append-section\": {\n const filePath = typeof obj.filePath === \"string\" ? obj.filePath.trim() : \"\";\n const sectionHeader = typeof obj.sectionHeader === \"string\" ? obj.sectionHeader.trim() : \"\";\n if (!filePath || !sectionHeader) return null;\n if (isSystemMetaPath(filePath)) return null;\n return { actionKind: \"append-section\", rationale, filePath, sectionHeader };\n }\n case \"update-file\": {\n const filePath = typeof obj.filePath === \"string\" ? obj.filePath.trim() : \"\";\n const reason = typeof obj.reason === \"string\" ? obj.reason.trim() : \"\";\n if (!filePath || !reason) return null;\n if (isSystemMetaPath(filePath)) return null;\n return { actionKind: \"update-file\", rationale, filePath, reason };\n }\n default:\n return null;\n }\n}\n\nfunction isSystemMetaPath(p: string): boolean {\n const normalized = p.replace(/\\\\/g, \"/\").replace(/^\\/+/, \"\");\n const first = normalized.split(\"/\")[0] ?? \"\";\n if (SYSTEM_META_DIRS.has(first)) return true;\n if (first.startsWith(\"_\")) return true;\n return false;\n}\n\nfunction buildAction(\n placement: PlacementDecision,\n summary: string,\n topic: string,\n now: Date,\n): ProposalAction | null {\n const body = renderCaptureBody(summary, topic, now);\n switch (placement.actionKind) {\n case \"create-folder\":\n case \"create-file\":\n if (!placement.folderPath || !placement.filename) return null;\n return {\n kind: placement.actionKind,\n folderPath: placement.folderPath,\n filename: placement.filename,\n body,\n };\n case \"append-section\":\n if (!placement.filePath || !placement.sectionHeader) return null;\n return {\n kind: \"append-section\",\n filePath: placement.filePath,\n sectionHeader: placement.sectionHeader,\n body: renderSectionBody(summary, now),\n };\n case \"update-file\":\n if (!placement.filePath || !placement.reason) return null;\n return {\n kind: \"update-file\",\n filePath: placement.filePath,\n body: renderUpdateBody(summary, topic, placement.reason, now),\n reason: placement.reason,\n };\n }\n}\n\nfunction renderCaptureBody(summary: string, topic: string, now: Date): string {\n const today = formatYmd(now);\n return `---\ntype: note\ntopic: ${topic}\ncreated: ${today}\nupdated: ${today}\ntags: [note, proactive-curator]\n---\n\n# ${topic}\n\n> Captured by proactive-curator on ${today}. The user accepted this proposal; edit freely.\n\n${summary}\n`;\n}\n\nfunction renderSectionBody(summary: string, now: Date): string {\n const ymd = formatYmd(now);\n return `\\n_Appended ${ymd} by proactive-curator._\\n\\n${summary}\\n`;\n}\n\nfunction renderUpdateBody(\n summary: string,\n topic: string,\n reason: string,\n now: Date,\n): string {\n const ymd = formatYmd(now);\n return `---\ntype: note\ntopic: ${topic}\nupdated: ${ymd}\n---\n\n# ${topic}\n\n> Updated ${ymd} by proactive-curator. Reason: ${reason}\n\n${summary}\n`;\n}\n\nfunction formatYmd(d: Date): string {\n const y = d.getFullYear();\n const m = String(d.getMonth() + 1).padStart(2, \"0\");\n const day = String(d.getDate()).padStart(2, \"0\");\n return `${y}-${m}-${day}`;\n}\n\nfunction targetPathFromAction(action: ProposalAction): string {\n if (action.kind === \"create-folder\" || action.kind === \"create-file\") {\n return joinDataPath(action.folderPath, action.filename);\n }\n return joinDataPath(action.filePath);\n}\n\nfunction joinDataPath(...parts: string[]): string {\n return parts\n .filter((p) => p.length > 0)\n .map((p) => p.replace(/\\\\/g, \"/\").replace(/^\\/+|\\/+$/g, \"\"))\n .join(\"/\");\n}\n\nasync function applyAction(\n cwd: string,\n action: ProposalAction,\n): Promise<string> {\n const dataDir = join(cwd, \"data\");\n switch (action.kind) {\n case \"create-folder\":\n case \"create-file\": {\n const folder = join(dataDir, action.folderPath);\n await mkdir(folder, { recursive: true });\n const file = join(folder, action.filename);\n await writeFile(file, action.body, \"utf8\");\n return file;\n }\n case \"append-section\": {\n const file = join(dataDir, action.filePath);\n await mkdir(dirname(file), { recursive: true });\n const existing = existsSync(file) ? await readFile(file, \"utf8\") : \"\";\n const newline = existing.length > 0 && !existing.endsWith(\"\\n\") ? \"\\n\" : \"\";\n const section = `${newline}\\n## ${action.sectionHeader}\\n${action.body}`;\n await appendFile(file, section, \"utf8\");\n return file;\n }\n case \"update-file\": {\n const file = join(dataDir, action.filePath);\n await mkdir(dirname(file), { recursive: true });\n await writeFile(file, action.body, \"utf8\");\n return file;\n }\n }\n}\n\nfunction nextActionHintFor(action: ProposalAction): string {\n if (action.kind === \"append-section\") {\n return `Section appended to ${action.filePath}. Open it to see the full thread of this topic.`;\n }\n if (action.kind === \"update-file\") {\n return `File updated at ${action.filePath}. The original content was replaced; check git history if you need to recover it.`;\n }\n return `New file at ${action.folderPath}/${action.filename}. Add cross-links from related docs as the topic grows.`;\n}\n\nasync function scanTopicTree(\n cwd: string,\n maxEntries: number,\n): Promise<TopicTreeSnapshot> {\n const dataDir = join(cwd, \"data\");\n if (!existsSync(dataDir)) {\n return { folders: [], truncated: false };\n }\n const folders: TopicFolderSnapshot[] = [];\n let counted = 0;\n let truncated = false;\n\n async function visit(absDir: string, relDir: string): Promise<void> {\n if (counted >= maxEntries) {\n truncated = true;\n return;\n }\n let entries;\n try {\n entries = await readdir(absDir, { withFileTypes: true });\n } catch {\n return;\n }\n const files: TopicFile[] = [];\n const subdirs: string[] = [];\n for (const e of entries) {\n if (e.isDirectory()) {\n if (isReservedDir(e.name, relDir === \"\")) continue;\n subdirs.push(e.name);\n } else if (e.isFile() && e.name.endsWith(\".md\")) {\n if (e.name === \"README.md\" || e.name === \"_INDEX.md\" || e.name === \"MEMORY.md\") continue;\n const filePath = join(absDir, e.name);\n let frontmatterTopic: string | undefined;\n let tags: readonly string[] | undefined;\n try {\n const raw = await readFile(filePath, \"utf8\");\n const parsed = parseFrontmatter<Record<string, unknown>>(raw);\n if (typeof parsed.frontmatter.topic === \"string\") {\n frontmatterTopic = parsed.frontmatter.topic;\n }\n if (Array.isArray(parsed.frontmatter.tags)) {\n tags = parsed.frontmatter.tags.filter((t): t is string => typeof t === \"string\");\n }\n } catch {\n // unreadable / no frontmatter — skip enrichment\n }\n files.push({\n path: joinDataPath(relDir, e.name),\n filename: e.name,\n ...(frontmatterTopic ? { frontmatterTopic } : {}),\n ...(tags ? { tags } : {}),\n });\n }\n }\n if (files.length > 0 || subdirs.length === 0) {\n // Record this folder if it has files of its own, or if it is a leaf\n // (subdir with neither files nor subfolders gets skipped naturally).\n if (relDir !== \"\") {\n folders.push({ path: relDir, files });\n counted += 1 + files.length;\n } else if (files.length > 0) {\n folders.push({ path: \".\", files });\n counted += 1 + files.length;\n }\n }\n for (const d of subdirs) {\n if (counted >= maxEntries) {\n truncated = true;\n return;\n }\n const childRel = joinDataPath(relDir, d);\n await visit(join(absDir, d), childRel);\n }\n }\n\n await visit(dataDir, \"\");\n return { folders, truncated };\n}\n\nfunction isReservedDir(name: string, atRoot: boolean): boolean {\n if (atRoot && SYSTEM_META_DIRS.has(name)) return true;\n if (name.startsWith(\".\")) return true;\n if (atRoot && name.startsWith(\"_\")) return true;\n return false;\n}\n\n// Re-export `DeclinedEntry` so consumers that only import from the\n// insight-proposer module can introspect a decline entry without a\n// separate `decline-store` import.\nexport type { DeclinedEntry };\n","import { existsSync } from \"node:fs\";\nimport { mkdir, readFile, readdir, writeFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport { parseFrontmatter } from \"@vortex-os/core\";\nimport {\n recordAcceptance,\n recordDecline,\n} from \"./decline-store.js\";\nimport { computeFingerprint } from \"./fingerprint.js\";\nimport type { ExpectedShape, LLMJudge } from \"./llm-judge.js\";\nimport type {\n AcceptResult,\n Proposal,\n ProposalAction,\n Proposer,\n ProposerContext,\n} from \"./proposer.js\";\n\n/**\n * Hub auto-curation surface — Sub-phase b.\n *\n * Walks the configured content categories (default: `worklog/`,\n * `decision-log/`, `runbooks/`), groups documents by candidate topic, and\n * proposes a `_HUB-<topic>.md` cross-link page when the cluster crosses a\n * threshold *and* the LLM's coherence judgment agrees.\n *\n * Threshold ladder:\n *\n * - **Below `weakSignalAt`** (default 3) → no LLM call, no proposal. A\n * one- or two-doc topic does not deserve a hub.\n * - **Weak signal (`weakSignalAt` ≤ count < `strongSignalAt`)** → LLM gate\n * runs in **propose-veto** mode. The LLM must affirm the cluster has\n * real cross-cutting cohesion; default is suppress. This avoids hubs\n * over thin coincidences (three docs that share a word but not a topic).\n * - **Strong signal (count ≥ `strongSignalAt`, default 5)** → LLM gate\n * runs in **suppress-veto** mode. The LLM must actively reject the\n * cluster; default is propose. Quantitative accumulation alone is\n * enough to surface a candidate, but the LLM can still hide nonsense\n * clusters.\n *\n * The asymmetry is the design's core safeguard: thresholds catch what the\n * LLM might miss, and the LLM catches what counts miss. Neither alone is\n * sufficient.\n *\n * `action.kind` is always `create-file` — hubs live flat under `hubs/` by\n * convention. There is no folder-creation decision for the hub surface.\n *\n * If a hub at the proposed path already exists, the proposer returns\n * `null` — the hub is the user's to curate after that point; the proposer\n * does not auto-update existing hubs.\n */\n\nconst DEFAULT_CATEGORIES: readonly string[] = [\n \"worklog\",\n \"decision-log\",\n \"runbooks\",\n];\nconst HUB_DIR = \"hubs\";\nconst MIN_KEYWORD_LENGTH = 3;\nconst MAX_LLM_DOC_LIST = 30;\n\nexport interface HubProposerOptions {\n /** Threshold for triggering propose-veto LLM gate. Below this, no proposal. Default 3. */\n readonly weakSignalAt: number;\n /** Threshold for switching to suppress-veto LLM gate. Default 5. */\n readonly strongSignalAt: number;\n /**\n * Content categories (data-relative) to scan for topic clusters. Default\n * `worklog`, `decision-log`, `runbooks`. Hub itself, `_memory/`, and the\n * curator's own `_proactive-curator/` are never scanned (a hub-of-hubs\n * is out of scope; memory is not topical content).\n */\n readonly scanCategories?: readonly string[];\n /** Decline expiry in days. Default 30. */\n readonly declineExpiryDays?: number;\n}\n\nexport interface HubInput {\n /**\n * Hub evaluation has no per-call input beyond context — the filesystem is\n * the input. This shape is kept for future extension (e.g. a hint to scan\n * only a specific category) without breaking the `Proposer<Input, P>`\n * contract.\n */\n readonly hint?: { readonly onlyCategories?: readonly string[] };\n}\n\nexport interface HubProposal extends Proposal {\n readonly kind: \"create-hub\";\n}\n\ninterface DocRecord {\n /** data-relative path, POSIX-slash. */\n readonly path: string;\n readonly filename: string;\n readonly frontmatterTopic?: string;\n readonly tags: readonly string[];\n readonly filenameKeywords: readonly string[];\n}\n\ninterface TopicCluster {\n readonly topic: string;\n readonly docs: readonly DocRecord[];\n}\n\ninterface HubCoherenceVerdict {\n readonly verdict: \"yes\" | \"no\";\n readonly contextParagraph?: string;\n}\n\nexport class HubProposer implements Proposer<HubInput, HubProposal> {\n readonly kind = \"create-hub\";\n\n constructor(private readonly options: HubProposerOptions) {}\n\n async evaluate(\n input: HubInput,\n ctx: ProposerContext,\n ): Promise<HubProposal | null> {\n const categories = input.hint?.onlyCategories\n ?? this.options.scanCategories\n ?? DEFAULT_CATEGORIES;\n\n // 1. Scan + group.\n const docs = await scanDocs(ctx.cwd, categories);\n if (docs.length === 0) return null;\n const clusters = groupByTopic(docs);\n\n // 2. Pick the best cluster — the largest above the weak threshold whose\n // proposed hub does not already exist. We surface at most one hub\n // proposal per evaluate() call; the host can re-call to surface more.\n const candidate = pickCluster(clusters, this.options.weakSignalAt, ctx.cwd);\n if (!candidate) return null;\n\n // 3. LLM gate (asymmetric).\n const verdict = await askCoherence(\n ctx.llm,\n candidate,\n candidate.docs.length >= this.options.strongSignalAt,\n );\n if (!verdict) return null;\n\n // 4. Build the proposal.\n const slug = candidate.topic;\n const filename = `_HUB-${slug}.md`;\n const action: ProposalAction = {\n kind: \"create-file\",\n folderPath: HUB_DIR,\n filename,\n body: renderHubBody(candidate, verdict.contextParagraph, ctx.now),\n };\n const targetPath = `${HUB_DIR}/${filename}`;\n\n // 5. Decline check.\n const sourceDocs = candidate.docs.map((d) => d.path);\n const fingerprint = computeFingerprint({\n kind: \"create-hub\",\n topic: candidate.topic,\n sourceDocs,\n actionKind: action.kind,\n targetPath,\n });\n if (ctx.declinedFingerprints.has(fingerprint)) return null;\n\n // 6. Emit.\n const rationale = candidate.docs.length >= this.options.strongSignalAt\n ? `${candidate.docs.length} docs about \"${candidate.topic}\" — strong-signal cluster (above ${this.options.strongSignalAt}); LLM concurred.`\n : `${candidate.docs.length} docs about \"${candidate.topic}\" — weak-signal cluster (≥ ${this.options.weakSignalAt}); LLM affirmed cohesion.`;\n const declineExpiryDays = this.options.declineExpiryDays;\n\n return {\n kind: \"create-hub\",\n fingerprint,\n action,\n preview: renderPreview(candidate, verdict.contextParagraph),\n rationale,\n sourceRefs: sourceDocs,\n onAccept: async () => {\n const writtenPath = await applyHubCreate(ctx.cwd, action);\n await recordAcceptance(ctx.cwd, {\n kind: \"create-hub\",\n fingerprint,\n topic: candidate.topic,\n actionKind: action.kind,\n writtenPath,\n now: ctx.now,\n });\n return {\n writtenPath,\n actionApplied: action.kind,\n nextActionHint: `Hub created at hubs/${filename}. Open it to review the cross-links; the source docs were not modified.`,\n } satisfies AcceptResult;\n },\n onDecline: async () => {\n await recordDecline(ctx.cwd, {\n kind: \"create-hub\",\n fingerprint,\n topic: candidate.topic,\n actionKind: action.kind,\n targetPath,\n sourceDocs,\n now: ctx.now,\n ...(declineExpiryDays !== undefined ? { expiryDays: declineExpiryDays } : {}),\n });\n },\n };\n }\n}\n\nasync function scanDocs(\n cwd: string,\n categories: readonly string[],\n): Promise<DocRecord[]> {\n const dataDir = join(cwd, \"data\");\n if (!existsSync(dataDir)) return [];\n const out: DocRecord[] = [];\n for (const category of categories) {\n const abs = join(dataDir, category);\n if (!existsSync(abs)) continue;\n await walk(abs, category, out);\n }\n return out;\n}\n\nasync function walk(\n absDir: string,\n relPath: string,\n acc: DocRecord[],\n): Promise<void> {\n let entries;\n try {\n entries = await readdir(absDir, { withFileTypes: true });\n } catch {\n return;\n }\n for (const e of entries) {\n if (e.isDirectory()) {\n if (e.name.startsWith(\".\") || e.name.startsWith(\"_\")) continue;\n await walk(join(absDir, e.name), `${relPath}/${e.name}`, acc);\n } else if (e.isFile() && e.name.endsWith(\".md\")) {\n if (e.name === \"README.md\" || e.name === \"_INDEX.md\" || e.name === \"MEMORY.md\") continue;\n if (e.name.startsWith(\"_TEMPLATE\")) continue;\n const filePath = join(absDir, e.name);\n let frontmatterTopic: string | undefined;\n let tags: string[] = [];\n try {\n const raw = await readFile(filePath, \"utf8\");\n const parsed = parseFrontmatter<Record<string, unknown>>(raw);\n if (typeof parsed.frontmatter.topic === \"string\") {\n frontmatterTopic = parsed.frontmatter.topic.trim();\n }\n if (Array.isArray(parsed.frontmatter.tags)) {\n tags = parsed.frontmatter.tags.filter((t): t is string => typeof t === \"string\");\n }\n } catch {\n // unreadable or no frontmatter — leave fields empty\n }\n acc.push({\n path: `${relPath}/${e.name}`,\n filename: e.name,\n ...(frontmatterTopic ? { frontmatterTopic } : {}),\n tags,\n filenameKeywords: extractFilenameKeywords(e.name),\n });\n }\n }\n}\n\nfunction extractFilenameKeywords(filename: string): string[] {\n const stem = filename.replace(/\\.md$/i, \"\");\n const withoutDate = stem.replace(/^\\d{4}-\\d{2}-\\d{2}-/, \"\");\n return withoutDate\n .split(/[-_\\s]+/)\n .map((s) => s.toLowerCase())\n .filter((s) => s.length >= MIN_KEYWORD_LENGTH);\n}\n\nfunction groupByTopic(docs: readonly DocRecord[]): TopicCluster[] {\n const buckets = new Map<string, DocRecord[]>();\n for (const doc of docs) {\n const topics = candidateTopicsFor(doc);\n for (const topic of topics) {\n const list = buckets.get(topic);\n if (list) {\n if (!list.some((d) => d.path === doc.path)) list.push(doc);\n } else {\n buckets.set(topic, [doc]);\n }\n }\n }\n const clusters: TopicCluster[] = [];\n for (const [topic, list] of buckets) {\n clusters.push({ topic, docs: list });\n }\n // Largest cluster first so pickCluster() finds the best candidate quickly.\n clusters.sort((a, b) => b.docs.length - a.docs.length);\n return clusters;\n}\n\nfunction candidateTopicsFor(doc: DocRecord): string[] {\n const topics = new Set<string>();\n if (doc.frontmatterTopic) topics.add(slugify(doc.frontmatterTopic));\n for (const tag of doc.tags) {\n const slug = slugify(tag);\n if (slug.length >= MIN_KEYWORD_LENGTH) topics.add(slug);\n }\n for (const kw of doc.filenameKeywords) {\n topics.add(kw);\n }\n return [...topics];\n}\n\nfunction slugify(s: string): string {\n return s.trim().toLowerCase().replace(/\\s+/g, \"-\");\n}\n\nfunction pickCluster(\n clusters: readonly TopicCluster[],\n weakThreshold: number,\n cwd: string,\n): TopicCluster | null {\n for (const c of clusters) {\n if (c.docs.length < weakThreshold) return null; // sorted desc — first under-threshold means done\n const hubPath = join(cwd, \"data\", HUB_DIR, `_HUB-${c.topic}.md`);\n if (existsSync(hubPath)) continue;\n return c;\n }\n return null;\n}\n\nasync function askCoherence(\n llm: LLMJudge,\n cluster: TopicCluster,\n isStrongSignal: boolean,\n): Promise<HubCoherenceVerdict | null> {\n const prompt = renderCoherencePrompt(cluster, isStrongSignal);\n const expected: ExpectedShape = {\n shape: \"json\",\n schema: {\n verdict: \"yes|no\",\n contextParagraph: \"string (1-2 sentences, used in the hub body when verdict=yes)\",\n },\n };\n const raw = await llm.ask(prompt, expected);\n return interpretCoherence(raw, isStrongSignal);\n}\n\nfunction renderCoherencePrompt(\n cluster: TopicCluster,\n isStrongSignal: boolean,\n): string {\n const docList = cluster.docs\n .slice(0, MAX_LLM_DOC_LIST)\n .map((d) => ` - ${d.path}`)\n .join(\"\\n\");\n const truncationNote = cluster.docs.length > MAX_LLM_DOC_LIST\n ? `\\n (... ${cluster.docs.length - MAX_LLM_DOC_LIST} more docs omitted for brevity)`\n : \"\";\n if (isStrongSignal) {\n return [\n `${cluster.docs.length} documents share the candidate topic \"${cluster.topic}\" — a strong-signal cluster.`,\n \"\",\n \"Documents:\",\n docList + truncationNote,\n \"\",\n \"Default action is to propose creating a `_HUB-` page that cross-links them. Reject *only* if the docs are clearly incoherent — sharing a keyword but not a real subject. If the cluster has any reasonable cohesion, return verdict=yes.\",\n \"\",\n `Return JSON: { \"verdict\": \"yes\" | \"no\", \"contextParagraph\": \"1-2 sentences describing the topic for the hub body (required if verdict=yes)\" }`,\n ].join(\"\\n\");\n }\n return [\n `${cluster.docs.length} documents share the candidate topic \"${cluster.topic}\" — a weak-signal cluster.`,\n \"\",\n \"Documents:\",\n docList + truncationNote,\n \"\",\n \"Affirm verdict=yes only if the topic is clearly cross-cutting and the cluster has real cohesion (not a coincidence of keywords or tags). When uncertain, return verdict=no.\",\n \"\",\n `Return JSON: { \"verdict\": \"yes\" | \"no\", \"contextParagraph\": \"1-2 sentences describing the topic for the hub body (required if verdict=yes)\" }`,\n ].join(\"\\n\");\n}\n\nfunction interpretCoherence(\n raw: unknown,\n isStrongSignal: boolean,\n): HubCoherenceVerdict | null {\n if (typeof raw !== \"object\" || raw === null) return null;\n const obj = raw as Record<string, unknown>;\n const verdict = obj.verdict === \"yes\" ? \"yes\" : obj.verdict === \"no\" ? \"no\" : null;\n if (verdict === null) return null;\n if (isStrongSignal) {\n // Suppress-veto: explicit \"no\" suppresses; otherwise propose.\n if (verdict === \"no\") return null;\n const contextParagraph = typeof obj.contextParagraph === \"string\"\n ? obj.contextParagraph.trim() || undefined\n : undefined;\n return contextParagraph\n ? { verdict: \"yes\", contextParagraph }\n : { verdict: \"yes\" };\n }\n // Propose-veto (weak signal): explicit \"yes\" with context surfaces;\n // anything else suppresses.\n if (verdict !== \"yes\") return null;\n const contextParagraph = typeof obj.contextParagraph === \"string\"\n ? obj.contextParagraph.trim()\n : \"\";\n if (!contextParagraph) return null;\n return { verdict: \"yes\", contextParagraph };\n}\n\nfunction renderPreview(\n cluster: TopicCluster,\n contextParagraph: string | undefined,\n): string {\n const lines: string[] = [\n `Proposed hub: hubs/_HUB-${cluster.topic}.md`,\n `Cluster size: ${cluster.docs.length} documents`,\n ];\n if (contextParagraph) {\n lines.push(\"\", contextParagraph);\n }\n lines.push(\"\", \"Cross-linked docs:\");\n for (const d of cluster.docs.slice(0, MAX_LLM_DOC_LIST)) {\n lines.push(` - ${d.path}`);\n }\n if (cluster.docs.length > MAX_LLM_DOC_LIST) {\n lines.push(` ... ${cluster.docs.length - MAX_LLM_DOC_LIST} more`);\n }\n return lines.join(\"\\n\");\n}\n\nfunction renderHubBody(\n cluster: TopicCluster,\n contextParagraph: string | undefined,\n now: Date,\n): string {\n const ymd = formatYmd(now);\n const links = cluster.docs.map((d) => `- [[${stripMdExtension(d.path)}]]`).join(\"\\n\");\n const context = contextParagraph\n ? `${contextParagraph}\\n\\n`\n : \"\";\n return `---\ntype: hub\ntopic: ${cluster.topic}\ncreated: ${ymd}\nupdated: ${ymd}\ntags: [hub, proactive-curator]\n---\n\n# ${cluster.topic}\n\n> Hub proposed by proactive-curator on ${ymd}. The user accepted this proposal; edit freely. The cross-linked source docs were not modified.\n\n${context}## Cross-linked docs\n\n${links}\n`;\n}\n\nfunction stripMdExtension(p: string): string {\n return p.replace(/\\.md$/i, \"\");\n}\n\nfunction formatYmd(d: Date): string {\n const y = d.getFullYear();\n const m = String(d.getMonth() + 1).padStart(2, \"0\");\n const day = String(d.getDate()).padStart(2, \"0\");\n return `${y}-${m}-${day}`;\n}\n\nasync function applyHubCreate(\n cwd: string,\n action: Extract<ProposalAction, { kind: \"create-file\" }>,\n): Promise<string> {\n const folder = join(cwd, \"data\", action.folderPath);\n await mkdir(folder, { recursive: true });\n const file = join(folder, action.filename);\n await mkdir(dirname(file), { recursive: true });\n await writeFile(file, action.body, \"utf8\");\n return file;\n}\n","import type { TurnRecord } from \"./insight-proposer.js\";\n\n/**\n * Sliding buffer of recent conversation turns. The host pushes each turn as\n * it occurs; the buffer caps at `maxTurns` and discards the oldest entries\n * past the cap. Token count is estimated cheaply so the host can poll\n * `tokenCount()` to decide when InsightProposer's threshold has been met.\n *\n * Default estimator is `chars / 4` — a rough baseline that overshoots for\n * CJK content and undershoots for ASCII code. Hosts that have a real\n * tokenizer can inject one via the `estimator` option.\n *\n * The buffer is process-local and not persisted — a new session starts\n * with an empty buffer, which is the intended UX (proactive proposals are\n * about *this conversation*, not a re-ingestion of past sessions; that is\n * what `memory-extended/consolidate` is for).\n */\nexport class TurnBuffer {\n private readonly turns: TurnRecord[] = [];\n private readonly maxTurns: number;\n private readonly estimator: (turn: TurnRecord) => number;\n\n constructor(options?: {\n readonly maxTurns?: number;\n readonly estimator?: (turn: TurnRecord) => number;\n }) {\n this.maxTurns = options?.maxTurns ?? 50;\n this.estimator = options?.estimator ?? defaultTokenEstimator;\n }\n\n /** Append a turn, evicting the oldest entry if the buffer is full. */\n add(turn: TurnRecord): void {\n this.turns.push(turn);\n while (this.turns.length > this.maxTurns) {\n this.turns.shift();\n }\n }\n\n /** Return the most recent `n` turns (or fewer if the buffer has fewer). */\n recent(n: number): readonly TurnRecord[] {\n if (n >= this.turns.length) return [...this.turns];\n return this.turns.slice(-n);\n }\n\n /** Number of turns currently buffered. */\n get length(): number {\n return this.turns.length;\n }\n\n /** Estimated total token count over the entire buffer. */\n tokenCount(): number {\n let total = 0;\n for (const t of this.turns) total += this.estimator(t);\n return total;\n }\n\n /** Reset the buffer — typically called at session-end. */\n clear(): void {\n this.turns.length = 0;\n }\n}\n\n/**\n * Backpressure controller for ambient mid-session triggers. When the user\n * declines several proposals in a row, the controller flips into\n * `active=true` and the host should pause ambient evaluations for the\n * remainder of the session. Manual `/curate` invocations are still\n * allowed — the controller exists only to suppress unsolicited prompts.\n *\n * Reset semantics:\n * - `recordAccept()` — any acceptance clears the streak.\n * - `recordIgnored()` — proposals the host surfaced but the user did not\n * explicitly accept/decline do not count toward the streak.\n * - `reset()` — explicit reset, used by `/curate` (the user re-engaging\n * after backpressure kicked in).\n */\nexport class AmbientBackpressure {\n private declineStreak = 0;\n private readonly maxStreak: number;\n\n constructor(options?: { readonly maxStreak?: number }) {\n this.maxStreak = options?.maxStreak ?? 3;\n }\n\n /** Record a user decline. Counts toward backpressure. */\n recordDecline(): void {\n this.declineStreak++;\n }\n\n /** Record a user acceptance. Clears the streak. */\n recordAccept(): void {\n this.declineStreak = 0;\n }\n\n /** Explicit reset (e.g. user runs `/curate` after backpressure activated). */\n reset(): void {\n this.declineStreak = 0;\n }\n\n /** True when the streak has reached the maximum and ambient should pause. */\n isActive(): boolean {\n return this.declineStreak >= this.maxStreak;\n }\n\n /** Current decline streak — exposed for diagnostics. */\n get streak(): number {\n return this.declineStreak;\n }\n}\n\n/**\n * Rough token estimator — ~4 characters per token (English baseline).\n * Replace with a real tokenizer when accuracy matters; for the threshold\n * gate this estimate is adequate.\n */\nfunction defaultTokenEstimator(turn: TurnRecord): number {\n return Math.ceil(turn.content.length / 4);\n}\n","import { AmbientBackpressure } from \"./ambient-tracker.js\";\nimport type { TurnRecord } from \"./insight-proposer.js\";\n\n/**\n * Minimal shape of a recall hit the ambient recaller consumes.\n *\n * Defined locally — `proactive-curator` does not depend on\n * `@vortex-os/memory-extended`. The host injects a {@link RecallFn} whose\n * result structurally satisfies this shape (memory-extended's `RecallHit`\n * carries all of these fields plus a few extra, so the wiring is\n * zero-friction). This mirrors how `LLMJudge` keeps the host's LLM facility\n * behind an injected adapter: the recall *engine* lives in another package;\n * the *decision of when to surface a hit in conversation* lives here.\n */\nexport interface AmbientRecallHit {\n readonly id: string;\n /** Cosine similarity to the query (1 = identical direction). */\n readonly score: number;\n readonly name: string;\n /** Short body excerpt for the host to weave into prose. */\n readonly excerpt: string;\n /** Corpus the hit came from (e.g. \"memory\", \"session-archive\"). */\n readonly source: string;\n readonly type: string;\n readonly updated: string | null;\n readonly tags: readonly string[];\n}\n\n/**\n * Host-injected recall function. The host wires its `memory-extended` recall\n * engine (sqlite + vector + embedder + session chunks) behind this single\n * call so the recaller stays engine-agnostic and `proactive-curator` stays\n * free of any `memory-extended` dependency.\n */\nexport interface RecallFn {\n (query: string, opts?: { readonly k?: number }): Promise<{\n readonly hits: readonly AmbientRecallHit[];\n }>;\n}\n\n/** One surfaced suggestion — a recall hit that passed the ambient gate. */\nexport interface RecallSuggestion {\n readonly hit: AmbientRecallHit;\n /** Convenience copy of `hit.score` (the gate's ranking key). */\n readonly score: number;\n}\n\n/**\n * Result of one {@link AmbientRecaller.consider} call. Carries the surviving\n * suggestion(s) plus diagnostics (how many hits the engine returned, how many\n * each gate dropped) so an instance can tune `minScore` against real\n * conversations rather than guessing.\n */\nexport interface AmbientRecallResult {\n /** Hits that passed every gate, best-first, capped at `maxSuggestions`. */\n readonly suggestions: readonly RecallSuggestion[];\n /** True when backpressure is active — the recaller stayed silent. */\n readonly suppressed: boolean;\n /** The query actually used (derived or explicit); null if none/empty. */\n readonly query: string | null;\n /** Hits returned by the engine before filtering (transparency for tuning). */\n readonly considered: number;\n /** Hits dropped for scoring below `minScore`. */\n readonly belowThreshold: number;\n /** Hits dropped as already surfaced earlier this session. */\n readonly deduped: number;\n}\n\nexport interface AmbientRecallerOptions {\n readonly recall: RecallFn;\n /**\n * Minimum cosine score for a hit to be worth surfacing unprompted. The\n * single most important tuning knob — too low surfaces noise (naggy), too\n * high never fires. The right value depends on the embedder; calibrate per\n * instance against real conversations (the result diagnostics help). The\n * default 0.5 is a conservative starting point for the bundled e5-small\n * embedder.\n */\n readonly minScore?: number;\n /** Max suggestions per `consider()`. Default 1 — ambient is one nudge, not a list. */\n readonly maxSuggestions?: number;\n /** Below this query length, do not even call the engine. Default 12. */\n readonly minQueryChars?: number;\n /**\n * How many candidates to ask the engine for. Defaults to\n * `maxSuggestions + 4` so dedup/threshold filtering has headroom.\n */\n readonly candidateK?: number;\n /** Shared backpressure controller. Omit to use a fresh one. */\n readonly backpressure?: AmbientBackpressure;\n}\n\nconst DEFAULT_MIN_SCORE = 0.5;\nconst DEFAULT_MAX_SUGGESTIONS = 1;\nconst DEFAULT_MIN_QUERY_CHARS = 12;\n\n/**\n * Decides *whether* and *which* past memory to surface in the flow of a live\n * conversation — the ambient counterpart to the explicit `/recall` command\n * (memory-extended-design.md deferred this \"notice and offer\" reliability to\n * a proactive-curator-connected follow-up; this is it).\n *\n * It does not embed, search, or format anything itself. It takes the recent\n * conversation, derives a query, asks the injected recall engine, and applies\n * three gates so the surface stays useful and non-naggy:\n *\n * 1. **Backpressure** — after N consecutive declines (see\n * {@link AmbientBackpressure}) it goes silent for the rest of the session.\n * 2. **Score threshold** — only confident hits surface.\n * 3. **Session dedup** — a hit already offered this session is not re-offered.\n *\n * Stateful by design (the dedup set + backpressure streak live across turns),\n * so a host keeps ONE instance alive for the session — a long-lived runtime\n * or the opt-in embedder daemon. A stateless per-call host (a plain slash\n * command) cannot carry the gate state; that is exactly why the default\n * Claude Code surface is agent-guidance, not a command (see the design docs).\n */\nexport class AmbientRecaller {\n private readonly recall: RecallFn;\n private readonly minScore: number;\n private readonly maxSuggestions: number;\n private readonly minQueryChars: number;\n private readonly candidateK: number;\n private readonly backpressure: AmbientBackpressure;\n private readonly surfaced = new Set<string>();\n\n constructor(options: AmbientRecallerOptions) {\n this.recall = options.recall;\n this.minScore = options.minScore ?? DEFAULT_MIN_SCORE;\n this.maxSuggestions = options.maxSuggestions ?? DEFAULT_MAX_SUGGESTIONS;\n this.minQueryChars = options.minQueryChars ?? DEFAULT_MIN_QUERY_CHARS;\n this.candidateK = options.candidateK ?? this.maxSuggestions + 4;\n this.backpressure = options.backpressure ?? new AmbientBackpressure();\n }\n\n /**\n * Consider surfacing a memory given the current conversation. Pass an\n * explicit `query` (the host knows what the user is referencing) or recent\n * `turns` to derive one from. Returns the gated suggestions plus diagnostics.\n *\n * Does not catch errors from the injected engine — a failing embedder\n * should surface to the host (which decides whether to swallow it for the\n * turn), not be masked here.\n */\n async consider(input: {\n readonly query?: string;\n readonly turns?: readonly TurnRecord[];\n }): Promise<AmbientRecallResult> {\n if (this.backpressure.isActive()) {\n return emptyResult(true, null);\n }\n const query = (input.query ?? deriveQueryFromTurns(input.turns ?? [])).trim();\n if (query.length < this.minQueryChars) {\n return emptyResult(false, query.length === 0 ? null : query);\n }\n\n const { hits } = await this.recall(query, { k: this.candidateK });\n let belowThreshold = 0;\n let deduped = 0;\n const suggestions: RecallSuggestion[] = [];\n for (const hit of hits) {\n if (hit.score < this.minScore) {\n belowThreshold++;\n continue;\n }\n if (this.surfaced.has(hit.id)) {\n deduped++;\n continue;\n }\n suggestions.push({ hit, score: hit.score });\n if (suggestions.length >= this.maxSuggestions) break;\n }\n for (const s of suggestions) this.surfaced.add(s.hit.id);\n\n return {\n suggestions,\n suppressed: false,\n query,\n considered: hits.length,\n belowThreshold,\n deduped,\n };\n }\n\n /** The user engaged with a surfaced suggestion — clears the decline streak. */\n recordAccept(): void {\n this.backpressure.recordAccept();\n }\n\n /** The user dismissed a surfaced suggestion — counts toward backpressure. */\n recordDecline(): void {\n this.backpressure.recordDecline();\n }\n\n /** True when backpressure has silenced ambient surfacing for the session. */\n get suppressed(): boolean {\n return this.backpressure.isActive();\n }\n\n /**\n * Re-engage after backpressure (the user explicitly asks for suggestions\n * again, e.g. via `/curate`). Clears the decline streak AND the dedup set\n * so previously surfaced hits can be offered again.\n */\n reset(): void {\n this.backpressure.reset();\n this.surfaced.clear();\n }\n}\n\n/**\n * Build a recall query from recent turns. Uses the most recent *user* turn —\n * in ambient use the trigger is the user's latest utterance (\"didn't I do\n * this before?\"), and that utterance is the query. Falls back to the most\n * recent turn of any role if the window has no user turn.\n */\nexport function deriveQueryFromTurns(turns: readonly TurnRecord[]): string {\n for (let i = turns.length - 1; i >= 0; i--) {\n if (turns[i]!.role === \"user\") return turns[i]!.content;\n }\n return turns.length > 0 ? turns[turns.length - 1]!.content : \"\";\n}\n\nfunction emptyResult(suppressed: boolean, query: string | null): AmbientRecallResult {\n return { suggestions: [], suppressed, query, considered: 0, belowThreshold: 0, deduped: 0 };\n}\n","import type { ExpectedShape, LLMJudge } from \"../llm-judge.js\";\n\n/**\n * Shared building blocks for host `LLMJudge` adapters that work by injecting a\n * single-shot \"prompt in, string out\" call.\n *\n * Every first-party host (Claude Code, Codex, Gemini, Claude Desktop) reaches\n * its LLM differently — a sub-agent tool call, an inline completion, an MCP\n * call, a desktop surface — but that difference is entirely in the *raw\n * invoker* the host injects. The work *around* the call is identical: frame\n * the proposer's prompt so the model returns only the requested shape, then\n * parse the raw response tolerantly. That shared work lives here so each host\n * adapter is a thin shell over one injected function (the design's\n * \"subsequent hosts inherit the pattern\").\n */\n\n/** A host's single-shot LLM call: a prompt in, a raw string out. */\nexport interface InjectedInvoker {\n (input: { readonly prompt: string }): Promise<string>;\n}\n\n/**\n * Base error for injected-host LLMJudge adapters. Each host subclass narrows\n * the `name` (e.g. `ClaudeCodeLLMJudgeError`) so callers can distinguish the\n * source host while still catching the family with `instanceof LLMJudgeError`.\n */\nexport class LLMJudgeError extends Error {\n constructor(message: string, readonly raw?: string) {\n super(message);\n this.name = \"LLMJudgeError\";\n }\n}\n\n/**\n * Frame a proposer prompt for a single-shot host LLM call. Host-agnostic —\n * the instruction constrains the response to the expected shape and names no\n * host facility, so every adapter shares it verbatim.\n */\nexport function frameForJudge(prompt: string, expected: ExpectedShape): string {\n const tail = expected.shape === \"json\"\n ? \"\\n\\nReturn ONLY the JSON object described above. No prose, no markdown code fences, no explanation around it. If you cannot answer, return the JSON with verdict=\\\"no\\\" (for capture decisions) or actionKind=\\\"create-file\\\" with a brief rationale (for placement decisions).\"\n : \"\\n\\nReturn ONLY the answer string. No prose preamble, no markdown formatting around it.\";\n return prompt + tail;\n}\n\n/**\n * Parse a raw host response into the expected shape. Strings pass through\n * trimmed; JSON answers are extracted tolerantly (a leading/trailing ```json\n * fence, or a sentence wrapped around the object) and `JSON.parse`'d.\n * Persistent format failure throws via the injected `makeError` factory so\n * each adapter raises its own typed error rather than the base masking it.\n */\nexport function parseJudgeResponse(\n raw: string,\n expected: ExpectedShape,\n makeError: (message: string, raw?: string) => Error,\n): unknown {\n if (typeof raw !== \"string\") {\n throw makeError(\"Host LLM returned a non-string response.\");\n }\n const stripped = raw.trim();\n if (expected.shape === \"string\") {\n return stripped;\n }\n const jsonPayload = extractJsonPayload(stripped);\n try {\n return JSON.parse(jsonPayload);\n } catch (e) {\n throw makeError(`Host LLM response was not valid JSON: ${(e as Error).message}`, raw);\n }\n}\n\nfunction extractJsonPayload(s: string): string {\n // Strip leading/trailing markdown code fences if present.\n const fenced = s.match(/^```(?:json)?\\s*([\\s\\S]*?)\\s*```$/i);\n if (fenced) return fenced[1]!.trim();\n // Find the first { and matching last } — tolerant of a leading sentence.\n const firstBrace = s.indexOf(\"{\");\n const lastBrace = s.lastIndexOf(\"}\");\n if (firstBrace !== -1 && lastBrace > firstBrace) {\n return s.slice(firstBrace, lastBrace + 1);\n }\n return s;\n}\n\n/**\n * Shared base for host adapters built on an injected invoker. The base owns\n * framing + parsing; a subclass declares only the host id and (optionally)\n * overrides {@link makeError} to raise a host-named error type.\n */\nexport abstract class InjectedLLMJudge implements LLMJudge {\n abstract readonly host: string;\n\n constructor(protected readonly invoker: InjectedInvoker) {}\n\n /** Host adapters override to raise a host-named error subclass. */\n protected makeError(message: string, raw?: string): Error {\n return new LLMJudgeError(message, raw);\n }\n\n async ask(prompt: string, expected: ExpectedShape): Promise<unknown> {\n const framed = frameForJudge(prompt, expected);\n const raw = await this.invoker({ prompt: framed });\n return parseJudgeResponse(raw, expected, (m, r) => this.makeError(m, r));\n }\n}\n","import {\n InjectedLLMJudge,\n LLMJudgeError,\n type InjectedInvoker,\n} from \"./shared.js\";\n\n/**\n * Claude Code host adapter for `LLMJudge`.\n *\n * Claude Code's natural surface for a single-shot decision query is a\n * **sub-agent tool call** — a separate, ephemeral agent invoked by the outer\n * session with a focused prompt, returning its single answer. The adapter\n * does not know how to invoke a sub-agent itself (that is Claude Code runtime\n * territory); the host injects an invoker callback at construction time, and\n * the shared {@link InjectedLLMJudge} base handles prompt framing + tolerant\n * response parsing on top of it.\n *\n * The invoker callback is intentionally minimal — a single async function\n * that takes a string and returns a string. Hosts that want to thread\n * additional metadata (session id, tool budget) can capture them in the\n * closure when they create the invoker.\n */\n\n/** Claude Code's sub-agent invoker — a `prompt in, string out` call. */\nexport type ClaudeCodeSubAgentInvoker = InjectedInvoker;\n\nexport class ClaudeCodeLLMJudgeError extends LLMJudgeError {\n constructor(message: string, raw?: string) {\n super(message, raw);\n this.name = \"ClaudeCodeLLMJudgeError\";\n }\n}\n\nexport class ClaudeCodeLLMJudge extends InjectedLLMJudge {\n readonly host = \"claude-code\";\n\n protected override makeError(message: string, raw?: string): Error {\n return new ClaudeCodeLLMJudgeError(message, raw);\n }\n}\n","import {\n InjectedLLMJudge,\n LLMJudgeError,\n type InjectedInvoker,\n} from \"./shared.js\";\n\n/**\n * Codex CLI host adapter for `LLMJudge`.\n *\n * Codex's natural surface for a single-shot decision query is an **inline\n * completion** — the host runs the framed prompt as a one-off completion and\n * returns the text. As with every adapter, the host injects that call; the\n * shared base supplies framing + parsing. The only host-specific surface here\n * is the `host` identifier (`\"codex\"`, matching the sessionArchive adapter\n * convention) and the typed error.\n */\n\n/** Codex's inline-completion invoker — a `prompt in, string out` call. */\nexport type CodexCompletionInvoker = InjectedInvoker;\n\nexport class CodexLLMJudgeError extends LLMJudgeError {\n constructor(message: string, raw?: string) {\n super(message, raw);\n this.name = \"CodexLLMJudgeError\";\n }\n}\n\nexport class CodexLLMJudge extends InjectedLLMJudge {\n readonly host = \"codex\";\n\n protected override makeError(message: string, raw?: string): Error {\n return new CodexLLMJudgeError(message, raw);\n }\n}\n","import {\n InjectedLLMJudge,\n LLMJudgeError,\n type InjectedInvoker,\n} from \"./shared.js\";\n\n/**\n * Gemini CLI host adapter for `LLMJudge`.\n *\n * Gemini's natural surface for a single-shot decision query is an **MCP call**\n * — the host routes the framed prompt through its model-call tool and returns\n * the text. The host injects that call; the shared base supplies framing +\n * parsing. Host-specific surface is the `host` identifier (`\"gemini\"`,\n * matching the sessionArchive adapter convention) and the typed error.\n */\n\n/** Gemini's MCP-call invoker — a `prompt in, string out` call. */\nexport type GeminiMcpInvoker = InjectedInvoker;\n\nexport class GeminiLLMJudgeError extends LLMJudgeError {\n constructor(message: string, raw?: string) {\n super(message, raw);\n this.name = \"GeminiLLMJudgeError\";\n }\n}\n\nexport class GeminiLLMJudge extends InjectedLLMJudge {\n readonly host = \"gemini\";\n\n protected override makeError(message: string, raw?: string): Error {\n return new GeminiLLMJudgeError(message, raw);\n }\n}\n","import {\n InjectedLLMJudge,\n LLMJudgeError,\n type InjectedInvoker,\n} from \"./shared.js\";\n\n/**\n * Claude Desktop host adapter for `LLMJudge`.\n *\n * Claude Desktop's natural surface for a single-shot decision query is a\n * **response on its own conversation surface** — the host poses the framed\n * prompt and returns the model's reply. The host injects that call; the\n * shared base supplies framing + parsing. Host-specific surface is the `host`\n * identifier (`\"claude-desktop\"`, matching the sessionArchive adapter\n * convention) and the typed error.\n */\n\n/** Claude Desktop's response invoker — a `prompt in, string out` call. */\nexport type ClaudeDesktopInvoker = InjectedInvoker;\n\nexport class ClaudeDesktopLLMJudgeError extends LLMJudgeError {\n constructor(message: string, raw?: string) {\n super(message, raw);\n this.name = \"ClaudeDesktopLLMJudgeError\";\n }\n}\n\nexport class ClaudeDesktopLLMJudge extends InjectedLLMJudge {\n readonly host = \"claude-desktop\";\n\n protected override makeError(message: string, raw?: string): Error {\n return new ClaudeDesktopLLMJudgeError(message, raw);\n }\n}\n","export { createRitualRegistry } from \"./registry.js\";\r\nexport type { RitualRegistryOptions } from \"./registry.js\";\r\nexport { curateCommand } from \"./commands/curate.js\";\r\nexport type {\r\n CurateAnyProposal,\r\n CurateOptions,\r\n CurateResult,\r\n} from \"./commands/curate.js\";\r\nexport { recallCommand } from \"./commands/recall.js\";\r\nexport type { RecallOptions } from \"./commands/recall.js\";\r\nexport { createAmbientRecaller } from \"./ambient-recall.js\";\r\nexport type { AmbientRecallFactoryOptions } from \"./ambient-recall.js\";\r\nexport { sessionStartCommand } from \"./commands/session-start.js\";\r\nexport type { SessionStartReport } from \"./commands/session-start.js\";\r\nexport {\r\n collectSessionStartReport,\r\n renderSessionStartReport,\r\n detectWorklogGaps,\r\n} from \"./session-start-report.js\";\r\nexport type {\r\n GitPullResult,\r\n RecentWorklog,\r\n SessionStartHookReport,\r\n} from \"./session-start-report.js\";\r\nexport { ensureWorklogEntry } from \"./worklog-write.js\";\r\nexport type { EnsureWorklogResult } from \"./worklog-write.js\";\r\nexport { catchUpSessions } from \"./catch-up.js\";\r\nexport type { CatchUpResult, CatchUpOptions } from \"./catch-up.js\";\r\nexport {\r\n ensureVortexHooks,\r\n parseSettings,\r\n serializeSettings,\r\n SESSION_START_COMMAND,\r\n SESSION_END_COMMAND,\r\n} from \"./ensure-hooks.js\";\r\nexport type { ClaudeSettings, EnsureHooksResult } from \"./ensure-hooks.js\";\r\nexport { reindexCommand } from \"./commands/reindex.js\";\r\nexport type { ReindexResult } from \"./commands/reindex.js\";\r\nexport { decisionCommand } from \"./commands/decision.js\";\r\nexport type { NewDecisionResult } from \"./commands/decision.js\";\r\nexport { logCommand } from \"./commands/log.js\";\r\nexport type { WorklogAppendResult } from \"./commands/log.js\";\r\nexport { agendaCommand } from \"./commands/agenda.js\";\r\nexport {\r\n collectAgenda,\r\n renderAgenda,\r\n extractOpenTasks,\r\n extractNextUp,\r\n} from \"./agenda.js\";\r\nexport type {\r\n AgendaReport,\r\n OpenTask,\r\n OpenDecision,\r\n CollectAgendaOptions,\r\n} from \"./agenda.js\";\r\nexport { vortexCommand } from \"./commands/vortex.js\";\r\nexport type {\r\n VortexResult,\r\n VortexInitResult,\r\n VortexHelpResult,\r\n VortexPlannedResult,\r\n VortexSyncResult,\r\n VortexSyncStep,\r\n VortexSyncStepId,\r\n VortexSyncStepStatus,\r\n} from \"./commands/vortex.js\";\r\n","import {\n HubProposer,\n InsightProposer,\n type HubProposal,\n type InsightInput,\n type InsightProposal,\n type LLMJudge,\n type Proposal,\n loadDeclinedFingerprints,\n resetDeclined,\n} from \"@vortex-os/proactive-curator\";\nimport type { Command, CommandInput } from \"@vortex-os/slash-commands\";\n\n/**\n * `/curate` — surface accumulated proposals from the proactive-curator\n * module. Two surfaces share one command:\n *\n * - `/curate` — run both proposers; surface any results.\n * - `/curate --insight` — InsightProposer only.\n * - `/curate --hub` — HubProposer only.\n * - `/curate --reset-declined` — clear the decline list (escape hatch).\n *\n * Host integration:\n * 1. Construct an `LLMJudge` adapter for the host (Claude Code / Codex /\n * Gemini / Claude Desktop) — see `@vortex-os/proactive-curator`.\n * 2. Optionally provide an `insightInputProvider` callback that returns\n * the current `InsightInput` (recent turns + accumulated tokens) when\n * the host wants the in-session insight surface. Without this provider\n * the insight proposer is skipped.\n * 3. Pass both to `createRitualRegistry({ llm, insightInputProvider })`.\n * The `/curate` command is registered only when an LLMJudge is\n * supplied — instances that have not wired up a host LLM get the rest\n * of the rituals without a half-broken curate command.\n *\n * Result shape carries the full `Proposal` objects (with `onAccept` and\n * `onDecline` thunks). Hosts render the previews, ask the user to decide,\n * then call the thunks. This is the one command in `session-rituals`\n * whose result is intentionally non-serializable — the thunks are the\n * point.\n */\n\nexport interface CurateOptions {\n readonly llm: LLMJudge;\n /**\n * Returns the current InsightInput when the host wants the in-session\n * surface to run. Absence is a feature: hosts that only want hub\n * curation can omit it and the insight proposer is skipped without\n * error.\n */\n readonly insightInputProvider?: () => InsightInput | null;\n readonly insightProposer?: InsightProposer;\n readonly hubProposer?: HubProposer;\n}\n\nexport type CurateAnyProposal = InsightProposal | HubProposal;\n\nexport interface CurateResult {\n readonly subcommand: \"curate\";\n readonly status: \"ok\" | \"reset-declined\";\n readonly proposals: readonly CurateAnyProposal[];\n readonly skipped: {\n readonly insight: boolean;\n readonly hub: boolean;\n };\n readonly nextActions: readonly string[];\n}\n\ninterface CurateArgs {\n insightOnly?: boolean;\n hubOnly?: boolean;\n resetDeclined?: boolean;\n}\n\nfunction parseCurateArgs(input: string): CurateArgs {\n const args: CurateArgs = {};\n for (const t of input.split(/\\s+/).filter(Boolean)) {\n if (t === \"--insight\") args.insightOnly = true;\n else if (t === \"--hub\") args.hubOnly = true;\n else if (t === \"--reset-declined\") args.resetDeclined = true;\n }\n return args;\n}\n\n/**\n * Build the `/curate` command bound to a particular LLMJudge and optional\n * input provider. Returned as a factory so the registry can decide at\n * registration time whether to install the command at all.\n */\nexport function curateCommand(options: CurateOptions): Command<CurateResult> {\n const insightProposer = options.insightProposer ?? new InsightProposer({\n minTokensAccumulated: 2000,\n minTurnsBeforeFirstCheck: 6,\n });\n const hubProposer = options.hubProposer ?? new HubProposer({\n weakSignalAt: 3,\n strongSignalAt: 5,\n });\n\n return {\n name: \"curate\",\n description:\n \"Run proactive-curator proposers and surface any proposals. Flags: --insight | --hub | --reset-declined.\",\n args: [\n {\n name: \"flag\",\n description: \"Optional: --insight, --hub, or --reset-declined.\",\n required: false,\n },\n ],\n handler: async (input: CommandInput): Promise<CurateResult> => {\n const args = parseCurateArgs(input.rest);\n const { repoRoot } = input.context;\n const now = new Date();\n\n if (args.resetDeclined) {\n await resetDeclined(repoRoot);\n return {\n subcommand: \"curate\",\n status: \"reset-declined\",\n proposals: [],\n skipped: { insight: false, hub: false },\n nextActions: [\n \"Decline list cleared. Both insight and hub proposers will re-evaluate previously declined topics on the next /curate.\",\n ],\n };\n }\n\n const runInsight = !args.hubOnly;\n const runHub = !args.insightOnly;\n const declinedFingerprints = await loadDeclinedFingerprints(repoRoot, now);\n\n const proposals: CurateAnyProposal[] = [];\n let insightSkipped = !runInsight;\n let hubSkipped = !runHub;\n\n if (runInsight) {\n const insightInput = options.insightInputProvider?.() ?? null;\n if (!insightInput) {\n insightSkipped = true;\n } else {\n const p = await insightProposer.evaluate(insightInput, {\n cwd: repoRoot,\n declinedFingerprints,\n llm: options.llm,\n now,\n });\n if (p) proposals.push(p);\n }\n }\n\n if (runHub) {\n const p = await hubProposer.evaluate({}, {\n cwd: repoRoot,\n declinedFingerprints,\n llm: options.llm,\n now,\n });\n if (p) proposals.push(p);\n }\n\n const nextActions: string[] = [];\n if (proposals.length === 0) {\n nextActions.push(\"No proposals to surface right now.\");\n if (insightSkipped && hubSkipped) {\n nextActions.push(\"Both proposers were skipped — run /curate without flags to enable both.\");\n } else if (insightSkipped && runInsight) {\n nextActions.push(\"Insight proposer was skipped because no insightInputProvider was registered with this plugin.\");\n }\n } else {\n nextActions.push(\n `${proposals.length} proposal${proposals.length === 1 ? \"\" : \"s\"} ready. Review each preview and call onAccept() or onDecline() to apply or dismiss.`,\n );\n }\n\n return {\n subcommand: \"curate\",\n status: \"ok\",\n proposals,\n skipped: { insight: insightSkipped, hub: hubSkipped },\n nextActions,\n };\n },\n };\n}\n\nexport type { Proposal };\n","import { join } from \"node:path\";\r\n// Type-only — erased at compile time so the optional `memory-extended` add-on\r\n// (and its native sqlite/level deps) is NOT pulled into the module graph of a\r\n// base install. The runtime engine is loaded lazily inside the handler.\r\nimport type { vector, recall as recallNs } from \"@vortex-os/memory-extended\";\r\nimport type { Command, CommandInput } from \"@vortex-os/slash-commands\";\r\nimport type { ModuleContext } from \"@vortex-os/core\";\r\n\r\n/**\r\n * `/recall <query>` — hybrid semantic search over memories, defined in the\r\n * plugin over the `@vortex-os/memory-extended` engine (mirrors how\r\n * `/curate` is defined here over `proactive-curator`). Keeping the command\r\n * in the plugin lets the module stay free of any slash-commands dependency.\r\n *\r\n * Host integration:\r\n * 1. Supply an embedder. `vector.createLocalEmbedder()` is the bundled\r\n * default (local MiniLM, model downloads on first use); pass an\r\n * OpenAI/Voyage adapter to use an API instead.\r\n * 2. Pass it to `createRitualRegistry({ recall: { embed } })`. The command\r\n * is registered only when an embedder is supplied — instances that have\r\n * not wired one up get the rest of the rituals without a half-broken\r\n * recall command (same graceful-degradation rule as `/curate`).\r\n *\r\n * The handler returns the structured `RecallResult` (data, not a report —\r\n * operator decision 5 / 2026-05-29). The host renders a list with\r\n * `vector`/`recall` render helpers for an explicit search, or reads the\r\n * hits and phrases one in conversation for ambient use.\r\n */\r\n\r\nexport interface RecallOptions {\r\n /** Embedding function. `vector.createLocalEmbedder()` for the default. */\r\n readonly embed: vector.EmbedFn;\r\n /** Override the DB path. Default `<dataDir>/_indexes/memory.sqlite`. */\r\n readonly dbPath?: (ctx: ModuleContext) => string;\r\n /** Default hit count when `--k` is absent. Default 5. */\r\n readonly defaultK?: number;\r\n}\r\n\r\ninterface RecallArgs {\r\n k?: number;\r\n source?: vector.VectorSource;\r\n noHardFilter?: boolean;\r\n query: string;\r\n}\r\n\r\nfunction parseRecallArgs(rest: string, defaultK: number): RecallArgs {\r\n const tokens = rest.split(/\\s+/).filter(Boolean);\r\n const out: RecallArgs = { k: defaultK, query: \"\" };\r\n const queryParts: string[] = [];\r\n for (let i = 0; i < tokens.length; i++) {\r\n const t = tokens[i]!;\r\n if (t === \"--k\" && i + 1 < tokens.length) {\r\n const n = Number(tokens[++i]);\r\n if (Number.isFinite(n) && n > 0) out.k = Math.floor(n);\r\n } else if (t.startsWith(\"--k=\")) {\r\n const n = Number(t.slice(\"--k=\".length));\r\n if (Number.isFinite(n) && n > 0) out.k = Math.floor(n);\r\n } else if (t === \"--source\" && i + 1 < tokens.length) {\r\n out.source = tokens[++i] as vector.VectorSource;\r\n } else if (t.startsWith(\"--source=\")) {\r\n out.source = t.slice(\"--source=\".length) as vector.VectorSource;\r\n } else if (t === \"--no-filter\") {\r\n out.noHardFilter = true;\r\n } else {\r\n queryParts.push(t);\r\n }\r\n }\r\n out.query = queryParts.join(\" \");\r\n return out;\r\n}\r\n\r\nfunction defaultDbPath(ctx: ModuleContext): string {\r\n return join(ctx.dataDir, \"_indexes\", \"memory.sqlite\");\r\n}\r\n\r\nexport function recallCommand(options: RecallOptions): Command<recallNs.RecallResult> {\r\n const defaultK = options.defaultK ?? 5;\r\n const resolveDb = options.dbPath ?? defaultDbPath;\r\n\r\n return {\r\n name: \"recall\",\r\n description:\r\n \"Hybrid semantic search over memories. Usage: /recall <query> [--k N] [--source memory] [--no-filter].\",\r\n args: [{ name: \"query\", description: \"Natural-language query.\", required: true }],\r\n handler: async (input: CommandInput): Promise<recallNs.RecallResult> => {\r\n // Lazy-load the optional add-on. The command is only registered when an\r\n // embedder is supplied (see registry graceful-degradation), and base\r\n // ships without `memory-extended`; this resolves only when it is\r\n // installed alongside base.\r\n const { sqlite, vector, recall: recallEngine, sessionArchive } = await import(\r\n \"@vortex-os/memory-extended\"\r\n );\r\n const args = parseRecallArgs(input.rest, defaultK);\r\n const dbPath = resolveDb(input.context);\r\n\r\n if (args.query.trim().length === 0) {\r\n return {\r\n query: \"\",\r\n intent: { filters: {}, semanticText: \"\", notes: [\"empty query\"] },\r\n stage: { appliedFilters: {}, hardFilterCandidates: 0, hardFilterDropped: false, corpusSize: 0 },\r\n hits: [],\r\n };\r\n }\r\n\r\n const sqlStore = new sqlite.MemorySqliteStore(dbPath);\r\n const vecStore = new vector.MemoryVectorStore({ db: dbPath });\r\n\r\n // Lazy vectorization (A): fold any archived sessions not vectorized yet\r\n // into the index before searching. Session start does the cheap text\r\n // ingest; the heavier embedding lands here, the moment semantic search is\r\n // actually needed — so start stays fast and unused sessions cost nothing.\r\n // Best-effort: a missing archive or a rebuild hiccup must not fail recall.\r\n try {\r\n const archive = new sessionArchive.SessionArchiveStore(input.context.dataDir);\r\n try {\r\n await vecStore.rebuildSessions(archive, options.embed, { onlyMissing: true });\r\n } finally {\r\n archive.close();\r\n }\r\n } catch {\r\n // archive unavailable / rebuild failed — search whatever is already indexed\r\n }\r\n\r\n const chunkStore = new vector.SessionChunkStore(dbPath);\r\n try {\r\n return await recallEngine.recall(\r\n { query: args.query, k: args.k, source: args.source, noHardFilter: args.noHardFilter },\r\n { sqlite: sqlStore, vector: vecStore, embed: options.embed, sessionChunks: chunkStore },\r\n );\r\n } finally {\r\n chunkStore.close();\r\n vecStore.close();\r\n sqlStore.close();\r\n }\r\n },\r\n };\r\n}\r\n","import { writeFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport { existsSync } from \"node:fs\";\nimport { DecisionStore, renderTemplate } from \"@vortex-os/decision-log\";\nimport type { Command, CommandInput } from \"@vortex-os/slash-commands\";\n\nexport interface NewDecisionResult {\n readonly path: string;\n readonly date: string;\n readonly slug: string;\n}\n\n/**\n * `/decision <slug> <title...>` — Create a new Decision Log entry from\n * the canonical template at `data/decision-log/<today>-<slug>.md`.\n *\n * `slug` is required and used in the filename. The remaining tokens form\n * the entry title (the H1 in the rendered body). The command refuses to\n * overwrite an existing file — it errors out so the caller can decide.\n */\nexport const decisionCommand: Command<NewDecisionResult> = {\n name: \"decision\",\n description: \"Create a new Decision Log entry from the canonical template at `data/decision-log/<today>-<slug>.md`. Refuses to overwrite an existing file.\",\n args: [\n { name: \"slug\", description: \"Kebab-style identifier used in the filename.\", required: true },\n { name: \"title\", description: \"One-line decision title (rest of the input).\", required: true },\n ],\n handler: async (input: CommandInput): Promise<NewDecisionResult> => {\n const slug = input.args.slug;\n if (!slug) {\n throw new Error(\"`/decision` requires a slug argument.\");\n }\n // The runner already populated args.slug from the first token. The\n // title is `rest` minus that first token; recover it by taking the\n // raw input and stripping the leading \"decision <slug>\".\n const title = extractTitle(input.rest, slug);\n if (!title) {\n throw new Error(\"`/decision` requires a title after the slug.\");\n }\n\n const date = todayIso();\n const dir = join(input.context.dataDir, \"decision-log\");\n const store = new DecisionStore(dir);\n const path = store.pathFor(date, slug);\n\n if (existsSync(path)) {\n throw new Error(`Refusing to overwrite existing entry: ${path}`);\n }\n\n const body = renderTemplate({ date, slug, title });\n await writeFile(path, body, \"utf8\");\n return { path, date, slug };\n },\n};\n\nfunction extractTitle(rest: string, slug: string): string {\n const trimmed = rest.trim();\n if (trimmed.startsWith(slug)) {\n return trimmed.slice(slug.length).trim();\n }\n return trimmed;\n}\n\nfunction todayIso(): string {\n const d = new Date();\n const y = d.getFullYear();\n const m = String(d.getMonth() + 1).padStart(2, \"0\");\n const day = String(d.getDate()).padStart(2, \"0\");\n return `${y}-${m}-${day}`;\n}\n","import { existsSync } from \"node:fs\";\r\nimport { readFile, writeFile } from \"node:fs/promises\";\r\nimport { join } from \"node:path\";\r\nimport { renderIndex, scanDirectory } from \"@vortex-os/index-generator\";\r\nimport type { Command, CommandInput } from \"@vortex-os/slash-commands\";\r\n\r\ninterface ReindexTarget {\r\n readonly dir: string;\r\n readonly title: string;\r\n readonly description: string;\r\n readonly privacy: \"internal\" | \"personal\";\r\n readonly recursive: boolean;\r\n readonly skipPrefixes: readonly string[];\r\n readonly skipFilenames: readonly string[];\r\n}\r\n\r\nconst TARGETS: readonly ReindexTarget[] = [\r\n {\r\n dir: \"_memory\",\r\n title: \"Memory\",\r\n description:\r\n \"세션 간 공유되는 영속 메모리 항목들. MEMORY.md는 본 디렉토리의 원본 인덱스이며, 본 _INDEX.md는 사람·Obsidian 친화 양식의 파생물입니다.\",\r\n privacy: \"internal\",\r\n recursive: false,\r\n skipPrefixes: [],\r\n skipFilenames: [\"MEMORY.md\"],\r\n },\r\n {\r\n dir: \"worklog\",\r\n title: \"Worklog\",\r\n description: \"날짜별 작업 기록. `YYYY/MM/YYYY-MM-DD-keyword.md` 구조.\",\r\n privacy: \"internal\",\r\n recursive: true,\r\n skipPrefixes: [],\r\n skipFilenames: [],\r\n },\r\n {\r\n dir: \"decision-log\",\r\n title: \"Decision Log\",\r\n description: \"개인 의사결정 기록 — 왜 그걸 골랐는지를 남깁니다.\",\r\n privacy: \"personal\",\r\n recursive: false,\r\n skipPrefixes: [\"_TEMPLATE\"],\r\n skipFilenames: [],\r\n },\r\n {\r\n dir: \"runbooks\",\r\n title: \"Runbooks\",\r\n description: \"장애 대응·정기 정비 절차. `last_tested`로 갱신 기한 추적.\",\r\n privacy: \"internal\",\r\n recursive: false,\r\n skipPrefixes: [],\r\n skipFilenames: [],\r\n },\r\n {\r\n dir: \"hubs\",\r\n title: \"Hubs\",\r\n description: \"주제별 진입점 — 관련 자료를 한 곳에서 묶는 인덱스 페이지 모음.\",\r\n privacy: \"internal\",\r\n recursive: false,\r\n skipPrefixes: [],\r\n skipFilenames: [],\r\n },\r\n {\r\n dir: \"projects\",\r\n title: \"Projects\",\r\n description:\r\n \"진행 중·완료 프로젝트 모음 (Work·Home). 본 _INDEX는 평탄 목록이며, 하위 프로젝트 폴더별 _INDEX가 더 유용할 수 있음 (다음 사이클 검토).\",\r\n privacy: \"internal\",\r\n recursive: true,\r\n skipPrefixes: [],\r\n skipFilenames: [],\r\n },\r\n {\r\n dir: \"reference\",\r\n title: \"Reference\",\r\n description:\r\n \"AI 규칙·기술 치트시트·장비·스킬 등 레퍼런스 자료 (AI-Rules·Games·Gear·Infra·Org·Skills·Tech).\",\r\n privacy: \"internal\",\r\n recursive: true,\r\n skipPrefixes: [],\r\n skipFilenames: [],\r\n },\r\n {\r\n dir: \"reports\",\r\n title: \"Reports\",\r\n description:\r\n \"정기 건강검진 리포트 (Service-Health·Infra-Health). 시점 스냅샷 누적.\",\r\n privacy: \"internal\",\r\n recursive: true,\r\n skipPrefixes: [],\r\n skipFilenames: [],\r\n },\r\n {\r\n dir: \"inbox\",\r\n title: \"Inbox\",\r\n description:\r\n \"미분류 임시 메모·아이디어·백로그. 정식 분류 시 해당 카테고리로 이동.\",\r\n privacy: \"internal\",\r\n recursive: true,\r\n skipPrefixes: [],\r\n skipFilenames: [],\r\n },\r\n {\r\n dir: \"_templates\",\r\n title: \"Templates\",\r\n description: \"보고용·공유용 자료 템플릿 모음 (Sharing 등).\",\r\n privacy: \"internal\",\r\n recursive: true,\r\n skipPrefixes: [],\r\n skipFilenames: [],\r\n },\r\n];\r\n\r\nexport interface ReindexResult {\r\n readonly dir: string;\r\n readonly status: \"written\" | \"unchanged\" | \"missing\";\r\n readonly entries: number;\r\n readonly bytes: number;\r\n}\r\n\r\n/**\r\n * `/reindex [dir]` — Regenerate `_INDEX.md` for one or all known data\r\n * directories. When called with no argument, processes all targets;\r\n * when called with a directory name, processes only that target.\r\n *\r\n * Returns a list of results so the host can summarize. Unchanged\r\n * indexes are reported as `unchanged` (no write performed); missing\r\n * directories are reported as `missing` (no write attempted).\r\n */\r\nexport const reindexCommand: Command<readonly ReindexResult[]> = {\r\n name: \"reindex\",\r\n description:\r\n \"Regenerate _INDEX.md for any configured target directory (or all targets when called with no argument). Idempotent — unchanged indexes are not rewritten.\",\r\n args: [\r\n {\r\n name: \"dir\",\r\n description: \"Optional directory name. Omit to reindex all targets.\",\r\n },\r\n ],\r\n handler: async (input: CommandInput): Promise<readonly ReindexResult[]> => {\r\n const requested = input.args.dir;\r\n const targets = requested\r\n ? TARGETS.filter((t) => t.dir === requested)\r\n : TARGETS;\r\n\r\n if (requested && targets.length === 0) {\r\n throw new Error(\r\n `Unknown reindex target: \"${requested}\". Known: ${TARGETS.map((t) => t.dir).join(\", \")}`,\r\n );\r\n }\r\n\r\n const results: ReindexResult[] = [];\r\n for (const t of targets) {\r\n const dir = join(input.context.dataDir, t.dir);\r\n if (!existsSync(dir)) {\r\n results.push({ dir: t.dir, status: \"missing\", entries: 0, bytes: 0 });\r\n continue;\r\n }\r\n\r\n const entries = await scanDirectory(dir, {\r\n recursive: t.recursive,\r\n skipPrefixes: t.skipPrefixes,\r\n skipFilenames: t.skipFilenames,\r\n });\r\n const body = renderIndex({\r\n title: t.title,\r\n description: t.description,\r\n entries,\r\n privacy: t.privacy,\r\n });\r\n\r\n const target = join(dir, \"_INDEX.md\");\r\n let existing;\r\n try {\r\n existing = await readFile(target, \"utf8\");\r\n } catch {\r\n existing = undefined;\r\n }\r\n if (existing === body) {\r\n results.push({\r\n dir: t.dir,\r\n status: \"unchanged\",\r\n entries: entries.length,\r\n bytes: body.length,\r\n });\r\n continue;\r\n }\r\n\r\n await writeFile(target, body, \"utf8\");\r\n results.push({\r\n dir: t.dir,\r\n status: \"written\",\r\n entries: entries.length,\r\n bytes: body.length,\r\n });\r\n }\r\n return results;\r\n },\r\n};\r\n","import { existsSync } from \"node:fs\";\r\nimport { readdir } from \"node:fs/promises\";\r\nimport { join } from \"node:path\";\r\nimport type { Command, CommandInput } from \"@vortex-os/slash-commands\";\r\n\r\n/**\r\n * Output of {@link sessionStartCommand}'s handler. Pure data — the host\r\n * decides how to display it. Returning structured output rather than\r\n * printing keeps the command usable from non-CLI hosts (tests, web UIs).\r\n */\r\nexport interface SessionStartReport {\r\n readonly time: string;\r\n readonly repoRoot: string;\r\n readonly dataDir: string;\r\n readonly counts: Readonly<Record<string, number>>;\r\n readonly missing: readonly string[];\r\n}\r\n\r\nconst COUNTED_DIRS: readonly string[] = [\"_memory\", \"worklog\", \"decision-log\"];\r\n\r\n/**\r\n * `/session-start` — Emit a small report that anchors a new session.\r\n * No side effects: reads filesystem counts only.\r\n *\r\n * The host (e.g. Claude Code session loop) is expected to display the\r\n * report and decide what to do next. This command's job is to surface\r\n * the facts, not to take action.\r\n */\r\nexport const sessionStartCommand: Command<SessionStartReport> = {\r\n name: \"session-start\",\r\n description: \"Emit a start-of-session report (time + data directory counts).\",\r\n handler: async (input: CommandInput): Promise<SessionStartReport> => {\r\n const { dataDir, repoRoot } = input.context;\r\n const counts: Record<string, number> = {};\r\n const missing: string[] = [];\r\n\r\n for (const name of COUNTED_DIRS) {\r\n const dir = join(dataDir, name);\r\n if (!existsSync(dir)) {\r\n missing.push(name);\r\n counts[name] = 0;\r\n continue;\r\n }\r\n counts[name] = await countMarkdown(dir, name === \"worklog\");\r\n }\r\n\r\n return {\r\n time: new Date().toISOString(),\r\n repoRoot,\r\n dataDir,\r\n counts,\r\n missing,\r\n };\r\n },\r\n};\r\n\r\nasync function countMarkdown(dir: string, recursive: boolean): Promise<number> {\r\n let total = 0;\r\n const entries = await readdir(dir, { withFileTypes: true });\r\n for (const e of entries) {\r\n if (e.isFile()) {\r\n if (!e.name.endsWith(\".md\")) continue;\r\n if (e.name === \"README.md\" || e.name === \"_INDEX.md\" || e.name === \"MEMORY.md\") {\r\n continue;\r\n }\r\n if (e.name.startsWith(\"_TEMPLATE\")) continue;\r\n total++;\r\n } else if (e.isDirectory() && recursive) {\r\n if (e.name.startsWith(\".\") || e.name.startsWith(\"_\")) continue;\r\n total += await countMarkdown(join(dir, e.name), recursive);\r\n }\r\n }\r\n return total;\r\n}\r\n","import type { Command, CommandInput } from \"@vortex-os/slash-commands\";\r\nimport { WorklogStore, appendSection } from \"@vortex-os/worklog\";\r\n\r\nexport interface WorklogAppendResult {\r\n readonly path: string;\r\n readonly date: string;\r\n readonly keyword: string;\r\n readonly sectionTitle: string;\r\n}\r\n\r\n/**\r\n * `/log <section-title>` — Append a `## <section-title>` section to today's\r\n * worklog entry. If no worklog exists for today, the command errors (entry\r\n * creation with frontmatter is left to the host so it can apply\r\n * project-specific conventions). The body of the new section is left empty\r\n * for the caller to fill in.\r\n *\r\n * This is a deliberately small command — the goal is to make \"add a quick\r\n * note to today's worklog\" a one-liner, not to replace a real editor.\r\n */\r\nexport const logCommand: Command<WorklogAppendResult> = {\r\n name: \"log\",\r\n description: \"Append a `## <section-title>` section to today's worklog entry. Throws if today's worklog does not exist (run `/vortex init` once to bootstrap).\",\r\n args: [\r\n {\r\n name: \"section\",\r\n description: \"Title for the new `## ` section (rest of the input).\",\r\n required: true,\r\n },\r\n ],\r\n handler: async (input: CommandInput): Promise<WorklogAppendResult> => {\r\n const sectionTitle = input.rest.trim();\r\n if (!sectionTitle) {\r\n throw new Error(\"`/log` requires a section title.\");\r\n }\r\n\r\n const date = todayIso();\r\n const store = new WorklogStore(`${input.context.dataDir}/worklog`);\r\n const todayEntry = await store.get(date);\r\n if (!todayEntry) {\r\n throw new Error(\r\n `No worklog entry exists for ${date}. Create one first; this command only appends sections.`,\r\n );\r\n }\r\n\r\n await appendSection(todayEntry, sectionTitle, \"\");\r\n return {\r\n path: todayEntry.path,\r\n date: todayEntry.date,\r\n keyword: todayEntry.keyword,\r\n sectionTitle,\r\n };\r\n },\r\n};\r\n\r\nfunction todayIso(): string {\r\n const d = new Date();\r\n const y = d.getFullYear();\r\n const m = String(d.getMonth() + 1).padStart(2, \"0\");\r\n const day = String(d.getDate()).padStart(2, \"0\");\r\n return `${y}-${m}-${day}`;\r\n}\r\n","import { spawn } from \"node:child_process\";\r\nimport { existsSync } from \"node:fs\";\r\nimport { copyFile, mkdir, readdir, readFile, stat, writeFile } from \"node:fs/promises\";\r\nimport { basename, dirname, join } from \"node:path\";\r\nimport { fileURLToPath } from \"node:url\";\r\nimport { parseFrontmatter, serializeFrontmatter } from \"@vortex-os/core\";\r\nimport {\r\n lintDirectory,\r\n privacyValid,\r\n requireFrontmatter,\r\n wikiLinkResolves,\r\n} from \"@vortex-os/data-lint\";\r\nimport { checkDirectory } from \"@vortex-os/link-rewriter\";\r\nimport { WorklogStore } from \"@vortex-os/worklog\";\r\nimport type { Command, CommandInput } from \"@vortex-os/slash-commands\";\r\nimport {\r\n ensureVortexHooks,\r\n parseSettings,\r\n serializeSettings,\r\n} from \"../ensure-hooks.js\";\r\n\r\n/**\r\n * `/vortex <sub>` — Root command for VortEX instance operations.\r\n *\r\n * Subcommands:\r\n * init — first-time setup wizard (user profile + first worklog; detects\r\n * external folders in $HOME and surfaces an import hint)\r\n * status — instance state report (counts, profile, latestWorklog, missing)\r\n * import — copy a folder into the instance, auto-classify into 5 categories\r\n * or preserve user folder structure, inject frontmatter, scan\r\n * wiki-link health via @vortex-os/link-rewriter\r\n * doctor — 8-check health diagnosis (system dirs, profile, indexes,\r\n * wiki links, data-lint rules, runbook aging, node version,\r\n * git remote)\r\n * sync — framework-developer workflow: git pull → npm install → npm run\r\n * build → npm run verify. Stops on first failure with stdout/stderr\r\n * tail. End users who consume vortex from npm registry do not need\r\n * this — they get pre-built dist via `npm install @vortex-os/*`.\r\n * help — list available subcommands\r\n */\r\n\r\n// Reserved subcommand slot. Adding a future stub-then-promoted subcommand\r\n// (e.g. /vortex export, /vortex link-rewrite) only needs an entry here + the\r\n// `not-implemented` advertisement branch below. The unknown-subcommand branch\r\n// handles user typos either way.\r\nconst PLANNED_SUBS = [] as const;\r\ntype PlannedSub = (typeof PLANNED_SUBS)[number];\r\n\r\nexport interface VortexInitResult {\r\n readonly subcommand: \"init\";\r\n readonly status: \"completed\" | \"needs-input\" | \"already-initialized\";\r\n readonly created: readonly string[];\r\n readonly nextActions: readonly string[];\r\n readonly missingInputs?: readonly { name: string; prompt: string }[];\r\n readonly externalFolders?: readonly {\r\n readonly path: string;\r\n readonly basename: string;\r\n readonly mdCount: number;\r\n }[];\r\n}\r\n\r\nexport interface VortexPlannedResult {\r\n readonly subcommand: PlannedSub | \"unknown\";\r\n readonly status: \"not-implemented\";\r\n readonly message: string;\r\n}\r\n\r\nexport interface VortexHelpResult {\r\n readonly subcommand: \"help\";\r\n readonly status: \"ok\";\r\n /** `/vortex <sub>` subcommands routed inside this command. */\r\n readonly subcommands: readonly {\r\n readonly name: string;\r\n readonly description: string;\r\n readonly state: \"active\" | \"planned\";\r\n }[];\r\n /**\r\n * Other top-level slash commands shipped by the same plugin\r\n * (`session-rituals`). Independent commands, not `/vortex` subcommands —\r\n * surfaced here so users discover the full plugin surface from a single\r\n * `/vortex help` call instead of needing to know they exist separately.\r\n */\r\n readonly siblingCommands: readonly {\r\n readonly name: string;\r\n readonly description: string;\r\n }[];\r\n}\r\n\r\nexport interface VortexStatusResult {\r\n readonly subcommand: \"status\";\r\n readonly status: \"ok\" | \"uninitialized\";\r\n readonly instance: {\r\n readonly dataDir: string;\r\n readonly initialized: boolean;\r\n readonly profile?: { readonly name?: string; readonly role?: string };\r\n };\r\n readonly counts: {\r\n readonly memory: number;\r\n readonly worklog: number;\r\n readonly decisionLog: number;\r\n readonly runbooks: number;\r\n readonly hubs: number;\r\n };\r\n readonly latestWorklog?: {\r\n readonly date: string;\r\n readonly keyword: string;\r\n readonly path: string;\r\n };\r\n readonly missing: readonly string[];\r\n readonly nextActions: readonly string[];\r\n}\r\n\r\nexport interface VortexImportResult {\r\n readonly subcommand: \"import\";\r\n readonly status: \"completed\" | \"dry-run\" | \"needs-input\" | \"source-missing\";\r\n readonly source?: string;\r\n readonly totalFiles: number;\r\n readonly copied: number;\r\n readonly classified: {\r\n readonly worklog: number;\r\n readonly decisionLog: number;\r\n readonly runbooks: number;\r\n readonly hubs: number;\r\n readonly memory: number;\r\n readonly preserved: number;\r\n };\r\n readonly frontmatterInjected: number;\r\n readonly frontmatterPreserved: number;\r\n readonly systemDirsCreated: readonly string[];\r\n readonly skipped: number;\r\n readonly links?: {\r\n readonly filesScanned: number;\r\n readonly total: number;\r\n readonly resolved: number;\r\n readonly broken: number;\r\n readonly ambiguous: number;\r\n };\r\n readonly missingInputs?: readonly { name: string; prompt: string }[];\r\n readonly nextActions: readonly string[];\r\n}\r\n\r\nexport type DoctorCheckStatus = \"pass\" | \"warn\" | \"fail\" | \"info\";\r\n\r\nexport interface DoctorCheck {\r\n readonly id: string;\r\n readonly label: string;\r\n readonly status: DoctorCheckStatus;\r\n readonly detail?: string;\r\n}\r\n\r\nexport interface VortexDoctorResult {\r\n readonly subcommand: \"doctor\";\r\n readonly status: \"ok\" | \"warnings\" | \"errors\";\r\n readonly checks: readonly DoctorCheck[];\r\n readonly summary: {\r\n readonly pass: number;\r\n readonly warn: number;\r\n readonly fail: number;\r\n readonly info: number;\r\n };\r\n readonly nextActions: readonly string[];\r\n}\r\n\r\nexport type VortexSyncStepId = \"pull\" | \"install\" | \"build\" | \"verify\";\r\nexport type VortexSyncStepStatus = \"ok\" | \"failed\" | \"skipped\";\r\n\r\nexport interface VortexSyncStep {\r\n readonly id: VortexSyncStepId;\r\n readonly label: string;\r\n readonly status: VortexSyncStepStatus;\r\n readonly exitCode?: number;\r\n readonly durationMs?: number;\r\n readonly stdoutTail?: string;\r\n readonly stderrTail?: string;\r\n}\r\n\r\nexport interface VortexSyncResult {\r\n readonly subcommand: \"sync\";\r\n readonly status: \"completed\" | \"failed\" | \"dry-run\";\r\n readonly steps: readonly VortexSyncStep[];\r\n readonly failedAt?: VortexSyncStepId;\r\n readonly nextActions: readonly string[];\r\n}\r\n\r\nexport type VortexResult =\r\n | VortexInitResult\r\n | VortexStatusResult\r\n | VortexImportResult\r\n | VortexDoctorResult\r\n | VortexSyncResult\r\n | VortexPlannedResult\r\n | VortexHelpResult;\r\n\r\nexport const vortexCommand: Command<VortexResult> = {\r\n name: \"vortex\",\r\n description:\r\n \"VortEX root command. Subcommands: init | status | import | doctor | sync | help.\",\r\n args: [\r\n {\r\n name: \"sub\",\r\n description: \"Subcommand (init|status|import|doctor|sync|help).\",\r\n required: false,\r\n },\r\n ],\r\n handler: async (input: CommandInput): Promise<VortexResult> => {\r\n const tokens = tokenize(input.rest);\r\n const sub = (tokens[0] ?? \"help\") as string;\r\n const restAfterSub = tokens.slice(1);\r\n\r\n if (sub === \"init\") return runInit(input, restAfterSub);\r\n if (sub === \"status\") return runStatus(input);\r\n if (sub === \"import\") return runImport(input, restAfterSub);\r\n if (sub === \"doctor\") return runDoctor(input);\r\n if (sub === \"sync\") return runSync(input, restAfterSub);\r\n if (sub === \"help\" || sub === \"\") return runHelp();\r\n if ((PLANNED_SUBS as readonly string[]).includes(sub)) {\r\n return {\r\n subcommand: sub as PlannedSub,\r\n status: \"not-implemented\",\r\n message:\r\n `\\`/vortex ${sub}\\` is reserved but not yet implemented. ` +\r\n `Planned in a future phase. Run \\`/vortex help\\` for available subcommands.`,\r\n };\r\n }\r\n return {\r\n subcommand: \"unknown\",\r\n status: \"not-implemented\",\r\n message: `Unknown subcommand \"${sub}\". Run \\`/vortex help\\` for the list.`,\r\n };\r\n },\r\n};\r\n\r\nfunction runHelp(): VortexHelpResult {\r\n return {\r\n subcommand: \"help\",\r\n status: \"ok\",\r\n subcommands: [\r\n {\r\n name: \"init\",\r\n description:\r\n \"First-time setup wizard. Creates user profile memory and first worklog (hubs grow organically — not seeded here).\",\r\n state: \"active\",\r\n },\r\n {\r\n name: \"status\",\r\n description:\r\n \"Show instance state (memory count, latest worklog, missing skeletons).\",\r\n state: \"active\",\r\n },\r\n {\r\n name: \"import\",\r\n description:\r\n \"Bring an existing folder into data/ — preserves your folder structure, auto-classifies worklog/decision-log/runbooks/hubs/_memory files, injects missing frontmatter.\",\r\n state: \"active\",\r\n },\r\n {\r\n name: \"doctor\",\r\n description:\r\n \"Diagnose instance health (system dirs, profile, indexes, wiki links, frontmatter, runbook freshness, node version, git remote).\",\r\n state: \"active\",\r\n },\r\n {\r\n name: \"sync\",\r\n description:\r\n \"Framework-developer workflow: git pull → npm install → npm run build → npm run verify. Stops on first failure. End users on npm registry do not need this.\",\r\n state: \"active\",\r\n },\r\n { name: \"help\", description: \"Show this list.\", state: \"active\" },\r\n ],\r\n siblingCommands: [\r\n {\r\n name: \"session-start\",\r\n description:\r\n \"Emit a start-of-session report (time + data directory counts + missing dirs).\",\r\n },\r\n {\r\n name: \"log\",\r\n description:\r\n \"Append a `## <section-title>` section to today's worklog entry. Throws if today's worklog does not exist (run `/vortex init` once to bootstrap).\",\r\n },\r\n {\r\n name: \"decision\",\r\n description:\r\n \"Create a new Decision Log entry from the canonical template at `data/decision-log/<today>-<slug>.md`. Refuses to overwrite an existing file.\",\r\n },\r\n {\r\n name: \"reindex\",\r\n description:\r\n \"Regenerate _INDEX.md for any configured target directory (or all targets when called with no argument). Idempotent — unchanged indexes are not rewritten.\",\r\n },\r\n ],\r\n };\r\n}\r\n\r\ninterface InitArgs {\r\n name?: string;\r\n role?: string;\r\n task?: string;\r\n force?: boolean;\r\n}\r\n\r\n/**\r\n * Copy the agent-mediated slash-command prompts (templates/commands/*.md) into\r\n * the instance's `.claude/commands/` so the host (Claude Code) exposes /recall,\r\n * /agenda, … — each is a prompt that runs the `vortex` CLI and lets the agent\r\n * present/judge the result. Non-destructive: a command file the user already\r\n * customized is left untouched. Returns the paths written.\r\n */\r\nasync function installCommandTemplates(repoRoot: string): Promise<string[]> {\r\n const here = dirname(fileURLToPath(import.meta.url)); // <pkg>/dist/commands\r\n const templatesDir = join(here, \"..\", \"..\", \"templates\", \"commands\");\r\n if (!existsSync(templatesDir)) return [];\r\n const destDir = join(repoRoot, \".claude\", \"commands\");\r\n await mkdir(destDir, { recursive: true });\r\n const written: string[] = [];\r\n for (const name of await readdir(templatesDir)) {\r\n if (!name.endsWith(\".md\")) continue;\r\n const dest = join(destDir, name);\r\n if (existsSync(dest)) continue;\r\n await copyFile(join(templatesDir, name), dest);\r\n written.push(dest);\r\n }\r\n return written;\r\n}\r\n\r\nasync function runInit(\r\n input: CommandInput,\r\n tokens: readonly string[],\r\n): Promise<VortexInitResult> {\r\n const args = parseInitArgs(tokens);\r\n const { dataDir } = input.context;\r\n\r\n const requiredDirs = [\"_memory\", \"worklog\", \"decision-log\", \"hubs\", \"inbox\", \"runbooks\"];\r\n for (const d of requiredDirs) {\r\n const p = join(dataDir, d);\r\n if (!existsSync(p)) await mkdir(p, { recursive: true });\r\n }\r\n\r\n const profilePath = join(dataDir, \"_memory\", \"user_profile.md\");\r\n if (existsSync(profilePath) && !args.force) {\r\n return {\r\n subcommand: \"init\",\r\n status: \"already-initialized\",\r\n created: [],\r\n nextActions: [\r\n `VortEX instance is already initialized (${profilePath} exists).`,\r\n \"To re-run, pass `--force` (existing user_profile / first worklog / first hub will be overwritten).\",\r\n \"To check current state, try `/session-start`.\",\r\n ],\r\n };\r\n }\r\n\r\n const missing: { name: string; prompt: string }[] = [];\r\n if (!args.name) {\r\n missing.push({\r\n name: \"name\",\r\n prompt:\r\n 'What name or handle should VortEX use for you? (e.g. \"Alex\" or \"team-lead\")',\r\n });\r\n }\r\n if (!args.role) {\r\n missing.push({\r\n name: \"role\",\r\n prompt:\r\n 'What is your main role in one word? (e.g. \"engineer\", \"researcher\", \"writer\")',\r\n });\r\n }\r\n if (!args.task) {\r\n missing.push({\r\n name: \"task\",\r\n prompt:\r\n \"What is one thing you're working on right now? (one sentence — this becomes your first worklog seed)\",\r\n });\r\n }\r\n\r\n if (missing.length > 0) {\r\n return {\r\n subcommand: \"init\",\r\n status: \"needs-input\",\r\n created: [],\r\n missingInputs: missing,\r\n nextActions: [\r\n \"Ask the user the prompts in `missingInputs`, then re-run with the answers:\",\r\n ' /vortex init --name \"<name>\" --role \"<role>\" --task \"<task>\"',\r\n \"Optional: append `--force` to overwrite an already-initialized instance.\",\r\n ],\r\n };\r\n }\r\n\r\n const today = todayIso();\r\n const created: string[] = [];\r\n\r\n await writeFile(\r\n profilePath,\r\n renderUserProfile(args.name!, args.role!, args.task!, today),\r\n \"utf8\",\r\n );\r\n created.push(profilePath);\r\n\r\n const [year, month] = today.split(\"-\");\r\n const worklogDir = join(dataDir, \"worklog\", year!, month!);\r\n await mkdir(worklogDir, { recursive: true });\r\n const worklogPath = join(worklogDir, `${today}-vortex-init.md`);\r\n await writeFile(\r\n worklogPath,\r\n renderFirstWorklog(args.name!, args.role!, args.task!, today),\r\n \"utf8\",\r\n );\r\n created.push(worklogPath);\r\n\r\n // Wire the SessionStart / SessionEnd hooks into .claude/settings.json so the\r\n // boot report + worklog net fire automatically — without the user knowing any\r\n // command. Non-destructive: only adds our entries if absent; a malformed\r\n // settings file is reported (never overwritten) and init still completes.\r\n const hookNotes: string[] = [];\r\n try {\r\n const settingsPath = join(input.context.repoRoot, \".claude\", \"settings.json\");\r\n const existingText = existsSync(settingsPath) ? await readFile(settingsPath, \"utf8\") : null;\r\n const { settings, added, alreadyWired } = ensureVortexHooks(parseSettings(existingText));\r\n if (!alreadyWired) {\r\n await mkdir(join(input.context.repoRoot, \".claude\"), { recursive: true });\r\n await writeFile(settingsPath, serializeSettings(settings), \"utf8\");\r\n created.push(settingsPath);\r\n hookNotes.push(\r\n `Wired ${added.join(\" + \")} hook(s) into .claude/settings.json — the VortEX boot report runs automatically at session start.`,\r\n );\r\n } else {\r\n hookNotes.push(\"Session hooks already wired in .claude/settings.json.\");\r\n }\r\n } catch (e) {\r\n hookNotes.push(\r\n `⚠️ Could not wire session hooks automatically: ${(e as Error).message} ` +\r\n \"Copy .claude/settings.example.json to .claude/settings.json by hand to enable the boot report.\",\r\n );\r\n }\r\n\r\n // Install the agent-mediated slash commands so the host exposes /recall,\r\n // /agenda, … — prompts that run the `vortex` CLI and let the agent present\r\n // the result. Non-destructive (keeps any command the user has customized).\r\n try {\r\n const cmds = await installCommandTemplates(input.context.repoRoot);\r\n created.push(...cmds);\r\n if (cmds.length > 0) {\r\n hookNotes.push(\r\n `Installed ${cmds.length} slash command(s) into .claude/commands/ (${cmds.map((c) => \"/\" + basename(c, \".md\")).join(\", \")}).`,\r\n );\r\n }\r\n } catch (e) {\r\n hookNotes.push(`⚠️ Could not install slash commands: ${(e as Error).message}`);\r\n }\r\n\r\n const externalFolders = await detectExternalFolders(input.context.repoRoot);\r\n\r\n const baseNext = [\r\n `Done. Created ${created.length} files.`,\r\n ...hookNotes,\r\n \"Next 3 things you can try right now:\",\r\n \" /log <one-line update> — append a section to today's worklog\",\r\n \" /decision <slug> <title> — record a decision\",\r\n \" /session-start — daily start-of-session report\",\r\n `Open ${worklogPath} to see your first worklog — it already names \"${args.task!}\".`,\r\n \"Hubs grow organically: once 3+ categories accumulate on the same topic, create `hubs/_HUB-<topic>.md` to cross-link them.\",\r\n ];\r\n\r\n const importPrompt: string[] = [];\r\n if (externalFolders && externalFolders.length > 0) {\r\n importPrompt.push(\"\");\r\n importPrompt.push(\r\n \"📁 Detected existing folders that look like notes/vaults you may want to import:\",\r\n );\r\n for (const f of externalFolders) {\r\n importPrompt.push(` - ${f.path} (${f.mdCount} .md files)`);\r\n }\r\n importPrompt.push(\" Import any of them now with:\");\r\n for (const f of externalFolders) {\r\n importPrompt.push(` /vortex import --from \"${f.path}\"`);\r\n }\r\n importPrompt.push(\r\n \" (Append --dry-run first to preview without copying. You can also do this later — these folders are not modified.)\",\r\n );\r\n }\r\n\r\n return {\r\n subcommand: \"init\",\r\n status: \"completed\",\r\n created,\r\n externalFolders,\r\n nextActions: [...baseNext, ...importPrompt],\r\n };\r\n}\r\n\r\nfunction parseInitArgs(tokens: readonly string[]): InitArgs {\r\n const args: InitArgs = {};\r\n for (let i = 0; i < tokens.length; i++) {\r\n const t = tokens[i]!;\r\n if (t === \"--force\") {\r\n args.force = true;\r\n continue;\r\n }\r\n if (t === \"--name\" && i + 1 < tokens.length) {\r\n args.name = tokens[++i];\r\n continue;\r\n }\r\n if (t === \"--role\" && i + 1 < tokens.length) {\r\n args.role = tokens[++i];\r\n continue;\r\n }\r\n if (t === \"--task\" && i + 1 < tokens.length) {\r\n args.task = tokens[++i];\r\n continue;\r\n }\r\n }\r\n return args;\r\n}\r\n\r\n/** Quote-aware tokenizer: supports \"double\" and 'single' quotes. */\r\nfunction tokenize(s: string): string[] {\r\n const out: string[] = [];\r\n let i = 0;\r\n while (i < s.length) {\r\n while (i < s.length && /\\s/.test(s[i]!)) i++;\r\n if (i >= s.length) break;\r\n const ch = s[i]!;\r\n if (ch === '\"' || ch === \"'\") {\r\n const quote = ch;\r\n i++;\r\n let buf = \"\";\r\n while (i < s.length && s[i] !== quote) {\r\n buf += s[i++];\r\n }\r\n if (i < s.length) i++;\r\n out.push(buf);\r\n } else {\r\n let buf = \"\";\r\n while (i < s.length && !/\\s/.test(s[i]!)) {\r\n buf += s[i++];\r\n }\r\n out.push(buf);\r\n }\r\n }\r\n return out;\r\n}\r\n\r\nfunction renderUserProfile(\r\n name: string,\r\n role: string,\r\n task: string,\r\n date: string,\r\n): string {\r\n return `---\r\nname: user-profile\r\ndescription: Operator profile captured by /vortex init.\r\ntype: user\r\ncreated: ${date}\r\nupdated: ${date}\r\n---\r\n\r\n# User Profile\r\n\r\n- **Name/handle**: ${name}\r\n- **Role**: ${role}\r\n- **Initial focus**: ${task}\r\n\r\nThis memory was created by \\`/vortex init\\` on ${date}. Edit freely as your role evolves.\r\n`;\r\n}\r\n\r\nfunction renderFirstWorklog(\r\n name: string,\r\n role: string,\r\n task: string,\r\n date: string,\r\n): string {\r\n return `---\r\ntype: worklog\r\nstatus: active\r\ncreated: ${date}\r\nupdated: ${date}\r\ntags: [worklog, onboarding]\r\n---\r\n\r\n# ${date} — VortEX 시작\r\n\r\n> First worklog, created by \\`/vortex init\\`. ${name} (${role}). Today's focus: ${task}\r\n\r\n## What I'm working on\r\n\r\n${task}\r\n\r\n## Notes\r\n\r\n(append more with \\`/log <section-title>\\`)\r\n\r\n## Next\r\n\r\n- [ ] Try \\`/decision <slug> <title>\\` for your first decision record\r\n- [ ] Add a memory by editing \\`data/_memory/user_profile.md\\` or creating new ones\r\n- [ ] Run \\`/session-start\\` tomorrow to see your accumulated state\r\n`;\r\n}\r\n\r\nfunction todayIso(): string {\r\n const d = new Date();\r\n const y = d.getFullYear();\r\n const m = String(d.getMonth() + 1).padStart(2, \"0\");\r\n const day = String(d.getDate()).padStart(2, \"0\");\r\n return `${y}-${m}-${day}`;\r\n}\r\n\r\nconst COUNT_KEY_TO_DIR: Record<keyof VortexStatusResult[\"counts\"], string> = {\r\n memory: \"_memory\",\r\n worklog: \"worklog\",\r\n decisionLog: \"decision-log\",\r\n runbooks: \"runbooks\",\r\n hubs: \"hubs\",\r\n};\r\n\r\nasync function runStatus(input: CommandInput): Promise<VortexStatusResult> {\r\n const { dataDir } = input.context;\r\n const profilePath = join(dataDir, \"_memory\", \"user_profile.md\");\r\n const initialized = existsSync(profilePath);\r\n\r\n const counts = {\r\n memory: await safeCount(join(dataDir, \"_memory\"), false),\r\n worklog: await safeCount(join(dataDir, \"worklog\"), true),\r\n decisionLog: await safeCount(join(dataDir, \"decision-log\"), false),\r\n runbooks: await safeCount(join(dataDir, \"runbooks\"), false),\r\n hubs: await safeCount(join(dataDir, \"hubs\"), false),\r\n };\r\n\r\n let latestWorklog: VortexStatusResult[\"latestWorklog\"];\r\n try {\r\n const store = new WorklogStore(join(dataDir, \"worklog\"));\r\n const latest = await store.getLatest();\r\n if (latest) {\r\n latestWorklog = {\r\n date: latest.date,\r\n keyword: latest.keyword,\r\n path: latest.path,\r\n };\r\n }\r\n } catch {\r\n // worklog dir missing or unreadable — leave undefined\r\n }\r\n\r\n let profile: VortexStatusResult[\"instance\"][\"profile\"];\r\n if (initialized) {\r\n try {\r\n const raw = await readFile(profilePath, \"utf8\");\r\n const { body } = parseFrontmatter<Record<string, unknown>>(raw);\r\n profile = extractProfile(body);\r\n } catch {\r\n // unreadable — leave undefined\r\n }\r\n }\r\n\r\n const missing: string[] = [];\r\n if (!initialized) {\r\n missing.push(\"_memory/user_profile.md — run `/vortex init`\");\r\n }\r\n for (const [key, count] of Object.entries(counts) as [\r\n keyof typeof counts,\r\n number,\r\n ][]) {\r\n if (count === 0) {\r\n const dirName = COUNT_KEY_TO_DIR[key];\r\n const dirPath = join(dataDir, dirName);\r\n missing.push(\r\n existsSync(dirPath)\r\n ? `${dirName}/ is empty`\r\n : `${dirName}/ does not exist`,\r\n );\r\n }\r\n }\r\n\r\n const nextActions: string[] = [];\r\n if (!initialized) {\r\n nextActions.push(\"Run `/vortex init --name <name> --role <role> --task <task>` to set up this instance.\");\r\n } else {\r\n nextActions.push(\r\n \"Run `/session-start` for a fuller session-opening report.\",\r\n \"Run `/log <section-title>` to append a section to today's worklog.\",\r\n );\r\n if (counts.decisionLog === 0) {\r\n nextActions.push(\"Try `/decision <slug> <title>` to record your first decision.\");\r\n }\r\n }\r\n\r\n return {\r\n subcommand: \"status\",\r\n status: initialized ? \"ok\" : \"uninitialized\",\r\n instance: { dataDir, initialized, profile },\r\n counts,\r\n latestWorklog,\r\n missing,\r\n nextActions,\r\n };\r\n}\r\n\r\nfunction extractProfile(\r\n body: string,\r\n): { name?: string; role?: string } | undefined {\r\n const nameMatch = body.match(/^- \\*\\*Name\\/handle\\*\\*:\\s*(.+)$/m);\r\n const roleMatch = body.match(/^- \\*\\*Role\\*\\*:\\s*(.+)$/m);\r\n if (!nameMatch && !roleMatch) return undefined;\r\n const out: { name?: string; role?: string } = {};\r\n if (nameMatch) out.name = nameMatch[1]!.trim();\r\n if (roleMatch) out.role = roleMatch[1]!.trim();\r\n return out;\r\n}\r\n\r\nasync function safeCount(dir: string, recursive: boolean): Promise<number> {\r\n if (!existsSync(dir)) return 0;\r\n try {\r\n return await countMarkdown(dir, recursive);\r\n } catch {\r\n return 0;\r\n }\r\n}\r\n\r\nasync function countMarkdown(dir: string, recursive: boolean): Promise<number> {\r\n let total = 0;\r\n const entries = await readdir(dir, { withFileTypes: true });\r\n for (const e of entries) {\r\n if (e.isFile()) {\r\n if (!e.name.endsWith(\".md\")) continue;\r\n if (e.name === \"README.md\" || e.name === \"_INDEX.md\" || e.name === \"MEMORY.md\") {\r\n continue;\r\n }\r\n if (e.name.startsWith(\"_TEMPLATE\")) continue;\r\n total++;\r\n } else if (e.isDirectory() && recursive) {\r\n if (e.name.startsWith(\".\") || e.name.startsWith(\"_\")) continue;\r\n total += await countMarkdown(join(dir, e.name), recursive);\r\n }\r\n }\r\n return total;\r\n}\r\n\r\ntype ImportCategory =\r\n | \"worklog\"\r\n | \"decisionLog\"\r\n | \"runbooks\"\r\n | \"hubs\"\r\n | \"memory\"\r\n | \"preserved\";\r\n\r\ninterface ImportArgs {\r\n from?: string;\r\n dryRun?: boolean;\r\n}\r\n\r\ninterface ImportStats {\r\n totalFiles: number;\r\n copied: number;\r\n classified: Record<ImportCategory, number>;\r\n frontmatterInjected: number;\r\n frontmatterPreserved: number;\r\n skipped: number;\r\n}\r\n\r\nconst IMPORT_SKIP_DIRS = new Set([\r\n \".git\",\r\n \"node_modules\",\r\n \".vscode\",\r\n \".idea\",\r\n \"dist\",\r\n \"build\",\r\n \".obsidian\",\r\n \".trash\",\r\n]);\r\nconst IMPORT_SKIP_FILES = new Set([\".DS_Store\", \"Thumbs.db\", \".gitkeep\"]);\r\n\r\nconst WORKLOG_FOLDER_NAMES = new Set([\r\n \"worklog\",\r\n \"til\",\r\n \"daily\",\r\n \"journal\",\r\n \"diary\",\r\n \"daily-notes\",\r\n \"logs\",\r\n \"log\",\r\n \"일지\",\r\n \"날짜별\",\r\n]);\r\nconst DECISION_FOLDER_NAMES = new Set([\r\n \"decision-log\",\r\n \"decisions\",\r\n \"decision\",\r\n]);\r\nconst RUNBOOK_FOLDER_NAMES = new Set([\"runbooks\", \"runbook\", \"sop\"]);\r\nconst HUB_FOLDER_NAMES = new Set([\"hubs\", \"hub\", \"_hub\"]);\r\nconst MEMORY_FOLDER_NAMES = new Set([\"_memory\", \"memory\", \"memories\"]);\r\n\r\nconst LEGACY_WORKLOG_TYPES = new Set([\r\n \"til\",\r\n \"daily\",\r\n \"journal\",\r\n \"diary\",\r\n \"log\",\r\n]);\r\n\r\nconst FILENAME_DATE_PATTERN = /^\\d{4}-\\d{2}-\\d{2}-/;\r\n\r\nfunction parseImportArgs(tokens: readonly string[]): ImportArgs {\r\n const args: ImportArgs = {};\r\n for (let i = 0; i < tokens.length; i++) {\r\n const t = tokens[i]!;\r\n if (t === \"--dry-run\") {\r\n args.dryRun = true;\r\n continue;\r\n }\r\n if (t === \"--from\" && i + 1 < tokens.length) {\r\n args.from = tokens[++i];\r\n continue;\r\n }\r\n }\r\n return args;\r\n}\r\n\r\nasync function runImport(\r\n input: CommandInput,\r\n tokens: readonly string[],\r\n): Promise<VortexImportResult> {\r\n const args = parseImportArgs(tokens);\r\n const { dataDir } = input.context;\r\n\r\n const emptyClassified: Record<ImportCategory, number> = {\r\n worklog: 0,\r\n decisionLog: 0,\r\n runbooks: 0,\r\n hubs: 0,\r\n memory: 0,\r\n preserved: 0,\r\n };\r\n\r\n if (!args.from) {\r\n return {\r\n subcommand: \"import\",\r\n status: \"needs-input\",\r\n totalFiles: 0,\r\n copied: 0,\r\n classified: emptyClassified,\r\n frontmatterInjected: 0,\r\n frontmatterPreserved: 0,\r\n systemDirsCreated: [],\r\n skipped: 0,\r\n missingInputs: [\r\n {\r\n name: \"from\",\r\n prompt:\r\n \"Where is the folder you want to import? (absolute path, e.g. C:/Users/me/notes)\",\r\n },\r\n ],\r\n nextActions: [\r\n \"Re-run with the path:\",\r\n ' /vortex import --from \"<absolute path>\"',\r\n \"Optional: append --dry-run to preview without copying.\",\r\n ],\r\n };\r\n }\r\n\r\n if (!existsSync(args.from)) {\r\n return {\r\n subcommand: \"import\",\r\n status: \"source-missing\",\r\n source: args.from,\r\n totalFiles: 0,\r\n copied: 0,\r\n classified: emptyClassified,\r\n frontmatterInjected: 0,\r\n frontmatterPreserved: 0,\r\n systemDirsCreated: [],\r\n skipped: 0,\r\n nextActions: [\r\n `Source folder does not exist: ${args.from}`,\r\n \"Check the path and re-run.\",\r\n ],\r\n };\r\n }\r\n\r\n const systemDirs = [\r\n \"_memory\",\r\n \"worklog\",\r\n \"decision-log\",\r\n \"runbooks\",\r\n \"hubs\",\r\n \"inbox\",\r\n ];\r\n const systemDirsCreated: string[] = [];\r\n if (!args.dryRun) {\r\n for (const d of systemDirs) {\r\n const p = join(dataDir, d);\r\n if (!existsSync(p)) {\r\n await mkdir(p, { recursive: true });\r\n systemDirsCreated.push(d);\r\n }\r\n }\r\n }\r\n\r\n const stats: ImportStats = {\r\n totalFiles: 0,\r\n copied: 0,\r\n classified: { ...emptyClassified },\r\n frontmatterInjected: 0,\r\n frontmatterPreserved: 0,\r\n skipped: 0,\r\n };\r\n\r\n await walkAndImport(args.from, args.from, dataDir, args.dryRun ?? false, stats);\r\n\r\n // After copying, scan the whole dataDir for wiki-link health. Read-only —\r\n // does not rewrite any links. Case-insensitive because imported content may\r\n // come from vaults with different filename casing conventions.\r\n let links: VortexImportResult[\"links\"];\r\n if (!args.dryRun && stats.copied > 0) {\r\n try {\r\n const check = await checkDirectory(dataDir, { caseInsensitive: true });\r\n links = {\r\n filesScanned: check.filesScanned,\r\n total: check.totalLinks,\r\n resolved: check.resolved,\r\n broken: check.broken.length,\r\n ambiguous: check.ambiguous.length,\r\n };\r\n } catch {\r\n // Link check is informational only — never let it fail the import.\r\n }\r\n }\r\n\r\n const nextActions: string[] = [];\r\n if (args.dryRun) {\r\n nextActions.push(\r\n \"This was a dry-run — no files were copied. Re-run without --dry-run to apply.\",\r\n );\r\n } else {\r\n nextActions.push(\"Run `/vortex status` to see the new counts.\");\r\n if (stats.classified.preserved > 0) {\r\n nextActions.push(\r\n `${stats.classified.preserved} files preserved your original folder structure (under <dataDir>/<same-paths>).`,\r\n );\r\n }\r\n const autoClassified =\r\n stats.classified.worklog +\r\n stats.classified.decisionLog +\r\n stats.classified.runbooks +\r\n stats.classified.hubs +\r\n stats.classified.memory;\r\n if (autoClassified > 0) {\r\n nextActions.push(\r\n `${autoClassified} files auto-classified into vortex categories (worklog/decision-log/runbooks/hubs/_memory).`,\r\n );\r\n }\r\n if (links && (links.broken > 0 || links.ambiguous > 0)) {\r\n nextActions.push(\r\n `Wiki-link health: ${links.resolved}/${links.total} resolved across ${links.filesScanned} files; ${links.broken} broken, ${links.ambiguous} ambiguous. Review and curate links over time.`,\r\n );\r\n } else if (links && links.total > 0) {\r\n nextActions.push(\r\n `Wiki-link health: ${links.resolved}/${links.total} resolved across ${links.filesScanned} files — all clean.`,\r\n );\r\n }\r\n }\r\n\r\n return {\r\n subcommand: \"import\",\r\n status: args.dryRun ? \"dry-run\" : \"completed\",\r\n source: args.from,\r\n totalFiles: stats.totalFiles,\r\n copied: stats.copied,\r\n classified: stats.classified,\r\n frontmatterInjected: stats.frontmatterInjected,\r\n frontmatterPreserved: stats.frontmatterPreserved,\r\n systemDirsCreated,\r\n skipped: stats.skipped,\r\n links,\r\n nextActions,\r\n };\r\n}\r\n\r\nasync function walkAndImport(\r\n rootSource: string,\r\n currentDir: string,\r\n dataDir: string,\r\n dryRun: boolean,\r\n stats: ImportStats,\r\n): Promise<void> {\r\n const entries = await readdir(currentDir, { withFileTypes: true });\r\n for (const e of entries) {\r\n const sourcePath = join(currentDir, e.name);\r\n if (e.isDirectory()) {\r\n if (IMPORT_SKIP_DIRS.has(e.name.toLowerCase())) continue;\r\n await walkAndImport(rootSource, sourcePath, dataDir, dryRun, stats);\r\n } else if (e.isFile()) {\r\n if (IMPORT_SKIP_FILES.has(e.name)) {\r\n stats.skipped++;\r\n continue;\r\n }\r\n if (!e.name.endsWith(\".md\")) {\r\n stats.skipped++;\r\n continue;\r\n }\r\n stats.totalFiles++;\r\n\r\n const raw = await readFile(sourcePath, \"utf8\");\r\n const parsed = parseFrontmatter<Record<string, unknown>>(raw);\r\n const hasFrontmatter = Object.keys(parsed.frontmatter).length > 0;\r\n\r\n const category = classifyFile(\r\n sourcePath,\r\n rootSource,\r\n e.name,\r\n parsed.frontmatter,\r\n );\r\n stats.classified[category]++;\r\n\r\n if (hasFrontmatter) {\r\n stats.frontmatterPreserved++;\r\n } else {\r\n stats.frontmatterInjected++;\r\n }\r\n\r\n if (!dryRun) {\r\n const fileStat = await stat(sourcePath);\r\n const enhanced = enhanceFrontmatter(\r\n parsed.frontmatter,\r\n category,\r\n fileStat.birthtime,\r\n fileStat.mtime,\r\n sourcePath,\r\n rootSource,\r\n );\r\n const targetPath = computeTargetPath(\r\n category,\r\n sourcePath,\r\n rootSource,\r\n dataDir,\r\n e.name,\r\n );\r\n await mkdir(dirname(targetPath), { recursive: true });\r\n const out = serializeFrontmatter({\r\n frontmatter: enhanced,\r\n body: parsed.body,\r\n });\r\n await writeFile(targetPath, out, \"utf8\");\r\n stats.copied++;\r\n }\r\n }\r\n }\r\n}\r\n\r\nfunction classifyFile(\r\n sourcePath: string,\r\n rootSource: string,\r\n filename: string,\r\n frontmatter: Record<string, unknown>,\r\n): ImportCategory {\r\n const type = String(frontmatter.type ?? \"\").toLowerCase();\r\n if (type === \"worklog\" || LEGACY_WORKLOG_TYPES.has(type)) return \"worklog\";\r\n if (type === \"decision-log\" || type === \"decision\") return \"decisionLog\";\r\n if (type === \"runbook\") return \"runbooks\";\r\n if (type === \"hub\") return \"hubs\";\r\n if (type === \"memory\" || type === \"user\") return \"memory\";\r\n\r\n if (filename.startsWith(\"_HUB-\")) return \"hubs\";\r\n if (FILENAME_DATE_PATTERN.test(filename)) return \"worklog\";\r\n\r\n const relPath = sourcePath\r\n .substring(rootSource.length)\r\n .replace(/^[/\\\\]/, \"\");\r\n const parts = relPath.split(/[/\\\\]/).map((p) => p.toLowerCase());\r\n for (const part of parts) {\r\n if (WORKLOG_FOLDER_NAMES.has(part)) return \"worklog\";\r\n if (DECISION_FOLDER_NAMES.has(part)) return \"decisionLog\";\r\n if (RUNBOOK_FOLDER_NAMES.has(part)) return \"runbooks\";\r\n if (HUB_FOLDER_NAMES.has(part)) return \"hubs\";\r\n if (MEMORY_FOLDER_NAMES.has(part)) return \"memory\";\r\n }\r\n\r\n return \"preserved\";\r\n}\r\n\r\nfunction computeTargetPath(\r\n category: ImportCategory,\r\n sourcePath: string,\r\n rootSource: string,\r\n dataDir: string,\r\n filename: string,\r\n): string {\r\n if (category === \"preserved\") {\r\n const relPath = sourcePath\r\n .substring(rootSource.length)\r\n .replace(/^[/\\\\]/, \"\");\r\n return join(dataDir, relPath);\r\n }\r\n if (category === \"worklog\") {\r\n const match = filename.match(/^(\\d{4})-(\\d{2})-/);\r\n if (match) {\r\n return join(dataDir, \"worklog\", match[1]!, match[2]!, filename);\r\n }\r\n const d = new Date();\r\n const y = String(d.getFullYear());\r\n const m = String(d.getMonth() + 1).padStart(2, \"0\");\r\n return join(dataDir, \"worklog\", y, m, filename);\r\n }\r\n if (category === \"decisionLog\") return join(dataDir, \"decision-log\", filename);\r\n if (category === \"runbooks\") return join(dataDir, \"runbooks\", filename);\r\n if (category === \"hubs\") return join(dataDir, \"hubs\", filename);\r\n if (category === \"memory\") return join(dataDir, \"_memory\", filename);\r\n return join(dataDir, filename);\r\n}\r\n\r\nfunction enhanceFrontmatter(\r\n frontmatter: Record<string, unknown>,\r\n category: ImportCategory,\r\n birthtime: Date,\r\n mtime: Date,\r\n sourcePath: string,\r\n rootSource: string,\r\n): Record<string, unknown> {\r\n const enhanced: Record<string, unknown> = { ...frontmatter };\r\n\r\n const existingType = String(enhanced.type ?? \"\").toLowerCase();\r\n if (!existingType) {\r\n const typeMap: Record<ImportCategory, string> = {\r\n worklog: \"worklog\",\r\n decisionLog: \"decision-log\",\r\n runbooks: \"runbook\",\r\n hubs: \"hub\",\r\n memory: \"memory\",\r\n preserved: \"note\",\r\n };\r\n enhanced.type = typeMap[category];\r\n } else if (LEGACY_WORKLOG_TYPES.has(existingType)) {\r\n enhanced.type = \"worklog\";\r\n }\r\n\r\n if (Array.isArray(enhanced.tags)) {\r\n enhanced.tags = enhanced.tags.map((t) => {\r\n const s = String(t).toLowerCase();\r\n if (LEGACY_WORKLOG_TYPES.has(s)) return \"worklog\";\r\n return t;\r\n });\r\n }\r\n\r\n if (!enhanced.created) {\r\n enhanced.created = formatYmd(birthtime);\r\n }\r\n if (!enhanced.updated) {\r\n enhanced.updated = formatYmd(mtime);\r\n }\r\n\r\n if (!enhanced.privacy) {\r\n const relLower = sourcePath\r\n .substring(rootSource.length)\r\n .toLowerCase();\r\n if (\r\n relLower.includes(\"personal-records\") ||\r\n relLower.includes(\"personal_records\")\r\n ) {\r\n enhanced.privacy = \"personal\";\r\n } else {\r\n enhanced.privacy = \"internal\";\r\n }\r\n }\r\n\r\n return enhanced;\r\n}\r\n\r\nfunction formatYmd(d: Date): string {\r\n const y = d.getFullYear();\r\n const m = String(d.getMonth() + 1).padStart(2, \"0\");\r\n const day = String(d.getDate()).padStart(2, \"0\");\r\n return `${y}-${m}-${day}`;\r\n}\r\n\r\nconst DOCTOR_SYSTEM_DIRS = [\r\n \"_memory\",\r\n \"worklog\",\r\n \"decision-log\",\r\n \"runbooks\",\r\n \"hubs\",\r\n] as const;\r\n\r\nconst RUNBOOK_AGING_DAYS = 90;\r\nconst NODE_MIN_MAJOR = 18;\r\n\r\nasync function runDoctor(input: CommandInput): Promise<VortexDoctorResult> {\r\n const { dataDir, repoRoot } = input.context;\r\n const checks: DoctorCheck[] = [];\r\n\r\n checks.push(checkSystemDirs(dataDir));\r\n checks.push(checkUserProfile(dataDir));\r\n checks.push(await checkIndexes(dataDir));\r\n checks.push(await checkWikilinks(dataDir));\r\n checks.push(await checkFrontmatterLint(dataDir));\r\n checks.push(await checkRunbookAging(dataDir));\r\n checks.push(checkNodeVersion());\r\n checks.push(await checkGitRemote(repoRoot));\r\n\r\n const summary = { pass: 0, warn: 0, fail: 0, info: 0 };\r\n for (const c of checks) summary[c.status]++;\r\n\r\n const status: VortexDoctorResult[\"status\"] =\r\n summary.fail > 0 ? \"errors\" : summary.warn > 0 ? \"warnings\" : \"ok\";\r\n\r\n const nextActions: string[] = [];\r\n if (summary.fail > 0) {\r\n nextActions.push(\r\n `${summary.fail} check(s) failed. Address them before relying on the instance.`,\r\n );\r\n }\r\n if (summary.warn > 0) {\r\n nextActions.push(\r\n `${summary.warn} warning(s). Review the detail lines — most are recoverable in one command.`,\r\n );\r\n }\r\n if (status === \"ok\") {\r\n nextActions.push(\r\n \"All checks pass. Run `/vortex status` for activity counts or `/log <section>` to keep working.\",\r\n );\r\n }\r\n\r\n return { subcommand: \"doctor\", status, checks, summary, nextActions };\r\n}\r\n\r\nfunction checkSystemDirs(dataDir: string): DoctorCheck {\r\n const missing = DOCTOR_SYSTEM_DIRS.filter(\r\n (d) => !existsSync(join(dataDir, d)),\r\n );\r\n if (missing.length === 0) {\r\n return {\r\n id: \"system-dirs\",\r\n label: \"vortex system directories present\",\r\n status: \"pass\",\r\n };\r\n }\r\n return {\r\n id: \"system-dirs\",\r\n label: \"vortex system directories present\",\r\n status: \"fail\",\r\n detail: `Missing: ${missing.join(\", \")}. Run \\`/vortex init\\` or create them manually.`,\r\n };\r\n}\r\n\r\nfunction checkUserProfile(dataDir: string): DoctorCheck {\r\n const profilePath = join(dataDir, \"_memory\", \"user_profile.md\");\r\n if (existsSync(profilePath)) {\r\n return {\r\n id: \"user-profile\",\r\n label: \"user_profile.md exists\",\r\n status: \"pass\",\r\n };\r\n }\r\n return {\r\n id: \"user-profile\",\r\n label: \"user_profile.md exists\",\r\n status: \"fail\",\r\n detail:\r\n \"Missing _memory/user_profile.md. Run `/vortex init` to bootstrap the instance.\",\r\n };\r\n}\r\n\r\nasync function checkIndexes(dataDir: string): Promise<DoctorCheck> {\r\n const missing: string[] = [];\r\n for (const d of DOCTOR_SYSTEM_DIRS) {\r\n const dirPath = join(dataDir, d);\r\n if (!existsSync(dirPath)) continue;\r\n const indexPath = join(dirPath, \"_INDEX.md\");\r\n if (!existsSync(indexPath)) missing.push(`${d}/_INDEX.md`);\r\n }\r\n if (missing.length === 0) {\r\n return {\r\n id: \"indexes\",\r\n label: \"_INDEX.md present in each system directory\",\r\n status: \"pass\",\r\n };\r\n }\r\n return {\r\n id: \"indexes\",\r\n label: \"_INDEX.md present in each system directory\",\r\n status: \"warn\",\r\n detail: `Missing: ${missing.join(\", \")}. Run \\`/reindex\\` to generate them.`,\r\n };\r\n}\r\n\r\nasync function checkWikilinks(dataDir: string): Promise<DoctorCheck> {\r\n try {\r\n const result = await checkDirectory(dataDir, { caseInsensitive: true });\r\n if (result.totalLinks === 0) {\r\n return {\r\n id: \"wikilinks\",\r\n label: \"wiki links resolve\",\r\n status: \"pass\",\r\n detail: \"No wiki links found.\",\r\n };\r\n }\r\n const broken = result.broken.length;\r\n const ambiguous = result.ambiguous.length;\r\n if (broken === 0 && ambiguous === 0) {\r\n return {\r\n id: \"wikilinks\",\r\n label: \"wiki links resolve\",\r\n status: \"pass\",\r\n detail: `${result.resolved}/${result.totalLinks} resolved across ${result.filesScanned} files.`,\r\n };\r\n }\r\n return {\r\n id: \"wikilinks\",\r\n label: \"wiki links resolve\",\r\n status: \"warn\",\r\n detail: `${broken} broken, ${ambiguous} ambiguous out of ${result.totalLinks} total. Curate or run a rewrite pass.`,\r\n };\r\n } catch (e) {\r\n return {\r\n id: \"wikilinks\",\r\n label: \"wiki links resolve\",\r\n status: \"warn\",\r\n detail: `Could not scan: ${(e as Error).message}`,\r\n };\r\n }\r\n}\r\n\r\nasync function checkFrontmatterLint(dataDir: string): Promise<DoctorCheck> {\r\n try {\r\n const report = await lintDirectory({\r\n dir: dataDir,\r\n rules: [\r\n requireFrontmatter({ required: [\"type\"] }),\r\n privacyValid(),\r\n wikiLinkResolves({ searchRoot: dataDir }),\r\n ],\r\n });\r\n const errors = report.findings.filter((f) => f.severity === \"error\").length;\r\n const warnings = report.findings.filter(\r\n (f) => f.severity === \"warning\",\r\n ).length;\r\n if (errors === 0 && warnings === 0) {\r\n return {\r\n id: \"frontmatter-lint\",\r\n label: \"frontmatter / privacy / wiki-link rules\",\r\n status: \"pass\",\r\n detail: `${report.filesScanned} files scanned, 0 findings.`,\r\n };\r\n }\r\n if (errors > 0) {\r\n return {\r\n id: \"frontmatter-lint\",\r\n label: \"frontmatter / privacy / wiki-link rules\",\r\n status: \"fail\",\r\n detail: `${errors} error(s), ${warnings} warning(s) across ${report.filesScanned} files.`,\r\n };\r\n }\r\n return {\r\n id: \"frontmatter-lint\",\r\n label: \"frontmatter / privacy / wiki-link rules\",\r\n status: \"warn\",\r\n detail: `${warnings} warning(s) across ${report.filesScanned} files.`,\r\n };\r\n } catch (e) {\r\n return {\r\n id: \"frontmatter-lint\",\r\n label: \"frontmatter / privacy / wiki-link rules\",\r\n status: \"warn\",\r\n detail: `Could not lint: ${(e as Error).message}`,\r\n };\r\n }\r\n}\r\n\r\nasync function checkRunbookAging(dataDir: string): Promise<DoctorCheck> {\r\n const runbooksDir = join(dataDir, \"runbooks\");\r\n if (!existsSync(runbooksDir)) {\r\n return {\r\n id: \"runbook-aging\",\r\n label: `runbooks tested within ${RUNBOOK_AGING_DAYS} days`,\r\n status: \"pass\",\r\n detail: \"No runbooks directory.\",\r\n };\r\n }\r\n const stale: string[] = [];\r\n let total = 0;\r\n const cutoff = Date.now() - RUNBOOK_AGING_DAYS * 24 * 60 * 60 * 1000;\r\n try {\r\n const entries = await readdir(runbooksDir, { withFileTypes: true });\r\n for (const e of entries) {\r\n if (!e.isFile() || !e.name.endsWith(\".md\")) continue;\r\n if (\r\n e.name === \"README.md\" ||\r\n e.name === \"_INDEX.md\" ||\r\n e.name.startsWith(\"_TEMPLATE\")\r\n ) {\r\n continue;\r\n }\r\n total++;\r\n const filePath = join(runbooksDir, e.name);\r\n const raw = await readFile(filePath, \"utf8\");\r\n const { frontmatter } = parseFrontmatter<{ last_tested?: string }>(raw);\r\n if (!frontmatter.last_tested) {\r\n stale.push(`${e.name} (no last_tested)`);\r\n continue;\r\n }\r\n const testedAt = new Date(String(frontmatter.last_tested)).getTime();\r\n if (Number.isNaN(testedAt) || testedAt < cutoff) {\r\n stale.push(`${e.name} (${String(frontmatter.last_tested)})`);\r\n }\r\n }\r\n } catch (e) {\r\n return {\r\n id: \"runbook-aging\",\r\n label: `runbooks tested within ${RUNBOOK_AGING_DAYS} days`,\r\n status: \"warn\",\r\n detail: `Could not scan: ${(e as Error).message}`,\r\n };\r\n }\r\n if (total === 0 || stale.length === 0) {\r\n return {\r\n id: \"runbook-aging\",\r\n label: `runbooks tested within ${RUNBOOK_AGING_DAYS} days`,\r\n status: \"pass\",\r\n detail: total === 0 ? \"No runbooks.\" : `${total} runbook(s), all fresh.`,\r\n };\r\n }\r\n return {\r\n id: \"runbook-aging\",\r\n label: `runbooks tested within ${RUNBOOK_AGING_DAYS} days`,\r\n status: \"warn\",\r\n detail:\r\n `${stale.length}/${total} runbook(s) stale or untested: ${stale.slice(0, 3).join(\"; \")}${stale.length > 3 ? \"…\" : \"\"}. ` +\r\n `Even rarely-used runbooks stay valuable — re-verify when the environment changes, do not delete.`,\r\n };\r\n}\r\n\r\nfunction checkNodeVersion(): DoctorCheck {\r\n const raw = process.version; // e.g. \"v22.17.0\"\r\n const match = raw.match(/^v?(\\d+)\\./);\r\n if (!match) {\r\n return {\r\n id: \"node-version\",\r\n label: `node >= ${NODE_MIN_MAJOR}`,\r\n status: \"warn\",\r\n detail: `Could not parse node version \"${raw}\".`,\r\n };\r\n }\r\n const major = Number.parseInt(match[1]!, 10);\r\n if (major >= NODE_MIN_MAJOR) {\r\n return {\r\n id: \"node-version\",\r\n label: `node >= ${NODE_MIN_MAJOR}`,\r\n status: \"pass\",\r\n detail: `Running ${raw}.`,\r\n };\r\n }\r\n return {\r\n id: \"node-version\",\r\n label: `node >= ${NODE_MIN_MAJOR}`,\r\n status: \"fail\",\r\n detail: `Found ${raw}. TypeScript modules require node ${NODE_MIN_MAJOR} or later. Upgrade node.`,\r\n };\r\n}\r\n\r\nasync function checkGitRemote(repoRoot: string): Promise<DoctorCheck> {\r\n const gitConfig = join(repoRoot, \".git\", \"config\");\r\n if (!existsSync(gitConfig)) {\r\n return {\r\n id: \"git-remote\",\r\n label: \"git remote for sync\",\r\n status: \"info\",\r\n detail:\r\n \"Not a git repository. VortEX works fine without git, but git + a hosted remote (GitHub, Gitea, GitLab) is recommended if you want to sync across machines (work / home / USB).\",\r\n };\r\n }\r\n try {\r\n const raw = await readFile(gitConfig, \"utf8\");\r\n const match = raw.match(/\\[remote \"origin\"\\][\\s\\S]*?url\\s*=\\s*(.+)/);\r\n if (!match) {\r\n return {\r\n id: \"git-remote\",\r\n label: \"git remote for sync\",\r\n status: \"info\",\r\n detail:\r\n \"Git repo present but no `origin` remote configured. Add one (`git remote add origin <url>`) if you want cross-machine sync.\",\r\n };\r\n }\r\n return {\r\n id: \"git-remote\",\r\n label: \"git remote for sync\",\r\n status: \"pass\",\r\n detail: `origin = ${match[1]!.trim()}`,\r\n };\r\n } catch (e) {\r\n return {\r\n id: \"git-remote\",\r\n label: \"git remote for sync\",\r\n status: \"info\",\r\n detail: `Could not read .git/config: ${(e as Error).message}`,\r\n };\r\n }\r\n}\r\n\r\nasync function detectExternalFolders(\r\n excludePath: string,\r\n): Promise<VortexInitResult[\"externalFolders\"]> {\r\n const home = process.env.HOME ?? process.env.USERPROFILE ?? \"\";\r\n if (!home) return undefined;\r\n const candidates = [\r\n join(home, \"Documents\", \"obsidian-vault\"),\r\n join(home, \"Documents\", \"notes\"),\r\n join(home, \"Documents\", \"Notebook\"),\r\n join(home, \"notes\"),\r\n join(home, \"Notes\"),\r\n ];\r\n const excludeNorm = excludePath.replace(/[/\\\\]+$/, \"\");\r\n const found: { path: string; basename: string; mdCount: number }[] = [];\r\n for (const candidate of candidates) {\r\n const candNorm = candidate.replace(/[/\\\\]+$/, \"\");\r\n // Skip if the candidate is the same as, contains, or is contained by the\r\n // instance — avoid suggesting self-import.\r\n if (\r\n candNorm === excludeNorm ||\r\n candNorm.startsWith(excludeNorm + \"/\") ||\r\n candNorm.startsWith(excludeNorm + \"\\\\\") ||\r\n excludeNorm.startsWith(candNorm + \"/\") ||\r\n excludeNorm.startsWith(candNorm + \"\\\\\")\r\n ) {\r\n continue;\r\n }\r\n if (!existsSync(candidate)) continue;\r\n let mdCount = 0;\r\n try {\r\n mdCount = await countMarkdown(candidate, true);\r\n } catch {\r\n continue;\r\n }\r\n if (mdCount === 0) continue;\r\n found.push({ path: candidate, basename: basename(candidate), mdCount });\r\n }\r\n return found.length > 0 ? found : undefined;\r\n}\r\n\r\ninterface SyncArgs {\r\n skipPull?: boolean;\r\n skipInstall?: boolean;\r\n skipBuild?: boolean;\r\n skipVerify?: boolean;\r\n dryRun?: boolean;\r\n}\r\n\r\nfunction parseSyncArgs(tokens: readonly string[]): SyncArgs {\r\n const args: SyncArgs = {};\r\n for (const t of tokens) {\r\n if (t === \"--skip-pull\") args.skipPull = true;\r\n else if (t === \"--skip-install\") args.skipInstall = true;\r\n else if (t === \"--skip-build\") args.skipBuild = true;\r\n else if (t === \"--skip-verify\") args.skipVerify = true;\r\n else if (t === \"--dry-run\") args.dryRun = true;\r\n }\r\n return args;\r\n}\r\n\r\ninterface SyncStepPlan {\r\n readonly id: VortexSyncStepId;\r\n readonly label: string;\r\n readonly cmd: string;\r\n readonly cmdArgs: readonly string[];\r\n readonly skip: boolean;\r\n}\r\n\r\nasync function runSync(\r\n input: CommandInput,\r\n tokens: readonly string[],\r\n): Promise<VortexSyncResult> {\r\n const args = parseSyncArgs(tokens);\r\n const { repoRoot } = input.context;\r\n\r\n const plan: readonly SyncStepPlan[] = [\r\n {\r\n id: \"pull\",\r\n label: \"git pull\",\r\n cmd: \"git\",\r\n cmdArgs: [\"pull\"],\r\n skip: args.skipPull ?? false,\r\n },\r\n {\r\n id: \"install\",\r\n label: \"npm install\",\r\n cmd: \"npm\",\r\n cmdArgs: [\"install\"],\r\n skip: args.skipInstall ?? false,\r\n },\r\n {\r\n id: \"build\",\r\n label: \"npm run build\",\r\n cmd: \"npm\",\r\n cmdArgs: [\"run\", \"build\"],\r\n skip: args.skipBuild ?? false,\r\n },\r\n {\r\n id: \"verify\",\r\n label: \"npm run verify\",\r\n cmd: \"npm\",\r\n cmdArgs: [\"run\", \"verify\"],\r\n skip: args.skipVerify ?? false,\r\n },\r\n ];\r\n\r\n if (args.dryRun) {\r\n const steps: VortexSyncStep[] = plan.map((p) => ({\r\n id: p.id,\r\n label: p.label,\r\n status: p.skip ? \"skipped\" : \"ok\",\r\n }));\r\n return {\r\n subcommand: \"sync\",\r\n status: \"dry-run\",\r\n steps,\r\n nextActions: [\r\n \"Dry-run only — no commands executed.\",\r\n \"Re-run without --dry-run to apply.\",\r\n ],\r\n };\r\n }\r\n\r\n const steps: VortexSyncStep[] = [];\r\n for (const p of plan) {\r\n if (p.skip) {\r\n steps.push({ id: p.id, label: p.label, status: \"skipped\" });\r\n continue;\r\n }\r\n const result = await runShellCommand(p.cmd, p.cmdArgs, repoRoot);\r\n const step: VortexSyncStep = {\r\n id: p.id,\r\n label: p.label,\r\n status: result.exitCode === 0 ? \"ok\" : \"failed\",\r\n exitCode: result.exitCode,\r\n durationMs: result.durationMs,\r\n stdoutTail: result.stdoutTail,\r\n stderrTail: result.stderrTail,\r\n };\r\n steps.push(step);\r\n if (step.status === \"failed\") {\r\n return {\r\n subcommand: \"sync\",\r\n status: \"failed\",\r\n steps,\r\n failedAt: p.id,\r\n nextActions: [\r\n `\\`${p.label}\\` failed with exit code ${result.exitCode}.`,\r\n \"Review the stdoutTail / stderrTail and fix the underlying issue, then re-run.\",\r\n \"You can skip already-passed earlier steps with --skip-pull / --skip-install / --skip-build / --skip-verify.\",\r\n ],\r\n };\r\n }\r\n }\r\n\r\n const ranCount = steps.filter((s) => s.status === \"ok\").length;\r\n return {\r\n subcommand: \"sync\",\r\n status: \"completed\",\r\n steps,\r\n nextActions: [\r\n `All ${ranCount} step(s) passed. Your framework checkout is up-to-date and verified.`,\r\n \"Run `/vortex status` for an instance-side snapshot.\",\r\n ],\r\n };\r\n}\r\n\r\ninterface ShellCommandResult {\r\n exitCode: number;\r\n durationMs: number;\r\n stdoutTail: string;\r\n stderrTail: string;\r\n}\r\n\r\nconst SYNC_TAIL_LENGTH = 1000;\r\n\r\nasync function runShellCommand(\r\n cmd: string,\r\n cmdArgs: readonly string[],\r\n cwd: string,\r\n): Promise<ShellCommandResult> {\r\n const start = Date.now();\r\n return new Promise<ShellCommandResult>((resolve) => {\r\n let stdout = \"\";\r\n let stderr = \"\";\r\n // shell: true is required so that platform-native launchers find\r\n // batch/cmd wrappers (e.g. npm.cmd on Windows). Inputs come from a\r\n // hardcoded plan above — no user-supplied strings reach the shell.\r\n const child = spawn(cmd, [...cmdArgs], { cwd, shell: true });\r\n child.stdout?.on(\"data\", (chunk: Buffer) => {\r\n stdout += chunk.toString(\"utf8\");\r\n });\r\n child.stderr?.on(\"data\", (chunk: Buffer) => {\r\n stderr += chunk.toString(\"utf8\");\r\n });\r\n child.on(\"close\", (code) => {\r\n resolve({\r\n exitCode: code ?? -1,\r\n durationMs: Date.now() - start,\r\n stdoutTail: tailString(stdout, SYNC_TAIL_LENGTH),\r\n stderrTail: tailString(stderr, SYNC_TAIL_LENGTH),\r\n });\r\n });\r\n child.on(\"error\", (err) => {\r\n resolve({\r\n exitCode: -1,\r\n durationMs: Date.now() - start,\r\n stdoutTail: tailString(stdout, SYNC_TAIL_LENGTH),\r\n stderrTail: tailString(\r\n stderr + \"\\n[spawn error] \" + err.message,\r\n SYNC_TAIL_LENGTH,\r\n ),\r\n });\r\n });\r\n });\r\n}\r\n\r\nfunction tailString(s: string, n: number): string {\r\n if (s.length <= n) return s;\r\n return \"...\" + s.slice(-n);\r\n}\r\n","/**\n * Hook wiring for `/vortex init`: make sure the instance's\n * `.claude/settings.json` registers the VortEX SessionStart / SessionEnd hooks,\n * so the boot report + worklog-net fire automatically without the user knowing\n * any command. NON-DESTRUCTIVE — like the MCP install merge, this preserves\n * every other hook and top-level field and only adds our two entries if absent.\n *\n * Pure functions here (parse / merge / detect); the command does the actual\n * file read/write around them. Keeping them pure makes the merge unit-testable\n * and the \"writes only what's missing\" guarantee verifiable.\n */\n\nexport const SESSION_START_COMMAND =\n \"node plugins/session-rituals/scripts/session-start-hook.mjs\";\nexport const SESSION_END_COMMAND =\n \"node plugins/session-rituals/scripts/session-end-hook.mjs\";\n\ninterface HookCommand {\n readonly type: \"command\";\n readonly command: string;\n}\ninterface HookGroup {\n readonly hooks: readonly HookCommand[];\n readonly matcher?: string;\n}\nexport interface ClaudeSettings {\n hooks?: {\n SessionStart?: HookGroup[];\n SessionEnd?: HookGroup[];\n [event: string]: HookGroup[] | undefined;\n };\n [key: string]: unknown;\n}\n\nexport interface EnsureHooksResult {\n readonly settings: ClaudeSettings;\n /** Which hook events we added a VortEX entry to (empty if already wired). */\n readonly added: readonly (\"SessionStart\" | \"SessionEnd\")[];\n /** True when nothing changed — every VortEX hook was already present. */\n readonly alreadyWired: boolean;\n}\n\n/**\n * Parse existing settings.json text. Empty/whitespace → `{}` (fresh). Throws on\n * malformed JSON so the caller aborts rather than clobbering a hand-edited file.\n */\nexport function parseSettings(text: string | null | undefined): ClaudeSettings {\n const trimmed = (text ?? \"\").trim();\n if (trimmed.length === 0) return {};\n let parsed: unknown;\n try {\n parsed = JSON.parse(trimmed);\n } catch (e) {\n throw new Error(\n `.claude/settings.json is not valid JSON — refusing to overwrite. Fix or remove it first. (${(e as Error).message})`,\n );\n }\n if (parsed === null || typeof parsed !== \"object\" || Array.isArray(parsed)) {\n throw new Error(\".claude/settings.json is not a JSON object — refusing to overwrite.\");\n }\n return parsed as ClaudeSettings;\n}\n\nfunction hasCommand(groups: HookGroup[] | undefined, command: string): boolean {\n if (!groups) return false;\n return groups.some((g) => g.hooks?.some((h) => h.command === command));\n}\n\n/**\n * Merge the VortEX hooks into an existing settings object WITHOUT mutating the\n * input. A hook event is left untouched if it already references our command\n * (idempotent); otherwise our group is appended alongside any existing groups.\n */\nexport function ensureVortexHooks(existing: ClaudeSettings | null | undefined): EnsureHooksResult {\n const base: ClaudeSettings = existing && typeof existing === \"object\" ? existing : {};\n const hooks = { ...(base.hooks ?? {}) };\n const added: (\"SessionStart\" | \"SessionEnd\")[] = [];\n\n const wire = (event: \"SessionStart\" | \"SessionEnd\", command: string) => {\n const groups = hooks[event] ? [...hooks[event]!] : [];\n if (hasCommand(groups, command)) return;\n groups.push({ hooks: [{ type: \"command\", command }] });\n hooks[event] = groups;\n added.push(event);\n };\n\n wire(\"SessionStart\", SESSION_START_COMMAND);\n wire(\"SessionEnd\", SESSION_END_COMMAND);\n\n const settings: ClaudeSettings = { ...base, hooks };\n return { settings, added, alreadyWired: added.length === 0 };\n}\n\n/** Serialize settings the way Claude writes them (2-space, trailing newline). */\nexport function serializeSettings(settings: ClaudeSettings): string {\n return JSON.stringify(settings, null, 2) + \"\\n\";\n}\n","import { WorklogStore, type WorklogEntry } from \"@vortex-os/worklog\";\nimport { DecisionStore, type DecisionEntry } from \"@vortex-os/decision-log\";\nimport type { ModuleContext } from \"@vortex-os/core\";\n\n/**\n * \"What should I do today?\" — a read-only synthesis over existing records\n * (worklog + decision-log + open `- [ ]` checkboxes), the P2 work-management\n * surface. No new store: it reads what's already written and answers\n * \"what were you doing, what's open, what's next\" from it.\n *\n * Design goal (operator, 2026-05-30): adapt to EVERY data state — a brand-new\n * user with nothing, a partly-used instance, and a rich history must each get a\n * sensible report. So the collector returns a structured, presence-flagged\n * shape and the renderer branches on what's actually there rather than assuming\n * any section exists.\n */\n\n/** An unchecked `- [ ]` item lifted from a recent worklog body. */\nexport interface OpenTask {\n readonly text: string;\n /** Worklog date the task was found in (`YYYY-MM-DD`). */\n readonly fromDate: string;\n}\n\nexport interface OpenDecision {\n readonly title: string;\n readonly date: string;\n readonly slug: string;\n}\n\nexport interface AgendaReport {\n /** Most recent worklog (what you were last doing), or null if none. */\n readonly lastWorklog: { readonly date: string; readonly title: string; readonly path: string } | null;\n /**\n * \"Next up\" lines lifted from the most recent worklog's hand-off section\n * (`## 다음 작업` / `## Next` / a `📋`-marked heading) — the planned-work\n * pointer, mirroring the vault TIL hand-off block. Empty if none.\n */\n readonly nextUp: readonly string[];\n /** Date of the worklog the nextUp lines came from (or null). */\n readonly nextUpFrom: string | null;\n /** Unchecked checkboxes from recent worklogs, newest first, capped. */\n readonly openTasks: readonly OpenTask[];\n /** Active (non-archived) decisions, newest first, capped. */\n readonly openDecisions: readonly OpenDecision[];\n /** Total worklog / decision counts — used to distinguish \"new\" from \"quiet\". */\n readonly worklogCount: number;\n readonly decisionCount: number;\n /** True when there is essentially nothing yet (brand-new instance). */\n readonly isEmpty: boolean;\n /** True when there are records but nothing actionable surfaced. */\n readonly nothingOpen: boolean;\n}\n\nexport interface CollectAgendaOptions {\n /** How many recent worklogs to scan for open tasks. Default 7. */\n readonly recentWorklogs?: number;\n /** Max open tasks / decisions to surface. Default 8 each. */\n readonly maxTasks?: number;\n readonly maxDecisions?: number;\n}\n\nconst DEFAULT_RECENT = 7;\nconst DEFAULT_MAX = 8;\n\n/** First `# ` heading of a worklog body, else its keyword/filename stem. */\nfunction worklogTitle(entry: WorklogEntry): string {\n const m = entry.body.match(/^#\\s+(.+)$/m);\n if (m) return m[1]!.trim();\n return entry.keyword || entry.date;\n}\n\n/**\n * Pull unchecked GitHub-style checkboxes (`- [ ]` / `* [ ]`, any indent) from a\n * worklog body. Checked items (`- [x]`) are ignored. Returns the trimmed label.\n */\n/**\n * Lift the \"next up / hand-off\" section from a worklog body — the planned-work\n * pointer the agent leaves at wind-down (mirrors the vault's TIL `## 📋 다음\n * 작업` block). Matches a heading whose text contains any of: \"다음 작업\",\n * \"다음 세션\", \"next\", \"next up\", \"todo\", \"후속\", \"📋\". Returns the section's\n * content lines (bullets de-marked, blanks dropped), capped. Empty if no such\n * section. Stops at the next heading of the same-or-higher level.\n */\nexport function extractNextUp(body: string, max = 8): string[] {\n const lines = body.split(/\\r?\\n/);\n const headingRe = /^(#{1,6})\\s+(.*)$/;\n const cueRe = /(다음\\s*작업|다음\\s*세션|후속|next\\s*up|next|todo|to-do|📋)/i;\n let collecting = false;\n let startLevel = 0;\n const out: string[] = [];\n for (const line of lines) {\n const h = line.match(headingRe);\n if (h) {\n const level = h[1]!.length;\n if (collecting && level <= startLevel) break; // end of section\n if (!collecting && cueRe.test(h[2]!)) {\n collecting = true;\n startLevel = level;\n continue;\n }\n continue;\n }\n if (!collecting) continue;\n const trimmed = line.trim();\n if (trimmed.length === 0) continue;\n if (trimmed.startsWith(\">\")) continue; // skip callout/quote framing\n // De-mark common bullet / numbered / checkbox prefixes for a clean line.\n const cleaned = trimmed\n .replace(/^[-*]\\s+\\[[ xX]\\]\\s+/, \"\")\n .replace(/^[-*]\\s+/, \"\")\n .replace(/^\\d+[.)]\\s+/, \"\")\n .trim();\n if (cleaned.length === 0) continue;\n out.push(cleaned);\n if (out.length >= max) break;\n }\n return out;\n}\n\n/**\n * Pull unchecked GitHub-style checkboxes (`- [ ]` / `* [ ]`, any indent) from a\n * worklog body. Checked items (`- [x]`) are ignored. Returns the trimmed label.\n */\nexport function extractOpenTasks(body: string): string[] {\n const out: string[] = [];\n for (const line of body.split(/\\r?\\n/)) {\n const m = line.match(/^\\s*[-*]\\s+\\[\\s\\]\\s+(.+\\S)\\s*$/);\n if (m) out.push(m[1]!.trim());\n }\n return out;\n}\n\n/**\n * Collect the agenda inputs. Read-only; tolerant of missing dirs (both stores\n * return empty rather than throwing), so a brand-new instance yields an empty —\n * but well-formed — report.\n */\nexport async function collectAgenda(\n ctx: ModuleContext,\n opts?: CollectAgendaOptions,\n): Promise<AgendaReport> {\n const recentN = opts?.recentWorklogs ?? DEFAULT_RECENT;\n const maxTasks = opts?.maxTasks ?? DEFAULT_MAX;\n const maxDecisions = opts?.maxDecisions ?? DEFAULT_MAX;\n\n // WorklogStore's root is the worklog/ folder itself (it walks YYYY/MM under it);\n // DecisionStore's root is the decision-log/ folder. Both live under dataDir.\n const worklogStore = new WorklogStore(`${ctx.dataDir}/worklog`);\n const decisionStore = new DecisionStore(joinDecisionRoot(ctx));\n\n const allWorklogs = await worklogStore.list();\n // `list()` order is not guaranteed sorted; sort by date desc for \"recent\".\n const sortedWorklogs = [...allWorklogs].sort((a, b) => (a.date < b.date ? 1 : a.date > b.date ? -1 : 0));\n const recent = sortedWorklogs.slice(0, recentN);\n\n const lastWorklog = sortedWorklogs[0]\n ? { date: sortedWorklogs[0].date, title: worklogTitle(sortedWorklogs[0]), path: sortedWorklogs[0].path }\n : null;\n\n const openTasks: OpenTask[] = [];\n for (const wl of recent) {\n for (const text of extractOpenTasks(wl.body)) {\n openTasks.push({ text, fromDate: wl.date });\n if (openTasks.length >= maxTasks) break;\n }\n if (openTasks.length >= maxTasks) break;\n }\n\n // Planned work: the hand-off section of the MOST RECENT worklog (only — older\n // worklogs' \"next up\" are superseded). Mirrors the vault TIL hand-off block.\n const newest = sortedWorklogs[0];\n const nextUp = newest ? extractNextUp(newest.body, maxTasks) : [];\n const nextUpFrom = newest && nextUp.length > 0 ? newest.date : null;\n\n const allDecisions = await decisionStore.list();\n const active = allDecisions.filter((d: DecisionEntry) => {\n const s = (d.frontmatter?.status ?? \"active\").toLowerCase();\n return s !== \"archived\" && s !== \"template\";\n });\n const sortedDecisions = [...active].sort((a, b) => (a.date < b.date ? 1 : a.date > b.date ? -1 : 0));\n const openDecisions: OpenDecision[] = sortedDecisions.slice(0, maxDecisions).map((d) => ({\n title: decisionTitle(d),\n date: d.date,\n slug: d.slug,\n }));\n\n const worklogCount = allWorklogs.length;\n const decisionCount = allDecisions.length;\n const isEmpty = worklogCount === 0 && decisionCount === 0;\n const nothingOpen =\n !isEmpty && openTasks.length === 0 && openDecisions.length === 0 && nextUp.length === 0;\n\n return {\n lastWorklog,\n nextUp,\n nextUpFrom,\n openTasks,\n openDecisions,\n worklogCount,\n decisionCount,\n isEmpty,\n nothingOpen,\n };\n}\n\nfunction joinDecisionRoot(ctx: ModuleContext): string {\n // DecisionStore takes the decision-log root directly.\n return `${ctx.dataDir}/decision-log`;\n}\n\nfunction decisionTitle(d: DecisionEntry): string {\n const m = (d.body ?? \"\").match(/^#\\s+(.+)$/m);\n if (m) return m[1]!.trim();\n return d.slug;\n}\n\n/**\n * Render the agenda as a compact markdown block. Branches on data state so the\n * output is sensible whether the instance is brand-new, quiet, or busy:\n * - brand-new (no records) → a short \"getting started\" nudge\n * - records but nothing open → \"you're clear\" + last activity\n * - open tasks / decisions → an actionable list\n */\nexport function renderAgenda(report: AgendaReport): string {\n const lines: string[] = [\"## What should I do today?\", \"\"];\n\n if (report.isEmpty) {\n lines.push(\"- No worklog or decisions yet — this looks like a fresh instance.\");\n lines.push(\"- Start with `/vortex init` (if you haven't), then `/log <one-line update>` as you work.\");\n lines.push(\"- A worklog entry per working day is the seed; everything else grows from it.\");\n return lines.join(\"\\n\") + \"\\n\";\n }\n\n if (report.lastWorklog) {\n lines.push(`- last active: ${report.lastWorklog.date} — ${report.lastWorklog.title}`);\n }\n\n // Planned work first — it's the explicit hand-off of \"what's next\".\n if (report.nextUp.length > 0) {\n lines.push(`- next up (planned, from ${report.nextUpFrom}):`);\n for (const n of report.nextUp) {\n lines.push(` - ${n}`);\n }\n }\n\n if (report.openTasks.length > 0) {\n lines.push(`- open tasks (${report.openTasks.length}):`);\n for (const t of report.openTasks) {\n lines.push(` - [ ] ${t.text} (${t.fromDate})`);\n }\n }\n\n if (report.openDecisions.length > 0) {\n lines.push(`- open decisions (${report.openDecisions.length}):`);\n for (const d of report.openDecisions) {\n lines.push(` - ${d.title} (${d.date})`);\n }\n }\n\n if (report.nothingOpen) {\n lines.push(\n `- nothing open in recent worklogs — you're clear. ${report.worklogCount} worklog(s), ${report.decisionCount} decision(s) on record.`,\n );\n lines.push(\n \"- Leave a `## 다음 작업` (or `## Next`) section in a worklog, or `- [ ] <task>` lines, to have them surface here next time.\",\n );\n }\n\n return lines.join(\"\\n\") + \"\\n\";\n}\n","import type { Command, CommandInput } from \"@vortex-os/slash-commands\";\nimport { collectAgenda, type AgendaReport, type CollectAgendaOptions } from \"../agenda.js\";\n\n/**\n * `/agenda` — \"What should I do today?\" Read-only synthesis over existing\n * worklog + decision-log records (open `- [ ]` tasks, active decisions, last\n * activity). Returns structured {@link AgendaReport} data; the host renders it\n * (or calls `renderAgenda`). No writes, no new store — answers from what's\n * already recorded, and adapts to any data state (new / quiet / busy).\n */\nexport const agendaCommand: Command<AgendaReport> = {\n name: \"agenda\",\n description:\n \"What should I do today? Synthesize open tasks (- [ ] in recent worklogs), active decisions, and last activity from existing records.\",\n handler: async (input: CommandInput): Promise<AgendaReport> => {\n const opts: CollectAgendaOptions = {};\n return collectAgenda(input.context, opts);\n },\n};\n","import { CommandRegistry } from \"@vortex-os/slash-commands\";\r\nimport { curateCommand, type CurateOptions } from \"./commands/curate.js\";\r\nimport { recallCommand, type RecallOptions } from \"./commands/recall.js\";\r\nimport { decisionCommand } from \"./commands/decision.js\";\r\nimport { reindexCommand } from \"./commands/reindex.js\";\r\nimport { sessionStartCommand } from \"./commands/session-start.js\";\r\nimport { logCommand } from \"./commands/log.js\";\r\nimport { vortexCommand } from \"./commands/vortex.js\";\r\nimport { agendaCommand } from \"./commands/agenda.js\";\r\n\r\n/**\r\n * Options accepted by {@link createRitualRegistry}. All fields are optional;\r\n * each one unlocks an additional command surface when supplied:\r\n *\r\n * - `curate` — when an `LLMJudge` is provided, the `/curate` command from\r\n * `@vortex-os/proactive-curator` is registered. Without it the rest of\r\n * the rituals work as before and `/curate` is simply absent (graceful\r\n * degradation rather than a half-broken command).\r\n * - `recall` — when an embedder is provided, the `/recall` command over\r\n * `@vortex-os/memory-extended` is registered. Same graceful-degradation\r\n * rule: absent the embedder, semantic recall would not work, so the\r\n * command is simply not installed.\r\n */\r\nexport interface RitualRegistryOptions {\r\n readonly curate?: CurateOptions;\r\n readonly recall?: RecallOptions;\r\n}\r\n\r\n/**\r\n * Build a {@link CommandRegistry} with all ritual commands registered.\r\n *\r\n * Hosts that want a subset can register the individual exports instead.\r\n * This factory exists for the common case — \"give me everything\" — plus\r\n * opt-in surfaces that depend on host-supplied adapters (currently\r\n * `/curate`, which needs an `LLMJudge`).\r\n */\r\nexport function createRitualRegistry(\r\n options?: RitualRegistryOptions,\r\n): CommandRegistry {\r\n const registry = new CommandRegistry();\r\n registry.register(sessionStartCommand);\r\n registry.register(reindexCommand);\r\n registry.register(decisionCommand);\r\n registry.register(logCommand);\r\n registry.register(vortexCommand);\r\n registry.register(agendaCommand);\r\n if (options?.curate) {\r\n registry.register(curateCommand(options.curate));\r\n }\r\n if (options?.recall) {\r\n registry.register(recallCommand(options.recall));\r\n }\r\n return registry;\r\n}\r\n","import { join } from \"node:path\";\n// Type-only — erased at compile time so the optional `memory-extended` add-on\n// (and its native sqlite/level deps) is NOT pulled into the module graph of a\n// base install. The runtime engine is loaded lazily inside the recall closure.\nimport type { vector } from \"@vortex-os/memory-extended\";\nimport { AmbientRecaller } from \"@vortex-os/proactive-curator\";\nimport type { ModuleContext } from \"@vortex-os/core\";\n\n/**\n * Bridge the `@vortex-os/memory-extended` recall engine into a\n * `@vortex-os/proactive-curator` {@link AmbientRecaller} — defined in the\n * plugin, exactly where `/recall` and `/curate` are defined over their\n * respective engines. This keeps both modules free of a dependency on each\n * other; the plugin is the only place that knows about both.\n *\n * This is deliberately **not** a slash command. Ambient recall is stateful\n * across turns (its dedup set + backpressure streak), so it belongs to a\n * long-lived host — the opt-in embedder daemon / `UserPromptSubmit` hook, or\n * any host runtime that keeps one instance alive for the session. The default\n * Claude Code surface is agent-guidance (see `docs/proactive-curator-design.md`);\n * this factory is for hosts that opt into the *automatic* surface.\n *\n * Construct **once per session** and reuse the returned recaller so its gate\n * state persists. The injected `RecallFn` opens DB handles lazily per call\n * and closes them in a `finally`, so a long-lived process never holds a file\n * lock between turns. The embedder (the expensive, warm-able part) is\n * supplied by the host so it can keep the model resident across calls.\n */\nexport interface AmbientRecallFactoryOptions {\n /** Embedding function. The host keeps this warm (daemon) to avoid per-call model loads. */\n readonly embed: vector.EmbedFn;\n /** Override the DB path. Default `<dataDir>/_indexes/memory.sqlite`. */\n readonly dbPath?: (ctx: ModuleContext) => string;\n /** Restrict recall to one corpus. Omit to search all. */\n readonly source?: vector.VectorSource;\n /** Forwarded to AmbientRecaller — minimum cosine score to surface. Default 0.5. */\n readonly minScore?: number;\n /** Forwarded to AmbientRecaller — max suggestions per consider(). Default 1. */\n readonly maxSuggestions?: number;\n /** Forwarded to AmbientRecaller — skip the engine below this query length. Default 12. */\n readonly minQueryChars?: number;\n}\n\nfunction defaultDbPath(ctx: ModuleContext): string {\n return join(ctx.dataDir, \"_indexes\", \"memory.sqlite\");\n}\n\n/**\n * Build a session-scoped {@link AmbientRecaller} wired to the recall engine.\n * Returns `undefined`-free — the caller owns the lifecycle.\n */\nexport function createAmbientRecaller(\n ctx: ModuleContext,\n options: AmbientRecallFactoryOptions,\n): AmbientRecaller {\n const resolveDb = options.dbPath ?? defaultDbPath;\n const dbPath = resolveDb(ctx);\n\n return new AmbientRecaller({\n ...(options.minScore !== undefined ? { minScore: options.minScore } : {}),\n ...(options.maxSuggestions !== undefined ? { maxSuggestions: options.maxSuggestions } : {}),\n ...(options.minQueryChars !== undefined ? { minQueryChars: options.minQueryChars } : {}),\n recall: async (query, opts) => {\n // Lazy-load the optional add-on per call. Base ships without it; this\n // resolves only when `memory-extended` is installed alongside base.\n const { sqlite, vector, recall: recallEngine } = await import(\n \"@vortex-os/memory-extended\"\n );\n const sqlStore = new sqlite.MemorySqliteStore(dbPath);\n const vecStore = new vector.MemoryVectorStore({ db: dbPath });\n const chunkStore = new vector.SessionChunkStore(dbPath);\n try {\n const result = await recallEngine.recall(\n {\n query,\n ...(opts?.k !== undefined ? { k: opts.k } : {}),\n ...(options.source !== undefined ? { source: options.source } : {}),\n },\n { sqlite: sqlStore, vector: vecStore, embed: options.embed, sessionChunks: chunkStore },\n );\n // RecallResult.hits structurally satisfies readonly AmbientRecallHit[].\n return { hits: result.hits };\n } finally {\n chunkStore.close();\n vecStore.close();\n sqlStore.close();\n }\n },\n });\n}\n","import { existsSync } from \"node:fs\";\nimport { readdir, readFile } from \"node:fs/promises\";\nimport { join } from \"node:path\";\nimport type { ModuleContext } from \"@vortex-os/core\";\n\n/**\n * Read-only facts for a start-of-session report, gathered by the SessionStart\n * hook and rendered into the session context.\n *\n * This is the operational session ritual (auto, not proposed — see\n * `AGENT.md` \"Default behaviors\"). This collector is **read-only**: it counts\n * the data tree, finds the most recent worklog, lists recent worklog dates\n * (for gap detection), and accepts an optional environment label. `git` is\n * the hook's job (pull, and commit-day lookup for gap detection); this never\n * touches git or the network.\n */\n\nconst COUNTED_DIRS = [\"_memory\", \"worklog\", \"decision-log\"] as const;\nconst DEFAULT_GAP_WINDOW_DAYS = 30;\n\n/**\n * Boot banner for the start-of-session report — a small cosmetic that gives the\n * session an \"OS boot\" feel while the lines below carry the real ritual report.\n * `String.raw` keeps the figlet backslashes literal. Rendered with figlet's\n * `Small` font (\"VortEX\"); the tagline is the project's one-liner from README.\n */\nconst BOOT_BANNER = String.raw`\n __ __ _ _____ __\n \\ \\ / ___ _ _| |_| __\\ \\/ /\n \\ V / _ | '_| _| _| > <\n \\_/\\___|_| \\__|___/_/\\_\\\n Vortex absorbs context · EX executes it`;\n\nexport interface RecentWorklog {\n /** Path relative to the data directory (e.g. `worklog/2026/05/2026-05-30-foo.md`). */\n readonly path: string;\n /** First `# ` heading, else the filename without extension. */\n readonly title: string;\n}\n\n/** Outcome of the optional `git pull` the hook runs before reporting. */\nexport interface GitPullResult {\n readonly ran: boolean;\n readonly summary: string;\n /** True when the pull could not fast-forward (divergence / dirty tree). Never auto-resolved. */\n readonly conflict: boolean;\n}\n\nexport interface SessionStartHookReport {\n readonly time: string;\n readonly repoRoot: string;\n readonly dataDir: string;\n readonly counts: Readonly<Record<string, number>>;\n readonly missing: readonly string[];\n readonly recentWorklog: RecentWorklog | null;\n /** Worklog dates (`YYYY-MM-DD`) present within the gap window — for backfill detection. */\n readonly recentWorklogDates: readonly string[];\n /** Resolved environment label (e.g. home/work), or null when none is configured. */\n readonly environment: string | null;\n}\n\n/**\n * Gather the read-only facts for a start-of-session report: data-dir counts,\n * the most recent worklog, recent worklog dates, and an optional environment\n * label. Mirrors the `/session-start` command's counting.\n */\nexport async function collectSessionStartReport(\n ctx: ModuleContext,\n opts?: { readonly now?: Date; readonly environment?: string | null; readonly gapWindowDays?: number },\n): Promise<SessionStartHookReport> {\n const now = opts?.now ?? new Date();\n const counts: Record<string, number> = {};\n const missing: string[] = [];\n for (const name of COUNTED_DIRS) {\n const dir = join(ctx.dataDir, name);\n if (!existsSync(dir)) {\n missing.push(name);\n counts[name] = 0;\n continue;\n }\n counts[name] = await countMarkdown(dir, name === \"worklog\");\n }\n\n const { recent, dates } = await scanWorklog(ctx.dataDir);\n const cutoff = isoDate(addDays(now, -(opts?.gapWindowDays ?? DEFAULT_GAP_WINDOW_DAYS)));\n const recentWorklogDates = dates.filter((d) => d >= cutoff);\n\n return {\n time: now.toISOString(),\n repoRoot: ctx.repoRoot,\n dataDir: ctx.dataDir,\n counts,\n missing,\n recentWorklog: recent,\n recentWorklogDates,\n environment: opts?.environment ?? null,\n };\n}\n\n/**\n * Days that have commits but no worklog — backfill candidates. Pure set\n * difference (`commitDays` − `presentDates`), de-duplicated and sorted. The\n * hook supplies `commitDays` from git; the report supplies the present dates.\n */\nexport function detectWorklogGaps(\n commitDays: readonly string[],\n presentDates: readonly string[],\n): string[] {\n const present = new Set(presentDates);\n return [...new Set(commitDays)].filter((d) => d && !present.has(d)).sort();\n}\n\n/**\n * Render a session-start report as a compact markdown block for a host hook\n * to inject as session context. A pull conflict and any worklog gaps are\n * surfaced as warnings (the agent acts on the gaps — see AGENT.md).\n */\nexport function renderSessionStartReport(\n report: SessionStartHookReport,\n extras?: {\n readonly git?: GitPullResult | null;\n readonly missingWorklogDays?: readonly string[];\n readonly catchUp?: {\n readonly ingestedLocal: number;\n readonly indexedPulled: number;\n readonly errors: number;\n };\n },\n): string {\n const lines: string[] = [BOOT_BANNER, \"\"];\n const env = report.environment ? ` · env: ${report.environment}` : \"\";\n lines.push(`- time: ${report.time}${env}`);\n\n const git = extras?.git;\n if (git?.ran) {\n lines.push(\n git.conflict\n ? `- git: ⚠️ ${git.summary} — resolve manually (not auto-resolved)`\n : `- git: ${git.summary}`,\n );\n }\n\n const countStr = COUNTED_DIRS.map((d) => `${d} ${report.counts[d] ?? 0}`).join(\" · \");\n const miss = report.missing.length ? ` (missing: ${report.missing.join(\", \")})` : \"\";\n lines.push(`- data: ${countStr}${miss}`);\n\n lines.push(\n report.recentWorklog\n ? `- last worklog: ${report.recentWorklog.title} (${report.recentWorklog.path})`\n : `- last worklog: none yet`,\n );\n\n const gaps = extras?.missingWorklogDays ?? [];\n if (gaps.length) {\n lines.push(`- ⚠️ work without a worklog: ${gaps.join(\", \")} — backfill from that day's commits`);\n }\n\n const cu = extras?.catchUp;\n if (cu && (cu.ingestedLocal > 0 || cu.indexedPulled > 0 || cu.errors > 0)) {\n const parts: string[] = [];\n if (cu.ingestedLocal > 0) parts.push(`${cu.ingestedLocal} new`);\n if (cu.indexedPulled > 0) parts.push(`${cu.indexedPulled} pulled`);\n const n = cu.ingestedLocal + cu.indexedPulled;\n let line = `- caught up: archived ${parts.join(\" + \")} conversation${n === 1 ? \"\" : \"s\"}`;\n if (cu.errors > 0) line += ` (${cu.errors} error${cu.errors === 1 ? \"\" : \"s\"})`;\n lines.push(line);\n }\n\n return lines.join(\"\\n\") + \"\\n\";\n}\n\nasync function countMarkdown(dir: string, recursive: boolean): Promise<number> {\n let total = 0;\n const entries = await readdir(dir, { withFileTypes: true });\n for (const e of entries) {\n if (e.isFile()) {\n if (!e.name.endsWith(\".md\")) continue;\n if (e.name === \"README.md\" || e.name === \"_INDEX.md\" || e.name === \"MEMORY.md\") continue;\n if (e.name.startsWith(\"_TEMPLATE\")) continue;\n total++;\n } else if (e.isDirectory() && recursive) {\n if (e.name.startsWith(\".\") || e.name.startsWith(\"_\")) continue;\n total += await countMarkdown(join(dir, e.name), recursive);\n }\n }\n return total;\n}\n\n/**\n * One pass over `<dataDir>/worklog/` (`YYYY/MM/YYYY-MM-DD-*.md`): the most\n * recent entry (lexically-greatest relative path) and the set of dates seen.\n */\nasync function scanWorklog(\n dataDir: string,\n): Promise<{ recent: RecentWorklog | null; dates: string[] }> {\n const root = join(dataDir, \"worklog\");\n if (!existsSync(root)) return { recent: null, dates: [] };\n let bestRel: string | null = null;\n const dates = new Set<string>();\n\n async function walk(absDir: string, rel: string): Promise<void> {\n let entries;\n try {\n entries = await readdir(absDir, { withFileTypes: true });\n } catch {\n return;\n }\n for (const e of entries) {\n const childRel = rel ? `${rel}/${e.name}` : e.name;\n if (e.isDirectory()) {\n await walk(join(absDir, e.name), childRel);\n } else if (e.isFile()) {\n const m = e.name.match(/^(\\d{4}-\\d{2}-\\d{2})-.+\\.md$/);\n if (!m) continue;\n dates.add(m[1]!);\n if (bestRel === null || childRel > bestRel) bestRel = childRel;\n }\n }\n }\n\n await walk(root, \"\");\n const recent =\n bestRel === null\n ? null\n : { path: `worklog/${bestRel}`, title: await readTitle(join(root, bestRel)) };\n return { recent, dates: [...dates] };\n}\n\nasync function readTitle(absPath: string): Promise<string> {\n try {\n const raw = await readFile(absPath, \"utf8\");\n const m = raw.match(/^#\\s+(.+)$/m);\n if (m) return m[1]!.trim();\n } catch {\n // unreadable — fall through to filename\n }\n const base = absPath.replace(/\\\\/g, \"/\").split(\"/\").pop() ?? absPath;\n return base.replace(/\\.md$/, \"\");\n}\n\nfunction addDays(d: Date, n: number): Date {\n const out = new Date(d);\n out.setDate(out.getDate() + n);\n return out;\n}\n\nfunction isoDate(d: Date): string {\n const y = d.getFullYear();\n const m = String(d.getMonth() + 1).padStart(2, \"0\");\n const day = String(d.getDate()).padStart(2, \"0\");\n return `${y}-${m}-${day}`;\n}\n","import { mkdir, writeFile } from \"node:fs/promises\";\nimport { dirname, join } from \"node:path\";\nimport type { ModuleContext } from \"@vortex-os/core\";\nimport { WorklogStore } from \"@vortex-os/worklog\";\n\n/**\n * Ensure a dated worklog entry exists — the host-side **create** primitive\n * the worklog module deliberately leaves out (`WorklogStore` reads; `/log`\n * only appends and errors when today's entry is missing). Auto-worklog\n * (the agent at wind-down, or the SessionEnd net) needs *creation*, so it\n * lives here, where instance frontmatter conventions belong.\n *\n * Idempotent: if a worklog already exists for the date (with any keyword), it\n * is returned untouched (`created: false`) — never overwritten. Pair with\n * `appendSection` from `@vortex-os/worklog` to add the session's content.\n */\nexport interface EnsureWorklogResult {\n readonly path: string;\n readonly date: string;\n readonly keyword: string;\n /** True when this call created the file; false when one already existed. */\n readonly created: boolean;\n}\n\nexport async function ensureWorklogEntry(\n ctx: ModuleContext,\n opts?: {\n readonly now?: Date;\n readonly keyword?: string;\n readonly title?: string;\n readonly body?: string;\n },\n): Promise<EnsureWorklogResult> {\n const date = isoDate(opts?.now ?? new Date());\n const keyword = (opts?.keyword ?? \"worklog\").trim() || \"worklog\";\n const store = new WorklogStore(join(ctx.dataDir, \"worklog\"));\n\n // Any existing entry for the date (any keyword) counts — never duplicate a day.\n const existing = await store.get(date);\n if (existing) {\n return { path: existing.path, date: existing.date, keyword: existing.keyword, created: false };\n }\n\n const path = store.pathFor(date, keyword);\n const title = opts?.title ?? `${date} worklog`;\n await mkdir(dirname(path), { recursive: true });\n await writeFile(path, renderWorklogFile(date, title, opts?.body ?? \"\"), \"utf8\");\n return { path, date, keyword, created: true };\n}\n\nfunction renderWorklogFile(date: string, title: string, body: string): string {\n const trimmed = body.trimEnd();\n return (\n `---\\n` +\n `type: worklog\\n` +\n `created: ${date}\\n` +\n `updated: ${date}\\n` +\n `tags: [worklog]\\n` +\n `---\\n\\n` +\n `# ${title}\\n` +\n (trimmed ? `\\n${trimmed}\\n` : ``)\n );\n}\n\nfunction isoDate(d: Date): string {\n const y = d.getFullYear();\n const m = String(d.getMonth() + 1).padStart(2, \"0\");\n const day = String(d.getDate()).padStart(2, \"0\");\n return `${y}-${m}-${day}`;\n}\n","import type { ModuleContext } from \"@vortex-os/core\";\n// Type-only — erased at compile time, so importing it does NOT pull the\n// `@vortex-os/memory-extended` add-on (or its native sqlite/level deps) into\n// the module graph of consumers that only need the types. The runtime engine\n// is loaded lazily inside the function body via `await import(...)`.\nimport type { sessionArchive } from \"@vortex-os/memory-extended\";\n\n/**\n * Start-of-session \"catch-up\": fold conversation transcripts into the local\n * search archive without the user ever having to wrap up a session.\n *\n * Two sources, one pass:\n * - **local (a)** — this machine's own transcripts that are not archived yet,\n * read from the agent's transcript store and scoped to the current project.\n * - **pulled (b)** — transcripts created on another machine that arrived as\n * normalized text via git sync. Their text is present but this machine's\n * DB (local, derived, gitignored) has never indexed them.\n *\n * Text only — vectorization is deferred to recall/rebuild so session start\n * stays fast. The whole step is gated by `autoRecord.archive` at the call site\n * and is best-effort: callers should treat a thrown archive backend (e.g. the\n * native sqlite module not built) as \"skip\", never as a fatal start error.\n */\nexport interface CatchUpResult {\n /** Local transcripts newly archived this run (source a). */\n readonly ingestedLocal: number;\n /** Normalized transcripts from another machine newly indexed (source b). */\n readonly indexedPulled: number;\n /** Per-session ingest errors (source a). */\n readonly errors: number;\n}\n\nexport interface CatchUpOptions {\n /** Restrict local ingest to one project's transcripts. Default: `ctx.repoRoot`. */\n readonly cwd?: string;\n /**\n * Transcript adapters for local ingest. Default: Claude Code only. Other\n * hosts (Codex, Gemini) can be added by a caller; tests inject fakes so the\n * scan never touches the real home directory.\n */\n readonly adapters?: sessionArchive.IngestParams[\"adapters\"];\n /** Adapter environment override (e.g. a sandbox HOME). Tests use this. */\n readonly env?: sessionArchive.IngestParams[\"env\"];\n}\n\nexport async function catchUpSessions(\n ctx: ModuleContext,\n opts?: CatchUpOptions,\n): Promise<CatchUpResult> {\n // Lazy-load the optional add-on. Base ships without `memory-extended`; this\n // import resolves only when the add-on is installed alongside it. The call\n // site already gates this step on `autoRecord.archive` and treats a thrown\n // backend as \"skip\", so a missing add-on surfaces as a normal load error\n // the caller can catch.\n const { sessionArchive } = await import(\"@vortex-os/memory-extended\");\n\n const dataDir = ctx.dataDir;\n const cwd = opts?.cwd ?? ctx.repoRoot;\n const adapters = opts?.adapters ?? [sessionArchive.claudeCodeAdapter];\n\n // (a) Ingest this machine's not-yet-archived transcripts for the current\n // project. Writes the normalized copy into the archive (which git syncs) and\n // a local DB row. Text only — no vectorization here.\n const ingestResult = await sessionArchive.ingest({ adapters, dataDir, cwd, env: opts?.env });\n\n // (b) Index normalized transcripts that arrived from another machine via git\n // pull — their text is on disk but this machine's DB has no row yet.\n const store = new sessionArchive.SessionArchiveStore(dataDir);\n let indexedPulled = 0;\n try {\n indexedPulled = store.reindexFromNormalized().indexed;\n } finally {\n store.close();\n }\n\n return {\n ingestedLocal: ingestResult.sessionsIngested,\n indexedPulled,\n errors: ingestResult.errors.length,\n };\n}\n"],"mappings":"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","names":["b","join","v","dist_exports","dist_exports","join","join","writeFile","join","readFile","b","dist_exports","readdir","readFile","join","readdir","basename","extname","join","dist_exports","readdir","readFile","basename","extname","join","b","readdir","join","readFile","basename","extname","dist_exports","readdir","readFile","basename","extname","join","b","readdir","join","readFile","basename","extname","dist_exports","_getDefaults","_defaults","changeDefaults","newDefaults","noopTest","edit","regex","opt","source","obj","name","val","valSource","other","supportsLookbehind","bull","indent","newline","blockCode","fences","hr","heading","bullet","lheadingCore","lheading","lheadingGfm","_paragraph","blockText","_blockLabel","def","list","_tag","_comment","html","paragraph","blockquote","blockNormal","gfmTable","blockGfm","blockPedantic","escape","inlineCode","br","inlineText","_punctuation","_punctuationOrSpace","_notPunctuationOrSpace","punctuation","_punctuationGfmStrongEm","_punctuationOrSpaceGfmStrongEm","_notPunctuationOrSpaceGfmStrongEm","blockSkip","emStrongLDelimCore","emStrongLDelim","emStrongLDelimGfm","emStrongRDelimAstCore","emStrongRDelimAst","emStrongRDelimAstGfm","emStrongRDelimUnd","anyPunctuation","autolink","_inlineComment","tag","_inlineLabel","link","reflink","nolink","reflinkSearch","_caseInsensitiveProtocol","inlineNormal","inlinePedantic","inlineGfm","inlineBreaks","block","inline","escapeReplacements","getEscapeReplacement","ch","encode","cleanUrl","href","splitCells","tableRow","count","row","match","offset","str","escaped","curr","cells","i","rtrim","c","invert","l","suffLen","currChar","findClosingBracket","b","level","outputLink","cap","raw","lexer","rules","title","text","token","indentCodeCompensation","matchIndentToCode","indentToCode","node","matchIndentInNode","indentInNode","_Tokenizer","options","src","trimmed","lines","tokens","inBlockquote","currentLines","currentRaw","currentText","top","lastToken","oldToken","newText","newToken","isordered","itemRegex","endsWithBlankLine","endEarly","itemContents","line","t","nextLine","blankLine","nextBulletRegex","hrRegex","fencesBeginRegex","headingBeginRegex","htmlBeginRegex","rawLine","nextLineWithoutTabs","istask","ischecked","lastItem","spacers","hasMultipleLineBreaks","headers","aligns","rows","item","align","cell","trimmedUrl","rtrimSlash","lastParenIndex","linkLen","links","linkString","maskedSrc","prevChar","lLength","rDelim","rLength","delimTotal","midDelimTotal","endReg","lastCharLength","hasNonSpaceChars","hasSpaceCharsOnBothEnds","prevCapZero","_Lexer","__Lexer","next","lastParagraphClipped","extTokenizer","cutSrc","startIndex","tempSrc","tempStart","getStartIndex","errMsg","keepPrevChar","_Renderer","lang","langString","code","depth","ordered","start","body","j","type","startAttr","itemBody","checkbox","checked","header","k","content","cleanHref","out","_TextRenderer","_Parser","__Parser","anyToken","genericToken","ret","textToken","renderer","_Hooks","markdown","Marked","args","callback","values","tableToken","listToken","childTokens","extensions","pack","opts","ext","prevRenderer","extLevel","prop","rendererProp","rendererFunc","tokenizer","tokenizerProp","tokenizerFunc","prevTokenizer","hooks","hooksProp","hooksFunc","prevHook","arg","walkTokens","packWalktokens","blockType","origOpt","throwError","processedSrc","processedTokens","e","silent","async","msg","markedInstance","marked","setOptions","use","parseInline","parser","_Parser","lexer","_Lexer","dist_exports","readdir","readFile","stat","join","join","b","readdir","stat","readFile","readFile","writeFile","dist_exports","readdir","readFile","stat","join","FILENAME_PATTERN","readdir","join","stat","readFile","b","dist_exports","readdir","readFile","stat","basename","extname","join","b","readdir","join","extname","basename","stat","readFile","m","v","d","y","m","readdir","stat","extname","join","walk","dist_exports","readdir","readFile","stat","extname","join","RESERVED_FILES","readdir","extname","join","stat","readFile","b","dist_exports","readdir","stat","basename","extname","join","relative","walk","readFile","extname","extname","readFile","b","readFile","writeFile","extname","extname","readFile","writeFile","m","dist_exports","existsSync","mkdir","readFile","writeFile","join","existsSync","appendFile","mkdir","readFile","readdir","writeFile","dirname","join","today","d","y","m","join","mkdir","writeFile","dirname","existsSync","readFile","appendFile","readdir","existsSync","mkdir","readFile","readdir","writeFile","dirname","join","d","join","existsSync","walk","readdir","readFile","b","contextParagraph","formatYmd","y","m","mkdir","dirname","writeFile","m","dist_exports","join","writeFile","join","existsSync","extractTitle","join","existsSync","writeFile","d","y","m","existsSync","readFile","writeFile","join","join","existsSync","readFile","writeFile","existsSync","readdir","join","todayIso","d","y","m","existsSync","mkdir","readdir","readFile","stat","writeFile","basename","dirname","join","dirname","join","existsSync","mkdir","readdir","d","today","todayIso","writeFile","readFile","basename","y","m","countMarkdown","stat","formatYmd","steps","resolve","m","b","d","join","defaultDbPath","join","existsSync","readdir","readFile","join","COUNTED_DIRS","countMarkdown","d","walk","m","y","mkdir","writeFile","dirname","join","isoDate","join","mkdir","dirname","writeFile","d","y","m"]}