@north-light/cli 0.3.578 → 0.3.580

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 (74) hide show
  1. package/dist/build-root.js +1 -1
  2. package/dist/builtin-memory/crouter-sdk/release-notes.md +1 -1
  3. package/dist/builtin-memory/internal/storage-tiers.md +2 -2
  4. package/dist/clients/attach/viewer.js +338 -338
  5. package/dist/core/canvas/export-sqlite.js +1 -1
  6. package/dist/core/canvas/schema-pg/009-bodies.sql +10 -0
  7. package/dist/core/canvas/schema-version.d.ts +1 -1
  8. package/dist/core/canvas/schema-version.js +1 -1
  9. package/dist/core/command.js +5 -5
  10. package/dist/core/feed/feed.js +3 -3
  11. package/dist/core/feed/inbox.js +1 -1
  12. package/dist/core/feed/reports.js +2 -2
  13. package/dist/core/graph/access.d.ts +1 -1
  14. package/dist/core/graph/bodies-boot-copy.d.ts +14 -0
  15. package/dist/core/graph/bodies-boot-copy.js +1 -0
  16. package/dist/core/graph/bodies.d.ts +13 -6
  17. package/dist/core/graph/bodies.js +1 -1
  18. package/dist/core/graph/documents.js +8 -8
  19. package/dist/core/graph/objects.js +11 -11
  20. package/dist/core/graph/package-docs.js +5 -5
  21. package/dist/core/graph/repo-sync/exchange.js +2 -2
  22. package/dist/core/graph/repo-sync/ref-format.d.ts +0 -1
  23. package/dist/core/graph/repo-sync/ref-format.js +2 -2
  24. package/dist/core/human/feedback-companion.js +1 -1
  25. package/dist/core/human/page.d.ts +2 -4
  26. package/dist/core/human/page.js +6 -6
  27. package/dist/core/human/request-files.d.ts +14 -0
  28. package/dist/core/human/request-files.js +1 -0
  29. package/dist/core/human/requests.d.ts +3 -0
  30. package/dist/core/human/requests.js +18 -17
  31. package/dist/core/human/tickets.js +1 -1
  32. package/dist/core/human/visible-paths.d.ts +7 -0
  33. package/dist/core/human/visible-paths.js +1 -1
  34. package/dist/core/peer/receiver.js +1 -1
  35. package/dist/core/review/document.d.ts +4 -4
  36. package/dist/core/review/document.js +2 -2
  37. package/dist/core/review/project.d.ts +7 -5
  38. package/dist/core/review/project.js +2 -1
  39. package/dist/core/review/remap.js +1 -1
  40. package/dist/core/review/stage.d.ts +2 -0
  41. package/dist/core/review/stage.js +1 -1
  42. package/dist/core/review/store.js +1 -1
  43. package/dist/core/runtime/roadmap.js +3 -3
  44. package/dist/core/substrate/delivery/corpus.d.ts +2 -0
  45. package/dist/core/substrate/delivery/corpus.js +3 -3
  46. package/dist/core/substrate/delivery/deliver.js +3 -3
  47. package/dist/core/substrate/delivery/render-boot.js +25 -25
  48. package/dist/core/substrate/delivery/render-event.d.ts +1 -1
  49. package/dist/core/substrate/delivery/render-event.js +4 -4
  50. package/dist/core/substrate/delivery/types.d.ts +2 -2
  51. package/dist/daemon/api/bridge.d.ts +1 -1
  52. package/dist/daemon/api/bridge.js +5 -5
  53. package/dist/daemon/api/document-listener.js +4 -4
  54. package/dist/daemon/api/handlers/docs.js +1 -1
  55. package/dist/daemon/api/handlers/feedback-comments.js +2 -2
  56. package/dist/daemon/api/handlers/inbox-page.js +1 -1
  57. package/dist/daemon/api/handlers/inbox.js +1 -1
  58. package/dist/daemon/api/handlers/memory.js +4 -4
  59. package/dist/daemon/api/handlers/reports.js +4 -4
  60. package/dist/daemon/api/handlers/reviews.js +1 -1
  61. package/dist/daemon/boot-migrations.js +1 -1
  62. package/dist/daemon/profile-delete.js +1 -1
  63. package/dist/daemon/review/finish.js +1 -1
  64. package/dist/daemon/review/sweep.js +1 -1
  65. package/dist/daemon/runs/observer.js +3 -3
  66. package/dist/migrations/004-canvas-documents/apply.d.ts +2 -4
  67. package/dist/migrations/004-canvas-documents/apply.js +1 -1
  68. package/dist/migrations/004-canvas-documents/index.js +2 -2
  69. package/dist/shared/env.d.ts +5 -0
  70. package/dist/shared/env.js +2 -2
  71. package/docs/sdk/release-notes.md +1 -1
  72. package/package.json +2 -2
  73. package/packages/crouter-identity/package.json +1 -1
  74. package/runtime.lock.json +13 -13
