@inkeep/open-knowledge 0.5.0-beta.43 → 0.5.0-beta.45

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.
@@ -1207,11 +1207,11 @@ Karpathy's insight: "The tedious part of maintaining a knowledge base is not the
1207
1207
  `),w=[],E=null;for(let e of S)if(E)isFenceClose$1(e,E)&&(E=null);else{let S=matchFence$1(e);if(S)E=S;else{let S=extractExternalMarkdownLinksFromLine(e,t);w.push(...S.occurrences.map(({url:e,label:t,start:w,end:E})=>({url:e,label:t,snippet:snippetAround$1(S.text,w,E)})))}}return w}function serializeState(e){return{backward:Object.fromEntries([...e.backward.entries()].map(([e,t])=>[e,[...t.entries()].map(([e,t])=>({source:e,anchor:t.anchor,snippet:t.snippet}))])),forward:Object.fromEntries([...e.forward.entries()].map(([e,t])=>[e,[...t].sort()])),externalForward:Object.fromEntries([...e.externalForward.entries()].map(([e,t])=>[e,[...t.entries()].map(([e,t])=>({url:e,label:t.label,snippet:t.snippet})).sort((e,t)=>e.url.localeCompare(t.url))]))}}function buildExternalBackward(e){let t=new Map;for(let[S,w]of e)for(let[e,E]of w){let w=t.get(e);w||(w=new Map,t.set(e,w)),w.set(S,E)}return t}function deserializeState(e){let t=new Map(Object.entries(e.externalForward??{}).map(([e,t])=>[e,new Map(t.map(e=>[e.url,{label:e.label??null,snippet:e.snippet??null}]))]));return{backward:new Map(Object.entries(e.backward??{}).map(([e,t])=>[e,new Map(t.map(e=>[e.source,{anchor:e.anchor??null,snippet:e.snippet??null}]))])),forward:new Map(Object.entries(e.forward??{}).map(([e,t])=>[e,new Set(t)])),externalForward:t,externalBackward:buildExternalBackward(t)}}var BacklinkIndex=class{projectDir;contentDir;contentFilter;states=new Map;mtimesByBranch=new Map;activeBranch=`main`;constructor(e){this.projectDir=e.projectDir,this.contentDir=e.contentDir,this.contentFilter=e.contentFilter,this.states.set(this.activeBranch,createEmptyState$1())}getState(e=this.activeBranch){let t=this.states.get(e);return t||(t=createEmptyState$1(),this.states.set(e,t)),t}getActiveBranch(){return this.activeBranch}switchBranch(e){this.activeBranch=e,this.getState(e)}cachePath(e=this.activeBranch){return resolve(getLocalDir(this.projectDir),`cache`,e,`backlinks.json`)}updateDocument(e,t,S=[],w=this.activeBranch){if(isSystemDoc(e)||isConfigDoc(e))return;let E=this.getState(w),D=E.forward.get(e)??new Set,O=E.externalForward.get(e)??new Map;for(let t of D){let S=E.backward.get(t);S&&(S.delete(e),S.size===0&&E.backward.delete(t))}for(let t of O.keys()){let S=E.externalBackward.get(t);S&&(S.delete(e),S.size===0&&E.externalBackward.delete(t))}let k=new Set,j=new Map;E.forward.set(e,k),E.externalForward.set(e,j);for(let S of t){if(!S.target)continue;k.add(S.target);let t=E.backward.get(S.target);t||(t=new Map,E.backward.set(S.target,t)),t.set(e,mergeLinkMeta(t.get(e),{anchor:S.anchor,snippet:S.snippet}))}for(let t of S){if(!t.url)continue;j.set(t.url,{label:t.label,snippet:t.snippet});let S=E.externalBackward.get(t.url);S||(S=new Map,E.externalBackward.set(t.url,S)),(!S.has(e)||!S.get(e)?.snippet&&t.snippet)&&S.set(e,{label:t.label,snippet:t.snippet})}}updateDocumentFromMarkdown(e,t,S=this.activeBranch){try{let{body:w}=stripFrontmatter(t),E=extractWikiLinksFromMarkdown(w),D=extractMarkdownLinksFromMarkdown(w,e),O=extractExternalWikiLinksFromMarkdown(w),k=extractExternalMarkdownLinksFromMarkdown(w,e),j=new Set(E.map(e=>e.target)),F=[...E,...D.filter(e=>!j.has(e.target))],L=new Set(O.map(e=>e.url)),B=[...O,...k.filter(e=>!L.has(e.url))];this.updateDocument(e,F,B,S)}catch(t){console.warn(`[backlinks] Failed to scan ${e} for link extraction:`,t),this.deleteDocument(e,S)}}deleteDocument(e,t=this.activeBranch){if(isSystemDoc(e)||isConfigDoc(e))return;let S=this.getState(t),w=S.forward.get(e)??new Set,E=S.externalForward.get(e)??new Map;for(let t of w){let w=S.backward.get(t);w&&(w.delete(e),w.size===0&&S.backward.delete(t))}for(let t of E.keys()){let w=S.externalBackward.get(t);w&&(w.delete(e),w.size===0&&S.externalBackward.delete(t))}S.forward.delete(e),S.externalForward.delete(e)}renameDocument(e,t,S,w=this.activeBranch){this.deleteDocument(e,w),this.updateDocumentFromMarkdown(t,S,w)}getBacklinks(e,t=this.activeBranch){let S=this.getState(t).backward.get(e);return S?[...S.entries()].map(([e,t])=>({source:e,anchor:t.anchor,snippet:t.snippet})).sort((e,t)=>e.source.localeCompare(t.source)):[]}getBacklinkCount(e,t=this.activeBranch){return this.getState(t).backward.get(e)?.size??0}getForwardLinks(e,t=this.activeBranch){return[...this.getState(t).forward.get(e)??new Set].sort((e,t)=>e.localeCompare(t))}getForwardLinkEntries(e,t=this.activeBranch){let S=this.getState(t),w=this.getForwardLinks(e,t).map(t=>({kind:`doc`,target:t,anchor:S.backward.get(t)?.get(e)?.anchor??null,snippet:S.backward.get(t)?.get(e)?.snippet??null})),E=[...(S.externalForward.get(e)??new Map).entries()].map(([e,t])=>({kind:`external`,url:e,label:t.label,snippet:t.snippet})).sort((e,t)=>e.url.localeCompare(t.url));return[...w,...E]}getOrphans(e,t=`both`,S=this.activeBranch){let w=this.getState(S);return[...e].filter(e=>{let S=(w.backward.get(e)?.size??0)>0,E=(w.forward.get(e)?.size??0)>0;return t===`incoming`?!S:(t===`outgoing`||!S)&&!E}).sort((e,t)=>e.localeCompare(t))}getHubs(e=20,t=this.activeBranch){return[...this.getState(t).backward.entries()].map(([e,t])=>({docName:e,count:t.size})).sort((e,t)=>t.count===e.count?e.docName.localeCompare(t.docName):t.count-e.count).slice(0,e)}getDeadLinks(e,t,S=this.activeBranch){let w=this.getState(S),E=new Set(e),D=t?.length?new Set(t):null;return[...w.backward.entries()].filter(([e,t])=>{if(E.has(e))return!1;if(!D)return t.size>0;for(let e of t.keys())if(D.has(e))return!0;return!1}).map(([e,t])=>({target:e,sources:[...t.entries()].filter(([e])=>!D||D.has(e)).map(([e,t])=>({source:e,anchor:t.anchor,snippet:t.snippet})).sort((e,t)=>e.source.localeCompare(t.source))})).filter(e=>e.sources.length>0).sort((e,t)=>t.sources.length===e.sources.length?e.target.localeCompare(t.target):t.sources.length-e.sources.length)}getLinkGraph(e=this.activeBranch){let t=this.getState(e),S=new Map,w=[];for(let[e,E]of t.forward){S.set(e,{kind:`doc`,id:e,docName:e,anchor:getRepresentativeAnchor(t.backward.get(e))});for(let D of E)S.set(D,{kind:`doc`,id:D,docName:D,anchor:getRepresentativeAnchor(t.backward.get(D))}),w.push({source:e,target:D})}for(let[e,E]of t.externalForward){S.set(e,{kind:`doc`,id:e,docName:e,anchor:getRepresentativeAnchor(t.backward.get(e))});for(let[t,D]of E){let E=externalNodeId(t);S.set(E,{kind:`external`,id:E,url:t,label:D.label}),w.push({source:e,target:E})}}return{nodes:[...S.values()].sort((e,t)=>e.id.localeCompare(t.id)),links:w}}getLinkGraphNeighborhood(e,t,S=this.activeBranch){let w=this.getState(S),E=new Map;for(let e of w.externalForward.values())for(let[t,S]of e)E.has(t)||E.set(t,S.label);let D=new Set([e]),O=[{nodeId:e,degree:0}],k=0;for(;k<O.length;){let e=O[k++];if(e.degree>=t)continue;let S=externalUrlFromNodeId(e.nodeId),E=new Set;if(S)for(let e of w.externalBackward.get(S)?.keys()??[])E.add(e);else{for(let t of w.forward.get(e.nodeId)??new Set)E.add(t);for(let t of w.externalForward.get(e.nodeId)?.keys()??[])E.add(externalNodeId(t));for(let t of w.backward.get(e.nodeId)?.keys()??[])E.add(t)}for(let t of E)D.has(t)||(D.add(t),O.push({nodeId:t,degree:e.degree+1}))}let j=[];for(let[e,t]of w.forward)if(D.has(e))for(let S of t)D.has(S)&&j.push({source:e,target:S});for(let[e,t]of w.externalForward)if(D.has(e))for(let S of t.keys()){let t=externalNodeId(S);D.has(t)&&j.push({source:e,target:t})}return{nodes:[...D].sort().map(e=>{let t=externalUrlFromNodeId(e);return t?{kind:`external`,id:e,url:t,label:E.get(t)??null}:{kind:`doc`,id:e,docName:e,anchor:getRepresentativeAnchor(w.backward.get(e))}}),links:j}}async saveToDisk(e=this.activeBranch){let t=this.cachePath(e);mkdirSync(dirname(t),{recursive:!0});let S=this.getState(e),w=this.mtimesByBranch.get(e),E={...serializeState(S),...w?{mtimes:Object.fromEntries(w)}:{}};await writeFile(t,JSON.stringify(E,null,2),`utf-8`)}async loadFromDisk(e=this.activeBranch){let t=this.cachePath(e);if(!existsSync(t))return!1;try{let S=await readFile$1(t,`utf-8`),w=JSON.parse(S);return this.states.set(e,deserializeState(w)),w.mtimes?this.mtimesByBranch.set(e,new Map(Object.entries(w.mtimes))):this.mtimesByBranch.delete(e),!0}catch(t){return console.warn(`[backlinks] Failed to load cache for ${e}:`,t),!1}}clear(e=this.activeBranch){this.states.set(e,createEmptyState$1()),this.mtimesByBranch.delete(e)}async rebuildFromDisk(e=this.activeBranch){let t=createEmptyState$1(),S=new Map,w=[];this.walkForPaths(this.contentDir,w);let E=new Set,D=w.filter(({docName:e})=>E.has(e)?!1:(E.add(e),!0)),O=50;for(let e=0;e<D.length;e+=50){let w=D.slice(e,e+50),E=await Promise.allSettled(w.map(async({docName:e,filePath:t})=>{let[S,w]=await Promise.all([stat$1(t),readFile$1(t,`utf-8`)]);return{docName:e,mtimeMs:S.mtimeMs,markdown:w}}));for(let e of E){if(e.status===`rejected`){console.warn(`[backlinks] Failed to rebuild entry:`,e.reason);continue}let{docName:w,mtimeMs:E,markdown:D}=e.value;S.set(w,E);let{body:O}=stripFrontmatter(D),k=extractWikiLinksFromMarkdown(O),j=extractMarkdownLinksFromMarkdown(O,w),F=extractExternalWikiLinksFromMarkdown(O),L=extractExternalMarkdownLinksFromMarkdown(O,w),B=new Set(k.map(e=>e.target)),H=[...k,...j.filter(e=>!B.has(e.target))],q=new Set(F.map(e=>e.url)),J=[...F,...L.filter(e=>!q.has(e.url))],Y=new Set,ee=new Map;t.forward.set(w,Y),t.externalForward.set(w,ee);for(let e of H){if(!e.target)continue;Y.add(e.target);let S=t.backward.get(e.target);S||(S=new Map,t.backward.set(e.target,S)),S.set(w,mergeLinkMeta(S.get(w),{anchor:e.anchor,snippet:e.snippet}))}for(let e of J){if(!e.url)continue;ee.set(e.url,{label:e.label,snippet:e.snippet});let S=t.externalBackward.get(e.url);S||(S=new Map,t.externalBackward.set(e.url,S)),S.set(w,{label:e.label,snippet:e.snippet})}}}this.states.set(e,t),this.mtimesByBranch.set(e,S)}walkForPaths(e,t){let S;try{S=readdirSync(e,{withFileTypes:!0})}catch(t){console.warn(`[backlinks] Failed to read directory ${e}:`,t);return}for(let w of S){let S=join(e,w.name);if(w.isDirectory()){let e=relative(this.contentDir,S);if(this.contentFilter&&e&&this.contentFilter.isDirExcluded(e))continue;this.walkForPaths(S,t)}else if(w.isFile()&&isSupportedDocFile(w.name)){let e=relative(this.contentDir,S);if(this.contentFilter?.isExcluded(e))continue;t.push({docName:stripDocExtension(e),filePath:S})}}}async reconcileWithDisk(e=this.activeBranch){if(!existsSync(this.contentDir))return{added:0,updated:0,deleted:0};let t=this.mtimesByBranch.get(e)??new Map,S=[];this.walkForPaths(this.contentDir,S);let w=new Set,E=S.filter(({docName:e})=>w.has(e)?!1:(w.add(e),!0)),D=new Set(E.map(e=>e.docName)),O=new Map,k=0,j=0,F=[],L=await Promise.allSettled(E.map(async({docName:e,filePath:t})=>({docName:e,filePath:t,mtimeMs:(await stat$1(t)).mtimeMs})));for(let e of L){if(e.status===`rejected`)continue;let{docName:S,filePath:w,mtimeMs:E}=e.value,D=t.get(S);if(D!==void 0&&D===E){O.set(S,E);continue}F.push({docName:S,filePath:w,mtimeMs:E,isNew:D===void 0})}let B=50;for(let t=0;t<F.length;t+=50){let S=F.slice(t,t+50),w=await Promise.allSettled(S.map(async({docName:e,filePath:t,mtimeMs:S,isNew:w})=>({docName:e,mtimeMs:S,isNew:w,markdown:await readFile$1(t,`utf-8`)})));for(let t of w){if(t.status===`rejected`){console.warn(`[backlinks] Failed to reconcile file:`,t.reason);continue}let{docName:S,mtimeMs:w,isNew:E,markdown:D}=t.value;this.updateDocumentFromMarkdown(S,D,e),O.set(S,w),E?k++:j++}}let H=0,q=new Set([...t.keys(),...this.getState(e).forward.keys()]);for(let t of q)D.has(t)||(this.deleteDocument(t,e),H++);return this.mtimesByBranch.set(e,O),{added:k,updated:j,deleted:H}}};function extractActorIdentity(e,t){let S=normalizeSummary(e.summary);if(S.kind===`invalid`)return{kind:`invalid-summary`};let w=parseAgentBodyFields(e),E=t?.()??null;return w.rawAgentId!==void 0&&w.writerId!==void 0?{kind:`agent`,writerId:w.writerId,displayName:w.displayName,colorSeed:w.colorSeed??w.rawAgentId,clientName:w.clientName,clientVersion:w.clientVersion,label:w.label,actor:{principalId:E?.id,agentType:resolveAgentType(w.clientName),clientName:w.clientName,clientVersion:w.clientVersion,label:w.label},summary:S}:E?{kind:`principal`,writerId:E.id,displayName:E.display_name,colorSeed:E.id,actor:{principalId:E.id},summary:S}:{kind:`anonymous`,summary:S}}const defaultGitConfigReader=(e,t,S)=>{let w=spawnSync(`git`,[`config`,S===`worktree`?`--worktree`:S===`local`?`--local`:`--global`,t],{cwd:e,encoding:`utf-8`,timeout:5e3});return w.status!==0||!w.stdout?null:w.stdout.trim()||null};function isLinkedWorktree(e){let t=spawnSync(`git`,[`rev-parse`,`--git-dir`],{cwd:e,encoding:`utf-8`,timeout:5e3}),S=spawnSync(`git`,[`rev-parse`,`--git-common-dir`],{cwd:e,encoding:`utf-8`,timeout:5e3});return t.status!==0||S.status!==0?!1:resolve(e,t.stdout.trim())!==resolve(e,S.stdout.trim())}function ensureWorktreeConfigExtension(e){let t=spawnSync(`git`,[`config`,`--local`,`--get`,`extensions.worktreeConfig`],{cwd:e,encoding:`utf-8`,timeout:5e3});if(t.status===0&&/^(true|yes|on|1)$/i.test(t.stdout.trim()))return;let S=spawnSync(`git`,[`config`,`--local`,`extensions.worktreeConfig`,`true`],{cwd:e,encoding:`utf-8`,timeout:5e3});if(S.status!==0){let e=S.stderr?.trim()??``,t=S.error?` [${S.error.message}]`:``;throw Error(`failed to enable extensions.worktreeConfig: ${e}${t}`)}}async function resolveGitIdentity(e,t,S,w=defaultGitConfigReader){let E=w(e,`user.name`,`worktree`),D=w(e,`user.email`,`worktree`);if(E&&D)return{name:E,email:D};let O=w(e,`user.name`,`local`),k=w(e,`user.email`,`local`);if(O&&k)return{name:O,email:k};let j=w(e,`user.name`,`global`),F=w(e,`user.email`,`global`);if(j&&F)return{name:j,email:F};if(t&&S){let e=await t.get(S);if(e){let t=e.name??e.login,S=e.email??`${e.login}@users.noreply.github.com`;if(t)return{name:t,email:S}}}return null}function writeGitIdentity(e,t,S){let w=`--local`;isLinkedWorktree(e)&&(ensureWorktreeConfigExtension(e),w=`--worktree`);let E=(t,S)=>{let E=spawnSync(`git`,[`config`,w,t,S],{cwd:e,encoding:`utf-8`,timeout:5e3});if(E.status!==0){let e=E.stderr?.trim()??``,S=E.error?` [${E.error.message}]`:``;throw Error(`git config ${w} ${t} failed: ${e}${S}`)}};E(`user.name`,t),E(`user.email`,S)}const ALLOWED_URL_PATTERNS=[/^https?:\/\//i,/^ssh:\/\//i,/^git:\/\//i,/^git@[^:]+:/],BLOCKED_URL_PATTERNS=[/^file:\/\//i,/^javascript:/i,/^ext::/i,/^data:/i,/^vbscript:/i];function isAllowedGitUrl(e){return!e||typeof e!=`string`||BLOCKED_URL_PATTERNS.some(t=>t.test(e))?!1:ALLOWED_URL_PATTERNS.some(t=>t.test(e))}function expandTilde(e){return e===`~`?homedir():e.startsWith(`~/`)?join(homedir(),e.slice(2)):e}function tryRealpathSync(e){try{return realpathSync(e)}catch{return null}}function isPathWithinHome(e,t){if(!e||typeof e!=`string`||e.includes(`\0`))return!1;let S=tryRealpathSync(t);if(S===null)return!1;let w=resolve(expandTilde(e)),E=[],D=w;for(;;){let e=!0;try{lstatSync(D)}catch(t){if(t.code===`ENOENT`)e=!1;else return!1}if(e){let e=tryRealpathSync(D);if(e===null)return!1;let t=relative(S,E.length===0?e:join(e,...E));return t===``||!t.startsWith(`..`)&&!isAbsolute(t)}let t=dirname(D);if(t===D)return!1;E.unshift(basename(D)),D=t}}function isSafeLocalPath(e){return isPathWithinHome(e,homedir())}function isLoopbackRequest(e){let t=e.socket.remoteAddress;return t===`127.0.0.1`||t===`::1`||t===`::ffff:127.0.0.1`}function hasValidLocalOpOrigin(e){let t=e.headers.origin;if(!t)return!0;try{let{hostname:e}=new URL(t);return e===`127.0.0.1`||e===`localhost`||e===`[::1]`||e===`::1`}catch{return!1}}function checkLocalOpSecurity(e,t,S){return isLoopbackRequest(e)?hasValidLocalOpOrigin(e)?!0:(errorResponse(t,403,`urn:ok:error:invalid-origin`,`Origin header is not a permitted loopback origin.`,{handler:S.handler}),!1):(errorResponse(t,403,`urn:ok:error:loopback-required`,`Local-op endpoints require a loopback connection.`,{handler:S.handler}),!1)}function createConcurrencyGuard(){let e=new Set;return{tryAcquire(t){return e.has(t)?!1:(e.add(t),!0)},release(t){e.delete(t)}}}function runSubprocess(e){let[t,...S]=e.cliArgs;if(!t)return{done:Promise.resolve({code:-1,stderr:`no command provided`,timedOut:!1,cancelled:!1}),cancel:()=>{}};let w=[...S,...e.trailingArgs],E=!1,D=!1,O=``,k=[],j=spawn(t,w,{cwd:e.cwd,stdio:[`ignore`,`pipe`,`pipe`],env:{...process.env}}),F=setTimeout(()=>{E=!0,j.kill(`SIGTERM`)},e.timeoutMs),L=t=>{if(!t.trim())return;let S=null;try{let e=JSON.parse(t);S=e&&typeof e==`object`?e:null}catch{S=null}e.onLine({raw:t,parsed:S})};return j.stdout.on(`data`,e=>{O+=e.toString(`utf-8`);let t=O.split(`
