@inkeep/open-knowledge 0.5.0-beta.16 → 0.5.0-beta.18
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/assets/skills/open-knowledge/SKILL.md +1 -1
- package/dist/cli.mjs +38 -38
- package/dist/constants-B4KnJDAZ.mjs +2 -0
- package/dist/{dist-D5J2z1mI.mjs → dist-Be0To_ZO.mjs} +1 -1
- package/dist/{dist-V31CRf7D.mjs → dist-pXZHJhkA.mjs} +6 -6
- package/dist/index.mjs +1 -1
- package/dist/{init-Db-MJvF_.mjs → init-CJjj7SKR.mjs} +4 -4
- package/dist/init-CS6mOIgn.mjs +1 -0
- package/dist/loader-H7wE7QNZ.mjs +1 -0
- package/dist/{loader-BF1HVIAE.mjs → loader-muqLro6E.mjs} +2 -2
- package/dist/preview-BeYDA-OZ.mjs +1 -0
- package/dist/{preview-qR7FFUro.mjs → preview-viMhTOSc.mjs} +2 -2
- package/dist/public/assets/ActivityModeContent-BzC9xwru.js +2 -0
- package/dist/public/assets/{ConsentDialogBody-BYenkRKt.js → ConsentDialogBody-BpM_eICS.js} +1 -1
- package/dist/public/assets/DocumentContext-DEXQEbv8.js +52 -0
- package/dist/public/assets/{GraphPanel-DwQX9Gl9.js → GraphPanel-D39O3dBN.js} +3 -3
- package/dist/public/assets/{McpConsentDialogBody-CEvkljQ2.js → McpConsentDialogBody-BDYRADff.js} +1 -1
- package/dist/public/assets/SettingsDialog-CO7dzaPy.js +11 -0
- package/dist/public/assets/{SourceEditor-CSsFAy0n.js → SourceEditor-DRa5FCh7.js} +2 -2
- package/dist/public/assets/{agent-presence-BrTlNKmt.js → agent-presence-Beup8CI-.js} +1 -1
- package/dist/public/assets/button-B-xLb7H7.js +1 -0
- package/dist/public/assets/config-validation-events-D8UOvZmc.js +10 -0
- package/dist/public/assets/dialog-BcU1169q.js +45 -0
- package/dist/public/assets/{dist-Bej94Urx.js → dist-DETlERpz.js} +1 -1
- package/dist/public/assets/{dist-Cg-Qaqw_.js → dist-mowPQv9h.js} +1 -1
- package/dist/public/assets/{doc-hash-kxo-uZOQ.js → doc-hash-DRRChZD7.js} +51 -51
- package/dist/public/assets/index-C4KiMV-Z.js +1853 -0
- package/dist/public/assets/index-C5eHVirw.css +1 -0
- package/dist/public/assets/{input-hZk8Tm0e.js → input-UWVR4RR-.js} +1 -1
- package/dist/public/assets/{label-Dv_9VZWz.js → label-D7TT13L_.js} +1 -1
- package/dist/public/assets/mcp-consent-store-QV8NF9CY.js +1 -0
- package/dist/public/assets/{panel-8fydlQgn.js → panel-D9tzSGAf.js} +1 -1
- package/dist/public/assets/{target-navigation-intent-Bc974sw4.js → target-navigation-intent-3OGuOhN2.js} +1 -1
- package/dist/public/assets/{textarea-gXd-JXvQ.js → textarea-2wg2OyKW.js} +1 -1
- package/dist/public/assets/toggle-group-Ba3po_CE.js +1 -0
- package/dist/public/assets/tooltip-BuhzbWzZ.js +1 -0
- package/dist/public/assets/{typing-burst-detector-D-ghtRdu.js → typing-burst-detector-KTL86FBm.js} +1 -1
- package/dist/public/index.html +19 -19
- package/dist/{repair-mcp-configs-DUU6zN1U.mjs → repair-mcp-configs-BeZWSiY1.mjs} +2 -2
- package/dist/{src-DzWkP5Kf.mjs → src-ct_-cWOI.mjs} +2 -2
- package/dist/start-CC-R8Mvd.mjs +1 -0
- package/dist/{start-DivgyWbO.mjs → start-ClRV9jYM.mjs} +2 -2
- package/package.json +1 -1
- package/dist/constants-XCszYh-u.mjs +0 -2
- package/dist/init-De5O5Atd.mjs +0 -1
- package/dist/loader-C1hxiMbK.mjs +0 -1
- package/dist/preview-N6-E_vFx.mjs +0 -1
- package/dist/public/assets/ActivityModeContent-BMLTkwc9.js +0 -2
- package/dist/public/assets/DocumentContext-BIHXIA3J.js +0 -52
- package/dist/public/assets/SettingsDialog-x6fsBA_3.js +0 -11
- package/dist/public/assets/button-C1nwPVFQ.js +0 -1
- package/dist/public/assets/config-validation-events-DCCNVo39.js +0 -10
- package/dist/public/assets/dialog-Blv3p5PJ.js +0 -45
- package/dist/public/assets/index-B3_TwSZA.css +0 -1
- package/dist/public/assets/index-BXFJIE7O.js +0 -1853
- package/dist/public/assets/mcp-consent-store-DZ1pCmhN.js +0 -1
- package/dist/public/assets/toggle-group-KbPGx9kK.js +0 -1
- package/dist/public/assets/tooltip-C-s5R-Gs.js +0 -1
- package/dist/start-D6YbKWO-.mjs +0 -1
|
@@ -1199,7 +1199,7 @@ Karpathy's insight: "The tedious part of maintaining a knowledge base is not the
|
|
|
1199
1199
|
`).replaceAll(`\r`,`
|
|
1200
1200
|
`).split(`
|
|
1201
1201
|
`),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===`local`?`--local`:`--global`,t],{cwd:e,encoding:`utf-8`,timeout:5e3});return w.status!==0||!w.stdout?null:w.stdout.trim()||null};async function resolveGitIdentity(e,t,S,w=defaultGitConfigReader){let E=w(e,`user.name`,`local`),D=w(e,`user.email`,`local`);if(E&&D)return{name:E,email:D};let O=w(e,`user.name`,`global`),k=w(e,`user.email`,`global`);if(O&&k)return{name:O,email:k};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=(t,S)=>{let w=spawnSync(`git`,[`config`,`--local`,t,S],{cwd:e,encoding:`utf-8`,timeout:5e3});if(w.status!==0){let e=w.stderr?.trim()??``;throw Error(`git config --local ${t} failed: ${e}`)}};w(`user.name`,t),w(`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(`
|
|
1202
|
-
`);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;return w.authenticated===!0&&typeof w.login==`string`?{authenticated:!0,host:E,login:w.login,name:typeof w.name==`string`?w.name:void 0,email:typeof w.email==`string`?w.email:void 0}:{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. 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:`---
|
|
1202
|
+
`);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. 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:`---
|
|
1203
1203
|
title: External Source
|
|
1204
1204
|
description: Capture a URL, PDF, or referenced file verbatim. Update title to match the actual source after instantiation.
|
|
1205
1205
|
source:
|
|
@@ -2268,7 +2268,7 @@ tags: [travel]
|
|
|
2268
2268
|
`).filter(e=>e.length===40);ne.push(...e)}catch{}let se=[];if(oe)try{se=(await te.raw(`for-each-ref`,`--format=%(objectname)`,`refs/checkpoints/main/`)).trim().split(`
|
|
2269
2269
|
`).filter(e=>e.length===40)}catch{}try{let e=(await te.raw(`for-each-ref`,`--format=%(refname)`,`refs/wip/${E}/`)).trim().split(`
|
|
2270
2270
|
`).filter(Boolean);ae.push(...e)}catch{}if(oe&&ae.length===0)try{let e=(await te.raw(`for-each-ref`,`--format=%(refname)`,`refs/wip/main/`)).trim().split(`
|
|
2271
|
-
`).filter(Boolean);ae.push(...e)}catch{}if(ae.length===0&&ne.length===0&&se.length===0)return EMPTY;let ce=[...ne,...se],ue=[];if(ce.length>0){let t=parseGitLogOutput(await te.raw(`log`,`--no-walk`,`--author-date-order`,`--format=${GIT_LOG_FORMAT}`,...ce)).map(e=>({...e,type:`checkpoint`}));if(H&&(t=await filterEntriesByChain(e,t,L,E,B,ee,Y)),oe&&ne.length>0&&se.length>0){let e=new Set(ne),S=t.filter(t=>e.has(t.sha)),w=t.filter(t=>!e.has(t.sha)),E=S.reduce((e,t)=>{let S=new Date(t.timestamp).getTime();return S<e?S:e},1/0);ue=[...S,...w.filter(e=>new Date(e.timestamp).getTime()<E)]}else ue=t}let de=[...ae];for(let e of ce)de.push(e);let fe=[];if(de.length>0&&(fe=parseGitLogOutput(await te.raw(`log`,`--full-history`,`--author-date-order`,`--format=${GIT_LOG_FORMAT}`,...de,...H?[`--`,H]:[])),J))for(let t=0;t<L.length-1;t++){let S=L[t];if(S.renameCommit!==null)try{let t=await buildSeeds(e,S.renameCommit,E,Y);if(t.length===0)continue;let w=B(S.path),D=await logSeededReachable(e,[`--full-history`,`--author-date-order`,`--format=${GIT_LOG_FORMAT}`],t,w);fe=[...fe,...parseGitLogOutput(D)]}catch(e){console.warn(`[timeline] predecessor walk failed for step ${t} (${S.path}); skipping:`,e)}}let me=[...ue,...fe],ge=new Set,_e=[];for(let e of me)ge.has(e.sha)||(ge.add(e.sha),_e.push(e));let ve=_e;
|
|
2271
|
+
`).filter(Boolean);ae.push(...e)}catch{}if(ae.length===0&&ne.length===0&&se.length===0)return EMPTY;let ce=[...ne,...se],ue=[];if(ce.length>0){let t=parseGitLogOutput(await te.raw(`log`,`--no-walk`,`--author-date-order`,`--format=${GIT_LOG_FORMAT}`,...ce)).map(e=>({...e,type:`checkpoint`}));if(H&&(t=await filterEntriesByChain(e,t,L,E,B,ee,Y)),oe&&ne.length>0&&se.length>0){let e=new Set(ne),S=t.filter(t=>e.has(t.sha)),w=t.filter(t=>!e.has(t.sha)),E=S.reduce((e,t)=>{let S=new Date(t.timestamp).getTime();return S<e?S:e},1/0);ue=[...S,...w.filter(e=>new Date(e.timestamp).getTime()<E)]}else ue=t}let de=[...ae];for(let e of ce)de.push(e);let fe=[];if(de.length>0&&(fe=parseGitLogOutput(await te.raw(`log`,`--full-history`,`--author-date-order`,`--format=${GIT_LOG_FORMAT}`,...de,...H?[`--`,H]:[])),J))for(let t=0;t<L.length-1;t++){let S=L[t];if(S.renameCommit!==null)try{let t=await buildSeeds(e,S.renameCommit,E,Y);if(t.length===0)continue;let w=B(S.path),D=await logSeededReachable(e,[`--full-history`,`--author-date-order`,`--format=${GIT_LOG_FORMAT}`],t,w);fe=[...fe,...parseGitLogOutput(D)]}catch(e){console.warn(`[timeline] predecessor walk failed for step ${t} (${S.path}); skipping:`,e)}}let me=[...ue,...fe],ge=new Set,_e=[];for(let e of me)ge.has(e.sha)||(ge.add(e.sha),_e.push(e));let ve=_e;_e.length>0&&L.length>0&&(ve=filterEntriesByOkActorDocs(_e,L,await Promise.all(L.map(async t=>{if(t.renameCommit===null)return null;let S=await buildSeeds(e,t.renameCommit,E,Y);return S.length===0?new Set:buildAncestorShaSet(e,S,E,ee)})))),ve.sort((e,t)=>new Date(t.timestamp).getTime()-new Date(e.timestamp).getTime());let ye=ve;ye=ye.filter(e=>e.type!==`park`),k.length>0&&(ye=ye.filter(e=>k.includes(e.type))),j.length>0&&(ye=ye.filter(e=>matchesAuthor(e,j))),F.length>0&&(ye=ye.filter(e=>!matchesAuthor(e,F)));let Ce=ye.length;return{entries:ye.slice(O,O+D).map(({rawBody:e,...t})=>t),total:Ce,hasMore:O+D<Ce}}catch(e){return console.warn(`[timeline] getDocumentHistory failed, returning empty result:`,e),EMPTY}}let _httpDurationHist=null;function httpDurationHist(){return _httpDurationHist||=getMeter().createHistogram(`http.server.request.duration`,{description:`HTTP server request duration in seconds`,unit:`s`}),_httpDurationHist}let _hintEmittedCounter=null;function hintEmittedCounter(){return _hintEmittedCounter||=getMeter().createCounter(`ok.preview_attach.hint_emitted`,{description:`Count of attach-preview-once hints emitted on write-tool responses when no editor is attached to __system__`}),_hintEmittedCounter}let _agentPatchFmTouchCounter=null;function agentPatchFmTouchCounter(){return _agentPatchFmTouchCounter||=getMeter().createCounter(`ok.frontmatter.agent_patch_fm_touch_total`,{description:`Count of agent-patch calls whose find string targets the frontmatter region. Measures incidence during the soft-deprecation window before agent-patch FM-intersecting calls are enforced as 400. Bounded label: result ∈ {rejected, pre_deprecation_passthrough}.`}),_agentPatchFmTouchCounter}function findLooksLikeFrontmatter(e){return!!(/(^|\n)---(\s|\n|$)/.test(e)||/^\s*[\w-]+:\s+\S/.test(e))}let _renameAttributionCounter=null;function renameAttributionCounter(){return _renameAttributionCounter||=getMeter().createCounter(`ok.rename.attribution_kind`,{description:`Count of rename and rollback handler dispatches by attribution kind (agent | principal | anonymous)`}),_renameAttributionCounter}const ROLLBACK_ORIGIN={source:`local`,skipStoreHooks:!1,context:{origin:`rollback-apply`,paired:!0}},MANAGED_RENAME_ORIGIN={source:`local`,skipStoreHooks:!1,context:{origin:`managed-rename`,paired:!0}},log$2=getLogger(`api`);function safeDocPath(e,t){if(!e||e.includes(`..`)||e.includes(`\0`))return{error:`Invalid document name.`};let S=t===`.`?``:t.replace(/^\.\//,``),w=getDocExtension(e);return{path:S?`${S}/${e}${w}`:`${e}${w}`}}const GENERIC_PASTE_NAMES=/^(image\.(png|jpe?g|gif|webp)|Clipboard.*|Untitled.*)$/i,SAFE_FILENAME_CHARS=/[^\p{L}\p{N}\p{M}\p{Extended_Pictographic}.\-_ ]/gu,STRIP_ON_SIGHT=/[/\\\x00-\x1f\x7f]/g;function sanitizeFilename(e){let t=e.replace(STRIP_ON_SIGHT,``);if(t=t.replace(SAFE_FILENAME_CHARS,`_`),t=t.replace(/_+/g,`_`).replace(/\.{2,}/g,`.`),t=t.replace(/^[._]+/,``),t=t.replace(/\.+$/,``),t===``)return`upload`;let S=255,w=new TextEncoder;if(w.encode(t).length>255){let e=t.lastIndexOf(`.`),S=e>=0?t.slice(e):``,E=e>=0?t.slice(0,e):t;for(;w.encode(E+S).length>255&&E.length>0;)E=E.slice(0,-1);t=(E||`upload`)+S,w.encode(t).length>255&&(t=`upload`)}return t}function resolveUploadDestDir(e,t,S){let w=t.trim();return w===``||w===`./`?resolve(S,dirname(e)):w===`/`?S:w.startsWith(`./`)?resolve(S,dirname(e),w.slice(2)):resolve(S,w)}function readTempFileHead(e,t){let S=openSync(e,`r`);try{let e=Buffer.alloc(t),w=readSync(S,e,0,t,0);return e.subarray(0,w)}finally{closeSync(S)}}const MAX_DEDUP_SCAN_CANDIDATES=1e3;async function streamingHashFile(e){let t=createHash(`sha256`);return await pipeline(createReadStream(e),t),t.digest(`hex`)}async function findDuplicateAsset(e,t,S){let w;try{w=await readdir(e)}catch{return null}let E=getLogger(`upload`),D=0;for(let O of w){let w=extname(O).slice(1).toLowerCase();if(!ASSET_EXTENSIONS.has(w))continue;let k=resolve(e,O),j;try{j=await stat$1(k)}catch{continue}if(!j.isFile()||j.size!==S)continue;if(D++,D>MAX_DEDUP_SCAN_CANDIDATES)return E.warn({event:`upload-dedup-skip`,reason:`scan-cap-exceeded`,destDir:e,scanned:MAX_DEDUP_SCAN_CANDIDATES,expectedSize:S},`[upload-dedup] candidate scan exceeded ${MAX_DEDUP_SCAN_CANDIDATES} same-size siblings — degrading to no-dedup for this upload`),null;let F;try{F=await streamingHashFile(k)}catch(e){let t=e.code;t!==`ENOENT`&&E.warn({event:`upload-dedup-skip`,reason:`read-failed`,code:t,entry:O},`[upload-dedup] skipped candidate — read failed`);continue}if(F===t)return O}return null}function readUploadBody(e,t){return new Promise((S,w)=>{let E;try{E=(0,import_lib.default)({headers:e.headers,limits:{files:1,fields:10,fieldSize:2*1024}})}catch(e){w(new UploadWriteError(`urn:ok:error:malformed-upload`,e));return}let D=!1,O=`upload`,k=``,j=``,F,L,B=!1,H=(e,t)=>{if(!D){if(D=!0,F)try{unlinkSync(F)}catch{}w(t instanceof UploadWriteError?t:new UploadWriteError(e,t))}},q=classifyUploadErrno;E.on(`field`,(e,t)=>{e===`parentDocName`&&(j=t)}),E.on(`file`,(e,w,E)=>{B=!0,O=E.filename||`upload`,k=E.mimeType||``;let J;try{J=mintTempUploadPath(t)}catch(e){H(q(e),e),w.resume();return}F=J;let Y=new HashingPassThrough;pipeline(w,Y,createWriteStream(J)).then(()=>{D||(D=!0,S({filename:O,mimeType:k,parentDocName:j,tempPath:J,sha:Y.digest(),byteLength:Y.byteLength()}))}).catch(e=>{L=e,H(q(e),e)})}),E.on(`error`,e=>{H(`urn:ok:error:malformed-upload`,e)}),E.on(`close`,()=>{D||L||B||(D=!0,S({filename:``,mimeType:``,parentDocName:j,tempPath:``,sha:``,byteLength:0}))}),e.on(`close`,()=>{D||L||e.complete||H(`urn:ok:error:malformed-upload`,Error(`client disconnected`))}),e.pipe(E)})}function safeSubdir(e,t){let S=resolve(e,t);if(S!==e&&!S.startsWith(`${e}/`))throw Error(`Invalid directory: ${t}`);return S}function isValidRelativeContentPath(e){return!e||e.startsWith(`/`)||e.includes(`\\`)||e.includes(`\0`)?!1:e.split(`/`).every(e=>e&&e!==`.`&&e!==`..`)}function listAffectedDocNames(e,t,S){let w=[...e.keys()].filter(e=>t===`file`?e===S:e===S||e.startsWith(`${S}/`));return w.sort((e,t)=>e.localeCompare(t)),w}function remapDocNameForRename(e,t,S,w){return t===`file`||e===S?w:`${w}${e.slice(S.length)}`}function assertNoSymlinkEscape(e,t){let S;try{S=realpathSync(t)}catch(e){throw e.code===`ENOENT`?new SymlinkEscapeError(`content directory does not exist`):e}let w=e;for(;;)try{if(!isWithinContentDir(realpathSync(w),S))throw new SymlinkEscapeError(`path resolves outside content directory`);return}catch(e){let S=e.code;if(S===`ELOOP`)throw new SymlinkEscapeError(`symlink cycle in path`);if(S!==`ENOENT`)throw e;let E=dirname(w);if(E===w||E!==t&&!E.startsWith(`${t}${sep}`))throw e;w=E}}function resolveContentEntryPath(e,t,S){if(!isValidRelativeContentPath(S))throw Error(`path must be a relative content path`);let w=resolve(e),E=resolve(w,t===`file`?isSupportedDocFile(S)?S:`${S}${getDocExtension(S)}`:S);if(E!==w&&!E.startsWith(`${w}${sep}`))throw Error(`path must not escape content directory`);return assertNoSymlinkEscape(E,w),E}function probeAndRegisterSourceFileExtension(e,t){if(!isValidRelativeContentPath(t))return;let S=resolve(e);for(let e of SUPPORTED_DOC_EXTENSIONS){let w=resolve(S,`${t}${e}`);if(!(w!==S&&!w.startsWith(`${S}${sep}`))&&existsSync(w)){registerDocExtension(t,e);return}}}function toGitRelativePath(e,t){let S=resolve(e),w=resolve(t);return w!==S&&!w.startsWith(`${S}${sep}`)?null:relative(S,w).split(sep).join(`/`)}async function renameTrackedPathInGit(e,t,S){if(!e)return!1;let w=toGitRelativePath(e,t),E=toGitRelativePath(e,S);return!w||!E?!1:await withParentLock(async()=>{let t=esm_default({baseDir:e,timeout:{block:15e3}}),D=``;try{D=(await t.raw(`ls-files`,`--`,w)).trim()}catch(e){return console.warn(`[renameTrackedPathInGit] git ls-files failed, falling back to fs rename:`,e),!1}if(!D)return!1;mkdirSync(dirname(S),{recursive:!0});try{return await t.raw(`mv`,`--`,w,E),!0}catch(e){return console.warn(`[renameTrackedPathInGit] git mv failed, falling back to fs rename:`,e),!1}})}const workspaceSearchCaches=new Map;function extractHeadings(e){let t=e;if(e.startsWith(`---
|
|
2272
2272
|
`)||e.startsWith(`---\r
|
|
2273
2273
|
`)){let S=e.indexOf(`
|
|
2274
2274
|
---`,3);S!==-1&&(t=e.slice(S+4))}let S=[],w=new Map,E=createCodeFenceTracker();for(let e of t.split(`
|
|
@@ -2279,7 +2279,7 @@ tags: [travel]
|
|
|
2279
2279
|
`)[0]??``).split(/\s+/)[2];if(S){let w=await e.raw(`cat-file`,`-p`,S);t.writeHead(200,{"Content-Type":`text/markdown`,"X-Content-Type-Options":`nosniff`}),t.end(w);return}}}catch(e){console.warn(`[rescue] timeline-ref fallback failed:`,e)}errorResponse(t,404,`urn:ok:error:not-found`,`Not found.`,{handler:`rescue-get`})}let _s=withValidation(CreatePageRequestSchema,async(e,t,S)=>{try{let e=extractActorIdentity(S,fe);if(e.kind===`invalid-summary`){errorResponse(t,400,`urn:ok:error:invalid-request`,`Summary must be a string.`,{handler:`create-page`});return}let E=S.path;if(!isSupportedDocFile(E)){errorResponse(t,400,`urn:ok:error:invalid-request`,`path must end with .md or .mdx.`,{handler:`create-page`});return}if(E.includes(`..`)||E.startsWith(`/`)||E.includes(`\0`)||E.includes(`\\`)){errorResponse(t,400,`urn:ok:error:path-escape`,`Invalid path.`,{handler:`create-page`,detail:`path must not contain .. or start with /`});return}let O=resolve(w),k=resolve(O,E);if(!k.startsWith(`${O}/`)&&k!==O){errorResponse(t,400,`urn:ok:error:path-escape`,`path must not escape content directory.`,{handler:`create-page`});return}let j=stripDocExtension(E);if(isSystemDoc(j)||isConfigDoc(j)){errorResponse(t,400,`urn:ok:error:reserved-doc-name`,`'${j}' is a reserved document name.`,{handler:`create-page`});return}let F=typeof S.template==`string`?S.template.trim():``,L=``,B;if(F.length>0){if(!/^[A-Za-z0-9_-]+$/.test(F)){errorResponse(t,400,`urn:ok:error:invalid-request`,`Template name must match [A-Za-z0-9_-]+.`,{handler:`create-page`});return}let S=E.includes(`/`)?E.slice(0,E.lastIndexOf(`/`)):``,w=resolveTemplatesAvailable(O,S),D=w.find(e=>e.name===F);if(!D){let e=w.length===0?`(none)`:w.map(e=>`"${e.name}" (${e.scope})`).join(`, `);errorResponse(t,400,`urn:ok:error:invalid-request`,`Template "${F}" does not resolve for folder "${S||`(root)`}". Available: ${e}`,{handler:`create-page`});return}let k=D.scope===`user`?D.path:resolve(O,D.path),j;try{j=readFileSync(k,`utf-8`)}catch(e){errorResponse(t,500,`urn:ok:error:internal-server-error`,`Failed to read template at ${D.scope===`user`?`~/.ok/templates/${D.name}.md`:D.path}.`,{handler:`create-page`,cause:e});return}let{body:H}=stripFrontmatter(j),q=e.kind===`agent`||e.kind===`principal`?e.displayName??``:``;L=applySubstitution(H,{date:todayIsoUtc(),user:q}),B=D.scope}mkdirSync(dirname(k),{recursive:!0});try{writeFileSync(k,L,{encoding:`utf-8`,flag:`wx`})}catch(e){if(e.code===`EEXIST`){errorResponse(t,409,`urn:ok:error:doc-already-exists`,`File already exists.`,{handler:`create-page`,cause:e});return}throw e}let H=stripDocExtension(E);switch(ye?.delete(H),me&&me.incrementMdDir(dirname(H)),registerWrite(k,contentHash(L)),e.kind){case`agent`:case`principal`:recordContributor(H,e.writerId,e.displayName,e.colorSeed,void 0,e.actor);break;case`anonymous`:break;default:throw Error(`Unhandled actor kind in handleCreatePage: ${String(e.kind)}`)}let q=typeof D==`function`?D():null;q instanceof Map&&updateFileIndex({kind:`create`,path:k,docName:H,content:L},q),ee&&(ee.updateDocumentFromMarkdown(H,L),ee.saveToDisk().catch(e=>{console.warn(`[backlinks] Failed to persist create-page cache for ${H}:`,e)}),ne?.(`backlinks`),ne?.(`graph`)),ne?.(`files`),B!==void 0&&console.warn(JSON.stringify({event:`template-instantiate`,templateName:F,templateScope:B,docName:H})),successResponse(t,200,CreatePageSuccessSchema,{docName:H},{handler:`create-page`})}catch(e){errorResponse(t,500,`urn:ok:error:internal-server-error`,`Failed to create page.`,{handler:`create-page`,cause:e})}},{handler:`create-page`,method:`POST`}),xs=withValidation(CreateFolderRequestSchema,async(e,t,S)=>{try{if(extractActorIdentity(S,fe).kind===`invalid-summary`){errorResponse(t,400,`urn:ok:error:invalid-request`,`Summary must be a string.`,{handler:`create-folder`});return}let e=S.path;if(!isValidRelativeContentPath(e)){errorResponse(t,400,`urn:ok:error:invalid-request`,`path must be a relative content path.`,{handler:`create-folder`});return}if(e===`.ok`||e.startsWith(`.ok/`)){errorResponse(t,400,`urn:ok:error:reserved-doc-name`,`'.ok' is a reserved directory.`,{handler:`create-folder`});return}if(me?.isDirExcluded(e)){errorResponse(t,400,`urn:ok:error:invalid-request`,`Destination folder is excluded by the workspace content config.`,{handler:`create-folder`});return}let E=resolveContentEntryPath(w,`folder`,e);if(existsSync(E)){errorResponse(t,409,`urn:ok:error:doc-already-exists`,`Folder already exists.`,{handler:`create-folder`});return}tracedMkdirSync(E,{recursive:!0}),je(e),ne?.(`files`),successResponse(t,200,CreateFolderSuccessSchema,{path:e},{handler:`create-folder`})}catch(e){errorResponse(t,500,`urn:ok:error:internal-server-error`,`Failed to create folder.`,{handler:`create-folder`,cause:e})}},{handler:`create-folder`,method:`POST`}),Cs=withValidation(EmptyRequestSchema,async(e,t)=>{try{let S=new URL(e.url??``,`http://localhost`).searchParams.get(`docName`);if(!S||S.length===0){errorResponse(t,400,`urn:ok:error:invalid-request`,`Missing docName query parameter.`,{handler:`page-headings`});return}if(!isSafeDocName(S)){errorResponse(t,400,`urn:ok:error:invalid-request`,`Invalid docName.`,{handler:`page-headings`});return}let w=ze(S);if(!w){errorResponse(t,400,`urn:ok:error:invalid-request`,`Invalid docName.`,{handler:`page-headings`});return}if(!existsSync(w)){errorResponse(t,404,`urn:ok:error:doc-not-found`,`Page not found.`,{handler:`page-headings`});return}successResponse(t,200,PageHeadingsSuccessSchema,{docName:S,headings:extractHeadings(readFileSync(w,`utf-8`))},{handler:`page-headings`})}catch(e){errorResponse(t,500,`urn:ok:error:internal-server-error`,`Failed to read headings.`,{handler:`page-headings`,cause:e})}},{handler:`page-headings`,method:`GET`,skipBodyParse:!0}),Ts=withValidation(RenamePathRequestSchema,async(e,t,S)=>{try{let e=extractActorIdentity(S,fe);if(e.kind===`invalid-summary`){errorResponse(t,400,`urn:ok:error:invalid-request`,`Summary must be a string.`,{handler:`rename-path`});return}let{kind:E,fromPath:D,toPath:O}=S;if(!isValidRelativeContentPath(D)||!isValidRelativeContentPath(O)){errorResponse(t,400,`urn:ok:error:invalid-request`,`Paths must be relative content paths.`,{handler:`rename-path`});return}if(E===`file`&&(isSystemDoc(D)||isSystemDoc(O)||isConfigDoc(D)||isConfigDoc(O))){errorResponse(t,400,`urn:ok:error:reserved-doc-name`,`Reserved document names cannot be renamed.`,{handler:`rename-path`});return}if(D===`.ok`||D.startsWith(`.ok/`)||O===`.ok`||O.startsWith(`.ok/`)){errorResponse(t,400,`urn:ok:error:reserved-doc-name`,`.ok is a reserved directory.`,{handler:`rename-path`});return}if(D===O){successResponse(t,200,RenamePathSuccessSchema,{renamed:[],rewrittenDocs:[]},{handler:`rename-path`});return}if(D.toLowerCase()===O.toLowerCase()){errorResponse(t,400,`urn:ok:error:invalid-request`,`Case-only renames are not supported.`,{handler:`rename-path`});return}if(E===`file`&&probeAndRegisterSourceFileExtension(w,D),me&&(E===`file`?me.isExcluded(isSupportedDocFile(O)?O:`${O}${getDocExtension(D)}`):me.isDirExcluded(O))){errorResponse(t,400,`urn:ok:error:invalid-request`,`Destination ${E===`file`?`document`:`folder`} is excluded by the project content config.`,{handler:`rename-path`});return}let k=e.kind===`agent`||e.kind===`principal`?{writerId:e.writerId,displayName:e.displayName,colorSeed:e.colorSeed,actorMetadata:e.actor}:void 0,j;try{j=await Lt(D,O,E,{...k?{actor:k}:{}})}catch(e){if(e instanceof ManagedRenameCollisionError){errorResponse(t,409,`urn:ok:error:doc-already-exists`,vt(e.message),{handler:`rename-path`,extensions:{colliding:e.colliding},cause:e});return}throw e}if(j.renamed.length===0){successResponse(t,200,RenamePathSuccessSchema,{renamed:[],rewrittenDocs:[]},{handler:`rename-path`});return}let F;switch(e.kind){case`agent`:{let t=e.summary.kind===`value`,S=t?e.summary:normalizeSummary(`Renamed ${D} → ${O}`),w=Bt(S);F=t||!w.response?w.response:Vt(w.response);for(let t=0;t<j.renamed.length;t++){let{fromDocName:S,toDocName:E}=j.renamed[t];recordContributor(E,e.writerId,e.displayName,e.colorSeed,formatRenameSubject(S,E),e.actor,t===0?w.stored:void 0)}incrementAgentWriteCalls(),Ht(S,!t);for(let{toDocName:e}of j.renamed)rt(e,`rename-path`);break}case`principal`:{let t=Bt(e.summary);F=t.response;for(let S=0;S<j.renamed.length;S++){let{fromDocName:w,toDocName:E}=j.renamed[S];recordContributor(E,e.writerId,e.displayName,e.colorSeed,formatRenameSubject(w,E),e.actor,S===0?t.stored:void 0)}Ht(e.summary,!1);for(let{toDocName:e}of j.renamed)rt(e,`rename-path`);break}case`anonymous`:log$2.debug({kind:E,fromPath:D,toPath:O,affectedDocs:j.renamed.length},`[rename-path] anonymous actor — no contributor recorded (no agentId in body and getPrincipal() returned null)`);break;default:throw Error(`Unhandled actor kind in handleRenamePath: ${String(e.kind)}`)}if(renameAttributionCounter().add(1,{kind:`rename-${E}`,attribution_kind:e.kind}),H)try{await H()}catch(e){console.warn(`[rename-path] flushContributors failed (commitSha backfill may be deferred):`,e)}successResponse(t,200,RenamePathSuccessSchema,{renamed:j.renamed,rewrittenDocs:j.rewrittenDocs,...F?{summary:F}:{}},{handler:`rename-path`})}catch(e){let{status:S,type:w,error:E}=Tt(e);errorResponse(t,S,w,E,{handler:`rename-path`,cause:e})}},{handler:`rename-path`,method:`POST`}),Ds=withValidation(DeletePathRequestSchema,async(e,t,S)=>{try{Rt(S);let{kind:e,path:E}=S;if(!isValidRelativeContentPath(E)){errorResponse(t,400,`urn:ok:error:invalid-request`,`path must be a relative content path.`,{handler:`delete-path`});return}let O=resolveContentEntryPath(w,e,E);if(!existsSync(O)){errorResponse(t,404,`urn:ok:error:doc-not-found`,`${e} does not exist.`,{handler:`delete-path`});return}let k=statSync(O);if(e===`file`&&!k.isFile()||e===`folder`&&!k.isDirectory()){errorResponse(t,400,`urn:ok:error:invalid-request`,`Target path is not a ${e}.`,{handler:`delete-path`});return}let j=e===`file`?[E]:listAffectedDocNames(D(),e,E);if(await Et(j),ye)for(let e of j)isSystemDoc(e)||isConfigDoc(e)||(ye.setDeleted(e),console.info(JSON.stringify({event:`recently-removed-docs-populate`,docName:e,kind:`deleted`,source:`handleDeletePath`})));e===`file`?unlinkSync(O):(rmSync(O,{recursive:!0,force:!1}),Me(E));let F=D();if(F instanceof Map)for(let e of j)updateFileIndex({kind:`delete`,path:resolve(w,`${e}${getDocExtension(e)}`),docName:e},F);successResponse(t,200,DeletePathSuccessSchema,{deletedDocNames:j},{handler:`delete-path`})}catch(e){errorResponse(t,500,`urn:ok:error:internal-server-error`,`Failed to delete path.`,{handler:`delete-path`,cause:e})}},{handler:`delete-path`,method:`POST`}),Os=withValidation(EmptyRequestSchema,async(e,t)=>{try{let e=D(),S=[];for(let[t,E]of e){let e=t,D=getDocExtension(t);try{e=extractPageTitle(readFileSync(resolve(w,`${t}${D}`),`utf-8`),t)}catch(e){console.warn(`[pages] Failed to read title for ${t}:`,e)}S.push({docName:t,title:e,docExt:D,size:E.size,modified:E.modified})}S.sort((e,t)=>e.docName.localeCompare(t.docName)),successResponse(t,200,PagesSuccessSchema,{pages:S},{handler:`pages`})}catch(e){errorResponse(t,500,`urn:ok:error:internal-server-error`,`Failed to list pages.`,{handler:`pages`,cause:e})}},{handler:`pages`,method:`GET`,skipBodyParse:!0}),ks=withValidation(EmptyRequestSchema,async(e,S)=>{try{let w=new URL(e.url??``,`http://localhost`).searchParams.get(`docName`);if(!w){errorResponse(S,400,`urn:ok:error:invalid-request`,`Missing docName parameter.`,{handler:`suggest-links`});return}if(!isSafeDocName(w)){errorResponse(S,400,`urn:ok:error:invalid-request`,`Invalid docName.`,{handler:`suggest-links`});return}if(isSystemDoc(w)||isConfigDoc(w)){errorResponse(S,400,`urn:ok:error:reserved-doc-name`,`'${w}' is a reserved document name.`,{handler:`suggest-links`});return}successResponse(S,200,SuggestLinksSuccessSchema,await suggestLinks({hocuspocus:t,fileIndex:D(),docName:w}),{handler:`suggest-links`})}catch(e){if(e instanceof SuggestLinksTargetNotFoundError){errorResponse(S,404,`urn:ok:error:doc-not-found`,`Page not found.`,{handler:`suggest-links`,cause:e});return}errorResponse(S,500,`urn:ok:error:internal-server-error`,`Failed to suggest links.`,{handler:`suggest-links`,cause:e})}},{handler:`suggest-links`,method:`GET`,skipBodyParse:!0});async function As(e,t){if(e.method!==`POST`){errorResponse(t,405,`urn:ok:error:method-not-allowed`,`Method not allowed.`,{handler:`upload-asset`,extraHeaders:{Allow:`POST`}});return}let S;try{S=await readUploadBody(e,de??w)}catch(e){if(e instanceof UploadWriteError){errorResponse(t,uploadStatusFor(e.reason),e.reason,uploadTitleFor(e.reason),{handler:`upload-asset`,cause:e});return}errorResponse(t,400,`urn:ok:error:malformed-upload`,`Failed to parse upload.`,{handler:`upload-asset`,cause:e});return}let{filename:E,tempPath:D,sha:O,byteLength:k,parentDocName:j}=S,F=()=>{if(existsSync(D))try{unlinkSync(D)}catch{}},L=validateBody(UploadRequestSchema,{parentDocName:j},t,{handler:`upload-asset`});if(!L.ok){F();return}let{parentDocName:B}=L.value,{agentId:H,agentName:q}=Rt(Object.fromEntries(new URL(e.url??``,`http://localhost`).searchParams.entries()));if(k===0){F(),errorResponse(t,400,`urn:ok:error:no-file-received`,`No file received.`,{handler:`upload-asset`});return}if(B.includes(`\0`)||B.includes(`..`)||B.startsWith(`/`)){F(),errorResponse(t,400,`urn:ok:error:path-escape`,`Path escape detected.`,{handler:`upload-asset`});return}let J=resolve(w),Y=resolveUploadDestDir(B,`./`,J);if(!isWithinContentDir(Y,J)){F(),errorResponse(t,400,`urn:ok:error:path-escape`,`Path escape detected.`,{handler:`upload-asset`});return}try{assertNoSymlinkEscape(Y,J)}catch(e){if(F(),(e instanceof Error?e.message:String(e)).startsWith(`symlink-escape:`)){errorResponse(t,400,`urn:ok:error:path-escape`,`Path escape detected.`,{handler:`upload-asset`});return}log$2.error({err:e,destDir:Y},`[upload] failed to validate destination directory`),errorResponse(t,500,`urn:ok:error:storage-error`,`Storage error.`,{handler:`upload-asset`,cause:e});return}try{mkdirSync(Y,{recursive:!0})}catch(e){if(e.code!==`EEXIST`){F();let S=classifyUploadErrno(e);errorResponse(t,uploadStatusFor(S),S,uploadTitleFor(S),{handler:`upload-asset`,cause:e,detail:`failed to create attachment directory`});return}}try{let e=realpathSync(Y),S;try{S=realpathSync(J)}catch{S=J}if(!isWithinContentDir(e,S)){F(),errorResponse(t,400,`urn:ok:error:path-escape`,`Path escape detected.`,{handler:`upload-asset`});return}}catch(e){if(e.code!==`ENOENT`){F(),errorResponse(t,400,`urn:ok:error:path-escape`,`Path escape detected.`,{handler:`upload-asset`,cause:e});return}}let ee=await fileTypeFromFile(D),te=ee?.mime,ne=ee?.ext;if(!te){let e=readTempFileHead(D,256).toString(`utf-8`).replace(/^/,``).trimStart();(e.startsWith(`<svg`)||e.startsWith(`<?xml`)&&e.includes(`<svg`))&&(te=`image/svg+xml`,ne=`svg`)}{let S=await findDuplicateAsset(Y,O,k);if(S){F();let E=relative(w,resolve(Y,S));log$2.info({event:`upload`,endpoint:e.url??`/api/upload`,agentId:H,agentName:q,dedup:!0,mime:te??null,size:k,destPath:E,httpStatus:200},`[upload] dedup hit`),successResponse(t,200,UploadAssetSuccessSchema,{src:S,path:E,deduped:!0},{handler:`upload-asset`});return}}let ae;if(!E||E===`upload`||GENERIC_PASTE_NAMES.test(E)){let e=new Date().toISOString().replace(/[-:T]/g,``).slice(0,14).replace(/(\d{8})(\d{6})/,`$1-$2`),t=E?extname(E).slice(1):``,S=ne??t??``;ae=S===``?`pasted-${e}`:`pasted-${e}.${S}`}else ae=sanitizeFilename(E);try{let S=linkTempToFinalWithCollisionRetry(D,Y,ae),E=relative(w,resolve(Y,S));log$2.info({event:`upload`,endpoint:e.url??`/api/upload`,agentId:H,agentName:q,dedup:!1,mime:te??null,size:k,destPath:E,httpStatus:200},`[upload] write ok`),successResponse(t,200,UploadAssetSuccessSchema,{src:S,path:E,deduped:!1},{handler:`upload-asset`})}catch(S){let w=S instanceof UploadWriteError?S.reason:`urn:ok:error:storage-error`;log$2.error({event:`upload`,endpoint:e.url??`/api/upload`,agentId:H,agentName:q,filename:ae,size:k,reason:w,httpStatus:uploadStatusFor(w),err:S},`[upload] write failed`),errorResponse(t,uploadStatusFor(w),w,uploadTitleFor(w),{handler:`upload-asset`,cause:S})}}let Ns=`/api/local-op/clone`,Ps=`/api/local-op/open`,Is=600*1e3,Rs=45e3,$s=`local-op-clone`,ec=withValidation(LocalOpCloneRequestSchema,tc,{handler:$s,method:`POST`,preBodyGate:(e,t)=>checkLocalOpSecurity(e,t,{handler:$s})});async function tc(e,t,S){let{url:w,dir:E}=S;if(!isAllowedGitUrl(w)){errorResponse(t,400,`urn:ok:error:url-not-allowed`,`URL protocol is not allowed for clone.`,{handler:$s,cause:Error(`url=${w}`)});return}if(!isSafeLocalPath(E)){errorResponse(t,400,`urn:ok:error:dir-outside-home`,`Clone destination must be within the user home directory.`,{handler:$s,cause:Error(`dir=${E}`)});return}if(!Ce.tryAcquire(Ns)){errorResponse(t,429,`urn:ok:error:concurrent-operation`,`A clone operation is already in progress.`,{handler:$s,extraHeaders:{"Retry-After":`30`}});return}t.writeHead(200,{"Content-Type":`application/x-ndjson`,"Transfer-Encoding":`chunked`,"X-Content-Type-Options":`nosniff`,"Cache-Control":`no-cache`});let D=createStreamingErrorWriter(t,$s),O=null,k=runCloneSubprocess({cliArgs:ue,url:w,dir:E,timeoutMs:Is,onEvent:e=>{if(e.type===`complete`){O=e.dir;return}if(e.type===`error`){e.message&&log$2.warn({stderr:e.message,url:w,dir:E},`[local-op/clone] clone failed`),D(500,`urn:ok:error:clone-failed`,`Clone subprocess reported an error.`,{cause:e.message?Error(e.message):void 0});return}if(!t.writableEnded&&!t.destroyed)try{t.write(`${JSON.stringify(e)}\n`)}catch{}}});(async()=>{try{if(await k.done,O&&!t.writableEnded&&!t.destroyed){let e=await nc(O);!t.writableEnded&&!t.destroyed&&(`port`in e?t.write(`${JSON.stringify({type:`complete`,port:e.port,dir:O})}\n`):D(500,`urn:ok:error:server-start-failed`,`Cloned successfully but failed to start the project server.`,{cause:Error(e.error)}))}}catch(e){!t.writableEnded&&!t.destroyed?D(500,`urn:ok:error:internal-server-error`,`Unexpected error during clone post-processing.`,{cause:e}):log$2.error({err:e,handler:$s},`clone IIFE rejected after stream ended`)}finally{t.writableEnded||t.end(),Ce.release(Ns)}})(),t.on(`close`,()=>{k.cancel()})}async function nc(e){let t=resolve(expandTilde(e)),S=getLocalDir(t),w=readUiLock(S);if(w&&w.port>0)return{port:w.port};let E=readServerLock(S),[D,...O]=ue,k=E&&E.port>0?`ui`:`start`,j=spawn(D,[...O,k],{cwd:t,detached:!0,stdio:[`ignore`,`ignore`,`pipe`],env:{...process.env,OK_LOCK_KIND:`interactive`}}),F=[];j.stderr?.on(`data`,e=>{F.push(e),log$2.warn({cwd:t,cliCmd:k,msg:e.toString(`utf-8`).trim()},`[local-op/open] child stderr`)});let L=null;j.on(`exit`,e=>{L=e??-1}),j.unref();let B=Date.now()+45e3;for(;Date.now()<B;){await setTimeout$1(500);let e=readUiLock(S);if(e&&e.port>0)return{port:e.port};if(L!==null){let e=Buffer.concat(F).toString(`utf-8`).trim();return{error:`\`ok ${k}\` exited (code ${L})${e?` — ${e}`:``}`}}}let H=Buffer.concat(F).toString(`utf-8`).trim();return{error:`UI did not start within the expected time${H?` — ${H}`:``}`}}let rc=`local-op-open`,ic=withValidation(LocalOpOpenRequestSchema,async(e,t,S)=>{let{dir:w}=S;if(!isSafeLocalPath(w)){errorResponse(t,400,`urn:ok:error:dir-outside-home`,`dir must be within the user home directory.`,{handler:rc,cause:Error(`dir=${w}`)});return}if(!Ce.tryAcquire(Ps)){errorResponse(t,429,`urn:ok:error:concurrent-operation`,`A server-open operation is already in progress.`,{handler:rc,extraHeaders:{"Retry-After":`5`}});return}try{let e=await nc(w);`port`in e?successResponse(t,200,LocalOpOpenSuccessSchema,{port:e.port},{handler:rc}):errorResponse(t,504,`urn:ok:error:server-open-failed`,`Failed to open project server.`,{handler:rc,cause:Error(e.error)})}finally{Ce.release(Ps)}},{handler:rc,method:`POST`,preBodyGate:(e,t)=>checkLocalOpSecurity(e,t,{handler:rc})}),ac=`/api/local-op/auth/login`,oc=`/api/local-op/auth/status`,sc=`/api/local-op/auth/repos`,cc=`/api/local-op/auth/signout`,lc=`/api/local-op/auth/pat`,uc=`local-op-auth-login`,dc=withValidation(LocalOpAuthHostRequestSchema,fc,{handler:uc,method:`POST`,preBodyGate:(e,t)=>checkLocalOpSecurity(e,t,{handler:uc})});async function fc(e,t,S){let w=S.host??`github.com`;if(!Ce.tryAcquire(ac)){errorResponse(t,429,`urn:ok:error:concurrent-operation`,`An auth login operation is already in progress.`,{handler:uc,extraHeaders:{"Retry-After":`5`}});return}t.writeHead(200,{"Content-Type":`application/x-ndjson`,"Transfer-Encoding":`chunked`,"X-Content-Type-Options":`nosniff`,"Cache-Control":`no-cache`});let E=createStreamingErrorWriter(t,uc),D=runDeviceFlowSubprocess({cliArgs:ue,host:w,timeoutMs:Is,onEvent:e=>{if(e.type===`error`){E(500,`urn:ok:error:auth-failed`,`Auth subprocess reported an error.`,{cause:e.message?Error(e.message):void 0});return}if(!t.writableEnded&&!t.destroyed)try{t.write(`${JSON.stringify(e)}\n`)}catch{}}}),O=()=>{D.cancel()};t.on(`close`,O),D.done.finally(()=>{t.off(`close`,O),t.writableEnded||t.end(),Ce.release(ac)})}let pc=`local-op-auth-status`,mc=withValidation(LocalOpAuthHostRequestSchema,async(e,t,S)=>{let w=S.host??`github.com`;if(!Ce.tryAcquire(oc)){errorResponse(t,429,`urn:ok:error:concurrent-operation`,`An auth status operation is already in progress.`,{handler:pc,extraHeaders:{"Retry-After":`5`}});return}try{let[e,...S]=ue,E=[...S,`auth`,`status`,`--json`,`--host`,w],D=(await new Promise((t,S)=>{let w=spawn(e,E,{stdio:[`ignore`,`pipe`,`pipe`],env:{...process.env}}),D=!1,O=setTimeout(()=>{D=!0,w.kill(`SIGTERM`)},3e4),k=[];w.stdout.on(`data`,e=>k.push(e)),w.on(`close`,()=>{if(clearTimeout(O),D){S(Error(`auth status subprocess timed out after 30s`));return}t(Buffer.concat(k).toString(`utf-8`))}),w.on(`error`,e=>{clearTimeout(O),S(e)})})).split(`
|
|
2280
2280
|
`).map(e=>e.trim()).filter(Boolean),O=null;for(let e=D.length-1;e>=0;e--)try{O=JSON.parse(D[e]);break}catch{}O===null?successResponse(t,200,LocalOpAuthStatusSuccessSchema,{authenticated:!1},{handler:pc}):successResponse(t,200,LocalOpAuthStatusSuccessSchema,O,{handler:pc})}catch(e){errorResponse(t,500,`urn:ok:error:auth-failed`,`Auth status check failed.`,{handler:pc,cause:e})}finally{Ce.release(oc)}},{handler:pc,method:`POST`,preBodyGate:(e,t)=>checkLocalOpSecurity(e,t,{handler:pc})}),hc=`local-op-auth-repos`,gc=withValidation(LocalOpAuthHostRequestSchema,_c,{handler:hc,method:`POST`,preBodyGate:(e,t)=>checkLocalOpSecurity(e,t,{handler:hc})});async function _c(e,t,S){let w=S.host??`github.com`;if(!Ce.tryAcquire(sc)){errorResponse(t,429,`urn:ok:error:concurrent-operation`,`An auth repos operation is already in progress.`,{handler:hc,extraHeaders:{"Retry-After":`5`}});return}t.writeHead(200,{"Content-Type":`application/x-ndjson`,"Transfer-Encoding":`chunked`,"X-Content-Type-Options":`nosniff`,"Cache-Control":`no-cache`});let E=createStreamingErrorWriter(t,hc),[D,...O]=ue,k=[...O,`auth`,`repos`,`--json`,`--host`,w],j=!1,F=``,L=spawn(D,k,{stdio:[`ignore`,`pipe`,`pipe`],env:{...process.env}}),B=setTimeout(()=>{L.kill(`SIGTERM`)},Is);L.stdout.on(`data`,e=>{F+=e.toString(`utf-8`);let S=F.split(`
|
|
2281
2281
|
`);F=S.pop()??``;for(let e of S){if(!e.trim())continue;let S=null;try{S=JSON.parse(e)}catch{}if(S&&S.type===`error`){E(500,`urn:ok:error:auth-failed`,`Auth repos subprocess reported an error.`,{detail:typeof S.message==`string`?S.message:void 0});continue}if(!t.writableEnded&&!t.destroyed)try{t.write(`${e}\n`)}catch{}}}),L.stderr.on(`data`,e=>{log$2.debug({msg:e.toString(`utf-8`).trim()},`[local-op/auth/repos] stderr`)}),L.on(`close`,e=>{clearTimeout(B),j||(j=!0,e!==0&&!t.writableEnded&&E(500,`urn:ok:error:auth-failed`,`Auth repos subprocess exited with code ${e}.`),t.end(),Ce.release(sc))}),L.on(`error`,e=>{clearTimeout(B),j||(j=!0,t.writableEnded||(E(500,`urn:ok:error:auth-failed`,`Failed to spawn the auth repos subprocess.`,{cause:e}),t.end()),Ce.release(sc))}),t.on(`close`,()=>{j||(j=!0,clearTimeout(B),L.kill(`SIGTERM`),Ce.release(sc))})}let vc=`local-op-auth-signout`,yc=withValidation(LocalOpAuthHostRequestSchema,async(e,t,S)=>{let w=S.host??`github.com`;if(!Ce.tryAcquire(cc)){errorResponse(t,429,`urn:ok:error:concurrent-operation`,`An auth signout operation is already in progress.`,{handler:vc,extraHeaders:{"Retry-After":`5`}});return}try{let[e,...S]=ue,E=[...S,`auth`,`signout`,`--host`,w];await new Promise((t,S)=>{let w=spawn(e,E,{stdio:`ignore`,env:{...process.env}}),D=setTimeout(()=>{w.kill(`SIGTERM`)},3e4);w.on(`close`,()=>{clearTimeout(D),t()}),w.on(`error`,e=>{clearTimeout(D),S(e)})}),successResponse(t,200,LocalOpAuthEmptySuccessSchema,{},{handler:vc})}catch(e){errorResponse(t,500,`urn:ok:error:auth-failed`,`Auth signout failed.`,{handler:vc,cause:e})}finally{Ce.release(cc)}},{handler:vc,method:`POST`,preBodyGate:(e,t)=>checkLocalOpSecurity(e,t,{handler:vc})}),bc=`local-op-auth-pat`,xc=withValidation(LocalOpAuthPatRequestSchema,async(e,t,S)=>{let{pat:w,host:E}=S,D=E??`github.com`;if(!Ce.tryAcquire(lc)){errorResponse(t,429,`urn:ok:error:concurrent-operation`,`An auth pat operation is already in progress.`,{handler:bc,extraHeaders:{"Retry-After":`5`}});return}try{let[e,...S]=ue,E=[...S,`auth`,`pat`,`--json`,`--host`,D],O=(await new Promise((t,S)=>{let D=spawn(e,E,{stdio:[`pipe`,`pipe`,`pipe`],env:{...process.env}}),O=setTimeout(()=>{D.kill(`SIGTERM`)},3e4);D.stdin.write(`${w}\n`),D.stdin.end();let k=[];D.stdout.on(`data`,e=>k.push(e)),D.on(`close`,e=>{clearTimeout(O),e===0?t(Buffer.concat(k).toString(`utf-8`)):S(Error(`auth pat exited with code ${e}`))}),D.on(`error`,e=>{clearTimeout(O),S(e)})})).split(`
|
|
2282
|
-
`).map(e=>e.trim()).filter(Boolean),k=null;for(let e=O.length-1;e>=0;e--)try{k=JSON.parse(O[e]);break}catch{}k===null?successResponse(t,200,LocalOpAuthPatSuccessSchema,{},{handler:bc}):successResponse(t,200,LocalOpAuthPatSuccessSchema,k,{handler:bc})}catch(e){errorResponse(t,500,`urn:ok:error:auth-failed`,`Auth pat failed.`,{handler:bc,cause:e})}finally{Ce.release(lc)}},{handler:bc,method:`POST`,preBodyGate:(e,t)=>checkLocalOpSecurity(e,t,{handler:bc})}),Sc=`local-op-auth-identity`;async function Cc(e,t){if(checkLocalOpSecurity(e,t,{handler:Sc})){if(e.method!==`GET`){errorResponse(t,405,`urn:ok:error:method-not-allowed`,`Method not allowed.`,{handler:Sc,extraHeaders:{Allow:`GET`}});return}if(!de){errorResponse(t,503,`urn:ok:error:no-project-dir`,`No project directory configured.`,{handler:Sc});return}try{successResponse(t,200,LocalOpAuthIdentitySuccessSchema,{identity:await resolveGitIdentity(de)},{handler:Sc})}catch(e){errorResponse(t,500,`urn:ok:error:internal-server-error`,`Identity resolution failed.`,{handler:Sc,cause:e})}}}let wc=`/api/local-op/auth/set-identity`,Tc=`local-op-auth-set-identity`,Ec=withValidation(LocalOpAuthSetIdentityRequestSchema,async(e,t,S)=>{let w=S.name.trim(),E=S.email.trim();if(!de){errorResponse(t,503,`urn:ok:error:no-project-dir`,`No project directory configured.`,{handler:Tc});return}if(!Ce.tryAcquire(wc)){errorResponse(t,429,`urn:ok:error:concurrent-operation`,`A set-identity operation is already in progress.`,{handler:Tc,extraHeaders:{"Retry-After":`5`}});return}try{writeGitIdentity(de,w,E),ce?.()?.refreshIdentity().catch(()=>{}),successResponse(t,200,LocalOpAuthEmptySuccessSchema,{},{handler:Tc})}catch(e){errorResponse(t,500,`urn:ok:error:internal-server-error`,`Set-identity failed.`,{handler:Tc,cause:e})}finally{Ce.release(wc)}},{handler:Tc,method:`POST`,preBodyGate:(e,t)=>checkLocalOpSecurity(e,t,{handler:Tc})});async function Dc(e,t){if(checkLocalOpSecurity(e,t,{handler:`sync-status`})){if(e.method!==`GET`){errorResponse(t,405,`urn:ok:error:method-not-allowed`,`Method not allowed.`,{handler:`sync-status`,extraHeaders:{Allow:`GET`}});return}try{let e=ce?.();if(!e){successResponse(t,200,SyncStatusSchema,{state:`dormant`,lastSyncUtc:null,lastFetchUtc:null,lastPushedSha:null,ahead:0,behind:0,consecutiveFailures:0,conflictCount:0,hasRemote:!1,syncEnabled:!1,identityUnresolved:!1},{handler:`sync-status`});return}successResponse(t,200,SyncStatusSchema,e.getStatus(),{handler:`sync-status`})}catch(e){errorResponse(t,500,`urn:ok:error:internal-server-error`,`Internal server error.`,{handler:`sync-status`,cause:e})}}}let Oc=withValidation(SyncTriggerRequestSchema,async(e,t,S)=>{let w=ce?.();if(!w){errorResponse(t,503,`urn:ok:error:sync-not-active`,`Sync engine not active.`,{handler:`sync-trigger`});return}let E=S.op??`sync`;successResponse(t,202,SyncTriggerSuccessSchema,{op:E},{handler:`sync-trigger`}),w.trigger(E)},{handler:`sync-trigger`,method:`POST`,preBodyGate:(e,t)=>checkLocalOpSecurity(e,t,{handler:`sync-trigger`})?ce?.()?!0:(errorResponse(t,503,`urn:ok:error:sync-not-active`,`Sync engine not active.`,{handler:`sync-trigger`}),!1):!1});async function kc(e,t){if(checkLocalOpSecurity(e,t,{handler:`sync-conflicts`})){if(e.method!==`GET`){errorResponse(t,405,`urn:ok:error:method-not-allowed`,`Method not allowed.`,{handler:`sync-conflicts`,extraHeaders:{Allow:`GET`}});return}try{let e=ce?.();successResponse(t,200,SyncConflictsSuccessSchema,{conflicts:e?e.getConflicts():[]},{handler:`sync-conflicts`})}catch(e){errorResponse(t,500,`urn:ok:error:internal-server-error`,`Internal server error.`,{handler:`sync-conflicts`,cause:e})}}}let Ac=withValidation(SyncResolveConflictRequestSchema,async(e,t,S)=>{let w=ce?.();if(!w){errorResponse(t,503,`urn:ok:error:sync-not-active`,`Sync engine not active.`,{handler:`sync-resolve-conflict`});return}let{file:E,strategy:D,content:O}=S;try{await w.resolveConflict(E,D,O),successResponse(t,200,SyncResolveConflictSuccessSchema,{},{handler:`sync-resolve-conflict`})}catch(e){errorResponse(t,500,`urn:ok:error:internal-server-error`,`Failed to resolve conflict.`,{handler:`sync-resolve-conflict`,cause:e})}},{handler:`sync-resolve-conflict`,method:`POST`,preBodyGate:(e,t)=>checkLocalOpSecurity(e,t,{handler:`sync-resolve-conflict`})?ce?.()?!0:(errorResponse(t,503,`urn:ok:error:sync-not-active`,`Sync engine not active.`,{handler:`sync-resolve-conflict`}),!1):!1});async function jc(e,t){if(!checkLocalOpSecurity(e,t,{handler:`sync-conflict-content`}))return;if(e.method!==`GET`){errorResponse(t,405,`urn:ok:error:method-not-allowed`,`Method not allowed.`,{handler:`sync-conflict-content`,extraHeaders:{Allow:`GET`}});return}if(!de){errorResponse(t,503,`urn:ok:error:project-repo-not-configured`,`Project repo not configured.`,{handler:`sync-conflict-content`});return}let S=new URL(e.url??`/`,`http://${e.headers.host??`localhost`}`).searchParams.get(`file`);if(!S){errorResponse(t,400,`urn:ok:error:invalid-request`,`Missing required query param: file.`,{handler:`sync-conflict-content`});return}if(S.includes(`..`)||S.startsWith(`/`)){errorResponse(t,400,`urn:ok:error:invalid-request`,`Invalid file path.`,{handler:`sync-conflict-content`});return}let w=esm_default({baseDir:de,timeout:{block:15e3}});async function E(e){try{return await w.raw([`show`,`:${e}:${S}`])}catch{return``}}try{let[e,w,D]=await Promise.all([E(1),E(2),E(3)]);successResponse(t,200,SyncConflictContentSuccessSchema,{file:S,base:e,ours:w,theirs:D},{handler:`sync-conflict-content`})}catch(e){errorResponse(t,500,`urn:ok:error:internal-server-error`,`Failed to read conflict content.`,{handler:`sync-conflict-content`,cause:e})}}async function Mc(e,t){if(!checkLocalOpSecurity(e,t,{handler:`seed-plan`}))return;if(e.method!==`GET`){errorResponse(t,405,`urn:ok:error:method-not-allowed`,`Method not allowed.`,{handler:`seed-plan`,extraHeaders:{Allow:`GET`}});return}let S=new URL(e.url??`/`,`http://localhost`),E=S.searchParams.get(`rootDir`)??void 0,D=S.searchParams.get(`packId`),O=coercePackId(D);if(D!==null&&D!==``&&O===void 0){errorResponse(t,400,`urn:ok:error:invalid-request`,`Unknown packId.`,{handler:`seed-plan`,detail:`Pack id "${D}" is not registered.`});return}let k=S.searchParams.get(`includePersonalTemplates`)===`true`;try{let e=await planSeed({projectDir:w,rootDir:E,packId:O});successResponse(t,200,SeedPlanSuccessSchema,{plan:k?{...e,personalTemplates:planPersonalTemplates()}:e},{handler:`seed-plan`})}catch(e){if(e instanceof SeedPrerequisiteError){errorResponse(t,422,`urn:ok:error:seed-prerequisite-missing`,`Seed prerequisite missing.`,{handler:`seed-plan`,cause:e});return}if(e instanceof SeedRootDirError){errorResponse(t,400,`urn:ok:error:seed-invalid-root`,`Invalid seed root directory.`,{handler:`seed-plan`,detail:`The provided root directory is not within the workspace content directory.`,cause:e});return}errorResponse(t,500,`urn:ok:error:internal-server-error`,`Internal server error.`,{handler:`seed-plan`,cause:e})}}let Nc=withValidation(SeedApplyRequestSchema,async(e,t,S)=>{let E=S.plan;if(!E||typeof E!=`object`){errorResponse(t,400,`urn:ok:error:invalid-request`,`Invalid plan payload.`,{handler:`seed-apply`});return}let D=E,O=S,k=O.packId,j=coercePackId(k);if(typeof k==`string`&&k.length>0&&j===void 0){errorResponse(t,400,`urn:ok:error:invalid-request`,`Unknown packId.`,{handler:`seed-apply`,detail:`Pack id "${k}" is not registered.`});return}let F=O.includePersonalTemplates===!0;try{let e=await applySeed(D,{projectDir:w,packId:j}),S=F?writePersonalTemplates():void 0;successResponse(t,200,SeedApplySuccessSchema,S?{result:e,personalTemplates:S}:{result:e},{handler:`seed-apply`})}catch(e){errorResponse(t,500,`urn:ok:error:internal-server-error`,`Failed to apply seed plan.`,{handler:`seed-apply`,cause:e})}},{handler:`seed-apply`,method:`POST`,preBodyGate:(e,t)=>checkLocalOpSecurity(e,t,{handler:`seed-apply`})});async function Pc(e,t){if(checkLocalOpSecurity(e,t,{handler:`seed-packs`})){if(e.method!==`GET`){errorResponse(t,405,`urn:ok:error:method-not-allowed`,`Method not allowed.`,{handler:`seed-packs`,extraHeaders:{Allow:`GET`}});return}successResponse(t,200,SeedListPacksSuccessSchema,{packs:listStarterPacks()},{handler:`seed-packs`})}}let Fc=withValidation(InstallSkillRequestSchema,async(e,t,S)=>{if(S.out!==void 0&&!isSafeLocalPath(S.out)){errorResponse(t,400,`urn:ok:error:invalid-request`,`Output path must be within home directory.`,{handler:`install-skill`});return}try{successResponse(t,200,InstallSkillSuccessSchema,await buildAndOpenSkill({...S.noOpen===void 0?{}:{noOpen:S.noOpen},...S.out===void 0?{}:{out:S.out}}),{handler:`install-skill`})}catch(e){errorResponse(t,500,`urn:ok:error:internal-server-error`,`Failed to install skill.`,{handler:`install-skill`,cause:e})}},{handler:`install-skill`,method:`POST`,preBodyGate:(e,t)=>checkLocalOpSecurity(e,t,{handler:`install-skill`})});async function Ic(e,t){if(checkLocalOpSecurity(e,t,{handler:`installed-agents`}))try{await handleInstalledAgents(e,t,Re.probeAll)}catch(e){t.headersSent||(log$2.error({err:e},`[installed-agents] route wrapper failed`),errorResponse(t,500,`urn:ok:error:internal-server-error`,`Internal server error.`,{handler:`installed-agents`,cause:e}))}}async function Lc(e,t){if(!checkLocalOpSecurity(e,t,{handler:`sync-abort-merge`}))return;if(e.method!==`POST`){errorResponse(t,405,`urn:ok:error:method-not-allowed`,`Method not allowed.`,{handler:`sync-abort-merge`,extraHeaders:{Allow:`POST`}});return}let S=ce?.();if(!S){errorResponse(t,503,`urn:ok:error:sync-not-active`,`Sync engine not active.`,{handler:`sync-abort-merge`});return}try{await S.abortMerge(),successResponse(t,200,SyncAbortMergeSuccessSchema,{},{handler:`sync-abort-merge`})}catch(e){errorResponse(t,500,`urn:ok:error:internal-server-error`,`Failed to abort merge.`,{handler:`sync-abort-merge`,cause:e})}}let Rc=withValidation(EmptyRequestSchema,async(e,t)=>{if(!te){errorResponse(t,503,`urn:ok:error:tag-index-not-configured`,`Tag index not configured.`,{handler:`tags-list`});return}try{successResponse(t,200,TagsListSuccessSchema,{tags:te.getAllTags()},{handler:`tags-list`})}catch(e){errorResponse(t,500,`urn:ok:error:internal-server-error`,`Failed to read tags.`,{handler:`tags-list`,cause:e})}},{handler:`tags-list`,method:`GET`,skipBodyParse:!0});async function zc(e,t,S){if(e.method!==`GET`){errorResponse(t,405,`urn:ok:error:method-not-allowed`,`Method not allowed.`,{handler:`tags-for-name`,extraHeaders:{Allow:`GET`}});return}if(!te){errorResponse(t,503,`urn:ok:error:tag-index-not-configured`,`Tag index not configured.`,{handler:`tags-for-name`});return}let w;try{w=decodeURIComponent(S)}catch{errorResponse(t,400,`urn:ok:error:invalid-request`,`Invalid tag name encoding.`,{handler:`tags-for-name`});return}if(!w){errorResponse(t,400,`urn:ok:error:invalid-request`,`Missing tag name.`,{handler:`tags-for-name`});return}try{let e=te.getDocsForTagWithMatches(w).map(({docName:e,matchingTags:t})=>({docName:e,title:Be(e),matchingTags:t,snippet:null}));successResponse(t,200,TagsForNameSuccessSchema,{name:w,docs:e},{handler:`tags-for-name`})}catch(e){errorResponse(t,500,`urn:ok:error:internal-server-error`,`Failed to read tag membership.`,{handler:`tags-for-name`,cause:e})}}function Bc(e,t,S=`path`,E=`folder-config`){let D=e.replace(/^\.\//,``).replace(/^\/+/,``).replace(/\/+$/,``);if(D.split(`/`).some(e=>e===`..`)||e.startsWith(`/`))return errorResponse(t,400,`urn:ok:error:invalid-request`,`Invalid ${S}: must be project-root-relative.`,{handler:E}),null;let O=resolve(w),k=D===``?O:resolve(O,D);return k!==O&&!k.startsWith(`${O}${sep}`)?(errorResponse(t,400,`urn:ok:error:invalid-request`,`Path escapes content directory.`,{handler:E}),null):{folderRel:D,resolvedContentDir:O}}let Vc=/^[A-Za-z0-9_-]+$/;function Hc(e,t,S=`template`){return!e||!Vc.test(e)?(errorResponse(t,400,`urn:ok:error:invalid-request`,"Invalid name: must be letters / digits / `_` / `-` only (no `.md` extension).",{handler:S}),!1):!0}function Uc(e,t,S=`template`){if(!(e==null||e===``))return e===`project`||e===`user`?e:(errorResponse(t,400,`urn:ok:error:invalid-request`,`target must be "project" or "user", got: ${JSON.stringify(e)}`,{handler:S}),null)}function Wc(e){let t={};if(!e||typeof e!=`object`||Array.isArray(e))return t;for(let[S,w]of Object.entries(e))w!==void 0&&(t[S]=w);return t}async function Gc(e,t){if(e.method===`GET`)return Kc(e,t);if(e.method===`PUT`)return qc(e,t);errorResponse(t,405,`urn:ok:error:method-not-allowed`,`Method not allowed.`,{handler:`folder-config`,extraHeaders:{Allow:`GET, PUT`}})}let Kc=withValidation(EmptyRequestSchema,async(e,t)=>{try{let S=Bc(new URL(e.url??``,`http://localhost`).searchParams.get(`path`)??``,t,`path`,`folder-config-get`);if(!S)return;let w=await enrichDirectory(S.folderRel,{projectDir:S.resolvedContentDir}),E=resolve(S.resolvedContentDir,S.folderRel,`.ok`,`frontmatter.yml`),D=null;if(existsSync(E))try{let e=(0,import_dist$1.parse)(await readFile$1(E,`utf-8`));D=e&&typeof e==`object`&&!Array.isArray(e)?e:{}}catch(e){let t=e instanceof Error?e.message:String(e);console.warn(`[folder-config:get] malformed YAML in ${E}: ${t}`),D=null}successResponse(t,200,FolderConfigGetSuccessSchema,{folder:w,frontmatter_local:D},{handler:`folder-config-get`})}catch(e){errorResponse(t,500,`urn:ok:error:internal-server-error`,`Failed to read folder config.`,{handler:`folder-config-get`,cause:e})}},{handler:`folder-config-get`,method:`GET`,skipBodyParse:!0}),qc=withValidation(FolderConfigPutRequestSchema,async(e,t,S)=>{try{let e=Bc(S.path,t,`path`,`folder-config-put`);if(!e)return;let w=e.folderRel===``?`**`:`${e.folderRel}/**`,E=applyNestedFolderRulesUpsert({projectDir:e.resolvedContentDir,rules:[{match:w,frontmatter:Wc(S.frontmatter)}]});if(!E.ok){let e=E.error.code===`WRITE_ERROR`||E.error.code===`BAD_PROJECT_DIR`?500:400;errorResponse(t,e,e===500?`urn:ok:error:internal-server-error`:`urn:ok:error:invalid-request`,e===500?`Failed to write folder config.`:`Invalid folder config request.`,{handler:`folder-config-put`,detail:E.error.code,cause:Error(E.error.message)});return}successResponse(t,200,FolderConfigPutSuccessSchema,{applied:E.applied},{handler:`folder-config-put`})}catch(e){errorResponse(t,500,`urn:ok:error:internal-server-error`,`Failed to write folder config.`,{handler:`folder-config-put`,cause:e})}},{handler:`folder-config-put`,method:`PUT`});async function Jc(e,t){if(e.method===`GET`)return Zc(e,t);if(e.method===`PUT`)return Qc(e,t);if(e.method===`DELETE`)return $c(e,t);errorResponse(t,405,`urn:ok:error:method-not-allowed`,`Method not allowed.`,{handler:`template`,extraHeaders:{Allow:`GET, PUT, DELETE`}})}let Yc=/^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/,Xc=e=>{let t=e.match(Yc),S={},w=e;if(t){try{let e=(0,import_dist$1.parse)(t[1]??``);e&&typeof e==`object`&&!Array.isArray(e)&&(S=e)}catch{}w=e.slice(t[0].length)}return{frontmatter:S,body:w}},Zc=withValidation(EmptyRequestSchema,async(e,t)=>{try{let S=new URL(e.url??``,`http://localhost`),w=S.searchParams.get(`name`)??``;if(!Hc(w,t,`template-get`))return;let E=Uc(S.searchParams.get(`target`),t,`template-get`);if(E===null)return;if(E===`user`){let e=getUserHome();if(!e){errorResponse(t,500,`urn:ok:error:internal-server-error`,`User home directory could not be resolved.`,{handler:`template-get`});return}let S=resolve(e,`.ok`,`templates`,`${w}.md`);if(!existsSync(S)){errorResponse(t,404,`urn:ok:error:template-not-found`,`Template not found.`,{handler:`template-get`,detail:`User template "${w}" not found at ~/.ok/templates/${w}.md`});return}let{frontmatter:E,body:D}=Xc(await readFile$1(S,`utf-8`));successResponse(t,200,TemplateGetSuccessSchema,{template:{name:w,folder:`~/.ok`,scope:`user`,path:`~/.ok/templates/${w}.md`,frontmatter:E,body:D}},{handler:`template-get`});return}let D=Bc(S.searchParams.get(`folder`)??``,t,`folder`,`template-get`);if(!D)return;let{folderRel:O,resolvedContentDir:k}=D,j=O===``?[]:O.split(`/`),F=null,L=null,B=null;for(let e=j.length;e>=0;e--){let t=e===0?``:j.slice(0,e).join(`/`),S=t===``?k:resolve(k,t);if(S!==k&&!S.startsWith(`${k}${sep}`))continue;let E=resolve(S,`.ok`,`templates`,`${w}.md`);if(existsSync(E)){F=E,L=t,B=e===j.length?`local`:`inherited`;break}}if(!F||L===null||B===null){errorResponse(t,404,`urn:ok:error:template-not-found`,`Template not found.`,{handler:`template-get`,detail:`Template "${w}" not found for folder "${O||`.`}". Walked leaf → root.`});return}let{frontmatter:H,body:q}=Xc(await readFile$1(F,`utf-8`)),J=relative(k,F).split(/[\\/]/).filter(Boolean).join(`/`);successResponse(t,200,TemplateGetSuccessSchema,{template:{name:w,folder:L,scope:B,path:J,frontmatter:H,body:q}},{handler:`template-get`})}catch(e){errorResponse(t,500,`urn:ok:error:internal-server-error`,`Failed to read template.`,{handler:`template-get`,cause:e})}},{handler:`template-get`,method:`GET`,skipBodyParse:!0}),Qc=withValidation(TemplatePutRequestSchema,async(e,t,S)=>{try{let e=S.name;if(!Hc(e,t,`template-put`))return;let w=Uc(S.target,t,`template-put`);if(w===null)return;let E=Bc(w===`user`?``:S.folder,t,`folder`,`template-put`);if(!E)return;let D={projectDir:E.resolvedContentDir,folder:E.folderRel,name:e,body:typeof S.body==`string`?S.body:``,frontmatter:Wc(S.frontmatter)};w!==void 0&&(D.target=w);let O=applyTemplateWrite(D);if(!O.ok){let e=O.error.code===`WRITE_ERROR`||O.error.code===`BAD_PROJECT_DIR`||O.error.code===`USER_HOME_UNAVAILABLE`?500:400;errorResponse(t,e,e===500?`urn:ok:error:internal-server-error`:`urn:ok:error:invalid-request`,e===500?`Failed to write template.`:`Invalid template request.`,{handler:`template-put`,detail:O.error.code,cause:Error(O.error.message)});return}successResponse(t,200,TemplatePutSuccessSchema,{path:O.path,created:O.created,warnings:O.warnings},{handler:`template-put`})}catch(e){errorResponse(t,500,`urn:ok:error:internal-server-error`,`Failed to write template.`,{handler:`template-put`,cause:e})}},{handler:`template-put`,method:`PUT`}),$c=withValidation(EmptyRequestSchema,async(e,t)=>{try{let S=new URL(e.url??``,`http://localhost`),w=S.searchParams.get(`name`)??``;if(!Hc(w,t,`template-delete`))return;let E=Uc(S.searchParams.get(`target`),t,`template-delete`);if(E===null)return;let D=Bc(E===`user`?``:S.searchParams.get(`folder`)??``,t,`folder`,`template-delete`);if(!D)return;let O={projectDir:D.resolvedContentDir,folder:D.folderRel,name:w};E!==void 0&&(O.target=E);let k=applyTemplateDelete(O);if(!k.ok){let e=k.error.code===`WRITE_ERROR`||k.error.code===`UNLINK_FAILED`||k.error.code===`BAD_PROJECT_DIR`||k.error.code===`USER_HOME_UNAVAILABLE`?500:400;errorResponse(t,e,e===500?`urn:ok:error:internal-server-error`:`urn:ok:error:invalid-request`,e===500?`Failed to delete template.`:`Invalid template request.`,{handler:`template-delete`,detail:k.error.code,cause:Error(k.error.message)});return}successResponse(t,200,TemplateDeleteSuccessSchema,{existed:k.existed,path:k.path},{handler:`template-delete`})}catch(e){errorResponse(t,500,`urn:ok:error:internal-server-error`,`Failed to delete template.`,{handler:`template-delete`,cause:e})}},{handler:`template-delete`,method:`DELETE`,skipBodyParse:!0});function nl(e){let t=new Map;for(let S of e){let e=S.path.split(`/`).filter(Boolean);e.pop();for(let w=1;w<=e.length;w++){let E=e.slice(0,w).join(`/`);t.set(E,Math.max(t.get(E)??0,S.modifiedTs))}}return[...t.entries()].map(([e,t])=>createWorkspaceSearchDocument({kind:`folder`,path:e,modifiedTs:t}))}function il(e,t){let S=t.trim().toLowerCase();if(!S||!e)return;let w=e.toLowerCase().indexOf(S);if(w<0)return;let E=Math.max(0,w-80),D=Math.min(e.length,w+S.length+120),O=E>0?`…`:``,k=D<e.length?`…`:``;return`${O}${e.slice(E,D).replace(/\s+/g,` `).trim()}${k}`}function al(e){return e===`autocomplete`||e===`full_text`||e===`omnibar`?e:`omnibar`}function cl(e){let t=typeof e==`string`?e.split(`,`):Array.isArray(e)?e:void 0;if(!t)return;let S=t.filter(e=>e===`page`||e===`folder`||e===`content`);return S.length>0?S:void 0}async function ll(){let e=[];for(let[t,S]of D()){if(isSystemDoc(t)||isConfigDoc(t))continue;let w=``,E=t;try{w=await readFile$1(S.canonicalPath,`utf-8`),E=extractPageTitle(w,t)}catch(e){console.warn(`[search] Failed to index ${t}:`,e)}e.push(createWorkspaceSearchDocument({kind:`page`,path:t,title:E,content:w,modifiedTs:Date.parse(S.modified)}))}return[...e,...nl(e)]}function ul(){return[...D()].filter(([e])=>!isSystemDoc(e)&&!isConfigDoc(e)).sort(([e],[t])=>e.localeCompare(t)).map(([e,t])=>`${e}${t.modified}${t.size}${t.canonicalPath}${t.inode}${t.aliases.join(`,`)}`).join(``)}async function dl(){let e=`${w}${de??``}`,t=ul(),S=workspaceSearchCaches.get(e);if(S?.fingerprint===t&&S.corpus)return S.corpus;if(S?.fingerprint===t&&S.pending)return S.pending;let E=ll().then(e=>createWorkspaceSearchCorpus(e));workspaceSearchCaches.set(e,{fingerprint:t,pending:E});try{let S=await E;return workspaceSearchCaches.get(e)?.pending===E&&workspaceSearchCaches.set(e,{fingerprint:t,corpus:S}),S}catch(t){throw workspaceSearchCaches.get(e)?.pending===E&&workspaceSearchCaches.delete(e),t}}function fl(){if(process.env.NODE_ENV!==`test`)for(let e of[0,1e3,3e3])setTimeout(()=>{dl().catch(e=>{console.warn(`[search] Failed to prewarm workspace search cache:`,e)})},e)}fl();async function pl(e,t){if(e.method===`GET`)return ml(e,t);if(e.method===`POST`)return hl(e,t);errorResponse(t,405,`urn:ok:error:method-not-allowed`,`Method not allowed.`,{handler:`search`,extraHeaders:{Allow:`GET, POST`}})}let ml=withValidation(EmptyRequestSchema,async(e,t)=>{let S=new URL(e.url??``,`http://localhost`),w=S.searchParams.get(`limit`),E=S.searchParams.get(`query`)??``,D=al(S.searchParams.get(`intent`)),O=cl(S.searchParams.get(`scope`)??S.searchParams.get(`scopes`)),k=w===null?void 0:Number(w);if(E.length>200){errorResponse(t,400,`urn:ok:error:invalid-request`,`Query is too long (max 200 chars).`,{handler:`search-get`});return}try{let e=performance.now();successResponse(t,200,SearchSuccessSchema,{query:E,intent:D,results:searchWorkspaceCorpus(await dl(),E,{intent:D,scopes:O,limit:k}).map(e=>({kind:e.document.kind,path:e.document.path,title:e.document.title,score:e.score,signals:e.signals,snippet:e.document.kind===`page`?il(e.document.content,E):void 0})),elapsedMs:Math.max(0,performance.now()-e)},{handler:`search-get`})}catch(e){errorResponse(t,500,`urn:ok:error:internal-server-error`,`Failed to search workspace.`,{handler:`search-get`,cause:e})}},{handler:`search-get`,method:`GET`,skipBodyParse:!0}),hl=withValidation(SearchRequestSchema,async(e,t,S)=>{let w=typeof S.query==`string`?S.query:``,E=al(S.intent),D=cl(S.scopes??S.scope),O=typeof S.limit==`number`?S.limit:void 0;if(w.length>200){errorResponse(t,400,`urn:ok:error:invalid-request`,`Query is too long (max 200 chars).`,{handler:`search-post`});return}try{let e=performance.now();successResponse(t,200,SearchSuccessSchema,{query:w,intent:E,results:searchWorkspaceCorpus(await dl(),w,{intent:E,scopes:D,limit:O}).map(e=>({kind:e.document.kind,path:e.document.path,title:e.document.title,score:e.score,signals:e.signals,snippet:e.document.kind===`page`?il(e.document.content,w):void 0})),elapsedMs:Math.max(0,performance.now()-e)},{handler:`search-post`})}catch(e){errorResponse(t,500,`urn:ok:error:internal-server-error`,`Failed to search workspace.`,{handler:`search-post`,cause:e})}},{handler:`search-post`,method:`POST`}),gl=withValidation(EmptyRequestSchema,async(e,t)=>{try{successResponse(t,200,SkillInstallStateSuccessSchema,{...await readSkillInstallStateSnapshot(homedir())},{handler:`skill-install-state`,extraHeaders:{"Cache-Control":`no-store`}})}catch(e){errorResponse(t,500,`urn:ok:error:internal-server-error`,`Failed to read skill install state.`,{handler:`skill-install-state`,cause:e})}},{handler:`skill-install-state`,method:`GET`,skipBodyParse:!0,preBodyGate:(e,t)=>checkLocalOpSecurity(e,t,{handler:`skill-install-state`})});async function _l(e,t){if(checkLocalOpSecurity(e,t,{handler:`handoff`}))try{await handleHandoffDispatch(e,t,{contentDir:w,platform:process.platform})}catch(e){t.headersSent||(log$2.error({err:e},`[handoff] route wrapper failed`),errorResponse(t,500,`urn:ok:error:internal-server-error`,`Internal server error.`,{handler:`handoff`,cause:e}))}}async function vl(e,t){if(checkLocalOpSecurity(e,t,{handler:`spawn-cursor`}))try{await handleSpawnCursor(e,t,{contentDir:w,platform:process.platform})}catch(e){t.headersSent||(log$2.error({err:e},`[spawn-cursor] route wrapper failed`),errorResponse(t,500,`urn:ok:error:internal-server-error`,`Internal server error.`,{handler:`spawn-cursor`,cause:e}))}}let yl={"/api/asset":Yi,"/api/document":Kt,"/api/documents":$t,"/api/backlinks":en,"/api/backlink-counts":jr,"/api/forward-links":Mr,"/api/link-graph":Fr,"/api/dead-links":zr,"/api/orphans":Ir,"/api/hubs":Lr,"/api/tags":Rc,"/api/pages":Os,"/api/folder-config":Gc,"/api/template":Jc,"/api/search":pl,"/api/suggest-links":ks,"/api/page-headings":Cs,"/api/create-page":_s,"/api/create-folder":xs,"/api/rename-path":Ts,"/api/delete-path":Ds,"/api/upload":As,"/api/agent-write":Ut,"/api/agent-write-md":Wt,"/api/agent-patch":Br,"/api/agent-undo":Vr,"/api/agent-activity":Hr,"/api/agent-burst-diff":Ur,"/api/save-version":qr,"/api/history":Jr,"/api/diff":Xr,"/api/rollback":Zr,"/api/metrics/reconciliation":Qr,"/api/metrics/parse-health":ji,"/api/metrics/agent-presence":Gi,"/api/server-info":Hi,"/api/principal":Ui,"/api/rescue":Zi,"/api/workspace":Ki,"/api/sync/status":Dc,"/api/sync/trigger":Oc,"/api/sync/conflicts":kc,"/api/sync/conflict-content":jc,"/api/sync/resolve-conflict":Ac,"/api/sync/abort-merge":Lc,"/api/local-op/clone":ec,"/api/local-op/open":ic,"/api/local-op/auth/login":dc,"/api/local-op/auth/status":mc,"/api/local-op/auth/repos":gc,"/api/local-op/auth/signout":yc,"/api/local-op/auth/pat":xc,"/api/local-op/auth/identity":Cc,"/api/local-op/auth/set-identity":Ec,"/api/installed-agents":Ic,"/api/spawn-cursor":vl,"/api/handoff":_l,"/api/install-skill":Fc,"/api/skill/install-state":gl,"/api/seed/plan":Mc,"/api/seed/apply":Nc,"/api/seed/packs":Pc};F&&(yl[`/api/test-reset`]=Wr,yl[`/api/test-rescan-backlinks`]=Gr,yl[`/api/test-rescan-files`]=Kr);let xl=new Set([`/api/upload`,`/api/create-page`,`/api/create-folder`,`/api/rename-path`,`/api/delete-path`,`/api/agent-write`,`/api/agent-write-md`,`/api/agent-patch`,`/api/agent-undo`,`/api/save-version`,`/api/rollback`,`/api/sync/trigger`,`/api/sync/resolve-conflict`,`/api/sync/abort-merge`,`/api/test-reset`,`/api/test-rescan-backlinks`,`/api/test-rescan-files`,`/api/install-skill`,`/api/folder-config`,`/api/template`,`/api/seed/apply`]),Cl=[`/api/local-op/`];return{priority:100,async onRequest({request:e,response:t}){let S=e.url?.split(`?`)[0];if(!S)return;if(S.startsWith(`/api/`)){let S=e.headers.origin;if(S!==void 0&&!isAllowedApiOrigin(S)){errorResponse(t,403,`urn:ok:error:invalid-origin`,`Origin not allowed.`,{handler:`api-origin-gate`});return}if(typeof t.setHeader==`function`&&(S!==void 0&&(t.setHeader(`Access-Control-Allow-Origin`,S),t.setHeader(`Vary`,`Origin`)),t.setHeader(`Access-Control-Allow-Methods`,`GET, POST, PUT, DELETE, OPTIONS`),t.setHeader(`Access-Control-Allow-Headers`,`Content-Type, Authorization, traceparent, tracestate, baggage`)),e.method===`OPTIONS`){t.writeHead(204),t.end();return}}if(xl.has(S)||Cl.some(e=>S.startsWith(e))){let S=e.socket?.remoteAddress;if(S!==void 0&&!isLoopbackAddress(S)){errorResponse(t,403,`urn:ok:error:loopback-required`,`Loopback required.`,{handler:`api-mutating-gate`});return}if(!isAllowedWorkspaceHostHeader(e.headers.host)){errorResponse(t,403,`urn:ok:error:host-not-allowed`,`Host header not allowed.`,{handler:`api-mutating-gate`});return}}if(!S.startsWith(`/api/`))return;let w=propagation.extract(context.active(),e.headers),E=e.method??`GET`,D=S;S.startsWith(`/api/rescue/`)?D=`/api/rescue/:docName`:S.startsWith(`/api/history/`)?D=`/api/history/:sha`:S.startsWith(`/api/tags/`)?D=`/api/tags/:name`:yl[S]||(D=`/api/*`);let O=getTracer(),k=Date.now();await context.with(w,()=>O.startActiveSpan(`HTTP ${E} ${D}`,{kind:SpanKind.SERVER,attributes:{[ATTR_HTTP_REQUEST_METHOD]:E,[ATTR_HTTP_ROUTE]:D,[ATTR_URL_PATH]:S,[ATTR_URL_SCHEME]:`http`,[ATTR_USER_AGENT_ORIGINAL]:e.headers[`user-agent`]??``}},async w=>{try{let D=yl[S],O=!1;if(D)O=!0,await D(e,t);else if(S.startsWith(`/api/rescue/`)){let w=decodeURIComponent(S.slice(12));w&&(O=!0,await ka(e,t,w))}else if(S.startsWith(`/api/history/`)){let w=decodeURIComponent(S.slice(13));w&&(O=!0,await Yr(e,t,w))}else if(S.startsWith(`/api/tags/`)){let w=S.slice(10);w&&(O=!0,await zc(e,t,w))}O||errorResponse(t,404,`urn:ok:error:not-found`,`API endpoint not found.`,{handler:`api-dispatch`,detail:`No handler for ${E} ${S}`});let k=t.statusCode;w.setAttribute(ATTR_HTTP_RESPONSE_STATUS_CODE,k),k>=500&&w.setStatus({code:SpanStatusCode.ERROR,message:`status ${k}`})}catch(e){throw w.recordException(e),w.setStatus({code:SpanStatusCode.ERROR,message:e instanceof Error?e.message:String(e)}),!t.headersSent&&!t.writableEnded&&!t.destroyed&&errorResponse(t,500,`urn:ok:error:internal-server-error`,`Internal server error.`,{handler:D,cause:e}),e}finally{w.end();let e=(Date.now()-k)/1e3;httpDurationHist().record(e,{[ATTR_HTTP_REQUEST_METHOD]:E,[ATTR_HTTP_ROUTE]:D,[ATTR_HTTP_RESPONSE_STATUS_CODE]:t.statusCode})}}))}}}function isWithinDir(e,t){return e===t?!0:e.startsWith(`${t}${sep}`)}function errnoCode(e){let t=e?.code;return typeof t==`string`?t:void 0}function seedBasenameIndex(e){let t=e.contentDir,S=new Set;function w(E){let D;try{D=readdirSync(E,{withFileTypes:!0})}catch(t){let S=errnoCode(t);S!==`ENOENT`&&e.onSkip?.(`read-failed`,S,E);return}for(let O of D){let D=join(E,O.name),k=relative(t,D);if(k.startsWith(`..`)||e.contentFilter?.isDirExcluded(k)&&O.isDirectory())continue;let j;try{j=lstatSync(D)}catch(t){let S=errnoCode(t);S!==`ENOENT`&&e.onSkip?.(`lstat-failed`,S,D);continue}if(j.isSymbolicLink()){let E;try{E=realpathSync(D)}catch(t){let S=errnoCode(t);S!==`ENOENT`&&e.onSkip?.(`realpath-failed`,S,D);continue}if(!isWithinDir(E,t)){e.onSkip?.(`symlink-escape`,void 0,D);continue}let O;try{O=statSync(E)}catch(t){let S=errnoCode(t);S!==`ENOENT`&&e.onSkip?.(`symlink-stat-failed`,S,E);continue}if(S.has(O.ino))continue;S.add(O.ino),O.isDirectory()?w(E):O.isFile()&&isSupportedAssetFile(D,ASSET_EXTENSIONS)&&!e.contentFilter?.isExcluded(k)&&e.basenameIndex.add(k);continue}if(j.isDirectory()){if(S.has(j.ino))continue;S.add(j.ino),w(D);continue}j.isFile()&&isSupportedAssetFile(D,ASSET_EXTENSIONS)&&!e.contentFilter?.isExcluded(k)&&e.basenameIndex.add(k)}}w(t)}const HocuspocusAuthTokenSchema=object$1({principalId:string$2().optional(),tabSessionId:string$2().optional(),expectedServerInstanceId:string$2().optional(),expectedBranch:string$2().optional()}).loose(),HOCUSPOCUS_AUTH_REJECTION_REASONS=[`server-instance-mismatch`,`branch-mismatch`,`rename-redirect`,`doc-deleted`];function isHocuspocusAuthRejectionReason(e){return HOCUSPOCUS_AUTH_REJECTION_REASONS.includes(e)}const WIRE_PAYLOAD_SEPARATOR=`:`;function formatAuthRejectionWire(e,t){return typeof t!=`string`||t.length===0?e:`${e}${WIRE_PAYLOAD_SEPARATOR}${t}`}function parseAuthRejectionWire(e){if(e.length===0)return{kind:null,payload:void 0};let t=e.indexOf(WIRE_PAYLOAD_SEPARATOR),S=t===-1?e:e.slice(0,t);if(!isHocuspocusAuthRejectionReason(S))return{kind:null,payload:void 0};if(t===-1)return{kind:S,payload:void 0};let w=e.slice(t+1);return{kind:S,payload:w.length>0?w:void 0}}var HocuspocusAuthRejection=class extends Error{kind;payload;reason;constructor(e,t,S){super(t),this.name=`HocuspocusAuthRejection`,this.kind=e,this.payload=typeof S==`string`&&S.length>0?S:void 0,this.reason=formatAuthRejectionWire(e,this.payload)}};function parseHocuspocusAuthToken(e){if(typeof e!=`string`||e.length===0)return;let t;try{t=JSON.parse(e)}catch{return}let S=HocuspocusAuthTokenSchema.safeParse(t);return S.success?S.data:void 0}const DEFAULT_WARN_BEFORE_MS=300*1e3;function attachIdleShutdown(e){let t=e.scheduler??defaultScheduler,S=e.warnBeforeMs??DEFAULT_WARN_BEFORE_MS,w=0,E=null,D=null,O=!1,k=!1;function j(){E!==null&&(t.clearTimeout(E),E=null),D!==null&&(t.clearTimeout(D),D=null)}function F(){j(),!(k||O)&&w===0&&(S>0&&S<e.thresholdMs&&(D=t.setTimeout(()=>{D=null,w===0&&!O&&e.log?.warn({msUntilShutdown:S,webSocketClientCount:0},`idle shutdown pending: no WebSocket clients`)},e.thresholdMs-S)),E=t.setTimeout(()=>{if(E=null,!(k||O)&&w===0){O=!0,e.log?.info({webSocketClientCount:0},`idle shutdown firing`);try{let t=e.onShutdown();t&&typeof t.then==`function`&&t.catch(t=>{e.log?.error({err:t},`idle shutdown handler rejected`)})}catch(t){e.log?.error({err:t},`idle shutdown handler threw`)}}},e.thresholdMs))}let L=(e,t)=>{e.url?.startsWith(`/collab`)&&(w++,j(),t.once(`close`,()=>{w--,w<0&&(w=0),w===0&&F()}))};return e.httpServer.on(`upgrade`,L),F(),{detach:()=>{k||(k=!0,e.httpServer.off(`upgrade`,L),j())}}}const MCP_SERVER_NAME=`open-knowledge`,MCP_CONNECTION_ID_HEADER=`x-ok-connection-id`;function sanitizeClientName(e,t){let S=Array.from(e??``).map(e=>{let t=e.charCodeAt(0);return t<=31||t===127?` `:e}).join(``).replace(/\s+/g,` `).trim();return S?S.slice(0,128):t}function buildInstructions(e){return`# Open Knowledge (OK) — collaborative markdown via MCP
|
|
2282
|
+
`).map(e=>e.trim()).filter(Boolean),k=null;for(let e=O.length-1;e>=0;e--)try{k=JSON.parse(O[e]);break}catch{}k===null?successResponse(t,200,LocalOpAuthPatSuccessSchema,{},{handler:bc}):successResponse(t,200,LocalOpAuthPatSuccessSchema,k,{handler:bc})}catch(e){errorResponse(t,500,`urn:ok:error:auth-failed`,`Auth pat failed.`,{handler:bc,cause:e})}finally{Ce.release(lc)}},{handler:bc,method:`POST`,preBodyGate:(e,t)=>checkLocalOpSecurity(e,t,{handler:bc})}),Sc=`local-op-auth-identity`;async function Cc(e,t){if(checkLocalOpSecurity(e,t,{handler:Sc})){if(e.method!==`GET`){errorResponse(t,405,`urn:ok:error:method-not-allowed`,`Method not allowed.`,{handler:Sc,extraHeaders:{Allow:`GET`}});return}if(!de){errorResponse(t,503,`urn:ok:error:no-project-dir`,`No project directory configured.`,{handler:Sc});return}try{successResponse(t,200,LocalOpAuthIdentitySuccessSchema,{identity:await resolveGitIdentity(de)},{handler:Sc})}catch(e){errorResponse(t,500,`urn:ok:error:internal-server-error`,`Identity resolution failed.`,{handler:Sc,cause:e})}}}let wc=`/api/local-op/auth/set-identity`,Tc=`local-op-auth-set-identity`,Ec=withValidation(LocalOpAuthSetIdentityRequestSchema,async(e,t,S)=>{let w=S.name.trim(),E=S.email.trim();if(!de){errorResponse(t,503,`urn:ok:error:no-project-dir`,`No project directory configured.`,{handler:Tc});return}if(!Ce.tryAcquire(wc)){errorResponse(t,429,`urn:ok:error:concurrent-operation`,`A set-identity operation is already in progress.`,{handler:Tc,extraHeaders:{"Retry-After":`5`}});return}try{writeGitIdentity(de,w,E),ce?.()?.refreshIdentity().catch(()=>{}),successResponse(t,200,LocalOpAuthEmptySuccessSchema,{},{handler:Tc})}catch(e){errorResponse(t,500,`urn:ok:error:internal-server-error`,`Set-identity failed.`,{handler:Tc,cause:e})}finally{Ce.release(wc)}},{handler:Tc,method:`POST`,preBodyGate:(e,t)=>checkLocalOpSecurity(e,t,{handler:Tc})});async function Dc(e,t){if(checkLocalOpSecurity(e,t,{handler:`sync-status`})){if(e.method!==`GET`){errorResponse(t,405,`urn:ok:error:method-not-allowed`,`Method not allowed.`,{handler:`sync-status`,extraHeaders:{Allow:`GET`}});return}try{let e=ce?.();if(!e){successResponse(t,200,SyncStatusSchema,{state:`dormant`,lastSyncUtc:null,lastFetchUtc:null,lastPushedSha:null,ahead:0,behind:0,consecutiveFailures:0,conflictCount:0,hasRemote:!1,syncEnabled:!1,identityUnresolved:!1},{handler:`sync-status`});return}await e.refreshRemote(),successResponse(t,200,SyncStatusSchema,e.getStatus(),{handler:`sync-status`})}catch(e){errorResponse(t,500,`urn:ok:error:internal-server-error`,`Internal server error.`,{handler:`sync-status`,cause:e})}}}let Oc=withValidation(SyncTriggerRequestSchema,async(e,t,S)=>{let w=ce?.();if(!w){errorResponse(t,503,`urn:ok:error:sync-not-active`,`Sync engine not active.`,{handler:`sync-trigger`});return}let E=S.op??`sync`;successResponse(t,202,SyncTriggerSuccessSchema,{op:E},{handler:`sync-trigger`}),w.trigger(E)},{handler:`sync-trigger`,method:`POST`,preBodyGate:(e,t)=>checkLocalOpSecurity(e,t,{handler:`sync-trigger`})?ce?.()?!0:(errorResponse(t,503,`urn:ok:error:sync-not-active`,`Sync engine not active.`,{handler:`sync-trigger`}),!1):!1});async function kc(e,t){if(checkLocalOpSecurity(e,t,{handler:`sync-conflicts`})){if(e.method!==`GET`){errorResponse(t,405,`urn:ok:error:method-not-allowed`,`Method not allowed.`,{handler:`sync-conflicts`,extraHeaders:{Allow:`GET`}});return}try{let e=ce?.();successResponse(t,200,SyncConflictsSuccessSchema,{conflicts:e?e.getConflicts():[]},{handler:`sync-conflicts`})}catch(e){errorResponse(t,500,`urn:ok:error:internal-server-error`,`Internal server error.`,{handler:`sync-conflicts`,cause:e})}}}let Ac=withValidation(SyncResolveConflictRequestSchema,async(e,t,S)=>{let w=ce?.();if(!w){errorResponse(t,503,`urn:ok:error:sync-not-active`,`Sync engine not active.`,{handler:`sync-resolve-conflict`});return}let{file:E,strategy:D,content:O}=S;try{await w.resolveConflict(E,D,O),successResponse(t,200,SyncResolveConflictSuccessSchema,{},{handler:`sync-resolve-conflict`})}catch(e){errorResponse(t,500,`urn:ok:error:internal-server-error`,`Failed to resolve conflict.`,{handler:`sync-resolve-conflict`,cause:e})}},{handler:`sync-resolve-conflict`,method:`POST`,preBodyGate:(e,t)=>checkLocalOpSecurity(e,t,{handler:`sync-resolve-conflict`})?ce?.()?!0:(errorResponse(t,503,`urn:ok:error:sync-not-active`,`Sync engine not active.`,{handler:`sync-resolve-conflict`}),!1):!1});async function jc(e,t){if(!checkLocalOpSecurity(e,t,{handler:`sync-conflict-content`}))return;if(e.method!==`GET`){errorResponse(t,405,`urn:ok:error:method-not-allowed`,`Method not allowed.`,{handler:`sync-conflict-content`,extraHeaders:{Allow:`GET`}});return}if(!de){errorResponse(t,503,`urn:ok:error:project-repo-not-configured`,`Project repo not configured.`,{handler:`sync-conflict-content`});return}let S=new URL(e.url??`/`,`http://${e.headers.host??`localhost`}`).searchParams.get(`file`);if(!S){errorResponse(t,400,`urn:ok:error:invalid-request`,`Missing required query param: file.`,{handler:`sync-conflict-content`});return}if(S.includes(`..`)||S.startsWith(`/`)){errorResponse(t,400,`urn:ok:error:invalid-request`,`Invalid file path.`,{handler:`sync-conflict-content`});return}let w=esm_default({baseDir:de,timeout:{block:15e3}});async function E(e){try{return await w.raw([`show`,`:${e}:${S}`])}catch{return``}}try{let[e,w,D]=await Promise.all([E(1),E(2),E(3)]);successResponse(t,200,SyncConflictContentSuccessSchema,{file:S,base:e,ours:w,theirs:D},{handler:`sync-conflict-content`})}catch(e){errorResponse(t,500,`urn:ok:error:internal-server-error`,`Failed to read conflict content.`,{handler:`sync-conflict-content`,cause:e})}}async function Mc(e,t){if(!checkLocalOpSecurity(e,t,{handler:`seed-plan`}))return;if(e.method!==`GET`){errorResponse(t,405,`urn:ok:error:method-not-allowed`,`Method not allowed.`,{handler:`seed-plan`,extraHeaders:{Allow:`GET`}});return}let S=new URL(e.url??`/`,`http://localhost`),E=S.searchParams.get(`rootDir`)??void 0,D=S.searchParams.get(`packId`),O=coercePackId(D);if(D!==null&&D!==``&&O===void 0){errorResponse(t,400,`urn:ok:error:invalid-request`,`Unknown packId.`,{handler:`seed-plan`,detail:`Pack id "${D}" is not registered.`});return}let k=S.searchParams.get(`includePersonalTemplates`)===`true`;try{let e=await planSeed({projectDir:w,rootDir:E,packId:O});successResponse(t,200,SeedPlanSuccessSchema,{plan:k?{...e,personalTemplates:planPersonalTemplates()}:e},{handler:`seed-plan`})}catch(e){if(e instanceof SeedPrerequisiteError){errorResponse(t,422,`urn:ok:error:seed-prerequisite-missing`,`Seed prerequisite missing.`,{handler:`seed-plan`,cause:e});return}if(e instanceof SeedRootDirError){errorResponse(t,400,`urn:ok:error:seed-invalid-root`,`Invalid seed root directory.`,{handler:`seed-plan`,detail:`The provided root directory is not within the workspace content directory.`,cause:e});return}errorResponse(t,500,`urn:ok:error:internal-server-error`,`Internal server error.`,{handler:`seed-plan`,cause:e})}}let Nc=withValidation(SeedApplyRequestSchema,async(e,t,S)=>{let E=S.plan;if(!E||typeof E!=`object`){errorResponse(t,400,`urn:ok:error:invalid-request`,`Invalid plan payload.`,{handler:`seed-apply`});return}let D=E,O=S,k=O.packId,j=coercePackId(k);if(typeof k==`string`&&k.length>0&&j===void 0){errorResponse(t,400,`urn:ok:error:invalid-request`,`Unknown packId.`,{handler:`seed-apply`,detail:`Pack id "${k}" is not registered.`});return}let F=O.includePersonalTemplates===!0;try{let e=await applySeed(D,{projectDir:w,packId:j}),S=F?writePersonalTemplates():void 0;successResponse(t,200,SeedApplySuccessSchema,S?{result:e,personalTemplates:S}:{result:e},{handler:`seed-apply`})}catch(e){errorResponse(t,500,`urn:ok:error:internal-server-error`,`Failed to apply seed plan.`,{handler:`seed-apply`,cause:e})}},{handler:`seed-apply`,method:`POST`,preBodyGate:(e,t)=>checkLocalOpSecurity(e,t,{handler:`seed-apply`})});async function Pc(e,t){if(checkLocalOpSecurity(e,t,{handler:`seed-packs`})){if(e.method!==`GET`){errorResponse(t,405,`urn:ok:error:method-not-allowed`,`Method not allowed.`,{handler:`seed-packs`,extraHeaders:{Allow:`GET`}});return}successResponse(t,200,SeedListPacksSuccessSchema,{packs:listStarterPacks()},{handler:`seed-packs`})}}let Fc=withValidation(InstallSkillRequestSchema,async(e,t,S)=>{if(S.out!==void 0&&!isSafeLocalPath(S.out)){errorResponse(t,400,`urn:ok:error:invalid-request`,`Output path must be within home directory.`,{handler:`install-skill`});return}try{successResponse(t,200,InstallSkillSuccessSchema,await buildAndOpenSkill({...S.noOpen===void 0?{}:{noOpen:S.noOpen},...S.out===void 0?{}:{out:S.out}}),{handler:`install-skill`})}catch(e){errorResponse(t,500,`urn:ok:error:internal-server-error`,`Failed to install skill.`,{handler:`install-skill`,cause:e})}},{handler:`install-skill`,method:`POST`,preBodyGate:(e,t)=>checkLocalOpSecurity(e,t,{handler:`install-skill`})});async function Ic(e,t){if(checkLocalOpSecurity(e,t,{handler:`installed-agents`}))try{await handleInstalledAgents(e,t,Re.probeAll)}catch(e){t.headersSent||(log$2.error({err:e},`[installed-agents] route wrapper failed`),errorResponse(t,500,`urn:ok:error:internal-server-error`,`Internal server error.`,{handler:`installed-agents`,cause:e}))}}async function Lc(e,t){if(!checkLocalOpSecurity(e,t,{handler:`sync-abort-merge`}))return;if(e.method!==`POST`){errorResponse(t,405,`urn:ok:error:method-not-allowed`,`Method not allowed.`,{handler:`sync-abort-merge`,extraHeaders:{Allow:`POST`}});return}let S=ce?.();if(!S){errorResponse(t,503,`urn:ok:error:sync-not-active`,`Sync engine not active.`,{handler:`sync-abort-merge`});return}try{await S.abortMerge(),successResponse(t,200,SyncAbortMergeSuccessSchema,{},{handler:`sync-abort-merge`})}catch(e){errorResponse(t,500,`urn:ok:error:internal-server-error`,`Failed to abort merge.`,{handler:`sync-abort-merge`,cause:e})}}let Rc=withValidation(EmptyRequestSchema,async(e,t)=>{if(!te){errorResponse(t,503,`urn:ok:error:tag-index-not-configured`,`Tag index not configured.`,{handler:`tags-list`});return}try{successResponse(t,200,TagsListSuccessSchema,{tags:te.getAllTags()},{handler:`tags-list`})}catch(e){errorResponse(t,500,`urn:ok:error:internal-server-error`,`Failed to read tags.`,{handler:`tags-list`,cause:e})}},{handler:`tags-list`,method:`GET`,skipBodyParse:!0});async function zc(e,t,S){if(e.method!==`GET`){errorResponse(t,405,`urn:ok:error:method-not-allowed`,`Method not allowed.`,{handler:`tags-for-name`,extraHeaders:{Allow:`GET`}});return}if(!te){errorResponse(t,503,`urn:ok:error:tag-index-not-configured`,`Tag index not configured.`,{handler:`tags-for-name`});return}let w;try{w=decodeURIComponent(S)}catch{errorResponse(t,400,`urn:ok:error:invalid-request`,`Invalid tag name encoding.`,{handler:`tags-for-name`});return}if(!w){errorResponse(t,400,`urn:ok:error:invalid-request`,`Missing tag name.`,{handler:`tags-for-name`});return}try{let e=te.getDocsForTagWithMatches(w).map(({docName:e,matchingTags:t})=>({docName:e,title:Be(e),matchingTags:t,snippet:null}));successResponse(t,200,TagsForNameSuccessSchema,{name:w,docs:e},{handler:`tags-for-name`})}catch(e){errorResponse(t,500,`urn:ok:error:internal-server-error`,`Failed to read tag membership.`,{handler:`tags-for-name`,cause:e})}}function Bc(e,t,S=`path`,E=`folder-config`){let D=e.replace(/^\.\//,``).replace(/^\/+/,``).replace(/\/+$/,``);if(D.split(`/`).some(e=>e===`..`)||e.startsWith(`/`))return errorResponse(t,400,`urn:ok:error:invalid-request`,`Invalid ${S}: must be project-root-relative.`,{handler:E}),null;let O=resolve(w),k=D===``?O:resolve(O,D);return k!==O&&!k.startsWith(`${O}${sep}`)?(errorResponse(t,400,`urn:ok:error:invalid-request`,`Path escapes content directory.`,{handler:E}),null):{folderRel:D,resolvedContentDir:O}}let Vc=/^[A-Za-z0-9_-]+$/;function Hc(e,t,S=`template`){return!e||!Vc.test(e)?(errorResponse(t,400,`urn:ok:error:invalid-request`,"Invalid name: must be letters / digits / `_` / `-` only (no `.md` extension).",{handler:S}),!1):!0}function Uc(e,t,S=`template`){if(!(e==null||e===``))return e===`project`||e===`user`?e:(errorResponse(t,400,`urn:ok:error:invalid-request`,`target must be "project" or "user", got: ${JSON.stringify(e)}`,{handler:S}),null)}function Wc(e){let t={};if(!e||typeof e!=`object`||Array.isArray(e))return t;for(let[S,w]of Object.entries(e))w!==void 0&&(t[S]=w);return t}async function Gc(e,t){if(e.method===`GET`)return Kc(e,t);if(e.method===`PUT`)return qc(e,t);errorResponse(t,405,`urn:ok:error:method-not-allowed`,`Method not allowed.`,{handler:`folder-config`,extraHeaders:{Allow:`GET, PUT`}})}let Kc=withValidation(EmptyRequestSchema,async(e,t)=>{try{let S=Bc(new URL(e.url??``,`http://localhost`).searchParams.get(`path`)??``,t,`path`,`folder-config-get`);if(!S)return;let w=await enrichDirectory(S.folderRel,{projectDir:S.resolvedContentDir}),E=resolve(S.resolvedContentDir,S.folderRel,`.ok`,`frontmatter.yml`),D=null;if(existsSync(E))try{let e=(0,import_dist$1.parse)(await readFile$1(E,`utf-8`));D=e&&typeof e==`object`&&!Array.isArray(e)?e:{}}catch(e){let t=e instanceof Error?e.message:String(e);console.warn(`[folder-config:get] malformed YAML in ${E}: ${t}`),D=null}successResponse(t,200,FolderConfigGetSuccessSchema,{folder:w,frontmatter_local:D},{handler:`folder-config-get`})}catch(e){errorResponse(t,500,`urn:ok:error:internal-server-error`,`Failed to read folder config.`,{handler:`folder-config-get`,cause:e})}},{handler:`folder-config-get`,method:`GET`,skipBodyParse:!0}),qc=withValidation(FolderConfigPutRequestSchema,async(e,t,S)=>{try{let e=Bc(S.path,t,`path`,`folder-config-put`);if(!e)return;let w=e.folderRel===``?`**`:`${e.folderRel}/**`,E=applyNestedFolderRulesUpsert({projectDir:e.resolvedContentDir,rules:[{match:w,frontmatter:Wc(S.frontmatter)}]});if(!E.ok){let e=E.error.code===`WRITE_ERROR`||E.error.code===`BAD_PROJECT_DIR`?500:400;errorResponse(t,e,e===500?`urn:ok:error:internal-server-error`:`urn:ok:error:invalid-request`,e===500?`Failed to write folder config.`:`Invalid folder config request.`,{handler:`folder-config-put`,detail:E.error.code,cause:Error(E.error.message)});return}successResponse(t,200,FolderConfigPutSuccessSchema,{applied:E.applied},{handler:`folder-config-put`})}catch(e){errorResponse(t,500,`urn:ok:error:internal-server-error`,`Failed to write folder config.`,{handler:`folder-config-put`,cause:e})}},{handler:`folder-config-put`,method:`PUT`});async function Jc(e,t){if(e.method===`GET`)return Zc(e,t);if(e.method===`PUT`)return Qc(e,t);if(e.method===`DELETE`)return $c(e,t);errorResponse(t,405,`urn:ok:error:method-not-allowed`,`Method not allowed.`,{handler:`template`,extraHeaders:{Allow:`GET, PUT, DELETE`}})}let Yc=/^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/,Xc=e=>{let t=e.match(Yc),S={},w=e;if(t){try{let e=(0,import_dist$1.parse)(t[1]??``);e&&typeof e==`object`&&!Array.isArray(e)&&(S=e)}catch{}w=e.slice(t[0].length)}return{frontmatter:S,body:w}},Zc=withValidation(EmptyRequestSchema,async(e,t)=>{try{let S=new URL(e.url??``,`http://localhost`),w=S.searchParams.get(`name`)??``;if(!Hc(w,t,`template-get`))return;let E=Uc(S.searchParams.get(`target`),t,`template-get`);if(E===null)return;if(E===`user`){let e=getUserHome();if(!e){errorResponse(t,500,`urn:ok:error:internal-server-error`,`User home directory could not be resolved.`,{handler:`template-get`});return}let S=resolve(e,`.ok`,`templates`,`${w}.md`);if(!existsSync(S)){errorResponse(t,404,`urn:ok:error:template-not-found`,`Template not found.`,{handler:`template-get`,detail:`User template "${w}" not found at ~/.ok/templates/${w}.md`});return}let{frontmatter:E,body:D}=Xc(await readFile$1(S,`utf-8`));successResponse(t,200,TemplateGetSuccessSchema,{template:{name:w,folder:`~/.ok`,scope:`user`,path:`~/.ok/templates/${w}.md`,frontmatter:E,body:D}},{handler:`template-get`});return}let D=Bc(S.searchParams.get(`folder`)??``,t,`folder`,`template-get`);if(!D)return;let{folderRel:O,resolvedContentDir:k}=D,j=O===``?[]:O.split(`/`),F=null,L=null,B=null;for(let e=j.length;e>=0;e--){let t=e===0?``:j.slice(0,e).join(`/`),S=t===``?k:resolve(k,t);if(S!==k&&!S.startsWith(`${k}${sep}`))continue;let E=resolve(S,`.ok`,`templates`,`${w}.md`);if(existsSync(E)){F=E,L=t,B=e===j.length?`local`:`inherited`;break}}if(!F||L===null||B===null){errorResponse(t,404,`urn:ok:error:template-not-found`,`Template not found.`,{handler:`template-get`,detail:`Template "${w}" not found for folder "${O||`.`}". Walked leaf → root.`});return}let{frontmatter:H,body:q}=Xc(await readFile$1(F,`utf-8`)),J=relative(k,F).split(/[\\/]/).filter(Boolean).join(`/`);successResponse(t,200,TemplateGetSuccessSchema,{template:{name:w,folder:L,scope:B,path:J,frontmatter:H,body:q}},{handler:`template-get`})}catch(e){errorResponse(t,500,`urn:ok:error:internal-server-error`,`Failed to read template.`,{handler:`template-get`,cause:e})}},{handler:`template-get`,method:`GET`,skipBodyParse:!0}),Qc=withValidation(TemplatePutRequestSchema,async(e,t,S)=>{try{let e=S.name;if(!Hc(e,t,`template-put`))return;let w=Uc(S.target,t,`template-put`);if(w===null)return;let E=Bc(w===`user`?``:S.folder,t,`folder`,`template-put`);if(!E)return;let D={projectDir:E.resolvedContentDir,folder:E.folderRel,name:e,body:typeof S.body==`string`?S.body:``,frontmatter:Wc(S.frontmatter)};w!==void 0&&(D.target=w);let O=applyTemplateWrite(D);if(!O.ok){let e=O.error.code===`WRITE_ERROR`||O.error.code===`BAD_PROJECT_DIR`||O.error.code===`USER_HOME_UNAVAILABLE`?500:400;errorResponse(t,e,e===500?`urn:ok:error:internal-server-error`:`urn:ok:error:invalid-request`,e===500?`Failed to write template.`:`Invalid template request.`,{handler:`template-put`,detail:O.error.code,cause:Error(O.error.message)});return}successResponse(t,200,TemplatePutSuccessSchema,{path:O.path,created:O.created,warnings:O.warnings},{handler:`template-put`})}catch(e){errorResponse(t,500,`urn:ok:error:internal-server-error`,`Failed to write template.`,{handler:`template-put`,cause:e})}},{handler:`template-put`,method:`PUT`}),$c=withValidation(EmptyRequestSchema,async(e,t)=>{try{let S=new URL(e.url??``,`http://localhost`),w=S.searchParams.get(`name`)??``;if(!Hc(w,t,`template-delete`))return;let E=Uc(S.searchParams.get(`target`),t,`template-delete`);if(E===null)return;let D=Bc(E===`user`?``:S.searchParams.get(`folder`)??``,t,`folder`,`template-delete`);if(!D)return;let O={projectDir:D.resolvedContentDir,folder:D.folderRel,name:w};E!==void 0&&(O.target=E);let k=applyTemplateDelete(O);if(!k.ok){let e=k.error.code===`WRITE_ERROR`||k.error.code===`UNLINK_FAILED`||k.error.code===`BAD_PROJECT_DIR`||k.error.code===`USER_HOME_UNAVAILABLE`?500:400;errorResponse(t,e,e===500?`urn:ok:error:internal-server-error`:`urn:ok:error:invalid-request`,e===500?`Failed to delete template.`:`Invalid template request.`,{handler:`template-delete`,detail:k.error.code,cause:Error(k.error.message)});return}successResponse(t,200,TemplateDeleteSuccessSchema,{existed:k.existed,path:k.path},{handler:`template-delete`})}catch(e){errorResponse(t,500,`urn:ok:error:internal-server-error`,`Failed to delete template.`,{handler:`template-delete`,cause:e})}},{handler:`template-delete`,method:`DELETE`,skipBodyParse:!0});function nl(e){let t=new Map;for(let S of e){let e=S.path.split(`/`).filter(Boolean);e.pop();for(let w=1;w<=e.length;w++){let E=e.slice(0,w).join(`/`);t.set(E,Math.max(t.get(E)??0,S.modifiedTs))}}return[...t.entries()].map(([e,t])=>createWorkspaceSearchDocument({kind:`folder`,path:e,modifiedTs:t}))}function il(e,t){let S=t.trim().toLowerCase();if(!S||!e)return;let w=e.toLowerCase().indexOf(S);if(w<0)return;let E=Math.max(0,w-80),D=Math.min(e.length,w+S.length+120),O=E>0?`…`:``,k=D<e.length?`…`:``;return`${O}${e.slice(E,D).replace(/\s+/g,` `).trim()}${k}`}function al(e){return e===`autocomplete`||e===`full_text`||e===`omnibar`?e:`omnibar`}function cl(e){let t=typeof e==`string`?e.split(`,`):Array.isArray(e)?e:void 0;if(!t)return;let S=t.filter(e=>e===`page`||e===`folder`||e===`content`);return S.length>0?S:void 0}async function ll(){let e=[];for(let[t,S]of D()){if(isSystemDoc(t)||isConfigDoc(t))continue;let w=``,E=t;try{w=await readFile$1(S.canonicalPath,`utf-8`),E=extractPageTitle(w,t)}catch(e){console.warn(`[search] Failed to index ${t}:`,e)}e.push(createWorkspaceSearchDocument({kind:`page`,path:t,title:E,content:w,modifiedTs:Date.parse(S.modified)}))}return[...e,...nl(e)]}function ul(){return[...D()].filter(([e])=>!isSystemDoc(e)&&!isConfigDoc(e)).sort(([e],[t])=>e.localeCompare(t)).map(([e,t])=>`${e}${t.modified}${t.size}${t.canonicalPath}${t.inode}${t.aliases.join(`,`)}`).join(``)}async function dl(){let e=`${w}${de??``}`,t=ul(),S=workspaceSearchCaches.get(e);if(S?.fingerprint===t&&S.corpus)return S.corpus;if(S?.fingerprint===t&&S.pending)return S.pending;let E=ll().then(e=>createWorkspaceSearchCorpus(e));workspaceSearchCaches.set(e,{fingerprint:t,pending:E});try{let S=await E;return workspaceSearchCaches.get(e)?.pending===E&&workspaceSearchCaches.set(e,{fingerprint:t,corpus:S}),S}catch(t){throw workspaceSearchCaches.get(e)?.pending===E&&workspaceSearchCaches.delete(e),t}}function fl(){if(process.env.NODE_ENV!==`test`)for(let e of[0,1e3,3e3])setTimeout(()=>{dl().catch(e=>{console.warn(`[search] Failed to prewarm workspace search cache:`,e)})},e)}fl();async function pl(e,t){if(e.method===`GET`)return ml(e,t);if(e.method===`POST`)return hl(e,t);errorResponse(t,405,`urn:ok:error:method-not-allowed`,`Method not allowed.`,{handler:`search`,extraHeaders:{Allow:`GET, POST`}})}let ml=withValidation(EmptyRequestSchema,async(e,t)=>{let S=new URL(e.url??``,`http://localhost`),w=S.searchParams.get(`limit`),E=S.searchParams.get(`query`)??``,D=al(S.searchParams.get(`intent`)),O=cl(S.searchParams.get(`scope`)??S.searchParams.get(`scopes`)),k=w===null?void 0:Number(w);if(E.length>200){errorResponse(t,400,`urn:ok:error:invalid-request`,`Query is too long (max 200 chars).`,{handler:`search-get`});return}try{let e=performance.now();successResponse(t,200,SearchSuccessSchema,{query:E,intent:D,results:searchWorkspaceCorpus(await dl(),E,{intent:D,scopes:O,limit:k}).map(e=>({kind:e.document.kind,path:e.document.path,title:e.document.title,score:e.score,signals:e.signals,snippet:e.document.kind===`page`?il(e.document.content,E):void 0})),elapsedMs:Math.max(0,performance.now()-e)},{handler:`search-get`})}catch(e){errorResponse(t,500,`urn:ok:error:internal-server-error`,`Failed to search workspace.`,{handler:`search-get`,cause:e})}},{handler:`search-get`,method:`GET`,skipBodyParse:!0}),hl=withValidation(SearchRequestSchema,async(e,t,S)=>{let w=typeof S.query==`string`?S.query:``,E=al(S.intent),D=cl(S.scopes??S.scope),O=typeof S.limit==`number`?S.limit:void 0;if(w.length>200){errorResponse(t,400,`urn:ok:error:invalid-request`,`Query is too long (max 200 chars).`,{handler:`search-post`});return}try{let e=performance.now();successResponse(t,200,SearchSuccessSchema,{query:w,intent:E,results:searchWorkspaceCorpus(await dl(),w,{intent:E,scopes:D,limit:O}).map(e=>({kind:e.document.kind,path:e.document.path,title:e.document.title,score:e.score,signals:e.signals,snippet:e.document.kind===`page`?il(e.document.content,w):void 0})),elapsedMs:Math.max(0,performance.now()-e)},{handler:`search-post`})}catch(e){errorResponse(t,500,`urn:ok:error:internal-server-error`,`Failed to search workspace.`,{handler:`search-post`,cause:e})}},{handler:`search-post`,method:`POST`}),gl=withValidation(EmptyRequestSchema,async(e,t)=>{try{successResponse(t,200,SkillInstallStateSuccessSchema,{...await readSkillInstallStateSnapshot(homedir())},{handler:`skill-install-state`,extraHeaders:{"Cache-Control":`no-store`}})}catch(e){errorResponse(t,500,`urn:ok:error:internal-server-error`,`Failed to read skill install state.`,{handler:`skill-install-state`,cause:e})}},{handler:`skill-install-state`,method:`GET`,skipBodyParse:!0,preBodyGate:(e,t)=>checkLocalOpSecurity(e,t,{handler:`skill-install-state`})});async function _l(e,t){if(checkLocalOpSecurity(e,t,{handler:`handoff`}))try{await handleHandoffDispatch(e,t,{contentDir:w,platform:process.platform})}catch(e){t.headersSent||(log$2.error({err:e},`[handoff] route wrapper failed`),errorResponse(t,500,`urn:ok:error:internal-server-error`,`Internal server error.`,{handler:`handoff`,cause:e}))}}async function vl(e,t){if(checkLocalOpSecurity(e,t,{handler:`spawn-cursor`}))try{await handleSpawnCursor(e,t,{contentDir:w,platform:process.platform})}catch(e){t.headersSent||(log$2.error({err:e},`[spawn-cursor] route wrapper failed`),errorResponse(t,500,`urn:ok:error:internal-server-error`,`Internal server error.`,{handler:`spawn-cursor`,cause:e}))}}let yl={"/api/asset":Yi,"/api/document":Kt,"/api/documents":$t,"/api/backlinks":en,"/api/backlink-counts":jr,"/api/forward-links":Mr,"/api/link-graph":Fr,"/api/dead-links":zr,"/api/orphans":Ir,"/api/hubs":Lr,"/api/tags":Rc,"/api/pages":Os,"/api/folder-config":Gc,"/api/template":Jc,"/api/search":pl,"/api/suggest-links":ks,"/api/page-headings":Cs,"/api/create-page":_s,"/api/create-folder":xs,"/api/rename-path":Ts,"/api/delete-path":Ds,"/api/upload":As,"/api/agent-write":Ut,"/api/agent-write-md":Wt,"/api/agent-patch":Br,"/api/agent-undo":Vr,"/api/agent-activity":Hr,"/api/agent-burst-diff":Ur,"/api/save-version":qr,"/api/history":Jr,"/api/diff":Xr,"/api/rollback":Zr,"/api/metrics/reconciliation":Qr,"/api/metrics/parse-health":ji,"/api/metrics/agent-presence":Gi,"/api/server-info":Hi,"/api/principal":Ui,"/api/rescue":Zi,"/api/workspace":Ki,"/api/sync/status":Dc,"/api/sync/trigger":Oc,"/api/sync/conflicts":kc,"/api/sync/conflict-content":jc,"/api/sync/resolve-conflict":Ac,"/api/sync/abort-merge":Lc,"/api/local-op/clone":ec,"/api/local-op/open":ic,"/api/local-op/auth/login":dc,"/api/local-op/auth/status":mc,"/api/local-op/auth/repos":gc,"/api/local-op/auth/signout":yc,"/api/local-op/auth/pat":xc,"/api/local-op/auth/identity":Cc,"/api/local-op/auth/set-identity":Ec,"/api/installed-agents":Ic,"/api/spawn-cursor":vl,"/api/handoff":_l,"/api/install-skill":Fc,"/api/skill/install-state":gl,"/api/seed/plan":Mc,"/api/seed/apply":Nc,"/api/seed/packs":Pc};F&&(yl[`/api/test-reset`]=Wr,yl[`/api/test-rescan-backlinks`]=Gr,yl[`/api/test-rescan-files`]=Kr);let xl=new Set([`/api/upload`,`/api/create-page`,`/api/create-folder`,`/api/rename-path`,`/api/delete-path`,`/api/agent-write`,`/api/agent-write-md`,`/api/agent-patch`,`/api/agent-undo`,`/api/save-version`,`/api/rollback`,`/api/sync/trigger`,`/api/sync/resolve-conflict`,`/api/sync/abort-merge`,`/api/test-reset`,`/api/test-rescan-backlinks`,`/api/test-rescan-files`,`/api/install-skill`,`/api/folder-config`,`/api/template`,`/api/seed/apply`]),Cl=[`/api/local-op/`];return{priority:100,async onRequest({request:e,response:t}){let S=e.url?.split(`?`)[0];if(!S)return;if(S.startsWith(`/api/`)){let S=e.headers.origin;if(S!==void 0&&!isAllowedApiOrigin(S)){errorResponse(t,403,`urn:ok:error:invalid-origin`,`Origin not allowed.`,{handler:`api-origin-gate`});return}if(typeof t.setHeader==`function`&&(S!==void 0&&(t.setHeader(`Access-Control-Allow-Origin`,S),t.setHeader(`Vary`,`Origin`)),t.setHeader(`Access-Control-Allow-Methods`,`GET, POST, PUT, DELETE, OPTIONS`),t.setHeader(`Access-Control-Allow-Headers`,`Content-Type, Authorization, traceparent, tracestate, baggage`)),e.method===`OPTIONS`){t.writeHead(204),t.end();return}}if(xl.has(S)||Cl.some(e=>S.startsWith(e))){let S=e.socket?.remoteAddress;if(S!==void 0&&!isLoopbackAddress(S)){errorResponse(t,403,`urn:ok:error:loopback-required`,`Loopback required.`,{handler:`api-mutating-gate`});return}if(!isAllowedWorkspaceHostHeader(e.headers.host)){errorResponse(t,403,`urn:ok:error:host-not-allowed`,`Host header not allowed.`,{handler:`api-mutating-gate`});return}}if(!S.startsWith(`/api/`))return;let w=propagation.extract(context.active(),e.headers),E=e.method??`GET`,D=S;S.startsWith(`/api/rescue/`)?D=`/api/rescue/:docName`:S.startsWith(`/api/history/`)?D=`/api/history/:sha`:S.startsWith(`/api/tags/`)?D=`/api/tags/:name`:yl[S]||(D=`/api/*`);let O=getTracer(),k=Date.now();await context.with(w,()=>O.startActiveSpan(`HTTP ${E} ${D}`,{kind:SpanKind.SERVER,attributes:{[ATTR_HTTP_REQUEST_METHOD]:E,[ATTR_HTTP_ROUTE]:D,[ATTR_URL_PATH]:S,[ATTR_URL_SCHEME]:`http`,[ATTR_USER_AGENT_ORIGINAL]:e.headers[`user-agent`]??``}},async w=>{try{let D=yl[S],O=!1;if(D)O=!0,await D(e,t);else if(S.startsWith(`/api/rescue/`)){let w=decodeURIComponent(S.slice(12));w&&(O=!0,await ka(e,t,w))}else if(S.startsWith(`/api/history/`)){let w=decodeURIComponent(S.slice(13));w&&(O=!0,await Yr(e,t,w))}else if(S.startsWith(`/api/tags/`)){let w=S.slice(10);w&&(O=!0,await zc(e,t,w))}O||errorResponse(t,404,`urn:ok:error:not-found`,`API endpoint not found.`,{handler:`api-dispatch`,detail:`No handler for ${E} ${S}`});let k=t.statusCode;w.setAttribute(ATTR_HTTP_RESPONSE_STATUS_CODE,k),k>=500&&w.setStatus({code:SpanStatusCode.ERROR,message:`status ${k}`})}catch(e){throw w.recordException(e),w.setStatus({code:SpanStatusCode.ERROR,message:e instanceof Error?e.message:String(e)}),!t.headersSent&&!t.writableEnded&&!t.destroyed&&errorResponse(t,500,`urn:ok:error:internal-server-error`,`Internal server error.`,{handler:D,cause:e}),e}finally{w.end();let e=(Date.now()-k)/1e3;httpDurationHist().record(e,{[ATTR_HTTP_REQUEST_METHOD]:E,[ATTR_HTTP_ROUTE]:D,[ATTR_HTTP_RESPONSE_STATUS_CODE]:t.statusCode})}}))}}}function isWithinDir(e,t){return e===t?!0:e.startsWith(`${t}${sep}`)}function errnoCode(e){let t=e?.code;return typeof t==`string`?t:void 0}function seedBasenameIndex(e){let t=e.contentDir,S=new Set;function w(E){let D;try{D=readdirSync(E,{withFileTypes:!0})}catch(t){let S=errnoCode(t);S!==`ENOENT`&&e.onSkip?.(`read-failed`,S,E);return}for(let O of D){let D=join(E,O.name),k=relative(t,D);if(k.startsWith(`..`)||e.contentFilter?.isDirExcluded(k)&&O.isDirectory())continue;let j;try{j=lstatSync(D)}catch(t){let S=errnoCode(t);S!==`ENOENT`&&e.onSkip?.(`lstat-failed`,S,D);continue}if(j.isSymbolicLink()){let E;try{E=realpathSync(D)}catch(t){let S=errnoCode(t);S!==`ENOENT`&&e.onSkip?.(`realpath-failed`,S,D);continue}if(!isWithinDir(E,t)){e.onSkip?.(`symlink-escape`,void 0,D);continue}let O;try{O=statSync(E)}catch(t){let S=errnoCode(t);S!==`ENOENT`&&e.onSkip?.(`symlink-stat-failed`,S,E);continue}if(S.has(O.ino))continue;S.add(O.ino),O.isDirectory()?w(E):O.isFile()&&isSupportedAssetFile(D,ASSET_EXTENSIONS)&&!e.contentFilter?.isExcluded(k)&&e.basenameIndex.add(k);continue}if(j.isDirectory()){if(S.has(j.ino))continue;S.add(j.ino),w(D);continue}j.isFile()&&isSupportedAssetFile(D,ASSET_EXTENSIONS)&&!e.contentFilter?.isExcluded(k)&&e.basenameIndex.add(k)}}w(t)}const HocuspocusAuthTokenSchema=object$1({principalId:string$2().optional(),tabSessionId:string$2().optional(),expectedServerInstanceId:string$2().optional(),expectedBranch:string$2().optional()}).loose(),HOCUSPOCUS_AUTH_REJECTION_REASONS=[`server-instance-mismatch`,`branch-mismatch`,`rename-redirect`,`doc-deleted`];function isHocuspocusAuthRejectionReason(e){return HOCUSPOCUS_AUTH_REJECTION_REASONS.includes(e)}const WIRE_PAYLOAD_SEPARATOR=`:`;function formatAuthRejectionWire(e,t){return typeof t!=`string`||t.length===0?e:`${e}${WIRE_PAYLOAD_SEPARATOR}${t}`}function parseAuthRejectionWire(e){if(e.length===0)return{kind:null,payload:void 0};let t=e.indexOf(WIRE_PAYLOAD_SEPARATOR),S=t===-1?e:e.slice(0,t);if(!isHocuspocusAuthRejectionReason(S))return{kind:null,payload:void 0};if(t===-1)return{kind:S,payload:void 0};let w=e.slice(t+1);return{kind:S,payload:w.length>0?w:void 0}}var HocuspocusAuthRejection=class extends Error{kind;payload;reason;constructor(e,t,S){super(t),this.name=`HocuspocusAuthRejection`,this.kind=e,this.payload=typeof S==`string`&&S.length>0?S:void 0,this.reason=formatAuthRejectionWire(e,this.payload)}};function parseHocuspocusAuthToken(e){if(typeof e!=`string`||e.length===0)return;let t;try{t=JSON.parse(e)}catch{return}let S=HocuspocusAuthTokenSchema.safeParse(t);return S.success?S.data:void 0}const DEFAULT_WARN_BEFORE_MS=300*1e3;function attachIdleShutdown(e){let t=e.scheduler??defaultScheduler,S=e.warnBeforeMs??DEFAULT_WARN_BEFORE_MS,w=0,E=null,D=null,O=!1,k=!1;function j(){E!==null&&(t.clearTimeout(E),E=null),D!==null&&(t.clearTimeout(D),D=null)}function F(){j(),!(k||O)&&w===0&&(S>0&&S<e.thresholdMs&&(D=t.setTimeout(()=>{D=null,w===0&&!O&&e.log?.warn({msUntilShutdown:S,webSocketClientCount:0},`idle shutdown pending: no WebSocket clients`)},e.thresholdMs-S)),E=t.setTimeout(()=>{if(E=null,!(k||O)&&w===0){O=!0,e.log?.info({webSocketClientCount:0},`idle shutdown firing`);try{let t=e.onShutdown();t&&typeof t.then==`function`&&t.catch(t=>{e.log?.error({err:t},`idle shutdown handler rejected`)})}catch(t){e.log?.error({err:t},`idle shutdown handler threw`)}}},e.thresholdMs))}let L=(e,t)=>{e.url?.startsWith(`/collab`)&&(w++,j(),t.once(`close`,()=>{w--,w<0&&(w=0),w===0&&F()}))};return e.httpServer.on(`upgrade`,L),F(),{detach:()=>{k||(k=!0,e.httpServer.off(`upgrade`,L),j())}}}const MCP_SERVER_NAME=`open-knowledge`,MCP_CONNECTION_ID_HEADER=`x-ok-connection-id`;function sanitizeClientName(e,t){let S=Array.from(e??``).map(e=>{let t=e.charCodeAt(0);return t<=31||t===127?` `:e}).join(``).replace(/\s+/g,` `).trim();return S?S.slice(0,128):t}function buildInstructions(e){return`# Open Knowledge (OK) — collaborative markdown via MCP
|
|
2283
2283
|
|
|
2284
2284
|
**STOP** *(when \`.ok/\` exists)* — do NOT use native \`Read\`, \`Grep\`, \`Glob\`, \`Edit\`, \`Write\` on in-scope \`.md\` / \`.mdx\`. Reads: \`exec\` / \`read_document\` / \`search\` / \`grep\`. Writes: \`write_document\` / \`edit_document\` ONLY.
|
|
2285
2285
|
|
|
@@ -3242,13 +3242,13 @@ In headless mode, write the recap into the research article's "Further reading"
|
|
|
3242
3242
|
`)}function register$4(e,t){e.registerTool(`search`,{description:DESCRIPTION$4,inputSchema:InputSchema$2,outputSchema:OutputSchema$2,annotations:{readOnlyHint:!0,destructiveHint:!1,idempotentHint:!0}},async e=>{try{let S=await resolveProjectServerContext(t.resolveCwd,t.config,t.serverUrl,e.cwd);if(!S.ok)return textResult(`Error: ${S.error}`,!0);let{cwd:w,config:E,url:D}=S;if(!D)return textResult(`${HOCUSPOCUS_NOT_RUNNING_ERROR}\nFor server-free literal-string search, use \`grep\` instead — it walks the filesystem and does not need Hocuspocus.`,!0);let O=e.intent??`full_text`,k=e.limit??20,j={query:e.query,intent:O,limit:k};e.scopes&&(j.scopes=e.scopes);let F=await httpPost(D,`/api/search`,j);if(!F.ok)return textResult(`Error: ${F.error}`,!0);let{resolve:L,ui:B}=await buildListResolver({config:E,resolveCwd:async()=>w},w),H=(F.results??[]).flatMap(e=>{if(!isSearchKind(e.kind)||typeof e.path!=`string`)return[];let t=docNameFromPath(e.path),S=L(t);return[{kind:e.kind,path:e.path,docName:t,title:e.title??null,score:typeof e.score==`number`?e.score:0,signals:normalizeSignals(e.signals),...e.snippet?{snippet:e.snippet}:{},previewUrl:S?.url??null,...S?{previewUrlSource:S.source}:{}}]}),q={cwd:w,query:e.query,intent:O,resultCount:H.length,results:H,elapsedMs:typeof F.elapsedMs==`number`?F.elapsedMs:null,ui:B},J=`## Search results for "${e.query}" (${H.length} hit${H.length===1?``:`s`}, intent: ${O})`;return textPlusStructured(H.length===0?`No matches for "${e.query}".`:`${J}\n\n${formatResultsBlock(H)}`,q)}catch(e){return textResult(`Error: ${e instanceof Error?e.message:String(e)}`,!0)}})}const DESCRIPTION$3=["[Operates on disk; no running OK server required] Upsert one or more folder rules — writes nested `<folder>/.ok/frontmatter.yml` files.",``,"Folder rules apply default frontmatter to every doc inside `<folder>/` (and its descendants via cascade). Open shape — any YAML-representable key is accepted. Common keys: `title`, `description`, `tags` (the well-known three) plus arbitrary additions like `status`, `team`, `owners`, `review_cycle`. Use this tool to add a new rule, replace an existing one keyed by `match`, or rename via `new_match`.",``,`**Cascade merge semantics (D6 generalized):** scalars (string / number / boolean / null) replace last-wins along the leaf → root walk; arrays union-and-dedup with first-occurrence preserved; objects replace last-wins.`,``,'Each `match` glob must resolve to a SINGLE target folder by walking leading literal segments — `"specs/**"` writes `specs/.ok/frontmatter.yml`. Multi-folder globs (e.g. `"specs/*/evidence/**"`, where the literal `evidence` follows `*`) are rejected with `MULTI_FOLDER_GLOB`; split into per-folder rules instead.',``,"Always pass an array — even for a single rule. Validation runs against every rule first; if any fails (e.g. `MULTI_FOLDER_GLOB`, `PATH_ESCAPE`), NO rules are applied to disk. Filesystem-level errors during the write phase (disk full, permissions) may leave a partial result — the error response includes `partiallyApplied` listing which rules already landed.",``,'**To remove a rule**, pass an empty `frontmatter: {}` — the merge collapses, the file is deleted, and `<folder>/.ok/` is auto-cleaned if no other tenant remains. To clear a SPECIFIC key while keeping others, set that key to `null` / `""` / `[]` in the patch.',``,`**Parameters:**`,"- `rules` — Array of `{match, frontmatter, new_match?}`.",' - `match` — Glob pattern that identifies the target folder (e.g. `"specs/**"`, `"meetings/prep-notes/**"`). Required.'," - `frontmatter` — Open `Record<string, unknown>` of key/value defaults. Common: `{title?, description?, tags?: string[]}`. Any other key persists too (`status`, `team`, etc.)."," - `new_match` — If set, move the rule from `match` to this new glob (deletes the old folder's frontmatter.yml + auto-cleans).","- `cwd` (optional) — Project root."].join(`
|
|
3243
3243
|
`),FolderRuleUpsertInputSchema=object$1({match:string$2().min(1).describe(`Glob pattern (e.g. "specs/**", "meetings/prep-notes/**") that identifies the target folder.`),frontmatter:record(string$2(),unknown$2()).refine(e=>!(`title`in e&&e.title!==null&&typeof e.title!=`string`||`description`in e&&e.description!==null&&typeof e.description!=`string`||`tags`in e&&e.tags!==null&&!Array.isArray(e.tags)),{message:"Well-known keys must match expected types when present: `title` (string|null), `description` (string|null), `tags` (string[]|null)."}).describe('Default frontmatter to apply to matched docs. Open shape — any YAML-representable key. Common: `{title?, description?, tags?: string[]}`; arbitrary keys (`status`, `team`, `owners`, `review_cycle`, …) also persist. Pass `{}` to remove the rule (auto-cleans `.ok/` if empty). Pass `key: null | "" | []` to clear that specific key while keeping others.'),new_match:string$2().min(1).optional().describe("If set, move the rule from `match` to this new folder (deletes the old folder's frontmatter.yml + auto-cleans).")}),InputSchema$1={rules:array(FolderRuleUpsertInputSchema).min(1).describe("One or more folder rules to upsert. Always an array — pass `[{...}]` for a single rule."),cwd:string$2().optional().describe(ROUTED_CWD_DESCRIPTION)},AppliedEntrySchema=object$1({match:string$2(),path:string$2(),action:_enum([`written`,`deleted`])}),SuccessOutputSchema=object$1({ok:literal(!0),applied:array(AppliedEntrySchema)}),ErrorOutputSchema=object$1({ok:literal(!1),error:object$1({code:_enum([`MULTI_FOLDER_GLOB`,`PATH_ESCAPE`,`BAD_PROJECT_DIR`,`WRITE_ERROR`]),message:string$2(),rule:string$2().optional()}),partiallyApplied:array(AppliedEntrySchema).optional()}),OutputSchema$1={result:union([SuccessOutputSchema,ErrorOutputSchema])};function register$3(e,t){e.registerTool(`set_folder_rule`,{description:DESCRIPTION$3,inputSchema:InputSchema$1,outputSchema:OutputSchema$1,annotations:{readOnlyHint:!1,idempotentHint:!0,destructiveHint:!1}},async e=>{let S=await resolveProjectConfigContext(t.resolveCwd,t.config,e.cwd);if(!S.ok)return{isError:!0,content:[{type:`text`,text:`Error: ${S.error}`}]};let{cwd:w}=S,E=applyNestedFolderRulesUpsert({projectDir:w,rules:e.rules.map(e=>({match:e.match,frontmatter:e.frontmatter??{},...e.new_match===void 0?{}:{new_match:e.new_match}}))});return E.ok?textPlusStructured(JSON.stringify(E,null,2),{result:E}):{isError:!0,structuredContent:{result:E},content:[{type:`text`,text:`${E.error.code}: ${E.error.message}`}]}})}const DESCRIPTION$2=[`[Requires: Hocuspocus server] Find missing link candidates for a target page.`,"Returns JSON with structure: `{ target: { docName, title, aliases }, mentions: [{ source, excerpt, offset }], truncated }`.","Each mention includes an `offset` you can pass to `edit_document` for precision patching.","When `truncated` is true, the scan hit its time budget before reading every admitted document.",``,`**Parameters:**`,'- `docName` — Target page docName, typically without extension (for example, "articles/project-alpha"). A trailing `.md` or `.mdx` is stripped automatically.'].join(`
|
|
3244
3244
|
`);function register$2(e,t){e.tool(`suggest_links`,DESCRIPTION$2,{docName:string$2().describe(`Target page docName`),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=normalizeDocName(e.docName);if(!D.ok)return textResult(D.error,!0);let O=await httpGet(E,`/api/suggest-links?docName=${encodeURIComponent(D.docName)}`);if(!O.ok)return textResult(`Error: ${O.error}`,!0);let{ok:k,...j}=O,F=await resolvePreviewUrlForTool(D.docName,{config:t.config,resolveCwd:t.resolveCwd},w);return textPlusStructured(JSON.stringify(j,null,2),{...j,previewUrl:F?.url??null,...F?{previewUrlSource:F.source}:{}})})}const DESCRIPTION$1=[`[Requires: Hocuspocus server] Write markdown content to a document via the CRDT layer.`,`Content is applied through Hocuspocus and propagated to all connected editors in real-time.`,``,'**Frontmatter.** The markdown payload may include a YAML frontmatter block (`---`-fenced). To change frontmatter, call this tool with `position: "replace"` and a payload that includes the new YAML block — per-property MCP editing is currently unavailable. `edit_document` rejects frontmatter-intersecting find/replace calls.',``,'**Link liberally.** Every noun-phrase that names another document in this knowledge base should be a `[[wiki-link]]`, not plain prose. Backlinks are the primary navigation surface — underlinked documents become islands. Redlinks (links to pages that don\'t exist yet) are fine; they signal "this should exist." Prefer `[[Page Name]]` over Markdown `[text](./page.md)` — only wiki-links participate in the backlinks index.',``,"**Templates.** When creating a new doc, pass `template: \"<name>\"` to instantiate from a folder-scoped template. The name resolves against `templates_available` for the doc's parent folder (leaf → root walk-up; check `list_documents({ dir, depth: 1 })` to see the menu). The template's body + frontmatter become the doc's starting content; folder cascade merges naturally at read time. Templates scoped to a descendant subfolder are rejected for parent-folder targets. **`template` and `markdown` are mutually exclusive** — pass exactly one. To start from the template body and then customize, instantiate via `template` first, then call `edit_document` to fill placeholders.",``,`**Parameters:**`,'- `docName` — Document name, typically without extension (e.g., "my-doc" or "notes/meeting"). A trailing `.md` or `.mdx` is stripped automatically. New documents are created as `.md` by default; to create a `.mdx` file, first place it on disk, then use this tool for edits.',"- `markdown` — Markdown content to write. Required unless `template` is set (mutually exclusive — pass exactly one).","- `template` (optional) — Template name resolved against the parent folder's `templates_available`. The template body becomes the new doc verbatim. Cannot be combined with `markdown`.",'- `position` — Where to insert: "append", "prepend", or "replace". When `template` is set, `position` is forced to "replace".','- `summary` — Optional one-line user-outcome description of this edit (≤80 chars). Appears as a bullet in the document timeline so readers can scan intent without opening every diff. Prefer outcome phrasing ("Fixed token-refresh race") over structural ("Added 3 lines"). Avoid including secrets or PII — summaries are persisted to git history.'].join(`
|
|
3245
|
-
`);function register$1(e,t){e.tool(`write_document`,DESCRIPTION$1,{docName:string$2().describe(`Document name to write to`),markdown:string$2().optional().describe("Markdown content to write. Optional when `template` is set — the template body is used."),template:string$2().min(1).optional().describe(`Template name resolved against parent folder's templates_available (leaf → root walk-up; closest-wins on collision). See list_documents({ dir, depth: 1 }) to inspect the menu.`),position:_enum([`append`,`prepend`,`replace`]).describe(`Where to insert the content`),summary:summaryArgSchema,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=normalizeDocName(e.docName);if(!D.ok)return textResult(D.error,!0);let O=t.identityRef?.current;if(e.template===void 0&&e.markdown===void 0)return textResult("Error: either `markdown` or `template` must be provided. Omitting both would write empty content.",!0);if(e.template!==void 0&&e.markdown!==void 0)return textResult("Error: TEMPLATE_AND_MARKDOWN_BOTH_SET — `template` and `markdown` are mutually exclusive. Pass one. The template body becomes the new doc verbatim; fill placeholders via subsequent `edit_document` calls.",!0);let k=e.markdown??``,j=e.position;if(e.template!==void 0){let t=parentFolderOf(D.docName),S=resolveTemplatesAvailable(w,t,{depth:1}),E=S.find(t=>t.name===e.template);if(!E)return textResult(`Error: template "${e.template}" not found for folder "${t||`.`}". Available: ${S.length===0?`(none)`:S.map(e=>`${e.name} [${e.scope}]`).join(`, `)}. Templates are resolved by walk-up
|
|
3245
|
+
`);function register$1(e,t){e.tool(`write_document`,DESCRIPTION$1,{docName:string$2().describe(`Document name to write to`),markdown:string$2().optional().describe("Markdown content to write. Optional when `template` is set — the template body is used."),template:string$2().min(1).optional().describe(`Template name resolved against parent folder's templates_available (leaf → root walk-up; closest-wins on collision). See list_documents({ dir, depth: 1 }) to inspect the menu.`),position:_enum([`append`,`prepend`,`replace`]).describe(`Where to insert the content`),summary:summaryArgSchema,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=normalizeDocName(e.docName);if(!D.ok)return textResult(D.error,!0);let O=t.identityRef?.current;if(e.template===void 0&&e.markdown===void 0)return textResult("Error: either `markdown` or `template` must be provided. Omitting both would write empty content.",!0);if(e.template!==void 0&&e.markdown!==void 0)return textResult("Error: TEMPLATE_AND_MARKDOWN_BOTH_SET — `template` and `markdown` are mutually exclusive. Pass one. The template body becomes the new doc verbatim; fill placeholders via subsequent `edit_document` calls.",!0);let k=e.markdown??``,j=e.position;if(e.template!==void 0){let t=parentFolderOf(D.docName),S=resolveTemplatesAvailable(w,t,{depth:1}),E=S.find(t=>t.name===e.template);if(!E)return textResult(`Error: template "${e.template}" not found for folder "${t||`.`}". Available: ${S.length===0?`(none)`:S.map(e=>`${e.name} [${e.scope}]`).join(`, `)}. Templates are resolved by walk-up; check list_documents({ dir, depth: 1 }) at the parent folder to see the menu.`,!0);let F;try{F=readFileSync(resolve(w,E.path),`utf-8`)}catch(e){return textResult(`Error: failed to read template at ${E.path}: ${e.message}`,!0)}k=applySubstitution(F,{date:todayIsoUtc(),user:O?.displayName??``}),j=`replace`}let F=await httpPost(E,`/api/agent-write-md`,{docName:D.docName,markdown:k,position:j,...e.summary===void 0?{}:{summary:e.summary},...O?{agentId:O.connectionId,agentName:O.displayName,clientName:O.clientInfo?.name,colorSeed:O.colorSeed}:{}});if(!F.ok)return textResult(`Error: ${F.error}`,!0);let L=resolveLockDir(w),B=resolvePreviewUrl(D.docName,{lockDir:L}),H=typeof F.subscriberCount==`number`?F.subscriberCount:void 0,q=(typeof F.systemSubscriberCount==`number`?F.systemSubscriberCount:void 0)===0,J=H===0,Y=Array.isArray(F.hints)?F.hints:void 0,ee=F.summary&&typeof F.summary==`object`?F.summary:void 0,te=typeof ee?.hint==`string`?ee.hint:void 0,ne=[e.template===void 0?`Written successfully (${j}).`:`Written successfully (instantiated from template "${e.template}").`];if(B&&ne.push(`Preview: ${B.url}`),q&&ne.push(B?`Open ${B.url} in your preview browser.`:`No preview attached. Start the UI.`),te&&ne.push(te),Y)for(let e of Y)e.message&&ne.push(e.message);let ae=ne.join(`
|
|
3246
3246
|
`);if(!B&&!q&&!J&&!Y&&!ee)return textResult(ae);let oe={};return B&&(oe.previewUrl=B.url,oe.previewUrlSource=B.source),q&&(oe.warning={message:`Open the previewUrl in your preview browser.`,action:`attach-preview-once`,previewUrl:B?.url??null}),Y&&(oe.hints=Y),ee&&(oe.summary=ee),textPlusStructured(ae,oe)})}const DESCRIPTION=[`[Operates on disk; no running OK server required] Create or update a template.`,``,"Templates are markdown starter shapes that agents pick from when creating a new doc — `write_document({ template: <name> })` resolves the name against the folder cascade and instantiates the body + frontmatter.",``,`**Targets.** A template can live in one of two locations:`,'- `target: "project"` (default) — folder-scoped within the current project at `<folder>/.ok/templates/<name>.md`. The `folder` argument selects which project folder owns it (project-wide via `folder: ""`, or scoped to a subfolder).','- `target: "user"` — user-global at `~/.ok/templates/<name>.md`, available across every OK project the same user opens. The `folder` argument is ignored when `target` is `"user"` — user templates live in a single flat location.',``,"**`title` is required** in the frontmatter — it is the menu surface agents pick from. Missing or empty title returns `TEMPLATE_TITLE_REQUIRED`. `description` is recommended (soft warning when absent) — it disambiguates similarly-named templates.",``,"**Substitution allowlist.** The body MAY contain `{{date}}` (today, ISO-8601) and `{{user}}` (calling principal display name). Any other `{{...}}` token is rejected at write time with `TEMPLATE_UNKNOWN_VARIABLE`. Substitution happens at instantiation time (when `write_document({ template })` materializes the doc), not at template-write time — templates on disk show the raw `{{date}}` token.",``,`**Parameters:**`,'- `folder` — Project-root-relative folder (e.g. `"meetings"`, `"meetings/prep-notes"`). Empty / `.` means project root. Ignored when `target` is `"user"`.',"- `name` — Template filename without `.md`. Letters, digits, `_`, `-` only.","- `body` — Markdown body. May use `{{date}}` / `{{user}}` substitution tokens. Other placeholder text in `{shape}` form (e.g. `{Meeting Title}`) is LITERAL — agents fill it in via subsequent `edit_document` calls.","- `frontmatter` — `{title (required), description?, tags?: string[]}` for the template menu.",'- `target` (optional) — `"project"` (default) or `"user"`. Selects where the template lives.'].join(`
|
|
3247
3247
|
`),InputSchema={folder:string$2().describe('Project-root-relative folder. Empty / `.` means project root. Ignored when `target: "user"`.'),name:string$2().min(1).regex(/^[A-Za-z0-9_-]+$/,"Template name must use letters, digits, `_`, or `-` only (no slashes, dots, or spaces).").describe("Template filename without `.md` extension."),body:string$2().describe(`Markdown body for the template.`),frontmatter:object$1({title:string$2().min(1,"Template `title` is required — it is the menu surface agents pick from.").describe(`Required. The menu surface agents pick from. Empty / missing returns TEMPLATE_TITLE_REQUIRED.`),description:string$2().optional().describe(`Recommended. Disambiguates similarly-named templates. Soft warning when absent.`),tags:array(string$2()).optional().describe(`Optional. Concatenated with cascade tags at instantiation time.`)}).describe("Template menu metadata. `title` MUST be present (hard error if missing). `description` SHOULD be present (warning)."),target:_enum([`project`,`user`]).optional().describe('Where the template lives. `"project"` (default) writes to `<folder>/.ok/templates/`; `"user"` writes to `~/.ok/templates/` (folder ignored).'),cwd:string$2().optional().describe(ROUTED_CWD_DESCRIPTION)},OutputSchema={result:union([object$1({ok:literal(!0),path:string$2(),created:boolean$1(),warnings:array(string$2())}),object$1({ok:literal(!1),error:object$1({code:string$2(),message:string$2()})})])};function register(e,t){e.registerTool(`write_template`,{description:DESCRIPTION,inputSchema:InputSchema,outputSchema:OutputSchema,annotations:{readOnlyHint:!1,idempotentHint:!0,destructiveHint:!1}},async e=>{let S=await resolveProjectConfigContext(t.resolveCwd,t.config,e.cwd);if(!S.ok)return{isError:!0,content:[{type:`text`,text:`Error: ${S.error}`}]};let{cwd:w}=S,E={projectDir:w,folder:e.folder,name:e.name,body:e.body,frontmatter:e.frontmatter};e.target!==void 0&&(E.target=e.target);let D=applyTemplateWrite(E);if(!D.ok)return{isError:!0,structuredContent:{result:D},content:[{type:`text`,text:`${D.error.code}: ${D.error.message}`}]};let O=[`${D.created?`Created`:`Updated`} template at ${D.path}`];if(D.warnings.length>0){O.push(``,`Warnings:`);for(let e of D.warnings)O.push(` - ${e}`)}return textPlusStructured(O.join(`
|
|
3248
3248
|
`),{result:D})})}function registerAllTools(e,t){let S=t.logger,w=createLoggedServer(e,{logger:t.logger,identityRef:t.identityRef}),E=e=>async w=>{try{let E=await t.resolveCwd(w);return(getCurrentMcpLogger()??S)?.debug(`tool cwd resolved`,{tool:e,cwd:E,...w?{explicit:w}:{}}),E}catch(t){throw(getCurrentMcpLogger()??S)?.warn(`tool call failed`,{tool:e,error:t instanceof Error?t.message:String(t),...w?{explicit:w}:{}}),t}};register$21(w,{resolveCwd:E(`exec`),serverUrl:t.serverUrl,config:t.config}),register$12(w,{config:t.config,resolveCwd:E(`ingest`)}),register$7(w,{config:t.config,resolveCwd:E(`research`)}),register$26(w,{config:t.config,resolveCwd:E(`consolidate`)}),register$23(w,{config:t.config,resolveCwd:E(`discover`)}),register$10(w,{resolveCwd:E(`read_document`),config:t.config,serverUrl:t.serverUrl}),register$4(w,{resolveCwd:E(`search`),config:t.config,serverUrl:t.serverUrl}),register$13(w,{resolveCwd:E(`grep`),config:t.config,serverUrl:t.serverUrl}),register$2(w,{serverUrl:t.serverUrl,config:t.config,resolveCwd:E(`suggest_links`)}),register$1(w,{serverUrl:t.serverUrl,config:t.config,resolveCwd:E(`write_document`),identityRef:t.identityRef}),register$22(w,{serverUrl:t.serverUrl,config:t.config,resolveCwd:E(`edit_document`),identityRef:t.identityRef}),register$25(w,{serverUrl:t.serverUrl,config:t.config,resolveCwd:E(`delete_document`),identityRef:t.identityRef}),register$9(w,{serverUrl:t.serverUrl,config:t.config,resolveCwd:E(`rename_document`),identityRef:t.identityRef}),register$8(w,{serverUrl:t.serverUrl,config:t.config,resolveCwd:E(`rename_folder`),identityRef:t.identityRef}),register$16(w,{serverUrl:t.serverUrl,config:t.config,resolveCwd:E(`get_history`)}),register$5(w,t.config,t.serverUrl,E(`save_version`),t.identityRef),register$6(w,{serverUrl:t.serverUrl,config:t.config,resolveCwd:E(`rollback_to_version`),identityRef:t.identityRef}),register$11(w,{serverUrl:t.serverUrl,config:t.config,resolveCwd:E(`list_documents`)}),register$20(w,{serverUrl:t.serverUrl,config:t.config,resolveCwd:E(`get_backlinks`)}),register$17(w,{serverUrl:t.serverUrl,config:t.config,resolveCwd:E(`get_forward_links`)}),register$14(w,{serverUrl:t.serverUrl,config:t.config,resolveCwd:E(`get_orphans`)}),register$15(w,{serverUrl:t.serverUrl,config:t.config,resolveCwd:E(`get_hubs`)}),register$18(w,{serverUrl:t.serverUrl,config:t.config,resolveCwd:E(`get_dead_links`)}),register$19(w,{config:t.config,resolveCwd:E(`get_config`)}),register$3(w,{config:t.config,resolveCwd:E(`set_folder_rule`)}),register(w,{config:t.config,resolveCwd:E(`write_template`)}),register$24(w,{config:t.config,resolveCwd:E(`delete_template`)})}function firstHeader(e){return Array.isArray(e)?e[0]:e}function writePlain(e,t,S){e.writableEnded||(e.statusCode=t,e.setHeader(`Content-Type`,`text/plain; charset=utf-8`),e.end(S))}function createSessionServer(e,t,S){let w=e.config,E=new McpServer({name:MCP_SERVER_NAME,version:RUNTIME_VERSION},{instructions:buildInstructions(w.content)}),D=S??randomUUID(),O={current:{connectionId:D,displayName:D,colorSeed:D}};E.server.oninitialized=()=>{let e=E.server.getClientVersion(),t=sanitizeClientName(e?.name,D);O.current={connectionId:D,clientInfo:e?{name:t,version:e.version}:void 0,displayName:t,colorSeed:t}};let k=e.projectDir??e.contentDir;return registerAllTools(E,{serverUrl:async()=>e.getServerUrl(),resolveCwd:async e=>{if(e===void 0)return k;let t=resolveWithinRoot(k,e);if(!t.ok)throw Error(`cwd "${e}" is not within the configured project root: ${t.reason}`);return t.abs},config:w,identityRef:O}),{server:E,transport:t}}function createMcpHttpHandler(e){let t=new Map,S=e.sessionTtlMs??1800*1e3,w=e.maxSessions??100;async function E(S,w){let E=t.get(S);if(!E)return;t.delete(S),E.ttlTimer!==void 0&&clearTimeout(E.ttlTimer);let D=await Promise.allSettled([E.server.close(),E.transport.close()]);for(let t of D)t.status===`rejected`&&e.log?.warn?.({err:t.reason,sessionId:S,reason:w},`MCP HTTP session close failed`);e.log?.info?.({sessionId:S,reason:w},`MCP HTTP session closed`)}function D(t,w){w.ttlTimer!==void 0&&clearTimeout(w.ttlTimer),w.ttlTimer=setTimeout(()=>{E(t,`ttl-expired`).catch(S=>{e.log?.warn?.({err:S,sessionId:t},`MCP HTTP session TTL cleanup failed`)})},S),w.ttlTimer.unref?.()}return{async handle(S,O){let k=firstHeader(S.headers[`mcp-session-id`]);if(k){let e=t.get(k);if(!e){writePlain(O,404,`MCP session not found`);return}D(k,e),await e.transport.handleRequest(S,O);return}if(S.method!==`POST`){writePlain(O,400,`Missing MCP session. Initialize with POST /mcp first.`);return}if(t.size>=w){e.log?.warn?.({activeSessions:t.size,maxSessions:w},`MCP HTTP session cap reached`),writePlain(O,503,`Too many active MCP sessions`);return}let j=firstHeader(S.headers[MCP_CONNECTION_ID_HEADER]),F=validateAgentId(j)??void 0;j!==void 0&&F===void 0&&e.log?.warn?.({headerLength:j.length},`MCP HTTP forwarded connectionId header failed validation; falling back to randomUUID`);let L=new StreamableHTTPServerTransport({sessionIdGenerator:()=>randomUUID(),enableJsonResponse:!0,onsessioninitialized:async S=>{try{let w=createSessionServer(e,L,F);await w.server.connect(L),t.set(S,w),D(S,w),e.log?.info?.({sessionId:S},`MCP HTTP session initialized`)}catch(w){throw t.delete(S),e.log?.error?.({err:w,sessionId:S},`MCP HTTP session initialization failed`),w}}});L.onerror=t=>{e.log?.warn?.({err:t},`MCP HTTP transport error`)},L.onclose=()=>{let t=L.sessionId;if(!t){e.log?.info?.({sessionId:t,reason:`transport-closed`},`MCP HTTP session closed`);return}E(t,`transport-closed`).catch(S=>{e.log?.warn?.({err:S,sessionId:t},`MCP HTTP transport-close cleanup failed`)})},await L.handleRequest(S,O)},async close(){let e=[...t.entries()];await Promise.allSettled(e.map(([e])=>E(e,`handler-close`)))}}}const DEFAULT_KEEPALIVE_GRACE_MS=1e4,MAX_COLLAB_MESSAGE_BYTES=1024*1024,MCP_CORS_HEADERS={"Access-Control-Allow-Methods":`GET, POST, DELETE, OPTIONS`,"Access-Control-Allow-Headers":`Content-Type, Authorization, traceparent, tracestate, baggage, mcp-session-id, mcp-protocol-version`,"Access-Control-Max-Age":`86400`};function mountMcpAndApi(e){let{httpServer:t,hocuspocus:S,mcpHttpHandler:w,log:E,sessionManager:D,agentFocusBroadcaster:O,agentPresenceBroadcaster:k,contentAssetMiddleware:j}=e,F=e.keepaliveGraceMs??DEFAULT_KEEPALIVE_GRACE_MS,L=new import_websocket_server$1.default({noServer:!0,maxPayload:MAX_COLLAB_MESSAGE_BYTES});L.on(`error`,e=>{E.error({err:e},`WebSocketServer error`)});let B=new Map,H=new Set,q=!1;return t.on(`request`,(e,t)=>{let D=e.url?.split(`?`)[0];if(w!==void 0&&D===`/mcp`){let S=e.headers.origin,D=Array.isArray(e.headers[`mcp-session-id`])?e.headers[`mcp-session-id`][0]:e.headers[`mcp-session-id`];if(!isLoopbackAddress(e.socket.remoteAddress)){errorResponse(t,403,`urn:ok:error:loopback-required`,`Loopback access required.`,{handler:`mcp`});return}if(!isAllowedWorkspaceHostHeader(e.headers.host)){errorResponse(t,403,`urn:ok:error:host-not-allowed`,`Host header not allowed.`,{handler:`mcp`});return}if(S!==void 0&&!isAllowedApiOrigin(S)){errorResponse(t,403,`urn:ok:error:invalid-origin`,`Origin not allowed.`,{handler:`mcp`});return}S!==void 0&&(t.setHeader(`Access-Control-Allow-Origin`,S),t.setHeader(`Vary`,`Origin`));for(let[e,S]of Object.entries(MCP_CORS_HEADERS))t.setHeader(e,S);if(e.method===`OPTIONS`){t.writeHead(204),t.end();return}w.handle(e,t).catch(e=>{E.error({err:e,sessionId:D},`Unhandled MCP HTTP error`),!t.writableEnded&&!t.headersSent?errorResponse(t,500,`urn:ok:error:internal-server-error`,`Internal server error.`,{handler:`mcp`,cause:e}):t.writableEnded||t.end()});return}if(D?.startsWith(`/api/`)){S.hooks(`onRequest`,{request:e,response:t}).then(()=>{t.writableEnded||t.headersSent||errorResponse(t,404,`urn:ok:error:not-found`,`API endpoint not found.`,{handler:`mcp-mount`,detail:`No handler for ${e.method??`GET`} ${D}`})}).catch(e=>{E.error({err:e},`Unhandled onRequest error`),!t.writableEnded&&!t.headersSent?errorResponse(t,500,`urn:ok:error:internal-server-error`,`Internal server error.`,{handler:`mcp-mount`,cause:e}):t.writableEnded||t.end()});return}if(j!==void 0){try{j(e,t,()=>{t.writableEnded||t.headersSent||errorResponse(t,404,`urn:ok:error:not-found`,`Not found.`,{handler:`mcp-mount`,detail:`No handler for ${D??`/`}`})})}catch(e){E.error({err:e},`Unhandled content-asset middleware error`),!t.writableEnded&&!t.headersSent?errorResponse(t,500,`urn:ok:error:internal-server-error`,`Internal server error.`,{handler:`mcp-mount`,cause:e}):t.writableEnded||t.end()}return}errorResponse(t,404,`urn:ok:error:not-found`,`Not found.`,{handler:`mcp-mount`,detail:`The React UI is served by \`ok ui\` (run \`ok ui\` and check \`ui.lock.port\`). No handler for ${D??`/`}`})}),t.on(`upgrade`,(e,t,w)=>{if(e.url?.startsWith(`/collab/keepalive`)){if(!isLoopbackAddress(e.socket.remoteAddress)||!isAllowedWorkspaceHostHeader(e.headers.host)){t.destroy();return}t.on(`error`,e=>{handleCollabSocketError(e)||E.error({err:e},`MCP keepalive socket error`)}),L.handleUpgrade(e,t,w,t=>{let S=parseKeepaliveConnectionId(e.url);if(S){let e=B.get(S);e!==void 0&&(clearTimeout(e),B.delete(S),E.info({connectionId:S},`[keepalive] reconnect during grace — timer cancelled`))}if(S&&k){let t=parseKeepaliveIdentity(e.url);if(t)try{let e=iconFromClientName(t.clientName),w=AGENT_ICON_COLORS[e]??colorFromSeed(t.colorSeed);k.setPresence(toBroadcasterKey(S),{displayName:t.displayName,icon:e,color:w,currentDoc:`(connected)`,mode:`idle`,ts:Date.now()})}catch(e){E.error({err:e,connectionId:S},`[keepalive] presence bootstrap failed`)}}let w=setInterval(()=>{try{t.ping()}catch{}},3e4);w.unref?.();let j=S?setInterval(()=>{k?.bumpPresenceTs(toBroadcasterKey(S))},3e3):null;j?.unref?.(),t.on(`close`,()=>{if(clearInterval(w),j!==null&&clearInterval(j),!S)return;let e=setTimeout(()=>{if(B.delete(S),q)return;let e=(async()=>{E.info({connectionId:S},`[keepalive] grace expired — cleaning up sessions`);try{await D?.closeAllForAgent(S)}catch(e){E.error({err:e,connectionId:S},`[keepalive] closeAllForAgent failed`)}try{O?.clearFocus(S)}catch(e){E.error({err:e,connectionId:S},`[keepalive] clearFocus failed`)}try{k?.clearPresence(toBroadcasterKey(S))}catch(e){E.error({err:e,connectionId:S},`[keepalive] clearPresence failed`)}})();H.add(e),e.finally(()=>H.delete(e))},F);e.unref?.(),B.set(S,e),E.info({connectionId:S,graceMs:F},`[keepalive] disconnected — grace timer started`)}),t.on(`error`,e=>{handleCollabSocketError(e)||E.error({err:e},`MCP keepalive WS error`),t.terminate()})});return}if(e.url?.startsWith(`/collab`)){t.on(`error`,e=>{handleCollabSocketError(e)||E.error({err:e},`Upgrade socket error`)}),L.handleUpgrade(e,t,w,t=>{let w=S.handleConnection(t,e),D=!1;t.on(`message`,e=>{if(D)return;let S=e.byteLength;if(S>MAX_COLLAB_MESSAGE_BYTES){D=!0,incrementCollabMessageTooLarge(),E.warn({event:`collab-message-too-large`,bytes:S,limit:MAX_COLLAB_MESSAGE_BYTES},`Collab WebSocket message rejected before Yjs processing`),t.close(1009,`Message Too Big`);return}w.handleMessage(new Uint8Array(e))}),t.on(`close`,(e,t)=>{w.handleClose({code:e,reason:t.toString()})}),t.on(`error`,e=>{if(e.code===`WS_ERR_UNSUPPORTED_MESSAGE_LENGTH`){incrementCollabMessageTooLarge(),E.warn({event:`collab-message-too-large`,limit:MAX_COLLAB_MESSAGE_BYTES},`Collab WebSocket frame rejected by ws maxPayload before Yjs processing`),t.terminate();return}handleCollabSocketError(e)||E.error({err:e},`WebSocket error`),t.terminate()})});return}t.destroy()}),{wss:L,shutdown:async()=>{if(!q){q=!0;for(let e of B.values())clearTimeout(e);B.clear(),H.size>0&&await Promise.allSettled([...H])}}}}function parseKeepaliveConnectionId(e){if(!e)return null;try{return validateAgentId(new URL(e,`http://localhost`).searchParams.get(`connectionId`))}catch{return null}}const MAX_KEEPALIVE_IDENTITY_LEN=256;function sanitizeIdentityField(e){return e===null||e.length===0||e.length>MAX_KEEPALIVE_IDENTITY_LEN||/[-]/.test(e)?null:e}function parseKeepaliveIdentity(e){if(!e)return null;try{let t=new URL(e,`http://localhost`),S=sanitizeIdentityField(t.searchParams.get(`displayName`)),w=sanitizeIdentityField(t.searchParams.get(`clientName`)),E=sanitizeIdentityField(t.searchParams.get(`colorSeed`));return S===null||w===null||E===null?null:{displayName:S,clientName:w,colorSeed:E}}catch{return null}}const MISSING_OK_CONFIG_MESSAGE=`Open Knowledge config not found at .ok/config.yml. Run ok init to scaffold OK in this directory.`;var MissingOkConfigError=class extends Error{kind;projectDir;constructor(e,t,S){super(MISSING_OK_CONFIG_MESSAGE,S),this.name=`MissingOkConfigError`,this.kind=e,this.projectDir=t}};async function startConfigFileWatcher(e,t){let S=getLogger(`config-file-watcher`),{watch:w}=await import(`./chokidar-CxU7f6JW.mjs`),E=dirname(e);try{tracedMkdirSync(E,{recursive:!0})}catch(e){e.code!==`EEXIST`&&S.warn({err:e,watchDir:E},`failed to create watch directory; watcher may be inert`)}let D=w(E,{ignoreInitial:!0,depth:0,usePolling:!0,interval:200,awaitWriteFinish:{stabilityThreshold:100,pollInterval:50},ignored:t=>t!==E&&t!==e});await new Promise(e=>{D.once(`ready`,e)});let O=null;try{O=readFileSync(e,`utf-8`)}catch{}let k=(w,E=!0)=>{if(w!==e)return;let D;try{D=readFileSync(w,`utf-8`)}catch(e){if(e.code===`ENOENT`){E&&S.debug({path:w},`config file disappeared between event and read; dropping`);return}S.warn({err:e,path:w},`config file read failed; dropping event`);return}if(D!==O){O=D;try{t(D)}catch(e){S.warn({err:e,path:w},`config file change handler threw`)}}},j=e=>k(e);D.on(`add`,j),D.on(`change`,j),D.on(`unlink`,t=>{t===e&&S.debug({path:t},`config file unlinked; Y.Text retained at current state`)}),D.on(`error`,t=>{S.warn({err:t,watchDir:E,absPath:e},`[config-file-watcher] chokidar error while watching ${e}`)});let F=0,L=setInterval(()=>{F++,k(e,!1),F>=20&&clearInterval(L)},500);L.unref?.();let B=!1;return async()=>{B||(B=!0,clearInterval(L),await D.close())}}async function startMultiPathConfigFileWatcher(e,t){if(e.length===0)throw Error(`startMultiPathConfigFileWatcher requires at least one absolute path`);let S=getLogger(`config-file-watcher`),{watch:w}=await import(`./chokidar-CxU7f6JW.mjs`),E=new Set(e),D=Array.from(new Set(Array.from(E,e=>dirname(e))));for(let e of D)try{tracedMkdirSync(e,{recursive:!0})}catch(t){t.code!==`EEXIST`&&S.warn({err:t,dir:e},`failed to create watch directory; watcher may be inert`)}let O=w(D,{ignoreInitial:!0,depth:0,usePolling:!0,interval:200,awaitWriteFinish:{stabilityThreshold:100,pollInterval:50},ignored:e=>!E.has(e)&&!D.includes(e)});await new Promise(e=>{O.once(`ready`,e)});let k=new Map;for(let e of E)try{k.set(e,readFileSync(e,`utf-8`))}catch{k.set(e,null)}let j=(e,w=!0)=>{if(!E.has(e))return;let D;try{D=readFileSync(e,`utf-8`)}catch(t){if(t.code===`ENOENT`){w&&S.debug({path:e},`config file disappeared between event and read; dropping`);return}S.warn({err:t,path:e},`config file read failed; dropping event`);return}if(D!==k.get(e)){k.set(e,D);try{t(e,D)}catch(t){S.warn({err:t,path:e},`config file change handler threw`)}}},F=e=>j(e);O.on(`add`,F),O.on(`change`,F),O.on(`unlink`,e=>{E.has(e)&&S.debug({path:e},`config file unlinked; downstream state retained`)}),O.on(`error`,e=>{S.warn({err:e,watchDirs:D,paths:Array.from(E)},`[config-file-watcher] chokidar error in multi-path watcher`)});let L=0,B=setInterval(()=>{L++;for(let e of E)j(e,!1);L>=20&&clearInterval(B)},500);B.unref?.();let H=!1;return async()=>{H||(H=!0,clearInterval(B),await O.close())}}const QUIET_WINDOW_MS=100,BATCH_TIMEOUT_MS=3e4,WATCHED_FILES=new Set([`HEAD`,`MERGE_HEAD`,`ORIG_HEAD`,`index.lock`]);function readHeadSha(e){try{let t=readFileSync(resolve(e,`HEAD`),`utf-8`).trim();if(t.startsWith(`ref: `)){let S=resolve(e,t.slice(5));try{return readFileSync(S,`utf-8`).trim()}catch{try{let S=readFileSync(resolve(e,`packed-refs`),`utf-8`),w=t.slice(5),E=S.split(`
|
|
3249
3249
|
`).find(e=>e.endsWith(` ${w}`));if(E)return E.split(` `)[0]}catch{}return null}}return t.length>=40?t.slice(0,40):null}catch{return null}}function readBranchFromHead(e){try{let t=readFileSync(resolve(e,`HEAD`),`utf-8`).trim();return t.startsWith(`ref: refs/heads/`)?t.slice(16):t.length>=40?`detached-${t.slice(0,12)}`:null}catch{return null}}async function startHeadWatcher(e,t,S){let w=resolveGitDir(e);if(!w)return{unsubscribe:async()=>{},getLastKnownBranch:()=>null};let E=w,D=!1,O=null,k=null,j=null,F=null;async function L(e){if(H&&await H,!D)return;O&&=(clearTimeout(O),null),k&&=(clearTimeout(k),null);let t=readHeadSha(E),w=j!==t,L=readBranchFromHead(E),B;B=L?.startsWith(`detached-`)?`detached-head`:F===L?`within-branch`:`cross-branch`;let q=F;try{await S({headMoved:w,oldHead:j,newHead:t,timeout:e,batchKind:B,oldBranch:q,newBranch:L})}catch(e){console.error(`[head-watcher] onBatchEnd callback failed:`,e)}finally{D=!1,j=t,F=L}}function B(){O&&clearTimeout(O),O=setTimeout(()=>{O=null,L(!1)},QUIET_WINDOW_MS)}let H=null;async function q(e){if(!D){D=!0,j=readHeadSha(E);let S=(async()=>{try{await t({trigger:e})}catch(e){console.error(`[head-watcher] onBatchBegin callback failed:`,e)}})();H=S,await S,H=null,k=setTimeout(()=>{k=null,L(!0)},BATCH_TIMEOUT_MS)}B()}let J,Y;try{Y=await import(`@parcel/watcher`)}catch(e){throw Error(`@parcel/watcher unavailable for HEAD watching: ${e instanceof Error?e.message:e}`)}try{let e=await Y.subscribe(E,(e,t)=>{if(e){console.error(`[head-watcher]`,e);return}for(let e of t){let t=e.path.split(`/`).pop()??``;if(WATCHED_FILES.has(t)){q(t);break}}});J=()=>e.unsubscribe()}catch(e){throw Error(`@parcel/watcher subscribe failed for HEAD watching: ${e instanceof Error?e.message:e}`)}return j=readHeadSha(E),F=readBranchFromHead(E),console.log(`[head-watcher] Watching ${E} for HEAD changes`),{unsubscribe:async()=>{D&&await L(!1),O&&clearTimeout(O),k&&clearTimeout(k),await J()},getLastKnownBranch:()=>F}}const LIVE_DERIVED_INDEX_DEBOUNCE_MS=100;function isLocalOriginLike(e){return typeof e!=`object`||!e?!1:e.source===`local`}function serializeLiveDocument(e){return e.getText(`source`).toString()}function createLiveDerivedIndexExtension(e){let{backlinkIndex:t,tagIndex:S,signalChannel:w,debounceMs:E=100}=e,D=new Map;function O(e){let t=D.get(e);t&&(clearTimeout(t),D.delete(e))}function k(e,k){O(e),D.set(e,setTimeout(()=>{D.delete(e);try{let E=serializeLiveDocument(k);t.updateDocumentFromMarkdown(e,E),w?.(`backlinks`),w?.(`graph`),S&&(S.updateDocumentFromMarkdown(e,E),w?.(`tags`))}catch(t){console.error(`[live-derived-index] Failed to update derived views for ${e}:`,t)}},E))}return{async onChange({documentName:e,document:t,transactionOrigin:S}){isSystemDoc(e)||isConfigDoc(e)||isLocalOriginLike(S)&&S.context?.origin===`file-watcher`||k(e,t)},async beforeUnloadDocument({documentName:e}){O(e)},async onDestroy(){for(let e of D.values())clearTimeout(e);D.clear()}}}const PRINCIPAL_FILE=`principal.json`,GIT_TIMEOUT_MS=3e3;async function readGitConfig(e){try{let t=esm_default({baseDir:e,timeout:{block:GIT_TIMEOUT_MS}});return{name:(await t.raw(`config`,`--get`,`user.name`)).trim()||null,email:(await t.raw(`config`,`--get`,`user.email`)).trim()||null}}catch{return{name:null,email:null}}}async function loadPrincipal(e){let t=getLocalDir(e),S=resolve(t,PRINCIPAL_FILE),{name:w,email:E}=await readGitConfig(e);if(existsSync(S)){let e;try{e=JSON.parse(readFileSync(S,`utf-8`))}catch{e={}}let t=typeof e.id==`string`&&e.id.startsWith(`principal-`)?e.id:`principal-${randomUUID()}`,D=typeof e.created_at==`string`?e.created_at:new Date().toISOString(),O=t.slice(10,18),k={id:t,display_name:w?sanitizeGitIdentity(w):typeof e.display_name==`string`?e.display_name:`Local User`,display_email:E?sanitizeGitIdentity(E):typeof e.display_email==`string`?e.display_email:`principal-${O}@openknowledge.local`,source:w||E?`git-config`:`synthesized`,created_at:D};return writeFileSync(S,JSON.stringify(k,null,2),`utf-8`),k}mkdirSync(t,{recursive:!0});let D=`principal-${randomUUID()}`,O=D.slice(10,18),k={id:D,display_name:w?sanitizeGitIdentity(w):`Local User`,display_email:E?sanitizeGitIdentity(E):`principal-${O}@openknowledge.local`,source:w||E?`git-config`:`synthesized`,created_at:new Date().toISOString()};return writeFileSync(S,JSON.stringify(k,null,2),`utf-8`),k}const DEFAULT_CAPACITY=1e4;var RecentlyRemovedDocs=class{map=new Map;capacity;onEviction;onSizeChange;now;constructor(e=DEFAULT_CAPACITY,t={}){this.capacity=Math.max(0,Math.floor(e)),this.onEviction=t.onEviction,this.onSizeChange=t.onSizeChange,this.now=t.now??Date.now}setRenamed(e,t){this.put(e,{kind:`renamed`,newDocName:t,addedAt:this.now()})}setDeleted(e){this.put(e,{kind:`deleted`,addedAt:this.now()})}get(e){let t=this.map.get(e);if(t!==void 0)return this.map.delete(e),this.map.set(e,t),t}has(e){return this.map.has(e)}peek(e){return this.map.get(e)}delete(e){this.map.delete(e)&&this.onSizeChange?.(this.map.size)}get size(){return this.map.size}put(e,t){if(this.capacity===0){this.onSizeChange?.(0);return}for(this.map.delete(e),this.map.set(e,t);this.map.size>this.capacity;){let e=this.map.keys().next().value;if(e===void 0)break;this.map.delete(e),this.onEviction?.()}this.onSizeChange?.(this.map.size)}};function fileExistsForDocName(e,t){let S=e.resolveFilePath(t);return S!==null&&e.fileExists(S)}async function runRemovalRedirectGuard(e,t){try{if(isSystemDoc(e)||isConfigDoc(e))return;let S=t.recentlyRemovedDocs.get(e);if(S===void 0)return;if(S.kind===`deleted`){if(fileExistsForDocName(t,e)){t.recentlyRemovedDocs.delete(e);return}throw incrementAuthDocDeleted(),setActiveSpanAttributes({"auth.reason":`doc-deleted`}),new HocuspocusAuthRejection(`doc-deleted`,`removed-doc rejection for deleted ${e}`)}let w=new Set([e]),E=S.newDocName;for(;;){if(w.has(E)){incrementRemovalRedirectChainCycle(),console.warn(JSON.stringify({event:`removal-redirect-chain-cycle`,documentName:e,target:E}));return}w.add(E);let S=t.recentlyRemovedDocs.get(E);if(S===void 0)throw incrementAuthRenameRedirect(),setActiveSpanAttributes({"auth.reason":`rename-redirect`}),new HocuspocusAuthRejection(`rename-redirect`,`removed-doc redirect for ${e} → ${E}`,E);if(S.kind===`deleted`)throw fileExistsForDocName(t,E)?(t.recentlyRemovedDocs.delete(E),incrementAuthRenameRedirect(),setActiveSpanAttributes({"auth.reason":`rename-redirect`}),new HocuspocusAuthRejection(`rename-redirect`,`removed-doc redirect for ${e} → ${E}`,E)):(incrementAuthDocDeleted(),setActiveSpanAttributes({"auth.reason":`doc-deleted`}),new HocuspocusAuthRejection(`doc-deleted`,`removed-doc rejection for deleted ${e}`));E=S.newDocName}}catch(t){if(t instanceof HocuspocusAuthRejection)throw t;incrementAuthRemovalGuardError(),console.warn(JSON.stringify({event:`removal-redirect-extension-error`,documentName:e,message:t instanceof Error?t.message:String(t)}))}}function createServerObserverExtension(e){let t=new Map,S=new Map;return{async afterLoadDocument({documentName:w,document:E}){if(isSystemDoc(w)||isConfigDoc(w)||t.has(w))return;let D=E,O=D.getXmlFragment(`default`),k=D.getText(`source`),j=()=>{try{let S=setupServerObservers({doc:D,xmlFragment:O,ytext:k,mdManager:e.mdManager,schema:e.schema,docName:w,shadow:e.shadowRef?()=>e.shadowRef?.current:void 0,getBranch:e.getCurrentBranch?()=>e.getCurrentBranch?.()??`main`:void 0,contentRoot:e.contentRoot,resolveEmbed:e.resolveEmbed,resolveSize:e.resolveSize});return t.set(w,S),!0}catch(e){return console.error(`[ServerObserverExtension] Failed to attach observers for '${w}':`,e),incrementServerObserverError(`a`),incrementServerObserverError(`b`),!1}};if(!j()){let e=setTimeout(()=>{S.delete(w),!t.has(w)&&(console.warn(`[ServerObserverExtension] Retrying observer attachment for '${w}'`),j())},5e3);S.set(w,e)}},async afterUnloadDocument({documentName:e}){let w=S.get(e);w&&(clearTimeout(w),S.delete(e));let E=t.get(e);E&&(E(),t.delete(e))},async onDestroy(){for(let e of S.values())clearTimeout(e);S.clear();for(let[e,S]of t.entries())try{S()}catch(t){console.error(`[ServerObserverExtension] Cleanup failed for '${e}':`,t)}t.clear()}}}const STATE_MANIFEST_FILENAME=`state.json`;function detectProjectShape(e){return e.lockDir,existsSync(e.shadowRepoDir)?`adopt`:`fresh`}function manifestPath(e){return resolve(e,STATE_MANIFEST_FILENAME)}function isCompatibleSchema(e,t){return e===t||e===0&&t===1}var StateManifestError=class extends Error{kind;path;constructor(e){super(e.message),this.name=`StateManifestError`,this.kind=e.kind,this.path=e.path}};function isStateManifestRecord(e){if(!e||typeof e!=`object`)return!1;let t=e;if(typeof t.stateSchemaVersion!=`number`||typeof t.createdAt!=`string`||!t.createdBy||typeof t.createdBy!=`object`)return!1;let S=t.createdBy;return!(typeof S.runtimeVersion!=`string`||S.protocolVersion!==void 0&&typeof S.protocolVersion!=`number`)}function readStateManifest(e){let t=manifestPath(e);if(!existsSync(t))return{status:`absent`};let S;try{S=readFileSync(t,`utf-8`)}catch(e){throw new StateManifestError({kind:`corrupt`,path:t,message:`Failed to read state manifest at ${t}: ${e instanceof Error?e.message:String(e)}`})}let w;try{w=JSON.parse(S)}catch(e){throw new StateManifestError({kind:`corrupt`,path:t,message:`State manifest at ${t} is not valid JSON: ${e instanceof Error?e.message:String(e)}`})}if(!isStateManifestRecord(w))throw new StateManifestError({kind:`corrupt`,path:t,message:`State manifest at ${t} has invalid shape (missing or wrong-typed required fields)`});return{status:`present`,manifest:w}}function writeStateManifest(e,t){let S=manifestPath(e);mkdirSync(dirname(S),{recursive:!0}),writeFileSync(S,JSON.stringify(t,null,2),{encoding:`utf-8`,mode:384})}function assertCompatibleStateManifest(e){let t=getLogger(`state-manifest`),S=e.currentStateSchemaVersion??1,w=e.currentRuntimeVersion??RUNTIME_VERSION,E=e.currentProtocolVersion??1,D=(e.now??(()=>new Date))().toISOString(),O=manifestPath(e.lockDir),k=readStateManifest(e.lockDir);if(k.status===`present`){let j=k.manifest;if(!isCompatibleSchema(j.stateSchemaVersion,S))throw new StateManifestError({kind:`incompatible`,path:O,message:`State manifest at ${O} declares stateSchemaVersion=${j.stateSchemaVersion} but this binary supports ${S}. Refusing to boot — on-the-fly migration is out of scope. (Manifest written by runtime ${j.createdBy.runtimeVersion}, protocol ${j.createdBy.protocolVersion}.)`});try{let t={...j,lastWriteBy:{runtimeVersion:w,protocolVersion:E,at:D}};return writeStateManifest(e.lockDir,t),t}catch(e){return t.warn({err:e},`[state-manifest] failed to update lastWriteBy — proceeding`),j}}if(detectProjectShape({lockDir:e.lockDir,shadowRepoDir:e.shadowRepoDir})===`fresh`){let k={stateSchemaVersion:S,createdAt:D,createdBy:{runtimeVersion:w,protocolVersion:E}};return writeStateManifest(e.lockDir,k),t.info({path:O,stateSchemaVersion:S},`[state-manifest] fresh project — wrote manifest`),k}let j={stateSchemaVersion:0,createdAt:D,createdBy:{runtimeVersion:w,protocolVersion:E,adoptedAt:D}};return writeStateManifest(e.lockDir,j),t.warn({path:O,runtimeVersion:w},`[state-manifest] adopting pre-versioned project — wrote schema-0 manifest. Future binaries with STATE_SCHEMA_VERSION>=2 may refuse if they cannot read schema-0 state.`),j}const log$1=getLogger(`conflict-storage`);var ConflictStore=class{storePath;projectDir;branch;conflicts=[];constructor(e,t=`main`){this.storePath=join(getLocalDir(e),`conflicts.json`),this.projectDir=e,this.branch=t,this.load()}load(){if(!existsSync(this.storePath)){this.conflicts=[];return}try{let e=readFileSync(this.storePath,`utf-8`),t=JSON.parse(e);if(t.version!==1){log$1.warn({path:this.storePath},`[conflicts] unknown schema version — resetting`),this.conflicts=[];return}this.branch=t.branch??this.branch,this.conflicts=t.conflicts??[]}catch(e){log$1.warn({err:e},`[conflicts] failed to load conflicts.json — starting empty`),this.conflicts=[]}}save(){try{let e=dirname(this.storePath);existsSync(e)||mkdirSync(e,{recursive:!0});let t={version:1,branch:this.branch,conflicts:this.conflicts};writeFileSync(this.storePath,JSON.stringify(t,null,2),`utf-8`)}catch(e){log$1.warn({err:e},`[conflicts] failed to save conflicts.json`)}}addConflict(e){let t=this.conflicts.findIndex(t=>t.file===e.file);t===-1?this.conflicts.push(e):this.conflicts[t]=e,this.save()}removeConflict(e){this.conflicts=this.conflicts.filter(t=>t.file!==e),this.save()}clear(){this.conflicts=[],this.save()}count(){return this.conflicts.length}list(){return[...this.conflicts]}hasConflicts(){return this.conflicts.length>0}setBranch(e){this.branch=e}async resolveConflict(e,t,S,w=[]){if(!this.conflicts.find(t=>t.file===e))throw Error(`[conflicts] no conflict tracked for file: ${e}`);if(t===`content`&&S===void 0)throw Error(`[conflicts] strategy 'content' requires content parameter`);let{createGitInstance:E}=await import(`./git-handle-DwfYp_z--DreW3fNC.mjs`).then(e=>e.n),D=E(this.projectDir,{credentialArgs:w});switch(t){case`mine`:await D.git.raw([`checkout`,`--ours`,`--`,e]),await D.git.raw([`add`,`--`,e]);break;case`theirs`:await D.git.raw([`checkout`,`--theirs`,`--`,e]),await D.git.raw([`add`,`--`,e]);break;case`content`:{if(!S)throw Error(`[conflicts] strategy 'content' requires content parameter`);let t=resolve(this.projectDir),w=resolve(t,e);if(w!==t&&!w.startsWith(`${t}/`))throw Error(`[conflicts] file path escapes project directory: ${e}`);writeFileSync(w,S,`utf-8`),await D.git.raw([`add`,`--`,e]);break}default:throw Error(`[conflicts] unknown resolve strategy: ${t}`)}if(this.removeConflict(e),!this.hasConflicts())try{await D.git.raw([`commit`,`--no-edit`]),log$1.info({file:e},`[conflicts] all conflicts resolved — merge commit created`)}catch(t){let S=new Date().toISOString(),w=!1;try{let e=(await D.git.raw([`diff`,`--name-only`,`--diff-filter=U`])).split(`
|
|
3250
3250
|
`).map(e=>e.trim()).filter(Boolean);for(let t of e)this.addConflict({file:t,detectedAt:S});w=e.length>0}catch(e){log$1.warn({err:e},`[conflicts] commit failed and re-scan of unmerged files failed — falling back to single-file re-add`)}w||this.addConflict({file:e,detectedAt:S}),log$1.warn({err:t},`[conflicts] failed to commit merge after all conflicts resolved — unmerged files re-added`)}}};function extractStderr(e){return e.git?.toString()??e.message??``}function matchesAny(e,t){return t.some(t=>t.test(e))}const AUTH_PATTERNS=[/\b(401|403)\b/,/authentication failed/i,/authorization failed/i,/invalid credentials/i,/credential helper/i,/bad credentials/i,/token.*expired/i,/expired.*token/i,/permission denied.*\(publickey\)/i,/host key verification failed/i,/fatal:.*repository.*not found/i],SCOPE_MISMATCH_PATTERNS=[/insufficient scopes/i,/missing.*scope/i,/required scope/i],NON_FAST_FORWARD_PATTERNS=[/non-fast-forward/i,/rejected.*non-fast-forward/i,/would overwrite.*commits/i,/\[rejected\]/,/fetch first/i,/updates were rejected/i],PROTECTED_BRANCH_PATTERNS=[/protected branch/i,/refusing to allow/i,/at least \d+ approving review/i,/required status check/i,/branch policy/i,/GH001/i,/GH002/i,/GH003/i,/GH004/i,/push declined due to repository rule/i,/cannot push to a protected branch/i],MERGE_CONFLICT_PATTERNS=[/\bmerge conflict\b/i,/automatic merge failed/i,/CONFLICT \(/,/\bconflict\b.*\bmerge\b/i,/(?:^|\n)CONFLICTS:\s/i],LFS_PATTERNS=[/lfs.*quota/i,/exceeded.*bandwidth/i,/lfs storage/i],LARGE_FILE_PATTERNS=[/file.*too large/i,/exceeded.*file size/i,/push file size limit/i],PRE_RECEIVE_PATTERNS=[/pre-receive hook/i,/remote:.*rejected/i,/hook declined/i],SECRET_DETECTED_PATTERNS=[/secret.*detected/i,/push.*secret/i,/secret scanning/i,/leaking.*credentials/i,/token.*detected/i],INDEX_LOCK_PATTERNS=[/\.git\/index\.lock/i,/another git process/i,/unable to create.*\.lock/i],DIRTY_TREE_PATTERNS=[/dirty.*working tree/i,/working tree.*not clean/i,/untracked.*files.*would be overwritten/i,/local changes.*would be overwritten/i,/uncommitted changes/i,/changes.*not staged/i,/please.*commit.*changes/i,/please.*stash/i,/commit your changes or stash/i],DISK_FULL_PATTERNS=[/no space left on device/i,/disk quota exceeded/i,/ENOSPC/],NETWORK_PATTERNS=[/could not resolve host/i,/name.*resolution/i,/connection.*timed out/i,/operation timed out/i,/connection refused/i,/network.*unreachable/i,/ssl.*handshake/i,/unable to connect/i,/getaddrinfo/i,/econnrefused/i,/enotfound/i,/etimedout/i,/ehostunreach/i],HTTP_5XX_PATTERNS=[/\bHTTP[\s/]*5[0-9]{2}\b/i,/\bstatus:?\s*5[0-9]{2}\b/i,/\berror\s*5[0-9]{2}\b/i,/\bresponse.*?\b5[0-9]{2}\b/i],HTTP_429_PATTERNS=[/\bHTTP[\s/]*429\b/i,/\bstatus:?\s*429\b/i,/\berror\s*429\b/i,/rate.?limit/i,/too many requests/i];function classifyGitError(e){let t=e instanceof Error?e:Error(String(e)),S=extractStderr(t),w=`${t.message}\n${S}`.toLowerCase();return matchesAny(w,INDEX_LOCK_PATTERNS)?{class:`local`,subclass:`index-lock`,retryable:!0,message:`Git index locked by another process`,rawStderr:S}:matchesAny(w,DIRTY_TREE_PATTERNS)?{class:`local`,subclass:`dirty-tree`,retryable:!0,message:`Working tree has uncommitted changes`,rawStderr:S}:matchesAny(w,DISK_FULL_PATTERNS)?{class:`local`,subclass:`disk-full`,retryable:!0,message:`Disk full or quota exceeded`,rawStderr:S}:matchesAny(w,SCOPE_MISMATCH_PATTERNS)?{class:`auth`,subclass:`scope-mismatch`,retryable:!1,message:`GitHub token missing required scopes`,rawStderr:S}:matchesAny(w,AUTH_PATTERNS)?/\b401\b/.test(w)||/token.*expired/i.test(w)?{class:`auth`,subclass:`401`,retryable:!1,message:`Authentication failed — token may be expired`,rawStderr:S}:/\b403\b/.test(w)?matchesAny(w,PROTECTED_BRANCH_PATTERNS)?{class:`semantic`,subclass:`protected-branch`,retryable:!1,message:`Push rejected — branch is protected`,rawStderr:S}:{class:`auth`,subclass:`403`,retryable:!1,message:`Access denied (403)`,rawStderr:S}:{class:`auth`,subclass:`unknown-auth`,retryable:!1,message:`Authentication failed`,rawStderr:S}:matchesAny(w,PROTECTED_BRANCH_PATTERNS)?{class:`semantic`,subclass:`protected-branch`,retryable:!1,message:`Push rejected — branch is protected`,rawStderr:S}:matchesAny(w,NON_FAST_FORWARD_PATTERNS)?{class:`semantic`,subclass:`non-fast-forward`,retryable:!1,message:`Push rejected — remote has diverged (non-fast-forward)`,rawStderr:S}:matchesAny(w,MERGE_CONFLICT_PATTERNS)?{class:`semantic`,subclass:`merge-conflict`,retryable:!1,message:`Merge conflict — manual resolution required`,rawStderr:S}:matchesAny(w,LFS_PATTERNS)?{class:`structural`,subclass:`lfs-quota`,retryable:!1,message:`Git LFS quota exceeded`,rawStderr:S}:matchesAny(w,LARGE_FILE_PATTERNS)?{class:`structural`,subclass:`large-file`,retryable:!1,message:`File exceeds size limit`,rawStderr:S}:matchesAny(w,SECRET_DETECTED_PATTERNS)?{class:`structural`,subclass:`secret-detected`,retryable:!1,message:`Push blocked — secret or credential detected in content`,rawStderr:S}:matchesAny(w,PRE_RECEIVE_PATTERNS)?{class:`structural`,subclass:`pre-receive-hook`,retryable:!1,message:`Push rejected by server pre-receive hook`,rawStderr:S}:matchesAny(w,HTTP_429_PATTERNS)?{class:`network`,subclass:`429`,retryable:!0,message:`Rate limited — too many requests`,rawStderr:S}:matchesAny(w,HTTP_5XX_PATTERNS)?{class:`network`,subclass:`5xx`,retryable:!0,message:`Server error (5xx)`,rawStderr:S}:matchesAny(w,NETWORK_PATTERNS)?/timed? out/i.test(w)?{class:`network`,subclass:`timeout`,retryable:!0,message:`Connection timed out`,rawStderr:S}:/refused/i.test(w)||/econnrefused/i.test(w)?{class:`network`,subclass:`connection-refused`,retryable:!0,message:`Connection refused`,rawStderr:S}:/resolve.*host/i.test(w)||/enotfound/i.test(w)||/getaddrinfo/i.test(w)?{class:`network`,subclass:`dns`,retryable:!0,message:`DNS resolution failed`,rawStderr:S}:{class:`network`,subclass:`unknown-network`,retryable:!0,message:`Network error`,rawStderr:S}:{class:`local`,subclass:`unknown-local`,retryable:!0,message:t.message||`Unknown git error`,rawStderr:S}}function computeRemainingMs(e,t,S=Date.now()){if(!e)return 0;let w=new Date(e).getTime();if(Number.isNaN(w))return 0;let E=w+t*1e3;return Math.max(0,E-S)}const log=getLogger(`sync-engine`),SHA_HEX_40=/^[0-9a-f]{40}$/i;function jitteredMs(e){let t=e*1e3,S=t*.15*(2*Math.random()-1);return Math.round(t+S)}function isUnbornHead(e){try{let t=join(e,`.git`,`HEAD`);if(!existsSync(t))return!1;let S=readFileSync(t,`utf-8`).trim(),w=/^ref:\s+(refs\/.+)$/.exec(S);if(!w)return!1;let E=w[1];if(existsSync(join(e,`.git`,E)))return!1;let D=join(e,`.git`,`packed-refs`);if(existsSync(D)){let e=readFileSync(D,`utf-8`);if(RegExp(`^[0-9a-f]+\\s+${E}$`,`m`).test(e))return!1}return!0}catch{return!1}}function backoffMs(e){return e>=8?3600*1e3:e>=5?900*1e3:e>=3?300*1e3:0}var SyncEngine=class{state=`dormant`;projectDir;contentDir;contentFilter;contentRoot;pullIntervalSeconds;pushIntervalSeconds;syncEnabled;credentialArgs;cc1Broadcaster;onStateChange;setBatchInProgress;onAutoDisable;pullTimer=null;pushTimer=null;stateSaveTimer=null;lastSyncUtc=null;lastFetchUtc=null;lastPushedSha=null;consecutiveFailures=0;ahead=0;behind=0;conflictCount=0;error;pausedReason;currentBranch=`main`;pullInFlight=!1;pushInFlight=!1;hasRemote=!1;identityUnresolved=!1;statePath;conflictStore;constructor(e){this.projectDir=e.projectDir,this.contentDir=e.contentDir,this.contentFilter=e.contentFilter,this.contentRoot=e.contentRoot??``,this.pullIntervalSeconds=e.pullIntervalSeconds??30,this.pushIntervalSeconds=e.pushIntervalSeconds??60,this.syncEnabled=e.syncEnabled,this.credentialArgs=e.credentialArgs??[],this.cc1Broadcaster=e.cc1Broadcaster??null,this.onStateChange=e.onStateChange,this.setBatchInProgress=e.setBatchInProgress,this.onAutoDisable=e.onAutoDisable,this.statePath=resolve(getLocalDir(this.projectDir),`sync-state.json`),this.conflictStore=new ConflictStore(this.projectDir,this.currentBranch)}async start(){if(this.state!==`dormant`)return;this.loadState();let e=!1;try{let t=createGitInstance(this.projectDir,{credentialArgs:this.credentialArgs});e=(await t.git.raw(`remote`,`-v`)).trim().length>0,this.hasRemote=e;try{let e=(await t.git.raw(`rev-parse`,`--abbrev-ref`,`HEAD`)).trim();e&&e!==`HEAD`&&(this.currentBranch=e,this.conflictStore.setBranch(e))}catch{}}catch(e){log.warn({err:e},`[sync] remote detection failed`)}if(this.syncEnabled!==!0){e&&this.transitionTo(`disabled`),log.info({hasRemote:e,syncEnabled:this.syncEnabled},`[sync] sync not enabled — staying inactive`);return}if(!e){log.info({},`[sync] no remote detected — staying dormant`);return}this.transitionTo(`idle`);let t=existsSync(join(this.projectDir,`.git`,`MERGE_HEAD`));if(this.conflictCount>0&&!t)log.warn({count:this.conflictCount},`[sync] persisted conflicts but no MERGE_HEAD — clearing stale state`),this.conflictStore.clear(),this.conflictCount=0;else if(this.conflictCount>0&&t)try{let e=(await createGitInstance(this.projectDir,{credentialArgs:this.credentialArgs}).git.raw([`diff`,`--name-only`,`--diff-filter=U`])).trim(),t=new Set(e?e.split(`
|
|
3251
|
-
`).map(e=>e.trim()).filter(Boolean):[]),S=this.conflictCount;for(let e of this.conflictStore.list())t.has(e.file)||this.conflictStore.removeConflict(e.file);this.conflictCount=this.conflictStore.count(),this.conflictCount<S&&log.info({cleared:S-this.conflictCount,remaining:this.conflictCount},`[sync] reconciled conflicts.json against git unmerged index`)}catch(e){log.warn({err:e},`[sync] failed to reconcile conflicts with git index`)}if(t&&this.conflictCount===0){log.warn({},`[sync] stale MERGE_HEAD detected with no tracked conflicts — aborting merge`);try{await createGitInstance(this.projectDir,{credentialArgs:this.credentialArgs}).git.raw([`merge`,`--abort`])}catch(e){log.warn({err:e},`[sync] git merge --abort for stale MERGE_HEAD failed`)}}if(this.conflictCount>0){this.transitionTo(`conflict`),log.warn({count:this.conflictCount},`[sync] restarted with active conflicts — sync paused`);return}let S=computeRemainingMs(this.lastFetchUtc,this.pullIntervalSeconds),w=computeRemainingMs(this.lastSyncUtc,this.pushIntervalSeconds);this.schedulePull(S>0?S:void 0),this.schedulePush(w>0?w:void 0),log.info({branch:this.currentBranch,pullDelayMs:S,pushDelayMs:w},`[sync] started`)}stop(){this.pullTimer!==null&&(clearTimeout(this.pullTimer),this.pullTimer=null),this.pushTimer!==null&&(clearTimeout(this.pushTimer),this.pushTimer=null),this.stateSaveTimer!==null&&(clearTimeout(this.stateSaveTimer),this.stateSaveTimer=null),this.state!==`dormant`&&this.transitionTo(`dormant`)}async destroy(){this.stop(),this.saveStateNow()}async setEnabled(e){if(this.syncEnabled!==e){if(this.syncEnabled=e,!e){this.pullTimer!==null&&(clearTimeout(this.pullTimer),this.pullTimer=null),this.pushTimer!==null&&(clearTimeout(this.pushTimer),this.pushTimer=null);let e=3e4,t=Date.now();for(;this.pullInFlight||this.pushInFlight;){if(Date.now()-t>3e4){log.warn({pullInFlight:this.pullInFlight,pushInFlight:this.pushInFlight},`[sync] setEnabled(false): timed out waiting for in-flight cycle to drain`);break}await setTimeout$1(50)}this.pausedReason=void 0,this.error=void 0,this.transitionTo(this.hasRemote?`disabled`:`dormant`),this.saveStateNow();return}
|
|
3251
|
+
`).map(e=>e.trim()).filter(Boolean):[]),S=this.conflictCount;for(let e of this.conflictStore.list())t.has(e.file)||this.conflictStore.removeConflict(e.file);this.conflictCount=this.conflictStore.count(),this.conflictCount<S&&log.info({cleared:S-this.conflictCount,remaining:this.conflictCount},`[sync] reconciled conflicts.json against git unmerged index`)}catch(e){log.warn({err:e},`[sync] failed to reconcile conflicts with git index`)}if(t&&this.conflictCount===0){log.warn({},`[sync] stale MERGE_HEAD detected with no tracked conflicts — aborting merge`);try{await createGitInstance(this.projectDir,{credentialArgs:this.credentialArgs}).git.raw([`merge`,`--abort`])}catch(e){log.warn({err:e},`[sync] git merge --abort for stale MERGE_HEAD failed`)}}if(this.conflictCount>0){this.transitionTo(`conflict`),log.warn({count:this.conflictCount},`[sync] restarted with active conflicts — sync paused`);return}let S=computeRemainingMs(this.lastFetchUtc,this.pullIntervalSeconds),w=computeRemainingMs(this.lastSyncUtc,this.pushIntervalSeconds);this.schedulePull(S>0?S:void 0),this.schedulePush(w>0?w:void 0),log.info({branch:this.currentBranch,pullDelayMs:S,pushDelayMs:w},`[sync] started`)}stop(){this.pullTimer!==null&&(clearTimeout(this.pullTimer),this.pullTimer=null),this.pushTimer!==null&&(clearTimeout(this.pushTimer),this.pushTimer=null),this.stateSaveTimer!==null&&(clearTimeout(this.stateSaveTimer),this.stateSaveTimer=null),this.state!==`dormant`&&this.transitionTo(`dormant`)}async destroy(){this.stop(),this.saveStateNow()}async setEnabled(e){if(this.syncEnabled!==e){if(this.syncEnabled=e,!e){this.pullTimer!==null&&(clearTimeout(this.pullTimer),this.pullTimer=null),this.pushTimer!==null&&(clearTimeout(this.pushTimer),this.pushTimer=null);let e=3e4,t=Date.now();for(;this.pullInFlight||this.pushInFlight;){if(Date.now()-t>3e4){log.warn({pullInFlight:this.pullInFlight,pushInFlight:this.pushInFlight},`[sync] setEnabled(false): timed out waiting for in-flight cycle to drain`);break}await setTimeout$1(50)}this.pausedReason=void 0,this.error=void 0,this.transitionTo(this.hasRemote?`disabled`:`dormant`),this.saveStateNow();return}if(this.hasRemote=await this.probeRemote(),this.pausedReason=void 0,this.error=void 0,this.consecutiveFailures=0,!this.hasRemote){this.transitionTo(`dormant`),this.saveStateNow();return}this.transitionTo(`idle`),this.schedulePull(0),this.schedulePush(),this.saveStateNow()}}async trigger(e=`sync`){this.consecutiveFailures=0,(this.pausedReason===`dirty-tree`||this.pausedReason===`external-changes-pending`)&&(this.pausedReason=void 0,this.error=void 0),this.state===`dormant`||this.state===`disabled`||this.state===`conflict`||this.state===`auth-error`?log.warn({op:e,state:this.state,syncEnabled:this.syncEnabled,hasRemote:this.hasRemote,pausedReason:this.pausedReason,conflictCount:this.conflictCount},`[sync] trigger(${e}) ignored — state=${this.state}`):log.info({op:e,state:this.state},`[sync] trigger(${e}) running`),e===`push`?await this.runPushCycle():(e===`pull`||await this.runPushCycle(),await this.runPullCycle())}getStatus(){return{state:this.state,lastSyncUtc:this.lastSyncUtc,lastFetchUtc:this.lastFetchUtc,lastPushedSha:this.lastPushedSha,ahead:this.ahead,behind:this.behind,consecutiveFailures:this.consecutiveFailures,conflictCount:this.conflictCount,hasRemote:this.hasRemote,syncEnabled:this.syncEnabled===!0,identityUnresolved:this.identityUnresolved,error:this.error,pausedReason:this.pausedReason}}async refreshIdentity(){let e=await resolveGitIdentity(this.projectDir)===null;this.identityUnresolved!==e&&(this.identityUnresolved=e,this.cc1Broadcaster?.signal(`sync-status`))}async refreshRemote(){this.hasRemote||await this.probeRemote()&&(this.hasRemote=!0,log.info({syncEnabled:this.syncEnabled},`[sync] remote detected post-boot — re-evaluating state`),this.syncEnabled===!0?(this.transitionTo(`idle`),this.schedulePull(0),this.schedulePush()):this.transitionTo(`disabled`))}async probeRemote(){if(!existsSync(join(this.projectDir,`.git`)))return!1;try{return(await createGitInstance(this.projectDir,{credentialArgs:this.credentialArgs}).git.raw(`remote`,`-v`)).trim().length>0}catch(e){return log.warn({err:e},`[sync] remote detection failed`),!1}}getConflicts(){return this.conflictStore.list()}async resolveConflict(e,t,S){await this.conflictStore.resolveConflict(e,t,S),this.conflictCount=this.conflictStore.count(),this.conflictCount===0&&this.state===`conflict`&&(this.transitionTo(`idle`),this.pausedReason=void 0,this.schedulePull(),this.schedulePush()),this.scheduleSaveState()}updateCurrentBranch(e){e===null?this.state!==`dormant`&&this.state!==`disabled`&&(this.transitionTo(`disabled`),this.pausedReason=`detached-head`,this.scheduleSaveState()):this.currentBranch!==e&&(this.currentBranch=e,this.conflictStore.setBranch(e),this.state===`disabled`&&this.pausedReason===`detached-head`&&(this.pausedReason=void 0,this.transitionTo(`idle`),this.schedulePull(),this.schedulePush()))}schedulePull(e){this.pullTimer!==null&&clearTimeout(this.pullTimer);let t=e??this.effectivePullDelayMs();this.pullTimer=setTimeout(()=>{this.pullTimer=null,this.runPullCycle().catch(e=>{log.error({err:e},`[sync] pull cycle uncaught error`)})},t)}schedulePush(e){this.pushTimer!==null&&clearTimeout(this.pushTimer);let t=e??jitteredMs(this.pushIntervalSeconds);this.pushTimer=setTimeout(()=>{this.pushTimer=null,this.runPushCycle().catch(e=>{log.error({err:e},`[sync] push cycle uncaught error`)})},t)}effectivePullDelayMs(){let e=this.consecutiveFailures,t=backoffMs(e);return t>0?t:jitteredMs(this.pullIntervalSeconds)}async runPullCycle(){if(!this.pullInFlight&&!(this.state===`dormant`||this.state===`disabled`)){if(this.state===`conflict`){this.schedulePull();return}if(isUnbornHead(this.projectDir)){this.schedulePull();return}this.pullInFlight=!0;try{await this.doPullCycle()}finally{this.pullInFlight=!1,this.schedulePull()}}}async doPullCycle(){let e=createGitInstance(this.projectDir,{credentialArgs:this.credentialArgs}),t;try{let S=(await e.git.raw(`rev-parse`,`--abbrev-ref`,`HEAD`)).trim();if(!S||S===`HEAD`){this.transitionTo(`disabled`),this.pausedReason=`detached-head`,log.warn({},`[sync] detached HEAD — pausing sync`);return}t=S,this.currentBranch=t}catch(e){this.handleError(classifyGitError(e instanceof Error?e:Error(String(e))));return}this.transitionTo(`fetching`);try{await e.git.fetch(`origin`),this.lastFetchUtc=new Date().toISOString(),this.consecutiveFailures=0,this.error=void 0}catch(e){let t=classifyGitError(e instanceof Error?e:Error(String(e)));this.handleError(t);return}try{let t=await e.git.status();this.ahead=t.ahead,this.behind=t.behind}catch{}if(this.behind>0&&this.conflictCount===0){this.transitionTo(`pulling`),this.setBatchInProgress?.(!0);try{if(await this.commitDirtyContentFilesToHead(e),!await this.pauseIfNonContentDirty(e))return;await e.git.merge([`origin/${t}`]),this.lastSyncUtc=new Date().toISOString(),this.behind=0,this.transitionTo(`idle`)}catch(e){let t=classifyGitError(e instanceof Error?e:Error(String(e)));t.class===`semantic`&&t.subclass===`merge-conflict`?await this.handleMergeConflict():this.handleError(t);return}finally{this.setBatchInProgress?.(!1)}}else this.transitionTo(`idle`);this.scheduleSaveState()}async runPushCycle(){if(!this.pushInFlight&&!(this.state===`dormant`||this.state===`disabled`)&&!(this.state===`conflict`||this.state===`auth-error`)){if(isUnbornHead(this.projectDir)){this.schedulePush();return}this.pushInFlight=!0;try{await this.doPushCycle(1)}finally{this.pushInFlight=!1,this.schedulePush()}}}async doPushCycle(e=0){let t=this.gatherContentFilesSync(),S=join(tmpdir(),`ok-sync-idx-${process.pid}-${Date.now()}.idx`),w=null;this.transitionTo(`pushing`);try{await withParentLock(async()=>{let e=createGitInstance(this.projectDir,{credentialArgs:this.credentialArgs,gitIndexFile:S});if(isUnbornHead(this.projectDir)){log.info({},`[sync] repo has no commits yet — skipping push cycle`),this.transitionTo(`idle`);return}let E;try{E=(await e.git.revparse(`HEAD`)).trim()}catch(e){let t=e instanceof Error?e.message:String(e),S=`${t}\n${e.git?.toString()??t}`;if(/unknown revision or path not in the working tree/i.test(S)||/ambiguous argument 'HEAD'/i.test(S)||/does not have any commits yet/i.test(S)){log.info({},`[sync] repo has no commits yet — skipping push cycle`),this.transitionTo(`idle`);return}this.handleError(classifyGitError(e instanceof Error?e:Error(String(e))));return}await e.git.raw([`read-tree`,E]);let D=new Set;try{let t=(await e.git.raw([`ls-tree`,`-r`,`--name-only`,E])).trim();for(let e of t?t.split(`
|
|
3252
3252
|
`):[]){let t=e.trim();if(!t)continue;let S=join(this.projectDir,t),w=relative(this.contentDir,S);!w.startsWith(`..`)&&!this.contentFilter.isExcluded(w)&&D.add(t)}}catch{}if(t.length>0){let S=100;for(let S=0;S<t.length;S+=100){let w=t.slice(S,S+100).map(e=>e.projectRelPath);await e.git.raw([`add`,`--`,...w])}}let O=new Set(t.map(e=>e.projectRelPath)),k=[...D].filter(e=>!O.has(e));k.length>0&&await e.git.raw([`rm`,`--cached`,`--`,...k]);let j=(await e.git.raw([`write-tree`])).trim(),F=``;try{F=(await e.git.raw([`rev-parse`,`${E}^{tree}`])).trim()}catch{}if(F&&F===j){let S=null;try{S=(await e.git.raw([`rev-parse`,`origin/${this.currentBranch}`])).trim()}catch{}if(S===E){log.info({contentFileCount:t.length,headSha:E},`[sync] push cycle: nothing to commit (tree unchanged, origin matches HEAD)`),this.lastPushedSha=E,this.lastSyncUtc=new Date().toISOString(),this.transitionTo(`idle`);return}log.info({headSha:E,upstreamSha:S},`[sync] push cycle: tree unchanged but local ahead of origin — pushing existing commits`);let D=!1;try{await e.git.raw([`rev-parse`,`--abbrev-ref`,`${this.currentBranch}@{u}`]),D=!0}catch{}D?await e.git.raw([`push`,`origin`,this.currentBranch]):await e.git.raw([`push`,`--set-upstream`,`origin`,this.currentBranch]),w=E;return}let L=[];try{let S=(await e.git.raw([`diff-tree`,`--name-only`,`-r`,E,j])).trim();if(S){let e=new Map(t.map(e=>[e.projectRelPath,e.contentRelPath]));for(let t of S.split(`
|
|
3253
3253
|
`)){let S=t.trim();if(!S)continue;let w=e.get(S)??relative(this.contentDir,join(this.projectDir,S));w&&!w.startsWith(`..`)&&L.push(w)}}}catch{L=t.map(e=>e.contentRelPath)}let B=this.buildCommitMessage(L),H=await resolveGitIdentity(this.projectDir),q=H===null;this.identityUnresolved!==q&&(this.identityUnresolved=q,this.cc1Broadcaster?.signal(`sync-status`));let J=H?.name??`Open Knowledge`,Y=H?.email??`sync@open-knowledge.local`;e.git.env({GIT_AUTHOR_NAME:J,GIT_AUTHOR_EMAIL:Y,GIT_COMMITTER_NAME:J,GIT_COMMITTER_EMAIL:Y});let ee=(await e.git.raw([`commit-tree`,j,`-p`,E,`-m`,B])).trim();if(!ee||!SHA_HEX_40.test(ee)){log.warn({raw:ee},`[sync] commit-tree returned invalid SHA — aborting push`),this.transitionTo(`idle`);return}if(await e.git.raw([`update-ref`,`refs/heads/${this.currentBranch}`,ee,E]),t.length>0){let e=createGitInstance(this.projectDir,{credentialArgs:this.credentialArgs}),S=100;for(let S=0;S<t.length;S+=100){let w=t.slice(S,S+100).map(e=>e.projectRelPath);try{await e.git.raw([`reset`,`HEAD`,`--`,...w])}catch{}}}let te=!1;try{await e.git.raw([`rev-parse`,`--abbrev-ref`,`${this.currentBranch}@{u}`]),te=!0}catch{}te?await e.git.raw([`push`,`origin`,this.currentBranch]):await e.git.raw([`push`,`--set-upstream`,`origin`,this.currentBranch]),w=ee}),w&&(this.lastPushedSha=w,this.lastSyncUtc=new Date().toISOString(),this.ahead=0,this.state===`pushing`&&this.transitionTo(`idle`),this.pausedReason===`dirty-tree`&&(this.pausedReason=void 0,this.error=void 0,this.schedulePull(0)))}catch(t){let S=classifyGitError(t instanceof Error?t:Error(String(t)));if(S.class===`semantic`&&S.subclass===`non-fast-forward`){if(e>0){log.info({},`[sync] push rejected (non-fast-forward) — fetching, merging, retrying`);let e=createGitInstance(this.projectDir,{credentialArgs:this.credentialArgs});this.setBatchInProgress?.(!0);try{if(await e.git.fetch(`origin`),await this.commitDirtyContentFilesToHead(e),!await this.pauseIfNonContentDirty(e)){this.setBatchInProgress?.(!1);return}await e.git.merge([`origin/${this.currentBranch}`])}catch(e){let t=classifyGitError(e instanceof Error?e:Error(String(e)));t.class===`semantic`&&t.subclass===`merge-conflict`?await this.handleMergeConflict():this.handleError(t),this.scheduleSaveState();return}finally{this.setBatchInProgress?.(!1)}await this.doPushCycle(0);return}log.info({},`[sync] push still rejected after retry — waiting for next pull cycle`),this.consecutiveFailures++,this.state===`pushing`&&this.transitionTo(`idle`)}else this.handleError(S)}finally{try{unlinkSync(S)}catch{}}this.scheduleSaveState()}async commitDirtyContentFilesToHead(e){if((await e.git.status()).files.length===0)return null;let t=(await e.git.revparse(`HEAD`)).trim(),S=this.gatherContentFilesSync();if(S.length===0)return null;let w=join(tmpdir(),`ok-sync-retry-idx-${process.pid}-${Date.now()}.idx`),E=createGitInstance(this.projectDir,{credentialArgs:this.credentialArgs,gitIndexFile:w});try{await E.git.raw([`read-tree`,t]);let w=100;for(let e=0;e<S.length;e+=100){let t=S.slice(e,e+100).map(e=>e.projectRelPath);await E.git.raw([`add`,`--`,...t])}let D=(await E.git.raw([`write-tree`])).trim();if(D===(await E.git.raw([`rev-parse`,`${t}^{tree}`])).trim())return null;let O=await resolveGitIdentity(this.projectDir),k=O?.name??`Open Knowledge`,j=O?.email??`sync@open-knowledge.local`;E.git.env({GIT_AUTHOR_NAME:k,GIT_AUTHOR_EMAIL:j,GIT_COMMITTER_NAME:k,GIT_COMMITTER_EMAIL:j});let F=(await E.git.raw([`commit-tree`,D,`-p`,t,`-m`,`Auto-save: interim before merge`])).trim();if(!F||!SHA_HEX_40.test(F))return log.warn({raw:F},`[sync] commit-tree returned invalid SHA in commitDirtyContentFilesToHead`),null;await e.git.raw([`update-ref`,`refs/heads/${this.currentBranch}`,F,t]);for(let t=0;t<S.length;t+=100){let w=S.slice(t,t+100).map(e=>e.projectRelPath);try{await e.git.raw([`reset`,`HEAD`,`--`,...w])}catch{}}return F}finally{try{unlinkSync(w)}catch{}}}async pauseIfNonContentDirty(e){let t=``;try{t=(await e.git.raw([`diff-index`,`--name-only`,`HEAD`])).trim()}catch{return!0}if(!t)return!0;let S=t.split(`
|
|
3254
3254
|
`).map(e=>e.trim()).filter(Boolean);return S.length===0?!0:(this.error=`External changes pending: ${S.slice(0,3).join(`, `)}${S.length>3?`, +${S.length-3} more`:``}`,this.pausedReason=`external-changes-pending`,this.consecutiveFailures=0,this.transitionTo(`idle`),this.scheduleSaveState(),log.warn({files:S},`[sync] paused — non-content tracked files dirty`),!1)}gatherContentFilesSync(){let e=[],t=S=>{let w;try{w=readdirSync(S,{withFileTypes:!0})}catch{return}for(let E of w){let w=join(S,E.name);if(E.isDirectory()){if(E.name===`node_modules`||E.name===`.git`||E.name.startsWith(`.`)&&E.name!==`.ok`)continue;t(w)}else if(E.isFile()){let t=relative(this.contentDir,w);if(!t.startsWith(`..`)&&!this.contentFilter.isExcluded(t)){let S=relative(this.projectDir,w);e.push({contentRelPath:t,projectRelPath:S})}}}};return existsSync(this.contentDir)&&t(this.contentDir),e}buildCommitMessage(e){return e.length===0?`Auto-save: changes saved`:e.length<=3?`Auto-save: Updated ${e.join(`, `)}`:`Auto-save: ${e.length} files changed`}async handleMergeConflict(){let e=createGitInstance(this.projectDir,{credentialArgs:this.credentialArgs}),t=[];try{let S=(await e.git.raw([`diff`,`--name-only`,`--diff-filter=U`])).trim();t=S?S.split(`
|
|
@@ -3257,4 +3257,4 @@ In headless mode, write the recap into the research article's "Further reading"
|
|
|
3257
3257
|
`).split(`
|
|
3258
3258
|
`),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=Lt?.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:()=>Rt?.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:()=>Lt?Lt.getFileIndex():new Map,getFolderIndex:()=>Lt?Lt.getFolderIndex():new Map,getAliasMap:()=>Lt?Lt.getAliasMap():new Map,rescanFiles:()=>Lt?.rescanFromDisk(),enableTestRoutes:L,shadowRef:me,flushGitCommit:()=>ge.flushPendingGitCommit(),flushContributors:()=>ge.flushContributors(),getCurrentBranch:()=>Rt?.getLastKnownBranch()??null,getDiskAckSVs:()=>ye?.getLatestDiskAckSVsAsBase64()??{},contentRoot:H,backlinkIndex:de,tagIndex:fe,signalChannel:ze,agentFocusBroadcaster:Ce,agentPresenceBroadcaster:we,onAgentWrite:e.onAgentWrite,getSyncEngine:()=>zt,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:()=>Rt?.getLastKnownBranch()??null,resolveEmbed:se,resolveSize:ce}))}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),vt=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}`)}}},Tt=null,Et=e=>{e&&(Tt===null&&(Tt=new Set,setImmediate(()=>{let e=Tt;if(Tt=null,e)try{for(let t of e)vt(t)}catch(t){ee.error({err:t,basenames:[...e]},`[asset-event] dedup rerender pass crashed`)}})),Tt.add(e))};function Dt(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 jt(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`: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(),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)}break;case`merged`:try{st(t,O.newContent),setReconciledBase(t,O.newContent),incrementReconcile(),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)}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=Rt?.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=S.getMap(`lifecycle`);w.set(`status`,`conflict`),w.set(`reason`,`conflict-markers`),ee.info({docName:t},`[reconcile] conflict markers detected: ${t}`);break}case`asset-create`:oe.add(e.relativePath),ze(`files`),Et(basename(e.relativePath));break;case`asset-delete`:oe.remove(e.relativePath),ze(`files`),Et(basename(e.relativePath));break;case`folder-create`:case`folder-delete`:ze(`files`);break;default:assertNeverDiskEvent(e)}}catch(t){let S=Dt(e);ee.error({err:t,kind:e.kind,label:S},`[reconcile] failed to handle ${e.kind} for ${S}`)}}let Mt=[];async function Ft(e){if(isBatchInProgress()){Mt.push(e);return}await jt(e)}async function It(){let e=Mt.splice(0,Mt.length);for(let t of e)await jt(t)}let Lt=null,Rt=null,zt=null,Bt=null;async function Vt(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 Ht(){return Bt||(Bt=(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{Rt&&=(await Rt.unsubscribe(),null),Lt&&=(await Lt.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 Vt(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{zt&&=(await zt.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)})}}})(),Bt)}let Ut=[];async function Wt(){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`),Ut.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,Ut.includes(`shadow-repo`)||Ut.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`),Ut.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`),Ut.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`),Ut.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`),Ut.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();zt?.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}`),Ut.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`),Ut.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`)}}Lt=await startWatcher(t,Ft,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`),Ut.push(`basename-index-partial`))}catch(e){ee.error({err:e},`[basename-index] startup seed failed`),Ut.push(`basename-index`)}}catch(e){ee.error({err:e},`[server] disk bridge watcher failed to start`),Ut.push(`file-watcher`)}try{Rt=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=Mt.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 It(),await ge.flushDeferredStores(`within-branch`);else{incrementBranchSwitch(),Mt.splice(0,Mt.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`),Ut.includes(`basename-index-partial`)||Ut.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(`
|
|
3259
3259
|
`))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`),Ut.push(`head-watcher`)}let D=J?.[0]??`open-knowledge`,O=[`-c`,`credential.helper=!${J&&J.length>1?J.join(` `):D} auth git-credential`];try{zt=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 zt.start()}catch(e){ee.warn({err:e},`[server] SyncEngine failed to start — sync disabled`),zt=null}ze(`files`),ze(`backlinks`),ze(`graph`),ze(`tags`)}return Wt().then(Pe,Ie),{hocuspocus:_e,sessionManager:ve,cc1Broadcaster:ye,agentFocusBroadcaster:Ce,agentPresenceBroadcaster:we,contentFilter:ue,basenameIndex:oe,serverInstanceId:ne,destroy:Ht,ready:Re,degraded:Ut,lockDir:ae,get syncEngine(){return zt}}}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,ge=mountMcpAndApi({httpServer:fe,hocuspocus:J,mcpHttpHandler:de,log:E,sessionManager:ae,agentFocusBroadcaster:oe,agentPresenceBroadcaster:se,keepaliveGraceMs:e.keepaliveGraceMs,contentAssetMiddleware:me}),_e=null;w!==null&&(_e=attachIdleShutdown({httpServer:fe,thresholdMs:w??DEFAULT_IDLE_THRESHOLD_MS,log:E,onShutdown:(e.idleShutdownHandler??(e=>async()=>{await e()}))(async()=>{await Y()})})),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()})});let ve=fe.address(),ye=typeof ve==`object`&&ve?ve.port:e.port??0;if(ue=ye,j(ne,ye),S&&e.spawnUiSiblingFn)try{await e.spawnUiSiblingFn({lockDir:ne,log:E})}catch(e){E.warn({err:e},`spawnUiSiblingFn failed`)}let Ce=!1,we=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{httpServer:fe,destroy:async()=>{if(Ce)return;Ce=!0;let e=[],t=async(t,S)=>{try{await we(t,S)}catch(S){e.push(S),E.warn({err:S,step:t},`bootServer destroy step failed`)}};try{_e?.detach()}catch(t){e.push(t),E.warn({err:t,step:`idleHandle.detach`},`bootServer destroy step failed`)}if(await t(`mount.shutdown`,()=>ge.shutdown()),await t(`mcpHttpHandler.close`,()=>de.close()),await t(`mount.wss.close`,()=>new Promise((e,t)=>{ge.wss.close(S=>S?t(S):e())})),await t(`httpServer.closeAllConnections`,async()=>{fe.closeAllConnections?.()}),await t(`httpServer.close`,()=>new Promise((e,t)=>{fe.close(S=>S&&S.code!==`ERR_SERVER_NOT_RUNNING`?t(S):e())})),await t(`destroyHocuspocus`,()=>Y()),await t(`shutdownTelemetry`,()=>shutdownTelemetry()),e.length>0)throw AggregateError(e,`bootServer destroy completed with errors`)},lockDir:ne,contentDir:e.contentDir,port:ye,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{applySeed as $,rewriteWikiLinksForDocumentRename as $n,ASSET_EXTENSIONS as $r,incrementCollabSocketFilteredError as $t,MissingOkConfigError as A,NEVER as Ai,readBranchFromHead as An,updateLastKnownHash as Ar,createServer$1 as At,STARTER_FOLDER_FRONTMATTER_FILENAME as B,registerAllTools as Bn,writeTracker as Br,findEnclosingGitRoot as Bt,LOG_MD_TEMPLATE as C,literal as Ci,parseAuthRejectionWire as Cn,tracedRename as Cr,createContentFilter as Ct,MCP_SERVER_NAME as D,string$2 as Di,planPersonalTemplates as Dn,tracedUnlinkSync as Dr,createMcpHttpHandler as Dt,MCP_CONNECTION_ID_HEADER as E,object$1 as Ei,pathToDocName as En,tracedRmdirSync as Er,createLiveDerivedIndexExtension as Et,ProjectGitInitError as F,readTargetVersion as Fn,withSpan as Fr,detectProjectShape as Ft,SeedPrerequisiteError as G,resolveBundledSkillDir as Gn,isJSONRPCRequest as Gr,getCurrentMcpLogger as Gt,STARTER_PACK_IDS as H,releaseUiLock as Hn,JSONRPCMessageSchema as Hr,formatAuthRejectionWire as Ht,ROLLBACK_ORIGIN as I,readUiLock as In,withSpanSync as Ir,ensureProjectGit as It,TagIndex as J,resolveCursorSpawnInvocation as Jn,resolveConfigPath as Jr,getMeter as Jt,SeedRootDirError as K,resolveContentDir as Kn,isJSONRPCResultResponse as Kr,getLocalDir as Kt,SERVICE_WRITER as L,reconcile as Ln,writePersonalTemplates as Lr,errorResponse as Lt,PERSONAL_TEMPLATES as M,readSkillInstallStateSnapshot as Mn,validateAgentId as Mr,createStreamingErrorWriter as Mt,PERSONAL_TEMPLATE_NAMES as N,readStateManifest as Nn,validateCloneInputs as Nr,createTestLogger as Nt,MISSING_OK_CONFIG_MESSAGE as O,url as Oi,planSeed as On,tracedWriteFile as Or,createOsProbe as Ot,PinoLogger as P,readTargetRecordedAt as Pn,validateSkillZip as Pr,detectClaudeDesktopPresence as Pt,applyExternalChange as Q,rewriteMarkdownLinksForDocumentRename as Qn,ALL_EDITOR_IDS as Qr,handleSpawnCursor as Qt,SKILL_INSTALL_EVENTS_FILE_REL as R,recordContributor as Rn,writeStateManifest as Rr,evictStaleTrackerEntries as Rt,LIVE_DERIVED_INDEX_DEBOUNCE_MS as S,boolean$1 as Si,normalizeFsPath as Sn,tracedMkdirSync as Sr,createAssetServeMiddleware as St,MAX_AGENT_SESSIONS as T,number$1 as Ti,parseKeepaliveConnectionId as Tn,tracedRmSync as Tr,createExternalChangeHandler as Tt,STARTER_TEMPLATES as U,removeLastKnownHash as Un,LATEST_PROTOCOL_VERSION as Ur,formatContributors as Ut,STARTER_PACKS as V,registerWrite as Vn,McpServer as Vr,findEnclosingProjectRoot as Vt,STATE_MANIFEST_FILENAME as W,resetMetrics as Wn,isInitializedNotification as Wr,gcCheckpointRefs as Wt,acquireUiLock as X,resolvePack as Xn,GitDirAccessError as Xr,getTracer as Xt,UiLockCollisionError as Y,resolveLockDir as Yn,writeConfigPatch as Yr,getMetrics as Yt,applyAgentMarkdownWrite as Z,resolvePackageVersion as Zn,MalformedGitPointerError as Zr,handleCollabSocketError as Zt,GIT_UPSTREAM_WRITER as _,OK_PROJECT_MARKER as _i,listRescueCheckpoints as _n,streamingProblemEvent as _r,commitWipFromTree as _t,AgentPresenceBroadcaster as a,INLINE_RENDERABLE_EXTENSIONS as ai,isAllowedApiOrigin as an,safeContentPath as ar,buildExecResult as at,HocuspocusAuthTokenSchema as b,any$1 as bi,loggerFactory as bn,tracedLinkSync as br,contributorCount as bt,BacklinkIndex as c,SKILL_STATE_TARGETS as ci,isHocuspocusAuthRejectionReason as cn,sanitizeClientName as cr,buildSkillZip as ct,CURSOR_BUNDLE_PATHS_BY_PLATFORM as d,defaultScheduler as di,isPairedWriteOrigin as dn,seedBasenameIndex as dr,classifyEvents as dt,CC1_CONTRACT_VERSION as ei,incrementServerObserverFire as en,runAuthReposSubprocess as er,assertCompatibleStateManifest as et,ConfigSchema as f,humanFormat as fi,isPathWithinDir as fn,setActiveSpanAttributes as fr,classifyFsPath as ft,FILE_WATCHER_ORIGIN as g,LOCAL_DIR as gi,lastKnownHash as gn,startWatcher as gr,commitWip as gt,FILE_SYSTEM_WRITER as h,CONFIG_SCHEMA_MAJOR_PATH as hi,isSystemDoc as hn,splitMarkdownBlocks as hr,commitUpstreamImport as ht,AgentFocusBroadcaster as i,EXECUTABLE_BLOCKLIST_EXTENSIONS as ii,installUserSkill as in,runWithMcpLogger as ir,buildAndOpenSkill as it,OBSERVER_SYNC_ORIGIN as j,require_dist$2 as ji,readServerPackageVersion as jn,updateUiLockPort as jr,createServerObserverExtension as jt,McpLogger as k,_coercedNumber as ki,readAllTargets as kn,tracedWriteFileSync as kr,createPersistenceExtension as kt,CC1Broadcaster as l,SYSTEM_DOC_NAME as li,isKnownPackId as ln,saveInMemoryCheckpoint as lr,buildStarterFolderFrontmatterYaml as lt,DEFAULT_PACK_ID as m,isOrphanMode as mi,isSelfWrite as mn,shutdownTelemetry as mr,coercePackId as mt,AGENT_ID_RE as n,DEFAULT_SERVER_HOST as ni,initTelemetry as nn,runCloneSubprocess as nr,attachIdleShutdown as nt,AgentSessionCapacityError as o,ORPHAN_MODES as oi,isAllowedWorkspaceHostHeader as on,safeSubdir as or,buildInstructions as ot,DEFAULT_CHECKPOINT_RETENTION as p,iconFromClientName as pi,isProjectRoot as pn,shadowGit as pr,clearContributors as pt,StateManifestError as q,resolveCursorBinaryDefault as qn,readConfigSafely as qr,getLogger as qt,AGENT_WRITE_ORIGIN as r,EDITOR_LABELS as ri,installTestLoggers as rn,runDeviceFlowSubprocess as rr,bootServer as rt,AgentSessionManager as s,ProblemDetailsSchema as si,isConfigDoc as sn,safetyCheckpoint as sr,buildReadResult as st,AGENT_ID_MAX_LEN as t,DEFAULT_GITHUB_OAUTH_CLIENT_ID as ti,initShadowRepo as tn,runAuthStatusSubprocess as tr,assertNeverDiskEvent as tt,CONFLICT_MARKER_RE as u,colorFromSeed as ui,isLoopbackAddress as un,saveVersion as ur,buildWipTree as ut,HOCUSPOCUS_AUTH_REJECTION_REASONS as v,locateIssue as vi,listStarterPacks as vn,toBroadcasterKey as vr,containsConflictMarkers as vt,MANAGED_RENAME_ORIGIN as w,looseObject as wi,parseHocuspocusAuthToken as wn,tracedRenameSync as wr,createContentFilterAsync as wt,INSTALLED_AGENTS_SCHEMES as x,array as xi,mountMcpAndApi as xn,tracedMkdir as xr,createApiExtension as xt,HocuspocusAuthRejection as y,ZodNumber$1 as yi,loadPrincipal as yn,tracedAppendFileSync as yr,contentHash as yt,STARTER_FOLDERS as z,recordSkillInstallEvent as zn,writeTargetVersion as zr,extractWikiLinksFromMarkdown as zt};
|
|
3260
|
-
//# sourceMappingURL=dist-
|
|
3260
|
+
//# sourceMappingURL=dist-pXZHJhkA.mjs.map
|