@@ -1 +1 @@
1
- var I=Object.defineProperty;var n=(e,t)=>I(e,"name",{value:t,configurable:!0});import{defineBranch as D,defineRoot as y,GLOBAL_TOKENS as R}from"./core/command.js";import{createCoreHookCatalog as x}from"./core/command-hooks/catalog.js";import{composeCoreHooks as B}from"./core/command-hooks/compose.js";import{mark as p}from"./core/timing.js";import{envNodeId as G,envScopes as U,isSandboxedNode as E,scopeAllowed as q}from"./shared/env.js";const S="crtr: agentic runtime.",b=[{name:"--json",desc:"stdout as the leaf's declared outputs in raw JSON instead of prose \u2014 for scripts (a cron's bash, external tooling) that must branch on canvas state; prose stays the contract for what you read yourself."}],k=Object.assign(Object.create(null),{doc:n(async()=>(await import("./commands/doc.js")).registerDoc(),"doc"),"custom-object":n(async()=>(await import("./commands/custom-object.js")).registerCustomObject(),"custom-object"),profile:n(async()=>(await import("./commands/profile.js")).registerProfile(),"profile"),pkg:n(async()=>(await import("./commands/pkg.js")).registerPkg(),"pkg"),human:n(async()=>(await import("./commands/human.js")).registerHuman(),"human"),sys:n(async()=>(await import("./commands/sys.js")).registerSys(),"sys"),node:n(async()=>(await import("./commands/node.js")).registerNode(),"node"),push:n(async()=>(await import("./commands/push.js")).registerPush(),"push"),cron:n(async()=>(await import("./commands/cron.js")).registerCron(),"cron"),canvas:n(async()=>(await import("./commands/canvas.js")).registerCanvas(),"canvas"),surface:n(async()=>(await import("./commands/surface.js")).registerSurface(),"surface")}),m=Object.freeze(Object.keys(k)),z={human:["crtr:act"],cron:["crtr:schedule"],doc:["crtr:memory:read:user","crtr:memory:rw:user"]};function N(e){const t=U();return t===null?e:e.filter(r=>{const o=z[r.name];return o===void 0||o.some(s=>q(t,s))||r.name==="doc"&&process.env.CRTR_GRANTEE?.startsWith("app:")===!0})}n(N,"allowedSubtrees");const j=new Map;function L(e){let t=j.get(e);return t===void 0&&(t=k[e](),j.set(e,t)),t}n(L,"loadSubtree");function v(e){return Promise.all(m.filter(t=>e.has(t)).map(L))}n(v,"loadCoreSubtreesNamed");function C(){return v(new Set(m))}n(C,"loadCoreSubtrees");function P(e){const t=new Set;for(const r of e){const o=r.split(" ")[0];m.includes(o)&&t.add(o)}return t}n(P,"subtreesNamedBy");let T;function re(){return p("cli.hooks.catalog"),T??=C().then(x),T}n(re,"coreHookCatalog");function _(){let e;return()=>(e??=(async()=>{const{compileHookRegistry:t,declaredCommandHookTargets:r,effectiveHookPlugins:o}=await import("./core/command-hooks/discovery.js"),s=o(),a=E()&&G()!==void 0?await(await import("./core/command-hooks/transport/plan.js")).remoteHookPlan(process.cwd()):[];if(p("cli.hooks.effective_plugins",{count:s.length+a.length}),s.length===0&&a.length===0)return p("cli.hooks.empty_registry"),t(x([]),[]);const c=E()?s.filter(l=>l.scope==="project"):s,i=P([...r(c),...a.map(l=>l.target)]);return p("cli.hooks.catalog",{subtrees:[...i].join(",")}),t(x(await v(i)),c,a)})(),e)}n(_,"hookRegistryLoader");function g(e){const t=new Set,r=n((o,s)=>{if(!(o.kind==="branch"&&o.passthrough!==void 0)&&(t.add(s),o.kind==="branch"))for(const a of o.children)r(a,`${s} ${a.name}`)},"visit");for(const o of e)r(o,o.name);return t}n(g,"commandPathsFor");async function se(){return g(await C())}n(se,"coreCommandPaths");async function ae(e){return g(await v(P(e)))}n(ae,"coreCommandPathsCovering");function J(e){const t=[],r=n((o,s)=>{o.extensible===!0&&t.push(s);for(const a of o.children)a.kind==="branch"&&r(a,[...s,a.name])},"visit");for(const o of e)r(o,[o.name]);return t}n(J,"extensibleBranchPaths");const W=Object.freeze(["human","sys tutorial"]);async function A(){return new Set(W)}n(A,"extensibleCoreBranches");async function ie(){return new Set(J(await C()).map(e=>e.join(" ")))}n(ie,"declaredExtensibleCoreBranches");function $(e,t){const{listing:r,...o}=e.help;return D({name:e.name,description:e.description,whenToUse:e.whenToUse,tier:e.tier,help:o,rootEntry:e.rootEntry,extensible:e.extensible,plugin:e.plugin,slash:e.slash,passthrough:e.passthrough,children:t})}n($,"rebuildBranch");async function M(e,t,r){if(t.size===0)return e;const[{buildExternalCommandSnapshot:o},{composeCoreBranchMounts:s}]=await Promise.all([import("./core/command-plugins/discovery.js"),import("./core/command-plugins/compose.js")]),a=o(new Set(m),void 0,void 0,r,t),c=n((i,l)=>{let h=!1;const w=i.children.map(d=>{if(d.kind!=="branch")return d;const u=c(d,[...l,d.name]);return u!==d&&(h=!0),u}),f=i.extensible===!0?s(a.coreMounts,l):[];return h||f.length>0?$(i,[...w,...f]):i},"composeBranch");return e.map(i=>c(i,[i.name]))}n(M,"composeCorePluginMounts");async function F(e,t){const{validateEffectiveCommandPlugins:r}=await import("./core/command-plugins/discovery.js"),s=r(new Set(m),void 0,void 0,void 0,t).flatMap(c=>c.manifest===void 0?[]:[c.manifest]).filter(c=>c.coreMounts.some(i=>i.parent[0]===e));if(s.length===0)return null;const a=P(s.flatMap(c=>[...c.coreMounts.map(i=>i.parent.join(" ")),...Object.keys(c.helpAddenda??{})]));return a.add(e),g(await v(a))}n(F,"dispatchCommandPaths");function O(e,t){const r=e.slice(2).filter(o=>!R.has(o));return r[0]==="sys"&&r[1]===t}n(O,"isSysInvocation");const K=[["surface"],["sys"],["pkg"],["profile","default"],["canvas","chord"],["canvas","config"],["canvas","use"],["canvas","browse"],["canvas","issue"]],X=[["sys","feedback"]];function H(e,t){return t.every((r,o)=>e[o]===r)}n(H,"startsWithPath");function ce(e){const t=e.slice(2).filter(o=>!R.has(o));if(X.some(o=>H(t,o)))return null;const r=K.find(o=>H(t,o));return r===void 0?null:r.join(" ")}n(ce,"personOnlyInvocation");function ue(e){return O(e,"daemon")}n(ue,"isDaemonControlInvocation");function le(e){return O(e,"join")}n(le,"isJoinInvocation");function de(e){return O(e,"migrate")}n(de,"isLayoutMigrationInvocation");async function me(){const{registerDaemonControlSys:e}=await import("./commands/sys/daemon.js");return y({tagline:S,globals:b,subtrees:[e()]})}n(me,"resolveDaemonControlRoot");async function pe(){const[{defineSysBranch:e},{sysMigrateLeaf:t}]=await Promise.all([import("./commands/sys/branch.js"),import("./commands/sys/migrate.js")]);return y({tagline:S,globals:b,subtrees:[e([t])]})}n(pe,"resolveLayoutMigrationRoot");async function fe(e){return(e!==void 0?await Y(e):null)??Q()}n(fe,"resolveRoot");async function Y(e){if(k[e]===void 0)return null;const t=await L(e),r=await A(),o=[...r].some(a=>a.split(" ")[0]===e)?await F(e,r):null,s=N(o===null?[t]:await M([t],r,o));return s.length>0?y({tagline:S,globals:b,subtrees:B(s,_())}):null}n(Y,"resolveCoreRoot");async function Q(){const e=await C(),[{buildExternalCommandSnapshot:t},{composeExternalSubtrees:r,composeSandboxProviderSubtrees:o},{qualifiedTopLevelCommandName:s}]=await Promise.all([import("./core/command-plugins/discovery.js"),import("./core/command-plugins/compose.js"),import("./core/command-manifests/registry.js")]),a=await A(),c=await M(e,a,g(e)),i=t(new Set(m),void 0,void 0,g(e),a);let l=r(i);if(E()){const{cliClient:h}=await import("./commands/api-client.js");p("cli.providers.request");const{providers:w}=await h().request("GET","/v1/providers/tools");p("cli.providers.fetched",{providers:w.length});const f=o(w,new Set(m)),d=new Set(f.map(u=>u.name));l=[...f,...r({...i,contributions:i.contributions.map(u=>d.has(u.node.name)?{...u,node:{...u.node,name:s(u.contributor,u.node.name)}}:u)})]}return y({tagline:S,globals:b,subtrees:[...B(N(c),_()),...l]})}n(Q,"buildRoot");export{W as EXTENSIBLE_CORE_BRANCHES,m as SUBTREE_NAMES,Q as buildRoot,se as coreCommandPaths,ae as coreCommandPathsCovering,re as coreHookCatalog,ie as declaredExtensibleCoreBranches,A as extensibleCoreBranches,ue as isDaemonControlInvocation,le as isJoinInvocation,de as isLayoutMigrationInvocation,ce as personOnlyInvocation,Y as resolveCoreRoot,me as resolveDaemonControlRoot,pe as resolveLayoutMigrationRoot,fe as resolveRoot};
1
+ var I=Object.defineProperty;var n=(e,t)=>I(e,"name",{value:t,configurable:!0});import{defineBranch as D,defineRoot as y,GLOBAL_TOKENS as R}from"./core/command.js";import{createCoreHookCatalog as x}from"./core/command-hooks/catalog.js";import{composeCoreHooks as B}from"./core/command-hooks/compose.js";import{mark as p}from"./core/timing.js";import{envNodeId as G,envScopes as U,isSandboxedNode as E,providerProjectionOverBrokerRelay as q,scopeAllowed as z}from"./shared/env.js";const S="crtr: agentic runtime.",b=[{name:"--json",desc:"stdout as the leaf's declared outputs in raw JSON instead of prose \u2014 for scripts (a cron's bash, external tooling) that must branch on canvas state; prose stays the contract for what you read yourself."}],k=Object.assign(Object.create(null),{doc:n(async()=>(await import("./commands/doc.js")).registerDoc(),"doc"),"custom-object":n(async()=>(await import("./commands/custom-object.js")).registerCustomObject(),"custom-object"),profile:n(async()=>(await import("./commands/profile.js")).registerProfile(),"profile"),pkg:n(async()=>(await import("./commands/pkg.js")).registerPkg(),"pkg"),human:n(async()=>(await import("./commands/human.js")).registerHuman(),"human"),sys:n(async()=>(await import("./commands/sys.js")).registerSys(),"sys"),node:n(async()=>(await import("./commands/node.js")).registerNode(),"node"),push:n(async()=>(await import("./commands/push.js")).registerPush(),"push"),cron:n(async()=>(await import("./commands/cron.js")).registerCron(),"cron"),canvas:n(async()=>(await import("./commands/canvas.js")).registerCanvas(),"canvas"),surface:n(async()=>(await import("./commands/surface.js")).registerSurface(),"surface")}),m=Object.freeze(Object.keys(k)),J={human:["crtr:act"],cron:["crtr:schedule"],doc:["crtr:memory:read:user","crtr:memory:rw:user"]};function j(e){const t=U();return t===null?e:e.filter(r=>{const o=J[r.name];return o===void 0||o.some(s=>z(t,s))||r.name==="doc"&&process.env.CRTR_GRANTEE?.startsWith("app:")===!0})}n(j,"allowedSubtrees");const N=new Map;function L(e){let t=N.get(e);return t===void 0&&(t=k[e](),N.set(e,t)),t}n(L,"loadSubtree");function v(e){return Promise.all(m.filter(t=>e.has(t)).map(L))}n(v,"loadCoreSubtreesNamed");function C(){return v(new Set(m))}n(C,"loadCoreSubtrees");function P(e){const t=new Set;for(const r of e){const o=r.split(" ")[0];m.includes(o)&&t.add(o)}return t}n(P,"subtreesNamedBy");let T;function se(){return p("cli.hooks.catalog"),T??=C().then(x),T}n(se,"coreHookCatalog");function _(){let e;return()=>(e??=(async()=>{const{compileHookRegistry:t,declaredCommandHookTargets:r,effectiveHookPlugins:o}=await import("./core/command-hooks/discovery.js"),s=o(),a=E()&&G()!==void 0?await(await import("./core/command-hooks/transport/plan.js")).remoteHookPlan(process.cwd()):[];if(p("cli.hooks.effective_plugins",{count:s.length+a.length}),s.length===0&&a.length===0)return p("cli.hooks.empty_registry"),t(x([]),[]);const c=E()?s.filter(l=>l.scope==="project"):s,i=P([...r(c),...a.map(l=>l.target)]);return p("cli.hooks.catalog",{subtrees:[...i].join(",")}),t(x(await v(i)),c,a)})(),e)}n(_,"hookRegistryLoader");function g(e){const t=new Set,r=n((o,s)=>{if(!(o.kind==="branch"&&o.passthrough!==void 0)&&(t.add(s),o.kind==="branch"))for(const a of o.children)r(a,`${s} ${a.name}`)},"visit");for(const o of e)r(o,o.name);return t}n(g,"commandPathsFor");async function ae(){return g(await C())}n(ae,"coreCommandPaths");async function ie(e){return g(await v(P(e)))}n(ie,"coreCommandPathsCovering");function W(e){const t=[],r=n((o,s)=>{o.extensible===!0&&t.push(s);for(const a of o.children)a.kind==="branch"&&r(a,[...s,a.name])},"visit");for(const o of e)r(o,[o.name]);return t}n(W,"extensibleBranchPaths");const $=Object.freeze(["human","sys tutorial"]);async function A(){return new Set($)}n(A,"extensibleCoreBranches");async function ce(){return new Set(W(await C()).map(e=>e.join(" ")))}n(ce,"declaredExtensibleCoreBranches");function F(e,t){const{listing:r,...o}=e.help;return D({name:e.name,description:e.description,whenToUse:e.whenToUse,tier:e.tier,help:o,rootEntry:e.rootEntry,extensible:e.extensible,plugin:e.plugin,slash:e.slash,passthrough:e.passthrough,children:t})}n(F,"rebuildBranch");async function M(e,t,r){if(t.size===0)return e;const[{buildExternalCommandSnapshot:o},{composeCoreBranchMounts:s}]=await Promise.all([import("./core/command-plugins/discovery.js"),import("./core/command-plugins/compose.js")]),a=o(new Set(m),void 0,void 0,r,t),c=n((i,l)=>{let h=!1;const w=i.children.map(d=>{if(d.kind!=="branch")return d;const u=c(d,[...l,d.name]);return u!==d&&(h=!0),u}),f=i.extensible===!0?s(a.coreMounts,l):[];return h||f.length>0?F(i,[...w,...f]):i},"composeBranch");return e.map(i=>c(i,[i.name]))}n(M,"composeCorePluginMounts");async function K(e,t){const{validateEffectiveCommandPlugins:r}=await import("./core/command-plugins/discovery.js"),s=r(new Set(m),void 0,void 0,void 0,t).flatMap(c=>c.manifest===void 0?[]:[c.manifest]).filter(c=>c.coreMounts.some(i=>i.parent[0]===e));if(s.length===0)return null;const a=P(s.flatMap(c=>[...c.coreMounts.map(i=>i.parent.join(" ")),...Object.keys(c.helpAddenda??{})]));return a.add(e),g(await v(a))}n(K,"dispatchCommandPaths");function O(e,t){const r=e.slice(2).filter(o=>!R.has(o));return r[0]==="sys"&&r[1]===t}n(O,"isSysInvocation");const X=[["surface"],["sys"],["pkg"],["profile","default"],["canvas","chord"],["canvas","config"],["canvas","use"],["canvas","browse"],["canvas","issue"]],Y=[["sys","feedback"]];function H(e,t){return t.every((r,o)=>e[o]===r)}n(H,"startsWithPath");function ue(e){const t=e.slice(2).filter(o=>!R.has(o));if(Y.some(o=>H(t,o)))return null;const r=X.find(o=>H(t,o));return r===void 0?null:r.join(" ")}n(ue,"personOnlyInvocation");function le(e){return O(e,"daemon")}n(le,"isDaemonControlInvocation");function de(e){return O(e,"join")}n(de,"isJoinInvocation");function me(e){return O(e,"migrate")}n(me,"isLayoutMigrationInvocation");async function pe(){const{registerDaemonControlSys:e}=await import("./commands/sys/daemon.js");return y({tagline:S,globals:b,subtrees:[e()]})}n(pe,"resolveDaemonControlRoot");async function fe(){const[{defineSysBranch:e},{sysMigrateLeaf:t}]=await Promise.all([import("./commands/sys/branch.js"),import("./commands/sys/migrate.js")]);return y({tagline:S,globals:b,subtrees:[e([t])]})}n(fe,"resolveLayoutMigrationRoot");async function ge(e){return(e!==void 0?await Q(e):null)??V()}n(ge,"resolveRoot");async function Q(e){if(k[e]===void 0)return null;const t=await L(e),r=await A(),o=[...r].some(a=>a.split(" ")[0]===e)?await K(e,r):null,s=j(o===null?[t]:await M([t],r,o));return s.length>0?y({tagline:S,globals:b,subtrees:B(s,_())}):null}n(Q,"resolveCoreRoot");async function V(){const e=await C(),[{buildExternalCommandSnapshot:t},{composeExternalSubtrees:r,composeSandboxProviderSubtrees:o},{qualifiedTopLevelCommandName:s}]=await Promise.all([import("./core/command-plugins/discovery.js"),import("./core/command-plugins/compose.js"),import("./core/command-manifests/registry.js")]),a=await A(),c=await M(e,a,g(e)),i=t(new Set(m),void 0,void 0,g(e),a);let l=r(i);if(E()||q()){const{cliClient:h}=await import("./commands/api-client.js");p("cli.providers.request");const{providers:w}=await h().request("GET","/v1/providers/tools");p("cli.providers.fetched",{providers:w.length});const f=o(w,new Set(m)),d=new Set(f.map(u=>u.name));l=[...f,...r({...i,contributions:i.contributions.map(u=>d.has(u.node.name)?{...u,node:{...u.node,name:s(u.contributor,u.node.name)}}:u)})]}return y({tagline:S,globals:b,subtrees:[...B(j(c),_()),...l]})}n(V,"buildRoot");export{$ as EXTENSIBLE_CORE_BRANCHES,m as SUBTREE_NAMES,V as buildRoot,ae as coreCommandPaths,ie as coreCommandPathsCovering,se as coreHookCatalog,ce as declaredExtensibleCoreBranches,A as extensibleCoreBranches,le as isDaemonControlInvocation,de as isJoinInvocation,me as isLayoutMigrationInvocation,ue as personOnlyInvocation,Q as resolveCoreRoot,pe as resolveDaemonControlRoot,fe as resolveLayoutMigrationRoot,ge as resolveRoot};
@@ -21,7 +21,7 @@ Changes to `@north-light/sdk` that can change what an existing app sees. Newest
21
21
 