1208
1208
  `);O=t.pop()??``;for(let e of t)L(e)}),j.stderr.on(`data`,t=>{k.push(t),e.onStderr?.(t)}),{done:new Promise(e=>{j.on(`close`,t=>{clearTimeout(F),O.trim()&&L(O),O=``,e({code:t,stderr:Buffer.concat(k).toString(`utf-8`).trim(),timedOut:E,cancelled:D})}),j.on(`error`,t=>{clearTimeout(F),k.push(Buffer.from(t.message,`utf-8`)),e({code:-1,stderr:Buffer.concat(k).toString(`utf-8`).trim(),timedOut:E,cancelled:D})})}),cancel:()=>{if(!D&&(D=!0,!j.killed))try{j.kill(`SIGTERM`)}catch{}}}}const DEFAULT_TIMEOUT_MS$2=600*1e3;function asAuthEvent(e){let t=e.type;return t===`verification`?typeof e.user_code==`string`&&typeof e.verification_uri==`string`&&typeof e.expires_in==`number`?{type:`verification`,user_code:e.user_code,verification_uri:e.verification_uri,expires_in:e.expires_in}:null:t===`complete`?{type:`complete`,host:typeof e.host==`string`?e.host:``,login:typeof e.login==`string`?e.login:``,name:typeof e.name==`string`?e.name:void 0,email:typeof e.email==`string`?e.email:void 0,avatarUrl:typeof e.avatarUrl==`string`?e.avatarUrl:void 0}:t===`error`?{type:`error`,message:typeof e.message==`string`?e.message:`Unknown error`}:null}function runDeviceFlowSubprocess(e){let t=e.host??`github.com`,S=e.timeoutMs??DEFAULT_TIMEOUT_MS$2,w=!1,E=runSubprocess({cliArgs:e.cliArgs,trailingArgs:[`auth`,`login`,`--json`,`--host`,t],timeoutMs:S,onLine:({parsed:t})=>{if(!t)return;let S=asAuthEvent(t);S&&((S.type===`complete`||S.type===`error`)&&(w=!0),e.onEvent(S))}});return{done:E.done.then(S=>{w||(S.code===0?e.onEvent({type:`complete`,host:t,login:``}):e.onEvent({type:`error`,message:S.timedOut?`Sign-in timed out`:`auth login exited with code ${S.code??-1}`}))}),cancel:E.cancel}}const DEFAULT_TIMEOUT_MS$1=3e4;async function runAuthStatusSubprocess(e){let t=e.host??`github.com`,S=[],w=await runSubprocess({cliArgs:e.cliArgs,trailingArgs:[`auth`,`status`,`--json`,`--host`,t],timeoutMs:e.timeoutMs??DEFAULT_TIMEOUT_MS$1,onLine:({parsed:e})=>{e&&S.push(e)}}).done;for(let e=S.length-1;e>=0;e--){let w=S[e];if(w.type!==`status`)continue;let E=typeof w.host==`string`?w.host:t;if(w.authenticated===!0&&typeof w.login==`string`){let e=w.tier===`A`||w.tier===`B`||w.tier===`C`?w.tier:void 0;return{authenticated:!0,host:E,login:w.login,tier:e,name:typeof w.name==`string`?w.name:void 0,email:typeof w.email==`string`?w.email:void 0}}return{authenticated:!1,host:E,error:typeof w.error==`string`?w.error:void 0}}return{authenticated:!1,host:t,error:w.timedOut?`auth status timed out`:w.code===0?void 0:w.stderr||`auth status exited with code ${w.code??-1}`}}async function runAuthReposSubprocess(e){let t=e.host??`github.com`,S=[],w=await runSubprocess({cliArgs:e.cliArgs,trailingArgs:[`auth`,`repos`,`--json`,`--host`,t],timeoutMs:e.timeoutMs??DEFAULT_TIMEOUT_MS$1,onLine:({parsed:e})=>{e&&S.push(e)}}).done;if(w.timedOut)return{ok:!1,error:`auth repos timed out`};if(w.code!==0)return{ok:!1,error:w.stderr||`auth repos exited with code ${w.code??-1}`};for(let e=S.length-1;e>=0;e--){let w=S[e];if(w.type!==`repos`||!Array.isArray(w.repos))continue;let E=[];for(let e of w.repos){if(!e||typeof e!=`object`)continue;let t=e;typeof t.full_name!=`string`||typeof t.clone_url!=`string`||E.push({full_name:t.full_name,clone_url:t.clone_url,private:t.private===!0})}return{ok:!0,host:typeof w.host==`string`?w.host:t,repos:E}}return{ok:!1,error:`auth repos returned no data`}}const DEFAULT_TIMEOUT_MS=600*1e3;function validateCloneInputs(e,t){return isAllowedGitUrl(e)?isSafeLocalPath(t)?{ok:!0}:{ok:!1,reason:`invalid-dir`}:{ok:!1,reason:`invalid-url`}}function asRawCloneEvent(e){let t=e.type;return t===`progress`?typeof e.phase==`string`&&typeof e.pct==`number`?{type:`progress`,phase:e.phase,pct:e.pct}:null:t===`complete`?typeof e.dir==`string`?{type:`complete`,dir:e.dir}:null:t===`error`?{type:`error`,message:typeof e.message==`string`?e.message:`Unknown error`}:null}function runCloneSubprocess(e){let t=expandTilde(e.dir),S=e.timeoutMs??DEFAULT_TIMEOUT_MS,w=!1,E=runSubprocess({cliArgs:e.cliArgs,trailingArgs:[`clone`,`--json`,e.url,t],timeoutMs:S,onLine:({parsed:t})=>{if(!t)return;let S=asRawCloneEvent(t);S&&((S.type===`complete`||S.type===`error`)&&(w=!0),e.onEvent(S))}});return{done:E.done.then(S=>{if(!w){if(S.timedOut){e.onEvent({type:`error`,message:`Clone timed out after 10 minutes`});return}if(S.code!==0){let t=S.stderr?` — ${S.stderr}`:``;e.onEvent({type:`error`,message:`Clone process exited with code ${S.code??-1}${t}`});return}e.onEvent({type:`complete`,dir:t})}}),cancel:E.cancel}}function isLoopbackAddress(e){return e?!!(e===`::1`||e.startsWith(`::ffff:127.`)||e.startsWith(`127.`)):!1}function isAllowedWorkspaceHostHeader(e){if(!e)return!1;if(e.startsWith(`[`)){let t=e.indexOf(`]`);if(t<0)return!1;let S=e.slice(1,t),w=e.slice(t+1);return w!==``&&!/^:\d+$/.test(w)?!1:S===`::1`}let t=e.lastIndexOf(`:`),S=t>=0?e.slice(0,t):e,w=t>=0?e.slice(t+1):null;return w!==null&&!/^\d+$/.test(w)?!1:!!(S===`localhost`||/^127\.\d{1,3}\.\d{1,3}\.\d{1,3}$/.test(S))}const MANAGED_RENAME_JOURNAL_FILENAME=`managed-rename.json`;function journalDir(e){return getLocalDir(e)}function managedRenameJournalPath(e){return resolve(journalDir(e),MANAGED_RENAME_JOURNAL_FILENAME)}function createManagedRenameRecoveryJournal(e){return{version:2,fromPath:e.fromPath,toPath:e.toPath,affectedDocs:e.affectedDocs,createdAt:e.createdAt??new Date().toISOString(),snapshots:e.snapshots}}function isManagedRenameSnapshot(e){if(!e||typeof e!=`object`)return!1;let t=e;return typeof t.docName==`string`&&typeof t.content==`string`}function isManagedRenameAffectedDoc(e){if(!e||typeof e!=`object`)return!1;let t=e;return typeof t.from==`string`&&typeof t.to==`string`}function parseV2(e){if(typeof e.fromPath!=`string`||e.fromPath.length===0)throw Error(`Managed rename journal v2 is missing fromPath`);if(typeof e.toPath!=`string`||e.toPath.length===0)throw Error(`Managed rename journal v2 is missing toPath`);if(typeof e.createdAt!=`string`||e.createdAt.length===0)throw Error(`Managed rename journal v2 is missing createdAt`);if(!Array.isArray(e.affectedDocs)||e.affectedDocs.length===0||!e.affectedDocs.every(isManagedRenameAffectedDoc))throw Error(`Managed rename journal v2 has invalid affectedDocs`);if(!Array.isArray(e.snapshots)||e.snapshots.length===0||!e.snapshots.every(isManagedRenameSnapshot))throw Error(`Managed rename journal v2 has invalid snapshots`);for(let t of e.affectedDocs)if(!e.snapshots.some(e=>e.docName===t.from))throw Error(`Managed rename journal v2 is missing snapshot for affected doc: ${t.from}`);return{version:2,fromPath:e.fromPath,toPath:e.toPath,affectedDocs:e.affectedDocs,createdAt:e.createdAt,snapshots:e.snapshots}}function parseV1(e){if(typeof e.sourceDocName!=`string`||e.sourceDocName.length===0)throw Error(`Managed rename journal v1 is missing sourceDocName`);if(typeof e.destinationDocName!=`string`||e.destinationDocName.length===0)throw Error(`Managed rename journal v1 is missing destinationDocName`);if(typeof e.createdAt!=`string`||e.createdAt.length===0)throw Error(`Managed rename journal v1 is missing createdAt`);if(!Array.isArray(e.snapshots)||e.snapshots.length===0||!e.snapshots.every(isManagedRenameSnapshot))throw Error(`Managed rename journal v1 has invalid snapshots`);if(!e.snapshots.some(t=>t.docName===e.sourceDocName))throw Error(`Managed rename journal v1 must include the source document snapshot`);return{version:1,sourceDocName:e.sourceDocName,destinationDocName:e.destinationDocName,createdAt:e.createdAt,snapshots:e.snapshots}}function parseManagedRenameRecoveryJournal(e){if(!e||typeof e!=`object`)throw Error(`Managed rename journal must be an object`);let t=e;if(t.version===2)return parseV2(t);if(t.version===1)return parseV1(t);throw Error(`Unsupported managed rename journal version: ${String(t.version)}`)}function readManagedRenameJournal(e){let t=managedRenameJournalPath(e);if(!existsSync(t))return null;try{let e=readFileSync(t,`utf-8`);return parseManagedRenameRecoveryJournal(JSON.parse(e))}catch(e){throw Error(`Managed rename journal at ${t} is corrupt: ${e instanceof Error?e.message:String(e)}`)}}function writeManagedRenameJournal(e,t){let S=managedRenameJournalPath(e);tracedMkdirSync(dirname(S),{recursive:!0});let w=`${S}.tmp`;tracedWriteFileSync(w,JSON.stringify(t,null,2),`utf-8`),tracedRenameSync(w,S)}function clearManagedRenameJournal(e){tracedRmSync(managedRenameJournalPath(e),{force:!0})}async function withManagedRenameRecovery(e,t,S){writeManagedRenameJournal(e,t);let w=await S();return clearManagedRenameJournal(e),w}function destinationsToCleanV1(e){return[e.destinationDocName]}function destinationsToCleanV2(e){return e.affectedDocs.map(e=>e.to)}function pruneEmptyAncestors(e,t){let S=resolve(t),w=`${S}${sep}`,E=dirname(e);for(;E.startsWith(w)&&E!==S;){let e;try{e=readdirSync(E)}catch(e){console.warn(`[managed-rename] pruneEmptyAncestors: cannot read ${E}:`,e);return}if(e.length>0)return;try{tracedRmdirSync(E)}catch(e){console.warn(`[managed-rename] pruneEmptyAncestors: cannot rmdir ${E}:`,e);return}E=dirname(E)}}function recoverPendingManagedRename(e,t=e){let S=readManagedRenameJournal(t);if(!S)return{recovered:!1,journal:null,restoredDocNames:[]};let w=new Set,E=[];for(let t of S.snapshots)try{let S=safeContentPath(t.docName,e);tracedMkdirSync(dirname(S),{recursive:!0}),tracedWriteFileSync(S,t.content,`utf-8`),w.add(t.docName)}catch(e){E.push({docName:t.docName,cause:e}),console.warn(`[managed-rename] Failed to restore ${t.docName}:`,e)}if(E.length>0){let e=E.map(e=>e.docName).join(`, `);console.warn(`[managed-rename] Recovery incomplete; keeping journal for retry (${e})`);let t=E.map(e=>e.cause instanceof Error?e.cause:Error(String(e.cause)));throw AggregateError(t,`Managed rename recovery incomplete; failed to restore: ${e}`)}let D=S.version===2?destinationsToCleanV2(S):destinationsToCleanV1(S),O=[];for(let t of D){if(w.has(t))continue;let S=safeContentPath(t,e);try{tracedRmSync(S,{force:!0}),pruneEmptyAncestors(S,e)}catch(e){existsSync(S)&&console.warn(`[managed-rename] Both source and destination files exist after partial recovery for ${t}`),console.warn(`[managed-rename] Recovery incomplete; failed to clean destination ${t}:`,e),O.push({destination:t,cause:e})}}if(O.length>0){let e=O.map(e=>e.destination).join(`, `),t=O.map(e=>e.cause instanceof Error?e.cause:Error(String(e.cause)));throw AggregateError(t,`Managed rename recovery incomplete; failed to clean destinations: ${e}`)}return clearManagedRenameJournal(t),{recovered:!0,journal:S,restoredDocNames:[...w].sort((e,t)=>e.localeCompare(t))}}var SeedPrerequisiteError=class extends Error{constructor(e){super(e),this.name=`SeedPrerequisiteError`}},SeedRootDirError=class extends Error{constructor(e){super(e),this.name=`SeedRootDirError`}};function assertEntryPathInProject(e,t){if(typeof t!=`string`||t===``)throw new SeedRootDirError(`entry path must be a non-empty string, got: ${typeof t}`);if(t.includes(`\0`))throw new SeedRootDirError(`entry path must not contain null bytes`);if(isAbsolute(t))throw new SeedRootDirError(`entry path must be relative, got: ${t}`);if(t.split(/[/\\]/).some(e=>e===`..`))throw new SeedRootDirError(`entry path must not contain '..' segments, got: ${t}`);let S=resolve(e),w=resolve(S,t);if(w!==S&&!w.startsWith(S+sep))throw new SeedRootDirError(`entry path must resolve inside the project directory, got: ${t}`);return assertNoSymlinkEscape$1(w,S),w}function assertNoSymlinkEscape$1(e,t){let S;try{S=realpathSync(t)}catch{return}let w=e;for(;;){if(existsSync(w)){let t;try{t=realpathSync(w)}catch(t){throw t.code===`ELOOP`?new SeedRootDirError(`entry path traverses a symlink cycle: ${e}`):t}if(t!==S&&!t.startsWith(S+sep))throw new SeedRootDirError(`entry path resolves outside the project directory via symlink: ${e}`);return}let t=dirname(w);if(t===w)throw new SeedRootDirError(`entry path has no existing ancestor inside the project directory: ${e}`);w=t}}const DEFAULT_PACK_ID=`knowledge-base`,KNOWLEDGE_BASE_FOLDERS=[{path:`external-sources`,title:`External Sources`,description:"Raw sources SAVED verbatim, not just cited. The actual fetched text of URLs, extracted text of PDFs, and copies of any referenced files live as .md files here, each with frontmatter carrying the original URL, access date, and any publisher / author metadata. Produced by `ingest`; applies whether the user shared the URL OR the agent fetched it itself to ground a knowledge-base claim. The KB is closed-loop: downstream docs cite local paths in this folder, never bare web URLs. Immutable after capture (update only to refresh a stale fetch). No analysis in these files; that belongs in `research/`. Downstream articles cite specific docs here by path so every claim is traceable to preserved evidence rather than a dead link.",tags:[`source`,`immutable`,`layer-ingest`],starterTemplate:`clip`},{path:`research`,title:`Research`,description:"Provisional analysis synthesizing external sources. Produced by the `research` tool. Every factual claim cites a specific doc in `external-sources/` (or an inline URL if ingest was skipped); no unsourced assertions. Each article has `status: provisional` and a `sources:` frontmatter list of cited paths — keep the `sources:` list aligned with the docs linked in the article's body. Promoted to `articles/` via `consolidate` once the team decides the findings are stable.",tags:[`research`,`provisional`,`layer-research`],starterTemplate:`research-log`},{path:`articles`,title:`Articles`,description:"Canonical knowledge committed after a team decision. Produced by `consolidate`. Carries `status: canonical` plus a `supersedes:` chain tying back to the `research/` docs it replaces, which in turn cite `external-sources/`. The full evidence chain is traceable without leaving the repo. Source-of-truth for the domain; update only when a new decision supersedes it.",tags:[`article`,`canonical`,`layer-consolidate`],starterTemplate:`article`}],KNOWLEDGE_BASE_TEMPLATES={clip:`---
1209
1209
  title: External Source
