@north-light/cli 0.3.519 → 0.3.521

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/dist/api/command-manifest/result.d.ts +20 -8
  2. package/dist/api/command-manifest/result.js +1 -1
  3. package/dist/api/command-manifest/schema.js +1 -1
  4. package/dist/api/contract.d.ts +1 -1
  5. package/dist/api/contract.js +1 -1
  6. package/dist/api/dto/health.d.ts +3 -0
  7. package/dist/api/plugin-manifest-schema.d.ts +7 -3
  8. package/dist/builtin-memory/crouter-plugin/deploying.md +3 -1
  9. package/dist/builtin-memory/crouter-plugin/output.md +1 -1
  10. package/dist/builtin-memory/crouter-sdk/release-notes.md +6 -0
  11. package/dist/clients/attach/viewer.js +533 -533
  12. package/dist/commands/pkg/browse/model.d.ts +1 -1
  13. package/dist/commands/pkg/plugin-manage.js +1 -1
  14. package/dist/commands/sys/daemon.js +1 -1
  15. package/dist/core/canvas/migrations.js +28 -22
  16. package/dist/core/command-hooks/transport/exec-invoke.js +1 -1
  17. package/dist/core/command-plugins/transport/exec-invoke.js +1 -1
  18. package/dist/core/command-plugins/transport/http-plan.js +1 -1
  19. package/dist/core/command.js +9 -9
  20. package/dist/core/graph/documents.d.ts +6 -5
  21. package/dist/core/graph/documents.js +7 -7
  22. package/dist/core/graph/edges.d.ts +16 -0
  23. package/dist/core/graph/edges.js +1 -1
  24. package/dist/core/graph/repo-sync/exchange.js +2 -2
  25. package/dist/core/help.d.ts +4 -2
  26. package/dist/core/help.js +7 -7
  27. package/dist/core/plugin-app.js +1 -1
  28. package/dist/core/plugin-objects-manifest.d.ts +5 -3
  29. package/dist/core/plugin-objects-manifest.js +1 -1
  30. package/dist/core/providers/call.d.ts +2 -1
  31. package/dist/core/providers/call.js +1 -1
  32. package/dist/core/spaces/cache-env.d.ts +1 -1
  33. package/dist/core/spaces/cache-env.js +1 -1
  34. package/dist/daemon/api/handlers/crons.js +1 -1
  35. package/dist/daemon/api/handlers/docs.js +1 -1
  36. package/dist/daemon/api/handlers/health.js +3 -3
  37. package/docs/ci-runner.md +4 -5
  38. package/docs/plugin/deploying.md +3 -1
  39. package/docs/plugin/output.md +1 -1
  40. package/docs/sdk/release-notes.md +6 -0
  41. package/package.json +2 -2
  42. package/packages/crouter-identity/package.json +1 -1
  43. package/runtime.lock.json +12 -12