22
22
  On a cloud role, `provider.tools` now reports a granted provider as `available` once its bundle is installed in the deployment's shared plugin directory. It no longer answers `500` when a person has no materialized bundle; a granted provider still being installed reports `installing` or `install_failed`. Providers without that person's grant remain hidden. The Mac's plugin settings and provider tools behavior are unchanged.
23
23
 
24
- ## Next release
24
+ ## 0.3.579
25
25
 
26
26
  A turn that ends because every model route is rate-limited for longer than a turn waits now reports `error.code: 'rate_limited'` with `error.retry_at` (ISO time the limit is expected to lift), on `turn.completed` and `runs.get().last_turn_error`. It was `model_error` with the time only inside `message`. The run stays `idle` and usable, as before. An app that matches `error.code` exhaustively should handle the new value; one that treats any other code as a model error needs no change.
27
27
 
@@ -13,7 +13,7 @@ surfaces:
13
13
 
14
14
  Everything on the canvas — documents, nodes, jobs, owners, custom objects — is an **object** in one SQLite database; see [[internal]] for the object model. Two places on disk hold the rest: the **scope root**, for configuration and prepared content that is files by nature, and the **canvas home**, for the database and per-node runtime files. This is the routing contract; precise resolver behavior lives in `src/core/scope.ts` and `src/core/canvas/paths.ts`.
