@north-light/crouter 0.3.354 → 0.3.355

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 (56) hide show
  1. package/dist/api/dto/docs.d.ts +2 -0
  2. package/dist/api/dto/objects.d.ts +1 -0
  3. package/dist/api/dto/reviews.d.ts +6 -4
  4. package/dist/builtin-memory/02-turn-lifecycle/02-resident.md +1 -0
  5. package/dist/builtin-memory/04-orchestration-kernel.md +10 -31
  6. package/dist/builtin-memory/internal/memory-loading.md +1 -1
  7. package/dist/clients/attach/overlays/file-review.d.ts +1 -0
  8. package/dist/clients/attach/overlays/file-review.js +2 -2
  9. package/dist/clients/attach/render/chat-view.d.ts +6 -0
  10. package/dist/clients/attach/render/chat-view.js +2 -2
  11. package/dist/clients/attach/render/doc-links.d.ts +34 -0
  12. package/dist/clients/attach/render/doc-links.js +1 -0
  13. package/dist/clients/attach/render/markdown-source.js +5 -5
  14. package/dist/clients/attach/session/doc-materialize.d.ts +53 -0
  15. package/dist/clients/attach/session/doc-materialize.js +3 -0
  16. package/dist/clients/attach/session/document-links.d.ts +21 -0
  17. package/dist/clients/attach/session/document-links.js +1 -0
  18. package/dist/clients/attach/session/file-links.d.ts +2 -0
  19. package/dist/clients/attach/session/file-links.js +1 -1
  20. package/dist/clients/attach/viewer.js +622 -620
  21. package/dist/clients/inbox/review/review-client.d.ts +5 -1
  22. package/dist/clients/inbox/review/review-client.js +1 -1
  23. package/dist/commands/canvas/read.js +4 -4
  24. package/dist/commands/doc/write.js +1 -1
  25. package/dist/commands/node/lifecycle.js +2 -2
  26. package/dist/core/graph/deletion.d.ts +5 -4
  27. package/dist/core/graph/deletion.js +3 -3
  28. package/dist/core/graph/documents.d.ts +8 -1
  29. package/dist/core/graph/documents.js +9 -6
  30. package/dist/core/graph/edges.d.ts +3 -2
  31. package/dist/core/graph/edges.js +1 -1
  32. package/dist/core/graph/events.d.ts +2 -2
  33. package/dist/core/graph/events.js +5 -4
  34. package/dist/core/graph/names.d.ts +3 -1
  35. package/dist/core/graph/names.js +3 -3
  36. package/dist/core/graph/repo-sync/exchange.js +2 -2
  37. package/dist/core/runs/operations.js +5 -5
  38. package/dist/core/runtime/broker-persona-guidance.js +2 -2
  39. package/dist/core/runtime/persona.js +2 -2
  40. package/dist/core/runtime/roadmap.d.ts +3 -0
  41. package/dist/core/runtime/roadmap.js +8 -4
  42. package/dist/core/substrate/delivery/deliver.js +1 -1
  43. package/dist/core/substrate/delivery/listings.d.ts +3 -0
  44. package/dist/core/substrate/delivery/listings.js +5 -2
  45. package/dist/core/substrate/delivery/render-boot.js +26 -26
  46. package/dist/core/substrate/delivery/render-event.d.ts +13 -6
  47. package/dist/core/substrate/delivery/render-event.js +6 -4
  48. package/dist/daemon/api/handlers/docs.js +1 -1
  49. package/dist/daemon/api/handlers/objects.js +5 -5
  50. package/dist/daemon/api/handlers/reviews.d.ts +4 -1
  51. package/dist/daemon/api/handlers/reviews.js +1 -1
  52. package/dist/shared/inbox-entry-body.js +7 -7
  53. package/package.json +2 -2
  54. package/packages/crouter-identity/package.json +1 -1
  55. package/runtime.lock.json +11 -11
  56. package/scripts/lib/isolation-env.mjs +8 -2
@@ -1,12 +1,12 @@
1
- var de=Object.defineProperty;var m=(e,t)=>de(e,"name",{value:t,configurable:!0});import{createHash as ae}from"node:crypto";import{SessionManager as ce}from"@earendil-works/pi-coding-agent";import{covers as L}from"@north-light/crouter-identity";import{openDb as ue,withCanvasWrite as H}from"../canvas/db.js";import{repairRunConversations as W}from"../canvas/sessions.js";import{getNode as h,nodeFiles as me,removeNodeFiles as pe,updateNode as _e}from"../canvas/canvas.js";import{fullName as le}from"../canvas/labels.js";import{renameWindow as fe}from"../runtime/placement.js";import{liveExecutionForNode as q}from"../canvas/executions.js";import{conversationStore as U,isConversationNotFound as Ee}from"../conversation-store/index.js";import{enqueueNodeMail as ge}from"../feed/messages.js";import{newestReportBody as we}from"../feed/reports.js";import{ensureAppProfile as Re,loadExactProfileManifest as ye}from"../profiles/manifest.js";import{stopNodeSandboxes as B}from"../spaces/stop.js";import{BrokerUnreachableError as he}from"../runtime/broker-request.js";import{interruptLive as Se}from"../runtime/interactive-deliver.js";import{isBrokerLive as P}from"../runtime/model-swap.js";import{newNodeId as Ne}from"../runtime/nodes.js";import{writeGoal as ve}from"../runtime/kickoff.js";import{reviveNode as J}from"../runtime/revive.js";import{spawnChildPrepared as Oe}from"../runtime/spawn.js";import{resolveRunKind as Te}from"../runtime/launch-target.js";import{cycleAwareMessages as be}from"../runtime/session-cycles.js";import{originFor as j}from"../runtime/stamp/protocol.js";import{readOutputResult as De}from"../runtime/structured-output.js";import{toRunOutcomeDTO as Me}from"../../daemon/api/map.js";import{openAssistantMessageStartSequence as Le}from"../../daemon/runs/observer.js";import{closeNode as $}from"../runtime/close.js";import{parseScope as Ae}from"@north-light/crouter-identity";import{appendRunEvent as G,subscribeRunEvents as Ce}from"./events.js";import{cancelOpenQuestions as Y,openQuestionIds as X}from"./questions.js";import{appSpace as Ie}from"../layout.js";import{ensureAppSpace as ke}from"../spaces/space.js";import{assertUploadsUsable as z,resolveStorageUrls as Fe}from"../storage/attachments.js";import{storageClient as xe,storageConfig as He}from"../storage/client.js";import{deleteUploadRow as We,insertUploadUses as Q,releaseRunUploads as qe}from"../storage/tables.js";const V=m((e,t,r)=>Fe(t,e,r),"defaultResolver"),Ue=3e3;function Tt(e){return Number(e.prepare("UPDATE idempotency_keys SET grantee = 'app:terminal' WHERE grantee = 'user:local'").run().changes)}m(Tt,"rewriteLocalIdempotencyGrantee");class R extends Error{static{m(this,"RunError")}status;code;param;details;scope;retryable;constructor(t,r,n,d,a,i,s=t===503){super(n),this.status=t,this.code=r,this.param=d,this.details=a,this.scope=i,this.retryable=s}}const b=m((e,t)=>new R(400,"invalid_request",e,t),"invalid"),I=m(()=>new R(404,"not_found","run not found"),"missing"),k=m(()=>({input_tokens:0,output_tokens:0,cache_read_tokens:0,cache_write_tokens:0,cost_usd:0}),"usage"),S=m(()=>ue(),"db");function A(e,t,r=!1){const n=h(e);if(!n||n.parent!==null||n.run_id!==e||n.grantee!==t||!r&&n.deleting_at)throw I();return n}m(A,"ownedRun");const F=["waiting_on_user","idle","settled"];function D(e){if(e.status==="canceled"||e.status==="dead"||e.status==="done"&&e.intent!=="parked")return"settled";const t=S().prepare(`SELECT 1 FROM node_rows n WHERE n.run_id = ? AND n.status = 'active' AND
1
+ var ae=Object.defineProperty;var p=(e,t)=>ae(e,"name",{value:t,configurable:!0});import{createHash as de}from"node:crypto";import{SessionManager as ce}from"@earendil-works/pi-coding-agent";import{covers as M}from"@north-light/crouter-identity";import{openDb as ue,withCanvasWrite as W}from"../canvas/db.js";import{deleteNodeWithOwned as me}from"../graph/deletion.js";import{getById as pe}from"../graph/objects.js";import{repairRunConversations as H}from"../canvas/sessions.js";import{getNode as h,nodeFiles as le,removeNodeFiles as _e,updateNode as fe}from"../canvas/canvas.js";import{fullName as Ee}from"../canvas/labels.js";import{renameWindow as ge}from"../runtime/placement.js";import{liveExecutionForNode as q}from"../canvas/executions.js";import{conversationStore as U,isConversationNotFound as we}from"../conversation-store/index.js";import{enqueueNodeMail as ye}from"../feed/messages.js";import{newestReportBody as Re}from"../feed/reports.js";import{ensureAppProfile as he,loadExactProfileManifest as Se}from"../profiles/manifest.js";import{stopNodeSandboxes as B}from"../spaces/stop.js";import{BrokerUnreachableError as Ne}from"../runtime/broker-request.js";import{interruptLive as ve}from"../runtime/interactive-deliver.js";import{isBrokerLive as P}from"../runtime/model-swap.js";import{newNodeId as Oe}from"../runtime/nodes.js";import{writeGoal as Te}from"../runtime/kickoff.js";import{reviveNode as $}from"../runtime/revive.js";import{spawnChildPrepared as be}from"../runtime/spawn.js";import{resolveRunKind as De}from"../runtime/launch-target.js";import{cycleAwareMessages as Ae}from"../runtime/session-cycles.js";import{originFor as j}from"../runtime/stamp/protocol.js";import{readOutputResult as Me}from"../runtime/structured-output.js";import{toRunOutcomeDTO as Le}from"../../daemon/api/map.js";import{openAssistantMessageStartSequence as Ce}from"../../daemon/runs/observer.js";import{closeNode as J}from"../runtime/close.js";import{parseScope as Ie}from"@north-light/crouter-identity";import{appendRunEvent as G,subscribeRunEvents as ke}from"./events.js";import{cancelOpenQuestions as Y,openQuestionIds as X}from"./questions.js";import{appSpace as xe}from"../layout.js";import{ensureAppSpace as Fe}from"../spaces/space.js";import{assertUploadsUsable as z,resolveStorageUrls as We}from"../storage/attachments.js";import{storageClient as He,storageConfig as qe}from"../storage/client.js";import{deleteUploadRow as Ue,insertUploadUses as Q,releaseRunUploads as Be}from"../storage/tables.js";const V=p((e,t,r)=>We(t,e,r),"defaultResolver"),Pe=3e3;function Mt(e){return Number(e.prepare("UPDATE idempotency_keys SET grantee = 'app:terminal' WHERE grantee = 'user:local'").run().changes)}p(Mt,"rewriteLocalIdempotencyGrantee");class y extends Error{static{p(this,"RunError")}status;code;param;details;scope;retryable;constructor(t,r,n,a,d,i,s=t===503){super(n),this.status=t,this.code=r,this.param=a,this.details=d,this.scope=i,this.retryable=s}}const b=p((e,t)=>new y(400,"invalid_request",e,t),"invalid"),I=p(()=>new y(404,"not_found","run not found"),"missing"),k=p(()=>({input_tokens:0,output_tokens:0,cache_read_tokens:0,cache_write_tokens:0,cost_usd:0}),"usage"),S=p(()=>ue(),"db");function L(e,t,r=!1){const n=h(e);if(!n||n.parent!==null||n.run_id!==e||n.grantee!==t||!r&&n.deleting_at)throw I();return n}p(L,"ownedRun");const x=["waiting_on_user","idle","settled"];function D(e){if(e.status==="canceled"||e.status==="dead"||e.status==="done"&&e.intent!=="parked")return"settled";const t=S().prepare(`SELECT 1 FROM node_rows n WHERE n.run_id = ? AND n.status = 'active' AND
2
2
  (n.last_settled_at IS NULL OR EXISTS (
3
3
  SELECT 1 FROM run_events e WHERE e.run_id = ? AND e.node_id = n.node_id AND e.type = 'node.turn.started'
4
4
  AND e.sequence_number > COALESCE((SELECT MAX(c.sequence_number) FROM run_events c
5
5
  WHERE c.run_id = e.run_id AND c.node_id = e.node_id AND c.type = 'node.turn.completed'), 0)
6
- )) LIMIT 1`).get(e.node_id,e.node_id),r=S().prepare("SELECT 1 FROM deliveries WHERE destination_kind = 'node_inbox' AND destination_id IN (SELECT node_id FROM nodes WHERE run_id = ?) AND state IN ('armed', 'pending') AND wake = 1 LIMIT 1").get(e.node_id);return t||r||!e.last_settled_at?"running":X(e.node_id).length?"waiting_on_user":"idle"}m(D,"runStatus");function M(e){W(e.node_id),e=h(e.node_id)??e;const t=D(e),r=t==="settled"?[]:X(e.node_id),n=we(e.node_id)||void 0,d=t==="settled"?Me(e):null,a=d?.kind==="result"?De(e.node_id,e.grantee):void 0;return{run_id:e.node_id,name:e.name,status:t,...d?{outcome:d}:{},...a===void 0?{}:{result:a},...n!==void 0?{last_report:n}:{},pending_question_ids:r,usage:JSON.parse(e.usage_json??JSON.stringify(k())),payer:"user",scopes:e.scopes,metadata:e.metadata_json?JSON.parse(e.metadata_json):{},created_at:e.created,...t==="settled"&&e.outcome_at?{settled_at:e.outcome_at}:{},latest_sequence:(e.event_cursor??1)-1,last_activity_at:e.last_activity_at}}m(M,"runObject");async function bt(e,t,r,n=V){const d=ae("sha256").update(JSON.stringify(t)).digest("hex");if(r){const c=S().prepare("SELECT body_hash, run_id, response_json, created_at FROM idempotency_keys WHERE grantee = ? AND key = ?").get(e.grantee,r);if(c&&Date.now()-Date.parse(c.created_at)<864e5){if(c.body_hash!==d)throw new R(409,"idempotency_conflict","key used with a different request");const E=A(c.run_id,e.grantee);return!E.pi_pid&&D(E)==="running"&&await J(E.node_id,{resume:!0,capacity:"freeze"}),JSON.parse(c.response_json)}}await ke(e.grantee);const a=t.profile===void 0?Re(e.grantee):ye(t.profile),i=a.manifest.grantee??"app:terminal";if(i!==e.grantee){const c=`crtr:memory:rw:${i}:profile:${a.profileId}`;if(!e.resolved.some(E=>L(E,c))||t.scopes!==null&&!t.scopes.some(E=>L(E,c)))throw new R(403,"scope_missing",`missing scope ${c}`,"profile",void 0,c)}const s=Ne(),o=await n(s,e.grantee,t.prompt),_=o.text;let f;try{await Oe({kind:Te(a),mode:"base",root:!0,rootLifecycle:"resident",readiness:"launch",cwd:Ie(e.grantee).files,profile:a.profileId,prompt:_,nodeId:s,...t.scopes===null?{}:{scopes:t.scopes},run:{grantee:e.grantee,sub:e.sub,grant_id:e.grant,client_id:e.client_id,metadata_json:JSON.stringify(t.metadata),run_id:s,event_cursor:1,usage_json:JSON.stringify(k())},withinCreate:m((c,E)=>{o.uses.length&&(z(e.grantee,o.uses,c),Q(o.uses.map(({upload_id:p,path:g})=>({upload_id:p,path:g,run_id:s})),c)),ve(s,_),f={run_id:s,node_id:s,grantee:e.grantee,grant:e.grant,rev:e.rev,scopes:t.scopes,payer:"user",status:"running",created_at:E.created,metadata:t.metadata,sequence_number:0},G(c,s,s,"run.started",{served_model:E.launch?.model??null,scopes:t.scopes,payer:"user",usage:k()}),r&&(c.prepare("DELETE FROM idempotency_keys WHERE grantee = ? AND key = ? AND created_at <= ?").run(e.grantee,r,new Date(Date.now()-864e5).toISOString()),c.prepare("INSERT INTO idempotency_keys (grantee, key, body_hash, run_id, response_json, created_at) VALUES (?, ?, ?, ?, ?, ?)").run(e.grantee,r,d,s,JSON.stringify(f),E.created))},"withinCreate")})}catch(c){throw h(s)||o.cleanup(),c}if(!f)throw new Error("run creation did not commit");return f}m(bt,"startRun");function Dt(e,t){let r;if(t.after)try{const s=JSON.parse(Buffer.from(t.after,"base64url").toString());if(!s||typeof s!="object"||!("activity"in s)||typeof s.activity!="string"||!("id"in s)||typeof s.id!="string")throw new Error("invalid cursor");r={activity:s.activity,id:s.id}}catch{throw b("invalid list cursor","after")}const d=S().prepare(`SELECT node_id, COALESCE(last_activity_at, created) AS activity FROM node_rows
6
+ )) LIMIT 1`).get(e.node_id,e.node_id),r=S().prepare("SELECT 1 FROM deliveries WHERE destination_kind = 'node_inbox' AND destination_id IN (SELECT node_id FROM nodes WHERE run_id = ?) AND state IN ('armed', 'pending') AND wake = 1 LIMIT 1").get(e.node_id);return t||r||!e.last_settled_at?"running":X(e.node_id).length?"waiting_on_user":"idle"}p(D,"runStatus");function A(e){H(e.node_id),e=h(e.node_id)??e;const t=D(e),r=t==="settled"?[]:X(e.node_id),n=Re(e.node_id)||void 0,a=t==="settled"?Le(e):null,d=a?.kind==="result"?Me(e.node_id,e.grantee):void 0;return{run_id:e.node_id,name:e.name,status:t,...a?{outcome:a}:{},...d===void 0?{}:{result:d},...n!==void 0?{last_report:n}:{},pending_question_ids:r,usage:JSON.parse(e.usage_json??JSON.stringify(k())),payer:"user",scopes:e.scopes,metadata:e.metadata_json?JSON.parse(e.metadata_json):{},created_at:e.created,...t==="settled"&&e.outcome_at?{settled_at:e.outcome_at}:{},latest_sequence:(e.event_cursor??1)-1,last_activity_at:e.last_activity_at}}p(A,"runObject");async function Lt(e,t,r,n=V){const a=de("sha256").update(JSON.stringify(t)).digest("hex");if(r){const c=S().prepare("SELECT body_hash, run_id, response_json, created_at FROM idempotency_keys WHERE grantee = ? AND key = ?").get(e.grantee,r);if(c&&Date.now()-Date.parse(c.created_at)<864e5){if(c.body_hash!==a)throw new y(409,"idempotency_conflict","key used with a different request");const _=L(c.run_id,e.grantee);return!_.pi_pid&&D(_)==="running"&&await $(_.node_id,{resume:!0,capacity:"freeze"}),JSON.parse(c.response_json)}}await Fe(e.grantee);const d=t.profile===void 0?he(e.grantee):Se(t.profile),i=d.manifest.grantee??"app:terminal";if(i!==e.grantee){const c=`crtr:memory:rw:${i}:profile:${d.profileId}`;if(!e.resolved.some(_=>M(_,c))||t.scopes!==null&&!t.scopes.some(_=>M(_,c)))throw new y(403,"scope_missing",`missing scope ${c}`,"profile",void 0,c)}const s=Oe(),o=await n(s,e.grantee,t.prompt),l=o.text;let E;try{await be({kind:De(d),mode:"base",root:!0,rootLifecycle:"resident",readiness:"launch",cwd:xe(e.grantee).files,profile:d.profileId,prompt:l,nodeId:s,...t.scopes===null?{}:{scopes:t.scopes},run:{grantee:e.grantee,sub:e.sub,grant_id:e.grant,client_id:e.client_id,metadata_json:JSON.stringify(t.metadata),run_id:s,event_cursor:1,usage_json:JSON.stringify(k())},withinCreate:p((c,_)=>{o.uses.length&&(z(e.grantee,o.uses,c),Q(o.uses.map(({upload_id:m,path:g})=>({upload_id:m,path:g,run_id:s})),c)),Te(s,l),E={run_id:s,node_id:s,grantee:e.grantee,grant:e.grant,rev:e.rev,scopes:t.scopes,payer:"user",status:"running",created_at:_.created,metadata:t.metadata,sequence_number:0},G(c,s,s,"run.started",{served_model:_.launch?.model??null,scopes:t.scopes,payer:"user",usage:k()}),r&&(c.prepare("DELETE FROM idempotency_keys WHERE grantee = ? AND key = ? AND created_at <= ?").run(e.grantee,r,new Date(Date.now()-864e5).toISOString()),c.prepare("INSERT INTO idempotency_keys (grantee, key, body_hash, run_id, response_json, created_at) VALUES (?, ?, ?, ?, ?, ?)").run(e.grantee,r,a,s,JSON.stringify(E),_.created))},"withinCreate")})}catch(c){throw h(s)||o.cleanup(),c}if(!E)throw new Error("run creation did not commit");return E}p(Lt,"startRun");function Ct(e,t){let r;if(t.after)try{const s=JSON.parse(Buffer.from(t.after,"base64url").toString());if(!s||typeof s!="object"||!("activity"in s)||typeof s.activity!="string"||!("id"in s)||typeof s.id!="string")throw new Error("invalid cursor");r={activity:s.activity,id:s.id}}catch{throw b("invalid list cursor","after")}const a=S().prepare(`SELECT node_id, COALESCE(last_activity_at, created) AS activity FROM node_rows
7
7
  WHERE run_id = node_id AND deleting_at IS NULL ${e===null?"":"AND grantee = ?"}