@@ -1,10 +1,10 @@
1
- var J=Object.defineProperty;var f=(e,i)=>J(e,"name",{value:i,configurable:!0});import{renderRoot as F,renderBranch as V,renderLeafArgv as O,withAsyncHelpState as z,collapseWideChildren as G,rootPromotedChildren as I}from"./help.js";import{beginPreview as L,publishPreviewResult as K,readStdinRaw as B,peekStdinRaw as D,emit as Y,handle as Q,setJsonOutput as X,isJsonOutput as Z}from"./io.js";import{renderResult as ee}from"./render.js";import{CrtrError as N}from"./errors.js";import{isManifestStaleError as ne}from"./manifest-stale.js";import{operationIdContext as te}from"./events/operation-id.js";import{ExitCode as S}from"../types.js";import{envNodeId as ie}from"../shared/env.js";import{readFileSync as re}from"node:fs";import{spawnSync as ae}from"node:child_process";import{constants as oe}from"node:os";import{isatty as se}from"node:tty";import{resolve as le}from"node:path";function W(e){if(e===null||typeof e!="object"||Object.isFrozen(e))return e;for(const i of Object.values(e))W(i);return Object.freeze(e)}f(W,"freezeCommandMetadata");function Fe(e){const i=W(e.help),{helpState:r}=e;if(r!==void 0&&e.effectiveHelp!==void 0)throw new Error(`leaf ${e.name} declares both helpState and effectiveHelp`);return Object.freeze({kind:"leaf",name:e.name,description:e.description,whenToUse:e.whenToUse,tier:e.tier,help:i,effectiveHelp:e.effectiveHelp??(r===void 0?void 0:n=>z(i,r,n)),slash:e.slash===void 0?void 0:W(e.slash),hookEligible:e.hookEligible,plugin:e.plugin,machineSelector:e.machineSelector,run:e.run,render:e.render,preview:e.preview,stdoutExact:e.stdoutExact})}f(Fe,"defineLeaf");function de(e){return e.kind!=="branch"?0:(e.help.listing??[]).filter(i=>i.tier!=="hidden").length}f(de,"visibleSubCount");function Ve(e){if(e.passthrough!==void 0&&e.children.length>0)throw new Error(`defineBranch("${e.name}"): a passthrough branch must declare no children (found ${e.children.length})`);return e.help.listing=e.children.map(i=>{const r=de(i);return{name:i.name,description:i.description??"",whenToUse:i.whenToUse??"",tier:i.tier??"normal",kind:i.kind,...i.plugin!==void 0?{plugin:i.plugin}:{},...r>0?{subCount:r}:{}}}),{kind:"branch",name:e.name,description:e.description,whenToUse:e.whenToUse,tier:e.tier,help:e.help,effectiveHelp:e.effectiveHelp,rootEntry:e.rootEntry,extensible:e.extensible,plugin:e.plugin,slash:e.slash,passthrough:e.passthrough,children:e.children}}f(Ve,"defineBranch");function Ie(e){const i=[],r=f(n=>{if(n.slash!==void 0&&i.push(n.slash),n.kind==="branch")for(const a of n.children)r(a)},"visit");for(const n of e.subtrees)r(n);return i}f(Ie,"collectSlashSpecs");function Be(e){const i=e.subtrees.filter(n=>n.rootEntry!==void 0).map(n=>{const a=(n.help.listing??[]).filter(s=>s.tier!=="hidden"),l=I(a).map(s=>({path:`${n.name} ${s.name}`,desc:s.tier==="important"?s.description:void 0}));return{name:n.name,concept:n.rootEntry.concept,desc:n.rootEntry.desc,useWhen:n.rootEntry.useWhen,dynamicState:n.rootEntry.dynamicState,subcommands:l.length>0?l:void 0,otherSubcommandCount:a.length-l.length}});return{kind:"root",help:{tagline:e.tagline,commands:i,globals:e.globals},subtrees:e.subtrees}}f(Be,"defineRoot");function fe(e){if(e.kind==="root")return e.subtrees.filter(i=>i.tier!=="hidden").map(i=>i.name);if(e.kind==="branch"){const{listed:i,unlisted:r}=G(e.children.filter(n=>n.tier!=="hidden"));return[...i.map(n=>n.name),...r>0?[`(and ${r} more)`]:[]]}return[]}f(fe,"childNames");function ce(e,i){let r=e;const n=[];let a=0;for(;a<i.length;){const l=i[a];if(l==="-h"||l==="--help")break;if(r.kind==="root"){const s=r.subtrees.find(o=>o.name===l);if(s===void 0)break;r=s,n.push(s.name),a++}else if(r.kind==="branch"){const s=r.children.find(o=>o.name===l);if(s===void 0)break;r=s,n.push(s.name),a++}else break}return{node:r,path:n,remaining:i.slice(a)}}f(ce,"walk");function ue(e){return e.kind==="root"?F(e.help):e.kind==="branch"?V(e.help):O(e.help)}f(ue,"renderNode");async function M(e,i,r){if(r!==void 0&&e.kind==="leaf")return O(e.effectiveHelp!==void 0?await e.effectiveHelp(r):e.help,r);const n=e.kind==="leaf"&&e.effectiveHelp!==void 0?O(await e.effectiveHelp()):e.kind==="branch"&&e.effectiveHelp!==void 0?V(await e.effectiveHelp()):ue(e);if(i.length===0)return n;const{hasEffectiveCommandPlugins:a}=await import("./command-plugins/presence.js");if(!a())return n;const[{collectHelpAddenda:l},{SUBTREE_NAMES:s,coreCommandPathsCovering:o,extensibleCoreBranches:x}]=await Promise.all([import("./command-plugins/help-addenda.js"),import("../build-root.js")]),b=await l(i.join(" "),{reservedCoreNames:new Set(s),coreCommandPaths:o,extensibleCoreBranches:x});return n+b.map($=>`
1
+ var G=Object.defineProperty;var f=(e,i)=>G(e,"name",{value:i,configurable:!0});import{renderRoot as V,renderBranch as I,renderLeafArgv as W,withAsyncHelpState as L,collapseWideChildren as K,rootPromotedChildren as J}from"./help.js";import{beginPreview as D,publishPreviewResult as Y,readStdinRaw as B,peekStdinRaw as Q,emit as X,handle as Z,setJsonOutput as ee,isJsonOutput as ne}from"./io.js";import{renderResult as te}from"./render.js";import{CrtrError as H}from"./errors.js";import{validateValue as ie}from"../api/command-manifest/result.js";import{isManifestStaleError as re}from"./manifest-stale.js";import{operationIdContext as ae}from"./events/operation-id.js";import{ExitCode as C}from"../types.js";import{envNodeId as oe}from"../shared/env.js";import{readFileSync as se}from"node:fs";import{spawnSync as le}from"node:child_process";import{constants as de}from"node:os";import{isatty as fe}from"node:tty";import{resolve as ce}from"node:path";function q(e){if(e===null||typeof e!="object"||Object.isFrozen(e))return e;for(const i of Object.values(e))q(i);return Object.freeze(e)}f(q,"freezeCommandMetadata");function Je(e){const i=q(e.help),{helpState:r}=e;if(r!==void 0&&e.effectiveHelp!==void 0)throw new Error(`leaf ${e.name} declares both helpState and effectiveHelp`);return Object.freeze({kind:"leaf",name:e.name,description:e.description,whenToUse:e.whenToUse,tier:e.tier,help:i,effectiveHelp:e.effectiveHelp??(r===void 0?void 0:n=>L(i,r,n)),slash:e.slash===void 0?void 0:q(e.slash),hookEligible:e.hookEligible,plugin:e.plugin,machineSelector:e.machineSelector,run:e.run,render:e.render,preview:e.preview,stdoutExact:e.stdoutExact})}f(Je,"defineLeaf");function A(e){return e.kind==="branch"&&e.children.length>0&&M(e)===0?"hidden":e.tier??"normal"}f(A,"effectiveTier");function M(e){return e.kind!=="branch"?0:(e.help.listing??[]).filter(i=>i.tier!=="hidden").length}f(M,"visibleSubCount");function Be(e){if(e.passthrough!==void 0&&e.children.length>0)throw new Error(`defineBranch("${e.name}"): a passthrough branch must declare no children (found ${e.children.length})`);return e.help.listing=e.children.map(i=>{const r=M(i);return{name:i.name,description:i.description??"",whenToUse:i.whenToUse??"",tier:A(i),kind:i.kind,...i.plugin!==void 0?{plugin:i.plugin}:{},...r>0?{subCount:r}:{}}}),{kind:"branch",name:e.name,description:e.description,whenToUse:e.whenToUse,tier:e.tier,help:e.help,effectiveHelp:e.effectiveHelp,rootEntry:e.rootEntry,extensible:e.extensible,plugin:e.plugin,slash:e.slash,passthrough:e.passthrough,children:e.children}}f(Be,"defineBranch");function Me(e){const i=[],r=f(n=>{if(n.slash!==void 0&&i.push(n.slash),n.kind==="branch")for(const a of n.children)r(a)},"visit");for(const n of e.subtrees)r(n);return i}f(Me,"collectSlashSpecs");function ze(e){const i=e.subtrees.filter(n=>n.rootEntry!==void 0&&A(n)!=="hidden").map(n=>{const a=(n.help.listing??[]).filter(s=>s.tier!=="hidden"),d=J(a).map(s=>({path:`${n.name} ${s.name}`,desc:s.tier==="important"?s.description:void 0}));return{name:n.name,concept:n.rootEntry.concept,desc:n.rootEntry.desc,useWhen:n.rootEntry.useWhen,dynamicState:n.rootEntry.dynamicState,subcommands:d.length>0?d:void 0,otherSubcommandCount:a.length-d.length}});return{kind:"root",help:{tagline:e.tagline,commands:i,globals:e.globals},subtrees:e.subtrees}}f(ze,"defineRoot");function ue(e){if(e.kind==="root")return e.subtrees.filter(i=>A(i)!=="hidden").map(i=>i.name);if(e.kind==="branch"){const{listed:i,unlisted:r}=K(e.children.filter(n=>A(n)!=="hidden"));return[...i.map(n=>n.name),...r>0?[`(and ${r} more)`]:[]]}return[]}f(ue,"childNames");function he(e,i){let r=e;const n=[];let a=0;for(;a<i.length;){const d=i[a];if(d==="-h"||d==="--help")break;if(r.kind==="root"){const s=r.subtrees.find(o=>o.name===d);if(s===void 0)break;r=s,n.push(s.name),a++}else if(r.kind==="branch"){const s=r.children.find(o=>o.name===d);if(s===void 0)break;r=s,n.push(s.name),a++}else break}return{node:r,path:n,remaining:i.slice(a)}}f(he,"walk");function pe(e){return e.kind==="root"?V(e.help):e.kind==="branch"?I(e.help):W(e.help)}f(pe,"renderNode");async function z(e,i,r){if(r!==void 0&&e.kind==="leaf")return W(e.effectiveHelp!==void 0?await e.effectiveHelp(r):e.help,r);const n=e.kind==="leaf"&&e.effectiveHelp!==void 0?W(await e.effectiveHelp()):e.kind==="branch"&&e.effectiveHelp!==void 0?I(await e.effectiveHelp()):pe(e);if(i.length===0)return n;const{hasEffectiveCommandPlugins:a}=await import("./command-plugins/presence.js");if(!a())return n;const[{collectHelpAddenda:d},{SUBTREE_NAMES:s,coreCommandPathsCovering:o,extensibleCoreBranches:k}]=await Promise.all([import("./command-plugins/help-addenda.js"),import("../build-root.js")]),v=await d(i.join(" "),{reservedCoreNames:new Set(s),coreCommandPaths:o,extensibleCoreBranches:k});return n+v.map(E=>`
2
2
 
3
- <plugin-help plugin="${$.plugin}">
4
- ${$.text}
5
- </plugin-help>`).join("")}f(M,"renderNodeWithAddenda");function he(e){return e.some(i=>i==="-h"||i==="--help")}f(he,"helpRequested");function me(e,i){if(e.kind!=="leaf"||i.length!==2)return;const[r,n]=i;if(n!=="-h"&&n!=="--help"||!r.startsWith("--")||r.includes("="))return;const a=r.slice(2);return(e.help.params??[]).find(s=>s.kind==="flag"&&s.name===a)?.focusedHelp!==void 0?a:void 0}f(me,"focusedHelpFlag");function pe(e,i){let r=0;for(let n=0;n<e.length;n++){if(r===i.length)return e.slice(n);e[n]!=="--json"&&e[n]===i[r]&&r++}return[]}f(pe,"rawArgsAfterPath");function ge(e,i){const r=ae(e.bin,i,{stdio:"inherit"});if(r.error!==void 0){const n=r.error;throw new N("binary_missing",`${e.bin} could not be run (${n.code??n.message})`,S.USAGE,{received:e.bin,next:e.installHint})}if(r.status!==null&&process.exit(r.status),r.signal!==null){const n=oe.signals[r.signal];n!==void 0&&process.exit(128+n)}process.exit(1)}f(ge,"runPassthrough");function we(e,i,r){const n=fe(e),a=n.length>0?n.join(", "):"(none)",l=i.length>0?`crtr ${i.join(" ")} -h`:"crtr -h",s=n.some(o=>o.startsWith("(and "));return new N("unknown_path",`unknown subcommand: ${r}`,S.USAGE,{received:r,next:s?`Valid children include: ${a}. Run \`${l}\` for how to find the rest.`:`Valid children: ${a}. Run \`${l}\` for the full list.`})}f(we,"unknownPathError");const be="https://account.northlight.ai";function ve(e){const i=be,r=`open ${i}/account/machines, choose Create join token, then run \`crtr sys join --directory ${i} --token <token>\``;return new N("not_joined",`\`crtr ${e}\` isn't a command on this machine. If it comes from Northlight, this machine isn't joined to your account yet: ${r}.`,S.USAGE,{received:e,next:`${r[0].toUpperCase()}${r.slice(1)}.`})}f(ve,"notJoinedError");async function xe(){try{const{readConfig:e}=await import("./config.js");return!e("user").runtime?.issuer}catch{return!1}}f(xe,"runtimeUnjoined");function p(e,i,r,n,a){return new N(e,i,S.USAGE,{received:r,field:n,next:a!==void 0?a:"Run the command with -h to see the parameter schema."})}f(p,"parseArgvError");function k(e){return e.replace(/-([a-z])/g,(i,r)=>r.toUpperCase())}f(k,"flagNameToKey");async function ke(e,i,r){const n={},a=new Set,l=new Map,s=e.filter(t=>t.kind==="positional"),o=e.find(t=>t.kind==="stdin"),x=e.find(t=>t.kind==="context-file"),b=e.filter(t=>t.kind==="flag"),$=new Map(b.map(t=>[t.name,t])),y=b.some(t=>t.sensitive===!0);for(const t of b)t.type==="bool"?n[k(t.name)]=t.default!==void 0?t.default:!1:t.default!==void 0&&(n[k(t.name)]=t.default);const g=[];let v=0,_=!1,w=!1,c=0;for(;c<i.length;){const t=i[c];if(t==="--"&&!w){w=!0,c++;continue}if(!w&&t.startsWith("--")){const h=t.indexOf("=");let d,P;if(h!==-1?(d=t.slice(2,h),P=t.slice(h+1)):d=t.slice(2),d==="context-file"){if(x===void 0)throw p("unknown_flag","unknown flag: --context-file","--context-file",void 0,"This leaf does not accept --context-file.");const m=P!==void 0?P:i[++c];if(m===void 0)throw p("missing_parameter","--context-file requires a PATH argument","--context-file","context-file");let H;try{H=re(m,"utf8")}catch{throw p("invalid_type",`--context-file: cannot read file: ${m}`,m,"context-file","Provide a readable file path.")}let q;try{q=JSON.parse(H)}catch{throw p("invalid_type",`--context-file: file is not valid JSON: ${m}`,m,"context-file","Ensure the file contains a valid JSON object.")}const T=k(x.name);n[T]=q,l.set(T,le(m)),a.add(T),c++;continue}const E=$.get(d);if(E===void 0)throw p("unknown_flag",`unknown flag: --${d}`,`--${d}`,void 0,"Use --<flag-name> for declared flags only. Run -h for the schema.");const U=k(d);if(a.add(U),E.type==="bool"){if(P!==void 0)throw p("invalid_type",`boolean flag --${d} takes no value`,`--${d}=${P}`,d,`Use --${d} (presence = true) with no value.`);n[U]=!0,c++;continue}const C=P!==void 0?P:i[++c];if(C===void 0||P===void 0&&C.startsWith("--")){const m=E.focusedHelp!==void 0&&(r?.leafPath?.length??0)>0?`Run \`crtr ${r.leafPath.join(" ")} --${d} -h\` and read the focused value contract before retrying.`:void 0;throw p("missing_parameter",`--${d} requires a value`,`--${d}`,d,m)}let R;if(E.type==="int"){const m=Number(C);if(!Number.isInteger(m))throw p("invalid_type",`--${d} must be an integer`,C,d,`Provide an integer value for --${d}.`);R=m}else if(E.type==="enum"){const m=E.choices;if(m!==void 0&&!m.includes(C))throw p("invalid_type",`--${d} must be one of: ${m.join(", ")}`,C,d,`Retry with one of: ${m.join(", ")}.`);R=C}else R=C;if(E.repeatable===!0){const m=n[U],H=Array.isArray(m)?m:[];H.push(R),n[U]=H}else n[U]=R;c++;continue}const u=s[v];if(u!==void 0){const h=k(u.name);if(u.repeatable===!0){const d=n[h]??[];d.push(t),n[h]=d}else n[h]=t,v++;g.push(t),_=!0,a.add(h),c++;continue}if(g.length>0){if(o!==void 0&&s.length===0){g.push(t),_=!0,c++;continue}throw o!==void 0?p("bad_invocation",`unexpected extra positional argument (value withheld: this leaf reads "${o.name}" from stdin, never argv)`,void 0,void 0,"Pipe it on stdin instead of passing it as a positional argument."):p("bad_invocation",y?"unexpected extra positional argument (value withheld: this leaf takes a secret)":`unexpected extra positional argument: ${t}`,y?void 0:i.join(" "),void 0,"Use declared flags or positional parameters. Run -h for the schema.")}if(s.length===0&&(o===void 0||o.allowPositional===!1))throw p("bad_invocation",y?"this leaf takes no positional arguments (value withheld: this leaf takes a secret)":`this leaf takes no positional arguments: ${t}`,y?void 0:t,void 0,"Use --flag for parameters. Run -h for the schema.");g.push(t),_=!0,c++}let A=!1;if(o!==void 0){if(g.length>1&&s.length===0){const t=o.positionalStdinConflict?.(n);throw t!==void 0?p("bad_invocation",t.message,void 0,t.field,t.next):p("bad_invocation",`unexpected extra positional argument (value withheld: this leaf reads "${o.name}" from stdin, never argv)`,void 0,void 0,"Pipe it on stdin instead of passing it as a positional argument.")}if(g.length>0&&s.length===0&&o.allowPositional!==!1){const t=g[0];if(t==="-"){const u=await B();(u.trim()!==""||!o.required)&&(n[k(o.name)]=u),A=!0}else{if((await D()).trim()!==""){const h=o.positionalStdinConflict?.(n);throw p("bad_invocation",h?.message??`both a positional argument ("${t}") and piped stdin were provided for ${o.name}`,t,h?.field??o.name,h?.next??"Pass exactly one: either the positional argument or piped stdin, not both.")}n[k(o.name)]=t,A=!0}}else{const t=se(0),u=await B();(u.trim()!==""||!o.required)&&(n[k(o.name)]=u),A=!t||_}}A&&o!==void 0&&a.add(k(o.name));for(const t of e){if(t.kind!=="flag"&&t.kind!=="positional"||t.defaultFromEnv===void 0)continue;const u=k(t.name);if(a.has(u))continue;const h=process.env[t.defaultFromEnv];h===void 0||h===""||(n[u]=t.kind==="positional"&&t.repeatable===!0?[h]:h,a.add(u))}const j=[];for(const t of e){const u=k(t.name),h=t.kind==="flag"&&t.type==="bool"&&!a.has(u);if(t.required&&(h||n[u]===void 0||n[u]===null)){const d=t.kind==="positional"?`positional ${t.name.toUpperCase()}`:t.kind==="flag"?`--${t.name}`:t.kind==="context-file"?"--context-file":"stdin";j.push({display:d,name:t.name})}}if(j.length>0){const t=j.map(d=>d.display).join(", "),u=r?.leafPath,h=u!==void 0&&u.length>0?`\`crtr ${u.join(" ")} -h\``:"this command with -h";throw p("missing_parameter",j.length===1?`required parameter is missing: ${t}`:`required parameters are missing: ${t}`,void 0,j.map(d=>d.name).join(", "),`Run ${h} and read the full schema before re-issuing \u2014 do not guess parameters one at a time.`)}return r?.onProvidedParams!==void 0&&r.onProvidedParams(a),r?.onContextFilePaths!==void 0&&r.onContextFilePaths(l),n}f(ke,"parseArgv");function ye(e){const i=[];let r;for(let n=0;n<e.length;n++){const a=e[n];if(a==="--"){i.push(...e.slice(n));break}const l=a.startsWith("--machine=")?a.slice(10):void 0;if(a!=="--machine"&&l===void 0){i.push(a);continue}const s=l??e[n+1];if(s===void 0||s===""||l===void 0&&s.startsWith("-"))throw p("missing_parameter","--machine requires a machine id","--machine","machine","Pass the machine_id of one of the candidates a `machine_required` answer lists.");l===void 0&&n++,r=s}return r===void 0?{rest:i}:{rest:i,machine:r}}f(ye,"takeMachineSelector");const Se=new Set(["--json","--no-autostart"]);async function Me(e,i){const r=i.slice(2);r.includes("--json")&&X(!0);const n=r.filter(o=>!Se.has(o));if(n.length===0||n.length===1&&(n[0]==="-h"||n[0]==="--help")){const o=ie()?{...e.help,commands:await Promise.all(e.help.commands.map(async x=>{const b=e.subtrees.find(v=>v.name===x.name);if(b?.effectiveHelp===void 0)return x;const y=((await b.effectiveHelp()).listing??[]).filter(v=>v.tier!=="hidden"),g=I(y).map(v=>({path:`${b.name} ${v.name}`,desc:v.tier==="important"?v.description:void 0}));return{...x,subcommands:g.length?g:void 0,otherSubcommandCount:y.length-g.length}}))}:e.help;process.stdout.write(F(o)+`
6
- `),process.exitCode=S.SUCCESS;return}if(n.length===1&&(n[0]==="--version"||n[0]==="-v")){const{readPackageVersion:o}=await import("../commands/sys/shared.js");process.stdout.write(o()+`
7
- `),process.exitCode=S.SUCCESS;return}let{node:a,path:l,remaining:s}=ce(e,n);try{if(a.kind==="branch"&&a.passthrough!==void 0&&ge(a.passthrough,pe(r,l)),a.kind==="branch"&&a.unavailable!==void 0&&s.length>0&&s[0]!=="-h"&&s[0]!=="--help")throw new N("provider_unavailable",a.unavailable,S.NETWORK,{next:"The daemon retries bundle installation on grant sync; retry after the provider becomes available."});if((a.kind==="root"||a.kind==="branch")&&s.length>0&&s[0]!=="-h"&&s[0]!=="--help")throw a.kind==="root"&&!s[0].startsWith("-")&&await xe()?ve(s[0]):we(a,l,s[0]);if(he(s)){process.stdout.write(await M(a,l,me(a,s))+`
8
- `),process.exitCode=S.SUCCESS;return}if(a.kind==="root"||a.kind==="branch"){process.stdout.write(await M(a,l)+`
9
- `),process.exitCode=S.SUCCESS;return}const o=a;L(l.join(" "));const x=o.help.params!==void 0?o.help.params:[];let b=new Set,$=new Map,y=s,g;if(o.machineSelector===!0&&!x.some(c=>c.kind==="flag"&&c.name==="machine")){const c=ye(s);y=c.rest,g=c.machine}const v=await ke(x,y,{leafPath:l,onProvidedParams:f(c=>{b=c},"onProvidedParams"),onContextFilePaths:f(c=>{$=c},"onContextFilePaths")}),_={providedParams:b,contextFilePaths:$,...g===void 0?{}:{machine:g}},w=await te.fresh(()=>o.run(v,_));if(K(w==null?w:o.preview?.(w)??w),w!=null)if(Z())Y(w);else{const c=o.render!==void 0?o.render(w):ee(w,o.help);process.stdout.write(c+(o.stdoutExact?.(w)?"":`
10
- `))}}catch(o){if(ne(o))throw o;Q(o)}}f(Me,"runCli");export{be as DEFAULT_DIRECTORY_ISSUER,Se as GLOBAL_TOKENS,Ie as collectSlashSpecs,Ve as defineBranch,Fe as defineLeaf,Be as defineRoot,ve as notJoinedError,ke as parseArgv,ue as renderNode,Me as runCli,ye as takeMachineSelector,we as unknownPathError,ce as walk};
3
+ <plugin-help plugin="${E.plugin}">
4
+ ${E.text}
5
+ </plugin-help>`).join("")}f(z,"renderNodeWithAddenda");function me(e){return e.some(i=>i==="-h"||i==="--help")}f(me,"helpRequested");function ge(e,i){if(e.kind!=="leaf"||i.length!==2)return;const[r,n]=i;if(n!=="-h"&&n!=="--help"||!r.startsWith("--")||r.includes("="))return;const a=r.slice(2);return(e.help.params??[]).find(s=>s.kind==="flag"&&s.name===a)?.focusedHelp!==void 0?a:void 0}f(ge,"focusedHelpFlag");function we(e,i){let r=0;for(let n=0;n<e.length;n++){if(r===i.length)return e.slice(n);e[n]!=="--json"&&e[n]===i[r]&&r++}return[]}f(we,"rawArgsAfterPath");function ve(e,i){const r=le(e.bin,i,{stdio:"inherit"});if(r.error!==void 0){const n=r.error;throw new H("binary_missing",`${e.bin} could not be run (${n.code??n.message})`,C.USAGE,{received:e.bin,next:e.installHint})}if(r.status!==null&&process.exit(r.status),r.signal!==null){const n=de.signals[r.signal];n!==void 0&&process.exit(128+n)}process.exit(1)}f(ve,"runPassthrough");function be(e,i,r){const n=ue(e),a=n.length>0?n.join(", "):"(none)",d=i.length>0?`crtr ${i.join(" ")} -h`:"crtr -h",s=n.some(o=>o.startsWith("(and "));return new H("unknown_path",`unknown subcommand: ${r}`,C.USAGE,{received:r,next:s?`Valid children include: ${a}. Run \`${d}\` for how to find the rest.`:`Valid children: ${a}. Run \`${d}\` for the full list.`})}f(be,"unknownPathError");const xe="https://account.northlight.ai";function ke(e){const i=xe,r=`open ${i}/account/machines, choose Create join token, then run \`crtr sys join --directory ${i} --token <token>\``;return new H("not_joined",`\`crtr ${e}\` isn't a command on this machine. If it comes from Northlight, this machine isn't joined to your account yet: ${r}.`,C.USAGE,{received:e,next:`${r[0].toUpperCase()}${r.slice(1)}.`})}f(ke,"notJoinedError");async function ye(){try{const{readConfig:e}=await import("./config.js");return!e("user").runtime?.issuer}catch{return!1}}f(ye,"runtimeUnjoined");function m(e,i,r,n,a){return new H(e,i,C.USAGE,{received:r,field:n,next:a!==void 0?a:"Run the command with -h to see the parameter schema."})}f(m,"parseArgvError");function $(e){return e.replace(/-([a-z])/g,(i,r)=>r.toUpperCase())}f($,"flagNameToKey");async function $e(e,i,r){const n={},a=new Set,d=new Map,s=e.filter(t=>t.kind==="positional"),o=e.find(t=>t.kind==="stdin"),k=e.find(t=>t.kind==="context-file"),v=e.filter(t=>t.kind==="flag"),E=new Map(v.map(t=>[t.name,t])),S=v.some(t=>t.sensitive===!0);for(const t of v)t.type==="bool"?n[$(t.name)]=t.default!==void 0?t.default:!1:t.default!==void 0&&(n[$(t.name)]=t.default);const g=[];let b=0,j=!1,w=!1,u=0;for(;u<i.length;){const t=i[u];if(t==="--"&&!w){w=!0,u++;continue}if(!w&&t.startsWith("--")){const p=t.indexOf("=");let l,_;if(p!==-1?(l=t.slice(2,p),_=t.slice(p+1)):l=t.slice(2),l==="context-file"){if(k===void 0)throw m("unknown_flag","unknown flag: --context-file","--context-file",void 0,"This leaf does not accept --context-file.");const c=_!==void 0?_:i[++u];if(c===void 0)throw m("missing_parameter","--context-file requires a PATH argument","--context-file","context-file");let x;try{x=se(c,"utf8")}catch{throw m("invalid_type",`--context-file: cannot read file: ${c}`,c,"context-file","Provide a readable file path.")}let F;try{F=JSON.parse(x)}catch{throw m("invalid_type",`--context-file: file is not valid JSON: ${c}`,c,"context-file","Ensure the file contains a valid JSON object.")}const O=$(k.name);n[O]=F,d.set(O,ce(c)),a.add(O),u++;continue}const P=E.get(l);if(P===void 0)throw m("unknown_flag",`unknown flag: --${l}`,`--${l}`,void 0,"Use --<flag-name> for declared flags only. Run -h for the schema.");const R=$(l);if(a.add(R),P.type==="bool"){if(_!==void 0)throw m("invalid_type",`boolean flag --${l} takes no value`,`--${l}=${_}`,l,`Use --${l} (presence = true) with no value.`);n[R]=!0,u++;continue}const y=_!==void 0?_:i[++u];if(y===void 0||_===void 0&&y.startsWith("--")){const c=P.focusedHelp!==void 0&&(r?.leafPath?.length??0)>0?`Run \`crtr ${r.leafPath.join(" ")} --${l} -h\` and read the focused value contract before retrying.`:void 0;throw m("missing_parameter",`--${l} requires a value`,`--${l}`,l,c)}let U;if(P.type==="int"){const c=Number(y);if(!Number.isInteger(c))throw m("invalid_type",`--${l} must be an integer`,y,l,`Provide an integer value for --${l}.`);U=c}else if(P.type==="enum"){const c=P.choices;if(c!==void 0&&!c.includes(y))throw m("invalid_type",`--${l} must be one of: ${c.join(", ")}`,y,l,`Retry with one of: ${c.join(", ")}.`);U=y}else if(P.type==="json"){let c;try{c=JSON.parse(y)}catch{throw m("invalid_type",`--${l} is not valid JSON`,y,l,`Pass one JSON value for --${l}; run -h for its shape.`)}const x=P.shape===void 0?null:ie(P.shape,c,`--${l}`);if(x!==null)throw m("invalid_type",`${x.path} must be ${x.expected}, got ${x.receivedType}`,y,x.path,`Fix ${x.path}; run -h for the shape of --${l}.`);U=c}else U=y;if(P.repeatable===!0){const c=n[R],x=Array.isArray(c)?c:[];x.push(U),n[R]=x}else n[R]=U;u++;continue}const h=s[b];if(h!==void 0){const p=$(h.name);if(h.repeatable===!0){const l=n[p]??[];l.push(t),n[p]=l}else n[p]=t,b++;g.push(t),j=!0,a.add(p),u++;continue}if(g.length>0){if(o!==void 0&&s.length===0){g.push(t),j=!0,u++;continue}throw o!==void 0?m("bad_invocation",`unexpected extra positional argument (value withheld: this leaf reads "${o.name}" from stdin, never argv)`,void 0,void 0,"Pipe it on stdin instead of passing it as a positional argument."):m("bad_invocation",S?"unexpected extra positional argument (value withheld: this leaf takes a secret)":`unexpected extra positional argument: ${t}`,S?void 0:i.join(" "),void 0,"Use declared flags or positional parameters. Run -h for the schema.")}if(s.length===0&&(o===void 0||o.allowPositional===!1))throw m("bad_invocation",S?"this leaf takes no positional arguments (value withheld: this leaf takes a secret)":`this leaf takes no positional arguments: ${t}`,S?void 0:t,void 0,"Use --flag for parameters. Run -h for the schema.");g.push(t),j=!0,u++}let T=!1;if(o!==void 0){if(g.length>1&&s.length===0){const t=o.positionalStdinConflict?.(n);throw t!==void 0?m("bad_invocation",t.message,void 0,t.field,t.next):m("bad_invocation",`unexpected extra positional argument (value withheld: this leaf reads "${o.name}" from stdin, never argv)`,void 0,void 0,"Pipe it on stdin instead of passing it as a positional argument.")}if(g.length>0&&s.length===0&&o.allowPositional!==!1){const t=g[0];if(t==="-"){const h=await B();(h.trim()!==""||!o.required)&&(n[$(o.name)]=h),T=!0}else{if((await Q()).trim()!==""){const p=o.positionalStdinConflict?.(n);throw m("bad_invocation",p?.message??`both a positional argument ("${t}") and piped stdin were provided for ${o.name}`,t,p?.field??o.name,p?.next??"Pass exactly one: either the positional argument or piped stdin, not both.")}n[$(o.name)]=t,T=!0}}else{const t=fe(0),h=await B();(h.trim()!==""||!o.required)&&(n[$(o.name)]=h),T=!t||j}}T&&o!==void 0&&a.add($(o.name));for(const t of e){if(t.kind!=="flag"&&t.kind!=="positional"||t.defaultFromEnv===void 0)continue;const h=$(t.name);if(a.has(h))continue;const p=process.env[t.defaultFromEnv];p===void 0||p===""||(n[h]=t.kind==="positional"&&t.repeatable===!0?[p]:p,a.add(h))}const N=[];for(const t of e){const h=$(t.name),p=t.kind==="flag"&&t.type==="bool"&&!a.has(h);if(t.required&&(p||n[h]===void 0||n[h]===null)){const l=t.kind==="positional"?`positional ${t.name.toUpperCase()}`:t.kind==="flag"?`--${t.name}`:t.kind==="context-file"?"--context-file":"stdin";N.push({display:l,name:t.name})}}if(N.length>0){const t=N.map(l=>l.display).join(", "),h=r?.leafPath,p=h!==void 0&&h.length>0?`\`crtr ${h.join(" ")} -h\``:"this command with -h";throw m("missing_parameter",N.length===1?`required parameter is missing: ${t}`:`required parameters are missing: ${t}`,void 0,N.map(l=>l.name).join(", "),`Run ${p} and read the full schema before re-issuing \u2014 do not guess parameters one at a time.`)}return r?.onProvidedParams!==void 0&&r.onProvidedParams(a),r?.onContextFilePaths!==void 0&&r.onContextFilePaths(d),n}f($e,"parseArgv");function Se(e){const i=[];let r;for(let n=0;n<e.length;n++){const a=e[n];if(a==="--"){i.push(...e.slice(n));break}const d=a.startsWith("--machine=")?a.slice(10):void 0;if(a!=="--machine"&&d===void 0){i.push(a);continue}const s=d??e[n+1];if(s===void 0||s===""||d===void 0&&s.startsWith("-"))throw m("missing_parameter","--machine requires a machine id","--machine","machine","Pass the machine_id of one of the candidates a `machine_required` answer lists.");d===void 0&&n++,r=s}return r===void 0?{rest:i}:{rest:i,machine:r}}f(Se,"takeMachineSelector");const Pe=new Set(["--json","--no-autostart"]);async function Ge(e,i){const r=i.slice(2);r.includes("--json")&&ee(!0);const n=r.filter(o=>!Pe.has(o));if(n.length===0||n.length===1&&(n[0]==="-h"||n[0]==="--help")){const o=oe()?{...e.help,commands:await Promise.all(e.help.commands.map(async k=>{const v=e.subtrees.find(b=>b.name===k.name);if(v?.effectiveHelp===void 0)return k;const S=((await v.effectiveHelp()).listing??[]).filter(b=>b.tier!=="hidden"),g=J(S).map(b=>({path:`${v.name} ${b.name}`,desc:b.tier==="important"?b.description:void 0}));return{...k,subcommands:g.length?g:void 0,otherSubcommandCount:S.length-g.length}}))}:e.help;process.stdout.write(V(o)+`
6
+ `),process.exitCode=C.SUCCESS;return}if(n.length===1&&(n[0]==="--version"||n[0]==="-v")){const{readPackageVersion:o}=await import("../commands/sys/shared.js");process.stdout.write(o()+`
7
+ `),process.exitCode=C.SUCCESS;return}let{node:a,path:d,remaining:s}=he(e,n);try{if(a.kind==="branch"&&a.passthrough!==void 0&&ve(a.passthrough,we(r,d)),a.kind==="branch"&&a.unavailable!==void 0&&s.length>0&&s[0]!=="-h"&&s[0]!=="--help")throw new H("provider_unavailable",a.unavailable,C.NETWORK,{next:"The daemon retries bundle installation on grant sync; retry after the provider becomes available."});if((a.kind==="root"||a.kind==="branch")&&s.length>0&&s[0]!=="-h"&&s[0]!=="--help")throw a.kind==="root"&&!s[0].startsWith("-")&&await ye()?ke(s[0]):be(a,d,s[0]);if(me(s)){process.stdout.write(await z(a,d,ge(a,s))+`
8
+ `),process.exitCode=C.SUCCESS;return}if(a.kind==="root"||a.kind==="branch"){process.stdout.write(await z(a,d)+`
9
+ `),process.exitCode=C.SUCCESS;return}const o=a;D(d.join(" "));const k=o.help.params!==void 0?o.help.params:[];let v=new Set,E=new Map,S=s,g;if(o.machineSelector===!0&&!k.some(u=>u.kind==="flag"&&u.name==="machine")){const u=Se(s);S=u.rest,g=u.machine}const b=await $e(k,S,{leafPath:d,onProvidedParams:f(u=>{v=u},"onProvidedParams"),onContextFilePaths:f(u=>{E=u},"onContextFilePaths")}),j={providedParams:v,contextFilePaths:E,...g===void 0?{}:{machine:g}},w=await ae.fresh(()=>o.run(b,j));if(Y(w==null?w:o.preview?.(w)??w),w!=null)if(ne())X(w);else{const u=o.render!==void 0?o.render(w):te(w,o.help);process.stdout.write(u+(o.stdoutExact?.(w)?"":`
10
+ `))}}catch(o){if(re(o))throw o;Z(o)}}f(Ge,"runCli");export{xe as DEFAULT_DIRECTORY_ISSUER,Pe as GLOBAL_TOKENS,Me as collectSlashSpecs,Be as defineBranch,Je as defineLeaf,ze as defineRoot,ke as notJoinedError,$e as parseArgv,pe as renderNode,Ge as runCli,Se as takeMachineSelector,be as unknownPathError,he as walk};
@@ -2,7 +2,7 @@
2
2
  * delete, history, read, and the two import paths (migration, repo sync). Every act records
