@north-light/cli 0.3.433 → 0.3.435

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.
@@ -1623,7 +1623,7 @@ ${i}`}function Kyn(t,e,n){return t.children.filter(i=>Lx(i)&&i.tag==="li").map((
1623
1623
  `)}done(){return this.buffers.join("").replace(/\n{3,}/g,`
1624
1624
 
1625
1625
  `).replace(/[ \t]+\n/g,`
1626
- `).trim()}}});var Xyn=h(()=>{"use strict"});var Zyn=h(()=>{"use strict"});var eAn=h(()=>{"use strict"});var tAn=h(()=>{"use strict"});var nAn=h(()=>{"use strict"});var rAn=h(()=>{"use strict"});var iAn=h(()=>{"use strict"});var oAn=h(()=>{"use strict"});var sAn=h(()=>{"use strict"});var aAn=h(()=>{"use strict"});var cAn=h(()=>{"use strict"});var uAn=h(()=>{"use strict"});var lAn=h(()=>{"use strict"});var dAn=h(()=>{"use strict"});var pAn=h(()=>{"use strict"});var fAn=h(()=>{"use strict"});var mAn=h(()=>{"use strict"});var hAn=h(()=>{"use strict"});var gAn=h(()=>{"use strict"});var yAn=h(()=>{"use strict"});var AAn=h(()=>{"use strict"});var wAn=h(()=>{"use strict"});var xAn=h(()=>{"use strict"});var bAn=h(()=>{"use strict"});var EAn=h(()=>{"use strict"});var _An=h(()=>{"use strict"});var vAn=h(()=>{"use strict"});var SAn=h(()=>{"use strict"});var CAn=h(()=>{"use strict"});var IAn=h(()=>{"use strict"});var TAn=h(()=>{"use strict"});var kAn=h(()=>{"use strict"});var RAn=h(()=>{"use strict"});var DAn=h(()=>{"use strict"});var MAn=h(()=>{"use strict"});var OAn=h(()=>{"use strict"});var Xfe=h(()=>{"use strict";Wwe();hp();Xyn();Lwe();Zyn();eAn();tAn();id();Bwe();nAn();rAn();iAn();oAn();sAn();aAn();cAn();uAn();lAn();$we();dAn();pAn();fAn();mAn();hAn();gAn();Fwe();yAn();AAn();wAn();R9();xAn();bAn();EAn();_An();vAn();SAn();CAn();IAn();TAn();kAn();RAn();DAn();MAn();OAn()});var NAn=h(()=>{"use strict";as()});var PAn=h(()=>{"use strict"});function LAn(t,e){if(t.code==="daemon_restarting")return new lo("daemon_restarting",t.message,Gi.NETWORK,{next:"crtrd is now on the new generation \u2014 retry the command."});if(t.code==="layout_migration_required")return new lo("layout_migration_required",t.message,Gi.NETWORK,{next:"Run `crtr sys migrate` while the runtime is offline, then restart it."});if(t.code==="daemon_unavailable")return new lo("daemon_unavailable",t.message,Gi.NETWORK,{next:"Start it with `crtr sys daemon start`, then retry."});if(t.status===503)return new lo(t.code,t.message,Gi.NETWORK,{next:e??"Retry the command; if it persists, inspect the unavailable service named in the error."});let n=t.details,r=Array.isArray(n?.violations)?n.violations.map(o=>`${String(o.field)} ${String(o.problem)}${o.received!==void 0?` (received ${JSON.stringify(o.received)})`:""}`):[],i=n&&typeof n.error=="string"&&typeof n.message=="string"&&typeof n.next=="string"?n:{error:Qsi[t.status]??t.code,message:r.length>0?`${t.message}: ${r.join("; ")}`:t.message,next:e??(t.status>=500?"This is a crtr bug, not a bad call. Retry; if it persists, report it (the daemon log holds the full cause).":t.status===404?"List nodes with `crtr node inspect list`.":"Inspect the error and adjust the call. See -h for the schema.")};return new af(i,Wsi(i.error,t.status))}function Wsi(t,e){return t==="not_found"||e===404?Gi.NOT_FOUND:t==="ambiguous"?Gi.AMBIGUOUS:Gi.USAGE}var D5s,af,Qsi,Bx=h(()=>{"use strict";Ss();dc();NAn();PAn();Xfe();D5s=256*1024,af=class extends lo{payload;constructor(e,n=Gi.USAGE){super(e.error,e.message,n,{...e}),this.name="InputError",this.payload=e}},Qsi={400:"invalid_request",404:"not_found",409:"conflict",422:"unprocessable"}});import{copyFileSync as Hsi,mkdirSync as eme,existsSync as Zfe,readFileSync as jsi,writeFileSync as FAn,chmodSync as qsi,readdirSync as Gsi,renameSync as sD,realpathSync as H3,unlinkSync as zsi,rmSync as Vsi,linkSync as BAn}from"node:fs";import{homedir as UAn}from"node:os";import{dirname as QAn,join as bs}from"node:path";import{execFile as Ksi,spawn as Ysi,spawnSync as nme}from"node:child_process";function EF(){return bs(UAn(),cC,"host")}function WAn(){return bs(EF(),rme)}function OKe(){return bs(EF(),".source.json")}function Jsi(t){let e=QAn(t);for(let n of[e,bs(e,"..","lib")]){if(!Zfe(n))continue;let r=Gsi(n).find(i=>i.startsWith("libnode.")&&i.endsWith(".dylib"));if(r!==void 0)return bs(n,r)}return null}function $An(t,e,n){let r=`${e}.tmp.${process.pid}.${Math.random().toString(36).slice(2)}`;Hsi(t,r),n!==void 0&&qsi(r,n),sD(r,e)}function MKe(t=OKe()){try{return JSON.parse(jsi(t,"utf8"))}catch{return null}}function Zsi(t){let e=bs(UAn(),cC),n=bs(e,"host.lock");return eme(e,{recursive:!0}),fc(n,t,{timeoutMs:Xsi,timeoutError:()=>new Error(`timed out waiting for branded host lock: ${n}`)})}function eai(t={}){let e=t.configured?.trim();return e?[e]:[t.discovered?.trim()||"-"]}function tai(){if(process.platform!=="darwin")return null;let t=nme("security",["find-identity","-v","-p","codesigning"],{stdio:["pipe","pipe","pipe"]});if(t.status!==0)return null;let n=(t.stdout??"").toString().split(`
1626
+ `).trim()}}});var Xyn=h(()=>{"use strict"});var Zyn=h(()=>{"use strict"});var eAn=h(()=>{"use strict"});var tAn=h(()=>{"use strict"});var nAn=h(()=>{"use strict"});var rAn=h(()=>{"use strict"});var iAn=h(()=>{"use strict"});var oAn=h(()=>{"use strict"});var sAn=h(()=>{"use strict"});var aAn=h(()=>{"use strict"});var cAn=h(()=>{"use strict"});var uAn=h(()=>{"use strict"});var lAn=h(()=>{"use strict"});var dAn=h(()=>{"use strict"});var pAn=h(()=>{"use strict"});var fAn=h(()=>{"use strict"});var mAn=h(()=>{"use strict"});var hAn=h(()=>{"use strict"});var gAn=h(()=>{"use strict"});var yAn=h(()=>{"use strict"});var AAn=h(()=>{"use strict"});var wAn=h(()=>{"use strict"});var xAn=h(()=>{"use strict"});var bAn=h(()=>{"use strict"});var EAn=h(()=>{"use strict"});var _An=h(()=>{"use strict"});var vAn=h(()=>{"use strict"});var SAn=h(()=>{"use strict"});var CAn=h(()=>{"use strict"});var IAn=h(()=>{"use strict"});var TAn=h(()=>{"use strict"});var kAn=h(()=>{"use strict"});var RAn=h(()=>{"use strict"});var DAn=h(()=>{"use strict"});var MAn=h(()=>{"use strict"});var OAn=h(()=>{"use strict"});var Xfe=h(()=>{"use strict";Wwe();hp();Xyn();Lwe();Zyn();eAn();tAn();id();Bwe();nAn();rAn();iAn();oAn();sAn();aAn();cAn();uAn();lAn();$we();dAn();pAn();fAn();mAn();hAn();gAn();Fwe();yAn();AAn();wAn();R9();xAn();bAn();EAn();_An();vAn();SAn();CAn();IAn();TAn();kAn();RAn();DAn();MAn();OAn()});var NAn=h(()=>{"use strict";as()});var PAn=h(()=>{"use strict"});function LAn(t,e){if(t.code==="daemon_restarting")return new lo("daemon_restarting",t.message,Gi.NETWORK,{next:"crtrd is now on the new generation \u2014 retry the command."});if(t.code==="layout_migration_required")return new lo("layout_migration_required",t.message,Gi.NETWORK,{next:"Run `crtr sys migrate` while the runtime is offline, then restart it."});if(t.code==="daemon_unavailable")return new lo("daemon_unavailable",t.message,Gi.NETWORK,{next:"Start it with `crtr sys daemon start`, then retry."});if(t.status===503)return new lo(t.code,t.message,Gi.NETWORK,{next:e??"Retry the command; if it persists, inspect the unavailable service named in the error."});let n=t.details,r=Array.isArray(n?.violations)?n.violations.map(o=>`${String(o.field)} ${String(o.problem)}${o.received!==void 0?` (received ${JSON.stringify(o.received)})`:""}`):[],i=n&&typeof n.error=="string"&&typeof n.message=="string"&&typeof n.next=="string"?n:{error:Qsi[t.status]??t.code,message:r.length>0?`${t.message}: ${r.join("; ")}`:t.message.trim()!==""?t.message:`request refused (HTTP ${t.status}, ${t.code}) with no message`,next:e??(t.status>=500?"This is a crtr bug, not a bad call. Retry; if it persists, report it (the daemon log holds the full cause).":t.status===404?"List nodes with `crtr node inspect list`.":"Inspect the error and adjust the call. See -h for the schema.")};return new af(i,Wsi(i.error,t.status))}function Wsi(t,e){return t==="not_found"||e===404?Gi.NOT_FOUND:t==="ambiguous"?Gi.AMBIGUOUS:Gi.USAGE}var D5s,af,Qsi,Bx=h(()=>{"use strict";Ss();dc();NAn();PAn();Xfe();D5s=256*1024,af=class extends lo{payload;constructor(e,n=Gi.USAGE){super(e.error,e.message,n,{...e}),this.name="InputError",this.payload=e}},Qsi={400:"invalid_request",404:"not_found",409:"conflict",422:"unprocessable"}});import{copyFileSync as Hsi,mkdirSync as eme,existsSync as Zfe,readFileSync as jsi,writeFileSync as FAn,chmodSync as qsi,readdirSync as Gsi,renameSync as sD,realpathSync as H3,unlinkSync as zsi,rmSync as Vsi,linkSync as BAn}from"node:fs";import{homedir as UAn}from"node:os";import{dirname as QAn,join as bs}from"node:path";import{execFile as Ksi,spawn as Ysi,spawnSync as nme}from"node:child_process";function EF(){return bs(UAn(),cC,"host")}function WAn(){return bs(EF(),rme)}function OKe(){return bs(EF(),".source.json")}function Jsi(t){let e=QAn(t);for(let n of[e,bs(e,"..","lib")]){if(!Zfe(n))continue;let r=Gsi(n).find(i=>i.startsWith("libnode.")&&i.endsWith(".dylib"));if(r!==void 0)return bs(n,r)}return null}function $An(t,e,n){let r=`${e}.tmp.${process.pid}.${Math.random().toString(36).slice(2)}`;Hsi(t,r),n!==void 0&&qsi(r,n),sD(r,e)}function MKe(t=OKe()){try{return JSON.parse(jsi(t,"utf8"))}catch{return null}}function Zsi(t){let e=bs(UAn(),cC),n=bs(e,"host.lock");return eme(e,{recursive:!0}),fc(n,t,{timeoutMs:Xsi,timeoutError:()=>new Error(`timed out waiting for branded host lock: ${n}`)})}function eai(t={}){let e=t.configured?.trim();return e?[e]:[t.discovered?.trim()||"-"]}function tai(){if(process.platform!=="darwin")return null;let t=nme("security",["find-identity","-v","-p","codesigning"],{stdio:["pipe","pipe","pipe"]});if(t.status!==0)return null;let n=(t.stdout??"").toString().split(`
1627
1627
  `).map(r=>r.match(/\)\s+[A-Fa-f0-9]{40}\s+"([^"]+)"/)?.[1]??null).filter(r=>r!==null);return n.find(r=>r.startsWith("Apple Development:"))??n.find(r=>r.startsWith("Developer ID Application:"))??n[0]??null}function nai(t,e){let n=nme("codesign",["-s",e,"--deep","--force",t],{stdio:["pipe","pipe","pipe"]});return{ok:n.status===0,stderr:(n.stderr??"").toString().trim()}}function rai(t){if(process.platform!=="darwin")return;let e=eai({configured:process.env.CRTR_CODESIGN_IDENTITY,discovered:tai()}),n="";for(let r of e){let i=nai(t,r);if(i.ok)return;n=i.stderr}throw n&&!n.includes("valid on disk")&&ja({event:"host.codesign.failed",level:"debug",error:n}),new Error(`codesign failed for ${t}: ${n||"codesign did not exit successfully"}`)}function iai(t,e,n=rai){e!==null&&n(e),n(t)}function bF(t,e=5e3){try{return nme(t,["-e",""],{stdio:"ignore",timeout:e}).status===0}catch{return!1}}function oai(t={}){return Zsi(()=>{let e=EF(),n=WAn(),r=H3(t.execPath??process.execPath);if(Zfe(n)&&H3(n)===r){if(bF(n))return n;let f=uai();if(f===null)throw new Error(`branded host cannot start and no working node was found to rebuild it from: ${n}`);r=f}let i=MKe(),o=Jsi(r),s=o!==null?o.split("/").pop():null,a=f=>Zfe(n)&&f!==null&&f.version===2&&(f.libnode===null||Zfe(bs(e,f.libnode))),c=f=>a(f)&&f.source===r&&f.libnode===s;if(c(i)&&bF(n))return n;eme(e,{recursive:!0});let u=bs(e,`.reconcile.${process.pid}.${Math.random().toString(36).slice(2)}`),l=bs(u,"previous");eme(u);let d=!1,p=a(i)&&bF(n);try{let f=bs(u,rme),m=s!==null?bs(u,s):null;if(o!==null&&m!==null&&$An(o,m),$An(r,f,493),iai(f,m),!bF(f))throw new Error(`rebuilt branded host failed its startup check: ${f}`);if(p&&aai(l,n,i),d=!0,m!==null&&sD(m,bs(e,s)),sD(f,n),sai({version:2,source:r,libnode:s}),!c(MKe())||!bF(n))throw new Error(`published branded host tuple failed validation: ${n}`);if(i?.libnode!=null&&i.libnode!==s)try{zsi(bs(e,i.libnode))}catch{}return n}catch(f){throw d&&p&&cai(l,n,i),f}finally{Vsi(u,{recursive:!0,force:!0})}})}function sai(t){let e=OKe(),n=`${e}.tmp.${process.pid}.${Math.random().toString(36).slice(2)}`;FAn(n,JSON.stringify(t)),sD(n,e)}function aai(t,e,n){eme(t),BAn(e,bs(t,rme)),n.libnode!==null&&BAn(bs(EF(),n.libnode),bs(t,n.libnode)),FAn(bs(t,".source.json"),JSON.stringify(n))}function cai(t,e,n){if(n.libnode!==null&&sD(bs(t,n.libnode),bs(EF(),n.libnode)),sD(bs(t,rme),e),sD(bs(t,".source.json"),OKe()),!bF(e))throw new Error(`failed to restore previous branded host tuple: ${e}`)}function tme(t){try{let e=H3(EF());return QAn(H3(t))===e}catch{return!1}}function HAn(){let t=["/opt/homebrew/bin/node","/usr/local/bin/node"];tme(process.execPath)||t.push(process.execPath);for(let i of(process.env.PATH??"").split(":"))i!==""&&t.push(bs(i,"node"));let e=MKe();e!==null&&typeof e.source=="string"&&t.push(e.source);let n=new Set,r=[];for(let i of t){let o;try{o=H3(i)}catch{continue}n.has(o)||tme(o)||(n.add(o),r.push(o))}return r}function qAn(t){return t!==null&&t.trim()===process.versions.modules}function uai(){for(let t of HAn())try{let e=nme(t,jAn,{encoding:"utf8",timeout:5e3,stdio:["ignore","pipe","ignore"]});if(e.status===0&&qAn(e.stdout))return t}catch{}return null}function GAn(t,e,n){return new Promise(r=>{try{Ksi(t,e,{encoding:"utf8",timeout:n},(i,o)=>r(i===null?o:null))}catch{r(null)}})}async function lai(){for(let t of HAn())if(qAn(await GAn(t,jAn,5e3)))return t;return null}function fai(t){if(import.meta.url.endsWith(".ts"))return;let e=Date.now();if(!(e-tp.lastHealAt<pai)){tp.lastHealAt=e;try{let n=`import(${JSON.stringify(import.meta.url)}).then((m) => m.ensureBrandedHost())`,r=Ysi(t,["--input-type=module","-e",n],{detached:!0,stdio:"ignore"});r.on("error",()=>{}),r.unref()}catch{}}}function mai(t){return tp.probing!==null||(tp.probing=(async()=>{try{if(await GAn(t,["-e",""],5e3)!==null){tp.fallback=null;return}let e=await lai();e!==tp.fallback&&e!==null&&ja({event:"host.fallback.node",level:"warn",fields:{host:t,node:e}}),tp.fallback=e,e!==null&&fai(e)}finally{tp.checkedAt=Date.now(),tp.probing=null}})()),tp.probing}function hai(t=process.execPath){return tme(t)?(Date.now()-tp.checkedAt>dai&&tp.probing===null&&mai(t),tp.fallback??t):t}function zAn(){if(process.env.CRTR_BRANDED_HOST==="0"||process.platform!=="darwin"||import.meta.url.endsWith(".ts"))return process.execPath;if(tme(process.execPath))return hai();try{return oai()}catch(t){return ja({event:"host.fallback.node",level:"warn",error:t,fields:{host:WAn(),node:process.execPath}}),process.execPath}}var rme,Xsi,jAn,dai,pai,tp,VAn=h(()=>{"use strict";dc();kf();Mf();rme="crouter";Xsi=3e4;jAn=["-p","process.versions.modules"];dai=15e3,pai=6e4,tp={checkedAt:0,fallback:null,probing:null,lastHealAt:0}});import{existsSync as gai,readFileSync as yai}from"node:fs";import{join as Aai}from"node:path";function wai(){return Vtt()??Aai(Cs(),"crtrd.pid")}function aD(){let t=wai();if(!gai(t))return null;let e=yai(t,"utf8").trim(),n=Number(e);return Number.isFinite(n)&&n>0?n:null}function KAn(){let t=aD();return t!==null&&fy(t)}var YAn=h(()=>{"use strict";Fr();Ob();as()});var NKe=h(()=>{"use strict"});import{spawn as xai,execFileSync as K5s}from"node:child_process";import{createRequire as bai}from"node:module";import{dirname as PKe,join as _F}from"node:path";import{fileURLToPath as Eai,pathToFileURL as LKe}from"node:url";import{existsSync as JAn,lstatSync as _ai,mkdirSync as vai,openSync as XAn,closeSync as ZAn,fstatSync as e0n,readSync as Sai}from"node:fs";function Iai(){let t={...process.env};for(let e of Cai)delete t[e];return t}function Tai(){for(let t=PKe(Eai(import.meta.url));;t=PKe(t)){if(JAn(_F(t,"bin","runtime-generation-manifest.mjs")))return t;if(PKe(t)===t)throw new Error(`cannot locate the crouter generation root from ${import.meta.url}`)}}async function kai(){let t=Tai(),e=LKe(_F(t,"bin","runtime-generation-manifest.mjs")).href,{runtimeHome:n}=await import(e);try{_ai(_F(n(),"selected"))}catch(s){if(s.code!=="ENOENT")throw s;return["--conditions","crtr-src","--import",LKe(bai(import.meta.url).resolve("tsx/esm")).href,_F(t,"src","daemon","crtrd-cli.ts")]}let r=LKe(_F(t,"bin","runtime-selector.mjs")).href,{tryResolveRuntime:i}=await import(r),o=i("daemon");if(!o.ok)throw new Error(`cannot resolve the selected runtime generation's daemon entry: ${o.error}`);return[o.runtime.entryPath]}async function UKe(t=$Ke){let e=Math.min(t,$Ke);return z0({autostart:!1,timeoutMs:e}).probeHealthz(e)}function Rai(t){let e=t instanceof Error?t.message:String(t);if(typeof t!="object"||t===null)return e;let n=t.code,r=t.cause,i=typeof n=="string"?n:r?.code;return typeof i=="string"&&!e.includes(i)?`${e}: ${i}`:e}async function Dai(t=$Ke){let e=await UKe(t);if(e.startup_blocked!==void 0){let n=aD()??process.pid;throw new vF(n,e.startup_blocked)}if(!e.ok)throw new Error("crtrd health check reported not ready")}function QKe(t){return new Promise(e=>{setTimeout(e,t)})}async function Mai(t,e=3e5,n={},r="ready"){let i=n.readPidfile??aD,o=n.isPidAlive??fy,s=n.childExited,a=n.isDaemonServing,c=n.probeDaemonServing??(async m=>{if(a!==void 0){if(await a())return;throw new Error("crtrd health check reported not ready")}await Dai(m)}),u=n.probeDaemonHealth??UKe,l=n.sleepMs??QKe,d=n.now??Date.now,p=null,f=null;return await E9({windowMs:e,pollIntervalMs:FKe,now:d,sleep:l,retry:m=>m!==f,probe:async m=>{let g=i();if(g===null||!o(g)){let w=s?.();throw w!=null&&(w.signal!==null?f=new q3(`daemon ${t} exited before becoming ready (by ${w.signal})`,n.childStderrTail?.()??""):w.code!==0&&(f=new q3(`daemon ${t} exited before becoming ready (with exit code ${w.code??"?"})`,n.childStderrTail?.()??"")),f!==null)?f:new Error(`daemon ${t} has no live pidfile owner`)}if(r==="ready"){try{await c(m)}catch(w){throw w instanceof vF&&(f=w),w}p=g;return}let y=await u(m);if(y.startup_phase==="prepared"){p=g;return}throw y.startup_phase==="blocked"?(f=new vF(g,y.startup_blocked??"on-disk migration is blocked"),f):y.startup_phase==="ready"?(f=new G3(g,y.startup_phase),f):new Error(`daemon ${g} is ${y.startup_phase??"not reporting a startup phase"}; waiting for prepared`)}}),p===t?null:p}async function Oai(t,e=t0n,n={}){let r=n.readPidfile??aD,i=n.isPidAlive??fy,o=n.sleepMs??QKe,s=n.now??Date.now,a=s()+e;for(;s()<=a;){if(!i(t)&&r()!==t)return;await o(FKe)}throw new Error(`daemon ${t} did not exit and release its pidfile within ${e}ms`)}async function Lai(t,e=t0n,n={}){let r=n.isPidAlive??fy,i=n.sleepMs??QKe,o=n.now??Date.now;try{process.kill(t,"SIGTERM")}catch{}try{return await Oai(t,e,n),"terminated"}catch{}try{process.kill(t,"SIGKILL")}catch{}let s=o()+Nai;for(;o()<=s;){if(!r(t))return"killed";await i(FKe)}throw new Error(`daemon ${t} survived both SIGTERM and SIGKILL`)}function Bai(t,e,n=2048){let r;try{r=XAn(t,"r");let{size:i}=e0n(r),o=Math.max(e,i-n),s=i-o;if(s<=0)return"";let a=Buffer.alloc(s);return Sai(r,a,0,s,o),a.toString("utf8").trim()}catch{return""}finally{if(r!==void 0)try{ZAn(r)}catch{}}}async function $ai(t={}){if(process.platform==="linux"&&JAn("/run/crtr/launcher.sock")&&!fy(aD()??-1))throw new Error("crtrd is managed by the root launcher; it cannot self-daemonize");let e=t.targetPhase??"ready",n=aD();if(n!==null&&fy(n))try{let d=await UKe();if(e==="prepared"){if(d.startup_phase==="prepared")return{started:!1,existing_pid:n,startup_phase:d.startup_phase};throw new G3(n,d.startup_phase)}return d.ok?{started:!1,existing_pid:n,...d.startup_phase===void 0?{}:{startup_phase:d.startup_phase}}:{started:!1,existing_pid:n,running:!0,serving:!1,probe_error:d.startup_blocked??"crtrd health check reported not ready",...d.startup_phase===void 0?{}:{startup_phase:d.startup_phase}}}catch(d){if(d instanceof G3)throw d;return{started:!1,existing_pid:n,running:!0,serving:!1,probe_error:Rai(d)}}vai(Cs(),{recursive:!0});let r=await kai(),i=_F(Cs(),"crtrd.err"),o=XAn(i,"a"),s=(()=>{try{return e0n(o).size}catch{return 0}})();x9()===void 0&&aat();let a=xai(zAn(),[...r,"--canvas-home",Cs(),...e==="prepared"?["--prepare"]:[]],{detached:!0,stdio:["ignore",o,o],env:Iai()});ZAn(o);let c=a.pid;if(c===void 0)throw new Error("daemon spawn did not return a pid");let u=null;a.once("exit",(d,p)=>{u={code:d,signal:p}}),a.unref();let l;try{l=await Mai(c,3e5,{childExited:()=>u,childStderrTail:()=>Bai(i,s)},e)}catch(d){let p=W9(nat())===c;if(u===null&&!p&&!(d instanceof vF))try{await Lai(c,Pai)}catch{}throw d}return l!==null?{started:!1,existing_pid:l,startup_phase:e}:{started:!0,pid:c,startup_phase:e}}function WKe(){return Ktt()||process.argv.includes("--no-autostart")}function Qai(t){return Math.min(Fai*2**(t-1),Uai)}function Wai(){j3=void 0,ime=0,ome=0}function n0n(){return j3}function r0n(t={}){let e=t.isDaemonRunning??KAn,n=t.spawnDaemon??$ai,r=t.now??Date.now;if(!WKe()&&!BKe&&!(r()<ome)){if(e()){Wai();return}j3=void 0,BKe=!0,n().then(()=>{j3=void 0,ime=0,ome=0},i=>{i instanceof q3&&(j3=i.message),ime+=1,ome=r()+Qai(ime)}).finally(()=>{BKe=!1})}}var Cai,t0n,FKe,$Ke,q3,vF,G3,Nai,Pai,Fai,Uai,BKe,j3,ime,ome,i0n=h(()=>{"use strict";Fr();Ob();Nwe();VAn();YAn();NKe();Mf();Fr();as();Xfe();LQ();Cai=["CRTR_NODE_ID","CRTR_KIND","CRTR_MODE","CRTR_LIFECYCLE","CRTR_NODE_CWD","CRTR_CONTEXT_DIR","CRTR_CYCLES","CRTR_PROFILE_ID","CRTR_PARENT_NODE_ID","CRTR_FRONT_DOOR","TMUX","TMUX_PANE","CRTR_BROKER_ENGINE","CRTR_PI_BINARY","NODE_OPTIONS"];t0n=2e4,FKe=10,$Ke=1e3;q3=class extends Error{stderrTail;constructor(e,n){super(n===""?e:`${e}
