@north-light/crouter 0.3.354 → 0.3.356
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.
- package/dist/api/dto/delivery.d.ts +13 -3
- package/dist/api/dto/docs.d.ts +2 -0
- package/dist/api/dto/objects.d.ts +25 -22
- package/dist/api/dto/objects.js +1 -1
- package/dist/api/dto/reviews.d.ts +6 -4
- package/dist/builtin-memory/02-turn-lifecycle/02-resident.md +1 -0
- package/dist/builtin-memory/04-orchestration-kernel.md +10 -31
- package/dist/builtin-memory/internal/memory-loading.md +1 -1
- package/dist/clients/attach/overlays/file-review.d.ts +1 -0
- package/dist/clients/attach/overlays/file-review.js +2 -2
- package/dist/clients/attach/render/chat-view.d.ts +6 -0
- package/dist/clients/attach/render/chat-view.js +2 -2
- package/dist/clients/attach/render/doc-links.d.ts +34 -0
- package/dist/clients/attach/render/doc-links.js +1 -0
- package/dist/clients/attach/render/markdown-source.js +5 -5
- package/dist/clients/attach/session/doc-materialize.d.ts +53 -0
- package/dist/clients/attach/session/doc-materialize.js +3 -0
- package/dist/clients/attach/session/document-links.d.ts +21 -0
- package/dist/clients/attach/session/document-links.js +1 -0
- package/dist/clients/attach/session/file-links.d.ts +2 -0
- package/dist/clients/attach/session/file-links.js +1 -1
- package/dist/clients/attach/viewer.js +837 -761
- package/dist/clients/inbox/review/review-client.d.ts +5 -1
- package/dist/clients/inbox/review/review-client.js +1 -1
- package/dist/commands/canvas/list.js +3 -3
- package/dist/commands/canvas/read.d.ts +2 -4
- package/dist/commands/canvas/read.js +3 -5
- package/dist/commands/canvas/search.js +1 -1
- package/dist/commands/doc/write.js +1 -1
- package/dist/commands/node/lifecycle.js +2 -2
- package/dist/commands/sys/context/admin/actions.js +1 -1
- package/dist/commands/sys/sync-deps.js +1 -1
- package/dist/commands/sys/sync-shared.js +1 -1
- package/dist/core/canvas/daemon-actions.d.ts +43 -0
- package/dist/core/canvas/daemon-actions.js +26 -0
- package/dist/core/canvas/deliveries.d.ts +1 -0
- package/dist/core/canvas/deliveries.js +1 -1
- package/dist/core/canvas/migrations.js +106 -46
- package/dist/core/feed/messages.d.ts +2 -20
- package/dist/core/feed/messages.js +6 -10
- package/dist/core/graph/deletion.d.ts +5 -4
- package/dist/core/graph/deletion.js +3 -3
- package/dist/core/graph/documents.d.ts +8 -1
- package/dist/core/graph/documents.js +9 -6
- package/dist/core/graph/edges.d.ts +3 -2
- package/dist/core/graph/edges.js +1 -1
- package/dist/core/graph/events.d.ts +11 -6
- package/dist/core/graph/events.js +5 -4
- package/dist/core/graph/jobs.js +2 -2
- package/dist/core/graph/kinds/document.d.ts +19 -0
- package/dist/core/graph/kinds/document.js +5 -0
- package/dist/core/graph/kinds/dto.d.ts +5 -0
- package/dist/core/graph/kinds/dto.js +1 -0
- package/dist/core/graph/kinds/job.d.ts +2 -0
- package/dist/core/graph/kinds/job.js +2 -0
- package/dist/core/graph/kinds/kind.d.ts +39 -0
- package/dist/core/graph/kinds/kind.js +1 -0
- package/dist/core/graph/kinds/node.d.ts +2 -0
- package/dist/core/graph/kinds/node.js +4 -0
- package/dist/core/graph/kinds/owner.d.ts +2 -0
- package/dist/core/graph/kinds/owner.js +2 -0
- package/dist/core/graph/kinds/registry.d.ts +8 -0
- package/dist/core/graph/kinds/registry.js +1 -0
- package/dist/core/graph/kinds/render.d.ts +9 -0
- package/dist/core/graph/kinds/render.js +1 -0
- package/dist/core/graph/names.d.ts +3 -1
- package/dist/core/graph/names.js +3 -3
- package/dist/core/graph/objects.d.ts +5 -4
- package/dist/core/graph/objects.js +5 -5
- package/dist/core/graph/repo-sync/exchange.js +2 -2
- package/dist/core/graph/types.d.ts +6 -5
- package/dist/core/runs/operations.js +5 -5
- package/dist/core/runtime/broker-persona-guidance.js +2 -2
- package/dist/core/runtime/broker-protocol.d.ts +2 -7
- package/dist/core/runtime/persona.js +2 -2
- package/dist/core/runtime/roadmap.d.ts +3 -0
- package/dist/core/runtime/roadmap.js +8 -4
- package/dist/core/substrate/delivery/deliver.js +1 -1
- package/dist/core/substrate/delivery/listings.d.ts +3 -0
- package/dist/core/substrate/delivery/listings.js +5 -2
- package/dist/core/substrate/delivery/render-boot.js +26 -26
- package/dist/core/substrate/delivery/render-event.d.ts +13 -6
- package/dist/core/substrate/delivery/render-event.js +6 -4
- package/dist/daemon/api/handlers/docs.js +1 -1
- package/dist/daemon/api/handlers/human-requests.js +1 -1
- package/dist/daemon/api/handlers/objects.js +2 -5
- package/dist/daemon/api/handlers/reviews.d.ts +4 -1
- package/dist/daemon/api/handlers/reviews.js +1 -1
- package/dist/daemon/cron/settle.js +1 -1
- package/dist/daemon/cron/sinks.d.ts +3 -3
- package/dist/daemon/cron/sinks.js +2 -2
- package/dist/daemon/crtrd.js +6 -6
- package/dist/daemon/human/finish.js +6 -6
- package/dist/daemon/human/settle.d.ts +2 -3
- package/dist/daemon/human/settle.js +1 -1
- package/dist/daemon/reconcilers/action-lane.d.ts +8 -0
- package/dist/daemon/reconcilers/action-lane.js +1 -0
- package/dist/daemon/reconcilers/delivery-lane.d.ts +1 -1
- package/dist/daemon/reconcilers/delivery-lane.js +1 -1
- package/dist/shared/inbox-entry-body.js +7 -7
- package/package.json +2 -2
- package/packages/crouter-identity/package.json +1 -1
- package/runtime.lock.json +11 -11
- package/scripts/lib/isolation-env.mjs +8 -2
|
@@ -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};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var N=Object.defineProperty;var o=(e,t)=>N(e,"name",{value:t,configurable:!0});import{statSync as P}from"node:fs";import{isAbsolute as T}from"node:path";import{ApiError as s}from"../../../api/index.js";import{readExternalActionDelivery as C}from"../../../core/canvas/deliveries.js";import{isSafeNodeId as I}from"../../../core/canvas/paths.js";import{getNode as b}from"../../../core/canvas/canvas.js";import{assertScope as $}from"../../../core/scopes.js";import{resolvePageComponents as g}from"../../../core/config.js";import{resolveHumanAction as x}from"../../../core/human-actions.js";import{HUMAN_ACTION_NAME_PATTERN as D}from"../../../core/human/action-binding.js";import{createPageRequest as J,getRequest as F}from"../../../core/human/requests.js";import{preparePageSource as M}from"../../../core/human/page-authoring.js";import{publishPage as G,validatePageTicketResponses as H}from"../../../core/human/tickets.js";import{cancelHumanTicket as L,resolvePageTicket as U}from"../../human/finish.js";import{inboxPageProjection as B}from"./inbox-page.js";const K=1e3,q=200,m={placement:"inline",inbox:!0,reply:!1},v=["sessionName","askedBy","emittedAt","profileName","nodeId"];function c(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}o(c,"isPlainObject");function l(e,t,n){for(const r of Object.keys(e))if(!t.includes(r))throw new s(400,"invalid_request",`unexpected field in ${n}: ${r}`)}o(l,"requireNoExtraKeys");function i(e){return new s(400,"invalid_request",e)}o(i,"invalid");function w(e){if(!c(e))throw i("`page` must be an object");if(l(e,["dialect","source"],"`page`"),e.dialect!=="jsx"&&e.dialect!=="html")throw i('`page.dialect` must be "jsx" or "html"');if(typeof e.source!="string"||e.source.trim()==="")throw i("`page.source` must be the authored page text");return{dialect:e.dialect,source:e.source}}o(w,"validatePage");function S(e,t){const n=e??t;if(n!=="inline"&&n!=="panel")throw i('`delivery.placement` must be "inline" or "panel"');return n}o(S,"validatePlacement");function X(e,t){if(e===void 0)return m;if(!c(e))throw i("`delivery` must be an object");l(e,["placement","inbox","reply"],"`delivery`");const n=e.inbox??m.inbox,r=e.reply??m.reply;if(typeof n!="boolean")throw i("`delivery.inbox` must be boolean");if(typeof r!="boolean")throw i("`delivery.reply` must be boolean");if(r&&t===null)throw i("`delivery.reply` requires `requester_node_id`");return{placement:S(e.placement,m.placement),inbox:n,reply:r}}o(X,"validateCreateDelivery");function z(e,t){if(e===void 0)return t;if(!c(e))throw i("`delivery` must be an object");return l(e,["placement"],"`delivery`"),{...t,placement:S(e.placement,t.placement)}}o(z,"validateReplaceDelivery");function V(e){if(e===void 0)return;if(!c(e))throw i("`source` must be an object");l(e,v,"`source`");const t={};for(const n of v){const r=e[n];if(r!==void 0){if(typeof r!="string"||r==="")throw i(`\`source.${n}\` must be a nonempty string`);t[n]=r}}return t}o(V,"validateSource");function Y(e){if(typeof e!="string"||e==="")throw i("`creator_cwd` is required");if(!T(e))throw i("`creator_cwd` must be an absolute path");try{if(!P(e).isDirectory())throw i(`\`creator_cwd\` is not a directory: ${e}`)}catch(t){throw t instanceof s?t:i(`\`creator_cwd\` does not exist: ${e}`)}return e}o(Y,"validateCreatorCwd");function Q(e){if(e!==void 0){if(!c(e))throw i("`action` must be an object");if(l(e,["name","payload"],"`action`"),typeof e.name!="string"||!D.test(e.name))throw i("`action.name` must be a declared action name");return{name:e.name,payload:e.payload??null}}}o(Q,"validateActionSelection");function W(e){if(e==null)return null;if(typeof e!="string"||!I(e))throw i("`requester_node_id` must be a safe node id or null");return e}o(W,"validateRequesterNodeId");function Z(e){if(!c(e))throw i("request body is required");l(e,["page","delivery","source","requester_node_id","creator_cwd","action"],"the request body");const t=V(e.source),n=W(e.requester_node_id),r=Q(e.action);return{page:w(e.page),delivery:X(e.delivery,n),...t===void 0?{}:{source:t},requesterNodeId:n,creatorCwd:Y(e.creator_cwd),...r===void 0?{}:{action:r}}}o(Z,"validateCreateRequest");function ee(e,t){if(!c(e))throw i("request body is required");return l(e,["page","delivery"],"the request body"),{page:w(e.page),delivery:z(e.delivery,t)}}o(ee,"validateReplaceRequest");function _(e,t,n){if(e!==void 0){if(typeof e!="string"||e.trim()===""||e.length>n)throw i(`\`${t}\` must be nonempty after trim and at most ${n} characters`);return e}}o(_,"optionalBoundedString");function te(e){if(!c(e))throw i("request body is required");if(l(e,["responses","actor"],"the request body"),!c(e.responses))throw i("`responses` must be an object");const t=_(e.actor,"actor",q);return{responses:e.responses,...t===void 0?{}:{actor:t}}}o(te,"validateRespondRequest");function ne(e){if(e===void 0)return{};if(!c(e))throw i("request body must be an object");l(e,["reason","actor"],"the request body");const t=_(e.reason,"reason",K),n=_(e.actor,"actor",q);return{...t===void 0?{}:{reason:t},...n===void 0?{}:{actor:n}}}o(ne,"validateSettleRequest");function h(e){const t=e.params.request_id;if(typeof t!="string"||t==="")throw i("request id is required");return t}o(h,"requestId");function f(e){const t=F(e);if(t===null||t.kind!=="page")throw new s(404,"not_found","no request with that id");return t}o(f,"requirePageRequest");function A(e){try{const t=JSON.parse(e.specification_json);if(!c(t))throw new Error("not an object");return t}catch{throw new s(500,"internal","the request specification could not be read")}}o(A,"manifest");function re(e){if(e.result_json===null)return null;try{return JSON.parse(e.result_json)}catch{throw new s(500,"internal","the request result could not be read")}}o(re,"terminalResult");function oe(e){if(e.action_json===null)return null;try{const t=JSON.parse(e.action_json);if(t.schema!=="crtr.human-action-binding/v1"||typeof t.name!="string")throw new Error("invalid action");return t}catch{throw new s(500,"internal","the request action could not be read")}}o(oe,"frozenAction");function ie(e){return e.state!=="settled"?"pending":e.outcome==="answered"?"answered":e.outcome==="dismissed"?"dismissed":"canceled"}o(ie,"requestState");function ae(e){if(e.action_delivery_id===null)return{state:"none",attempt:0};const t=C(`human-action:${e.inbox_ticket_id}`);if(t===null)return{state:"none",attempt:0};const n=t.state==="acknowledged"?"accepted":t.state==="permanent_failed"?"permanent_failed":t.state==="handed_off"?"running":"pending",r={state:n,attempt:t.attempts};return n==="pending"&&t.nextAttemptAt!==null&&(r.next_attempt_at=new Date(t.nextAttemptAt).toISOString()),t.acknowledgedAt!==null&&(r.accepted_at=new Date(t.acknowledgedAt).toISOString()),t.failedAt!==null&&(r.permanent_failed_at=new Date(t.failedAt).toISOString()),t.lastFailure!==null&&(r.last_failure=t.lastFailure),r}o(ae,"deliveryDetail");function y(e){const t=A(e),n=re(e),r=ie(e),a={request_id:e.request_id,inbox_ticket_id:e.inbox_ticket_id,request_dir:e.request_dir,kind:e.kind,state:r,title:e.title,source:t.source??{},emitted_at:t.source?.emittedAt??e.created_at};e.subtitle!==null&&(a.subtitle=e.subtitle),e.kind==="page"&&(a.page=B(e)),n!==null&&(a.settled_at=e.settled_at??e.updated_at,n.kind==="page"&&r==="answered"&&(a.responses=n.responses),n.kind==="canceled"&&n.reason!==void 0&&(a.reason=n.reason),n.kind==="page"&&n.actor!==void 0&&(a.actor=n.actor),n.kind==="canceled"&&n.actor!==void 0&&(a.actor=n.actor));const u=oe(e);return u!==null&&(a.action={name:u.name,payload:u.payload},a.delivery=ae(e)),a}o(y,"requestToDTO");function k(e,t,n,r){try{return M({dialect:e,document:t,source:n,delivery:r,productKinds:g()})}catch(a){throw i(a instanceof Error?a.message:"the page could not be prepared")}}o(k,"prepareOrReject");function se(e){const t=Z(e.body),n=t.requesterNodeId??t.source?.nodeId;if(n!=null){const d=b(n);d!==null&&$(d,"crtr:act")}let r;if(t.action!==void 0){const d=x(t.action.name,t.creatorCwd);if("kind"in d){const E=d.kind==="unknown_action"?`no action named ${d.name} is declared from ${t.creatorCwd}`:`${d.name} is declared in ${d.configOrigin} but unusable: ${d.reason}`;throw new s(400,d.kind,E)}const p=n==null?null:b(n);if(n&&!p)throw new s(404,"not_found","action requester node not found");if(p&&e.principal.class!=="person"&&p.grantee!==e.principal.app)throw new s(403,"permission_error","action requester belongs to another app");r=JSON.stringify({schema:"crtr.human-action-binding/v1",name:t.action.name,payload:t.action.payload,creatorCwd:t.creatorCwd,configOrigin:d.configOrigin,argv:d.argv,cwd:d.cwd,app:p?.grantee??(e.principal.class==="broker"?e.principal.app:"app:terminal")})}const a=k(t.page.dialect,t.page.source,t.source,t.delivery),u=J({prepared:a,requester_node_id:t.requesterNodeId,...r===void 0?{}:{action_json:r}});return{status:201,body:{request_id:u.request_id,request_dir:u.request_dir,state:"pending",...t.action===void 0?{}:{action:{name:t.action.name}},delivery_state:"none"}}}o(se,"handleCreate");function de(e){return{status:200,body:y(f(h(e)))}}o(de,"handleGet");function ce(e){const t=f(h(e));if(t.state==="settled")throw new s(409,"already_settled","the request already has a terminal result");const n=A(t),r=ee(e.body,n.delivery),a=k(r.page.dialect,r.page.source,n.source,r.delivery);try{G(t.request_dir,a)}catch(u){throw u instanceof Error&&u.message===`page request is not open: ${t.request_id}`?new s(409,"already_settled","the request already has a terminal result"):u}return{status:200,body:y(f(t.request_id))}}o(ce,"handleReplace");function O(e){return e instanceof s?e:e instanceof Error&&e.message.includes("unknown page request")?new s(404,"not_found","no request with that id"):e instanceof Error&&e.message==="page_has_no_response_lifecycle"?new s(409,"not_settleable","this request carries no response lifecycle"):new s(500,"internal","the request could not be settled")}o(O,"settlementError");function R(e){if(e.state==="settled")throw new s(409,"already_settled","the request already has a terminal result");if(!e.settleable)throw new s(409,"not_settleable","this request carries no response lifecycle")}o(R,"requireSettleable");async function ue(e){const t=f(h(e)),n=te(e.body);R(t);try{H(t.request_dir,n.responses)}catch(r){throw i(r instanceof Error?r.message:"the response map is invalid")}try{await U(t.request_id,n.responses,n.actor===void 0?{}:{actor:n.actor})}catch(r){throw O(r)}return{status:200,body:y(f(t.request_id))}}o(ue,"handleRespond");async function j(e,t){const n=f(h(e)),r=ne(e.body);R(n);try{await L(n.request_id,{...r,disposition:t})}catch(a){throw O(a)}return{status:200,body:y(f(n.request_id))}}o(j,"settle");function le(){return{status:200,body:{components:[...g()]}}}o(le,"handleComponents");const je=[{method:"GET",pattern:"/v1/human/components",handler:o(()=>le(),"handler")},{method:"POST",pattern:"/v1/human/requests",scope:"crtr:act",handler:se},{method:"GET",pattern:"/v1/human/requests/:request_id",handler:de},{method:"POST",pattern:"/v1/human/requests/:request_id/replace",handler:ce},{method:"POST",pattern:"/v1/human/requests/:request_id/respond",handler:ue},{method:"POST",pattern:"/v1/human/requests/:request_id/dismiss",handler:o(e=>j(e,"dismissed"),"handler")},{method:"POST",pattern:"/v1/human/requests/:request_id/cancel",handler:o(e=>j(e,"canceled"),"handler")}];export{je as humanRequestRoutes};
|
|
1
|
+
var N=Object.defineProperty;var o=(e,t)=>N(e,"name",{value:t,configurable:!0});import{statSync as P}from"node:fs";import{isAbsolute as T}from"node:path";import{ApiError as s}from"../../../api/index.js";import{readDaemonActionById as C}from"../../../core/canvas/daemon-actions.js";import{isSafeNodeId as I}from"../../../core/canvas/paths.js";import{getNode as b}from"../../../core/canvas/canvas.js";import{assertScope as $}from"../../../core/scopes.js";import{resolvePageComponents as g}from"../../../core/config.js";import{resolveHumanAction as D}from"../../../core/human-actions.js";import{HUMAN_ACTION_NAME_PATTERN as x}from"../../../core/human/action-binding.js";import{createPageRequest as J,getRequest as F}from"../../../core/human/requests.js";import{preparePageSource as M}from"../../../core/human/page-authoring.js";import{publishPage as B,validatePageTicketResponses as G}from"../../../core/human/tickets.js";import{cancelHumanTicket as H,resolvePageTicket as L}from"../../human/finish.js";import{inboxPageProjection as U}from"./inbox-page.js";const K=1e3,q=200,m={placement:"inline",inbox:!0,reply:!1},v=["sessionName","askedBy","emittedAt","profileName","nodeId"];function c(e){return typeof e=="object"&&e!==null&&!Array.isArray(e)}o(c,"isPlainObject");function l(e,t,n){for(const r of Object.keys(e))if(!t.includes(r))throw new s(400,"invalid_request",`unexpected field in ${n}: ${r}`)}o(l,"requireNoExtraKeys");function i(e){return new s(400,"invalid_request",e)}o(i,"invalid");function w(e){if(!c(e))throw i("`page` must be an object");if(l(e,["dialect","source"],"`page`"),e.dialect!=="jsx"&&e.dialect!=="html")throw i('`page.dialect` must be "jsx" or "html"');if(typeof e.source!="string"||e.source.trim()==="")throw i("`page.source` must be the authored page text");return{dialect:e.dialect,source:e.source}}o(w,"validatePage");function S(e,t){const n=e??t;if(n!=="inline"&&n!=="panel")throw i('`delivery.placement` must be "inline" or "panel"');return n}o(S,"validatePlacement");function X(e,t){if(e===void 0)return m;if(!c(e))throw i("`delivery` must be an object");l(e,["placement","inbox","reply"],"`delivery`");const n=e.inbox??m.inbox,r=e.reply??m.reply;if(typeof n!="boolean")throw i("`delivery.inbox` must be boolean");if(typeof r!="boolean")throw i("`delivery.reply` must be boolean");if(r&&t===null)throw i("`delivery.reply` requires `requester_node_id`");return{placement:S(e.placement,m.placement),inbox:n,reply:r}}o(X,"validateCreateDelivery");function z(e,t){if(e===void 0)return t;if(!c(e))throw i("`delivery` must be an object");return l(e,["placement"],"`delivery`"),{...t,placement:S(e.placement,t.placement)}}o(z,"validateReplaceDelivery");function V(e){if(e===void 0)return;if(!c(e))throw i("`source` must be an object");l(e,v,"`source`");const t={};for(const n of v){const r=e[n];if(r!==void 0){if(typeof r!="string"||r==="")throw i(`\`source.${n}\` must be a nonempty string`);t[n]=r}}return t}o(V,"validateSource");function Y(e){if(typeof e!="string"||e==="")throw i("`creator_cwd` is required");if(!T(e))throw i("`creator_cwd` must be an absolute path");try{if(!P(e).isDirectory())throw i(`\`creator_cwd\` is not a directory: ${e}`)}catch(t){throw t instanceof s?t:i(`\`creator_cwd\` does not exist: ${e}`)}return e}o(Y,"validateCreatorCwd");function Q(e){if(e!==void 0){if(!c(e))throw i("`action` must be an object");if(l(e,["name","payload"],"`action`"),typeof e.name!="string"||!x.test(e.name))throw i("`action.name` must be a declared action name");return{name:e.name,payload:e.payload??null}}}o(Q,"validateActionSelection");function W(e){if(e==null)return null;if(typeof e!="string"||!I(e))throw i("`requester_node_id` must be a safe node id or null");return e}o(W,"validateRequesterNodeId");function Z(e){if(!c(e))throw i("request body is required");l(e,["page","delivery","source","requester_node_id","creator_cwd","action"],"the request body");const t=V(e.source),n=W(e.requester_node_id),r=Q(e.action);return{page:w(e.page),delivery:X(e.delivery,n),...t===void 0?{}:{source:t},requesterNodeId:n,creatorCwd:Y(e.creator_cwd),...r===void 0?{}:{action:r}}}o(Z,"validateCreateRequest");function ee(e,t){if(!c(e))throw i("request body is required");return l(e,["page","delivery"],"the request body"),{page:w(e.page),delivery:z(e.delivery,t)}}o(ee,"validateReplaceRequest");function _(e,t,n){if(e!==void 0){if(typeof e!="string"||e.trim()===""||e.length>n)throw i(`\`${t}\` must be nonempty after trim and at most ${n} characters`);return e}}o(_,"optionalBoundedString");function te(e){if(!c(e))throw i("request body is required");if(l(e,["responses","actor"],"the request body"),!c(e.responses))throw i("`responses` must be an object");const t=_(e.actor,"actor",q);return{responses:e.responses,...t===void 0?{}:{actor:t}}}o(te,"validateRespondRequest");function ne(e){if(e===void 0)return{};if(!c(e))throw i("request body must be an object");l(e,["reason","actor"],"the request body");const t=_(e.reason,"reason",K),n=_(e.actor,"actor",q);return{...t===void 0?{}:{reason:t},...n===void 0?{}:{actor:n}}}o(ne,"validateSettleRequest");function h(e){const t=e.params.request_id;if(typeof t!="string"||t==="")throw i("request id is required");return t}o(h,"requestId");function f(e){const t=F(e);if(t===null||t.kind!=="page")throw new s(404,"not_found","no request with that id");return t}o(f,"requirePageRequest");function A(e){try{const t=JSON.parse(e.specification_json);if(!c(t))throw new Error("not an object");return t}catch{throw new s(500,"internal","the request specification could not be read")}}o(A,"manifest");function re(e){if(e.result_json===null)return null;try{return JSON.parse(e.result_json)}catch{throw new s(500,"internal","the request result could not be read")}}o(re,"terminalResult");function oe(e){if(e.action_json===null)return null;try{const t=JSON.parse(e.action_json);if(t.schema!=="crtr.human-action-binding/v1"||typeof t.name!="string")throw new Error("invalid action");return t}catch{throw new s(500,"internal","the request action could not be read")}}o(oe,"frozenAction");function ie(e){return e.state!=="settled"?"pending":e.outcome==="answered"?"answered":e.outcome==="dismissed"?"dismissed":"canceled"}o(ie,"requestState");function ae(e){if(e.action_delivery_id===null)return{state:"none",attempt:0};const t=C(e.action_delivery_id);if(t===null)return{state:"none",attempt:0};const n=t.state==="acknowledged"?"accepted":t.state==="permanent_failed"?"permanent_failed":t.state==="handed_off"?"running":"pending",r={state:n,attempt:t.attempts};return n==="pending"&&t.nextAttemptAt!==null&&(r.next_attempt_at=new Date(t.nextAttemptAt).toISOString()),t.acknowledgedAt!==null&&(r.accepted_at=new Date(t.acknowledgedAt).toISOString()),t.failedAt!==null&&(r.permanent_failed_at=new Date(t.failedAt).toISOString()),t.lastFailure!==null&&(r.last_failure=t.lastFailure),r}o(ae,"deliveryDetail");function y(e){const t=A(e),n=re(e),r=ie(e),a={request_id:e.request_id,inbox_ticket_id:e.inbox_ticket_id,request_dir:e.request_dir,kind:e.kind,state:r,title:e.title,source:t.source??{},emitted_at:t.source?.emittedAt??e.created_at};e.subtitle!==null&&(a.subtitle=e.subtitle),e.kind==="page"&&(a.page=U(e)),n!==null&&(a.settled_at=e.settled_at??e.updated_at,n.kind==="page"&&r==="answered"&&(a.responses=n.responses),n.kind==="canceled"&&n.reason!==void 0&&(a.reason=n.reason),n.kind==="page"&&n.actor!==void 0&&(a.actor=n.actor),n.kind==="canceled"&&n.actor!==void 0&&(a.actor=n.actor));const u=oe(e);return u!==null&&(a.action={name:u.name,payload:u.payload},a.delivery=ae(e)),a}o(y,"requestToDTO");function k(e,t,n,r){try{return M({dialect:e,document:t,source:n,delivery:r,productKinds:g()})}catch(a){throw i(a instanceof Error?a.message:"the page could not be prepared")}}o(k,"prepareOrReject");function se(e){const t=Z(e.body),n=t.requesterNodeId??t.source?.nodeId;if(n!=null){const d=b(n);d!==null&&$(d,"crtr:act")}let r;if(t.action!==void 0){const d=D(t.action.name,t.creatorCwd);if("kind"in d){const E=d.kind==="unknown_action"?`no action named ${d.name} is declared from ${t.creatorCwd}`:`${d.name} is declared in ${d.configOrigin} but unusable: ${d.reason}`;throw new s(400,d.kind,E)}const p=n==null?null:b(n);if(n&&!p)throw new s(404,"not_found","action requester node not found");if(p&&e.principal.class!=="person"&&p.grantee!==e.principal.app)throw new s(403,"permission_error","action requester belongs to another app");r=JSON.stringify({schema:"crtr.human-action-binding/v1",name:t.action.name,payload:t.action.payload,creatorCwd:t.creatorCwd,configOrigin:d.configOrigin,argv:d.argv,cwd:d.cwd,app:p?.grantee??(e.principal.class==="broker"?e.principal.app:"app:terminal")})}const a=k(t.page.dialect,t.page.source,t.source,t.delivery),u=J({prepared:a,requester_node_id:t.requesterNodeId,...r===void 0?{}:{action_json:r}});return{status:201,body:{request_id:u.request_id,request_dir:u.request_dir,state:"pending",...t.action===void 0?{}:{action:{name:t.action.name}},delivery_state:"none"}}}o(se,"handleCreate");function de(e){return{status:200,body:y(f(h(e)))}}o(de,"handleGet");function ce(e){const t=f(h(e));if(t.state==="settled")throw new s(409,"already_settled","the request already has a terminal result");const n=A(t),r=ee(e.body,n.delivery),a=k(r.page.dialect,r.page.source,n.source,r.delivery);try{B(t.request_dir,a)}catch(u){throw u instanceof Error&&u.message===`page request is not open: ${t.request_id}`?new s(409,"already_settled","the request already has a terminal result"):u}return{status:200,body:y(f(t.request_id))}}o(ce,"handleReplace");function O(e){return e instanceof s?e:e instanceof Error&&e.message.includes("unknown page request")?new s(404,"not_found","no request with that id"):e instanceof Error&&e.message==="page_has_no_response_lifecycle"?new s(409,"not_settleable","this request carries no response lifecycle"):new s(500,"internal","the request could not be settled")}o(O,"settlementError");function R(e){if(e.state==="settled")throw new s(409,"already_settled","the request already has a terminal result");if(!e.settleable)throw new s(409,"not_settleable","this request carries no response lifecycle")}o(R,"requireSettleable");async function ue(e){const t=f(h(e)),n=te(e.body);R(t);try{G(t.request_dir,n.responses)}catch(r){throw i(r instanceof Error?r.message:"the response map is invalid")}try{await L(t.request_id,n.responses,n.actor===void 0?{}:{actor:n.actor})}catch(r){throw O(r)}return{status:200,body:y(f(t.request_id))}}o(ue,"handleRespond");async function j(e,t){const n=f(h(e)),r=ne(e.body);R(n);try{await H(n.request_id,{...r,disposition:t})}catch(a){throw O(a)}return{status:200,body:y(f(n.request_id))}}o(j,"settle");function le(){return{status:200,body:{components:[...g()]}}}o(le,"handleComponents");const je=[{method:"GET",pattern:"/v1/human/components",handler:o(()=>le(),"handler")},{method:"POST",pattern:"/v1/human/requests",scope:"crtr:act",handler:se},{method:"GET",pattern:"/v1/human/requests/:request_id",handler:de},{method:"POST",pattern:"/v1/human/requests/:request_id/replace",handler:ce},{method:"POST",pattern:"/v1/human/requests/:request_id/respond",handler:ue},{method:"POST",pattern:"/v1/human/requests/:request_id/dismiss",handler:o(e=>j(e,"dismissed"),"handler")},{method:"POST",pattern:"/v1/human/requests/:request_id/cancel",handler:o(e=>j(e,"canceled"),"handler")}];export{je as humanRequestRoutes};
|
|
@@ -1,5 +1,2 @@
|
|
|
1
|
-
var G=Object.defineProperty;var
|
|
2
|
-
|
|
3
|
-
`).map(n=>n.trim()).find(n=>n!=="")??""}c(we,"firstLine");function ye(t,n,e){const r=t.prepare("SELECT status FROM nodes WHERE node_id = ?").get(e.id),o=c(s=>s.filter(l=>I(t,n,l)).map(l=>f(t,l)),"visible"),i=t.prepare(`SELECT o.* FROM nodes n JOIN objects o ON o.id = n.node_id
|
|
4
|
-
WHERE n.parent = ? AND o.deleted_at IS NULL ORDER BY o.rowid`).all(e.id),d=t.prepare("SELECT * FROM objects WHERE owner = ? AND deleted_at IS NULL ORDER BY rowid").all(e.rowid);return D(t,n,e),{state:"object",type:"node",object:f(t,e),status:r?.status??"deleted",mandate_first_line:we(ue(e.id)),children:o(i),owned:o(d.filter(s=>s.type!=="job")),jobs:o(d.filter(s=>s.type==="job"))}}c(ye,"readNode");function ge(t,n,e){const r=K(t,e);if(!r)throw new Error(`job object ${e.id} has no jobs row`);return D(t,n,e),{state:"object",type:"job",object:f(t,e),command:r.command,status:r.status,exit_code:r.exit_code,log_path:r.log_path}}c(ge,"readJob");function be(t,n,e){const r=t.prepare("SELECT scheme, external_id FROM identities WHERE object = ?").get(e.rowid);return D(t,n,e),{state:"object",type:e.type,object:f(t,e),handle:e.name,display_name:e.preview||e.name,identity:{scheme:r?.scheme??"",external_id:r?.external_id??""}}}c(be,"readOwner");function je(t){const n=["1","true"].includes(t.query.get("fields")??"");return w(e=>{const r=y(e,t),o=W(e,r,R(t));return"remote"in o?{state:"remote",remote:o.remote}:"deleted"in o?{state:"deleted",deleted:f(e,o.deleted)}:o.type==="document"?he(e,r,o,n):o.type==="node"?ye(e,r,o):o.type==="job"?ge(e,r,o):be(e,r,o)})}c(je,"read");function j(t,n,e,r){if(t!=null){if(!e.includes(t)){r.push({field:n,problem:`must be one of ${e.join(", ")}`,received:t});return}return t}}c(j,"oneOf");function B(t,n,e,r){if(t==null)return r;const o=Number(t);return!Number.isInteger(o)||o<1||o>100?(e.push({field:n,problem:"must be an integer from 1 to 100",received:t}),r):o}c(B,"limitOf");function _e(t){const n=t.query,e=[],r=j(n.get("type"),"type",A,e),o=j(n.get("privacy"),"privacy",J,e),i=B(n.get("limit"),"limit",e,50),d=n.get("cursor");d!==null&&!/^\d+$/.test(d)&&e.push({field:"cursor",problem:"is not a cursor from a previous page",received:d});const s=n.get("deleted");return s!==null&&!["0","1","true","false"].includes(s)&&e.push({field:"deleted",problem:"must be true or false",received:s}),e.length>0&&v("object list request",e),w(l=>{const u=y(l,t),p={...r?{type:r}:{},...o?{privacy:o}:{},...n.get("kind")!==null?{kind:n.get("kind")}:{},...s==="1"||s==="true"?{deleted:!0}:{}},_=n.get("owner");if(_!==null){const h=P(l,u,_);if(h===null)return{items:[],next_cursor:null};p.owner=h}const O=n.get("name"),m=[];let a=d===null?0:Number(d),T=!0;for(;m.length<i&&T;){const h=Q(l,u,p,{limit:100,after_rowid:a});T=h.length===100;for(const k of h)if(a=k.rowid,(O===null||k.name.startsWith(O))&&m.push(k),m.length===i)break}const x=m.at(-1);return{items:m.map(h=>H(l,h)),next_cursor:m.length===i&&x?String(x.rowid):null}})}c(_e,"list");function ve(t){const n=[],e=b(t.body)?t.body:{};b(t.body)||n.push({field:"body",problem:"must be an object",received:t.body});const r=e.text;(typeof r!="string"||r.trim()==="")&&n.push({field:"text",problem:"is required",received:r});const o=e.grep;if(o!==void 0)if(typeof o!="string")n.push({field:"grep",problem:"must be a regular expression string",received:o});else try{new RegExp(o)}catch(s){n.push({field:"grep",problem:`is not a valid regular expression: ${s.message}`,received:o})}e.body!==void 0&&typeof e.body!="boolean"&&n.push({field:"body",problem:"must be a boolean",received:e.body});const i=j(e.type,"type",A,n);e.kind!==void 0&&typeof e.kind!="string"&&n.push({field:"kind",problem:"must be a string",received:e.kind}),e.owner!==void 0&&typeof e.owner!="string"&&n.push({field:"owner",problem:"must be a string",received:e.owner});const d=B(e.limit,"limit",n,50);return n.length>0&&v("object search request",n),w(s=>{const l=y(s,t),u=typeof e.owner=="string"?P(s,l,e.owner):null;if(typeof e.owner=="string"&&u===null)return{items:[]};const p=M(s,l,{text:r,body:e.body===!0||typeof o=="string"}),_=new Set(p.map(a=>a.object.rowid));return{items:(typeof o=="string"?M(s,l,{text:o,grep:!0}).filter(a=>_.has(a.object.rowid)):p).filter(a=>(!i||a.object.type===i)&&(e.kind===void 0||a.object.kind===e.kind)&&(!u||a.object.owner===u.rowid)).slice(0,d).map(a=>({object:H(s,a.object),...a.line!==void 0?{matches:[{line:a.line,text:a.text??""}]}:{}}))}})}c(ve,"search");const Y=["interrupt","steer","after-turn","next-turn"],Ee=/^(\*|>|[A-Za-z0-9_-]+)(\.(\*|>|[A-Za-z0-9_-]+))*$/;function Re(t,n){if(t!==void 0){if(!Array.isArray(t)||t.length===0||t.some(e=>typeof e!="string"||!Ee.test(e)||e.includes(">")&&!e.endsWith(">"))){n.push({field:"patterns",problem:"must be a non-empty list of event patterns (dot-separated words, `*` for one word, a final `>` for the rest)",received:t});return}return t}}c(Re,"patternsOf");function Oe(t,n){if(t===void 0)return;if(!b(t)||Object.keys(t).length===0){n.push({field:"config",problem:"must map levels 1-10 to a delivery",received:t});return}const e=[];for(const[r,o]of Object.entries(t)){const i=Number(r);!Number.isInteger(i)||i<1||i>10?n.push({field:`config.${r}`,problem:"level must be an integer from 1 to 10"}):Y.includes(o)?e.push({threshold:i,delivery:o}):n.push({field:`config.${r}`,problem:`delivery must be one of ${Y.join(", ")}`,received:o})}return e.sort((r,o)=>o.threshold-r.threshold)}c(Oe,"configOf");function ke(t){const n=[],e=t.body===void 0?{}:b(t.body)?t.body:(n.push({field:"body",problem:"must be an object"}),{}),r=Re(e.patterns,n),o=Oe(e.config,n);return e.filter!==void 0&&!b(e.filter)&&n.push({field:"filter",problem:"must be an object",received:e.filter}),n.length>0&&v("watch request",n),w(i=>{const d=y(i,t),s=E(i,d,R(t)),l=N(d),u=r??[">"];return $(i,l,s,"ask",{patterns:u,...o?{config:o}:{},...e.filter!==void 0?{filter:e.filter}:{}}),C(i,{event:"watched",object:s,actor:l,level:1,attrs:{}},L(i)),{object:f(i,s),patterns:u}})}c(ke,"watch");function Se(t){const n=t.query.get("pattern");return w(e=>{const r=y(e,t),o=E(e,r,R(t)),i=N(r),d=c(()=>e.prepare(`SELECT count(*) AS n FROM watch_subscriptions s JOIN watches w ON w.rowid = s.watch
|
|
5
|
-
WHERE w.watcher = ? AND w.object = ?`).get(i.rowid,o.rowid).n,"count"),s=d();return ee(e,i,o,n??void 0),{object:f(e,o),removed:s-d()}})}c(Se,"unwatchRoute");function Ne(t){const n=[],e=j(t.query.get("type"),"type",["acted-on","links-to","watches"],n),r=j(t.query.get("direction"),"direction",["out","in"],n);return n.length>0&&v("edges request",n),w(o=>{const i=y(o,t),d=E(o,i,R(t)),s=[];if(e!=="watches")for(const l of Z(o,i,d,{...e?{type:e}:{},direction:r??"both"}))s.push({type:l.type,src:f(o,l.src),dst:f(o,l.dst),...l.written_as?{written_as:l.written_as}:{}});if(e===void 0||e==="watches"){const l=[...r!=="in"?ne(o,i,d):[],...r!=="out"?te(o,i,d):[]];for(const u of l)s.push({type:"watches",src:f(o,u.watcher),dst:f(o,u.object)})}return{items:s}})}c(Ne,"edges");const g=c(t=>n=>({status:200,body:t(n)}),"ok"),Ze=[{method:"POST",pattern:"/v1/objects/search",handler:g(ve)},{method:"GET",pattern:"/v1/objects/:ref/edges",handler:g(Ne)},{method:"POST",pattern:"/v1/objects/:ref/watch",handler:g(ke)},{method:"DELETE",pattern:"/v1/objects/:ref/watch",handler:g(Se)},{method:"GET",pattern:"/v1/objects/:ref",handler:g(je)},{method:"GET",pattern:"/v1/objects",handler:g(_e)}];export{Ze as objectRoutes};
|
|
1
|
+
var G=Object.defineProperty;var d=(e,r)=>G(e,"name",{value:r,configurable:!0});import{ApiError as R}from"../../../api/errors.js";import{PRIVACY_LEVELS_DTO as V}from"../../../api/dto/objects.js";import{withCanvasWrite as h}from"../../../core/canvas/db.js";import{actorOf as $}from"../../../core/graph/documents.js";import{edgesOf as x}from"../../../core/graph/edges.js";import{publish as z}from"../../../core/graph/events.js";import{objectDTO as a}from"../../../core/graph/kinds/dto.js";import{isKind as H,kindNames as M,kindOf as A}from"../../../core/graph/kinds/registry.js";import{listObjects as Z,searchObjects as I}from"../../../core/graph/objects.js";import{reposForCwd as J}from"../../../core/graph/repo-sync/repos.js";import{recordWatch as K,unwatch as U,watchersOf as Y,watchesOf as B}from"../../../core/graph/watches.js";import{readerFor as b,resolveRef as F}from"../reader.js";import{invalidRequest as v,isRecord as w}from"./validate.js";const S=d(e=>r=>J(e,r),"reposFnFor");function C(e,r){return{...a(e,r),...A(r.type).listItem?.(e,r)}}d(C,"listItem");function Q(e){return`no object named ${e} on this runtime; it may be on another runtime, or the name may be misspelled`}d(Q,"remoteMessage");function D(e,r,t){try{return k(e,r,t)}catch(o){if(o instanceof R&&o.code==="not_found"&&!o.details?.deleted)return null;throw o}}d(D,"ownerFilter");function k(e,r,t){const o=F(e,r,t);if("remote"in o)throw new R(404,"not_found",Q(o.remote),{next:"Check the name with `crtr canvas search`."});if("deleted"in o)throw new R(404,"not_found",`${o.deleted.name} is deleted`,{id:o.deleted.id,deleted:!0});return o}d(k,"liveRef");const O=d(e=>decodeURIComponent(e.params.ref),"refParam");function X(e){const r=["1","true"].includes(e.query.get("fields")??"");return h(t=>{const o=b(t,e),n=F(t,o,O(e));if("remote"in n)return{state:"remote",remote:n.remote};if("deleted"in n)return{state:"deleted",deleted:a(t,n.deleted)};const{data:i,text:c}=A(n.type).read(t,o,n,{fields:r,reposFn:S(t)});return{state:"object",type:n.type,object:a(t,n),text:c,data:i}})}d(X,"read");function q(e,r,t,o){if(e!=null){if(!t.includes(e)){o.push({field:r,problem:`must be one of ${t.join(", ")}`,received:e});return}return e}}d(q,"oneOf");function L(e,r){if(e!=null){if(typeof e!="string"||!H(e)){r.push({field:"type",problem:`must be a kind: one of ${M().join(", ")}`,received:e});return}return e}}d(L,"kindName");function P(e,r,t,o){if(e==null)return o;const n=Number(e);return!Number.isInteger(n)||n<1||n>100?(t.push({field:r,problem:"must be an integer from 1 to 100",received:e}),o):n}d(P,"limitOf");function ee(e){const r=e.query,t=[],o=L(r.get("type"),t),n=q(r.get("privacy"),"privacy",V,t),i=P(r.get("limit"),"limit",t,50),c=r.get("cursor");c!==null&&!/^\d+$/.test(c)&&t.push({field:"cursor",problem:"is not a cursor from a previous page",received:c});const s=r.get("deleted");return s!==null&&!["0","1","true","false"].includes(s)&&t.push({field:"deleted",problem:"must be true or false",received:s}),t.length>0&&v("object list request",t),h(u=>{const l=b(u,e),g={...o?{type:o}:{},...n?{privacy:n}:{},...r.get("kind")!==null?{kind:r.get("kind")}:{},...s==="1"||s==="true"?{deleted:!0}:{}},j=r.get("owner");if(j!==null){const m=D(u,l,j);if(m===null)return{items:[],next_cursor:null};g.owner=m}const E=r.get("name"),p=[];let f=c===null?0:Number(c),N=!0;for(;p.length<i&&N;){const m=Z(u,l,g,{limit:100,after_rowid:f});N=m.length===100;for(const _ of m)if(f=_.rowid,(E===null||_.name.startsWith(E))&&p.push(_),p.length===i)break}const T=p.at(-1);return{items:p.map(m=>C(u,m)),next_cursor:p.length===i&&T?String(T.rowid):null}})}d(ee,"list");function te(e){const r=[],t=w(e.body)?e.body:{};w(e.body)||r.push({field:"body",problem:"must be an object",received:e.body});const o=t.text;(typeof o!="string"||o.trim()==="")&&r.push({field:"text",problem:"is required",received:o});const n=t.grep;if(n!==void 0)if(typeof n!="string")r.push({field:"grep",problem:"must be a regular expression string",received:n});else try{new RegExp(n)}catch(s){r.push({field:"grep",problem:`is not a valid regular expression: ${s.message}`,received:n})}t.body!==void 0&&typeof t.body!="boolean"&&r.push({field:"body",problem:"must be a boolean",received:t.body});const i=L(t.type,r);t.kind!==void 0&&typeof t.kind!="string"&&r.push({field:"kind",problem:"must be a string",received:t.kind}),t.owner!==void 0&&typeof t.owner!="string"&&r.push({field:"owner",problem:"must be a string",received:t.owner});const c=P(t.limit,"limit",r,50);return r.length>0&&v("object search request",r),h(s=>{const u=b(s,e),l=typeof t.owner=="string"?D(s,u,t.owner):null;if(typeof t.owner=="string"&&l===null)return{items:[]};const g=I(s,u,{text:o,body:t.body===!0||typeof n=="string"}),j=new Set(g.map(f=>f.object.rowid));return{items:(typeof n=="string"?I(s,u,{text:n,grep:!0}).filter(f=>j.has(f.object.rowid)):g).filter(f=>(!i||f.object.type===i)&&(t.kind===void 0||f.object.kind===t.kind)&&(!l||f.object.owner===l.rowid)).slice(0,c).map(f=>({object:C(s,f.object),...f.line!==void 0?{matches:[{line:f.line,text:f.text??""}]}:{}}))}})}d(te,"search");const W=["interrupt","steer","after-turn","next-turn"],re=/^(\*|>|[A-Za-z0-9_-]+)(\.(\*|>|[A-Za-z0-9_-]+))*$/;function ne(e,r){if(e!==void 0){if(!Array.isArray(e)||e.length===0||e.some(t=>typeof t!="string"||!re.test(t)||t.includes(">")&&!t.endsWith(">"))){r.push({field:"patterns",problem:"must be a non-empty list of event patterns (dot-separated words, `*` for one word, a final `>` for the rest)",received:e});return}return e}}d(ne,"patternsOf");function oe(e,r){if(e===void 0)return;if(!w(e)||Object.keys(e).length===0){r.push({field:"config",problem:"must map levels 1-10 to a delivery",received:e});return}const t=[];for(const[o,n]of Object.entries(e)){const i=Number(o);!Number.isInteger(i)||i<1||i>10?r.push({field:`config.${o}`,problem:"level must be an integer from 1 to 10"}):W.includes(n)?t.push({threshold:i,delivery:n}):r.push({field:`config.${o}`,problem:`delivery must be one of ${W.join(", ")}`,received:n})}return t.sort((o,n)=>n.threshold-o.threshold)}d(oe,"configOf");function ie(e){const r=[],t=e.body===void 0?{}:w(e.body)?e.body:(r.push({field:"body",problem:"must be an object"}),{}),o=ne(t.patterns,r),n=oe(t.config,r);return t.filter!==void 0&&!w(t.filter)&&r.push({field:"filter",problem:"must be an object",received:t.filter}),r.length>0&&v("watch request",r),h(i=>{const c=b(i,e),s=k(i,c,O(e)),u=$(c),l=o??[">"];return K(i,u,s,"ask",{patterns:l,...n?{config:n}:{},...t.filter!==void 0?{filter:t.filter}:{}}),z(i,{event:"watched",object:s,actor:u,level:1,attrs:{}},S(i)),{object:a(i,s),patterns:l}})}d(ie,"watch");function se(e){const r=e.query.get("pattern");return h(t=>{const o=b(t,e),n=k(t,o,O(e)),i=$(o),c=d(()=>t.prepare(`SELECT count(*) AS n FROM watch_subscriptions s JOIN watches w ON w.rowid = s.watch
|
|
2
|
+
WHERE w.watcher = ? AND w.object = ?`).get(i.rowid,n.rowid).n,"count"),s=c();return U(t,i,n,r??void 0),{object:a(t,n),removed:s-c()}})}d(se,"unwatchRoute");function de(e){const r=[],t=q(e.query.get("type"),"type",["acted-on","links-to","watches"],r),o=q(e.query.get("direction"),"direction",["out","in"],r);return r.length>0&&v("edges request",r),h(n=>{const i=b(n,e),c=k(n,i,O(e)),s=[];if(t!=="watches")for(const u of x(n,i,c,{...t?{type:t}:{},direction:o??"both"}))s.push({type:u.type,src:a(n,u.src),dst:a(n,u.dst),...u.written_as?{written_as:u.written_as}:{}});if(t===void 0||t==="watches"){const u=[...o!=="in"?B(n,i,c):[],...o!=="out"?Y(n,i,c):[]];for(const l of u)s.push({type:"watches",src:a(n,l.watcher),dst:a(n,l.object)})}return{items:s}})}d(de,"edges");const y=d(e=>r=>({status:200,body:e(r)}),"ok"),ke=[{method:"POST",pattern:"/v1/objects/search",handler:y(te)},{method:"GET",pattern:"/v1/objects/:ref/edges",handler:y(de)},{method:"POST",pattern:"/v1/objects/:ref/watch",handler:y(ie)},{method:"DELETE",pattern:"/v1/objects/:ref/watch",handler:y(se)},{method:"GET",pattern:"/v1/objects/:ref",handler:y(X)},{method:"GET",pattern:"/v1/objects",handler:y(ee)}];export{ke as objectRoutes};
|
|
@@ -1,2 +1,5 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import type { CreateReviewRequest } from '../../../api/index.js';
|
|
2
|
+
import { type RequestContext, type RouteTable } from '../router.js';
|
|
3
|
+
/** Validate a create body. Exported for its contract test. */
|
|
4
|
+
export declare function parseCreate(ctx: RequestContext): CreateReviewRequest;
|
|
2
5
|
export declare const reviewRoutes: RouteTable;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var R=Object.defineProperty;var s=(t,e)=>R(t,"name",{value:e,configurable:!0});import{ApiError as m}from"../../../api/index.js";import{withCanvasWrite as k}from"../../../core/canvas/db.js";import{isSafeNodeId as p}from"../../../core/canvas/paths.js";import{readDocument as q}from"../../../core/graph/documents.js";import{getByRowid as E}from"../../../core/graph/objects.js";import{reposForCwd as S}from"../../../core/graph/repo-sync/repos.js";import{getNode as b}from"../../../core/canvas/canvas.js";import{assertScope as T}from"../../../core/scopes.js";import{createReview as $}from"../../../core/review/birth.js";import{readAnchorBase as C,listReviews as D,requireVisibleReview as y}from"../../../core/review/store.js";import{cancelReview as I,submitReviewApproval as A}from"../../review/finish.js";import{toFeedbackResultDTO as O,toReviewDTO as F}from"../map.js";import{readerFor as L,resolveRef as B}from"../reader.js";import{canReadNode as N}from"../router.js";import{invalidRequest as P,objectBody as w,optionalString as c,requireParam as j,requiredString as g}from"./validate.js";const G=new Set(["open","approved","canceled"]),V=["origin_kind","origin_node_id","document","file","idempotency_key","subtitle","output_path"],W=["reason","actor","disposition"];function l(t){P("review request",t)}s(l,"invalidRequest");function h(t,e){return j(t,"review_id","must be a safe review id",p,e)}s(h,"requireReviewId");function f(t){return{...F(t,t.state==="approved"?{result_path:`${t.review_dir}/result.json`}:{}),review_dir:t.review_dir}}s(f,"toReviewResponseDTO");function K(t){const e=[],i=w(t.body,V,e),o=i.origin_kind,n=o==="ticket"||o==="inline"?o:void 0;n===void 0&&e.push({field:"origin_kind",problem:"must be ticket or inline",...o===void 0?{}:{received:o}});const r=g(i,"origin_node_id",e);r!==void 0&&!p(r)&&e.push({field:"origin_node_id",problem:"must be a safe node id",received:r});const d=c(i,"document",e),a=c(i,"file",e);n==="ticket"&&(d===void 0||a!==void 0)&&e.push({field:"document",problem:"is required for ticket reviews, and file is not allowed"}),n==="inline"&&
|
|
1
|
+
var R=Object.defineProperty;var s=(t,e)=>R(t,"name",{value:e,configurable:!0});import{ApiError as m}from"../../../api/index.js";import{withCanvasWrite as k}from"../../../core/canvas/db.js";import{isSafeNodeId as p}from"../../../core/canvas/paths.js";import{readDocument as q}from"../../../core/graph/documents.js";import{getByRowid as E}from"../../../core/graph/objects.js";import{reposForCwd as S}from"../../../core/graph/repo-sync/repos.js";import{getNode as b}from"../../../core/canvas/canvas.js";import{assertScope as T}from"../../../core/scopes.js";import{createReview as $}from"../../../core/review/birth.js";import{readAnchorBase as C,listReviews as D,requireVisibleReview as y}from"../../../core/review/store.js";import{cancelReview as I,submitReviewApproval as A}from"../../review/finish.js";import{toFeedbackResultDTO as O,toReviewDTO as F}from"../map.js";import{readerFor as L,resolveRef as B}from"../reader.js";import{canReadNode as N}from"../router.js";import{invalidRequest as P,objectBody as w,optionalString as c,requireParam as j,requiredString as g}from"./validate.js";const G=new Set(["open","approved","canceled"]),V=["origin_kind","origin_node_id","document","file","idempotency_key","subtitle","output_path"],W=["reason","actor","disposition"];function l(t){P("review request",t)}s(l,"invalidRequest");function h(t,e){return j(t,"review_id","must be a safe review id",p,e)}s(h,"requireReviewId");function f(t){return{...F(t,t.state==="approved"?{result_path:`${t.review_dir}/result.json`}:{}),review_dir:t.review_dir}}s(f,"toReviewResponseDTO");function K(t){const e=[],i=w(t.body,V,e),o=i.origin_kind,n=o==="ticket"||o==="inline"?o:void 0;n===void 0&&e.push({field:"origin_kind",problem:"must be ticket or inline",...o===void 0?{}:{received:o}});const r=g(i,"origin_node_id",e);r!==void 0&&!p(r)&&e.push({field:"origin_node_id",problem:"must be a safe node id",received:r});const d=c(i,"document",e),a=c(i,"file",e);n==="ticket"&&(d===void 0||a!==void 0)&&e.push({field:"document",problem:"is required for ticket reviews, and file is not allowed"}),n==="inline"&&a===void 0==(d===void 0)&&e.push({field:"file",problem:"inline reviews take exactly one of file or document"});const u=g(i,"idempotency_key",e);u!==void 0&&u.length>128&&e.push({field:"idempotency_key",problem:"must be at most 128 characters",received:u});const v=c(i,"subtitle",e),_=c(i,"output_path",e);return n==="ticket"&&v===void 0&&i.subtitle===void 0&&e.push({field:"subtitle",problem:"is required for ticket reviews"}),n==="inline"&&i.subtitle!==void 0&&e.push({field:"subtitle",problem:"is only allowed for ticket reviews",received:i.subtitle}),n==="inline"&&i.output_path!==void 0&&e.push({field:"output_path",problem:"is only allowed for ticket reviews",received:i.output_path}),(e.length>0||n===void 0||r===void 0||!p(r)||u===void 0||u.length>128)&&l(e),{origin_kind:n,origin_node_id:r,...d===void 0?{}:{document:d},...a===void 0?{}:{file:a},idempotency_key:u,...v===void 0?{}:{subtitle:v},..._===void 0?{}:{output_path:_}}}s(K,"parseCreate");function M(t){const e=[],i={},o=new Set(["state","origin_node_id","file"]);for(const[n,r]of t.query.entries())o.has(n)||e.push({field:n,problem:"is not allowed",received:r});for(const n of o){const r=t.query.getAll(n);if(r.length>1){e.push({field:n,problem:"must appear at most once",received:r});continue}const d=r[0];d!==void 0&&(n==="state"?G.has(d)?i.state=d:e.push({field:n,problem:"must be open, approved, or canceled",received:d}):n==="origin_node_id"?p(d)?i.origin_node_id=d:e.push({field:n,problem:"must be a safe node id",received:d}):d===""?e.push({field:n,problem:"must be a non-empty string",received:d}):i.file=d)}return e.length>0&&l(e),i}s(M,"parseList");function x(t,e){const i=t.body===void 0?{}:w(t.body,W,e),o=c(i,"reason",e),n=c(i,"actor",e),r=c(i,"disposition",e);return r!==void 0&&r!=="canceled"&&r!=="dismissed"&&e.push({field:"disposition",problem:'must be "canceled" or "dismissed"',received:r}),{...o===void 0?{}:{reason:o},...n===void 0?{}:{actor:n},...r==="canceled"||r==="dismissed"?{disposition:r}:{}}}s(x,"parseCancel");function z(t,e){w(t.body,[],e)}s(z,"requireEmptyBody");async function H(t){const e=K(t),i=b(e.origin_node_id);i!==null&&T(i,"crtr:act");const{document:o,file:n,...r}=e,d=await $({...r,...o===void 0?{file:n??""}:{document:J(t,o)}});return{status:200,body:f(d)}}s(H,"handleCreate");function J(t,e){return k(i=>{const o=L(i,t),n=B(i,o,e);if("remote"in n)throw new m(404,"not_found",`no document named ${n.remote} on this runtime`,{next:"Check the name with `crtr canvas search`."});if("deleted"in n)throw new m(404,"not_found",`${n.deleted.name} is deleted`,{id:n.deleted.id,deleted:!0});if(n.type!=="document")throw new m(400,"invalid_request",`${e} is a ${n.type}, not a document`);const r=q(i,o,n,u=>S(i,u));if(r.needsMerge)throw new m(409,"needs_merge",`${n.name} has ${r.heads.length} heads; merge them before a review`,{id:n.id,next:`Read it with \`crtr canvas read ${n.id}\` and write the merged body with \`crtr doc edit\`.`});const d=n.owner===null?null:E(i,n.owner),a=d===null?"":d.type==="node"?d.id:d.name;return{id:n.id,name:a===""?n.name:`${a}/${n.name}`,base:r.record.heads_key,body:r.heads[0].body}})}s(J,"reviewedDocument");function Q(t){const e=M(t);return{status:200,body:{reviews:D(e).filter(o=>{if(t.principal.class==="person")return!0;const n=b(o.origin_node_id);return n!==null&&N(t.principal,n.grantee??"app:terminal")}).map(f)}}}s(Q,"handleList");function U(t){const e=[],i=h(t,e);return(e.length>0||i===void 0)&&l(e),{status:200,body:f(y(i))}}s(U,"handleRead");async function X(t){const e=[],i=h(t,e);z(t,e),(e.length>0||i===void 0)&&l(e);const o=await A(i);return{status:200,body:o.outcome==="awaiting_companion"?{review:f(o.record),outcome:o.outcome}:{review:f(o.record),result:O(o.result),outcome:o.outcome}}}s(X,"handleSubmit");async function Y(t){const e=[],i=h(t,e),o=x(t,e);(e.length>0||i===void 0)&&l(e);const n=await I(i,o);return{status:200,body:{review:f(n.record),outcome:n.outcome}}}s(Y,"handleCancel");function Z(t){const e=[],i=h(t,e);(e.length>0||i===void 0)&&l(e);const o=y(i),n=C(o.review_id);if(n===null)throw new Error(`review anchor base is missing: ${o.review_id}`);return{status:200,body:{review_id:o.review_id,anchor_base_sha256:n.sha256,anchor_base_text:new TextDecoder("utf-8",{fatal:!0}).decode(n.bytes),file:o.file}}}s(Z,"handleDocument");const ve=[{method:"POST",pattern:"/v1/human/reviews",scope:"crtr:act",handler:H},{method:"GET",pattern:"/v1/human/reviews",handler:Q},{method:"GET",pattern:"/v1/human/reviews/:review_id",handler:U},{method:"POST",pattern:"/v1/human/reviews/:review_id/submit",handler:X},{method:"POST",pattern:"/v1/human/reviews/:review_id/cancel",handler:Y},{method:"GET",pattern:"/v1/human/reviews/:review_id/document",handler:Z}];export{K as parseCreate,ve as reviewRoutes};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var m=Object.defineProperty;var u=(e,s)=>m(e,"name",{value:s,configurable:!0});import{consumeCron as y,recordCronRunLocked as I,releaseCronRunLease as b}from"../../core/canvas/crons.js";import{withCanvasWrite as k}from"../../core/canvas/db.js";import{enqueueDaemonAction as _}from"../../core/canvas/daemon-actions.js";import{enqueueNodeMail as v}from"../../core/feed/messages.js";import{disposeSettledRun as g}from"./disposition.js";function w(e){return typeof e=="object"&&(e.kind==="park"||e.kind==="redue")}u(w,"occurrenceStaysOwed");async function S(e,s){const{outOfBand:c,outcome:o,record:n,lease:i}=s;let t,a,d;if(o.kind==="disposed"){const r=await g(e,o.ctx,c,o.selfCanceled??!1);t=r.delivered,a=r.paused,d=r.obligation}else t=o.delivered,a=o.paused??!1;const f=k(r=>{d!==void 0&&(d.kind==="node"?t=`delivered: ${v(d.destinationNodeId,{kind:"message",label:d.label,senderNodeId:d.senderNodeId,bodyJson:{body:d.stdout},urgency:d.urgency,wake:1,idempotencyKey:n.runId}).deliveryId}`:d.kind==="action"&&(t=`delivered: ${_({adapter:d.adapter,bodyJson:d.bodyJson,idempotencyKey:n.runId})}`));const l={run_id:n.runId,cron_id:e.cron_id,started:n.startedAtIso,finished:new Date(n.finishedAtMs).toISOString(),duration_ms:n.durationMs,exit_code:n.exitCode,stdout_head:n.stdoutHead,stderr_head:n.stderrHead,delivered:t};return I(r,l),l});return i!=="none"&&b(e.cron_id,i==="release"?void 0:i),!c&&e.recur==null&&!a&&!w(i)&&y(e.cron_id),f}u(S,"settleRun");export{S as settleRun};
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { type Cron } from '../../core/canvas/crons.js';
|
|
2
|
+
import type { DaemonActionAdapter } from '../../core/canvas/daemon-actions.js';
|
|
2
3
|
export type CronSinkResolution = {
|
|
3
4
|
kind: 'none';
|
|
4
5
|
delivered: string;
|
|
@@ -10,9 +11,8 @@ export type CronSinkResolution = {
|
|
|
10
11
|
stdout: string;
|
|
11
12
|
urgency: 'critical' | 'urgent' | 'normal' | 'deferred';
|
|
12
13
|
} | {
|
|
13
|
-
kind: '
|
|
14
|
-
|
|
15
|
-
adapter: Record<string, unknown>;
|
|
14
|
+
kind: 'action';
|
|
15
|
+
adapter: DaemonActionAdapter;
|
|
16
16
|
bodyJson: unknown;
|
|
17
17
|
};
|
|
18
18
|
/** Resolve a completed run into a durable obligation. No sink effect happens here. */
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var m=Object.defineProperty;var d=(
|
|
2
|
-
`);return{kind:"
|
|
1
|
+
var m=Object.defineProperty;var d=(e,r)=>m(e,"name",{value:r,configurable:!0});import{newNodeId as t}from"../../core/runtime/nodes.js";import{getNode as a}from"../../core/canvas/canvas.js";import{parseCronSink as s}from"../../core/canvas/crons.js";import{hasNoNaturalCycle as u}from"../../core/runtime/revive-all.js";import{isParked as p}from"../../core/runtime/lifecycle.js";import{cronWakeOrigin as f}from"../../core/runtime/bearings.js";import{cronBirthParent as k,resolveLiveProfile as c,resolveLiveProfileName as y}from"./armed-context.js";function I(e,r,i){const n=s(e.sink);if(n===null)return{kind:"none",delivered:"no sink armed \u2014 nothing delivered"};if(n.kind==="node"){const o=a(n.node);if(o===null)throw new Error(`node sink ${n.node} is gone`);if(u(o)&&!p(o))throw new Error(`node sink ${n.node} has no natural cycle ahead (done or finalized)`);return{kind:"node",destinationNodeId:n.node,senderNodeId:e.created_by!==null&&a(e.created_by)!==null?e.created_by:null,label:`\u23F0 cron ${e.name}`,stdout:i,urgency:e.tier}}if(n.kind==="spawn"){const o=k(e),l=[`Scheduled cron "${e.name}" (${e.cron_id}) fired and delivered its output to you as your kickoff.`,"","## Command output","",i].join(`
|
|
2
|
+
`);return{kind:"action",adapter:{adapter:"cron_spawn",cronId:e.cron_id,nodeId:t(),kind:n.spawn,cwd:e.cwd,...o!==null?{parent:o,root:!1}:{parent:null,root:!0,rootLifecycle:"terminal"},profile:c(e),wakeOrigin:f(e,"node_birth"),prompt:l},bodyJson:{runId:r,stdout:i}}}return{kind:"action",adapter:{adapter:"cron_human",cronId:e.cron_id,requestId:t(),title:`\u23F0 cron ${e.name}`,summary:`Scheduled cron "${e.name}" delivered output for your attention.`,sessionName:`cron ${e.name} (${e.cron_id})`,profileName:y(e)??null},bodyJson:{runId:r,stdout:i}}}d(I,"resolveCronSink");export{I as resolveCronSink};
|
package/dist/daemon/crtrd.js
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
var ve=Object.defineProperty;var a=(t,n)=>ve(t,"name",{value:n,configurable:!0});import{writeFileSync as ge,readFileSync as we,rmSync as ye,mkdirSync as V,existsSync as b,chmodSync as Se}from"node:fs";import{createServer as Q}from"node:http";import{dirname as _e}from"node:path";import{envCrtrdTcp as be}from"../shared/env.js";import{serveCanvasConversationStore as ke}from"../core/canvas/sessions.js";import{pollRunObservers as Ee}from"./runs/observer.js";import{randomBytes as Pe}from"node:crypto";import{apiSocketPath as Ie,crtrHome as Re}from"../core/canvas/paths.js";import{activeAppUsers as Te}from"../core/spaces/users.js";import{ensureAppSpace as xe,ensureUserFiles as De}from"../core/spaces/space.js";import{LAUNCHER_SOCKET as E}from"../launcher/spec.js";import{launcherRequest as R}from"../launcher/client.js";import{initializeEmptyLayout as Ce,layoutNeedsMigration as Ae,socketDir as Y}from"../core/layout.js";import{listNodesForSupervision as Le}from"../core/canvas/index.js";import{createApiServer as $e}from"./api/server.js";import{createAppListener as Me}from"./api/app-listener.js";import{installLocalTerminalGrant as Ne}from"../core/grants/local.js";import{createGrantSync as Ge,GRANT_SYNC_INTERVAL_S as Oe}from"../core/grants/sync.js";import{runRemovalCascades as Fe}from"../core/grants/remove.js";import{sweepSandboxes as je}from"../core/grants/on-sync.js";import{hasSyncedGrants as He}from"../core/grants/mirror.js";import{readConfig as Be}from"../core/config.js";import{reconcileUndeliveredTickets as ze}from"./human/sweep.js";import{resetHandedOffDeliveries as We}from"../core/canvas/deliveries.js";import{sweepReviews as qe}from"./review/sweep.js";import{pidfilePath as G}from"./pidfile.js";import{rendererWarning as Ue}from"../core/runtime/package-health.js";import{DEFAULT_INTERVAL_MS as Ke}from"./supervise-cadence.js";import{BrokerSupervisionReconciler as Je}from"./reconcilers/broker-supervision.js";import{ControllerDeathReconciler as Ve}from"./reconcilers/controller-death.js";import{NodeLifecycleReconciler as Qe}from"./reconcilers/node-lifecycle/tick.js";import{NodeDeadlineReconciler as Ye}from"./reconcilers/node-deadline.js";import{CronLaneReconciler as Xe}from"./reconcilers/cron-lane.js";import{DeliveryLaneReconciler as Ze}from"./reconcilers/delivery-lane.js";import{migrateLegacyExecutionIdentities as er}from"../core/canvas/executions.js";import{revokePriorEpochNodeTokens as rr}from"../core/canvas/node-tokens.js";import{PendingReviewSubmitReconciler as tr}from"./reconcilers/pending-review-submit.js";import{StorageMaintenanceReconciler as nr}from"./reconcilers/storage-maintenance.js";import{StorageDueWorkReconciler as or}from"./reconcilers/storage-due-work.js";import{BashDeadlineReconciler as ir}from"./reconcilers/bash-deadline.js";import{captureLivenessSnapshot as X,capturePidCommand as ar,captureTeardownSnapshot as Z,isPidAlive as sr,isAnyPidAlive as ee,killProcessTreePids as re}from"../core/canvas/pid.js";import{bindFleet as cr,boundFleet as lr}from"../core/runtime/fleet.js";import{bindDaemonControl as dr,clearDaemonControl as pr}from"./control.js";import{execDaemon as mr,spawnDaemon as fr}from"./manage.js";import{reconcileAndMigrateBoot as ur}from"../core/canvas/boot.js";import{resolveInstallId as hr}from"../core/canvas/install-id.js";import{setInstallId as vr}from"../core/runtime/nodes.js";import{claimDaemonOwnership as gr,releaseDaemonOwnership as te}from"../core/canvas/daemon-owner.js";import{migrate as wr,openDb as ne,withCanvasWrite as yr}from"../core/canvas/db.js";import{reconcilePackageDocuments as Sr}from"../core/graph/package-docs.js";import{startRepoSync as _r}from"../core/graph/repo-sync/index.js";import{prewarmRecentRecipes as br,reapStaleSpares as kr}from"../core/runtime/warm-pool.js";import{DaemonFleet as Er}from"./fleet.js";import{BOOT_MIGRATIONS as Pr}from"./boot-migrations.js";import{applyJoinedOwner as Ir}from"./joined-owner.js";import{emitEvent as h}from"../core/events/emit.js";import{operationIdContext as _}from"../core/events/operation-id.js";import{bindDaemonEventSource as Rr}from"../core/events/source.js";import{activateCanvasImport as Tr,MigrationBlockedError as xr,runForcedCanvasImport as Dr}from"../migrations/activation.js";import{convertLegacyProviderStore as Cr,convertLegacyScopedStore as Ar}from"../core/scoped-state/migrate.js";import{userScopeRoot as Lr}from"../core/scope.js";import{secretsDir as $r}from"../core/layout.js";function O(t,n){return t.includes(` --canvas-home ${n} `)}a(O,"brokerCommandDeclaresCanvasHome");function F(t){return/ --epoch (\S+) /.exec(t)?.[1]??null}a(F,"brokerCommandEpoch");const Mr=5e3,oe=150;async function Nr(t){const n=X();if(n===null)throw h({level:"error",event:"daemon.census.snapshot_failed",fields:{invariant:"prior-epoch brokers are reaped before readiness"}}),new Error("prior-epoch broker census could not capture the process table");const s=Re(),m=[];for(const[i,p]of n.processes){const g=p.command;if(p.zombie||!g.includes("broker-cli.js")||!O(g,s)||F(g)===t)continue;const y=g.trim().split(/\s+/).at(-1)??"";y===""||y.endsWith("broker-cli.js")||m.push({pid:i,nodeId:y})}let f=0;const o=[];for(const i of m){const p=ar(i.pid);if(p===null||!p.includes("broker-cli.js")||!O(p,s)||F(p)===t||p.trim().split(/\s+/).at(-1)!==i.nodeId)continue;const g=Z(i.pid,null);if(!g.reused){try{process.platform==="linux"&&b(E)?await R({operation:"stop",pid:i.pid}):process.kill(i.pid,"SIGTERM")}catch{continue}f++,o.push({pid:i.pid,snap:g})}}const w=Date.now()+Mr;for(;Date.now()<w&&o.some(i=>ee(i.snap.tree.length>0?i.snap.tree:[i.pid]));)await new Promise(i=>setTimeout(i,oe));let v=0;for(const i of o){const p=i.snap.tree.length>0?i.snap.tree:[i.pid];ee(p)&&(process.platform==="linux"&&b(E)?await R({operation:"stop",pid:i.pid}):re(p,"SIGKILL",i.snap.identities),v++)}v>0&&await new Promise(i=>setTimeout(i,oe));const c=X();if(c===null)throw h({level:"error",event:"daemon.census.snapshot_failed",fields:{invariant:"prior-epoch brokers are reaped before readiness",stage:"final"}}),new Error("prior-epoch broker census could not capture the final process table");const d=[];for(const[i,p]of c.processes){const g=p.command;p.zombie||!g.includes("broker-cli.js")||O(g,s)&&F(g)!==t&&d.push(i)}if(d.length>0)throw new Error(`prior-epoch broker census could not prove termination of pid(s): ${d.join(", ")}`);h({level:"info",event:"daemon.census.completed",fields:{prior_epoch_brokers:m.length,sigtermed:f,sigkilled:v}})}a(Nr,"reapPriorEpochBrokers");const Gr=5e3;async function Or(t){const n=Array.from(t.entries());if(n.length===0)return;const s=n.map(([,o])=>({pid:o.pid,snap:Z(o.pid,null),exited:o.handle.exited}));for(const o of s)if(!o.snap.reused)try{process.platform==="linux"&&b(E)?await R({operation:"stop",pid:o.pid}):process.kill(o.pid,"SIGTERM")}catch{}const m=new Promise(o=>{setTimeout(o,Gr).unref()});await Promise.allSettled(s.map(o=>Promise.race([o.exited.then(()=>{}),m])));const f=[];for(const o of s)sr(o.pid)&&(process.platform==="linux"&&b(E)?await R({operation:"stop",pid:o.pid}):re(o.snap.tree.length>0?o.snap.tree:[o.pid],"SIGKILL",o.snap.identities),f.push(o));await Promise.all(f.map(o=>o.exited)),h({level:"info",event:"daemon.fleet_teardown.completed",fields:{brokers:s.length,sigkilled:f.length}})}a(Or,"teardownFleet");function ie(){V(_e(G()),{recursive:!0}),ge(G(),String(process.pid),"utf8")}a(ie,"writePidfile");function ae(t){return typeof t=="object"&&t!==null&&t.code==="ENOENT"}a(ae,"isMissingPathError");function se(t){const n=G();let s;try{s=we(n,"utf8")}catch(m){if(ae(m))return;throw m}if(s.trim()!==String(t))throw new Error(`daemon readiness mirror does not name this invocation (expected pid ${t})`);try{ye(n)}catch(m){if(ae(m))return;throw m}}a(se,"removeOwnedPidfileMirror");const Fr={acceptsDetachedWork:a(()=>!0,"acceptsDetachedWork"),registerDetached:a(t=>{t.catch(()=>{})},"registerDetached")},j=new Je,jr=new Ve,Hr=new Qe,Br=new Ye,zr=new Xe,Wr=new Ze,qr=new tr,Ur=new nr,Kr=new or,Jr=new ir;async function Vr(t=Date.now(),n=Fr){const s=lr(),m=await j.runFleetPreamble(s);let f,o;try{const v=Le();f=v.filter(c=>c.status==="active"||c.status==="idle"),o=v.filter(c=>c.status==="done"||c.status==="canceled"||c.status==="dead")}catch(v){h({level:"error",event:"canvas.node_list.failed",error:v});return}await j.run(t,{rows:f,fleet:s,lifecycle:n}),jr.run(t,{rows:f});const w=await Hr.run(t,{rows:[...f,...o],fleet:s});Br.run(t),zr.run(t,{lifecycle:n}),Wr.run(t,{lifecycle:n}),qr.run(t,{lifecycle:n}),Ur.run(t,{lifecycle:n,fleet:s}),Kr.run(t,{lifecycle:n}),Ee(),await Jr.run(t,{rows:f}),j.warnIfSaturated({fleet:s,lifecycle:n,thresholds:m,frozen:w})}a(Vr,"superviseTick");async function Qr(t){V(Y(),{recursive:!0,mode:493}),process.platform==="linux"&&Se(Y(),493);const n=Ie();if(b(n))throw new Error(`layout refusal cannot bind occupied socket: ${n}`);const s=Q((c,d)=>{if(c.method==="GET"&&c.url==="/healthz"){d.writeHead(200,{"content-type":"application/json; charset=utf-8"}),d.end(JSON.stringify({ok:!1,daemon_up:!0,store_accessible:!1,brokers_reconciled:!1,startup_phase:"blocked",startup_blocked:"layout_migration_required"}));return}d.writeHead(503,{"content-type":"application/json; charset=utf-8"}),d.end(JSON.stringify({error:{code:"layout_migration_required",message:"run crtr sys migrate while the runtime is offline",type:"server_error",origin:"runtime",retryable:!1}}))});await new Promise((c,d)=>{s.once("error",d),s.listen(n,()=>{s.off("error",d),c()})});let m;const f=t.tcp??be();if(f){const c=/^(.*):(\d+)$/.exec(f);if(!c||Number(c[2])>65535)throw new Error(`invalid refusal TCP address: ${f}`);const d=Q(s.listeners("request")[0]);await new Promise((i,p)=>{d.once("error",p),d.listen(Number(c[2]),c[1],()=>{d.off("error",p),i()})}),m=d}ie();let o;const w=a(()=>(o??=(async()=>{s.closeAllConnections(),m?.closeAllConnections(),await Promise.all([s,m].filter(c=>c!==void 0).map(c=>new Promise((d,i)=>c.close(p=>p?i(p):d())))),se(process.pid),process.off("SIGINT",v),process.off("SIGTERM",v)})(),o),"cleanup"),v=a(()=>{w().then(()=>process.exit(0),c=>{process.stderr.write(`[crtrd] layout refusal cleanup failed: ${String(c)}
|
|
2
|
-
`),process.exit(1)})},"onSignal");return process.on("SIGINT",v),process.on("SIGTERM",v),w}a(
|
|
1
|
+
var ve=Object.defineProperty;var a=(t,n)=>ve(t,"name",{value:n,configurable:!0});import{writeFileSync as ge,readFileSync as we,rmSync as ye,mkdirSync as V,existsSync as b,chmodSync as Se}from"node:fs";import{createServer as Q}from"node:http";import{dirname as _e}from"node:path";import{envCrtrdTcp as be}from"../shared/env.js";import{serveCanvasConversationStore as ke}from"../core/canvas/sessions.js";import{pollRunObservers as Ee}from"./runs/observer.js";import{randomBytes as Pe}from"node:crypto";import{apiSocketPath as Ie,crtrHome as Re}from"../core/canvas/paths.js";import{activeAppUsers as Te}from"../core/spaces/users.js";import{ensureAppSpace as xe,ensureUserFiles as De}from"../core/spaces/space.js";import{LAUNCHER_SOCKET as E}from"../launcher/spec.js";import{launcherRequest as R}from"../launcher/client.js";import{initializeEmptyLayout as Ce,layoutNeedsMigration as Ae,socketDir as Y}from"../core/layout.js";import{listNodesForSupervision as Le}from"../core/canvas/index.js";import{createApiServer as $e}from"./api/server.js";import{createAppListener as Me}from"./api/app-listener.js";import{installLocalTerminalGrant as Ne}from"../core/grants/local.js";import{createGrantSync as Ge,GRANT_SYNC_INTERVAL_S as Oe}from"../core/grants/sync.js";import{runRemovalCascades as Fe}from"../core/grants/remove.js";import{sweepSandboxes as He}from"../core/grants/on-sync.js";import{hasSyncedGrants as je}from"../core/grants/mirror.js";import{readConfig as Be}from"../core/config.js";import{reconcileUndeliveredTickets as ze}from"./human/sweep.js";import{resetHandedOffDeliveries as We}from"../core/canvas/deliveries.js";import{resetHandedOffDaemonActions as qe}from"../core/canvas/daemon-actions.js";import{sweepReviews as Ue}from"./review/sweep.js";import{pidfilePath as G}from"./pidfile.js";import{rendererWarning as Ke}from"../core/runtime/package-health.js";import{DEFAULT_INTERVAL_MS as Je}from"./supervise-cadence.js";import{BrokerSupervisionReconciler as Ve}from"./reconcilers/broker-supervision.js";import{ControllerDeathReconciler as Qe}from"./reconcilers/controller-death.js";import{NodeLifecycleReconciler as Ye}from"./reconcilers/node-lifecycle/tick.js";import{NodeDeadlineReconciler as Xe}from"./reconcilers/node-deadline.js";import{CronLaneReconciler as Ze}from"./reconcilers/cron-lane.js";import{DeliveryLaneReconciler as er}from"./reconcilers/delivery-lane.js";import{ActionLaneReconciler as rr}from"./reconcilers/action-lane.js";import{migrateLegacyExecutionIdentities as tr}from"../core/canvas/executions.js";import{revokePriorEpochNodeTokens as nr}from"../core/canvas/node-tokens.js";import{PendingReviewSubmitReconciler as or}from"./reconcilers/pending-review-submit.js";import{StorageMaintenanceReconciler as ir}from"./reconcilers/storage-maintenance.js";import{StorageDueWorkReconciler as ar}from"./reconcilers/storage-due-work.js";import{BashDeadlineReconciler as sr}from"./reconcilers/bash-deadline.js";import{captureLivenessSnapshot as X,capturePidCommand as cr,captureTeardownSnapshot as Z,isPidAlive as lr,isAnyPidAlive as ee,killProcessTreePids as re}from"../core/canvas/pid.js";import{bindFleet as dr,boundFleet as pr}from"../core/runtime/fleet.js";import{bindDaemonControl as mr,clearDaemonControl as fr}from"./control.js";import{execDaemon as ur,spawnDaemon as hr}from"./manage.js";import{reconcileAndMigrateBoot as vr}from"../core/canvas/boot.js";import{resolveInstallId as gr}from"../core/canvas/install-id.js";import{setInstallId as wr}from"../core/runtime/nodes.js";import{claimDaemonOwnership as yr,releaseDaemonOwnership as te}from"../core/canvas/daemon-owner.js";import{migrate as Sr,openDb as ne,withCanvasWrite as _r}from"../core/canvas/db.js";import{reconcilePackageDocuments as br}from"../core/graph/package-docs.js";import{startRepoSync as kr}from"../core/graph/repo-sync/index.js";import{prewarmRecentRecipes as Er,reapStaleSpares as Pr}from"../core/runtime/warm-pool.js";import{DaemonFleet as Ir}from"./fleet.js";import{BOOT_MIGRATIONS as Rr}from"./boot-migrations.js";import{applyJoinedOwner as Tr}from"./joined-owner.js";import{emitEvent as h}from"../core/events/emit.js";import{operationIdContext as _}from"../core/events/operation-id.js";import{bindDaemonEventSource as xr}from"../core/events/source.js";import{activateCanvasImport as Dr,MigrationBlockedError as Cr,runForcedCanvasImport as Ar}from"../migrations/activation.js";import{convertLegacyProviderStore as Lr,convertLegacyScopedStore as $r}from"../core/scoped-state/migrate.js";import{userScopeRoot as Mr}from"../core/scope.js";import{secretsDir as Nr}from"../core/layout.js";function O(t,n){return t.includes(` --canvas-home ${n} `)}a(O,"brokerCommandDeclaresCanvasHome");function F(t){return/ --epoch (\S+) /.exec(t)?.[1]??null}a(F,"brokerCommandEpoch");const Gr=5e3,oe=150;async function Or(t){const n=X();if(n===null)throw h({level:"error",event:"daemon.census.snapshot_failed",fields:{invariant:"prior-epoch brokers are reaped before readiness"}}),new Error("prior-epoch broker census could not capture the process table");const s=Re(),m=[];for(const[i,p]of n.processes){const g=p.command;if(p.zombie||!g.includes("broker-cli.js")||!O(g,s)||F(g)===t)continue;const y=g.trim().split(/\s+/).at(-1)??"";y===""||y.endsWith("broker-cli.js")||m.push({pid:i,nodeId:y})}let f=0;const o=[];for(const i of m){const p=cr(i.pid);if(p===null||!p.includes("broker-cli.js")||!O(p,s)||F(p)===t||p.trim().split(/\s+/).at(-1)!==i.nodeId)continue;const g=Z(i.pid,null);if(!g.reused){try{process.platform==="linux"&&b(E)?await R({operation:"stop",pid:i.pid}):process.kill(i.pid,"SIGTERM")}catch{continue}f++,o.push({pid:i.pid,snap:g})}}const w=Date.now()+Gr;for(;Date.now()<w&&o.some(i=>ee(i.snap.tree.length>0?i.snap.tree:[i.pid]));)await new Promise(i=>setTimeout(i,oe));let v=0;for(const i of o){const p=i.snap.tree.length>0?i.snap.tree:[i.pid];ee(p)&&(process.platform==="linux"&&b(E)?await R({operation:"stop",pid:i.pid}):re(p,"SIGKILL",i.snap.identities),v++)}v>0&&await new Promise(i=>setTimeout(i,oe));const c=X();if(c===null)throw h({level:"error",event:"daemon.census.snapshot_failed",fields:{invariant:"prior-epoch brokers are reaped before readiness",stage:"final"}}),new Error("prior-epoch broker census could not capture the final process table");const d=[];for(const[i,p]of c.processes){const g=p.command;p.zombie||!g.includes("broker-cli.js")||O(g,s)&&F(g)!==t&&d.push(i)}if(d.length>0)throw new Error(`prior-epoch broker census could not prove termination of pid(s): ${d.join(", ")}`);h({level:"info",event:"daemon.census.completed",fields:{prior_epoch_brokers:m.length,sigtermed:f,sigkilled:v}})}a(Or,"reapPriorEpochBrokers");const Fr=5e3;async function Hr(t){const n=Array.from(t.entries());if(n.length===0)return;const s=n.map(([,o])=>({pid:o.pid,snap:Z(o.pid,null),exited:o.handle.exited}));for(const o of s)if(!o.snap.reused)try{process.platform==="linux"&&b(E)?await R({operation:"stop",pid:o.pid}):process.kill(o.pid,"SIGTERM")}catch{}const m=new Promise(o=>{setTimeout(o,Fr).unref()});await Promise.allSettled(s.map(o=>Promise.race([o.exited.then(()=>{}),m])));const f=[];for(const o of s)lr(o.pid)&&(process.platform==="linux"&&b(E)?await R({operation:"stop",pid:o.pid}):re(o.snap.tree.length>0?o.snap.tree:[o.pid],"SIGKILL",o.snap.identities),f.push(o));await Promise.all(f.map(o=>o.exited)),h({level:"info",event:"daemon.fleet_teardown.completed",fields:{brokers:s.length,sigkilled:f.length}})}a(Hr,"teardownFleet");function ie(){V(_e(G()),{recursive:!0}),ge(G(),String(process.pid),"utf8")}a(ie,"writePidfile");function ae(t){return typeof t=="object"&&t!==null&&t.code==="ENOENT"}a(ae,"isMissingPathError");function se(t){const n=G();let s;try{s=we(n,"utf8")}catch(m){if(ae(m))return;throw m}if(s.trim()!==String(t))throw new Error(`daemon readiness mirror does not name this invocation (expected pid ${t})`);try{ye(n)}catch(m){if(ae(m))return;throw m}}a(se,"removeOwnedPidfileMirror");const jr={acceptsDetachedWork:a(()=>!0,"acceptsDetachedWork"),registerDetached:a(t=>{t.catch(()=>{})},"registerDetached")},H=new Ve,Br=new Qe,zr=new Ye,Wr=new Xe,qr=new Ze,Ur=new er,Kr=new rr,Jr=new or,Vr=new ir,Qr=new ar,Yr=new sr;async function Xr(t=Date.now(),n=jr){const s=pr(),m=await H.runFleetPreamble(s);let f,o;try{const v=Le();f=v.filter(c=>c.status==="active"||c.status==="idle"),o=v.filter(c=>c.status==="done"||c.status==="canceled"||c.status==="dead")}catch(v){h({level:"error",event:"canvas.node_list.failed",error:v});return}await H.run(t,{rows:f,fleet:s,lifecycle:n}),Br.run(t,{rows:f});const w=await zr.run(t,{rows:[...f,...o],fleet:s});Wr.run(t),qr.run(t,{lifecycle:n}),Ur.run(t,{lifecycle:n}),Kr.run(t,{lifecycle:n}),Jr.run(t,{lifecycle:n}),Vr.run(t,{lifecycle:n,fleet:s}),Qr.run(t,{lifecycle:n}),Ee(),await Yr.run(t,{rows:f}),H.warnIfSaturated({fleet:s,lifecycle:n,thresholds:m,frozen:w})}a(Xr,"superviseTick");async function Zr(t){V(Y(),{recursive:!0,mode:493}),process.platform==="linux"&&Se(Y(),493);const n=Ie();if(b(n))throw new Error(`layout refusal cannot bind occupied socket: ${n}`);const s=Q((c,d)=>{if(c.method==="GET"&&c.url==="/healthz"){d.writeHead(200,{"content-type":"application/json; charset=utf-8"}),d.end(JSON.stringify({ok:!1,daemon_up:!0,store_accessible:!1,brokers_reconciled:!1,startup_phase:"blocked",startup_blocked:"layout_migration_required"}));return}d.writeHead(503,{"content-type":"application/json; charset=utf-8"}),d.end(JSON.stringify({error:{code:"layout_migration_required",message:"run crtr sys migrate while the runtime is offline",type:"server_error",origin:"runtime",retryable:!1}}))});await new Promise((c,d)=>{s.once("error",d),s.listen(n,()=>{s.off("error",d),c()})});let m;const f=t.tcp??be();if(f){const c=/^(.*):(\d+)$/.exec(f);if(!c||Number(c[2])>65535)throw new Error(`invalid refusal TCP address: ${f}`);const d=Q(s.listeners("request")[0]);await new Promise((i,p)=>{d.once("error",p),d.listen(Number(c[2]),c[1],()=>{d.off("error",p),i()})}),m=d}ie();let o;const w=a(()=>(o??=(async()=>{s.closeAllConnections(),m?.closeAllConnections(),await Promise.all([s,m].filter(c=>c!==void 0).map(c=>new Promise((d,i)=>c.close(p=>p?i(p):d())))),se(process.pid),process.off("SIGINT",v),process.off("SIGTERM",v)})(),o),"cleanup"),v=a(()=>{w().then(()=>process.exit(0),c=>{process.stderr.write(`[crtrd] layout refusal cleanup failed: ${String(c)}
|
|
2
|
+
`),process.exit(1)})},"onSignal");return process.on("SIGINT",v),process.on("SIGTERM",v),w}a(Zr,"serveLayoutRefusal");async function et(t={}){if(Ae())return Zr(t);Ce();const n=yr(Pe(16).toString("hex"));if(!n.claimed){if(n.reason==="incumbent_alive")process.stderr.write(`[crtrd] already running (pid ${n.incumbentPid??"?"})
|
|
3
3
|
`);else{const e=[n.incumbentPid!==void 0?`pid ${n.incumbentPid}`:void 0,n.verdict!==void 0?`verdict ${n.verdict}`:void 0].filter(l=>l!==void 0),r=e.length>0?` (${e.join(", ")})`:"";process.stderr.write(`[crtrd] claim lost: ${n.reason}${r}
|
|
4
|
-
`)}return async()=>{}}const s=n.claim;let m=null;try{await
|
|
4
|
+
`)}return async()=>{}}const s=n.claim;let m=null;try{await Or(s.token),$r({kind:"user",root:Mr()}),await Lr(Nr()),Sr(ne());const e=_r(r=>br(r));for(const r of e.conflicts)process.stderr.write(`[crtrd] plugin documents not reconciled: ${r.message}
|
|
5
5
|
`);for(const r of e.invalid)process.stderr.write(`[crtrd] package file is not a document: ${r.path}: ${r.error}
|
|
6
|
-
`);m=
|
|
6
|
+
`);m=Tr(),process.platform==="linux"&&b(E)&&await R({operation:"users.sync",users:Te()}),nr(s.token)}catch(e){try{const{released:r}=te(s);if(!r)throw new Error("daemon ownership claim was not released")}catch(r){throw new AggregateError([e,r],"daemon startup failed and cleanup also failed")}throw e}let f=!0,o,w=Promise.resolve(),v=!1,c,d;const i=new Set;let p=!1,g=!1,y,C,j=!1,A,T,x,L,u={phase:"initializing",message:"daemon startup is running the canvas import and normal services are unavailable",blockerPaths:[]},P="initial startup activation",ce=null;function le(){return u.phase==="ready"?null:{phase:u.phase,message:u.message,blockerPaths:u.blockerPaths}}a(le,"startupBlock");function I(e){i.add(e),e.finally(()=>{i.delete(e)}).catch(()=>{})}a(I,"registerDetached");const B={acceptsDetachedWork:a(()=>f,"acceptsDetachedWork"),registerDetached:I};kr(B,ne);async function de(){try{f=!1,c!==void 0&&(clearInterval(c),c=void 0),x!==void 0&&(clearInterval(x),x=void 0);let e;do e=w,await e;while(e!==w);for(;i.size>0;)await Promise.allSettled([...i]);if(d!==void 0&&(await Hr(d),d.dispose()),C!==void 0&&!j&&(j=!0,await C.close()),T!==void 0){const r=T;T=void 0,await r.close()}if(A!==void 0){const r=A;A=void 0,await r.close()}if(p||(se(process.pid),p=!0),p&&!g){const{released:r}=te(s);if(!r)throw new Error("daemon ownership claim was not released");g=!0}}finally{fr(),process.off("SIGINT",q),process.off("SIGTERM",U),process.off("exit",K)}}a(de,"cleanupAttempt");const $=1e3;let z=!1;function pe(){return z?{graceMs:$}:(z=!0,_.fresh(()=>{h({level:"info",event:"daemon.handover.armed",fields:{pid:process.pid,grace_ms:$}})}),setTimeout(()=>{me()},$),{graceMs:$})}a(pe,"requestHandover");async function me(){try{await k()}catch(e){const r=e instanceof Error?e.stack??e.message:String(e);process.stderr.write(`[crtrd] handover cleanup failed:
|
|
7
7
|
${r}
|
|
8
|
-
`),process.exit(1)}try{process.platform==="linux"&&b(E)&&(await R({operation:"daemon.handover"}),process.exit(0)),process.pid===1&&await
|
|
8
|
+
`),process.exit(1)}try{process.platform==="linux"&&b(E)&&(await R({operation:"daemon.handover"}),process.exit(0)),process.pid===1&&await ur();const e=await hr();_.fresh(()=>{h({level:"info",event:"daemon.handover.completed",fields:{predecessor_pid:process.pid,successor_pid:e.pid??e.existing_pid??null,spawned:e.started}})})}catch(e){_.fresh(()=>{h({level:"error",event:"daemon.handover.successor_failed",error:e})});const r=e instanceof Error?e.message:String(e);process.stderr.write(`[crtrd] handover successor failed to start: ${r}
|
|
9
9
|
`),process.exit(1)}process.exit(0)}a(me,"performHandover");function k(){if(y!==void 0)return y;const e=de();return y=e,e.then(()=>{y===e&&(y=void 0)},()=>{y===e&&(y=void 0)}),e}a(k,"requestCleanup");async function W(e){try{await k(),process.exit(0)}catch(r){process.exitCode=1;const l=r instanceof Error?r.stack??`${r.name}: ${r.message}`:String(r);process.stderr.write(`[crtrd] ${e} cleanup failed:
|
|
10
10
|
${l}
|
|
11
|
-
`),process.exit(1)}}a(W,"handleSignal");function q(){W("SIGINT")}a(q,"onSigint");function U(){W("SIGTERM")}a(U,"onSigterm");function K(){k().catch(()=>{})}a(K,"onExit");function M(e){f&&(w=w.then(e).then(()=>{},r=>{_.fresh(()=>{h({level:"error",event:"daemon.lane_job.failed",error:r})})}))}a(M,"enqueue");function J(){!f||v||(v=!0,M(async()=>{if(v=!1,!!f)try{await
|
|
11
|
+
`),process.exit(1)}}a(W,"handleSignal");function q(){W("SIGINT")}a(q,"onSigint");function U(){W("SIGTERM")}a(U,"onSigterm");function K(){k().catch(()=>{})}a(K,"onExit");function M(e){f&&(w=w.then(e).then(()=>{},r=>{_.fresh(()=>{h({level:"error",event:"daemon.lane_job.failed",error:r})})}))}a(M,"enqueue");function J(){!f||v||(v=!0,M(async()=>{if(v=!1,!!f)try{await Xr(Date.now(),B)}catch(e){_.fresh(()=>{h({level:"error",event:"daemon.tick.failed",error:e})})}}))}a(J,"enqueueTick");let D=null;async function fe(){if(D!==null)throw{status:500,code:"admission_failed",message:`daemon admission previously failed: ${D instanceof Error?D.message:String(D)}`};if(u.phase==="ready")return{admitted:!1,already_admitted:!0,startup_phase:"ready"};if(u.phase!=="prepared"&&u.phase!=="recovering")throw{status:409,code:"not_prepared",message:u.message};const e=u.phase==="prepared";try{return await N(),u={phase:"ready",message:"",blockerPaths:[]},e?{admitted:!0,already_admitted:!1,startup_phase:"ready"}:{admitted:!1,already_admitted:!0,startup_phase:"ready"}}catch(r){throw D=r,{status:500,code:"admission_failed",message:`daemon admission failed: ${r instanceof Error?r.message:String(r)}`}}}a(fe,"admitStartup");async function ue(e){if(P!==null)throw{status:409,code:"migration_in_progress",message:`the canvas import is already running (${P})`};P="repair";try{const r=await Ar({dryRun:e.dryRun});if(e.dryRun||r.pending||u.phase!=="blocked")return{result:r,resumed:!1};if(t.prepare)return u={phase:"prepared",message:"daemon storage is prepared and normal services are unavailable until admission",blockerPaths:[]},{result:r,resumed:!1};try{return await N(),u={phase:"ready",message:"",blockerPaths:[]},{result:r,resumed:!0}}catch(l){const S=l instanceof Error?l.message:String(l);return setTimeout(()=>{k().catch(()=>{})},1e3),{result:r,resumed:!1,resumeError:S}}}finally{P=null}}a(ue,"repairMigrations");async function he(){o=t.intervalMs??Je;const e=s.token;d=new Ir({epoch:e,enqueue:M}),dr(d),u={phase:"recovering",message:"daemon startup recovery is running and normal services are unavailable",blockerPaths:[]},_.fresh(()=>{h({level:"info",event:"daemon.started",fields:{pid:process.pid,interval_ms:o}})});const r=gr();if(wr(r),_.fresh(()=>{h({level:"info",event:"daemon.install_id.resolved",fields:{install_id:r}})}),_.fresh(()=>{let l;try{l=Ke()}catch{return}l!==null&&h({level:"warn",event:"daemon.startup.warning",fields:{stage:"termrender",warning:l.slice(0,2048)}})}),await _.fresh(async()=>{await Ue(),await ze(),We(Date.now()),qe(Date.now())}),_.fresh(()=>{const{reconcile:l,migrated:S}=vr(tr);l.changed&&h({level:"info",event:"daemon.boot_change.reconciled",fields:{cleared_count:l.cleared.length,same_boot_proven:l.sameBootProven}}),S.length>0&&h({level:"info",event:"daemon.pid_identity.migrated",fields:{migrated_count:S.length}})}),_.fresh(()=>{for(const l of Rr){const S=l.apply();S.changed&&h({level:"info",event:"daemon.boot_migration.applied",fields:{migration:l.id,...S.summary}})}}),L){const l=a(()=>{I(L().catch(()=>{}))},"refresh");I(Fe().catch(()=>{})),I(He().then(({completion:S})=>S).catch(S=>{h({level:"error",event:"daemon.grants.sweep_failed",error:S})})),l(),x=setInterval(l,Oe*1e3),x.unref()}M(()=>{Pr(),Er()}),c=setInterval(J,o),J()}a(he,"completeStartup");function N(){return ce??=he().catch(e=>{throw u={phase:"initializing",message:"daemon startup recovery failed and normal services are unavailable",blockerPaths:[]},e})}a(N,"resumeStartup");try{process.on("SIGINT",q),process.on("SIGTERM",U),process.on("exit",K),xr(),m!==null&&h({level:"info",event:"daemon.joined_owner.applied",fields:{owner:m.owner,rows:m.rows}}),A=await ke();const e=s.token;mr({epoch:e,requestHandover:pe,registerDetached:I,startupBlock:le,admitStartup:fe,repairMigrations:ue}),ie(),C=$e({tcp:t.tcp}),await C.ready;const r=Be("user").runtime;r?.issuer?L=Ge(r.issuer,I):Ne(),r!==void 0&&(T=Me(r,()=>je(r.issuer.replace(/\/$/,"")),L),await T.ready);try{await Dr()}catch(l){if(P=null,l instanceof Cr)return u={phase:"blocked",message:l.message,blockerPaths:l.blockerPaths},k;throw l}process.platform==="linux"&&b(E)&&(De(),await xe("app:terminal"));try{t.prepare?u={phase:"prepared",message:"daemon storage is prepared and normal services are unavailable until admission",blockerPaths:[]}:(await N(),u={phase:"ready",message:"",blockerPaths:[]})}finally{P=null}return k}catch(e){try{await k()}catch(r){throw new AggregateError([e,r],"daemon startup failed and cleanup also failed")}throw e}}a(et,"runDaemon");var fn=et;export{O as brokerCommandDeclaresCanvasHome,F as brokerCommandEpoch,fn as default,et as runDaemon,Xr as superviseTick};
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
var _=Object.defineProperty;var
|
|
2
|
-
`)[0]??"";return
|
|
1
|
+
var _=Object.defineProperty;var r=(t,e)=>_(t,"name",{value:e,configurable:!0});import{getRequest as y,getRequestByInboxTicket as b,presentationDir as q}from"../../core/human/requests.js";import{buildPageSummary as v}from"../../core/human/summary.js";import{validateFinalPageResponses as $}from"../../core/human/tickets.js";import{composeHumanCompletion as j}from"../../core/human/completion.js";import{describePageAnswer as k}from"../../core/human/answer.js";import{renderAnswerText as S}from"../../core/human/answer-text.js";import{readPageFeedback as T}from"../../core/human/feedback.js";import{pageDocumentSha256 as A}from"../../core/human/feedback-companion.js";import{pagePath as N}from"../../core/human/convention.js";import{retireCompanion as f}from"../companion-retire.js";import{settleHumanRequest as h}from"./settle.js";function d(t){const e=y(t)??b(t);if(e===null||e.kind!=="page")throw new Error(`unknown page request: ${t}`);return e}r(d,"requestForTicket");function c(t){try{const e=JSON.parse(t.specification_json);if(typeof e!="object"||e===null)throw new Error("not an object");return e}catch(e){throw new Error(`corrupt page specification: ${t.request_id}`,{cause:e})}}r(c,"manifest");function u(t,e){if(t.action_json!==null)try{const n=JSON.parse(t.action_json);if(n.schema!=="crtr.human-action-binding/v1"||!Array.isArray(n.argv)||typeof n.cwd!="string")throw new Error("invalid binding");return{adapter:{adapter:"subprocess",argv:n.argv,cwd:n.cwd,node_id:t.requester_node_id,...n.app?{app:n.app}:{}},bodyJson:j({requestId:t.request_id,result:e,binding:n,source:c(t).source??{}})}}catch(n){throw new Error(`corrupt frozen completion action: ${t.request_id}`,{cause:n})}}r(u,"completionAction");function O(t,e=80){const n=t.split(`
|
|
2
|
+
`)[0]??"";return n.length>e?`${n.slice(0,e-1)}\u2026`:n}r(O,"firstLine");function x(t){try{return c(t).title}catch{return}}r(x,"pageTitle");function w(t){let e;try{const n=T(t.request_dir);if(n.companionNodeId===void 0)return"";e=[],n.firstCommentedSha256!==void 0&&A(t.request_dir)!==n.firstCommentedSha256&&e.push(`The page changed during feedback: the person commented on it and its companion conversation (node ${n.companionNodeId}) revised it in place. Reread the final page at ${N(q(t),c(t).dialect)} before interpreting this outcome.`);const o=n.comments.filter(i=>i.status==="open");if(o.length>0){const i=o.map(s=>[...s.quote.split(`
|
|
3
3
|
`).map(a=>`> ${a}`),s.note].join(`
|
|
4
|
-
`));
|
|
4
|
+
`));e.push([`Feedback left unresolved at settlement \u2014 the companion conversation (node ${n.companionNodeId}) had not dealt with these items:`,...i].join(`
|
|
5
5
|
|
|
6
|
-
`))}}catch{return""}return
|
|
6
|
+
`))}}catch{return""}return e.length===0?"":`
|
|
7
7
|
|
|
8
|
-
${
|
|
8
|
+
${e.join(`
|
|
9
9
|
|
|
10
|
-
`)}`}
|
|
10
|
+
`)}`}r(w,"feedbackAddendum");function E(t,e){const n=k(c(t),e.responses,{completedAt:e.completedAt});return S(n)+w(t)}r(E,"answerBody");function J(t,e,n){const o=x(t),i=o===void 0?`the human interaction ${t.request_id}`:`\u201C${o}\u201D`,s=n!==void 0&&n!==""?n:"no reason was given";return(e?`The user dismissed ${i} without answering \u2014 a deliberate \u201Cno, I'm not answering this.\u201D Treat it as a rejection: no response will arrive, no partial answer exists, and the same ask must not be raised again.`:`${o===void 0?`The human interaction ${t.request_id}`:`The page \u201C${o}\u201D`} was canceled \u2014 ${s}. No response will arrive, and any partial answers the user had entered were discarded unsent.`)+w(t)}r(J,"cancelBody");function g(t,e,n,o){if(t.requester_node_id!==null)return{label:O(n),disposition:e,body_json:{body:n,result:o}}}r(g,"notification");function l(t){return t.companion_node_id===null?void 0:{retire:r(async(e,n)=>{await f(e,n)},"retire")}}r(l,"retire");async function Q(t,e,n={}){return(await P(t,e,n)).result}r(Q,"resolvePageTicket");async function P(t,e,n={}){const o=d(t),i=c(o),s=$(i,e),a={schema:"crtr.page-response/v1",kind:"page",responses:s,summary:v(i,s),completedAt:n.completedAt??new Date().toISOString(),...n.actor===void 0?{}:{actor:n.actor}},m=await h({request_id:o.request_id,outcome:"answered",result_json:JSON.stringify(a),notification:r(p=>g(p,"human-answer",E(p,a),a),"notification"),...u(o,a)===void 0?{}:{completion_action:u(o,a)},...l(o)===void 0?{}:{post_commit:l(o)}});if(m.outcome==="already_settled"){if(m.request.result_json===null)throw new Error(`settled page request lacks a result: ${o.request_id}`);return{outcome:"already_settled",result:JSON.parse(m.request.result_json)}}return{outcome:"settled",result:a}}r(P,"answerPageTicket");async function U(t,e){const n=d(t),i={schema:"humanloop.cancel/v1",kind:"canceled",canceledAt:new Date().toISOString(),...e.reason===void 0?{}:{reason:e.reason},...e.actor===void 0?{}:{actor:e.actor},...e.disposition===void 0?{}:{disposition:e.disposition}},s=await h({request_id:n.request_id,outcome:e.disposition==="dismissed"?"dismissed":"canceled",result_json:JSON.stringify(i),notification:r(a=>g(a,"human-canceled",J(a,e.disposition==="dismissed",e.reason),i),"notification"),...u(n,i)===void 0?{}:{completion_action:u(n,i)},...l(n)===void 0?{}:{post_commit:l(n)}});if(s.outcome==="already_settled"){if(s.request.result_json===null)throw new Error(`settled page request lacks a result: ${n.request_id}`);return{outcome:"already_settled",result:JSON.parse(s.request.result_json)}}return{outcome:"settled",result:i}}r(U,"cancelHumanTicket");async function V(t){return d(t).state==="settled"}r(V,"deliverTerminalResult");async function W(t,e){const n=d(t);n.companion_node_id!==null&&await f(n.companion_node_id,e)}r(W,"settleFeedbackCompanion");export{P as answerPageTicket,U as cancelHumanTicket,V as deliverTerminalResult,Q as resolvePageTicket,W as settleFeedbackCompanion};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type
|
|
1
|
+
import { type DaemonActionAdapter } from '../../core/canvas/daemon-actions.js';
|
|
2
2
|
import { type HumanRequestOutcome, type HumanRequestRecord } from '../../core/human/requests.js';
|
|
3
3
|
interface SettlementNotification {
|
|
4
4
|
label: string;
|
|
@@ -13,8 +13,7 @@ export interface SettleHumanRequestInput {
|
|
|
13
13
|
settled_at?: string;
|
|
14
14
|
notification?: SettlementNotification | ((request: HumanRequestRecord) => SettlementNotification | undefined);
|
|
15
15
|
completion_action?: {
|
|
16
|
-
|
|
17
|
-
adapter: ExternalActionAdapter;
|
|
16
|
+
adapter: DaemonActionAdapter;
|
|
18
17
|
bodyJson: unknown;
|
|
19
18
|
};
|
|
20
19
|
post_commit?: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var u=Object.defineProperty;var d=(e,o)=>u(e,"name",{value:o,configurable:!0});import{withCanvasWrite as m}from"../../core/canvas/db.js";import{enqueueDaemonAction as f}from"../../core/canvas/daemon-actions.js";import{cancelDelivery as p,enqueueNodeMail as w}from"../../core/feed/messages.js";import{getRequest as l,markCompanionRetired as y,markProjected as q,markProjectionError as h,setSettlementDeliveryMarksLocked as j,settleRequestLocked as v}from"../../core/human/requests.js";import{appendQuestionAnswered as k}from"../../core/runs/questions.js";async function R(e){const o=m(i=>{const _=e.settled_at??new Date().toISOString(),t=v(i,{request_id:e.request_id,outcome:e.outcome,result_json:e.result_json,settled_at:_});if(t===null){const c=l(e.request_id);if(c===null)throw new Error(`human request disappeared while settling: ${e.request_id}`);return{outcome:"already_settled",request:c}}const n=typeof e.notification=="function"?e.notification(t):e.notification;if(t.requester_node_id!==null&&n===void 0)throw new Error(`request ${t.request_id} needs a requester notification`);if(t.action_json!==null&&t.kind==="page"&&e.completion_action===void 0)throw new Error(`request ${t.request_id} needs its frozen completion action`);if(t.kind==="review"&&t.projected_at===null&&e.post_commit?.project===void 0)throw new Error(`review ${t.request_id} needs a projection effect`);if(t.companion_node_id!==null&&t.companion_retired_at===null&&e.post_commit?.retire===void 0)throw new Error(`request ${t.request_id} needs a companion retirement effect`);let a=null,s=null;if(t.requester_node_id!==null){if(n===void 0)throw new Error(`request ${t.request_id} needs a requester notification`);a=w(t.requester_node_id,{kind:"completed",label:n.label,senderName:"crtrd",...n.body_ref===void 0?{}:{bodyRef:n.body_ref},...n.body_json===void 0?{}:{bodyJson:n.body_json},disposition:n.disposition==="human-answer"?"human-answer":"human-canceled",urgency:"normal",wake:1}).deliveryId}t.action_json!==null&&e.completion_action!==void 0&&t.kind==="page"&&(s=f({adapter:e.completion_action.adapter,bodyJson:e.completion_action.bodyJson,idempotencyKey:`human-action:${t.inbox_ticket_id}`})),t.submit_note_delivery_id!==null&&p(t.submit_note_delivery_id),j(i,t.request_id,{settlement_delivery_id:a,action_delivery_id:s});const r=l(t.request_id);if(r===null)throw new Error(`settled human request disappeared: ${t.request_id}`);return k(i,r),{outcome:"settled",request:r}});return o.outcome==="settled"&&e.post_commit!==void 0&&await b(o.request,e.post_commit),o}d(R,"settleHumanRequest");async function b(e,o){if(e.kind==="review"&&e.projected_at===null&&o.project!==void 0)try{await o.project(e),q(e.request_id,new Date().toISOString())}catch(i){h(e.request_id,i instanceof Error?i.message:String(i))}if(e.companion_node_id!==null&&e.companion_retired_at===null&&o.retire!==void 0)try{await o.retire(e.companion_node_id,e.outcome==="canceled"||e.outcome==="dismissed"?"canceled":"approved"),y(e.request_id,new Date().toISOString())}catch{}}d(b,"projectAndRetire");export{b as projectAndRetire,R as settleHumanRequest};
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import type { DetachedWorkLifecycle } from './broker-supervision.js';
|
|
2
|
+
export interface ActionLaneContext {
|
|
3
|
+
lifecycle: DetachedWorkLifecycle;
|
|
4
|
+
}
|
|
5
|
+
/** The daemon lane for one-shot obligations with no publishing object: cron spawn/human sinks and human completion actions. */
|
|
6
|
+
export declare class ActionLaneReconciler {
|
|
7
|
+
run(now: number, ctx: ActionLaneContext): void;
|
|
8
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var p=Object.defineProperty;var d=(n,r)=>p(n,"name",{value:r,configurable:!0});import{rmSync as h}from"node:fs";import{claimDaemonAction as y,dueDaemonActions as g,settleDaemonAction as I}from"../../core/canvas/daemon-actions.js";import{getNode as _}from"../../core/canvas/canvas.js";import{emitEvent as c}from"../../core/events/emit.js";import{operationIdContext as l}from"../../core/events/operation-id.js";import{createPageRequest as v,getRequest as u}from"../../core/human/requests.js";import{synthesizedPageDocument as w,writeSynthesizedPage as k}from"../../core/human/page-synth.js";import{preparePage as $}from"../../core/human/page-authoring.js";import{resolvePageComponents as q}from"../../core/config.js";import{spawnChild as b}from"../../core/runtime/spawn.js";import{runDelivery as D}from"../delivery/run-delivery.js";import{deliveryDaemonInstanceId as f}from"./delivery-lane.js";function s(n,r,e){I(n.actionId,n.attempts,r,e,Date.now())}d(s,"settle");function a(n,r,e){s(n,r,{state:"permanent_failed",failure:{kind:"spawn_error",message:e}})}d(a,"failed");async function N(n,r,e){const t=_(e.nodeId);if(t!==null){if(t.frozen_at!==null||t.pi_session_id!==null||t.status==="idle"||t.status==="done"||t.status==="canceled"){s(n,r,{state:"acknowledged"});return}a(n,r,t.status==="dead"?`cron spawn ${e.nodeId} recorded a failed birth`:`cron spawn ${e.nodeId} found an incomplete birth`);return}try{await b({nodeId:e.nodeId,kind:e.kind,cwd:e.cwd,prompt:e.prompt,...e.root?{root:!0,rootLifecycle:e.rootLifecycle}:{parent:e.parent},readiness:"launch",profile:e.profile,wakeOrigin:e.wakeOrigin}),s(n,r,{state:"acknowledged"})}catch(o){a(n,r,`cron spawn ${e.nodeId} failed: ${o instanceof Error?o.message:String(o)}`),l.fresh(()=>c({level:"error",event:"delivery.cron_spawn_failed",node_id:e.nodeId,error:o,fields:{action_id:n.actionId}}))}}d(N,"deliverSpawn");function P(n,r){const e=k(w(n.title,n.summary,r,!1));try{return $({sourceFile:e.path,source:{sessionName:n.sessionName,...n.profileName===null?{}:{profileName:n.profileName}},productKinds:q(),delivery:{placement:"inline",inbox:!0,reply:!1}})}finally{h(e.dir,{recursive:!0,force:!0})}}d(P,"preparedCronPage");function S(n,r,e){if(u(e.requestId)!==null){s(n,r,{state:"acknowledged"});return}const t=n.body,o=typeof t?.stdout=="string"?t.stdout:null;if(o===null){a(n,r,`cron human ${e.requestId} has no frozen stdout`);return}try{v({request_id:e.requestId,prepared:P(e,o)}),s(n,r,{state:"acknowledged"})}catch(i){a(n,r,`cron human ${e.requestId} failed: ${i instanceof Error?i.message:String(i)}`)}}d(S,"deliverHuman");async function z(n,r){const e=n.adapter;if(n.body===null){a(n,r,`daemon action ${n.actionId} has no body`);return}if(e.adapter==="subprocess"){let t=e.node_id;if(t===void 0){const o=n.idempotencyKey;if(!o.startsWith("human-action:"))throw new Error(`daemon action ${n.actionId} has no originating app`);const i=u(o.slice(13));if(!i)throw new Error(`daemon action ${n.actionId} has no originating human request`);t=i.requester_node_id}await D({argv:e.argv,cwd:e.cwd,document:n.body,attempt:n.attempts,nodeId:t,...e.app?{app:e.app}:{}},o=>s(n,r,o));return}if(e.adapter==="cron_spawn"){await N(n,r,e);return}if(e.adapter==="cron_human"){S(n,r,e);return}a(n,r,`daemon action ${n.actionId} has unknown adapter ${String(e.adapter)}`)}d(z,"deliverAction");class G{static{d(this,"ActionLaneReconciler")}run(r,e){if(!e.lifecycle.acceptsDetachedWork())return;let t;try{t=g(r)}catch(o){l.fresh(()=>c({level:"error",event:"daemon_action.scan_failed",error:o}));return}for(const o of t)try{const i=y(o.actionId,r,f);if(i===null)continue;e.lifecycle.registerDetached(z(i,f).catch(m=>{l.fresh(()=>c({level:"error",event:"daemon_action.failed",error:m,fields:{action_id:i.actionId}}))}))}catch(i){l.fresh(()=>c({level:"error",event:"daemon_action.claim_failed",error:i,fields:{action_id:o.actionId}}))}}}export{G as ActionLaneReconciler};
|
|
@@ -3,7 +3,7 @@ export declare const deliveryDaemonInstanceId: `${string}-${string}-${string}-${
|
|
|
3
3
|
export interface DeliveryLaneContext {
|
|
4
4
|
lifecycle: DetachedWorkLifecycle;
|
|
5
5
|
}
|
|
6
|
-
/** The
|
|
6
|
+
/** The daemon lane for node-outcome external actions. Node-inbox rows are claimed by their destination. */
|
|
7
7
|
export declare class DeliveryLaneReconciler {
|
|
8
8
|
run(now: number, ctx: DeliveryLaneContext): void;
|
|
9
9
|
}
|