8
- ORDER BY activity DESC, node_id DESC`).all(...e===null?[]:[e]).filter(({activity:s,node_id:o})=>!r||s<r.activity||s===r.activity&&o<r.id).map(s=>({root:h(s.node_id),activity:s.activity})).filter(({root:s})=>!t.status||D(s)===t.status),a=d.slice(0,t.limit),i=a.at(-1);return{runs:a.map(({root:s})=>M(s)),next:d.length>t.limit&&i?Buffer.from(JSON.stringify({activity:i.activity,id:i.root.node_id})).toString("base64url"):null}}m(Dt,"listRuns");async function Mt(e,t,r){const n=A(e,t),d=m(()=>M(A(e,t)),"read");return!r||F.includes(D(n))?d():new Promise((a,i)=>{const s=m(()=>{clearTimeout(f),clearInterval(_),o();try{a(d())}catch(c){i(c)}},"finish"),o=Ce(e,()=>{try{F.includes(String(d().status))&&s()}catch(c){clearTimeout(f),clearInterval(_),o(),i(c)}}),_=setInterval(()=>{F.includes(String(d().status))&&s()},250),f=setTimeout(s,r*1e3)})}m(Mt,"waitRun");async function Lt(e,t,r=V){if(e.status==="canceled"||e.outcome_reason==="closed")throw new R(409,"run_settled","canceled run cannot receive a message");const n=e.grantee??"app:terminal",d=await r(e.node_id,n,t),a=d.text;let i;try{if(e.final_report&&!e.pi_pid){const{commitReopenResident:o}=await import("../runtime/reopen.js");o(e.node_id)}i=ge(e.node_id,{kind:"message",label:a.slice(0,120),senderNodeId:"human",bodyJson:{body:a},urgency:"normal",wake:1,withinEnqueue:m((o,_)=>{d.uses.length&&(z(n,d.uses,o),Q(d.uses.map(({upload_id:f,path:c})=>({upload_id:f,path:c,run_id:e.node_id})),o)),G(o,e.node_id,e.node_id,"node.message.accepted",{message_id:_})},"withinEnqueue")})}catch(o){throw d.cleanup(),o}const s=S().prepare("SELECT event_cursor FROM nodes WHERE node_id = ?").get(e.node_id).event_cursor-1;return e.pi_pid||await J(e.node_id,{resume:!0,capacity:"freeze"}),{run_id:e.node_id,message_id:i.messageId,sequence_number:s}}m(Lt,"messageRun");async function Be(e){const t=m(()=>new R(503,"server_error",`node ${e} broker was unavailable before the interrupt reached it`),"unavailable");for(let r=0;r<2;r++){const n=h(e);if(!n)throw I();if(!P(n)){if(n.streaming)throw t();return}const d=q(e)?.executionId;try{await Se(e);return}catch(a){if(!(a instanceof he))throw a;const i=h(e);if(!i)throw I();if(!i.streaming)return;if(r===0&&P(i)&&q(e)?.executionId!==d)continue;throw t()}}throw t()}m(Be,"interruptNode");async function At(e,t="stop"){const r=t==="stop"?S().prepare("SELECT node_id FROM nodes WHERE run_id = ?").all(e.node_id).map(({node_id:n})=>n):[e.node_id];return await Promise.all(r.map(n=>Be(n))),M(h(e.node_id)??e)}m(At,"interruptRun");async function Ct(e,t={}){const r=S().prepare("SELECT node_id FROM nodes WHERE run_id = ? ORDER BY created DESC").all(e.node_id).map(i=>i.node_id),n=[];if(D(e)!=="settled")n.push(...$(e.node_id,{preserveEmpty:!0,stopReason:"run_canceled"}).closed);else for(const i of r){if(i===e.node_id)continue;const s=h(i);s&&s.status!=="done"&&s.status!=="canceled"&&s.status!=="dead"&&n.push(...$(i,{preserveEmpty:!0,stopReason:"run_canceled"}).closed)}if(await Y({run_id:e.node_id},"the run was canceled"),(await Promise.all([...new Set([e.node_id,...n])].map(i=>B(i,"run_canceled")))).some(i=>!i.confirmed))throw new R(500,"server_error","run process teardown could not be confirmed",void 0,void 0,void 0,!0);const a=h(e.node_id);return M(a??e)}m(Ct,"cancelRun");const Z=200;function It(e,t){if(typeof t!="string"||!t.trim())throw b("name is required","name");const r=t.trim();if(r.length>Z)throw b(`name exceeds ${Z} characters`,"name");const n=_e(e.node_id,{name:r});return n.window&&fe(n.window,le(n)),M(n)}m(It,"renameRun");async function kt(e,t={config:He,client:xe}){await Y({run_id:e.node_id},"the run was deleted");const r=H(o=>(o.prepare("UPDATE nodes SET deleting_at = COALESCE(deleting_at, ?) WHERE node_id = ?").run(new Date().toISOString(),e.node_id),o.prepare("SELECT node_id FROM nodes WHERE run_id = ? ORDER BY created DESC").all(e.node_id).map(_=>_.node_id)));if((await Promise.all(r.map(o=>B(o,"run_deleted",{deleting:!0})))).some(o=>!o.confirmed))throw new R(500,"server_error","run process teardown could not be confirmed",void 0,void 0,void 0,!0);const d=r.map(o=>{const _=me(o);if(_.app===null)throw new Error(`run node missing during deletion: ${o}`);return _}),a=S().prepare("SELECT DISTINCT session_id FROM sessions WHERE session_id IS NOT NULL AND node_id IN (SELECT node_id FROM nodes WHERE run_id = ?)").all(e.node_id);for(const{session_id:o}of a)try{U().delete(o)}catch(_){if(!Ee(_))throw _}const i=H(o=>{const _=qe([e.node_id],o);o.prepare("DELETE FROM run_events WHERE run_id = ?").run(e.node_id),o.prepare("DELETE FROM idempotency_keys WHERE run_id = ?").run(e.node_id);const f=o.prepare("SELECT message_id FROM messages WHERE sender_node_id IN (SELECT node_id FROM nodes WHERE run_id = ?) UNION SELECT message_id FROM deliveries WHERE destination_kind = 'node_inbox' AND destination_id IN (SELECT node_id FROM nodes WHERE run_id = ?)").all(e.node_id,e.node_id);o.prepare("DELETE FROM deliveries WHERE destination_kind = 'node_inbox' AND destination_id IN (SELECT node_id FROM nodes WHERE run_id = ?)").run(e.node_id);for(const{message_id:c}of f)o.prepare("DELETE FROM messages WHERE message_id = ? AND NOT EXISTS (SELECT 1 FROM deliveries WHERE message_id = ?)").run(c,c);for(const c of r)o.prepare("DELETE FROM nodes WHERE node_id = ?").run(c);return _});for(const o of d)pe(o);const{notifyRunDeleted:s}=await import("./events.js");return s(e.node_id),{uploads_pending:await Pe(i,t)}}m(kt,"deleteRun");async function Pe(e,t){if(!e.length||!t.config())return e.length;let r;try{r=t.client()}catch{return e.length}const n=new Set,d=e.map(i=>r.deleteUpload(i).then(()=>{We(i),n.add(i)},()=>{}));let a;return await Promise.race([Promise.all(d),new Promise(i=>{a=setTimeout(i,t.budgetMs??Ue),a.unref?.()})]),clearTimeout(a),e.length-n.size}m(Pe,"deleteReleasedUploads");function Ft(e,t,r){A(e,t),W(e);const n=S();n.exec("BEGIN");try{const a=n.prepare("SELECT node_id, parent FROM nodes WHERE run_id = ? ORDER BY CASE WHEN node_id = ? THEN 0 ELSE 1 END, created, node_id").all(e,e).map(p=>({node_id:p.node_id,parent_node_id:p.parent,conversations:n.prepare("SELECT DISTINCT session_id FROM sessions WHERE node_id = ? ORDER BY created_at").all(p.node_id).map(({session_id:g})=>{const{header:v,entries:w}=U().read(g);if(r==="entries")return{conversation_id:g,header:v,entries:w};const K=ce.inMemory(v.cwd,void 0,[v,...w]),ee=be(K)??[],x=new Map(w.map((l,N)=>[l.id,N])),te=w.filter(l=>l.type==="custom"&&l.customType==="crtr-system-prompt").map(l=>({id:l.id,message:{role:"custom",customType:"crtr-system-prompt",data:"data"in l?l.data:void 0,timestamp:l.timestamp}})),ne=p.node_id===e?w.find(l=>{if(l.type!=="message"||l.message.role!=="user")return!1;const N=j(w,l.message.timestamp);return N?.type==="runtime"&&N.kind==="kickoff"})?.id:void 0,re=[...ee,...te].sort((l,N)=>(x.get(l.id)??Number.MAX_SAFE_INTEGER)-(x.get(N.id)??Number.MAX_SAFE_INTEGER)).map(({id:l,message:N})=>{const u=N,O=u.usage,C=u.role==="user"?j(w,Number(u.timestamp)):null,se=C?.type==="human"||l===ne,T=u.role==="toolResult"?"tool_result":u.role==="bashExecution"?"bash_execution":u.role==="compactionSummary"?"compaction_summary":u.role==="branchSummary"?"branch_summary":u.role==="custom"&&u.customType==="crtr-system-prompt"?"system":u.role==="user"?se?"user":"custom":u.role,oe=T==="custom"?u.role==="custom"?u.customType:C?.type==="runtime"?C.kind:"unknown":void 0,ie=T==="system"&&u.customType==="crtr-system-prompt"?[{type:"text",text:u.data?.text??""}]:typeof u.content=="string"?[{type:"text",text:u.content}]:Array.isArray(u.content)?u.content.map(y=>y.type==="toolCall"?{type:"tool_call",tool_call_id:y.id,name:y.name,arguments:y.arguments}:y.type==="image"?{type:"image",mime_type:y.mimeType}:y.type==="thinking"?{type:"thinking",text:y.thinking}:y):[];return{entry_id:l,role:T,...T==="custom"?{custom_type:oe}:{},time:typeof u.timestamp=="string"?u.timestamp:new Date(Number(u.timestamp??Date.now())).toISOString(),content:ie,...T==="assistant"?{model:u.model,provider:u.provider,stop_reason:u.stopReason,...u.errorMessage?{error_message:u.errorMessage}:{},...O?{usage:{input_tokens:O.input??0,output_tokens:O.output??0,cache_read_tokens:O.cacheRead??0,cache_write_tokens:O.cacheWrite??0,cost_usd:O.cost?.total??0}}:{}}:{},...T==="tool_result"?{tool_call_id:u.toolCallId,tool_name:u.toolName,is_error:u.isError}:{}}})??[];return{conversation_id:g,messages:re}})})),s=n.prepare("SELECT event_cursor FROM nodes WHERE node_id = ?").get(e).event_cursor-1,o=new Map(a.map(p=>[p.node_id,Le(p.node_id)])),_=n.prepare(`SELECT node_id, sequence_number FROM run_events
8
+ ORDER BY activity DESC, node_id DESC`).all(...e===null?[]:[e]).filter(({activity:s,node_id:o})=>!r||s<r.activity||s===r.activity&&o<r.id).map(s=>({root:h(s.node_id),activity:s.activity})).filter(({root:s})=>!t.status||D(s)===t.status),d=a.slice(0,t.limit),i=d.at(-1);return{runs:d.map(({root:s})=>A(s)),next:a.length>t.limit&&i?Buffer.from(JSON.stringify({activity:i.activity,id:i.root.node_id})).toString("base64url"):null}}p(Ct,"listRuns");async function It(e,t,r){const n=L(e,t),a=p(()=>A(L(e,t)),"read");return!r||x.includes(D(n))?a():new Promise((d,i)=>{const s=p(()=>{clearTimeout(E),clearInterval(l),o();try{d(a())}catch(c){i(c)}},"finish"),o=ke(e,()=>{try{x.includes(String(a().status))&&s()}catch(c){clearTimeout(E),clearInterval(l),o(),i(c)}}),l=setInterval(()=>{x.includes(String(a().status))&&s()},250),E=setTimeout(s,r*1e3)})}p(It,"waitRun");async function kt(e,t,r=V){if(e.status==="canceled"||e.outcome_reason==="closed")throw new y(409,"run_settled","canceled run cannot receive a message");const n=e.grantee??"app:terminal",a=await r(e.node_id,n,t),d=a.text;let i;try{if(e.final_report&&!e.pi_pid){const{commitReopenResident:o}=await import("../runtime/reopen.js");o(e.node_id)}i=ye(e.node_id,{kind:"message",label:d.slice(0,120),senderNodeId:"human",bodyJson:{body:d},urgency:"normal",wake:1,withinEnqueue:p((o,l)=>{a.uses.length&&(z(n,a.uses,o),Q(a.uses.map(({upload_id:E,path:c})=>({upload_id:E,path:c,run_id:e.node_id})),o)),G(o,e.node_id,e.node_id,"node.message.accepted",{message_id:l})},"withinEnqueue")})}catch(o){throw a.cleanup(),o}const s=S().prepare("SELECT event_cursor FROM nodes WHERE node_id = ?").get(e.node_id).event_cursor-1;return e.pi_pid||await $(e.node_id,{resume:!0,capacity:"freeze"}),{run_id:e.node_id,message_id:i.messageId,sequence_number:s}}p(kt,"messageRun");async function $e(e){const t=p(()=>new y(503,"server_error",`node ${e} broker was unavailable before the interrupt reached it`),"unavailable");for(let r=0;r<2;r++){const n=h(e);if(!n)throw I();if(!P(n)){if(n.streaming)throw t();return}const a=q(e)?.executionId;try{await ve(e);return}catch(d){if(!(d instanceof Ne))throw d;const i=h(e);if(!i)throw I();if(!i.streaming)return;if(r===0&&P(i)&&q(e)?.executionId!==a)continue;throw t()}}throw t()}p($e,"interruptNode");async function xt(e,t="stop"){const r=t==="stop"?S().prepare("SELECT node_id FROM nodes WHERE run_id = ?").all(e.node_id).map(({node_id:n})=>n):[e.node_id];return await Promise.all(r.map(n=>$e(n))),A(h(e.node_id)??e)}p(xt,"interruptRun");async function Ft(e,t={}){const r=S().prepare("SELECT node_id FROM nodes WHERE run_id = ? ORDER BY created DESC").all(e.node_id).map(i=>i.node_id),n=[];if(D(e)!=="settled")n.push(...J(e.node_id,{preserveEmpty:!0,stopReason:"run_canceled"}).closed);else for(const i of r){if(i===e.node_id)continue;const s=h(i);s&&s.status!=="done"&&s.status!=="canceled"&&s.status!=="dead"&&n.push(...J(i,{preserveEmpty:!0,stopReason:"run_canceled"}).closed)}if(await Y({run_id:e.node_id},"the run was canceled"),(await Promise.all([...new Set([e.node_id,...n])].map(i=>B(i,"run_canceled")))).some(i=>!i.confirmed))throw new y(500,"server_error","run process teardown could not be confirmed",void 0,void 0,void 0,!0);const d=h(e.node_id);return A(d??e)}p(Ft,"cancelRun");const Z=200;function Wt(e,t){if(typeof t!="string"||!t.trim())throw b("name is required","name");const r=t.trim();if(r.length>Z)throw b(`name exceeds ${Z} characters`,"name");const n=fe(e.node_id,{name:r});return n.window&&ge(n.window,Ee(n)),A(n)}p(Wt,"renameRun");async function Ht(e,t={config:qe,client:He}){await Y({run_id:e.node_id},"the run was deleted");const r=W(o=>(o.prepare("UPDATE nodes SET deleting_at = COALESCE(deleting_at, ?) WHERE node_id = ?").run(new Date().toISOString(),e.node_id),o.prepare("SELECT node_id FROM nodes WHERE run_id = ? ORDER BY created DESC").all(e.node_id).map(l=>l.node_id)));if((await Promise.all(r.map(o=>B(o,"run_deleted",{deleting:!0})))).some(o=>!o.confirmed))throw new y(500,"server_error","run process teardown could not be confirmed",void 0,void 0,void 0,!0);const a=r.map(o=>{const l=le(o);if(l.app===null)throw new Error(`run node missing during deletion: ${o}`);return l}),d=S().prepare("SELECT DISTINCT session_id FROM sessions WHERE session_id IS NOT NULL AND node_id IN (SELECT node_id FROM nodes WHERE run_id = ?)").all(e.node_id);for(const{session_id:o}of d)try{U().delete(o)}catch(l){if(!we(l))throw l}const i=W(o=>{for(const _ of r){const m=pe(o,_);m!==null&&m.deleted_at===null&&me(o,m)}const l=Be([e.node_id],o);o.prepare("DELETE FROM run_events WHERE run_id = ?").run(e.node_id),o.prepare("DELETE FROM idempotency_keys WHERE run_id = ?").run(e.node_id);const E=r.map(()=>"?").join(","),c=o.prepare(`SELECT message_id FROM messages WHERE sender_node_id IN (${E}) UNION SELECT message_id FROM deliveries WHERE destination_kind = 'node_inbox' AND destination_id IN (${E})`).all(...r,...r);o.prepare(`DELETE FROM deliveries WHERE destination_kind = 'node_inbox' AND destination_id IN (${E})`).run(...r);for(const{message_id:_}of c)o.prepare("DELETE FROM messages WHERE message_id = ? AND NOT EXISTS (SELECT 1 FROM deliveries WHERE message_id = ?)").run(_,_);return l});for(const o of a)_e(o);const{notifyRunDeleted:s}=await import("./events.js");return s(e.node_id),{uploads_pending:await je(i,t)}}p(Ht,"deleteRun");async function je(e,t){if(!e.length||!t.config())return e.length;let r;try{r=t.client()}catch{return e.length}const n=new Set,a=e.map(i=>r.deleteUpload(i).then(()=>{Ue(i),n.add(i)},()=>{}));let d;return await Promise.race([Promise.all(a),new Promise(i=>{d=setTimeout(i,t.budgetMs??Pe),d.unref?.()})]),clearTimeout(d),e.length-n.size}p(je,"deleteReleasedUploads");function qt(e,t,r){L(e,t),H(e);const n=S();n.exec("BEGIN");try{const d=n.prepare("SELECT node_id, parent FROM nodes WHERE run_id = ? ORDER BY CASE WHEN node_id = ? THEN 0 ELSE 1 END, created, node_id").all(e,e).map(m=>({node_id:m.node_id,parent_node_id:m.parent,conversations:n.prepare("SELECT DISTINCT session_id FROM sessions WHERE node_id = ? ORDER BY created_at").all(m.node_id).map(({session_id:g})=>{const{header:v,entries:w}=U().read(g);if(r==="entries")return{conversation_id:g,header:v,entries:w};const K=ce.inMemory(v.cwd,void 0,[v,...w]),ee=Ae(K)??[],F=new Map(w.map((f,N)=>[f.id,N])),te=w.filter(f=>f.type==="custom"&&f.customType==="crtr-system-prompt").map(f=>({id:f.id,message:{role:"custom",customType:"crtr-system-prompt",data:"data"in f?f.data:void 0,timestamp:f.timestamp}})),ne=m.node_id===e?w.find(f=>{if(f.type!=="message"||f.message.role!=="user")return!1;const N=j(w,f.message.timestamp);return N?.type==="runtime"&&N.kind==="kickoff"})?.id:void 0,re=[...ee,...te].sort((f,N)=>(F.get(f.id)??Number.MAX_SAFE_INTEGER)-(F.get(N.id)??Number.MAX_SAFE_INTEGER)).map(({id:f,message:N})=>{const u=N,O=u.usage,C=u.role==="user"?j(w,Number(u.timestamp)):null,se=C?.type==="human"||f===ne,T=u.role==="toolResult"?"tool_result":u.role==="bashExecution"?"bash_execution":u.role==="compactionSummary"?"compaction_summary":u.role==="branchSummary"?"branch_summary":u.role==="custom"&&u.customType==="crtr-system-prompt"?"system":u.role==="user"?se?"user":"custom":u.role,oe=T==="custom"?u.role==="custom"?u.customType:C?.type==="runtime"?C.kind:"unknown":void 0,ie=T==="system"&&u.customType==="crtr-system-prompt"?[{type:"text",text:u.data?.text??""}]:typeof u.content=="string"?[{type:"text",text:u.content}]:Array.isArray(u.content)?u.content.map(R=>R.type==="toolCall"?{type:"tool_call",tool_call_id:R.id,name:R.name,arguments:R.arguments}:R.type==="image"?{type:"image",mime_type:R.mimeType}:R.type==="thinking"?{type:"thinking",text:R.thinking}:R):[];return{entry_id:f,role:T,...T==="custom"?{custom_type:oe}:{},time:typeof u.timestamp=="string"?u.timestamp:new Date(Number(u.timestamp??Date.now())).toISOString(),content:ie,...T==="assistant"?{model:u.model,provider:u.provider,stop_reason:u.stopReason,...u.errorMessage?{error_message:u.errorMessage}:{},...O?{usage:{input_tokens:O.input??0,output_tokens:O.output??0,cache_read_tokens:O.cacheRead??0,cache_write_tokens:O.cacheWrite??0,cost_usd:O.cost?.total??0}}:{}}:{},...T==="tool_result"?{tool_call_id:u.toolCallId,tool_name:u.toolName,is_error:u.isError}:{}}})??[];return{conversation_id:g,messages:re}})})),s=n.prepare("SELECT event_cursor FROM nodes WHERE node_id = ?").get(e).event_cursor-1,o=new Map(d.map(m=>[m.node_id,Ce(m.node_id)])),l=n.prepare(`SELECT node_id, sequence_number FROM run_events
9
9
  WHERE run_id = ? AND sequence_number <= ? AND type IN ('node.thinking.done', 'node.output_text.done', 'usage')