15
15
 
16
- Documents are not a third place. A document is an object row in `canvas.db` plus a content-addressed body (a package document — crtr's own or a plugin's — keeps its body in its package file, read through `source_path`); who may read it comes from its privacy (`public` or `private`), the app's schema and its relation facts (`crtr doc write --owner -h`), not from a directory. Do not look for documents on disk, and do not write one as a file: use `crtr doc write`, and read with `crtr canvas read`.
16
+ Documents are not a third place. A document is an object row in `canvas.db` plus a content-addressed body, a row in the `bodies` table (a package document — crtr's own or a plugin's — is the same; its `source_path` only records where it shipped from and marks it read-only); who may read it comes from its privacy (`public` or `private`), the app's schema and its relation facts (`crtr doc write --owner -h`), not from a directory. Do not look for documents on disk, and do not write one as a file: use `crtr doc write`, and read with `crtr canvas read`.
17
17
 
18
18
  ## 1. Scope root — configuration and prepared content
19
19
 
@@ -25,7 +25,7 @@ User-wide content with no cwd dimension also belongs here: `~/.crouter/profile-d
25
25
 
26
26
  ## 2. Canvas home — the object database, per-node files, and bounded diagnostics
27
27
 
28
- `~/.crouter/canvas/` (overridable with `CRTR_HOME`) is the cwd-agnostic node-graph home. `canvas.db` is the SQLite WAL store for every object and its edges, watches, events and rules, including durable tmux-pane focus. `nodes/<node_id>/` owns `meta.json`, `context/` (the node's context directory: scripts, data, logs and page modules — files only, not a way to share writing), `messages/`, `inbox.jsonl`, `transcript.jsonl`, `session.ptr`, and `job/` state. Human ticket files (`page.json`, `page.tsx`, `page.js`, optional `reply-route.json`, `action.json`, `response.json`, `review.json`, and `branch-point.jsonl`) live under `nodes/`, the single derived ticket root. A ticket is not owned by a node: reply-bearing tickets target the bridge recorded in `reply-route.json`, while a ticket created programmatically has no bridge and outlives the process that created it. `action.json` is the frozen action binding — the declared `humanActions` name, its resolved argv and cwd, and the opaque payload — written once at creation and never rewritten, so a later config edit cannot redirect an existing request. Whichever writer wins settlement is the one that queues delivery; the attempt schedule itself is crtrd scheduling state in `canvas.db`, not a ticket file, and delivery never rewrites the ticket's terminal result. Runtime-authored document bodies are content-addressed files under `bodies/`; a package document (crtr's own or a plugin's) keeps its body in its package file, read through `source_path`. All records, revisions, delivery rules, edges and watches are rows in `canvas.db`. A repo-owned document also travels on the repo's git ref `refs/crtr/docs` (one JSON file per document), which is how collaborators receive it; the checkout's working tree never holds it.
28
+ `~/.crouter/canvas/` (overridable with `CRTR_HOME`) is the cwd-agnostic node-graph home. `canvas.db` is the SQLite WAL store for every object and its edges, watches, events and rules, including durable tmux-pane focus. `nodes/<node_id>/` owns `meta.json`, `context/` (the node's context directory: scripts, data, logs and page modules — files only, not a way to share writing), `messages/`, `inbox.jsonl`, `transcript.jsonl`, `session.ptr`, and `job/` state. Human ticket files (`page.json`, `page.tsx`, `page.js`, optional `reply-route.json`, `action.json`, `response.json`, `review.json`, and `branch-point.jsonl`) live under `nodes/`, the single derived ticket root. A ticket is not owned by a node: reply-bearing tickets target the bridge recorded in `reply-route.json`, while a ticket created programmatically has no bridge and outlives the process that created it. `action.json` is the frozen action binding — the declared `humanActions` name, its resolved argv and cwd, and the opaque payload — written once at creation and never rewritten, so a later config edit cannot redirect an existing request. Whichever writer wins settlement is the one that queues delivery; the attempt schedule itself is crtrd scheduling state in `canvas.db`, not a ticket file, and delivery never rewrites the ticket's terminal result. Document text, including a package document's, is a content-addressed row in the `bodies` table keyed by the revision's `body_hash`; the old `bodies/` files on a Mac remain only for rollback. All records, revisions, delivery rules, edges and watches are rows in `canvas.db`. A repo-owned document also travels on the repo's git ref `refs/crtr/docs` (one JSON file per document), which is how collaborators receive it; the checkout's working tree never holds it.
29
29
 
30
30
  A specification, plan or report is a document its node owns, named `<node-id>/<name>` and shared by `[[pointer]]`. It is deleted with that node unless a kept document links to it or it is given another owner (`crtr doc move --owner`).
31
31