@inkeep/open-knowledge 0.0.0-dev-20260421192027 → 0.0.0-dev-20260422092332
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/cli.mjs +9 -9
- package/dist/constants-DigVOZ9o.mjs +2 -0
- package/dist/index.mjs +1 -1
- package/dist/init-BPHczY2k.mjs +6 -0
- package/dist/{init-DeoOI04P.mjs → init-DiUw5TDX.mjs} +2 -2
- package/dist/{init-CyxGRu4t.mjs → init-EiMNbiMk.mjs} +1 -1
- package/dist/init-bL3p670c.mjs +1 -0
- package/dist/{loader-BNuhNFOT.mjs → loader-BOYrnnNP.mjs} +2 -2
- package/dist/loader-CecgSwbH.mjs +1 -0
- package/dist/paths-8lEuqzzC.mjs +1 -0
- package/dist/paths-Ub0bMbwu.mjs +2 -0
- package/dist/preview-CCBPkWf0.mjs +1 -0
- package/dist/{preview-oS_HbHIz.mjs → preview-DlFxxSWj.mjs} +2 -2
- package/dist/public/assets/index-DVyr5aVx.css +1 -0
- package/dist/public/assets/index-e4QpKJH0.js +381 -0
- package/dist/public/index.html +2 -2
- package/dist/{src-ViJPkmPW.mjs → src-CdcLi3q2.mjs} +8 -8
- package/dist/{src-DcVg7_6f.mjs → src-Cgk_X3wh.mjs} +51 -54
- package/dist/src-DYjDx2Br.mjs +1 -0
- package/dist/src-Dh_UJnt4.mjs +1 -0
- package/dist/start-BocQMsT6.mjs +1 -0
- package/dist/start-D6ddaQ_D.mjs +2 -0
- package/package.json +1 -1
- package/dist/constants-BLW6shM6.mjs +0 -2
- package/dist/init-B6g8iwyX.mjs +0 -1
- package/dist/init-WENor_lZ.mjs +0 -5
- package/dist/loader-bM_eCxHL.mjs +0 -1
- package/dist/paths-DxI4FHOZ.mjs +0 -2
- package/dist/paths-xS3o7pK2.mjs +0 -1
- package/dist/preview-BGOwfgOL.mjs +0 -1
- package/dist/public/assets/index-BqGPiKcl.js +0 -381
- package/dist/public/assets/index-DfpTuEYh.css +0 -1
- package/dist/src-D9A_jCdV.mjs +0 -1
- package/dist/src-NsJfsnSl.mjs +0 -1
- package/dist/start-BPpXybFr.mjs +0 -1
- package/dist/start-CNULXoun.mjs +0 -2
package/dist/cli.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
import{a as e,i as t}from"./constants-
|
|
2
|
+
import{a as e,i as t}from"./constants-DigVOZ9o.mjs";import{D as n,O as r,s as i}from"./src-CdcLi3q2.mjs";import{n as a,t as o}from"./paths-Ub0bMbwu.mjs";import{G as s,K as c,Q as l,W as u,d,q as f}from"./src-Cgk_X3wh.mjs";import{c as p,f as m,r as h}from"./server-lock-B4frNnOB.mjs";import{i as g}from"./init-DiUw5TDX.mjs";import{t as _}from"./is-object-B4GcZahG.mjs";import{r as v}from"./init-BPHczY2k.mjs";import{i as y,n as b,t as x}from"./loader-BOYrnnNP.mjs";import{a as S,o as C}from"./start-D6ddaQ_D.mjs";import"./src-DYjDx2Br.mjs";import{Command as w}from"commander";import{appendFileSync as T,closeSync as E,existsSync as D,mkdirSync as O,openSync as ee,readFileSync as k,readdirSync as te,statSync as ne,unlinkSync as re,writeFileSync as ie}from"node:fs";import{homedir as ae,hostname as oe}from"node:os";import{basename as se,dirname as ce,isAbsolute as le,join as ue,relative as de,resolve as A}from"node:path";import{parse as fe,stringify as pe}from"yaml";import{createOAuthDeviceAuth as me}from"@octokit/auth-oauth-device";import he from"@inquirer/password";import{Octokit as ge}from"@octokit/rest";import{fileURLToPath as _e}from"node:url";import{randomUUID as ve}from"node:crypto";import{execFileSync as ye,spawn as be}from"node:child_process";import xe from"simple-git";import{readFile as Se,readdir as Ce,stat as we}from"node:fs/promises";import{createServer as Te,request as Ee}from"node:http";import De from"picomatch";import{z as j}from"zod";import{McpServer as Oe}from"@modelcontextprotocol/sdk/server/mcp.js";import{StdioServerTransport as ke}from"@modelcontextprotocol/sdk/server/stdio.js";import{RootsListChangedNotificationSchema as Ae}from"@modelcontextprotocol/sdk/types.js";import{Bash as je,ReadWriteFs as Me}from"just-bash";import Ne from"shell-quote";const Pe=`open-knowledge`;var Fe=class{backend=`keyring`;async get(e){let{Entry:t}=await import(`@napi-rs/keyring`);try{let n=new t(Pe,e).getPassword();return n==null?null:JSON.parse(n)}catch{return null}}async set(e,t,n,r){let{Entry:i}=await import(`@napi-rs/keyring`),a=new i(Pe,e),o={login:t,token:n,...r};a.setPassword(JSON.stringify(o))}async clear(e){let{Entry:t}=await import(`@napi-rs/keyring`);try{new t(Pe,e).deletePassword()}catch{}}},Ie=class{backend=`file`;authFile;constructor(e){this.authFile=e??ue(ae(),`.open-knowledge`,`auth.yml`)}read(){if(!D(this.authFile))return{};try{return fe(k(this.authFile,`utf-8`))??{}}catch(e){let t=e instanceof Error?e.message:`unknown error`;return process.stderr.write(`[auth] Failed to parse ${this.authFile}: ${t}. Starting with empty credentials.\n`),{}}}write(e){let t=ce(this.authFile);D(t)||O(t,{recursive:!0,mode:448}),ie(this.authFile,pe(e),{mode:384})}async get(e){return this.read()[e]??null}async set(e,t,n,r){let i=this.read();i[e]={login:t,token:n,...r},this.write(i)}async clear(e){let t=this.read();delete t[e],this.write(t)}};async function Le(e){try{let{Entry:e}=await import(`@napi-rs/keyring`);return new e(Pe,`__probe__`),process.stderr.write(`[auth] token storage: OS keychain
|
|
3
3
|
`),new Fe}catch{return process.stderr.write(`[auth] token storage: file (~/.open-knowledge/auth.yml)
|
|
4
4
|
`),new Ie(e)}}async function Re(e,t,n){let r=ze(await Be(e)).host??``;if(!r)return 1;let i=await n.get(r);if(i==null)return 1;let a=e=>e.replace(/[\r\n]/g,``);return t.write(`username=${a(i.login)}\npassword=${a(i.token)}\n`),0}function ze(e){let t={};for(let n of e.split(`
|
|
5
5
|
`)){let e=n.trim();if(e===``)continue;let r=e.indexOf(`=`);r!==-1&&(t[e.slice(0,r)]=e.slice(r+1))}return t}function Be(e){return new Promise((t,n)=>{let r=[];e.on(`data`,e=>r.push(e)),e.on(`end`,()=>t(Buffer.concat(r).toString(`utf-8`))),e.on(`error`,n)})}function Ve(e){let t=new w(`git-credential`);return t.description(`Git credential helper (git credential-helper protocol)`),t.command(`get`).description(`Lookup credentials from TokenStore (called by git)`).action(async()=>{let t=await e(),n=await Re(process.stdin,process.stdout,t);process.exit(n)}),t}async function He(e){let{clientId:t,scopes:n=[`repo`,`read:user`,`user:email`],onVerification:r,host:i}=e,a=i&&i!==`github.com`?`https://${i}/api/v3`:`https://api.github.com`,o=me({clientType:`oauth-app`,clientId:t,scopes:n,onVerification:async e=>{await r({verificationUri:e.verification_uri,userCode:e.user_code,expiresIn:e.expires_in,interval:e.interval})},request:a===`https://api.github.com`?void 0:(await import(`@octokit/request`)).request.defaults({baseUrl:a})}),s;try{s=await o({type:`oauth`})}catch(e){if(e instanceof Error){let t=e.message.toLowerCase();throw t.includes(`access_denied`)?Error(`Device-flow authorization was denied.`):t.includes(`expired_token`)||t.includes(`timeout`)||t.includes(`timed out`)?Error(`Device-flow code expired before authorization — please try again.`):Error(`GitHub sign-in failed: ${e.message}`)}throw e}return{token:s.token,tokenType:s.tokenType,scopes:s.scopes??[]}}function Ue(e){return process.env.OPEN_KNOWLEDGE_GITHUB_CLIENT_ID??e?.github?.oauthAppClientId??`Ov23liqlSd0V1MwR6rhI`}const We=new Set([`gitlab.com`,`bitbucket.org`,`codeberg.org`,`gitea.com`,`sr.ht`,`sourcehut.org`]);function Ge(e){let t=e.toLowerCase().replace(/:\d+$/,``);We.has(t)&&(process.stderr.write(`Error: ${e} is not a GitHub host. Only GitHub and GitHub Enterprise Server are supported.\n`),process.exit(1))}function Ke(e,t){e&&process.stdout.write(`${JSON.stringify(t)}\n`)}async function qe(e,t,n,r=He){let i=Ue(n),{host:a,json:o}=e;Ge(a),o||process.stderr.write(`Logging in to ${a}…\n`);let s=await r({clientId:i,host:a===`github.com`?void 0:a,onVerification:e=>{e.userCode,e.verificationUri,o?Ke(!0,{type:`verification`,user_code:e.userCode,verification_uri:e.verificationUri,expires_in:e.expiresIn}):process.stderr.write(`Open: ${e.verificationUri}\nEnter code: ${e.userCode}\n`)}}),c=`unknown`,l,u;try{let e=a===`github.com`?`https://api.github.com`:`https://${a}/api/v3`,t=await fetch(`${e}/user`,{headers:{Authorization:`Bearer ${s.token}`,"User-Agent":`open-knowledge-cli`,Accept:`application/vnd.github+json`}});if(t.ok){let e=await t.json();c=e.login??c,l=e.name??void 0,u=e.email??void 0}}catch{}await t.set(a,c,s.token,{gitProtocol:`https`,name:l,email:u}),o?Ke(!0,{type:`complete`,host:a,login:c}):process.stderr.write(`✓ Logged in as ${c} on ${a}\n`)}function Je(e,t){return new w(`login`).description(`Authenticate with GitHub via Device Flow`).option(`--host <host>`,`GitHub or GitHub Enterprise hostname`,`github.com`).option(`--json`,`Output JSONL progress events`,!1).action(async n=>{await qe(n,await t(),e())})}async function Ye(e,t,n){let{host:r,json:i}=e;Ge(r);let a=await(n??(()=>he({message:`Enter PAT:`})))();a||(process.stderr.write(`No token provided
|
|
@@ -7,7 +7,7 @@ import{a as e,i as t}from"./constants-BLW6shM6.mjs";import{D as n,O as r,s as i}
|
|
|
7
7
|
`),process.exit(1)}await t.set(r,c,a,{gitProtocol:`https`,name:l,email:u}),i?process.stdout.write(`${JSON.stringify({type:`complete`,host:r,login:c})}\n`):process.stderr.write(`✓ PAT stored for ${c} on ${r}\n`)}function Xe(e){return new w(`pat`).description(`Store a Personal Access Token`).option(`--host <host>`,`GitHub or GitHub Enterprise hostname`,`github.com`).option(`--json`,`Output JSON`,!1).action(async t=>{await Ye(t,await e())})}async function Ze(e,t){let{host:n,json:r}=e;Ge(n);let i=await t.get(n);i??(process.stderr.write(`Not logged in to ${n}\n`),process.exit(1));let a=n===`github.com`?void 0:`https://${n}/api/v3`,o=new ge({auth:i.token,...a?{baseUrl:a}:{}}),s=[];for await(let e of o.paginate.iterator(o.repos.listForAuthenticatedUser,{per_page:100,sort:`updated`}))for(let t of e.data)s.push({full_name:t.full_name,clone_url:t.clone_url,private:t.private});if(r)process.stdout.write(`${JSON.stringify({type:`repos`,host:n,repos:s})}\n`);else for(let e of s)process.stdout.write(`${e.full_name} ${e.clone_url}\n`)}function Qe(e){return new w(`repos`).description(`List accessible repositories`).option(`--host <host>`,`GitHub or GitHub Enterprise hostname`,`github.com`).option(`--json`,`Output JSON`,!1).action(async t=>{await Ze(t,await e())})}async function $e(e,t){let{host:n}=e;await t.clear(n),process.stderr.write(`✓ Signed out from ${n}\n`)}function et(e){return new w(`signout`).description(`Remove stored credentials`).option(`--host <host>`,`GitHub hostname`,`github.com`).action(async t=>{await $e(t,await e())})}async function tt(e,t){let{host:n,json:r}=e;Ge(n);let i=await t.get(n);i??(r?process.stdout.write(`${JSON.stringify({type:`status`,host:n,authenticated:!1})}\n`):process.stderr.write(`Not logged in to ${n}\n`),process.exit(1));let a=n===`github.com`?void 0:`https://${n}/api/v3`,o=new ge({auth:i.token,...a?{baseUrl:a}:{}});try{let{data:e}=await o.users.getAuthenticated();r?process.stdout.write(`${JSON.stringify({type:`status`,host:n,authenticated:!0,login:e.login,name:e.name,email:e.email})}\n`):process.stderr.write(`✓ Logged in as ${e.login} on ${n}\n`)}catch{r?process.stdout.write(JSON.stringify({type:`status`,host:n,authenticated:!1,error:`token invalid`})+`
|
|
8
8
|
`):process.stderr.write(`✗ Token invalid for ${n}\n`),process.exit(1)}}function nt(e){return new w(`status`).description(`Show authentication status`).option(`--host <host>`,`GitHub or GitHub Enterprise hostname`,`github.com`).option(`--json`,`Output JSON`,!1).action(async t=>{await tt(t,await e())})}function rt(e){let t=new w(`auth`);t.description(`GitHub authentication management`);let n=()=>Le(),r=e??(()=>({}));return t.addCommand(Je(r,n)),t.addCommand(nt(n)),t.addCommand(Qe(n)),t.addCommand(et(n)),t.addCommand(Xe(n)),t.addCommand(Ve(n)),t}function it(e,t,n={}){let r=p(e,t);if(!D(r))return{status:`missing`,lockPath:r};let i;try{i=JSON.parse(k(r,`utf-8`))}catch{return{status:`corrupt`,lockPath:r}}if(!i||typeof i!=`object`||typeof i.pid!=`number`)return{status:`corrupt`,lockPath:r};let a=i,o=n.host??oe();return a.hostname===o?(n.isAlive??m)(a.pid)?{status:`alive`,lockPath:r,lock:a}:{status:`dead-pid`,lockPath:r,lock:a}:{status:`foreign-host`,lockPath:r,lock:a}}function at(e,t){let n=[];for(let[r,i]of[[`server`,e],[`ui`,t]])(i.status===`dead-pid`||i.status===`corrupt`)&&n.push({name:r,lockPath:i.lockPath,reason:i.status});return{prune:n}}function ot(e){let t=e.inspect??(t=>it(e.lockDir,t)),n=e.unlink??(e=>re(e)),r=e.log??(e=>console.log(e)),i=e.error??(e=>console.error(e)),a=at(t(`server`),t(`ui`));if(a.prune.length===0)return r(`No stale locks.`),{pruned:[],failed:[]};let o=[],s=[];for(let e of a.prune)try{n(e.lockPath),o.push(e)}catch(t){s.push({target:e,error:t instanceof Error?t.message:String(t)})}if(o.length>0){let e=o.map(e=>`${e.name} (${e.reason})`).join(`, `);r(`Pruned ${o.length} stale lock${o.length===1?``:`s`}: ${e}`)}return s.length>0&&i(`Failed to prune: ${s.map(({target:e,error:t})=>`${e.name} (${e.lockPath}): ${t}`).join(`; `)}`),{pruned:o,failed:s}}function st(e){return new w(`clean`).description(`Prune stale / corrupt open-knowledge lock files (never touches live locks)`).action(()=>{ot({lockDir:a(o(e(),process.cwd()))}).failed.length>0&&(process.exitCode=1)})}function ct(){try{let e=ye(`gh`,[`auth`,`token`],{encoding:`utf-8`,stdio:[`ignore`,`pipe`,`pipe`],timeout:5e3}).trim();return e.length===0?{available:!1}:{available:!0,token:e}}catch{return{available:!1}}}async function lt(e,t,n={},r=ct){if(!n.skipGhDetect&&r().available)return{tier:`A`,credentialArgs:[`-c`,`credential.helper=!gh auth git-credential`]};let i=await t.get(e);return i==null?{tier:`none`,credentialArgs:[]}:{tier:i.gitProtocol===`ssh`?`C`:`B`,credentialArgs:[`-c`,`credential.helper=!open-knowledge auth git-credential`]}}function ut(e){return e.replace(/:\d+$/,``)}function dt(e){let t=e.trim();if(!t)return null;{let e=/^https?:\/\/([^/?#]+)\/([\w.\-~%]+)\/([\w.\-~%]+?)(?:\.git)?\/?$/.exec(t);if(e)return{protocol:`https`,hostname:ut(e[1]),owner:e[2],name:e[3]}}{let e=/^ssh:\/\/(?:[\w.-]+@)?([^/?#]+)\/([\w.\-~%]+)\/([\w.\-~%]+?)(?:\.git)?\/?$/.exec(t);if(e)return{protocol:`ssh`,hostname:ut(e[1]),owner:e[2],name:e[3]}}{let e=/^git:\/\/([^/?#]+)\/([\w.\-~%]+)\/([\w.\-~%]+?)(?:\.git)?\/?$/.exec(t);if(e)return{protocol:`git`,hostname:ut(e[1]),owner:e[2],name:e[3]}}{let e=/^(?:[\w.-]+@)?([\w.-]+):([\w.\-~%]+)\/([\w.\-~%]+?)(?:\.git)?$/.exec(t);if(e?.[1].includes(`.`)||e&&t.startsWith(`git@`))return{protocol:`ssh`,hostname:e[1],owner:e[2],name:e[3]}}{let e=/^git:([\w.-]+)\/([\w.\-~%]+)\/([\w.\-~%]+?)(?:\.git)?\/?$/.exec(t);if(e)return{protocol:`git`,hostname:e[1],owner:e[2],name:e[3]}}if(!t.includes(`://`)&&!t.includes(`@`)&&!t.startsWith(`/`)){let e=/^([\w.-]+)\/([\w.\-~%]+?)(?:\.git)?$/.exec(t);if(e)return{protocol:`https`,hostname:`github.com`,owner:e[1],name:e[2]}}return null}const ft=[[`count`,0,10],[`compress`,10,20],[`receiv`,20,60],[`resolv`,60,100]];function pt(e){let t=/^([\w ]+):\s+(\d+)%/.exec(e.trim());if(!t)return null;let n=t[1].toLowerCase(),r=Number(t[2]);for(let[e,i,a]of ft)if(n.includes(e))return{stage:t[1],pct:Math.round(i+r/100*(a-i))};return null}function mt(e,t){e&&process.stdout.write(`${JSON.stringify(t)}\n`)}async function ht(e,t,n,r=process.cwd()){let i=dt(e);if(!i)throw Error(`Invalid git URL: ${e}`);let a=t.dir?A(r,t.dir):A(r,i.name);if(D(a)&&te(a).length>0)throw Error(`Target directory is not empty: ${a}`);let o=await Le(),s=await lt(i.hostname,o,{}),c=xe({baseDir:r,config:s.credentialArgs.length>=2?[s.credentialArgs[1]]:[],unsafe:{allowUnsafeCredentialHelper:!0}}).env({GIT_TERMINAL_PROMPT:`0`}),l=-1;if(c.outputHandler((e,n,r)=>{r.on(`data`,e=>{let n=e.toString(`utf-8`);for(let e of n.split(`
|
|
9
9
|
`)){let n=pt(e);n&&n.pct!==l&&(l=n.pct,mt(t.json,{type:`progress`,pct:n.pct,stage:n.stage}),t.json||process.stderr.write(`\r Cloning… ${n.pct}%`))}})}),await c.clone(e,a,[`--progress`]),t.json||process.stderr.write(`
|
|
10
|
-
`),!D(A(a,`.open-knowledge`)))try{let[{runInit:e},{ensureOkGitignoredAtRoot:t}]=await Promise.all([import(`./init-
|
|
10
|
+
`),!D(A(a,`.open-knowledge`)))try{let[{runInit:e},{ensureOkGitignoredAtRoot:t}]=await Promise.all([import(`./init-bL3p670c.mjs`),import(`./init-EiMNbiMk.mjs`)]);await e({cwd:a,mcp:!1});try{t(a)}catch{}}catch{}return a}function gt(e){return new w(`clone`).description(`Clone a git repository and open it`).argument(`<url>`,`Repository URL or owner/repo shorthand`).argument(`[dir]`,`Target directory (default: ./<repo-name>)`).option(`--json`,`Output JSONL progress events`,!1).action(async(t,n,r)=>{let i=e();try{let a=await ht(t,{json:r.json,dir:n},i);if(r.json)mt(!0,{type:`complete`,dir:a});else{process.stderr.write(`✓ Cloned to ${a}\n`),process.chdir(a);let{startCommand:t}=await import(`./start-BocQMsT6.mjs`);await t(e).parseAsync([],{from:`user`})}}catch(e){let t=e instanceof Error?e.message:String(e);r.json?mt(!0,{type:`error`,message:t}):process.stderr.write(`✗ ${t}\n`),process.exitCode=1}})}var _t=class e{sessionId;corrId;component;constructor(e=`mcp`,t){this.sessionId=t??ve().slice(0,12),this.corrId=ve().slice(0,8),this.component=e}info(e,t={}){this.emit(`info`,e,t)}warn(e,t={}){this.emit(`warn`,e,t)}error(e,t,n={}){let r=t?{error:t instanceof Error?t.message:String(t),...n}:n;this.emit(`error`,e,r)}debug(e,t={}){(process.env.MCP_DEBUG===`1`||process.env.DEBUG?.includes(`mcp`))&&this.emit(`debug`,e,t)}child(t){return new e(t??this.component,this.sessionId)}asCallback(){return e=>this.info(e)}emit(e,t,n){let r={ts:new Date().toISOString(),level:e,sessionId:this.sessionId,corrId:this.corrId,component:this.component,msg:t,...n},i=`${JSON.stringify(r)}\n`;process.stderr.write(i);let a=process.env.OK_LOG_FILE;if(a)try{T(a,i)}catch(e){console.warn(`[mcp-logger] Failed to write to OK_LOG_FILE: ${e instanceof Error?e.message:e}`)}}};function vt(e=`mcp`){return new _t(e)}const M="Absolute host path to resolve the request against. Defaults only when the MCP client advertises exactly one root; otherwise pass `cwd` explicitly.";function N(e,t){return{content:[{type:`text`,text:e}],...t?{isError:!0}:{}}}function P(e,t,n){return{content:[{type:`text`,text:e}],structuredContent:t,...n?{isError:!0}:{}}}const F="Error: Hocuspocus server is not running. Start it with `open-knowledge start`, then retry.\nFor disk-only writes without real-time sync, use your native Edit tool directly.";async function yt(e,t){return typeof e==`function`?await e(t):e}async function bt(e,t){return typeof e==`function`?await e(t):e}async function I(e,t,n){let r;try{r=await e(n)}catch(e){return{ok:!1,error:e instanceof Error?e.message:String(e)}}try{let e=await bt(t,r);return{ok:!0,cwd:r,config:e}}catch(e){return{ok:!1,error:e instanceof Error?e.message:String(e)}}}async function L(e,t,n,r){let i=await I(e,t,r);if(!i.ok)return i;let{cwd:a,config:o}=i;try{return{ok:!0,cwd:a,config:o,url:await yt(n,a)}}catch(e){return{ok:!1,error:e instanceof Error?e.message:String(e)}}}function R(e){let t=e.toLowerCase();return t.endsWith(`.md`)?{ok:!0,docName:e.slice(0,-3)}:t.endsWith(`.mdx`)?{ok:!0,docName:e.slice(0,-4)}:t.endsWith(`.markdown`)?{ok:!1,error:`Error: docName "${e}" ends in ".markdown", which is not a supported extension. Use ".md" or ".mdx", or strip the extension to let the server auto-detect.`}:{ok:!0,docName:e}}async function z(e,t){let n;try{n=await fetch(`${e}${t}`,{signal:AbortSignal.timeout(3e4)})}catch(e){return{ok:!1,error:`Server unreachable: ${e instanceof Error?e.message:e}`}}try{return await n.json()}catch{return{ok:!1,error:`Server returned HTTP ${n.status} with non-JSON body`}}}async function B(e,t,n){let r;try{r=await fetch(`${e}${t}`,{method:`POST`,headers:{"Content-Type":`application/json`},body:n?JSON.stringify(n):void 0,signal:AbortSignal.timeout(3e4)})}catch(e){return{ok:!1,error:`Server unreachable: ${e instanceof Error?e.message:e}`}}try{return await r.json()}catch{return{ok:!1,error:`Server returned HTTP ${r.status} with non-JSON body`}}}function xt(e,t){return`Promote existing research on this topic into a canonical article inside the project content directory. **Canonical, not provisional** — the output is the source of truth for future agents.
|
|
11
11
|
|
|
12
12
|
Topic: ${e}
|
|
13
13
|
|
|
@@ -150,15 +150,15 @@ superseded_by: <path-to-new-canonical-article>.md
|
|
|
150
150
|
- **Don't skip the supersedes / superseded_by links** — the audit trail matters for future readers
|
|
151
151
|
|
|
152
152
|
Full convention: read \`${n}/AGENTS.md\`.`}const St=[`Promote research into a canonical article inside the project content directory. Canonical, not provisional — the output is the source of truth for future agents.`,``,`**Use when:**`,`- A team has made a decision after research and wants the outcome committed as canonical knowledge`,`- Compacting several provisional research notes into one authoritative article`,`- A developer asks to "consolidate" or "finalize" knowledge on a topic`,``,`**Triggers on:**`,`- "consolidate", "finalize", "promote to canonical", "make this official"`,`- User says the team has decided and wants the outcome written as canonical`,`- Research has stabilized and a destination article is needed`].join(`
|
|
153
|
-
`);function Ct(e,t){e.tool(`consolidate`,St,{topic:j.string().describe(`The topic to consolidate into a canonical article`),cwd:j.string().optional().describe(M)},async e=>{let n=await I(t.resolveCwd,t.config,e.cwd);return n.ok?P(xt(e.topic,n.config.content.dir),{previewUrl:null}):N(`Error: ${n.error}`,!0)})}function wt(e){return e.split(`/`).map(encodeURIComponent).join(`/`)}function Tt(e){return e.endsWith(`/`)?e.slice(0,-1):e}function Et(e){try{return new URL(e),!0}catch{return!1}}async function V(e,t,n){let r=n??await t.resolveCwd(),i=await bt(t.config,r);return U(e,{config:i,lockDir:a(o(i,r))})}function Dt(e){try{let t=
|
|
153
|
+
`);function Ct(e,t){e.tool(`consolidate`,St,{topic:j.string().describe(`The topic to consolidate into a canonical article`),cwd:j.string().optional().describe(M)},async e=>{let n=await I(t.resolveCwd,t.config,e.cwd);return n.ok?P(xt(e.topic,n.config.content.dir),{previewUrl:null}):N(`Error: ${n.error}`,!0)})}function wt(e){return e.split(`/`).map(encodeURIComponent).join(`/`)}function Tt(e){return e.endsWith(`/`)?e.slice(0,-1):e}function Et(e){try{return new URL(e),!0}catch{return!1}}async function V(e,t,n){let r=n??await t.resolveCwd(),i=await bt(t.config,r);return U(e,{config:i,lockDir:a(o(i,r))})}function Dt(e){try{let t=l(e.lockDir);if(t&&t.port>0)return{baseUrl:`http://localhost:${t.port}`,port:t.port}}catch(t){process.stderr.write(`[preview-url] readUiLock failed at ${e.lockDir} while building ui block: ${t instanceof Error?t.message:String(t)}\n`)}return{baseUrl:null,port:null}}async function H(e,t){let n=t??await e.resolveCwd(),r=await bt(e.config,n),i={config:r,lockDir:a(o(r,n))};return{resolve:e=>U(e,i),ui:Dt(i)}}function Ot(e){let t=e.toLowerCase();return t.endsWith(`.md`)?e.slice(0,-3):t.endsWith(`.mdx`)?e.slice(0,-4):e}function U(e,t){let n=`/#/${wt(e)}`,r=process.env.OPEN_KNOWLEDGE_PREVIEW_BASE_URL;if(r&&Et(r))return{url:`${Tt(r)}${n}`,source:`env`};try{let e=l(t.lockDir);if(e&&e.port>0)return{url:`http://localhost:${e.port}${n}`,source:`lock`}}catch(e){process.stderr.write(`[preview-url] readUiLock failed at ${t.lockDir}, falling through to config: ${e instanceof Error?e.message:String(e)}\n`)}let i=t.config.preview?.baseUrl;return i&&Et(i)?{url:`${Tt(i)}${n}`,source:`config`}:null}const kt=["**IMPORTANT: Before calling this tool, you MUST first call `get_preview_url` and navigate to the returned URL in your preview browser. If `get_preview_url` returns null, start the server first (`open-knowledge start` or `preview_start`), then call `get_preview_url` again. Do NOT call this tool without the preview open. NEVER manually construct the URL.**",``,`[Requires: Hocuspocus server] Find-and-replace on a live document via the CRDT layer.`,`The patch is applied through Hocuspocus and propagated to all connected editors in real-time.`,"Use `offset` when you need to patch an exact occurrence; omit it to preserve first-match behavior.",``,"**When rewriting prose, add `[[wiki-links]]` aggressively.** If the replacement mentions other documents or entities that should have their own page, link them as `[[Page Name]]`. Over-linking is the goal; underlinked documents lose their value in backlink-driven navigation.",``,`**Parameters:**`,"- `docName` — Document name, typically without extension. A trailing `.md` or `.mdx` is stripped automatically.","- `find` — Text to find (exact match)","- `replace` — Replacement text","- `offset` (optional) — Exact occurrence to patch, as a JavaScript string offset in the current markdown. If the document changed and the text no longer matches there, the server returns a stale-target error; re-run `suggest_links` to get fresh offsets."].join(`
|
|
154
154
|
`);function At(e,t){e.tool(`edit_document`,kt,{docName:j.string().describe(`Document name to edit`),find:j.string().describe(`Text to find (exact match)`),replace:j.string().describe(`Replacement text`),offset:j.number().int().min(0).optional().describe(`Exact occurrence to patch, as a JavaScript string offset in the current markdown`),cwd:j.string().optional().describe(M)},async e=>{let n=await L(t.resolveCwd,t.config,t.serverUrl,e.cwd);if(!n.ok)return N(`Error: ${n.error}`,!0);let{cwd:r,config:i,url:s}=n;if(!s)return N(F,!0);let c=R(e.docName);if(!c.ok)return N(c.error,!0);let l=t.identityRef?.current,u=await B(s,`/api/agent-patch`,{docName:c.docName,find:e.find,replace:e.replace,offset:e.offset,...l?{agentId:l.connectionId,agentName:l.displayName,clientName:l.clientInfo?.name,colorSeed:l.colorSeed}:{}});if(!u.ok)return N(`Error: ${u.error}`,!0);let d=a(o(i,r)),f=U(c.docName,{config:i,lockDir:d}),p=(typeof u.subscriberCount==`number`?u.subscriberCount:void 0)===0,m=[`Edit applied successfully.`];f&&m.push(`Preview: ${f.url}`),p&&m.push(f?`Warning: no preview is currently attached to "${c.docName}". Open ${f.url} to watch future edits live.`:`Warning: no preview is currently attached to "${c.docName}".`);let h=m.join(`
|
|
155
155
|
`);if(!f&&!p)return N(h);let g={};return f&&(g.previewUrl=f.url,g.previewUrlSource=f.source),p&&(g.warning={message:`No preview attached to ${c.docName}.`,previewUrl:f?.url??null}),P(h,g)})}const jt=new Set([`cat`,`ls`,`grep`,`find`]),Mt=/\b[\w./-]+\.(md|mdx)\b/g;function W(e){return/\.(md|mdx)$/.test(e)}function G(e){let t=e.trim();return t?(t=t.replace(/\/+/g,`/`),t.startsWith(`./`)&&(t=t.slice(2)),t.endsWith(`/`)&&(t=t.slice(0,-1)),t):``}function K(e){return e.args.slice(1)}function q(e){return e.filter(e=>!e.startsWith(`-`))}function Nt(e){return q(K(e)).filter(W)}function Pt(e,t){let n=q(K(t)),r=n.length>0?n[n.length-1]:``,i=r&&r!==`.`?G(r):``,a=[];i&&a.push(i);for(let t of e.split(`
|
|
156
156
|
`)){let e=t.trim();if(!e||/\.[a-z0-9]+$/i.test(e)&&!W(e))continue;let n=i?`${i}/${e}`:e;a.push(n)}return a}function Ft(e){let t=[];for(let n of e.split(`
|
|
157
157
|
`)){if(!n)continue;let e=n.indexOf(`:`);if(e<0)continue;let r=G(n.slice(0,e));W(r)&&t.push(r)}return t}function It(e){let t=[];for(let n of e.split(`
|
|
158
158
|
`)){let e=G(n);e&&W(e)&&t.push(e)}return t}function Lt(e){return q(K(e)).filter(W)}function Rt(e){return q(K(e)).length>0}function zt(e){let t=[],n=e.matchAll(Mt);for(let e of n)t.push(G(e[0]));return t}function Bt(e,t){let n=null;for(let e=t.length-1;e>=0;e--){let r=t[e];if(jt.has(r.command)){n=r;break}if((r.command===`head`||r.command===`tail`)&&Rt(r)){n=r;break}}let r;if(!n)r=zt(e);else{switch(n.command){case`cat`:r=Nt(n);break;case`ls`:r=Pt(e,n);break;case`grep`:r=Ft(e);break;case`find`:r=It(e);break;case`head`:case`tail`:r=Lt(n);break;default:r=zt(e)}r.length===0&&(r=zt(e))}let i=new Set,a=[];for(let e of r){let t=G(e);!t||i.has(t)||(i.add(t),a.push(t))}return a}function J(e){return e===``?`''`:/^[\w.\-/]+$/.test(e)?e:`'${e.replace(/'/g,`'\\''`)}'`}const Vt=16*1024*1024;var Ht=class extends Error{limitBytes;actualBytes;partial;constructor(e,t,n){super(`Output exceeded ${e} byte buffer (got ${t}); narrow the command`),this.name=`StdoutOverflowError`,this.limitBytes=e,this.actualBytes=t,this.partial=n}};function Ut(e){if(!le(e))throw Error(`createBashInstance: cwd must be absolute (got: ${e})`);return new je({cwd:`/`,fs:new Me({root:A(e),allowSymlinks:!1})})}async function Wt(e,t){let n=await e.exec(t);if(n.stdout.length>Vt)throw new Ht(Vt,n.stdout.length,{stdout:n.stdout.slice(0,Vt),stderr:n.stderr,exitCode:n.exitCode});return{stdout:n.stdout,stderr:n.stderr,exitCode:n.exitCode}}function Gt(e){return e.startsWith(`**/`)?e.slice(3):e}async function Kt(e,t,n={}){let r=Ut(t),i=[`-rn`,`-F`];(n.caseInsensitive??!0)&&i.push(`-i`);for(let e of n.include??[])i.push(`--include=${J(Gt(e))}`);for(let e of n.exclude??[])i.push(`--exclude=${J(Gt(e))}`),i.push(`--exclude-dir=${J(Gt(e))}`);let a=n.paths?.length?n.paths.map(J):[`.`],o=`grep ${i.join(` `)} ${J(e)} ${a.join(` `)}`,s;try{s=await Wt(r,o)}catch(e){if(e instanceof Ht)s=e.partial;else throw e}if(s.exitCode===1&&!s.stdout)return[];if(s.exitCode!==0&&s.exitCode!==1&&!s.stdout)throw Error(`grep exited ${s.exitCode}: ${s.stderr}`);let c=[],l=n.maxResults??1/0;for(let e of s.stdout.split(`
|
|
159
|
-
`)){if(!e)continue;if(c.length>=l)break;let t=e.indexOf(`:`);if(t===-1)continue;let n=e.indexOf(`:`,t+1);if(n===-1)continue;let r=e.slice(0,t),i=e.slice(t+1,n),a=e.slice(n+1),o=Number.parseInt(i,10);Number.isFinite(o)&&c.push({path:r,line:o,text:a})}return c}const qt=new Set([`.git`,n
|
|
160
|
-
`)){if(!e)continue;let t=e.indexOf(`|`);if(t<0)continue;let n=e.indexOf(`|`,t+1);if(n<0)continue;let r=e.indexOf(`|`,n+1);r<0||a.push({hash:e.slice(0,t),date:e.slice(t+1,n),authorName:e.slice(n+1,r),subject:e.slice(r+1)})}return{commits:a,source:`git`}}const Sn=5e3;async function Cn(e){try{let t=(await xe({baseDir:e,timeout:{block:Sn}}).revparse([`--abbrev-ref`,`HEAD`])).trim();return t&&t!==`HEAD`?t:null}catch{return null}}function wn(e,t){return xe({baseDir:t,timeout:{block:Sn}}).env({GIT_DIR:e,GIT_WORK_TREE:t})}function Tn(e,t){let n=
|
|
161
|
-
`).map(e=>e.trim()).filter(Boolean);return
|
|
159
|
+
`)){if(!e)continue;if(c.length>=l)break;let t=e.indexOf(`:`);if(t===-1)continue;let n=e.indexOf(`:`,t+1);if(n===-1)continue;let r=e.slice(0,t),i=e.slice(t+1,n),a=e.slice(n+1),o=Number.parseInt(i,10);Number.isFinite(o)&&c.push({path:r,line:o,text:a})}return c}const qt=new Set([`.git`,n,`node_modules`,`.changeset`,`.claude`,`.agents`,`dist`,`build`]);async function Jt(e){let t=A(e),n=new Map,r=0,i=!1;async function a(e){if(i)return;let o;try{o=await Ce(e,{withFileTypes:!0})}catch{return}for(let s of o){if(i)return;if(s.isDirectory()&&qt.has(s.name))continue;let o=A(e,s.name);if(s.isDirectory()){await a(o);continue}if(s.isFile()){if(r>=1e3){i=!0;return}try{let e=await we(o);n.set(de(t,o),e.mtimeMs),r++}catch{}}}}return await a(t),{snapshot:n,truncated:i}}function Yt(e,t){let n=[];for(let[r,i]of t){let t=e.get(r);(t===void 0||t!==i)&&n.push(r)}for(let[r]of e)t.has(r)||n.push(r);return{changed:n}}const Xt=[`node_modules`,`.git`,`dist`,`build`,`.next`,`.turbo`,`.nuxt`,`coverage`,`.cache`,`.parcel-cache`,`.vercel`,n,`.claude`];function Zt(e){return e===`--recursive`||e===`--dereference-recursive`?!0:e.startsWith(`--`)||!e.startsWith(`-`)?!1:/[rR]/.test(e.slice(1))}const Qt=[{command:`grep`,applies:e=>e.slice(1).some(Zt),hasUserExcludes:e=>e.some(e=>e===`--exclude-dir`||e.startsWith(`--exclude-dir=`)),buildExcludeArgs:e=>e.map(e=>`--exclude-dir=${e}`),insertionIndex:()=>1},{command:`find`,applies:()=>!0,hasUserExcludes:e=>e.slice(1).some(e=>e===`-not`||e===`!`||e===`-prune`),buildExcludeArgs:e=>{let t=[];for(let n of e)t.push(`-not`,`-path`,`*/${n}/*`);return t},insertionIndex:e=>{for(let t=1;t<e.length;t++)if(e[t].startsWith(`-`))return t;return e.length}}];function $t(e){return e.map(e=>{let t=Qt.find(t=>t.command===e.command);if(!t||!t.applies(e.args)||t.hasUserExcludes(e.args))return e;let n=t.buildExcludeArgs(Xt),r=t.insertionIndex(e.args);return{command:e.command,args:[...e.args.slice(0,r),...n,...e.args.slice(r)]}})}function en(e){return e.map(e=>e.args.map(J).join(` `)).join(` | `)}const tn=new Set([`cat`,`ls`,`grep`,`find`,`head`,`tail`,`wc`,`sort`,`uniq`,`cut`]),nn=new Set([`>`,`>>`,`<`,`>&`,`<&`,`|&`]),rn=new Set([`&`,`;`,`;;`,`&&`,`||`,`(`,`)`,`<(`,`>(`,`<<`,`<<-`]),an=new Set([`-o`,`--output-file`,`--output`]),on=[`-o=`,`--output-file=`,`--output=`],sn=new Set([`-exec`,`-execdir`,`-delete`,`-fprint`,`-fprintf`,`-fprint0`,`-ok`,`-okdir`]),cn=/[`]|\$\(|\$\{|\$'/;function ln(e){return typeof e==`object`&&!!e&&`op`in e}function un(e){let t=typeof e.op==`string`?e.op:`(unknown)`;return nn.has(t)?{category:`write_blocked`,message:`Write operation blocked: '${t}'. exec is read-only. For document changes, use write_document or edit_document.`}:rn.has(t)?{category:`shell_construct_blocked`,message:`Shell construct '${t}' is not supported. Only pipes (|) are allowed between allowlisted stages.`}:{category:`shell_construct_blocked`,message:`Operator '${t}' is not supported.`}}function dn(e){let t=[];for(let n of e){if(typeof n==`string`){if(cn.test(n))return{error:{category:`shell_construct_blocked`,message:`Argument '${n}' contains a shell-injection pattern (backtick, $(), or \${}); not supported.`}};t.push(n);continue}if(!ln(n))return{error:{category:`shell_construct_blocked`,message:`Unrecognized token shape.`}};if(n.op===`glob`&&typeof n.pattern==`string`){t.push(n.pattern);continue}return typeof n.comment==`string`?{error:{category:`shell_construct_blocked`,message:`Comments are not allowed in exec commands.`}}:{error:un(n)}}return{args:t}}function fn(e){if(!tn.has(e.command))return{category:`unknown_command`,message:`Command '${e.command}' is not in the allowlist. For pattern matching try 'grep'; for file listing try 'ls' or 'find'. Allowlist: cat, ls, grep, find, head, tail, wc, sort, uniq, cut.`};for(let t of e.args.slice(1)){if(an.has(t)||on.some(e=>t.startsWith(e)))return{category:`write_blocked`,message:`Write operation blocked: '${t}'. exec is read-only. For document changes, use write_document or edit_document.`};if(e.command===`find`&&sn.has(t))return{category:`write_blocked`,message:`find flag '${t}' is blocked (executes commands or deletes files). Use exec for read-only discovery; chain with another allowlisted tool via '|' if you need to transform output.`}}return null}function pn(e){let t=e.trim();if(!t)return{error:{category:`unknown_command`,message:`Empty command.`}};let n;try{n=Ne.parse(t)}catch{return{error:{category:`shell_construct_blocked`,message:`Failed to parse command — likely malformed quoting or an unsupported construct.`}}}let r=[],i=[];for(let e of n){if(ln(e)&&e.op===`|`){r.push(i),i=[];continue}i.push(e)}r.push(i);let a=[];for(let e of r){let t=dn(e);if(`error`in t)return t;if(t.args.length===0)return{error:{category:`shell_construct_blocked`,message:`Empty pipeline stage (trailing pipe or leading pipe).`}};let n={command:t.args[0],args:t.args},r=fn(n);if(r)return{error:r};a.push(n)}return{stages:a}}const mn=/^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/;function hn(e,t){let n=e.match(mn);if(!n)return null;try{let e=fe(n[1]);if(_(e)){if(t){let n=t.safeParse(e);return n.success?n.data:null}return e}}catch{}return null}const gn=new WeakMap;function _n(e){let t=gn.get(e);if(t)return t;let n=e.map(e=>De(e.match,{dot:!0}));return gn.set(e,n),n}function vn(e,t){if(e.length===0)return{};let n=_n(e),r={},i=[],a=!1;for(let o=0;o<e.length;o++){if(!n[o](t))continue;a=!0;let s=e[o].frontmatter;if(s.title!==void 0&&(r.title=s.title),s.description!==void 0&&(r.description=s.description),s.tags!==void 0)for(let e of s.tags)i.includes(e)||i.push(e)}return a?(i.length>0&&(r.tags=i),r):{}}function yn(e){try{return ne(A(e,`.git`)).isDirectory()}catch{return!1}}function bn(e){return xe({baseDir:A(e),timeout:{block:5e3}})}async function xn(e,t,n=5){if(!yn(e))return{commits:[],source:`git-absent`};let r=bn(e),i=``;try{i=await r.raw(`log`,`-${Math.max(1,n)}`,`--format=%H|%aI|%an|%s`,`--follow`,`--`,t)}catch{return{commits:[],source:`git`}}let a=[];for(let e of i.split(`
|
|
160
|
+
`)){if(!e)continue;let t=e.indexOf(`|`);if(t<0)continue;let n=e.indexOf(`|`,t+1);if(n<0)continue;let r=e.indexOf(`|`,n+1);r<0||a.push({hash:e.slice(0,t),date:e.slice(t+1,n),authorName:e.slice(n+1,r),subject:e.slice(r+1)})}return{commits:a,source:`git`}}const Sn=5e3;async function Cn(e){try{let t=(await xe({baseDir:e,timeout:{block:Sn}}).revparse([`--abbrev-ref`,`HEAD`])).trim();return t&&t!==`HEAD`?t:null}catch{return null}}function wn(e,t){return xe({baseDir:t,timeout:{block:Sn}}).env({GIT_DIR:e,GIT_WORK_TREE:t})}function Tn(e,t){let n=s(t);return e.startsWith(n)?e.slice(n.length):e}async function En(e,t,n,r,i){let a=``;try{a=await e.raw(`log`,t,`-${Math.max(1,i*2)}`,`--format=%H%x00%aI%x00%an%x00%s%x00%B%x1e`,`--`,n)}catch{return[]}let o=Tn(t,r),s=f(o),l=[];for(let e of a.split(``)){let t=e.trimStart();if(!t)continue;let[n=``,i=``,a=``,u=``,d=``]=t.split(`\0`),f=n.trim();f.length===40&&l.push({hash:f,date:i,writerName:a,message:u,contributors:c(d),writerId:o,isAgent:s.isAgent,writerClassification:s.classification,branch:r})}return l}async function Dn(e,t,n=5){let r=u(e);if(!r)return{commits:[],source:`shadow-repo-absent`};let i=await Cn(e);if(!i)return{commits:[],source:`shadow-repo`};let a=wn(r,A(e)),o=``;try{o=await a.raw(`for-each-ref`,s(i),`--format=%(refname)`)}catch{return{commits:[],source:`shadow-repo`}}let c=o.split(`
|
|
161
|
+
`).map(e=>e.trim()).filter(Boolean);return c.length===0?{commits:[],source:`shadow-repo`}:{commits:(await Promise.all(c.map(e=>En(a,e,t,i,n)))).flat().sort((e,t)=>t.date.localeCompare(e.date)).slice(0,n),source:`shadow-repo`}}const On=1e3,kn=new Set([`.git`,n,`node_modules`,`.changeset`,`.claude`,`.agents`,`dist`,`build`]),An=/\.(md|mdx)$/i,jn=j.object({title:j.string().optional(),description:j.string().optional(),tags:j.array(j.string()).default([])});function Mn(e){return e.replace(/\.md$/,``).replace(/\.mdx$/,``)}async function Nn(e){try{let t=hn(await Se(e,`utf-8`),jn);return t?{title:t.title,description:t.description,tags:t.tags??[]}:{tags:[]}}catch{return null}}async function Pn(e,t){if(!e)return null;let n=await z(e,`/api/backlinks?docName=${encodeURIComponent(t)}`);if(!n.ok)return null;let r=n.backlinks??n.results??n.links;if(!Array.isArray(r))return[];let i=[];for(let e of r){if(typeof e!=`object`||!e)continue;let t=e,n=typeof t.docName==`string`?t.docName:typeof t.source==`string`?t.source:typeof t.page==`string`?t.page:void 0;n&&i.push({source:n,title:typeof t.title==`string`?t.title:void 0,snippet:typeof t.snippet==`string`?t.snippet:null})}return i}async function Fn(e,t){if(!e||t.length===0)return null;let n=[...new Set(t)],r=[];for(let e=0;e<n.length;e+=100)r.push(n.slice(e,e+100));let i=await Promise.all(r.map(async t=>{let n=await z(e,`/api/backlink-counts?docNames=${encodeURIComponent(t.join(`,`))}`);return n.ok?n.counts??{}:null})),a=new Map,o=!1;for(let e of i)if(e){o=!0;for(let[t,n]of Object.entries(e))typeof n==`number`&&Number.isFinite(n)&&a.set(t,n)}return o?a:null}async function In(e,t){if(!e)return null;let n=await z(e,`/api/forward-links?docName=${encodeURIComponent(t)}`);if(!n.ok)return null;let r=n.forwardLinks??n.links??n.results;if(!Array.isArray(r))return[];let i=[];for(let e of r){if(typeof e!=`object`||!e)continue;let t=e;if(t.kind===`external`&&typeof t.url==`string`){i.push({kind:`external`,url:t.url,title:typeof t.title==`string`?t.title:void 0,snippet:typeof t.snippet==`string`?t.snippet:null});continue}let n=typeof t.docName==`string`?t.docName:void 0;n&&i.push({kind:`doc`,docName:n,title:typeof t.title==`string`?t.title:void 0,snippet:typeof t.snippet==`string`?t.snippet:null})}return i}function Ln(e,t,n){let r=t??[],i=r.length===0?{}:vn(r,n),a=e?.title??i.title,o=e?.description??i.description,s=e?.tags??[],c=i.tags??[],l;if(c.length===0)l=s;else{let e=new Set;l=[];for(let t of c)e.has(t)||(e.add(t),l.push(t));for(let t of s)e.has(t)||(e.add(t),l.push(t))}return{title:a,description:o,tags:l}}async function Rn(e,t,n={}){let r=e.replace(/^\.\//,``).replace(/^\/+/,``),i=A(t.projectDir,r),a=t.historyDepth??5,o=n.includeRichFields===!0,s=Nn(i);if(!o){let e=Ln(await s,t.folderRules,r);return{path:r,title:e.title,description:e.description,tags:e.tags,backlinkCount:null,backlinks:null,forwardLinkCount:null,forwardLinks:null,history:null,historySource:null,projectHistory:null,projectHistorySource:null}}let[c,l,u,d,f]=await Promise.all([s,Pn(t.serverUrl,Mn(r)).catch(()=>null),In(t.serverUrl,Mn(r)).catch(()=>null),Dn(t.projectDir,r,a).catch(()=>({commits:[],source:`shadow-repo`})),xn(t.projectDir,r,a).catch(()=>({commits:[],source:`git`}))]),p=Ln(c,t.folderRules,r);return{path:r,title:p.title,description:p.description,tags:p.tags,backlinkCount:l?.length??null,backlinks:l,forwardLinkCount:u?.length??null,forwardLinks:u,history:d.commits,historySource:d.source,projectHistory:f.commits,projectHistorySource:f.source}}async function zn(e,t){let n={directMdCount:0,recursiveMdCount:0,childDirCount:0,mostRecent:null,truncated:!1},r=0,i=[{path:e,depth:0}];for(;i.length>0;){let e=i.shift();if(!e)break;if(r>=On){n.truncated=!0;break}let a;try{a=await Ce(e.path,{withFileTypes:!0})}catch{continue}for(let o of a){if(r>=On){n.truncated=!0;break}r++;let a=o.name;if(o.isDirectory()){if(kn.has(a)||a.startsWith(`.`))continue;e.depth===0&&n.childDirCount++,i.push({path:`${e.path}/${a}`,depth:e.depth+1})}else if(o.isFile()&&An.test(a)){n.recursiveMdCount++,e.depth===0&&n.directMdCount++;let r=`${e.path}/${a}`;try{let e=await we(r);(!n.mostRecent||e.mtimeMs>n.mostRecent.mtimeMs)&&(n.mostRecent={absPath:r,relPath:de(t,r).split(/[\\/]/).filter(Boolean).join(`/`),mtimeMs:e.mtimeMs})}catch{}}}}return n}async function Bn(e,t){let n=e.replace(/^\.\//,``).replace(/^\/+/,``).replace(/\/+$/,``),r=await zn(A(t.projectDir,n),t.projectDir),i;if(r.mostRecent){let e=await Nn(r.mostRecent.absPath);i={path:r.mostRecent.relPath,title:e?.title??se(r.mostRecent.relPath),updatedAt:new Date(r.mostRecent.mtimeMs).toISOString()}}let a={path:n,type:`directory`,directMdCount:r.directMdCount,recursiveMdCount:r.recursiveMdCount,childDirCount:r.childDirCount,mostRecentMd:i,truncated:r.truncated},o=t.folderRules??[];if(o.length>0){let e=vn(o,n);e.title!==void 0&&(a.title=e.title),e.description!==void 0&&(a.description=e.description),e.tags!==void 0&&e.tags.length>0&&(a.tags=e.tags)}return a}const Vn=50*1024,Hn=/\.(png|jpe?g|gif|webp|svg|pdf|zip|tar|gz|tgz|mp4|mov|mp3|wav|ico|bmp)$/i,Un=[`Run a read-only bash-like command against the project content directory. Returns raw stdout plus enriched metadata for every wiki file referenced (frontmatter, backlink/forward-link counts, shadow-repo activity with agent/human attribution).`,``,`Allowlist: cat, ls, grep, find, head, tail, wc, sort, uniq, cut. Pipes (|) work between stages. Redirections, subshells, and writes are rejected.`,``,"cwd: the command runs in the explicit absolute `cwd` you pass, or in the MCP client's only advertised root when there is exactly one. If the client has zero or multiple roots, pass `cwd` explicitly. Paths inside the command resolve relative to that cwd; traversal above it is rejected.",``,"Stdout provenance headers (GNU-style): `ls <dir>/` prepends `<dir>/:`, single-file `cat`/`head`/`tail` prepends `==> <path> <==`, so the subject of the command is visible in raw output. Multi-file `cat a b` emits no header — the `enrichedPaths` array still lists every file. `head`/`tail` used as pipe trimmers (no file arg) defer to the upstream producer.",``,`Examples:`,'- `exec({ command: "cat articles/auth.md" })` — file contents + full enrichment','- `exec({ command: "ls articles/" })` — listing + per-file enrichment (slim)','- `exec({ command: "grep -rn oauth articles/ | head -5" })` — pipe with enrichment on matched files','- `exec({ command: "ls", cwd: "/abs/path/to/other-repo" })` — run in a different project'].join(`
|
|
162
162
|
`);function Wn(e){let t=e.split(`
|
|
163
163
|
`),n=t[t.length-1]===``?t.length-1:t.length;if(n<=500&&e.length<=Vn)return{text:e,truncated:!1,omittedLines:0};let r=Math.min(n,500),i=0,a=0;for(let e=0;e<r;e++){let n=t[e];if(i+=n.length+1,i>Vn)break;a++}let o=t.slice(0,a).join(`
|
|
164
164
|
`),s=n-a;return{text:`${o}\n<truncated: ${s} more lines — re-run with a more-specific query>`,truncated:!0,omittedLines:s}}function Gn(e){let t=[];for(let n of e)if(n.command===`cat`)for(let e of n.args.slice(1))e.startsWith(`-`)||Hn.test(e)&&t.push(e);return t}function Kn(e){for(let t=1;t<e.length;t++){let n=e[t],r=n.match(/^--lines=(\d+)$/);if(r)return Number(r[1]);if(n===`--lines`&&t+1<e.length){let n=Number(e[t+1]);if(Number.isFinite(n))return n}if(n===`-n`&&t+1<e.length){let n=Number(e[t+1]);if(Number.isFinite(n))return n}let i=n.match(/^-n(\d+)$/);if(i)return Number(i[1]);let a=n.match(/^-(\d+)$/);if(a)return Number(a[1])}return 10}function qn(e,t){if(e.length<2)return null;let n=e[e.length-1];if(n.command!==`head`&&n.command!==`tail`)return null;let r=Kn(n.args),i=t.split(`
|
|
@@ -171,7 +171,7 @@ Full convention: read \`${n}/AGENTS.md\`.`}const St=[`Promote research into a ca
|
|
|
171
171
|
`);function ur(e,t){e.tool(`get_history`,lr,{docName:j.string().describe(`Document name to query history for`),branch:j.string().optional().describe(`Branch name (default: current branch)`),limit:j.number().int().min(1).max(200).optional().describe(`Maximum entries to return (default 50, max 200)`),offset:j.number().int().min(0).optional().describe(`Number of entries to skip for pagination (default 0)`),type:j.enum([`checkpoint`,`upstream`,`wip`]).optional().describe(`Filter by entry type`),author:j.string().optional().describe(`Filter to entries by this author name or email`),excludeAuthor:j.string().optional().describe(`Exclude entries by this author name or email`),cwd:j.string().optional().describe(M)},async e=>{let n=await L(t.resolveCwd,t.config,t.serverUrl,e.cwd);if(!n.ok)return N(`Error: ${n.error}`,!0);let{cwd:r,url:i}=n;if(!i)return N(F,!0);let a=R(e.docName);if(!a.ok)return N(a.error,!0);let o=new URLSearchParams;o.set(`docName`,a.docName),e.branch&&o.set(`branch`,e.branch),e.limit!=null&&o.set(`limit`,String(e.limit)),e.offset!=null&&o.set(`offset`,String(e.offset)),e.type&&o.set(`type`,e.type),e.author&&o.set(`author`,e.author),e.excludeAuthor&&o.set(`excludeAuthor`,e.excludeAuthor);let s=await z(i,`/api/history?${o.toString()}`);if(!s.ok)return N(`Error: ${s.error}`,!0);let{ok:c,...l}=s,u=await V(a.docName,{config:t.config,resolveCwd:t.resolveCwd},r);return P(JSON.stringify(l,null,2),{...l,previewUrl:u?.url??null,...u?{previewUrlSource:u.source}:{}})})}const dr=[`[Requires: Hocuspocus server] Find the most-linked pages in the knowledge graph.`,`Returns hub pages ordered by inbound link count as JSON.`,``,`**Parameters:**`,"- `limit` (optional) — Maximum number of hubs to return (default 20)"].join(`
|
|
172
172
|
`);function fr(e,t){e.tool(`get_hubs`,dr,{limit:j.number().int().positive().optional().describe(`Maximum number of hubs to return`),cwd:j.string().optional().describe(M)},async e=>{let n=await L(t.resolveCwd,t.config,t.serverUrl,e.cwd);if(!n.ok)return N(`Error: ${n.error}`,!0);let{cwd:r,url:i}=n;if(!i)return N(F,!0);let a=await z(i,`/api/hubs${e.limit?`?limit=${encodeURIComponent(String(e.limit))}`:``}`);if(!a.ok)return N(`Error: ${a.error}`,!0);let{ok:o,...s}=a,c=s,{resolve:l,ui:u}=await H(t,r),d=(c.hubs??[]).map(e=>{let t=typeof e.docName==`string`?e.docName:null,n=t?l(t):null;return{...e,previewUrl:n?.url??null,...n?{previewUrlSource:n.source}:{}}}),f={...c,hubs:d,ui:u,cwd:r};return P(JSON.stringify(f,null,2),f)})}const pr=[`[Requires: Hocuspocus server] Find disconnected pages in the knowledge graph.`,`Returns orphaned pages as JSON.`,``,`**Parameters:**`,"- `mode` (optional) — Orphan lens: `incoming`, `outgoing`, or `both` (default `both`)"].join(`
|
|
173
173
|
`);function mr(e,t){e.tool(`get_orphans`,pr,{mode:j.enum(r).optional().describe(`Filter which type of graph disconnection to surface`),cwd:j.string().optional().describe(M)},async e=>{let n=await L(t.resolveCwd,t.config,t.serverUrl,e.cwd);if(!n.ok)return N(`Error: ${n.error}`,!0);let{cwd:r,url:i}=n;if(!i)return N(F,!0);let a=await z(i,`/api/orphans${e.mode?`?mode=${encodeURIComponent(e.mode)}`:``}`);if(!a.ok)return N(`Error: ${a.error}`,!0);let{ok:o,...s}=a,c=s,{resolve:l,ui:u}=await H(t,r),d=(c.orphans??[]).map(e=>{let t=typeof e.docName==`string`?e.docName:null,n=t?l(t):null;return{...e,previewUrl:n?.url??null,...n?{previewUrlSource:n.source}:{}}}),f={...c,orphans:d,ui:u,cwd:r};return P(JSON.stringify(f,null,2),f)})}const hr=["Return a browser URL for the given wiki docName. Agents should call this IMMEDIATELY BEFORE `write_document` / `edit_document` so they can navigate the preview browser to the doc first and watch the CRDT edit land live.",``,`**Parameters:**`,"- `docName` — Wiki doc name, typically without extension.",``,"Returns `{ previewUrl, previewUrlSource }` (source: `env` / `lock` / `config`). When no source is configured, returns `{ previewUrl: null }` and the agent may proceed without navigation."].join(`
|
|
174
|
-
`);async function gr(e,t){let n=R(e.docName);if(!n.ok)return{ok:!1,error:n.error};let r=n.docName,i=await I(t.resolveCwd,t.config,e.cwd);if(!i.ok)return i;let{cwd:s,config:c}=i,l=o(c,s),u;try{u=
|
|
174
|
+
`);async function gr(e,t){let n=R(e.docName);if(!n.ok)return{ok:!1,error:n.error};let r=n.docName,i=await I(t.resolveCwd,t.config,e.cwd);if(!i.ok)return i;let{cwd:s,config:c}=i,l=o(c,s),u;try{u=d({projectDir:s,contentDir:l,includePatterns:c.content.include,excludePatterns:c.content.exclude})}catch(e){return{ok:!1,error:`Cannot evaluate content filter: ${e instanceof Error?e.message:String(e)}`}}if(![`${r}.md`,`${r}.mdx`].some(e=>!u.isExcluded(e)))return{ok:!1,error:`Error: docName "${r}" is not inside content.include globs (${c.content.include.join(`, `)}). This tool only returns URLs for docs that match those globs.`};let f=U(r,{config:c,lockDir:a(l)});return f?{ok:!0,result:{previewUrl:f.url,previewUrlSource:f.source},text:`Preview URL for "${r}" (source: ${f.source}):\n${f.url}`}:{ok:!0,result:{previewUrl:null},text:`No preview URL resolvable for "${r}". The server is likely not running yet. Start it with \`open-knowledge start\` (or \`preview_start\`), then **call \`get_preview_url\` again** — the server writes a lock file that this tool reads to resolve the URL. NEVER guess or manually construct the preview URL. Alternatively, set \`OPEN_KNOWLEDGE_PREVIEW_BASE_URL\` or add \`preview.baseUrl\` to .open-knowledge/config.yml.`}}function _r(e,t){e.tool(`get_preview_url`,hr,{docName:j.string().min(1),cwd:j.string().optional().describe(M)},async e=>{let n=await gr(e,t);return n.ok?P(n.text,n.result):N(n.error,!0)})}function vr(e,t){return`Capture this external source into the project knowledge base as raw reference material. **Raw preservation only** — no summary, no analysis, no interpretation. Summarizing is the job of the \`research\` tool later.
|
|
175
175
|
|
|
176
176
|
Source: ${e}
|
|
177
177
|
|
|
@@ -590,6 +590,6 @@ Folder metadata lives in \`config.yml\`, **not** in content files — this is in
|
|
|
590
590
|
${Object.entries(ti).map(([e,t])=>`### \`${e}\`\n${t}`).join(`
|
|
591
591
|
|
|
592
592
|
`)}
|
|
593
|
-
`}async function ci(e,t){try{let t=e.replace(`ws://`,`http://`).replace(`wss://`,`https://`);return(await fetch(`${t}/api/agent-undo-status`,{signal:AbortSignal.timeout(2e3)})).ok}catch(n){return t.warn(`Hocuspocus probe failed`,{serverUrl:e,error:n instanceof Error?n.message:String(n)}),!1}}async function li(n){let{projectDir:r,serverUrl:i,config:a,startupConfig:o,bypassProjectSelection:s=!1}=n;if(X=vt(),X.info(`MCP server starting`,{startupCwd:r,bypassProjectSelection:s,serverUrlType:typeof i==`string`?`explicit`:`lazy`}),typeof i==`string`){let e=await ci(i,X);X.info(`Hocuspocus detection complete`,{serverUrl:i,available:e})}else X.info(`server discovery is lazy per effective cwd`);let c=new Oe({name:t,version:e},{instructions:si(o,{dynamicConfig:typeof a==`function`&&!s})}),l=ai({startupCwd:r,bypassProjectSelection:s,listRoots:()=>c.server.listRoots(),logger:X}),u=oi({startupCwd:r,resolveCwd:l.resolveCwd,bypassProjectSelection:s}),d=u.resolveCwdForTools;c.server.setNotificationHandler(Ae,async()=>{l.invalidateRoots()});let f=async e=>{if(typeof i==`string`)return i.replace(`ws://`,`http://`).replace(`wss://`,`https://`);let t=e??await d();return(typeof i==`function`?await i(t):i)?.replace(`ws://`,`http://`).replace(`wss://`,`https://`)},p=ve(),m=process.env.AGENT_LABEL||void 0,h={current:{connectionId:p,label:m,displayName:m??`Agent`,colorSeed:m??p}};c.server.oninitialized=()=>{let e=c.server.getClientVersion();h.current={connectionId:p,clientInfo:e?{name:e.name,version:e.version}:void 0,label:m,displayName:m??e?.name??`Agent`,colorSeed:m??e?.name??p},X?.info(`agent identity established`,{displayName:h.current.displayName,connectionId:p.slice(0,8),clientName:e?.name})},ni(c,{serverUrl:f,resolveCwd:d,config:a,identityRef:h,logger:X});let g=new ke;await c.connect(g),X.info(`MCP server running on stdio`);let{startKeepalive:_}=await import(`./keepalive-BI3oBFIq.mjs`),v=_({resolveWsUrl:async()=>{let e=await u.getKeepaliveCwd();if(!e)return;let t=await f(e);if(t)return t.replace(/^http:/,`ws:`).replace(/^https:/,`wss:`)},logger:X.child(`keepalive`)}),y=e=>{X?.info(`MCP server shutting down`,{signal:e});try{v.close()}catch{}process.exit(0)};process.on(`SIGINT`,()=>y(`SIGINT`)),process.on(`SIGTERM`,()=>y(`SIGTERM`))}function ui(e){if(e===void 0||e===``)return;let t=Number.parseInt(e,10);if(!(Number.isNaN(t)||t<=0))return t}function di(e){if(e.portOverride!==void 0){let t=Number.parseInt(e.portOverride,10);if(Number.isNaN(t))return{action:`disk-only`,message:`invalid --port value '${e.portOverride}' — disk-only mode`};if(t>0){let n=`ws://${e.host}:${t}`;return{action:`connect`,url:n,message:`using --port override, connecting to ${n}`}}return{action:`disk-only`,message:`--port=0 — disk-only mode`}}let t=e.readLock();if(t&&t.port>0&&e.isAlive(t.pid)){let e=`ws://localhost:${t.port}`;return{action:`connect`,url:e,message:`connected to running instance at ${e} (pid ${t.pid})`}}return e.envAutoStart===`0`?{action:`disk-only`,message:`auto-spawn disabled via OK_MCP_AUTOSTART=0 — disk-only mode`}:e.configAutoStart?t?{action:`spawn`,message:`existing lock is not usable (port=${t.port}, pid=${t.pid}) — spawning ok start`}:{action:`spawn`,message:`no running instance — spawning ok start`}:{action:`disk-only`,message:`auto-spawn disabled via config.mcp.autoStart=false — disk-only mode`}}async function fi(e){let t=e.readLock??(()=>h(e.lockDir)),n=e.isAlive??m,r=e.sleep??(e=>new Promise(t=>setTimeout(t,e))),i=e.spawn??be,a=e.readErrorLog??(e=>D(e)?k(e,`utf-8`).trim():``),o=e.openErrorLog??(e=>ee(e,`w`)),s=e.closeFd??(e=>E(e)),c=e.timeoutMs??5e3,l=e.pollIntervalMs??100,u=di({host:e.host,portOverride:e.portOverride,envAutoStart:e.envAutoStart,configAutoStart:e.configAutoStart,readLock:t,isAlive:n});if(e.logger?.info(`auto-start decision`,{action:u.action,message:u.message,contentDir:e.contentDir}),u.action===`connect`)return{serverUrl:u.url,message:u.message};if(u.action===`disk-only`)return{serverUrl:void 0,message:u.message};D(e.lockDir)||O(e.lockDir,{recursive:!0});let d=ue(e.lockDir,`last-spawn-error.log`),f=o(d),p,g,_=C();e.logger?.info(`spawning server`,{command:_.command,cwd:e.contentDir,timeoutMs:c});try{try{p=i(_.command,[..._.prefixArgs,`start`],{detached:!0,stdio:[`ignore`,`ignore`,f],cwd:e.contentDir}),p.on(`error`,e=>{g=e instanceof Error?e.message:String(e)}),p.unref()}catch(e){g=e instanceof Error?e.message:String(e)}}finally{try{s(f)}catch{}}let v=Date.now()+c;for(;Date.now()<v;){if(g){let t=a(d);throw e.logger?.error(`spawn failed`,void 0,{error:g,stderr:t}),Error(`Error: spawn failed: ${g}${t?` stderr:\n${t}`:``}`)}await r(l);let i=t();if(i&&i.port>0&&n(i.pid)){let t=`ws://localhost:${i.port}`;return e.logger?.info(`server ready after spawn`,{url:t,pid:i.pid}),{serverUrl:t,message:`spawned ok start; connected at ${t} (pid ${i.pid})`}}}if(g){let t=a(d);throw e.logger?.error(`spawn failed (post-deadline)`,void 0,{error:g,stderr:t}),Error(`Error: spawn failed: ${g}${t?` stderr:\n${t}`:``}`)}let y=a(d),b=(c/1e3).toFixed(c%1e3==0?0:2),x=p?.pid,S=``;throw typeof x==`number`&&(S=n(x)?` child pid=${x} is still running — raise OK_MCP_SPAWN_TIMEOUT_MS if this is a slow boot.`:` child pid=${x} exited — check last-spawn-error.log.`),e.logger?.error(`spawn poll timeout`,void 0,{timeoutMs:c,childPid:x,childAlive:typeof x==`number`?n(x):void 0,stderr:y||void 0}),Error(`Error: server did not start within ${b}s.${S}${y?` stderr:\n${y}`:``}`)}function pi(e){if(e.portOverride!==void 0){let t=Number.parseInt(e.portOverride,10);if(Number.isNaN(t)||t<=0)return async()=>void 0;let n=`ws://${e.host}:${t}`;return async()=>n}let t=e.ensureServerRunningFn??fi,n=e.cacheMs??1e3,r=new Map,i=new Map;return async s=>{let c=await y(s??e.startupCwd),l=Date.now(),u=r.get(c);if(u&&u.expiresAt>l)return e.logger?.debug(`server url cache hit`,{cwd:c,url:u.url}),u.url;let d=i.get(c);if(d)return e.logger?.debug(`server url resolution pending`,{cwd:c}),await d;e.logger?.debug(`server url cache miss`,{cwd:c});let f=(async()=>{let i=await e.resolveConfig(c),s=o(i,c),l=a(s),u=e.readLock,d=u?()=>u(l):void 0,f=await t({lockDir:l,contentDir:s,host:i.server.host,portOverride:void 0,envAutoStart:e.envAutoStart,configAutoStart:i.mcp.autoStart,logger:e.logger,timeoutMs:e.timeoutMs,pollIntervalMs:e.pollIntervalMs,spawn:e.spawn,readLock:d,isAlive:e.isAlive,sleep:e.sleep,readErrorLog:e.readErrorLog,openErrorLog:e.openErrorLog,closeFd:e.closeFd});return r.set(c,{url:f.serverUrl,expiresAt:Date.now()+n}),f.serverUrl})();i.set(c,f);try{return await f}finally{i.delete(c)}}}function mi(e){return new w(`mcp`).description(`Start MCP stdio server for project knowledge base`).option(`-p, --port <port>`,`Override port discovery and connect to this port (0 = disk-only)`,void 0).action(async t=>{try{let n=e(),r=process.cwd(),i=x({startupCwd:r,startupConfig:n}),a=ui(process.env.OK_MCP_SPAWN_TIMEOUT_MS),o,s;if(t.port!==void 0){let e=Number.parseInt(t.port,10);Number.isNaN(e)?(o=void 0,s=`invalid --port value '${t.port}' — disk-only mode`):e>0?(o=`ws://${n.server.host}:${e}`,s=`using --port override, connecting to ${o}`):(o=void 0,s=`--port=0 — disk-only mode`)}else o=pi({startupCwd:r,resolveConfig:i,host:n.server.host,portOverride:void 0,envAutoStart:process.env.OK_MCP_AUTOSTART,timeoutMs:a}),s=`project server discovery/autostart is lazy per effective cwd`;process.stderr.write(`[mcp] ${s}\n`),await li({projectDir:r,serverUrl:o,config:i,startupConfig:n,bypassProjectSelection:t.port!==void 0})}catch(e){process.stderr.write(`MCP server failed to start: ${e instanceof Error?e.message:String(e)}\n`),process.exitCode=1}})}function hi(e){return new w(`preview`).description(`Show what content the watcher will track (read-only)`).action(async()=>{let{previewContent:t,formatPreviewBlock:n}=await import(`./preview-
|
|
594
|
-
`)),Z(e.json,{type:`complete`,op:r}),e.json||process.stderr.write(`✓ ${r} complete\n`)}function _i(e){return new w(`sync`).description(`Commit, pull, and push to the remote`).option(`--json`,`Output JSONL progress events`,!1).action(async t=>{try{await gi({json:t.json,op:`sync`},e())}catch(e){let n=e instanceof Error?e.message:String(e);t.json?process.stdout.write(`${JSON.stringify({type:`error`,message:n})}\n`):process.stderr.write(`✗ sync failed: ${n}\n`),process.exit(1)}})}function vi(e){return new w(`pull`).description(`Pull changes from the remote`).option(`--json`,`Output JSONL progress events`,!1).action(async t=>{try{await gi({json:t.json,op:`pull`},e())}catch(e){let n=e instanceof Error?e.message:String(e);t.json?process.stdout.write(`${JSON.stringify({type:`error`,message:n})}\n`):process.stderr.write(`✗ pull failed: ${n}\n`),process.exit(1)}})}function yi(e){return new w(`push`).description(`Push commits to the remote`).option(`--json`,`Output JSONL progress events`,!1).action(async t=>{try{await gi({json:t.json,op:`push`},e())}catch(e){let n=e instanceof Error?e.message:String(e);t.json?process.stdout.write(`${JSON.stringify({type:`error`,message:n})}\n`):process.stderr.write(`✗ push failed: ${n}\n`),process.exit(1)}})}function bi(e,t){return{server:xi(`server`,e),ui:xi(`ui`,t)}}function xi(e,t){switch(t.status){case`missing`:return{name:e,state:`missing`,alive:!1};case`corrupt`:return{name:e,state:`corrupt`,alive:!1};case`foreign-host`:return{name:e,state:`foreign-host`,pid:t.lock.pid,port:t.lock.port,startedAt:t.lock.startedAt,host:t.lock.hostname,alive:`unknown`};case`dead-pid`:return{name:e,state:`dead-pid`,pid:t.lock.pid,port:t.lock.port,startedAt:t.lock.startedAt,host:t.lock.hostname,alive:!1};case`alive`:return{name:e,state:`alive`,pid:t.lock.pid,port:t.lock.port,startedAt:t.lock.startedAt,host:t.lock.hostname,alive:!0}}}function Si(e){return`${Ci(e.server)}\n${Ci(e.ui)}`}function Ci(e){let t=e.name===`server`?`server`:`ui `;return e.state===`missing`?`${t} not running`:e.state===`corrupt`?`${t} lock file corrupt — run \`ok clean\``:e.state===`foreign-host`?`${t} foreign host (${e.host}) pid=${e.pid} port=${e.port}`:e.state===`dead-pid`?`${t} stale (dead pid=${e.pid}) — run \`ok clean\``:`${t} alive pid=${e.pid} port=${e.port} started=${e.startedAt}`}function wi(e){let t=e.inspect??(t=>it(e.lockDir,t)),n=e.log??(e=>console.log(e)),r=bi(t(`server`),t(`ui`));return e.json?n(JSON.stringify(r,null,2)):n(Si(r)),r}function Ti(e){return new w(`status`).description(`Show live state of the server + ui lockfiles for this project`).option(`--json`,`Emit structured JSON instead of formatted text`).action(t=>{wi({lockDir:a(o(e(),process.cwd())),json:t.json===!0})})}function Ei(e,t){let n=[];return e.status===`alive`&&n.push({name:`server`,pid:e.lock.pid,port:e.lock.port}),t.status===`alive`&&n.push({name:`ui`,pid:t.lock.pid,port:t.lock.port}),{targets:n}}function Di(e){let t=e.inspect??(t=>it(e.lockDir,t)),n=e.kill??((e,t)=>process.kill(e,t)),r=e.log??(e=>console.log(e)),i=e.error??(e=>console.error(e)),a=Ei(t(`server`),t(`ui`));if(a.targets.length===0)return r(`No running open-knowledge processes.`),{stopped:[],failed:[],hadTargets:!1};let o=[],s=[];for(let e of a.targets)try{n(e.pid,`SIGTERM`),o.push(e)}catch(t){s.push({target:e,error:t instanceof Error?t.message:String(t)})}return o.length>0&&r(`Stopped: ${o.map(e=>`${e.name} (pid=${e.pid}, port=${e.port})`).join(`, `)}`),s.length>0&&i(`Failed to stop: ${s.map(({target:e,error:t})=>`${e.name} (pid=${e.pid}): ${t}`).join(`; `)}`),{stopped:o,failed:s,hadTargets:!0}}function Oi(e){return new w(`stop`).description(`Stop the running open-knowledge server and UI (live only)`).action(()=>{Di({lockDir:a(o(e(),process.cwd()))}).failed.length>0&&(process.exitCode=1)})}const ki=1e4,Ai=[`connection`,`keep-alive`,`proxy-authenticate`,`proxy-authorization`,`te`,`trailer`,`transfer-encoding`,`upgrade`,`cookie`,`set-cookie`];async function ji(e){let t=e.upstreamTimeoutMs??ki,n=Te((n,r)=>{Ni(n,r,e.upstreamHost,e.upstreamPort,t)});await new Promise((t,r)=>{let i=e=>r(e);n.once(`error`,i),n.listen(e.listenPort,e.host,()=>{n.off(`error`,i),t()})});let r=n.address();return{httpServer:n,port:typeof r==`object`&&r?r.port:e.listenPort,close:()=>new Promise(e=>{n.close(()=>e())})}}function Mi(e,t,n){Ni(e,t,n.upstreamHost,n.upstreamPort,n.upstreamTimeoutMs??ki)}function Ni(e,t,n,r,i){let a={...e.headers};delete a.host;for(let e of Ai)delete a[e];e.setTimeout(3e4,()=>{if(t.headersSent)try{t.end()}catch{}else try{t.writeHead(408,{"Content-Type":`text/plain`}),t.end(`Request Timeout`)}catch{}try{e.socket?.destroy()}catch{}});let o=Ee({host:n,port:r,method:e.method,path:e.url,headers:{...a,host:`${n}:${r}`}},e=>{let n={...e.headers};for(let e of Ai)delete n[e];t.writeHead(e.statusCode??502,n),e.pipe(t),e.once(`error`,()=>{try{t.end()}catch{}})});i>0&&o.setTimeout(i,()=>{if(!t.headersSent)t.writeHead(504,{"Content-Type":`text/plain`}),t.end(`Gateway Timeout`);else try{t.end()}catch{}o.destroy()}),o.on(`error`,()=>{if(!t.headersSent)t.writeHead(502,{"Content-Type":`text/plain`}),t.end(`Bad Gateway`);else try{t.end()}catch{}}),e.on(`error`,()=>{o.destroy()}),e.pipe(o)}async function Pi(e){await Promise.all(e.map(e=>new Promise(t=>{e.close(()=>t())})))}async function Fi(e){let{existsSync:t}=await import(`node:fs`),{createServer:n}=await import(`node:http`),{resolve:r}=await import(`node:path`),{acquireUiLock:a,readServerLock:o,releaseUiLock:s,updateUiLockPort:c}=await import(`./src-NsJfsnSl.mjs`),{default:l}=await import(`sirv`),{resolveContentDir:u,resolveLockDir:d}=await import(`./paths-xS3o7pK2.mjs`),f=u(e.config,e.cwd),p=d(f);a(p,{port:0,worktreeRoot:e.cwd});let m=import.meta.dirname??new URL(`.`,import.meta.url).pathname,h=[r(m,`public`),r(m,`../../app/dist`),r(m,`../../../app/dist`)].find(e=>t(e)),g=h?l(h,{single:!0,gzip:!0,immutable:!0}):null,_=t(f)?l(f,{dotfiles:!1,dev:!0}):null,v=e.port,y=null,b=(e,t)=>{let n=e.url?.split(`?`)[0];if(n===`/api/config`&&(e.method===`GET`||e.method===`HEAD`)){y?.();let n=o(p),r=n&&n.port>0?`ws://localhost:${n.port}/collab`:null,i=JSON.stringify({collabUrl:r,previewUrl:null,port:v});t.setHeader(`Content-Type`,`application/json`),t.setHeader(`Cache-Control`,`no-store`),t.setHeader(`X-Content-Type-Options`,`nosniff`),t.statusCode=200,e.method===`HEAD`?t.end():t.end(i);return}if(n?.startsWith(`/api/`)){y?.();let r=o(p);if(!r||r.port<=0){t.writeHead(503,{"Content-Type":`application/json`,"Cache-Control":`no-store`}),t.end(JSON.stringify({error:"Collab server not running. Start `ok start` or run `ok status`.",path:n}));return}Mi(e,t,{upstreamHost:`localhost`,upstreamPort:r.port});return}if(decodeURIComponent(n?.replace(/^\//,``)??``)&&_){t.setHeader(`X-Content-Type-Options`,`nosniff`),_(e,t,()=>{g?g(e,t):Ii(t)});return}if(g){g(e,t);return}Ii(t)},x=e.host===void 0?[`::1`,`127.0.0.1`]:[e.host],S=[],C=e.port;try{for(let e of x){let t=n(b);S.push(t),await new Promise((n,r)=>{let i=e=>r(e);t.once(`error`,i),t.listen(C,e,()=>{t.off(`error`,i);let e=t.address();typeof e==`object`&&e&&(C=e.port),n()})})}}catch(e){await Promise.all(S.map(e=>new Promise(t=>{try{e.close(()=>t())}catch{t()}})));try{s(p)}catch{}throw e}let w=C;v=w,c(p,w);let T=e.scheduler??i,E=e.safetyNetMs??432e5,D=null,O=!1,ee=!1,k=()=>{O||(O=!0,D!==null&&(T.clearTimeout(D),D=null))},te=()=>{if(k(),!ee){ee=!0;try{s(p)}catch{}}},ne=()=>{O||E<=0||(D!==null&&(T.clearTimeout(D),D=null),D=T.setTimeout(()=>{D=null,console.warn(`[ui] safety-net (${E}ms) reached — shutting down (D-025 backstop)`);try{e.onSafetyNet?.()}catch{}for(let e of S)try{e.close()}catch{}te()},E))},re=()=>{O||E<=0||ne()};return y=re,ne(),{httpServers:S,port:w,release:te,detachSafetyNet:k,nudgeSafetyNet:re}}function Ii(e){e.writeHead(404),e.end(`Not found`)}function Li(e,t){if(e!==void 0){let t=Number.parseInt(e,10);if(Number.isNaN(t)||t<0||t>65535)throw Error(`Invalid --port value '${e}'`);return t}if(t!==void 0&&t!==``){let e=Number.parseInt(t,10);if(Number.isNaN(e)||e<0||e>65535)throw Error(`Invalid PORT env value '${t}'`);return e}return 0}async function Ri(e){let t=e.readLock??(async()=>{let{readUiLock:t}=await import(`./src-NsJfsnSl.mjs`);return t(e.lockDir)}),n=await t();if(!n)throw Error(`UI lock collision reported but the lock disappeared before handling — retry acquiring.`);if(n.port===e.requestedPort&&n.port>0)return{mode:`already-running`,port:n.port};let r=n.port;if(r===0){let n=Date.now()+(e.pollDeadlineMs??2e3),i=e.pollIntervalMs??100;for(;Date.now()<n;){await new Promise(e=>{setTimeout(e,i)});let e=await t();if(e&&e.port>0){r=e.port;break}}if(r===0)throw Error("UI did not bind within 2s; run `ok clean`");if(r===e.requestedPort)return{mode:`already-running`,port:r}}return{mode:`proxy`,handle:await ji({listenPort:e.requestedPort,host:e.host,upstreamHost:`localhost`,upstreamPort:r}),upstreamPort:r}}function zi(e){return new w(`ui`).description(`Serve the Open Knowledge React editor UI`).option(`-p, --port <port>`,`UI port (default: $PORT env or 0 / kernel-allocated)`).option(`-H, --host <host>`,"UI host. Default: two-socket loopback bind (`[::1]` + `127.0.0.1`) so cross-family collisions fail loud (D-033). Pass an explicit host (e.g. `127.0.0.1`, `0.0.0.0`) to bind a single socket on that host.").action(async t=>{let{dim:n}=await import(`./colors-BNRrOlZZ.mjs`),{UiLockCollisionError:r}=await import(`./src-NsJfsnSl.mjs`),{resolveContentDir:i,resolveLockDir:a}=await import(`./paths-xS3o7pK2.mjs`),o=e(),s=t.host,c;try{c=Li(t.port,process.env.PORT)}catch(e){console.error(e instanceof Error?e.message:String(e)),process.exitCode=1;return}try{let e=await Fi({config:o,cwd:process.cwd(),port:c,host:s}),t=s===void 0||s===`::`||s===`0.0.0.0`?`localhost`:s;console.log(`${n(`[ui]`)} listening on http://${t}:${e.port}`);let r=!1,i=t=>{if(r)return;r=!0,console.log(n(`\n[ui] Shutting down (${t})...`)),e.detachSafetyNet();let i=()=>{try{e.release()}finally{process.exit(process.exitCode??0)}};Pi(e.httpServers).then(i,i),setTimeout(i,2e3).unref()};process.once(`SIGINT`,()=>i(`SIGINT`)),process.once(`SIGTERM`,()=>i(`SIGTERM`));return}catch(e){if(!(e instanceof r))throw e;let t=a(i(o,process.cwd())),l=s??`localhost`,u;try{u=await Ri({requestedPort:c,host:l,lockDir:t})}catch(e){console.error(e instanceof Error?e.message:String(e)),process.exit(1)}u.mode===`already-running`&&(console.log(`UI already running at http://${l}:${u.port}`),process.exit(0)),console.log(`UI running at http://${l}:${u.upstreamPort}; acting as HTTP proxy on port ${u.handle.port}`);let d=!1,f=e=>{d||(d=!0,console.log(n(`\n[ui-proxy] Shutting down (${e})...`)),u.handle.close().finally(()=>process.exit(process.exitCode??0)),setTimeout(()=>process.exit(process.exitCode??0),2e3).unref())};process.once(`SIGINT`,()=>f(`SIGINT`)),process.once(`SIGTERM`,()=>f(`SIGTERM`))}})}process.argv.includes(`--no-color`)?(process.env.NO_COLOR=`1`,delete process.env.FORCE_COLOR):process.argv.includes(`--color`)&&(process.env.FORCE_COLOR=`1`,delete process.env.NO_COLOR);const Q=new w;let $;Q.name(`open-knowledge`).description(`Local-first knowledge base with CRDT collaboration`).version(e).option(`--cwd <path>`,`Working directory`).option(`--log-level <level>`,`Log level`,`info`).option(`--no-color`,`Disable color output`).option(`--color`,`Force color output`).hook(`preAction`,e=>{let t=e.opts(),n=t.cwd;n!==void 0&&process.chdir(n);let{config:r}=b(n),i=e.args.length===0?t:e.commands[0]?.opts()??{};i.port!==void 0&&(r.server.port=Number(i.port)),i.host!==void 0&&(r.server.host=i.host),process.env.PORT&&(r.server.port=Number(process.env.PORT)),process.env.HOST&&(r.server.host=process.env.HOST),$=r});const Bi=S(()=>$);Q.addCommand(Bi,{isDefault:!0});const Vi=mi(()=>$);Q.addCommand(Vi),Q.addCommand(v());const Hi=hi(()=>$);Q.addCommand(Hi);const Ui=zi(()=>$);Q.addCommand(Ui),Q.addCommand(Oi(()=>$)),Q.addCommand(st(()=>$)),Q.addCommand(Ti(()=>$)),Q.addCommand(rt(()=>$)),Q.addCommand(gt(()=>$)),Q.addCommand(_i(()=>$)),Q.addCommand(yi(()=>$)),Q.addCommand(vi(()=>$)),await Q.parseAsync();export{};
|
|
593
|
+
`}async function ci(e,t){try{let t=e.replace(`ws://`,`http://`).replace(`wss://`,`https://`);return(await fetch(`${t}/api/agent-undo-status`,{signal:AbortSignal.timeout(2e3)})).ok}catch(n){return t.warn(`Hocuspocus probe failed`,{serverUrl:e,error:n instanceof Error?n.message:String(n)}),!1}}async function li(n){let{projectDir:r,serverUrl:i,config:a,startupConfig:o,bypassProjectSelection:s=!1}=n;if(X=vt(),X.info(`MCP server starting`,{startupCwd:r,bypassProjectSelection:s,serverUrlType:typeof i==`string`?`explicit`:`lazy`}),typeof i==`string`){let e=await ci(i,X);X.info(`Hocuspocus detection complete`,{serverUrl:i,available:e})}else X.info(`server discovery is lazy per effective cwd`);let c=new Oe({name:t,version:e},{instructions:si(o,{dynamicConfig:typeof a==`function`&&!s})}),l=ai({startupCwd:r,bypassProjectSelection:s,listRoots:()=>c.server.listRoots(),logger:X}),u=oi({startupCwd:r,resolveCwd:l.resolveCwd,bypassProjectSelection:s}),d=u.resolveCwdForTools;c.server.setNotificationHandler(Ae,async()=>{l.invalidateRoots()});let f=async e=>{if(typeof i==`string`)return i.replace(`ws://`,`http://`).replace(`wss://`,`https://`);let t=e??await d();return(typeof i==`function`?await i(t):i)?.replace(`ws://`,`http://`).replace(`wss://`,`https://`)},p=ve(),m=process.env.AGENT_LABEL||void 0,h={current:{connectionId:p,label:m,displayName:m??`Agent`,colorSeed:m??p}};c.server.oninitialized=()=>{let e=c.server.getClientVersion();h.current={connectionId:p,clientInfo:e?{name:e.name,version:e.version}:void 0,label:m,displayName:m??e?.name??`Agent`,colorSeed:m??e?.name??p},X?.info(`agent identity established`,{displayName:h.current.displayName,connectionId:p.slice(0,8),clientName:e?.name})},ni(c,{serverUrl:f,resolveCwd:d,config:a,identityRef:h,logger:X});let g=new ke;await c.connect(g),X.info(`MCP server running on stdio`);let{startKeepalive:_}=await import(`./keepalive-BI3oBFIq.mjs`),v=_({resolveWsUrl:async()=>{let e=await u.getKeepaliveCwd();if(!e)return;let t=await f(e);if(t)return t.replace(/^http:/,`ws:`).replace(/^https:/,`wss:`)},logger:X.child(`keepalive`)}),y=e=>{X?.info(`MCP server shutting down`,{signal:e});try{v.close()}catch{}process.exit(0)};process.on(`SIGINT`,()=>y(`SIGINT`)),process.on(`SIGTERM`,()=>y(`SIGTERM`))}function ui(e){if(e===void 0||e===``)return;let t=Number.parseInt(e,10);if(!(Number.isNaN(t)||t<=0))return t}function di(e){if(e.portOverride!==void 0){let t=Number.parseInt(e.portOverride,10);if(Number.isNaN(t))return{action:`disk-only`,message:`invalid --port value '${e.portOverride}' — disk-only mode`};if(t>0){let n=`ws://${e.host}:${t}`;return{action:`connect`,url:n,message:`using --port override, connecting to ${n}`}}return{action:`disk-only`,message:`--port=0 — disk-only mode`}}let t=e.readLock();if(t&&t.port>0&&e.isAlive(t.pid)){let e=`ws://localhost:${t.port}`;return{action:`connect`,url:e,message:`connected to running instance at ${e} (pid ${t.pid})`}}return e.envAutoStart===`0`?{action:`disk-only`,message:`auto-spawn disabled via OK_MCP_AUTOSTART=0 — disk-only mode`}:e.configAutoStart?t?{action:`spawn`,message:`existing lock is not usable (port=${t.port}, pid=${t.pid}) — spawning ok start`}:{action:`spawn`,message:`no running instance — spawning ok start`}:{action:`disk-only`,message:`auto-spawn disabled via config.mcp.autoStart=false — disk-only mode`}}async function fi(e){let t=e.readLock??(()=>h(e.lockDir)),n=e.isAlive??m,r=e.sleep??(e=>new Promise(t=>setTimeout(t,e))),i=e.spawn??be,a=e.readErrorLog??(e=>D(e)?k(e,`utf-8`).trim():``),o=e.openErrorLog??(e=>ee(e,`w`)),s=e.closeFd??(e=>E(e)),c=e.timeoutMs??5e3,l=e.pollIntervalMs??100,u=di({host:e.host,portOverride:e.portOverride,envAutoStart:e.envAutoStart,configAutoStart:e.configAutoStart,readLock:t,isAlive:n});if(e.logger?.info(`auto-start decision`,{action:u.action,message:u.message,contentDir:e.contentDir}),u.action===`connect`)return{serverUrl:u.url,message:u.message};if(u.action===`disk-only`)return{serverUrl:void 0,message:u.message};D(e.lockDir)||O(e.lockDir,{recursive:!0});let d=ue(e.lockDir,`last-spawn-error.log`),f=o(d),p,g,_=C();e.logger?.info(`spawning server`,{command:_.command,cwd:e.contentDir,timeoutMs:c});try{try{p=i(_.command,[..._.prefixArgs,`start`],{detached:!0,stdio:[`ignore`,`ignore`,f],cwd:e.contentDir}),p.on(`error`,e=>{g=e instanceof Error?e.message:String(e)}),p.unref()}catch(e){g=e instanceof Error?e.message:String(e)}}finally{try{s(f)}catch{}}let v=Date.now()+c;for(;Date.now()<v;){if(g){let t=a(d);throw e.logger?.error(`spawn failed`,void 0,{error:g,stderr:t}),Error(`Error: spawn failed: ${g}${t?` stderr:\n${t}`:``}`)}await r(l);let i=t();if(i&&i.port>0&&n(i.pid)){let t=`ws://localhost:${i.port}`;return e.logger?.info(`server ready after spawn`,{url:t,pid:i.pid}),{serverUrl:t,message:`spawned ok start; connected at ${t} (pid ${i.pid})`}}}if(g){let t=a(d);throw e.logger?.error(`spawn failed (post-deadline)`,void 0,{error:g,stderr:t}),Error(`Error: spawn failed: ${g}${t?` stderr:\n${t}`:``}`)}let y=a(d),b=(c/1e3).toFixed(c%1e3==0?0:2),x=p?.pid,S=``;throw typeof x==`number`&&(S=n(x)?` child pid=${x} is still running — raise OK_MCP_SPAWN_TIMEOUT_MS if this is a slow boot.`:` child pid=${x} exited — check last-spawn-error.log.`),e.logger?.error(`spawn poll timeout`,void 0,{timeoutMs:c,childPid:x,childAlive:typeof x==`number`?n(x):void 0,stderr:y||void 0}),Error(`Error: server did not start within ${b}s.${S}${y?` stderr:\n${y}`:``}`)}function pi(e){if(e.portOverride!==void 0){let t=Number.parseInt(e.portOverride,10);if(Number.isNaN(t)||t<=0)return async()=>void 0;let n=`ws://${e.host}:${t}`;return async()=>n}let t=e.ensureServerRunningFn??fi,n=e.cacheMs??1e3,r=new Map,i=new Map;return async s=>{let c=await y(s??e.startupCwd),l=Date.now(),u=r.get(c);if(u&&u.expiresAt>l)return e.logger?.debug(`server url cache hit`,{cwd:c,url:u.url}),u.url;let d=i.get(c);if(d)return e.logger?.debug(`server url resolution pending`,{cwd:c}),await d;e.logger?.debug(`server url cache miss`,{cwd:c});let f=(async()=>{let i=await e.resolveConfig(c),s=o(i,c),l=a(s),u=e.readLock,d=u?()=>u(l):void 0,f=await t({lockDir:l,contentDir:s,host:i.server.host,portOverride:void 0,envAutoStart:e.envAutoStart,configAutoStart:i.mcp.autoStart,logger:e.logger,timeoutMs:e.timeoutMs,pollIntervalMs:e.pollIntervalMs,spawn:e.spawn,readLock:d,isAlive:e.isAlive,sleep:e.sleep,readErrorLog:e.readErrorLog,openErrorLog:e.openErrorLog,closeFd:e.closeFd});return r.set(c,{url:f.serverUrl,expiresAt:Date.now()+n}),f.serverUrl})();i.set(c,f);try{return await f}finally{i.delete(c)}}}function mi(e){return new w(`mcp`).description(`Start MCP stdio server for project knowledge base`).option(`-p, --port <port>`,`Override port discovery and connect to this port (0 = disk-only)`,void 0).action(async t=>{try{let n=e(),r=process.cwd(),i=x({startupCwd:r,startupConfig:n}),a=ui(process.env.OK_MCP_SPAWN_TIMEOUT_MS),o,s;if(t.port!==void 0){let e=Number.parseInt(t.port,10);Number.isNaN(e)?(o=void 0,s=`invalid --port value '${t.port}' — disk-only mode`):e>0?(o=`ws://${n.server.host}:${e}`,s=`using --port override, connecting to ${o}`):(o=void 0,s=`--port=0 — disk-only mode`)}else o=pi({startupCwd:r,resolveConfig:i,host:n.server.host,portOverride:void 0,envAutoStart:process.env.OK_MCP_AUTOSTART,timeoutMs:a}),s=`project server discovery/autostart is lazy per effective cwd`;process.stderr.write(`[mcp] ${s}\n`),await li({projectDir:r,serverUrl:o,config:i,startupConfig:n,bypassProjectSelection:t.port!==void 0})}catch(e){process.stderr.write(`MCP server failed to start: ${e instanceof Error?e.message:String(e)}\n`),process.exitCode=1}})}function hi(e){return new w(`preview`).description(`Show what content the watcher will track (read-only)`).action(async()=>{let{previewContent:t,formatPreviewBlock:n}=await import(`./preview-CCBPkWf0.mjs`),r=e(),i=process.cwd(),a=o(r,i),s;try{s=t({projectDir:i,contentDir:a,include:r.content.include,exclude:r.content.exclude})}catch(e){console.error(`Content preview failed: ${e instanceof Error?e.message:String(e)}`),process.exitCode=1;return}process.stdout.write(`${n(s,i)}\n`),s.totalCount===0&&s.warnings.length>0&&(process.exitCode=1)})}function Z(e,t){e&&process.stdout.write(`${JSON.stringify(t)}\n`)}async function gi(e,t,n=process.cwd()){let r=e.op??`sync`,i=h(a(o(t,n)));if(i&&i.port>0){let t=`http://127.0.0.1:${i.port}/api/sync/trigger`;e.json||process.stderr.write(`Triggering ${r} via running server (port ${i.port})…\n`);try{let n=await fetch(t,{method:`POST`,headers:{"Content-Type":`application/json`},body:JSON.stringify({op:r})});if(!n.ok){let e=await n.json().catch(()=>({}));throw Error(e.error??`Server responded with ${n.status}`)}Z(e.json,{type:`triggered`,op:r,port:i.port}),e.json||process.stderr.write(`✓ ${r} triggered\n`);return}catch(t){let n=t instanceof Error?t.message:String(t);e.json||process.stderr.write(`Server trigger failed (${n}), running directly…\n`)}}e.json||process.stderr.write(`Running ${r} directly (no live server)…\n`);let s=xe({baseDir:n});if(r===`sync`||r===`pull`){Z(e.json,{type:`step`,step:`pull`});let t=await s.pull();Z(e.json,{type:`pull`,summary:t.summary}),e.json||process.stderr.write(` pull: ${t.summary.changes} changes\n`)}(r===`sync`||r===`push`)&&(Z(e.json,{type:`step`,step:`push`}),await s.push(),Z(e.json,{type:`push`,ok:!0}),e.json||process.stderr.write(` push: ok
|
|
594
|
+
`)),Z(e.json,{type:`complete`,op:r}),e.json||process.stderr.write(`✓ ${r} complete\n`)}function _i(e){return new w(`sync`).description(`Commit, pull, and push to the remote`).option(`--json`,`Output JSONL progress events`,!1).action(async t=>{try{await gi({json:t.json,op:`sync`},e())}catch(e){let n=e instanceof Error?e.message:String(e);t.json?process.stdout.write(`${JSON.stringify({type:`error`,message:n})}\n`):process.stderr.write(`✗ sync failed: ${n}\n`),process.exit(1)}})}function vi(e){return new w(`pull`).description(`Pull changes from the remote`).option(`--json`,`Output JSONL progress events`,!1).action(async t=>{try{await gi({json:t.json,op:`pull`},e())}catch(e){let n=e instanceof Error?e.message:String(e);t.json?process.stdout.write(`${JSON.stringify({type:`error`,message:n})}\n`):process.stderr.write(`✗ pull failed: ${n}\n`),process.exit(1)}})}function yi(e){return new w(`push`).description(`Push commits to the remote`).option(`--json`,`Output JSONL progress events`,!1).action(async t=>{try{await gi({json:t.json,op:`push`},e())}catch(e){let n=e instanceof Error?e.message:String(e);t.json?process.stdout.write(`${JSON.stringify({type:`error`,message:n})}\n`):process.stderr.write(`✗ push failed: ${n}\n`),process.exit(1)}})}function bi(e,t){return{server:xi(`server`,e),ui:xi(`ui`,t)}}function xi(e,t){switch(t.status){case`missing`:return{name:e,state:`missing`,alive:!1};case`corrupt`:return{name:e,state:`corrupt`,alive:!1};case`foreign-host`:return{name:e,state:`foreign-host`,pid:t.lock.pid,port:t.lock.port,startedAt:t.lock.startedAt,host:t.lock.hostname,alive:`unknown`};case`dead-pid`:return{name:e,state:`dead-pid`,pid:t.lock.pid,port:t.lock.port,startedAt:t.lock.startedAt,host:t.lock.hostname,alive:!1};case`alive`:return{name:e,state:`alive`,pid:t.lock.pid,port:t.lock.port,startedAt:t.lock.startedAt,host:t.lock.hostname,alive:!0}}}function Si(e){return`${Ci(e.server)}\n${Ci(e.ui)}`}function Ci(e){let t=e.name===`server`?`server`:`ui `;return e.state===`missing`?`${t} not running`:e.state===`corrupt`?`${t} lock file corrupt — run \`ok clean\``:e.state===`foreign-host`?`${t} foreign host (${e.host}) pid=${e.pid} port=${e.port}`:e.state===`dead-pid`?`${t} stale (dead pid=${e.pid}) — run \`ok clean\``:`${t} alive pid=${e.pid} port=${e.port} started=${e.startedAt}`}function wi(e){let t=e.inspect??(t=>it(e.lockDir,t)),n=e.log??(e=>console.log(e)),r=bi(t(`server`),t(`ui`));return e.json?n(JSON.stringify(r,null,2)):n(Si(r)),r}function Ti(e){return new w(`status`).description(`Show live state of the server + ui lockfiles for this project`).option(`--json`,`Emit structured JSON instead of formatted text`).action(t=>{wi({lockDir:a(o(e(),process.cwd())),json:t.json===!0})})}function Ei(e,t){let n=[];return e.status===`alive`&&n.push({name:`server`,pid:e.lock.pid,port:e.lock.port}),t.status===`alive`&&n.push({name:`ui`,pid:t.lock.pid,port:t.lock.port}),{targets:n}}function Di(e){let t=e.inspect??(t=>it(e.lockDir,t)),n=e.kill??((e,t)=>process.kill(e,t)),r=e.log??(e=>console.log(e)),i=e.error??(e=>console.error(e)),a=Ei(t(`server`),t(`ui`));if(a.targets.length===0)return r(`No running open-knowledge processes.`),{stopped:[],failed:[],hadTargets:!1};let o=[],s=[];for(let e of a.targets)try{n(e.pid,`SIGTERM`),o.push(e)}catch(t){s.push({target:e,error:t instanceof Error?t.message:String(t)})}return o.length>0&&r(`Stopped: ${o.map(e=>`${e.name} (pid=${e.pid}, port=${e.port})`).join(`, `)}`),s.length>0&&i(`Failed to stop: ${s.map(({target:e,error:t})=>`${e.name} (pid=${e.pid}): ${t}`).join(`; `)}`),{stopped:o,failed:s,hadTargets:!0}}function Oi(e){return new w(`stop`).description(`Stop the running open-knowledge server and UI (live only)`).action(()=>{Di({lockDir:a(o(e(),process.cwd()))}).failed.length>0&&(process.exitCode=1)})}const ki=1e4,Ai=[`connection`,`keep-alive`,`proxy-authenticate`,`proxy-authorization`,`te`,`trailer`,`transfer-encoding`,`upgrade`,`cookie`,`set-cookie`];async function ji(e){let t=e.upstreamTimeoutMs??ki,n=Te((n,r)=>{Ni(n,r,e.upstreamHost,e.upstreamPort,t)});await new Promise((t,r)=>{let i=e=>r(e);n.once(`error`,i),n.listen(e.listenPort,e.host,()=>{n.off(`error`,i),t()})});let r=n.address();return{httpServer:n,port:typeof r==`object`&&r?r.port:e.listenPort,close:()=>new Promise(e=>{n.close(()=>e())})}}function Mi(e,t,n){Ni(e,t,n.upstreamHost,n.upstreamPort,n.upstreamTimeoutMs??ki)}function Ni(e,t,n,r,i){let a={...e.headers};delete a.host;for(let e of Ai)delete a[e];e.setTimeout(3e4,()=>{if(t.headersSent)try{t.end()}catch{}else try{t.writeHead(408,{"Content-Type":`text/plain`}),t.end(`Request Timeout`)}catch{}try{e.socket?.destroy()}catch{}});let o=Ee({host:n,port:r,method:e.method,path:e.url,headers:{...a,host:`${n}:${r}`}},e=>{let n={...e.headers};for(let e of Ai)delete n[e];t.writeHead(e.statusCode??502,n),e.pipe(t),e.once(`error`,()=>{try{t.end()}catch{}})});i>0&&o.setTimeout(i,()=>{if(!t.headersSent)t.writeHead(504,{"Content-Type":`text/plain`}),t.end(`Gateway Timeout`);else try{t.end()}catch{}o.destroy()}),o.on(`error`,()=>{if(!t.headersSent)t.writeHead(502,{"Content-Type":`text/plain`}),t.end(`Bad Gateway`);else try{t.end()}catch{}}),e.on(`error`,()=>{o.destroy()}),e.pipe(o)}async function Pi(e){await Promise.all(e.map(e=>new Promise(t=>{e.close(()=>t())})))}async function Fi(e){let{existsSync:t}=await import(`node:fs`),{createServer:n}=await import(`node:http`),{resolve:r}=await import(`node:path`),{acquireUiLock:a,readServerLock:o,releaseUiLock:s,updateUiLockPort:c}=await import(`./src-Dh_UJnt4.mjs`),{default:l}=await import(`sirv`),{resolveContentDir:u,resolveLockDir:d}=await import(`./paths-8lEuqzzC.mjs`),f=u(e.config,e.cwd),p=d(f);a(p,{port:0,worktreeRoot:e.cwd});let m=import.meta.dirname??new URL(`.`,import.meta.url).pathname,h=[r(m,`public`),r(m,`../../app/dist`),r(m,`../../../app/dist`)].find(e=>t(e)),g=h?l(h,{single:!0,gzip:!0,immutable:!0}):null,_=t(f)?l(f,{dotfiles:!1,dev:!0}):null,v=e.port,y=null,b=(e,t)=>{let n=e.url?.split(`?`)[0];if(n===`/api/config`&&(e.method===`GET`||e.method===`HEAD`)){y?.();let n=o(p),r=n&&n.port>0?`ws://localhost:${n.port}/collab`:null,i=JSON.stringify({collabUrl:r,previewUrl:null,port:v});t.setHeader(`Content-Type`,`application/json`),t.setHeader(`Cache-Control`,`no-store`),t.setHeader(`X-Content-Type-Options`,`nosniff`),t.statusCode=200,e.method===`HEAD`?t.end():t.end(i);return}if(n?.startsWith(`/api/`)){y?.();let r=o(p);if(!r||r.port<=0){t.writeHead(503,{"Content-Type":`application/json`,"Cache-Control":`no-store`}),t.end(JSON.stringify({error:"Collab server not running. Start `ok start` or run `ok status`.",path:n}));return}Mi(e,t,{upstreamHost:`localhost`,upstreamPort:r.port});return}if(decodeURIComponent(n?.replace(/^\//,``)??``)&&_){t.setHeader(`X-Content-Type-Options`,`nosniff`),_(e,t,()=>{g?g(e,t):Ii(t)});return}if(g){g(e,t);return}Ii(t)},x=e.host===void 0?[`::1`,`127.0.0.1`]:[e.host],S=[],C=e.port;try{for(let e of x){let t=n(b);S.push(t),await new Promise((n,r)=>{let i=e=>r(e);t.once(`error`,i),t.listen(C,e,()=>{t.off(`error`,i);let e=t.address();typeof e==`object`&&e&&(C=e.port),n()})})}}catch(e){await Promise.all(S.map(e=>new Promise(t=>{try{e.close(()=>t())}catch{t()}})));try{s(p)}catch{}throw e}let w=C;v=w,c(p,w);let T=e.scheduler??i,E=e.safetyNetMs??432e5,D=null,O=!1,ee=!1,k=()=>{O||(O=!0,D!==null&&(T.clearTimeout(D),D=null))},te=()=>{if(k(),!ee){ee=!0;try{s(p)}catch{}}},ne=()=>{O||E<=0||(D!==null&&(T.clearTimeout(D),D=null),D=T.setTimeout(()=>{D=null,console.warn(`[ui] safety-net (${E}ms) reached — shutting down (D-025 backstop)`);try{e.onSafetyNet?.()}catch{}for(let e of S)try{e.close()}catch{}te()},E))},re=()=>{O||E<=0||ne()};return y=re,ne(),{httpServers:S,port:w,release:te,detachSafetyNet:k,nudgeSafetyNet:re}}function Ii(e){e.writeHead(404),e.end(`Not found`)}function Li(e,t){if(e!==void 0){let t=Number.parseInt(e,10);if(Number.isNaN(t)||t<0||t>65535)throw Error(`Invalid --port value '${e}'`);return t}if(t!==void 0&&t!==``){let e=Number.parseInt(t,10);if(Number.isNaN(e)||e<0||e>65535)throw Error(`Invalid PORT env value '${t}'`);return e}return 0}async function Ri(e){let t=e.readLock??(async()=>{let{readUiLock:t}=await import(`./src-Dh_UJnt4.mjs`);return t(e.lockDir)}),n=await t();if(!n)throw Error(`UI lock collision reported but the lock disappeared before handling — retry acquiring.`);if(n.port===e.requestedPort&&n.port>0)return{mode:`already-running`,port:n.port};let r=n.port;if(r===0){let n=Date.now()+(e.pollDeadlineMs??2e3),i=e.pollIntervalMs??100;for(;Date.now()<n;){await new Promise(e=>{setTimeout(e,i)});let e=await t();if(e&&e.port>0){r=e.port;break}}if(r===0)throw Error("UI did not bind within 2s; run `ok clean`");if(r===e.requestedPort)return{mode:`already-running`,port:r}}return{mode:`proxy`,handle:await ji({listenPort:e.requestedPort,host:e.host,upstreamHost:`localhost`,upstreamPort:r}),upstreamPort:r}}function zi(e){return new w(`ui`).description(`Serve the Open Knowledge React editor UI`).option(`-p, --port <port>`,`UI port (default: $PORT env or 0 / kernel-allocated)`).option(`-H, --host <host>`,"UI host. Default: two-socket loopback bind (`[::1]` + `127.0.0.1`) so cross-family collisions fail loud (D-033). Pass an explicit host (e.g. `127.0.0.1`, `0.0.0.0`) to bind a single socket on that host.").action(async t=>{let{dim:n}=await import(`./colors-BNRrOlZZ.mjs`),{UiLockCollisionError:r}=await import(`./src-Dh_UJnt4.mjs`),{resolveContentDir:i,resolveLockDir:a}=await import(`./paths-8lEuqzzC.mjs`),o=e(),s=t.host,c;try{c=Li(t.port,process.env.PORT)}catch(e){console.error(e instanceof Error?e.message:String(e)),process.exitCode=1;return}try{let e=await Fi({config:o,cwd:process.cwd(),port:c,host:s}),t=s===void 0||s===`::`||s===`0.0.0.0`?`localhost`:s;console.log(`${n(`[ui]`)} listening on http://${t}:${e.port}`);let r=!1,i=t=>{if(r)return;r=!0,console.log(n(`\n[ui] Shutting down (${t})...`)),e.detachSafetyNet();let i=()=>{try{e.release()}finally{process.exit(process.exitCode??0)}};Pi(e.httpServers).then(i,i),setTimeout(i,2e3).unref()};process.once(`SIGINT`,()=>i(`SIGINT`)),process.once(`SIGTERM`,()=>i(`SIGTERM`));return}catch(e){if(!(e instanceof r))throw e;let t=a(i(o,process.cwd())),l=s??`localhost`,u;try{u=await Ri({requestedPort:c,host:l,lockDir:t})}catch(e){console.error(e instanceof Error?e.message:String(e)),process.exit(1)}u.mode===`already-running`&&(console.log(`UI already running at http://${l}:${u.port}`),process.exit(0)),console.log(`UI running at http://${l}:${u.upstreamPort}; acting as HTTP proxy on port ${u.handle.port}`);let d=!1,f=e=>{d||(d=!0,console.log(n(`\n[ui-proxy] Shutting down (${e})...`)),u.handle.close().finally(()=>process.exit(process.exitCode??0)),setTimeout(()=>process.exit(process.exitCode??0),2e3).unref())};process.once(`SIGINT`,()=>f(`SIGINT`)),process.once(`SIGTERM`,()=>f(`SIGTERM`))}})}process.argv.includes(`--no-color`)?(process.env.NO_COLOR=`1`,delete process.env.FORCE_COLOR):process.argv.includes(`--color`)&&(process.env.FORCE_COLOR=`1`,delete process.env.NO_COLOR);const Q=new w;let $;Q.name(`open-knowledge`).description(`Local-first knowledge base with CRDT collaboration`).version(e).option(`--cwd <path>`,`Working directory`).option(`--log-level <level>`,`Log level`,`info`).option(`--no-color`,`Disable color output`).option(`--color`,`Force color output`).hook(`preAction`,e=>{let t=e.opts(),n=t.cwd;n!==void 0&&process.chdir(n);let{config:r}=b(n),i=e.args.length===0?t:e.commands[0]?.opts()??{};i.port!==void 0&&(r.server.port=Number(i.port)),i.host!==void 0&&(r.server.host=i.host),process.env.PORT&&(r.server.port=Number(process.env.PORT)),process.env.HOST&&(r.server.host=process.env.HOST),$=r});const Bi=S(()=>$);Q.addCommand(Bi,{isDefault:!0});const Vi=mi(()=>$);Q.addCommand(Vi),Q.addCommand(v());const Hi=hi(()=>$);Q.addCommand(Hi);const Ui=zi(()=>$);Q.addCommand(Ui),Q.addCommand(Oi(()=>$)),Q.addCommand(st(()=>$)),Q.addCommand(Ti(()=>$)),Q.addCommand(rt(()=>$)),Q.addCommand(gt(()=>$)),Q.addCommand(_i(()=>$)),Q.addCommand(yi(()=>$)),Q.addCommand(vi(()=>$)),await Q.parseAsync();export{};
|
|
595
595
|
//# sourceMappingURL=cli.mjs.map
|
package/dist/index.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
import{n as e,r as t}from"./loader-
|
|
1
|
+
import{n as e,r as t}from"./loader-BOYrnnNP.mjs";import"./src-DYjDx2Br.mjs";export{t as ConfigSchema,e as loadConfig};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import{i as e}from"./constants-DigVOZ9o.mjs";import{D as t}from"./src-CdcLi3q2.mjs";import{n,t as r}from"./src-Cgk_X3wh.mjs";import{o as i,s as a}from"./init-DiUw5TDX.mjs";import{t as o}from"./preview-DlFxxSWj.mjs";import{o as s}from"./colors-CoV_NlQL.mjs";import{t as c}from"./is-object-B4GcZahG.mjs";import{Command as l}from"commander";import{existsSync as u,mkdirSync as d,readFileSync as f,writeFileSync as p}from"node:fs";import{homedir as m}from"node:os";import{basename as h,dirname as g,isAbsolute as ee,join as _,posix as v,relative as y,resolve as b,sep as x,win32 as S}from"node:path";import{parse as C,stringify as w}from"smol-toml";const T=[`claude`,`claude-desktop`,`cursor`,`vscode`,`windsurf`,`codex`],E=[`@inkeep/open-knowledge`,`mcp`],D={MCP_DEBUG:`1`,OK_LOG_FILE:`/tmp/ok-mcp.log`};function O(e=process.argv[1]){if(!e)throw Error(`Cannot infer the local CLI entry for --dev-mcp because process.argv[1] is empty.`);let t=b(e);if(h(t)===`cli.mjs`&&h(g(t))===`dist`)return t;let n=t.split(x),r=n.lastIndexOf(`packages`);if(r===-1||n[r+1]!==`cli`)throw Error(`Cannot infer the repo root for --dev-mcp from ${t}. Run the local CLI from this repo so the built dist path can be derived.`);let i=n.slice(0,r);return _(i.length===0?x:i.join(x),`packages`,`cli`,`dist`,`cli.mjs`)}function k(e={}){return e.mode===`dev`?{command:`node`,args:[O(e.cliEntryPath),`mcp`],env:{...D}}:{command:`npx`,args:[...E]}}function A(e){return e===`win32`?S:v}function te(e={}){let t=e.platformName??process.platform,n=e.home??m(),r=e.env??process.env,i=A(t);return t===`darwin`?i.join(n,`Library`,`Application Support`):t===`win32`?r.APPDATA??i.join(n,`AppData`,`Roaming`):r.XDG_CONFIG_HOME??i.join(n,`.config`)}function j(e={}){let t=e.platformName??process.platform,n=e.home??m();return A(t).join(n,`.claude.json`)}function M(e={}){let t=e.platformName??process.platform,n=e.home??m(),r=e.env??process.env;if(t===`darwin`)return v.join(n,`Library`,`Application Support`,`Claude`,`claude_desktop_config.json`);if(t===`win32`){let e=r.APPDATA??S.join(n,`AppData`,`Roaming`);return S.join(e,`Claude`,`claude_desktop_config.json`)}throw Error(`Claude Desktop is not available on ${t}. Supported: macOS, Windows.`)}function N(e={}){let t=e.platformName??process.platform,n=e.home??m();return A(t).join(n,`.cursor`,`mcp.json`)}function P(e={}){return A(e.platformName??process.platform).join(te(e),`Code`,`User`,`mcp.json`)}function F(e={}){let t=e.platformName??process.platform,n=e.home??m();return A(t).join(n,`.codeium`,`windsurf`,`mcp_config.json`)}function I(e={}){let t=e.platformName??process.platform,n=e.home??m();return(e.env??process.env).CODEX_HOME??A(t).join(n,`.codex`)}function L(e={}){return A(e.platformName??process.platform).join(I(e),`config.toml`)}function R(e,t){if(e===t)return!0;if(Array.isArray(e)&&Array.isArray(t))return e.length===t.length&&e.every((e,n)=>R(e,t[n]));if(c(e)&&c(t)){let n=Object.keys(e).sort(),r=Object.keys(t).sort();return n.length===r.length&&n.every((e,t)=>e===r[t])&&n.every(n=>R(e[n],t[n]))}return!1}function ne(e,t){return Object.entries(t).every(([t,n])=>R(e[t],n))}function re(e,t){return{...e,...t}}function z(e){return{...e,isCompatible(t,n,r){return ne(t,e.buildEntry(n,r))},mergeManagedFields(t,n,r){return re(t,e.buildEntry(n,r))}}}const B={claude:z({id:`claude`,label:`Claude Code`,configPath:(e,t)=>j({home:t}),format:`json`,topLevelKey:`mcpServers`,serverName:()=>e,buildEntry:(e,t)=>k(t),scope:`global`,detectPath:(e,t)=>_(t??m(),`.claude`),legacyProjectConfigPath:e=>_(e,`.mcp.json`),instructionsPath:e=>_(e,`CLAUDE.md`)}),"claude-desktop":z({id:`claude-desktop`,label:`Claude Desktop`,configPath:(e,t)=>M({home:t}),format:`json`,topLevelKey:`mcpServers`,serverName:()=>e,buildEntry:(e,t)=>k(t),scope:`global`,detectPath:(e,t)=>g(M({home:t}))}),cursor:z({id:`cursor`,label:`Cursor`,configPath:(e,t)=>N({home:t}),format:`json`,topLevelKey:`mcpServers`,serverName:()=>e,buildEntry:(e,t)=>k(t),scope:`global`,detectPath:(e,t)=>g(N({home:t})),legacyProjectConfigPath:e=>_(e,`.cursor`,`mcp.json`)}),vscode:z({id:`vscode`,label:`VS Code`,configPath:(e,t)=>P({home:t}),format:`json`,topLevelKey:`servers`,serverName:()=>e,buildEntry:(e,t)=>({type:`stdio`,...k(t)}),scope:`global`,detectPath:(e,t)=>g(P({home:t})),legacyProjectConfigPath:e=>_(e,`.vscode`,`mcp.json`)}),windsurf:z({id:`windsurf`,label:`Windsurf`,configPath:(e,t)=>F({home:t}),format:`json`,topLevelKey:`mcpServers`,serverName:()=>e,buildEntry:(e,t)=>k(t),scope:`global`,detectPath:(e,t)=>g(F({home:t}))}),codex:z({id:`codex`,label:`Codex`,configPath:(e,t)=>L({home:t}),format:`toml`,topLevelKey:`mcp_servers`,serverName:()=>e,buildEntry:(e,t)=>k(t),scope:`global`,detectPath:(e,t)=>g(L({home:t})),legacyProjectConfigPath:e=>_(e,`.codex`,`config.toml`)})};function V(e){let t=e.filter(e=>!(e in B));if(t.length>0)throw Error(`Unknown editor(s): ${t.join(`, `)}. Valid options: ${T.join(`, `)}`);return e.map(e=>B[e])}function H(e){if(!u(e))return{};let t=f(e,`utf-8`).trim();if(t===``)return{};try{let n=JSON.parse(t);if(c(n))return n;throw Error(`${e} root must be a JSON object`)}catch(t){throw t instanceof SyntaxError?Error(`${e} contains invalid JSON: ${t.message}`):t}}function U(e){if(!u(e))return{};let t=f(e,`utf-8`).trim();if(t===``)return{};try{let n=C(t);if(c(n))return n;throw Error(`${e} root must be a TOML table`)}catch(t){throw Error(`${e} contains invalid TOML: ${t instanceof Error?t.message:String(t)}`)}}function W(e,t){d(g(e),{recursive:!0}),p(e,`${JSON.stringify(t,null,2)}\n`,`utf-8`)}function G(e,t){d(g(e),{recursive:!0});let n=w(t);p(e,n.endsWith(`
|
|
2
|
+
`)?n:`${n}\n`,`utf-8`)}const K=`0.0.1`,q=`open-knowledge-ui`;function J(e,t){let n=[];e.runtimeExecutable!==t.runtimeExecutable&&n.push(`runtimeExecutable`);let r=e.runtimeArgs;return Array.isArray(r)&&r.length===t.runtimeArgs.length&&r.every((e,n)=>e===t.runtimeArgs[n])||n.push(`runtimeArgs`),e.port!==t.port&&n.push(`port`),n}function Y(e,t,n={}){let r=_(e,`.claude`,`launch.json`),i=n.mode===`dev`,a=n.mode===`dev`?{name:q,runtimeExecutable:`node`,runtimeArgs:[O(n.cliEntryPath),`ui`],port:3e3}:{name:q,runtimeExecutable:`npx`,runtimeArgs:[`@inkeep/open-knowledge`,`ui`],port:3e3};try{if(!u(r))return d(g(r),{recursive:!0}),p(r,`${JSON.stringify({version:K,configurations:[a]},null,2)}\n`,`utf-8`),{action:`created`,configPath:r};let e=f(r,`utf-8`).trim(),n=e?JSON.parse(e):{};if(!c(n))return{action:`failed`,configPath:r,error:`launch.json root is not an object`};let o=Array.isArray(n.configurations)?n.configurations:[],s=o.findIndex(e=>c(e)&&e.name===q);if(s>=0&&!t){let e=o[s],t=J(e,a);if(t.length>0){if(!i)return{action:`skipped-stale`,configPath:r,staleFields:t}}else return{action:`skipped-existing`,configPath:r}}s>=0?o[s]=a:o.push(a);let l={...n,version:n.version??K,configurations:o};return p(r,`${JSON.stringify(l,null,2)}\n`,`utf-8`),{action:`merged`,configPath:r}}catch(e){return{action:`failed`,configPath:r,error:e instanceof Error?e.message:String(e)}}}function ie(e,t,n,r,i){let a=e.serverName(t),o;try{o=e.configPath(t,i)}catch(t){return{editorId:e.id,label:e.label,action:`failed`,configPath:``,serverName:a,error:t instanceof Error?t.message:String(t)}}let s;try{s=e.format===`toml`?U(o):H(o)}catch(t){return{editorId:e.id,label:e.label,action:`failed`,configPath:o,serverName:a,error:t instanceof Error?t.message:String(t)}}let l=s[e.topLevelKey]??{},u=l[a],d=r.mode===`dev`,f;try{if(u!==void 0&&!n){if(c(u)&&e.isCompatible(u,t,r))return{editorId:e.id,label:e.label,action:`skipped-existing`,configPath:o,serverName:a};if(!d)return{editorId:e.id,label:e.label,action:`skipped-conflict`,configPath:o,serverName:a}}f=c(u)&&(n||d)?e.mergeManagedFields(u,t,r):e.buildEntry(t,r)}catch(t){return{editorId:e.id,label:e.label,action:`failed`,configPath:o,serverName:a,error:t instanceof Error?t.message:String(t)}}let p={...s,[e.topLevelKey]:{...l,[a]:f}};try{e.format===`toml`?G(o,p):W(o,p)}catch(t){return{editorId:e.id,label:e.label,action:`failed`,configPath:o,serverName:a,error:t instanceof Error?t.message:String(t)}}return{editorId:e.id,label:e.label,action:u===void 0?`written`:`overwritten`,configPath:o,serverName:a}}function ae(e,t){let n=e.legacyProjectConfigPath?.(t);if(!(!n||!u(n)))return{editorId:e.id,label:e.label,path:n}}async function X(e={}){let t=b(e.cwd??process.cwd()),r={mode:e.devMcp?`dev`:`published`,cliEntryPath:e.cliEntryPath},o=await n(t),s;try{s=i(t)}catch(n){let r=B.claude.configPath(t,e.home);return{contentCreated:[],contentSkipped:[],editors:[],legacyProjectConfigs:[],rootInstructions:[],didGitInit:o.didInit,mcpAction:`failed`,mcpPath:r,mcpError:`Content scaffolding failed: ${n instanceof Error?n.message:String(n)}`}}let c=e.editors??[`claude`],l=V(c),u=[];for(let n of l){if(e.mcp===!1){let r=``;try{r=n.configPath(t,e.home)}catch{}u.push({editorId:n.id,label:n.label,action:`skipped-flag`,configPath:r,serverName:n.serverName(t)});continue}u.push(ie(n,t,e.force??!1,r,e.home))}let d=e.mcp===!1?[]:l.map(e=>ae(e,t)).filter(e=>e!==void 0),f=c.includes(`claude`)&&e.mcp!==!1?Y(t,e.force??!1,r):void 0,p=l.map(e=>e.instructionsPath?.(t)).filter(e=>e!==void 0).map(e=>ee(e)?y(t,e):e),m=e.rootInstructions===!1?[]:a(t,e.force??!1,p),h=u.find(e=>e.editorId===`claude`)??u[0]??{action:`skipped-flag`,configPath:B.claude.configPath(t,e.home)};return{contentCreated:s.created,contentSkipped:s.skipped,editors:u,legacyProjectConfigs:d,rootInstructions:m,launchJson:f,didGitInit:o.didInit,mcpAction:h.action,mcpPath:h.configPath,mcpError:`error`in h?h.error:void 0}}function Z(e,n){let r=[];e.didGitInit&&r.push(`Initialized git repo at ${n}/.git/ (default branch: main)`);let i=_(n,t);if(e.contentCreated.length>0?(r.push(`Content scaffolded at ${i}/`),r.push(` Created: ${e.contentCreated.join(`, `)}`)):r.push(`Content already present at ${i}/`),e.contentSkipped.length>0&&r.push(` Skipped (already exist): ${e.contentSkipped.join(`, `)}`),r.push(``),e.editors.length===0)e.mcpError&&r.push(`Warning: ${e.mcpError}`);else{let t=e.editors.some(e=>e.action===`written`||e.action===`overwritten`),i=e.editors.some(e=>e.action===`failed`);if(e.editors.every(e=>e.action===`skipped-flag`))r.push(`MCP config not written — use without --no-mcp to configure editors`);else{r.push(`MCP server configuration:`);for(let t of e.editors){let e=t.configPath.startsWith(n)?y(n,t.configPath):t.configPath.replace(/^\/Users\/[^/]+/,`~`),i=t.serverName===`open-knowledge`?``:` (${t.serverName})`,a=` `.repeat(Math.max(1,14-t.label.length)),o=t.editorId===`claude-desktop`&&(t.action===`written`||t.action===`overwritten`)?` — quit and relaunch Claude Desktop to activate`:``;switch(t.action){case`written`:r.push(` ${t.label}${a}${e} registered${i}${o}`);break;case`overwritten`:r.push(` ${t.label}${a}${e} updated${i}${o}`);break;case`skipped-existing`:r.push(` ${t.label}${a}${e} already configured${i}`);break;case`skipped-conflict`:r.push(` ${t.label}${a}${e} managed MCP fields differ from current defaults${i}; re-run with --force to update`);break;case`failed`:r.push(` ${t.label}${a}${e} FAILED: ${t.error}`);break;case`skipped-flag`:break}}}if(i&&(r.push(``),r.push(`For failed editors, add the MCP server entry manually. See:`),r.push(` https://github.com/inkeep/open-knowledge#mcp-setup`)),e.legacyProjectConfigs.length>0){r.push(``),r.push(`Legacy project MCP configs detected:`);for(let t of e.legacyProjectConfigs)r.push(` ${t.label} ${y(n,t.path)}`);r.push(` These project-local files may override the new global config. Remove them if you want fully user-scoped MCP setup in this project.`)}if(e.launchJson){let t=e.launchJson,i=t.configPath.startsWith(n)?y(n,t.configPath):t.configPath;switch(t.action){case`created`:r.push(` launch.json ${i} created (preview_start("${q}") ready)`);break;case`merged`:r.push(` launch.json ${i} merged open-knowledge entry`);break;case`skipped-existing`:r.push(` launch.json ${i} already has open-knowledge entry`);break;case`skipped-stale`:r.push(` launch.json ${i} ${s(`⚠ existing open-knowledge entry is out of date`)}`),t.staleFields&&t.staleFields.length>0&&r.push(` ${s(`${t.staleFields.join(`, `)} differ from current defaults`)}`),r.push(` ${s(`re-run with --force to update`)}`);break;case`failed`:r.push(` launch.json ${i} FAILED: ${t.error}`);break}}if(e.rootInstructions.length>0){let t=e.rootInstructions.filter(e=>e.action!==`skipped-symlink`);if(t.length>0){r.push(``),r.push(`Root instructions:`);for(let e of t){let t=e.path.startsWith(n)?y(n,e.path):e.path,i=` `.repeat(Math.max(1,14-e.file.length));switch(e.action){case`created`:r.push(` ${e.file}${i}${t} created`);break;case`appended`:r.push(` ${e.file}${i}${t} appended Open Knowledge section`);break;case`replaced`:r.push(` ${e.file}${i}${t} replaced Open Knowledge section (--force)`);break;case`skipped-existing`:r.push(` ${e.file}${i}${t} already has Open Knowledge section`);break}}}}if(e.preview?(r.push(``),r.push(o(e.preview,n))):e.previewWarning&&(r.push(``),r.push(`Content preview unavailable: ${e.previewWarning}`)),t){let t=e.editors.filter(e=>e.action===`written`||e.action===`overwritten`).map(e=>e.label);r.push(``),r.push(`Next steps:`),r.push(` 1. Open your editor (${t.join(` / `)})`),r.push(` 2. Approve the MCP server when prompted`),r.push(` 3. The knowledge base is ready — use the three workflow tools:`),r.push(` - mcp__open-knowledge__init-content — bootstrap articles from the codebase`),r.push(` - mcp__open-knowledge__ingest — capture an external source`),r.push(` - mcp__open-knowledge__research — gather sources and write findings`)}}return r.join(`
|
|
3
|
+
`)}function oe(e){switch(e){case`claude_desktop`:return`claude-desktop`;default:return e}}function Q(e){if(e===`all`)return[...T];let t=e.split(`,`).map(e=>e.trim()).map(oe);return V(t),t}function $(e,t){let n=[];for(let r of T){let i=B[r],a;try{a=i.detectPath?.(e,t)??g(i.configPath(e,t))}catch{continue}u(a)&&n.push(r)}return n}function se(){return new l(`init`).description(`Scaffold ${t}/ in the current directory and register the MCP server for your editor(s)`).option(`--mcp`,`Register the MCP server for selected editors (default: true)`,!0).option(`--no-mcp`,`Scaffold the ${t}/ directory but do not touch MCP config`).option(`--force`,`Overwrite existing open-knowledge MCP entries (default: skip)`).option(`--dev-mcp`,`Register a local dev MCP entry using node + packages/cli/dist/cli.mjs with debug logging`).option(`--editor <editors>`,`Target editor(s): ${T.join(`, `)}, all (comma-separated) — default: all detected editors (non-TTY) / preselects detected editors (TTY)`).action(async e=>{let t=process.cwd(),n;if(e.editor)try{n=Q(e.editor)}catch(e){process.stderr.write(`${e instanceof Error?e.message:String(e)}\n`),process.exitCode=1;return}else if(e.mcp!==!1&&process.stdin.isTTY){let{multiselect:e,isCancel:r}=await import(`@clack/prompts`),i=new Set($(t));i.size===0&&process.stdout.write(`No MCP-capable editors detected — select manually, or cancel and use --editor <all|${T.join(`|`)}>.\n`);let a=await e({message:`Which tools do you use? (space to toggle, enter to confirm)`,options:T.flatMap(e=>{let n=B[e];try{let r=n.configPath(t),a=n.scope===`global`?r.replace(/^\/Users\/[^/]+/,`~`):y(t,r);return[{value:e,label:n.label,hint:a,initialValue:i.has(e)}]}catch{return[]}}),required:!0});if(r(a)){process.stdout.write(`Init cancelled.
|
|
4
|
+
`);return}n=a}else if(n=$(t),n.length===0){process.stderr.write(`No MCP-capable editors detected. Use --editor <all|${T.join(`|`)}> to force.\n`),process.exitCode=1;return}let i;try{i=await X({cwd:t,mcp:e.mcp,force:e.force,devMcp:e.devMcp,editors:n})}catch(e){if(e instanceof r){process.stderr.write(`open-knowledge requires git to initialize a parent repo. Install git or run 'git init' yourself, then re-run.
|
|
5
|
+
`),e.stderr&&process.stderr.write(`${e.stderr.trim()}\n`),process.exitCode=1;return}throw e}try{let{previewContent:e}=await import(`./preview-CCBPkWf0.mjs`),{loadConfig:n}=await import(`./loader-CecgSwbH.mjs`),{resolveContentDir:r}=await import(`./paths-8lEuqzzC.mjs`),{config:a}=n(t),o=r(a,t);i.preview=e({projectDir:t,contentDir:o,include:a.content.include,exclude:a.content.exclude})}catch(e){i.previewWarning=e instanceof Error?e.message:String(e)}process.stdout.write(`${Z(i,t)}\n`),(i.editors.some(e=>e.action===`failed`)||i.mcpAction===`failed`)&&(process.exitCode=1)})}export{X as a,Q as i,Z as n,se as r,$ as t};
|
|
6
|
+
//# sourceMappingURL=init-BPHczY2k.mjs.map
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import{n as e,r as t,t as n}from"./constants-
|
|
1
|
+
import{n as e,r as t,t as n}from"./constants-DigVOZ9o.mjs";import{D as r}from"./src-CdcLi3q2.mjs";import{existsSync as i,mkdirSync as a,readFileSync as o,realpathSync as s,writeFileSync as c}from"node:fs";import{join as l,resolve as u}from"node:path";const d=`<!-- open-knowledge:begin -->`,f=`<!-- open-knowledge:end -->`,p=/<!-- open-knowledge:begin -->[\s\S]*?<!-- open-knowledge:end -->/,m=`# ${r}/ — Open Knowledge config
|
|
2
2
|
|
|
3
3
|
This directory holds Open Knowledge's configuration for this project. It's **not** where content lives — content lives wherever \`content.dir\` + \`content.include\` in \`config.yml\` point. The default is the repo root with \`**/*.md\`, so any markdown file in the project is fair game. Inspect \`config.yml\` for the actual setting.
|
|
4
4
|
|
|
@@ -227,4 +227,4 @@ ${f}`;function v(e,t,r){let a=[n,...r??[]],u=new Set,d=[];for(let n of a){let r=
|
|
|
227
227
|
|
|
228
228
|
`)?`
|
|
229
229
|
`:``}${n}`,`utf-8`),`appended`)}const x=[{name:n,content:m},{name:`.gitignore`,content:`${e}/\nserver.lock\nui.lock\nsync-state.json\n`},{name:t,content:h}];function S(t){let n=u(t,r),i=[],o=[];a(n,{recursive:!0}),a(l(n,e),{recursive:!0});for(let e of x)y(l(n,e.name),e.content)?i.push(e.name):o.push(e.name);return{created:i,skipped:o}}export{b as a,g as i,d as n,S as o,f as r,v as s,_ as t};
|
|
230
|
-
//# sourceMappingURL=init-
|
|
230
|
+
//# sourceMappingURL=init-DiUw5TDX.mjs.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{a as e,i as t,n,o as r,r as i,s as a,t as o}from"./init-
|
|
1
|
+
import{a as e,i as t,n,o as r,r as i,s as a,t as o}from"./init-DiUw5TDX.mjs";export{o as CLAUDE_MD_SECTION,n as OK_MARKER_BEGIN,i as OK_MARKER_END,t as PREVIEW_GUIDANCE,e as ensureOkGitignoredAtRoot,r as initContent,a as upsertRootInstructions};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{a as e,i as t,n,r,t as i}from"./init-BPHczY2k.mjs";export{i as detectInstalledEditors,n as formatInitResult,r as initCommand,t as parseEditorFlag,e as runInit};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import{r as e}from"./constants-
|
|
1
|
+
import{r as e}from"./constants-DigVOZ9o.mjs";import{D as t}from"./src-CdcLi3q2.mjs";import{t as n}from"./is-object-B4GcZahG.mjs";import{existsSync as r,readFileSync as i}from"node:fs";import{homedir as a}from"node:os";import{resolve as o}from"node:path";import{parse as s}from"yaml";import{realpath as c}from"node:fs/promises";import{z as l}from"zod";async function u(e){let t=o(e);try{return await c(t)}catch(e){if(e.code!==`ENOENT`){let n=e instanceof Error?e.message:String(e);console.warn(`[normalize-cwd] realpath failed for ${t}: ${n}`)}return t}}const d=l.object({title:l.string().optional(),description:l.string().optional(),tags:l.array(l.string()).optional()}).strict(),f=l.object({match:l.string().min(1,"`match` must be a non-empty glob pattern (e.g. 'specs/**' or 'reports/*/**')"),frontmatter:d}).strict(),p=l.object({content:l.object({dir:l.string().default(`.`),include:l.array(l.string()).min(1).default([`**/*.md`,`**/*.mdx`]),exclude:l.array(l.string()).default([])}).default({dir:`.`,include:[`**/*.md`,`**/*.mdx`],exclude:[]}),github:l.object({oauthAppClientId:l.string().default(`Ov23liqlSd0V1MwR6rhI`)}).default({oauthAppClientId:`Ov23liqlSd0V1MwR6rhI`}),sync:l.object({enabled:l.boolean().optional(),pushIntervalSeconds:l.number().int().min(1).default(60),pullIntervalSeconds:l.number().int().min(1).default(30),autoCommit:l.boolean().default(!0),autoPush:l.boolean().default(!0),autoPull:l.boolean().default(!0),commitMessage:l.string().default(`auto`)}).default({pushIntervalSeconds:60,pullIntervalSeconds:30,autoCommit:!0,autoPush:!0,autoPull:!0,commitMessage:`auto`}),server:l.object({port:l.number().int().min(0).max(65535).default(0),host:l.string().regex(/^[\w.\-:]+$/,`Invalid hostname`).default(`localhost`),openOnAgentEdit:l.boolean().default(!1)}).default({port:0,host:`localhost`,openOnAgentEdit:!1}),persistence:l.object({debounceMs:l.number().int().min(0).default(2e3),maxDebounceMs:l.number().int().min(0).default(1e4)}).default({debounceMs:2e3,maxDebounceMs:1e4}),preview:l.object({baseUrl:l.url().optional()}).default({}),folders:l.array(f).default([]),mcp:l.object({autoStart:l.boolean().default(!0),tools:l.object({read_document:l.object({historyDepth:l.number().int().min(0).default(5)}).default({historyDepth:5}),search:l.object({maxResults:l.number().int().min(1).default(50)}).default({maxResults:50})}).default({read_document:{historyDepth:5},search:{maxResults:50}})}).default({autoStart:!0,tools:{read_document:{historyDepth:5},search:{maxResults:50}}})});function m(e,t){let r={...e};for(let i of Object.keys(t)){let a=e[i],o=t[i];n(o)&&n(a)?r[i]=m(a,o):o!==void 0&&(r[i]=o)}return r}function h(e){if(!r(e))return null;try{let t=s(i(e,`utf-8`));return n(t)?t:null}catch(t){return console.warn(`[config] Failed to parse ${e}: ${t instanceof Error?t.message:t}`),null}}function g(n){let r=n??process.cwd(),i=[],s=o(a(),t,e),c={},l=h(s);l&&(c=m(c,l),i.push(s));let u=o(r,t,e),d=h(u);d&&(c=m(c,d),i.push(u));let f=p.safeParse(c);if(!f.success){let e=f.error.issues.map(e=>` ${e.path.join(`.`)}: ${e.message}`);throw Error(`Invalid configuration:\n${e.join(`
|
|
2
2
|
`)}`)}return{config:f.data,sources:i}}function _(e,t=process.env){let n=e;return t.PORT&&(n={...n,server:{...n.server,port:Number(t.PORT)}}),t.HOST&&(n={...n,server:{...n.server,host:t.HOST}}),n}function v(e){let t=e.env??process.env,n=e.cacheMs??1e3,r=e.loadConfigFn??g,i=new Map,a=new Map,o=u(e.startupCwd);return async s=>{let c=await u(s??e.startupCwd),l=Date.now(),d=i.get(c);if(d&&d.expiresAt>l)return d.config;let f=a.get(c);if(f)return await f;let p=(async()=>{if(c===await o){let r=_(e.startupConfig,t);return i.set(c,{config:r,expiresAt:Date.now()+n}),r}let a=_(r(c).config,t);return i.set(c,{config:a,expiresAt:Date.now()+n}),a})();a.set(c,p);try{return await p}finally{a.delete(c)}}}export{u as i,g as n,p as r,v as t};
|
|
3
|
-
//# sourceMappingURL=loader-
|
|
3
|
+
//# sourceMappingURL=loader-BOYrnnNP.mjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{n as e}from"./loader-BOYrnnNP.mjs";export{e as loadConfig};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{n as e,t}from"./paths-Ub0bMbwu.mjs";export{t as resolveContentDir,e as resolveLockDir};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{n as e,t}from"./preview-DlFxxSWj.mjs";export{t as formatPreviewBlock,e as previewContent};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
import"./constants-
|
|
1
|
+
import"./constants-DigVOZ9o.mjs";import{D as e}from"./src-CdcLi3q2.mjs";import{d as t}from"./src-Cgk_X3wh.mjs";import{existsSync as n,lstatSync as r,readdirSync as i,realpathSync as a,statSync as o}from"node:fs";import{join as s,relative as c}from"node:path";function l(e){let{projectDir:n,contentDir:l,include:u,exclude:d,sampleCap:f=5}=e,p=[],m=[];try{r(l)}catch(e){return{totalCount:0,sample:[],contentDir:l,include:u,exclude:d,warnings:[`cannot access content directory ${l}: ${e instanceof Error?e.message:String(e)}`]}}let h;try{h=t({projectDir:n,contentDir:l,includePatterns:u,excludePatterns:d})}catch(e){return{totalCount:0,sample:[],contentDir:l,include:u,exclude:d,warnings:[e instanceof Error?e.message:String(e)]}}function g(e){let t;try{t=i(e,{withFileTypes:!0})}catch(t){let n=t instanceof Error?t.message:String(t);p.push(`could not read directory ${c(l,e)||`.`}: ${n}`);return}for(let n of t){let t=s(e,n.name);if(n.isSymbolicLink()){let e;try{e=a(t)}catch(e){let n=e.code;n===`ENOENT`||n===`ELOOP`?p.push(`broken or cyclic symlink: ${c(l,t)}`):p.push(`cannot resolve symlink ${c(l,t)}: ${n??`unknown error`}`);continue}let n;try{n=o(e)}catch{continue}if(n.isDirectory()){let e=c(l,t);if(h.isDirExcluded(e))continue;g(t)}else if(n.isFile()){let e=c(l,t);if(h.isExcluded(e))continue;m.push(e)}}else if(n.isDirectory()){let e=c(l,t);if(h.isDirExcluded(e))continue;g(t)}else if(n.isFile()){let e=c(l,t);if(h.isExcluded(e))continue;m.push(e)}}}return g(l),{totalCount:m.length,sample:m.slice(0,f),contentDir:l,include:u,exclude:d,warnings:p}}function u(t,r){let i=[],a=c(r,t.contentDir),o=a===``?`./`:`./${a}`;i.push(`Content:`),i.push(` Found ${t.totalCount} markdown files in ${o}`);let l=t.include.join(`, `),u=t.exclude.length>0?t.exclude.join(`, `):`(none)`;if(i.push(` Scope: include=${l} exclude=${u}`),t.sample.length>0){let e=t.sample.join(`, `),n=t.totalCount>t.sample.length?`, …`:``;i.push(` Sample: ${e}${n}`)}if(t.warnings.length>0)for(let e of t.warnings)i.push(` Warning: ${e}`);return i.push(``),n(s(r,`.open-knowledge`,`config.yml`))?(i.push(` To adjust, edit ${e}/config.yml:`),i.push(` content:`),i.push(` include: ${JSON.stringify(t.include)}`),i.push(` exclude: ${JSON.stringify(t.exclude)}`)):(i.push(" Run `open-knowledge init` to scaffold config, then adjust:"),i.push(` ${e}/config.yml → content.include / content.exclude`)),i.push(``),i.push(` Re-check anytime: open-knowledge preview`),i.join(`
|
|
2
2
|
`)}export{l as n,u as t};
|
|
3
|
-
//# sourceMappingURL=preview-
|
|
3
|
+
//# sourceMappingURL=preview-DlFxxSWj.mjs.map
|