3
3
  * its actor's `acted-on` edge and watch and publishes its event in the caller's transaction. */
4
4
  import type { DatabaseSync } from 'node:sqlite';
5
- import type { ReposFn } from './reader.js';
5
+ import { type ReposFn } from './reader.js';
6
6
  import type { ObjectRow, Privacy, Reader, Revision, RuleSpec } from './types.js';
7
7
  export interface DocumentFields {
8
8
  preview?: string;
@@ -64,7 +64,8 @@ export declare function documentRecord(db: DatabaseSync, doc: ObjectRow): Docume
64
64
  /** The `[[name]]` links a body names, in order, each once. */
65
65
  export declare function linksIn(body: string): string[];
66
66
  /** Derive the document's `links-to` edges from `body`, resolving each name in the writer's
67
- * view. A name that resolves to nothing or to several objects stays text and is returned;
67
+ * view. A name that resolves to nothing or to several objects stays text and is returned,
68
+ * and remembered so {@link linkNewlyNamed} can link it when a document by that name appears;
68
69
  * one that may live on another runtime is neither linked nor reported. */
69
70
  export declare function setRevisionLinks(db: DatabaseSync, reader: Reader, doc: ObjectRow, body: string): string[];
70
71
  /** `body` with each `[[link]]` the document's `links-to` edges resolved shown under its target's
@@ -121,14 +122,14 @@ export declare function history(db: DatabaseSync, reader: Reader, doc: ObjectRow
121
122
  export declare function moveDocument(db: DatabaseSync, reader: Reader | null, doc: ObjectRow, to: {
122
123
  name?: string;
123
124
  owner?: ObjectRow;
124
- }): ObjectRow;
125
+ }, reposFn?: ReposFn): ObjectRow;
125
126
  /** Mark the document deleted; the row stays with its last preview. Publishes `deleted`
126
127
  * (level 8), then ends the watches on it and drops its rules. A null actor is repo sync or
127
128
  * node deletion; `deletedAt` is the tombstone's own time when sync imports one. What it linked to is re-checked by {@link collectUnlinked}. */
128
129
  export declare function deleteDocument(db: DatabaseSync, reader: Reader | null, doc: ObjectRow, reposFn?: ReposFn, deletedAt?: string): ObjectRow;
129
130
  /** Repo sync: bring a deleted document back under `name` (checked free first). Revisions, record
130
131
  * and links are untouched; the watches and rules deletion dropped are not recreated here. */
131
- export declare function restoreDocument(db: DatabaseSync, doc: ObjectRow, name: string): ObjectRow;
132
+ export declare function restoreDocument(db: DatabaseSync, doc: ObjectRow, name: string, reposFn?: ReposFn): ObjectRow;
132
133
  /** Delete each of `targets` that is a kept document nothing links to any more: a live document
133
134
  * whose owner is deleted (node deletion kept it because a live document linked to it) and that
134
135
  * no other live document links to. Each one deleted re-checks what it linked to, so chains of
@@ -150,7 +151,7 @@ export interface ImportSpec extends WriteSpec {
150
151
  /** Migration: a document with its linear history (oldest first; bodies already in the body
151
152
  * store). Explicit authors and times; records no edge or watch and publishes nothing — the
152
153
  * caller adds links (`setRevisionLinks`), acted-on edges and watches. */
153
- export declare function importDocument(db: DatabaseSync, spec: ImportSpec): ObjectRow;
154
+ export declare function importDocument(db: DatabaseSync, spec: ImportSpec, reposFn?: ReposFn): ObjectRow;
154
155
  export interface SyncedRevision {
155
156
  rev_id: string;
156
157
  parents: readonly string[];
@@ -1,10 +1,10 @@
1
- var ne=Object.defineProperty;var s=(t,n)=>ne(t,"name",{value:n,configurable:!0});import{prepared as c}from"../sqlite-statements.js";import{randomUUID as re}from"node:crypto";import{CrtrError as O,notFound as R,usage as m}from"../errors.js";import{ExitCode as D}from"../../types.js";import{canChange as k,canRead as J,missingMemoryScope as oe,missingMemoryScopeUnder as ie,ownerChain as se}from"./access.js";import{bodyOf as ae,get as ue,put as P}from"./bodies.js";import{recordActedOn as N,setLinks as ce}from"./edges.js";import{publish as x}from"./events.js";import{resolveName as le}from"./names.js";import{createObject as me,getById as we,getByRowid as d}from"./objects.js";import{replaceRules as B,setRulesOwner as pe}from"./rules.js";import{recordWatch as $}from"./watches.js";function y(t){return t.class==="node"?t.node:t.class==="app"?t.app:t.class==="object"?t.object:t.person}s(y,"actorOf");let de=0;function E(t,n){const e=`graph_doc_${++de}`;t.exec(`SAVEPOINT ${e}`);try{const r=n();return t.exec(`RELEASE ${e}`),r}catch(r){throw t.exec(`ROLLBACK TO ${e}`),t.exec(`RELEASE ${e}`),r}}s(E,"atomic");function fe(t,n){return new O("conflict",t,D.GENERAL,n)}s(fe,"conflict");function _(t){if(t.type!=="document")throw m(`${t.type} ${t.id} is not a document`)}s(_,"assertDocument");function K(t,n){const e=se(t,n);return(e.length?e[e.length-1]:n).type}s(K,"spaceType");function I(t,n,e){if(e!=="public"&&K(t,n)==="repo")throw m(`a repo owns only public documents; ${n.name} cannot own a ${e} one`,{rule:"repo-public-only",next:"Write it as public, or give it another owner (your own documents can carry `if: {repo: <handle>}`)."})}s(I,"assertPublicInRepo");function H(t,n,e,r){if(e.trim()===""||e!==e.trim())throw m(`invalid document name ${JSON.stringify(e)}`);const o=c(t,"SELECT id FROM objects WHERE (type = 'document' OR instr(type, '.') > 0) AND owner = ? AND name = ? AND deleted_at IS NULL AND home_machine IS NULL").get(n.rowid,e);if(o&&o.id!==r?.id)throw fe(`${n.name} already has a document named ${e}`,{name:e,holder:o.id})}s(H,"assertNameFree");function C(t,n,e){if(!J(t,n,e))throw R(`no document ${e.id}`)}s(C,"readable");function G(t){return new O("scope_missing",`missing scope ${t}`,D.GENERAL,{scope:t})}s(G,"scopeMissing");function T(t,n,e){C(t,n,e);const r=oe(t,n,e,"rw");if(r!==null)throw G(r);if(!k(t,n,e))throw new O("forbidden",`you cannot change ${e.name}`,D.GENERAL,{id:e.id})}s(T,"changeable");function V(t,n){const e=c(t,`SELECT p.rev_id FROM revision_parents rp JOIN revisions p ON p.rowid = rp.parent
2
- WHERE rp.child = ? ORDER BY p.rev_id`).all(n.rowid);return{rowid:n.rowid,rev_id:n.rev_id,number:n.number,body_hash:n.body_hash,author:n.author===null?null:d(t,n.author)?.id??null,rationale:n.rationale,verbatim:n.verbatim===1,created_at:n.created_at,parents:e.map(r=>r.rev_id)}}s(V,"toRevision");function W(t,n){return c(t,`SELECT * FROM revisions r WHERE r.document = ?
3
- AND NOT EXISTS (SELECT 1 FROM revision_parents p WHERE p.parent = r.rowid) ORDER BY r.number DESC, r.rev_id`).all(n.rowid).map(r=>V(t,r))}s(W,"heads");function he(t){return t.map(n=>n.rev_id).sort().join(",")}s(he,"headsKeyOf");function A(t,n){const e=c(t,"SELECT * FROM documents WHERE object = ?").get(n.rowid);if(!e)throw R(`no document record for ${n.id}`);return{summary:e.summary,heads_key:e.heads_key,revision:e.revision,why_it_exists:e.why_it_exists,unlisted:e.unlisted===1,lint_ignore:e.lint_ignore_json===null?null:JSON.parse(e.lint_ignore_json),extensions:e.extensions_json===null?null:JSON.parse(e.extensions_json),source_path:e.source_path}}s(A,"documentRecord");function L(t,n,e){const r=c(t,`INSERT INTO revisions (document, rev_id, number, body_hash, author, rationale, verbatim, created_at)
4
- VALUES (?, ?, ?, ?, ?, ?, ?, ?) RETURNING *`).get(n.rowid,e.rev_id??re(),e.number,e.body_hash,e.author?.rowid??null,e.rationale,e.verbatim?1:0,e.created_at??new Date().toISOString()),o=c(t,"INSERT INTO revision_parents (child, parent) VALUES (?, ?)");for(const i of e.parents)o.run(r.rowid,i);return r}s(L,"insertRevision");function Ee(t){const n=new Set;for(const e of t.matchAll(/\[\[([^[\]\n]+?)\]\]/g))n.add(e[1].trim());return[...n]}s(Ee,"linksIn");function Y(t,n,e,r){const o=[],i=[];for(const a of Ee(r)){const u=le(t,n,a);"object"in u?o.push({written_as:a,dst:u.object}):"deleted"in u?o.push({written_as:a,dst:u.deleted}):"remote"in u||i.push(a)}return b(t,ce(t,e,o)),i}s(Y,"setRevisionLinks");function _e(t,n,e){return n.type==="node"?n.id:c(t,`SELECT 1 FROM objects o JOIN objects d ON d.owner = o.rowid
1
+ var ie=Object.defineProperty;var a=(e,t)=>ie(e,"name",{value:t,configurable:!0});import{prepared as l}from"../sqlite-statements.js";import{randomUUID as se}from"node:crypto";import{CrtrError as O,notFound as N,usage as w}from"../errors.js";import{ExitCode as D}from"../../types.js";import{canChange as j,canRead as P,missingMemoryScope as ae,missingMemoryScopeUnder as ue,ownerChain as ce}from"./access.js";import{bodyOf as le,get as me,put as B}from"./bodies.js";import{dropUnresolved as we,linksOf as de,recordActedOn as R,setLinks as K,setUnresolved as pe,unresolvedLinksCouldName as fe}from"./edges.js";import{publish as x}from"./events.js";import{resolveName as he}from"./names.js";import{createObject as Ee,getById as _e,getByRowid as p}from"./objects.js";import{liveLookups as ye,readerForNode as ve,readerForObject as Ne}from"./reader.js";import{replaceRules as G,setRulesOwner as Re}from"./rules.js";import{recordWatch as $}from"./watches.js";function y(e){return e.class==="node"?e.node:e.class==="app"?e.app:e.class==="object"?e.object:e.person}a(y,"actorOf");let ge=0;function E(e,t){const n=`graph_doc_${++ge}`;e.exec(`SAVEPOINT ${n}`);try{const r=t();return e.exec(`RELEASE ${n}`),r}catch(r){throw e.exec(`ROLLBACK TO ${n}`),e.exec(`RELEASE ${n}`),r}}a(E,"atomic");function Se(e,t){return new O("conflict",e,D.GENERAL,t)}a(Se,"conflict");function _(e){if(e.type!=="document")throw w(`${e.type} ${e.id} is not a document`)}a(_,"assertDocument");function V(e,t){const n=ce(e,t);return(n.length?n[n.length-1]:t).type}a(V,"spaceType");function I(e,t,n){if(n!=="public"&&V(e,t)==="repo")throw w(`a repo owns only public documents; ${t.name} cannot own a ${n} one`,{rule:"repo-public-only",next:"Write it as public, or give it another owner (your own documents can carry `if: {repo: <handle>}`)."})}a(I,"assertPublicInRepo");function H(e,t,n,r){if(n.trim()===""||n!==n.trim())throw w(`invalid document name ${JSON.stringify(n)}`);const o=l(e,"SELECT id FROM objects WHERE (type = 'document' OR instr(type, '.') > 0) AND owner = ? AND name = ? AND deleted_at IS NULL AND home_machine IS NULL").get(t.rowid,n);if(o&&o.id!==r?.id)throw Se(`${t.name} already has a document named ${n}`,{name:n,holder:o.id})}a(H,"assertNameFree");function C(e,t,n){if(!P(e,t,n))throw N(`no document ${n.id}`)}a(C,"readable");function Y(e){return new O("scope_missing",`missing scope ${e}`,D.GENERAL,{scope:e})}a(Y,"scopeMissing");function T(e,t,n){C(e,t,n);const r=ae(e,t,n,"rw");if(r!==null)throw Y(r);if(!j(e,t,n))throw new O("forbidden",`you cannot change ${n.name}`,D.GENERAL,{id:n.id})}a(T,"changeable");function X(e,t){const n=l(e,`SELECT p.rev_id FROM revision_parents rp JOIN revisions p ON p.rowid = rp.parent
2
+ WHERE rp.child = ? ORDER BY p.rev_id`).all(t.rowid);return{rowid:t.rowid,rev_id:t.rev_id,number:t.number,body_hash:t.body_hash,author:t.author===null?null:p(e,t.author)?.id??null,rationale:t.rationale,verbatim:t.verbatim===1,created_at:t.created_at,parents:n.map(r=>r.rev_id)}}a(X,"toRevision");function U(e,t){return l(e,`SELECT * FROM revisions r WHERE r.document = ?
3
+ AND NOT EXISTS (SELECT 1 FROM revision_parents p WHERE p.parent = r.rowid) ORDER BY r.number DESC, r.rev_id`).all(t.rowid).map(r=>X(e,r))}a(U,"heads");function Oe(e){return e.map(t=>t.rev_id).sort().join(",")}a(Oe,"headsKeyOf");function k(e,t){const n=l(e,"SELECT * FROM documents WHERE object = ?").get(t.rowid);if(!n)throw N(`no document record for ${t.id}`);return{summary:n.summary,heads_key:n.heads_key,revision:n.revision,why_it_exists:n.why_it_exists,unlisted:n.unlisted===1,lint_ignore:n.lint_ignore_json===null?null:JSON.parse(n.lint_ignore_json),extensions:n.extensions_json===null?null:JSON.parse(n.extensions_json),source_path:n.source_path}}a(k,"documentRecord");function L(e,t,n){const r=l(e,`INSERT INTO revisions (document, rev_id, number, body_hash, author, rationale, verbatim, created_at)
4
+ VALUES (?, ?, ?, ?, ?, ?, ?, ?) RETURNING *`).get(t.rowid,n.rev_id??se(),n.number,n.body_hash,n.author?.rowid??null,n.rationale,n.verbatim?1:0,n.created_at??new Date().toISOString()),o=l(e,"INSERT INTO revision_parents (child, parent) VALUES (?, ?)");for(const i of n.parents)o.run(r.rowid,i);return r}a(L,"insertRevision");function De(e){const t=new Set;for(const n of e.matchAll(/\[\[([^[\]\n]+?)\]\]/g))t.add(n[1].trim());return[...t]}a(De,"linksIn");function q(e,t,n){const r=[],o=[];for(const i of n){const s=he(e,t,i);"object"in s?r.push({written_as:i,dst:s.object}):"deleted"in s?r.push({written_as:i,dst:s.deleted}):"remote"in s||o.push(i)}return{links:r,unresolved:o}}a(q,"resolveLinks");function z(e,t,n,r){const{links:o,unresolved:i}=q(e,t,De(r));return te(e,K(e,n,o)),pe(e,n,i),i}a(z,"setRevisionLinks");function W(e,t,n){const r=new Map;for(const{src:o,name:i}of fe(e,t.name,t.id))r.set(o,[...r.get(o)??[],i]);for(const[o,i]of r){const s=p(e,o),u=s?.owner==null?null:p(e,s.owner);if(!s||s.deleted_at||s.home_machine!==null||!u||u.deleted_at)continue;const c=u.type==="node"?ve(e,u.id,n??(()=>[]),ye(e),!0):Ne(e,s,n),m=q(e,c,i).links.filter(d=>d.dst.rowid===t.rowid);m.length!==0&&(K(e,s,[...de(e,s),...m]),we(e,s,m.map(d=>d.written_as)))}}a(W,"linkNewlyNamed");function xe(e,t,n){return t.type==="node"?t.id:l(e,`SELECT 1 FROM objects o JOIN objects d ON d.owner = o.rowid
5
5
  WHERE o.name = ? AND o.type <> ? AND o.type IN ('person','app','repo','profile')
6
- AND d.type = 'document' AND d.name = ? AND d.deleted_at IS NULL LIMIT 1`).get(n.name,n.type,e)?`${n.type}:${n.name}`:n.name}s(_e,"ownerPrefix");function X(t,n,e){const r=c(t,`SELECT e.written_as, o.* FROM edges e JOIN objects o ON o.rowid = e.dst
7
- WHERE e.type = 'links-to' AND e.src = ? AND e.written_as IS NOT NULL`).all(n.rowid);if(r.length===0)return e;const o=new Map;for(const i of r){if(i.deleted_at||i.written_as===i.id)continue;const a=!i.written_as.includes("/");if(a&&i.name===i.written_as)continue;const u=i.owner===null?null:d(t,i.owner),l=u?`${_e(t,u,i.name)}/${i.name}`:i.name,w=a&&i.owner===n.owner?i.name:l;w!==i.written_as&&o.set(i.written_as,w)}return o.size===0?e:e.replace(/\[\[([^[\]\n]+?)\]\]/g,(i,a)=>{const u=o.get(a.trim());return u===void 0?i:`[[${u}]]`})}s(X,"withCurrentNames");function U(t,n,e){if(e.preview!==void 0){if(e.preview.trim()==="")throw m("a document needs a preview",{field:"preview"});c(t,"UPDATE objects SET preview = ? WHERE rowid = ?").run(e.preview,n.rowid)}e.privacy!==void 0&&(I(t,d(t,n.owner),e.privacy),c(t,"UPDATE objects SET privacy = ? WHERE rowid = ?").run(e.privacy,n.rowid));const r=s((i,a)=>t.prepare(`UPDATE documents SET ${i} = ? WHERE object = ?`).run(a,n.rowid),"set");e.summary!==void 0&&r("summary",e.summary),e.whyItExists!==void 0&&r("why_it_exists",e.whyItExists),e.unlisted!==void 0&&r("unlisted",e.unlisted?1:0),e.lintIgnore!==void 0&&r("lint_ignore_json",e.lintIgnore===null?null:JSON.stringify(e.lintIgnore)),e.extensions!==void 0&&r("extensions_json",e.extensions===null?null:JSON.stringify(e.extensions));const o=d(t,n.rowid);return e.rules!==void 0&&B(t,o,e.rules),o}s(U,"applyDocumentFields");function q(t,n){if(n.owner.deleted_at)throw m(`${n.owner.name} is deleted`);if(n.preview.trim()==="")throw m("a document needs a preview",{field:"preview"});I(t,n.owner,n.privacy),H(t,n.owner,n.name);const e=me(t,{...n.id?{id:n.id}:{},type:"document",kind:n.kind,owner:n.owner.rowid,privacy:n.privacy,name:n.name,preview:n.preview});return c(t,"INSERT INTO documents (object, heads_key, revision) VALUES (?, '', 0)").run(e.rowid),U(t,e,{...n,preview:void 0,privacy:void 0,rules:n.rules??[]})}s(q,"createDocument");function M(t,n){const e=W(t,n),r=he(e),o=Math.max(0,...e.map(i=>i.number));return c(t,"UPDATE documents SET heads_key = ?, revision = ? WHERE object = ?").run(r,o,n.rowid),{heads_key:r,revision:o,headCount:e.length}}s(M,"setHeads");function Ie(t,n,e,r,o){const i=P(r);return E(t,()=>{const a=y(n),u=ie(t,n,e.owner,"rw");if(u!==null)throw G(u);const l=q(t,e),w=L(t,l,{number:1,body_hash:i,author:a,rationale:null,parents:[]}),{heads_key:f}=M(t,l);if(!k(t,n,l))throw R(`no owner ${e.owner.name} you can write to`);const p=Y(t,n,l,r);return N(t,a,l),$(t,a,l,"write",{readHeadsKey:f}),x(t,{event:"created",object:l,actor:a,attrs:{revision:1},pointer:w.rev_id},o),{object:l,revision:1,unresolved:p}})}s(Ie,"writeDocument");function He(t,n,e){return c(t,"SELECT read_heads_key FROM watches WHERE watcher = ? AND object = ?").get(y(n).rowid,e.rowid)?.read_heads_key??null}s(He,"readBase");function ye(t,n){let e=t;for(const[r,{old:o,new:i}]of n.entries()){if(o==="")throw m(`block ${r+1}: a replacement needs non-empty old text`,{field:"replace"});const a=e.indexOf(o);if(a<0)throw m(`block ${r+1}: old text not found: ${JSON.stringify(o.slice(0,120))}`,{field:"replace",old:o});if(e.indexOf(o,a+1)>=0)throw m(`block ${r+1}: old text occurs more than once: ${JSON.stringify(o.slice(0,120))}`,{field:"replace",old:o});e=e.slice(0,a)+i+e.slice(a+o.length)}return e}s(ye,"applyReplacements");function Ce(t,n,e,r,o,i,a={},u){if(_(e),T(t,n,e),e.deleted_at)throw m(`${e.name} is deleted`);if(i===null)throw new O("read_first",`read ${e.name} before editing it`,D.GENERAL,{id:e.id});if(o.trim()==="")throw m("an edit needs a rationale",{field:"rationale"});const l=A(t,e);if(l.heads_key!==i)return{stale:{heads_key:l.heads_key,revision:l.revision}};const w=W(t,e);let f;if("body"in r)f=r.body;else{if(w.length!==1)throw m(`${e.name} has ${w.length} heads and needs a merge; pass the whole merged body`,{heads:w.length});f=ye(X(t,e,ue(w[0].body_hash)),r.replace)}const p=P(f);try{return E(t,()=>{const h=y(n),g=1+Math.max(0,...w.map(v=>v.number)),F=L(t,e,{number:g,body_hash:p,author:h,rationale:o,verbatim:r.verbatim===!0,parents:w.map(v=>v.rowid)}),j=F.rev_id,ee=c(t,"UPDATE documents SET heads_key = ?, revision = ? WHERE object = ? AND heads_key = ?").run(j,g,e.rowid,i);if(Number(ee.changes)===0){const v=A(t,e);throw new z(v.heads_key,v.revision)}const S=U(t,e,a),te=Y(t,n,S,f);return N(t,h,S),$(t,h,S,"write",{readHeadsKey:j}),x(t,{event:"edited",object:S,actor:h,pointer:F.rev_id,attrs:{revision:g,from_revision:l.revision,rationale:o}},u),{revision:g,heads_key:j,unresolved:te}})}catch(h){if(h instanceof z)return{stale:{heads_key:h.heads_key,revision:h.revision}};throw h}}s(Ce,"editDocument");class z extends Error{static{s(this,"StaleEdit")}heads_key;revision;constructor(n,e){super("stale"),this.heads_key=n,this.revision=e}}function We(t,n,e,r){return _(e),n&&T(t,n,e),E(t,()=>{const o=U(t,e,r);return n&&N(t,y(n),o),o})}s(We,"setDocumentRecord");function ve(t,n,e,r){const o=y(n),{heads_key:i}=A(t,e);$(t,o,e,"read",{readHeadsKey:i}),x(t,{event:"read",object:e,actor:o,attrs:{}},r)}s(ve,"recordRead");function Ue(t,n,e,r){return _(e),C(t,n,e),E(t,()=>{const o=A(t,e),i=W(t,e).map(u=>({...u,body:X(t,e,ae(u.body_hash,o.source_path))})),a=c(t,"SELECT dst, written_as FROM edges WHERE type = 'links-to' AND src = ? ORDER BY written_as").all(e.rowid).map(u=>({written_as:u.written_as??"",object:d(t,u.dst)})).filter(u=>u.object&&J(t,n,u.object)).map(u=>({...u,deleted:u.object.deleted_at!==null}));return e.deleted_at||ve(t,n,e,r),{object:e,record:o,heads:i,needsMerge:i.length>1,links:a}})}s(Ue,"readDocument");function Me(t,n,e){return _(e),C(t,n,e),c(t,"SELECT * FROM revisions WHERE document = ? ORDER BY number DESC, created_at DESC, rowid DESC").all(e.rowid).map(o=>V(t,o))}s(Me,"history");function Fe(t,n,e,r){if(_(e),e.deleted_at)throw m(`${e.name} is deleted`);return n&&T(t,n,e),E(t,()=>{const o=r.owner??d(t,e.owner),i=r.name??e.name;H(t,o,i,e),I(t,o,e.privacy),c(t,"UPDATE objects SET name = ?, owner = ? WHERE rowid = ?").run(i,o.rowid,e.rowid);const a=d(t,e.rowid);if(o.rowid!==e.owner&&(pe(t,a),n&&!k(t,n,a)))throw R(`no owner ${o.name} you can move documents to`);return n&&N(t,y(n),a),a})}s(Fe,"moveDocument");function Je(t,n,e,r,o){return _(e),e.deleted_at?e:(n&&T(t,n,e),E(t,()=>{const i=Q(t,n,e,r,o);return b(t,Z(t,e.rowid),r),i}))}s(Je,"deleteDocument");function Pe(t,n,e){return _(n),n.deleted_at?E(t,()=>(H(t,d(t,n.owner),e,n),c(t,"UPDATE objects SET deleted_at = NULL, name = ? WHERE rowid = ?").run(e,n.rowid),d(t,n.rowid))):n}s(Pe,"restoreDocument");function Q(t,n,e,r,o){c(t,"UPDATE objects SET deleted_at = ? WHERE rowid = ?").run(o??new Date().toISOString(),e.rowid);const i=d(t,e.rowid),a=n?y(n):null;return a&&N(t,a,i),x(t,{event:"deleted",object:i,actor:a,attrs:{}},r),c(t,"DELETE FROM watches WHERE object = ?").run(e.rowid),B(t,i,[]),i}s(Q,"markDeleted");function Z(t,n){return c(t,"SELECT dst FROM edges WHERE type = 'links-to' AND src = ?").all(n).map(({dst:e})=>e)}s(Z,"linkTargets");function b(t,n,e){const r=c(t,`SELECT 1 FROM objects d JOIN objects w ON w.rowid = d.owner
6
+ AND d.type = 'document' AND d.name = ? AND d.deleted_at IS NULL LIMIT 1`).get(t.name,t.type,n)?`${t.type}:${t.name}`:t.name}a(xe,"ownerPrefix");function Q(e,t,n){const r=l(e,`SELECT e.written_as, o.* FROM edges e JOIN objects o ON o.rowid = e.dst
7
+ WHERE e.type = 'links-to' AND e.src = ? AND e.written_as IS NOT NULL`).all(t.rowid);if(r.length===0)return n;const o=new Map;for(const i of r){if(i.deleted_at||i.written_as===i.id)continue;const s=!i.written_as.includes("/");if(s&&i.name===i.written_as)continue;const u=i.owner===null?null:p(e,i.owner),c=u?`${xe(e,u,i.name)}/${i.name}`:i.name,m=s&&i.owner===t.owner?i.name:c;m!==i.written_as&&o.set(i.written_as,m)}return o.size===0?n:n.replace(/\[\[([^[\]\n]+?)\]\]/g,(i,s)=>{const u=o.get(s.trim());return u===void 0?i:`[[${u}]]`})}a(Q,"withCurrentNames");function M(e,t,n){if(n.preview!==void 0){if(n.preview.trim()==="")throw w("a document needs a preview",{field:"preview"});l(e,"UPDATE objects SET preview = ? WHERE rowid = ?").run(n.preview,t.rowid)}n.privacy!==void 0&&(I(e,p(e,t.owner),n.privacy),l(e,"UPDATE objects SET privacy = ? WHERE rowid = ?").run(n.privacy,t.rowid));const r=a((i,s)=>e.prepare(`UPDATE documents SET ${i} = ? WHERE object = ?`).run(s,t.rowid),"set");n.summary!==void 0&&r("summary",n.summary),n.whyItExists!==void 0&&r("why_it_exists",n.whyItExists),n.unlisted!==void 0&&r("unlisted",n.unlisted?1:0),n.lintIgnore!==void 0&&r("lint_ignore_json",n.lintIgnore===null?null:JSON.stringify(n.lintIgnore)),n.extensions!==void 0&&r("extensions_json",n.extensions===null?null:JSON.stringify(n.extensions));const o=p(e,t.rowid);return n.rules!==void 0&&G(e,o,n.rules),o}a(M,"applyDocumentFields");function Z(e,t,n){if(t.owner.deleted_at)throw w(`${t.owner.name} is deleted`);if(t.preview.trim()==="")throw w("a document needs a preview",{field:"preview"});I(e,t.owner,t.privacy),H(e,t.owner,t.name);const r=Ee(e,{...t.id?{id:t.id}:{},type:"document",kind:t.kind,owner:t.owner.rowid,privacy:t.privacy,name:t.name,preview:t.preview});l(e,"INSERT INTO documents (object, heads_key, revision) VALUES (?, '', 0)").run(r.rowid);const o=M(e,r,{...t,preview:void 0,privacy:void 0,rules:t.rules??[]});return W(e,o,n),o}a(Z,"createDocument");function F(e,t){const n=U(e,t),r=Oe(n),o=Math.max(0,...n.map(i=>i.number));return l(e,"UPDATE documents SET heads_key = ?, revision = ? WHERE object = ?").run(r,o,t.rowid),{heads_key:r,revision:o,headCount:n.length}}a(F,"setHeads");function Ke(e,t,n,r,o){const i=B(r);return E(e,()=>{const s=y(t),u=ue(e,t,n.owner,"rw");if(u!==null)throw Y(u);const c=Z(e,n,o),m=L(e,c,{number:1,body_hash:i,author:s,rationale:null,parents:[]}),{heads_key:d}=F(e,c);if(!j(e,t,c))throw N(`no owner ${n.owner.name} you can write to`);const f=z(e,t,c,r);return R(e,s,c),$(e,s,c,"write",{readHeadsKey:d}),x(e,{event:"created",object:c,actor:s,attrs:{revision:1},pointer:m.rev_id},o),{object:c,revision:1,unresolved:f}})}a(Ke,"writeDocument");function Ge(e,t,n){return l(e,"SELECT read_heads_key FROM watches WHERE watcher = ? AND object = ?").get(y(t).rowid,n.rowid)?.read_heads_key??null}a(Ge,"readBase");function Te(e,t){let n=e;for(const[r,{old:o,new:i}]of t.entries()){if(o==="")throw w(`block ${r+1}: a replacement needs non-empty old text`,{field:"replace"});const s=n.indexOf(o);if(s<0)throw w(`block ${r+1}: old text not found: ${JSON.stringify(o.slice(0,120))}`,{field:"replace",old:o});if(n.indexOf(o,s+1)>=0)throw w(`block ${r+1}: old text occurs more than once: ${JSON.stringify(o.slice(0,120))}`,{field:"replace",old:o});n=n.slice(0,s)+i+n.slice(s+o.length)}return n}a(Te,"applyReplacements");function Ve(e,t,n,r,o,i,s={},u){if(_(n),T(e,t,n),n.deleted_at)throw w(`${n.name} is deleted`);if(i===null)throw new O("read_first",`read ${n.name} before editing it`,D.GENERAL,{id:n.id});if(o.trim()==="")throw w("an edit needs a rationale",{field:"rationale"});const c=k(e,n);if(c.heads_key!==i)return{stale:{heads_key:c.heads_key,revision:c.revision}};const m=U(e,n);let d;if("body"in r)d=r.body;else{if(m.length!==1)throw w(`${n.name} has ${m.length} heads and needs a merge; pass the whole merged body`,{heads:m.length});d=Te(Q(e,n,me(m[0].body_hash)),r.replace)}const f=B(d);try{return E(e,()=>{const h=y(t),g=1+Math.max(0,...m.map(v=>v.number)),J=L(e,n,{number:g,body_hash:f,author:h,rationale:o,verbatim:r.verbatim===!0,parents:m.map(v=>v.rowid)}),A=J.rev_id,re=l(e,"UPDATE documents SET heads_key = ?, revision = ? WHERE object = ? AND heads_key = ?").run(A,g,n.rowid,i);if(Number(re.changes)===0){const v=k(e,n);throw new b(v.heads_key,v.revision)}const S=M(e,n,s),oe=z(e,t,S,d);return R(e,h,S),$(e,h,S,"write",{readHeadsKey:A}),x(e,{event:"edited",object:S,actor:h,pointer:J.rev_id,attrs:{revision:g,from_revision:c.revision,rationale:o}},u),{revision:g,heads_key:A,unresolved:oe}})}catch(h){if(h instanceof b)return{stale:{heads_key:h.heads_key,revision:h.revision}};throw h}}a(Ve,"editDocument");class b extends Error{static{a(this,"StaleEdit")}heads_key;revision;constructor(t,n){super("stale"),this.heads_key=t,this.revision=n}}function Ye(e,t,n,r){return _(n),t&&T(e,t,n),E(e,()=>{const o=M(e,n,r);return t&&R(e,y(t),o),o})}a(Ye,"setDocumentRecord");function ke(e,t,n,r){const o=y(t),{heads_key:i}=k(e,n);$(e,o,n,"read",{readHeadsKey:i}),x(e,{event:"read",object:n,actor:o,attrs:{}},r)}a(ke,"recordRead");function Xe(e,t,n,r){return _(n),C(e,t,n),E(e,()=>{const o=k(e,n),i=U(e,n).map(u=>({...u,body:Q(e,n,le(u.body_hash,o.source_path))})),s=l(e,"SELECT dst, written_as FROM edges WHERE type = 'links-to' AND src = ? ORDER BY written_as").all(n.rowid).map(u=>({written_as:u.written_as??"",object:p(e,u.dst)})).filter(u=>u.object&&P(e,t,u.object)).map(u=>({...u,deleted:u.object.deleted_at!==null}));return n.deleted_at||ke(e,t,n,r),{object:n,record:o,heads:i,needsMerge:i.length>1,links:s}})}a(Xe,"readDocument");function qe(e,t,n){return _(n),C(e,t,n),l(e,"SELECT * FROM revisions WHERE document = ? ORDER BY number DESC, created_at DESC, rowid DESC").all(n.rowid).map(o=>X(e,o))}a(qe,"history");function ze(e,t,n,r,o){if(_(n),n.deleted_at)throw w(`${n.name} is deleted`);return t&&T(e,t,n),E(e,()=>{const i=r.owner??p(e,n.owner),s=r.name??n.name;H(e,i,s,n),I(e,i,n.privacy),l(e,"UPDATE objects SET name = ?, owner = ? WHERE rowid = ?").run(s,i.rowid,n.rowid);const u=p(e,n.rowid);if(i.rowid!==n.owner&&(Re(e,u),t&&!j(e,t,u)))throw N(`no owner ${i.name} you can move documents to`);return t&&R(e,y(t),u),(s!==n.name||i.rowid!==n.owner)&&W(e,u,o),u})}a(ze,"moveDocument");function Qe(e,t,n,r,o){return _(n),n.deleted_at?n:(t&&T(e,t,n),E(e,()=>{const i=ee(e,t,n,r,o);return te(e,ne(e,n.rowid),r),i}))}a(Qe,"deleteDocument");function Ze(e,t,n,r){return _(t),t.deleted_at?E(e,()=>{H(e,p(e,t.owner),n,t),l(e,"UPDATE objects SET deleted_at = NULL, name = ? WHERE rowid = ?").run(n,t.rowid);const o=p(e,t.rowid);return W(e,o,r),o}):t}a(Ze,"restoreDocument");function ee(e,t,n,r,o){l(e,"UPDATE objects SET deleted_at = ? WHERE rowid = ?").run(o??new Date().toISOString(),n.rowid);const i=p(e,n.rowid),s=t?y(t):null;return s&&R(e,s,i),x(e,{event:"deleted",object:i,actor:s,attrs:{}},r),l(e,"DELETE FROM watches WHERE object = ?").run(n.rowid),G(e,i,[]),i}a(ee,"markDeleted");function ne(e,t){return l(e,"SELECT dst FROM edges WHERE type = 'links-to' AND src = ?").all(t).map(({dst:n})=>n)}a(ne,"linkTargets");function te(e,t,n){const r=l(e,`SELECT 1 FROM objects d JOIN objects w ON w.rowid = d.owner
8
8
  WHERE d.rowid = ? AND d.type = 'document' AND d.deleted_at IS NULL AND w.deleted_at IS NOT NULL
9
9
  AND NOT EXISTS (SELECT 1 FROM edges e JOIN objects s ON s.rowid = e.src
10
- WHERE e.type = 'links-to' AND e.dst = d.rowid AND e.src != d.rowid AND s.deleted_at IS NULL)`),o=[...n];for(;o.length>0;){const i=o.pop();r.get(i)!==void 0&&(Q(t,null,d(t,i),e),o.push(...Z(t,i)))}}s(b,"collectUnlinked");function Be(t,n){if(n.revisions.length===0)throw m(`import of ${n.name}: no revisions`);return E(t,()=>{const e=q(t,n);c(t,"UPDATE objects SET created_at = ? WHERE rowid = ?").run(n.revisions[0].created_at,e.rowid);let r=null;return n.revisions.forEach((o,i)=>{r=L(t,e,{...o,number:i+1,parents:r===null?[]:[r]}).rowid}),M(t,e),d(t,e.rowid)})}s(Be,"importDocument");function Ke(t,n,e){if(_(n),n.privacy!=="public"&&K(t,n)==="repo")throw m(`a repo owns only public documents; refusing revisions of ${n.name}`);return E(t,()=>{const r=c(t,"SELECT rowid, number, document FROM revisions WHERE rev_id = ?");let o=e.filter(u=>!r.get(u.rev_id));for(;o.length>0;){const u=[];for(const l of o){const w=l.parents.map(p=>r.get(p));if(w.some(p=>p===void 0)){u.push(l);continue}const f=w;if(f.some(p=>p.document!==n.rowid))throw m(`revision ${l.rev_id} names a parent of another document`);L(t,n,{...l,author:null,number:1+Math.max(0,...f.map(p=>p.number)),parents:f.map(p=>p.rowid)})}if(u.length===o.length)throw m(`revisions of ${n.name} name unknown parents: ${u.map(l=>l.rev_id).join(", ")}`);o=u}const{heads_key:i,headCount:a}=M(t,n);return{heads_key:i,headCount:a}})}s(Ke,"insertImportedRevisions");function Ge(t,n){const e=we(t,n);if(!e||e.type!=="document")throw R(`no document ${n}`);return e}s(Ge,"documentById");export{y as actorOf,U as applyDocumentFields,ye as applyReplacements,b as collectUnlinked,Je as deleteDocument,Ge as documentById,A as documentRecord,Ce as editDocument,W as heads,Me as history,Be as importDocument,Ke as insertImportedRevisions,Ee as linksIn,Fe as moveDocument,He as readBase,Ue as readDocument,ve as recordRead,Pe as restoreDocument,We as setDocumentRecord,Y as setRevisionLinks,X as withCurrentNames,Ie as writeDocument};
10
+ WHERE e.type = 'links-to' AND e.dst = d.rowid AND e.src != d.rowid AND s.deleted_at IS NULL)`),o=[...t];for(;o.length>0;){const i=o.pop();r.get(i)!==void 0&&(ee(e,null,p(e,i),n),o.push(...ne(e,i)))}}a(te,"collectUnlinked");function be(e,t,n){if(t.revisions.length===0)throw w(`import of ${t.name}: no revisions`);return E(e,()=>{const r=Z(e,t,n);l(e,"UPDATE objects SET created_at = ? WHERE rowid = ?").run(t.revisions[0].created_at,r.rowid);let o=null;return t.revisions.forEach((i,s)=>{o=L(e,r,{...i,number:s+1,parents:o===null?[]:[o]}).rowid}),F(e,r),p(e,r.rowid)})}a(be,"importDocument");function en(e,t,n){if(_(t),t.privacy!=="public"&&V(e,t)==="repo")throw w(`a repo owns only public documents; refusing revisions of ${t.name}`);return E(e,()=>{const r=l(e,"SELECT rowid, number, document FROM revisions WHERE rev_id = ?");let o=n.filter(u=>!r.get(u.rev_id));for(;o.length>0;){const u=[];for(const c of o){const m=c.parents.map(f=>r.get(f));if(m.some(f=>f===void 0)){u.push(c);continue}const d=m;if(d.some(f=>f.document!==t.rowid))throw w(`revision ${c.rev_id} names a parent of another document`);L(e,t,{...c,author:null,number:1+Math.max(0,...d.map(f=>f.number)),parents:d.map(f=>f.rowid)})}if(u.length===o.length)throw w(`revisions of ${t.name} name unknown parents: ${u.map(c=>c.rev_id).join(", ")}`);o=u}const{heads_key:i,headCount:s}=F(e,t);return{heads_key:i,headCount:s}})}a(en,"insertImportedRevisions");function nn(e,t){const n=_e(e,t);if(!n||n.type!=="document")throw N(`no document ${t}`);return n}a(nn,"documentById");export{y as actorOf,M as applyDocumentFields,Te as applyReplacements,te as collectUnlinked,Qe as deleteDocument,nn as documentById,k as documentRecord,Ve as editDocument,U as heads,qe as history,be as importDocument,en as insertImportedRevisions,De as linksIn,ze as moveDocument,Ge as readBase,Xe as readDocument,ke as recordRead,Ze as restoreDocument,Ye as setDocumentRecord,z as setRevisionLinks,Q as withCurrentNames,Ke as writeDocument};
@@ -17,6 +17,22 @@ export declare function setLinks(db: DatabaseSync, doc: ObjectRow, links: Readon
17
17
  written_as: string;
18
18
  dst: ObjectRow;
19
19
  }>): number[];
20
+ /** Replace the names the document's current revision links that resolved to nothing or to several objects.
21
+ * Kept so that when a document with such a name comes into being, the link can gain its edge. */
22
+ export declare function setUnresolved(db: DatabaseSync, doc: ObjectRow, names: readonly string[]): void;
23
+ /** Forget `names` among the document's remembered unresolved links: they have gained an edge. */
24
+ export declare function dropUnresolved(db: DatabaseSync, doc: ObjectRow, names: Iterable<string>): void;
25
+ /** The unresolved links, as `{src, name}`, whose written name is the document's id or `name`, or ends in `/<name>`: every
26
+ * link that could name a document called `name`, bare or qualified by its owner. */
27
+ export declare function unresolvedLinksCouldName(db: DatabaseSync, name: string, id: string): Array<{
28
+ src: number;
29
+ name: string;
30
+ }>;
31
+ /** The document's current `links-to` edges as the links they were written from. */
32
+ export declare function linksOf(db: DatabaseSync, doc: ObjectRow): Array<{
33
+ written_as: string;
34
+ dst: ObjectRow;
35
+ }>;
20
36
  /** Documents whose body links to `object`. */
21
37
  export declare function backlinks(db: DatabaseSync, reader: Reader, object: ObjectRow): Edge[];
22
38
  export declare function edgesOf(db: DatabaseSync, reader: Reader, object: ObjectRow, opts?: {
@@ -1 +1 @@
1
- var O=Object.defineProperty;var d=(t,r)=>O(t,"name",{value:r,configurable:!0});import{prepared as o}from"../sqlite-statements.js";import{canRead as R}from"./access.js";import{getByRowid as l}from"./objects.js";function L(t,r,e){o(t,"INSERT OR IGNORE INTO edges (type, src, dst, written_as, created_at) VALUES ('acted-on', ?, ?, NULL, ?)").run(r.rowid,e.rowid,new Date().toISOString())}d(L,"recordActedOn");function _(t,r,e){const i=o(t,"SELECT dst FROM edges WHERE type = 'links-to' AND src = ?").all(r.rowid).map(({dst:s})=>s);o(t,"DELETE FROM edges WHERE type = 'links-to' AND src = ?").run(r.rowid);const a=o(t,"INSERT OR IGNORE INTO edges (type, src, dst, written_as, created_at) VALUES ('links-to', ?, ?, ?, ?)"),w=new Date().toISOString();for(const s of e)a.run(r.rowid,s.dst.rowid,s.written_as,w);const c=new Set(e.map(s=>s.dst.rowid));return i.filter(s=>!c.has(s))}d(_,"setLinks");function h(t,r,e){return S(t,r,e,{type:"links-to",direction:"in"})}d(h,"backlinks");function S(t,r,e,i={}){if(!R(t,r,e))return[];const a=i.direction??"both",w=i.type?[i.type]:["acted-on","links-to"],c=[];for(const n of w)a!=="in"&&c.push(...o(t,"SELECT * FROM edges WHERE type = ? AND src = ?").all(n,e.rowid)),a!=="out"&&c.push(...o(t,"SELECT * FROM edges WHERE type = ? AND dst = ?").all(n,e.rowid));const s=new Set,f=[];for(const n of c){const u=`${n.type}|${n.src}|${n.dst}`;if(s.has(u))continue;s.add(u);const p=n.src===e.rowid?e:l(t,n.src),E=n.dst===e.rowid?e:l(t,n.dst);if(!p||!E)continue;const y=p===e?E:p;y!==e&&!R(t,r,y)||f.push({type:n.type,src:p,dst:E,written_as:n.written_as,created_at:n.created_at})}return f}d(S,"edgesOf");export{h as backlinks,S as edgesOf,L as recordActedOn,_ as setLinks};
1
+ var m=Object.defineProperty;var c=(t,e)=>m(t,"name",{value:e,configurable:!0});import{prepared as i}from"../sqlite-statements.js";import{canRead as O}from"./access.js";import{getByRowid as p}from"./objects.js";function L(t,e,n){i(t,"INSERT OR IGNORE INTO edges (type, src, dst, written_as, created_at) VALUES ('acted-on', ?, ?, NULL, ?)").run(e.rowid,n.rowid,new Date().toISOString())}c(L,"recordActedOn");function T(t,e,n){const s=i(t,"SELECT dst FROM edges WHERE type = 'links-to' AND src = ?").all(e.rowid).map(({dst:o})=>o);i(t,"DELETE FROM edges WHERE type = 'links-to' AND src = ?").run(e.rowid);const d=i(t,"INSERT OR IGNORE INTO edges (type, src, dst, written_as, created_at) VALUES ('links-to', ?, ?, ?, ?)"),u=new Date().toISOString();for(const o of n)d.run(e.rowid,o.dst.rowid,o.written_as,u);const a=new Set(n.map(o=>o.dst.rowid));return s.filter(o=>!a.has(o))}c(T,"setLinks");function D(t,e,n){i(t,"DELETE FROM unresolved_links WHERE src = ?").run(e.rowid);const s=i(t,"INSERT OR IGNORE INTO unresolved_links (src, name) VALUES (?, ?)");for(const d of n)s.run(e.rowid,d)}c(D,"setUnresolved");function g(t,e,n){const s=i(t,"DELETE FROM unresolved_links WHERE src = ? AND name = ?");for(const d of n)s.run(e.rowid,d)}c(g,"dropUnresolved");function I(t,e,n){return i(t,"SELECT src, name FROM unresolved_links WHERE name = ? OR name = ? OR substr(name, -length(?) - 1) = '/' || ? ORDER BY src, name").all(e,n,e,e)}c(I,"unresolvedLinksCouldName");function A(t,e){return i(t,"SELECT e.dst, e.written_as FROM edges e WHERE e.type = 'links-to' AND e.src = ? ORDER BY e.written_as").all(e.rowid).map(s=>({written_as:s.written_as??"",dst:p(t,s.dst)}))}c(A,"linksOf");function h(t,e,n){return S(t,e,n,{type:"links-to",direction:"in"})}c(h,"backlinks");function S(t,e,n,s={}){if(!O(t,e,n))return[];const d=s.direction??"both",u=s.type?[s.type]:["acted-on","links-to"],a=[];for(const r of u)d!=="in"&&a.push(...i(t,"SELECT * FROM edges WHERE type = ? AND src = ?").all(r,n.rowid)),d!=="out"&&a.push(...i(t,"SELECT * FROM edges WHERE type = ? AND dst = ?").all(r,n.rowid));const o=new Set,w=[];for(const r of a){const R=`${r.type}|${r.src}|${r.dst}`;if(o.has(R))continue;o.add(R);const E=r.src===n.rowid?n:p(t,r.src),l=r.dst===n.rowid?n:p(t,r.dst);if(!E||!l)continue;const f=E===n?l:E;f!==n&&!O(t,e,f)||w.push({type:r.type,src:E,dst:l,written_as:r.written_as,created_at:r.created_at})}return w}c(S,"edgesOf");export{h as backlinks,g as dropUnresolved,S as edgesOf,A as linksOf,L as recordActedOn,T as setLinks,D as setUnresolved,I as unresolvedLinksCouldName};
@@ -1,2 +1,2 @@
1
- var H=Object.defineProperty;var p=(t,i)=>H(t,"name",{value:i,configurable:!0});import{prepared as g}from"../../sqlite-statements.js";import{get as W,put as P}from"../bodies.js";import{setLinks as J}from"../edges.js";import{collectUnlinked as U,deleteDocument as M,documentRecord as C,heads as D,importDocument as F,insertImportedRevisions as Y,moveDocument as z,restoreDocument as K,setDocumentRecord as V}from"../documents.js";import{CrtrError as G}from"../../errors.js";import{publish as T}from"../events.js";import{getById as x,getByRowid as N,setObjectKind as q}from"../objects.js";import{rulesOf as Q}from"../rules.js";import{SPACES as X}from"../spaces/index.js";import{docPath as Z,mergeDoc as b,parseDoc as y,serializeDoc as $}from"./ref-format.js";function L(t){const i=X[t.type];if(t.owner!==null||!i||i.sync!=="repo-ref")throw new Error(`${t.type} ${t.id} is not a space that syncs through a repo ref`)}p(L,"assertRepoRefSpace");function ee(t){const i=new Map;for(const[o,n]of t??[]){const _=y(o,n);_.ok&&i.set(_.doc.id,_.doc)}return i}p(ee,"parseMap");function ke(t,i,o,n=null){L(i);const _=ee(o),f=g(t,"SELECT * FROM objects WHERE type = 'document' AND owner = ? AND privacy = 'public' ORDER BY rowid").all(i.rowid),m=g(t,"SELECT rowid, rev_id, number, body_hash, author, rationale, created_at FROM revisions WHERE document = ? ORDER BY number, rev_id"),v=g(t,"SELECT p.rev_id FROM revision_parents rp JOIN revisions p ON p.rowid = rp.parent WHERE rp.child = ?"),r=g(t,`SELECT e.written_as, o.id FROM edges e JOIN objects o ON o.rowid = e.dst
2
- WHERE e.type = 'links-to' AND e.src = ? ORDER BY e.written_as, o.id`),a=new Map;for(const e of f){const d=C(t,e),c=new Map((_.get(e.id)?.revisions??[]).map(s=>[s.rev_id,s])),h=new Set(D(t,e).map(s=>s.rev_id)),w=r.all(e.rowid).map(s=>({written_as:s.written_as??"",dst:s.id})),R=m.all(e.rowid).map(s=>c.get(s.rev_id)??{rev_id:s.rev_id,number:s.number,parents:v.all(s.rowid).map(O=>O.rev_id),body:W(s.body_hash),body_hash:s.body_hash,author:s.author===null?null:N(t,s.author)?.id??null,rationale:s.rationale,created_at:s.created_at,links:h.has(s.rev_id)?w:[]});if(R.length===0)continue;const E=Q(t,e).map(s=>({position:s.position,on:s.on,match:s.match??null,match_frontmatter:s.matchFrontmatter??null,if:s.if??null,deliver:s.deliver})),A={id:e.id,name:e.name,kind:e.kind??"document",privacy:"public",preview:e.preview,summary:d.summary,why_it_exists:d.why_it_exists,unlisted:d.unlisted,lint_ignore:d.lint_ignore,extensions:d.extensions,created_at:e.created_at,deleted_at:e.deleted_at,rules:E,revisions:R};a.set(Z(e.id),$(A))}for(const e of te(o,n)){const d=o.get(e),c=a.get(e);if(c===void 0){a.set(e,d);continue}const h=y(e,d),w=y(e,c);if(!h.ok){a.set(e,d);continue}if(!w.ok)continue;const R=n?.has(e)?y(e,n.get(e)):null,E=b(R?.ok?R.doc:null,w.doc,h.doc);E&&a.set(e,$(E))}return a}p(ke,"exportRepo");function te(t,i){return[...t??[]].filter(([o,n])=>i?.get(o)!==n).map(([o])=>o)}p(te,"pendingPaths");function ne(t){return[...t].sort((i,o)=>i.position-o.position).map(i=>({on:i.on,deliver:i.deliver,...i.match!==null&&i.match!==void 0?{match:i.match}:{},...i.match_frontmatter!==null&&i.match_frontmatter!==void 0?{matchFrontmatter:i.match_frontmatter}:{},...i.if!==null&&i.if!==void 0?{if:i.if}:{}}))}p(ne,"toRuleSpecs");const ie=p((t,i)=>JSON.stringify(t??null)===JSON.stringify(i??null),"same");function j(t,i){const o={},n=p(_=>!t||!ie(t[_],i[_]),"differs");return n("preview")&&(o.preview=i.preview),n("summary")&&(o.summary=i.summary),n("why_it_exists")&&(o.whyItExists=i.why_it_exists),n("unlisted")&&(o.unlisted=i.unlisted),n("lint_ignore")&&(o.lintIgnore=i.lint_ignore),n("extensions")&&(o.extensions=i.extensions),n("rules")&&(o.rules=ne(i.rules)),o}p(j,"changedFields");let oe=0;function B(t,i){const o=`repo_sync_import_${++oe}`;t.exec(`SAVEPOINT ${o}`);try{const n=i();return t.exec(`RELEASE ${o}`),n}catch(n){throw t.exec(`ROLLBACK TO ${o}`),t.exec(`RELEASE ${o}`),n}}p(B,"atomic");function Oe(t,i,o,n,_){L(i);const f={created:0,revisions:0,deleted:0,needsMerge:[],refused:[]},m=[];for(const[r,a]of n){if(o.get(r)===a)continue;const e=y(r,a);if(!e.ok){f.refused.push({path:r,reason:e.reason});continue}const d=o.has(r)?y(r,o.get(r)):null;m.push({path:r,prior:d?.ok?d.doc:null,doc:e.doc})}for(const[r,a]of o){if(n.has(r))continue;const e=y(r,a);e.ok&&m.push({path:r,prior:e.doc,doc:null,priorId:e.doc.id})}for(const r of m)for(const a of r.doc?.revisions??[])P(a.body);const v=[];return B(t,()=>{let r=m;for(;;){const a=[];for(const e of r){const d={created:0,revisions:0,deleted:0,needsMerge:[],refused:[]};try{const c=[];B(t,()=>le(t,i,e.prior,e.doc,e.priorId??e.doc.id,d,_,c)),v.push(...c),f.created+=d.created,f.revisions+=d.revisions,f.deleted+=d.deleted,f.needsMerge.push(...d.needsMerge)}catch(c){ce(c)?a.push({w:e,error:c}):f.refused.push({path:e.path,reason:c.message})}}if(a.length===0)break;if(a.length===r.length){for(const e of a)f.refused.push({path:e.w.path,reason:e.error.message});break}r=a.map(e=>e.w)}re(t,n,new Set(v),new Set(m.map(a=>a.path)))}),f}p(Oe,"importTree");function re(t,i,o,n){if(o.size===0)return;const _=g(t,"INSERT OR IGNORE INTO edges (type, src, dst, written_as, created_at) VALUES ('links-to', ?, ?, ?, ?)"),f=new Date().toISOString();for(const[m,v]of i){if(!n.has(m)&&!ae(v,o))continue;const r=y(m,v);if(!r.ok||r.doc.deleted_at)continue;const a=x(t,r.doc.id);if(!a||a.type!=="document"||a.deleted_at)continue;const e=D(t,a)[0],d=r.doc.revisions.find(c=>c.rev_id===e?.rev_id)?.links??[];for(const c of d){const h=x(t,c.dst);h&&h.rowid!==a.rowid&&_.run(a.rowid,h.rowid,c.written_as,f)}}}p(re,"completeLinks");const se=/"dst":\s*"((?:[^"\\]|\\.)*)"/g;function ae(t,i){for(const o of t.matchAll(se))if(i.has(de(o[1])))return!0;return!1}p(ae,"namesArrived");function de(t){if(!t.includes("\\"))return t;try{return JSON.parse(`"${t}"`)}catch{return t}}p(de,"decodeJsonString");function ce(t){return t instanceof G&&t.code==="conflict"&&t.details?.holder!==void 0}p(ce,"isNameConflict");function le(t,i,o,n,_,f,m,v){const r=x(t,_);if(r&&(r.type!=="document"||r.owner!==i.rowid))throw new Error(`id ${_} is held by ${r.type} ${r.name} outside ${i.name}`);if(!n){r&&!r.deleted_at&&(M(t,null,r,m),f.deleted++);return}const a=g(t,"SELECT count(*) AS n FROM revisions WHERE document = ?");let e,d=!1,c=!1,h=0,w=0;if(r){e=r,h=C(t,e).revision,e.created_at!==n.created_at&&(g(t,"UPDATE objects SET created_at = ? WHERE rowid = ?").run(n.created_at,e.rowid),e=N(t,e.rowid));const l=n.kind;(o?o.kind!==l:e.kind!==l)&&q(t,e,l),c=!!e.deleted_at&&n.deleted_at===null&&(o===null||o.deleted_at!=null);let u=j(c?null:o,n);if(n.deleted_at&&e.deleted_at){const{rules:k,...S}=u;u=S}c&&(e=K(t,e,n.name),v?.push(e.id)),Object.keys(u).length>0&&(e=V(t,null,e,u)),n.name!==e.name&&!e.deleted_at&&(e=z(t,null,e,{name:n.name}))}else{const u=n.revisions.filter(k=>k.parents.length===0).sort((k,S)=>k.number-S.number||k.rev_id.localeCompare(S.rev_id))[0];if(!u)throw new Error(`${n.name}: no root revision`);e=F(t,{id:n.id,owner:i,name:n.name,kind:n.kind,preview:n.preview,privacy:"public",...j(null,n),revisions:[{rev_id:u.rev_id,body_hash:u.body_hash,author:null,rationale:u.rationale,created_at:u.created_at}]}),e.created_at!==n.created_at&&(g(t,"UPDATE objects SET created_at = ? WHERE rowid = ?").run(n.created_at,e.rowid),e=N(t,e.rowid)),d=!0,v?.push(e.id),w=1}const R=a.get(e.rowid).n,{headCount:E}=Y(t,e,n.revisions.map(l=>({rev_id:l.rev_id,parents:l.parents,body_hash:l.body_hash,rationale:l.rationale,created_at:l.created_at})));w+=a.get(e.rowid).n-R,f.revisions+=w;const s=D(t,e)[0],O=new Map(n.revisions.map(l=>[l.rev_id,l]));if(w>0||c){const l=(O.get(s.rev_id)?.links??[]).map(u=>({written_as:u.written_as,dst:x(t,u.dst)})).filter(u=>u.dst!==null);U(t,J(t,e,l),m)}if(E>1&&f.needsMerge.push(e.id),n.deleted_at&&!e.deleted_at){M(t,null,e,m,n.deleted_at),f.deleted++;return}if(n.deleted_at&&e.deleted_at&&e.deleted_at!==n.deleted_at&&g(t,"UPDATE objects SET deleted_at = ? WHERE rowid = ?").run(n.deleted_at,e.rowid),d){f.created++,T(t,{event:"created",object:e,actor:null,attrs:{revision:s.number},pointer:s.rev_id},m);return}if(c){f.created++,T(t,{event:"created",object:e,actor:null,attrs:{revision:s.number},pointer:s.rev_id},m);return}if(w===0)return;const I=n.revisions.filter(l=>!o?.revisions.some(u=>u.rev_id===l.rev_id)).sort((l,u)=>u.number-l.number||u.created_at.localeCompare(l.created_at))[0]??O.get(s.rev_id);T(t,{event:"edited",object:e,actor:null,pointer:s.rev_id,attrs:{revision:s.number,from_revision:h,rationale:I?.rationale??null,author:I?.author??null,heads:E,needs_merge:E>1}},m)}p(le,"importOne");export{ke as exportRepo,Oe as importTree,ae as namesArrived,te as pendingPaths};
1
+ var H=Object.defineProperty;var p=(t,i)=>H(t,"name",{value:i,configurable:!0});import{prepared as g}from"../../sqlite-statements.js";import{get as W,put as P}from"../bodies.js";import{setLinks as J,setUnresolved as U}from"../edges.js";import{collectUnlinked as Y,deleteDocument as M,documentRecord as C,heads as D,importDocument as z,insertImportedRevisions as K,moveDocument as V,restoreDocument as G,setDocumentRecord as q}from"../documents.js";import{CrtrError as F}from"../../errors.js";import{publish as T}from"../events.js";import{getById as x,getByRowid as N,setObjectKind as Q}from"../objects.js";import{rulesOf as X}from"../rules.js";import{SPACES as Z}from"../spaces/index.js";import{docPath as b,mergeDoc as ee,parseDoc as y,serializeDoc as $}from"./ref-format.js";function L(t){const i=Z[t.type];if(t.owner!==null||!i||i.sync!=="repo-ref")throw new Error(`${t.type} ${t.id} is not a space that syncs through a repo ref`)}p(L,"assertRepoRefSpace");function te(t){const i=new Map;for(const[o,n]of t??[]){const _=y(o,n);_.ok&&i.set(_.doc.id,_.doc)}return i}p(te,"parseMap");function Oe(t,i,o,n=null){L(i);const _=te(o),m=g(t,"SELECT * FROM objects WHERE type = 'document' AND owner = ? AND privacy = 'public' ORDER BY rowid").all(i.rowid),l=g(t,"SELECT rowid, rev_id, number, body_hash, author, rationale, created_at FROM revisions WHERE document = ? ORDER BY number, rev_id"),v=g(t,"SELECT p.rev_id FROM revision_parents rp JOIN revisions p ON p.rowid = rp.parent WHERE rp.child = ?"),r=g(t,`SELECT e.written_as, o.id FROM edges e JOIN objects o ON o.rowid = e.dst
2
+ WHERE e.type = 'links-to' AND e.src = ? ORDER BY e.written_as, o.id`),a=new Map;for(const e of m){const d=C(t,e),c=new Map((_.get(e.id)?.revisions??[]).map(s=>[s.rev_id,s])),h=new Set(D(t,e).map(s=>s.rev_id)),w=r.all(e.rowid).map(s=>({written_as:s.written_as??"",dst:s.id})),R=l.all(e.rowid).map(s=>c.get(s.rev_id)??{rev_id:s.rev_id,number:s.number,parents:v.all(s.rowid).map(O=>O.rev_id),body:W(s.body_hash),body_hash:s.body_hash,author:s.author===null?null:N(t,s.author)?.id??null,rationale:s.rationale,created_at:s.created_at,links:h.has(s.rev_id)?w:[]});if(R.length===0)continue;const E=X(t,e).map(s=>({position:s.position,on:s.on,match:s.match??null,match_frontmatter:s.matchFrontmatter??null,if:s.if??null,deliver:s.deliver})),A={id:e.id,name:e.name,kind:e.kind??"document",privacy:"public",preview:e.preview,summary:d.summary,why_it_exists:d.why_it_exists,unlisted:d.unlisted,lint_ignore:d.lint_ignore,extensions:d.extensions,created_at:e.created_at,deleted_at:e.deleted_at,rules:E,revisions:R};a.set(b(e.id),$(A))}for(const e of ne(o,n)){const d=o.get(e),c=a.get(e);if(c===void 0){a.set(e,d);continue}const h=y(e,d),w=y(e,c);if(!h.ok){a.set(e,d);continue}if(!w.ok)continue;const R=n?.has(e)?y(e,n.get(e)):null,E=ee(R?.ok?R.doc:null,w.doc,h.doc);E&&a.set(e,$(E))}return a}p(Oe,"exportRepo");function ne(t,i){return[...t??[]].filter(([o,n])=>i?.get(o)!==n).map(([o])=>o)}p(ne,"pendingPaths");function ie(t){return[...t].sort((i,o)=>i.position-o.position).map(i=>({on:i.on,deliver:i.deliver,...i.match!==null&&i.match!==void 0?{match:i.match}:{},...i.match_frontmatter!==null&&i.match_frontmatter!==void 0?{matchFrontmatter:i.match_frontmatter}:{},...i.if!==null&&i.if!==void 0?{if:i.if}:{}}))}p(ie,"toRuleSpecs");const oe=p((t,i)=>JSON.stringify(t??null)===JSON.stringify(i??null),"same");function j(t,i){const o={},n=p(_=>!t||!oe(t[_],i[_]),"differs");return n("preview")&&(o.preview=i.preview),n("summary")&&(o.summary=i.summary),n("why_it_exists")&&(o.whyItExists=i.why_it_exists),n("unlisted")&&(o.unlisted=i.unlisted),n("lint_ignore")&&(o.lintIgnore=i.lint_ignore),n("extensions")&&(o.extensions=i.extensions),n("rules")&&(o.rules=ie(i.rules)),o}p(j,"changedFields");let re=0;function B(t,i){const o=`repo_sync_import_${++re}`;t.exec(`SAVEPOINT ${o}`);try{const n=i();return t.exec(`RELEASE ${o}`),n}catch(n){throw t.exec(`ROLLBACK TO ${o}`),t.exec(`RELEASE ${o}`),n}}p(B,"atomic");function Se(t,i,o,n,_){L(i);const m={created:0,revisions:0,deleted:0,needsMerge:[],refused:[]},l=[];for(const[r,a]of n){if(o.get(r)===a)continue;const e=y(r,a);if(!e.ok){m.refused.push({path:r,reason:e.reason});continue}const d=o.has(r)?y(r,o.get(r)):null;l.push({path:r,prior:d?.ok?d.doc:null,doc:e.doc})}for(const[r,a]of o){if(n.has(r))continue;const e=y(r,a);e.ok&&l.push({path:r,prior:e.doc,doc:null,priorId:e.doc.id})}for(const r of l)for(const a of r.doc?.revisions??[])P(a.body);const v=[];return B(t,()=>{let r=l;for(;;){const a=[];for(const e of r){const d={created:0,revisions:0,deleted:0,needsMerge:[],refused:[]};try{const c=[];B(t,()=>ue(t,i,e.prior,e.doc,e.priorId??e.doc.id,d,_,c)),v.push(...c),m.created+=d.created,m.revisions+=d.revisions,m.deleted+=d.deleted,m.needsMerge.push(...d.needsMerge)}catch(c){le(c)?a.push({w:e,error:c}):m.refused.push({path:e.path,reason:c.message})}}if(a.length===0)break;if(a.length===r.length){for(const e of a)m.refused.push({path:e.w.path,reason:e.error.message});break}r=a.map(e=>e.w)}se(t,n,new Set(v),new Set(l.map(a=>a.path)))}),m}p(Se,"importTree");function se(t,i,o,n){if(o.size===0)return;const _=g(t,"INSERT OR IGNORE INTO edges (type, src, dst, written_as, created_at) VALUES ('links-to', ?, ?, ?, ?)"),m=new Date().toISOString();for(const[l,v]of i){if(!n.has(l)&&!de(v,o))continue;const r=y(l,v);if(!r.ok||r.doc.deleted_at)continue;const a=x(t,r.doc.id);if(!a||a.type!=="document"||a.deleted_at)continue;const e=D(t,a)[0],d=r.doc.revisions.find(c=>c.rev_id===e?.rev_id)?.links??[];for(const c of d){const h=x(t,c.dst);h&&h.rowid!==a.rowid&&_.run(a.rowid,h.rowid,c.written_as,m)}}}p(se,"completeLinks");const ae=/"dst":\s*"((?:[^"\\]|\\.)*)"/g;function de(t,i){for(const o of t.matchAll(ae))if(i.has(ce(o[1])))return!0;return!1}p(de,"namesArrived");function ce(t){if(!t.includes("\\"))return t;try{return JSON.parse(`"${t}"`)}catch{return t}}p(ce,"decodeJsonString");function le(t){return t instanceof F&&t.code==="conflict"&&t.details?.holder!==void 0}p(le,"isNameConflict");function ue(t,i,o,n,_,m,l,v){const r=x(t,_);if(r&&(r.type!=="document"||r.owner!==i.rowid))throw new Error(`id ${_} is held by ${r.type} ${r.name} outside ${i.name}`);if(!n){r&&!r.deleted_at&&(M(t,null,r,l),m.deleted++);return}const a=g(t,"SELECT count(*) AS n FROM revisions WHERE document = ?");let e,d=!1,c=!1,h=0,w=0;if(r){e=r,h=C(t,e).revision,e.created_at!==n.created_at&&(g(t,"UPDATE objects SET created_at = ? WHERE rowid = ?").run(n.created_at,e.rowid),e=N(t,e.rowid));const u=n.kind;(o?o.kind!==u:e.kind!==u)&&Q(t,e,u),c=!!e.deleted_at&&n.deleted_at===null&&(o===null||o.deleted_at!=null);let f=j(c?null:o,n);if(n.deleted_at&&e.deleted_at){const{rules:k,...S}=f;f=S}c&&(e=G(t,e,n.name,l),v?.push(e.id)),Object.keys(f).length>0&&(e=q(t,null,e,f)),n.name!==e.name&&!e.deleted_at&&(e=V(t,null,e,{name:n.name},l))}else{const f=n.revisions.filter(k=>k.parents.length===0).sort((k,S)=>k.number-S.number||k.rev_id.localeCompare(S.rev_id))[0];if(!f)throw new Error(`${n.name}: no root revision`);e=z(t,{id:n.id,owner:i,name:n.name,kind:n.kind,preview:n.preview,privacy:"public",...j(null,n),revisions:[{rev_id:f.rev_id,body_hash:f.body_hash,author:null,rationale:f.rationale,created_at:f.created_at}]},l),e.created_at!==n.created_at&&(g(t,"UPDATE objects SET created_at = ? WHERE rowid = ?").run(n.created_at,e.rowid),e=N(t,e.rowid)),d=!0,v?.push(e.id),w=1}const R=a.get(e.rowid).n,{headCount:E}=K(t,e,n.revisions.map(u=>({rev_id:u.rev_id,parents:u.parents,body_hash:u.body_hash,rationale:u.rationale,created_at:u.created_at})));w+=a.get(e.rowid).n-R,m.revisions+=w;const s=D(t,e)[0],O=new Map(n.revisions.map(u=>[u.rev_id,u]));if(w>0||c){const u=(O.get(s.rev_id)?.links??[]).map(f=>({written_as:f.written_as,dst:x(t,f.dst)})).filter(f=>f.dst!==null);Y(t,J(t,e,u),l),U(t,e,[])}if(E>1&&m.needsMerge.push(e.id),n.deleted_at&&!e.deleted_at){M(t,null,e,l,n.deleted_at),m.deleted++;return}if(n.deleted_at&&e.deleted_at&&e.deleted_at!==n.deleted_at&&g(t,"UPDATE objects SET deleted_at = ? WHERE rowid = ?").run(n.deleted_at,e.rowid),d){m.created++,T(t,{event:"created",object:e,actor:null,attrs:{revision:s.number},pointer:s.rev_id},l);return}if(c){m.created++,T(t,{event:"created",object:e,actor:null,attrs:{revision:s.number},pointer:s.rev_id},l);return}if(w===0)return;const I=n.revisions.filter(u=>!o?.revisions.some(f=>f.rev_id===u.rev_id)).sort((u,f)=>f.number-u.number||f.created_at.localeCompare(u.created_at))[0]??O.get(s.rev_id);T(t,{event:"edited",object:e,actor:null,pointer:s.rev_id,attrs:{revision:s.number,from_revision:h,rationale:I?.rationale??null,author:I?.author??null,heads:E,needs_merge:E>1}},l)}p(ue,"importOne");export{Oe as exportRepo,Se as importTree,de as namesArrived,ne as pendingPaths};
@@ -1,4 +1,4 @@
1
- import type { DeclaredOutputField } from '../api/command-manifest/result.js';
1
+ import type { DeclaredOutputField, DeclaredOutputShape } from '../api/command-manifest/result.js';
2
2
  export type Field = DeclaredOutputField;
