"use strict";exports.id=9708,exports.ids=[9708],exports.modules={39708:(e,t,n)=>{n.d(t,{eW:()=>eb,Fh:()=>eF,rx:()=>tw,GP:()=>tk,NQ:()=>t_,K4:()=>o,vE:()=>f,PT:()=>e7,HP:()=>tM,Xi:()=>tg,O_:()=>er,yw:()=>tN,P4:()=>tH,D4:()=>ty,hq:()=>tI,df:()=>eA,GO:()=>t1,JN:()=>J,m_:()=>td,Pi:()=>eR,mb:()=>et,uM:()=>no,fx:()=>C,WN:()=>l,b5:()=>Z,mk:()=>es,l6:()=>eo,BC:()=>ew,sW:()=>e5,li:()=>e1,Fo:()=>e2,dY:()=>k,$3:()=>nr,NZ:()=>t2,mm:()=>en,xD:()=>t9,bb:()=>F,Me:()=>X,IW:()=>G,Eo:()=>ey,xw:()=>eO,pq:()=>e3,Iw:()=>tV,nP:()=>A,ed:()=>eK,jb:()=>t0,uD:()=>t7,Of:()=>tF,Ze:()=>tZ,FK:()=>O,lj:()=>v,pf:()=>L,iT:()=>eZ,un:()=>tp,pZ:()=>e_,vw:()=>tQ,BR:()=>tS,cp:()=>eE,zC:()=>e8,uX:()=>th,FM:()=>eN,bE:()=>t8,f7:()=>ek,Lb:()=>eM,Ex:()=>eT,G2:()=>tT,tx:()=>eg});let a=`# Wiki Schema

This file is your operating contract with the LLM agent that maintains this
wiki. Edit it freely to steer what gets written and how.

## Topic

(Describe the topic of this wiki in one or two sentences. The agent reads this
on every ingest and query, so be specific about scope and audience.)

## Style guidelines

- Be concise. This is a personal wiki, not Wikipedia.
- One entity or concept per page.
- Cross-link generously with \`[[slug]]\`.
- Flag contradictions in a \`> [!contradiction]\` callout.

## Page type definitions

- **entity**: a person, organization, product, place
- **concept**: an idea, technique, framework, theorem
- **source**: a single document summary (for important sources only)
- **comparison**: two or more entities/concepts contrasted
- **overview**: high-level synthesis

## Additional instructions

(Add any project-specific rules the LLM should follow when reading sources or
answering questions.)
`,i=`# Wiki Index

_No pages yet. Add a source to get started._
`,r=`# Wiki Log
`,s=`# LLM Wiki tooling state (metadata cache, settings, trash, page history).
# Safe to delete; nothing important is lost.
.llm-wiki/
`,o=[{id:"blank",label:"Blank",description:"Default schema with generic style guidelines. Edit later in Settings → Schema.",body:a},{id:"research",label:"Research",description:"Academic / scholarly tone. Source-grounded claims, technical register, surfaces open questions.",body:`# Wiki Schema — Research

## Topic

(One or two sentences naming the field, sub-field, and your interest. Be
specific: "Quantum error-correction codes for fault-tolerant computing" beats
"Quantum computing".)

## Style guidelines

- Technical register. Use field-standard terminology rather than plain-language
  paraphrases.
- Prefer claims grounded in the source over the LLM's general knowledge. When
  introducing a claim, link the contributing source.
- Flag contradictions between sources explicitly in a \`> [!contradiction]\`
  callout — they're often the most interesting finding.
- Every quantitative claim should include the metric + units + reference.
- Be concise. Don't pad pages to look comprehensive; an honest "open question"
  paragraph is better than confident filler.

## Page type definitions

- **concept**: a technique, framework, theorem, method, model
- **entity**: a researcher, lab, institution, dataset, instrument
- **comparison**: two or more concepts/methods contrasted along measurable axes
- **source**: a single paper / preprint summary (only for landmark sources)
- **overview**: a high-level synthesis tying together a sub-area

## Additional instructions

- Preserve dates and historical sequence — when was a result first published,
  who else replicated, what superseded it.
- When a source disagrees with the consensus, note it as a contradiction
  rather than smoothing it over.
- Use \`> [!open-question]\` callouts for things the current sources don't
  resolve. These become research directions.
`},{id:"legal",label:"Legal",description:"Precise quoting, distinguishes holdings from dicta, flags overruled precedents.",body:`# Wiki Schema — Legal

## Topic

(Name the matter, regulatory area, or jurisdiction. E.g. "California
employment law — wage & hour", "ACME v. Smith litigation file", "EU AI Act
compliance research".)

## Style guidelines

- Precision over fluency. Quote source language verbatim for findings of
  fact, holdings, and statutory text — don't paraphrase.
- Every claim links back to its source page (case, statute, regulation,
  filing).
- Distinguish holding from dicta; majority from concurrence/dissent.
- Flag overruled or distinguished precedents with a \`> [!stale]\` callout.

## Page type definitions

- **entity**: parties, courts, judges, regulatory bodies, law firms
- **concept**: doctrines, tests, standards of review, legal theories
- **comparison**: how courts have applied a doctrine across jurisdictions
- **source**: a single case, statute, regulation, or filing summary
- **overview**: high-level synthesis of a doctrinal area

## Additional instructions

- Preserve citation format (jurisdiction, year, reporter). Don't strip it
  for prose flow.
- Never invent citations or holdings. If a source is ambiguous, say so.
- Flag conflicts between authorities; resolution is the user's call.
- Use \`> [!warning]\` callouts for time-sensitive items (statutes of
  limitations, filing deadlines).
`},{id:"clinical",label:"Clinical",description:"Evidence-graded, flags superseded guidelines, preserves doses/units exactly.",body:`# Wiki Schema — Clinical

## Topic

(Name the clinical area. E.g. "Hypertension management guidelines", "Type 2
diabetes treatment algorithms", "Pediatric vaccine schedule references".)

## Style guidelines

- Evidence-graded. When summarizing a recommendation, note the evidence level
  (e.g. "Class I, Level A" or guideline body's own grading) and the source.
- Prefer the most recent guideline; flag superseded recommendations with a
  \`> [!stale]\` callout pointing at the newer guidance.
- Distinguish recommendations from observational findings.
- This wiki is a personal reference, NOT clinical decision support. Avoid
  language that reads as patient-specific advice.

## Page type definitions

- **entity**: drugs, diseases, conditions, organizations (guideline bodies),
  diagnostic tests
- **concept**: mechanisms of action, pathophysiology, treatment algorithms,
  clinical pearls
- **comparison**: head-to-head treatment options, diagnostic workups
- **source**: a guideline document or landmark trial summary
- **overview**: synthesis of a condition's evaluation + management

## Additional instructions

- Surface contradictions between guideline bodies (e.g. ACC/AHA vs ESC).
- Flag rare adverse events with \`> [!warning]\` callouts.
- Preserve dose ranges + units exactly as cited; don't round.
- Note off-label uses explicitly when the source flags them.
`},{id:"project",label:"Project",description:"Opinionated, decision-oriented, dates opinions, captures failure modes explicitly.",body:`# Wiki Schema — Project

## Topic

(Name the project, market, or problem space. E.g. "Building a feedback
collection tool for B2B SaaS", "Competitor research for vertical AI agents",
"Investor + customer notes — pre-seed fundraise".)

## Style guidelines

- Opinionated. Don't hedge; capture what you actually think.
- Decisions get dated: "2026-05-24: chose Postgres over SQLite because…"
- "What we tried, what worked, what failed" beats "what's possible".
- Cross-link to entities (people, companies, competitors) liberally.
- Prefer 1-paragraph pages over 5-paragraph ones. Edit ruthlessly.

## Page type definitions

- **entity**: competitors, customers, investors, advisors, prospective hires
- **concept**: mechanisms (PLG, network effects), patterns (pricing models),
  decisions
- **comparison**: build-vs-buy, this-vs-that for evaluated options
- **overview**: strategy memos, quarterly retrospectives
- **source**: customer interview summaries, investor meeting notes (use the
  per-source promotion; usually the chat or interview transcript IS the source)

## Additional instructions

- Date-stamp opinions. They expire.
- Capture failure modes explicitly. A wiki that only records wins is
  marketing copy.
- Flag decisions you'd revisit if X happened ("\`> [!decision]\` Going with
  Stripe over Lemon Squeezy; would revisit if EU VAT becomes painful").
`},{id:"personal",label:"Personal KB",description:"Friendly + exploratory. Open questions welcome, capture sources for re-finding.",body:`# Wiki Schema — Personal knowledge base

## Topic

(Whatever you want to learn or remember. Multiple areas are fine — books +
podcasts + things-you-keep-googling + …. The agent works best with a stated
theme, even a loose one like "things I read about systems thinking and
adjacent topics".)

## Style guidelines

- Friendly + exploratory. Incomplete is fine; questions are welcome.
- Don't force every page to be a self-contained essay — fragments and
  cross-links count.
- Capture sources for "I want to find this again later" pages even when
  there's nothing to summarize.

## Page type definitions

- **concept**: ideas, frameworks, terms-of-art you encountered
- **entity**: people, books, podcasts, organizations, places
- **comparison**: when you're trying to choose between two things
- **overview**: occasional "what I learned about X" syntheses
- **source**: long-form pieces worth a dedicated summary

## Additional instructions

- Use \`> [!open-question]\` callouts liberally — they're prompts for future
  reading.
- Tag pages with where you found them (book + chapter, podcast + timestamp,
  article + author) so you can re-locate the original.
- If you don't fully understand something, say so. The wiki should reflect
  your actual state of knowledge, not a curated front.
`}];function l(e){return o.find(t=>t.id===e)??o[0]}var u=n(93977),c=n(49411),d=n(91876),g=n.n(d);let p=["entity","concept","source","comparison","overview"],h=["pdf","docx","html","md","txt","url","image","pptx","xlsx"],m=["ingest","query","lint","chat"],f={schema:"CLAUDE.md",index:"index.md",log:"log.md",gitignore:".gitignore",wiki:"wiki",raw:"raw",chats:"chats",tooling:".llm-wiki"},w=["inbox","pinned","archive"];async function y(e){try{return await (0,u.access)(e),!0}catch{return!1}}async function E(e,t){await y(e)||await (0,u.writeFile)(e,t,"utf8")}async function k(e){await (0,u.mkdir)(e,{recursive:!0});let t=[(0,c.join)(e,f.wiki),(0,c.join)(e,f.raw),(0,c.join)(e,f.chats),(0,c.join)(e,f.tooling),...w.map(t=>(0,c.join)(e,f.chats,t))];await Promise.all(t.map(e=>(0,u.mkdir)(e,{recursive:!0}))),await E((0,c.join)(e,f.schema),a),await E((0,c.join)(e,f.index),i),await E((0,c.join)(e,f.log),r),await E((0,c.join)(e,f.gitignore),s)}function T(e,t){return(0,c.join)(e,f.wiki,`${t}.md`)}function _(e){if(null!=e){if(e instanceof Date)return e.toISOString().slice(0,10);if("string"==typeof e)return e}}function S(e,t){if(null!=e){if(!Array.isArray(e))throw Error(`frontmatter '${t}' must be an array of strings`);return e.map((e,n)=>{if("string"!=typeof e)throw Error(`frontmatter '${t}[${n}]' must be a string`);return e})}}async function v(e,t){let n=await (0,u.readFile)(T(e,t),"utf8"),a=g()(n),i=function(e,t){let n=t.title,a=t.type,i=t.created,r=t.updated;if("string"!=typeof n||0===n.length)throw Error(`page ${e}: frontmatter missing required field 'title'`);if("string"!=typeof a||!p.includes(a))throw Error(`page ${e}: frontmatter 'type' must be one of ${p.join(", ")}, got ${String(a)}`);let s=_(i),o=_(r);if(void 0===s)throw Error(`page ${e}: frontmatter missing required field 'created'`);if(void 0===o)throw Error(`page ${e}: frontmatter missing required field 'updated'`);let l=S(t.sources,`${e}.sources`),u=S(t.tags,`${e}.tags`),c={title:n,slug:e,type:a,created:s,updated:o};return l&&(c.sources=l),u&&(c.tags=u),c}(t,a.data);return{slug:t,frontmatter:i,content:a.content.replace(/^\n/,"")}}async function b(e,t){await (0,u.mkdir)((0,c.join)(e,f.wiki),{recursive:!0});let n={...t.frontmatter,slug:t.slug},a=g().stringify(t.content,n);await (0,u.writeFile)(T(e,t.slug),a,"utf8")}async function $(e){let t;let n=(0,c.join)(e,f.wiki);try{t=await (0,u.readdir)(n)}catch(e){if("ENOENT"===e.code)return[];throw e}let a=t.filter(e=>e.endsWith(".md")).map(e=>e.slice(0,-3));return(await Promise.all(a.map(async t=>{try{let n=await v(e,t);return{slug:n.slug,title:n.frontmatter.title,type:n.frontmatter.type,updated:n.frontmatter.updated}}catch{return null}}))).filter(e=>null!==e).sort((e,t)=>e.slug.localeCompare(t.slug))}async function O(e){return(0,u.readFile)((0,c.join)(e,f.index),"utf8")}async function N(e,t){await (0,u.writeFile)((0,c.join)(e,f.index),t,"utf8")}async function P(e,t){let n=t.endsWith("\n")?t:`${t}
`;await (0,u.appendFile)((0,c.join)(e,f.log),`
${n}`,"utf8")}async function L(e){return(0,u.readFile)((0,c.join)(e,f.schema),"utf8")}var I=n(87561),x=n(85890),R=n.n(x);let M=`
CREATE TABLE IF NOT EXISTS sources (
  id TEXT PRIMARY KEY,
  filename TEXT NOT NULL,
  original_name TEXT,
  format TEXT NOT NULL,
  size_bytes INTEGER NOT NULL,
  added_at TEXT NOT NULL,
  ingested_at TEXT,
  url TEXT,
  title TEXT
);

CREATE TABLE IF NOT EXISTS pages (
  slug TEXT PRIMARY KEY,
  title TEXT NOT NULL,
  type TEXT NOT NULL,
  created_at TEXT NOT NULL,
  updated_at TEXT NOT NULL,
  word_count INTEGER NOT NULL,
  tags TEXT
);

CREATE VIRTUAL TABLE IF NOT EXISTS pages_fts USING fts5(
  slug UNINDEXED,
  title,
  content,
  tags
);

CREATE TABLE IF NOT EXISTS page_sources (
  page_slug TEXT NOT NULL,
  source_id TEXT NOT NULL,
  PRIMARY KEY (page_slug, source_id),
  FOREIGN KEY (page_slug) REFERENCES pages(slug) ON DELETE CASCADE,
  FOREIGN KEY (source_id) REFERENCES sources(id) ON DELETE CASCADE
);

CREATE TABLE IF NOT EXISTS chats (
  id TEXT PRIMARY KEY,
  filename TEXT NOT NULL,
  folder TEXT NOT NULL,
  title TEXT NOT NULL,
  created_at TEXT NOT NULL,
  updated_at TEXT NOT NULL,
  pinned INTEGER NOT NULL DEFAULT 0,
  message_count INTEGER NOT NULL DEFAULT 0
);

CREATE TABLE IF NOT EXISTS usage (
  id INTEGER PRIMARY KEY AUTOINCREMENT,
  operation TEXT NOT NULL,
  model TEXT NOT NULL,
  input_tokens INTEGER NOT NULL,
  output_tokens INTEGER NOT NULL,
  cost_cents REAL,
  created_at TEXT NOT NULL
);

CREATE TABLE IF NOT EXISTS response_cache (
  hash TEXT PRIMARY KEY,
  response TEXT NOT NULL,
  created_at TEXT NOT NULL,
  hits INTEGER NOT NULL DEFAULT 0
);

-- Tracks file mtime + size per path so syncWikiToDb can skip unchanged files
-- on startup. Internal bookkeeping; not part of the user-facing docs/03 schema.
CREATE TABLE IF NOT EXISTS sync_state (
  rel_path TEXT PRIMARY KEY,
  mtime_ms INTEGER NOT NULL,
  size_bytes INTEGER NOT NULL,
  synced_at TEXT NOT NULL
);
`;function A(e){let t=(0,c.join)(e,f.tooling);(0,I.mkdirSync)(t,{recursive:!0});let n=new(R())((0,c.join)(t,"meta.sqlite"));return n.pragma("foreign_keys = ON"),n.pragma("journal_mode = WAL"),n.pragma("synchronous = NORMAL"),function(e){e.exec(M)}(n),n}function j(e){if(!p.includes(e.type))throw Error(`pages.${e.slug}: unknown type in DB: ${e.type}`);return{slug:e.slug,title:e.title,type:e.type,created_at:e.created_at,updated_at:e.updated_at,word_count:e.word_count,tags:e.tags?JSON.parse(e.tags):[]}}function U(e,t){e.prepare(`INSERT INTO pages (slug, title, type, created_at, updated_at, word_count, tags)
     VALUES (@slug, @title, @type, @created_at, @updated_at, @word_count, @tags)
     ON CONFLICT(slug) DO UPDATE SET
       title = excluded.title,
       type = excluded.type,
       created_at = excluded.created_at,
       updated_at = excluded.updated_at,
       word_count = excluded.word_count,
       tags = excluded.tags`).run({...t,tags:JSON.stringify(t.tags)})}function C(e,t){let n=e.prepare("SELECT * FROM pages WHERE slug = ?").get(t);return n?j(n):null}function D(e,t){e.prepare("DELETE FROM pages WHERE slug = ?").run(t)}function F(e){return e.prepare("SELECT * FROM pages ORDER BY slug").all().map(j)}function W(e,t,n){e.prepare("INSERT OR IGNORE INTO page_sources (page_slug, source_id) VALUES (?, ?)").run(t,n)}function X(e,t){return e.prepare("SELECT source_id FROM page_sources WHERE page_slug = ? ORDER BY source_id").all(t).map(e=>e.source_id)}function q(e,t){e.prepare("DELETE FROM pages_fts WHERE slug = ?").run(t.slug),e.prepare("INSERT INTO pages_fts (slug, title, content, tags) VALUES (?, ?, ?, ?)").run(t.slug,t.title,t.content,t.tags.join(" "))}function z(e,t){e.prepare("DELETE FROM pages_fts WHERE slug = ?").run(t)}function B(e,t,n=20){let a=t.trim().split(/\s+/).filter(Boolean).map(e=>`"${e.replace(/"/g,'""')}"`).join(" ");return 0===a.length?[]:e.prepare(`SELECT slug, title, snippet(pages_fts, 2, '[', ']', '...', 16) AS snippet
         FROM pages_fts
        WHERE pages_fts MATCH ?
        ORDER BY rank
        LIMIT ?`).all(a,n)}function K(e){if(!h.includes(e.format))throw Error(`sources.${e.id}: unknown format in DB: ${e.format}`);return{...e,format:e.format}}function Y(e,t){e.prepare(`INSERT INTO sources (id, filename, original_name, format, size_bytes, added_at, ingested_at, url, title)
     VALUES (@id, @filename, @original_name, @format, @size_bytes, @added_at, @ingested_at, @url, @title)`).run(t)}function H(e,t){if(0===e.prepare(`UPDATE sources
         SET filename = @filename,
             original_name = @original_name,
             format = @format,
             size_bytes = @size_bytes,
             added_at = @added_at,
             ingested_at = @ingested_at,
             url = @url,
             title = @title
       WHERE id = @id`).run(t).changes)throw Error(`updateSource: no row with id '${t.id}'`)}function Z(e,t){let n=e.prepare("SELECT * FROM sources WHERE id = ?").get(t);return n?K(n):null}function J(e,t){e.prepare("DELETE FROM sources WHERE id = ?").run(t)}function G(e){return e.prepare("SELECT * FROM sources ORDER BY added_at DESC").all().map(K)}function Q(e){return{...e,pinned:0!==e.pinned}}function V(e){return{...e,pinned:e.pinned?1:0}}function ee(e,t){if(0===e.prepare(`UPDATE chats
         SET filename = @filename,
             folder = @folder,
             title = @title,
             created_at = @created_at,
             updated_at = @updated_at,
             pinned = @pinned,
             message_count = @message_count
       WHERE id = @id`).run(V(t)).changes)throw Error(`updateChat: no row with id '${t.id}'`)}function et(e,t){let n=e.prepare("SELECT * FROM chats WHERE id = ?").get(t);return n?Q(n):null}function en(e,t){return(t?e.prepare("SELECT * FROM chats WHERE folder = ? ORDER BY pinned DESC, updated_at DESC").all(t):e.prepare("SELECT * FROM chats ORDER BY pinned DESC, updated_at DESC").all()).map(Q)}var ea=n(19706);function ei(e,t){return e.prepare(`INSERT INTO usage (operation, model, input_tokens, output_tokens, cost_cents, created_at)
       VALUES (@operation, @model, @input_tokens, @output_tokens, @cost_cents, @created_at)`).run(t).lastInsertRowid}function er(e){let t=e.prepare("SELECT id, model, input_tokens, output_tokens FROM usage WHERE cost_cents IS NULL").all();if(0===t.length)return 0;let n=e.prepare("UPDATE usage SET cost_cents = ? WHERE id = ?"),a=0;return e.transaction(()=>{for(let e of t){let t=(0,ea.Ij)(e.model,e.input_tokens,e.output_tokens);null!==t&&(n.run(t,e.id),a++)}})(),a}function es(e){return e.prepare("SELECT COALESCE(SUM(cost_cents), 0) AS total FROM usage").get().total}function eo(e){return e.prepare(`SELECT model,
              operation,
              COUNT(*) AS call_count,
              COALESCE(SUM(input_tokens), 0) AS total_input_tokens,
              COALESCE(SUM(output_tokens), 0) AS total_output_tokens,
              COALESCE(SUM(cost_cents), 0) AS total_cost_cents
         FROM usage
        GROUP BY model, operation
        ORDER BY (total_input_tokens + total_output_tokens) DESC`).all().map(e=>{if(!m.includes(e.operation))throw Error(`usage breakdown: unknown operation ${e.operation}`);return{...e,operation:e.operation}})}function el(e,t){e.prepare(`INSERT INTO sync_state (rel_path, mtime_ms, size_bytes, synced_at)
     VALUES (@rel_path, @mtime_ms, @size_bytes, @synced_at)
     ON CONFLICT(rel_path) DO UPDATE SET
       mtime_ms = excluded.mtime_ms,
       size_bytes = excluded.size_bytes,
       synced_at = excluded.synced_at`).run(t)}n(12408);let eu=`${f.wiki}/`;function ec(e){return(0,c.basename)(e,".md")}async function ed(e,t,n,a){let i,r;let s=(0,c.join)(t,n);try{i=await (0,u.stat)(s)}catch(e){if("ENOENT"===e.code)return;throw e}let o=e.prepare("SELECT * FROM sync_state WHERE rel_path = ?").get(n)??null;if(o&&o.mtime_ms===i.mtimeMs&&o.size_bytes===i.size){a.skipped.push(ec(n));return}let l=ec(n);try{r=await v(t,l)}catch(e){a.errors.push({slug:l,error:e.message});return}let d={slug:l,title:r.frontmatter.title,type:r.frontmatter.type,created_at:r.frontmatter.created,updated_at:r.frontmatter.updated,word_count:r.content.split(/\s+/).filter(Boolean).length,tags:r.frontmatter.tags??[]};U(e,d),q(e,{slug:l,title:d.title,content:r.content,tags:d.tags}),el(e,{rel_path:n,mtime_ms:i.mtimeMs,size_bytes:i.size,synced_at:new Date().toISOString()}),(o?a.updated:a.added).push(l)}async function eg(e,t){let n={added:[],updated:[],deleted:[],skipped:[],errors:[]},a=(0,c.join)(e,f.wiki),i=[];try{i=await (0,u.readdir)(a)}catch(e){if("ENOENT"!==e.code)throw e}let r=new Set;for(let a of i){if(!a.endsWith(".md"))continue;let i=`${eu}${a}`;await ed(t,e,i,n),r.add(a.slice(0,-3))}for(let e of(eu?t.prepare("SELECT rel_path FROM sync_state WHERE rel_path LIKE ? ORDER BY rel_path").all(`${eu}%`):t.prepare("SELECT rel_path FROM sync_state ORDER BY rel_path").all()).map(e=>e.rel_path)){let a=ec(e);r.has(a)||(D(t,a),z(t,a),function(e,t){e.prepare("DELETE FROM sync_state WHERE rel_path = ?").run(t)}(t,e),n.deleted.push(a))}return n}var ep=n(70612);let eh={version:1,recentWikis:[],uiTheme:"auto"},em=["light","dark","auto"];function ef(){return process.env.LLM_WIKI_CONFIG_DIR??(0,c.join)((0,ep.homedir)(),".llm-wiki")}function ew(){return(0,c.join)(ef(),"config.json")}async function ey(){let e,t;let n=ew();try{e=await (0,u.readFile)(n,"utf8")}catch(e){if("ENOENT"===e.code)return{...eh};throw e}try{t=JSON.parse(e)}catch(e){throw Error(`global config at ${n} is not valid JSON: ${e.message}`)}return function(e){if("object"!=typeof e||null===e||Array.isArray(e))throw Error("global config: expected a JSON object");let t={...eh};return"string"==typeof e.openrouterKey&&e.openrouterKey.length>0&&(t.openrouterKey=e.openrouterKey),"string"==typeof e.activeWiki&&e.activeWiki.length>0&&(t.activeWiki=e.activeWiki),"string"==typeof e.onboardingCompletedAt&&e.onboardingCompletedAt.length>0&&(t.onboardingCompletedAt=e.onboardingCompletedAt),Array.isArray(e.recentWikis)&&(t.recentWikis=e.recentWikis.filter(e=>"string"==typeof e)),"string"==typeof e.uiTheme&&em.includes(e.uiTheme)&&(t.uiTheme=e.uiTheme),t}(t)}async function eE(e){let t=ef();await (0,u.mkdir)(t,{recursive:!0});let n=ew(),a=`${JSON.stringify(e,null,2)}
`;await (0,u.writeFile)(n,a,{encoding:"utf8",mode:384});try{await (0,u.chmod)(n,384)}catch{}}async function ek(e){let t=await ey(),n=t.recentWikis.filter(t=>t!==e),a={...t,activeWiki:e,recentWikis:[e,...n].slice(0,10)};return await eE(a),a}async function eT(){let e=await ey();if(e.onboardingCompletedAt)return e;let t={...e,onboardingCompletedAt:new Date().toISOString()};return await eE(t),t}async function e_(e){let t=await ey(),n={...t,recentWikis:t.recentWikis.filter(t=>t!==e)};if(t.activeWiki===e){let{activeWiki:e,...t}=n;return await eE({...t,version:1}),{...t,version:1}}return await eE(n),n}let eS=["openrouter","ollama"];function ev(e,t="openrouter"){return{provider:t,model:e}}let eb={version:1,topic:"",defaultModels:{ingest:ev("anthropic/claude-haiku-4.5"),query:ev("anthropic/claude-sonnet-4.6"),chat:ev("anthropic/claude-sonnet-4.6"),lint:ev("anthropic/claude-sonnet-4.6"),vision:ev("anthropic/claude-sonnet-4.6")},autoLintAfterIngest:!1,showCostEstimates:!0,requireApprovalForIngest:!1};function e$(e){return(0,c.join)(e,f.tooling,"settings.json")}async function eO(e){let t,n;let a=e$(e);try{t=await (0,u.readFile)(a,"utf8")}catch(e){if("ENOENT"===e.code)return{...eb,defaultModels:{...eb.defaultModels}};throw e}try{n=JSON.parse(t)}catch(e){throw Error(`wiki settings at ${a} is not valid JSON: ${e.message}`)}return function(e){if("object"!=typeof e||null===e||Array.isArray(e))throw Error("wiki settings: expected a JSON object");let t={...eb,defaultModels:{...eb.defaultModels}};"string"==typeof e.topic&&(t.topic=e.topic),"boolean"==typeof e.autoLintAfterIngest&&(t.autoLintAfterIngest=e.autoLintAfterIngest),"boolean"==typeof e.showCostEstimates&&(t.showCostEstimates=e.showCostEstimates),"boolean"==typeof e.requireApprovalForIngest&&(t.requireApprovalForIngest=e.requireApprovalForIngest);let n=e.defaultModels;if("object"==typeof n&&null!==n)for(let e of["ingest","query","chat","lint","vision"]){let a=n[e];if("string"==typeof a&&a.length>0)t.defaultModels[e]={provider:"openrouter",model:a};else if("object"==typeof a&&null!==a){let n="string"==typeof a.model&&a.model.length>0?a.model:t.defaultModels[e].model,i=a.provider,r="string"==typeof i&&eS.includes(i)?i:"openrouter";t.defaultModels[e]={provider:r,model:n}}}return t}(n)}async function eN(e,t){let n=(0,c.join)(e,f.tooling);await (0,u.mkdir)(n,{recursive:!0});let a=e$(e);await (0,u.writeFile)(a,`${JSON.stringify(t,null,2)}
`,"utf8")}let eP="llm-wiki",eL="openrouter",eI=null;async function ex(){return eI||(eI=(async()=>{try{let e=await Promise.resolve().then(n.t.bind(n,25606,23));return await e.findCredentials(eP),e}catch{return null}})())}async function eR(){let e=await ex();if(e)try{let t=await e.getPassword(eP,eL);if(t)return{key:t,source:"keychain",keychainAvailable:!0}}catch{}let t=await ey();return t.openrouterKey?{key:t.openrouterKey,source:"config",keychainAvailable:null!==e}:{key:null,source:"none",keychainAvailable:null!==e}}async function eM(e){if(!e.trim())throw Error("setApiKey: key must be non-empty");let t=await ex();if(t)try{await t.setPassword(eP,eL,e);let n=await ey();if(n.openrouterKey){let{openrouterKey:e,...t}=n;await eE({...t,version:1})}return{key:e,source:"keychain",keychainAvailable:!0}}catch{}let n=await ey();return await eE({...n,openrouterKey:e}),{key:e,source:"config",keychainAvailable:null!==t}}async function eA(){let e=await ex();if(e)try{await e.deletePassword(eP,eL)}catch{}let t=await ey();if(t.openrouterKey){let{openrouterKey:e,...n}=t;await eE({...n,version:1})}}var ej=n(91436);let eU=ej.Z_().min(1).regex(/^[a-z0-9-]+$/,"slug must be kebab-case (lowercase, hyphens only)"),eC=ej.Km(["entity","concept","source","comparison","overview"]),eD=ej.Km(["entities","concepts","sources","comparisons","overviews"]),eF=ej.Ry({summary:ej.Z_(),newPages:ej.IX(ej.Ry({slug:eU,title:ej.Z_().min(1),type:eC,content:ej.Z_(),tags:ej.IX(ej.Z_())})),pageUpdates:ej.IX(ej.Ry({slug:eU,content:ej.Z_(),updateReason:ej.Z_()})),indexEntries:ej.IX(ej.Ry({slug:eU,category:eD,summary:ej.Z_().max(500).transform(e=>e.length>200?`${e.slice(0,199).trimEnd()}…`:e)})),logEntry:ej.Z_(),contradictions:ej.IX(ej.Ry({description:ej.Z_(),pages:ej.IX(eU)}))}),eW=ej.Ry({answer:ej.Z_(),pagesUsed:ej.IX(eU),suggestedNewPage:ej.Ry({slug:eU,title:ej.Z_(),content:ej.Z_(),reason:ej.Z_()}).nullable(),confidence:ej.Km(["high","medium","low"]),caveats:ej.IX(ej.Z_())}),eX=ej.Ry({issues:ej.IX(ej.Ry({severity:ej.Km(["high","medium","low"]),type:ej.Km(["contradiction","orphan","missing-page","broken-link","gap","stale"]),description:ej.Z_(),affectedPages:ej.IX(eU),suggestedFix:ej.Z_().nullable()})),suggestedQuestions:ej.IX(ej.Z_()),overallHealth:ej.Km(["excellent","good","fair","needs-work"])});var eq=n(6005);let ez=[{heading:"Overviews",key:"overviews"},{heading:"Concepts",key:"concepts"},{heading:"Entities",key:"entities"},{heading:"Comparisons",key:"comparisons"},{heading:"Sources",key:"sources"}],eB={concept:"concepts",entity:"entities",comparison:"comparisons",source:"sources",overview:"overviews"};function eK(e){let t=new Map,n=null;for(let a of e.split(/\r?\n/)){let e=a.match(/^##\s+(.+?)\s*$/);if(e){let t=e[1]?.trim().toLowerCase()??"",a=ez.find(e=>e.heading.toLowerCase()===t);n=a?.key??null;continue}let i=a.match(/^-\s+\[\[([a-z0-9-]+)(?:\|[^\]]*)?\]\]:\s*(.*)$/);if(i&&n){let e=i[1],a=i[2]??"";e&&t.set(e,{category:n,summary:a.trim()})}}return t}function eY(e){if(0===e.size)return"# Wiki Index\n\n_No pages yet. Add a source to get started._\n";let t=new Map;for(let[n,a]of e){let e=t.get(a.category)??[];e.push({slug:n,summary:a.summary}),t.set(a.category,e)}for(let e of t.values())e.sort((e,t)=>e.slug.localeCompare(t.slug));let n=["# Wiki Index",""];for(let{heading:e,key:a}of ez){let i=t.get(a);if(i&&0!==i.length){for(let t of(n.push(`## ${e}`),i)){let e=t.summary.length>0?`: ${t.summary}`:"";n.push(`- [[${t.slug}]]${e}`)}n.push("")}}return`${n.join("\n").trimEnd()}
`}function eH(e,t=120){let n=e.replace(/^\s*#+\s+.*$/gm,"").replace(/^\s*>.*$/gm,"").trim(),a=n.match(/^([\s\S]*?[.!?])(?:\s|$)/),i=a?a[1]:n.split(/\n/)[0]??"";return(i=i.replace(/\[\[([^\]|]+)\|([^\]]+)\]\]/g,"$2").replace(/\[\[([^\]]+)\]\]/g,"$1").replace(/\s+/g," ").trim()).length>t&&(i=`${i.slice(0,t-1).trimEnd()}…`),i}async function eZ(e,t){let n=(0,c.join)(e,f.index),a="";try{a=await (0,u.readFile)(n,"utf8")}catch{a=""}let i=eK(a),r=F(t),s=new Set(r.map(e=>e.slug)),o=new Map,l=[];for(let t of r){let n=eB[t.type],a=i.get(t.slug);if(a&&a.summary.length>0){o.set(t.slug,{category:n,summary:a.summary});continue}let r="";try{let n=await v(e,t.slug);r=eH(n.content)}catch{r=""}o.set(t.slug,{category:n,summary:r}),l.push(t.slug)}let d=[];for(let e of i.keys())s.has(e)||d.push(e);return await N(e,eY(o)),{totalPages:r.length,added:l,removed:d}}async function eJ(e,t,n){let a;let i=C(t,n);if(!i)return;try{a=await v(e,n)}catch{return}let r=eH(a.content),s=eB[i.type],o=(0,c.join)(e,f.index),l="";try{l=await (0,u.readFile)(o,"utf8")}catch{l=""}let d=eK(l);d.set(n,{category:s,summary:r}),await N(e,eY(d))}let eG=`You maintain an LLM Wiki following Andrej Karpathy's pattern. Read the new source and produce structured updates as a single JSON object.

Behavior rules:
- Slugs are kebab-case, lowercase, hyphens only, no special chars.
- Cross-link liberally with [[slug]] or [[slug|Display Name]].
- One entity or concept per page. Keep pages focused.
- Update existing pages rather than duplicating info.
- If new info contradicts an existing page, flag it in the contradictions array.
- Be concise. This is a personal wiki, not Wikipedia.
- Page type guidance:
  - entity: a person, organization, product, place
  - concept: an idea, technique, framework, theorem
  - source: a single-document summary (use sparingly, only for important sources)
  - comparison: two or more entities/concepts contrasted
  - overview: high-level synthesis`,eQ=`Output ONLY a valid JSON object matching this exact shape. No prose, no markdown fences:

{
  "summary": "Short, single-sentence summary of what was extracted from this source.",
  "newPages": [
    {
      "slug": "kebab-case-slug",
      "title": "Display Title",
      "type": "concept",
      "content": "Markdown body. Use [[other-slug]] for cross-links.",
      "tags": ["tag1", "tag2"]
    }
  ],
  "pageUpdates": [
    {
      "slug": "existing-page-slug",
      "content": "Full new body for this page (entire replacement, not a diff).",
      "updateReason": "Why this update was needed."
    }
  ],
  "indexEntries": [
    {
      "slug": "page-slug",
      "category": "concepts",
      "summary": "Short one-liner for the index — aim for 100-150 chars, hard cap 200."
    }
  ],
  "logEntry": "Single-line summary of this ingest.",
  "contradictions": [
    {
      "description": "Description of what disagrees and where.",
      "pages": ["slug-a", "slug-b"]
    }
  ]
}

Strict field rules — get any of these wrong and the JSON is rejected:
- "type" on newPages MUST be one of: "entity", "concept", "source", "comparison", "overview" (singular, lowercase).
- "category" on indexEntries MUST be one of: "entities", "concepts", "sources", "comparisons", "overviews" (PLURAL, lowercase). Do NOT use the wiki's topic name.
- "slug" everywhere MUST be kebab-case ([a-z0-9-]+), never capitalized, never spaced.
- "newPages", "pageUpdates", "indexEntries", "contradictions" are ALWAYS arrays. Use [] (not omitted, not null) when empty.
- "summary" and "logEntry" are required strings.`;function eV(e){let t=e.relevantPages.length>0?e.relevantPages.map(e=>`### ${e.title} (slug: ${e.slug}, type: ${e.type})
${function(e,t){let n=e.split(/\s+/);return n.length<=1e3?e:`${n.slice(0,1e3).join(" ")}

[truncated: ${n.length-t} more words]`}(e.excerpt,1e3)}`).join("\n\n---\n\n"):"(no existing pages yet — this wiki is empty)";return{system:[eG,"","User schema (CLAUDE.md) — describes the wiki's topic and editorial rules. Do NOT confuse the user's topic with the JSON schema below.",e0(e.schema),"","Current wiki index:",e0(e.index),"",`Existing pages (top ${e.relevantPages.length} most relevant):`,e0(t),"",eQ].join("\n"),user:[`New source: "${e.source.title}" (format: ${e.source.format})`,"","--- BEGIN SOURCE ---",e.source.content,"--- END SOURCE ---"].join("\n")}}function e0(e){return`\`\`\`\`markdown
${e}
\`\`\`\``}async function e1(e){e.onProgress?.({phase:"context",message:"Loading wiki schema and index..."});let[t,n]=await Promise.all([e4(e.wikiPath),e6(e.wikiPath)]);e.onProgress?.({phase:"context",message:`Searching for relevant existing pages…`});let a=await e9(e.wikiPath,e.db,e.source);e.onProgress?.({phase:"llm",message:`Calling ${e.model} (this is the slow step)…`});let i=eV({schema:t,index:n,relevantPages:a,source:{title:e.source.title,format:e.source.format,content:e.source.content}}),r=await (0,ea.wI)({client:e.client,model:e.model,system:i.system,user:i.user,schema:eF});return ei(e.db,{operation:"ingest",model:r.model,input_tokens:r.usage.inputTokens,output_tokens:r.usage.outputTokens,cost_cents:(0,ea.Ij)(r.model,r.usage.inputTokens,r.usage.outputTokens),created_at:new Date().toISOString()}),e.dryRun||(e.onProgress?.({phase:"apply",message:`Writing ${r.data.newPages.length} new pages, updating ${r.data.pageUpdates.length}…`}),await e7({response:r.data,wikiPath:e.wikiPath,db:e.db,sourceId:e.sourceId??null,sourceTitle:e.source.title,format:e.source.format})),e.onProgress?.({phase:"done",result:r.data}),r.data}async function e2(e){e.onProgress?.({phase:"context",message:"Loading wiki schema and index..."});let[t,n]=await Promise.all([e4(e.wikiPath),e6(e.wikiPath)]),a=eV({schema:t,index:n,relevantPages:[],source:{title:e.source.title,format:e.source.format,content:`(The actual content is attached as a ${e.source.mediaType} file.)`}});e.onProgress?.({phase:"llm",message:`Calling ${e.model} with attached ${e.source.format} (${Math.round(e.source.sizeBytes/1024)} KB)…`});let i=[{type:"text",text:`New source: "${e.source.title}" (format: ${e.source.format}, ${Math.round(e.source.sizeBytes/1024)} KB).

Read the attached file carefully and produce the JSON response per the schema.`},{type:"image_url",image_url:{url:`data:${e.source.mediaType};base64,${e.source.base64}`}}],r=await (0,ea.wI)({client:e.client,model:e.model,system:a.system,user:"(see attached file)",userParts:i,schema:eF});return ei(e.db,{operation:"ingest",model:r.model,input_tokens:r.usage.inputTokens,output_tokens:r.usage.outputTokens,cost_cents:(0,ea.Ij)(r.model,r.usage.inputTokens,r.usage.outputTokens),created_at:new Date().toISOString()}),e.dryRun||(e.onProgress?.({phase:"apply",message:`Writing ${r.data.newPages.length} new pages, updating ${r.data.pageUpdates.length}…`}),await e7({response:r.data,wikiPath:e.wikiPath,db:e.db,sourceId:e.sourceId??null,sourceTitle:e.source.title,format:e.source.format})),e.onProgress?.({phase:"done",result:r.data}),r.data}async function e8(e){let t=new Date().toISOString().slice(0,10),n=ts(e.title),a=e.ext.startsWith(".")?e.ext:`.${e.ext}`,i=`${t}-${n}${a}`,r=(0,c.join)(e.wikiPath,f.raw);await (0,u.mkdir)(r,{recursive:!0});let s=(0,c.join)(r,i);await (0,u.writeFile)(s,e.buffer);let o=(0,eq.randomUUID)(),l={id:o,filename:i,original_name:e.originalName??null,format:e.format,size_bytes:e.buffer.length,added_at:new Date().toISOString(),ingested_at:null,url:e.url??null,title:e.title};return Y(e.db,l),{sourceId:o,rawFilename:i,rawPath:s}}function e3(e,t){var n,a;let i=(n=e,a=t,n.prepare("SELECT * FROM sources WHERE id = ?").get(a)||null);i&&H(e,{...i,ingested_at:new Date().toISOString()})}async function e5(e){var t;let n=(e.title??(t=e.text,(t.split(/\r?\n/,1)[0]?.trim()??"").replace(/^#+\s*/,"").slice(0,120)||"Untitled note")).trim()||"Untitled note",a=ts(n),i=new Date().toISOString().slice(0,10),r=`${i}-${a}.md`,s=(0,c.join)(e.wikiPath,f.raw);await (0,u.mkdir)(s,{recursive:!0});let o=(0,c.join)(s,r);await (0,u.writeFile)(o,`# ${n}

${e.text.trim()}
`,"utf8");let l=Buffer.byteLength(e.text,"utf8"),d=(0,eq.randomUUID)(),g={id:d,filename:r,original_name:null,format:"md",size_bytes:l,added_at:new Date().toISOString(),ingested_at:null,url:null,title:n};Y(e.db,g);try{let t=await e1({source:{content:e.text,title:n,format:"md"},wikiPath:e.wikiPath,db:e.db,client:e.client,model:e.model,sourceId:d,dryRun:e.dryRun,onProgress:e.onProgress});if(e.dryRun)return{sourceId:d,rawFilename:r,response:t,dryRun:!0};return H(e.db,{...g,ingested_at:new Date().toISOString()}),{sourceId:d,rawFilename:r,response:t,dryRun:!1}}catch(e){throw e}}async function e4(e){try{return await L(e)}catch{return"(no schema set yet — assume a general-purpose personal wiki)"}}async function e6(e){try{return await O(e)}catch{return"(no index yet)"}}async function e9(e,t,n){let a=`${n.title} ${n.content.slice(0,500)}`,i=[];try{i=B(t,a,15)}catch{i=[]}let r=[];for(let t of i)try{let n=await v(e,t.slug);r.push({slug:n.slug,title:n.frontmatter.title,type:n.frontmatter.type,excerpt:n.content})}catch{}return r}async function e7(e){let{response:t,wikiPath:n,db:a,sourceId:i}=e,r=new Date().toISOString().slice(0,10),s=[];for(let e of t.newPages)await b(n,{slug:e.slug,frontmatter:{title:e.title,slug:e.slug,type:e.type,created:r,updated:r,tags:e.tags,...i?{sources:[i]}:{}},content:tr(e.content)}),te(a,n,e.slug,e.title,e.type,r,r,e.content,e.tags),i&&W(a,e.slug,i),s.push(e.slug);for(let e of t.pageUpdates){var o;let t=await tn(n,e.slug);if(!t){await b(n,{slug:e.slug,frontmatter:{title:to(e.slug),slug:e.slug,type:"concept",created:r,updated:r,...i?{sources:[i]}:{}},content:tr(e.content)}),te(a,n,e.slug,to(e.slug),"concept",r,r,e.content,[]),i&&W(a,e.slug,i),s.push(e.slug);continue}await ta(n,e.slug);let l=i?(o=t.frontmatter.sources)?o.includes(i)?o:[...o,i]:[i]:t.frontmatter.sources;await b(n,{slug:e.slug,frontmatter:{...t.frontmatter,updated:r,...l?{sources:l}:{}},content:tr(e.content)}),te(a,n,e.slug,t.frontmatter.title,t.frontmatter.type,t.frontmatter.created,r,e.content,t.frontmatter.tags??[]),i&&W(a,e.slug,i),s.push(e.slug)}await ti(n,t,s);let l=function(e,t,n){let a=new Date().toISOString().replace("T"," ").slice(0,16),i=[`## [${a}] ingest | ${e} (${t})`];return n.newPages.length>0&&i.push(`- created pages: ${n.newPages.map(e=>e.slug).join(", ")}`),n.pageUpdates.length>0&&i.push(`- updated pages: ${n.pageUpdates.map(e=>e.slug).join(", ")}`),n.contradictions.length>0&&i.push(`- contradictions flagged: ${n.contradictions.length}`),n.summary&&i.push(`- summary: ${n.summary}`),i.join("\n")}(e.sourceTitle,e.format,t);await P(n,l)}function te(e,t,n,a,i,r,s,o,l){U(e,{slug:n,title:a,type:i,created_at:r,updated_at:s,word_count:o.split(/\s+/).filter(Boolean).length,tags:l}),q(e,{slug:n,title:a,content:o,tags:l}),tt(e,t,n)}async function tt(e,t,n){let a=`${f.wiki}/${n}.md`;try{let n=await (0,u.stat)((0,c.join)(t,a));el(e,{rel_path:a,mtime_ms:n.mtimeMs,size_bytes:n.size,synced_at:new Date().toISOString()})}catch{}}async function tn(e,t){try{return await v(e,t)}catch{return null}}async function ta(e,t){let n=(0,c.join)(e,f.wiki,`${t}.md`);try{await (0,u.stat)(n)}catch{return}let a=(0,c.join)(e,f.tooling,"page-history");await (0,u.mkdir)(a,{recursive:!0});let i=new Date().toISOString().replace(/[:.]/g,"-");await (0,u.copyFile)(n,(0,c.join)(a,`${t}-${i}.md`))}async function ti(e,t,n){let a=(0,c.join)(e,f.index),i="";try{i=await (0,u.readFile)(a,"utf8")}catch{i=""}let r=eK(i);for(let e of t.indexEntries)r.delete(e.slug);for(let e of n)r.delete(e);for(let e of t.indexEntries)r.set(e.slug,{category:e.category,summary:e.summary});await N(e,eY(r))}function tr(e){return e.endsWith("\n")?e:`${e}
`}function ts(e){return e.toLowerCase().normalize("NFKD").replace(/[̀-ͯ]/g,"").replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,80)||"untitled"}function to(e){return e.split("-").map(e=>e.length?e[0].toUpperCase()+e.slice(1):"").join(" ")}let tl=/\[\[([a-z0-9-]+)(?:\|([^\]]+))?\]\]/g;function tu(e){let t=[];for(let n of e.matchAll(tl)){let e=n[1],a=n[2]?.trim();e&&t.push({slug:e,display:a&&a.length>0?a:e})}return t}function tc(e){let t=new Set;for(let n of tu(e))t.add(n.slug);return t}async function td(e,t,n){let a=n.toLowerCase(),i=F(e),r=[];for(let e of i){let n;if(e.slug!==a){try{n=await v(t,e.slug)}catch{continue}tc(n.content).has(a)&&r.push({slug:e.slug,title:n.frontmatter.title,excerpt:function(e,t){let n=e.toLowerCase().indexOf(`[[${t}`);if(-1===n)return e.slice(0,160);let a=Math.max(0,n-80),i=Math.min(e.length,n+160),r=a>0?"…":"",s=i<e.length?"…":"";return`${r}${e.slice(a,i).replace(/\s+/g," ").trim()}${s}`}(n.content,a)})}}return r.sort((e,t)=>e.title.localeCompare(t.title))}async function tg(e,t,n,a){let i=await v(e,n),r=await tb(e,n),s=new Date().toISOString().slice(0,10),o={...i.frontmatter,...void 0!==a.title?{title:a.title}:{},...void 0!==a.type?{type:a.type}:{},...void 0!==a.tags?{tags:a.tags}:{},updated:s,slug:n},l={slug:n,frontmatter:o,content:tO(a.content)};await b(e,l),U(t,{slug:n,title:o.title,type:o.type,created_at:o.created,updated_at:o.updated,word_count:t$(l.content),tags:o.tags??[]}),q(t,{slug:n,title:o.title,content:l.content,tags:o.tags??[]});try{let a=await (0,u.stat)((0,c.join)(e,f.wiki,`${n}.md`));el(t,{rel_path:`${f.wiki}/${n}.md`,mtime_ms:a.mtimeMs,size_bytes:a.size,synced_at:new Date().toISOString()})}catch{}let d=new Date().toISOString().replace("T"," ").slice(0,16);return await P(e,`## [${d}] edit | ${o.title} (${n})`),await eJ(e,t,n),{slug:n,page:l,backupPath:r}}async function tp(e,t,n,a){let i=await v(e,n),r=a.replace(/[.*+?^${}()|[\]\\]/g,"\\$&"),s=RegExp(`\\[\\[${r}(?:\\|([^\\]]+))?\\]\\]`,"g"),o=i.content.replace(s,(e,t)=>t&&t.length>0?t:a);if(o===i.content)throw Error(`page ${n} doesn't contain a [[${a}]] reference`);return tg(e,t,n,{content:o})}async function th(e,t){let n=(0,c.join)(e,f.schema),a=(0,c.join)(e,f.tooling,"schema-history");await (0,u.mkdir)(a,{recursive:!0});let i=null;try{await (0,u.stat)(n);let e=new Date().toISOString().replace(/[:.]/g,"-");i=(0,c.join)(a,`CLAUDE-${e}.md`),await (0,u.copyFile)(n,i)}catch{}await tm(n,tO(t));let r=await tf(a,10),s=new Date().toISOString().replace("T"," ").slice(0,16);return await P(e,`## [${s}] schema | edited CLAUDE.md`),{backupPath:i,prunedCount:r}}async function tm(e,t){let{writeFile:a}=await Promise.resolve().then(n.t.bind(n,93977,23));await a(e,t,"utf8")}async function tf(e,t){let a;let{readdir:i,unlink:r}=await Promise.resolve().then(n.t.bind(n,93977,23));try{a=await i(e)}catch{return 0}let s=a.filter(e=>e.startsWith("CLAUDE-")).sort(),o=s.length-t;if(o<=0)return 0;for(let t of s.slice(0,o))await r((0,c.join)(e,t));return o}class tw extends Error{constructor(e){super(`page already exists: ${e}`),this.name="PageAlreadyExistsError",this.slug=e}}async function ty(e,t,n){let a=(0,c.join)(e,f.wiki,`${n.slug}.md`);if(await tv(a))throw new tw(n.slug);let i=new Date().toISOString().slice(0,10),r=n.tags??[],s={slug:n.slug,frontmatter:{title:n.title,slug:n.slug,type:n.type,created:i,updated:i,...r.length>0?{tags:r}:{},...n.sources&&n.sources.length>0?{sources:n.sources}:{}},content:tO(n.content)};await b(e,s),U(t,{slug:n.slug,title:n.title,type:n.type,created_at:i,updated_at:i,word_count:t$(s.content),tags:r}),q(t,{slug:n.slug,title:n.title,content:s.content,tags:r});try{let e=await (0,u.stat)(a);el(t,{rel_path:`${f.wiki}/${n.slug}.md`,mtime_ms:e.mtimeMs,size_bytes:e.size,synced_at:new Date().toISOString()})}catch{}let o=new Date().toISOString().replace("T"," ").slice(0,16);return await P(e,`## [${o}] create | ${n.title} (${n.slug})`),await eJ(e,t,n.slug),s}let tE="trash/wiki";class tk extends Error{constructor(e){super(`page not found: ${e}`),this.name="PageNotFoundError",this.slug=e}}async function tT(e,t,n){let a=(0,c.join)(e,f.wiki,`${n}.md`);if(!await tv(a))throw new tk(n);let i=await $(e),r=[];for(let t of i)if(t.slug!==n)try{let a=await v(e,t.slug);tc(a.content).has(n)&&r.push(t.slug)}catch{}let s=(0,c.join)(e,f.tooling,tE);await (0,u.mkdir)(s,{recursive:!0});let o=new Date().toISOString().replace(/[:.]/g,"-"),l=`${o}-${n}.md`,d=(0,c.join)(s,l);await (0,u.rename)(a,d),D(t,n),z(t,n);let g=(0,c.join)(e,f.index);try{let t=await (0,u.readFile)(g,"utf8"),a=eK(t);a.delete(n)&&await N(e,eY(a))}catch{}let p=new Date().toISOString().replace("T"," ").slice(0,16);return await P(e,`## [${p}] delete | ${n} (trashed → ${tE}/${l})`),{slug:n,trashFilename:l,trashPath:d,backlinkSlugs:r}}class t_ extends Error{constructor(e){super(`cannot restore: a page already exists at slug "${e}". Rename or delete it first, or restore the trash file manually.`),this.name="PageRestoreConflictError",this.slug=e}}async function tS(e,t,n,a){let i=(0,c.join)(e,f.wiki,`${n}.md`);if(await tv(i))throw new t_(n);let r=(0,c.join)(e,f.tooling,tE),s=(0,c.join)(r,a),o=s.replace(/\\/g,"/"),l=r.replace(/\\/g,"/");if(!o.startsWith(l+"/")&&o!==l)throw Error("trashFilename must not contain path separators");if(!await tv(s))throw Error(`trash file not found: ${a}`);await (0,u.rename)(s,i);let d=await v(e,n),g=new Date().toISOString().slice(0,10),p=d.frontmatter.tags??[];U(t,{slug:n,title:d.frontmatter.title,type:d.frontmatter.type,created_at:d.frontmatter.created,updated_at:d.frontmatter.updated||g,word_count:t$(d.content),tags:p}),q(t,{slug:n,title:d.frontmatter.title,content:d.content,tags:p});try{let e=await (0,u.stat)(i);el(t,{rel_path:`${f.wiki}/${n}.md`,mtime_ms:e.mtimeMs,size_bytes:e.size,synced_at:new Date().toISOString()})}catch{}await eJ(e,t,n);let h=new Date().toISOString().replace("T"," ").slice(0,16);return await P(e,`## [${h}] restore | ${n} (from trash)`),{slug:n,page:d}}async function tv(e){try{return await (0,u.access)(e),!0}catch{return!1}}async function tb(e,t){let n=(0,c.join)(e,f.wiki,`${t}.md`);try{await (0,u.stat)(n)}catch{return null}let a=(0,c.join)(e,f.tooling,"page-history");await (0,u.mkdir)(a,{recursive:!0});let i=new Date().toISOString().replace(/[:.]/g,"-"),r=(0,c.join)(a,`${t}-${i}.md`);return await (0,u.copyFile)(n,r),r}function t$(e){return e.split(/\s+/).filter(Boolean).length}function tO(e){return e.endsWith("\n")?e:`${e}
`}async function tN(e,t){let n=F(t),a=new Set(n.map(e=>e.slug)),i=[],r=[],s=new Set,o=new Map;for(let e of n)o.set(e.slug,0);for(let t of n){let n="";try{n=(await v(e,t.slug)).content}catch{}for(let e of tc(n)){if(e===t.slug||!a.has(e))continue;let n=`${t.slug}->${e}`;s.has(n)||(s.add(n),r.push({source:t.slug,target:e}),o.set(t.slug,(o.get(t.slug)??0)+1),o.set(e,(o.get(e)??0)+1))}i.push({id:t.slug,title:t.title,group:t.type,preview:function(e){let t=e.replace(/\[\[([^\]|]+)\|([^\]]+)\]\]/g,"$2").replace(/\[\[([^\]]+)\]\]/g,"$1").replace(/^#+\s+.*$/m,"").trim().replace(/\s+/g," ").trim();return t.length<=280?t:t.slice(0,280).trimEnd()+"…"}(n),degree:0,tags:t.tags})}for(let e of i)e.degree=o.get(e.id)??0;return{nodes:i,links:r}}let tP=ej.Ry({title:ej.Z_().min(1),type:ej.Km(p),content:ej.Z_().min(1),tags:ej.IX(ej.Z_()).default([])}),tL=`You write a brand-new wiki page to fill a gap in an LLM Wiki.

Rules:
- Output ONLY a JSON object matching the schema. No preamble, no markdown fences.
- Slug is fixed by the caller — DO NOT invent a different one.
- Pick the correct \`type\`: entity (person, org, place), concept (idea, technique, framework, theorem), source (a single document summary), comparison (two or more things contrasted), overview (high-level synthesis).
- Keep the page concise — this is a stub. ~50-150 words of body. The user will expand it later.
- Cross-link with [[slug]] notation to pages that referenced this stub, so it's not orphaned.
- Don't fabricate detailed facts you can't ground in the context excerpts. If a fact isn't in the context, state it generically or leave it out.
- Be honest about uncertainty in a brief opening sentence.

JSON_SHAPE:
{
  "title": "Human-readable title (e.g. 'No-Cloning Theorem')",
  "type": "concept",
  "content": "Markdown body. Open with one sentence defining the topic, then 2-3 short paragraphs or a short list. Use [[other-slug]] cross-links.",
  "tags": ["string", "tags"]
}`;async function tI(e){let[t,n]=await Promise.all([tA(e.wikiPath),tj(e.wikiPath)]),a=["Wiki schema (CLAUDE.md):",t,"","Current wiki index:",n,"",`Create a stub page with slug: ${e.missingSlug}`,"",function(e,t){if(0===t.length)return`No existing pages reference [[${e}]] yet. Use your general knowledge to write a brief, honest stub.`;let n=[`[[${e}]] is referenced from the following pages. Use these excerpts to write a stub that fits the wiki's existing voice and links back to them.`,""];for(let e of t)n.push(`### ${e.title} ([[${e.slug}]])`),n.push(e.excerpt.trim()),n.push("");return n.join("\n")}(e.missingSlug,e.referencingPages)].join("\n"),i=await (0,ea.wI)({client:e.client,model:e.model,system:tL,user:a,schema:tP});ei(e.db,{operation:"lint",model:i.model,input_tokens:i.usage.inputTokens,output_tokens:i.usage.outputTokens,cost_cents:(0,ea.Ij)(i.model,i.usage.inputTokens,i.usage.outputTokens),created_at:new Date().toISOString()});let r=await ty(e.wikiPath,e.db,{slug:e.missingSlug,title:i.data.title,type:i.data.type,content:i.data.content,tags:i.data.tags});return await eZ(e.wikiPath,e.db),{page:r,modelUsed:i.model}}let tx=ej.Ry({newContent:ej.Z_().min(1),changeSummary:ej.Z_().min(1)}),tR=`You apply a lint fix to a wiki page.

You are given a page's current body, a description of the issue, and a proposed fix. Apply the fix and return the page body's NEW content. Keep everything else identical — only change what the fix requires.

Rules:
- Output ONLY a JSON object matching the schema. No preamble, no markdown fences.
- Preserve every [[wikilink]] in the page unless the fix explicitly removes one.
- Preserve the page's voice and structure (headings, lists, paragraphs).
- The fix is usually one or two sentences of change. Don't rewrite the whole page.
- If the fix is impossible without losing important content, return the original content unchanged and explain in changeSummary.

JSON_SHAPE:
{
  "newContent": "Full page body, with the fix applied. Markdown only — no frontmatter.",
  "changeSummary": "One sentence describing what changed."
}`;async function tM(e){let t=await v(e.wikiPath,e.pageSlug),n=[`Page slug: ${e.pageSlug}`,`Page title: ${t.frontmatter.title}`,"",`Issue: ${e.issueDescription}`,`Proposed fix: ${e.fixInstruction}`,"","Current page body:",t.content].join("\n"),a=await (0,ea.wI)({client:e.client,model:e.model,system:tR,user:n,schema:tx});return(ei(e.db,{operation:"lint",model:a.model,input_tokens:a.usage.inputTokens,output_tokens:a.usage.outputTokens,cost_cents:(0,ea.Ij)(a.model,a.usage.inputTokens,a.usage.outputTokens),created_at:new Date().toISOString()}),a.data.newContent.trim()===t.content.trim())?{edit:null,modelUsed:a.model,changeSummary:a.data.changeSummary,noop:!0}:{edit:await tg(e.wikiPath,e.db,e.pageSlug,{content:a.data.newContent}),modelUsed:a.model,changeSummary:a.data.changeSummary,noop:!1}}async function tA(e){try{return await L(e)}catch{return"(no schema set yet)"}}async function tj(e){try{return await O(e)}catch{return"(no index yet)"}}let tU=`You answer questions against an LLM Wiki.

Process:
1. Read the index to find pages potentially relevant to the question.
2. Read those pages.
3. Synthesize a concise answer with [[slug]] citations pointing at the pages you actually used.
4. If you can't answer from the wiki, say so honestly — better to admit a gap than invent.
5. If the answer reveals a clearly useful new wiki page (one that doesn't exist yet but should), put it in suggestedNewPage; otherwise leave it null.`,tC=`Output ONLY a valid JSON object matching this exact shape. No prose, no markdown fences:

{
  "answer": "Markdown body of the answer. Use [[slug]] for citations.",
  "pagesUsed": ["page-slug-1", "page-slug-2"],
  "suggestedNewPage": null,
  "confidence": "high",
  "caveats": ["Optional notes about limitations or things the wiki doesn't cover."]
}

OR if you'd suggest a new page:

{
  "answer": "...",
  "pagesUsed": [...],
  "suggestedNewPage": {
    "slug": "new-page-slug",
    "title": "Display Title",
    "content": "Markdown body for the page.",
    "reason": "Why this page should exist."
  },
  "confidence": "medium",
  "caveats": []
}

Strict field rules:
- "confidence" MUST be one of: "high", "medium", "low".
- "pagesUsed" MUST be an array of slugs (kebab-case, [a-z0-9-]+). Every slug must exist in the index above. Use [] if none.
- "caveats" MUST be an array of strings. Use [] if none.
- "suggestedNewPage" MUST be null or an object — never an array, never omitted.
- "answer" is a required string.`;function tD(e){return`\`\`\`\`markdown
${e}
\`\`\`\``}async function tF(e){if(!e.question.trim())throw Error("queryWiki: question must be non-empty");e.onProgress?.({phase:"context",message:"Loading wiki schema and index..."});let[t,n]=await Promise.all([tW(e.wikiPath),tX(e.wikiPath)]);e.onProgress?.({phase:"context",message:"Searching for relevant pages..."});let a=await tq(e.wikiPath,e.db,e.question);e.onProgress?.({phase:"llm",message:`Calling ${e.model}...`});let i=function(e){let t=e.relevantPages.length>0?e.relevantPages.map(e=>`### ${e.title} (slug: ${e.slug}, type: ${e.type})
${function(e,t){let n=e.split(/\s+/);return n.length<=1e3?e:`${n.slice(0,1e3).join(" ")}

[truncated: ${n.length-t} more words]`}(e.excerpt,1e3)}`).join("\n\n---\n\n"):"(no pages currently match this question — the wiki may not cover this topic yet)";return{system:[tU,"","User schema (CLAUDE.md):",tD(e.schema),"","Current wiki index:",tD(e.index),"",`Possibly relevant pages (top ${e.relevantPages.length}):`,tD(t),"",tC].join("\n"),user:`User question:

${e.question.trim()}`}}({schema:t,index:n,relevantPages:a,question:e.question}),r=await (0,ea.wI)({client:e.client,model:e.model,system:i.system,user:i.user,schema:eW});return ei(e.db,{operation:"query",model:r.model,input_tokens:r.usage.inputTokens,output_tokens:r.usage.outputTokens,cost_cents:(0,ea.Ij)(r.model,r.usage.inputTokens,r.usage.outputTokens),created_at:new Date().toISOString()}),e.onProgress?.({phase:"done",result:r.data}),r.data}async function tW(e){try{return await L(e)}catch{return"(no schema set yet — assume a general-purpose personal wiki)"}}async function tX(e){try{return await O(e)}catch{return"(no index yet)"}}async function tq(e,t,n){let a=[];try{a=B(t,n,10)}catch{a=[]}let i=[];for(let t of a)try{let n=await v(e,t.slug);i.push({slug:n.slug,title:n.frontmatter.title,type:n.frontmatter.type,excerpt:n.content})}catch{}return i}let tz=`You are answering questions in a persistent chat thread against a personal LLM Wiki.

Rules:
- Cite wiki pages with [[slug]] (use the slugs from the index — kebab-case, lowercase).
- Reference earlier turns in the thread when relevant.
- If the wiki doesn't cover something, say so honestly — don't invent.
- Use markdown freely (lists, headings, tables). No JSON output unless explicitly asked.
- Be concise but complete. Prioritize the user's question over restating context.`;function tB(e){return`\`\`\`\`markdown
${e}
\`\`\`\``}let tK=["inbox","pinned","archive"];function tY(e,t,n){return(0,c.join)(e,f.chats,t,n)}async function tH(e,t,n){let a=n.folder??"inbox",i=(n.title??"Untitled chat").trim()||"Untitled chat",r=(0,eq.randomUUID)(),{date:s,hhmm:o}=function(){let e=new Date,t=e=>`${e}`.padStart(2,"0");return{date:`${e.getFullYear()}-${t(e.getMonth()+1)}-${t(e.getDate())}`,hhmm:`${t(e.getHours())}${t(e.getMinutes())}`}}(),l=`${s}-${o}-${i.toLowerCase().normalize("NFKD").replace(/[̀-ͯ]/g,"").replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"").slice(0,60)||"untitled"}.md`,d=(0,c.join)(e,f.chats,a);await (0,u.mkdir)(d,{recursive:!0});let p=new Date().toISOString(),h={id:r,title:i,folder:a,created:p,updated:p,model:n.model,pinned:!1,message_count:0,...n.tags&&n.tags.length>0?{tags:n.tags}:{}},m=g().stringify("",h);await (0,u.writeFile)((0,c.join)(d,l),m,"utf8");let w={id:r,filename:l,folder:a,title:i,created_at:p,updated_at:p,pinned:!1,message_count:0};return function(e,t){e.prepare(`INSERT INTO chats (id, filename, folder, title, created_at, updated_at, pinned, message_count)
     VALUES (@id, @filename, @folder, @title, @created_at, @updated_at, @pinned, @message_count)`).run(V(t))}(t,w),w}async function tZ(e,t,n){let a=et(n,t);if(!a)throw nt(t);let i=await (0,u.readFile)(tY(e,a.folder,a.filename),"utf8");return{row:a,messages:function(e){let t=e.split(/\r?\n/),n=[],a=null,i=[];function r(){a&&(a.content=i.join("\n").trim(),n.push(a)),i=[],a=null}for(let e of t){let t=e.match(tJ);t?(r(),a={role:t[1].toLowerCase(),time:t[2],content:""}):a&&i.push(e)}return r(),n}(g()(i).content)}}let tJ=/^##\s+(user|assistant)\s+\[(\d{2}:\d{2}:\d{2})\]\s*$/i;async function tG(e,t,n,a,i){let r=et(t,n);if(!r)throw nt(n);let s=tY(e,r.folder,r.filename),o=await (0,u.readFile)(s,"utf8"),l=g()(o),c={role:a,time:function(){let e=new Date,t=e=>`${e}`.padStart(2,"0");return`${t(e.getHours())}:${t(e.getMinutes())}:${t(e.getSeconds())}`}(),content:i.trim()},d=l.content.replace(/\s+$/u,""),p=d.length>0?"\n\n":"",h=`## ${c.role} [${c.time}]
${c.content}
`,m=`${d}${p}${h}`,f=new Date().toISOString(),w={...l.data,updated:f,message_count:r.message_count+1},y=g().stringify(m,w);await (0,u.writeFile)(s,y,"utf8");let E={...r,updated_at:f,message_count:r.message_count+1};return ee(t,E),{row:E,message:c}}async function tQ(e,t,n,a){let i=a.trim();if(!i)throw Error("renameChat: newTitle must be non-empty");let r=et(t,n);if(!r)throw nt(n);let s=tY(e,r.folder,r.filename),o=await (0,u.readFile)(s,"utf8"),l=g()(o),c={...l.data,title:i};await (0,u.writeFile)(s,g().stringify(l.content,c),"utf8");let d={...r,title:i};return ee(t,d),d}async function tV(e,t,n,a){let i=a.trim();if(!i)throw Error("moveChat: newFolder must be non-empty");let r=et(t,n);if(!r)throw nt(n);if(i===r.folder)return r;let s=tY(e,r.folder,r.filename),o=(0,c.join)(e,f.chats,i);await (0,u.mkdir)(o,{recursive:!0});let l=(0,c.join)(o,r.filename);await (0,u.rename)(s,l);let d=await (0,u.readFile)(l,"utf8"),p=g()(d),h={...p.data,folder:i};await (0,u.writeFile)(l,g().stringify(p.content,h),"utf8");let m={...r,folder:i};return ee(t,m),m}async function t0(e,t,n,a){let i=et(t,n);if(!i)throw nt(n);let r=tY(e,i.folder,i.filename),s=await (0,u.readFile)(r,"utf8"),o=g()(s),l={...o.data,pinned:a};await (0,u.writeFile)(r,g().stringify(o.content,l),"utf8");let c={...i,pinned:a};return ee(t,c),c}async function t1(e,t,n){let a=et(t,n);if(!a)throw nt(n);let i=tY(e,a.folder,a.filename),r=(0,c.join)(e,f.tooling,"trash/chats");await (0,u.mkdir)(r,{recursive:!0});let s=new Date().toISOString().replace(/[:.]/g,"-"),o=(0,c.join)(r,`${s}-${(0,c.basename)(i)}`);return await (0,u.rename)(i,o),function(e,t){e.prepare("DELETE FROM chats WHERE id = ?").run(t)}(t,n),{trashedPath:o}}async function t2(e){let t=(0,c.join)(e,f.chats);try{let e=(await (0,u.readdir)(t,{withFileTypes:!0})).filter(e=>e.isDirectory()).map(e=>e.name),n=new Set([...tK,...e]);return Array.from(n).sort()}catch(e){if("ENOENT"===e.code)return[...tK];throw e}}async function t8(e){let t=et(e.db,e.chatId);if(!t)throw nt(e.chatId);let n=e.modelOverride??await t3(e.wikiPath,t),a=await tG(e.wikiPath,e.db,e.chatId,"user",e.userMessage),i=await tZ(e.wikiPath,e.chatId,e.db),[r,s]=await Promise.all([t5(e.wikiPath),t4(e.wikiPath)]),o=[{role:"system",content:function(e){let t=e.relevantPages.length>0?e.relevantPages.map(e=>`### ${e.title} (slug: ${e.slug}, type: ${e.type})
${function(e,t){let n=e.split(/\s+/);return n.length<=800?e:`${n.slice(0,800).join(" ")}

[truncated: ${n.length-t} more words]`}(e.excerpt,800)}`).join("\n\n---\n\n"):"(no pages currently match — the wiki may not cover this thread's topic yet)";return[tz,"","User schema (CLAUDE.md):",tB(e.schema),"","Current wiki index:",tB(e.index),"",`Possibly relevant pages (top ${e.relevantPages.length}):`,tB(t)].join("\n")}({schema:r,index:s,relevantPages:await t6(e.wikiPath,e.db,e.userMessage)})},...i.messages.map(e=>({role:e.role,content:e.content}))],l=await (0,ea.Zq)({client:e.client,model:n,messages:o});ei(e.db,{operation:"chat",model:l.model,input_tokens:l.usage.inputTokens,output_tokens:l.usage.outputTokens,cost_cents:(0,ea.Ij)(l.model,l.usage.inputTokens,l.usage.outputTokens),created_at:new Date().toISOString()});let u=await tG(e.wikiPath,e.db,e.chatId,"assistant",l.text);return{row:u.row,user:a.message,assistant:u.message,modelUsed:l.model}}async function t3(e,t){let n;try{n=await eO(e)}catch{}try{let a=await (0,u.readFile)(tY(e,t.folder,t.filename),"utf8"),i=g()(a).data;if("string"==typeof i.model&&i.model.length>0){let e=n?.defaultModels.chat.provider,t=i.model.includes("/");if("ollama"===e&&t);else if("openrouter"!==e||t)return i.model}}catch{}return n?n.defaultModels.chat.model:ea.Fv.chat}async function t5(e){try{return await L(e)}catch{return"(no schema set yet)"}}async function t4(e){try{return await O(e)}catch{return"(no index yet)"}}async function t6(e,t,n){let a=[];try{a=B(t,n,8)}catch{a=[]}let i=[];for(let t of a)try{let n=await v(e,t.slug);i.push({slug:n.slug,title:n.frontmatter.title,type:n.frontmatter.type,excerpt:n.content})}catch{}return i}function t9(e,t){return en(e,t)}async function t7(e,t=2592e6){let a;let i=(0,c.join)(e,f.tooling,"trash"),{readdir:r,stat:s,unlink:o}=await Promise.resolve().then(n.t.bind(n,93977,23));try{a=(await r(i,{withFileTypes:!0})).filter(e=>e.isDirectory()).map(e=>e.name)}catch{return 0}let l=Date.now()-t,u=0;for(let e of a){let t;let n=(0,c.join)(i,e);try{t=await r(n)}catch{continue}for(let e of t){let t=(0,c.join)(n,e);try{let e=await s(t);e.isFile()&&e.mtimeMs<l&&(await o(t),u++)}catch{}}}return u}class ne extends Error{constructor(e){super(`chat not found: ${e}`),this.name="ChatNotFoundError",this.id=e}}function nt(e){return new ne(e)}let nn=`You health-check an LLM Wiki.

Look for:
- Contradictions between pages (two pages disagreeing on the same fact)
- Stale claims (claims that newer-dated sources would supersede)
- Orphan pages (no inbound [[slug]] references from any other page)
- Important concepts mentioned in passing but lacking their own page (missing-page)
- Broken cross-references ([[slug]] pointing to a slug that doesn't exist)
- Data gaps the wiki should fill given its topic

For each issue, suggest a fix when possible (a one-line description of what to change).
Also suggest follow-up questions the user could investigate to fill gaps.

The user has already run a deterministic local scan; treat the "deterministic findings" below
as ground truth and focus your output on semantic issues the local scan can't see
(contradictions, stale claims, missing-page suggestions, gaps).`,na=`Output ONLY a valid JSON object matching this exact shape. No prose, no markdown fences:

{
  "issues": [
    {
      "severity": "high",
      "type": "contradiction",
      "description": "What disagrees, and where.",
      "affectedPages": ["slug-a", "slug-b"],
      "suggestedFix": "One-line action the user could take, or null."
    }
  ],
  "suggestedQuestions": ["Up to 5 follow-up questions the user could investigate."],
  "overallHealth": "good"
}

Strict field rules:
- "severity" MUST be one of: "high", "medium", "low".
- "type" MUST be one of: "contradiction", "orphan", "missing-page", "broken-link", "gap", "stale".
- "overallHealth" MUST be one of: "excellent", "good", "fair", "needs-work".
- "affectedPages" MUST be an array of kebab-case slugs (use [] if none). Every slug must exist in the index above.
- "suggestedFix" MUST be a string or null.
- "issues" and "suggestedQuestions" MUST be arrays. Use [] when empty.

Severity guidance:
- "high" for contradictions and broken cross-references.
- "medium" for gaps and missing-page suggestions.
- "low" for orphans and stale claims.

Overall health rubric:
- "excellent" — zero issues.
- "good" — only low-severity issues.
- "fair" — some medium-severity issues.
- "needs-work" — any high-severity issues.`;function ni(e){return`\`\`\`\`markdown
${e}
\`\`\`\``}async function nr(e){e.onProgress?.({phase:"local",message:"Scanning for broken links and orphans..."});let t=await ns(e.wikiPath),n=F(e.db),a=new Set(n.map(e=>e.slug)),i=new Map;for(let e of a)i.set(e,0);let r=[],s=[];for(let t of n){let n;try{n=await v(e.wikiPath,t.slug)}catch{continue}r.push({slug:n.slug,title:n.frontmatter.title,type:n.frontmatter.type,excerpt:n.content});let o=tu(n.content),l=new Set;for(let e of o)a.has(e.slug)&&!l.has(e.slug)&&(i.set(e.slug,(i.get(e.slug)??0)+1),l.add(e.slug)),a.has(e.slug)||s.push({severity:"high",type:"broken-link",description:`${n.frontmatter.title} links to [[${e.slug}]], which doesn't exist`,affectedPages:[n.slug],suggestedFix:`Remove the [[${e.slug}]] reference or create the page.`,source:"local"})}for(let e of n)"overview"!==e.type&&(i.get(e.slug)??0)===0&&s.push({severity:"low",type:"orphan",description:`${e.title} has no inbound references from other pages`,affectedPages:[e.slug],suggestedFix:`Link to [[${e.slug}]] from a related page, or delete the page if it's no longer needed.`,source:"local"});let o=r.length>60,l=o?[...r].sort((e,t)=>e.slug.localeCompare(t.slug)).slice(0,60):r,u=s.map(e=>({type:e.type,page:e.affectedPages[0]??"",detail:e.description})),c=[],d=[],g="excellent";if(0===r.length)g="excellent";else{e.onProgress?.({phase:"llm",message:`Calling ${e.model} with ${l.length}${o?`/${r.length}`:""} pages…`});let[t,n]=await Promise.all([nl(e.wikiPath),nu(e.wikiPath)]),a=function(e){let t=e.pages.length>0?e.pages.map(e=>`### ${e.title} (slug: ${e.slug}, type: ${e.type})
${function(e,t){let n=e.split(/\s+/);return n.length<=800?e:`${n.slice(0,800).join(" ")}

[truncated]`}(e.excerpt,800)}`).join("\n\n---\n\n"):"(wiki is empty)",n=0===e.deterministicFindings.length?"(none — the wiki has no broken links and every page has at least one inbound reference)":e.deterministicFindings.map(e=>`- ${e.type} on ${e.page}: ${e.detail}`).join("\n");return{system:[nn,"","User schema (CLAUDE.md):",ni(e.schema),"","Current wiki index:",ni(e.index),"","Deterministic findings (already detected; you do not need to repeat these):",ni(n),"",na].join("\n"),user:[`All pages in the wiki (${e.pages.length}):`,"",t].join("\n")}}({schema:t,index:n,pages:l,deterministicFindings:u}),i=await (0,ea.wI)({client:e.client,model:e.model,system:a.system,user:a.user,schema:eX});ei(e.db,{operation:"lint",model:i.model,input_tokens:i.usage.inputTokens,output_tokens:i.usage.outputTokens,cost_cents:(0,ea.Ij)(i.model,i.usage.inputTokens,i.usage.outputTokens),created_at:new Date().toISOString()}),c=i.data.issues.map(e=>({...e,source:"llm"})),d=i.data.suggestedQuestions,g=i.data.overallHealth}let p=[...s,...c],h={high:p.filter(e=>"high"===e.severity).length,medium:p.filter(e=>"medium"===e.severity).length,low:p.filter(e=>"low"===e.severity).length},m=new Date().toISOString().replace("T"," ").slice(0,16),f=`## [${m}] lint | ${p.length} issue${1===p.length?"":"s"} — ${g}`,w=`- ${h.high} high, ${h.medium} medium, ${h.low} low across ${r.length} page${1===r.length?"":"s"}`;return await P(e.wikiPath,`${f}
${w}`),e.onProgress?.({phase:"done"}),{issues:p,suggestedQuestions:d,overallHealth:g,truncated:o,totalPages:r.length,previousRun:t}}async function ns(e){return(await no(e,1))[0]??null}async function no(e,t=10){let n;let a=(0,c.join)(e,f.log);try{n=await (0,u.readFile)(a,"utf8")}catch{return[]}let i=[],r=n.split(/\r?\n/);for(let e=r.length-1;e>=0&&i.length<t;e--){var s;let t=(r[e]??"").match(/^## \[(.+?)\] lint \| (\d+) issues?\s*(?:—\s*([a-z-]+))?\s*$/i);t&&i.push({stamp:t[1]??"",totalIssues:parseInt(t[2]??"0",10),health:(s=t[3])&&("excellent"===s||"good"===s||"fair"===s||"needs-work"===s)?s:null})}return i}async function nl(e){try{return await L(e)}catch{return"(no schema set yet)"}}async function nu(e){try{return await O(e)}catch{return"(no index yet)"}}},19706:(e,t,n)=>{n.d(t,{Q1:()=>r,Fv:()=>y,Aw:()=>u,gA:()=>s,wI:()=>g,Zq:()=>f,eI:()=>d,Ij:()=>k});var a=n(73055);class i extends Error{constructor(e,t){super(e),this.name="LlmError",void 0!==t&&(this.cause=t)}}class r extends i{constructor(e,t){super(e,t),this.name="ContextLengthError"}}class s extends i{constructor(e,t,n){super(`model not available on ${"ollama"===n?"Ollama":"OpenRouter"}: ${e}`,t),this.name="UnknownModelError",this.model=e}}class o extends i{constructor(e,t,n){super(`LLM response was not valid JSON: ${t}`,n),this.name="InvalidJsonError",this.rawResponse=e,this.parseError=t}}class l extends i{constructor(e,t,n){super(`LLM response failed schema validation (${t.length} issues): ${t.slice(0,3).map(e=>`${e.path.join(".")||"<root>"}: ${e.message}`).join("; ")}`,n),this.name="SchemaValidationError",this.rawResponse=e,this.issues=t}}class u extends i{constructor(e,t,n){super(`rate limited by ${"ollama"===n?"local server":"OpenRouter"}`,t),this.name="RateLimitError",this.retryAfterMs=e}}class c extends i{constructor(e,t){super(e,t),this.name="NetworkError"}}function d(e,t){if("ollama"===t){let e=process.env.OLLAMA_BASE_URL||"http://localhost:11434",t=e.endsWith("/v1")?e:`${e.replace(/\/$/,"")}/v1`;return new a.ZP({apiKey:"ollama",baseURL:t})}if(!e)throw Error("createClient: apiKey is required");return new a.ZP({apiKey:e,baseURL:"https://openrouter.ai/api/v1",defaultHeaders:{"HTTP-Referer":"https://github.com/ddsyasas/llm-wiki","X-Title":"LLM Wiki"}})}async function g(e){let t=e.maxRetries??3,n=null,a=!1;for(let i=1;i<=t;i++){e.signal?.throwIfAborted();try{return await m(e,a)}catch(m){let d,g;if(n=m,m instanceof r||m instanceof s||m instanceof l)throw m;if(m instanceof o){if(a)throw m;a=!0,e.onRetry?.(i+1,0,"invalid-json repair");continue}if(i===t)break;m instanceof u?(d=m.retryAfterMs??p(i),g="rate-limit"):m instanceof c?(d=p(i),g="network"):(d=p(i),g="unknown"),e.onRetry?.(i+1,d,g),await h(d,e.signal)}}throw n??new i("callLLM exhausted retries with no error captured")}function p(e){return Math.min(3e4,2**(e-1)*1e3)}function h(e,t){return new Promise((n,a)=>{if(e<=0)return n();let i=setTimeout(()=>{t?.removeEventListener("abort",r),n()},e),r=()=>{clearTimeout(i),a(t?.reason??Error("aborted"))};t?.addEventListener("abort",r,{once:!0})})}async function m(e,t){let n,a;let i=t?`${e.system}

Your previous response was not valid JSON. Output ONLY a valid JSON object that matches the schema. No prose, no markdown fences.`:e.system,r=e.userParts&&e.userParts.length>0?e.userParts:e.user;try{n=await e.client.chat.completions.create({model:e.model,response_format:{type:"json_object"},messages:[{role:"system",content:i},{role:"user",content:r}]},e.signal?{signal:e.signal}:void 0)}catch(t){throw w(t,e.model)}let s=n.choices[0],u=s?.message?.content??"";if(!u.trim())throw new o(u,"empty response");try{a=JSON.parse(function(e){let t=e.trim(),n=t.match(/^```(?:[a-zA-Z]+)?\s*([\s\S]*?)\s*```$/);n?.[1]!==void 0&&(t=n[1].trim());let a=t.indexOf("{"),i=t.lastIndexOf("}");return(a>0||0===a&&i<t.length-1)&&-1!==a&&i>a&&(t=t.slice(a,i+1)),t}(u))}catch(e){throw new o(u,e.message)}let c=e.schema.safeParse(a);if(!c.success)throw new l(u,c.error.issues);return{data:c.data,rawResponse:u,model:n.model??e.model,usage:{inputTokens:n.usage?.prompt_tokens??0,outputTokens:n.usage?.completion_tokens??0}}}async function f(e){let t=e.maxRetries??3,n=null;for(let a=1;a<=t;a++){e.signal?.throwIfAborted();try{let t=await e.client.chat.completions.create({model:e.model,messages:e.messages.map(e=>({role:e.role,content:e.content}))},e.signal?{signal:e.signal}:void 0);return{text:t.choices[0]?.message?.content??"",model:t.model??e.model,usage:{inputTokens:t.usage?.prompt_tokens??0,outputTokens:t.usage?.completion_tokens??0}}}catch(c){let i=w(c,e.model,e.client.baseURL);if(n=i,i instanceof r||i instanceof s)throw i;if(a===t)break;let o=i instanceof u?i.retryAfterMs??p(a):p(a),l=i instanceof u?"rate-limit":"network";e.onRetry?.(a+1,o,l),await h(o,e.signal)}}throw n??new i("chatComplete exhausted retries with no error captured")}function w(e,t,n){if(e instanceof i)return e;let a=n&&(n.includes("localhost")||n.includes("11434")),o=a?"ollama":"openrouter",l=(e.message??String(e)).toLowerCase();return 429===e.status?new u(function(e){if(!e)return null;let t=Number.parseInt(e,10);return Number.isNaN(t)?null:1e3*t}(e.headers?.["retry-after"]),e,o):l.includes("context length")||l.includes("maximum context")||l.includes("too long")?new r(`source too large for model ${t}`,e):404===e.status||l.includes("model not found")||l.includes("not available")||l.includes("unknown model")?new s(t,e,o):e.status&&e.status>=500?new c(`server error from ${a?"Ollama":"OpenRouter"} (${e.status})`,e):"ECONNRESET"===e.code||"ETIMEDOUT"===e.code||"ENOTFOUND"===e.code||l.includes("network")||l.includes("fetch failed")?new c(`network error: ${e.message??String(e)}`,e):new i(e.message??String(e),e)}let y={ingest:"anthropic/claude-haiku-4.5",query:"anthropic/claude-sonnet-4.6",chat:"anthropic/claude-sonnet-4.6",lint:"anthropic/claude-sonnet-4.6",vision:"anthropic/claude-sonnet-4.6"},E={"anthropic/claude-haiku-4.5":{inputPerMillion:1,outputPerMillion:5},"anthropic/claude-4.5-haiku":{inputPerMillion:1,outputPerMillion:5},"anthropic/claude-sonnet-4.6":{inputPerMillion:3,outputPerMillion:15},"anthropic/claude-4.6-sonnet":{inputPerMillion:3,outputPerMillion:15},"anthropic/claude-opus-4.7":{inputPerMillion:15,outputPerMillion:75},"anthropic/claude-4.7-opus":{inputPerMillion:15,outputPerMillion:75},"anthropic/claude-3-5-haiku":{inputPerMillion:.8,outputPerMillion:4},"anthropic/claude-3-5-sonnet":{inputPerMillion:3,outputPerMillion:15},"anthropic/claude-3-haiku":{inputPerMillion:.25,outputPerMillion:1.25},"anthropic/claude-3-opus":{inputPerMillion:15,outputPerMillion:75},"openai/gpt-4o-mini":{inputPerMillion:.15,outputPerMillion:.6},"openai/gpt-4o":{inputPerMillion:2.5,outputPerMillion:10},"google/gemini-2.5-pro":{inputPerMillion:1.25,outputPerMillion:10},"google/gemini-2.5-flash":{inputPerMillion:.3,outputPerMillion:2.5},"meta-llama/llama-3.3-70b-instruct":{inputPerMillion:.1,outputPerMillion:.3}};function k(e,t,n){let a=E[e]??E[e.replace(/-(?:\d{8}|\d{4}-\d{2}-\d{2})$/,"")]??null;return a?(a.inputPerMillion*t+a.outputPerMillion*n)/1e6*100:null}}};