@kitelev/exocortex-cli 16.71.3 → 16.71.5

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.
Files changed (2) hide show
  1. package/dist/index.js +5 -5
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -1,5 +1,5 @@
1
1
  #!/usr/bin/env node
2
- // @kitelev/exocortex-cli v16.71.3
2
+ // @kitelev/exocortex-cli v16.71.5
3
3
  // CLI tool for Exocortex knowledge management system - SPARQL queries, task management, and more
4
4
  // License: MIT
5
5
 
@@ -782,10 +782,10 @@ ${r}`}a(VZ,"serializeFile");function yN(n,e,t={}){let r=Cy.default.dirname(n),i=
782
782
  `).map(t=>t.trim()).filter(t=>t.length>0)}a(bee,"readStdinLines");function ky(n){if(n&&typeof n=="object"&&"value"in n){let e=n.value;return typeof e=="string"?e:String(e)}return String(n)}a(ky,"nodeValue");async function See(n,e){let t=new Re.IRI("https://exocortex.my/ontology/exocmd#Command_cliName"),r=await n.match(void 0,t,void 0),i=[];for(let s of r)if(ky(s.object)===e){let c=ky(s.subject).match(/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})\.md$/i);c&&i.push(c[1])}if(i.length===0)return null;if(i.length>1)throw new Le(`Ambiguous cliName "${e}" \u2014 resolves to ${i.length} commands: ${i.join(", ")}`,"Use the UUID directly: exocortex apply <uuid> <path>");return i[0]}a(See,"resolveSlugToUuid");async function wee(n,e){let t=new Re.IRI("https://exocortex.my/ontology/exocmd#Command_destructive"),r=await n.match(void 0,t,void 0);for(let i of r)if(ky(i.subject).includes(e)){let o=ky(i.object);if(o==="true"||o==="True")return!0}return!1}a(wee,"isDestructive");async function vee(n,e,t,r,i,s,o,l){let c=(0,FT.resolve)(n,i);if(!(0,OT.existsSync)(c))return console.error(`\u274C Target file not found: ${i}`),!1;let u=new Re.CommandResolver(e),f=await u.loadCommand(r);if(!f)return console.error(`\u274C Command with UID "${r}" not found.`),!1;if(await wee(e,r)&&!s.dryRun&&!s.yes)return console.error(`\u274C Command "${f.name}" is marked destructive. Add --dry-run to preview, or --yes to apply.`),!1;let h=(0,Re.vaultPathToIRI)(i),p=new yt(n),g=new Re.FolderRepairService(p),_=new Re.PreconditionEvaluator(e,void 0,{clock:o});(0,Re.registerDefaultHostFunctions)(_),_.registerHostFunction("isInWrongFolder",xN(p,g));let E=p.getAbstractFileByPath(i),S=E!==null&&"basename"in E?E:null,v=S?p.getFrontmatter(S):null,A=v&&typeof v=="object"?v.exo__Asset_uid:void 0,P={targetIRI:h,filePath:i,fileBasename:S?.basename,assetUid:typeof A=="string"?A:void 0};if(!await _.evaluate(f.precondition,h,P))return console.error(`\u274C Precondition not satisfied for "${f.name}" on "${i}".`),!1;if(s.dryRun)return console.log(`\u{1F50D} Dry-run: would apply "${f.name}" to "${i}" (precondition passed).`),!0;let j=new Re.ServiceRegistry,ye=new Re.GenericAssetCreationService(p).withDeterminism({clock:o,uidGenerator:l}),Ne=new Re.ArchiveAssetService(p),N=new Re.PropertyCleanupService(p),D=new Re.FixMissingLabelService(p),G=new Re.RenameToUidService(p),te=new Re.TaskStatusService(p,new Re.EffortStatusWorkflow,new Re.StatusTimestampService(p)),q=new Zt(n);LN(j,{vaultAdapter:p,fsAdapter:q,genericAssetCreationService:ye,archiveAssetService:Ne,taskStatusService:te,propertyCleanupService:N,fixMissingLabelService:D,renameToUidService:G,folderRepairService:g});let ie=new Re.GroundingExecutor(q,q,j,(0,Re.createVaultFrontmatterClassLabelResolver)(q),{clock:o,uidGenerator:l,workflowResolver:t,groundingLoader:a(K=>u.loadGroundingByUid(K),"groundingLoader")}),de;if(s.input)try{let K=JSON.parse(s.input);if(typeof K!="object"||K===null||Array.isArray(K))throw new Error("must be a JSON object");de=K}catch(K){let B=K instanceof Error?K.message:String(K);return console.error(`\u274C --input: invalid JSON object (${B})`),!1}let He=await ie.execute(f.grounding,h,i,de);if(He.success){let K=f.successMessage??`Applied "${f.name}" to "${i}".`;return console.log(`\u2705 ${K}`),!0}else return console.error(`\u274C "${f.name}" failed on "${i}": ${He.error}`),!1}a(vee,"executeOnTarget");function NN(){return new ne("apply").description("Apply an exocmd__Command to one or more vault assets (RFC 8e83442b T1.2). Pass a path arg or pipe paths via stdin.").argument("<cmd>","Command UUID or cliName slug").argument("[path]","Vault-relative path to target asset (omit to read paths from stdin)").option("--vault <path>","Path to Obsidian vault",process.cwd()).option("--dry-run","Preview without writing").option("--yes","Skip destructive-command confirmation").option("--input <json>","JSON userInput for service_call groundings").option("--seed <uuid>","Deterministic UID seed for test/replay (uses seededUidGenerator)").option("--frozen-clock <iso>","Freeze clock to ISO timestamp for test/replay (uses frozenClock)").action(async(n,e,t)=>{ee.setFormat("text");try{let r=(0,FT.resolve)(t.vault);if(!(0,OT.existsSync)(r))throw new le(r);by(r);let i=t.frozenClock?(0,Re.frozenClock)(t.frozenClock):(0,Re.liveClock)(),s=t.seed?(0,Re.seededUidGenerator)(t.seed):(0,Re.liveUidGenerator)(),o=new yt(r),c=await new Re.NoteToRDFConverter(o).convertVault(),u=new Re.InMemoryTripleStore;await u.addAll(c);let f=new Re.WorkflowResolver(u),d;if(_ee.test(n))d=n;else{let _=await See(u,n);_||(console.error(`\u274C No command found with UUID or cliName "${n}".`),process.exit(3)),d=_}let h;if(e)h=[e];else if(h=await bee(),h.length===0)throw new Le("No target path provided and stdin is empty.","exocortex apply <uuid> <path> OR exocortex find ... | exocortex apply <uuid>");let p=0,g=0;for(let _ of h)await vee(r,u,f,d,_,t,i,s)?p++:g++;h.length>1&&console.log(`
783
783
  \u{1F4CA} Applied to ${p}/${h.length} target(s) (${g} failed).`),g>0&&process.exit(5)}catch(r){ee.handle(r),process.exit(5)}})}a(NN,"applyCommand");var ha=require("fs"),Su=require("path");var kN=/^---\s*$/,Eee=/^exocmd__Grounding_type:\s*(.+?)\s*$/,Tee=/^"?\[\[[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}(?:\|[^\]]*)?\]\]"?$/i,Iee=new Set(["node_modules"]);function Aee(n){return n.startsWith(".")||Iee.has(n)}a(Aee,"shouldSkipDir");function*MN(n){let e;try{e=(0,ha.readdirSync)(n,{withFileTypes:!0})}catch(t){let r=t;if(r.code==="EPERM"||r.code==="EACCES"||r.code==="ENOENT")return;throw t}for(let t of e){let r=(0,Su.join)(n,t.name);if(t.isDirectory()){if(Aee(t.name))continue;yield*MN(r)}else t.isFile()&&t.name.endsWith(".md")&&(yield r)}}a(MN,"walkMarkdownFiles");function xee(n){let e=n.split(/\r?\n/);if(e.length<2||!kN.test(e[0]))return null;for(let t=1;t<e.length;t++)if(kN.test(e[t]))return{lines:e.slice(1,t),startLine:2};return null}a(xee,"extractFrontmatter");function Ree(n){let e=n.trim();return e===""||e==="null"||e==="~"?!1:!Tee.test(e)}a(Ree,"isLiteralForm");function Cee(n){let e=[];for(let t of MN(n)){let r;try{r=(0,ha.readFileSync)(t,"utf-8")}catch{continue}let i=xee(r);if(i)for(let s=0;s<i.lines.length;s++){let o=i.lines[s].match(Eee);if(!o)continue;let l=o[1];Ree(l)&&e.push({path:(0,Su.relative)(n,t),line:i.startLine+s,value:l})}}return e}a(Cee,"scanVaultForLiteralForm");function jN(){return new ne("grounding-type-literal-form").description("Detect post-Phase-4+1 regressions: any exocmd__Grounding_type literal-string form (not wikilink) in vault frontmatter").requiredOption("--vault <path>","Vault root directory").option("--output <type>","Response format: text|json","text").action(n=>{let e=n.output??"text";ee.setFormat(e);try{let t=(0,Su.resolve)(n.vault);if(!(0,ha.existsSync)(t)||!(0,ha.statSync)(t).isDirectory())throw new le(t);let r=Cee(t);if(e==="json")console.log(JSON.stringify({vaultPath:t,violationCount:r.length,violations:r,clean:r.length===0},null,2));else if(r.length===0)console.log(`OK ${t}: 0 exocmd__Grounding_type literal-form violations`);else{console.error(`FAIL ${t}: ${r.length} exocmd__Grounding_type literal-form violation(s):`);for(let i of r)console.error(` ${i.path}:${i.line} \u2014 value: ${i.value}`);console.error("\nRFC 9d20c91f Phase 3 migrated all values to wikilink form `[[<uid>]]`. Re-run the Phase 3 migration script or hand-edit offending files.")}r.length>0&&(process.exitCode=1)}catch(t){ee.handle(t)}})}a(jN,"auditGroundingTypeLiteralFormCommand");var $y=require("fs"),NT=Y(require("path")),UN=require("path"),VN=Y(dt());var My=class n extends Zt{constructor(t){super(t);this.indexed=!1;this.uidToPath=new Map;this.allPaths=[];this.pathSet=new Set;this.assets=[]}static{a(this,"CachingNodeFsAdapter")}async buildIndex(){if(this.indexed)return;let t=await super.getMarkdownFiles();for(let r of t){this.allPaths.push(r),this.pathSet.add(r);let i={};try{i=await super.getFileMetadata(r)}catch{i={}}let s=i?.exo__Asset_uid,o=Array.isArray(s)?s:[s];for(let l of o){let c=n.normalizeUid(l);c.length>0&&!this.uidToPath.has(c)&&this.uidToPath.set(c,r)}this.assets.push({path:r,metadata:i})}this.indexed=!0}async indexedAssets(){return await this.buildIndex(),this.assets}async getMarkdownFiles(t){return t?super.getMarkdownFiles(t):(await this.buildIndex(),this.allPaths)}async findFileByUID(t){return await this.buildIndex(),this.uidToPath.get(n.normalizeUid(t))??null}static normalizeUid(t){return t==null?"":String(t).replace(/["'[\]]/g,"").trim()}async fileExists(t){await this.buildIndex();let r=t.replace(/\\/g,"/").replace(/^\.\//,"");return this.pathSet.has(r)?!0:super.fileExists(t)}};var jy=Y(require("path"));async function $N(n,e,t){let r=e.endsWith(".md")?e:`${e}.md`;if(e.includes("/")&&await n.fileExists(r))return r;let i=jy.default.dirname(t),s=i!=="."?`${i}/${r}`:r;if(await n.fileExists(s))return s;let l=await n.findFileByUID(e);return l||(await n.getMarkdownFiles()).find(f=>{let d=jy.default.basename(f,".md"),h=jy.default.basename(r,".md");return d===h})||null}a($N,"findReferencedFile");function DT(n){return n.replace(/\\/g,"/").replace(/^\.\//,"").replace(/\/$/,"")}a(DT,"normalizePath");var Pee=5;function LT(n,e,t){n[e].length<Pee&&n[e].push(t)}a(LT,"addExample");async function Oee(n){let e=new My(n),t=await e.indexedAssets(),r=[],i={"empty-isDefinedBy":0,"bang-prefix":0,unresolvable:0},s={"empty-isDefinedBy":[],"bang-prefix":[],unresolvable:[]},o=0;for(let{path:l,metadata:c}of t){if(l.split("/").includes("node_modules")||l.split("/").includes("09 Templates"))continue;let u=c.exo__Asset_isDefinedBy,f=(0,VN.extractAssetReference)(u);if(!f){i["empty-isDefinedBy"]++,LT(s,"empty-isDefinedBy",l);continue}if(f.startsWith("!")){i["bang-prefix"]++,LT(s,"bang-prefix",l);continue}let d=await $N(e,f,l);if(!d){i.unresolvable++,LT(s,"unresolvable",l);continue}o++;let h=DT(NT.default.dirname(d)),p=DT(NT.default.dirname(l));h!==p&&r.push({path:l,isDefinedBy:f,expectedFolder:h,actualFolder:p})}return{vaultPath:n,totalFiles:t.length,checked:o,violations:r,skips:i,skipExamples:s}}a(Oee,"scanVaultForCoLocation");function BN(){return new ne("co-location").description("Detect asset\u2013ontology co-location violations: any asset not in the folder of its exo__Asset_isDefinedBy ontology file (fail-open, skip-accounted)").requiredOption("--vault <path>","Vault root directory").option("--output <type>","Response format: text|json","text").action(async n=>{let e=n.output??"text";ee.setFormat(e);try{let t=(0,UN.resolve)(n.vault);if(!(0,$y.existsSync)(t)||!(0,$y.statSync)(t).isDirectory())throw new le(t);let r=await Oee(t),i=r.skips["empty-isDefinedBy"]+r.skips["bang-prefix"]+r.skips.unresolvable;if(e==="json")console.log(JSON.stringify({vaultPath:r.vaultPath,totalFiles:r.totalFiles,checked:r.checked,violationCount:r.violations.length,violations:r.violations,skips:r.skips,skipTotal:i,skipExamples:r.skipExamples,clean:r.violations.length===0},null,2));else{if(r.violations.length===0)console.log(`OK ${t}: 0 co-location violations (${r.checked}/${r.totalFiles} checked)`);else{console.error(`FAIL ${t}: ${r.violations.length} co-location violation(s) (${r.checked}/${r.totalFiles} checked):`);for(let s of r.violations)console.error(` ${s.path}
784
784
  isDefinedBy=${s.isDefinedBy} expected=${s.expectedFolder}/ actual=${s.actualFolder}/`)}console.error(`
785
- Skipped (fail-open, NOT verified): ${i} \u2014 empty-isDefinedBy=${r.skips["empty-isDefinedBy"]}, bang-prefix=${r.skips["bang-prefix"]}, unresolvable(cross-vault/missing)=${r.skips.unresolvable}`)}r.violations.length>0&&(process.exitCode=1)}catch(t){ee.handle(t)}})}a(BN,"auditCoLocationCommand");function GN(){let n=new ne("audit").description("Audit vault for regression patterns (RFC cutover detectors)");return n.addCommand(jN()),n.addCommand(BN()),n}a(GN,"auditCommand");var XN=require("fs"),QN=require("path");var Uy=Y(ea()),Vy=Y(require("path"));var WN=Y(dt()),Gy=Y(dt());var Fee=WN.SDK_FLOOR_ASSETSPACE_UIDS,kT="73bd00e4-ccc0-4f3f-b20d-c4388c4588fb",MT="3de846cd-1f0e-4f98-8613-b8587aa15174",Dee=5,By=class{static{a(this,"CliProfileResolver")}constructor(e){let t=e.alsoVaultPaths??[];this.vaultPaths=[e.vaultPath,...t].map(r=>Vy.default.resolve(r)),this.maxExtendsDepth=e.maxExtendsDepth??Dee,this.warn=e.warn??(()=>{})}async resolveFilter(e){if(e==null||e==="")return{outcome:"no-profile"};let t;try{t=await this.scanAllVaults()}catch(u){let f=`[CliProfileResolver] vault scan threw \u2014 ${String(u)}`;return this.warn(f),{outcome:"error",reason:f}}if(t.profiles.get(e)===void 0)return this.warn(`[CliProfileResolver] profileUid=${e} not found in any scanned vault \u2014 falling back to no-filter (full vault).`),{outcome:"missing-profile",profileUid:e};let i=new Set;try{this.walkProfileChain(e,t.profiles,i,new Set,0)}catch(u){let f=`[CliProfileResolver] profile chain walk threw \u2014 ${String(u)}`;return this.warn(f),{outcome:"error",reason:f}}let s=new Set(t.folderMap.values()),o=new Set,l=[];for(let u of i){if(s.has(u)){o.add(u);continue}l.push(u)}for(let u of Fee)o.add(u);if(!Array.from(o).some(u=>s.has(u))){let u=`[CliProfileResolver] profileUid=${e} produced effective set with zero AssetSpace folder overlap (${o.size} AS UIDs incl. floor; ${t.folderMap.size} folders known). Likely cause: profile declares AssetSpace UIDs not present as descriptors, or vault has no scanned AssetSpaces. Falling back to no-filter (full vault indexed).`;return this.warn(u),{outcome:"degraded",reason:u}}return{outcome:"engaged",result:{effective:o,folderMap:t.folderMap,declaredOntologies:i,untranslated:l}}}walkProfileChain(e,t,r,i,s){if(s>this.maxExtendsDepth)throw new Error(`Profile chain exceeds max depth ${this.maxExtendsDepth} at ${e} \u2014 possible cycle`);if(i.has(e))return;i.add(e);let o=t.get(e);if(o!==void 0){for(let l of o.includes)r.add(l);typeof o.extends=="string"&&o.extends.length>0&&this.walkProfileChain(o.extends,t,r,i,s+1)}}async scanAllVaults(){let e=new Map,t=new Map;for(let r of this.vaultPaths){if(!await Uy.default.pathExists(r)){this.warn(`[CliProfileResolver] vault path does not exist: ${r} \u2014 skipping.`);continue}let i=await this.walkVault(r);for(let s of i){let o=Id(s.frontmatter.exo__Instance_class);if(o.some(l=>l===kT)){let l=Nee(s.filePath,s.vaultRoot);l.length>0&&e.set(l,s.uid)}if(o.some(l=>l===MT)){let l={uid:s.uid,label:typeof s.frontmatter.exo__Asset_label=="string"?s.frontmatter.exo__Asset_label:void 0,includes:Id(s.frontmatter.exo__Profile_includes),extends:Id(s.frontmatter.exo__Profile_imports)[0]??null};t.set(s.uid,l)}}}return{folderMap:e,profiles:t}}async walkVault(e){let t=[],r=[e];for(;r.length>0;){let i=r.pop(),s;try{s=await Uy.default.readdir(i,{withFileTypes:!0})}catch{continue}for(let o of s){let l=Vy.default.join(i,o.name);if(o.isDirectory()){if(o.name.startsWith(".")||o.name==="node_modules"||o.name===".obsidian"||o.name===".exocortex")continue;r.push(l);continue}if(!o.isFile()||!o.name.endsWith(".md"))continue;let c=await this.tryReadFrontmatter(l);if(c===null)continue;let u=c.exo__Asset_uid;typeof u!="string"||u.length===0||t.push({uid:u,filePath:l,vaultRoot:e,frontmatter:c})}}return t}async tryReadFrontmatter(e){let t;try{t=await Uy.default.readFile(e,"utf-8")}catch{return null}if(!t.startsWith("---"))return null;let r=t.match(/^---\r?\n([\s\S]*?)\r?\n---/);if(r===null)return null;try{let i=Dt.load(r[1]);return i&&typeof i=="object"&&!Array.isArray(i)?i:null}catch{return null}}};function Id(n){if(n==null)return[];let e=Array.isArray(n)?n:[n],t=[];for(let r of e){if(typeof r!="string")continue;let i=Lee(r);i!==null&&t.push(i)}return t}a(Id,"parseWikilinkArray");function Lee(n){let e=n.trim().replace(/^\[\[/,"").replace(/\]\]$/,"").split("|")[0].trim();return e.length===0?null:e}a(Lee,"extractUidFromWikilink");function Nee(n,e){let t=Vy.default.relative(e,n).replace(/\\/g,"/");if(!t.startsWith("assetspaces/"))return"";let r=t.slice(12),i=r.indexOf("/");return i<0?"":`assetspaces/${r.slice(0,i)}`}a(Nee,"parentFolderRelative");var hl=require("node:fs"),wu=require("node:path");var Cs=Y(dt());var Ct=require("node:fs"),zN=require("node:fs/promises"),HN=require("node:os"),sn=require("node:path"),dl=Y(dt());var kee=/^https:\/\/github\.com\/([a-zA-Z0-9_-]+)\/([a-zA-Z0-9_.-]+?)(?:\.git)?$/,qN=50*1024*1024,Yi=class n{static{a(this,"BootstrapAssetSpaceService")}static{this.PAT_REGEX=/(?:gh[pousr]_[A-Za-z0-9_]{36,}|github_pat_[A-Za-z0-9_]{22,}_[A-Za-z0-9_]{59,})/g}constructor(e={}){this.fetchImpl=e.fetchImpl??globalThis.fetch,this.token=e.token??""}redact(e){return(typeof e=="string"?e:String(e)).replace(n.PAT_REGEX,"***REDACTED***")}static parseGitHubURL(e){let t=e.match(kee);if(t===null)throw new Error(`parseGitHubURL: invalid URL shape \u2014 expected https://github.com/<owner>/<repo>, got: ${e}`);return{owner:t[1],repo:t[2]}}static deriveFolderName(e){let{repo:t}=n.parseGitHubURL(e);return t.startsWith("exoas-")?t.slice(6):t}async pullAssetSpace(e,t,r){let{owner:i,repo:s}=n.parseGitHubURL(e);if((0,Ct.existsSync)(r)&&(0,Ct.readdirSync)(r).length>0)throw new Error(`pullAssetSpace: target ${r} exists \u0438 not empty \u2014 refusing \u043A overwrite`);return(0,dl.mountAssetSpaceFiles)({http:this.httpPort(),fs:this.fsPort(),owner:i,repo:s,ref:t,targetPath:r})}httpPort(){let e=this.fetchImpl,t=this.token,r=a(i=>this.redact(i),"redact");return{async fetchTarball(i,s,o){let l=`https://api.github.com/repos/${i}/${s}/tarball/${o}`,c={signal:AbortSignal.timeout(6e4)};t.length>0&&(c.headers={Authorization:`Bearer ${t}`,"User-Agent":"exocortex-cli","X-GitHub-Api-Version":"2022-11-28"});let u;try{u=await e(l,c)}catch(d){throw new Error(r(`pullAssetSpace: fetch error for ${l}: ${d instanceof Error?d.message:String(d)}`))}if(!u.ok){if(u.status===403){let d=u.headers?.get?.("x-ratelimit-remaining"),h=u.headers?.get?.("x-ratelimit-reset");if(d==="0"||h!=null){let p=h!=null?new Date(Number(h)*1e3).toISOString():"unknown";throw new Error(`pullAssetSpace: GitHub anonymous API rate-limit exceeded (60 req/hour). Reset at ${p}. Wait or use authenticated CLI.`)}}if(u.status===404){let d=t.length>0?"repo not found, or the provided token lacks access to it":"if this is a private repo, pass --token <pat> (or set GITHUB_TOKEN / GH_TOKEN)";throw new Error(r(`pullAssetSpace: fetch failed (404 Not Found) for ${l} \u2014 ${d}`))}throw new Error(r(`pullAssetSpace: fetch failed (${u.status} ${u.statusText}) for ${l}`))}let f=await u.arrayBuffer();if(f.byteLength>qN)throw new Error(`pullAssetSpace: tarball too large (${f.byteLength} bytes > ${qN})`);return new Uint8Array(f)}}}fsPort(){return{async exists(e){return(0,Ct.existsSync)(e)},async read(e){return(0,Ct.readFileSync)(e,"utf8")},async write(e,t){(0,Ct.writeFileSync)(e,t,{encoding:"utf8"})},async removeDir(e){(0,Ct.rmSync)(e,{recursive:!0,force:!0})},async materialize(e,t){let r=await(0,zN.mkdtemp)((0,sn.join)((0,HN.tmpdir)(),`exo-bootstrap-${(0,sn.basename)(e)}-`)),i=0;try{for(let s of t){let o=s.relPath;if(o.split("/").some(c=>c===".."))throw new Error(`pullAssetSpace: path traversal detected for entry "${o}"`);let l=(0,sn.resolve)(r,o);if(l!==r&&!l.startsWith(r+sn.sep))throw new Error(`pullAssetSpace: zip-slip detected for entry "${o}"`);(0,Ct.mkdirSync)((0,sn.dirname)(l),{recursive:!0}),(0,Ct.writeFileSync)(l,s.content),i++}(0,Ct.mkdirSync)((0,sn.dirname)(e),{recursive:!0});try{(0,Ct.renameSync)(r,e)}catch(s){if(s.code==="EXDEV"){let{cpSync:o}=await import("node:fs");o(r,e,{recursive:!0}),(0,Ct.rmSync)(r,{recursive:!0,force:!0})}else throw s}}catch(s){throw(0,Ct.rmSync)(r,{recursive:!0,force:!0}),s}return i}}}ensureGitmodulesEntry(e,t,r){let i=(0,sn.join)(e,".gitmodules"),s="";try{s=(0,Ct.readFileSync)(i,"utf8")}catch(c){if(c.code!=="ENOENT")throw c}let{content:o,added:l}=(0,dl.appendGitmodulesEntry)(s,t,r);return l?((0,Ct.appendFileSync)(i,o.slice(s.length),{encoding:"utf8"}),{added:!0}):{added:!1}}removeGitmodulesEntry(e,t){let r=(0,sn.join)(e,".gitmodules"),i;try{i=(0,Ct.readFileSync)(r,"utf8")}catch(o){if(o.code==="ENOENT")return{removed:!1};throw o}let s=(0,dl.stripGitmodulesEntry)(i,t);return s===i?{removed:!1}:((0,Ct.writeFileSync)(r,s,{encoding:"utf8"}),{removed:!0})}static stripGitmodulesEntry(e,t){return(0,dl.stripGitmodulesEntry)(e,t)}unmountAssetSpace(e,t){let r=t.split("/");if(t.length===0||!t.startsWith("assetspaces/")||r.some(o=>o.length===0||o==="."||o===".."))throw new Error(`unmountAssetSpace: refusing unsafe submodulePath "${t}"`);let i=(0,sn.resolve)(e),s=(0,sn.resolve)(i,t);if(s===i||!s.startsWith(i+sn.sep))throw new Error(`unmountAssetSpace: target "${s}" escapes vault root "${i}"`);this.removeGitmodulesEntry(e,t),(0,Ct.existsSync)(s)&&(0,Ct.rmSync)(s,{recursive:!0,force:!0})}};function Mee(n){let e=(0,Cs.derivePath)(n);return e===null?n:`https://github.com/${e.slice(12)}`}a(Mee,"toHttpsGitHubUrl");var jee=new Set(["node_modules",".obsidian",".exocortex",".git"]),Wy=class{static{a(this,"CliHardSwitchService")}constructor(e){this.vaultPath=e.vaultPath,this.mount=e.mount??new Yi,this.ref=e.ref??"main"}scanVault(){let e=[],t=new Map,r=new Set,i=[this.vaultPath];for(;i.length>0;){let s=i.pop(),o;try{o=(0,hl.readdirSync)(s,{withFileTypes:!0})}catch{continue}for(let l of o){let c=(0,wu.join)(s,l.name);if(l.isDirectory()){if(l.name.startsWith(".")||jee.has(l.name))continue;i.push(c);continue}if(!l.isFile()||!l.name.endsWith(".md"))continue;let u=this.readFrontmatter(c);if(u===null)continue;let f=u.exo__Asset_uid;if(typeof f!="string"||f.length===0)continue;let d=Id(u.exo__Instance_class);if(d.includes(kT)){if(r.has(f))continue;let p=(typeof u.exo__AssetSpace_source=="string"?u.exo__AssetSpace_source:"")||(typeof u.exo__AssetSpace_git=="string"?u.exo__AssetSpace_git:"");if(p.length===0)continue;let g=(0,Cs.derivePath)(p);if(g===null)continue;let E=(typeof u.exo__AssetSpace_namespace=="string"?u.exo__AssetSpace_namespace:"")||Uee(g)||f.slice(0,8);r.add(f),e.push({uid:f,git:p,folderName:g,label:E})}if(d.includes(MT)){let h=u.exo__Asset_label;typeof h=="string"&&h.length>0&&t.set(f,h)}}}return{infos:e,profileLabels:t}}assertTsFloor(e){(0,Cs.assertTsFloor)(e,Cs.SDK_FLOOR_ASSETSPACE_UIDS)}buildDiff(e){let{targetProfileUid:t,targetProfileLabel:r,sourceProfileUid:i,sourceProfileLabel:s,result:o,infos:l}=e,c=new Map;for(let S of l)c.set(S.uid,S);let u=new Set(c.keys()),f=new Set;for(let S of o.declaredOntologies)u.has(S)&&f.add(S);this.assertTsFloor(f);let d=new Set([...o.effective,...f]),h=new Set;for(let S of l)(0,hl.existsSync)((0,wu.join)(this.vaultPath,S.folderName))&&h.add(S.uid);let p=[];for(let S of l)h.has(S.uid)&&(d.has(S.uid)||p.push({asUid:S.uid,folderName:S.folderName,label:S.label,files:this.enumerateFilesUnder(S.folderName)}));let g=[];for(let S of d){if(h.has(S))continue;let v=c.get(S);v!==void 0&&g.push({asUid:v.uid,folderName:v.folderName,httpsUrl:Mee(v.git),label:v.label})}let _=new Map;for(let S of p)_.set(S.asUid,S.files);let E={targetProfileUid:t,targetProfileLabel:r,sourceProfileUid:i,sourceProfileLabel:s,filesToDestroy:_,assetSpacesBeingTornDown:p.map(S=>({asUid:S.asUid,asLabel:S.label,fileCount:S.files.length})),assetSpacesBeingMaterialized:g.map(S=>({asUid:S.asUid,asLabel:S.label}))};return{toDestroy:p,toMaterialize:g,plan:E}}async execute(e){let t=[],r=[];for(let i of e.toDestroy)this.mount.unmountAssetSpace(this.vaultPath,i.folderName),t.push(i.asUid);for(let i of e.toMaterialize){let s=(0,wu.join)(this.vaultPath,i.folderName);await this.mount.pullAssetSpace(i.httpsUrl,this.ref,s),this.mount.ensureGitmodulesEntry(this.vaultPath,i.folderName,i.httpsUrl),r.push(i.asUid)}return{destroyed:t,materialized:r}}enumerateFilesUnder(e){let t=[],i=[(0,wu.join)(this.vaultPath,e)];for(;i.length>0;){let s=i.pop(),o;try{o=(0,hl.readdirSync)(s,{withFileTypes:!0})}catch{continue}for(let l of o){let c=(0,wu.join)(s,l.name);if(l.isDirectory()){if(l.name.startsWith("."))continue;i.push(c);continue}l.isFile()&&t.push($ee(c,this.vaultPath))}}return t}readFrontmatter(e){let t;try{t=(0,hl.readFileSync)(e,"utf-8")}catch{return null}if(!t.startsWith("---"))return null;let r=t.match(/^---\r?\n([\s\S]*?)\r?\n---/);if(r===null)return null;try{let i=Dt.load(r[1]);return i&&typeof i=="object"&&!Array.isArray(i)?i:null}catch{return null}}};function $ee(n,e){let t=e.endsWith("/")?e:e+"/";return(n.startsWith(t)?n.slice(t.length):n).split("\\").join("/")}a($ee,"relativeVaultPath");function Uee(n){let e=n.split("/").filter(t=>t.length>0);return e.length>0?e[e.length-1]:""}a(Uee,"lastSegment");var Vee=a(n=>{process.stderr.write(`${n}
786
- `)},"DEFAULT_LOG"),qy=class{static{a(this,"HeadlessConfirmGate")}constructor(e){this.yes=e.yes,this.verbose=e.verbose??!1,this.log=e.log??Vee}async confirmHardSwitch(e){if(this.verbose){let t=Array.from(e.filesToDestroy.values()).reduce((r,i)=>r+i.length,0);this.log(`[hard-switch] Target: ${e.targetProfileLabel} (${e.targetProfileUid})`),this.log(`[hard-switch] Source: ${e.sourceProfileLabel}`),this.log(`[hard-switch] ${t} files to remove, ${e.assetSpacesBeingTornDown.length} AS to tear down, ${e.assetSpacesBeingMaterialized.length} AS to materialize`)}return this.yes?!0:(this.log("[hard-switch] Refused: --yes flag required for headless mode (Decision #2 safety)."),!1)}};async function Bee(n,e,t={}){let r=[],i=[],s=t.out??(j=>process.stdout.write(`${j}
785
+ Skipped (fail-open, NOT verified): ${i} \u2014 empty-isDefinedBy=${r.skips["empty-isDefinedBy"]}, bang-prefix=${r.skips["bang-prefix"]}, unresolvable(cross-vault/missing)=${r.skips.unresolvable}`)}r.violations.length>0&&(process.exitCode=1)}catch(t){ee.handle(t)}})}a(BN,"auditCoLocationCommand");function GN(){let n=new ne("audit").description("Audit vault for regression patterns (RFC cutover detectors)");return n.addCommand(jN()),n.addCommand(BN()),n}a(GN,"auditCommand");var XN=require("fs"),QN=require("path");var Uy=Y(ea()),Vy=Y(require("path"));var WN=Y(dt()),Gy=Y(dt());var Fee=WN.SDK_FLOOR_ASSETSPACE_UIDS,kT="73bd00e4-ccc0-4f3f-b20d-c4388c4588fb",MT="3de846cd-1f0e-4f98-8613-b8587aa15174",Dee=5,By=class{static{a(this,"CliProfileResolver")}constructor(e){let t=e.alsoVaultPaths??[];this.vaultPaths=[e.vaultPath,...t].map(r=>Vy.default.resolve(r)),this.maxExtendsDepth=e.maxExtendsDepth??Dee,this.warn=e.warn??(()=>{})}async resolveFilter(e){if(e==null||e==="")return{outcome:"no-profile"};let t;try{t=await this.scanAllVaults()}catch(u){let f=`[CliProfileResolver] vault scan threw \u2014 ${String(u)}`;return this.warn(f),{outcome:"error",reason:f}}if(t.profiles.get(e)===void 0)return this.warn(`[CliProfileResolver] profileUid=${e} not found in any scanned vault \u2014 falling back to no-filter (full vault).`),{outcome:"missing-profile",profileUid:e};let i=new Set;try{this.walkProfileChain(e,t.profiles,i,new Set,0)}catch(u){let f=`[CliProfileResolver] profile chain walk threw \u2014 ${String(u)}`;return this.warn(f),{outcome:"error",reason:f}}let s=new Set(t.folderMap.values()),o=new Set,l=[];for(let u of i){if(s.has(u)){o.add(u);continue}l.push(u)}for(let u of Fee)o.add(u);if(!Array.from(o).some(u=>s.has(u))){let u=`[CliProfileResolver] profileUid=${e} produced effective set with zero AssetSpace folder overlap (${o.size} AS UIDs incl. floor; ${t.folderMap.size} folders known). Likely cause: profile declares AssetSpace UIDs not present as descriptors, or vault has no scanned AssetSpaces. Falling back to no-filter (full vault indexed).`;return this.warn(u),{outcome:"degraded",reason:u}}return{outcome:"engaged",result:{effective:o,folderMap:t.folderMap,declaredOntologies:i,untranslated:l}}}walkProfileChain(e,t,r,i,s){if(s>this.maxExtendsDepth)throw new Error(`Profile chain exceeds max depth ${this.maxExtendsDepth} at ${e} \u2014 possible cycle`);if(i.has(e))return;i.add(e);let o=t.get(e);if(o!==void 0){for(let l of o.includes)r.add(l);typeof o.extends=="string"&&o.extends.length>0&&this.walkProfileChain(o.extends,t,r,i,s+1)}}async scanAllVaults(){let e=new Map,t=new Map;for(let r of this.vaultPaths){if(!await Uy.default.pathExists(r)){this.warn(`[CliProfileResolver] vault path does not exist: ${r} \u2014 skipping.`);continue}let i=await this.walkVault(r);for(let s of i){let o=Id(s.frontmatter.exo__Instance_class);if(o.some(l=>l===kT)){let l=Nee(s.filePath,s.vaultRoot);l.length>0&&e.set(l,s.uid)}if(o.some(l=>l===MT)){let l={uid:s.uid,label:typeof s.frontmatter.exo__Asset_label=="string"?s.frontmatter.exo__Asset_label:void 0,includes:Id(s.frontmatter.exo__Profile_includes),extends:Id(s.frontmatter.exo__Profile_imports)[0]??null};t.set(s.uid,l)}}}return{folderMap:e,profiles:t}}async walkVault(e){let t=[],r=[e];for(;r.length>0;){let i=r.pop(),s;try{s=await Uy.default.readdir(i,{withFileTypes:!0})}catch{continue}for(let o of s){let l=Vy.default.join(i,o.name);if(o.isDirectory()){if(o.name.startsWith(".")||o.name==="node_modules"||o.name===".obsidian"||o.name===".exocortex")continue;r.push(l);continue}if(!o.isFile()||!o.name.endsWith(".md"))continue;let c=await this.tryReadFrontmatter(l);if(c===null)continue;let u=c.exo__Asset_uid;typeof u!="string"||u.length===0||t.push({uid:u,filePath:l,vaultRoot:e,frontmatter:c})}}return t}async tryReadFrontmatter(e){let t;try{t=await Uy.default.readFile(e,"utf-8")}catch{return null}if(!t.startsWith("---"))return null;let r=t.match(/^---\r?\n([\s\S]*?)\r?\n---/);if(r===null)return null;try{let i=Dt.load(r[1]);return i&&typeof i=="object"&&!Array.isArray(i)?i:null}catch{return null}}};function Id(n){if(n==null)return[];let e=Array.isArray(n)?n:[n],t=[];for(let r of e){if(typeof r!="string")continue;let i=Lee(r);i!==null&&t.push(i)}return t}a(Id,"parseWikilinkArray");function Lee(n){let e=n.trim().replace(/^\[\[/,"").replace(/\]\]$/,"").split("|")[0].trim();return e.length===0?null:e}a(Lee,"extractUidFromWikilink");function Nee(n,e){let t=Vy.default.relative(e,n).replace(/\\/g,"/");if(!t.startsWith("assetspaces/"))return"";let r=t.slice(12),i=r.indexOf("/");return i<0?"":`assetspaces/${r.slice(0,i)}`}a(Nee,"parentFolderRelative");var hl=require("node:fs"),wu=require("node:path");var Cs=Y(dt());var Ct=require("node:fs"),zN=require("node:fs/promises"),HN=require("node:os"),sn=require("node:path"),dl=Y(dt());var kee=/^https:\/\/github\.com\/([a-zA-Z0-9_-]+)\/([a-zA-Z0-9_.-]+?)(?:\.git)?$/,qN=50*1024*1024,Yi=class n{static{a(this,"BootstrapAssetSpaceService")}static{this.PAT_REGEX=/(?:gh[pousr]_[A-Za-z0-9_]{36,}|github_pat_[A-Za-z0-9_]{22,}_[A-Za-z0-9_]{59,})/g}constructor(e={}){this.fetchImpl=e.fetchImpl??globalThis.fetch,this.token=e.token??""}redact(e){return(typeof e=="string"?e:String(e)).replace(n.PAT_REGEX,"***REDACTED***")}static parseGitHubURL(e){let t=e.match(kee);if(t===null)throw new Error(`parseGitHubURL: invalid URL shape \u2014 expected https://github.com/<owner>/<repo>, got: ${e}`);return{owner:t[1],repo:t[2]}}static deriveFolderName(e){let{repo:t}=n.parseGitHubURL(e);return t.startsWith("exoas-")?t.slice(6):t}async pullAssetSpace(e,t,r){let{owner:i,repo:s}=n.parseGitHubURL(e);if((0,Ct.existsSync)(r)&&(0,Ct.readdirSync)(r).length>0)throw new Error(`pullAssetSpace: target ${r} exists \u0438 not empty \u2014 refusing \u043A overwrite`);return(0,dl.mountAssetSpaceFiles)({http:this.httpPort(),fs:this.fsPort(),owner:i,repo:s,ref:t,targetPath:r})}httpPort(){let e=this.fetchImpl,t=this.token,r=a(i=>this.redact(i),"redact");return{async fetchTarball(i,s,o){let l=`https://api.github.com/repos/${i}/${s}/tarball/${o}`,c={signal:AbortSignal.timeout(6e4)};t.length>0&&(c.headers={Authorization:`Bearer ${t}`,"User-Agent":"exocortex-cli","X-GitHub-Api-Version":"2022-11-28"});let u;try{u=await e(l,c)}catch(d){throw new Error(r(`pullAssetSpace: fetch error for ${l}: ${d instanceof Error?d.message:String(d)}`))}if(!u.ok){if(u.status===403){let d=u.headers?.get?.("x-ratelimit-remaining"),h=u.headers?.get?.("x-ratelimit-reset");if(d==="0"||h!=null){let p=h!=null?new Date(Number(h)*1e3).toISOString():"unknown";throw new Error(`pullAssetSpace: GitHub anonymous API rate-limit exceeded (60 req/hour). Reset at ${p}. Wait or use authenticated CLI.`)}}if(u.status===404){let d=t.length>0?"repo not found, or the provided token lacks access to it":"if this is a private repo, pass --token <pat> (or set GITHUB_TOKEN / GH_TOKEN)";throw new Error(r(`pullAssetSpace: fetch failed (404 Not Found) for ${l} \u2014 ${d}`))}throw new Error(r(`pullAssetSpace: fetch failed (${u.status} ${u.statusText}) for ${l}`))}let f=await u.arrayBuffer();if(f.byteLength>qN)throw new Error(`pullAssetSpace: tarball too large (${f.byteLength} bytes > ${qN})`);return new Uint8Array(f)}}}fsPort(){return{async exists(e){return(0,Ct.existsSync)(e)},async read(e){return(0,Ct.readFileSync)(e,"utf8")},async write(e,t){(0,Ct.writeFileSync)(e,t,{encoding:"utf8"})},async removeDir(e){(0,Ct.rmSync)(e,{recursive:!0,force:!0})},async materialize(e,t){let r=await(0,zN.mkdtemp)((0,sn.join)((0,HN.tmpdir)(),`exo-bootstrap-${(0,sn.basename)(e)}-`)),i=0;try{for(let s of t){let o=s.relPath;if(o.split("/").some(c=>c===".."))throw new Error(`pullAssetSpace: path traversal detected for entry "${o}"`);let l=(0,sn.resolve)(r,o);if(l!==r&&!l.startsWith(r+sn.sep))throw new Error(`pullAssetSpace: zip-slip detected for entry "${o}"`);(0,Ct.mkdirSync)((0,sn.dirname)(l),{recursive:!0}),(0,Ct.writeFileSync)(l,s.content),i++}(0,Ct.mkdirSync)((0,sn.dirname)(e),{recursive:!0});try{(0,Ct.renameSync)(r,e)}catch(s){if(s.code==="EXDEV"){let{cpSync:o}=await import("node:fs");o(r,e,{recursive:!0}),(0,Ct.rmSync)(r,{recursive:!0,force:!0})}else throw s}}catch(s){throw(0,Ct.rmSync)(r,{recursive:!0,force:!0}),s}return i}}}ensureGitmodulesEntry(e,t,r){let i=(0,sn.join)(e,".gitmodules"),s="";try{s=(0,Ct.readFileSync)(i,"utf8")}catch(c){if(c.code!=="ENOENT")throw c}let{content:o,added:l}=(0,dl.appendGitmodulesEntry)(s,t,r);return l?((0,Ct.appendFileSync)(i,o.slice(s.length),{encoding:"utf8"}),{added:!0}):{added:!1}}removeGitmodulesEntry(e,t){let r=(0,sn.join)(e,".gitmodules"),i;try{i=(0,Ct.readFileSync)(r,"utf8")}catch(o){if(o.code==="ENOENT")return{removed:!1};throw o}let s=(0,dl.stripGitmodulesEntry)(i,t);return s===i?{removed:!1}:((0,Ct.writeFileSync)(r,s,{encoding:"utf8"}),{removed:!0})}static stripGitmodulesEntry(e,t){return(0,dl.stripGitmodulesEntry)(e,t)}unmountAssetSpace(e,t){let r=t.split("/");if(t.length===0||!t.startsWith("assetspaces/")||r.some(o=>o.length===0||o==="."||o===".."))throw new Error(`unmountAssetSpace: refusing unsafe submodulePath "${t}"`);let i=(0,sn.resolve)(e),s=(0,sn.resolve)(i,t);if(s===i||!s.startsWith(i+sn.sep))throw new Error(`unmountAssetSpace: target "${s}" escapes vault root "${i}"`);this.removeGitmodulesEntry(e,t),(0,Ct.existsSync)(s)&&(0,Ct.rmSync)(s,{recursive:!0,force:!0})}};function Mee(n){let e=(0,Cs.derivePath)(n);return e===null?n:`https://github.com/${e.slice(12)}`}a(Mee,"toHttpsGitHubUrl");var jee=new Set(["node_modules",".obsidian",".exocortex",".git"]),Wy=class{static{a(this,"CliApplyProfileService")}constructor(e){this.vaultPath=e.vaultPath,this.mount=e.mount??new Yi,this.ref=e.ref??"main"}scanVault(){let e=[],t=new Map,r=new Set,i=[this.vaultPath];for(;i.length>0;){let s=i.pop(),o;try{o=(0,hl.readdirSync)(s,{withFileTypes:!0})}catch{continue}for(let l of o){let c=(0,wu.join)(s,l.name);if(l.isDirectory()){if(l.name.startsWith(".")||jee.has(l.name))continue;i.push(c);continue}if(!l.isFile()||!l.name.endsWith(".md"))continue;let u=this.readFrontmatter(c);if(u===null)continue;let f=u.exo__Asset_uid;if(typeof f!="string"||f.length===0)continue;let d=Id(u.exo__Instance_class);if(d.includes(kT)){if(r.has(f))continue;let p=(typeof u.exo__AssetSpace_source=="string"?u.exo__AssetSpace_source:"")||(typeof u.exo__AssetSpace_git=="string"?u.exo__AssetSpace_git:"");if(p.length===0)continue;let g=(0,Cs.derivePath)(p);if(g===null)continue;let E=(typeof u.exo__AssetSpace_namespace=="string"?u.exo__AssetSpace_namespace:"")||Uee(g)||f.slice(0,8);r.add(f),e.push({uid:f,git:p,folderName:g,label:E})}if(d.includes(MT)){let h=u.exo__Asset_label;typeof h=="string"&&h.length>0&&t.set(f,h)}}}return{infos:e,profileLabels:t}}assertTsFloor(e){(0,Cs.assertTsFloor)(e,Cs.SDK_FLOOR_ASSETSPACE_UIDS)}buildDiff(e){let{targetProfileUid:t,targetProfileLabel:r,sourceProfileUid:i,sourceProfileLabel:s,result:o,infos:l}=e,c=new Map;for(let S of l)c.set(S.uid,S);let u=new Set(c.keys()),f=new Set;for(let S of o.declaredOntologies)u.has(S)&&f.add(S);this.assertTsFloor(f);let d=new Set([...o.effective,...f]),h=new Set;for(let S of l)(0,hl.existsSync)((0,wu.join)(this.vaultPath,S.folderName))&&h.add(S.uid);let p=[];for(let S of l)h.has(S.uid)&&(d.has(S.uid)||p.push({asUid:S.uid,folderName:S.folderName,label:S.label,files:this.enumerateFilesUnder(S.folderName)}));let g=[];for(let S of d){if(h.has(S))continue;let v=c.get(S);v!==void 0&&g.push({asUid:v.uid,folderName:v.folderName,httpsUrl:Mee(v.git),label:v.label})}let _=new Map;for(let S of p)_.set(S.asUid,S.files);let E={targetProfileUid:t,targetProfileLabel:r,sourceProfileUid:i,sourceProfileLabel:s,filesToDestroy:_,assetSpacesBeingTornDown:p.map(S=>({asUid:S.asUid,asLabel:S.label,fileCount:S.files.length})),assetSpacesBeingMaterialized:g.map(S=>({asUid:S.asUid,asLabel:S.label}))};return{toDestroy:p,toMaterialize:g,plan:E}}async execute(e){let t=[],r=[];for(let i of e.toDestroy)this.mount.unmountAssetSpace(this.vaultPath,i.folderName),t.push(i.asUid);for(let i of e.toMaterialize){let s=(0,wu.join)(this.vaultPath,i.folderName);await this.mount.pullAssetSpace(i.httpsUrl,this.ref,s),this.mount.ensureGitmodulesEntry(this.vaultPath,i.folderName,i.httpsUrl),r.push(i.asUid)}return{destroyed:t,materialized:r}}enumerateFilesUnder(e){let t=[],i=[(0,wu.join)(this.vaultPath,e)];for(;i.length>0;){let s=i.pop(),o;try{o=(0,hl.readdirSync)(s,{withFileTypes:!0})}catch{continue}for(let l of o){let c=(0,wu.join)(s,l.name);if(l.isDirectory()){if(l.name.startsWith("."))continue;i.push(c);continue}l.isFile()&&t.push($ee(c,this.vaultPath))}}return t}readFrontmatter(e){let t;try{t=(0,hl.readFileSync)(e,"utf-8")}catch{return null}if(!t.startsWith("---"))return null;let r=t.match(/^---\r?\n([\s\S]*?)\r?\n---/);if(r===null)return null;try{let i=Dt.load(r[1]);return i&&typeof i=="object"&&!Array.isArray(i)?i:null}catch{return null}}};function $ee(n,e){let t=e.endsWith("/")?e:e+"/";return(n.startsWith(t)?n.slice(t.length):n).split("\\").join("/")}a($ee,"relativeVaultPath");function Uee(n){let e=n.split("/").filter(t=>t.length>0);return e.length>0?e[e.length-1]:""}a(Uee,"lastSegment");var Vee=a(n=>{process.stderr.write(`${n}
786
+ `)},"DEFAULT_LOG"),qy=class{static{a(this,"HeadlessConfirmGate")}constructor(e){this.yes=e.yes,this.verbose=e.verbose??!1,this.log=e.log??Vee}async confirmHardSwitch(e){if(this.verbose){let t=Array.from(e.filesToDestroy.values()).reduce((r,i)=>r+i.length,0);this.log(`[apply-profile] Target: ${e.targetProfileLabel} (${e.targetProfileUid})`),this.log(`[apply-profile] Source: ${e.sourceProfileLabel}`),this.log(`[apply-profile] ${t} files to remove, ${e.assetSpacesBeingTornDown.length} AS to tear down, ${e.assetSpacesBeingMaterialized.length} AS to materialize`)}return this.yes?!0:(this.log("[apply-profile] Refused: --yes flag required for headless mode (Decision #2 safety)."),!1)}};async function Bee(n,e,t={}){let r=[],i=[],s=t.out??(j=>process.stdout.write(`${j}
787
787
  `)),o=t.err??(j=>process.stderr.write(`${j}
788
- `)),l=a(j=>{r.push(j),s(j)},"out"),c=a(j=>{i.push(j),o(j)},"err");if(!e.vault)throw new Le("--vault is required");let u=(0,QN.resolve)(e.vault);if(!(0,XN.existsSync)(u))throw new le(u);if(!n||n.length===0)throw new Le("profile-uid argument is required","exocortex hard-switch <profile-uid> --vault <path>");let d=await(t.resolverFactory?.(e)??new By({vaultPath:u,warn:a(j=>c(j),"warn")})).resolveFilter(n);if(d.outcome==="missing-profile")throw new Le(`Profile not found: ${n}`,"Run `exocortex find --class exo__Profile` to list available profiles");if(d.outcome==="error")return c(`[hard-switch] Resolver error: ${d.reason}`),{exitCode:5,stdout:r,stderr:i};if(d.outcome==="degraded")return c(`[hard-switch] Refused: profile resolution degraded \u2014 ${d.reason}. Hard switch aborted to prevent vault corruption.`),{exitCode:5,stdout:r,stderr:i};if(d.outcome!=="engaged")return c(`[hard-switch] Unexpected resolver outcome: ${d.outcome}`),{exitCode:5,stdout:r,stderr:i};let h=d.result,p=e.token||process.env.GITHUB_TOKEN||process.env.GH_TOKEN||void 0,g=t.hardSwitchServiceFactory?.(e,u)??new Wy({vaultPath:u,ref:e.ref??"main",mount:new Yi({token:p})}),{infos:_,profileLabels:E}=g.scanVault(),S=E.get(n)??n,v;try{v=g.buildDiff({targetProfileUid:n,targetProfileLabel:S,sourceProfileUid:null,sourceProfileLabel:"<unknown>",result:h,infos:_})}catch(j){if(j instanceof Cs.TsFloorViolationError)return c(`[hard-switch] Refused: ${j.message}`),{exitCode:5,stdout:r,stderr:i};throw j}if(!await(t.confirmGate??new qy({yes:e.yes??!1,verbose:e.verbose??!1,log:a(j=>c(j),"log")})).confirmHardSwitch(v.plan))return{exitCode:0,stdout:r,stderr:i};if(v.toDestroy.length===0&&v.toMaterialize.length===0)return l(`[hard-switch] Already in target mount-state for ${S} \u2014 no-op.`),{exitCode:0,stdout:r,stderr:i};let L;try{L=await g.execute(v)}catch(j){return c(`[hard-switch] Execution failed: ${j instanceof Error?j.message:String(j)}`),{exitCode:5,stdout:r,stderr:i}}return l(`[hard-switch] Switched to ${S}: ${L.destroyed.length} AssetSpace(s) torn down, ${L.materialized.length} materialized.`),{exitCode:0,stdout:r,stderr:i}}a(Bee,"runHardSwitch");function YN(){return new ne("hard-switch").description("Hard switch to specified Profile (mount-state filesystem mutation). Requires --yes for headless mode.").argument("<profile-uid>","Target Profile UID").requiredOption("--vault <path>","Path to Obsidian vault").option("--yes","Confirm hard switch (headless mode safety override per RFC 22b50a17 Decision #2)",!1).option("--verbose","Print plan summary to stderr before deciding",!1).option("--ref <branch>","Git ref to pull when materialising AssetSpaces","main").option("--token <pat>","GitHub PAT for private-repo materialisation (or env GITHUB_TOKEN / GH_TOKEN)").action(async(e,t)=>{try{let r=await Bee(e,t);process.exit(r.exitCode)}catch(r){ee.handle(r)}})}a(YN,"hardSwitchCommand");var pl=require("node:path"),ml=require("node:fs");function KN(){return new ne("bootstrap").description("Bootstrap a vault with the SDK floor AssetSpace (exo). Pulls tarballs from public GitHub repos, extracts \u043A assetspaces/, writes .gitmodules. Only --exo is required; --exocmd (the optional UI-command library) is opt-in. Example URLs: https://github.com/kitelev/exoas-exo, https://github.com/kitelev/exoas-exocmd.").requiredOption("--vault <path>","Path \u043A target vault").requiredOption("--exo <url>","Public GitHub URL \u0434\u043B\u044F exo TBox AssetSpace (e.g. https://github.com/kitelev/exoas-exo)").option("--exocmd <url>","Optional: Public GitHub URL \u0434\u043B\u044F exocmd UI-command AssetSpace (e.g. https://github.com/kitelev/exoas-exocmd). Opt-in \u2014 omit for a bare SDK/headless vault; add later via `assetspace add`.").option("--ref <branch>","Branch ref \u043A pull from","main").option("--token <pat>","GitHub PAT for private repos (or env GITHUB_TOKEN / GH_TOKEN). Optional \u2014 anonymous for public repos.").option("--json","Emit result as JSON",!1).action(async n=>{try{if(!n.vault)throw new Le("--vault is required");let e=(0,pl.resolve)(n.vault);(0,ml.mkdirSync)(e,{recursive:!0});let t=(0,pl.join)(e,".gitmodules"),r=(0,pl.join)(e,"assetspaces");if((0,ml.existsSync)(t))throw new Le(`Vault ${e} already has .gitmodules \u2014 refusing \u043A re-bootstrap. Use \`assetspace add\` \u0434\u043B\u044F individual AS.`);if((0,ml.existsSync)(r)&&(0,ml.readdirSync)(r).length>0)throw new Le(`Vault ${e}/assetspaces/ already has content \u2014 refusing \u043A re-bootstrap.`);let i=n.token||process.env.GITHUB_TOKEN||process.env.GH_TOKEN||void 0,s=new Yi({token:i}),o=n.ref??"main",l=[],c="exo",u=(0,pl.join)(e,"assetspaces",c);process.stderr.write(`[bootstrap] Pulling ${n.exo}@${o} \u2192 assetspaces/${c}/...
788
+ `)),l=a(j=>{r.push(j),s(j)},"out"),c=a(j=>{i.push(j),o(j)},"err");if(!e.vault)throw new Le("--vault is required");let u=(0,QN.resolve)(e.vault);if(!(0,XN.existsSync)(u))throw new le(u);if(!n||n.length===0)throw new Le("profile-uid argument is required","exocortex apply-profile <profile-uid> --vault <path>");let d=await(t.resolverFactory?.(e)??new By({vaultPath:u,warn:a(j=>c(j),"warn")})).resolveFilter(n);if(d.outcome==="missing-profile")throw new Le(`Profile not found: ${n}`,"Run `exocortex find --class exo__Profile` to list available profiles");if(d.outcome==="error")return c(`[apply-profile] Resolver error: ${d.reason}`),{exitCode:5,stdout:r,stderr:i};if(d.outcome==="degraded")return c(`[apply-profile] Refused: profile resolution degraded \u2014 ${d.reason}. Apply aborted to prevent vault corruption.`),{exitCode:5,stdout:r,stderr:i};if(d.outcome!=="engaged")return c(`[apply-profile] Unexpected resolver outcome: ${d.outcome}`),{exitCode:5,stdout:r,stderr:i};let h=d.result,p=e.token||process.env.GITHUB_TOKEN||process.env.GH_TOKEN||void 0,g=t.applyServiceFactory?.(e,u)??new Wy({vaultPath:u,ref:e.ref??"main",mount:new Yi({token:p})}),{infos:_,profileLabels:E}=g.scanVault(),S=E.get(n)??n,v;try{v=g.buildDiff({targetProfileUid:n,targetProfileLabel:S,sourceProfileUid:null,sourceProfileLabel:"<unknown>",result:h,infos:_})}catch(j){if(j instanceof Cs.TsFloorViolationError)return c(`[apply-profile] Refused: ${j.message}`),{exitCode:5,stdout:r,stderr:i};throw j}if(!await(t.confirmGate??new qy({yes:e.yes??!1,verbose:e.verbose??!1,log:a(j=>c(j),"log")})).confirmHardSwitch(v.plan))return{exitCode:0,stdout:r,stderr:i};if(v.toDestroy.length===0&&v.toMaterialize.length===0)return l(`[apply-profile] Already in target mount-state for ${S} \u2014 no-op.`),{exitCode:0,stdout:r,stderr:i};let L;try{L=await g.execute(v)}catch(j){return c(`[apply-profile] Execution failed: ${j instanceof Error?j.message:String(j)}`),{exitCode:5,stdout:r,stderr:i}}return l(`[apply-profile] Switched to ${S}: ${L.destroyed.length} AssetSpace(s) torn down, ${L.materialized.length} materialized.`),{exitCode:0,stdout:r,stderr:i}}a(Bee,"runApplyProfile");function YN(){return new ne("apply-profile").description("Apply the specified Profile (mount-state filesystem mutation). Requires --yes for headless mode.").argument("<profile-uid>","Target Profile UID").requiredOption("--vault <path>","Path to Obsidian vault").option("--yes","Confirm apply (headless mode safety override per RFC 22b50a17 Decision #2)",!1).option("--verbose","Print plan summary to stderr before deciding",!1).option("--ref <branch>","Git ref to pull when materialising AssetSpaces","main").option("--token <pat>","GitHub PAT for private-repo materialisation (or env GITHUB_TOKEN / GH_TOKEN)").action(async(e,t)=>{try{let r=await Bee(e,t);process.exit(r.exitCode)}catch(r){ee.handle(r)}})}a(YN,"applyProfileCommand");var pl=require("node:path"),ml=require("node:fs");function KN(){return new ne("bootstrap").description("Bootstrap a vault with the SDK floor AssetSpace (exo). Pulls tarballs from public GitHub repos, extracts \u043A assetspaces/, writes .gitmodules. Only --exo is required; --exocmd (the optional UI-command library) is opt-in. Example URLs: https://github.com/kitelev/exoas-exo, https://github.com/kitelev/exoas-exocmd.").requiredOption("--vault <path>","Path \u043A target vault").requiredOption("--exo <url>","Public GitHub URL \u0434\u043B\u044F exo TBox AssetSpace (e.g. https://github.com/kitelev/exoas-exo)").option("--exocmd <url>","Optional: Public GitHub URL \u0434\u043B\u044F exocmd UI-command AssetSpace (e.g. https://github.com/kitelev/exoas-exocmd). Opt-in \u2014 omit for a bare SDK/headless vault; add later via `assetspace add`.").option("--ref <branch>","Branch ref \u043A pull from","main").option("--token <pat>","GitHub PAT for private repos (or env GITHUB_TOKEN / GH_TOKEN). Optional \u2014 anonymous for public repos.").option("--json","Emit result as JSON",!1).action(async n=>{try{if(!n.vault)throw new Le("--vault is required");let e=(0,pl.resolve)(n.vault);(0,ml.mkdirSync)(e,{recursive:!0});let t=(0,pl.join)(e,".gitmodules"),r=(0,pl.join)(e,"assetspaces");if((0,ml.existsSync)(t))throw new Le(`Vault ${e} already has .gitmodules \u2014 refusing \u043A re-bootstrap. Use \`assetspace add\` \u0434\u043B\u044F individual AS.`);if((0,ml.existsSync)(r)&&(0,ml.readdirSync)(r).length>0)throw new Le(`Vault ${e}/assetspaces/ already has content \u2014 refusing \u043A re-bootstrap.`);let i=n.token||process.env.GITHUB_TOKEN||process.env.GH_TOKEN||void 0,s=new Yi({token:i}),o=n.ref??"main",l=[],c="exo",u=(0,pl.join)(e,"assetspaces",c);process.stderr.write(`[bootstrap] Pulling ${n.exo}@${o} \u2192 assetspaces/${c}/...
789
789
  `);let f=await s.pullAssetSpace(n.exo,o,u);if(s.ensureGitmodulesEntry(e,`assetspaces/${c}`,n.exo),l.push({folder:`assetspaces/${c}`,url:n.exo,sha:f.sha,fileCount:f.fileCount}),n.exocmd){let d="exocmd",h=(0,pl.join)(e,"assetspaces",d);process.stderr.write(`[bootstrap] Pulling ${n.exocmd}@${o} \u2192 assetspaces/${d}/...
790
790
  `);let p=await s.pullAssetSpace(n.exocmd,o,h);s.ensureGitmodulesEntry(e,`assetspaces/${d}`,n.exocmd),l.push({folder:`assetspaces/${d}`,url:n.exocmd,sha:p.sha,fileCount:p.fileCount})}if(n.json)process.stdout.write(JSON.stringify({vault:e,materialized:l},null,2)+`
791
791
  `);else{process.stdout.write(`
@@ -815,7 +815,7 @@ Next steps:
815
815
  `),process.stdout.write(` File: ${e.file}
816
816
  `),process.stdout.write(` Commit: ${e.sha}
817
817
  `),process.stdout.write(` URL: ${e.url}
818
- `)),process.exit(0)}catch(e){let t=e instanceof Error?e:new Error(String(e)),r=new vu;t.message=r.redact(t.message),t.stack&&(t.stack=r.redact(t.stack)),ee.handle(t)}})}a(Qee,"restPushCommand");function sk(n){let e=new ne;return e.name("exocortex").description("CLI tool for Exocortex knowledge management system").version(n??"16.71.3"),e.addCommand(IN()),e.addCommand(NN()),e.addCommand(tL()),e.addCommand(iL()),e.addCommand(DL()),e.addCommand(lL()),e.addCommand(cL()),e.addCommand(pL()),e.addCommand(kL()),e.addCommand(GL()),e.addCommand(zL()),e.addCommand(HL()),e.addCommand(QL()),e.addCommand(oN()),e.addCommand(aN()),e.addCommand(pN()),e.addCommand(TN()),e.addCommand(GN()),e.addCommand(YN()),e.addCommand(KN()),e.addCommand(ZN()),e.addCommand(ik()),e}a(sk,"createProgram");sk().parse();0&&(module.exports={createProgram});
818
+ `)),process.exit(0)}catch(e){let t=e instanceof Error?e:new Error(String(e)),r=new vu;t.message=r.redact(t.message),t.stack&&(t.stack=r.redact(t.stack)),ee.handle(t)}})}a(Qee,"restPushCommand");function sk(n){let e=new ne;return e.name("exocortex").description("CLI tool for Exocortex knowledge management system").version(n??"16.71.5"),e.addCommand(IN()),e.addCommand(NN()),e.addCommand(tL()),e.addCommand(iL()),e.addCommand(DL()),e.addCommand(lL()),e.addCommand(cL()),e.addCommand(pL()),e.addCommand(kL()),e.addCommand(GL()),e.addCommand(zL()),e.addCommand(HL()),e.addCommand(QL()),e.addCommand(oN()),e.addCommand(aN()),e.addCommand(pN()),e.addCommand(TN()),e.addCommand(GN()),e.addCommand(YN()),e.addCommand(KN()),e.addCommand(ZN()),e.addCommand(ik()),e}a(sk,"createProgram");sk().parse();0&&(module.exports={createProgram});
819
819
  /*! Bundled license information:
820
820
 
821
821
  reflect-metadata/Reflect.js:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@kitelev/exocortex-cli",
3
- "version": "16.71.3",
3
+ "version": "16.71.5",
4
4
  "description": "CLI tool for Exocortex knowledge management system - SPARQL queries, task management, and more",
5
5
  "main": "dist/index.js",
6
6
  "bin": {