10
- ORDER BY sequence_number`).all(e,s);for(const p of _){const g=o.get(p.node_id);g!=null&&p.sequence_number>=g&&o.set(p.node_id,null)}const f=n.prepare(`SELECT node_id, sequence_number, type, body_json FROM run_events
10
+ ORDER BY sequence_number`).all(e,s);for(const m of l){const g=o.get(m.node_id);g!=null&&m.sequence_number>=g&&o.set(m.node_id,null)}const E=n.prepare(`SELECT node_id, sequence_number, type, body_json FROM run_events
11
11
  WHERE run_id = ? AND sequence_number <= ? AND type IN ('node.thinking.delta', 'node.output_text.delta')
12
- ORDER BY sequence_number`).all(e,s),c=new Map;for(const p of f){const g=o.get(p.node_id);if(g==null||p.sequence_number<g)continue;const v=JSON.parse(p.body_json),w=c.get(p.node_id)??{thinking:"",text:""};p.type==="node.thinking.delta"?w.thinking+=v.delta:w.text+=v.delta,c.set(p.node_id,w)}const E=a.map(p=>({...p,in_progress_message:o.get(p.node_id)==null?null:c.get(p.node_id)??{thinking:"",text:""}}));return n.exec("COMMIT"),{run_id:e,latest_sequence:s,nodes:E}}catch(d){throw n.exec("ROLLBACK"),d}}m(Ft,"traceRun");function xt(e,t,r){if(t===void 0){if(!e.some(n=>L(n,"crtr:llm")))throw new R(403,"scope_missing","missing scope crtr:llm",void 0,void 0,"crtr:llm");return null}if(!Array.isArray(t)||t.some(n=>typeof n!="string"))throw b("scopes must be a list of scope strings","scopes");for(const n of t){try{Ae(n)}catch{throw b(`invalid scope ${n}`,"scopes")}if(/^crtr:files:(?:read|rw):app:/.test(n)&&n.split(":")[4]===r.slice(4))throw b(`own-app files cannot narrow a run: ${n}`,"scopes");if(!(/^crtr:memory:(?:read|rw):app:/.test(n)&&n.split(":")[4]===r.slice(4))&&!e.some(a=>L(a,n)))throw new R(403,"scope_missing",`missing scope ${n}`,void 0,void 0,n)}if(!t.includes("crtr:llm"))throw new R(403,"scope_missing","missing scope crtr:llm",void 0,void 0,"crtr:llm");return t}m(xt,"requestedScopes");export{Ue as RUN_DELETE_STORAGE_BUDGET_MS,Z as RUN_NAME_MAX,R as RunError,Ct as cancelRun,kt as deleteRun,At as interruptRun,Dt as listRuns,Lt as messageRun,A as ownedRun,It as renameRun,xt as requestedScopes,Tt as rewriteLocalIdempotencyGrantee,M as runObject,bt as startRun,Ft as traceRun,Mt as waitRun};
12
+ ORDER BY sequence_number`).all(e,s),c=new Map;for(const m of E){const g=o.get(m.node_id);if(g==null||m.sequence_number<g)continue;const v=JSON.parse(m.body_json),w=c.get(m.node_id)??{thinking:"",text:""};m.type==="node.thinking.delta"?w.thinking+=v.delta:w.text+=v.delta,c.set(m.node_id,w)}const _=d.map(m=>({...m,in_progress_message:o.get(m.node_id)==null?null:c.get(m.node_id)??{thinking:"",text:""}}));return n.exec("COMMIT"),{run_id:e,latest_sequence:s,nodes:_}}catch(a){throw n.exec("ROLLBACK"),a}}p(qt,"traceRun");function Ut(e,t,r){if(t===void 0){if(!e.some(n=>M(n,"crtr:llm")))throw new y(403,"scope_missing","missing scope crtr:llm",void 0,void 0,"crtr:llm");return null}if(!Array.isArray(t)||t.some(n=>typeof n!="string"))throw b("scopes must be a list of scope strings","scopes");for(const n of t){try{Ie(n)}catch{throw b(`invalid scope ${n}`,"scopes")}if(/^crtr:files:(?:read|rw):app:/.test(n)&&n.split(":")[4]===r.slice(4))throw b(`own-app files cannot narrow a run: ${n}`,"scopes");if(!(/^crtr:memory:(?:read|rw):app:/.test(n)&&n.split(":")[4]===r.slice(4))&&!e.some(d=>M(d,n)))throw new y(403,"scope_missing",`missing scope ${n}`,void 0,void 0,n)}if(!t.includes("crtr:llm"))throw new y(403,"scope_missing","missing scope crtr:llm",void 0,void 0,"crtr:llm");return t}p(Ut,"requestedScopes");export{Pe as RUN_DELETE_STORAGE_BUDGET_MS,Z as RUN_NAME_MAX,y as RunError,Ft as cancelRun,Ht as deleteRun,xt as interruptRun,Ct as listRuns,kt as messageRun,L as ownedRun,Wt as renameRun,Ut as requestedScopes,Mt as rewriteLocalIdempotencyGrantee,A as runObject,Lt as startRun,qt as traceRun,It as waitRun};
@@ -1,4 +1,4 @@
1
- var g=Object.defineProperty;var a=(n,e)=>g(n,"name",{value:e,configurable:!0});import{emitEvent as b}from"../events/emit.js";import{brokerDelivery as v,brokerExtensionState as p,commitBrokerPersonaAck as m}from"./broker/daemon-ops.js";import{buildSubPersonaMenu as h}from"../substrate/delivery/sub-persona-menu.js";import{orchestratorContextNote as x}from"./bearings-render.js";import{formatCard as T}from"../../shared/generated-context.js";function C(n){return[`You are now a ${n.kind.toUpperCase()} ORCHESTRATOR. Your scarce resource is your own context window.`,"Your job is to manage context and delegate \u2014 not to do the goal yourself.","","Your roadmap is your document `roadmap`; it loads at every new session of yours. Author it now with `crtr doc edit roadmap`: state the goal, exit criteria, and the phase skeleton, using the approach below.","",x(),"","What promotion changes is how long your documents matter: you now persist across refresh cycles, so the documents you own (`crtr doc write`) carry what this goal needs between your refreshes, and a lesson that should outlive this node gets another owner (`--owner user|repo|profile`).","","Then delegate each phase with `crtr node new --kind <kind>`. When your context fills, run `crtr node yield` to refresh against this roadmap."].join(`
1
+ var g=Object.defineProperty;var a=(n,e)=>g(n,"name",{value:e,configurable:!0});import{emitEvent as b}from"../events/emit.js";import{brokerDelivery as v,brokerExtensionState as p,commitBrokerPersonaAck as m}from"./broker/daemon-ops.js";import{buildSubPersonaMenu as h}from"../substrate/delivery/sub-persona-menu.js";import{orchestratorContextNote as x}from"./bearings-render.js";import{formatCard as T}from"../../shared/generated-context.js";function C(n){return[`You are now a ${n.kind.toUpperCase()} ORCHESTRATOR. Your scarce resource is your own context window.`,"Your job is to manage context and delegate \u2014 not to do the goal yourself.","","Your roadmap is your document `roadmap`; it loads at every new session of yours. Author it now with `crtr doc edit roadmap`: state the goal and exit criteria, and set the preview to the goal\u2019s first line, using the approach below.","",x(),"","What promotion changes is how long your documents matter: you now persist across refresh cycles, so the documents you own (`crtr doc write`) carry what this goal needs between your refreshes, and a lesson that should outlive this node gets another owner (`--owner user|repo|profile`).","","Then delegate each unit with `crtr node new --kind <kind>`. When your context fills, run `crtr node yield` to refresh against this roadmap."].join(`
2
2
  `)}a(C,"orchestrationGuidance");function P(){return"You are HANDS-ON again \u2014 base mode. Do the work yourself in THIS window and finish it here; stop delegating by default. You no longer drive a roadmap, so `crtr node yield` is not your exit. Spawn a child only for a cleanly separable unit, never as your first move."}a(P,"baseModeGuidance");function S(n,e){if(n.kind===e.kind)return"";const r=h(n.kind),o=h(e.kind);return r===o?"":o===""?`The ${e.kind} kind has no specialist sub-personas available.`:o}a(S,"subPersonaGuidance");function D(n,e,r,o){const t=[];return e.mode!==r.mode&&t.push(r.mode==="orchestrator"?C(n.node):P()),t.push(S(e,r)),t.push(o),t.filter(i=>i!=="").join(`
3
3
 
4
- `)}a(D,"transitionGuidance");function u(n){const e=n.node,r={kind:e.kind,mode:e.mode,lifecycle:e.lifecycle},o=e.persona_ack,t=o===void 0?r:{kind:o.kind??e.kind,mode:o.mode,lifecycle:o.lifecycle};return t.kind===r.kind&&t.mode===r.mode&&t.lifecycle===r.lifecycle?null:{from:t,to:r}}a(u,"personaDriftFromBrokerState");async function B(n){const e=u(n);if(e===null)return!1;if(!(await m(n.node.node_id,e)).applied)throw new Error(`persona baseline acknowledgment was rejected for ${n.node.node_id}`);return!0}a(B,"acknowledgePersonaBaseline");async function Y(n,e){const r=n.node.node_id;let o=n,t=u(o);if(t===null)return!1;let i=t.from;for(;;){const s={kind:o.node.kind,mode:o.node.mode,lifecycle:o.node.lifecycle};if(i.kind!==s.kind||i.mode!==s.mode||i.lifecycle!==s.lifecycle){const d=await v(r,{activity:"persona"}),c=D(o,i,s,d.content);c!==""&&await e(T("persona-transition",{},c)),i=s}if(t=u(o),t===null||(await m(r,t)).applied)return!0;o=await p(r)}}a(Y,"deliverPendingPersonaTransition");function H(n,e,r=()=>{}){const{agent:o}=e,t=o.transformContext;o.transformContext=async(i,s)=>{const l=t===void 0?i:await t(i,s);try{const d=await p(n);return await Y(d,c=>{const f={nodeId:n},y={role:"custom",customType:"crtr-persona-transition",content:c,display:!0,details:f,timestamp:Date.now()};e.sessionManager.appendCustomMessageEntry("crtr-persona-transition",c,!0,f);const w=o.state.messages;for(const k of new Set([w,i,l]))k.push(y)}),l}catch(d){throw r(),b({event:"broker.daemon.operation.failed",level:"error",node_id:n,error:d,fields:{operation:"persona_transition"}}),d}}}a(H,"installPersonaTransitionGate");export{B as acknowledgePersonaBaseline,Y as deliverPendingPersonaTransition,H as installPersonaTransitionGate,u as personaDriftFromBrokerState};
4
+ `)}a(D,"transitionGuidance");function u(n){const e=n.node,r={kind:e.kind,mode:e.mode,lifecycle:e.lifecycle},o=e.persona_ack,t=o===void 0?r:{kind:o.kind??e.kind,mode:o.mode,lifecycle:o.lifecycle};return t.kind===r.kind&&t.mode===r.mode&&t.lifecycle===r.lifecycle?null:{from:t,to:r}}a(u,"personaDriftFromBrokerState");async function B(n){const e=u(n);if(e===null)return!1;if(!(await m(n.node.node_id,e)).applied)throw new Error(`persona baseline acknowledgment was rejected for ${n.node.node_id}`);return!0}a(B,"acknowledgePersonaBaseline");async function Y(n,e){const r=n.node.node_id;let o=n,t=u(o);if(t===null)return!1;let i=t.from;for(;;){const s={kind:o.node.kind,mode:o.node.mode,lifecycle:o.node.lifecycle};if(i.kind!==s.kind||i.mode!==s.mode||i.lifecycle!==s.lifecycle){const d=await v(r,{activity:"persona"}),c=D(o,i,s,d.content);c!==""&&await e(T("persona-transition",{},c)),i=s}if(t=u(o),t===null||(await m(r,t)).applied)return!0;o=await p(r)}}a(Y,"deliverPendingPersonaTransition");function H(n,e,r=()=>{}){const{agent:o}=e,t=o.transformContext;o.transformContext=async(i,s)=>{const l=t===void 0?i:await t(i,s);try{const d=await p(n);return await Y(d,c=>{const f={nodeId:n},w={role:"custom",customType:"crtr-persona-transition",content:c,display:!0,details:f,timestamp:Date.now()};e.sessionManager.appendCustomMessageEntry("crtr-persona-transition",c,!0,f);const y=o.state.messages;for(const k of new Set([y,i,l]))k.push(w)}),l}catch(d){throw r(),b({event:"broker.daemon.operation.failed",level:"error",node_id:n,error:d,fields:{operation:"persona_transition"}}),d}}}a(H,"installPersonaTransitionGate");export{B as acknowledgePersonaBaseline,Y as deliverPendingPersonaTransition,H as installPersonaTransitionGate,u as personaDriftFromBrokerState};
@@ -1,2 +1,2 @@
1
- var s=Object.defineProperty;var t=(o,e)=>s(o,"name",{value:e,configurable:!0});import{getNode as i,updateNode as d}from"../canvas/index.js";import{readRoadmap as c}from"./roadmap.js";import{orchestratorContextNote as u}from"./bearings.js";function l(o,e){const r=c(o)??"(no roadmap yet)",n=[`You are now a ${e.toUpperCase()} ORCHESTRATOR. Your scarce resource is your own context window.`,"Your job is to manage context and delegate \u2014 not to do the goal yourself."];return n.push("","Your roadmap is your document `roadmap`; it loads at every new session of yours. Author it now with `crtr doc edit roadmap`: state the goal, exit criteria, and the phase skeleton, using your orchestration protocol. Current contents:","",r,"",u(),"","What promotion changes is how long your documents matter: you now persist across refresh cycles, so the documents you own (`crtr doc write`) carry what this goal needs between your refreshes, and a lesson that should outlive this node gets another owner (`--owner user|repo|profile`).","","Then delegate each phase with `crtr node new --kind <kind>`. When your context fills, run `crtr node yield` to refresh against this roadmap."),n.join(`
2
- `)}t(l,"orchestrationGuidance");function m(){return"You are HANDS-ON again \u2014 base mode. Do the work yourself in THIS window and finish it here; stop delegating by default. You no longer drive a roadmap, so `crtr node yield` is not your exit. Spawn a child only for a cleanly separable unit, never as your first move."}t(m,"baseModeGuidance");function f(o,e,r){if(e.mode===r.mode)return"";if(r.mode==="base")return m();const n=i(o);return l(o,n?.kind??"general")}t(f,"transitionGuidance");function g(o){const e=i(o);if(e===null)return null;const r={kind:e.kind,mode:e.mode,lifecycle:e.lifecycle},n=e.persona_ack,a=n===void 0?r:{kind:n.kind??e.kind,mode:n.mode,lifecycle:n.lifecycle};return a.kind===r.kind&&a.mode===r.mode&&a.lifecycle===r.lifecycle?null:{from:a,to:r,guidance:f(o,a,r)}}t(g,"personaDrift");function k(o,e){d(o,{persona_ack:e})}t(k,"commitPersonaAck");export{k as commitPersonaAck,g as personaDrift,f as transitionGuidance};
1
+ var s=Object.defineProperty;var n=(o,e)=>s(o,"name",{value:e,configurable:!0});import{getNode as i,updateNode as d}from"../canvas/index.js";import{readRoadmap as c}from"./roadmap.js";import{orchestratorContextNote as u}from"./bearings.js";function l(o,e){const r=c(o)??"(no roadmap yet)",t=[`You are now a ${e.toUpperCase()} ORCHESTRATOR. Your scarce resource is your own context window.`,"Your job is to manage context and delegate \u2014 not to do the goal yourself."];return t.push("","Your roadmap is your document `roadmap`; it loads at every new session of yours. Author it now with `crtr doc edit roadmap`: state the goal and exit criteria, and set the preview to the goal\u2019s first line, using your orchestration protocol. Current contents:","",r,"",u(),"","What promotion changes is how long your documents matter: you now persist across refresh cycles, so the documents you own (`crtr doc write`) carry what this goal needs between your refreshes, and a lesson that should outlive this node gets another owner (`--owner user|repo|profile`).","","Then delegate each unit with `crtr node new --kind <kind>`. When your context fills, run `crtr node yield` to refresh against this roadmap."),t.join(`
2
+ `)}n(l,"orchestrationGuidance");function m(){return"You are HANDS-ON again \u2014 base mode. Do the work yourself in THIS window and finish it here; stop delegating by default. You no longer drive a roadmap, so `crtr node yield` is not your exit. Spawn a child only for a cleanly separable unit, never as your first move."}n(m,"baseModeGuidance");function f(o,e,r){if(e.mode===r.mode)return"";if(r.mode==="base")return m();const t=i(o);return l(o,t?.kind??"general")}n(f,"transitionGuidance");function g(o){const e=i(o);if(e===null)return null;const r={kind:e.kind,mode:e.mode,lifecycle:e.lifecycle},t=e.persona_ack,a=t===void 0?r:{kind:t.kind??e.kind,mode:t.mode,lifecycle:t.lifecycle};return a.kind===r.kind&&a.mode===r.mode&&a.lifecycle===r.lifecycle?null:{from:a,to:r,guidance:f(o,a,r)}}n(g,"personaDrift");function k(o,e){d(o,{persona_ack:e})}n(k,"commitPersonaAck");export{k as commitPersonaAck,g as personaDrift,f as transitionGuidance};
@@ -1,6 +1,9 @@
1
1
  import type { DatabaseSync } from 'node:sqlite';