3
3
  /** Positional argument. A repeatable positional consumes every remaining positional token. */
4
4
  export interface PositionalParam {
@@ -43,7 +43,9 @@ export interface FlagParam {
43
43
  name: string;
44
44
  /** 'bool' flags take no value — presence = true. 'file' names a
45
45
  * capability-provider file argument, sent locally as the string typed. */
46
- type: 'string' | 'int' | 'bool' | 'path' | 'enum' | 'file';
46
+ type: 'string' | 'int' | 'bool' | 'path' | 'enum' | 'file' | 'json';
47
+ /** Required only when type is 'json': the shape of the one JSON value the flag takes. */
48
+ shape?: DeclaredOutputShape;
47
49
  /** Required only when type is 'enum'. */
48
50
  choices?: string[];
49
51
  required: boolean;
package/dist/core/help.js CHANGED
@@ -1,9 +1,9 @@
1
- var w=Object.defineProperty;var r=(e,n)=>w(e,"name",{value:n,configurable:!0});async function O(e,n,t){const s=r(async a=>{try{const i=await a();return()=>i}catch{return()=>null}},"read"),o=t===void 0?void 0:n.flags?.[t],u=new Map(o===void 0?[]:[[t,await s(o)]]);return{...e,...t===void 0&&n.leaf!==void 0?{dynamicState:await s(n.leaf)}:{},params:e.params?.map(a=>{const i=a.kind==="flag"?u.get(a.name):void 0;return a.kind==="flag"&&a.focusedHelp!==void 0&&i!==void 0?{...a,focusedHelp:{...a.focusedHelp,dynamicState:i}}:a})}}r(O,"withAsyncHelpState");function j(e,n,t){const s=Object.entries(n).map(([o,u])=>` ${o}="${u}"`).join("");return`<${e}${s}>
1
+ var k=Object.defineProperty;var u=(e,n)=>k(e,"name",{value:n,configurable:!0});import{outputBaseType as y}from"../api/command-manifest/schema.js";async function E(e,n,t){const s=u(async o=>{try{const i=await o();return()=>i}catch{return()=>null}},"read"),r=t===void 0?void 0:n.flags?.[t],a=new Map(r===void 0?[]:[[t,await s(r)]]);return{...e,...t===void 0&&n.leaf!==void 0?{dynamicState:await s(n.leaf)}:{},params:e.params?.map(o=>{const i=o.kind==="flag"?a.get(o.name):void 0;return o.kind==="flag"&&o.focusedHelp!==void 0&&i!==void 0?{...o,focusedHelp:{...o.focusedHelp,dynamicState:i}}:o})}}u(E,"withAsyncHelpState");function A(e,n,t){const s=Object.entries(n).map(([r,a])=>` ${r}="${a}"`).join("");return`<${e}${s}>
2
2
  ${t}
3
- </${e}>`}r(j,"stateBlock");function f(e){if(e===void 0)return null;try{const n=e();return n!==null&&n!==""?n:null}catch{return null}}r(f,"evalDynamic");function l(e){let n=0;for(const t of e)t.length>n&&(n=t.length);return n}r(l,"maxLen");function p(e,n){return e+" ".repeat(Math.max(0,n-e.length))}r(p,"pad");const S=`I/O contract: flags and positional args on input; stdout is agent-ready markdown/XML you
3
+ </${e}>`}u(A,"stateBlock");function p(e){if(e===void 0)return null;try{const n=e();return n!==null&&n!==""?n:null}catch{return null}}u(p,"evalDynamic");function m(e){let n=0;for(const t of e)t.length>n&&(n=t.length);return n}u(m,"maxLen");function h(e,n){return e+" ".repeat(Math.max(0,n-e.length))}u(h,"pad");const N=`I/O contract: flags and positional args on input; stdout is agent-ready markdown/XML you
4
4
  act on directly \u2014 read it as a continuation of your prompt, don't parse it as data.
5
- Exit 0 on success, non-zero on failure. Schemas appear at leaf -h; a leaf may route an uncommon flag to focused --flag -h guidance.`,I="Before running a crtr command that changes state \u2014 creates, mutates, or deletes anything \u2014 whose exact contract (args, flags, effects) you haven't verified this session, run `-h` on it and read the schema first \u2014 a reliable read beats a guess that wastes a turn or triggers an unintended effect. When a leaf routes a flag to focused help, read that focused help before using the flag; the compact row is discovery, not its invocation contract. Same when the user names a capability you don't fully recognize: `-h` it before acting.";function N(e){const n=e.subcommands??[],t=e.otherSubcommandCount??0;if(n.length===0&&t===0)return[];const s=[];if(n.length>0){const o=l(n.map(u=>u.path));for(const u of n)s.push(u.desc!==void 0&&u.desc!==""?` ${p(u.path,o)} ${u.desc}`:` ${u.path}`)}if(t>0){const o=n.length>0?"other subcommand":"subcommand";s.push(` [+${t} ${o}${t===1?"":"s"} \u2014 \`crtr ${e.name} -h\`]`)}return s}r(N,"rootSubcommandLines");function E(e){const n=[];n.push(`${e.tagline}`),n.push("");for(const t of e.commands){n.push(`<command name="${t.name}">`),n.push(t.concept),n.push(`use when ${t.useWhen}`);for(const o of N(t))n.push(o);const s=f(t.dynamicState);s!==null&&n.push(s),n.push("</command>"),n.push("")}if(e.globals.length>0){n.push("Globals");const t=l(e.globals.map(s=>s.name));for(const s of e.globals)n.push(` ${p(s.name,t)} ${s.desc}`);n.push("")}return n.push(S),n.push(""),n.push(I),n.join(`
6
- `)}r(E,"renderRoot");function d(e){return e.replace(/"/g,"'")}r(d,"attr");const $=40;function k(e){if(e.length<=$)return{listed:[...e],unlisted:0};const n=e.filter(t=>t.tier==="common"||t.tier==="important");return n.length===0?{listed:[...e],unlisted:0}:{listed:n,unlisted:e.length-n.length}}r(k,"collapseWideChildren");function W(e){const n=e.length>$;return e.filter(t=>(t.tier==="common"||t.tier==="important")&&(!n||t.kind==="leaf"))}r(W,"rootPromotedChildren");function A(e){const n=[];n.push(`<command name="${e.name}" description="${d(e.summary)}">`);const t=f(e.dynamicState);t!==null&&n.push(t),e.model!==void 0&&n.push(e.model);const{listed:s,unlisted:o}=k((e.listing??[]).filter(u=>u.tier!=="hidden"));for(const u of s){const a=u.plugin===void 0?"":` plugin="${d(u.plugin)}"`,i=u.subCount!==void 0&&u.subCount>0?` subcommands="${u.subCount}"`:"";n.length>1&&n.push(""),n.push(`<subcommand name="${u.name}" description="${d(u.description)}" whenToUse="${d(u.whenToUse)}"${a}${i}/>`)}return o>0&&(n.push(""),n.push(`<unlisted-subcommands count="${o}">${o} more subcommands are not listed here. Each one runs by name, and \`crtr ${e.name} <name> -h\` prints its help.</unlisted-subcommands>`)),e.extensionIssue!==void 0&&n.push(`<extension-issue fragment="${d(e.extensionIssue.fragment)}">This repository's contributed commands were rejected: ${e.extensionIssue.message}. Run \`crtr sys doctor\` for the full report.</extension-issue>`),n.push("</command>"),n.join(`
7
- `)}r(A,"renderBranch");function C(e){if(e.kind==="positional")return`${e.name.toUpperCase()}${e.repeatable===!0?"...":""}`;if(e.kind==="stdin")return"stdin";if(e.kind==="context-file")return"--context-file PATH";const n=e;return n.type==="bool"?`--${n.name}`:`--${n.name} ${n.name.toUpperCase().replace(/-/g,"_")}`}r(C,"paramLabel");function g(e){return e===void 0?"":e==="base64"?" Local file path: the file is read and its raw bytes are base64-encoded into the request; the path itself is never sent.":" Local file path: the file is read as UTF-8 text and its content is sent as the value; the path itself is never sent."}r(g,"fileEncodingNote");function y(e){return e===void 0?"":` Defaults to $${e} when that is set and non-empty in the environment, and counts as supplied.`}r(y,"envDefaultNote");function b(e){return e==="file"?" A file: pass its path.":""}r(b,"fileParamNote");function v(e,n){return e.focusedHelp===void 0?"":` Before using this flag, run \`crtr ${n} --${e.name} -h\` and read its focused guidance.`}r(v,"focusedFlagHelpNote");function T(e,n){const t=e.required?"required":"optional";if(e.kind==="positional"){const c=e.repeatable===!0?" Repeatable \u2014 pass multiple values to accumulate in argv order.":"";return`positional, ${t}.${b(e.type)}${g(e.encoding)}${y(e.defaultFromEnv)} ${e.constraint}${c}`}if(e.kind==="stdin")return`${t}. ${e.constraint}`;if(e.kind==="context-file"){const c=e.shape!==void 0?` Shape: ${e.shape}`:"";return`${t}. Path to a JSON file.${c} ${e.constraint}`.trim()}const s=e,o=v(s,n);if(s.type==="bool")return`${t} boolean. Presence means true. ${s.constraint}${o}`.trim();const u=s.default!==void 0?` Default: ${String(s.default)}.`:"",a=s.type==="enum"&&s.choices!==void 0?` One of: ${s.choices.join(", ")}.`:"",i=s.repeatable===!0?" Repeatable \u2014 pass multiple times to accumulate.":"";return`${s.type}, ${t}.${a}${u}${b(s.type)}${g(s.encoding)}${y(s.defaultFromEnv)} ${s.constraint}${i}${o}`.trim()}r(T,"paramDesc");function m(e){if(e.items===void 0)return e.type;const n=/\|\s*null\s*$/i.test(e.type)?", or null":"";return`array of ${m(e.items)}${n}`}r(m,"outputTypePhrase");function x(e){return e.values!==void 0?` One of: ${e.values.join(", ")}.`:""}r(x,"outputValuesNote");function h(e,n,t){const s=l(e.map(o=>o.name));for(const o of e){const u=o.constraint.length>0?` ${o.constraint}`:"";t.push(`${n}${p(o.name,s)} ${m(o)}.${x(o)}${u}`),H(o,`${n} `,t)}}r(h,"renderOutputFields");function H(e,n,t){e.children!==void 0&&e.children.length>0&&h(e.children,n,t);let s=e.items;for(;s!==void 0;){const o=x(s);if((s.constraint.length>0||o.length>0)&&t.push(`${n}each element: ${m(s)}.${o}${s.constraint.length>0?` ${s.constraint}`:""}`),s.children!==void 0&&s.children.length>0){h(s.children,n,t);return}s=s.items}}r(H,"renderOutputShapeBody");function B(e,n){const t=[`${e.name}: ${e.summary}.`],s=(e.params??[]).filter(a=>!(a.kind==="flag"&&a.hidden===!0)),o=n===void 0?void 0:s.find(a=>a.kind==="flag"&&a.name===n&&a.focusedHelp!==void 0);if(o?.focusedHelp!==void 0){const a=o.focusedHelp;if(t.push(""),t.push(`<parameter name="${o.name}">`),t.push("When to use"),t.push(` ${a.whenToUse}`),t.push(""),t.push("Value"),t.push(` ${a.value}`),(a.effects??[]).length>0){t.push(""),t.push("Effects");for(const c of a.effects??[])t.push(` ${c}`)}const i=f(a.dynamicState);return i!==null&&(t.push(""),t.push(i)),t.push("</parameter>"),t.join(`
8
- `)}if(e.guide!==void 0&&(t.push(""),t.push(e.guide)),t.push(""),s.length>0){t.push("Input");const a=s.map(C),i=l(a);for(let c=0;c<s.length;c++)t.push(` ${p(a[c],i)} ${T(s[c],e.name)}`)}else t.push(e.inputNote!==void 0?e.inputNote:"No input parameters.");t.push(""),t.push("Output (fields carried in the rendered result)"),h(e.output," ",t),t.push(""),t.push("Effects");for(const a of e.effects)t.push(` ${a}`);const u=f(e.dynamicState);return u!==null&&(t.push(""),t.push(u)),t.join(`
9
- `)}r(B,"renderLeafArgv");export{$ as WIDE_BRANCH_LISTING_LIMIT,k as collapseWideChildren,A as renderBranch,B as renderLeafArgv,E as renderRoot,W as rootPromotedChildren,j as stateBlock,O as withAsyncHelpState};
5
+ Exit 0 on success, non-zero on failure. Schemas appear at leaf -h; a leaf may route an uncommon flag to focused --flag -h guidance.`,I="Before running a crtr command that changes state \u2014 creates, mutates, or deletes anything \u2014 whose exact contract (args, flags, effects) you haven't verified this session, run `-h` on it and read the schema first \u2014 a reliable read beats a guess that wastes a turn or triggers an unintended effect. When a leaf routes a flag to focused help, read that focused help before using the flag; the compact row is discovery, not its invocation contract. Same when the user names a capability you don't fully recognize: `-h` it before acting.";function j(e){const n=e.subcommands??[],t=e.otherSubcommandCount??0;if(n.length===0&&t===0)return[];const s=[];if(n.length>0){const r=m(n.map(a=>a.path));for(const a of n)s.push(a.desc!==void 0&&a.desc!==""?` ${h(a.path,r)} ${a.desc}`:` ${a.path}`)}if(t>0){const r=n.length>0?"other subcommand":"subcommand";s.push(` [+${t} ${r}${t===1?"":"s"} \u2014 \`crtr ${e.name} -h\`]`)}return s}u(j,"rootSubcommandLines");function B(e){const n=[];n.push(`${e.tagline}`),n.push("");for(const t of e.commands){n.push(`<command name="${t.name}">`),n.push(t.concept),n.push(`use when ${t.useWhen}`);for(const r of j(t))n.push(r);const s=p(t.dynamicState);s!==null&&n.push(s),n.push("</command>"),n.push("")}if(e.globals.length>0){n.push("Globals");const t=m(e.globals.map(s=>s.name));for(const s of e.globals)n.push(` ${h(s.name,t)} ${s.desc}`);n.push("")}return n.push(N),n.push(""),n.push(I),n.join(`
6
+ `)}u(B,"renderRoot");function f(e){return e.replace(/"/g,"'")}u(f,"attr");const v=40;function C(e){if(e.length<=v)return{listed:[...e],unlisted:0};const n=e.filter(t=>t.tier==="common"||t.tier==="important");return n.length===0?{listed:[...e],unlisted:0}:{listed:n,unlisted:e.length-n.length}}u(C,"collapseWideChildren");function D(e){const n=e.length>v;return e.filter(t=>(t.tier==="common"||t.tier==="important")&&(!n||t.kind==="leaf"))}u(D,"rootPromotedChildren");function P(e){const n=[];n.push(`<command name="${e.name}" description="${f(e.summary)}">`);const t=p(e.dynamicState);t!==null&&n.push(t),e.model!==void 0&&n.push(e.model);const{listed:s,unlisted:r}=C((e.listing??[]).filter(a=>a.tier!=="hidden"));for(const a of s){const o=a.plugin===void 0?"":` plugin="${f(a.plugin)}"`,i=a.subCount!==void 0&&a.subCount>0?` subcommands="${a.subCount}"`:"";n.length>1&&n.push(""),n.push(`<subcommand name="${a.name}" description="${f(a.description)}" whenToUse="${f(a.whenToUse)}"${o}${i}/>`)}return r>0&&(n.push(""),n.push(`<unlisted-subcommands count="${r}">${r} more subcommands are not listed here. Each one runs by name, and \`crtr ${e.name} <name> -h\` prints its help.</unlisted-subcommands>`)),e.extensionIssue!==void 0&&n.push(`<extension-issue fragment="${f(e.extensionIssue.fragment)}">This repository's contributed commands were rejected: ${e.extensionIssue.message}. Run \`crtr sys doctor\` for the full report.</extension-issue>`),n.push("</command>"),n.join(`
7
+ `)}u(P,"renderBranch");function O(e){if(e.kind==="positional")return`${e.name.toUpperCase()}${e.repeatable===!0?"...":""}`;if(e.kind==="stdin")return"stdin";if(e.kind==="context-file")return"--context-file PATH";const n=e;return n.type==="bool"?`--${n.name}`:`--${n.name} ${n.name.toUpperCase().replace(/-/g,"_")}`}u(O,"paramLabel");function x(e){return e===void 0?"":e==="base64"?" Local file path: the file is read and its raw bytes are base64-encoded into the request; the path itself is never sent.":" Local file path: the file is read as UTF-8 text and its content is sent as the value; the path itself is never sent."}u(x,"fileEncodingNote");function w(e){return e===void 0?"":` Defaults to $${e} when that is set and non-empty in the environment, and counts as supplied.`}u(w,"envDefaultNote");function S(e){return e==="file"?" A file: pass its path.":""}u(S,"fileParamNote");function T(e,n){return e.focusedHelp===void 0?"":` Before using this flag, run \`crtr ${n} --${e.name} -h\` and read its focused guidance.`}u(T,"focusedFlagHelpNote");function H(e,n){const t=e.required?"required":"optional";if(e.kind==="positional"){const c=e.repeatable===!0?" Repeatable \u2014 pass multiple values to accumulate in argv order.":"";return`positional, ${t}.${S(e.type)}${x(e.encoding)}${w(e.defaultFromEnv)} ${e.constraint}${c}`}if(e.kind==="stdin")return`${t}. ${e.constraint}`;if(e.kind==="context-file"){const c=e.shape!==void 0?` Shape: ${e.shape}`:"";return`${t}. Path to a JSON file.${c} ${e.constraint}`.trim()}const s=e,r=T(s,n);if(s.type==="bool")return`${t} boolean. Presence means true. ${s.constraint}${r}`.trim();const a=s.default!==void 0?` Default: ${String(s.default)}.`:"",o=s.type==="enum"&&s.choices!==void 0?` One of: ${s.choices.join(", ")}.`:"",i=s.repeatable===!0?" Repeatable \u2014 pass multiple times to accumulate.":"";return s.type==="json"?`json, ${t}. One JSON value: ${d(s.shape??{type:"unknown",constraint:""})}. ${s.constraint}${r}`.trim():`${s.type}, ${t}.${o}${a}${S(s.type)}${x(s.encoding)}${w(s.defaultFromEnv)} ${s.constraint}${i}${r}`.trim()}u(H,"paramDesc");function d(e){const n=/\|\s*null\s*$/i.test(e.type),t=y(e.type);return t==="union"&&e.variants!==void 0?`${e.variants.map(d).join(" | ")}${n?" | null":""}`:t==="map"&&e.items!==void 0?`{ [key: string]: ${d(e.items)} }${n?" | null":""}`:e.items===void 0?e.type:`array of ${d(e.items)}${n?", or null":""}`}u(d,"outputTypePhrase");function $(e){return e.values!==void 0?` One of: ${e.values.join(", ")}.`:""}u($,"outputValuesNote");function b(e,n,t){const s=m(e.map(r=>r.name));for(const r of e){const a=r.constraint.length>0?` ${r.constraint}`:"";t.push(`${n}${h(r.name,s)} ${d(r)}.${$(r)}${a}`),g(r,`${n} `,t)}}u(b,"renderOutputFields");function g(e,n,t){e.children!==void 0&&e.children.length>0&&b(e.children,n,t);for(const a of e.variants??[]){const o=$(a);t.push(`${n}variant: ${d(a)}.${o}${a.constraint.length>0?` ${a.constraint}`:""}`),g(a,`${n} `,t)}let s=e.items,r=y(e.type)==="map"?"each value":"each element";for(;s!==void 0;){const a=$(s);(s.constraint.length>0||a.length>0)&&t.push(`${n}${r}: ${d(s)}.${a}${s.constraint.length>0?` ${s.constraint}`:""}`);for(const o of s.variants??[])t.push(`${n}variant: ${d(o)}.${$(o)}${o.constraint.length>0?` ${o.constraint}`:""}`),g(o,`${n} `,t);if(s.children!==void 0&&s.children.length>0){b(s.children,n,t);return}r=y(s.type)==="map"?"each value":"each element",s=s.items}}u(g,"renderOutputShapeBody");function R(e,n){const t=[`${e.name}: ${e.summary}.`],s=(e.params??[]).filter(o=>!(o.kind==="flag"&&o.hidden===!0)),r=n===void 0?void 0:s.find(o=>o.kind==="flag"&&o.name===n&&o.focusedHelp!==void 0);if(r?.focusedHelp!==void 0){const o=r.focusedHelp;if(t.push(""),t.push(`<parameter name="${r.name}">`),t.push("When to use"),t.push(` ${o.whenToUse}`),t.push(""),t.push("Value"),t.push(` ${o.value}`),(o.effects??[]).length>0){t.push(""),t.push("Effects");for(const c of o.effects??[])t.push(` ${c}`)}const i=p(o.dynamicState);return i!==null&&(t.push(""),t.push(i)),t.push("</parameter>"),t.join(`
8
+ `)}if(e.guide!==void 0&&(t.push(""),t.push(e.guide)),t.push(""),s.length>0){t.push("Input");const o=s.map(O),i=m(o);for(let c=0;c<s.length;c++){t.push(` ${h(o[c],i)} ${H(s[c],e.name)}`);const l=s[c];l.kind==="flag"&&l.type==="json"&&l.shape!==void 0&&g(l.shape,` ${" ".repeat(i)} `,t)}}else t.push(e.inputNote!==void 0?e.inputNote:"No input parameters.");t.push(""),t.push("Output (fields carried in the rendered result)"),b(e.output," ",t),t.push(""),t.push("Effects");for(const o of e.effects)t.push(` ${o}`);const a=p(e.dynamicState);return a!==null&&(t.push(""),t.push(a)),t.join(`
9
+ `)}u(R,"renderLeafArgv");export{v as WIDE_BRANCH_LISTING_LIMIT,C as collapseWideChildren,P as renderBranch,R as renderLeafArgv,B as renderRoot,D as rootPromotedChildren,A as stateBlock,E as withAsyncHelpState};
@@ -1 +1 @@
1
- var c=Object.defineProperty;var o=(n,t)=>c(n,"name",{value:t,configurable:!0});import{apiSocketPath as l}from"./canvas/paths.js";import{validatePluginCommands as d}from"./command-plugins/discovery.js";import{declaresObjectBlocks as m,leafPathsBelowRoot as g,needsAppToken as f,objectBlocksReasons as h,streamingLeafPathsBelowRoot as P}from"./plugin-objects-manifest.js";import{listInstalledPlugins as k}from"./resolver.js";import{pluginAppToken as u}from"./secrets.js";function v(n){const t=d(n),e=t.manifest?.roots??[];return{leafPaths:g(n.name,e),streamingLeafPaths:P(n.name,e),issues:t.issues.map(i=>i.message)}}o(v,"pluginLeafPaths");function a(){const n=[],t=[];for(const e of k("user")){if(!e.enabled||!(f(e.manifest)||m(e.manifest)))continue;const{leafPaths:i,streamingLeafPaths:s,issues:p}=v(e),r=[...p,...h(e.manifest,{name:e.name,leafPaths:i,streamingLeafPaths:s})];r.length===0?n.push(e):t.push({plugin:e,error:r.join("; ")})}return{valid:n,invalid:t}}o(a,"classify");function A(){return a().valid.filter(n=>f(n.manifest))}o(A,"appPlugins");function O(){return a().valid.filter(n=>Object.keys(n.manifest.object_kinds??{}).length>0)}o(O,"kindPlugins");function _(){return a().invalid}o(_,"invalidAppPlugins");function B(n){const t=u(n);return t===void 0?null:{CRTR_APP_TOKEN:t.token,CRTR_DAEMON_SOCKET:l()}}o(B,"pluginAppEnv");function E(n){const t=A().find(s=>s.name===n);if(t===void 0)return null;const e=u(n);if(e===void 0)return null;const i=t.manifest.transport;return{plugin:t,token:e.token,socket:l(),endpoint:i?.kind==="http"?i.endpoint:null}}o(E,"pluginAppCredential");export{A as appPlugins,_ as invalidAppPlugins,O as kindPlugins,E as pluginAppCredential,B as pluginAppEnv,v as pluginLeafPaths};
1
+ var m=Object.defineProperty;var s=(n,t)=>m(n,"name",{value:t,configurable:!0});import{apiSocketPath as l}from"./canvas/paths.js";import{validatePluginCommands as c}from"./command-plugins/discovery.js";import{declaresObjectBlocks as d,leafPathsBelowRoot as h,needsAppToken as f,objectBlocksReasons as P,streamingLeafPathsBelowRoot as g}from"./plugin-objects-manifest.js";import{listInstalledPlugins as k}from"./resolver.js";import{pluginAppToken as u}from"./secrets.js";function v(n){const t=c(n),e=t.manifest?.roots??[];return{leafPaths:h(n.name,n.manifest,e),streamingLeafPaths:g(n.name,n.manifest,e),issues:t.issues.map(o=>o.message)}}s(v,"pluginLeafPaths");function a(){const n=[],t=[];for(const e of k("user")){if(!e.enabled||!(f(e.manifest)||d(e.manifest)))continue;const{leafPaths:o,streamingLeafPaths:i,issues:p}=v(e),r=[...p,...P(e.manifest,{name:e.name,leafPaths:o,streamingLeafPaths:i})];r.length===0?n.push(e):t.push({plugin:e,error:r.join("; ")})}return{valid:n,invalid:t}}s(a,"classify");function A(){return a().valid.filter(n=>f(n.manifest))}s(A,"appPlugins");function O(){return a().valid.filter(n=>Object.keys(n.manifest.object_kinds??{}).length>0)}s(O,"kindPlugins");function _(){return a().invalid}s(_,"invalidAppPlugins");function B(n){const t=u(n);return t===void 0?null:{CRTR_APP_TOKEN:t.token,CRTR_DAEMON_SOCKET:l()}}s(B,"pluginAppEnv");function E(n){const t=A().find(i=>i.name===n);if(t===void 0)return null;const e=u(n);if(e===void 0)return null;const o=t.manifest.transport;return{plugin:t,token:e.token,socket:l(),endpoint:o?.kind==="http"?o.endpoint:null}}s(E,"pluginAppCredential");export{A as appPlugins,_ as invalidAppPlugins,O as kindPlugins,E as pluginAppCredential,B as pluginAppEnv,v as pluginLeafPaths};
@@ -15,7 +15,9 @@ export declare function objectBlocksReasons(manifest: Pick<PluginManifest, 'obje
15
15
  export declare function declaresObjectBlocks(manifest: Pick<PluginManifest, 'object_kinds' | 'scopes'>): boolean;
16
16
  /** A user plugin holds a `crtr_app_` token when it is not a provider and declares kinds or scopes, or serves over HTTP. */
17
17
  export declare function needsAppToken(manifest: Pick<PluginManifest, 'object_kinds' | 'scopes' | 'provider' | 'transport'>): boolean;
18
- /** The space-joined path of every leaf below the plugin's root command (`page read` for plugin `search`'s leaf `search page read`). */
19
- export declare function leafPathsBelowRoot(name: string, roots: ReadonlyArray<DeclNode<DeclLeaf>>): Set<string>;
18
+ /** A provider leaf's tool path from its full command path (root first): root-relative when the bundle has one root command, else as declared. The one rule `providerLeaves` dispatches by and the object-kind gate validates against. */
19
+ export declare function providerToolPath(rootCount: number, path: readonly string[]): string;
20
+ /** The space-joined path of every leaf below the plugin's root command (`page read` for plugin `search`'s leaf `search page read`); for a provider bundle, every leaf's tool path (`providerToolPath`). */
21
+ export declare function leafPathsBelowRoot(name: string, manifest: Pick<PluginManifest, 'provider'>, roots: ReadonlyArray<DeclNode<DeclLeaf>>): Set<string>;
20
22
  /** The leaves of `leafPathsBelowRoot` that declare `rest.streaming: true`. */
21
- export declare function streamingLeafPathsBelowRoot(name: string, roots: ReadonlyArray<DeclNode<DeclLeaf>>): Set<string>;
23
+ export declare function streamingLeafPathsBelowRoot(name: string, manifest: Pick<PluginManifest, 'provider'>, roots: ReadonlyArray<DeclNode<DeclLeaf>>): Set<string>;
@@ -1 +1 @@
1
- var l=Object.defineProperty;var r=(e,n)=>l(e,"name",{value:n,configurable:!0});import{parseScope as h}from"@north-light/identity";import{KIND as g,LOCAL as k,RESERVED_KIND_ROOTS as b,MAX_KIND_EVENTS as E,MIN_EVENT_LEVEL as j,MAX_EVENT_LEVEL as _,eventCatalogReasons as S,objectBlocksShapeReasons as a,objectKindReadReasons as f}from"../api/command-manifest/object-kinds.js";const w=/^crtr:objects:(?:read|watch|link|write):/;function L(e,n){const t=a(e);if(t.length>0)return t;const{name:c,leafPaths:p,streamingLeafPaths:s}=n;for(const[o,u]of Object.entries(e.object_kinds??{}))o.split(".")[0]!==c&&t.push(`object_kinds ${JSON.stringify(o)} must start with the plugin name "${c}."`),t.push(...f(o,u,c,p,s));const i=e.scopes??[];e.scopes!==void 0&&e.provider!==void 0&&t.push("scopes is for local plugins; a provider gets its scopes from directory consent");for(const o of i){try{h(o)}catch{t.push(`scope ${JSON.stringify(o)} is not a recognized scope`);continue}w.test(o)?o.endsWith(`:app:${c}`)&&t.push(`scope ${JSON.stringify(o)} names the plugin's own space; an app needs no scope for its own objects`):t.push(`scope ${JSON.stringify(o)} must be crtr:objects:<read|watch|link|write>:<target>`)}return t}r(L,"objectBlocksReasons");function m(e){return e.object_kinds!==void 0||e.scopes!==void 0}r(m,"declaresObjectBlocks");function y(e){return e.provider!==void 0?!1:Object.keys(e.object_kinds??{}).length>0||(e.scopes?.length??0)>0||e.transport?.kind==="http"}r(y,"needsAppToken");function P(e,n){return d(e,n,()=>!0)}r(P,"leafPathsBelowRoot");function V(e,n){return d(e,n,t=>"rest"in t&&t.rest.streaming===!0)}r(V,"streamingLeafPathsBelowRoot");function d(e,n,t){const c=new Set,p=r((s,i)=>{if(s.kind==="leaf")t(s)&&c.add([...i,s.name].join(" "));else for(const o of s.children)p(o,[...i,s.name])},"walk");for(const s of n)if(s.name===e&&s.kind==="branch")for(const i of s.children)p(i,[]);return c}r(d,"collectLeafPaths");export{g as KIND,k as LOCAL,_ as MAX_EVENT_LEVEL,E as MAX_KIND_EVENTS,j as MIN_EVENT_LEVEL,b as RESERVED_KIND_ROOTS,m as declaresObjectBlocks,S as eventCatalogReasons,P as leafPathsBelowRoot,y as needsAppToken,L as objectBlocksReasons,a as objectBlocksShapeReasons,f as objectKindReadReasons,V as streamingLeafPathsBelowRoot};
1
+ var h=Object.defineProperty;var r=(e,n)=>h(e,"name",{value:n,configurable:!0});import{parseScope as g}from"@north-light/identity";import{KIND as k,LOCAL as b,RESERVED_KIND_ROOTS as j,MAX_KIND_EVENTS as E,MIN_EVENT_LEVEL as _,MAX_EVENT_LEVEL as S,eventCatalogReasons as w,objectBlocksShapeReasons as f,objectKindReadReasons as d}from"../api/command-manifest/object-kinds.js";const N=/^crtr:objects:(?:read|watch|link|write):/;function P(e,n){const o=f(e);if(o.length>0)return o;const{name:s,leafPaths:i,streamingLeafPaths:a}=n;for(const[t,c]of Object.entries(e.object_kinds??{}))t.split(".")[0]!==s&&o.push(`object_kinds ${JSON.stringify(t)} must start with the plugin name "${s}."`),o.push(...d(t,c,s,i,a));const p=e.scopes??[];e.scopes!==void 0&&e.provider!==void 0&&o.push("scopes is for local plugins; a provider gets its scopes from directory consent");for(const t of p){try{g(t)}catch{o.push(`scope ${JSON.stringify(t)} is not a recognized scope`);continue}N.test(t)?t.endsWith(`:app:${s}`)&&o.push(`scope ${JSON.stringify(t)} names the plugin's own space; an app needs no scope for its own objects`):o.push(`scope ${JSON.stringify(t)} must be crtr:objects:<read|watch|link|write>:<target>`)}return o}r(P,"objectBlocksReasons");function v(e){return e.object_kinds!==void 0||e.scopes!==void 0}r(v,"declaresObjectBlocks");function y(e){return e.provider!==void 0?!1:Object.keys(e.object_kinds??{}).length>0||(e.scopes?.length??0)>0||e.transport?.kind==="http"}r(y,"needsAppToken");function O(e,n){return(e===1?n.slice(1):n).join(" ")}r(O,"providerToolPath");function V(e,n,o){return u(e,n,o,()=>!0)}r(V,"leafPathsBelowRoot");function B(e,n,o){return u(e,n,o,s=>"rest"in s&&s.rest.streaming===!0)}r(B,"streamingLeafPathsBelowRoot");function u(e,n,o,s){const i=n.provider!==void 0,a=new Set,p=r((t,c)=>{if(t.kind==="leaf")s(t)&&a.add(i?O(o.length,[...c,t.name]):[...c,t.name].join(" "));else for(const l of t.children)p(l,[...c,t.name])},"walk");for(const t of o)if(!(t.kind!=="branch"||!i&&t.name!==e))if(i)p(t,[]);else for(const c of t.children)p(c,[]);return a}r(u,"collectLeafPaths");export{k as KIND,b as LOCAL,S as MAX_EVENT_LEVEL,E as MAX_KIND_EVENTS,_ as MIN_EVENT_LEVEL,j as RESERVED_KIND_ROOTS,v as declaresObjectBlocks,w as eventCatalogReasons,V as leafPathsBelowRoot,y as needsAppToken,P as objectBlocksReasons,f as objectBlocksShapeReasons,d as objectKindReadReasons,O as providerToolPath,B as streamingLeafPathsBelowRoot};
@@ -2,10 +2,11 @@ import type { ManifestHttpLeaf, ManifestBranch, ManifestRootEntry } from '../../
2
2
  import type { ValidatedCommandManifest } from '../../api/command-manifest/manifest.js';
3
3
  import type { ProviderCaller, ProviderCallInput, ProviderRequest } from '../../daemon/api/handlers/providers.js';
4
4
  import { ProviderError } from './errors.js';
5
- /** A canonical command path is relative to the provider, never provider-prefixed. */
5
+ /** `tool` is a canonical command path, relative to the provider and never provider-prefixed. `hidden` is true for a leaf declared hidden or under a hidden branch: it stays callable by its exact path but is never listed. */
6
6
  export interface ProviderLeaf {
7
7
  tool: string;
8
8
  leaf: ManifestHttpLeaf;
9
+ hidden: boolean;
9
10
  }
10
11
  export declare function providerLeaves(commands: ValidatedCommandManifest): ProviderLeaf[];
11
12
  export type ProviderHelpLeaf = Pick<ManifestHttpLeaf, 'kind' | 'name' | 'description' | 'whenToUse' | 'tier' | 'summary' | 'params' | 'output' | 'effects' | 'group'>;