1628
1628
  ${n}`),this.name="DaemonExitedBeforeReadyError",this.stderrTail=n}},vF=class extends Error{constructor(e,n){super(`daemon ${e} is running but normal startup is blocked: ${n}`),this.name="DaemonStartupBlockedError"}},G3=class extends Error{constructor(e,n){super(n===void 0?`daemon ${e} is serving but did not report the prepared startup phase`:`daemon ${e} reported startup phase ${n}, not prepared`),this.name="DaemonNotPreparedError"}};Nai=2e3,Pai=5e3;Fai=5e3,Uai=6e4,BKe=!1,ime=0,ome=0});import{existsSync as Hai,readFileSync as jai,writeFileSync as fHs,chmodSync as mHs}from"node:fs";import{join as qai}from"node:path";function zai(t){return qai(t===qa()?Eh():t,Gai)}function Vai(t){let e=Th(t);if(!e)return{relayTokens:{}};let n=zai(e);if(!Hai(n))return{relayTokens:{}};try{let r=JSON.parse(jai(n,"utf8")),i=Array.isArray(r.scopedApiTokens)?r.scopedApiTokens.filter(o=>typeof o?.token=="string"&&o.token!==""&&typeof o.grantee=="string"&&/^app:[a-zA-Z0-9][a-zA-Z0-9._-]*$/.test(o.grantee)&&Array.isArray(o.scopes)&&typeof o.created=="string"):[];return{relayTokens:r.relayTokens??{},...typeof r.apiToken=="string"&&r.apiToken!==""?{apiToken:r.apiToken}:{},...i.length>0?{scopedApiTokens:i}:{}}}catch{return{relayTokens:{}}}}function o0n(t,e){return Vai(e).relayTokens[t]}var Gai,s0n=h(()=>{"use strict";gp();zi();Gs();Gai="secrets.json"});function z3(t,e="user"){let n=jo(e),r=n.remoteCanvas.targets[t];if(r===void 0){let o=Object.keys(n.remoteCanvas.targets);throw fp(`no remote canvas target named '${t}'`+(o.length>0?` \u2014 configured: ${o.join(", ")}`:" \u2014 none configured yet")+`. Add one with \`crtr canvas config add ${t} --preview <url> --relay-token -\`.`)}let i=o0n(r.relayTokenRef,e);if(i===void 0||i==="")throw fp(`target '${t}' has no stored relay token \u2014 add it with \`crtr canvas config add ${t} --relay-token -\`.`);return{previewEndpoint:r.previewEndpoint,relayToken:i}}var ame=h(()=>{"use strict";Ss();qo();s0n()});function a0n(t,e,n=5e3){let r=/^[\x20-\x7e]+$/.test(e);return async function(o,s){if(!r)return{ok:!1,stdout:"",stderr:"remote source: invalid stored relay token"};let a={kind:"exec",bin:o,args:s},c=new AbortController,u=setTimeout(()=>c.abort(),n),l;try{l=await fetch(new URL("/__crtr/source",t),{method:"POST",headers:{"content-type":"application/json",authorization:`Bearer ${e}`},body:JSON.stringify(a),signal:c.signal})}catch{return c.signal.aborted?{ok:!1,stdout:"",stderr:`remote source: timeout after ${n}ms`}:{ok:!1,stdout:"",stderr:"remote source: network error"}}finally{clearTimeout(u)}return l.ok?await l.json():{ok:!1,stdout:"",stderr:`remote source: HTTP ${l.status} ${l.statusText}`}}}var c0n=h(()=>{"use strict"});function zl(t){return typeof t=="object"&&t!==null&&!Array.isArray(t)}function Kai(t){if(!zl(t))return!1;let e=t.node;if(!zl(e)||typeof e.node_id!="string"||!Array.isArray(t.reports)||!Array.isArray(t.managers))return!1;let n=t.artifacts;if(!zl(n)||typeof n.report!="number"||typeof n.doc!="number"||typeof n.roadmap!="number"||typeof t.pending_crons!="number")return!1;let r=t.paths;if(!zl(r)||typeof r.context_dir!="string"||"session_file"in r&&r.session_file!==null&&typeof r.session_file!="string"||typeof t.follow_up!="string")return!1;let i=t.fault;if(i!=null){if(!zl(i)||typeof i.link!="string"||typeof i.kind!="string"||typeof i.since!="string")return!1;let o=i.retry;if(!zl(o)||typeof o.disposition!="string")return!1}return!0}function u0n(t){return zl(t)&&typeof t.node_id=="string"&&typeof t.name=="string"&&typeof t.kind=="string"&&typeof t.status=="string"&&typeof t.active=="boolean"}function Yai(t){return zl(t)&&typeof t.from_id=="string"&&typeof t.to_id=="string"&&typeof t.active=="boolean"&&typeof t.created=="string"}function Jai(t){return zl(t)?typeof t.node_id=="string"&&typeof t.name=="string"&&typeof t.kind=="string"&&typeof t.mode=="string"&&typeof t.lifecycle=="string"&&typeof t.status=="string"&&typeof t.cwd=="string"&&typeof t.created=="string":!1}var cme,$x,V3=h(()=>{"use strict";c0n();cme=1e3;$x=class{constructor(e,n){this.previewEndpoint=e;this.relayToken=n;this.exec=a0n(e,n)}previewEndpoint;relayToken;exec;nodeCache=new Map;rosterCache=new Map;topologyCache=null;viewCache=new Map;async execJson(e){let n;try{n=await this.exec("crtr",["--json",...e])}catch{return null}if(!n.ok||n.exitCode!==void 0&&n.exitCode!==0)return null;try{return JSON.parse(n.stdout.trim())}catch{return null}}async fetchShow(e){let n=this.nodeCache.get(e);if(n&&Date.now()-n.at<cme)return n.value;let r=await this.execJson(["node","inspect","show",e]),i=Kai(r)?{...r,fault:r.fault??null,reports:r.reports.filter(u0n),managers:r.managers.filter(u0n)}:null;return this.nodeCache.set(e,{value:i,at:Date.now()}),i}topology(){if(this.topologyCache!==null&&Date.now()-this.topologyCache.at<cme)return this.topologyCache.value;let e=this.loadTopology();return this.topologyCache={value:e,at:Date.now()},e}async loadTopology(){let e=await this.exec("crtr",["--json","canvas","roster"]);if(!e.ok||e.exitCode!==void 0&&e.exitCode!==0)throw new Error("remote canvas topology is unavailable");let n;try{n=JSON.parse(e.stdout.trim())}catch{throw new Error("remote canvas topology is invalid")}if(!zl(n)||!Array.isArray(n.edges)||!n.edges.every(Yai))throw new Error("remote canvas topology is invalid");let r=n.edges,i={subscriptions:new Map,subscribers:new Map};for(let o of r){let s={node_id:o.to_id,active:o.active,created:o.created},a={node_id:o.from_id,active:o.active,created:o.created},c=i.subscriptions.get(o.from_id);c===void 0?i.subscriptions.set(o.from_id,[s]):c.push(s);let u=i.subscribers.get(o.to_id);u===void 0?i.subscribers.set(o.to_id,[a]):u.push(a)}return i}async rawShow(e){return this.fetchShow(e)}async getNode(e){return(await this.fetchShow(e))?.node??null}async getRow(e){let n=(await this.fetchShow(e))?.node;return n?{node_id:n.node_id,name:n.name,kind:n.kind,mode:n.mode,lifecycle:n.lifecycle,status:n.status,cwd:n.cwd,host_kind:n.host_kind??null,profile_id:n.profile_id??null,scopes:n.scopes??null,isolated:n.isolated===!0,parent:n.parent??null,created:n.created,intent:n.intent??null,waiting_for:n.waiting_for??null,frozen_at:n.frozen_at??null,terminal_reason:n.terminal_reason??null,pi_pid:n.pi_pid??null,pi_pid_identity:n.pi_pid_identity??null,window:n.window??null,tmux_session:n.tmux_session??null,pane:n.pane??null,fault:n.fault??null,streaming:n.streaming===!0}:null}async listNodes(e){let n=JSON.stringify(e?.status??null),r=this.rosterCache.get(n);if(r&&Date.now()-r.at<cme)return r.value;let i=["node","inspect","list"];e?.status&&i.push("--status",(Array.isArray(e.status)?e.status:[e.status]).join(","));let o=await this.execJson(i),a=(zl(o)&&Array.isArray(o.nodes)?o.nodes:[]).filter(Jai).map(c=>({...c,isolated:c.isolated===!0}));return this.rosterCache.set(n,{value:a,at:Date.now()}),a}async subscriptionsOf(e){return(await this.topology()).subscriptions.get(e)??[]}async subscribersOf(e){return(await this.topology()).subscribers.get(e)??[]}async view(e){let n=this.viewCache.get(e);if(n&&Date.now()-n.at<cme)return n.value;let r=new Set([e]),i=[],o=(await this.subscriptionsOf(e)).map(s=>s.node_id);for(;o.length>0;){let s=o.shift();if(!r.has(s)){r.add(s),i.push(s);for(let a of await this.subscriptionsOf(s))r.has(a.node_id)||o.push(a.node_id)}}return this.viewCache.set(e,{value:i,at:Date.now()}),i}async ticketCountsForNodes(e){if(e.length===0)return{};let n=await this.execJson(["canvas","attention","map","--nodes",e.join(",")]);return zl(n)&&zl(n.counts)?n.counts:{}}async ticketCountsForView(e){let n=await this.execJson(["canvas","attention","map","--view",e]);return zl(n)&&zl(n.counts)?n.counts:{}}async hasActiveLiveSubscription(e){let n=(await this.subscriptionsOf(e)).filter(r=>r.active);for(let r of n){let i=await this.getRow(r.node_id);if(i&&(i.status==="active"||i.status==="idle"))return!0}return!1}}});import{closeSync as Xai,fstatSync as Zai,openSync as eci,readSync as tci}from"node:fs";import{join as nci}from"node:path";import{gunzipSync as rci}from"node:zlib";function ume(t){return{...t,fault:t.fault??null}}function HKe(t,e){throw t instanceof fn?LAn(t,e):t}function sci(){let t;try{t=eci(nci(Cs(),"crtrd.log"),"r");let{size:e}=Zai(t),n=Math.max(0,e-ici),r=e-n;if(r<=0)return;let i=Buffer.alloc(r);tci(t,i,0,r,n);let s=i.toString("utf8").split(`
1629
1629
  `).filter(a=>a.trim()!=="").slice(-oci).join(`
@@ -1 +1 @@
1
- var m=Object.defineProperty;var s=(e,o)=>m(e,"name",{value:o,configurable:!0});import{defineLeaf as h}from"../../core/command.js";import{usage as d}from"../../core/errors.js";import{DOC_UNSET_FIELDS as u}from"../../api/dto/docs.js";import{cliClient as f}from"../api-client.js";import{parseReplaceBlocks as p}from"./replace-blocks.js";import{FIELD_FLAGS as t,REF_CONSTRAINT as y,fieldsFromInput as b,rethrowDocError as w,renderLinkReport as g,ruleParam as v}from"./shared.js";const q=h({name:"edit",description:"revise a document you have read",whenToUse:"a document you read needs a change to its body or fields",help:{name:"doc edit",summary:"revise a document you have read",guide:"The edit is made from the revision you last read (`crtr canvas read`); pass no revision. If someone edited it after your read, the edit is refused and nothing is overwritten. For a partial edit, pipe one or more literal blocks on stdin with --blocks: <<<<<<< SEARCH, old text, =======, new text, >>>>>>> REPLACE (markers on their own lines). Each SEARCH must match exactly once; empty REPLACE deletes text. Alternatively pipe a whole new body without --blocks, or use --replace JSON for scripts. Choose one mode. Pipe text straight in with a quoted heredoc (`<<'EOF'`); an unquoted one lets the shell expand `$` and backticks in the text, and the mangled text is what gets saved. A field flag replaces that field; omitted fields stay as they are.",params:[{kind:"positional",name:"ref",required:!0,constraint:y},{kind:"flag",name:"rationale",type:"string",required:!0,constraint:"Why this revision is made; recorded on the revision, never in the body."},{kind:"stdin",name:"body",required:!1,constraint:"Whole new body by default; with --blocks, exact SEARCH/REPLACE blocks."},{kind:"flag",name:"blocks",type:"bool",required:!1,constraint:"Interpret stdin as one or more whole-line <<<<<<< SEARCH / ======= / >>>>>>> REPLACE blocks; empty SEARCH is invalid, empty REPLACE deletes."},{kind:"flag",name:"replace",type:"string",required:!1,constraint:'JSON list `[{"old": "\u2026", "new": "\u2026"}]` of exact-text replacements; each `old` must match exactly once in the body you read.'},{kind:"flag",name:"verbatim",type:"bool",required:!1,constraint:"The body is the person's own text relayed unchanged; recorded on the revision."},t.preview("New one-line preview."),t.summary,t.privacy("Who beyond the owner may read it."),v("Replaces the whole rule list."),t.whyItExists,t.unlisted("Sets unlisted; remove it with `--unset unlisted`."),t.lintIgnore,t.extension,{kind:"flag",name:"unset",type:"enum",choices:[...u],required:!1,repeatable:!0,constraint:"Clear one optional field."}],output:[{name:"revision",type:"number",required:!0,constraint:"The new revision number."},{name:"unresolved_links",type:"string[]",required:!1,constraint:"`[[links]]` in the new body that name no document yet."},{name:"remote_links",type:"string[]",required:!1,constraint:"`[[links]]` whose first segment is no owner on this runtime: on another runtime, or misspelled."}],outputKind:"object",effects:["Commits a new revision based on your last read and pushes the edit to the document's watchers."]},run:s(async e=>{const o=e.ref;let n=typeof e.body=="string"&&e.body!==""?e.body:void 0,i;if(e.blocks===!0){if(e.replace!==void 0)throw d("choose --blocks or --replace, not both",{field:"blocks"});i=p(n??""),n=void 0}if(typeof e.replace=="string"){if(n!==void 0)throw d("give a stdin body or --replace, not both",{field:"replace",next:"Drop one of them and rerun."});try{const r=JSON.parse(e.replace);if(!Array.isArray(r)||r.length===0||r.some(a=>typeof a!="object"||a===null||typeof a.old!="string"||typeof a.new!="string"))throw new Error;i=r}catch{throw d('--replace must be a non-empty JSON list of {"old": string, "new": string}',{field:"replace",next:"Fix the JSON and rerun."})}}const l=e.unset===void 0?[]:[].concat(e.unset),c={rationale:e.rationale,...n!==void 0?{body:n}:{},...i!==void 0?{replace:i}:{},...e.verbatim===!0?{verbatim:!0}:{},...b(e),...l.length>0?{unset:l}:{}};try{return{...await f().docs.edit(o,c)}}catch(r){w(r,o)}},"run"),render:s(e=>`<edited name="${String(e.name)}" revision=${String(e.revision)}>${g(e)}`,"render")});export{q as editLeaf};
1
+ var h=Object.defineProperty;var a=(e,o)=>h(e,"name",{value:o,configurable:!0});import{defineLeaf as m}from"../../core/command.js";import{usage as d}from"../../core/errors.js";import{DOC_UNSET_FIELDS as u}from"../../api/dto/docs.js";import{cliClient as f}from"../api-client.js";import{parseReplaceBlocks as y}from"./replace-blocks.js";import{FIELD_FLAGS as t,REF_CONSTRAINT as p,fieldsFromInput as b,rethrowDocError as w,renderLinkReport as v,ruleParam as g}from"./shared.js";const q=m({name:"edit",description:"revise a document you have read",whenToUse:"a document you read needs a change to its body or fields",help:{name:"doc edit",summary:"revise a document you have read",guide:"The edit is made from the revision you last read (`crtr canvas read`); pass no revision. If someone edited it after your read, the edit is refused and nothing is overwritten. For a partial edit, pipe one or more literal blocks on stdin with --blocks: <<<<<<< SEARCH, old text, =======, new text, >>>>>>> REPLACE (markers on their own lines). Each SEARCH must match exactly once; empty REPLACE deletes text. Alternatively pipe a whole new body without --blocks, or use --replace JSON for scripts. Choose one mode. Pipe text straight in with a quoted heredoc (`<<'EOF'`); an unquoted one lets the shell expand `$` and backticks in the text, and the mangled text is what gets saved. A field flag replaces that field; omitted fields stay as they are. A change to fields alone (preview, summary, privacy, rules, why-it-exists, \u2026) takes effect at once, makes no new revision and returns the current revision number unchanged: revisions are versions of the body. Only a body edit records the rationale on a revision.",params:[{kind:"positional",name:"ref",required:!0,constraint:p},{kind:"flag",name:"rationale",type:"string",required:!0,constraint:"Why this revision is made; recorded on the revision, never in the body. A fields-only edit makes no revision, so it records nothing; the rationale is still required."},{kind:"stdin",name:"body",required:!1,constraint:"Whole new body by default; with --blocks, exact SEARCH/REPLACE blocks."},{kind:"flag",name:"blocks",type:"bool",required:!1,constraint:"Interpret stdin as one or more whole-line <<<<<<< SEARCH / ======= / >>>>>>> REPLACE blocks; empty SEARCH is invalid, empty REPLACE deletes."},{kind:"flag",name:"replace",type:"string",required:!1,constraint:'JSON list `[{"old": "\u2026", "new": "\u2026"}]` of exact-text replacements; each `old` must match exactly once in the body you read.'},{kind:"flag",name:"verbatim",type:"bool",required:!1,constraint:"The body is the person's own text relayed unchanged; recorded on the revision."},t.preview("New one-line preview."),t.summary,t.privacy("Who beyond the owner may read it."),g("Replaces the whole rule list."),t.whyItExists,t.unlisted("Sets unlisted; remove it with `--unset unlisted`."),t.lintIgnore,t.extension,{kind:"flag",name:"unset",type:"enum",choices:[...u],required:!1,repeatable:!0,constraint:"Clear one optional field."}],output:[{name:"revision",type:"number",required:!0,constraint:"The new revision number; for a fields-only edit, the current one, unchanged."},{name:"unresolved_links",type:"string[]",required:!1,constraint:"`[[links]]` in the new body that name no document yet."},{name:"remote_links",type:"string[]",required:!1,constraint:"`[[links]]` whose first segment is no owner on this runtime: on another runtime, or misspelled."}],outputKind:"object",effects:["Commits a new revision based on your last read and pushes the edit to the document's watchers."]},run:a(async e=>{const o=e.ref;let n=typeof e.body=="string"&&e.body!==""?e.body:void 0,i;if(e.blocks===!0){if(e.replace!==void 0)throw d("choose --blocks or --replace, not both",{field:"blocks"});i=y(n??""),n=void 0}if(typeof e.replace=="string"){if(n!==void 0)throw d("give a stdin body or --replace, not both",{field:"replace",next:"Drop one of them and rerun."});try{const r=JSON.parse(e.replace);if(!Array.isArray(r)||r.length===0||r.some(s=>typeof s!="object"||s===null||typeof s.old!="string"||typeof s.new!="string"))throw new Error;i=r}catch{throw d('--replace must be a non-empty JSON list of {"old": string, "new": string}',{field:"replace",next:"Fix the JSON and rerun."})}}const l=e.unset===void 0?[]:[].concat(e.unset),c={rationale:e.rationale,...n!==void 0?{body:n}:{},...i!==void 0?{replace:i}:{},...e.verbatim===!0?{verbatim:!0}:{},...b(e),...l.length>0?{unset:l}:{}};try{return{...await f().docs.edit(o,c)}}catch(r){w(r,o)}},"run"),render:a(e=>`<edited name="${String(e.name)}" revision=${String(e.revision)}>${v(e)}`,"render")});export{q as editLeaf};
package/dist/core/io.js CHANGED
@@ -1,7 +1,7 @@
1
- var w=Object.defineProperty;var n=(e,t)=>w(e,"name",{value:t,configurable:!0});import{appendFileSync as x,statSync as E}from"node:fs";import{CrtrError as a}from"./errors.js";import{ExitCode as c}from"../types.js";import{PREVIEW_RESULT_PATH_ENV as m}from"./preview-result-path.js";import{renderError as b}from"./render.js";import{ApiError as T}from"../api/index.js";let d=!1,u;const _=256*1024;function W(e){const t=process.env[m];u=t===void 0||t===""?void 0:{path:e,jsonl:[]}}n(W,"beginPreview");function f(e){const t=process.env[m];if(t===void 0||t==="")return;const s=`${JSON.stringify({path:u?.path??"",...e})}
2
- `;try{if((E(t,{throwIfNoEntry:!1})?.size??0)+Buffer.byteLength(s,"utf8")>_)return;x(t,s,"utf8")}catch{}}n(f,"publishPreview");function k(e){u!==void 0&&(e!=null?f({result:e}):(u.jsonl.length>0||u.error!==void 0)&&f({...u.jsonl.length>0?{jsonl:u.jsonl}:{},...u.error===void 0?{}:{error:u.error}}))}n(k,"publishPreviewResult");function y(e){u?.jsonl.push(e)}n(y,"recordPreviewLine");function B(e){try{const t=JSON.parse(e);t!==null&&typeof t=="object"&&!Array.isArray(t)&&y(t)}catch{}}n(B,"recordPreviewJsonLine");function F(e){u!==void 0&&(u.error=e)}n(F,"recordPreviewError");function G(e){d=e}n(G,"setJsonOutput");function K(){return d}n(K,"isJsonOutput");class h extends a{static{n(this,"InputError")}payload;constructor(t,s=c.USAGE){super(t.error,t.message,s,{...t}),this.name="InputError",this.payload=t}}async function q(){if(process.stdin.isTTY)return"";const e=[];for await(const t of process.stdin)e.push(t);return Buffer.concat(e).toString("utf8")}n(q,"readStdinRaw");async function D(e=200){return process.stdin.isTTY?"":await new Promise(t=>{const s=[];let o=!1;const r=n(()=>{o||(o=!0,clearTimeout(g),process.stdin.removeListener("data",i),process.stdin.removeListener("end",p),process.stdin.removeListener("error",l),process.stdin.pause(),t(Buffer.concat(s).toString("utf8")))},"finish"),i=n(S=>s.push(S),"onData"),p=n(()=>r(),"onEnd"),l=n(()=>r(),"onError"),g=setTimeout(r,e);process.stdin.on("data",i),process.stdin.on("end",p),process.stdin.on("error",l),process.stdin.resume()})}n(D,"peekStdinRaw");function V(e){process.stdout.write(JSON.stringify(e,null,2)+`
1
+ var w=Object.defineProperty;var n=(e,t)=>w(e,"name",{value:t,configurable:!0});import{appendFileSync as x,statSync as E}from"node:fs";import{CrtrError as a}from"./errors.js";import{ExitCode as c}from"../types.js";import{PREVIEW_RESULT_PATH_ENV as m}from"./preview-result-path.js";import{renderError as T}from"./render.js";import{ApiError as b}from"../api/index.js";let d=!1,u;const _=256*1024;function W(e){const t=process.env[m];u=t===void 0||t===""?void 0:{path:e,jsonl:[]}}n(W,"beginPreview");function f(e){const t=process.env[m];if(t===void 0||t==="")return;const s=`${JSON.stringify({path:u?.path??"",...e})}
2
+ `;try{if((E(t,{throwIfNoEntry:!1})?.size??0)+Buffer.byteLength(s,"utf8")>_)return;x(t,s,"utf8")}catch{}}n(f,"publishPreview");function k(e){u!==void 0&&(e!=null?f({result:e}):(u.jsonl.length>0||u.error!==void 0)&&f({...u.jsonl.length>0?{jsonl:u.jsonl}:{},...u.error===void 0?{}:{error:u.error}}))}n(k,"publishPreviewResult");function y(e){u?.jsonl.push(e)}n(y,"recordPreviewLine");function B(e){try{const t=JSON.parse(e);t!==null&&typeof t=="object"&&!Array.isArray(t)&&y(t)}catch{}}n(B,"recordPreviewJsonLine");function q(e){u!==void 0&&(u.error=e)}n(q,"recordPreviewError");function F(e){d=e}n(F,"setJsonOutput");function G(){return d}n(G,"isJsonOutput");class h extends a{static{n(this,"InputError")}payload;constructor(t,s=c.USAGE){super(t.error,t.message,s,{...t}),this.name="InputError",this.payload=t}}async function K(){if(process.stdin.isTTY)return"";const e=[];for await(const t of process.stdin)e.push(t);return Buffer.concat(e).toString("utf8")}n(K,"readStdinRaw");async function D(e=200){return process.stdin.isTTY?"":await new Promise(t=>{const s=[];let o=!1;const r=n(()=>{o||(o=!0,clearTimeout(g),process.stdin.removeListener("data",i),process.stdin.removeListener("end",p),process.stdin.removeListener("error",l),process.stdin.pause(),t(Buffer.concat(s).toString("utf8")))},"finish"),i=n(S=>s.push(S),"onData"),p=n(()=>r(),"onEnd"),l=n(()=>r(),"onError"),g=setTimeout(r,e);process.stdin.on("data",i),process.stdin.on("end",p),process.stdin.on("error",l),process.stdin.resume()})}n(D,"peekStdinRaw");function V(e){process.stdout.write(JSON.stringify(e,null,2)+`
3
3
  `)}n(V,"emit");function Y(e){y(e),process.stdout.write(JSON.stringify(e)+`
4
- `)}n(Y,"emitLine");function M(e){return new Promise(t=>{let s=!1;const o=n(i=>{i.code==="EPIPE"&&r(!1)},"onErr"),r=n(i=>{s||(s=!0,process.stdout.off("error",o),t(i))},"finish");process.stdout.on("error",o);try{process.stdout.write(e,i=>r(i==null))}catch{r(!1)}})}n(M,"writeStdout");function z(e){process.stderr.write(e+`
5
- `)}n(z,"diag");function O(e){if(e instanceof h)return e.payload;const t=e.details!==void 0?e.details:{},s=t.primaryCompleted===!0&&t.result!==null&&typeof t.result=="object"&&!Array.isArray(t.result)?N(t.result):void 0,o=t.next!==void 0?t.next:"Inspect the error and adjust the call. See -h for the schema.",r={error:e.code,message:e.message,received:t.received,field:t.field,...typeof t.http_status=="number"?{http_status:t.http_status}:{}};return s===void 0?{...r,next:o}:{...r,primaryCompleted:!0,result:s,next:o}}n(O,"payloadOf");function N(e){const t=new WeakSet;try{const s=JSON.stringify(e,(o,r)=>{if(typeof r=="bigint")return{$crtrType:"bigint",value:r.toString()};if(typeof r=="number"&&!Number.isFinite(r))return{$crtrType:"number",value:String(r)};if(typeof r>"u"||typeof r=="function"||typeof r=="symbol")return{$crtrType:typeof r};if(r!==null&&typeof r=="object"){if(t.has(r))return{$crtrType:"circular"};t.add(r)}return r});if(s!==void 0){const o=JSON.parse(s);if(o!==null&&typeof o=="object"&&!Array.isArray(o))return o}}catch{}return{$crtrType:"unavailable",message:"The completed primary result could not be represented as JSON."}}n(N,"jsonSafeResult");const R={400:"invalid_request",404:"not_found",409:"conflict",422:"unprocessable"};function A(e,t){if(e.code==="daemon_restarting")return new a("daemon_restarting",e.message,c.NETWORK,{next:"crtrd is now on the new generation \u2014 retry the command."});if(e.code==="layout_migration_required")return new a("layout_migration_required",e.message,c.NETWORK,{next:"Run `crtr sys migrate` while the runtime is offline, then restart it."});if(e.code==="daemon_unavailable")return new a("daemon_unavailable",e.message,c.NETWORK,{next:"Start it with `crtr sys daemon start`, then retry."});if(e.status===503)return new a(e.code,e.message,c.NETWORK,{next:t??"Retry the command; if it persists, inspect the unavailable service named in the error."});const s=e.details,o=Array.isArray(s?.violations)?s.violations.map(i=>`${String(i.field)} ${String(i.problem)}${i.received!==void 0?` (received ${JSON.stringify(i.received)})`:""}`):[],r=s&&typeof s.error=="string"&&typeof s.message=="string"&&typeof s.next=="string"?s:{error:R[e.status]??e.code,message:o.length>0?`${e.message}: ${o.join("; ")}`:e.message,next:t??(e.status>=500?"This is a crtr bug, not a bad call. Retry; if it persists, report it (the daemon log holds the full cause).":e.status===404?"List nodes with `crtr node inspect list`.":"Inspect the error and adjust the call. See -h for the schema.")};return new h(r,P(r.error,e.status))}n(A,"apiErrorToCliError");function P(e,t){return e==="not_found"||t===404?c.NOT_FOUND:e==="ambiguous"?c.AMBIGUOUS:c.USAGE}n(P,"exitForCliCode");function j(e){if(e instanceof T){j(A(e));return}if(e instanceof a){const o=O(e);u!==void 0&&f({error:o});const r=d?JSON.stringify(o,null,2):b(o);process.stdout.write(r+`
4
+ `)}n(Y,"emitLine");function H(e){return new Promise(t=>{let s=!1;const o=n(i=>{i.code==="EPIPE"&&r(!1)},"onErr"),r=n(i=>{s||(s=!0,process.stdout.off("error",o),t(i))},"finish");process.stdout.on("error",o);try{process.stdout.write(e,i=>r(i==null))}catch{r(!1)}})}n(H,"writeStdout");function M(e){process.stderr.write(e+`
5
+ `)}n(M,"diag");function O(e){if(e instanceof h)return e.payload;const t=e.details!==void 0?e.details:{},s=t.primaryCompleted===!0&&t.result!==null&&typeof t.result=="object"&&!Array.isArray(t.result)?N(t.result):void 0,o=t.next!==void 0?t.next:"Inspect the error and adjust the call. See -h for the schema.",r={error:e.code,message:e.message,received:t.received,field:t.field,...typeof t.http_status=="number"?{http_status:t.http_status}:{}};return s===void 0?{...r,next:o}:{...r,primaryCompleted:!0,result:s,next:o}}n(O,"payloadOf");function N(e){const t=new WeakSet;try{const s=JSON.stringify(e,(o,r)=>{if(typeof r=="bigint")return{$crtrType:"bigint",value:r.toString()};if(typeof r=="number"&&!Number.isFinite(r))return{$crtrType:"number",value:String(r)};if(typeof r>"u"||typeof r=="function"||typeof r=="symbol")return{$crtrType:typeof r};if(r!==null&&typeof r=="object"){if(t.has(r))return{$crtrType:"circular"};t.add(r)}return r});if(s!==void 0){const o=JSON.parse(s);if(o!==null&&typeof o=="object"&&!Array.isArray(o))return o}}catch{}return{$crtrType:"unavailable",message:"The completed primary result could not be represented as JSON."}}n(N,"jsonSafeResult");const R={400:"invalid_request",404:"not_found",409:"conflict",422:"unprocessable"};function A(e,t){if(e.code==="daemon_restarting")return new a("daemon_restarting",e.message,c.NETWORK,{next:"crtrd is now on the new generation \u2014 retry the command."});if(e.code==="layout_migration_required")return new a("layout_migration_required",e.message,c.NETWORK,{next:"Run `crtr sys migrate` while the runtime is offline, then restart it."});if(e.code==="daemon_unavailable")return new a("daemon_unavailable",e.message,c.NETWORK,{next:"Start it with `crtr sys daemon start`, then retry."});if(e.status===503)return new a(e.code,e.message,c.NETWORK,{next:t??"Retry the command; if it persists, inspect the unavailable service named in the error."});const s=e.details,o=Array.isArray(s?.violations)?s.violations.map(i=>`${String(i.field)} ${String(i.problem)}${i.received!==void 0?` (received ${JSON.stringify(i.received)})`:""}`):[],r=s&&typeof s.error=="string"&&typeof s.message=="string"&&typeof s.next=="string"?s:{error:R[e.status]??e.code,message:o.length>0?`${e.message}: ${o.join("; ")}`:e.message.trim()!==""?e.message:`request refused (HTTP ${e.status}, ${e.code}) with no message`,next:t??(e.status>=500?"This is a crtr bug, not a bad call. Retry; if it persists, report it (the daemon log holds the full cause).":e.status===404?"List nodes with `crtr node inspect list`.":"Inspect the error and adjust the call. See -h for the schema.")};return new h(r,P(r.error,e.status))}n(A,"apiErrorToCliError");function P(e,t){return e==="not_found"||t===404?c.NOT_FOUND:e==="ambiguous"?c.AMBIGUOUS:c.USAGE}n(P,"exitForCliCode");function j(e){if(e instanceof b){j(A(e));return}if(e instanceof a){const o=O(e);u!==void 0&&f({error:o});const r=d?JSON.stringify(o,null,2):T(o);process.stdout.write(r+`
6
6
  `),process.exitCode=e.exitCode;return}const t=e,s=t!=null&&typeof t.message=="string"?t.message:String(e);process.stderr.write(JSON.stringify({error:"internal",message:s,next:"This is a crtr bug, not a bad call. Retry; if it persists, report it."},null,2)+`
7
- `),process.exitCode=c.GENERAL}n(j,"handle");export{h as InputError,_ as PREVIEW_RESULT_MAX_BYTES,A as apiErrorToCliError,W as beginPreview,z as diag,V as emit,Y as emitLine,j as handle,K as isJsonOutput,D as peekStdinRaw,k as publishPreviewResult,q as readStdinRaw,F as recordPreviewError,B as recordPreviewJsonLine,y as recordPreviewLine,G as setJsonOutput,M as writeStdout};
7
+ `),process.exitCode=c.GENERAL}n(j,"handle");export{h as InputError,_ as PREVIEW_RESULT_MAX_BYTES,A as apiErrorToCliError,W as beginPreview,M as diag,V as emit,Y as emitLine,j as handle,G as isJsonOutput,D as peekStdinRaw,k as publishPreviewResult,K as readStdinRaw,q as recordPreviewError,B as recordPreviewJsonLine,y as recordPreviewLine,F as setJsonOutput,H as writeStdout};
@@ -1 +1 @@
1
- var re=Object.defineProperty;var u=(t,e)=>re(t,"name",{value:e,configurable:!0});import{prepared as P}from"../../../core/sqlite-statements.js";import{ApiError as g}from"../../../api/errors.js";import{DOC_KINDS as q,DOC_UNSET_FIELDS as H}from"../../../api/dto/docs.js";import{PRIVACY_LEVELS_DTO as V}from"../../../api/dto/objects.js";import{withCanvasWrite as k}from"../../../core/canvas/db.js";import{CrtrError as ie}from"../../../core/errors.js";import{emitEvent as se}from"../../../core/events/emit.js";import{canChange as K,spaceOf as ae}from"../../../core/graph/access.js";import{get as A}from"../../../core/graph/bodies.js";import{deleteDocument as ce,documentRecord as F,editDocument as de,heads as I,history as ue,linksIn as U,moveDocument as fe,readBase as le,setDocumentRecord as me,withCurrentNames as pe,writeDocument as he}from"../../../core/graph/documents.js";import{resolveName as X}from"../../../core/graph/names.js";import{getByRowid as M}from"../../../core/graph/objects.js";import{noteRepoDocumentsChanged as we}from"../../../core/graph/repo-sync/index.js";import{checkoutsForCwd as ye}from"../../../core/graph/repo-sync/repos.js";import{lintRules as ve,rulesOf as ge}from"../../../core/graph/rules.js";import{unifiedDiff as _e}from"../../../core/graph/diff.js";import{ownerFromFlag as W,readerFor as E,resolveRef as z}from"../reader.js";function _(t,e,n,o,i={}){return new g(t,e,n,{...i,error:e,message:n,next:o})}u(_,"refuse");const b=u((t,e)=>new g(400,"invalid_request",t,e),"invalid");function D(t){const e=t.body;if(e===void 0)return{};if(typeof e!="object"||e===null||Array.isArray(e))throw b("the request body must be a JSON object");return e}u(D,"bodyOf");const x=u(t=>e=>ye(t,e),"reposFnFor");function C(t,e){if(t instanceof ie){const n=t.details;if(t.code==="read_first")throw _(409,"read_first",t.message,`Read it first with \`crtr canvas read ${e?.id??"<ref>"}\`, then rerun the edit.`,n??{});if(t.code==="conflict")throw new g(409,"name_taken",t.message,n);if(t.code==="forbidden")throw new g(403,"forbidden",t.message,n);if(n?.rule==="repo-public-only")throw _(422,"repo_documents_are_public",t.message,'Own it as `user` and add a rule with `if: {"repo": "<handle>"}` so it loads only in that repo.')}throw t}u(C,"mapGraphError");function B(t,e,n){const o=z(t,e,decodeURIComponent(n));if("remote"in o)throw _(404,"not_found",G(o.remote),"Check the name with `crtr canvas search`.");if("deleted"in o)throw new g(404,"not_found",`${o.deleted.name} is deleted`,{id:o.deleted.id,deleted:!0});if(o.type!=="document")throw b(`${n} is a ${o.type}, not a document`);return o}u(B,"refDocument");function G(t){return`no object named ${t} on this runtime; it may be on another runtime, or the name may be misspelled`}u(G,"remoteMessage");function be(t,e){const n=e.owner===null?null:M(t,e.owner);return n?n.type==="node"?n.id:n.name:""}u(be,"ownerHandle");function j(t,e){const n=be(t,e);return n?`${n}/${e.name}`:e.name}u(j,"canonicalName");function ke(t,e){const n=e.owner===null?null:M(t,e.owner),o=n?{id:n.id,type:n.type,handle:n.type==="node"?n.id:n.name}:null;return{id:e.id,type:e.type,kind:e.kind,owner:o,privacy:e.privacy,name:e.name,preview:e.preview??"",created_at:e.created_at,deleted_at:e.deleted_at}}u(ke,"objectDTO");function Ee(t,e){const n=e.owner===null?null:M(t,e.owner);return n?.type==="repo"?n:null}u(Ee,"repoOwner");function S(t,e,n,o){const i=[...new Map(n.flatMap(r=>{const f=Ee(t,r);return f?[[f.id,f]]:[]})).values()],a=e.class==="node"?e.cwd:o;return{repos:i,...a!==void 0?{cwd:a}:{}}}u(S,"repoChange");function T(t){for(const e of t.repos)try{we(e,t.cwd)}catch(n){se({level:"warn",event:"repo_sync.failed",outcome:"failed",error:n,fields:{repo:e.name,step:"export",reason:n instanceof Error?n.message:String(n)}})}}u(T,"syncChanged");const Y=/^[A-Za-z0-9_-]+(\/[A-Za-z0-9_-]+)*$/;function Oe(t,e){if(t===void 0)return;if(!Array.isArray(t)){e.push("`rules` must be a list");return}const n=t.map(i=>{if(typeof i!="object"||i===null||Array.isArray(i))return i;const{match_frontmatter:a,...r}=i;return"matchFrontmatter"in r?{...r,match_frontmatter:r.matchFrontmatter}:a===void 0?r:{...r,matchFrontmatter:a}}),o=ve(n);if(o){e.push(o.replaceAll("matchFrontmatter","match_frontmatter"));return}return n}u(Oe,"rulesFromDTO");function Z(t,e){const n={},o=u(s=>{const c=t[s];if(c!==void 0){if(typeof c!="string"){e.push(`\`${s}\` must be a string`);return}return c}},"str"),i=o("preview");i!==void 0&&(i.trim()===""||/[\r\n]/.test(i)?e.push("`preview` must be one non-empty line"):n.preview=i);const a=o("summary");a!==void 0&&(n.summary=a);const r=o("why_it_exists");if(r!==void 0&&(n.whyItExists=r),t.privacy!==void 0&&(V.includes(t.privacy)?n.privacy=t.privacy:e.push(`\`privacy\` must be one of ${V.join(", ")}`)),t.unlisted!==void 0&&(typeof t.unlisted!="boolean"?e.push("`unlisted` must be a boolean"):n.unlisted=t.unlisted),t.lint_ignore!==void 0){const s=t.lint_ignore;!Array.isArray(s)||s.some(c=>typeof c!="string")?e.push("`lint_ignore` must be a list of strings"):n.lintIgnore=s}if(t.extensions!==void 0){const s=t.extensions;typeof s!="object"||s===null||Array.isArray(s)||Object.values(s).some(c=>typeof c!="object"||c===null||Array.isArray(c))?e.push("`extensions` must map each plugin to an object of fields"):n.extensions=s}const f=Oe(t.rules,e);return f!==void 0&&(n.rules=f),n}u(Z,"fieldsFrom");function J(t){if(t.length>0)throw b(t.join("; "),{errors:t})}u(J,"failOn");function Q(t,e,n,o){const i=U(n).filter(a=>"remote"in X(t,e,a));return{...o.length>0?{unresolved_links:o}:{},...i.length>0?{remote_links:i}:{}}}u(Q,"linkReport");function $e(t){const e=D(t),n=[],o=e.name;(typeof o!="string"||!Y.test(o))&&n.push("`name` must be segments of letters, digits, `_` or `-` joined by `/`"),typeof e.body!="string"&&n.push("`body` must be a string"),typeof e.preview!="string"&&n.push("`preview` is required");const i=e.kind??"knowledge";q.includes(i)||n.push(i==="report"?"reports are written only by `crtr push`":`\`kind\` must be one of ${q.join(", ")}`);const a=Z(e,n);e.cwd!==void 0&&typeof e.cwd!="string"&&n.push("`cwd` must be a string"),J(n);const r=e,{dto:f,change:s}=k(c=>{const h=E(c,t),d=W(c,h,r.owner,r.cwd);if(!K(c,h,d))throw new g(404,"not_found",`no owner ${d.name} you can write to`);try{const{object:p,unresolved:l}=he(c,h,{...a,owner:d,name:r.name,kind:i,preview:a.preview,privacy:a.privacy??"public"},r.body,x(c));return{dto:{id:p.id,name:j(c,p),...Q(c,h,r.body,l)},change:S(c,h,[p],r.cwd)}}catch(p){C(p)}});return T(s),f}u($e,"write");function Ae(t,e){let n=t;e.forEach(({old:o,new:i},a)=>{const r=o===""?-1:n.indexOf(o);if(r<0)throw _(422,"replace_no_match",`replace[${a}]: old text not found in the revision you read`,"Copy the old text exactly from your last read and rerun.",{index:a});if(n.indexOf(o,r+1)>=0)throw _(422,"replace_ambiguous",`replace[${a}]: old text occurs more than once`,"Include more surrounding text so the old text matches once, and rerun.",{index:a});n=n.slice(0,r)+i+n.slice(r+o.length)})}u(Ae,"checkReplacements");function je(t){const e=D(t),n=[],o=e.body!==void 0,i=e.replace!==void 0;o&&i&&n.push("give `body` or `replace`, not both"),o&&typeof e.body!="string"&&n.push("`body` must be a string");const a=e.replace;i&&(!Array.isArray(a)||a.length===0||a.some(d=>typeof d!="object"||d===null||typeof d.old!="string"||typeof d.new!="string"))&&n.push("`replace` must be a non-empty list of {old, new} strings"),(typeof e.rationale!="string"||e.rationale.trim()==="")&&n.push("`rationale` is required"),e.verbatim!==void 0&&typeof e.verbatim!="boolean"&&n.push("`verbatim` must be a boolean"),e.base!==void 0&&(typeof e.base!="string"||e.base==="")&&n.push("`base` must be a non-empty heads key"),e.base!==void 0&&!o&&!i&&n.push("`base` applies only to a `body` or `replace` edit");const r=Z(e,n),f=e.unset??[];if(!Array.isArray(f)||f.some(d=>!H.includes(d)))n.push(`\`unset\` takes only ${H.join(", ")}`);else for(const d of f)d==="summary"&&(r.summary=null),d==="why_it_exists"&&(r.whyItExists=null),d==="unlisted"&&(r.unlisted=!1),d==="lint_ignore"&&(r.lintIgnore=null),d==="extensions"&&(r.extensions=null),d==="rules"&&(r.rules=[]);!o&&!i&&Object.keys(r).length===0&&n.push("nothing to change: give `body`, `replace`, or a field"),J(n);const s=e,{dto:c,synced:h}=k(d=>{const p=E(d,t),l=B(d,p,t.params.ref),v=j(d,l),$=S(d,p,[l]);try{if(!o&&!i)return me(d,p,l,r),{dto:{id:l.id,name:v,revision:F(d,l).revision},synced:$};const w=s.base??le(d,p,l);if(i&&w!==null){const oe=F(d,l),L=I(d,l);oe.heads_key===w&&L.length===1&&Ae(pe(d,l,A(L[0].body_hash)),s.replace)}const R=s.verbatim===!0,m=o?{body:s.body,verbatim:R}:{replace:s.replace,verbatim:R},y=de(d,p,l,m,s.rationale,w,r,x(d));if("stale"in y)throw _(409,"stale_revision",`${v} changed after your read; it is now at revision ${y.stale.revision}`,`Read it again with \`crtr canvas read ${v}\`, then redo your change on the current text.`,{stale:y.stale});const N=A(I(d,l)[0].body_hash);return{dto:{id:l.id,name:v,revision:y.revision,...Q(d,p,N,y.unresolved)},synced:$}}catch(w){C(w,l)}});return T(h),c}u(je,"edit");function Re(t){const e=D(t);if(e.new_name===void 0&&e.owner===void 0)throw b("give a new name, an owner, or both");if(e.new_name!==void 0&&(typeof e.new_name!="string"||!Y.test(e.new_name)))throw b("`new_name` must be segments of letters, digits, `_` or `-` joined by `/`");const{dto:n,change:o}=k(i=>{const a=E(i,t),r=B(i,a,t.params.ref),f=e.owner===void 0?void 0:W(i,a,e.owner,e.cwd);try{const s=fe(i,a,r,{...e.new_name!==void 0?{name:e.new_name}:{},...f?{owner:f}:{}});return{dto:{id:s.id,name:j(i,s)},change:S(i,a,[r,s],e.cwd)}}catch(s){C(s,r)}});return T(o),n}u(Re,"move");function De(t){const{dto:e,change:n}=k(o=>{const i=E(o,t),a=B(o,i,t.params.ref),r=j(o,a),f=S(o,i,[a]);try{ce(o,i,a,x(o))}catch(s){C(s,a)}return{dto:{id:a.id,name:r},change:f}});return T(n),e}u(De,"remove");function Ce(t){const e=t.query.get("diff"),n=e===null?void 0:Number(e);if(n!==void 0&&!(Number.isInteger(n)&&n>0))throw b("`diff` must be a revision number");return k(o=>{const i=E(o,t),a=z(o,i,decodeURIComponent(t.params.ref));if("remote"in a)throw _(404,"not_found",G(a.remote),"Check the name with `crtr canvas search`.");const r="deleted"in a?a.deleted:a;if(r.type!=="document")throw b(`${r.name} is a ${r.type}, not a document`);const f=ue(o,i,r),s={object:ke(o,r),revisions:f.map(c=>({rev_id:c.rev_id,number:c.number,author_id:c.author,rationale:c.rationale,verbatim:c.verbatim,created_at:c.created_at,parents:c.parents}))};if(n!==void 0){const c=f.find(d=>d.number===n);if(!c)throw new g(404,"not_found",`${r.name} has no revision ${n}`);const h=c.parents[0]===void 0?void 0:f.find(d=>d.rev_id===c.parents[0]);s.diff=_e(h?A(h.body_hash):"",A(c.body_hash))}return s})}u(Ce,"revisionHistory");const ee=1e3,ne=1e3,te=3e3,Se=/^When\b.+\bbecause\b.+/,Te=u(t=>{const e=t.trim();return e===""?0:e.split(/\s+/).length},"words");function Ne(t,e){if(t.some(o=>o.on==="boot"&&o.deliver==="content")&&e>ee)return`body is ${e} words, over the ${ee}-word cap for a boot rule at content (the whole body enters every node's context). Keep the core here and move separate subjects into [[linked]] documents.`;const n=[...new Set(t.filter(o=>o.on!=="boot"&&o.deliver==="content").map(o=>o.on))];return n.length>0&&e>ne?`body is ${e} words, over the ${ne}-word cap for a content rule on ${n.join("/")}. Keep the core here and move separate subjects into [[linked]] documents.`:t.some(o=>o.on==="boot"&&o.deliver==="preview")&&e>te?`body is ${e} words, over the ${te}-word cap for a boot rule at preview. Keep the core here and move separate subjects into [[linked]] documents.`:null}u(Ne,"lengthFinding");function Fe(t){const e=D(t);return k(n=>{const o=E(n,t),i=e.owner===void 0?null:W(n,o,e.owner,e.cwd),a=P(n,"SELECT * FROM objects WHERE type = 'document' AND deleted_at IS NULL AND kind != 'report' ORDER BY name").all(),r=[],f=new Map;for(const s of a){if(i&&s.owner!==i.rowid||!K(n,o,s))continue;const c=F(n,s),h=new Set(c.lint_ignore??[]),d=j(n,s),p=u((m,y,N)=>{h.has(m)||r.push({name:d,severity:y,rule:m,message:N})},"add"),l=ge(n,s),v=I(n,s)[0],$=v?A(v.body_hash):"",w=Ne(l,Te($));w&&p("length","error",w),l.some(m=>m.deliver==="preview")&&!Se.test(s.preview??"")&&p("preview-shape","error",`a rule delivers this document at preview, so the preview must read "When <situation in the reader's work>, read this because <what the reader gains>"`);const R=new Set(P(n,"SELECT written_as FROM edges WHERE type = 'links-to' AND src = ?").all(s.rowid).map(m=>m.written_as));for(const m of U($))R.has(m)||"remote"in X(n,o,m)||p("links","warning",`[[${m}]] names no object in your view`);if(l.some(m=>m.on==="workspace-open"&&m.deliver==="content")){const m=ae(n,s);m.type==="repo"&&!h.has("workspace-open")&&f.set(m.name,[...f.get(m.name)??[],d])}}for(const[s,c]of f)if(!(c.length<2))for(const h of c)r.push({name:h,severity:"warning",rule:"workspace-open",message:`repo ${s} has ${c.length} documents delivered at content on workspace-open (${c.join(", ")}); keep one and link the rest from it`});return{findings:r}})}u(Fe,"lint");const O=u((t,e=200)=>n=>({status:e,body:t(n)}),"ok"),Qe=[{method:"POST",pattern:"/v1/docs",handler:O($e,201)},{method:"PATCH",pattern:"/v1/docs/:ref",handler:O(je)},{method:"POST",pattern:"/v1/docs/:ref/move",handler:O(Re)},{method:"DELETE",pattern:"/v1/docs/:ref",handler:O(De)},{method:"GET",pattern:"/v1/docs/:ref/history",handler:O(Ce)},{method:"POST",pattern:"/v1/docs/lint",handler:O(Fe)}];export{Qe as docRoutes};
1
+ var re=Object.defineProperty;var u=(t,e)=>re(t,"name",{value:e,configurable:!0});import{prepared as P}from"../../../core/sqlite-statements.js";import{ApiError as g}from"../../../api/errors.js";import{DOC_KINDS as q,DOC_UNSET_FIELDS as H}from"../../../api/dto/docs.js";import{PRIVACY_LEVELS_DTO as V}from"../../../api/dto/objects.js";import{withCanvasWrite as k}from"../../../core/canvas/db.js";import{CrtrError as ie}from"../../../core/errors.js";import{emitEvent as se}from"../../../core/events/emit.js";import{canChange as K,spaceOf as ae}from"../../../core/graph/access.js";import{get as A}from"../../../core/graph/bodies.js";import{deleteDocument as ce,documentRecord as F,editDocument as de,heads as I,history as ue,linksIn as U,moveDocument as fe,readBase as le,setDocumentRecord as me,withCurrentNames as pe,writeDocument as he}from"../../../core/graph/documents.js";import{resolveName as X}from"../../../core/graph/names.js";import{getByRowid as M}from"../../../core/graph/objects.js";import{noteRepoDocumentsChanged as we}from"../../../core/graph/repo-sync/index.js";import{checkoutsForCwd as ye}from"../../../core/graph/repo-sync/repos.js";import{lintRules as ve,rulesOf as ge}from"../../../core/graph/rules.js";import{unifiedDiff as _e}from"../../../core/graph/diff.js";import{ownerFromFlag as W,readerFor as E,resolveRef as z}from"../reader.js";function _(t,e,n,o,i={}){return new g(t,e,n,{...i,error:e,message:n,next:o})}u(_,"refuse");const b=u((t,e)=>new g(400,"invalid_request",t,e),"invalid");function D(t){const e=t.body;if(e===void 0)return{};if(typeof e!="object"||e===null||Array.isArray(e))throw b("the request body must be a JSON object");return e}u(D,"bodyOf");const x=u(t=>e=>ye(t,e),"reposFnFor");function C(t,e){if(t instanceof ie){const n=t.details;if(t.code==="read_first")throw _(409,"read_first",t.message,`Read it first with \`crtr canvas read ${e?.id??"<ref>"}\`, then rerun the edit.`,n??{});if(t.code==="conflict")throw new g(409,"name_taken",t.message,n);if(t.code==="forbidden")throw new g(403,"forbidden",t.message,n);if(n?.rule==="repo-public-only")throw _(422,"repo_documents_are_public",t.message,'Own it as `user` and add a rule with `if: {"repo": "<handle>"}` so it loads only in that repo.')}throw t}u(C,"mapGraphError");function B(t,e,n){const o=z(t,e,decodeURIComponent(n));if("remote"in o)throw _(404,"not_found",G(o.remote),"Check the name with `crtr canvas search`.");if("deleted"in o)throw new g(404,"not_found",`${o.deleted.name} is deleted`,{id:o.deleted.id,deleted:!0});if(o.type!=="document")throw b(`${n} is a ${o.type}, not a document`);return o}u(B,"refDocument");function G(t){return`no object named ${t} on this runtime; it may be on another runtime, or the name may be misspelled`}u(G,"remoteMessage");function be(t,e){const n=e.owner===null?null:M(t,e.owner);return n?n.type==="node"?n.id:n.name:""}u(be,"ownerHandle");function j(t,e){const n=be(t,e);return n?`${n}/${e.name}`:e.name}u(j,"canonicalName");function ke(t,e){const n=e.owner===null?null:M(t,e.owner),o=n?{id:n.id,type:n.type,handle:n.type==="node"?n.id:n.name}:null;return{id:e.id,type:e.type,kind:e.kind,owner:o,privacy:e.privacy,name:e.name,preview:e.preview??"",created_at:e.created_at,deleted_at:e.deleted_at}}u(ke,"objectDTO");function Ee(t,e){const n=e.owner===null?null:M(t,e.owner);return n?.type==="repo"?n:null}u(Ee,"repoOwner");function S(t,e,n,o){const i=[...new Map(n.flatMap(r=>{const f=Ee(t,r);return f?[[f.id,f]]:[]})).values()],a=e.class==="node"?e.cwd:o;return{repos:i,...a!==void 0?{cwd:a}:{}}}u(S,"repoChange");function T(t){for(const e of t.repos)try{we(e,t.cwd)}catch(n){se({level:"warn",event:"repo_sync.failed",outcome:"failed",error:n,fields:{repo:e.name,step:"export",reason:n instanceof Error?n.message:String(n)}})}}u(T,"syncChanged");const Y=/^[A-Za-z0-9_-]+(\/[A-Za-z0-9_-]+)*$/;function Oe(t,e){if(t===void 0)return;if(!Array.isArray(t)){e.push("`rules` must be a list");return}const n=t.map(i=>{if(typeof i!="object"||i===null||Array.isArray(i))return i;const{match_frontmatter:a,...r}=i;return"matchFrontmatter"in r?{...r,match_frontmatter:r.matchFrontmatter}:a===void 0?r:{...r,matchFrontmatter:a}}),o=ve(n);if(o){e.push(o.replaceAll("matchFrontmatter","match_frontmatter"));return}return n}u(Oe,"rulesFromDTO");function Z(t,e){const n={},o=u(s=>{const c=t[s];if(c!==void 0){if(typeof c!="string"){e.push(`\`${s}\` must be a string`);return}return c}},"str"),i=o("preview");i!==void 0&&(i.trim()===""||/[\r\n]/.test(i)?e.push("`preview` must be one non-empty line"):n.preview=i);const a=o("summary");a!==void 0&&(n.summary=a);const r=o("why_it_exists");if(r!==void 0&&(n.whyItExists=r),t.privacy!==void 0&&(V.includes(t.privacy)?n.privacy=t.privacy:e.push(`\`privacy\` must be one of ${V.join(", ")}`)),t.unlisted!==void 0&&(typeof t.unlisted!="boolean"?e.push("`unlisted` must be a boolean"):n.unlisted=t.unlisted),t.lint_ignore!==void 0){const s=t.lint_ignore;!Array.isArray(s)||s.some(c=>typeof c!="string")?e.push("`lint_ignore` must be a list of strings"):n.lintIgnore=s}if(t.extensions!==void 0){const s=t.extensions;typeof s!="object"||s===null||Array.isArray(s)||Object.values(s).some(c=>typeof c!="object"||c===null||Array.isArray(c))?e.push("`extensions` must map each plugin to an object of fields"):n.extensions=s}const f=Oe(t.rules,e);return f!==void 0&&(n.rules=f),n}u(Z,"fieldsFrom");function J(t){if(t.length>0)throw b(t.join("; "),{errors:t})}u(J,"failOn");function Q(t,e,n,o){const i=U(n).filter(a=>"remote"in X(t,e,a));return{...o.length>0?{unresolved_links:o}:{},...i.length>0?{remote_links:i}:{}}}u(Q,"linkReport");function $e(t){const e=D(t),n=[],o=e.name;(typeof o!="string"||!Y.test(o))&&n.push("`name` must be segments of letters, digits, `_` or `-` joined by `/`"),typeof e.body!="string"&&n.push("`body` must be a string"),typeof e.preview!="string"&&n.push("`preview` is required");const i=e.kind??"knowledge";q.includes(i)||n.push(i==="report"?"reports are written only by `crtr push`":`\`kind\` must be one of ${q.join(", ")}`);const a=Z(e,n);e.cwd!==void 0&&typeof e.cwd!="string"&&n.push("`cwd` must be a string"),J(n);const r=e,{dto:f,change:s}=k(c=>{const h=E(c,t),d=W(c,h,r.owner,r.cwd);if(!K(c,h,d))throw new g(404,"not_found",`no owner ${d.name} you can write to`);try{const{object:p,unresolved:l}=he(c,h,{...a,owner:d,name:r.name,kind:i,preview:a.preview,privacy:a.privacy??"public"},r.body,x(c));return{dto:{id:p.id,name:j(c,p),...Q(c,h,r.body,l)},change:S(c,h,[p],r.cwd)}}catch(p){C(p)}});return T(s),f}u($e,"write");function Ae(t,e){let n=t;e.forEach(({old:o,new:i},a)=>{const r=o===""?-1:n.indexOf(o);if(r<0)throw _(422,"replace_no_match",`replace[${a}]: old text not found in the revision you read`,"Copy the old text exactly from your last read and rerun.",{index:a});if(n.indexOf(o,r+1)>=0)throw _(422,"replace_ambiguous",`replace[${a}]: old text occurs more than once`,"Include more surrounding text so the old text matches once, and rerun.",{index:a});n=n.slice(0,r)+i+n.slice(r+o.length)})}u(Ae,"checkReplacements");function je(t){const e=D(t),n=[],o=e.body!==void 0,i=e.replace!==void 0;o&&i&&n.push("give `body` or `replace`, not both"),o&&typeof e.body!="string"&&n.push("`body` must be a string");const a=e.replace;i&&(!Array.isArray(a)||a.length===0||a.some(d=>typeof d!="object"||d===null||typeof d.old!="string"||typeof d.new!="string"))&&n.push("`replace` must be a non-empty list of {old, new} strings"),(typeof e.rationale!="string"||e.rationale.trim()==="")&&n.push("`rationale` is required"),e.verbatim!==void 0&&typeof e.verbatim!="boolean"&&n.push("`verbatim` must be a boolean"),e.base!==void 0&&(typeof e.base!="string"||e.base==="")&&n.push("`base` must be a non-empty heads key"),e.base!==void 0&&!o&&!i&&n.push("`base` applies only to a `body` or `replace` edit");const r=Z(e,n),f=e.unset??[];if(!Array.isArray(f)||f.some(d=>!H.includes(d)))n.push(`\`unset\` takes only ${H.join(", ")}`);else for(const d of f)d==="summary"&&(r.summary=null),d==="why_it_exists"&&(r.whyItExists=null),d==="unlisted"&&(r.unlisted=!1),d==="lint_ignore"&&(r.lintIgnore=null),d==="extensions"&&(r.extensions=null),d==="rules"&&(r.rules=[]);n.length===0&&!o&&!i&&Object.keys(r).length===0&&n.push("nothing to change: give `body`, `replace`, or a field"),J(n);const s=e,{dto:c,synced:h}=k(d=>{const p=E(d,t),l=B(d,p,t.params.ref),v=j(d,l),$=S(d,p,[l]);try{if(!o&&!i)return me(d,p,l,r),{dto:{id:l.id,name:v,revision:F(d,l).revision},synced:$};const w=s.base??le(d,p,l);if(i&&w!==null){const oe=F(d,l),L=I(d,l);oe.heads_key===w&&L.length===1&&Ae(pe(d,l,A(L[0].body_hash)),s.replace)}const R=s.verbatim===!0,m=o?{body:s.body,verbatim:R}:{replace:s.replace,verbatim:R},y=de(d,p,l,m,s.rationale,w,r,x(d));if("stale"in y)throw _(409,"stale_revision",`${v} changed after your read; it is now at revision ${y.stale.revision}`,`Read it again with \`crtr canvas read ${v}\`, then redo your change on the current text.`,{stale:y.stale});const N=A(I(d,l)[0].body_hash);return{dto:{id:l.id,name:v,revision:y.revision,...Q(d,p,N,y.unresolved)},synced:$}}catch(w){C(w,l)}});return T(h),c}u(je,"edit");function Re(t){const e=D(t);if(e.new_name===void 0&&e.owner===void 0)throw b("give a new name, an owner, or both");if(e.new_name!==void 0&&(typeof e.new_name!="string"||!Y.test(e.new_name)))throw b("`new_name` must be segments of letters, digits, `_` or `-` joined by `/`");const{dto:n,change:o}=k(i=>{const a=E(i,t),r=B(i,a,t.params.ref),f=e.owner===void 0?void 0:W(i,a,e.owner,e.cwd);try{const s=fe(i,a,r,{...e.new_name!==void 0?{name:e.new_name}:{},...f?{owner:f}:{}});return{dto:{id:s.id,name:j(i,s)},change:S(i,a,[r,s],e.cwd)}}catch(s){C(s,r)}});return T(o),n}u(Re,"move");function De(t){const{dto:e,change:n}=k(o=>{const i=E(o,t),a=B(o,i,t.params.ref),r=j(o,a),f=S(o,i,[a]);try{ce(o,i,a,x(o))}catch(s){C(s,a)}return{dto:{id:a.id,name:r},change:f}});return T(n),e}u(De,"remove");function Ce(t){const e=t.query.get("diff"),n=e===null?void 0:Number(e);if(n!==void 0&&!(Number.isInteger(n)&&n>0))throw b("`diff` must be a revision number");return k(o=>{const i=E(o,t),a=z(o,i,decodeURIComponent(t.params.ref));if("remote"in a)throw _(404,"not_found",G(a.remote),"Check the name with `crtr canvas search`.");const r="deleted"in a?a.deleted:a;if(r.type!=="document")throw b(`${r.name} is a ${r.type}, not a document`);const f=ue(o,i,r),s={object:ke(o,r),revisions:f.map(c=>({rev_id:c.rev_id,number:c.number,author_id:c.author,rationale:c.rationale,verbatim:c.verbatim,created_at:c.created_at,parents:c.parents}))};if(n!==void 0){const c=f.find(d=>d.number===n);if(!c)throw new g(404,"not_found",`${r.name} has no revision ${n}`);const h=c.parents[0]===void 0?void 0:f.find(d=>d.rev_id===c.parents[0]);s.diff=_e(h?A(h.body_hash):"",A(c.body_hash))}return s})}u(Ce,"revisionHistory");const ee=1e3,ne=1e3,te=3e3,Se=/^When\b.+\bbecause\b.+/,Te=u(t=>{const e=t.trim();return e===""?0:e.split(/\s+/).length},"words");function Ne(t,e){if(t.some(o=>o.on==="boot"&&o.deliver==="content")&&e>ee)return`body is ${e} words, over the ${ee}-word cap for a boot rule at content (the whole body enters every node's context). Keep the core here and move separate subjects into [[linked]] documents.`;const n=[...new Set(t.filter(o=>o.on!=="boot"&&o.deliver==="content").map(o=>o.on))];return n.length>0&&e>ne?`body is ${e} words, over the ${ne}-word cap for a content rule on ${n.join("/")}. Keep the core here and move separate subjects into [[linked]] documents.`:t.some(o=>o.on==="boot"&&o.deliver==="preview")&&e>te?`body is ${e} words, over the ${te}-word cap for a boot rule at preview. Keep the core here and move separate subjects into [[linked]] documents.`:null}u(Ne,"lengthFinding");function Fe(t){const e=D(t);return k(n=>{const o=E(n,t),i=e.owner===void 0?null:W(n,o,e.owner,e.cwd),a=P(n,"SELECT * FROM objects WHERE type = 'document' AND deleted_at IS NULL AND kind != 'report' ORDER BY name").all(),r=[],f=new Map;for(const s of a){if(i&&s.owner!==i.rowid||!K(n,o,s))continue;const c=F(n,s),h=new Set(c.lint_ignore??[]),d=j(n,s),p=u((m,y,N)=>{h.has(m)||r.push({name:d,severity:y,rule:m,message:N})},"add"),l=ge(n,s),v=I(n,s)[0],$=v?A(v.body_hash):"",w=Ne(l,Te($));w&&p("length","error",w),l.some(m=>m.deliver==="preview")&&!Se.test(s.preview??"")&&p("preview-shape","error",`a rule delivers this document at preview, so the preview must read "When <situation in the reader's work>, read this because <what the reader gains>"`);const R=new Set(P(n,"SELECT written_as FROM edges WHERE type = 'links-to' AND src = ?").all(s.rowid).map(m=>m.written_as));for(const m of U($))R.has(m)||"remote"in X(n,o,m)||p("links","warning",`[[${m}]] names no object in your view`);if(l.some(m=>m.on==="workspace-open"&&m.deliver==="content")){const m=ae(n,s);m.type==="repo"&&!h.has("workspace-open")&&f.set(m.name,[...f.get(m.name)??[],d])}}for(const[s,c]of f)if(!(c.length<2))for(const h of c)r.push({name:h,severity:"warning",rule:"workspace-open",message:`repo ${s} has ${c.length} documents delivered at content on workspace-open (${c.join(", ")}); keep one and link the rest from it`});return{findings:r}})}u(Fe,"lint");const O=u((t,e=200)=>n=>({status:e,body:t(n)}),"ok"),Qe=[{method:"POST",pattern:"/v1/docs",handler:O($e,201)},{method:"PATCH",pattern:"/v1/docs/:ref",handler:O(je)},{method:"POST",pattern:"/v1/docs/:ref/move",handler:O(Re)},{method:"DELETE",pattern:"/v1/docs/:ref",handler:O(De)},{method:"GET",pattern:"/v1/docs/:ref/history",handler:O(Ce)},{method:"POST",pattern:"/v1/docs/lint",handler:O(Fe)}];export{Qe as docRoutes};
@@ -1,4 +1,4 @@
1
- var A=Object.defineProperty;var a=(e,t)=>A(e,"name",{value:t,configurable:!0});import{randomBytes as O}from"node:crypto";import{joinedOwner as E}from"../../core/directory/join.js";import{consumeHandoffJti as j,handoffJtiConsumed as y}from"../../core/model-auth/handoff-jti.js";import{completeModelAuthFlow as I,modelAuthProvider as N,readModelAuthFlow as M,startModelAuthFlow as P,waitModelAuthFlow as L}from"../../core/model-auth/flows.js";import{RunError as d}from"../../core/runs/operations.js";import{LONG_POLL_MAX_WAIT_SECONDS as R}from"../../api/long-poll.js";const c="/signin/vendor",z=900,B=R*1e3,G="https://chatgpt.com/#settings/Security";function se(e){return e===c||e.startsWith(`${c}/`)}a(se,"isVendorSignInPath");function f(){return new d(401,"unauthorized","invalid vendor sign-in handoff")}a(f,"unauthorized");async function k(e,t){const n=await e.verifyHandoff(t);let r;try{r=E()}catch{r=null}if(n.sub!==r)throw f();return n}a(k,"verifyOwnerHandoff");function U(e){const t=e.headers.authorization;return t?.startsWith("Bearer ")&&t.length>7?t.slice(7):void 0}a(U,"bearer");function x(e,t){const n=e.getAll(t);return n.length===1?n[0]:void 0}a(x,"single");function H(e,t){const n=new URL(e);return n.searchParams.set("status",t),n.toString()}a(H,"returnUrl");function u(e){return e.replace(/[&<>"']/g,t=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[t])}a(u,"escapeHtml");function m(e,t,n){e.writeHead(t,{"Content-Type":"application/json; charset=utf-8","Cache-Control":"no-store"}),e.end(JSON.stringify(n))}a(m,"sendJson");async function J(e){const t=[];let n=0;for await(const i of e){if(n+=i.length,n>64*1024)throw new d(400,"invalid_request","request body too large");t.push(i)}let r;try{r=JSON.parse(Buffer.concat(t).toString("utf8"))}catch{throw new d(400,"invalid_request","invalid JSON body")}if(typeof r!="object"||r===null||Array.isArray(r))throw new d(400,"invalid_request","request body must be a JSON object");return r}a(J,"jsonBody");const D=`
1
+ var _=Object.defineProperty;var a=(e,t)=>_(e,"name",{value:t,configurable:!0});import{randomBytes as A}from"node:crypto";import{joinedOwner as O}from"../../core/directory/join.js";import{consumeHandoffJti as E,handoffJtiConsumed as x}from"../../core/model-auth/handoff-jti.js";import{completeModelAuthFlow as j,modelAuthProvider as I,readModelAuthFlow as C,startModelAuthFlow as N,waitModelAuthFlow as P}from"../../core/model-auth/flows.js";import{RunError as d}from"../../core/runs/operations.js";import{LONG_POLL_MAX_WAIT_SECONDS as R}from"../../api/long-poll.js";const c="/signin/vendor",y=900,H=R*1e3,V="https://chatgpt.com/#settings/Security";function s1(e){return e===c||e.startsWith(`${c}/`)}a(s1,"isVendorSignInPath");function f(){return new d(401,"unauthorized","invalid vendor sign-in handoff")}a(f,"unauthorized");async function M(e,t){const n=await e.verifyHandoff(t);let r;try{r=O()}catch{r=null}if(n.sub!==r)throw f();return n}a(M,"verifyOwnerHandoff");function D(e){const t=e.headers.authorization;return t?.startsWith("Bearer ")&&t.length>7?t.slice(7):void 0}a(D,"bearer");function w(e,t){const n=e.getAll(t);return n.length===1?n[0]:void 0}a(w,"single");function B(e,t){const n=new URL(e);return n.searchParams.set("status",t),n.toString()}a(B,"returnUrl");function u(e){return e.replace(/[&<>"']/g,t=>({"&":"&amp;","<":"&lt;",">":"&gt;",'"':"&quot;","'":"&#39;"})[t])}a(u,"escapeHtml");function m(e,t,n){e.writeHead(t,{"Content-Type":"application/json; charset=utf-8","Cache-Control":"no-store"}),e.end(JSON.stringify(n))}a(m,"sendJson");async function G(e){const t=[];let n=0;for await(const i of e){if(n+=i.length,n>64*1024)throw new d(400,"invalid_request","request body too large");t.push(i)}let r;try{r=JSON.parse(Buffer.concat(t).toString("utf8"))}catch{throw new d(400,"invalid_request","invalid JSON body")}if(typeof r!="object"||r===null||Array.isArray(r))throw new d(400,"invalid_request","request body must be a JSON object");return r}a(G,"jsonBody");const F=`
2
2
  :root{color-scheme:light dark;
3
3
  --canvas:#f0f2f4;--surface:#fff;--sunken:#e5e7ea;--zone:#e5e7ea;--neutral:#e5e7ea;--neutral-hover:#d7d9dc;--neutral-pressed:#cbcdd0;
4
4
  --accent:#217f51;--accent-hover:#1e6e46;--accent-pressed:#1a5e3c;--accent-border:#217f51;--accent-subtle:#d5f7e1;--accent-fg:#1e6e46;--on-accent:#fff;
@@ -84,7 +84,7 @@ form{display:flex;flex-direction:column;gap:.75rem}
84
84
  @keyframes spin{to{transform:rotate(360deg)}}
85
85
  @media (min-width:40rem){.top{padding:0 1.5rem}main{padding:3.5rem 1rem}}
86
86
  @media (max-width:30rem){.card{padding:1.25rem}.btn{padding-left:.875rem;padding-right:.875rem}#device-link{font-size:.84375rem}.steps>li{gap:.75rem}.alert .act{margin-left:1.875rem}}
87
- `,q=`
87
+ `,U=`
88
88
  (function(){
89
89
  var cfg=JSON.parse(document.getElementById('cfg').textContent);
90
90
  history.replaceState(null,'',location.pathname);
@@ -147,18 +147,18 @@ if(cfg.kind==='anthropic'){
147
147
  })();
148
148
  }
149
149
  })();
150
- `,F={arrow:'<path d="M7 7h10v10"/><path d="M7 17 17 7"/>',copy:'<rect width="14" height="14" x="8" y="8" rx="2" ry="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/>',clock:'<circle cx="12" cy="12" r="10"/><path d="M12 6v6l4 2"/>',warn:'<path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3"/><path d="M12 9v4"/><path d="M12 17h.01"/>',alert:'<circle cx="12" cy="12" r="10"/><path d="M12 8v4"/><path d="M12 16h.01"/>',check:'<path d="M20 6 9 18l-5-5"/>'};function s(e,t=""){return`<svg class="ic${t}" viewBox="0 0 24 24" aria-hidden="true" focusable="false">${F[e]}</svg>`}a(s,"icon");const W='<svg viewBox="-77.5 12 931 931" aria-hidden="true" focusable="false"><path fill="currentColor" d="M234 294m0 0h2l-1 5-6 16-5 15-6 25-4 23-2 22-1 5v47l5 38 5 26 6 22 10 24 8 16 9 14 14 19 13 16 11 13 9 11 11 12 7 8 13 16 11 14 14 19 12 19 12 23 7 17 6 23 3 14 3-1 5-15 20-84 6-24 6-21 10-33 10-25 8-16 8-15 8-12 9-12 8-10 9-10 7-8 6-7 20-20h2l2-4 17-17 7-8 10-13 14-21 8-16 8-18 5-15 2-7 2 1 6 36 2 18v41l-4 28-5 19-7 19-10 21-8 13-10 15-13 17-11 13-12 14-9 10-7 8-9 11h-2l-2 4-9 11-14 19-8 12-15 25-11 21-12 26-9 23-5 12-13 38-12 39-5 18-5 17h-2l-9-29-9-27-14-38-13-29-8-16-11-18-10-13-7-9-25-25-3-2v-2l-3-1v-2l-4-2-10-9-8-7-14-12-20-18-13-13-9-11-12-16-12-20-12-25-7-19-6-23-4-24-1-11-1-3v-39l3-23 6-27 7-23 5-11 11-23 9-16 10-14 8-11 9-11 10-11zM430 22m0 0h2v2h2l7 8 10 11 9 11 12 16 9 15 8 16 6 15 5 19 2 11 1 12v18l-1 16-5 24-5 16-7 15-9 17-7 11-10 15-10 13-9 11-13 14-7 8-11 12-7 8-13 16-11 15-13 20-10 18-8 16-7 18-5 15-4 18-2 14-1 27 2 24 3 17 5 23 8 30 12 36 9 28 3 8 4 12v2l-4-2-68-102-13-22-11-23-9-24-7-26-4-23-2-16v-31l3-25 6-27 7-21 7-15 8-16 14-21 11-14 26-30 12-13 8-10h2l2-4 10-11 7-9 14-19 7-10 13-24 7-19 4-15 3-14 3-22 2-24v-20l-2-31zM615 384m0 0 2 1 6 36 2 18v41l-4 28-5 19-7 19-10 21-8 13-10 15-13 17-11 13-12 14-9 10-7 8-9 11h-2l-2 4-9 11-14 19-8 12-15 25-11 21-2 5h-3l-2 2h-13l-6-5-11-6 1-9h-2l2-14-2 3 1-8 9-36 6-21 10-33 10-25 8-16 8-15 8-12 9-12 8-10 9-10 7-8 6-7 20-20h2l2-4 17-17 7-8 10-13 14-21 8-16 8-18 5-15zM557 254m0 0 2 1 4 16 2 16v34l-2 18-5 20-8 24-14 28-10 16-11 16-13 15-12 14-11 13-11 14-14 19-12 20-8 16-7 19-6 20-4 20-4 35-3 41-3 52-4 28-1 3h-2l-8-42-10-52-7-33-7-43v-54l4-24 5-17 8-20 10-19 7-10 10-13 9-11 19-19 8-7 16-15 8-7 9-9 8-7 11-11 1-2h2l2-4 11-13 10-14 11-17 9-19 8-21zM185 615m0 0 4 5 6 10 9 12 2 1 3 5 5-2 1-1h8l5 5 2 3 7 3 6 3 4 5 8 6 5 3v2h2v2h6l4 3 6 1 1 8 10 3 4 2 9 2 5 6 6 1h6l8 8 7 1 9 7h5l1-4-4-6-10-13-7-9-1-3h-2l-7-9v-3l7 6 7 9 11 14 14 19 12 19 12 23 7 17 6 23 3 14 3-1 5-15 10-42 5-22h2l1-4 1 4-1 8h-2l3 4-1 8 11 6 5 4h13l4-3-1 6-8 17-9 23-5 12-13 38-12 39-5 18-5 17h-2l-9-29-9-27-14-38-13-29-8-16-11-18-10-13-7-9-25-25-3-2v-2l-3-1v-2l-4-2-10-9-8-7-14-12-20-18-13-13-9-11-12-16-9-15zM369 553m0 0h1l1 43 2 3 3 4-1 6-1 1v7l1 2 1 15 7 1 5-2 5 1v-2l3-1 4 1 1-2h-3l1-3 6-2 2 11-1 8-3 12h2v2l3-1 2-12h-2l1-4 1-1 3-21 4-21h1v10l-4 30-3 34-4 69-4 28-1 3h-2l-8-42-10-52-7-33-6-37zM430 22m0 0h2v2h2l7 8 10 11 9 11 4 5 1 5 2 4 1 7 2 2-1 3-5-1h-7l-8-2-5 1v7l-1 1h-5l-2-8-1-2-1-15h-2l-2-31zM417 598m0 0h1v10l-4 30-3 34-4 69-4 28-1 3h-2l-7-37-1-16h8l2 1v-2h2l1-2 2-35v-13l-2-3-3-5-1-8 1-9-1-4-5-2v-2l-3-1v-2l3-1 4 1 1-2h-3l1-3 6-2 2 11-1 8-3 12h2v2l3-1 2-12h-2l1-4 1-1 3-21zM417 598m0 0h1v10l-4 30-3 34-1 17h-2v15l-1 12h-1v-18l1-17v-13l-2-3-3-5-1-8 1-9-1-4-5-2v-2l-3-1v-2l3-1 4 1 1-2h-3l1-3 6-2 2 11-1 8-3 12h2v2l3-1 2-12h-2l1-4 1-1 3-21zM310 619m0 0 4 2 4 6 5 8 7 9 3 5 2-1 2 1 2 10 6-1 2 1v2h-5l3 7 9 13 6 9 3 1v-2l-4-14h3l5 16 3 8 4 12v2l-4-2-60-90zM255 597m0 0 5 3 12 16 9 11 11 13 9 11 11 12 4 5-1 3-7-7-4-1-7-4v-2l-4-2-4-4 4 1 3-1v-3l-5-2-3-5v-2h-2l-6-8v-2l-3-1-1-2-8-1 1-2-2-8-3-4v-2h-2l-4-6-3-4zM425 181m0 0 7 1 1 3 12 2 2 3 3 1v-2h3l1 3-6 2-1 3h-2v2h-2l-1 7-5 1-2-5 2-3h3l1-5-3 1-3 3-1-4-5-2v-5h-6l-3-3zM369 553m0 0h1l1 43 2 3 3 4-1 6-1 1v7l1 2 1 15 2 1h-2l3 13 2 10v5l-3-4-5-25-4-26zM340 614m0 0 1 2h2l6 20 6 18 3 15-2-1-5-15-2-4v-5h-6l-3-2-9-2 2-3v2l5-4h4 2l-1-5-3-12zM296 649m0 0 5 2 11 12 4 5-1 3-7-7-4-1-7-4v-2l-4-2-4-4 4 1 3-1zM403 625m0 0h2l2 11-1 8-2 7-2 1v-9l-1-4-5-2v-2l-3-1v-2l3-1 4 1 1-2h-3l1-3zM417 598m0 0h1v10l-4 30-2 24h-1l-1-17h-2l1-4 1-1 3-21zM163 561m0 0 2 3 5 16 2 6 2 1 3 9 2 4 4-1 1-2 1 3h-2l-2 5 3 6-1 2-3-3-11-24-4-11-2-10zM439 685m0 0 1 2h9l3 4v6l7 2 3 7-4-1-6-4-5-4v-7h-9l-2-2zM369 553m0 0h1l1 43 2 3 3 4-1 6-1 1-1 7-2-2v-7h-2zM434 687m0 0h1v6l-3 9-7 29-4 5 1-8 9-36zM317 672m0 0 6 4 9 11 11 14 6 8v2l-4-2-10-13-7-9-1-3h-2l-7-9zM276 622m0 0 5 5 11 13 7 8-1 2-7-4-3-5v-2h-2l-6-8v-2l-3-1-2-4zM310 619m0 0 4 2 4 6 5 8 7 9-1 4-4-5-8-11-7-11zM416 172m0 0 2 1-1 7h-2v5l4-1-1 3-5 2-3-1v-7l4-8zM381 664m0 0 2 4 6 27v5l-1-2h-2l-5-24zM443 655m0 0 1 4-7 25-1 2h-2l1-7 6-22h2zM163 561m0 0 2 3 5 16 2 6 2 1v5l-2 1-7-18-2-10zM490 702m0 0 1 3-10 15-3 5-4 3v-5l5-5 7-11zM387 698m0 0 1 2h2l3 16v14h-1l-5-26zM426 139m0 0 1 3-1 5-7 22-2-1 2-9 5-18h2zM466 739m0 0h2l-1 6-8 15-3 1 2-7 7-12zM411 636m0 0h2v12l-1 14h-1l-1-17h-2l1-4zM349 645m0 0h3l3 9 3 15-2-1-5-15-2-4zM335 694m0 0 5 3 9 12v2l-4-2-10-13zM386 633m0 0 7 1-3 2-4 1-2 4h-4l-2-6h5zM547 287m0 0 3 2-3 7-1 5h-2l-1 4-2-1 1-5zM557 254m0 0 2 1 3 13-4-1 1-2h-2l-1 3-1-3zM560 311m0 0 3 1-2 5-3 6-9-3v-1l9-1zM409 664m0 0h1v25h-1l-2-24zM340 614m0 0 1 2h2l4 16-4-2-3-12zM438 705m0 0 10 2 1 7-3-1-4-4h-5zM502 685m0 0 1 3-8 11-3 1 2-5zM422 191m0 0 4 1 3 4-2 4-5-3zM359 675m0 0h3l4 13-1 4-4-9zM225 599m0 0 5 2 12 6-3 1-9-4-6-3zM255 597m0 0 5 3 6 8-1 2-3-1-4-6-3-4zM414 180m0 0h1v5l4-1-1 3-5 2-3-1 1-5zM341 665m0 0 3 1 6 9-1 4-8-12zM370 608m0 0h1l1 9 3 1-2 10h-1l-2-12zM439 671m0 0 1 2-4 13h-2l1-7 3-7zM341 658m0 0 6 1v2h-5l-1 5-3-3 1-4zM373 625m0 0h2l1 9 2 1h-2l-1 5h-1l-1-6zM185 615m0 0 4 5 5 8-1 3-4-5-4-7zM434 687m0 0h1v6l-3 9-2 3 1-13zM385 686m0 0h2l2 9v5l-1-2h-2l-1-5zM390 711m0 0h2l1 8v11h-1l-2-10zM355 657m0 0 2 3 4 12v3l-3-1-2-10zM413 624m0 0h1v14l-1-2h-2l1-11zM494 120m0 0h2l2 6v10l-2-3-2-9zM163 561m0 0 2 3 4 13-1 3v-2h-2l-3-13zM489 106m0 0h2l4 10-2 4-4-11zM230 609m0 0 5 1 4 5 3 2-6-1-3-3v-2l-3-1zM392 660m0 0h2v2h2l5 5 2 1-1 4-10-10zM254 615m0 0 8 1 1 1v5l-2-1v-2l-6-2zM190 587m0 0 6 1 2-1 4 2 1 3-13-2zM417 598m0 0h1v10l-1 5-2-1 1-9zM273 545m0 0 2 3 3 8v3h-2l-3-8z"/></svg>',V={claude:'<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><rect width="24" height="24" fill="#d97757"/><path d="M12 5v14M5 12h14M7 7l10 10M17 7 7 17" stroke="#fff" stroke-width="1.8" stroke-linecap="round"/></svg>',chatgpt:'<svg viewBox="0 0 24 24" aria-hidden="true" focusable="false"><rect width="24" height="24" fill="#141816"/><circle cx="12" cy="12" r="5.5" fill="none" stroke="#fff" stroke-width="1.8"/></svg>'},$="team@northlight.ai";function C(e){const t=JSON.stringify(e.config).replace(/</g,"\\u003c");return`<!doctype html>
150
+ `,J={arrow:'<path d="M7 7h10v10"/><path d="M7 17 17 7"/>',copy:'<rect width="14" height="14" x="8" y="8" rx="2" ry="2"/><path d="M4 16c-1.1 0-2-.9-2-2V4c0-1.1.9-2 2-2h10c1.1 0 2 .9 2 2"/>',clock:'<circle cx="12" cy="12" r="10"/><path d="M12 6v6l4 2"/>',warn:'<path d="m21.73 18-8-14a2 2 0 0 0-3.48 0l-8 14A2 2 0 0 0 4 21h16a2 2 0 0 0 1.73-3"/><path d="M12 9v4"/><path d="M12 17h.01"/>',alert:'<circle cx="12" cy="12" r="10"/><path d="M12 8v4"/><path d="M12 16h.01"/>',check:'<path d="M20 6 9 18l-5-5"/>'};function s(e,t=""){return`<svg class="ic${t}" viewBox="0 0 24 24" aria-hidden="true" focusable="false">${J[e]}</svg>`}a(s,"icon");const Z='<svg viewBox="-77.5 12 931 931" aria-hidden="true" focusable="false"><path fill="currentColor" d="M234 294m0 0h2l-1 5-6 16-5 15-6 25-4 23-2 22-1 5v47l5 38 5 26 6 22 10 24 8 16 9 14 14 19 13 16 11 13 9 11 11 12 7 8 13 16 11 14 14 19 12 19 12 23 7 17 6 23 3 14 3-1 5-15 20-84 6-24 6-21 10-33 10-25 8-16 8-15 8-12 9-12 8-10 9-10 7-8 6-7 20-20h2l2-4 17-17 7-8 10-13 14-21 8-16 8-18 5-15 2-7 2 1 6 36 2 18v41l-4 28-5 19-7 19-10 21-8 13-10 15-13 17-11 13-12 14-9 10-7 8-9 11h-2l-2 4-9 11-14 19-8 12-15 25-11 21-12 26-9 23-5 12-13 38-12 39-5 18-5 17h-2l-9-29-9-27-14-38-13-29-8-16-11-18-10-13-7-9-25-25-3-2v-2l-3-1v-2l-4-2-10-9-8-7-14-12-20-18-13-13-9-11-12-16-12-20-12-25-7-19-6-23-4-24-1-11-1-3v-39l3-23 6-27 7-23 5-11 11-23 9-16 10-14 8-11 9-11 10-11zM430 22m0 0h2v2h2l7 8 10 11 9 11 12 16 9 15 8 16 6 15 5 19 2 11 1 12v18l-1 16-5 24-5 16-7 15-9 17-7 11-10 15-10 13-9 11-13 14-7 8-11 12-7 8-13 16-11 15-13 20-10 18-8 16-7 18-5 15-4 18-2 14-1 27 2 24 3 17 5 23 8 30 12 36 9 28 3 8 4 12v2l-4-2-68-102-13-22-11-23-9-24-7-26-4-23-2-16v-31l3-25 6-27 7-21 7-15 8-16 14-21 11-14 26-30 12-13 8-10h2l2-4 10-11 7-9 14-19 7-10 13-24 7-19 4-15 3-14 3-22 2-24v-20l-2-31zM615 384m0 0 2 1 6 36 2 18v41l-4 28-5 19-7 19-10 21-8 13-10 15-13 17-11 13-12 14-9 10-7 8-9 11h-2l-2 4-9 11-14 19-8 12-15 25-11 21-2 5h-3l-2 2h-13l-6-5-11-6 1-9h-2l2-14-2 3 1-8 9-36 6-21 10-33 10-25 8-16 8-15 8-12 9-12 8-10 9-10 7-8 6-7 20-20h2l2-4 17-17 7-8 10-13 14-21 8-16 8-18 5-15zM557 254m0 0 2 1 4 16 2 16v34l-2 18-5 20-8 24-14 28-10 16-11 16-13 15-12 14-11 13-11 14-14 19-12 20-8 16-7 19-6 20-4 20-4 35-3 41-3 52-4 28-1 3h-2l-8-42-10-52-7-33-7-43v-54l4-24 5-17 8-20 10-19 7-10 10-13 9-11 19-19 8-7 16-15 8-7 9-9 8-7 11-11 1-2h2l2-4 11-13 10-14 11-17 9-19 8-21zM185 615m0 0 4 5 6 10 9 12 2 1 3 5 5-2 1-1h8l5 5 2 3 7 3 6 3 4 5 8 6 5 3v2h2v2h6l4 3 6 1 1 8 10 3 4 2 9 2 5 6 6 1h6l8 8 7 1 9 7h5l1-4-4-6-10-13-7-9-1-3h-2l-7-9v-3l7 6 7 9 11 14 14 19 12 19 12 23 7 17 6 23 3 14 3-1 5-15 10-42 5-22h2l1-4 1 4-1 8h-2l3 4-1 8 11 6 5 4h13l4-3-1 6-8 17-9 23-5 12-13 38-12 39-5 18-5 17h-2l-9-29-9-27-14-38-13-29-8-16-11-18-10-13-7-9-25-25-3-2v-2l-3-1v-2l-4-2-10-9-8-7-14-12-20-18-13-13-9-11-12-16-9-15zM369 553m0 0h1l1 43 2 3 3 4-1 6-1 1v7l1 2 1 15 7 1 5-2 5 1v-2l3-1 4 1 1-2h-3l1-3 6-2 2 11-1 8-3 12h2v2l3-1 2-12h-2l1-4 1-1 3-21 4-21h1v10l-4 30-3 34-4 69-4 28-1 3h-2l-8-42-10-52-7-33-6-37zM430 22m0 0h2v2h2l7 8 10 11 9 11 4 5 1 5 2 4 1 7 2 2-1 3-5-1h-7l-8-2-5 1v7l-1 1h-5l-2-8-1-2-1-15h-2l-2-31zM417 598m0 0h1v10l-4 30-3 34-4 69-4 28-1 3h-2l-7-37-1-16h8l2 1v-2h2l1-2 2-35v-13l-2-3-3-5-1-8 1-9-1-4-5-2v-2l-3-1v-2l3-1 4 1 1-2h-3l1-3 6-2 2 11-1 8-3 12h2v2l3-1 2-12h-2l1-4 1-1 3-21zM417 598m0 0h1v10l-4 30-3 34-1 17h-2v15l-1 12h-1v-18l1-17v-13l-2-3-3-5-1-8 1-9-1-4-5-2v-2l-3-1v-2l3-1 4 1 1-2h-3l1-3 6-2 2 11-1 8-3 12h2v2l3-1 2-12h-2l1-4 1-1 3-21zM310 619m0 0 4 2 4 6 5 8 7 9 3 5 2-1 2 1 2 10 6-1 2 1v2h-5l3 7 9 13 6 9 3 1v-2l-4-14h3l5 16 3 8 4 12v2l-4-2-60-90zM255 597m0 0 5 3 12 16 9 11 11 13 9 11 11 12 4 5-1 3-7-7-4-1-7-4v-2l-4-2-4-4 4 1 3-1v-3l-5-2-3-5v-2h-2l-6-8v-2l-3-1-1-2-8-1 1-2-2-8-3-4v-2h-2l-4-6-3-4zM425 181m0 0 7 1 1 3 12 2 2 3 3 1v-2h3l1 3-6 2-1 3h-2v2h-2l-1 7-5 1-2-5 2-3h3l1-5-3 1-3 3-1-4-5-2v-5h-6l-3-3zM369 553m0 0h1l1 43 2 3 3 4-1 6-1 1v7l1 2 1 15 2 1h-2l3 13 2 10v5l-3-4-5-25-4-26zM340 614m0 0 1 2h2l6 20 6 18 3 15-2-1-5-15-2-4v-5h-6l-3-2-9-2 2-3v2l5-4h4 2l-1-5-3-12zM296 649m0 0 5 2 11 12 4 5-1 3-7-7-4-1-7-4v-2l-4-2-4-4 4 1 3-1zM403 625m0 0h2l2 11-1 8-2 7-2 1v-9l-1-4-5-2v-2l-3-1v-2l3-1 4 1 1-2h-3l1-3zM417 598m0 0h1v10l-4 30-2 24h-1l-1-17h-2l1-4 1-1 3-21zM163 561m0 0 2 3 5 16 2 6 2 1 3 9 2 4 4-1 1-2 1 3h-2l-2 5 3 6-1 2-3-3-11-24-4-11-2-10zM439 685m0 0 1 2h9l3 4v6l7 2 3 7-4-1-6-4-5-4v-7h-9l-2-2zM369 553m0 0h1l1 43 2 3 3 4-1 6-1 1-1 7-2-2v-7h-2zM434 687m0 0h1v6l-3 9-7 29-4 5 1-8 9-36zM317 672m0 0 6 4 9 11 11 14 6 8v2l-4-2-10-13-7-9-1-3h-2l-7-9zM276 622m0 0 5 5 11 13 7 8-1 2-7-4-3-5v-2h-2l-6-8v-2l-3-1-2-4zM310 619m0 0 4 2 4 6 5 8 7 9-1 4-4-5-8-11-7-11zM416 172m0 0 2 1-1 7h-2v5l4-1-1 3-5 2-3-1v-7l4-8zM381 664m0 0 2 4 6 27v5l-1-2h-2l-5-24zM443 655m0 0 1 4-7 25-1 2h-2l1-7 6-22h2zM163 561m0 0 2 3 5 16 2 6 2 1v5l-2 1-7-18-2-10zM490 702m0 0 1 3-10 15-3 5-4 3v-5l5-5 7-11zM387 698m0 0 1 2h2l3 16v14h-1l-5-26zM426 139m0 0 1 3-1 5-7 22-2-1 2-9 5-18h2zM466 739m0 0h2l-1 6-8 15-3 1 2-7 7-12zM411 636m0 0h2v12l-1 14h-1l-1-17h-2l1-4zM349 645m0 0h3l3 9 3 15-2-1-5-15-2-4zM335 694m0 0 5 3 9 12v2l-4-2-10-13zM386 633m0 0 7 1-3 2-4 1-2 4h-4l-2-6h5zM547 287m0 0 3 2-3 7-1 5h-2l-1 4-2-1 1-5zM557 254m0 0 2 1 3 13-4-1 1-2h-2l-1 3-1-3zM560 311m0 0 3 1-2 5-3 6-9-3v-1l9-1zM409 664m0 0h1v25h-1l-2-24zM340 614m0 0 1 2h2l4 16-4-2-3-12zM438 705m0 0 10 2 1 7-3-1-4-4h-5zM502 685m0 0 1 3-8 11-3 1 2-5zM422 191m0 0 4 1 3 4-2 4-5-3zM359 675m0 0h3l4 13-1 4-4-9zM225 599m0 0 5 2 12 6-3 1-9-4-6-3zM255 597m0 0 5 3 6 8-1 2-3-1-4-6-3-4zM414 180m0 0h1v5l4-1-1 3-5 2-3-1 1-5zM341 665m0 0 3 1 6 9-1 4-8-12zM370 608m0 0h1l1 9 3 1-2 10h-1l-2-12zM439 671m0 0 1 2-4 13h-2l1-7 3-7zM341 658m0 0 6 1v2h-5l-1 5-3-3 1-4zM373 625m0 0h2l1 9 2 1h-2l-1 5h-1l-1-6zM185 615m0 0 4 5 5 8-1 3-4-5-4-7zM434 687m0 0h1v6l-3 9-2 3 1-13zM385 686m0 0h2l2 9v5l-1-2h-2l-1-5zM390 711m0 0h2l1 8v11h-1l-2-10zM355 657m0 0 2 3 4 12v3l-3-1-2-10zM413 624m0 0h1v14l-1-2h-2l1-11zM494 120m0 0h2l2 6v10l-2-3-2-9zM163 561m0 0 2 3 4 13-1 3v-2h-2l-3-13zM489 106m0 0h2l4 10-2 4-4-11zM230 609m0 0 5 1 4 5 3 2-6-1-3-3v-2l-3-1zM392 660m0 0h2v2h2l5 5 2 1-1 4-10-10zM254 615m0 0 8 1 1 1v5l-2-1v-2l-6-2zM190 587m0 0 6 1 2-1 4 2 1 3-13-2zM417 598m0 0h1v10l-1 5-2-1 1-9zM273 545m0 0 2 3 3 8v3h-2l-3-8z"/></svg>',q={claude:'<svg viewBox="0 0 48 48" aria-hidden="true" focusable="false"><rect width="48" height="48" fill="#F3E9D7"/><path transform="translate(24 24) scale(.13) translate(-124 -124)" fill="#D97757" d="M52.4285 162.873L98.7844 136.879L99.5485 134.602L98.7844 133.334H96.4921L88.7237 132.862L62.2346 132.153L39.3113 131.207L17.0249 130.026L11.4214 128.844L6.2 121.873L6.7094 118.447L11.4214 115.257L18.171 115.847L33.0711 116.911L55.485 118.447L71.6586 119.392L95.728 121.873H99.5485L100.058 120.337L98.7844 119.392L97.7656 118.447L74.5877 102.732L49.4995 86.1905L36.3823 76.62L29.3779 71.7757L25.8121 67.2858L24.2839 57.3608L30.6515 50.2716L39.3113 50.8623L41.4763 51.4531L50.2636 58.1879L68.9842 72.7209L93.4357 90.6804L97.0015 93.6343L98.4374 92.6652L98.6571 91.9801L97.0015 89.2625L83.757 65.2772L69.621 40.8192L63.2534 30.6579L61.5978 24.632C60.9565 22.1032 60.579 20.0111 60.579 17.4246L67.8381 7.49965L71.9133 6.19995L81.7193 7.49965L85.7946 11.0443L91.9074 24.9865L101.714 46.8451L116.996 76.62L121.453 85.4816L123.873 93.6343L124.764 96.1155H126.292V94.6976L127.566 77.9197L129.858 57.3608L132.15 30.8942L132.915 23.4505L136.608 14.4708L143.994 9.62643L149.725 12.344L154.437 19.0788L153.8 23.4505L150.998 41.6463L145.522 70.1215L141.957 89.2625H143.994L146.414 86.7813L156.093 74.0206L172.266 53.698L179.398 45.6635L187.803 36.802L193.152 32.5484H203.34L210.726 43.6549L207.415 55.1159L196.972 68.3492L188.312 79.5739L175.896 96.2095L168.191 109.585L168.882 110.689L170.738 110.53L198.755 104.504L213.91 101.787L231.994 98.7149L240.144 102.496L241.036 106.395L237.852 114.311L218.495 119.037L195.826 123.645L162.07 131.592L161.696 131.893L162.137 132.547L177.36 133.925L183.855 134.279H199.774L229.447 136.524L237.215 141.605L241.8 147.867L241.036 152.711L229.065 158.737L213.019 154.956L175.45 145.977L162.587 142.787H160.805V143.85L171.502 154.366L191.242 172.089L215.82 195.011L217.094 200.682L213.91 205.172L210.599 204.699L188.949 188.394L180.544 181.069L161.696 165.118H160.422V166.772L164.752 173.152L187.803 207.771L188.949 218.405L187.294 221.832L181.308 223.959L174.813 222.777L161.187 203.754L147.305 182.486L136.098 163.345L134.745 164.2L128.075 235.42L125.019 239.082L117.887 241.8L111.902 237.31L108.718 229.984L111.902 215.452L115.722 196.547L118.779 181.541L121.58 162.873L123.291 156.636L123.14 156.219L121.773 156.449L107.699 175.752L86.304 204.699L69.3663 222.777L65.291 224.431L58.2867 220.768L58.9235 214.27L62.8713 208.48L86.304 178.705L100.44 160.155L109.551 149.507L109.462 147.967L108.959 147.924L46.6977 188.512L35.6182 189.93L30.7788 185.44L31.4156 178.115L33.7079 175.752L52.4285 162.873Z"/></svg>',chatgpt:'<svg viewBox="0 0 48 48" aria-hidden="true" focusable="false"><rect width="48" height="48" fill="#0D0D0D"/><path transform="translate(24 24) scale(2.35) translate(-7.98 -8)" fill="#FFF" d="M12.9851 6.93777C13.1163 6.54364 13.1618 6.12607 13.1186 5.71295C13.0754 5.29983 12.9444 4.90072 12.7344 4.54231C12.4232 4.00021 11.9478 3.57101 11.3768 3.31664C10.8058 3.06227 10.1687 2.99589 9.55751 3.12706C9.28184 2.81639 8.943 2.56818 8.56362 2.39905C8.18425 2.22993 7.77314 2.14379 7.3578 2.1464C6.73292 2.1449 6.1237 2.34187 5.61797 2.70892C5.11225 3.07598 4.73616 3.59415 4.54391 4.18873C4.13684 4.27206 3.75225 4.44139 3.41591 4.68539C3.07957 4.92938 2.79924 5.24241 2.59368 5.60352C2.27994 6.14413 2.14602 6.77039 2.21123 7.39205C2.27644 8.01367 2.5374 8.59851 2.95649 9.06224C2.82527 9.45637 2.77975 9.87394 2.82297 10.2871C2.8662 10.7002 2.99718 11.0993 3.20713 11.4577C3.51841 11.9998 3.99385 12.4289 4.56484 12.6833C5.13584 12.9377 5.77289 13.0041 6.38407 12.8729C6.65975 13.1836 6.99862 13.4318 7.37796 13.601C7.75734 13.7701 8.16844 13.8562 8.58379 13.8536C9.20899 13.8552 9.81853 13.6582 10.3244 13.2909C10.8304 12.9236 11.2065 12.4051 11.3986 11.8101C11.8057 11.7268 12.1903 11.5575 12.5266 11.3135C12.8629 11.0695 13.1433 10.7564 13.3488 10.3953C13.6622 9.85477 13.7958 9.22866 13.7304 8.60726C13.6651 7.98587 13.4041 7.40129 12.9851 6.93777ZM8.58472 13.0883C8.0715 13.089 7.57441 12.9093 7.18031 12.5805C7.19808 12.5708 7.22925 12.5537 7.24956 12.5413L9.58061 11.1948C9.63911 11.1615 9.6877 11.1133 9.72136 11.055C9.75505 10.9967 9.77258 10.9305 9.77217 10.8632V7.57684L10.7575 8.14576C10.7626 8.14834 10.7671 8.15214 10.7704 8.15685C10.7738 8.16157 10.7759 8.16704 10.7766 8.17275V10.8943C10.7759 11.4756 10.5448 12.0329 10.1339 12.4441C9.72308 12.8554 9.16599 13.087 8.58472 13.0883ZM3.87091 11.075C3.61385 10.6309 3.5212 10.1105 3.60918 9.60485C3.62649 9.61524 3.65673 9.6337 3.67842 9.64617L6.00947 10.9926C6.06756 11.0266 6.13365 11.0445 6.20094 11.0445C6.2682 11.0445 6.33428 11.0266 6.39238 10.9926L9.23834 9.34936V10.4872C9.23867 10.493 9.23755 10.4988 9.23509 10.5041C9.23264 10.5094 9.22892 10.5139 9.22427 10.5174L6.86782 11.878C6.36379 12.1683 5.76516 12.2467 5.20333 12.0962C4.64148 11.9457 4.1623 11.5784 3.87091 11.075ZM3.25768 5.98617C3.51363 5.54141 3.91789 5.2009 4.39966 5.02421C4.39966 5.04429 4.39851 5.07985 4.39851 5.10452V7.79747C4.3981 7.86473 4.41561 7.93087 4.44924 7.98915C4.48287 8.04739 4.5314 8.09563 4.58984 8.1289L7.4358 9.77197L6.45054 10.3409C6.44568 10.3441 6.44009 10.346 6.43429 10.3465C6.4285 10.3471 6.42265 10.3462 6.41729 10.3439L4.06062 8.98216C3.55747 8.69077 3.19039 8.21176 3.03987 7.65013C2.88935 7.08853 2.96768 6.49014 3.25768 5.98617ZM11.3527 7.86994L8.50669 6.22667L9.49198 5.65799C9.49684 5.6548 9.50243 5.65283 9.50823 5.65231C9.51402 5.65178 9.51985 5.65272 9.5252 5.655L11.8819 7.01554C12.2429 7.2241 12.5371 7.53119 12.7299 7.90087C12.9228 8.27056 13.0063 8.68752 12.9707 9.10295C12.9351 9.51839 12.7819 9.91509 12.5291 10.2466C12.2762 10.5781 11.9341 10.8307 11.5428 10.9749C11.5428 10.9546 11.5428 10.919 11.5428 10.8943V8.20137C11.5434 8.13423 11.5261 8.06814 11.4926 8.0099C11.4592 7.95165 11.4109 7.90336 11.3527 7.86994ZM12.3333 6.394C12.316 6.38337 12.2858 6.36514 12.2641 6.3527L9.93303 5.00621C9.87493 4.97232 9.80887 4.95444 9.74158 4.95444C9.67432 4.95444 9.60824 4.97232 9.55014 5.00621L6.70418 6.64951V5.51167C6.70386 5.50585 6.70497 5.50005 6.70743 5.49479C6.70988 5.48952 6.7136 5.48492 6.71826 5.48144L9.0747 4.12203C9.4357 3.91387 9.84853 3.81281 10.2649 3.83068C10.6812 3.84856 11.0838 3.98462 11.4257 4.22296C11.7675 4.46129 12.0344 4.79204 12.1951 5.17652C12.3559 5.56099 12.4038 5.98327 12.3333 6.394ZM6.16851 8.42203L5.18299 7.85311C5.17784 7.85053 5.17336 7.84673 5.17002 7.84202C5.16668 7.8373 5.16455 7.83183 5.16385 7.82609V5.10452C5.16411 4.6877 5.28311 4.27956 5.5069 3.9279C5.73071 3.57623 6.05006 3.29559 6.42756 3.11883C6.80507 2.94206 7.22509 2.87649 7.63851 2.92977C8.05195 2.98306 8.44163 3.153 8.76197 3.41971C8.74421 3.42941 8.71327 3.44649 8.69272 3.45895L6.36168 4.80542C6.30317 4.83867 6.25462 4.8869 6.22093 4.94516C6.18727 5.0034 6.16974 5.06958 6.17012 5.13683L6.16851 8.42203ZM6.70371 7.26803L7.97126 6.53595L9.23878 7.26757V8.73127L7.97126 9.46292L6.70371 8.73127V7.26803Z"/></svg>'},z="team@northlight.ai";function k(e){const t=JSON.stringify(e.config).replace(/</g,"\\u003c");return`<!doctype html>
151
151
  <html lang="en"><head><meta charset="utf-8"><meta name="viewport" content="width=device-width,initial-scale=1">
152
152
  <meta name="color-scheme" content="light dark">
153
- <title>${u(e.title)}</title><style nonce="${e.nonce}">${D}</style></head>
153
+ <title>${u(e.title)}</title><style nonce="${e.nonce}">${F}</style></head>
154
154
  <body>
155
- <header class="top">${W}<span>Northlight</span></header>
155
+ <header class="top">${Z}<span>Northlight</span></header>
156
156
  <main><div class="col">${e.body}</div></main>
157
- <footer class="foot"><span>Need help? Email <a href="mailto:${$}">${$}</a></span></footer>
157
+ <footer class="foot"><span>Need help? Email <a href="mailto:${z}">${z}</a></span></footer>
158
158
  <script type="application/json" id="cfg">${t}<\/script>
159
- <script nonce="${e.nonce}">${q}<\/script>
160
- </body></html>`}a(C,"page");function S(e,t){return`<div class="head"><div class="logo">${V[e]}</div><div><span class="eyebrow">AI subscription</span><h1>Connect your ${t} account</h1></div></div>`}a(S,"header");function h(e,t,n="",r=""){return`<li${r}><span class="n"><span>${e}</span>${s("check")}</span><div class="body"><span class="title">${t}</span>${n}</div></li>`}a(h,"step");function X(e,t,n,r){return C({nonce:t,title:"Connect Claude",body:`<div class="card">
161
- ${S("claude","Claude")}
159
+ <script nonce="${e.nonce}">${U}<\/script>
160
+ </body></html>`}a(k,"page");function $(e,t){return`<div class="head"><div class="logo">${q[e]}</div><div><span class="eyebrow">AI subscription</span><h1>Connect your ${t} account</h1></div></div>`}a($,"header");function h(e,t,n="",r=""){return`<li${r}><span class="n"><span>${e}</span>${s("check")}</span><div class="body"><span class="title">${t}</span>${n}</div></li>`}a(h,"step");function W(e,t,n,r){return k({nonce:t,title:"Connect Claude",body:`<div class="card">
161
+ ${$("claude","Claude")}
162
162
  <ol class="steps">
163
163
  ${h(1,"Sign in to Claude in a new tab",`<div><a class="btn" href="${u(e.url)}" target="_blank" rel="noopener noreferrer">Open claude.ai${s("arrow")}</a></div>`," data-pre")}
164
164
  ${h(2,"Copy the code Claude shows you",""," data-pre")}
@@ -169,11 +169,11 @@ ${h(3,"Paste it here",`<form id="paste" autocomplete="off">
169
169
  <button class="btn primary lg wide" type="submit">Connect Claude</button>
170
170
  </form>`)}
171
171
  </ol>
172
- </div>`,config:{kind:"anthropic",base:`${c}/${encodeURIComponent(e.flow_id)}`,returnTo:n,handoff:r}})}a(X,"anthropicPage");function Y(e,t){const n=Date.parse(e.expires_at)-t;return Math.max(0,Math.floor(Math.min(Number.isNaN(n)?z*1e3:n,z*1e3)/1e3))}a(Y,"codeSecondsLeft");function K(e,t,n,r,i=Date.now()){const o=e.user_code??"";return C({nonce:t,title:"Connect ChatGPT",body:`<div class="card">
173
- ${S("chatgpt","ChatGPT")}
172
+ </div>`,config:{kind:"anthropic",base:`${c}/${encodeURIComponent(e.flow_id)}`,returnTo:n,handoff:r}})}a(W,"anthropicPage");function X(e,t){const n=Date.parse(e.expires_at)-t;return Math.max(0,Math.floor(Math.min(Number.isNaN(n)?y*1e3:n,y*1e3)/1e3))}a(X,"codeSecondsLeft");function Y(e,t,n,r,i=Date.now()){const o=e.user_code??"";return k({nonce:t,title:"Connect ChatGPT",body:`<div class="card">
173
+ ${$("chatgpt","ChatGPT")}
174
174
  <div class="alert" id="settings" role="alert">${s("warn")}
175
175
  <div class="text"><strong>Turn on device code sign-in first</strong>OpenAI refuses this sign-in unless device code authorization for Codex is on in ChatGPT's Security settings.</div>
176
- <div class="act"><a class="btn sm" href="${G}" target="_blank" rel="noopener noreferrer">Open settings${s("arrow")}</a></div></div>
176
+ <div class="act"><a class="btn sm" href="${V}" target="_blank" rel="noopener noreferrer">Open settings${s("arrow")}</a></div></div>
177
177
  <ol class="steps" id="device">
178
178
  ${h(1,"Open the OpenAI device page",`<div><a class="btn" id="device-link" href="${u(e.url)}" target="_blank" rel="noopener noreferrer">${u(e.url.replace(/^https:\/\//,""))}${s("arrow")}</a></div>`)}
179
179
  ${h(2,"Enter this code",`<div class="codebox"><span class="code" id="user-code">${u(o)}</span>
@@ -189,4 +189,4 @@ ${h(3,"Approve the sign-in",`<span class="small">When OpenAI shows an account em
189
189
  <div class="alert" id="expired" role="alert" hidden>${s("warn")}
190
190
  <div class="text"><strong>The code expired before it was approved</strong>Codes last 15 minutes. Getting a new one starts the sign-in over.</div>
191
191
  <div class="act"><button class="btn primary sm" type="button" id="renew">Get a new code</button></div></div>
192
- </div>`,config:{kind:"openai",base:`${c}/${encodeURIComponent(e.flow_id)}`,returnTo:n,handoff:r,userCode:o,expiresAt:e.expires_at,remainingSeconds:Y(e,i)}})}a(K,"openaiPage");async function Q(e,t,n,r){const i=x(n.searchParams,"handoff"),o=await k(r,i);if(y(o.jti))throw f();const l=x(n.searchParams,"return_to");let g;try{g=l===void 0?void 0:new URL(l).origin}catch{g=void 0}if(l===void 0||g!==new URL(r.issuer).origin)throw new d(400,"invalid_request","return_to must be an absolute URL on the directory origin","return_to");const p=x(n.searchParams,"vendor");if(p!=="anthropic"&&p!=="openai")throw new d(400,"invalid_request","vendor must be anthropic or openai","vendor");if(!j(o.jti,o.exp))throw f();let b;try{b=await P({provider:N(p),jti:o.jti})}catch(w){console.error("[vendor-signin] start failed:",w instanceof Error?w.message:w),t.writeHead(303,{Location:H(l,"failed"),"Cache-Control":"no-store","Referrer-Policy":"no-referrer"}),t.end();return}const v=O(16).toString("base64"),_=p==="anthropic"?X(b,v,l,i):K(b,v,l,i);t.writeHead(200,{"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-store","Referrer-Policy":"no-referrer","X-Content-Type-Options":"nosniff","Content-Security-Policy":`default-src 'none'; script-src 'nonce-${v}'; style-src 'nonce-${v}'; connect-src 'self'; form-action 'none'; base-uri 'none'; frame-ancestors 'none'`}),t.end(_)}a(Q,"startPage");async function T(e,t,n){const r=await k(t,U(e)),i=M(n);if(!i){if(y(r.jti))return!1;throw f()}if(i.jti===void 0||i.jti!==r.jti)throw f();return!0}a(T,"followUpFlow");async function Z(e,t,n,r){if(!await T(e,n,r)){m(t,200,{status:"failed"});return}const i=await J(e);try{await I(r,i.input),m(t,200,{status:"connected"})}catch(o){const l=M(r);if(l&&l.status!=="pending"){m(t,200,{status:"failed"});return}throw o}}a(Z,"submitCode");async function ee(e,t,n,r){if(!await T(e,n,r)){m(t,200,{status:"failed"});return}const i=new AbortController;t.once("close",()=>i.abort());const o=await L(r,B,i.signal);m(t,200,{status:o?.status??"failed"})}a(ee,"waitFlow");async function de(e,t,n,r){const i=e.method??"GET";if(n.pathname===c&&i==="GET"){await Q(e,t,n,r);return}const o=n.pathname.slice(c.length+1).split("/");let l="";try{l=o[0]?decodeURIComponent(o[0]):""}catch{throw new d(404,"not_found","unknown operation")}if(l&&o.length===1&&i==="POST"){await Z(e,t,r,l);return}if(l&&o.length===2&&o[1]==="wait"&&i==="GET"){await ee(e,t,r,l);return}throw new d(404,"not_found","unknown operation")}a(de,"handleVendorSignIn");export{c as VENDOR_SIGNIN_PATH,X as anthropicPage,de as handleVendorSignIn,se as isVendorSignInPath,K as openaiPage};
192
+ </div>`,config:{kind:"openai",base:`${c}/${encodeURIComponent(e.flow_id)}`,returnTo:n,handoff:r,userCode:o,expiresAt:e.expires_at,remainingSeconds:X(e,i)}})}a(Y,"openaiPage");async function K(e,t,n,r){const i=w(n.searchParams,"handoff"),o=await M(r,i);if(x(o.jti))throw f();const l=w(n.searchParams,"return_to");let g;try{g=l===void 0?void 0:new URL(l).origin}catch{g=void 0}if(l===void 0||g!==new URL(r.issuer).origin)throw new d(400,"invalid_request","return_to must be an absolute URL on the directory origin","return_to");const p=w(n.searchParams,"vendor");if(p!=="anthropic"&&p!=="openai")throw new d(400,"invalid_request","vendor must be anthropic or openai","vendor");if(!E(o.jti,o.exp))throw f();let b;try{b=await N({provider:I(p),jti:o.jti})}catch(L){console.error("[vendor-signin] start failed:",L instanceof Error?L.message:L),t.writeHead(303,{Location:B(l,"failed"),"Cache-Control":"no-store","Referrer-Policy":"no-referrer"}),t.end();return}const v=A(16).toString("base64"),T=p==="anthropic"?W(b,v,l,i):Y(b,v,l,i);t.writeHead(200,{"Content-Type":"text/html; charset=utf-8","Cache-Control":"no-store","Referrer-Policy":"no-referrer","X-Content-Type-Options":"nosniff","Content-Security-Policy":`default-src 'none'; script-src 'nonce-${v}'; style-src 'nonce-${v}'; connect-src 'self'; form-action 'none'; base-uri 'none'; frame-ancestors 'none'`}),t.end(T)}a(K,"startPage");async function S(e,t,n){const r=await M(t,D(e)),i=C(n);if(!i){if(x(r.jti))return!1;throw f()}if(i.jti===void 0||i.jti!==r.jti)throw f();return!0}a(S,"followUpFlow");async function Q(e,t,n,r){if(!await S(e,n,r)){m(t,200,{status:"failed"});return}const i=await G(e);try{await j(r,i.input),m(t,200,{status:"connected"})}catch(o){const l=C(r);if(l&&l.status!=="pending"){m(t,200,{status:"failed"});return}throw o}}a(Q,"submitCode");async function e1(e,t,n,r){if(!await S(e,n,r)){m(t,200,{status:"failed"});return}const i=new AbortController;t.once("close",()=>i.abort());const o=await P(r,H,i.signal);m(t,200,{status:o?.status??"failed"})}a(e1,"waitFlow");async function d1(e,t,n,r){const i=e.method??"GET";if(n.pathname===c&&i==="GET"){await K(e,t,n,r);return}const o=n.pathname.slice(c.length+1).split("/");let l="";try{l=o[0]?decodeURIComponent(o[0]):""}catch{throw new d(404,"not_found","unknown operation")}if(l&&o.length===1&&i==="POST"){await Q(e,t,r,l);return}if(l&&o.length===2&&o[1]==="wait"&&i==="GET"){await e1(e,t,r,l);return}throw new d(404,"not_found","unknown operation")}a(d1,"handleVendorSignIn");export{c as VENDOR_SIGNIN_PATH,W as anthropicPage,d1 as handleVendorSignIn,s1 as isVendorSignInPath,Y as openaiPage};
@@ -47,6 +47,6 @@ printf '%s\n' 'Production changes need an explicit approval.' | \
47
47
  crtr doc edit <name> --rationale "Updated the approval rule."
48
48
  ```
49
49
 
50
- `crtr doc edit` replaces the whole body you pipe; it does not append text. For a partial change, use `crtr doc edit <name> --rationale '…' --blocks <<'EOF'` with whole-line `<<<<<<< SEARCH`, `=======`, and `>>>>>>> REPLACE` markers around verbatim old and new text. An empty REPLACE deletes text. Scripts can still use `--replace '[{"old":"…","new":"…"}]'`. Read the document before you edit it; an edit made from an older revision is refused. Use `crtr doc history <name>` to read the revision history. If you want to create a document yourself, use `crtr doc write`; it takes a name, a preview sentence that tells agents when to read it, and the document body on stdin. `--kind knowledge|preference` (default `knowledge`) sets how agents use it, and `--owner node|user|profile|app|repo` chooses who owns it (default: the writing node; `profile:<name>` and `repo:<handle>` name a specific one). New documents are `privacy: public` unless `--privacy friends` or `--privacy private` is supplied; a repository owns only public documents. `crtr doc edit --privacy <level>` changes the level and records the revision.
50
+ `crtr doc edit` replaces the whole body you pipe; it does not append text. For a partial change, use `crtr doc edit <name> --rationale '…' --blocks <<'EOF'` with whole-line `<<<<<<< SEARCH`, `=======`, and `>>>>>>> REPLACE` markers around verbatim old and new text. An empty REPLACE deletes text. Scripts can still use `--replace '[{"old":"…","new":"…"}]'`. Read the document before you edit it; an edit made from an older revision is refused. Use `crtr doc history <name>` to read the revision history. If you want to create a document yourself, use `crtr doc write`; it takes a name, a preview sentence that tells agents when to read it, and the document body on stdin. `--kind knowledge|preference` (default `knowledge`) sets how agents use it, and `--owner node|user|profile|app|repo` chooses who owns it (default: the writing node; `profile:<name>` and `repo:<handle>` name a specific one). New documents are `privacy: public` unless `--privacy friends` or `--privacy private` is supplied; a repository owns only public documents. `crtr doc edit --privacy <level>` changes the level. An edit that changes only fields (privacy, preview, summary, rules, `--why-it-exists`) takes effect at once but makes no new revision: revisions are versions of the body, so the revision number does not move and `crtr doc history` shows nothing for it.
51
51
 
52
52
  Documents are for reusable current truth and durable instructions, not a transcript of one conversation. When a fact changes, update the existing document rather than saving a second version.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@north-light/cli",
3
- "version": "0.3.433",
3
+ "version": "0.3.435",
4
4
  "description": "crtr — agent runtime with memory, plugins, and marketplaces",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -137,7 +137,7 @@
137
137
  },
138
138
  "license": "UNLICENSED",
139
139
  "dependencies": {
140
- "@north-light/identity": "0.3.433",
140
+ "@north-light/identity": "0.3.435",
141
141
  "@earendil-works/pi-agent-core": "1.1.0",
142
142
  "@earendil-works/pi-ai": "1.1.0",
143
143
  "@earendil-works/pi-coding-agent": "1.1.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@north-light/identity",
3
- "version": "0.3.433",
3
+ "version": "0.3.435",
4
4
  "description": "Northlight access-token verification and scope rules",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
package/runtime.lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@north-light/cli",
3
- "version": "0.3.433",
3
+ "version": "0.3.435",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@north-light/cli",
9
- "version": "0.3.433",
9
+ "version": "0.3.435",
10
10
  "hasInstallScript": true,
11
11
  "license": "UNLICENSED",
12
12
  "workspaces": [
@@ -18,7 +18,7 @@
18
18
  "@earendil-works/pi-ai": "1.1.0",
19
19
  "@earendil-works/pi-coding-agent": "1.1.0",
20
20
  "@earendil-works/pi-tui": "1.1.0",
21
- "@north-light/identity": "0.3.433",
21
+ "@north-light/identity": "0.3.435",
22
22
  "cron-parser": "^5.6.0",
23
23
  "esbuild": "^0.27.7",
24
24
  "jose": "^6.2.12",
@@ -12095,17 +12095,17 @@
12095
12095
  },
12096
12096
  "packages/crouter-api": {
12097
12097
  "name": "@north-light/api",
12098
- "version": "0.3.433",
12098
+ "version": "0.3.435",
12099
12099
  "license": "UNLICENSED"
12100
12100
  },
12101
12101
  "packages/crouter-env-docker": {
12102
12102
  "name": "@north-light/env-docker",
12103
- "version": "0.3.433",
12103
+ "version": "0.3.435",
12104
12104
  "license": "UNLICENSED"
12105
12105
  },
12106
12106
  "packages/crouter-identity": {
12107
12107
  "name": "@north-light/identity",
12108
- "version": "0.3.433",
12108
+ "version": "0.3.435",
12109
12109
  "license": "UNLICENSED",
12110
12110
  "dependencies": {
12111
12111
  "jose": "^6.2.1"
@@ -12113,20 +12113,20 @@
12113
12113
  },
12114
12114
  "packages/crouter-plugin": {
12115
12115
  "name": "@north-light/plugin",
12116
- "version": "0.3.433",
12116
+ "version": "0.3.435",
12117
12117
  "license": "UNLICENSED",
12118
12118
  "dependencies": {
12119
- "@north-light/api": "0.3.433",
12120
- "@north-light/identity": "0.3.433"
12119
+ "@north-light/api": "0.3.435",
12120
+ "@north-light/identity": "0.3.435"
12121
12121
  }
12122
12122
  },
12123
12123
  "packages/crouter-sdk": {
12124
12124
  "name": "@north-light/sdk",
12125
- "version": "0.3.433",
12125
+ "version": "0.3.435",
12126
12126
  "license": "UNLICENSED",
12127
12127
  "dependencies": {
12128
- "@north-light/api": "0.3.433",
12129
- "@north-light/identity": "0.3.433",
12128
+ "@north-light/api": "0.3.435",
12129
+ "@north-light/identity": "0.3.435",
12130
12130
  "jose": "^6.2.1"
12131
12131
  },
12132
12132
  "bin": {