2
2
  export declare const ROADMAP_NAME = "roadmap";
3
+ /** Fallback preview when the roadmap is seeded without a goal. */
3
4
  export declare const ROADMAP_PREVIEW = "To understand this node's long-term task and current plan, read this.";
5
+ /** A roadmap's preview is its goal's first line; the fallback covers a goal-less seed. */
6
+ export declare function roadmapPreview(goal?: string): string;
4
7
  /** How a node addresses its own roadmap in `crtr canvas read` / `crtr doc edit`. */
5
8
  export declare function roadmapRef(nodeId: string): string;
6
9
  export declare function hasRoadmap(nodeId: string): boolean;
@@ -1,4 +1,5 @@
1
- var l=Object.defineProperty;var n=(e,r)=>l(e,"name",{value:r,configurable:!0});import{openDb as u,withCanvasWrite as d}from"../canvas/db.js";import{get as c}from"../graph/bodies.js";import{heads as s,writeDocument as m}from"../graph/documents.js";import{getById as p,liveDocumentNamed as f,nodeObject as h}from"../graph/objects.js";import{readerForNode as w}from"../graph/reader.js";const a="roadmap",x="To understand this node's long-term task and current plan, read this.";function E(e){return`${e}/${a}`}n(E,"roadmapRef");function i(e,r){const o=p(e,r);return o===null||o.type!=="node"?null:f(e,o.rowid,a)}n(i,"roadmapObject");function O(e){return i(u(),e)!==null}n(O,"hasRoadmap");function P(e){const r=u(),o=i(r,e);if(o===null)return null;const t=s(r,o)[0];if(t===void 0)return null;try{return c(t.body_hash)}catch{return null}}n(P,"readRoadmap");function R(e){return`# Roadmap
1
+ var l=Object.defineProperty;var r=(e,t)=>l(e,"name",{value:t,configurable:!0});import{openDb as u,withCanvasWrite as d}from"../canvas/db.js";import{get as s}from"../graph/bodies.js";import{heads as p,writeDocument as c}from"../graph/documents.js";import{getById as m,liveDocumentNamed as f,nodeObject as h}from"../graph/objects.js";import{readerForNode as g}from"../graph/reader.js";const i="roadmap",w="To understand this node's long-term task and current plan, read this.";function x(e){return e?.split(`
2
+ `).map(n=>n.trim()).find(n=>n!=="")??w}r(x,"roadmapPreview");function O(e){return`${e}/${i}`}r(O,"roadmapRef");function a(e,t){const n=m(e,t);return n===null||n.type!=="node"?null:f(e,n.rowid,i)}r(a,"roadmapObject");function P(e){return a(u(),e)!==null}r(P,"hasRoadmap");function W(e){const t=u(),n=a(t,e);if(n===null)return null;const o=p(t,n)[0];if(o===void 0)return null;try{return s(o.body_hash)}catch{return null}}r(W,"readRoadmap");function y(e){return`# Roadmap
2
3
 
3
4
  ## Goal
4
5
  ${e.goal?.trim()||"(the goal you now own)"}
@@ -6,6 +7,9 @@ ${e.goal?.trim()||"(the goal you now own)"}
6
7
  ## Exit criteria
7
8
  ${e.exitCriteria?.trim()||'(what "done" looks like)'}
8
9
 
9
- ## Phases
10
- (ordered phases from here to done; the current one carries a one-line status)
11
- `}n(R,"scaffold");function y(e,r,o={}){if(i(e,r)!==null)return null;const t=R(o);return m(e,w(e,r,()=>[]),{owner:h(e,r),name:a,kind:"knowledge",preview:x,privacy:"public",rules:[{on:"boot",deliver:"content"}]},t),t}n(y,"seedRoadmap");function $(e,r={}){return d(o=>y(o,e,r)!==null)}n($,"ensureRoadmap");export{a as ROADMAP_NAME,x as ROADMAP_PREVIEW,$ as ensureRoadmap,O as hasRoadmap,P as readRoadmap,E as roadmapRef,y as seedRoadmap};
10
+ ## Where things stand
11
+ (present state at your level: settled, in flight, remaining)
12
+
13
+ ## Working set
14
+ (links to the documents the work depends on now, one per line)
15
+ `}r(y,"scaffold");function R(e,t,n={}){if(a(e,t)!==null)return null;const o=y(n);return c(e,g(e,t,()=>[]),{owner:h(e,t),name:i,kind:"knowledge",preview:x(n.goal),privacy:"public",rules:[{on:"boot",deliver:"content"}]},o),o}r(R,"seedRoadmap");function $(e,t={}){return d(n=>R(n,e,t)!==null)}r($,"ensureRoadmap");export{i as ROADMAP_NAME,w as ROADMAP_PREVIEW,$ as ensureRoadmap,P as hasRoadmap,W as readRoadmap,x as roadmapPreview,O as roadmapRef,R as seedRoadmap};
@@ -1,4 +1,4 @@
1
- var A=Object.defineProperty;var a=(t,e)=>A(t,"name",{value:e,configurable:!0});import{dirname as F}from"node:path";import{clearLedger as L,demoteTranscript as $,freezePreferences as b,loadLedger as M,saveLedger as P}from"../../graph/exposures.js";import{recordWatch as T}from"../../graph/watches.js";import{publish as H}from"../../graph/events.js";import{viewOf as x}from"../../graph/names.js";import{reposForCwd as v}from"../../graph/repo-sync/repos.js";import{profileObject as W}from"../../graph/reader.js";import{ownerForGrantee as Y}from"../../graph/objects.js";import{resolveName as U}from"../../graph/names.js";import{SCOPE_VOCABULARY as B}from"../../scopes.js";import{getNode as G}from"../../canvas/index.js";import{recordMemoryReadsIn as J}from"../../canvas/memory-reads.js";import{lookupProfile as K}from"../../profiles/manifest.js";import{getDefaultProfileId as V}from"../../profiles/default-binding.js";import{effectiveScopes as X,profileNameFor as z,scopeForCwd as Q}from"../subject-fields.js";import{spineDepth as Z}from"../subject.js";import{appForNode as q}from"../../canvas/node-agent-paths.js";import{interpolateNodePaths as ee}from"../../canvas/paths.js";import{readableProjectForScopes as te}from"../../spaces/permissions.js";import{ApiError as p}from"../../../api/errors.js";import{buildContextBearings as oe}from"../../runtime/bearings.js";import{deliveryDocOf as g,listingCorpus as ne,loadCorpus as w,nodeSubject as j}from"./corpus.js";import{listingPrefixes as re}from"./listings.js";import{planDelivery as ie}from"./plan.js";import{renderEvent as N,renderExplicitRead as O}from"./render-event.js";import{renderConfigDelta as se,renderKnowledge as ce,renderPreferences as _,renderWorkspaceOpen as S}from"./render-boot.js";function f(t){if(t.class!=="node")throw new Error(`delivery needs a node reader, got ${t.class}`);return t}a(f,"nodeOf");const k=-1;function y(t){return t.node.rowid===k}a(y,"isHypothetical");function R(t,e){if(!y(e))return q(e.node.id);const o=t.prepare("SELECT external_id FROM identities WHERE object = ?").get(e.app.rowid);if(!o)throw new Error(`app object ${e.app.id} has no identity`);return o.external_id}a(R,"granteeOf");function de(t,e,o,r=i=>v(t,i)){const i=f(e).node,d=new Set,n=new Date().toISOString(),s=[];for(const{doc:c,level:l}of o)l!=="content"||d.has(c.object.rowid)||(d.add(c.object.rowid),T(t,i,c.object,"deliver",{readHeadsKey:c.headsKey}),H(t,{event:"read",object:c.object,actor:i,level:1,attrs:{}},r),s.push({name:c.name,scope:c.ownerHandle,at:n,type:"loaded"}));y(f(e))||J(t,i.id,s)}a(de,"recordContentDelivery");function E(t,e,o){const r=v(t,F(o)).filter(i=>!e.repos.some(d=>d.rowid===i.rowid));return r.length===0?e:{...e,repos:[...e.repos,...r]}}a(E,"fileReadReader");function ae(t,e,o){const r=R(t,e);if(!(o.startsWith("/")&&(process.platform!=="linux"&&r==="app:terminal"||te(o,r,e.scopes??[],null))))throw new p(403,"scope_missing","read file is outside the run mounts")}a(ae,"assertReadableFile");function le(t){const e=f(t.reader),o=e.node,r=R(t.db,e),i=w(t.db,t.reader,["slash-command"]),d=i.map(n=>{const s=n.body();return{name:n.displayName,command_name:n.displayName,description:n.preview,canonical_body:s,execution_body:ee(s,o.id,r)}});return{docs:i,commands:d}}a(le,"slashCommands");function pe(t){if(t.shipped)return"builtin";switch(t.owner.type){case"node":return"node";case"repo":return"project";case"profile":return"profile";default:return"user"}}a(pe,"scopeOf");function ue(t,e){const o=[],r=new Set;for(const i of x(t,e)){const d=ne(t,e,i);for(const n of d){o.push({name:n.displayName,kind:n.kind,scope:pe(n),shortForm:n.preview,gatewayVisible:!n.shipped}),r.add(n.displayName);const s=n.displayName===n.name?"":`${n.ownerHandle}/`;for(const c of re(d,n.name))r.add(`${s}${c}`)}}return{refs:o,names:[...r]}}a(ue,"composerNames");function C(t,e){const o=f(t.reader),{db:r,ledger:i}=t,d=a(()=>{if(typeof e.subject!="string"||e.subject==="")throw new p(400,"usage",`delivery activity ${e.activity} requires a subject`);return e.subject},"requireSubject");switch(e.activity){case"boot":{if(e.inherited===!0){for(const[c,l]of i.objects)if(l.transcript===void 0)i.objects.delete(c);else{const{system:u,...m}=l;i.objects.set(c,m)}for(const[c,l]of i.listed)l.transcript===void 0?i.listed.delete(c):i.listed.set(c,{transcript:l.transcript});return i.preferenceSnapshot=null,{result:{content:"",inherited:!0},delivered:[]}}const n=y(o)?me(t):oe(o.node.id,t),s=_({...t,channel:"system"});return b(i,s.content),{result:{content:n.content},delivered:[...n.delivered,...s.delivered]}}case"system-prompt":{if(i.preferenceSnapshot!==null)return{result:{content:i.preferenceSnapshot},delivered:[]};const n=_({...t,channel:"system"});return{result:{content:b(i,n.content)},delivered:n.delivered}}case"compact":{for(const n of w(r,o,["pre-command"]))$(i,n.object.rowid);return{result:{content:""},delivered:[]}}case"persona":{const n=se(t);return{result:{content:n.content},delivered:n.delivered}}case"file-read":{const n=d();ae(r,o,n);const s=E(r,o,n),c={...t,reader:s},l=N(c,"file-read",{absoluteFile:n},w(r,s,["file-read"]));return{result:{content:l.content},delivered:l.delivered}}case"command":case"pre-command":{const n=N(t,e.activity,{command:d()});return{result:{content:n.content},delivered:n.delivered}}case"slash-command":{const{docs:n,commands:s}=le(t);if(e.subject===void 0||e.subject==="")return{result:{content:"",commands:s},delivered:[]};const c=n.findIndex(m=>m.displayName===e.subject||m.name===e.subject);if(c<0)throw new p(404,"not_found",`no slash command named ${e.subject}`);const l=n[c],u=O(t,l);return{result:{content:"",execution_body:s[c].execution_body,blocks:u.attachments===""?[]:[u.attachments]},delivered:[{doc:l,level:"content"},...u.delivered]}}case"workspace-open":{const n=S(t);return{result:{content:n.content},delivered:n.delivered}}case"document-read":{const n=D(r,o,d()),s=O(t,g(r,o,n));return{result:{content:s.attachments},delivered:s.delivered}}case"names":return{result:{content:"",...ue(r,o)},delivered:[]};default:throw new p(400,"usage",`unknown delivery activity ${String(e.activity)}`)}}a(C,"render");function me(t){const e=ce(t),o=S(t);return{content:[e.content,o.content].filter(r=>r!=="").join(`
1
+ var A=Object.defineProperty;var a=(t,e)=>A(t,"name",{value:e,configurable:!0});import{dirname as F}from"node:path";import{clearLedger as L,demoteTranscript as $,freezePreferences as b,loadLedger as M,saveLedger as P}from"../../graph/exposures.js";import{recordWatch as T}from"../../graph/watches.js";import{publish as H}from"../../graph/events.js";import{viewOf as x}from"../../graph/names.js";import{reposForCwd as v}from"../../graph/repo-sync/repos.js";import{profileObject as W}from"../../graph/reader.js";import{ownerForGrantee as Y}from"../../graph/objects.js";import{resolveName as U}from"../../graph/names.js";import{SCOPE_VOCABULARY as B}from"../../scopes.js";import{getNode as G}from"../../canvas/index.js";import{recordMemoryReadsIn as J}from"../../canvas/memory-reads.js";import{lookupProfile as K}from"../../profiles/manifest.js";import{getDefaultProfileId as V}from"../../profiles/default-binding.js";import{effectiveScopes as X,profileNameFor as z,scopeForCwd as Q}from"../subject-fields.js";import{spineDepth as Z}from"../subject.js";import{appForNode as q}from"../../canvas/node-agent-paths.js";import{interpolateNodePaths as ee}from"../../canvas/paths.js";import{readableProjectForScopes as te}from"../../spaces/permissions.js";import{ApiError as p}from"../../../api/errors.js";import{buildContextBearings as oe}from"../../runtime/bearings.js";import{deliveryDocOf as g,listingCorpus as ne,loadCorpus as w,nodeSubject as j}from"./corpus.js";import{listingPrefixes as re}from"./listings.js";import{planDelivery as ie}from"./plan.js";import{renderEvent as N,renderExplicitRead as O}from"./render-event.js";import{renderConfigDelta as se,renderKnowledge as ce,renderPreferences as _,renderWorkspaceOpen as S}from"./render-boot.js";function f(t){if(t.class!=="node")throw new Error(`delivery needs a node reader, got ${t.class}`);return t}a(f,"nodeOf");const k=-1;function y(t){return t.node.rowid===k}a(y,"isHypothetical");function R(t,e){if(!y(e))return q(e.node.id);const o=t.prepare("SELECT external_id FROM identities WHERE object = ?").get(e.app.rowid);if(!o)throw new Error(`app object ${e.app.id} has no identity`);return o.external_id}a(R,"granteeOf");function de(t,e,o,r=i=>v(t,i)){const i=f(e).node,d=new Set,n=new Date().toISOString(),s=[];for(const{doc:c,level:l}of o)l!=="content"||d.has(c.object.rowid)||(d.add(c.object.rowid),T(t,i,c.object,"deliver",{readHeadsKey:c.headsKey}),H(t,{event:"read",object:c.object,actor:i,level:1,attrs:{}},r),s.push({name:c.name,scope:c.ownerHandle,at:n,type:"loaded"}));y(f(e))||J(t,i.id,s)}a(de,"recordContentDelivery");function E(t,e,o){const r=v(t,F(o)).filter(i=>!e.repos.some(d=>d.rowid===i.rowid));return r.length===0?e:{...e,repos:[...e.repos,...r]}}a(E,"fileReadReader");function ae(t,e,o){const r=R(t,e);if(!(o.startsWith("/")&&(process.platform!=="linux"&&r==="app:terminal"||te(o,r,e.scopes??[],null))))throw new p(403,"scope_missing","read file is outside the run mounts")}a(ae,"assertReadableFile");function le(t){const e=f(t.reader),o=e.node,r=R(t.db,e),i=w(t.db,t.reader,["slash-command"]),d=i.map(n=>{const s=n.body();return{name:n.displayName,command_name:n.displayName,description:n.preview,canonical_body:s,execution_body:ee(s,o.id,r)}});return{docs:i,commands:d}}a(le,"slashCommands");function pe(t){if(t.shipped)return"builtin";switch(t.owner.type){case"node":return"node";case"repo":return"project";case"profile":return"profile";default:return"user"}}a(pe,"scopeOf");function ue(t,e){const o=[],r=new Set;for(const i of x(t,e)){const d=ne(t,e,i);for(const n of d){o.push({name:n.displayName,kind:n.kind,scope:pe(n),shortForm:n.preview,gatewayVisible:!n.shipped}),r.add(n.displayName);const s=n.displayName===n.name?"":`${n.ownerHandle}/`;for(const c of re(d,n.name))r.add(`${s}${c}`)}}return{refs:o,names:[...r]}}a(ue,"composerNames");function C(t,e){const o=f(t.reader),{db:r,ledger:i}=t,d=a(()=>{if(typeof e.subject!="string"||e.subject==="")throw new p(400,"usage",`delivery activity ${e.activity} requires a subject`);return e.subject},"requireSubject");switch(e.activity){case"boot":{if(e.inherited===!0){for(const[c,l]of i.objects)if(l.transcript===void 0)i.objects.delete(c);else{const{system:u,...m}=l;i.objects.set(c,m)}for(const[c,l]of i.listed)l.transcript===void 0?i.listed.delete(c):i.listed.set(c,{transcript:l.transcript});return i.preferenceSnapshot=null,{result:{content:"",inherited:!0},delivered:[]}}const n=y(o)?me(t):oe(o.node.id,t),s=_({...t,channel:"system"});return b(i,s.content),{result:{content:n.content},delivered:[...n.delivered,...s.delivered]}}case"system-prompt":{if(i.preferenceSnapshot!==null)return{result:{content:i.preferenceSnapshot},delivered:[]};const n=_({...t,channel:"system"});return{result:{content:b(i,n.content)},delivered:n.delivered}}case"compact":{for(const n of w(r,o,["pre-command"]))$(i,n.object.rowid);return{result:{content:""},delivered:[]}}case"persona":{const n=se(t);return{result:{content:n.content},delivered:n.delivered}}case"file-read":{const n=d();ae(r,o,n);const s=E(r,o,n),c={...t,reader:s},l=N(c,"file-read",{absoluteFile:n},w(r,s,["file-read"]));return{result:{content:l.content},delivered:l.delivered}}case"command":case"pre-command":{const n=N(t,e.activity,{command:d()});return{result:{content:n.content},delivered:n.delivered}}case"slash-command":{const{docs:n,commands:s}=le(t);if(e.subject===void 0||e.subject==="")return{result:{content:"",commands:s},delivered:[]};const c=n.findIndex(m=>m.displayName===e.subject||m.name===e.subject);if(c<0)throw new p(404,"not_found",`no slash command named ${e.subject}`);const l=n[c],u=O(t,l,!0);return{result:{content:"",execution_body:s[c].execution_body,blocks:u.attachments===""?[]:[u.attachments]},delivered:[{doc:l,level:"content"},...u.delivered]}}case"workspace-open":{const n=S(t);return{result:{content:n.content},delivered:n.delivered}}case"document-read":{const n=D(r,o,d()),s=O(t,g(r,o,n),!0);return{result:{content:s.attachments},delivered:s.delivered}}case"names":return{result:{content:"",...ue(r,o)},delivered:[]};default:throw new p(400,"usage",`unknown delivery activity ${String(e.activity)}`)}}a(C,"render");function me(t){const e=ce(t),o=S(t);return{content:[e.content,o.content].filter(r=>r!=="").join(`
2
2
  `),delivered:[...e.delivered,...o.delivered]}}a(me,"hypotheticalBearings");function D(t,e,o){const r=U(t,e,o);if("object"in r&&r.object.type==="document")return r.object;throw"ambiguous"in r?new p(409,"ambiguous",`${o} names ${r.ambiguous.length} documents; name one as <type>:<owner>/<name>`):new p(404,"not_found",`no document ${o} the reader can read`)}a(D,"readDocument");const fe=["workspace-open","document-read"];function Be(t,e,o){if(fe.includes(o.activity))throw new p(400,"usage",`delivery activity ${o.activity} is available to a dry run only`);const r=f(e).node;o.activity==="boot"&&o.inherited!==!0&&L(t,r.rowid);const i=M(t,r.rowid),d={db:t,reader:e,subject:j(t,e),ledger:i,channel:"transcript"},{result:n,delivered:s}=C(d,o);return de(t,e,s),P(t,i),n}a(Be,"deliver");const we={boot:"boot","workspace-open":"workspace-open","file-read":"file-read","document-read":"document-read",command:"command","pre-command":"pre-command","slash-command":"slash-command"};function Ge(t,e){const o=G(t);if(o===null)throw new p(404,"not_found",`no node ${t}`);return{cwd:e.cwd??o.cwd,profile:e.profile!==void 0?e.profile:o.profile_id,grantee:e.grantee??o.grantee,kind:e.kind??o.kind,mode:e.mode??o.mode,lifecycle:e.lifecycle??o.lifecycle,hasManager:e.hasManager??(o.parent??null)!==null,depth:e.depth??Z(t)}}a(Ge,"hypotheticalFrom");function ve(t,e){if(t===null)return null;if(t===void 0||t==="")return V(e);const o=K(t);if(o.kind!=="resolved"){const r=`no profile ${t}`;throw new p(404,"not_found",r,{error:"not_found",message:r,next:"List profile ids and names with `crtr profile list`."})}return o.entry.profileId}a(ve,"resolveProfileId");function Je(t,e){const o=Y(t,e.grantee??"app:terminal"),r=ve(e.profile,e.cwd),i=v(t,e.cwd),d=e.mode??"base",s={class:"node",node:{rowid:k,id:"hypothetical",type:"node",kind:e.kind??"general",owner:o.rowid,privacy:"private",name:"hypothetical",preview:"",created_at:new Date(0).toISOString(),deleted_at:null},app:o,scopes:[...B],cwd:e.cwd,repos:i,profile:r===null?null:W(t,r,o)},c={kind:e.kind??"general",mode:d,lifecycle:e.lifecycle??(d==="orchestrator"?"resident":"terminal"),hasManager:e.hasManager??!0,cwd:e.cwd,scope:Q(e.cwd),orchestration:{depth:e.depth??0},profile:z(r),scopes:X(null),repo:i.map(l=>l.name)};return{reader:s,subject:c}}a(Je,"hypotheticalReader");function Ke(t,e,o,r,i){const n={node:f(e).node.rowid,preferenceSnapshot:null,objects:new Map,listed:new Map},s={...i??j(t,e),...r},c={db:t,reader:e,subject:s,ledger:n,channel:"transcript"},{result:l}=C(c,o),u=we[o.activity];let m=null;if(u!==void 0){const I=o.activity==="file-read"?{absoluteFile:o.subject}:o.activity==="command"||o.activity==="pre-command"?{command:o.subject}:o.activity==="document-read"&&o.subject!==void 0?{doc:g(t,e,D(t,e,o.subject))}:{},h=o.activity==="file-read"&&o.subject!==void 0?E(t,f(e),o.subject):e;m=ie(t,s,h,w(t,h,[u]),u,I)}return{result:l,plan:m}}a(Ke,"inspect");function Ve(t,e,o){return t.prepare(`SELECT o.*, MAX(r.number) AS to_seq, GROUP_CONCAT(DISTINCT a.id) AS authors
3
3
  FROM watches w JOIN objects o ON o.rowid = w.object AND o.type = 'document' AND o.deleted_at IS NULL
4
4
  JOIN revisions r ON r.document = o.rowid LEFT JOIN objects a ON a.rowid = r.author
@@ -25,3 +25,6 @@ export interface ListingLines {
25
25
  * renders is held in `ledger` on `channel`. */
26
26
  export declare function renderListing(members: readonly DeliveryDoc[], prefix: string, ledger: Ledger, channel: Channel, filterHeld: boolean): ListingLines;
27
27
  export declare function listingBlock(label: string, lines: readonly string[]): string;
28
+ /** A content delivery's own set: the names under `label` (`dir`, when there
29
+ * are any) and the documents it links to (`linked-from`), one line each. */
30
+ export declare function ownSetBlock(label: string, underLines: readonly string[], linkLines: readonly string[]): string;
@@ -1,4 +1,7 @@
1
- var w=Object.defineProperty;var r=(n,e)=>w(n,"name",{value:e,configurable:!0});import{heldAtOrAbove as x,hold as v}from"../../graph/exposures.js";function j(n){return n.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}r(j,"attr");function W(n,e){return`${n.owner.id}/${e}`}r(W,"listingKey");function u(n,e){return e!==""&&n.some(s=>s.name.startsWith(`${e}/`))}r(u,"isPrefix");function b(n,e){const s=e.split("/");return s.map((o,l)=>s.slice(0,s.length-l).join("/")).filter(o=>u(n,o))}r(b,"listingPrefixes");function N(n,e){return n.displayName===n.name?e:`${n.ownerHandle}/${e}`}r(N,"listingLabel");function A(n,e,s,p,o){const l=new Map(n.map(t=>[t.name,t])),f=[...new Set(n.filter(t=>t.name.startsWith(`${e}/`)).map(t=>`${e}/${t.name.slice(e.length+1).split("/")[0]}`))].sort(),$=f.filter(t=>!u(n,t)),m=f.filter(t=>u(n,t)),a=[],d=[],h=r(t=>{if(t===void 0||t.unlisted)return null;const i={object:t.object.rowid,headsKey:t.headsKey,contentHash:t.bodyHash};return o&&x(s,i,"preview")?null:(v(s,p,i,"preview"),d.push(t),t.preview.trim())},"suffix"),g=r((t,i)=>i===null||i===""?`[[${t}]]`:`[[${t}]]: ${i}`,"line");for(const t of $){const i=l.get(t),c=h(i);c!==null&&a.push(g(i.displayName,c))}for(const t of m){const i=l.get(t),c=i??n.find(y=>y.name.startsWith(`${t}/`));a.push(g(i?.displayName??N(c,t),h(i)))}return{lines:a,previewed:d}}r(A,"renderListing");function L(n,e){return`<memory-listing dir="${j(n)}">
1
+ var x=Object.defineProperty;var o=(n,e)=>x(n,"name",{value:e,configurable:!0});import{heldAtOrAbove as v,hold as j}from"../../graph/exposures.js";function p(n){return n.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}o(p,"attr");function k(n,e){return`${n.owner.id}/${e}`}o(k,"listingKey");function f(n,e){return e!==""&&n.some(r=>r.name.startsWith(`${e}/`))}o(f,"isPrefix");function A(n,e){const r=e.split("/");return r.map((s,l)=>r.slice(0,r.length-l).join("/")).filter(s=>f(n,s))}o(A,"listingPrefixes");function N(n,e){return n.displayName===n.name?e:`${n.ownerHandle}/${e}`}o(N,"listingLabel");function B(n,e,r,u,s){const l=new Map(n.map(t=>[t.name,t])),g=[...new Set(n.filter(t=>t.name.startsWith(`${e}/`)).map(t=>`${e}/${t.name.slice(e.length+1).split("/")[0]}`))].sort(),m=g.filter(t=>!f(n,t)),y=g.filter(t=>f(n,t)),a=[],d=[],h=o(t=>{if(t===void 0||t.unlisted)return null;const i={object:t.object.rowid,headsKey:t.headsKey,contentHash:t.bodyHash};return s&&v(r,i,"preview")?null:(j(r,u,i,"preview"),d.push(t),t.preview.trim())},"suffix"),$=o((t,i)=>i===null||i===""?`[[${t}]]`:`[[${t}]]: ${i}`,"line");for(const t of m){const i=l.get(t),c=h(i);c!==null&&a.push($(i.displayName,c))}for(const t of y){const i=l.get(t),c=i??n.find(w=>w.name.startsWith(`${t}/`));a.push($(i?.displayName??N(c,t),h(i)))}return{lines:a,previewed:d}}o(B,"renderListing");function H(n,e){return`<memory-listing dir="${p(n)}">
2
2
  ${e.join(`
3
3
  `)}
4
- </memory-listing>`}r(L,"listingBlock");export{u as isPrefix,L as listingBlock,W as listingKey,N as listingLabel,b as listingPrefixes,A as renderListing};
4
+ </memory-listing>`}o(H,"listingBlock");function P(n,e,r){return r.length===0?H(n,e):`<memory-listing ${e.length>0?`dir="${p(n)}" `:""}linked-from="${p(n)}">
5
+ ${[...e,...r].join(`
6
+ `)}
7
+ </memory-listing>`}o(P,"ownSetBlock");export{f as isPrefix,H as listingBlock,k as listingKey,N as listingLabel,A as listingPrefixes,P as ownSetBlock,B as renderListing};
@@ -1,54 +1,54 @@
1
- var M=Object.defineProperty;var l=(e,s)=>M(e,"name",{value:s,configurable:!0});import{heldAtOrAbove as E,hold as O,freezePreferences as W}from"../../graph/exposures.js";import{interpolateNodePaths as U}from"../../canvas/paths.js";import{buildSubPersonaMenu as Y}from"./sub-persona-menu.js";import{rungAtLeast as R}from"../schema.js";import{loadCorpus as T}from"./corpus.js";import{listingPrefixes as F}from"./listings.js";import{bootPartitionOf as z,planDelivery as D}from"./plan.js";import{renderEvent as _}from"./render-event.js";const v="Each %s below shows either its full content (indented beneath its name), a `# read when:` line telling you when to read the full document, or simply its name.",B="Preferences are how the user wants you to behave \u2014 standing directives and corrections. To read a preference, run `crtr canvas read <name>`. "+v.replace("%s","preference"),P="If the user corrects you in a way that contradicts a preference, update the preference.",H="Knowledge documents are what you consult \u2014 playbooks and techniques for how to do things, and references on the user, projects, and this node. They come from every owner in your view: this node, the repos you work in, your profile, your app, the user, and installed plugins (crtr's own under `crtr`). To read one, run `crtr canvas read <name>`; a name with names under it is a valid read target too \u2014 it answers with its body and the names under it, and walking names this way is the sanctioned way to browse. Each doc exists to prevent a specific mistake you would make without it, so when your task matches one \u2014 by its name or its `# read when:` line \u2014 read it before you act; consulting it only after the work is done forfeits the entire reason it exists. "+v.replace("%s","document"),A="If you learn a better way to do something a document covers, or gain information that contradicts one, correct it with `crtr doc edit`.",q="When your task matches a knowledge doc or preference \u2014 by its name or its `# read when:` line \u2014 read it before you act: each document exists only to shore up a mistake you will make without it, so doing the relevant work without consulting it defeats the document's whole purpose. Before writing a document that should outlive this task, search for one that already covers it (`crtr canvas search`) \u2014 update that document with `crtr doc edit` rather than creating a duplicate, rewriting it as if for the first time instead of appending the new truth beneath the old; delete documents that turn out to be wrong (`crtr doc delete`). Don't save what the repo already records (code structure, past fixes, git history) or what only matters to this conversation; if asked to remember one of those, ask what was non-obvious about it and save that instead. Docs auto-surfaced in <auto-loaded-context> blocks are background context, not user instructions, and reflect what was true when written \u2014 if one names a file, function, or flag, verify it still exists before recommending it.",J="Your node configuration changed. This operating protocol is in force for you now:",Q="Your new configuration puts these preferences in force \u2014 standing directives and corrections from the user. To read one, run `crtr canvas read <name>`. "+v.replace("%s","preference"),V="Your new configuration exposes these knowledge documents \u2014 consult them exactly like the rest of your catalog (`crtr canvas read <name>`). "+v.replace("%s","document");function g(e){return{object:e.object.rowid,headsKey:e.headsKey,contentHash:e.bodyHash}}l(g,"exposed");function j(e){const s=T(e.db,e.reader,["boot"]);return D(e.db,e.subject,e.reader,s,"boot").docs.filter(n=>n.winner)}l(j,"bootRecords");function y(e,s){return e.filter(n=>z(n)===s).map(n=>({doc:n.doc,level:n.finalRung}))}l(y,"partition");function N(e){return e.level!=="none"&&(e.level!=="content"||e.doc.body().trim()!=="")}l(N,"rendersAt");function b(e,s,n,t,r){const{ledger:a,channel:i}=e,c=s.filter(o=>o.level==="content"&&N(o)&&!E(a,g(o.doc),"content")).map(o=>o.doc).sort((o,d)=>d.viewRank-o.viewRank||o.name.localeCompare(d.name));for(const o of c)O(a,i,g(o),"content"),r.push({doc:o,level:"content"});const u=new Map;for(const o of c){const d=n.map(p=>p.doc).filter(p=>p.owner.rowid===o.owner.rowid);for(const p of F(d,o.name))for(const $ of n){const m=$.doc;m.owner.rowid!==o.owner.rowid||!m.name.startsWith(`${p}/`)||m.name.slice(p.length+1).includes("/")||$.level==="content"||R($.level,"preview")||m.unlisted||!m.ownNode&&!R(m.limit,"preview")||E(a,g(m),"preview")||u.set(m.object.rowid,{doc:m,level:"preview",cause:"directory listing attached to content delivery"})}}const f=c.map(o=>_(e,"document-read",{doc:o})).flatMap(({content:o,delivered:d})=>(r.push(...d),o===""?[]:[o])),h=s.filter(o=>o.level!=="content").map(o=>u.get(o.doc.object.rowid)??o),w=new Set(h.map(o=>o.doc.object.rowid));h.push(...[...u.values()].filter(o=>!w.has(o.doc.object.rowid)));for(const o of h)N(o)&&(O(a,i,g(o.doc),o.level),r.push({doc:o.doc,level:o.level,...o.cause===void 0?{}:{cause:o.cause}}));return{content:c,attachments:f,tree:Z(h,t)}}l(b,"renderGrouped");function C(e){return{segment:e,own:null,dirs:new Map,leaves:new Map,hidden:0,renders:!1,count:0}}l(C,"newDir");const X=l(e=>R(e,"name"),"visible");function L(e,s){let n=e.hidden;for(const t of e.dirs.values())n+=L(t,e.segment==="");return e.renders=e.own!==null||e.leaves.size>0||[...e.dirs.values()].some(t=>t.renders)||s||e.segment==="",e.count=e.renders?n:0,e.renders?0:n}l(L,"resolveDir");function S(e,s,n){const t=e.level==="preview"?e.doc.preview.trim():"";return t===""?`${n}${s}`:`${n}${s} # read when: ${t}`}l(S,"entryLine");function I(e,s,n){const t=[...[...e.dirs.values()].filter(r=>r.renders).map(r=>({name:r.segment,dir:r})),...[...e.leaves].map(([r,a])=>({name:r,leaf:a}))].sort((r,a)=>r.name.localeCompare(a.name));e.count>0&&t.push({name:"",more:e.count}),t.forEach((r,a)=>{const i=a===t.length-1,c=s+(i?"\u2514\u2500 ":"\u251C\u2500 ");if("more"in r)n.push(`${c}[+${r.more} more]`);else if(r.dir!==void 0){const u=`${r.dir.segment}/`;n.push(r.dir.own===null?`${c}${u}`:S(r.dir.own,u,c)),I(r.dir,s+(i?" ":"\u2502 "),n)}else n.push(S(r.leaf,r.name,c))})}l(I,"renderChildren");function Z(e,s){if(e.length===0)return"";const n=C(""),t=l(i=>{let c=n;for(const u of i){let f=c.dirs.get(u);f===void 0&&c.dirs.set(u,f=C(u)),c=f}return c},"dirAt"),r=new Set(e.map(i=>i.doc.displayName));for(const i of e){const c=i.doc.displayName.split("/"),u=[...r].some(f=>f.startsWith(`${i.doc.displayName}/`));X(i.level)?u?t(c).own=i:t(c.slice(0,-1)).leaves.set(c[c.length-1],i):t(u?c:c.slice(0,-1)).hidden+=1}L(n,!1);const a=[s];return I(n,"",a),a.join(`
2
- `)}l(Z,"buildTree");function k(e,s){const{reader:n}=e;return n.class==="node"?U(s,n.node.id,n.app.name):s}l(k,"interpolate");function G(e){return e.shipped}l(G,"isShipped");function K(e){const s=e.content.filter(G).map(t=>t.body().trim()).filter(t=>t!==""),n=e.content.filter(t=>!G(t)).map(t=>t.body().trim()===""?"":`<preference name="${t.displayName}">
3
- ${t.body().trim()}
4
- </preference>`).filter(t=>t!=="");return{shipped:s,editable:n}}l(K,"preferenceParts");function ce(e){if(e.ledger.preferenceSnapshot!==null)return{content:e.ledger.preferenceSnapshot,delivered:[]};const s={...e,channel:"system"},n=[];let t=[],r=q;if(e.subject!==null){const i=y(j(s),"preference"),c=b(s,i,i,"preferences",n),{shipped:u,editable:f}=K(c),h=Y(e.subject.kind);t=[...u,...c.attachments,...h===""?[]:[h]],(f.length>0||c.tree!=="")&&(r+=`
1
+ var Y=Object.defineProperty;var l=(e,s)=>Y(e,"name",{value:s,configurable:!0});import{heldAtOrAbove as $,hold as _,freezePreferences as F}from"../../graph/exposures.js";import{interpolateNodePaths as z}from"../../canvas/paths.js";import{buildSubPersonaMenu as B}from"./sub-persona-menu.js";import{rungAtLeast as k}from"../schema.js";import{loadCorpus as A}from"./corpus.js";import{listingPrefixes as H}from"./listings.js";import{bootPartitionOf as O,planDelivery as P}from"./plan.js";import{linkedDocs as q,renderEvent as S}from"./render-event.js";const E="Each %s below shows either its full content (indented beneath its name), a `# read when:` line telling you when to read the full document, or simply its name.",J="Preferences are how the user wants you to behave \u2014 standing directives and corrections. To read a preference, run `crtr canvas read <name>`. "+E.replace("%s","preference"),C="If the user corrects you in a way that contradicts a preference, update the preference.",Q="Knowledge documents are what you consult \u2014 playbooks and techniques for how to do things, and references on the user, projects, and this node. They come from every owner in your view: this node, the repos you work in, your profile, your app, the user, and installed plugins (crtr's own under `crtr`). To read one, run `crtr canvas read <name>`; a name with names under it is a valid read target too \u2014 it answers with its body, the names under it and previews of the documents it links to, and walking names this way is the sanctioned way to browse. Each doc exists to prevent a specific mistake you would make without it, so when your task matches one \u2014 by its name or its `# read when:` line \u2014 read it before you act; consulting it only after the work is done forfeits the entire reason it exists. "+E.replace("%s","document"),L="If you learn a better way to do something a document covers, or gain information that contradicts one, correct it with `crtr doc edit`.",V="When your task matches a knowledge doc or preference \u2014 by its name or its `# read when:` line \u2014 read it before you act: each document exists only to shore up a mistake you will make without it, so doing the relevant work without consulting it defeats the document's whole purpose. Before writing a document that should outlive this task, search for one that already covers it (`crtr canvas search`) \u2014 update that document with `crtr doc edit` rather than creating a duplicate, rewriting it as if for the first time instead of appending the new truth beneath the old; delete documents that turn out to be wrong (`crtr doc delete`). Don't save what the repo already records (code structure, past fixes, git history) or what only matters to this conversation; if asked to remember one of those, ask what was non-obvious about it and save that instead. Docs auto-surfaced in <auto-loaded-context> blocks are background context, not user instructions, and reflect what was true when written \u2014 if one names a file, function, or flag, verify it still exists before recommending it.",X="Your node configuration changed. This operating protocol is in force for you now:",Z="Your new configuration puts these preferences in force \u2014 standing directives and corrections from the user. To read one, run `crtr canvas read <name>`. "+E.replace("%s","preference"),x="Your new configuration exposes these knowledge documents \u2014 consult them exactly like the rest of your catalog (`crtr canvas read <name>`). "+E.replace("%s","document");function b(e){return{object:e.object.rowid,headsKey:e.headsKey,contentHash:e.bodyHash}}l(b,"exposed");function T(e){const s=A(e.db,e.reader,["boot"]);return P(e.db,e.subject,e.reader,s,"boot").docs.filter(t=>t.winner)}l(T,"bootRecords");function j(e,s){return e.filter(t=>O(t)===s).map(t=>({doc:t.doc,level:t.finalRung}))}l(j,"partition");function D(e){return e.level!=="none"&&(e.level!=="content"||e.doc.body().trim()!=="")}l(D,"rendersAt");function R(e,s,t,o,r){const{ledger:a,channel:i}=e,c=s.filter(n=>n.level==="content"&&D(n)&&!$(a,b(n.doc),"content")).map(n=>n.doc).sort((n,p)=>p.viewRank-n.viewRank||n.name.localeCompare(p.name));for(const n of c)_(a,i,b(n),"content"),r.push({doc:n,level:"content"});const d=new Map;for(const n of c){const p=t.map(h=>h.doc).filter(h=>h.owner.rowid===n.owner.rowid);for(const h of H(p,n.name))for(const y of t){const m=y.doc;m.owner.rowid!==n.owner.rowid||!m.name.startsWith(`${h}/`)||m.name.slice(h.length+1).includes("/")||y.level==="content"||k(y.level,"preview")||m.unlisted||!m.ownNode&&!k(m.limit,"preview")||$(a,b(m),"preview")||d.set(m.object.rowid,{doc:m,level:"preview",cause:"directory listing attached to content delivery"})}}const u=new Map(t.map(n=>[n.doc.object.rowid,n])),v=new Set(c.map(n=>n.object.rowid));for(const n of c)for(const p of q(e.db,e.reader,n)){const h=p.object.rowid,y=u.get(h);d.has(h)||v.has(h)||y!==void 0&&k(y.level,"preview")||O({doc:p})===O({doc:n})&&(!p.ownNode&&!k(p.limit,"preview")||$(a,b(p),"preview")||d.set(h,{doc:y?.doc??p,level:"preview",cause:"link preview attached to content delivery"}))}const g=c.map(n=>S(e,"document-read",{doc:n})).flatMap(({content:n,delivered:p})=>(r.push(...p),n===""?[]:[n])),w=s.filter(n=>n.level!=="content").map(n=>d.get(n.doc.object.rowid)??n),f=new Set(w.map(n=>n.doc.object.rowid));w.push(...[...d.values()].filter(n=>!f.has(n.doc.object.rowid)));for(const n of w)D(n)&&(_(a,i,b(n.doc),n.level),r.push({doc:n.doc,level:n.level,...n.cause===void 0?{}:{cause:n.cause}}));return{content:c,attachments:g,tree:ne(w,o)}}l(R,"renderGrouped");function I(e){return{segment:e,own:null,dirs:new Map,leaves:new Map,hidden:0,renders:!1,count:0}}l(I,"newDir");const ee=l(e=>k(e,"name"),"visible");function M(e,s){let t=e.hidden;for(const o of e.dirs.values())t+=M(o,e.segment==="");return e.renders=e.own!==null||e.leaves.size>0||[...e.dirs.values()].some(o=>o.renders)||s||e.segment==="",e.count=e.renders?t:0,e.renders?0:t}l(M,"resolveDir");function G(e,s,t){const o=e.level==="preview"?e.doc.preview.trim():"";return o===""?`${t}${s}`:`${t}${s} # read when: ${o}`}l(G,"entryLine");function K(e,s,t){const o=[...[...e.dirs.values()].filter(r=>r.renders).map(r=>({name:r.segment,dir:r})),...[...e.leaves].map(([r,a])=>({name:r,leaf:a}))].sort((r,a)=>r.name.localeCompare(a.name));e.count>0&&o.push({name:"",more:e.count}),o.forEach((r,a)=>{const i=a===o.length-1,c=s+(i?"\u2514\u2500 ":"\u251C\u2500 ");if("more"in r)t.push(`${c}[+${r.more} more]`);else if(r.dir!==void 0){const d=`${r.dir.segment}/`;t.push(r.dir.own===null?`${c}${d}`:G(r.dir.own,d,c)),K(r.dir,s+(i?" ":"\u2502 "),t)}else t.push(G(r.leaf,r.name,c))})}l(K,"renderChildren");function ne(e,s){if(e.length===0)return"";const t=I(""),o=l(i=>{let c=t;for(const d of i){let u=c.dirs.get(d);u===void 0&&c.dirs.set(d,u=I(d)),c=u}return c},"dirAt"),r=new Set(e.map(i=>i.doc.displayName));for(const i of e){const c=i.doc.displayName.split("/"),d=[...r].some(u=>u.startsWith(`${i.doc.displayName}/`));ee(i.level)?d?o(c).own=i:o(c.slice(0,-1)).leaves.set(c[c.length-1],i):o(d?c:c.slice(0,-1)).hidden+=1}M(t,!1);const a=[s];return K(t,"",a),a.join(`
2
+ `)}l(ne,"buildTree");function N(e,s){const{reader:t}=e;return t.class==="node"?z(s,t.node.id,t.app.name):s}l(N,"interpolate");function W(e){return e.shipped}l(W,"isShipped");function U(e){const s=e.content.filter(W).map(o=>o.body().trim()).filter(o=>o!==""),t=e.content.filter(o=>!W(o)).map(o=>o.body().trim()===""?"":`<preference name="${o.displayName}">
3
+ ${o.body().trim()}
4
+ </preference>`).filter(o=>o!=="");return{shipped:s,editable:t}}l(U,"preferenceParts");function ue(e){if(e.ledger.preferenceSnapshot!==null)return{content:e.ledger.preferenceSnapshot,delivered:[]};const s={...e,channel:"system"},t=[];let o=[],r=V;if(e.subject!==null){const i=j(T(s),"preference"),c=R(s,i,i,"preferences",t),{shipped:d,editable:u}=U(c),v=B(e.subject.kind);o=[...d,...c.attachments,...v===""?[]:[v]],(u.length>0||c.tree!=="")&&(r+=`
5
5
 
6
- ${B}`,f.length>0&&(r+=`
6
+ ${J}`,u.length>0&&(r+=`
7
7
 
8
- ${f.join(`
8
+ ${u.join(`
9
9
 
10
10
  `)}`),c.tree!==""&&(r+=`
11
11
 
12
12
  ${c.tree}`),r+=`
13
13
 
14
- ${P}`)}const a=[...t,`<memory kind="preference">
14
+ ${C}`)}const a=[...o,`<memory kind="preference">
15
15
  ${r}
16
16
  </memory>`].join(`
17
17
 
18
- `);return{content:W(e.ledger,k(e,a)),delivered:n}}l(ce,"renderPreferences");function de(e){const s=[],n=y(j(e),"knowledge"),t=b(e,n,n,"knowledge",s),r=[...t.content.map(i=>i.body().trim()),...t.attachments].filter(i=>i!=="");if(r.length===0&&t.tree==="")return{content:"",delivered:s};let a=H;return r.length>0&&(a+=`
18
+ `);return{content:F(e.ledger,N(e,a)),delivered:t}}l(ue,"renderPreferences");function fe(e){const s=[],t=j(T(e),"knowledge"),o=R(e,t,t,"knowledge",s),r=[...o.content.map(i=>i.body().trim()),...o.attachments].filter(i=>i!=="");if(r.length===0&&o.tree==="")return{content:"",delivered:s};let a=Q;return r.length>0&&(a+=`
19
19
 
20
20
  ${r.join(`
21
21
 
22
- `)}`),t.tree!==""&&(a+=`
22
+ `)}`),o.tree!==""&&(a+=`
23
23
 
24
- ${t.tree}`),a+=`
24
+ ${o.tree}`),a+=`
25
25
 
26
- ${A}`,{content:k(e,`<memory kind="knowledge">
26
+ ${L}`,{content:N(e,`<memory kind="knowledge">
27
27
  ${a}
28
- </memory>`),delivered:s}}l(de,"renderKnowledge");function le(e){const s=T(e.db,e.reader,["workspace-open"]),n=D(e.db,e.subject,e.reader,s,"workspace-open").docs.filter(a=>a.winner).map(a=>a.doc).sort((a,i)=>i.viewRank-a.viewRank||a.object.rowid-i.object.rowid),{content:t,delivered:r}=_(e,"workspace-open",{},n);return{content:k(e,t),delivered:r}}l(le,"renderWorkspaceOpen");function ue(e){const{ledger:s}=e,n=[],t=j(e),r=l(d=>d.filter(p=>N(p)&&!E(s,g(p.doc),p.level)),"fresh"),a=y(t,"preference"),i=b(e,r(a),a,"preferences",n),{shipped:c,editable:u}=K(i),f=[];if((c.length>0||i.attachments.length>0)&&f.push(`${J}
28
+ </memory>`),delivered:s}}l(fe,"renderKnowledge");function pe(e){const s=A(e.db,e.reader,["workspace-open"]),t=P(e.db,e.subject,e.reader,s,"workspace-open").docs.filter(a=>a.winner).map(a=>a.doc).sort((a,i)=>i.viewRank-a.viewRank||a.object.rowid-i.object.rowid),{content:o,delivered:r}=S(e,"workspace-open",{},t);return{content:N(e,o),delivered:r}}l(pe,"renderWorkspaceOpen");function he(e){const{ledger:s}=e,t=[],o=T(e),r=l(f=>f.filter(n=>D(n)&&!$(s,b(n.doc),n.level)),"fresh"),a=j(o,"preference"),i=R(e,r(a),a,"preferences",t),{shipped:c,editable:d}=U(i),u=[];if((c.length>0||i.attachments.length>0)&&u.push(`${X}
29
29
 
30
30
  ${[...c,...i.attachments].join(`
31
31
 
32
- `)}`),u.length>0||i.tree!==""){let d=Q;u.length>0&&(d+=`
32
+ `)}`),d.length>0||i.tree!==""){let f=Z;d.length>0&&(f+=`
33
33
 
34
- ${u.join(`
34
+ ${d.join(`
35
35
 
36
- `)}`),i.tree!==""&&(d+=`
36
+ `)}`),i.tree!==""&&(f+=`
37
37
 
38
- ${i.tree}`),d+=`
38
+ ${i.tree}`),f+=`
39
39
 
40
- ${P}`,f.push(`<memory kind="preference">
41
- ${d}
42
- </memory>`)}const h=y(t,"knowledge"),w=b(e,r(h),h,"knowledge",n),o=[...w.content.map(d=>d.body().trim()),...w.attachments].filter(d=>d!=="");if(o.length>0||w.tree!==""){let d=V;o.length>0&&(d+=`
40
+ ${C}`,u.push(`<memory kind="preference">
41
+ ${f}
42
+ </memory>`)}const v=j(o,"knowledge"),g=R(e,r(v),v,"knowledge",t),w=[...g.content.map(f=>f.body().trim()),...g.attachments].filter(f=>f!=="");if(w.length>0||g.tree!==""){let f=x;w.length>0&&(f+=`
43
43
 
44
- ${o.join(`
44
+ ${w.join(`
45
45
 
46
- `)}`),w.tree!==""&&(d+=`
46
+ `)}`),g.tree!==""&&(f+=`
47
47
 
48
- ${w.tree}`),d+=`
48
+ ${g.tree}`),f+=`
49
49
 
50
- ${A}`,f.push(`<memory kind="knowledge">
51
- ${d}
52
- </memory>`)}return{content:f.length===0?"":k(e,f.join(`
50
+ ${L}`,u.push(`<memory kind="knowledge">
51
+ ${f}
52
+ </memory>`)}return{content:u.length===0?"":N(e,u.join(`
53
53
 
54
- `)),delivered:n}}l(ue,"renderConfigDelta");export{ue as renderConfigDelta,de as renderKnowledge,ce as renderPreferences,le as renderWorkspaceOpen};
54
+ `)),delivered:t}}l(he,"renderConfigDelta");export{he as renderConfigDelta,fe as renderKnowledge,ue as renderPreferences,pe as renderWorkspaceOpen};
@@ -1,6 +1,6 @@
1
1
  /** Event rendering for the row-backed delivery engine: plan an activity, render
2
2
  * each winner the ledger does not already hold, and for every content
3
- * delivery attach its prefix listings and chain its `document-read` rules
3
+ * delivery attach its prefix listings and link previews and chain its `document-read` rules
4
4
  * until nothing new is delivered. Every rendered document is held in the
5
5
  * in-memory `ledger`; persisting it is the caller's. Envelope markup is the
6
6
  * `<memory>` / `<memory-listing>` / `<auto-loaded-context>` shape that
@@ -12,7 +12,7 @@ import type { Rung } from '../schema.js';
12
12
  import type { NodeConfigSubject } from '../subject-fields.js';
13
13
  import { type DeliveryPayload } from './plan.js';
14
14
  import type { DeliveryDoc } from './types.js';
15
- export type DeliveryCause = 'directory listing attached to content delivery' | 'memory-read companion of content delivery';
15
+ export type DeliveryCause = 'directory listing attached to content delivery' | 'link preview attached to content delivery' | 'memory-read companion of content delivery';
16
16
  export interface DeliveredDoc {
17
17
  doc: DeliveryDoc;
18
18
  level: Exclude<Rung, 'none'>;
@@ -30,6 +30,10 @@ export interface RenderContext {
30
30
  * otherwise (a preview carries its line as `readWhen`). Empty-bodied content renders self-closing. */
31
31
  export declare function renderEnvelope(doc: DeliveryDoc, level: Exclude<Rung, 'none'>): string;
32
32
  export declare function wrapAutoLoaded(blocks: readonly string[]): string;
33
+ /** The live documents `doc`'s current revision links to that the reader may
34
+ * read, in link order, without `doc` itself. Remote and unresolved links have
35
+ * no `links-to` edge, so they never appear. */
36
+ export declare function linkedDocs(db: DatabaseSync, reader: Reader, doc: DeliveryDoc): DeliveryDoc[];
33
37
  /** Deliver one activity. `corpus` overrides the reader's own corpus for `on`
34
38
  * (the file-read corpus also carries the rules of repos enclosing the file). */
35
39
  export declare function renderEvent(ctx: RenderContext, on: RuleOn, payload: DeliveryPayload, corpus?: readonly DeliveryDoc[]): {
@@ -37,11 +41,14 @@ export declare function renderEvent(ctx: RenderContext, on: RuleOn, payload: Del
37
41
  delivered: DeliveredDoc[];
38
42
  };
39
43
  /** What a document the node read on purpose brings with it: its own prefix
40
- * listing unfiltered (`listing`), enclosing listings and chained
41
- * `document-read` deliveries (`attachments`, wrapped). The read document
42
- * itself is held at content in `ledger`. */
43
- export declare function renderExplicitRead(ctx: RenderContext, doc: DeliveryDoc): {
44
+ * listing unfiltered (`listing`), the documents it links to not yet held at
45
+ * preview (`linked`, held at preview now), enclosing listings and chained
46
+ * `document-read` deliveries (`attachments`, wrapped). With `ownAsBlock`
47
+ * (a caller that renders only `attachments`), the own set rides there as a
48
+ * block instead. The read document itself is held at content in `ledger`. */
49
+ export declare function renderExplicitRead(ctx: RenderContext, doc: DeliveryDoc, ownAsBlock?: boolean): {
44
50
  attachments: string;
45
51
  listing?: string[];
52
+ linked: DeliveryDoc[];
46
53
  delivered: DeliveredDoc[];
47
54
  };
@@ -1,6 +1,8 @@
1
- var j=Object.defineProperty;var i=(e,n)=>j(e,"name",{value:n,configurable:!0});import{heldAtOrAbove as A,hold as g,holdListing as K,listedAtOrAbove as C}from"../../graph/exposures.js";import{listingCorpus as H,loadCorpus as y}from"./corpus.js";import{listingBlock as L,listingKey as E,listingLabel as O,listingPrefixes as M,renderListing as P}from"./listings.js";import{planDelivery as R}from"./plan.js";function b(e){return e.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}i(b,"attr");function q(e,n){let t=`kind="${b(e.kind)}" name="${b(e.displayName)}"`;if(n==="content"){const r=e.body().trim();if(r!=="")return`<memory ${t}>
2
- ${r}
3
- </memory>`}else n==="preview"&&e.preview.trim()!==""&&(t+=` readWhen="${b(e.preview.trim())}"`);return`<memory ${t} />`}i(q,"renderEnvelope");function x(e){return e.length===0?"":`<auto-loaded-context>
1
+ var A=Object.defineProperty;var s=(e,n)=>A(e,"name",{value:n,configurable:!0});import{canRead as D}from"../../graph/access.js";import{heldAtOrAbove as y,hold as b,holdListing as E,listedAtOrAbove as O}from"../../graph/exposures.js";import{deliveryDocOf as H,listingCorpus as K,loadCorpus as w}from"./corpus.js";import{listingBlock as L,ownSetBlock as R,listingKey as C,listingLabel as x,listingPrefixes as P,renderListing as k}from"./listings.js";import{planDelivery as B}from"./plan.js";function g(e){return e.replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;").replace(/>/g,"&gt;")}s(g,"attr");function M(e,n){let t=`kind="${g(e.kind)}" name="${g(e.displayName)}"`;if(n==="content"){const i=e.body().trim();if(i!=="")return`<memory ${t}>
2
+ ${i}
3
+ </memory>`}else n==="preview"&&e.preview.trim()!==""&&(t+=` readWhen="${g(e.preview.trim())}"`);return`<memory ${t} />`}s(M,"renderEnvelope");function j(e){return e.length===0?"":`<auto-loaded-context>
4
4
  ${e.join(`
5
5
  `)}
6
- </auto-loaded-context>`}i(x,"wrapAutoLoaded");function B(e,n){let t=e.members.get(n.owner.rowid);return t===void 0&&(t=H(e.ctx.db,e.ctx.reader,n.owner),e.members.set(n.owner.rowid,t)),t}i(B,"membersOf");function w(e,n,t){const{ledger:r,channel:o}=e.ctx,f=B(e,n),a=[];let m;for(const d of M(f,n.name)){const u=t&&d===n.name,h=E(n,d);if(!u&&C(r,h,"preview"))continue;const{lines:c,previewed:p}=P(f,d,r,o,!u);for(const s of p)e.delivered.push({doc:s,level:"preview",cause:"directory listing attached to content delivery"});c.length!==0&&(K(r,o,h,"preview"),u?m=c:a.push(L(O(n,d),c)))}return e.chainCorpus??=y(e.ctx.db,e.ctx.reader,["document-read"]),a.push(...$(e,e.chainCorpus,"document-read",{doc:n},"memory-read companion of content delivery")),{blocks:a,...m===void 0?{}:{listing:m}}}i(w,"attachments");function $(e,n,t,r,o){const{db:f,reader:a,subject:m,ledger:d,channel:u}=e.ctx,h=R(f,m,a,n,t,r),c=[];for(const p of h.docs){const s=p.finalRung;if(!p.winner||s==="none")continue;const{doc:l}=p,v={object:l.object.rowid,headsKey:l.headsKey,contentHash:l.bodyHash};A(d,v,s)||(g(d,u,v,s),e.delivered.push({doc:l,level:s,...o===void 0?{}:{cause:o}}),s==="content"&&c.push(...w(e,l,!1).blocks),c.push(q(l,s)))}return c}i($,"renderPlan");function G(e,n,t,r=y(e.db,e.reader,[n])){const o={ctx:e,delivered:[],members:new Map};return{content:x($(o,r,n,t)),delivered:o.delivered}}i(G,"renderEvent");function I(e,n){const t={ctx:e,delivered:[],members:new Map};g(e.ledger,e.channel,{object:n.object.rowid,headsKey:n.headsKey,contentHash:n.bodyHash},"content");const{blocks:r,listing:o}=w(t,n,!0);return{attachments:x(r),...o===void 0?{}:{listing:o},delivered:t.delivered}}i(I,"renderExplicitRead");export{q as renderEnvelope,G as renderEvent,I as renderExplicitRead,x as wrapAutoLoaded};
6
+ </auto-loaded-context>`}s(j,"wrapAutoLoaded");function S(e,n){let t=e.members.get(n.owner.rowid);return t===void 0&&(t=K(e.ctx.db,e.ctx.reader,n.owner),e.members.set(n.owner.rowid,t)),t}s(S,"membersOf");function W(e,n,t){return e.prepare(`SELECT o.* FROM edges e JOIN objects o ON o.rowid = e.dst
7
+ WHERE e.type = 'links-to' AND e.src = ? AND o.type = 'document' AND o.deleted_at IS NULL AND o.rowid <> ?
8
+ ORDER BY e.written_as`).all(t.object.rowid,t.object.rowid).filter(o=>D(e,n,o)).map(o=>H(e,n,o))}s(W,"linkedDocs");function I(e,n){return n.owner.rowid===e.owner.rowid&&n.name.startsWith(`${e.name}/`)&&!n.name.slice(e.name.length+1).includes("/")}s(I,"underOwnPrefix");function _(e,n){const{ledger:t,channel:i}=e.ctx,o=[],c=[];for(const r of W(e.ctx.db,e.ctx.reader,n)){if(I(n,r)&&!r.unlisted)continue;const a={object:r.object.rowid,headsKey:r.headsKey,contentHash:r.bodyHash};if(y(t,a,"preview"))continue;b(t,i,a,"preview"),e.delivered.push({doc:r,level:"preview",cause:"link preview attached to content delivery"}),c.push(r);const d=r.preview.trim();o.push(d===""?`[[${r.displayName}]]`:`[[${r.displayName}]]: ${d}`)}return{lines:o,linked:c}}s(_,"linkPreviews");function $(e,n,t){const{ledger:i,channel:o}=e.ctx,c=S(e,n),r=[];let a,d=[];for(const f of P(c,n.name)){const p=f===n.name,m=C(n,f);if(!(p&&t)&&O(i,m,"preview"))continue;const{lines:l,previewed:u}=k(c,f,i,o,!(p&&t));for(const v of u)e.delivered.push({doc:v,level:"preview",cause:"directory listing attached to content delivery"});l.length!==0&&(E(i,o,m,"preview"),p?d=l:r.push(L(x(n,f),l)))}const h=_(e,n);return t?d.length>0&&(a=d):d.length+h.lines.length>0&&r.unshift(R(x(n,n.name),d,h.lines)),e.chainCorpus??=w(e.ctx.db,e.ctx.reader,["document-read"]),r.push(...N(e,e.chainCorpus,"document-read",{doc:n},"memory-read companion of content delivery")),{blocks:r,...a===void 0?{}:{listing:a},linked:h.linked}}s($,"attachments");function N(e,n,t,i,o){const{db:c,reader:r,subject:a,ledger:d,channel:h}=e.ctx,f=B(c,a,r,n,t,i),p=[];for(const m of f.docs){const l=m.finalRung;if(!m.winner||l==="none")continue;const{doc:u}=m,v={object:u.object.rowid,headsKey:u.headsKey,contentHash:u.bodyHash};y(d,v,l)||(b(d,h,v,l),e.delivered.push({doc:u,level:l,...o===void 0?{}:{cause:o}}),l==="content"&&p.push(...$(e,u,!1).blocks),p.push(M(u,l)))}return p}s(N,"renderPlan");function z(e,n,t,i=w(e.db,e.reader,[n])){const o={ctx:e,delivered:[],members:new Map};return{content:j(N(o,i,n,t)),delivered:o.delivered}}s(z,"renderEvent");function G(e,n,t=!1){const i={ctx:e,delivered:[],members:new Map};b(e.ledger,e.channel,{object:n.object.rowid,headsKey:n.headsKey,contentHash:n.bodyHash},"content");const{blocks:o,listing:c,linked:r}=$(i,n,!t);return{attachments:j(o),...c===void 0?{}:{listing:c},linked:r,delivered:i.delivered}}s(G,"renderExplicitRead");export{W as linkedDocs,M as renderEnvelope,z as renderEvent,G as renderExplicitRead,j as wrapAutoLoaded};
@@ -1 +1 @@
1
- var oe=Object.defineProperty;var u=(t,e)=>oe(t,"name",{value:e,configurable:!0});import{ApiError as g}from"../../../api/errors.js";import{DOC_KINDS as P,DOC_UNSET_FIELDS as q}from"../../../api/dto/docs.js";import{PRIVACY_LEVELS_DTO as H}from"../../../api/dto/objects.js";import{withCanvasWrite as E}from"../../../core/canvas/db.js";import{CrtrError as re}from"../../../core/errors.js";import{emitEvent as ie}from"../../../core/events/emit.js";import{canChange as V,spaceOf as se}from"../../../core/graph/access.js";import{get as A}from"../../../core/graph/bodies.js";import{deleteDocument as ae,documentRecord as F,editDocument as ce,heads as I,history as de,linksIn as K,moveDocument as ue,readBase as fe,setDocumentRecord as le,withCurrentNames as me,writeDocument as pe}from"../../../core/graph/documents.js";import{resolveName as U}from"../../../core/graph/names.js";import{getByRowid as M}from"../../../core/graph/objects.js";import{noteRepoDocumentsChanged as he}from"../../../core/graph/repo-sync/index.js";import{reposForCwd as we}from"../../../core/graph/repo-sync/repos.js";import{lintRules as ye,rulesOf as ve}from"../../../core/graph/rules.js";import{unifiedDiff as ge}from"../../../core/graph/diff.js";import{ownerFromFlag as W,readerFor as k,resolveRef as X}from"../reader.js";function _(t,e,n,o,i={}){return new g(t,e,n,{...i,error:e,message:n,next:o})}u(_,"refuse");const b=u((t,e)=>new g(400,"invalid_request",t,e),"invalid");function D(t){const e=t.body;if(e===void 0)return{};if(typeof e!="object"||e===null||Array.isArray(e))throw b("the request body must be a JSON object");return e}u(D,"bodyOf");const x=u(t=>e=>we(t,e),"reposFnFor");function C(t,e){if(t instanceof re){const n=t.details;if(t.code==="read_first")throw _(409,"read_first",t.message,`Read it first with \`crtr canvas read ${e?.id??"<ref>"}\`, then rerun the edit.`,n??{});if(t.code==="conflict")throw new g(409,"name_taken",t.message,n);if(t.code==="forbidden")throw new g(403,"forbidden",t.message,n);if(n?.rule==="repo-public-only")throw _(422,"repo_documents_are_public",t.message,'Own it as `user` and add a rule with `if: {"repo": "<handle>"}` so it loads only in that repo.')}throw t}u(C,"mapGraphError");function B(t,e,n){const o=X(t,e,decodeURIComponent(n));if("remote"in o)throw _(404,"not_found",z(o.remote),"Check the name with `crtr canvas search`.");if("deleted"in o)throw new g(404,"not_found",`${o.deleted.name} is deleted`,{id:o.deleted.id,deleted:!0});if(o.type!=="document")throw b(`${n} is a ${o.type}, not a document`);return o}u(B,"refDocument");function z(t){return`no object named ${t} on this runtime; it may be on another runtime, or the name may be misspelled`}u(z,"remoteMessage");function _e(t,e){const n=e.owner===null?null:M(t,e.owner);return n?n.type==="node"?n.id:n.name:""}u(_e,"ownerHandle");function j(t,e){const n=_e(t,e);return n?`${n}/${e.name}`:e.name}u(j,"canonicalName");function be(t,e){const n=e.owner===null?null:M(t,e.owner),o=n?{id:n.id,type:n.type,handle:n.type==="node"?n.id:n.name}:null;return{id:e.id,type:e.type,kind:e.kind,owner:o,privacy:e.privacy,name:e.name,preview:e.preview??"",created_at:e.created_at,deleted_at:e.deleted_at}}u(be,"objectDTO");function Ee(t,e){const n=e.owner===null?null:M(t,e.owner);return n?.type==="repo"?n:null}u(Ee,"repoOwner");function T(t,e,n,o){const i=[...new Map(n.flatMap(r=>{const f=Ee(t,r);return f?[[f.id,f]]:[]})).values()],a=e.class==="node"?e.cwd:o;return{repos:i,...a!==void 0?{cwd:a}:{}}}u(T,"repoChange");function N(t){for(const e of t.repos)try{he(e,t.cwd)}catch(n){ie({level:"warn",event:"repo_sync.failed",outcome:"failed",error:n,fields:{repo:e.name,step:"export",reason:n instanceof Error?n.message:String(n)}})}}u(N,"syncChanged");const G=/^[A-Za-z0-9_-]+(\/[A-Za-z0-9_-]+)*$/;function ke(t,e){if(t===void 0)return;if(!Array.isArray(t)){e.push("`rules` must be a list");return}const n=t.map(i=>{if(typeof i!="object"||i===null||Array.isArray(i))return i;const{match_frontmatter:a,...r}=i;return"matchFrontmatter"in r?{...r,match_frontmatter:r.matchFrontmatter}:a===void 0?r:{...r,matchFrontmatter:a}}),o=ye(n);if(o){e.push(o.replaceAll("matchFrontmatter","match_frontmatter"));return}return n}u(ke,"rulesFromDTO");function Y(t,e){const n={},o=u(s=>{const c=t[s];if(c!==void 0){if(typeof c!="string"){e.push(`\`${s}\` must be a string`);return}return c}},"str"),i=o("preview");i!==void 0&&(i.trim()===""||/[\r\n]/.test(i)?e.push("`preview` must be one non-empty line"):n.preview=i);const a=o("summary");a!==void 0&&(n.summary=a);const r=o("why_it_exists");if(r!==void 0&&(n.whyItExists=r),t.privacy!==void 0&&(H.includes(t.privacy)?n.privacy=t.privacy:e.push(`\`privacy\` must be one of ${H.join(", ")}`)),t.unlisted!==void 0&&(typeof t.unlisted!="boolean"?e.push("`unlisted` must be a boolean"):n.unlisted=t.unlisted),t.lint_ignore!==void 0){const s=t.lint_ignore;!Array.isArray(s)||s.some(c=>typeof c!="string")?e.push("`lint_ignore` must be a list of strings"):n.lintIgnore=s}if(t.extensions!==void 0){const s=t.extensions;typeof s!="object"||s===null||Array.isArray(s)||Object.values(s).some(c=>typeof c!="object"||c===null||Array.isArray(c))?e.push("`extensions` must map each plugin to an object of fields"):n.extensions=s}const f=ke(t.rules,e);return f!==void 0&&(n.rules=f),n}u(Y,"fieldsFrom");function Z(t){if(t.length>0)throw b(t.join("; "),{errors:t})}u(Z,"failOn");function J(t,e,n,o){const i=K(n).filter(a=>"remote"in U(t,e,a));return{...o.length>0?{unresolved_links:o}:{},...i.length>0?{remote_links:i}:{}}}u(J,"linkReport");function Oe(t){const e=D(t),n=[],o=e.name;(typeof o!="string"||!G.test(o))&&n.push("`name` must be segments of letters, digits, `_` or `-` joined by `/`"),typeof e.body!="string"&&n.push("`body` must be a string"),typeof e.preview!="string"&&n.push("`preview` is required");const i=e.kind??"knowledge";P.includes(i)||n.push(i==="report"?"reports are written only by `crtr push`":`\`kind\` must be one of ${P.join(", ")}`);const a=Y(e,n);e.cwd!==void 0&&typeof e.cwd!="string"&&n.push("`cwd` must be a string"),Z(n);const r=e,{dto:f,change:s}=E(c=>{const h=k(c,t),d=W(c,h,r.owner,r.cwd);if(!V(c,h,d))throw new g(404,"not_found",`no owner ${d.name} you can write to`);try{const{object:p,unresolved:l}=pe(c,h,{...a,owner:d,name:r.name,kind:i,preview:a.preview,privacy:a.privacy??"public"},r.body,x(c));return{dto:{id:p.id,name:j(c,p),...J(c,h,r.body,l)},change:T(c,h,[p],r.cwd)}}catch(p){C(p)}});return N(s),f}u(Oe,"write");function $e(t,e){let n=t;e.forEach(({old:o,new:i},a)=>{const r=o===""?-1:n.indexOf(o);if(r<0)throw _(422,"replace_no_match",`replace[${a}]: old text not found in the revision you read`,"Copy the old text exactly from your last read and rerun.",{index:a});if(n.indexOf(o,r+1)>=0)throw _(422,"replace_ambiguous",`replace[${a}]: old text occurs more than once`,"Include more surrounding text so the old text matches once, and rerun.",{index:a});n=n.slice(0,r)+i+n.slice(r+o.length)})}u($e,"checkReplacements");function Ae(t){const e=D(t),n=[],o=e.body!==void 0,i=e.replace!==void 0;o&&i&&n.push("give `body` or `replace`, not both"),o&&typeof e.body!="string"&&n.push("`body` must be a string");const a=e.replace;i&&(!Array.isArray(a)||a.length===0||a.some(d=>typeof d!="object"||d===null||typeof d.old!="string"||typeof d.new!="string"))&&n.push("`replace` must be a non-empty list of {old, new} strings"),(typeof e.rationale!="string"||e.rationale.trim()==="")&&n.push("`rationale` is required"),e.verbatim!==void 0&&typeof e.verbatim!="boolean"&&n.push("`verbatim` must be a boolean");const r=Y(e,n),f=e.unset??[];if(!Array.isArray(f)||f.some(d=>!q.includes(d)))n.push(`\`unset\` takes only ${q.join(", ")}`);else for(const d of f)d==="summary"&&(r.summary=null),d==="why_it_exists"&&(r.whyItExists=null),d==="unlisted"&&(r.unlisted=!1),d==="lint_ignore"&&(r.lintIgnore=null),d==="extensions"&&(r.extensions=null),d==="rules"&&(r.rules=[]);!o&&!i&&Object.keys(r).length===0&&n.push("nothing to change: give `body`, `replace`, or a field"),Z(n);const s=e,{dto:c,synced:h}=E(d=>{const p=k(d,t),l=B(d,p,t.params.ref),v=j(d,l),$=T(d,p,[l]);try{if(!o&&!i)return le(d,p,l,r),{dto:{id:l.id,name:v,revision:F(d,l).revision},synced:$};const w=fe(d,p,l);if(i&&w!==null){const te=F(d,l),L=I(d,l);te.heads_key===w&&L.length===1&&$e(me(d,l,A(L[0].body_hash)),s.replace)}const R=s.verbatim===!0,m=o?{body:s.body,verbatim:R}:{replace:s.replace,verbatim:R},y=ce(d,p,l,m,s.rationale,w,r,x(d));if("stale"in y)throw _(409,"stale_revision",`${v} changed after your read; it is now at revision ${y.stale.revision}`,`Read it again with \`crtr canvas read ${v}\`, then redo your change on the current text.`,{stale:y.stale});const S=A(I(d,l)[0].body_hash);return{dto:{id:l.id,name:v,revision:y.revision,...J(d,p,S,y.unresolved)},synced:$}}catch(w){C(w,l)}});return N(h),c}u(Ae,"edit");function je(t){const e=D(t);if(e.new_name===void 0&&e.owner===void 0)throw b("give a new name, an owner, or both");if(e.new_name!==void 0&&(typeof e.new_name!="string"||!G.test(e.new_name)))throw b("`new_name` must be segments of letters, digits, `_` or `-` joined by `/`");const{dto:n,change:o}=E(i=>{const a=k(i,t),r=B(i,a,t.params.ref),f=e.owner===void 0?void 0:W(i,a,e.owner,e.cwd);try{const s=ue(i,a,r,{...e.new_name!==void 0?{name:e.new_name}:{},...f?{owner:f}:{}});return{dto:{id:s.id,name:j(i,s)},change:T(i,a,[r,s],e.cwd)}}catch(s){C(s,r)}});return N(o),n}u(je,"move");function Re(t){const{dto:e,change:n}=E(o=>{const i=k(o,t),a=B(o,i,t.params.ref),r=j(o,a),f=T(o,i,[a]);try{ae(o,i,a,x(o))}catch(s){C(s,a)}return{dto:{id:a.id,name:r},change:f}});return N(n),e}u(Re,"remove");function De(t){const e=t.query.get("diff"),n=e===null?void 0:Number(e);if(n!==void 0&&!(Number.isInteger(n)&&n>0))throw b("`diff` must be a revision number");return E(o=>{const i=k(o,t),a=X(o,i,decodeURIComponent(t.params.ref));if("remote"in a)throw _(404,"not_found",z(a.remote),"Check the name with `crtr canvas search`.");const r="deleted"in a?a.deleted:a;if(r.type!=="document")throw b(`${r.name} is a ${r.type}, not a document`);const f=de(o,i,r),s={object:be(o,r),revisions:f.map(c=>({rev_id:c.rev_id,number:c.number,author_id:c.author,rationale:c.rationale,verbatim:c.verbatim,created_at:c.created_at,parents:c.parents}))};if(n!==void 0){const c=f.find(d=>d.number===n);if(!c)throw new g(404,"not_found",`${r.name} has no revision ${n}`);const h=c.parents[0]===void 0?void 0:f.find(d=>d.rev_id===c.parents[0]);s.diff=ge(h?A(h.body_hash):"",A(c.body_hash))}return s})}u(De,"revisionHistory");const Q=1e3,ee=1e3,ne=3e3,Ce=/^When\b.+\bbecause\b.+/,Te=u(t=>{const e=t.trim();return e===""?0:e.split(/\s+/).length},"words");function Ne(t,e){if(t.some(o=>o.on==="boot"&&o.deliver==="content")&&e>Q)return`body is ${e} words, over the ${Q}-word cap for a boot rule at content (the whole body enters every node's context). Keep the core here and move separate subjects into [[linked]] documents.`;const n=[...new Set(t.filter(o=>o.on!=="boot"&&o.deliver==="content").map(o=>o.on))];return n.length>0&&e>ee?`body is ${e} words, over the ${ee}-word cap for a content rule on ${n.join("/")}. Keep the core here and move separate subjects into [[linked]] documents.`:t.some(o=>o.on==="boot"&&o.deliver==="preview")&&e>ne?`body is ${e} words, over the ${ne}-word cap for a boot rule at preview. Keep the core here and move separate subjects into [[linked]] documents.`:null}u(Ne,"lengthFinding");function Se(t){const e=D(t);return E(n=>{const o=k(n,t),i=e.owner===void 0?null:W(n,o,e.owner,e.cwd),a=n.prepare("SELECT * FROM objects WHERE type = 'document' AND deleted_at IS NULL AND kind != 'report' ORDER BY name").all(),r=[],f=new Map;for(const s of a){if(i&&s.owner!==i.rowid||!V(n,o,s))continue;const c=F(n,s),h=new Set(c.lint_ignore??[]),d=j(n,s),p=u((m,y,S)=>{h.has(m)||r.push({name:d,severity:y,rule:m,message:S})},"add"),l=ve(n,s),v=I(n,s)[0],$=v?A(v.body_hash):"",w=Ne(l,Te($));w&&p("length","error",w),l.some(m=>m.deliver==="preview")&&!Ce.test(s.preview??"")&&p("preview-shape","error",`a rule delivers this document at preview, so the preview must read "When <situation in the reader's work>, read this because <what the reader gains>"`);const R=new Set(n.prepare("SELECT written_as FROM edges WHERE type = 'links-to' AND src = ?").all(s.rowid).map(m=>m.written_as));for(const m of K($))R.has(m)||"remote"in U(n,o,m)||p("links","warning",`[[${m}]] names no object in your view`);if(l.some(m=>m.on==="workspace-open"&&m.deliver==="content")){const m=se(n,s);m.type==="repo"&&!h.has("workspace-open")&&f.set(m.name,[...f.get(m.name)??[],d])}}for(const[s,c]of f)if(!(c.length<2))for(const h of c)r.push({name:h,severity:"warning",rule:"workspace-open",message:`repo ${s} has ${c.length} documents delivered at content on workspace-open (${c.join(", ")}); keep one and link the rest from it`});return{findings:r}})}u(Se,"lint");const O=u((t,e=200)=>n=>({status:e,body:t(n)}),"ok"),Ze=[{method:"POST",pattern:"/v1/docs",handler:O(Oe,201)},{method:"PATCH",pattern:"/v1/docs/:ref",handler:O(Ae)},{method:"POST",pattern:"/v1/docs/:ref/move",handler:O(je)},{method:"DELETE",pattern:"/v1/docs/:ref",handler:O(Re)},{method:"GET",pattern:"/v1/docs/:ref/history",handler:O(De)},{method:"POST",pattern:"/v1/docs/lint",handler:O(Se)}];export{Ze as docRoutes};
1
+ var oe=Object.defineProperty;var u=(t,e)=>oe(t,"name",{value:e,configurable:!0});import{ApiError as g}from"../../../api/errors.js";import{DOC_KINDS as P,DOC_UNSET_FIELDS as q}from"../../../api/dto/docs.js";import{PRIVACY_LEVELS_DTO as H}from"../../../api/dto/objects.js";import{withCanvasWrite as k}from"../../../core/canvas/db.js";import{CrtrError as re}from"../../../core/errors.js";import{emitEvent as ie}from"../../../core/events/emit.js";import{canChange as V,spaceOf as se}from"../../../core/graph/access.js";import{get as A}from"../../../core/graph/bodies.js";import{deleteDocument as ae,documentRecord as F,editDocument as ce,heads as I,history as de,linksIn as K,moveDocument as ue,readBase as fe,setDocumentRecord as le,withCurrentNames as me,writeDocument as pe}from"../../../core/graph/documents.js";import{resolveName as U}from"../../../core/graph/names.js";import{getByRowid as M}from"../../../core/graph/objects.js";import{noteRepoDocumentsChanged as he}from"../../../core/graph/repo-sync/index.js";import{reposForCwd as we}from"../../../core/graph/repo-sync/repos.js";import{lintRules as ye,rulesOf as ve}from"../../../core/graph/rules.js";import{unifiedDiff as ge}from"../../../core/graph/diff.js";import{ownerFromFlag as W,readerFor as E,resolveRef as X}from"../reader.js";function _(t,e,n,o,i={}){return new g(t,e,n,{...i,error:e,message:n,next:o})}u(_,"refuse");const b=u((t,e)=>new g(400,"invalid_request",t,e),"invalid");function D(t){const e=t.body;if(e===void 0)return{};if(typeof e!="object"||e===null||Array.isArray(e))throw b("the request body must be a JSON object");return e}u(D,"bodyOf");const x=u(t=>e=>we(t,e),"reposFnFor");function C(t,e){if(t instanceof re){const n=t.details;if(t.code==="read_first")throw _(409,"read_first",t.message,`Read it first with \`crtr canvas read ${e?.id??"<ref>"}\`, then rerun the edit.`,n??{});if(t.code==="conflict")throw new g(409,"name_taken",t.message,n);if(t.code==="forbidden")throw new g(403,"forbidden",t.message,n);if(n?.rule==="repo-public-only")throw _(422,"repo_documents_are_public",t.message,'Own it as `user` and add a rule with `if: {"repo": "<handle>"}` so it loads only in that repo.')}throw t}u(C,"mapGraphError");function B(t,e,n){const o=X(t,e,decodeURIComponent(n));if("remote"in o)throw _(404,"not_found",z(o.remote),"Check the name with `crtr canvas search`.");if("deleted"in o)throw new g(404,"not_found",`${o.deleted.name} is deleted`,{id:o.deleted.id,deleted:!0});if(o.type!=="document")throw b(`${n} is a ${o.type}, not a document`);return o}u(B,"refDocument");function z(t){return`no object named ${t} on this runtime; it may be on another runtime, or the name may be misspelled`}u(z,"remoteMessage");function _e(t,e){const n=e.owner===null?null:M(t,e.owner);return n?n.type==="node"?n.id:n.name:""}u(_e,"ownerHandle");function j(t,e){const n=_e(t,e);return n?`${n}/${e.name}`:e.name}u(j,"canonicalName");function be(t,e){const n=e.owner===null?null:M(t,e.owner),o=n?{id:n.id,type:n.type,handle:n.type==="node"?n.id:n.name}:null;return{id:e.id,type:e.type,kind:e.kind,owner:o,privacy:e.privacy,name:e.name,preview:e.preview??"",created_at:e.created_at,deleted_at:e.deleted_at}}u(be,"objectDTO");function ke(t,e){const n=e.owner===null?null:M(t,e.owner);return n?.type==="repo"?n:null}u(ke,"repoOwner");function T(t,e,n,o){const i=[...new Map(n.flatMap(r=>{const f=ke(t,r);return f?[[f.id,f]]:[]})).values()],a=e.class==="node"?e.cwd:o;return{repos:i,...a!==void 0?{cwd:a}:{}}}u(T,"repoChange");function N(t){for(const e of t.repos)try{he(e,t.cwd)}catch(n){ie({level:"warn",event:"repo_sync.failed",outcome:"failed",error:n,fields:{repo:e.name,step:"export",reason:n instanceof Error?n.message:String(n)}})}}u(N,"syncChanged");const G=/^[A-Za-z0-9_-]+(\/[A-Za-z0-9_-]+)*$/;function Ee(t,e){if(t===void 0)return;if(!Array.isArray(t)){e.push("`rules` must be a list");return}const n=t.map(i=>{if(typeof i!="object"||i===null||Array.isArray(i))return i;const{match_frontmatter:a,...r}=i;return"matchFrontmatter"in r?{...r,match_frontmatter:r.matchFrontmatter}:a===void 0?r:{...r,matchFrontmatter:a}}),o=ye(n);if(o){e.push(o.replaceAll("matchFrontmatter","match_frontmatter"));return}return n}u(Ee,"rulesFromDTO");function Y(t,e){const n={},o=u(s=>{const c=t[s];if(c!==void 0){if(typeof c!="string"){e.push(`\`${s}\` must be a string`);return}return c}},"str"),i=o("preview");i!==void 0&&(i.trim()===""||/[\r\n]/.test(i)?e.push("`preview` must be one non-empty line"):n.preview=i);const a=o("summary");a!==void 0&&(n.summary=a);const r=o("why_it_exists");if(r!==void 0&&(n.whyItExists=r),t.privacy!==void 0&&(H.includes(t.privacy)?n.privacy=t.privacy:e.push(`\`privacy\` must be one of ${H.join(", ")}`)),t.unlisted!==void 0&&(typeof t.unlisted!="boolean"?e.push("`unlisted` must be a boolean"):n.unlisted=t.unlisted),t.lint_ignore!==void 0){const s=t.lint_ignore;!Array.isArray(s)||s.some(c=>typeof c!="string")?e.push("`lint_ignore` must be a list of strings"):n.lintIgnore=s}if(t.extensions!==void 0){const s=t.extensions;typeof s!="object"||s===null||Array.isArray(s)||Object.values(s).some(c=>typeof c!="object"||c===null||Array.isArray(c))?e.push("`extensions` must map each plugin to an object of fields"):n.extensions=s}const f=Ee(t.rules,e);return f!==void 0&&(n.rules=f),n}u(Y,"fieldsFrom");function Z(t){if(t.length>0)throw b(t.join("; "),{errors:t})}u(Z,"failOn");function J(t,e,n,o){const i=K(n).filter(a=>"remote"in U(t,e,a));return{...o.length>0?{unresolved_links:o}:{},...i.length>0?{remote_links:i}:{}}}u(J,"linkReport");function Oe(t){const e=D(t),n=[],o=e.name;(typeof o!="string"||!G.test(o))&&n.push("`name` must be segments of letters, digits, `_` or `-` joined by `/`"),typeof e.body!="string"&&n.push("`body` must be a string"),typeof e.preview!="string"&&n.push("`preview` is required");const i=e.kind??"knowledge";P.includes(i)||n.push(i==="report"?"reports are written only by `crtr push`":`\`kind\` must be one of ${P.join(", ")}`);const a=Y(e,n);e.cwd!==void 0&&typeof e.cwd!="string"&&n.push("`cwd` must be a string"),Z(n);const r=e,{dto:f,change:s}=k(c=>{const h=E(c,t),d=W(c,h,r.owner,r.cwd);if(!V(c,h,d))throw new g(404,"not_found",`no owner ${d.name} you can write to`);try{const{object:p,unresolved:l}=pe(c,h,{...a,owner:d,name:r.name,kind:i,preview:a.preview,privacy:a.privacy??"public"},r.body,x(c));return{dto:{id:p.id,name:j(c,p),...J(c,h,r.body,l)},change:T(c,h,[p],r.cwd)}}catch(p){C(p)}});return N(s),f}u(Oe,"write");function $e(t,e){let n=t;e.forEach(({old:o,new:i},a)=>{const r=o===""?-1:n.indexOf(o);if(r<0)throw _(422,"replace_no_match",`replace[${a}]: old text not found in the revision you read`,"Copy the old text exactly from your last read and rerun.",{index:a});if(n.indexOf(o,r+1)>=0)throw _(422,"replace_ambiguous",`replace[${a}]: old text occurs more than once`,"Include more surrounding text so the old text matches once, and rerun.",{index:a});n=n.slice(0,r)+i+n.slice(r+o.length)})}u($e,"checkReplacements");function Ae(t){const e=D(t),n=[],o=e.body!==void 0,i=e.replace!==void 0;o&&i&&n.push("give `body` or `replace`, not both"),o&&typeof e.body!="string"&&n.push("`body` must be a string");const a=e.replace;i&&(!Array.isArray(a)||a.length===0||a.some(d=>typeof d!="object"||d===null||typeof d.old!="string"||typeof d.new!="string"))&&n.push("`replace` must be a non-empty list of {old, new} strings"),(typeof e.rationale!="string"||e.rationale.trim()==="")&&n.push("`rationale` is required"),e.verbatim!==void 0&&typeof e.verbatim!="boolean"&&n.push("`verbatim` must be a boolean"),e.base!==void 0&&(typeof e.base!="string"||e.base==="")&&n.push("`base` must be a non-empty heads key"),e.base!==void 0&&!o&&!i&&n.push("`base` applies only to a `body` or `replace` edit");const r=Y(e,n),f=e.unset??[];if(!Array.isArray(f)||f.some(d=>!q.includes(d)))n.push(`\`unset\` takes only ${q.join(", ")}`);else for(const d of f)d==="summary"&&(r.summary=null),d==="why_it_exists"&&(r.whyItExists=null),d==="unlisted"&&(r.unlisted=!1),d==="lint_ignore"&&(r.lintIgnore=null),d==="extensions"&&(r.extensions=null),d==="rules"&&(r.rules=[]);!o&&!i&&Object.keys(r).length===0&&n.push("nothing to change: give `body`, `replace`, or a field"),Z(n);const s=e,{dto:c,synced:h}=k(d=>{const p=E(d,t),l=B(d,p,t.params.ref),v=j(d,l),$=T(d,p,[l]);try{if(!o&&!i)return le(d,p,l,r),{dto:{id:l.id,name:v,revision:F(d,l).revision},synced:$};const w=s.base??fe(d,p,l);if(i&&w!==null){const te=F(d,l),L=I(d,l);te.heads_key===w&&L.length===1&&$e(me(d,l,A(L[0].body_hash)),s.replace)}const R=s.verbatim===!0,m=o?{body:s.body,verbatim:R}:{replace:s.replace,verbatim:R},y=ce(d,p,l,m,s.rationale,w,r,x(d));if("stale"in y)throw _(409,"stale_revision",`${v} changed after your read; it is now at revision ${y.stale.revision}`,`Read it again with \`crtr canvas read ${v}\`, then redo your change on the current text.`,{stale:y.stale});const S=A(I(d,l)[0].body_hash);return{dto:{id:l.id,name:v,revision:y.revision,...J(d,p,S,y.unresolved)},synced:$}}catch(w){C(w,l)}});return N(h),c}u(Ae,"edit");function je(t){const e=D(t);if(e.new_name===void 0&&e.owner===void 0)throw b("give a new name, an owner, or both");if(e.new_name!==void 0&&(typeof e.new_name!="string"||!G.test(e.new_name)))throw b("`new_name` must be segments of letters, digits, `_` or `-` joined by `/`");const{dto:n,change:o}=k(i=>{const a=E(i,t),r=B(i,a,t.params.ref),f=e.owner===void 0?void 0:W(i,a,e.owner,e.cwd);try{const s=ue(i,a,r,{...e.new_name!==void 0?{name:e.new_name}:{},...f?{owner:f}:{}});return{dto:{id:s.id,name:j(i,s)},change:T(i,a,[r,s],e.cwd)}}catch(s){C(s,r)}});return N(o),n}u(je,"move");function Re(t){const{dto:e,change:n}=k(o=>{const i=E(o,t),a=B(o,i,t.params.ref),r=j(o,a),f=T(o,i,[a]);try{ae(o,i,a,x(o))}catch(s){C(s,a)}return{dto:{id:a.id,name:r},change:f}});return N(n),e}u(Re,"remove");function De(t){const e=t.query.get("diff"),n=e===null?void 0:Number(e);if(n!==void 0&&!(Number.isInteger(n)&&n>0))throw b("`diff` must be a revision number");return k(o=>{const i=E(o,t),a=X(o,i,decodeURIComponent(t.params.ref));if("remote"in a)throw _(404,"not_found",z(a.remote),"Check the name with `crtr canvas search`.");const r="deleted"in a?a.deleted:a;if(r.type!=="document")throw b(`${r.name} is a ${r.type}, not a document`);const f=de(o,i,r),s={object:be(o,r),revisions:f.map(c=>({rev_id:c.rev_id,number:c.number,author_id:c.author,rationale:c.rationale,verbatim:c.verbatim,created_at:c.created_at,parents:c.parents}))};if(n!==void 0){const c=f.find(d=>d.number===n);if(!c)throw new g(404,"not_found",`${r.name} has no revision ${n}`);const h=c.parents[0]===void 0?void 0:f.find(d=>d.rev_id===c.parents[0]);s.diff=ge(h?A(h.body_hash):"",A(c.body_hash))}return s})}u(De,"revisionHistory");const Q=1e3,ee=1e3,ne=3e3,Ce=/^When\b.+\bbecause\b.+/,Te=u(t=>{const e=t.trim();return e===""?0:e.split(/\s+/).length},"words");function Ne(t,e){if(t.some(o=>o.on==="boot"&&o.deliver==="content")&&e>Q)return`body is ${e} words, over the ${Q}-word cap for a boot rule at content (the whole body enters every node's context). Keep the core here and move separate subjects into [[linked]] documents.`;const n=[...new Set(t.filter(o=>o.on!=="boot"&&o.deliver==="content").map(o=>o.on))];return n.length>0&&e>ee?`body is ${e} words, over the ${ee}-word cap for a content rule on ${n.join("/")}. Keep the core here and move separate subjects into [[linked]] documents.`:t.some(o=>o.on==="boot"&&o.deliver==="preview")&&e>ne?`body is ${e} words, over the ${ne}-word cap for a boot rule at preview. Keep the core here and move separate subjects into [[linked]] documents.`:null}u(Ne,"lengthFinding");function Se(t){const e=D(t);return k(n=>{const o=E(n,t),i=e.owner===void 0?null:W(n,o,e.owner,e.cwd),a=n.prepare("SELECT * FROM objects WHERE type = 'document' AND deleted_at IS NULL AND kind != 'report' ORDER BY name").all(),r=[],f=new Map;for(const s of a){if(i&&s.owner!==i.rowid||!V(n,o,s))continue;const c=F(n,s),h=new Set(c.lint_ignore??[]),d=j(n,s),p=u((m,y,S)=>{h.has(m)||r.push({name:d,severity:y,rule:m,message:S})},"add"),l=ve(n,s),v=I(n,s)[0],$=v?A(v.body_hash):"",w=Ne(l,Te($));w&&p("length","error",w),l.some(m=>m.deliver==="preview")&&!Ce.test(s.preview??"")&&p("preview-shape","error",`a rule delivers this document at preview, so the preview must read "When <situation in the reader's work>, read this because <what the reader gains>"`);const R=new Set(n.prepare("SELECT written_as FROM edges WHERE type = 'links-to' AND src = ?").all(s.rowid).map(m=>m.written_as));for(const m of K($))R.has(m)||"remote"in U(n,o,m)||p("links","warning",`[[${m}]] names no object in your view`);if(l.some(m=>m.on==="workspace-open"&&m.deliver==="content")){const m=se(n,s);m.type==="repo"&&!h.has("workspace-open")&&f.set(m.name,[...f.get(m.name)??[],d])}}for(const[s,c]of f)if(!(c.length<2))for(const h of c)r.push({name:h,severity:"warning",rule:"workspace-open",message:`repo ${s} has ${c.length} documents delivered at content on workspace-open (${c.join(", ")}); keep one and link the rest from it`});return{findings:r}})}u(Se,"lint");const O=u((t,e=200)=>n=>({status:e,body:t(n)}),"ok"),Ze=[{method:"POST",pattern:"/v1/docs",handler:O(Oe,201)},{method:"PATCH",pattern:"/v1/docs/:ref",handler:O(Ae)},{method:"POST",pattern:"/v1/docs/:ref/move",handler:O(je)},{method:"DELETE",pattern:"/v1/docs/:ref",handler:O(Re)},{method:"GET",pattern:"/v1/docs/:ref/history",handler:O(De)},{method:"POST",pattern:"/v1/docs/lint",handler:O(Se)}];export{Ze as docRoutes};