1210
- description: Capture a URL, PDF, or referenced file verbatim. Update title to match the actual source after instantiation.
1211
- source:
1212
- clipped: {{date}}
1213
- status: raw
1214
- tags: [source]
1210
+ description: Capture a URL or article text verbatim as raw reference material. For binary files (PDFs, images, audio), use the \`ingest\` tool instead — this \`clip\` template is for text sources only.
1211
+ source_url:
1212
+ date_fetched: {{date}}
1213
+ preservation: text-extracted
1214
+ tags: [source, immutable, layer-ingest, text]
1215
1215
  ---
1216
1216
 
1217
1217
  ## Source
@@ -2606,6 +2606,8 @@ Link-graph activation:
2606
2606
  `);function groupByFile(e){let t=new Map;for(let S of e){let e=t.get(S.path);e?e.push(S):t.set(S.path,[S])}return[...t.entries()].map(([e,t])=>({path:e,matches:t}))}async function buildGrepResult(e,t){let S=await resolveProjectServerContext(t.resolveCwd,t.config,t.serverUrl,e.cwd);if(!S.ok)throw Error(S.error);let{cwd:w,config:E,url:D}=S,O=50,k=await grep(e.query,w,{caseInsensitive:!(e.case_sensitive??!1),include:[`**/*.md`,`**/*.mdx`],exclude:[`node_modules`,`.git`,`.claude`,`.changeset`,`.ok`],maxResults:51}),j=resolveContentDir(E,w),F=createContentFilter({projectDir:w,contentDir:j}),L=k.filter(e=>{let t=relative(j,resolve(w,e.path));return t.startsWith(`..`)?!1:!F.isExcluded(t)}),B=k.length>50,H=L.slice(0,50),{resolve:q,ui:J}=await buildListResolver({config:E,resolveCwd:async()=>w},w);if(H.length===0)return{text:`No matches for "${e.query}".`,structured:{query:e.query,matchCount:0,fileCount:0,truncated:!1,results:[],ui:J,cwd:w}};let Y=groupByFile(H),ee=new Map;await Promise.all(Y.map(async e=>{try{let t=await enrichPath(e.path,{projectDir:w,serverUrl:D});ee.set(e.path,t)}catch{}}));let te=[];te.push(`## Grep results for "${e.query}" (${H.length} match${H.length===1?``:`es`} in ${Y.length} file${Y.length===1?``:`s`})`,``);let ne=[];for(let e of Y){let t=ee.get(e.path),S=t?.title??e.path;te.push(`### ${S} (${e.path})`),t?.tags?.length&&te.push(`Tags: ${t.tags.join(`, `)}`),t?.description&&te.push(`${t.description}`);for(let t of e.matches)te.push(`- Line ${t.line}: ${t.text}`);te.push(``);let w=docNameFromPath(e.path),E=q(w);ne.push({path:e.path,docName:w,title:t?.title??null,description:t?.description??null,tags:t?.tags??[],matches:e.matches.map(e=>({line:e.line,text:e.text})),previewUrl:E?.url??null,...E?{previewUrlSource:E.source}:{}})}return B&&te.push(`_${H.length} of ${k.length}+ matches shown (max 50). Refine your query to narrow results._`),{text:te.join(`
2607
2607
  `),structured:{query:e.query,matchCount:H.length,fileCount:Y.length,truncated:B,results:ne,ui:J,cwd:w}}}const InputSchema$3={query:string$2().describe(`Literal text to search for`),case_sensitive:boolean$1().optional().describe(`Case-sensitive search (default false)`),cwd:string$2().optional().describe(ROUTED_CWD_DESCRIPTION)},GrepResultRowSchema=object$1({path:string$2(),docName:string$2(),title:string$2().nullable(),description:string$2().nullable(),tags:array(string$2()),matches:array(object$1({line:number$1().int(),text:string$2()})),previewUrl:string$2().nullable(),previewUrlSource:_enum(PREVIEW_URL_SOURCES).optional()}),OutputSchema$3=outputSchemaWithText({cwd:string$2(),query:string$2(),matchCount:number$1().int(),fileCount:number$1().int(),truncated:boolean$1(),results:array(GrepResultRowSchema),ui:object$1({baseUrl:string$2().nullable(),port:number$1().nullable()})});function register$13(e,t){e.registerTool(`grep`,{description:DESCRIPTION$13,inputSchema:InputSchema$3,outputSchema:OutputSchema$3,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0}},async e=>{try{let{text:S,structured:w}=await buildGrepResult(e,t);return w?textPlusStructured(S,w):textResult(S)}catch(e){return textResult(`Error: ${e instanceof Error?e.message:String(e)}`,!0)}})}function buildBody$1(e,t){return`Capture this external source into the project knowledge base as raw reference material. The KB is **closed-loop**: external sources are pulled INTO the knowledge base here so downstream docs cite local paths, never bare web URLs. This applies whether a user shared the source OR you fetched it yourself to ground a knowledge-base claim — agent-initiated fetches are not exempt. **Raw preservation only** — no summary, no analysis, no interpretation. Summarizing is the job of the \`research\` tool later.
2608
2608
 
2609
+ **Bias toward binary preservation.** When the source is a binary file (PDF, image, audio, video, Office doc, archive, dataset), preserve the raw bytes — do NOT settle for a text scrape. OK already ships a complete asset-embed surface (\`![[file.ext]]\` wiki-embed, file-watcher pickup, sha256 dedup, blocked-extension enforcement); this tool's job is to bridge \`ingest\` to it via your shell tool.
2610
+
2609
2611
  Source: ${e}
2610
2612
 
2611
2613
  The content directory for this project is **\`${t}\`** (from \`.ok/config.yml\`).
@@ -2615,77 +2617,232 @@ The content directory for this project is **\`${t}\`** (from \`.ok/config.yml\`)
2615
2617
  Before fetching anything, sanity-check:
2616
2618
 
2617
2619
  - **Is it in scope?** If the source is unrelated to what this knowledge base is accumulating, ingest is pollution. Check the existing layout: \`exec("ls ${t}")\` to see what topics are already covered.
2618
- - **Is it already ingested?** \`exec("grep -rln <source-url-or-title-slug> ${t}")\` — if the same source is already present with current content, stop and reuse. Re-ingest is appropriate when the source has changed materially (new version, significant edits) — note the reason in frontmatter's \`description\`.
2620
+ - **Is it already ingested?** \`exec("grep -rln <source-url-or-title-slug> ${t}")\` — if the same source is already present with current content, stop and reuse. Re-ingest is appropriate when the source has changed materially (new version, significant edits) — see Step 5 for sha256-mismatch re-ingest semantics.
2619
2621
  - **Is the user's intent actually \`ingest\` (preserve) or \`research\` (analyze)?** If they want findings synthesized rather than raw bytes archived, redirect: "\`research\` on this topic will pull sources via \`ingest\` as needed. Use \`research\` instead." Don't pre-ingest speculatively when the user wants analysis.
2620
2622
 
2621
2623
  If all three checks pass, proceed.
2622
2624
 
2623
- ## Step 1: Fetch the content
2625
+ ### Shell-capability self-detection (evaluate before any shell call)
2626
+
2627
+ If your host does not expose a shell-like tool (no Bash / Terminal / shell-exec / equivalent), you cannot run \`curl\` for either the HEAD probe (Step 1a) or the binary download (Step 1b). Detect once at the start of the workflow via a trivial probe (\`echo ok\` via the host's shell affordance, or a known-safe \`which curl\` invocation). On absence of a shell tool, route the source straight to **Step 1c (text fetch / shell-less fallback)** — skipping Step 1a's HEAD-tiebreaker classification and Step 1b's binary download entirely — and surface the degradation explicitly to the user.
2628
+
2629
+ ## Step 1a: Detect source kind (binary vs text)
2630
+
2631
+ Classify the source before fetching. **\`.svg\` is intentionally absent from the binary-extension list — SVG can contain scripts and is treated as a scripted-document extension; see Step 1b's executable hard-block.**
2632
+
2633
+ - **URL with a binary file extension** (\`.pdf\`, \`.png\`, \`.jpg\`, \`.jpeg\`, \`.gif\`, \`.webp\`, \`.mp4\`, \`.webm\`, \`.mov\`, \`.m4v\`, \`.mp3\`, \`.wav\`, \`.ogg\`, \`.m4a\`, \`.flac\`, \`.docx\`, \`.xlsx\`, \`.pptx\`, \`.doc\`, \`.xls\`, \`.ppt\`, \`.zip\`, \`.7z\`, \`.tar\`, \`.gz\`, \`.rar\`, \`.csv\`, \`.tsv\`, \`.epub\`, etc.) → treat as **binary**. Skip to Step 1b.
2634
+ - **URL with a clear HTML/text extension** (\`.html\`, \`.htm\`, none, \`.txt\`, \`.md\`) → treat as **text**. Skip to Step 1c. The executable hard-block does NOT apply here because Step 1c never writes the source extension to disk — it writes a \`.md\` wrapper containing the extracted text.
2635
+ - **Local file path** → use your native file read tool. If the local file is text (HTML, plain, markdown), skip to **Step 2b** (text wrapper). If the local file is a binary you want preserved verbatim, you already have the bytes on disk — skip Step 1b's download and proceed directly to **Step 2a** (binary wrapper), pointing \`source_path:\` at the existing local path (relative to the wrapper).
2636
+ - **Ambiguous URL** (no extension, query-string download URL, redirect-y link) → run \`curl -IL --proto =http,=https --proto-redir =http,=https --max-redirs 5 -A 'Mozilla/5.0' <url>\` to read response headers, then classify by \`Content-Type\`:
2637
+ - \`application/pdf\`, \`image/*\` (except \`image/svg+xml\`), \`video/*\`, \`audio/*\`, \`application/zip\`, \`application/vnd.openxmlformats-*\`, \`application/epub+zip\` → **binary**
2638
+ - \`text/html\`, \`text/plain\`, \`application/json\` (when the source is a doc/article, not data) → **text**
2639
+ - \`application/octet-stream\` → ambiguous; treat as binary BUT note in chat that the server didn't declare a specific type, and the captured \`sha256\` + bytes record gives downstream tooling the signal if the bytes turn out to be HTML.
2640
+
2641
+ ### STOP gates evaluated during Step 1a (before any download)
2642
+
2643
+ Before continuing past Step 1a, check the following gates against the response and URL:
2644
+
2645
+ 1. **Streaming-video / DRM-protected media (heuristic — D6).** If the URL hostname matches a known streaming pattern (examples — illustrative, not exhaustive: \`youtube.com\`, \`youtu.be\`, \`vimeo.com\`, \`twitch.tv\`, \`tiktok.com\`, \`spotify.com\`, \`soundcloud.com\`, \`open.spotify.com\`, \`podcasts.apple.com\`) **OR** the HEAD response shows \`Content-Type: text/html\` on a URL that looked like media **OR** the HEAD shows anti-bot characteristics (\`Server: cloudflare\` + \`cf-mitigated\` / \`cf-chl-bypass\` headers, Akamai/Imperva challenge response, 403 with HTML body) → **STOP**. Tell the user: "Streaming services and DRM-protected media require \`yt-dlp\` or vendor-specific tooling — out of scope for \`ingest\`. Ask the user to paste the transcript or run \`yt-dlp\` manually and re-share the resulting file as a local path."
2646
+
2647
+ 2. **URL scheme — HARD BLOCK (M1 review fix).** If the URL scheme is not \`http://\` or \`https://\` (i.e., \`file://\`, \`gopher://\`, \`ftp://\`, etc.) → **HARD STOP**. Tell the user: "\`ingest\` only fetches \`http(s)\` URLs. Other schemes (local-file paths, intranet protocols) bypass the size + redirect safeguards and risk pulling cloud-metadata or local-service responses into the KB. If you have a local file, pass its path directly to \`ingest\` as a local-file source instead of a URL."
2648
+
2649
+ 3. **Auth-walled / paywalled / 4xx (NG5).** If HEAD returns 401/402/403/407/429 → STOP. Ask the user to paste the content or share a local copy.
2650
+
2651
+ ## Step 1b: Binary fetch
2652
+
2653
+ You've classified the source as binary in Step 1a and Step 1a's STOP gates passed. Step 1b adds **write-path-specific** STOP gates that only apply when we're about to land bytes on disk under the source extension:
2654
+
2655
+ ### Step 1b STOP gates (write-path only)
2656
+
2657
+ 1. **Executable / scripted-document extension — HARD BLOCK (D7).** If the URL extension is in \`EXECUTABLE_BLOCKLIST_EXTENSIONS\` (source of truth: \`packages/core/src/constants/upload.ts\`) — covers Windows executables, POSIX shells, scripted documents (including \`.svg\` and \`.xml\`), macOS installer classes, URL-files, cross-platform packages, and Windows shortcut classes — **HARD STOP**. Refuse to download via \`ingest\`. Tell the user: "Executable / scripted-document extensions are not auto-fetched by \`ingest\` — the runtime backstop (Electron \`openAssetSafely\`) is desktop-only, so plan-level enforcement is the only line of defense in CLI / web / Cowork contexts. If you genuinely want to archive this file, \`curl\` it manually outside the agent and reference the local path." This gate fires HERE (write path) and NOT against Step 1c — Step 1c writes a \`.md\` wrapper with extracted text, not the source extension on disk.
2658
+
2659
+ 2. **Size pre-check (D5).** Run \`curl -IL --max-redirs 5 -A 'Mozilla/5.0' '${e}'\` (if not already done in Step 1a's ambiguous-URL branch) and read \`Content-Length\`:
2660
+ - \`Content-Length\` > 100 MB → **HARD STOP**. Tell the user the source exceeds GitHub's 100 MB file-size cap and offer the manual-\`curl\` + Git-LFS escape path.
2661
+ - \`Content-Length\` > 50 MB → STOP and ask explicitly: "Source is X MB (above the 50 MB GitHub warn threshold). Proceed?"
2662
+ - \`Content-Length\` absent → proceed; the \`curl --max-filesize\` flag is the enforced backstop. Note in chat that the size could not be pre-verified.
2663
+ - \`Content-Length\` <= 50 MB → proceed.
2664
+
2665
+ ### Slug derivation (M1 review fix — strict shape)
2666
+
2667
+ Pick a kebab-case slug from the source's filename or title (e.g., \`karpathy-2024-llm-os\`). The slug becomes both the binary basename and the wrapper basename. Don't put dates in the slug — dates go in frontmatter (and in dated-sibling slugs on re-ingest per Step 5).
2668
+
2669
+ **The slug MUST match \`^[a-z0-9][a-z0-9-]{0,99}$\` — kebab-case, ASCII letters / digits / single hyphens only. NO dots, slashes, leading hyphens, or path segments. If you derive the slug from a server-controlled value (\`Content-Disposition: filename=\`, URL path basename), strip non-conforming characters before using it.** A server returning \`Content-Disposition: attachment; filename="../../etc/passwd"\` is adversarial; the slug constraint prevents path traversal from a malicious source landing bytes outside \`external-sources/\`. If the stripped result is empty, ask the user for a slug.
2670
+
2671
+ ### Download
2672
+
2673
+ Use your shell tool. Use \`external-sources/\` as the destination folder under the content directory. Create the directory first if it doesn't exist (unseeded projects):
2674
+
2675
+ \`\`\`bash
2676
+ mkdir -p "${t}/external-sources"
2677
+ curl -L --fail \\
2678
+ --proto =http,=https --proto-redir =http,=https \\
2679
+ --max-redirs 5 \\
2680
+ --max-time 60 \\
2681
+ --max-filesize 104857600 \\
2682
+ -o "${t}/external-sources/<slug>.<ext>" \\
2683
+ -A 'Mozilla/5.0' \\
2684
+ '<SOURCE_URL>'
2685
+ \`\`\`
2686
+
2687
+ **Replace \`<SOURCE_URL>\` with the source URL above (\`${e}\`), shell-escaping any special characters (single quotes, backticks, dollar signs). Do NOT paste a URL containing a literal single quote directly into the single-quoted curl argument — break it into a shell-safe form first.**
2688
+
2689
+ Flag rationale:
2690
+ - \`-L\` follows redirects (CDN-fronted sources need this).
2691
+ - \`--proto =http,=https --proto-redir =http,=https\` (M1 review fix) — refuses any scheme other than http(s), and refuses redirects that would downgrade to other schemes. Prevents redirect-chain SSRF into \`file://\`, \`gopher://\`, or cloud-metadata endpoints reached via \`--max-redirs\`.
2692
+ - \`--fail\` exits non-zero on HTTP 4xx/5xx instead of writing an error body to disk.
2693
+ - \`--max-redirs 5\` caps redirect chains (exit 47 on excess).
2694
+ - \`--max-time 60\` caps total request time (exit 28).
2695
+ - \`--max-filesize 104857600\` enforces the 100 MB hard cap as defense-in-depth in case the server omits or lies about \`Content-Length\` (exit 63). The option has shipped since curl 7.10.8 (2003) — every modern install has it.
2696
+
2697
+ If curl exits non-zero:
2698
+ - 47 (too many redirects) → STOP. Likely a tracking-link or auth-flow URL. Ask the user to paste.
2699
+ - 28 (timeout) → STOP. Slow source. Ask the user to retry or share locally.
2700
+ - 63 (\`--max-filesize\` triggered) → \`rm -f\` the truncated output. STOP and tell the user the server's \`Content-Length\` was missing or wrong.
2701
+ - 22 (HTTP error returned by \`--fail\`) → STOP. Auth wall, anti-scraping, or vanished URL. Ask the user to paste.
2702
+ - Other (e.g., 1 = unsupported protocol from \`--proto\`) → STOP and report the curl exit code to the user.
2703
+
2704
+ After successful download, record the byte size and sha256:
2705
+
2706
+ \`\`\`bash
2707
+ ls -l "${t}/external-sources/<slug>.<ext>" # bytes
2708
+ sha256sum "${t}/external-sources/<slug>.<ext>" # or 'shasum -a 256' on macOS
2709
+ \`\`\`
2710
+
2711
+ OK's file-watcher will pick up the new file and emit \`asset-create\`. The sidebar refreshes; the file is now indexed.
2712
+
2713
+ ## Step 1c: Text fetch (HTML / article sources, or shell-less host fallback)
2714
+
2715
+ Either the source is genuinely text (HTML article, plain text doc) OR your host is shell-less and binary preservation is unavailable.
2624
2716
 
2625
- - **URL** → use your available web fetch tool.
2626
- - **Local file or attachment** → use your native file read tool.
2717
+ Use your available web fetch tool (e.g., \`WebFetch\` if you're a Claude Code-class host; or your host's equivalent). If the fetcher returns an obvious *summary* of the page instead of the raw content (some LLM-backed fetch tools do this), note it and try a raw alternative (\`curl -sL <url>\` for text-heavy sources if your host has shell, or ask the user to paste). The goal is verbatim bytes.
2627
2718
 
2628
2719
  If the fetch fails (login wall, 401/402/403/429, anti-scraping block), **stop and ask the user to paste the content directly**. Do not save a stub, an error page, or a login wall as "raw content" — that poisons the knowledge base.
2629
2720
 
2630
- If the fetcher returns an obvious *summary* of the page instead of the raw content (some LLM-backed fetch tools do this), note it and try a raw alternative (e.g., \`curl -sL <url>\` for text-heavy sources, or ask the user to paste). The goal is verbatim bytes.
2721
+ ## Step 2a: Save the binary wrapper (only after Step 1b succeeded)
2722
+
2723
+ Write a markdown wrapper file at \`${t}/external-sources/<slug>.md\` containing this frontmatter and body. **Declare the full tag list explicitly — do NOT assume an \`external-sources/**\` folder rule cascade exists** (the legacy \`.ok/config.yml folders[]\` mechanism is no longer honored by the runtime config loader; folder defaults today live in opt-in nested \`<folder>/.ok/frontmatter.yml\` files and \`external-sources/.ok/frontmatter.yml\` may not exist in this project).
2724
+
2725
+ \`\`\`yaml
2726
+ ---
2727
+ title: Original title of the source (from <title>, Content-Disposition filename, or your best read)
2728
+ description: One-line summary from the source (their words, not yours)
2729
+ source_url: https://example.com/path/to/file.pdf
2730
+ source_path: ./<slug>.<ext>
2731
+ media_type: application/pdf # RFC 6838 type/subtype, from HEAD Content-Type
2732
+ bytes: 1234567 # integer, from ls -l or stat
2733
+ sha256: <hex sha256 digest> # full 64-char hex
2734
+ date_fetched: YYYY-MM-DD
2735
+ author: Original author if known
2736
+ preservation: binary
2737
+ tags:
2738
+ - source
2739
+ - immutable
2740
+ - layer-ingest
2741
+ - binary
2742
+ ---
2743
+
2744
+ ![[<slug>.<ext>]]
2745
+ \`\`\`
2746
+
2747
+ The body is just the wiki-embed reference. For images, video, and audio, the embed renders inline. **For PDFs and other opaque file-attachment types (docx, xlsx, zip, etc.), the \`![[file.ext]]\` form renders as a Notion-style File row that click-dispatches to the appropriate viewer** — the pdfjs canvas viewer is opt-in via the explicit \`<Pdf src="./<slug>.pdf" />\` JSX form, NOT the wiki-embed default. If the user wants the inline canvas viewer for this specific PDF, they can post-edit the wrapper body to replace \`![[<slug>.pdf]]\` with \`<Pdf src="./<slug>.pdf" />\`.
2631
2748
 
2632
- ## Step 2: Save as raw reference material
2749
+ Write via \`write_document\` (NOT native \`Write\` the CRDT path is mandatory for in-scope markdown).
2633
2750
 
2634
- Write the content as a markdown file inside the content directory (\`${t}\`). The convention if this project adopts the three-tier lifecycle is to group raw sources together e.g., an \`external-sources/\` subfolder under the content dir — but it's just a convention. Use whatever the project's existing docs layout calls for. If unsure, ask the user or default to a sensible top-level subfolder name.
2751
+ ## Step 2b: Save the text wrapper (only after Step 1ctext path or shell-less fallback)
2635
2752
 
2636
- Name the file with a kebab-case slug from the source's own title (e.g., \`karpathy-llm-wiki.md\`, \`anthropic-prompt-caching.md\`). Don't put dates in the filenamedates go in frontmatter.
2753
+ Write a markdown wrapper at \`${t}/external-sources/<slug>.md\` with the text content preserved verbatim in the body. Strip obvious boilerplate (nav menus, cookie banners, ads, footer links, "related articles" widgets) but **do not summarize, paraphrase, or interpret** that's \`research\`'s job.
2637
2754
 
2638
- Prepend this frontmatter:
2755
+ Frontmatter shape:
2639
2756
 
2640
2757
  \`\`\`yaml
2641
2758
  ---
2642
2759
  title: Original title of the source
2643
2760
  description: One-line summary from the source (their words, not yours)
2644
- source_url: https://example.com/article # for URLs
2645
- source_path: ./relative/path/to/file.pdf # for local files
2761
+ source_url: https://example.com/article
2762
+ media_type: text/html
2646
2763
  date_fetched: YYYY-MM-DD
2647
2764
  author: Original author if known
2765
+ preservation: text-extracted # OR: text-only (use 'text-only' when this is a shell-less fallback for a binary source)
2766
+ # NOTE: no \`source_path\` — text wrappers ARE the content. \`source_path\` is meaningful only for binary wrappers (Step 2a), where it points at the co-located binary sibling.
2648
2767
  tags:
2649
- - relevant-topic
2768
+ - source
2769
+ - immutable
2770
+ - layer-ingest
2771
+ - text
2650
2772
  ---
2651
2773
  \`\`\`
2652
2774
 
2775
+ **If this is a shell-less fallback for a source that should have been binary** (you tried Step 1a and detected binary but your host couldn't \`curl\`), set \`preservation: text-only\` AND prepend a top-of-body admonition so a future agent (or you, on a different host) can detect and upgrade:
2776
+
2777
+ \`\`\`markdown
2778
+ > ⚠ Binary not preserved — this is an extracted-text snapshot of a binary source.
2779
+ > Re-run \`ingest\` from a shell-capable client (Claude Code / Desktop / Cursor / Codex) to capture the original file.
2780
+
2781
+ (...verbatim extracted text follows...)
2782
+ \`\`\`
2783
+
2784
+ Downstream tooling can grep \`preservation: text-only\` in frontmatter to find docs that need upgrading.
2785
+
2653
2786
  ## Step 3: Preserve the content faithfully
2654
2787
 
2655
- - **Keep** headings, lists, quotes, code blocks, images, citations, references
2656
- - **Strip** obvious boilerplate: nav menus, cookie banners, ads, footer links, "related articles" widgets
2788
+ For binary wrappers: the wrapper body is the wiki-embed reference; no further body content is needed. All metadata lives in frontmatter.
2789
+
2790
+ For text wrappers:
2791
+ - **Keep** headings, lists, quotes, code blocks, images, citations, references.
2792
+ - **Strip** obvious boilerplate: nav menus, cookie banners, ads, footer links, "related articles" widgets.
2657
2793
  - **Do NOT** summarize, critique, paraphrase, or interpret. That's \`research\`'s job.
2658
- - **For very long sources**, consider splitting by major section with cross-references in frontmatter
2794
+ - **For very long sources**, consider splitting by major section with cross-references in frontmatter.
2659
2795
 
2660
2796
  ## Step 4: Verify
2661
2797
 
2662
- - File exists at the chosen location under the content directory
2663
- - Valid frontmatter (at minimum \`title\`, \`description\`, and either \`source_url\` or \`source_path\`)
2664
- - \`exec("ls <dir>")\` should list the file with enrichment
2798
+ - File(s) exist at the chosen location under \`${t}/external-sources/\` (binary + wrapper, or wrapper alone for text).
2799
+ - Valid frontmatter (at minimum \`title\`, \`description\`, \`source_url\`, \`preservation\`, and the full \`tags\` list — plus \`source_path\` for binary wrappers).
2800
+ - For binary preservation: \`sha256\` and \`bytes\` recorded; \`media_type\` matches what the HEAD response returned.
2801
+ - \`exec("ls -A ${t}/external-sources/")\` should list the new file(s) with enrichment.
2802
+
2803
+ ## Step 5: Re-ingest semantics (sha256 mismatch on a previously-ingested source)
2804
+
2805
+ If \`${t}/external-sources/<slug>.<ext>\` already exists when you reach Step 1b:
2806
+
2807
+ 1. Compute its sha256.
2808
+ 2. If the new sha matches the existing sha → **STOP** (no-op). Tell the user: "Already at \`external-sources/<slug>.<ext>\` — sha256 matches, no change."
2809
+ 3. If the new sha differs → save the new bytes as \`external-sources/<slug>.YYYY-MM-DD.<ext>\` (today's date in the slug) AND write a **new** wrapper \`external-sources/<slug>.YYYY-MM-DD.md\` with \`supersedes:\` as a YAML list pointing at the predecessor (matches \`consolidate\`'s shape so downstream tooling that reads \`supersedes:\` doesn't trip on a type mismatch):
2810
+ \`\`\`yaml
2811
+ supersedes:
2812
+ - <slug>.md
2813
+ \`\`\`
2814
+ **Do not mutate the old wrapper or the old binary** — the \`external-sources/**\` layer is append-only by convention.
2815
+
2816
+ The latest-dated wrapper is the "current view"; older wrappers remain valid as historical snapshots.
2665
2817
 
2666
- ## Step 5: Discuss takeaways with the user (no file write)
2818
+ ## Step 6: Discuss takeaways with the user (no file write)
2667
2819
 
2668
2820
  After preservation, briefly surface back to the user what the source actually contains — in **chat**, not in the raw file. This is Karpathy's "discussing takeaways" step: the raw file stays verbatim, but the human collaborator gets a quick orientation.
2669
2821
 
2670
2822
  - 3–5 bullet points capturing the source's main claims, with no editorializing.
2671
2823
  - Note any **tensions** with existing knowledge-base docs you already surfaced in Step 0 — agents that ingest in isolation miss the "wait, this contradicts \`[prior article](./path/to/prior.md)\`" signal.
2672
2824
  - Offer next steps: "Shall I \`research\` this topic now, or is preservation enough?" Don't silently chain into \`research\` — the user may have just wanted the archive.
2825
+ - For binary preservation: include the one-line breadcrumb (\`saved external-sources/<slug>.<ext> — <bytes> bytes, sha256 <abbrev>\`).
2826
+ - For shell-less text fallback of a binary source: explicitly tell the user the binary was not preserved and recommend re-running from a shell-capable client.
2673
2827
 
2674
- ## Step 6 (optional): Update neighbor docs to link the new source
2828
+ ## Step 7 (optional): Update neighbor docs to link the new source
2675
2829
 
2676
2830
  If the source is directly relevant to an existing article or research doc, update that doc to link the new raw source. A preserved source that no doc points at is an island. Limit this to 1–3 high-signal neighbors — don't touch everything tangentially related.
2677
2831
 
2678
2832
  - Follow the \`write_document\` / \`edit_document\` contract from the skill (preview-before-edit).
2679
- - Use a markdown link: \`[Source title](./${t?`relative/path/to/source.md`:`raw/source.md`})\`.
2833
+ - For binary wrappers, prefer linking to the wrapper (the markdown doc), not the binary directly: \`[Source title](./external-sources/<slug>.md)\`. The wrapper is the closed-loop citation target; the binary is the embedded asset within it.
2680
2834
  - Do NOT mass-update every neighbor. Karpathy's pattern rewards focused cross-linking; noisy neighbor-pings degrade the signal.
2681
2835
 
2682
2836
  ## Non-goals
2683
2837
 
2684
- - **No analysis** — don't interpret, compare, or critique the source
2685
- - **No promotion to a canonical article** — that's the \`consolidate\` tool's job, later
2686
- - **No silent chaining into research** — ingest completes on its own; the user explicitly opts into \`research\`
2687
- - **No synthesis inside the raw file** — the takeaways live in chat or a separate summary doc, never mixed into the preserved source
2688
- `}const DESCRIPTION$12=[`Returns a multi-step plan for ingesting an external source (URL or local file). Does NOT fetch, write, or execute you execute the plan. The body details Karpathy's three-layer pattern + the closed-loop ingest contract.`,`Raw preservation only — no analysis or interpretation.`,`The knowledge base is closed-loop: web sources cited by KB docs MUST resolve to a local doc captured here, not bare URLs.`,``,`**Use when:**`,`- Capturing reference material for the project knowledge base`,`- Saving a URL or document for later research`,`- Archiving an external source alongside the codebase`,`- The user shares a URL or document they want preserved`,"- **You yourself fetched a URL (`WebFetch` / `WebSearch` / equivalent) to ground a claim that is about to land in a knowledge-base doc** — agent-initiated fetches are not exempt from the closed-loop rule",``,`**Triggers on:**`,`- "ingest", "save this source", "capture this URL", "add to external sources"`,`- User shares a URL, article, or document to preserve in the knowledge base`,`- Agent fetches a URL via WebFetch/WebSearch to support a knowledge-base claim — preserve the source before citing it`,`- Research workflow needs raw sources before analysis`].join(`
2838
+ - **No analysis** — don't interpret, compare, or critique the source.
2839
+ - **No promotion to a canonical article** — that's the \`consolidate\` tool's job, later.
2840
+ - **No silent chaining into research** — ingest completes on its own; the user explicitly opts into \`research\`.
2841
+ - **No synthesis inside the raw file** — the takeaways live in chat or a separate summary doc, never mixed into the preserved source.
2842
+ - **No OCR / transcription**binary preservation only. \`research\` may apply analysis layers downstream.
2843
+ - **No streaming-video direct download** — \`yt-dlp\` is a separate workflow; \`ingest\` STOPs and routes to it (Step 1a STOP gate 1).
2844
+ - **No executable / scripted-document auto-fetch** — hard-blocked at Step 1b STOP gate 1 (write-path only). User runs \`curl\` manually outside the agent if they need to archive such a file.
2845
+ `}const DESCRIPTION$12=[`Returns a multi-step plan for ingesting an external source (URL or local file). Does NOT fetch, write, or execute — you execute the plan. The body details Karpathy's three-layer pattern + the closed-loop ingest contract.`,"Biases agents toward downloading raw binary files (PDFs, images, audio, video, Office docs) via the shell tool + co-located `![[file.ext]]` embed surface, rather than scraping page text. Falls back to text extraction on shell-less hosts with an explicit `preservation: text-only` frontmatter flag.",`Raw preservation only — no analysis or interpretation.`,`The knowledge base is closed-loop: web sources cited by KB docs MUST resolve to a local doc captured here, not bare URLs.`,``,`**Use when:**`,`- Capturing reference material for the project knowledge base`,`- Saving a URL or document for later research`,`- Archiving an external source alongside the codebase`,`- The user shares a URL or document they want preserved`,"- **You yourself fetched a URL (`WebFetch` / `WebSearch` / equivalent) to ground a claim that is about to land in a knowledge-base doc** — agent-initiated fetches are not exempt from the closed-loop rule",``,`**Triggers on:**`,`- "ingest", "save this source", "capture this URL", "add to external sources"`,`- User shares a URL, article, or document to preserve in the knowledge base`,`- Agent fetches a URL via WebFetch/WebSearch to support a knowledge-base claim — preserve the source before citing it`,`- Research workflow needs raw sources before analysis`].join(`
2689
2846
  `);function register$12(e,t){e.registerTool(`ingest`,{description:DESCRIPTION$12,inputSchema:{source:string$2().describe(`URL, file path, or identifier of the source to ingest`),cwd:string$2().optional().describe(ROUTED_CWD_DESCRIPTION)}},buildWorkflowHandler(`ingest`,t,`source`,buildBody$1))}const DESCRIPTION$11=[`[Requires: Hocuspocus server] List available documents from the Hocuspocus server.`,"Returns document names, optionally filtered by directory. When `dir` is set,","also surfaces folder-level metadata: `frontmatter_defaults` (merged folder","defaults that new docs in this folder will inherit) and `templates_available`","(menu of starter shapes for `write_document({ template })`). Pass `depth: N`","to also enrich subfolders up to N levels deep — mirrors `find -maxdepth N`.",``,`**Parameters:**`,"- `dir` (optional) — Filter to documents in this directory","- `depth` (optional, default `1`) — Subfolder enrichment depth. `1` = this"," folder only; `2` = direct children's folder metadata too; `Infinity` =",` full subtree. Walk-up ancestors' templates always show regardless.`].join(`
2690
2847
  `);function register$11(e,t){e.registerTool(`list_documents`,{description:DESCRIPTION$11,inputSchema:{dir:string$2().optional().describe(`Optional directory to filter documents`),depth:number$1().int().min(1).optional().describe("Subfolder enrichment depth (find -maxdepth semantics). Default 1. Only meaningful when `dir` is also set."),cwd:string$2().optional().describe(ROUTED_CWD_DESCRIPTION)}},async e=>{let S=await resolveProjectServerContext(t.resolveCwd,t.config,t.serverUrl,e.cwd);if(!S.ok)return textResult(`Error: ${S.error}`,!0);let{cwd:w,url:E}=S;if(!E)return textResult(HOCUSPOCUS_NOT_RUNNING_ERROR,!0);let D=null;if(e.dir!==void 0){let t=resolveWithinRoot(w,e.dir);if(!t.ok)return textResult(`Error: ${t.reason}`,!0);D=t.rel}let O=await httpGet(E,`/api/documents${D===null?``:`?dir=${encodeURIComponent(D)}`}`);if(!O.ok)return textResult(`Error: ${O.error}`,!0);let{ok:k,...j}=O,F=j,{resolve:L,ui:B}=await buildListResolver(t,w),H=(F.documents??[]).filter(e=>e.kind!==`folder`).map(e=>{let t=typeof e.docName==`string`?e.docName:null,S=t?L(t):null;return{...e,previewUrl:S?.url??null,...S?{previewUrlSource:S.source}:{}}}),q;if(D!==null){let t=e.depth??1;try{q=await enrichDirectoryRecursive(D,t,{projectDir:w})}catch{q=void 0}}let J={...F,documents:H,ui:B,cwd:w,...q?{folder:q}:{}};return textPlusStructured(JSON.stringify(J,null,2),J)})}const DESCRIPTION$10=[`Read a wiki file with enriched context: contents + frontmatter metadata + recent shadow-repo activity (agent vs human attribution) + backlink/forward-link context.`,``,`**Use when:**`,`- Loading an article for context`,`- Understanding who changed a file recently and whether it was an agent or human`,`- Seeing how this page links out and what links back to it`,``,"**When the project has `.ok/`**, strongly prefer this over your native `Read` for wiki files — one call returns what otherwise takes 3-4. In projects without `.ok/`, use native `Read` as usual.",``,`**Parameters:**`,"- `path` — Project-root-relative path to the file, including extension (e.g. `articles/auth/sso.md`). To pass this document to `edit_document` / `write_document` / `get_backlinks`, strip the extension (they take extension-less `docName`).","- `since` (reserved) — Reserved for shadow-log since-filter; currently unused."].join(`
2691
2848
  `);function formatShadowHistory(e){if(!e||e.length===0)return``;let t=[``,`### Recent activity (OK edits)`,``];for(let S of e){let e=S.writerClassification===`agent`?`agent: ${S.writerName}`:S.writerClassification===`principal`?`human: ${S.writerName}`:`${S.writerClassification}: ${S.writerName}`,w=S.hash.slice(0,7);t.push(`- ${w} ${S.date} [${e}] ${S.message}`)}return t.join(`
@@ -3071,4 +3228,4 @@ In headless mode, write the recap into the research article's "Further reading"
3071
3228
  `).split(`
3072
3229
  `),S=[],w=!1,E=``;for(let e of t){let t=/^\s{0,3}([`~]{3,})/.exec(e);if(t){w?RegExp(`^\\s{0,3}${E[0]==="`"?"`":`~`}{${E.length},}\\s*$`).test(e)&&(w=!1,E=``):(w=!0,E=t[1]);continue}if(w)continue;let D=stripInlineCodeSpans(e);for(TAG_VALUE_RE.lastIndex=0;;){let e=TAG_VALUE_RE.exec(D);if(e===null)break;let t=e[2];t&&S.push(t)}}return S}var TagIndex=class{contentDir;contentFilter;state=createEmptyState();constructor(e){this.contentDir=e.contentDir,this.contentFilter=e.contentFilter}updateDocumentFromMarkdown(e,t){if(!(isSystemDoc(e)||isConfigDoc(e)))try{let{frontmatter:S,body:w}=stripFrontmatter(t),E=extractFrontmatterTags(S?unwrapFrontmatterFences(S):``),D=extractInlineTagsFromBody(w),O=new Set([...E,...D]),k=new Set;for(let e of O)for(let t of expandTagToHierarchy(e))k.add(t);this.applyDocSnapshot(e,O,k)}catch(t){console.warn(`[tag-index] Failed to scan ${e} for tag extraction:`,t),this.deleteDocument(e)}}deleteDocument(e){if(isSystemDoc(e)||isConfigDoc(e))return;let t=this.state.byDoc.get(e);if(t){for(let S of t){let t=this.state.byTag.get(S);t&&(t.delete(e),t.size===0&&this.state.byTag.delete(S))}this.state.byDoc.delete(e),this.state.byDocLiteral.delete(e)}}renameDocument(e,t,S){this.deleteDocument(e),this.updateDocumentFromMarkdown(t,S)}getDocsForTag(e){let t=this.state.byTag.get(e);return t?[...t].sort((e,t)=>e.localeCompare(t)):[]}getDocsForTagWithMatches(e){let t=this.state.byTag.get(e);if(!t)return[];let S=[];for(let w of t){let t=this.state.byDocLiteral.get(w);if(!t)continue;let E=tagsMatchingPrefix(t,e);S.push({docName:w,matchingTags:[...E].sort((e,t)=>e.localeCompare(t))})}return S.sort((e,t)=>e.docName.localeCompare(t.docName))}getAllTags(){let e=[...this.state.byTag.entries()],t=e.map(([e])=>e),S=new Set;for(let e of t){let t=e.indexOf(`/`);t>0&&S.add(e.slice(0,t));let w=t;for(;w>0;)S.add(e.slice(0,w)),w=e.indexOf(`/`,w+1)}return e.map(([e,t])=>({name:e,count:t.size,isLeaf:!S.has(e)})).sort((e,t)=>e.name.localeCompare(t.name))}init(){if(this.state=createEmptyState(),!existsSync(this.contentDir))return;let e=this.listDocsWithPaths();for(let{docName:t,filePath:S}of e)try{let e=readFileSync(S,`utf-8`);this.updateDocumentFromMarkdown(t,e)}catch(e){console.warn(`[tag-index] Failed to read ${t} during init:`,e)}}applyDocSnapshot(e,t,S){let w=this.state.byDoc.get(e)??new Set;for(let t of w){if(S.has(t))continue;let w=this.state.byTag.get(t);w&&(w.delete(e),w.size===0&&this.state.byTag.delete(t))}for(let t of S){let S=this.state.byTag.get(t);S||(S=new Set,this.state.byTag.set(t,S)),S.add(e)}S.size===0?(this.state.byDoc.delete(e),this.state.byDocLiteral.delete(e)):(this.state.byDoc.set(e,S),this.state.byDocLiteral.set(e,t))}listDocsWithPaths(){let e=[];this.walkContentDir(this.contentDir,e),e.sort((e,t)=>e.docName===t.docName?t.filePath.localeCompare(e.filePath):e.docName.localeCompare(t.docName));let t=new Set;return e.filter(({docName:e})=>t.has(e)?!1:(t.add(e),!0))}walkContentDir(e,t){let S;try{S=readdirSync(e,{withFileTypes:!0})}catch(t){console.warn(`[tag-index] Failed to read directory ${e}:`,t);return}for(let w of S){let S=join(e,w.name);if(w.isDirectory()){let e=relative(this.contentDir,S);if(this.contentFilter&&e&&this.contentFilter.isDirExcluded(e))continue;this.walkContentDir(S,t);continue}if(!w.isFile()||!isSupportedDocFile(w.name))continue;let E=relative(this.contentDir,S);this.contentFilter?.isExcluded(E)||t.push({docName:stripDocExtension(E),filePath:S})}}};const PARK_SNAPSHOT_ORIGIN=(()=>{let e=Object.freeze({origin:`park-snapshot`,paired:!0});return Object.freeze({source:`local`,skipStoreHooks:!1,context:e})})();function createServer$1(e){let{contentDir:t,projectDir:S=t,quiet:w=!0,debounce:E=2e3,maxDebounce:D=1e4,gitEnabled:O=!0,commitDebounceMs:k=3e4,wipRef:j=`refs/wip/main`,configHomedirOverride:F,enableTestRoutes:L=!1,shadowRepo:B,contentRoot:H,destroyTimeoutMs:q=1e4,localOpCliArgs:J,skipStateManifestCheck:Y=!1}=e,ee=getLogger(`server`);function te(){let e=readConfigSafely({absPath:resolveConfigPath(`project-local`,S),sideline:!1,warn:e=>ee.warn({message:e},`[config] could not read project-local config`)}),t=e.value.autoSync?.enabled;return t==null?(e.valid||ee.warn({},`[config] project-local autoSync.enabled unavailable (config invalid) — falling back to project config`),readConfigSafely({absPath:resolveConfigPath(`project`,S),sideline:!1,warn:e=>ee.warn({message:e},`[config] could not read project config`)}).value.autoSync?.enabled===!0):t===!0}initTelemetry();let ne=randomUUID(),ae=getLocalDir(S);if(acquireServerLock(ae,{port:e.port??0,worktreeRoot:S,kind:e.lockKind??`interactive`,capabilities:[`http`,`ws`]}),!Y)try{assertCompatibleStateManifest({lockDir:ae,shadowRepoDir:resolveShadowDir(S)})}catch(e){throw releaseServerLock(ae),e}let oe=createBasenameIndex(),se=(e,t)=>oe.resolveEmbed(e,t),ce=(e,S)=>{let w=oe.resolveEmbed(e,S);if(!w&&e.includes(`/`)&&(w=e.replace(/^\.?\//,``)),!w)return null;let E=resolve(t,w),D=resolve(t);if(E!==D&&!E.startsWith(`${D}/`))return null;try{let e=statSync(E);return e.isFile()?e.size:null}catch{return null}},ue,de,fe,me,ge,_e,ve,ye=null,Ce=null,we=null,Te=null,De=new Set,je=!1,Me,Pe,Ie,Re=new Promise((e,t)=>{Pe=e,Ie=t});function ze(e){ye?.signal(e)}let Be=2e3,Ve=null;function Ue(){Ve!==null&&clearTimeout(Ve),Ve=setTimeout(()=>{Ve=null,de.saveToDisk().catch(e=>{console.warn(`[backlinks] Failed to persist debounced cache:`,e)})},2e3)}let We=new RecentlyRemovedDocs(void 0,{onEviction:()=>incrementRecentlyRemovedDocsEviction(),onSizeChange:e=>setRecentlyRemovedDocsSize(e)}),Ge=(e,t)=>{isSystemDoc(e)||isConfigDoc(e)||We.setRenamed(e,t)},Ke=e=>{if(!(isSystemDoc(e)||isConfigDoc(e))){if(We.peek(e)?.kind===`renamed`){console.info(JSON.stringify({event:`recently-removed-docs-unpaired-delete-suppressed`,docName:e,source:`watcher-delete`}));return}We.setDeleted(e)}},Xe=e=>{isSystemDoc(e)||isConfigDoc(e)||We.delete(e)};try{ue=createContentFilter({projectDir:S,contentDir:t,onAfterRebuild:()=>{de.rebuildFromDisk(getActiveBranch()).catch(e=>{getLogger(`server-factory`).warn({err:e},`[content-filter] backlink-index rebuild failed after onAfterRebuild`)});try{fe.init()}catch(e){getLogger(`server-factory`).warn({err:e},`[content-filter] tag-index rebuild failed after onAfterRebuild`)}try{let e=Rt?.pruneFileIndexNowExcluded()??0;e>0&&getLogger(`server-factory`).info({pruned:e},`[content-filter] pruned now-excluded entries from fileIndex`)}catch(e){getLogger(`server-factory`).warn({err:e},`[content-filter] fileIndex prune failed after onAfterRebuild`)}}}),de=new BacklinkIndex({projectDir:S,contentDir:t,contentFilter:ue}),fe=new TagIndex({contentDir:t,contentFilter:ue});try{fe.init()}catch(e){console.warn(`[server-factory] tag-index init failed; continuing with empty index:`,e)}me={current:B},ge=createPersistenceExtension({contentDir:t,projectDir:S,gitEnabled:O,commitDebounceMs:k,wipRef:j,shadowRef:me,contentRoot:H,backlinkIndex:de,configHomedirOverride:F,getCurrentBranch:()=>zt?.getLastKnownBranch()??null,resolveEmbed:se,resolveSize:ce,getPrincipal:()=>Te,onAgentCommit:()=>ye?.signal(`session-activity`),onDiskFlush:(e,t)=>ye?.emitDiskAck(e,t),onConfigRejected:(e,t)=>ye?.emitConfigValidationRejected(e,t),mdManager:e.mdManager}),_e=new Hocuspocus({quiet:w,debounce:E,maxDebounce:D,extensions:[ge.extension]});let q=_e.shouldUnloadDocument.bind(_e);_e.shouldUnloadDocument=e=>{if(De.has(e)||je&&q(e))return!0;let t=e.name;return isSystemDoc(t)||isConfigDoc(t)||getReconciledBase(t)!==void 0||e.getXmlFragment(`default`).length!==0||e.getText(`source`).length!==0?!1:q(e)},Me=async e=>{De.add(e);try{await _e.unloadDocument(e)}finally{De.delete(e)}},ye=new CC1Broadcaster(_e),Ce=new AgentFocusBroadcaster(_e),we=new AgentPresenceBroadcaster(_e),ve=new AgentSessionManager(_e);let Y=createLiveDerivedIndexExtension({backlinkIndex:de,tagIndex:fe,signalChannel:ze});_e.configuration.extensions.push(Y),_e.configuration.extensions.push({__kind:`principal-auth`,async onAuthenticate(e){let t=e.token,S=parseHocuspocusAuthToken(t),w=S?.expectedServerInstanceId;if(typeof w==`string`&&w.length>0&&w!==ne)throw new HocuspocusAuthRejection(`server-instance-mismatch`,`server instance mismatch: client claimed ${w}, this server is ${ne}`);let E=S?.expectedBranch,D=getActiveBranch();if(typeof E==`string`&&E.length>0&&E!==D)throw new HocuspocusAuthRejection(`branch-mismatch`,`branch mismatch: client claimed ${E}, server is on ${D}`);if(!S)return;let O=e.context;typeof S.principalId==`string`&&(Te&&S.principalId===Te.id?O.principalId=Te.id:Te?console.warn(JSON.stringify({event:`principal-token-mismatch`,claimed:S.principalId,loaded:Te.id})):O.principalId=S.principalId),typeof S.tabSessionId==`string`&&(O.tabSessionId=S.tabSessionId),O.kind=`human`}}),_e.configuration.extensions.push({__kind:`config-doc-admission-guard`,async onAuthenticate(e){if(!isConfigDoc(e.documentName))return;let t=e.request,S=t.socket?.remoteAddress;if(S!==void 0&&!isLoopbackAddress(S))throw Error(`config-doc admission requires loopback peer (peer=${S}, doc=${e.documentName})`);let w=e.requestHeaders,E=(w&&typeof w.get==`function`?w.get(`host`):null)??t.headers?.host??void 0;if(!isAllowedWorkspaceHostHeader(E))throw Error(`config-doc admission requires loopback Host header (host=${E??`<absent>`}, doc=${e.documentName})`)}});let ee=resolve(t);function te(e){if(!isSafeDocName(e))return null;let t=resolve(ee,`${e}${getDocExtension(e)}`);return!t.startsWith(`${ee}/`)&&t!==ee?null:t}_e.configuration.extensions.push({__kind:`removal-redirect-guard`,async onAuthenticate(e){await runRemovalRedirectGuard(e.documentName,{recentlyRemovedDocs:We,resolveFilePath:te,fileExists:existsSync})}}),_e.configuration.extensions.push({__kind:`system-doc-broadcast-guard`,async beforeHandleMessage(e){if(e.documentName!==`__system__`)return;let t=new IncomingMessage(e.update);if(t.readVarString(),t.readVarUint()===MessageType.BroadcastStateless)throw Error(`inbound BroadcastStateless on ${SYSTEM_DOC_NAME} rejected — server-only channel`)}});let ae=createApiExtension({hocuspocus:_e,sessionManager:ve,contentDir:t,contentFilter:ue,serverInstanceId:ne,getFileIndex:()=>Rt?Rt.getFileIndex():new Map,getFolderIndex:()=>Rt?Rt.getFolderIndex():new Map,getAliasMap:()=>Rt?Rt.getAliasMap():new Map,rescanFiles:()=>Rt?.rescanFromDisk(),enableTestRoutes:L,shadowRef:me,flushGitCommit:()=>ge.flushPendingGitCommit(),flushContributors:()=>ge.flushContributors(),getCurrentBranch:()=>zt?.getLastKnownBranch()??null,getDiskAckSVs:()=>ye?.getLatestDiskAckSVsAsBase64()??{},contentRoot:H,backlinkIndex:de,tagIndex:fe,signalChannel:ze,agentFocusBroadcaster:Ce,agentPresenceBroadcaster:we,onAgentWrite:e.onAgentWrite,getSyncEngine:()=>Bt,localOpCliArgs:J,projectDir:S,resolveEmbed:se,getPrincipal:()=>Te,forceUnloadDocument:Me,ready:Re,recentlyRemovedDocs:We});_e.configuration.extensions.push(ae),_e.configuration.extensions.push(createServerObserverExtension({mdManager,schema,shadowRef:me,contentRoot:H,getCurrentBranch:()=>zt?.getLastKnownBranch()??null,resolveEmbed:se,resolveSize:ce})),_e.configuration.extensions.push(createSyncHandshakeSpanExtension())}catch(e){throw releaseServerLock(ae),e}let $e=null,nt=new Map,rt=[];function it(e,t){let S=resolve(e,`rescue`),w=resolve(S,`${t}${getDocExtension(t)}`);return w.startsWith(`${S}/`)?w:null}function at(e){let t=_e.documents.get(e);if(!t)return null;let{frontmatter:S,body:w}=stripFrontmatter(t.getText(`source`).toString());return prependFrontmatter(S,w)}let st=(e,t)=>applyExternalChange(_e,e,t,se,ce);function vt(e){let t=e.getMap(`lifecycle`);t.get(`status`)===`conflict`&&(t.delete(`status`),t.delete(`reason`))}let Tt=e=>{if(!e)return;let t=`[[${e}]]`;for(let[S]of _e.documents){if(isSystemDoc(S)||isConfigDoc(S))continue;let w=_e.documents.get(S);if(!w)continue;let E=w.getText(`source`).toString();if(E.includes(t))try{w.transact(()=>{applyDiskContentToDoc(w,E,se,S)},FILE_WATCHER_ORIGIN)}catch(t){ee.error({err:t,docName:S,assetBasename:e},`[asset-event] failed to re-render ${S} for asset basename ${e}`)}}},Et=null,Dt=e=>{e&&(Et===null&&(Et=new Set,setImmediate(()=>{let e=Et;if(Et=null,e)try{for(let t of e)Tt(t)}catch(t){ee.error({err:t,basenames:[...e]},`[asset-event] dedup rerender pass crashed`)}})),Et.add(e))};function jt(e){switch(e.kind){case`rename`:return e.newDocName;case`asset-create`:case`asset-delete`:case`folder-create`:case`folder-delete`:return e.relativePath;case`create`:case`update`:case`delete`:case`conflict`:return e.docName;default:return assertNeverDiskEvent(e)}}async function Mt(e){try{switch(e.kind){case`create`:ee.info({docName:e.docName},`[reconcile] create: ${e.docName}`),de.updateDocumentFromMarkdown(e.docName,e.content),Ue(),fe.updateDocumentFromMarkdown(e.docName,e.content),ze(`files`),ze(`backlinks`),ze(`graph`),ze(`tags`),Xe(e.docName);break;case`update`:{let{docName:t,content:S}=e,w=_e.documents.get(t);if(!w){de.updateDocumentFromMarkdown(t,S),Ue(),fe.updateDocumentFromMarkdown(t,S),ze(`backlinks`),ze(`graph`),ze(`tags`);return}let E=getReconciledBase(t)??``,D=at(t)??E,O=reconcile({docName:t,base:E,ours:D,theirs:S}),k=contentHash(E).slice(0,6),j=contentHash(D).slice(0,6),F=contentHash(S).slice(0,6);switch(ee.info({docName:t,base:k,ours:j,theirs:F,result:O.kind},`[reconcile] ${t} base=${k} ours=${j} theirs=${F} result=${O.kind}`),O.kind){case`noop`:vt(w),de.updateDocumentFromMarkdown(t,S),Ue(),fe.updateDocumentFromMarkdown(t,S),ze(`backlinks`),ze(`graph`),ze(`tags`);break;case`clean`:try{st(t,O.newContent),setReconciledBase(t,O.newContent),incrementReconcile(),vt(w),de.updateDocumentFromMarkdown(t,S),Ue(),fe.updateDocumentFromMarkdown(t,S),ze(`backlinks`),ze(`graph`),ze(`tags`)}catch(e){ee.error({err:e,docName:t},`[reconcile] failed to apply clean content to Y.Doc for ${t}`),setReconciledBase(t,S),vt(w)}break;case`merged`:try{st(t,O.newContent),setReconciledBase(t,O.newContent),incrementReconcile(),vt(w),de.updateDocumentFromMarkdown(t,S),Ue(),fe.updateDocumentFromMarkdown(t,S),ze(`backlinks`),ze(`graph`),ze(`tags`)}catch(e){ee.error({err:e,docName:t},`[reconcile] failed to apply merged content to Y.Doc for ${t}`),setReconciledBase(t,S),vt(w)}break;case`conflicts`:try{st(t,O.newContent),setReconciledBase(t,O.newContent),incrementReconcile(),incrementConflict(),de.updateDocumentFromMarkdown(t,S),Ue(),fe.updateDocumentFromMarkdown(t,S),ze(`backlinks`),ze(`graph`),ze(`tags`)}catch(e){ee.error({err:e,docName:t},`[reconcile] failed to apply conflict content to Y.Doc for ${t}`),setReconciledBase(t,S)}break;case`refused`:{incrementConflict();let e=w.getMap(`lifecycle`);e.set(`status`,`conflict`),e.set(`reason`,O.reason);break}}break}case`delete`:{let{docName:t}=e,S=_e.documents.get(t);if(!S){de.deleteDocument(t),Ue(),fe.deleteDocument(t),ze(`files`),ze(`backlinks`),ze(`graph`),ze(`tags`),Ke(t),console.info(JSON.stringify({event:`recently-removed-docs-populate`,docName:t,kind:`deleted`,source:`watcher-delete`}));return}let w=getReconciledBase(t)??``,E=at(t)??``,D=E!==w;if(D&&me.current){let e=me.current,S=zt?.getLastKnownBranch()??`main`;queueMicrotask(()=>{saveInMemoryCheckpoint(e,H??``,{kind:`external-change-rescue`,docName:t,contents:E,label:`External change recovered @ ${new Date().toISOString()}`,branch:S,metadata:{incomingDiskSha:``}}).then(()=>{incrementRescueBuffer(),ee.info({docName:t},`[reconcile] rescue checkpoint saved (delete): ${t}`)}).catch(e=>{ee.error({docName:t,err:e},`[reconcile] rescue checkpoint write failed: ${t}`)})})}S.getMap(`lifecycle`).set(`status`,`deleted-upstream`),deleteReconciledBase(t),de.deleteDocument(t),Ue(),fe.deleteDocument(t),ee.info({docName:t,isDirty:D},`[reconcile] delete: ${t} (dirty=${D})`),_e.closeConnections(t),await Me(S),ze(`files`),ze(`backlinks`),ze(`graph`),ze(`tags`),Ke(t),console.info(JSON.stringify({event:`recently-removed-docs-populate`,docName:t,kind:`deleted`,source:`watcher-delete`}));break}case`rename`:{let{oldDocName:t,newDocName:S,content:w}=e,E=_e.documents.get(t);if(deleteReconciledBase(t),setReconciledBase(S,w),de.renameDocument(t,S,w),Ue(),fe.renameDocument(t,S,w),E){let e=E.getMap(`lifecycle`);e.set(`status`,`renamed`),e.set(`newPath`,S)}ee.info({oldDocName:t,newDocName:S},`[reconcile] rename: ${t} → ${S}`),ze(`files`),ze(`backlinks`),ze(`graph`),ze(`tags`),Ge(t,S),console.info(JSON.stringify({event:`recently-removed-docs-populate`,from:t,to:S,kind:`renamed`,source:`watcher-rename`}));break}case`conflict`:{let{docName:t}=e,S=_e.documents.get(t);if(!S)return;let w=at(t);w===null?ee.warn({docName:t},`[reconcile] case 'conflict': serializeDoc returned null for ${t}; reconciledBase snapshot skipped — post-resolution reconcile may degrade to 3-way merge`):setReconciledBase(t,w);let E=S.getMap(`lifecycle`);E.set(`status`,`conflict`),E.set(`reason`,`conflict-markers`),ee.info({docName:t},`[reconcile] conflict markers detected: ${t}`);break}case`asset-create`:oe.add(e.relativePath),ze(`files`),Dt(basename(e.relativePath));break;case`asset-delete`:oe.remove(e.relativePath),ze(`files`),Dt(basename(e.relativePath));break;case`folder-create`:case`folder-delete`:ze(`files`);break;default:assertNeverDiskEvent(e)}}catch(t){let S=jt(e);ee.error({err:t,kind:e.kind,label:S},`[reconcile] failed to handle ${e.kind} for ${S}`)}}let Ft=[];async function It(e){if(isBatchInProgress()){Ft.push(e);return}await Mt(e)}async function Lt(){let e=Ft.splice(0,Ft.length);for(let t of e)await Mt(t)}let Rt=null,zt=null,Bt=null,Vt=null;async function Ht(e){if(_e.documents.size===0)return;let t=!1,S=new Promise(e=>{_e.configuration.extensions.push({async afterUnloadDocument({instance:S}){!t&&S.getDocumentsCount()===0&&(t=!0,e())}})}),w=Array.from(_e.documents.keys());_e.closeConnections(),_e.flushPendingStores();for(let e of _e.documents.values())e.getConnectionsCount()===0&&_e.unloadDocument(e).catch(t=>{console.warn(JSON.stringify({event:`ok-shutdown-unload-document-failed`,docName:e.name,reason:t instanceof Error?t.message:String(t)}))});let E,D=new Promise((S,D)=>{E=setTimeout(()=>{t=!0;let S=Array.from(_e.documents.keys()),E=[],O=[];if(me.current){for(let e of S)if(!(isSystemDoc(e)||isConfigDoc(e)))try{let t=at(e);if(t===null){ee.warn({docName:e},`[rescue] skipping ${e} — document dropped from map mid-rescue`),O.push(e);continue}let S=it(me.current.gitDir,e);if(!S){ee.warn({docName:e,gitDir:me.current.gitDir},`[rescue] path-traversal guard rejected docName: ${e}`),O.push(e);continue}mkdirSync(dirname(S),{recursive:!0}),writeFileSync(S,t,`utf-8`),incrementRescueBuffer(),E.push(e),ee.info({docName:e},`[rescue] rescue buffer saved on flush timeout: ${e}`)}catch(t){O.push(e),ee.error({err:t,docName:e},`[rescue] failed to write rescue buffer for ${e}`)}}else ee.warn({stillLoadedCount:S.length},`[rescue] shadow repo unavailable at flush timeout — ${S.length} doc(s) will be lost: [${S.join(`, `)}]`),O.push(...S);let k=E.length>0||O.length>0?` — rescued [${E.join(`, `)}]${O.length>0?`, lost [${O.join(`, `)}]`:``}`:``;D(Error(`flushAllStoresAndWait timeout after ${e}ms — ${S.length}/${w.length} docs did not unload: [${S.join(`, `)}]${k}`))},e)});try{await Promise.race([S,D])}finally{E!==void 0&&clearTimeout(E)}}async function Ut(){return Vt||(Vt=(async()=>{let e=Date.now(),t=[];je=!0,Ve!==null&&(clearTimeout(Ve),Ve=null);let w,E=await Promise.race([Re.then(()=>`completed`,e=>(ee.debug({err:e},`[server] init incomplete during shutdown`),`failed`)),new Promise(e=>{w=setTimeout(()=>e(`timeout`),5e3)})]);w!==void 0&&clearTimeout(w),E===`timeout`&&ee.warn({},`[server] init did not complete within 5s during shutdown`);let D=_e.documents.size;try{try{try{zt&&=(await zt.unsubscribe(),null),Rt&&=(await Rt.unsubscribe(),null);for(let{docName:e,cleanup:t}of rt)try{await t()}catch(t){ee.warn({err:t,docName:e},`[server] failed to stop config-file-watcher for ${e}`)}rt.length=0}catch(e){t.push({phase:`watcher-unsubscribe`,error:e instanceof Error?e.message:String(e)}),ee.error({err:e},`[server] shutdown phase-1 watcher unsubscribe failed`)}try{ye?.destroy(),we?.destroy(),$e&&=(await $e.disconnect(),null);for(let[e,t]of nt)try{await t.disconnect()}catch(t){ee.warn({err:t,docName:e},`[server] failed to disconnect ${e} during shutdown`)}nt.clear()}catch(e){t.push({phase:`cc1-teardown`,error:e instanceof Error?e.message:String(e)}),ee.error({err:e},`[server] shutdown phase-1b CC1 teardown failed`)}try{await ve.closeAll()}catch(e){t.push({phase:`agent-session-drain`,error:e instanceof Error?e.message:String(e)}),ee.error({err:e},`[server] shutdown phase-2 agent session drain failed`)}try{await Ht(q)}catch(e){t.push({phase:`flush-all-stores`,error:e instanceof Error?e.message:String(e)}),ee.error({err:e},`[server] shutdown phase-3 flush failed`)}let e;try{await Promise.race([(async()=>{await ge.flushPendingGitCommit(),await ge.waitForPendingCommits()})(),new Promise((t,S)=>{e=setTimeout(()=>S(Error(`L2 git flush timeout`)),q)})])}catch(e){t.push({phase:`git-commit-flush`,error:e instanceof Error?e.message:String(e)}),ee.error({err:e},`[server] shutdown phase-4 git commit flush failed`)}finally{e!==void 0&&clearTimeout(e)}try{Bt&&=(await Bt.destroy(),null)}catch(e){t.push({phase:`sync-engine-stop`,error:e instanceof Error?e.message:String(e)}),ee.error({err:e},`[server] shutdown sync-engine-stop failed`)}}finally{if(me.current){try{let e=(await esm_default({baseDir:S,timeout:{block:5e3}}).revparse(`HEAD`)).trim();e&&writeFileSync(resolve(me.current.gitDir,`last-known-head`),e,`utf-8`)}catch{}try{destroyShadowRepo(me.current)}catch(e){t.push({phase:`shadow-repo-release`,error:e instanceof Error?e.message:String(e)}),ee.error({err:e},`[server] shutdown phase-5 destroyShadowRepo failed`)}}let w=Date.now()-e;t.length===0?ee.info({documentCount:D,durationMs:w},`[server] shutdown flushed ${D} documents in ${w}ms`):ee.warn({documentCount:D,durationMs:w,phaseErrors:t},`[server] shutdown flushed ${D} documents in ${w}ms with ${t.length} phase error(s)`)}}finally{try{releaseServerLock(ae)}catch(e){t.push({phase:`server-lock-release`,error:e instanceof Error?e.message:String(e)}),ee.error({err:e},`[server] shutdown phase-6 releaseServerLock failed`)}try{await shutdownTelemetry()}catch(e){t.push({phase:`telemetry-shutdown`,error:e instanceof Error?e.message:String(e)})}}})(),Vt)}let Wt=[];async function Kt(){try{Te=await loadPrincipal(S),ee.info({principalId:Te.id},`[server] principal loaded`)}catch(e){ee.warn({err:e},`[server] principal load failed — browser writes will use SERVICE_WRITER`)}if(!me.current)try{me.current=await initShadowRepo(S),ee.info({gitDir:me.current.gitDir},`[server] history repo initialized at ${me.current.gitDir}`)}catch(e){ee.error({err:e},`[server] history repo init failed`),Wt.push(`shadow-repo`)}if(me.current){let e=null;try{e=loadRenameLogIndex(me.current.gitDir),sweepLazyPopOrphans(me.current.gitDir,e),setRenameLogIndex(me.current.gitDir,e),ee.info({entries:e.byTo.size},`[server] rename log loaded (${e.byTo.size} entries)`)}catch(e){ee.warn({err:e},`[rename-log] boot-time load/sweep failed; rename history unavailable`)}if(e){let t=1e4;try{await Promise.race([gcRenameLog(me.current,e,{rebuild:!0}),new Promise((e,S)=>setTimeout(()=>S(Error(`boot-time GC exceeded ${t}ms`)),t))])}catch(e){ee.warn({err:e},`[rename-log] boot-time GC/rebuild failed; index loaded without GC`)}}}if(me.current)try{await shadowGit(me.current).raw(`rev-parse`,`--git-dir`)}catch(e){let t=e instanceof Error?e.message:String(e);if(t.includes(`not a git repository`)||t.includes(`invalid object`)){ee.warn({},`[server] history repo appears corrupted — reinitializing`);try{me.current=await initShadowRepo(S)}catch(e){ee.error({err:e},`[server] history repo reinit failed`),me.current=void 0,Wt.includes(`shadow-repo`)||Wt.push(`shadow-repo`)}}else ee.error({err:e},`[server] history repo check failed (transient?)`)}if(me.current)try{let e=resolve(me.current.gitDir,`last-known-head`),t=null;try{t=readFileSync(e,`utf-8`).trim()||null}catch{}let w=null;try{w=(await esm_default({baseDir:S,timeout:{block:1e4}}).revparse(`HEAD`)).trim()||null}catch{}if(w!==null){if(w!==t){let e=`main`;try{let t=(await esm_default({baseDir:S,timeout:{block:1e4}}).raw(`rev-parse`,`--abbrev-ref`,`HEAD`)).trim();t&&t!==`HEAD`&&(e=t)}catch{}ee.info({lastKnownHead:t,currentHead:w,branch:e},`[head-drift] lastKnownHead=${t??`null`}, currentHead=${w}, action=import`);try{await commitUpstreamImport(me.current,H??``,t,w,e),incrementUpstreamImport()}catch(e){ee.warn({err:e},`[head-drift] commitUpstreamImport failed — continuing`)}}else ee.info({currentHead:w},`[head-drift] lastKnownHead=${t??`null`}, currentHead=${w}, action=noop`);try{writeFileSync(e,w,`utf-8`)}catch(e){ee.warn({err:e},`[head-drift] failed to write last-known-head`)}}}catch(e){ee.warn({err:e},`[head-drift] check failed — continuing`)}try{let e=recoverPendingManagedRename(t,S);if(e.recovered&&e.journal){let t=e.journal.version===2?e.journal.fromPath:e.journal.sourceDocName,S=e.journal.version===2?e.journal.toPath:e.journal.destinationDocName;ee.warn({journalVersion:e.journal.version,fromPath:t,toPath:S,restoredDocNames:e.restoredDocNames},`[managed-rename] recovered pending rename ${t} -> ${S}`)}}catch(e){ee.error({err:e},`[server] managed rename recovery failed`),Wt.push(`managed-rename-recovery`)}try{let e=cleanupOrphanUploadTempfiles(S);(e.deleted>0||e.errors>0)&&ee.info({scanned:e.scanned,deleted:e.deleted,errors:e.errors},`[upload-tempfile-sweep] swept ${e.deleted} orphan tempfile(s)`)}catch(e){ee.error({err:e},`[server] upload-tempfile sweep failed`),Wt.push(`upload-tempfile-sweep`)}try{$e=await _e.openDirectConnection(SYSTEM_DOC_NAME),ye?.emitServerInfo(ne,getActiveBranch())}catch(e){ee.error({err:e},`[server] failed to open __system__ direct connection — CC1 push disabled`),Wt.push(`cc1-push`)}for(let e of CONFIG_DOC_NAMES)try{let t=await _e.openDirectConnection(e);nt.set(e,t)}catch(t){ee.error({err:t,docName:e},`[server] failed to open ${e} direct connection — config bind degraded`),Wt.push(`config-doc:${e}`)}let e=new Map([[CONFIG_DOC_NAME_PROJECT,resolveConfigPath(`project`,S)],[CONFIG_DOC_NAME_PROJECT_LOCAL,resolveConfigPath(`project-local`,S)],[CONFIG_DOC_NAME_USER,resolveConfigPath(`user`,S,F)]]);for(let t of CONFIG_DOC_NAMES){let S=e.get(t);if(S)try{ee.info({docName:t,path:S},`[config-file-watcher] starting`);let e=await startConfigFileWatcher(S,e=>{let S=_e.documents.get(t);ee.info({docName:t,hasDocument:S!==void 0,contentLength:e.length},`[config-file-watcher] file changed`);let w=applyExternalConfigChange(S??null,t,e,ge.configPersistenceCtx);if(ee.info({docName:t,outcome:w},`[config-file-watcher] applyExternalConfigChange outcome`),t===`__config__/project`||t===`__local__/project`){let e=te();Bt?.setEnabled(e).catch(t=>{ee.warn({err:t,enabled:e},`[sync] failed to apply autoSync.enabled from config`)})}});rt.push({docName:t,cleanup:e}),ee.info({docName:t,path:S},`[config-file-watcher] started`)}catch(e){ee.warn({err:e,docName:t,path:S},`[config-file-watcher] failed to start for ${t}`),Wt.push(`config-file-watcher:${t}`)}}try{let e=resolve(t,`.okignore`),w=resolve(S,`.gitignore`),E=ee;E.info({okignorePath:e,gitignorePath:w},`[ignore-watcher] starting multi-path watcher for .okignore + .gitignore`);let D=await startMultiPathConfigFileWatcher([e,w],(t,w)=>{(async()=>{if(t===e)try{let e=applyExternalConfigChange(_e.documents.get(`__config__/okignore`)??null,CONFIG_DOC_NAME_OKIGNORE,w,ge.configPersistenceCtx);E.info({docName:CONFIG_DOC_NAME_OKIGNORE,outcome:e},`[ignore-watcher] applyExternalConfigChange outcome`)}catch(e){E.error({err:e,changedPath:relative(S,t)},`[ignore-watcher] applyExternalConfigChange failed; rebuild proceeds independently`)}let D=await ue.rebuildIgnorePatterns();if(D.ok)E.info({changedPath:relative(S,t),patternCount:D.patternCount,nestedFileCount:D.nestedFileCount,durationMs:D.durationMs},`[ignore-watcher] rebuild succeeded — broadcasting files channel`),ye?.signal(`files`);else{let e=relative(S,t)||`.`;E.warn({changedPath:e,error:D.error.message},`[ignore-watcher] rebuild failed — emitting config-ignore-nested-error`),ye?.emitConfigIgnoreNestedError(e,D.error.message)}})().catch(e=>{E.error({err:e,changedPath:relative(S,t)||`.`},`[ignore-watcher] handler threw`)})});rt.push({docName:`__ignore-files__`,cleanup:D}),E.info({okignorePath:e,gitignorePath:w},`[ignore-watcher] multi-path watcher started`)}catch(e){ee.warn({err:e,projectDir:S,contentDir:t},`[ignore-watcher] failed to start multi-path watcher`),Wt.push(`ignore-files-watcher`)}let w=resolveGitDir(S),E=w?readBranchFromHead(w)??`main`:`main`;switchReconciledBaseScope(E),de.switchBranch(E);try{{let e=getActiveBranch();try{if(await de.loadFromDisk(e)){let t=await de.reconcileWithDisk(e);(t.added>0||t.updated>0||t.deleted>0)&&ee.info(t,`[backlinks] startup reconcile: offline changes applied`)}else await de.rebuildFromDisk(e);de.saveToDisk().catch(t=>{console.warn(`[backlinks] Failed to persist startup cache for ${e}:`,t)})}catch(t){ee.error({err:t,branch:e},`[backlinks] startup init failed; index will populate incrementally via watcher`)}}Rt=await startWatcher(t,It,ue),fe.init();let e=0;try{seedBasenameIndex({contentDir:t,contentFilter:ue,basenameIndex:oe,onSkip:(t,S,w)=>{e++,ee.warn({reason:t,code:S,path:w},`[basename-index] skipped entry during seed (${t}${S?` ${S}`:``})`)}}),e>0&&(ee.warn({count:e},`[basename-index] startup seed completed with ${e} skipped entries — embeds under inaccessible subtrees will not resolve`),Wt.push(`basename-index-partial`))}catch(e){ee.error({err:e},`[basename-index] startup seed failed`),Wt.push(`basename-index`)}}catch(e){ee.error({err:e},`[server] disk bridge watcher failed to start`),Wt.push(`file-watcher`)}try{zt=await startHeadWatcher(S,async({trigger:e})=>{if(ee.info({trigger:e},`[batch] begin trigger=${e}`),incrementBatch(),_e.flushPendingStores(),await ge.flushPendingGitCommit(),setBatchInProgress(!0),me.current){let e=getActiveBranch(),t=resolveGitDir(S),w=t?readBranchFromHead(t)??e:e,E=[];for(let[e,t]of _e.documents){if(isSystemDoc(e)||isConfigDoc(e))continue;let S=null;if(t.transact(()=>{S=at(e)},PARK_SNAPSHOT_ORIGIN),S===null)continue;let w=getReconciledBase(e)??S;E.push({docName:e,markdown:S,diskSnapshot:w})}if(E.length>0)try{let t=await parkBranch(me.current,e,SERVICE_WRITER.id,E,w);t&&(incrementPark(),ee.info({count:E.length,branch:e,sha:t.slice(0,8)},`[history] parked ${E.length} docs on ${e} → ${t.slice(0,8)}`))}catch(e){ee.error({err:e},`[shadow] park failed`)}}},async e=>{let S=Ft.length,w=e.newBranch??`main`;if(ee.info({kind:e.batchKind,headMoved:e.headMoved,docs:S,timeout:!!e.timeout},`[batch] end kind=${e.batchKind} headMoved=${e.headMoved} docs=${S}${e.timeout?` timeout`:``}`),e.batchKind===`within-branch`)setBatchInProgress(!1),await Lt(),await ge.flushDeferredStores(`within-branch`);else{incrementBranchSwitch(),Ft.splice(0,Ft.length),switchReconciledBaseScope(w),Ve!==null&&(clearTimeout(Ve),Ve=null),de.switchBranch(w),ue.rebuildDirCount();try{let e=0;oe.clear(),seedBasenameIndex({contentDir:t,contentFilter:ue,basenameIndex:oe,onSkip:(t,S,E)=>{e++,ee.warn({reason:t,code:S,path:E,branch:w},`[basename-index] skipped entry during branch-switch reseed (${t}${S?` ${S}`:``})`)}}),e>0&&(ee.warn({count:e,branch:w},`[basename-index] branch-switch reseed completed with ${e} skipped entries — embeds under inaccessible subtrees will not resolve on this branch`),Wt.includes(`basename-index-partial`)||Wt.push(`basename-index-partial`))}catch(e){ee.error({err:e,branch:w},`[basename-index] branch-switch reseed failed`)}for(let[e,S]of _e.documents)if(!(isSystemDoc(e)||isConfigDoc(e)))try{let E=safeContentPath(e,t);if(!existsSync(E)){let t=getReconciledBase(e)??``,E=at(e)??``;if(E!==t&&me.current){let t=me.current;queueMicrotask(()=>{saveInMemoryCheckpoint(t,H??``,{kind:`external-change-rescue`,docName:e,contents:E,label:`External change recovered @ ${new Date().toISOString()}`,branch:w,metadata:{incomingDiskSha:``}}).then(()=>{incrementRescueBuffer(),ee.info({docName:e},`[reconcile] rescue checkpoint saved on branch switch: ${e}`)}).catch(t=>{ee.error({docName:e,err:t},`[reconcile] rescue checkpoint write failed: ${e}`)})})}S.getMap(`lifecycle`).set(`status`,`deleted-upstream`),ee.info({docName:e,branch:w},`[branch-switch] tombstone: ${e} (not on ${w})`);continue}let D=readFileSync(E,`utf-8`);st(e,D),setReconciledBase(e,D),ee.info({docName:e},`[branch-switch] reset: ${e}`)}catch(t){ee.error({err:t,docName:e},`[branch-switch] failed to reset ${e}`)}ee.info({branch:w,docCount:_e.documents.size},`[branch-switch] loaded branch ${w} (${_e.documents.size} docs)`);try{if(await de.loadFromDisk(w)){let e=await de.reconcileWithDisk(w);(e.added>0||e.updated>0||e.deleted>0)&&ee.info(e,`[backlinks] branch-switch reconcile for ${w}`)}else await de.rebuildFromDisk(w);de.saveToDisk(w).catch(e=>{console.warn(`[backlinks] Failed to persist branch cache for ${w}:`,e)})}catch(e){ee.error({err:e,branch:w},`[backlinks] branch-switch rebuild failed; backlinks may be stale`)}if(fe.init(),me.current&&e.batchKind===`cross-branch`){let e=0;for(let[t]of _e.documents)if(!(isSystemDoc(t)||isConfigDoc(t)))try{let S=await readParkedState(me.current,w,SERVICE_WRITER.id,t);if(!S||S.markdown===S.diskSnapshot)continue;let E=getReconciledBase(t);if(!E)continue;let D=reconcile({docName:t,base:S.diskSnapshot,ours:S.markdown,theirs:E});switch(D.kind){case`merged`:case`clean`:st(t,D.newContent),setReconciledBase(t,D.newContent),e++;break;case`conflicts`:st(t,D.newContent),setReconciledBase(t,D.newContent),incrementConflict(),e++;break;case`noop`:case`refused`:break}}catch(e){ee.error({err:e,docName:t},`[branch-switch] restore WIP failed for ${t}`)}e>0&&ee.info({count:e,branch:w},`[branch-switch] restored ${e} parked docs on ${w}`)}if(e.oldBranch?.startsWith(`detached-`)&&me.current)try{let t=shadowGit(me.current),S=(await t.raw(`for-each-ref`,`refs/wip/${e.oldBranch}/`,`--format=%(refname)`)).trim();if(S){for(let e of S.split(`
3073
3230
  `))e&&await t.raw(`update-ref`,`-d`,e);ee.info({context:e.oldBranch},`[branch-switch] cleaned up detached context ${e.oldBranch}`)}}catch(e){ee.error({err:e},`[branch-switch] detached cleanup failed`)}setBatchInProgress(!1),await ge.flushDeferredStores(`discard-stale`),ye?.emitBranchSwitched(w)}if(e.headMoved&&e.newHead&&me.current&&S>0){let t=H??`.`;try{let S=await commitUpstreamImport(me.current,t,e.oldHead,e.newHead,w);incrementUpstreamImport(),ee.info({oldHead:e.oldHead?.slice(0,8)??`null`,newHead:e.newHead.slice(0,8),sha:S.slice(0,8)},`[history] upstream-import from ${e.oldHead?.slice(0,8)??`null`}..${e.newHead.slice(0,8)} → ${S.slice(0,8)}`)}catch(e){ee.error({err:e},`[shadow] upstream-import failed`)}}})}catch(e){ee.error({err:e},`[server] HEAD watcher failed to start`),Wt.push(`head-watcher`)}let D=J?.[0]??`open-knowledge`,O=[`-c`,`credential.helper=!${J&&J.length>1?J.join(` `):D} auth git-credential`];try{Bt=new SyncEngine({projectDir:S,contentDir:t,contentFilter:ue,contentRoot:H,syncEnabled:te(),credentialArgs:O,cc1Broadcaster:ye,setBatchInProgress:e=>{setBatchInProgress(e),e||ge.flushDeferredStores(`within-branch`).catch(e=>{ee.error({err:e},`[persistence] deferred store drain failed after sync batch`)})},onStateChange:e=>{ee.info({state:e},`[sync] state → ${e}`)},onAutoDisable:async e=>{ee.warn({reason:e},`[sync] auto-disabled — persisting to project-local config`);let t=await writeConfigPatch({cwd:S,scope:`project-local`,patch:{autoSync:{enabled:!1}}});t.ok||ee.error({result:t,reason:e,humanError:humanFormat(t.error),configPath:resolveConfigPath(`project-local`,S)},`[sync] failed to persist auto-disable — next restart WILL re-enable sync and re-trigger the same failure. Check permissions on the config path.`)}}),await Bt.start()}catch(e){ee.warn({err:e},`[server] SyncEngine failed to start — sync disabled`),Bt=null}ze(`files`),ze(`backlinks`),ze(`graph`),ze(`tags`)}return Kt().then(Pe,Ie),{hocuspocus:_e,sessionManager:ve,cc1Broadcaster:ye,agentFocusBroadcaster:Ce,agentPresenceBroadcaster:we,contentFilter:ue,basenameIndex:oe,serverInstanceId:ne,destroy:Ut,ready:Re,degraded:Wt,lockDir:ae,get syncEngine(){return Bt}}}const LEGACY_RUNTIME_FILENAMES=[`server.lock`,`ui.lock`,`state.json`,`principal.json`,`sync-state.json`,`conflicts.json`,`last-spawn-error.log`],LEGACY_RUNTIME_DIRNAMES=[`cache`,`tmp`];function findLegacyRuntimeFiles(e){let t=resolve(e,LOCAL_DIR);if(!(()=>{if(!existsSync(t))return!0;try{return readdirSync(t).length===0}catch{return!0}})())return[];let S=[];for(let t of LEGACY_RUNTIME_FILENAMES)existsSync(resolve(e,t))&&S.push(t);for(let t of LEGACY_RUNTIME_DIRNAMES){let w=resolve(e,t);try{existsSync(w)&&statSync(w).isDirectory()&&S.push(`${t}/`)}catch{}}return S}function computeWorktreeAttributes(e){let t=resolveGitDirDetailed(e);switch(t.kind){case`directory`:return{kind:`main`,gitdir:t.path};case`linked`:return{kind:`linked`,gitdir:t.path};case`malformed-pointer`:return{kind:`linked`,gitdir:null};case`inaccessible`:case`absent`:return{kind:`main`,gitdir:null}}}const DEFAULT_IDLE_THRESHOLD_MS=1800*1e3,DESTROY_STEP_TIMEOUT_MS=5e3;async function bootServer(e){initTelemetry();let{kind:t,gitdir:S}=computeWorktreeAttributes(e.projectDir??e.contentDir),w={"ok.worktree.kind":t};return S!==null&&(w[`ok.worktree.gitdir`]=normalizeFsPath(S)),withSpan(`ok.boot`,{attributes:w},async()=>bootServerInner(e))}async function bootServerInner(e){let t=e.skipAutoInit??!1,S=e.attachUiSibling??!0,w=e.idleShutdownMs,E=e.log??getLogger(`boot`),D=process.env.OK_LOCK_KIND===`mcp-spawned`||process.env.OK_LOCK_KIND===`interactive`?process.env.OK_LOCK_KIND:void 0,O=e.lockKind??D??`interactive`,{createServer:k}=await import(`node:http`),{updateServerLockPort:j}=await import(`./server-lock-D7DXNVql-B5nINglj.mjs`).then(e=>e.a),F=!1;if(!t&&e.autoInitFn)try{F=!!await e.autoInitFn()}catch(e){E.warn({err:e},`autoInitFn failed`)}let L=e.projectDir??e.contentDir,B=resolve(L,`.ok`);if(!existsSync(resolve(B,`config.yml`)))throw new MissingOkConfigError(existsSync(B)?`config`:`okdir`,L);existsSync(resolve(B,`.gitignore`))||console.warn("[boot] Note: .ok/.gitignore is missing — per-machine state files in .ok/ may show up as untracked changes. Run `ok init` to add the recommended ignore entries.");let H=findLegacyRuntimeFiles(B);H.length>0&&console.warn(`[boot] Found legacy runtime files at .ok/${H.join(`, `)}. Delete .ok/ and re-init — these files moved to .ok/${LOCAL_DIR}/.`);let q=createServer$1({contentDir:e.contentDir,projectDir:e.projectDir,contentRoot:e.contentRoot,port:e.port,host:e.host,quiet:e.quiet??!1,debounce:e.debounce,maxDebounce:e.maxDebounce,gitEnabled:e.gitEnabled,commitDebounceMs:e.commitDebounceMs,wipRef:e.wipRef,enableTestRoutes:e.enableTestRoutes,shadowRepo:e.shadowRepo,destroyTimeoutMs:e.destroyTimeoutMs,localOpCliArgs:e.localOpCliArgs,onAgentWrite:e.onAgentWrite,lockKind:O,skipStateManifestCheck:e.skipStateManifestCheck}),{hocuspocus:J,destroy:Y,ready:ee,degraded:te,lockDir:ne,sessionManager:ae,agentFocusBroadcaster:oe,agentPresenceBroadcaster:se}=q,ce=(()=>{let t=e.host??`localhost`;return t===`0.0.0.0`||t===`::`?`localhost`:t.includes(`:`)&&!t.startsWith(`[`)?`[${t}]`:t})(),ue=e.port??0,de=createMcpHttpHandler({contentDir:e.contentDir,projectDir:e.projectDir??e.contentDir,config:e.config,getServerUrl:()=>`http://${ce}:${ue}`,log:E}),fe=k();fe.headersTimeout=3e4,fe.requestTimeout=6e4;let me=e.serveContentAssets?createAssetServeMiddleware({contentFilter:q.contentFilter,contentSirv:build_default(e.contentDir,{dev:!0,dotfiles:!1}),inlineExtensions:INLINE_RENDERABLE_EXTENSIONS,assetExtensions:ASSET_EXTENSIONS,blocklistExtensions:EXECUTABLE_BLOCKLIST_EXTENSIONS}):void 0;if(e.reactShellDistDir)try{acquireUiLock(ne,{port:0,worktreeRoot:e.projectDir??e.contentDir})}catch(e){throw await Y().catch(()=>{}),e}let ge=e.reactShellDistDir?build_default(e.reactShellDistDir,{single:!0,gzip:!0,immutable:!0}):void 0,_e=mountMcpAndApi({httpServer:fe,hocuspocus:J,mcpHttpHandler:de,log:E,sessionManager:ae,agentFocusBroadcaster:oe,agentPresenceBroadcaster:se,keepaliveGraceMs:e.keepaliveGraceMs,contentAssetMiddleware:me,reactShellMiddleware:ge}),ve=async()=>{throw Error(`bootServer: destroy() invoked before initialization — boot did not complete`)},ye=null;w!==null&&(ye=attachIdleShutdown({httpServer:fe,thresholdMs:w??DEFAULT_IDLE_THRESHOLD_MS,log:E,onShutdown:(e.idleShutdownHandler??(e=>async()=>{await e()}))(async()=>{await ve()})}));try{await new Promise((t,S)=>{let w=e=>S(e);fe.once(`error`,w),fe.listen(e.port,e.host,()=>{fe.removeListener(`error`,w),t()})})}catch(t){if(e.reactShellDistDir)try{releaseUiLock(ne)}catch(e){E.warn({err:e},`releaseUiLock failed during listen-error cleanup`)}throw await Y().catch(()=>{}),t}let Ce=fe.address(),we=typeof Ce==`object`&&Ce?Ce.port:e.port??0;if(ue=we,j(ne,we),e.reactShellDistDir&&updateUiLockPort(ne,we),S&&e.spawnUiSiblingFn)try{await e.spawnUiSiblingFn({lockDir:ne,log:E})}catch(e){E.warn({err:e},`spawnUiSiblingFn failed`)}let Te=!1,De=async(e,t)=>{let S;try{await Promise.race([t(),new Promise((t,w)=>{S=setTimeout(()=>{w(Error(`${e} timed out after ${DESTROY_STEP_TIMEOUT_MS}ms`))},DESTROY_STEP_TIMEOUT_MS),S.unref?.()})])}finally{S!==void 0&&clearTimeout(S)}};return ve=async()=>{if(Te)return;Te=!0;let t=[],S=async(e,S)=>{try{await De(e,S)}catch(S){t.push(S),E.warn({err:S,step:e},`bootServer destroy step failed`)}};try{ye?.detach()}catch(e){t.push(e),E.warn({err:e,step:`idleHandle.detach`},`bootServer destroy step failed`)}if(await S(`mount.shutdown`,()=>_e.shutdown()),await S(`mcpHttpHandler.close`,()=>de.close()),await S(`mount.wss.close`,()=>new Promise((e,t)=>{_e.wss.close(S=>S?t(S):e())})),await S(`httpServer.closeAllConnections`,async()=>{fe.closeAllConnections?.()}),await S(`httpServer.close`,()=>new Promise((e,t)=>{fe.close(S=>S&&S.code!==`ERR_SERVER_NOT_RUNNING`?t(S):e())})),await S(`destroyHocuspocus`,()=>Y()),e.reactShellDistDir&&await S(`releaseUiLock`,async()=>releaseUiLock(ne)),await S(`shutdownTelemetry`,()=>shutdownTelemetry()),t.length>0)throw AggregateError(t,`bootServer destroy completed with errors`)},{httpServer:fe,destroy:ve,lockDir:ne,contentDir:e.contentDir,port:we,ready:ee,degraded:te,didAutoInit:F,serverInstance:q}}const ConfigSchema=ConfigSchema$1;function detectClaudeDesktopPresence(e={}){let t=e.home??homedir(),S=e.platformName??process.platform,w=e.env??process.env;return S===`darwin`?existsSync(join(t,`Library`,`Application Support`,`Claude`)):S===`win32`?existsSync(join(w.APPDATA??join(t,`AppData`,`Roaming`),`Claude`)):!1}const ANCESTOR_WALK_DEPTH_LIMIT=30,GIT_MARKER=`.git`;function findEnclosingGitRoot(e){let t=resolve(e),S=0;for(;S<ANCESTOR_WALK_DEPTH_LIMIT;){let e=!1;try{e=existsSync(resolve(t,GIT_MARKER))}catch{e=!1}if(e)return{gitRoot:t,distance:S};let w=dirname(t);if(w===t)return null;t=w,S+=1}return null}const execFileAsync=promisify(execFile);var ProjectGitInitError=class extends Error{stderr;constructor(e,t=``,S){super(e,S),this.name=`ProjectGitInitError`,this.stderr=t}};async function isInsideExistingWorkTree(e){try{let{stdout:t}=await execFileAsync(`git`,[`rev-parse`,`--is-inside-work-tree`],{cwd:e});return t.trim()===`true`}catch{return!1}}async function ensureProjectGit(e){let t=resolve(e),S=resolve(t,`.git`),w=resolve(S,`HEAD`),E=!1;if(existsSync(S)){if(!statSync(S).isDirectory()||existsSync(w))return{didInit:!1};console.log(`[project-git] detected partial .git/ — running git init to repair`),E=!0}else if(await isInsideExistingWorkTree(t))return{didInit:!1};let D=``;try{D=(await execFileAsync(`git`,[`init`,`--initial-branch=main`,t])).stderr??``}catch(e){let S=typeof e==`object`&&e&&`stderr`in e?String(e.stderr??``):``;throw new ProjectGitInitError(`git init failed at ${t}: ${e instanceof Error?e.message:String(e)}`,S,{cause:e})}if(!existsSync(w))throw new ProjectGitInitError(`git init reported success but ${S}/HEAD is missing (partial init detected)`,D);return E?(console.log(`[project-git] backfilled missing .git/HEAD at ${t}`),{didInit:!0,repaired:!0}):(console.log(`[project-git] initialized .git/ at ${t} (branch: main)`),{didInit:!0})}async function resolvePackageVersion(e,t){let S;try{S=createRequire(t).resolve(e)}catch(e){if(e?.code===`MODULE_NOT_FOUND`)return;throw e}for(let t=dirname(S),w=0;w<32;w+=1){let S=join(t,`package.json`);if(existsSync(S))try{let t=JSON.parse(await readFile$1(S,`utf-8`));if(t.name===e&&typeof t.version==`string`)return t.version}catch{}let w=dirname(t);if(w===t)return;t=w}}export{assertNeverDiskEvent as $,rewriteWikiLinksForDocumentRename as $n,ALL_EDITOR_IDS as $r,incrementServerObserverFire as $t,MissingOkConfigError as A,_coercedNumber as Ai,readServerPackageVersion as An,tracedWriteFile as Ar,createStreamingErrorWriter as At,STARTER_PACK_IDS as B,registerWrite as Bn,writeTargetVersion as Br,formatAuthRejectionWire as Bt,LOG_MD_TEMPLATE as C,boolean$1 as Ci,parseAuthRejectionWire as Cn,tracedMkdir as Cr,createExternalChangeHandler as Ct,MCP_SERVER_NAME as D,object$1 as Di,planSeed as Dn,tracedRmSync as Dr,createPersistenceExtension as Dt,MCP_CONNECTION_ID_HEADER as E,number$1 as Ei,pathToDocName as En,tracedRenameSync as Er,createOsProbe as Et,SERVICE_WRITER as F,readUiLock as Fn,validateCloneInputs as Fr,errorResponse as Ft,StateManifestError as G,resolveContentDir as Gn,isInitializedNotification as Gr,getLocalDir as Gt,STATE_MANIFEST_FILENAME as H,removeLastKnownHash as Hn,McpServer as Hr,formatContributorsFrom as Ht,SKILL_INSTALL_EVENTS_FILE_REL as I,reconcile as In,validateSkillZip as Ir,evictStaleTrackerEntries as It,acquireUiLock as J,resolveLockDir as Jn,readConfigSafely as Jr,getMetrics as Jt,TagIndex as K,resolveCursorBinaryDefault as Kn,isJSONRPCRequest as Kr,getLogger as Kt,STARTER_FOLDERS as L,recordContributor as Ln,withSpan as Lr,extractWikiLinksFromMarkdown as Lt,PinoLogger as M,require_dist$2 as Mi,readStateManifest as Mn,updateLastKnownHash as Mr,detectClaudeDesktopPresence as Mt,ProjectGitInitError as N,readTargetRecordedAt as Nn,updateUiLockPort as Nr,detectProjectShape as Nt,MISSING_OK_CONFIG_MESSAGE as O,string$2 as Oi,readAllTargets as On,tracedRmdirSync as Or,createServer$1 as Ot,ROLLBACK_ORIGIN as P,readTargetVersion as Pn,validateAgentId as Pr,ensureProjectGit as Pt,assertCompatibleStateManifest as Q,rewriteMarkdownLinksForDocumentRename as Qn,MalformedGitPointerError as Qr,incrementCollabSocketFilteredError as Qt,STARTER_FOLDER_FRONTMATTER_FILENAME as R,recordSkillInstallEvent as Rn,withSpanSync as Rr,findEnclosingGitRoot as Rt,LIVE_DERIVED_INDEX_DEBOUNCE_MS as S,array as Si,normalizeFsPath as Sn,tracedLinkSync as Sr,createContentFilterAsync as St,MAX_AGENT_SESSIONS as T,looseObject as Ti,parseKeepaliveConnectionId as Tn,tracedRename as Tr,createMcpHttpHandler as Tt,SeedPrerequisiteError as U,resetMetrics as Un,JSONRPCMessageSchema as Ur,gcCheckpointRefs as Ut,STARTER_TEMPLATES as V,releaseUiLock as Vn,writeTracker as Vr,formatContributors as Vt,SeedRootDirError as W,resolveBundledSkillDir as Wn,LATEST_PROTOCOL_VERSION as Wr,getCurrentMcpLogger as Wt,applyExternalChange as X,resolvePackageVersion as Xn,writeConfigPatch as Xr,handleCollabSocketError as Xt,applyAgentMarkdownWrite as Y,resolvePack as Yn,resolveConfigPath as Yr,getTracer as Yt,applySeed as Z,restoreContributors as Zn,GitDirAccessError as Zr,handleSpawnCursor as Zt,GIT_UPSTREAM_WRITER as _,LOCAL_DIR as _i,listRescueCheckpoints as _n,startWatcher as _r,contentHash as _t,AgentPresenceBroadcaster as a,EXECUTABLE_BLOCKLIST_EXTENSIONS as ai,isAllowedApiOrigin as an,safeContentPath as ar,buildReadResult as at,HocuspocusAuthTokenSchema as b,ZodNumber$1 as bi,loggerFactory as bn,toBroadcasterKey as br,createAssetServeMiddleware as bt,BacklinkIndex as c,ProblemDetailsSchema as ci,isHocuspocusAuthRejectionReason as cn,sanitizeClientName as cr,buildWipTree as ct,CURSOR_BUNDLE_PATHS_BY_PLATFORM as d,colorFromSeed as di,isPairedWriteOrigin as dn,seedBasenameIndex as dr,clearContributors as dt,ASSET_EXTENSIONS as ei,initShadowRepo as en,runAuthReposSubprocess as er,attachIdleShutdown as et,ConfigSchema as f,defaultScheduler as fi,isPathWithinDir as fn,setActiveSpanAttributes as fr,coercePackId as ft,FILE_WATCHER_ORIGIN as g,CONFIG_SCHEMA_MAJOR_PATH as gi,lastKnownHash as gn,splitMarkdownBlocks as gr,containsConflictMarkers as gt,FILE_SYSTEM_WRITER as h,isOrphanMode as hi,isSystemDoc as hn,spawnDetached as hr,commitWipFromTree as ht,AgentFocusBroadcaster as i,EDITOR_LABELS as ii,installUserSkill as in,runWithMcpLogger as ir,buildInstructions as it,OBSERVER_SYNC_ORIGIN as j,NEVER as ji,readSkillInstallStateSnapshot as jn,tracedWriteFileSync as jr,createTestLogger as jt,McpLogger as k,url as ki,readBranchFromHead as kn,tracedUnlinkSync as kr,createServerObserverExtension as kt,CC1Broadcaster as l,SKILL_STATE_TARGETS as li,isKnownPackId as ln,saveInMemoryCheckpoint as lr,classifyEvents as lt,DEFAULT_PACK_ID as m,iconFromClientName as mi,isSelfWrite as mn,shutdownTelemetry as mr,commitWip as mt,AGENT_ID_RE as n,DEFAULT_GITHUB_OAUTH_CLIENT_ID as ni,installPrettyZodErrors as nn,runCloneSubprocess as nr,buildAndOpenSkill as nt,AgentSessionCapacityError as o,INLINE_RENDERABLE_EXTENSIONS as oi,isAllowedWorkspaceHostHeader as on,safeSubdir as or,buildSkillZip as ot,DEFAULT_CHECKPOINT_RETENTION as p,humanFormat as pi,isProjectRoot as pn,shadowGit as pr,commitUpstreamImport as pt,UiLockCollisionError as q,resolveCursorSpawnInvocation as qn,isJSONRPCResultResponse as qr,getMeter as qt,AGENT_WRITE_ORIGIN as r,DEFAULT_SERVER_HOST as ri,installTestLoggers as rn,runDeviceFlowSubprocess as rr,buildExecResult as rt,AgentSessionManager as s,ORPHAN_MODES as si,isConfigDoc as sn,safetyCheckpoint as sr,buildStarterFolderFrontmatterYaml as st,AGENT_ID_MAX_LEN as t,CC1_CONTRACT_VERSION as ti,initTelemetry as tn,runAuthStatusSubprocess as tr,bootServer as tt,CONFLICT_MARKER_RE as u,SYSTEM_DOC_NAME as ui,isLoopbackAddress as un,saveVersion as ur,classifyFsPath as ut,HOCUSPOCUS_AUTH_REJECTION_REASONS as v,OK_PROJECT_MARKER as vi,listStarterPacks as vn,streamingProblemEvent as vr,contributorCount as vt,MANAGED_RENAME_ORIGIN as w,literal as wi,parseHocuspocusAuthToken as wn,tracedMkdirSync as wr,createLiveDerivedIndexExtension as wt,INSTALLED_AGENTS_SCHEMES as x,any$1 as xi,mountMcpAndApi as xn,tracedAppendFileSync as xr,createContentFilter as xt,HocuspocusAuthRejection as y,locateIssue as yi,loadPrincipal as yn,swapContributors as yr,createApiExtension as yt,STARTER_PACKS as z,registerAllTools as zn,writeStateManifest as zr,findEnclosingProjectRoot as zt};
3074
- //# sourceMappingURL=dist-DhjzONr6.mjs.map
3231
+ //# sourceMappingURL=dist-CQVP3NVF.mjs.map
@@ -1 +1 @@
1
- import{$ as e,$n as t,$t as n,A as r,An as i,Ar as a,At as o,B as s,Bn as c,Br as l,Bt as u,C as d,Cn as f,Cr as p,Ct as m,D as h,Dn as g,Dr as _,Dt as v,E as y,En as b,Er as x,Et as S,F as C,Fn as w,Fr as T,Ft as E,G as D,Gn as O,Gt as k,H as A,Hn as j,Ht as M,I as N,In as P,Ir as F,It as I,J as L,Jn as R,Jt as z,K as B,Kn as V,Kt as H,L as U,Ln as W,Lr as G,Lt as K,M as q,Mn as J,Mr as Y,Mt as X,N as Z,Nn as Q,Nr as $,Nt as ee,O as te,On as ne,Or as re,Ot as ie,P as ae,Pn as oe,Pr as se,Pt as ce,Q as le,Qn as ue,Qr as de,Qt as fe,R as pe,Rn as me,Rr as he,Rt as ge,S as _e,Sn as ve,Sr as ye,St as be,T as xe,Tn as Se,Tr as Ce,Tt as we,U as Te,Un as Ee,Ut as De,V as Oe,Vn as ke,Vr as Ae,Vt as je,W as Me,Wn as Ne,Wt as Pe,X as Fe,Xn as Ie,Xt as Le,Y as Re,Yn as ze,Yt as Be,Z as Ve,Zn as He,Zr as Ue,Zt as We,_ as Ge,_n as Ke,_r as qe,_t as Je,a as Ye,an as Xe,ar as Ze,at as Qe,b as $e,bn as et,br as tt,bt as nt,c as rt,cn as it,cr as at,ct as ot,d as st,di as ct,dn as lt,dr as ut,dt,en as ft,er as pt,et as mt,f as ht,fn as gt,fr as _t,ft as vt,g as yt,gn as bt,gr as xt,gt as St,h as Ct,hi as wt,hn as Tt,hr as Et,ht as Dt,i as Ot,in as kt,ir as At,it as jt,j as Mt,jn as Nt,jr as Pt,jt as Ft,k as It,kn as Lt,kr as Rt,kt as zt,l as Bt,li as Vt,ln as Ht,lr as Ut,lt as Wt,m as Gt,mi as Kt,mn as qt,mr as Jt,mt as Yt,n as Xt,nn as Zt,nr as Qt,nt as $t,o as en,on as tn,or as nn,ot as rn,p as an,pn as on,pr as sn,pt as cn,q as ln,qn as un,qt as dn,r as fn,rn as pn,rr as mn,rt as hn,s as gn,si as _n,sn as vn,sr as yn,st as bn,t as xn,ti as Sn,tn as Cn,tr as wn,tt as Tn,u as En,ui as Dn,un as On,ur as kn,ut as An,v as jn,vn as Mn,vr as Nn,vt as Pn,w as Fn,wn as In,wr as Ln,wt as Rn,x as zn,xn as Bn,xr as Vn,xt as Hn,y as Un,yn as Wn,yr as Gn,yt as Kn,z as qn,zn as Jn,zr as Yn,zt as Xn}from"./dist-DhjzONr6.mjs";import{_ as Zn,a as Qn,c as $n,d as er,f as tr,g as nr,i as rr,l as ir,m as ar,n as or,o as sr,p as cr,r as lr,s as ur,t as dr,u as fr}from"./server-lock-D7DXNVql-BRVVzA6T.mjs";export{xn as AGENT_ID_MAX_LEN,Xt as AGENT_ID_RE,fn as AGENT_WRITE_ORIGIN,Ot as AgentFocusBroadcaster,Ye as AgentPresenceBroadcaster,en as AgentSessionCapacityError,gn as AgentSessionManager,rt as BacklinkIndex,Bt as CC1Broadcaster,Sn as CC1_CONTRACT_VERSION,En as CONFLICT_MARKER_RE,st as CURSOR_BUNDLE_PATHS_BY_PLATFORM,ht as ConfigSchema,an as DEFAULT_CHECKPOINT_RETENTION,Gt as DEFAULT_PACK_ID,Ct as FILE_SYSTEM_WRITER,yt as FILE_WATCHER_ORIGIN,Ge as GIT_UPSTREAM_WRITER,Ue as GitDirAccessError,jn as HOCUSPOCUS_AUTH_REJECTION_REASONS,Un as HocuspocusAuthRejection,$e as HocuspocusAuthTokenSchema,zn as INSTALLED_AGENTS_SCHEMES,_e as LIVE_DERIVED_INDEX_DEBOUNCE_MS,d as LOG_MD_TEMPLATE,Fn as MANAGED_RENAME_ORIGIN,xe as MAX_AGENT_SESSIONS,y as MCP_CONNECTION_ID_HEADER,h as MCP_SERVER_NAME,te as MISSING_OK_CONFIG_MESSAGE,de as MalformedGitPointerError,It as McpLogger,r as MissingOkConfigError,Mt as OBSERVER_SYNC_ORIGIN,_n as ORPHAN_MODES,q as PinoLogger,dr as ProcessLockCollisionError,Z as ProjectGitInitError,ae as ROLLBACK_ORIGIN,or as RUNTIME_VERSION,C as SERVICE_WRITER,N as SKILL_INSTALL_EVENTS_FILE_REL,Vt as SKILL_STATE_TARGETS,U as STARTER_FOLDERS,pe as STARTER_FOLDER_FRONTMATTER_FILENAME,qn as STARTER_PACKS,s as STARTER_PACK_IDS,Oe as STARTER_TEMPLATES,A as STATE_MANIFEST_FILENAME,lr as STATE_SCHEMA_VERSION,Dn as SYSTEM_DOC_NAME,Te as SeedPrerequisiteError,Me as SeedRootDirError,rr as ServerLockCollisionError,D as StateManifestError,B as TagIndex,ln as UiLockCollisionError,Qn as acquireProcessLock,sr as acquireServerLock,L as acquireUiLock,Re as applyAgentMarkdownWrite,Fe as applyExternalChange,Ve as applySeed,le as assertCompatibleStateManifest,e as assertNeverDiskEvent,mt as attachIdleShutdown,Tn as bootServer,$t as buildAndOpenSkill,hn as buildExecResult,jt as buildInstructions,Qe as buildReadResult,rn as buildSkillZip,bn as buildStarterFolderFrontmatterYaml,ot as buildWipTree,Wt as classifyEvents,An as classifyFsPath,dt as clearContributors,vt as coercePackId,ct as colorFromSeed,cn as commitUpstreamImport,Yt as commitWip,Dt as commitWipFromTree,St as containsConflictMarkers,Je as contentHash,Pn as contributorCount,Kn as createApiExtension,nt as createAssetServeMiddleware,Hn as createContentFilter,be as createContentFilterAsync,m as createExternalChangeHandler,Rn as createLiveDerivedIndexExtension,we as createMcpHttpHandler,S as createOsProbe,v as createPersistenceExtension,ie as createServer,zt as createServerObserverExtension,o as createStreamingErrorWriter,Ft as createTestLogger,X as detectClaudeDesktopPresence,ee as detectProjectShape,ce as ensureProjectGit,E as errorResponse,I as evictStaleTrackerEntries,K as extractWikiLinksFromMarkdown,ge as findEnclosingGitRoot,Xn as findEnclosingProjectRoot,u as formatAuthRejectionWire,je as formatContributors,M as formatContributorsFrom,De as gcCheckpointRefs,Pe as getCurrentMcpLogger,k as getLocalDir,H as getLogger,dn as getMeter,z as getMetrics,Be as getTracer,Le as handleCollabSocketError,We as handleSpawnCursor,Kt as iconFromClientName,fe as incrementCollabSocketFilteredError,n as incrementServerObserverFire,ft as initShadowRepo,Cn as initTelemetry,Zt as installPrettyZodErrors,pn as installTestLoggers,kt as installUserSkill,Xe as isAllowedApiOrigin,tn as isAllowedWorkspaceHostHeader,vn as isConfigDoc,it as isHocuspocusAuthRejectionReason,Ht as isKnownPackId,On as isLoopbackAddress,wt as isOrphanMode,lt as isPairedWriteOrigin,gt as isPathWithinDir,ur as isProcessAlive,on as isProjectRoot,qt as isSelfWrite,Tt as isSystemDoc,$n as isValidLockPid,bt as lastKnownHash,Ke as listRescueCheckpoints,Mn as listStarterPacks,Wn as loadPrincipal,ir as lockFilePath,et as loggerFactory,Bn as mountMcpAndApi,ve as normalizeFsPath,f as parseAuthRejectionWire,In as parseHocuspocusAuthToken,Se as parseKeepaliveConnectionId,b as pathToDocName,g as planSeed,ne as readAllTargets,Lt as readBranchFromHead,fr as readProcessLock,er as readProcessLockDetailed,tr as readServerLock,i as readServerPackageVersion,Nt as readSkillInstallStateSnapshot,J as readStateManifest,Q as readTargetRecordedAt,oe as readTargetVersion,w as readUiLock,P as reconcile,W as recordContributor,me as recordSkillInstallEvent,Jn as registerAllTools,c as registerWrite,cr as releaseProcessLock,ar as releaseServerLock,ke as releaseUiLock,j as removeLastKnownHash,Ee as resetMetrics,Ne as resolveBundledSkillDir,O as resolveContentDir,V as resolveCursorBinaryDefault,un as resolveCursorSpawnInvocation,R as resolveLockDir,ze as resolvePack,Ie as resolvePackageVersion,He as restoreContributors,ue as rewriteMarkdownLinksForDocumentRename,t as rewriteWikiLinksForDocumentRename,pt as runAuthReposSubprocess,wn as runAuthStatusSubprocess,Qt as runCloneSubprocess,mn as runDeviceFlowSubprocess,At as runWithMcpLogger,Ze as safeContentPath,nn as safeSubdir,yn as safetyCheckpoint,at as sanitizeClientName,Ut as saveInMemoryCheckpoint,kn as saveVersion,ut as seedBasenameIndex,_t as setActiveSpanAttributes,sn as shadowGit,Jt as shutdownTelemetry,Et as spawnDetached,xt as splitMarkdownBlocks,qe as startWatcher,Nn as streamingProblemEvent,Gn as swapContributors,tt as toBroadcasterKey,Vn as tracedAppendFileSync,ye as tracedLinkSync,p as tracedMkdir,Ln as tracedMkdirSync,Ce as tracedRename,x as tracedRenameSync,_ as tracedRmSync,re as tracedRmdirSync,Rt as tracedUnlinkSync,a as tracedWriteFile,Pt as tracedWriteFileSync,Y as updateLastKnownHash,nr as updateProcessLockPort,Zn as updateServerLockPort,$ as updateUiLockPort,se as validateAgentId,T as validateCloneInputs,F as validateSkillZip,G as withSpan,he as withSpanSync,Yn as writeStateManifest,l as writeTargetVersion,Ae as writeTracker};
1
+ import{$ as e,$n as t,$t as n,A as r,An as i,Ar as a,At as o,B as s,Bn as c,Br as l,Bt as u,C as d,Cn as f,Cr as p,Ct as m,D as h,Dn as g,Dr as _,Dt as v,E as y,En as b,Er as x,Et as S,F as C,Fn as w,Fr as T,Ft as E,G as D,Gn as O,Gt as k,H as A,Hn as j,Ht as M,I as N,In as P,Ir as F,It as I,J as L,Jn as R,Jt as z,K as B,Kn as V,Kt as H,L as U,Ln as W,Lr as G,Lt as K,M as q,Mn as J,Mr as Y,Mt as X,N as Z,Nn as Q,Nr as $,Nt as ee,O as te,On as ne,Or as re,Ot as ie,P as ae,Pn as oe,Pr as se,Pt as ce,Q as le,Qn as ue,Qr as de,Qt as fe,R as pe,Rn as me,Rr as he,Rt as ge,S as _e,Sn as ve,Sr as ye,St as be,T as xe,Tn as Se,Tr as Ce,Tt as we,U as Te,Un as Ee,Ut as De,V as Oe,Vn as ke,Vr as Ae,Vt as je,W as Me,Wn as Ne,Wt as Pe,X as Fe,Xn as Ie,Xt as Le,Y as Re,Yn as ze,Yt as Be,Z as Ve,Zn as He,Zr as Ue,Zt as We,_ as Ge,_n as Ke,_r as qe,_t as Je,a as Ye,an as Xe,ar as Ze,at as Qe,b as $e,bn as et,br as tt,bt as nt,c as rt,cn as it,cr as at,ct as ot,d as st,di as ct,dn as lt,dr as ut,dt,en as ft,er as pt,et as mt,f as ht,fn as gt,fr as _t,ft as vt,g as yt,gn as bt,gr as xt,gt as St,h as Ct,hi as wt,hn as Tt,hr as Et,ht as Dt,i as Ot,in as kt,ir as At,it as jt,j as Mt,jn as Nt,jr as Pt,jt as Ft,k as It,kn as Lt,kr as Rt,kt as zt,l as Bt,li as Vt,ln as Ht,lr as Ut,lt as Wt,m as Gt,mi as Kt,mn as qt,mr as Jt,mt as Yt,n as Xt,nn as Zt,nr as Qt,nt as $t,o as en,on as tn,or as nn,ot as rn,p as an,pn as on,pr as sn,pt as cn,q as ln,qn as un,qt as dn,r as fn,rn as pn,rr as mn,rt as hn,s as gn,si as _n,sn as vn,sr as yn,st as bn,t as xn,ti as Sn,tn as Cn,tr as wn,tt as Tn,u as En,ui as Dn,un as On,ur as kn,ut as An,v as jn,vn as Mn,vr as Nn,vt as Pn,w as Fn,wn as In,wr as Ln,wt as Rn,x as zn,xn as Bn,xr as Vn,xt as Hn,y as Un,yn as Wn,yr as Gn,yt as Kn,z as qn,zn as Jn,zr as Yn,zt as Xn}from"./dist-CQVP3NVF.mjs";import{_ as Zn,a as Qn,c as $n,d as er,f as tr,g as nr,i as rr,l as ir,m as ar,n as or,o as sr,p as cr,r as lr,s as ur,t as dr,u as fr}from"./server-lock-D7DXNVql-BRVVzA6T.mjs";export{xn as AGENT_ID_MAX_LEN,Xt as AGENT_ID_RE,fn as AGENT_WRITE_ORIGIN,Ot as AgentFocusBroadcaster,Ye as AgentPresenceBroadcaster,en as AgentSessionCapacityError,gn as AgentSessionManager,rt as BacklinkIndex,Bt as CC1Broadcaster,Sn as CC1_CONTRACT_VERSION,En as CONFLICT_MARKER_RE,st as CURSOR_BUNDLE_PATHS_BY_PLATFORM,ht as ConfigSchema,an as DEFAULT_CHECKPOINT_RETENTION,Gt as DEFAULT_PACK_ID,Ct as FILE_SYSTEM_WRITER,yt as FILE_WATCHER_ORIGIN,Ge as GIT_UPSTREAM_WRITER,Ue as GitDirAccessError,jn as HOCUSPOCUS_AUTH_REJECTION_REASONS,Un as HocuspocusAuthRejection,$e as HocuspocusAuthTokenSchema,zn as INSTALLED_AGENTS_SCHEMES,_e as LIVE_DERIVED_INDEX_DEBOUNCE_MS,d as LOG_MD_TEMPLATE,Fn as MANAGED_RENAME_ORIGIN,xe as MAX_AGENT_SESSIONS,y as MCP_CONNECTION_ID_HEADER,h as MCP_SERVER_NAME,te as MISSING_OK_CONFIG_MESSAGE,de as MalformedGitPointerError,It as McpLogger,r as MissingOkConfigError,Mt as OBSERVER_SYNC_ORIGIN,_n as ORPHAN_MODES,q as PinoLogger,dr as ProcessLockCollisionError,Z as ProjectGitInitError,ae as ROLLBACK_ORIGIN,or as RUNTIME_VERSION,C as SERVICE_WRITER,N as SKILL_INSTALL_EVENTS_FILE_REL,Vt as SKILL_STATE_TARGETS,U as STARTER_FOLDERS,pe as STARTER_FOLDER_FRONTMATTER_FILENAME,qn as STARTER_PACKS,s as STARTER_PACK_IDS,Oe as STARTER_TEMPLATES,A as STATE_MANIFEST_FILENAME,lr as STATE_SCHEMA_VERSION,Dn as SYSTEM_DOC_NAME,Te as SeedPrerequisiteError,Me as SeedRootDirError,rr as ServerLockCollisionError,D as StateManifestError,B as TagIndex,ln as UiLockCollisionError,Qn as acquireProcessLock,sr as acquireServerLock,L as acquireUiLock,Re as applyAgentMarkdownWrite,Fe as applyExternalChange,Ve as applySeed,le as assertCompatibleStateManifest,e as assertNeverDiskEvent,mt as attachIdleShutdown,Tn as bootServer,$t as buildAndOpenSkill,hn as buildExecResult,jt as buildInstructions,Qe as buildReadResult,rn as buildSkillZip,bn as buildStarterFolderFrontmatterYaml,ot as buildWipTree,Wt as classifyEvents,An as classifyFsPath,dt as clearContributors,vt as coercePackId,ct as colorFromSeed,cn as commitUpstreamImport,Yt as commitWip,Dt as commitWipFromTree,St as containsConflictMarkers,Je as contentHash,Pn as contributorCount,Kn as createApiExtension,nt as createAssetServeMiddleware,Hn as createContentFilter,be as createContentFilterAsync,m as createExternalChangeHandler,Rn as createLiveDerivedIndexExtension,we as createMcpHttpHandler,S as createOsProbe,v as createPersistenceExtension,ie as createServer,zt as createServerObserverExtension,o as createStreamingErrorWriter,Ft as createTestLogger,X as detectClaudeDesktopPresence,ee as detectProjectShape,ce as ensureProjectGit,E as errorResponse,I as evictStaleTrackerEntries,K as extractWikiLinksFromMarkdown,ge as findEnclosingGitRoot,Xn as findEnclosingProjectRoot,u as formatAuthRejectionWire,je as formatContributors,M as formatContributorsFrom,De as gcCheckpointRefs,Pe as getCurrentMcpLogger,k as getLocalDir,H as getLogger,dn as getMeter,z as getMetrics,Be as getTracer,Le as handleCollabSocketError,We as handleSpawnCursor,Kt as iconFromClientName,fe as incrementCollabSocketFilteredError,n as incrementServerObserverFire,ft as initShadowRepo,Cn as initTelemetry,Zt as installPrettyZodErrors,pn as installTestLoggers,kt as installUserSkill,Xe as isAllowedApiOrigin,tn as isAllowedWorkspaceHostHeader,vn as isConfigDoc,it as isHocuspocusAuthRejectionReason,Ht as isKnownPackId,On as isLoopbackAddress,wt as isOrphanMode,lt as isPairedWriteOrigin,gt as isPathWithinDir,ur as isProcessAlive,on as isProjectRoot,qt as isSelfWrite,Tt as isSystemDoc,$n as isValidLockPid,bt as lastKnownHash,Ke as listRescueCheckpoints,Mn as listStarterPacks,Wn as loadPrincipal,ir as lockFilePath,et as loggerFactory,Bn as mountMcpAndApi,ve as normalizeFsPath,f as parseAuthRejectionWire,In as parseHocuspocusAuthToken,Se as parseKeepaliveConnectionId,b as pathToDocName,g as planSeed,ne as readAllTargets,Lt as readBranchFromHead,fr as readProcessLock,er as readProcessLockDetailed,tr as readServerLock,i as readServerPackageVersion,Nt as readSkillInstallStateSnapshot,J as readStateManifest,Q as readTargetRecordedAt,oe as readTargetVersion,w as readUiLock,P as reconcile,W as recordContributor,me as recordSkillInstallEvent,Jn as registerAllTools,c as registerWrite,cr as releaseProcessLock,ar as releaseServerLock,ke as releaseUiLock,j as removeLastKnownHash,Ee as resetMetrics,Ne as resolveBundledSkillDir,O as resolveContentDir,V as resolveCursorBinaryDefault,un as resolveCursorSpawnInvocation,R as resolveLockDir,ze as resolvePack,Ie as resolvePackageVersion,He as restoreContributors,ue as rewriteMarkdownLinksForDocumentRename,t as rewriteWikiLinksForDocumentRename,pt as runAuthReposSubprocess,wn as runAuthStatusSubprocess,Qt as runCloneSubprocess,mn as runDeviceFlowSubprocess,At as runWithMcpLogger,Ze as safeContentPath,nn as safeSubdir,yn as safetyCheckpoint,at as sanitizeClientName,Ut as saveInMemoryCheckpoint,kn as saveVersion,ut as seedBasenameIndex,_t as setActiveSpanAttributes,sn as shadowGit,Jt as shutdownTelemetry,Et as spawnDetached,xt as splitMarkdownBlocks,qe as startWatcher,Nn as streamingProblemEvent,Gn as swapContributors,tt as toBroadcasterKey,Vn as tracedAppendFileSync,ye as tracedLinkSync,p as tracedMkdir,Ln as tracedMkdirSync,Ce as tracedRename,x as tracedRenameSync,_ as tracedRmSync,re as tracedRmdirSync,Rt as tracedUnlinkSync,a as tracedWriteFile,Pt as tracedWriteFileSync,Y as updateLastKnownHash,nr as updateProcessLockPort,Zn as updateServerLockPort,$ as updateUiLockPort,se as validateAgentId,T as validateCloneInputs,F as validateSkillZip,G as withSpan,he as withSpanSync,Yn as writeStateManifest,l as writeTargetVersion,Ae as writeTracker};
package/dist/index.mjs CHANGED
@@ -1 +1 @@
1
- import{_ as e,d as t,h as n,l as r,m as i,o as a,p as o,r as s,t as c,u as l,v as u}from"./init-cHZ7jSx2.mjs";import{i as d,n as f,r as p,t as m}from"./src-cHFxGZkG.mjs";import{n as h}from"./loader-Df-P6GSV.mjs";import{n as g}from"./preview-jzPJ1Cbd.mjs";export{o as ALL_EDITOR_IDS,i as EDITOR_LABELS,n as EDITOR_TARGETS,c as LAUNCH_CONFIG_NAME,s as detectInstalledEditors,u as initContent,h as loadConfig,p as parseGitHubBlobUrl,d as parseGitUrl,g as previewContent,a as readExistingMcpEntry,e as resolveProjectRoot,r as scaffoldLaunchJson,f as validateLocalFolderForShare,l as writeEditorMcpConfig,m as writeProjectAiIntegrations,t as writeUserMcpConfigs};
1
+ import{_ as e,d as t,h as n,l as r,m as i,o as a,p as o,r as s,t as c,u as l,v as u}from"./init-DqApv-bY.mjs";import{i as d,n as f,r as p,t as m}from"./src-BUH_zaQF.mjs";import{n as h}from"./loader-DXesUuxk.mjs";import{n as g}from"./preview-CGp3adCc.mjs";export{o as ALL_EDITOR_IDS,i as EDITOR_LABELS,n as EDITOR_TARGETS,c as LAUNCH_CONFIG_NAME,s as detectInstalledEditors,u as initContent,h as loadConfig,p as parseGitHubBlobUrl,d as parseGitUrl,g as previewContent,a as readExistingMcpEntry,e as resolveProjectRoot,r as scaffoldLaunchJson,f as validateLocalFolderForShare,l as writeEditorMcpConfig,m as writeProjectAiIntegrations,t as writeUserMcpConfigs};
@@ -0,0 +1 @@
1
+ import{c as e}from"./init-DqApv-bY.mjs";export{e as runInit};