@north-light/cli 0.3.573 → 0.3.574
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/clients/attach/viewer.js +1 -1
- package/dist/core/canvas/canvas.d.ts +2 -0
- package/dist/core/canvas/canvas.js +18 -18
- package/dist/core/canvas/crons.d.ts +6 -2
- package/dist/core/canvas/crons.js +11 -9
- package/dist/core/grants/mirror.d.ts +5 -0
- package/dist/core/grants/mirror.js +2 -2
- package/dist/core/provider-error-recognition.js +1 -1
- package/dist/core/providers/call.js +1 -1
- package/dist/core/runtime/revive.js +2 -2
- package/dist/daemon/api/handlers/broker-ops.js +1 -1
- package/dist/daemon/api/handlers/docs.js +1 -1
- package/dist/daemon/api/handlers/objects.d.ts +7 -1
- package/dist/daemon/api/handlers/objects.js +1 -1
- package/dist/daemon/boot-migrations.d.ts +1 -1
- package/dist/daemon/boot-migrations.js +1 -1
- package/dist/daemon/cron/lease-recovery.js +1 -1
- package/dist/daemon/cron/settle.js +1 -1
- package/dist/daemon/cron-run.js +2 -2
- package/dist/daemon/crtrd.js +1 -1
- package/package.json +2 -2
- package/packages/crouter-identity/package.json +1 -1
- package/runtime.lock.json +13 -13
|
@@ -1 +1 @@
|
|
|
1
|
-
var ie=Object.defineProperty;var g=(e,r)=>ie(e,"name",{value:r,configurable:!0});import{validateDeclaredResult as J}from"../../api/command-manifest/result.js";import{callerAllows as ae,requireGroup as se}from"../../daemon/api/handlers/providers.js";import{callerTerminalGrant as de}from"../grants/terminal.js";import{findRefusal as ue,payerOf as le,refusalError as pe,refusedMark as ce,writeCharge as fe}from"../ledger/index.js";import{listInstalledPlugins as me}from"../resolver.js";import{ProviderError as l}from"./errors.js";import{resolveProviderRef as ge}from"./roots.js";import{providerToolPath as ve}from"../plugin-objects-manifest.js";import{ensureProviderBundle as he,refreshProviderBundle as we,resolveProviderBundle as H,unavailableProviderError as ye}from"./bundles.js";import{prepareFileCall as be,resignForRetry as K,resolveFileResult as W}from"./files.js";import{consumeApproval as _e,requireProviderApproval as Ae}from"./approval.js";import{outboundToken as je}from"./mint.js";import{discardFile as ke}from"./token-cache.js";import{registerProviderCall as Pe}from"./inflight.js";import{buildRequestPlan as $e}from"../command-plugins/transport/http-plan.js";import{newTraceId as qe}from"../../shared/traceparent.js";import{sendProviderRequest as Ce,ProviderTransportError as Ee}from"./request.js";import{acceptProviderReceipt as Re}from"./receipts.js";import{writeProviderAudit as Te}from"./audit.js";import{selectDevice as Ie,sendDeviceCall as Me,deviceFailure as Se,deviceUnreachable as X,DEFAULT_DEVICE_REQUEST_MS as Be}from"./device.js";import{isLibsSearch as Y,wantsBundling as Ne,callLibsSearch as Oe,bundleExec as Fe,mapLibOutcome as De,reportLibCalls as Ue}from"./device-libs.js";import{ownMachineId as Le}from"../peer/directory.js";import{directoryIssuer as Je}from"../directory/issuer.js";import{formatCrtrCaller as Z}from"../command-plugins/caller-header.js";import{getNode as He}from"../canvas/canvas.js";import{envelopeForProviderCaller as xe}from"../peer/envelope.js";const Ge="app:terminal";function ee(e){const r=[],i=g((c,t,n)=>{const a=[...t,c.name],s=n||c.tier==="hidden";if(c.kind==="branch"){for(const v of c.children)i(v,a,s);return}const j=ve(e.roots.length,a);r.push({tool:j,leaf:c,hidden:s})},"walk");for(const c of e.roots)i(c,[],!1);return r}g(ee,"providerLeaves");function re(e){if(e.kind!=="branch")return null;const r=[];for(const h of e.children)if(h.kind==="branch"){const _=re(h);_&&r.push(_)}else if("group"in h&&h.group){const{kind:_,name:d,description:A,whenToUse:w,tier:y,summary:k,params:P,output:o,effects:p,group:m}=h;r.push({kind:_,name:d,description:A,whenToUse:w,...y===void 0?{}:{tier:y},summary:k,params:P,output:o,effects:p,group:m})}if(r.length===0)return null;const{kind:i,name:c,description:t,whenToUse:n,tier:a,summary:s,model:j,rootEntry:v}=e;return{kind:i,name:c,description:t,whenToUse:n,...a===void 0?{}:{tier:a},summary:s,...j===void 0?{}:{model:j},...v===void 0?{}:{rootEntry:v},children:r}}g(re,"providerHelpBranch");async function $r(e,r){const i=await H(r),c=ee(i.commands),t=me("user").find(n=>n.name===r)?.manifest.description??r;return{provider:r,status:"available",major:i.major,display_name:t,transport:i.transport.kind,groups:i.provider.groups.filter(n=>ae(e,`${r}:${n.group}`)).map(n=>({group:n.group,leaves:c.filter(({leaf:a,hidden:s})=>!s&&a.group===n.group).map(({tool:a,leaf:s})=>({tool:a,description:s.description,summary:s.summary,params:s.params,output:s.output}))})),commands:i.commands.roots.flatMap(n=>{const a=re(n);return a?[a]:[]})}}g($r,"providerTools");async function ze(e){return await Re(e.headers["crtr-receipt"],e)}g(ze,"onProviderResponse");async function Qe(e){if(e.class==="person"){const r=(await de())?.sub;if(!r)throw new l("grant_revoked","This machine has no active Northlight grant for your terminal. Run `crtr sys join` again from /account/machines.");return{sub:r,grantee:r}}if(!e.sub||!e.grantee)throw new l("grant_revoked","the caller has no active grant");return{sub:e.sub,grantee:e.grantee}}g(Qe,"identity");function Ve(e,r){return[`${e.id}:${r.group}`]}g(Ve,"callScope");function Ke(e,r){const i=ee(e.commands).find(c=>c.tool===r);if(!i)throw new l("not_found",`tool "${r}" is not in provider "${e.id}"`,{param:"tool"});if(!i.leaf.group)throw new l("not_found",`tool "${r}" has no group`,{param:"tool"});return i.leaf}g(Ke,"leafFor");function x(e){if(!e||typeof e!="object"||Array.isArray(e))return{};const r=e.error;return!r||typeof r!="object"||Array.isArray(r)?{}:r}g(x,"errorBody");function We(e){const r=Array.isArray(e)?e[0]:e;if(!r)return;const i=Number(r);if(Number.isFinite(i)&&i>=0)return i;const c=Date.parse(r);return Number.isFinite(c)?Math.max(0,Math.ceil((c-Date.now())/1e3)):void 0}g(We,"retryAfter");function N(e,r,i,c=!1){const t=x(r),n=typeof t.code=="string"?t.code:void 0,a=typeof t.message=="string"?t.message:`provider answered HTTP ${e}`,s=typeof t.field=="string"?t.field:void 0,v={origin:"provider",details:{code:n??null,message:a,...s?{field:s}:{},...typeof t.next=="string"?{next:t.next}:{},...t.received!==void 0?{received:t.received}:{},status:e},...s?{param:s}:{}};return e===429?new l("provider_rate_limited",a,{...v,retry_after_s:We(i["retry-after"])}):e===401||e>=500?new l("provider_unavailable",a,v):e===403&&n==="provider_refused"?new l("provider_refused",a,v):e===403&&n==="approval_required"?new l("provider_error",c?"provider asked for approval again":"provider approval question is invalid",{...v,status:e}):new l("provider_error",a,{...v,status:e})}g(N,"mapProviderResponse");function te(e,r){return JSON.stringify({major:e.major,endpoint:e.transport.kind==="http"?e.transport.endpoint:null,baseUrl:e.commands.baseUrl??null,rest:r.rest,params:r.params,output:r.output})}g(te,"approvalShape");async function Xe(e){const r=e.origin!==void 0?Z({node:e.origin.node??void 0,run:e.origin.run??void 0,machine:e.origin.machine}):Z({node:e.node_id??void 0,run:e.run_id??void 0,profile:e.node_id?(await He(e.node_id))?.profile_id??void 0:void 0,machine:Je()!==null?Le():void 0});return r===""?{}:{"Crtr-Caller":r}}g(Xe,"crtrCallerHeader");async function qr(e,r,i){const c=ge(r.provider);if(c===null)throw new l("not_found",`provider "${r.provider}" is not available`,{param:"provider"});const t={...r,provider:c},n=new AbortController,a=g(()=>n.abort(i.signal.reason),"abort");i.signal.aborted?a():i.signal.addEventListener("abort",a,{once:!0});let s=i.requestId;const j=i.traceId??qe(),v=Pe({request_id:s,run_id:e.run_id,node_id:e.node_id,controller:n});let h,_,d,A,w,y,k,P="allowed";try{try{await he(t.provider)}catch{throw ye(t.provider)}let o=await H(t.provider,t.version),p=!1,m,O,$,G=!1,z=!1,F,Q=0;for(;;){const b=Ke(o,t.tool);if(d=`${o.id}:${b.group}`,se(e,o.id,b.group),o.transport.kind!=="machine"&&t.machine!==void 0)throw new l("invalid_argument",`provider "${o.id}" is not served by a device, so it takes no machine`,{param:"machine"});o.transport.kind==="machine"&&F===void 0&&(F=await Ie(t.machine,void 0,{newest:Y(o.major,t.tool)}),Q=Date.now()+(o.commands.timeouts?.requestMs??Be));let D=null;if(t.approval&&!G){const u=await _e(e,t,te(o,b));$=u.option,D=u.prepared,k=t.approval,s=u.requestId,G=!0}const T={params:b.params.filter(u=>"type"in u&&u.type==="file").map(u=>u.name),output:b.output.find(u=>u.type==="file")?.name??null},V=JSON.stringify(T);if(O!==void 0&&O!==V)throw new l("provider_bad_response","the refreshed manifest changed the tool file contract",{origin:"provider",details:{status:409,message:"manifest_stale changed the tool file contract"}});O=V,D&&(m=await K(e,T,t.arguments,D,{signal:n.signal})),m??=await be(e,T,t.arguments,{signal:n.signal});const{sub:q,grantee:I}=await Qe(e);if(o.transport.kind==="machine"){const u=await Ye(e,o,t,b,m,{sub:q,requestId:s,deadlineAt:Q,signal:n.signal,machine:F});return y=u.responder,h=u.cleanup,{status:200,body:u.result}}const C=await je({audience:o.transport.endpoint,sub:q,grantee:I,initiating_app:I,scope:Ve(o,b)},{signal:n.signal});A=C.jti;const U=e.class==="person"?Ge:I,E=le({call:"tool",tokenPayer:C.payer,sub:q}),L=await ue({scope:"call",payer:E.payer,funding:E.funding,sub:q,grantee:U,provider:`app:${o.id}`});if(L!==null)throw await fe({request:s,kind:"tool",what:`${o.id}:${t.tool}`,usd:0,payer:E.payer,funding:E.funding,sub:q,grantee:U,node:e.node_id,run:e.run_id,provider:`app:${o.id}`,causedBy:i.causedBy??null,refused:ce(L)}),pe(L);const oe={registration:{name:o.id,endpoint:o.transport.endpoint},...o.commands.baseUrl?{baseUrl:o.commands.baseUrl}:{},...o.commands.timeouts?{timeouts:o.commands.timeouts}:{},params:b.params,rest:b.rest,output:b.output,commandPath:[o.id,...t.tool.split(" ")]},ne=$e(oe,m.arguments,void 0,{authorization:`Bearer ${C.access_token}`,requestId:s,traceId:j,fileMode:"pass-through",extraHeaders:{...i.causedBy?{"Crtr-Caused-By":i.causedBy}:{},...e.run_id?{"Crtr-Run-Id":e.run_id}:{},...await Xe(e),...$?{"Crtr-Approval":$}:{},...m.headers}});_??=Date.now()+(o.commands.timeouts?.requestMs??3e4);let f;try{if(f=await Ce(ne,{connectMs:o.commands.timeouts?.connectMs,requestMs:o.commands.timeouts?.requestMs,deadlineAt:_,signal:n.signal}),n.signal.aborted)throw n.signal.reason??new Error("provider call aborted")}catch(u){throw n.signal.aborted?n.signal.reason??u:u instanceof Ee?new l("provider_unavailable",u.message,{origin:"provider",details:{status:null,code:u.kind}}):u}if(w??=await ze({provider:o.id,tool:t.tool,request_id:s,run_id:e.run_id,sub:q,grantee:I,payer:C.payer,ledger_grantee:U,funding:E.funding,node_id:e.node_id,caused_by:i.causedBy??null,jti:C.jti,status:f.status,headers:f.headers}),y=f.headers["crtr-responder"],f.status===401&&ke(C.key),f.status>=200&&f.status<300){const u=f.body;if(!u||typeof u!="object"||Array.isArray(u))throw new l("provider_bad_response","provider result is not a JSON object",{origin:"provider",details:{status:f.status,message:"provider result is not a JSON object"}});let S;try{S=await W(e,m,u,{signal:n.signal})}catch(R){throw R instanceof l&&R.code==="provider_error"?new l("provider_bad_response",R.message,{origin:"provider",details:{status:f.status,message:R.message}}):R}h=S.cleanup;const B=J(b.output,S.result);if(B)throw new l("provider_bad_response",`provider result has an invalid output field "${B.field}"`,{origin:"provider",param:B.field,details:{status:f.status,...B}});if(n.signal.aborted)throw n.signal.reason??new Error("provider call aborted");return{status:200,body:S.result}}const M=x(f.body);if(f.status===403&&M.code==="approval_required"&&!$&&!z){z=!0;const u=await Ae(e,t,s,M.question,n.signal,te(o,b),m);if(k=u.questionId,$=u.option,m=await K(e,T,t.arguments,m,{signal:n.signal}),_=void 0,n.signal.aborted)throw new l("user_denied","the approval wait was canceled");continue}if(f.status===403&&M.code==="approval_required"&&$)throw N(f.status,f.body,f.headers,!0);if(f.status!==401&&M.manifest_stale===!0&&!p){p=!0,await we(o.id,{conditional:!1,...t.version===void 0?{}:{version:t.version}}),o=await H(o.id,t.version);continue}throw N(f.status,f.body,f.headers,!!$)}}catch(o){throw o instanceof l&&o.question_id&&(k=o.question_id),y===void 0&&o instanceof l&&typeof o.responder=="string"&&(y=o.responder),P=`refused:${o instanceof l?o.code:"server_error"}`,await h?.(),o}finally{try{await Te({request_id:s,caller:e,provider:t.provider,tool:t.tool,scope_checked:d,outcome:P,jti:A,receipt_id:w,responder:y,question_id:k})}finally{v()}i.signal.removeEventListener("abort",a)}}g(qr,"callProvider");async function Ye(e,r,i,c,t,n){const{machine:a}=n,s=await xe(e,n.sub),j={machine:a,envelope:s,signal:n.signal,deadlineAt:n.deadlineAt,mapFailure:N};if(Y(r.major,i.tool)){const p=await Oe(j,t.arguments,r.major),m=J(c.output,p);if(m)throw new l("provider_bad_response",`the libraries result has an invalid output field "${m.field}"`,{origin:"provider",param:m.field,details:{status:200,...m}});return{result:p,responder:void 0,cleanup:void 0}}let v=t.arguments,h=null,_="";if(Ne(r.major,i.tool,t.arguments)){const p=await Fe(j,t.arguments,r.major);if(n.deadlineAt-Date.now()<=0)throw X(a,"timeout","");p!==null&&(v=p.arguments,h=p.services,_=p.release)}const d=await Me(a,{tool:i.tool,arguments:v,version:r.major,requestId:n.requestId,runId:e.run_id,deadlineAt:n.deadlineAt,upload:t.upload===null?null:{id:t.upload.upload_id,link:t.upload.upload_link}},s,n.signal);if(n.signal.aborted)throw n.signal.reason??new Error("provider call aborted");if("unreachable"in d)throw X(a,d.unreachable.reason,d.unreachable.message);const A=d.headers["crtr-responder"],w=x(d.body);if(d.status<200||d.status>=300){const p=Se(a,d.status,typeof w.code=="string"?w.code:void 0,typeof w.message=="string"?w.message:void 0,d.body),m=p===null&&d.status>=500&&typeof w.code=="string"?new l("provider_error",typeof w.message=="string"?w.message:`the device answered HTTP ${d.status}`,{origin:"runtime",status:d.status,details:{code:w.code,status:d.status}}):null;throw Object.assign(p??m??N(d.status,d.body,d.headers),{responder:A})}const y=d.body&&typeof d.body=="object"&&!Array.isArray(d.body)?d.body.result:void 0;if(!y||typeof y!="object"||Array.isArray(y))throw Object.assign(new l("provider_bad_response","the device result is not a JSON object",{origin:"provider",details:{status:d.status,message:"the device result is not a JSON object"}}),{responder:A});let k=y;if(h!==null){const p=De(k,h);if(Ue(a,s,_,p.calls),"error"in p)throw Object.assign(p.error,{responder:A});k=p.result}let P;try{P=await W(e,t,k,{signal:n.signal})}catch(p){throw p instanceof l&&p.code==="provider_error"?Object.assign(new l("provider_bad_response",p.message,{origin:"provider",details:{status:d.status,message:p.message}}),{responder:A}):p}const o=J(c.output,P.result);if(o)throw await P.cleanup?.(),Object.assign(new l("provider_bad_response",`the device result has an invalid output field "${o.field}"`,{origin:"provider",param:o.field,details:{status:d.status,...o}}),{responder:A});return{result:P.result,responder:A,cleanup:P.cleanup}}g(Ye,"callDevice");export{qr as callProvider,Xe as crtrCallerHeader,Qe as identity,N as mapProviderResponse,ze as onProviderResponse,ee as providerLeaves,$r as providerTools};
|
|
1
|
+
var de=Object.defineProperty;var m=(e,r)=>de(e,"name",{value:r,configurable:!0});import{validateDeclaredResult as x}from"../../api/command-manifest/result.js";import{callerAllows as ue,requireGroup as le}from"../../daemon/api/handlers/providers.js";import{callerTerminalGrant as pe}from"../grants/terminal.js";import{findRefusal as ce,payerOf as fe,refusalError as me,refusedMark as ve,writeCharge as ge}from"../ledger/index.js";import{listInstalledPlugins as he}from"../resolver.js";import{ProviderError as l}from"./errors.js";import{resolveProviderRef as we}from"./roots.js";import{providerToolPath as ye}from"../plugin-objects-manifest.js";import{ensureProviderBundle as be,refreshProviderBundle as X,resolveProviderBundle as O,unavailableProviderError as _e}from"./bundles.js";import{prepareFileCall as Ae,resignForRetry as Y,resolveFileResult as Z}from"./files.js";import{consumeApproval as je,requireProviderApproval as ke}from"./approval.js";import{outboundToken as Pe}from"./mint.js";import{discardFile as $e}from"./token-cache.js";import{registerProviderCall as qe}from"./inflight.js";import{buildRequestPlan as Ce}from"../command-plugins/transport/http-plan.js";import{newTraceId as Ee}from"../../shared/traceparent.js";import{sendProviderRequest as Re,ProviderTransportError as Te}from"./request.js";import{acceptProviderReceipt as Ie}from"./receipts.js";import{writeProviderAudit as Me}from"./audit.js";import{selectDevice as Se,sendDeviceCall as Be,deviceFailure as Ne,deviceUnreachable as ee,DEFAULT_DEVICE_REQUEST_MS as Oe}from"./device.js";import{isLibsSearch as re,wantsBundling as Fe,callLibsSearch as De,bundleExec as Ue,mapLibOutcome as Le,reportLibCalls as Je}from"./device-libs.js";import{ownMachineId as He}from"../peer/directory.js";import{directoryIssuer as xe}from"../directory/issuer.js";import{formatCrtrCaller as te}from"../command-plugins/caller-header.js";import{getNode as Ge}from"../canvas/canvas.js";import{envelopeForProviderCaller as ze}from"../peer/envelope.js";const Qe="app:terminal";function oe(e){const r=[],n=m((c,t,i)=>{const s=[...t,c.name],d=i||c.tier==="hidden";if(c.kind==="branch"){for(const v of c.children)n(v,s,d);return}const j=ye(e.roots.length,s);r.push({tool:j,leaf:c,hidden:d})},"walk");for(const c of e.roots)n(c,[],!1);return r}m(oe,"providerLeaves");function ie(e){if(e.kind!=="branch")return null;const r=[];for(const g of e.children)if(g.kind==="branch"){const b=ie(g);b&&r.push(b)}else if("group"in g&&g.group){const{kind:b,name:u,description:_,whenToUse:h,tier:w,summary:k,params:P,output:o,effects:p,group:A}=g;r.push({kind:b,name:u,description:_,whenToUse:h,...w===void 0?{}:{tier:w},summary:k,params:P,output:o,effects:p,group:A})}if(r.length===0)return null;const{kind:n,name:c,description:t,whenToUse:i,tier:s,summary:d,model:j,rootEntry:v}=e;return{kind:n,name:c,description:t,whenToUse:i,...s===void 0?{}:{tier:s},summary:d,...j===void 0?{}:{model:j},...v===void 0?{}:{rootEntry:v},children:r}}m(ie,"providerHelpBranch");async function Cr(e,r){const n=await O(r),c=oe(n.commands),t=he("user").find(i=>i.name===r)?.manifest.description??r;return{provider:r,status:"available",major:n.major,display_name:t,transport:n.transport.kind,groups:n.provider.groups.filter(i=>ue(e,`${r}:${i.group}`)).map(i=>({group:i.group,leaves:c.filter(({leaf:s,hidden:d})=>!d&&s.group===i.group).map(({tool:s,leaf:d})=>({tool:s,description:d.description,summary:d.summary,params:d.params,output:d.output}))})),commands:n.commands.roots.flatMap(i=>{const s=ie(i);return s?[s]:[]})}}m(Cr,"providerTools");async function Ve(e){return await Ie(e.headers["crtr-receipt"],e)}m(Ve,"onProviderResponse");async function Ke(e){if(e.class==="person"){const r=(await pe())?.sub;if(!r)throw new l("grant_revoked","This machine has no active Northlight grant for your terminal. Run `crtr sys join` again from /account/machines.");return{sub:r,grantee:r}}if(!e.sub||!e.grantee)throw new l("grant_revoked","the caller has no active grant");return{sub:e.sub,grantee:e.grantee}}m(Ke,"identity");function We(e,r){return[`${e.id}:${r.group}`]}m(We,"callScope");function Xe(e,r){const n=oe(e.commands).find(c=>c.tool===r);if(!n)throw new l("not_found",`tool "${r}" is not in provider "${e.id}"`,{param:"tool"});if(!n.leaf.group)throw new l("not_found",`tool "${r}" has no group`,{param:"tool"});return n.leaf}m(Xe,"leafFor");function G(e){if(!e||typeof e!="object"||Array.isArray(e))return{};const r=e.error;return!r||typeof r!="object"||Array.isArray(r)?{}:r}m(G,"errorBody");function Ye(e){const r=Array.isArray(e)?e[0]:e;if(!r)return;const n=Number(r);if(Number.isFinite(n)&&n>=0)return n;const c=Date.parse(r);return Number.isFinite(c)?Math.max(0,Math.ceil((c-Date.now())/1e3)):void 0}m(Ye,"retryAfter");function F(e,r,n,c=!1){const t=G(r),i=typeof t.code=="string"?t.code:void 0,s=typeof t.message=="string"?t.message:`provider answered HTTP ${e}`,d=typeof t.field=="string"?t.field:void 0,v={origin:"provider",details:{code:i??null,message:s,...d?{field:d}:{},...typeof t.next=="string"?{next:t.next}:{},...t.received!==void 0?{received:t.received}:{},status:e},...d?{param:d}:{}};return e===429?new l("provider_rate_limited",s,{...v,retry_after_s:Ye(n["retry-after"])}):e===401||e>=500?new l("provider_unavailable",s,v):e===403&&i==="provider_refused"?new l("provider_refused",s,v):e===403&&i==="approval_required"?new l("provider_error",c?"provider asked for approval again":"provider approval question is invalid",{...v,status:e}):new l("provider_error",s,{...v,status:e})}m(F,"mapProviderResponse");function ne(e,r){return JSON.stringify({major:e.major,endpoint:e.transport.kind==="http"?e.transport.endpoint:null,baseUrl:e.commands.baseUrl??null,rest:r.rest,params:r.params,output:r.output})}m(ne,"approvalShape");async function Ze(e){const r=e.origin!==void 0?te({node:e.origin.node??void 0,run:e.origin.run??void 0,machine:e.origin.machine}):te({node:e.node_id??void 0,run:e.run_id??void 0,profile:e.node_id?(await Ge(e.node_id))?.profile_id??void 0:void 0,machine:xe()!==null?He():void 0});return r===""?{}:{"Crtr-Caller":r}}m(Ze,"crtrCallerHeader");async function Er(e,r,n){const c=we(r.provider);if(c===null)throw new l("not_found",`provider "${r.provider}" is not available`,{param:"provider"});const t={...r,provider:c},i=new AbortController,s=m(()=>i.abort(n.signal.reason),"abort");n.signal.aborted?s():n.signal.addEventListener("abort",s,{once:!0});let d=n.requestId;const j=n.traceId??Ee(),v=qe({request_id:d,run_id:e.run_id,node_id:e.node_id,controller:i});let g,b,u,_,h,w,k,P="allowed";try{try{await be(t.provider)}catch{throw _e(t.provider)}let o=await O(t.provider,t.version),p=!1,A=!1,$,D,C,z=!1,Q=!1,U,V=0;for(;;){const y=Xe(o,t.tool);if(u=`${o.id}:${y.group}`,le(e,o.id,y.group),o.transport.kind!=="machine"&&t.machine!==void 0)throw new l("invalid_argument",`provider "${o.id}" is not served by a device, so it takes no machine`,{param:"machine"});o.transport.kind==="machine"&&U===void 0&&(U=await Se(t.machine,void 0,{newest:re(o.major,t.tool)}),V=Date.now()+(o.commands.timeouts?.requestMs??Oe));let L=null;if(t.approval&&!z){const a=await je(e,t,ne(o,y));C=a.option,L=a.prepared,k=t.approval,d=a.requestId,z=!0}const M={params:y.params.filter(a=>"type"in a&&a.type==="file").map(a=>a.name),output:y.output.find(a=>a.type==="file")?.name??null},K=JSON.stringify(M);if(D!==void 0&&D!==K)throw new l("provider_bad_response","the refreshed manifest changed the tool file contract",{origin:"provider",details:{status:409,message:"manifest_stale changed the tool file contract"}});D=K,L&&($=await Y(e,M,t.arguments,L,{signal:i.signal})),$??=await Ae(e,M,t.arguments,{signal:i.signal});const{sub:R,grantee:S}=await Ke(e);if(o.transport.kind==="machine"){const a=await er(e,o,t,y,$,{sub:R,requestId:d,deadlineAt:V,signal:i.signal,machine:U});return w=a.responder,g=a.cleanup,{status:200,body:a.result}}const W=o.transport.endpoint;let E;try{E=await Pe({audience:W,sub:R,grantee:S,initiating_app:S,scope:We(o,y)},{signal:i.signal})}catch(a){if(!(a instanceof l)||a.details?.directory_error!=="invalid_target"||A)throw a;A=!0,await X(o.id,{conditional:!1,...t.version===void 0?{}:{version:t.version}});const q=await O(o.id,t.version);if(q.transport.kind==="machine"||q.transport.endpoint===W)throw a;o=q;continue}_=E.jti;const J=e.class==="person"?Qe:S,T=fe({call:"tool",tokenPayer:E.payer,sub:R}),H=await ce({scope:"call",payer:T.payer,funding:T.funding,sub:R,grantee:J,provider:`app:${o.id}`});if(H!==null)throw await ge({request:d,kind:"tool",what:`${o.id}:${t.tool}`,usd:0,payer:T.payer,funding:T.funding,sub:R,grantee:J,node:e.node_id,run:e.run_id,provider:`app:${o.id}`,causedBy:n.causedBy??null,refused:ve(H)}),me(H);const ae={registration:{name:o.id,endpoint:o.transport.endpoint},...o.commands.baseUrl?{baseUrl:o.commands.baseUrl}:{},...o.commands.timeouts?{timeouts:o.commands.timeouts}:{},params:y.params,rest:y.rest,output:y.output,commandPath:[o.id,...t.tool.split(" ")]},se=Ce(ae,$.arguments,void 0,{authorization:`Bearer ${E.access_token}`,requestId:d,traceId:j,fileMode:"pass-through",extraHeaders:{...n.causedBy?{"Crtr-Caused-By":n.causedBy}:{},...e.run_id?{"Crtr-Run-Id":e.run_id}:{},...await Ze(e),...C?{"Crtr-Approval":C}:{},...$.headers}});b??=Date.now()+(o.commands.timeouts?.requestMs??3e4);let f;try{if(f=await Re(se,{connectMs:o.commands.timeouts?.connectMs,requestMs:o.commands.timeouts?.requestMs,deadlineAt:b,signal:i.signal}),i.signal.aborted)throw i.signal.reason??new Error("provider call aborted")}catch(a){throw i.signal.aborted?i.signal.reason??a:a instanceof Te?new l("provider_unavailable",a.message,{origin:"provider",details:{status:null,code:a.kind}}):a}if(h??=await Ve({provider:o.id,tool:t.tool,request_id:d,run_id:e.run_id,sub:R,grantee:S,payer:E.payer,ledger_grantee:J,funding:T.funding,node_id:e.node_id,caused_by:n.causedBy??null,jti:E.jti,status:f.status,headers:f.headers}),w=f.headers["crtr-responder"],f.status===401&&$e(E.key),f.status>=200&&f.status<300){const a=f.body;if(!a||typeof a!="object"||Array.isArray(a))throw new l("provider_bad_response","provider result is not a JSON object",{origin:"provider",details:{status:f.status,message:"provider result is not a JSON object"}});let q;try{q=await Z(e,$,a,{signal:i.signal})}catch(I){throw I instanceof l&&I.code==="provider_error"?new l("provider_bad_response",I.message,{origin:"provider",details:{status:f.status,message:I.message}}):I}g=q.cleanup;const N=x(y.output,q.result);if(N)throw new l("provider_bad_response",`provider result has an invalid output field "${N.field}"`,{origin:"provider",param:N.field,details:{status:f.status,...N}});if(i.signal.aborted)throw i.signal.reason??new Error("provider call aborted");return{status:200,body:q.result}}const B=G(f.body);if(f.status===403&&B.code==="approval_required"&&!C&&!Q){Q=!0;const a=await ke(e,t,d,B.question,i.signal,ne(o,y),$);if(k=a.questionId,C=a.option,$=await Y(e,M,t.arguments,$,{signal:i.signal}),b=void 0,i.signal.aborted)throw new l("user_denied","the approval wait was canceled");continue}if(f.status===403&&B.code==="approval_required"&&C)throw F(f.status,f.body,f.headers,!0);if(f.status!==401&&B.manifest_stale===!0&&!p){p=!0,await X(o.id,{conditional:!1,...t.version===void 0?{}:{version:t.version}}),o=await O(o.id,t.version);continue}throw F(f.status,f.body,f.headers,!!C)}}catch(o){throw o instanceof l&&o.question_id&&(k=o.question_id),w===void 0&&o instanceof l&&typeof o.responder=="string"&&(w=o.responder),P=`refused:${o instanceof l?o.code:"server_error"}`,await g?.(),o}finally{try{await Me({request_id:d,caller:e,provider:t.provider,tool:t.tool,scope_checked:u,outcome:P,jti:_,receipt_id:h,responder:w,question_id:k})}finally{v()}n.signal.removeEventListener("abort",s)}}m(Er,"callProvider");async function er(e,r,n,c,t,i){const{machine:s}=i,d=await ze(e,i.sub),j={machine:s,envelope:d,signal:i.signal,deadlineAt:i.deadlineAt,mapFailure:F};if(re(r.major,n.tool)){const p=await De(j,t.arguments,r.major),A=x(c.output,p);if(A)throw new l("provider_bad_response",`the libraries result has an invalid output field "${A.field}"`,{origin:"provider",param:A.field,details:{status:200,...A}});return{result:p,responder:void 0,cleanup:void 0}}let v=t.arguments,g=null,b="";if(Fe(r.major,n.tool,t.arguments)){const p=await Ue(j,t.arguments,r.major);if(i.deadlineAt-Date.now()<=0)throw ee(s,"timeout","");p!==null&&(v=p.arguments,g=p.services,b=p.release)}const u=await Be(s,{tool:n.tool,arguments:v,version:r.major,requestId:i.requestId,runId:e.run_id,deadlineAt:i.deadlineAt,upload:t.upload===null?null:{id:t.upload.upload_id,link:t.upload.upload_link}},d,i.signal);if(i.signal.aborted)throw i.signal.reason??new Error("provider call aborted");if("unreachable"in u)throw ee(s,u.unreachable.reason,u.unreachable.message);const _=u.headers["crtr-responder"],h=G(u.body);if(u.status<200||u.status>=300){const p=Ne(s,u.status,typeof h.code=="string"?h.code:void 0,typeof h.message=="string"?h.message:void 0,u.body),A=p===null&&u.status>=500&&typeof h.code=="string"?new l("provider_error",typeof h.message=="string"?h.message:`the device answered HTTP ${u.status}`,{origin:"runtime",status:u.status,details:{code:h.code,status:u.status}}):null;throw Object.assign(p??A??F(u.status,u.body,u.headers),{responder:_})}const w=u.body&&typeof u.body=="object"&&!Array.isArray(u.body)?u.body.result:void 0;if(!w||typeof w!="object"||Array.isArray(w))throw Object.assign(new l("provider_bad_response","the device result is not a JSON object",{origin:"provider",details:{status:u.status,message:"the device result is not a JSON object"}}),{responder:_});let k=w;if(g!==null){const p=Le(k,g);if(Je(s,d,b,p.calls),"error"in p)throw Object.assign(p.error,{responder:_});k=p.result}let P;try{P=await Z(e,t,k,{signal:i.signal})}catch(p){throw p instanceof l&&p.code==="provider_error"?Object.assign(new l("provider_bad_response",p.message,{origin:"provider",details:{status:u.status,message:p.message}}),{responder:_}):p}const o=x(c.output,P.result);if(o)throw await P.cleanup?.(),Object.assign(new l("provider_bad_response",`the device result has an invalid output field "${o.field}"`,{origin:"provider",param:o.field,details:{status:u.status,...o}}),{responder:_});return{result:P.result,responder:_,cleanup:P.cleanup}}m(er,"callDevice");export{Er as callProvider,Ze as crtrCallerHeader,Ke as identity,F as mapProviderResponse,Ve as onProviderResponse,oe as providerLeaves,Cr as providerTools};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var ie=Object.defineProperty;var l=(e,r)=>ie(e,"name",{value:r,configurable:!0});import{assertGranteeRunsHere as te}from"./unsandboxed.js";import{existsSync as H}from"node:fs";import{conversationIdFromPath as v,conversationStore as p,ConversationNotFoundError as M}from"../conversation-store/index.js";import{isAbsolute as ne}from"node:path";import{findNodeBySessionFile as ae,getNode as S,updateNode as $,beginExecution as oe,ExecutionAlreadyLive as se,recordExecutionPid as le,abortExecution as N,endLiveExecution as ce,unbindSession as U,recordLaunch as ue,setFrozen as fe,clearFrozen as z,fullName as we}from"../canvas/index.js";import{emitEvent as K}from"../events/emit.js";import{consumeDeadlineOnWake as de}from"../feed/messages.js";import{isParked as G,transition as C}from"./lifecycle.js";import{publishNotice as he}from"./close.js";import{InputError as F}from"../io.js";import{buildPiArgv as _}from"./launch.js";import{buildReviveKickoff as pe,drainBearings as me,hasRetainedReports as ve,readGoal as g,readYieldMessage as _e,RUNTIME_RESTART_CONTINUATION as ye}from"./kickoff.js";import{readRoadmap as J}from"./roadmap.js";import{encodeKickoffOrigin as ke,KICKOFF_ORIGIN_ENV as ge}from"./stamp/protocol.js";import{headlessBrokerHost as be,brokerLaunchJson as Re}from"./host.js";import{processRunner as xe}from"./runner/process.js";import{runnerForEnvironment as Ee}from"./runner/index.js";import{blaxelEnvironmentOf as W}from"./blaxel-environment.js";import{recordLaunchFailure as Se}from"../../daemon/reconcilers/node-lifecycle/launch-failure.js";import{acceptedRelease as $e,checkBilledWake as Ne,EnvironmentImagePending as Ce,imageForWake as Fe}from"../../daemon/reconcilers/node-lifecycle/remote-wake.js";import{ExecutionCapReached as Ae,liveExecutionForNode as Pe,setExecutionLaunchJson as Be}from"../canvas/executions.js";import{appMemoryFull as Oe,appMemoryTooSmall as De,boundFleet as j,brokerCapReached as V,brokerThresholdsForDaemon as A}from"./fleet.js";import{admitBrokerMemory as Te}from"./memory-admission.js";import{beginBootFaultAttempt as Le,clearFault as He,hasAdmittedTurn as Me}from"../canvas/recovery.js";import{clearNodeLedger as X,forkNodeLedger as Ue,noticeChangedWhileDone as ze}from"./ledger.js";import{forkSourceNode as Ke,rootOfSpine as Ge}from"./nodes.js";import{checkStart as Je}from"./start-check.js";import{isReviewCompanionBound as We}from"../review/companion.js";import{assertProfileActive as je}from"../profiles/manifest.js";import{isPidAlive as Ve}from"../canvas/pid.js";import{crtrHome as Xe,jobDir as Ye}from"../canvas/paths.js";import{contextDir as qe,ensureNodeDirs as Qe,nodeAgentDir as Ze}from"../canvas/node-agent-paths.js";import{discoverLifecycleHookRegistry as Ie}from"../command-hooks/discovery.js";import{invokeLifecycleHooks as er}from"../command-hooks/transport/exec-lifecycle.js";async function rr(e,r){const i=e.pi_session_file,t=i?v(i):null;if(t===null)return{};try{const a=await p().header(t);return r?{resumeSessionPath:a.path}:{resumeSessionPath:a.path,newCycle:!0}}catch(a){if(a instanceof M)return{};throw a}}l(rr,"resumeArgs");async function Y(e){const r=v(e);if(r===null)return!1;try{return await p().header(r),!0}catch(i){if(i instanceof M)return!1;throw i}}l(Y,"conversationExists");async function ir(e){const r=v(e);return r===null?!0:(await p().read(r)).entries.some(i=>i.type==="message")}l(ir,"sessionHasConversation");async function tr(e){const r=v(e);if(r===null)return!0;const i=(await p().header(r)).header.cwd;return typeof i!="string"||H(i)}l(tr,"sessionCwdExists");async function nr(e,r,i,t){const a=r.pi_session_file;if(!a||!await Y(a))return{};const f=await ae(a);return f!==null&&f.node_id!==e&&Ve(f.pi_pid)?{}:t&&!await tr(a)?{}:await rr(r,i)}l(nr,"resumableSessionArgs");async function ar(e){return await J(e)===null&&await _e(e)===null&&!await ve(e)}l(ar,"isUnstartedBirth");async function Gr(e){const r=await g(e);if(r!==null&&r.trim()!=="")return!0;const i=await J(e);return i!==null&&i.trim()!==""}l(Gr,"hasFreshGroundState");async function Jr(e,r){const i=await q(e,r,!0);if(i.parked)throw new Error(`reviveNode: internal parked decision for activating revive ${e}`);return i.result}l(Jr,"reviveNode");async function Wr(e,r,i){return q(e,{...r,viewerAttach:!0},i)}l(Wr,"decideAttachRevive");async function q(e,r,i){let t=await S(e);if(t===null)throw new Error(`reviveNode: unknown node ${e}`);if(t=await S(e)??t,t.run_id&&(await S(t.run_id))?.deleting_at)throw new Error("run is deleting");if(t.final_report!==null)throw new Error(`reviveNode: refusing to revive ${e} \u2014 its finalization latch is set (final_report=${t.final_report}). A final landed between the caller's reopen-gate check and this revive; re-run with --reopen if this retask is still wanted.`);je(t.profile_id),te(t.grantee);const a=j();if(!await a.has(e)&&!await a.isClaimed(e)&&r.wakeReason!=="runtime-restart-abort"&&r.viewerAttach!==!0&&!(!i&&t.lifecycle==="resident"&&G(t))&&(await Je(t),await W(t.profile_id??null)!==null&&await Ne(t)),await a.has(e))return await C(e,t.intent==="refresh"?"refresh-launch":"revive"),{parked:!1,result:{window:null,session:t.tmux_session??null,resumed:!1,outcome:"already-live"}};if(await a.isClaimed(e))return{parked:!1,result:{window:null,session:t.tmux_session??null,resumed:!1,outcome:"already-live"}};if(!i&&t.lifecycle==="resident"&&G(t))return{parked:!0};const f=await a.reserveSlot(e);let o=null;if(f){try{o=await Te(e)}catch(w){throw a.releaseReservation(e),w}o.verdict!=="admitted"&&a.releaseReservation(e)}if(o?.verdict==="too_small")throw De(o);if(!f||o?.verdict==="denied"){if(r.capacity==="refuse")throw o?.verdict==="denied"?Oe(o):V(A().automaticReviveCap,await a.occupancy());return t.frozen_at==null&&(await fe(e,new Date().toISOString()),await ce(e,{reason:"frozen"}),K({level:"info",event:"broker.frozen",node_id:e,fields:o?.verdict==="denied"?{reason:"app_memory",free_bytes:o.free_bytes,needed_bytes:o.needed_bytes}:{reason:"broker_cap",live_count:await a.occupancy(),hard_cap:A().automaticReviveCap}})),{parked:!1,result:{window:null,session:t.tmux_session??null,resumed:!1,outcome:"frozen"}}}try{return{parked:!1,result:await or(e,t,r)}}finally{a.releaseReservation(e)}}l(q,"decideRevive");async function or(e,r,i){const t=await W(r.profile_id??null);if(t===null&&!H(r.cwd)){const s=r.fork_from!=null?`Restore ${r.cwd}, then revive the fork normally with \`crtr node lifecycle revive ${e}\`.`:r.managed_worktree?.state==="open"?"Restore or reconcile the recorded checkout, then use the managed-worktree close or abandon recovery.":`Recreate ${r.cwd}, or repair it with \`crtr node config --cwd <path> --node ${e}\`; durable node work resumes in a fresh conversation. Then retry \`crtr node lifecycle revive ${e}\`.`;throw new F({error:"cwd_missing",message:`${e} cannot be revived \u2014 its recorded cwd no longer exists: ${r.cwd}`,next:s})}r.host_kind!=="broker"&&(await $(e,{host_kind:"broker"}),r.host_kind="broker"),r.review_binding!=null&&!await We(e)&&(r.pi_session_id!=null||r.pi_session_file!=null)&&(await U(e),r.pi_session_id=null,r.pi_session_file=null);const f=r.fork_from!=null&&r.pi_session_id==null,o=r.fork_source_file;if(f&&(typeof o!="string"||!ne(o)))throw new F({error:"fork_source_invalid",message:`${e} cannot be revived \u2014 its resolved fork source file is missing or invalid.`,next:`Restore the node's fork source metadata, then retry \`crtr node lifecycle revive ${e}\`.`});const w=f&&typeof o=="string";if(w&&!await Y(o))throw new F({error:"fork_from_missing",message:`${e} cannot be revived \u2014 its fork source no longer exists: ${o}`,next:`Restore ${o}, or update the node's fork source, then retry \`crtr node lifecycle revive ${e}\`.`});const{automaticReviveCap:Q}=A();if(t!==null){const s=await Fe(t);if(s.state==="pending")throw new Ce(t,s.error)}const Z=t===null?xe:Ee("blaxel");let u;try{u=await oe(e,{daemonEpoch:j().epoch(),cap:Q,...t===null?{}:{runner:"blaxel",release:$e()}})}catch(s){if(s instanceof Ae)throw V(s.cap,s.live);if(s instanceof se)return{window:null,session:r.tmux_session??null,resumed:!1,outcome:"already-live"};throw s}try{r.cycles=(r.cycles??0)+1,await $(e,{cycles:r.cycles});const b=r.intent==="refresh"||r.cycle_pending===!0?!1:i.resume,h=w?{}:await nr(e,r,b,t===null),y=h.resumeSessionPath!==void 0,P=y&&h.newCycle===!0,m=y&&!P,B=!y&&(i.wakeReason===void 0||i.wakeReason==="runtime-restart-abort")&&await ar(e),R=m&&(i.wakeReason===void 0||i.wakeReason==="runtime-restart-abort")&&!await Me(e)&&!await ir(h.resumeSessionPath)?(await g(e))?.trim():void 0,O=R!==void 0&&R!=="",I=w||B||O,D=r.cycle_pending===!0||P;await $(e,{cycle_pending:D}),r.cycle_pending=D,!w&&!y&&(r.pi_session_id!=null||r.pi_session_file!=null)&&(await U(e),r.pi_session_id=null,r.pi_session_file=null);let c,d=null;const x=l(()=>({type:"runtime",kind:"kickoff",...r.spawned_by!=null&&r.spawned_by!==""?{spawnedBy:r.spawned_by}:{}}),"birthOrigin");if(w){const n=await g(e),E=v(o);if(E===null)throw new Error(`invalid fork source ${o}`);const re=(await p().header(await p().fork(E,e))).path;c=_(r,{resumeSessionPath:re,...n!=null&&n!==""?{prompt:n}:{}}),n!=null&&n!==""&&(d=x()),await Ue(e,(await Ke(o))?.node_id??null)}else if(O)c=_(r,{...h,prompt:R}),d=x();else if(m)c=_(r,{...h,...i.wakeReason==="runtime-restart-abort"?{prompt:ye}:{}}),i.wakeReason==="runtime-restart-abort"&&(d={type:"runtime",kind:"restart-continuation"});else if(B){const n=(await g(e))?.trim();c=_(r,n!==void 0&&n!==""?{prompt:n}:{}),n!==void 0&&n!==""&&(d=x()),await X(e)}else{const n=await me(r,u);c=_(r,{...h,prompt:await pe(r,n,i.wakeReason==="runtime-restart-abort"?void 0:i.wakeReason)}),r.run_id&&n.unreadMessageIds?.length&&(c.env.CRTR_KICKOFF_MESSAGE_IDS=JSON.stringify(n.unreadMessageIds)),d=i.wakeReason!==void 0&&i.wakeReason!=="runtime-restart-abort"?{type:"runtime",kind:"wake",wake:i.wakeReason}:{type:"runtime",kind:"revive",cycle:r.cycles??0},await X(e)}c.env={...c.env,CRTR_SUBTREE:await Ge(e)},d!==null&&(c.env[ge]=ke(d)),r.status==="done"&&r.last_settled_at!=null&&await ze(e,r.last_settled_at),await C(e,r.intent==="refresh"?"refresh-launch":"revive"),await He(e,{preserveEpisode:!0});const T=await Le(e);i.recovery!==!0&&i.viewerAttach!==!0&&await de(e),await Qe(e,r.grantee);const ee=Ie(r.cwd,r.profile_id).plans.get("node:start")??[];await er(ee,{node:{id:e,name:r.name,kind:r.kind,mode:r.mode,lifecycle:r.lifecycle,cwd:r.cwd,nodeDir:await Ze(e),contextDir:await qe(e),jobDir:Ye(e)},runtime:{isBirth:I,canvasHome:Xe(),profile:r.profile_id??null}}),c.env={...c.env,CRTR_EXECUTION_ID:u};const L=await Re(e,c,r.cwd);await Be(u,L);let k;try{const n=await Pe(e);if(k=await Z.start({executionId:u,nodeId:e,attempt:n?.attempt??1,sandboxName:n?.sandboxName??null,release:n?.release??"",launchJson:L,cwd:r.cwd,resuming:m}),t===null&&k.pid===null)throw new Error(`broker host returned no pid for ${e}`)}catch(n){try{await C(e,"crash",{reason:"launch_failed",outcome:{detail:{schema:"crtr.node-outcome-detail/v1",message:n instanceof Error?n.message:String(n)}}}),await he(e,"notice.crash",`Child crashed \u2014 ${we(r)} (${e}) failed to relaunch and is now dead: ${n.message}
|
|
1
|
+
var te=Object.defineProperty;var l=(e,r)=>te(e,"name",{value:r,configurable:!0});import{assertGranteeRunsHere as ne}from"./unsandboxed.js";import{existsSync as M}from"node:fs";import{conversationIdFromPath as v,conversationStore as p,ConversationNotFoundError as H}from"../conversation-store/index.js";import{isAbsolute as ae}from"node:path";import{findNodeBySessionFile as oe,getNode as $,updateNode as N,beginExecution as se,ExecutionAlreadyLive as le,recordExecutionPid as ce,abortExecution as C,endLiveExecution as ue,unbindSession as U,recordLaunch as fe,setFrozen as we,clearFrozen as G,fullName as de}from"../canvas/index.js";import{emitEvent as K}from"../events/emit.js";import{consumeDeadlineOnWake as he}from"../feed/messages.js";import{isParked as W,transition as F}from"./lifecycle.js";import{publishNotice as pe}from"./close.js";import{InputError as A}from"../io.js";import{buildPiArgv as _}from"./launch.js";import{buildReviveKickoff as me,drainBearings as ve,hasRetainedReports as _e,readGoal as g,readYieldMessage as ye,RUNTIME_RESTART_CONTINUATION as ke}from"./kickoff.js";import{readRoadmap as J}from"./roadmap.js";import{encodeKickoffOrigin as ge,KICKOFF_ORIGIN_ENV as be}from"./stamp/protocol.js";import{headlessBrokerHost as Re,brokerLaunchJson as xe}from"./host.js";import{processRunner as Ee}from"./runner/process.js";import{runnerForEnvironment as Se}from"./runner/index.js";import{blaxelEnvironmentOf as j}from"./blaxel-environment.js";import{recordLaunchFailure as $e}from"../../daemon/reconcilers/node-lifecycle/launch-failure.js";import{acceptedRelease as Ne,checkBilledWake as Ce,EnvironmentImagePending as Fe,imageForWake as Ae}from"../../daemon/reconcilers/node-lifecycle/remote-wake.js";import{ExecutionCapReached as Pe,liveExecutionForNode as Be,setExecutionLaunchJson as Oe}from"../canvas/executions.js";import{appMemoryFull as De,appMemoryTooSmall as Te,boundFleet as V,brokerCapReached as X,brokerThresholdsForDaemon as P}from"./fleet.js";import{admitBrokerMemory as Le}from"./memory-admission.js";import{beginBootFaultAttempt as ze,clearFault as Me,hasAdmittedTurn as He}from"../canvas/recovery.js";import{clearNodeLedger as Y,forkNodeLedger as Ue,noticeChangedWhileDone as Ge}from"./ledger.js";import{forkSourceNode as Ke,rootOfSpine as We}from"./nodes.js";import{ApiError as Je}from"../../api/errors.js";import{grantSnapshotMissing as je}from"../../daemon/readiness.js";import{checkStart as Ve}from"./start-check.js";import{isReviewCompanionBound as Xe}from"../review/companion.js";import{assertProfileActive as Ye}from"../profiles/manifest.js";import{isPidAlive as qe}from"../canvas/pid.js";import{crtrHome as Qe,jobDir as Ze}from"../canvas/paths.js";import{contextDir as Ie,ensureNodeDirs as er,nodeAgentDir as rr}from"../canvas/node-agent-paths.js";import{discoverLifecycleHookRegistry as ir}from"../command-hooks/discovery.js";import{invokeLifecycleHooks as tr}from"../command-hooks/transport/exec-lifecycle.js";async function nr(e,r){const i=e.pi_session_file,t=i?v(i):null;if(t===null)return{};try{const a=await p().header(t);return r?{resumeSessionPath:a.path}:{resumeSessionPath:a.path,newCycle:!0}}catch(a){if(a instanceof H)return{};throw a}}l(nr,"resumeArgs");async function q(e){const r=v(e);if(r===null)return!1;try{return await p().header(r),!0}catch(i){if(i instanceof H)return!1;throw i}}l(q,"conversationExists");async function ar(e){const r=v(e);return r===null?!0:(await p().read(r)).entries.some(i=>i.type==="message")}l(ar,"sessionHasConversation");async function or(e){const r=v(e);if(r===null)return!0;const i=(await p().header(r)).header.cwd;return typeof i!="string"||M(i)}l(or,"sessionCwdExists");async function sr(e,r,i,t){const a=r.pi_session_file;if(!a||!await q(a))return{};const w=await oe(a);return w!==null&&w.node_id!==e&&qe(w.pi_pid)?{}:t&&!await or(a)?{}:await nr(r,i)}l(sr,"resumableSessionArgs");async function lr(e){return await J(e)===null&&await ye(e)===null&&!await _e(e)}l(lr,"isUnstartedBirth");async function Xr(e){const r=await g(e);if(r!==null&&r.trim()!=="")return!0;const i=await J(e);return i!==null&&i.trim()!==""}l(Xr,"hasFreshGroundState");async function Yr(e,r){const i=await Q(e,r,!0);if(i.parked)throw new Error(`reviveNode: internal parked decision for activating revive ${e}`);return i.result}l(Yr,"reviveNode");async function qr(e,r,i){return Q(e,{...r,viewerAttach:!0},i)}l(qr,"decideAttachRevive");async function Q(e,r,i){let t=await $(e);if(t===null)throw new Error(`reviveNode: unknown node ${e}`);if(t=await $(e)??t,t.run_id&&(await $(t.run_id))?.deleting_at)throw new Error("run is deleting");if(t.final_report!==null)throw new Error(`reviveNode: refusing to revive ${e} \u2014 its finalization latch is set (final_report=${t.final_report}). A final landed between the caller's reopen-gate check and this revive; re-run with --reopen if this retask is still wanted.`);Ye(t.profile_id),ne(t.grantee);const a=V(),w=t.grantee==="app:terminal"&&await je();if(!await a.has(e)&&!await a.isClaimed(e)&&r.wakeReason!=="runtime-restart-abort"&&r.viewerAttach!==!0&&!(!i&&t.lifecycle==="resident"&&W(t))&&(await Ve(t),await j(t.profile_id??null)!==null&&await Ce(t)),await a.has(e))return await F(e,t.intent==="refresh"?"refresh-launch":"revive"),{parked:!1,result:{window:null,session:t.tmux_session??null,resumed:!1,outcome:"already-live"}};if(await a.isClaimed(e))return{parked:!1,result:{window:null,session:t.tmux_session??null,resumed:!1,outcome:"already-live"}};if(!i&&t.lifecycle==="resident"&&W(t))return{parked:!0};if(w){if(r.capacity==="refuse")throw new Je(503,"runtime_starting","the first grant snapshot from the directory has not committed");return await Z(e,t,{reason:"grant_snapshot"}),{parked:!1,result:{window:null,session:t.tmux_session??null,resumed:!1,outcome:"frozen"}}}const c=await a.reserveSlot(e);let o=null;if(c){try{o=await Le(e)}catch(b){throw a.releaseReservation(e),b}o.verdict!=="admitted"&&a.releaseReservation(e)}if(o?.verdict==="too_small")throw Te(o);if(!c||o?.verdict==="denied"){if(r.capacity==="refuse")throw o?.verdict==="denied"?De(o):X(P().automaticReviveCap,await a.occupancy());return await Z(e,t,o?.verdict==="denied"?{reason:"app_memory",free_bytes:o.free_bytes,needed_bytes:o.needed_bytes}:{reason:"broker_cap",live_count:await a.occupancy(),hard_cap:P().automaticReviveCap}),{parked:!1,result:{window:null,session:t.tmux_session??null,resumed:!1,outcome:"frozen"}}}try{return{parked:!1,result:await cr(e,t,r)}}finally{a.releaseReservation(e)}}l(Q,"decideRevive");async function Z(e,r,i){r.frozen_at==null&&(await we(e,new Date().toISOString()),await ue(e,{reason:"frozen"}),K({level:"info",event:"broker.frozen",node_id:e,fields:i}))}l(Z,"freezeForWait");async function cr(e,r,i){const t=await j(r.profile_id??null);if(t===null&&!M(r.cwd)){const s=r.fork_from!=null?`Restore ${r.cwd}, then revive the fork normally with \`crtr node lifecycle revive ${e}\`.`:r.managed_worktree?.state==="open"?"Restore or reconcile the recorded checkout, then use the managed-worktree close or abandon recovery.":`Recreate ${r.cwd}, or repair it with \`crtr node config --cwd <path> --node ${e}\`; durable node work resumes in a fresh conversation. Then retry \`crtr node lifecycle revive ${e}\`.`;throw new A({error:"cwd_missing",message:`${e} cannot be revived \u2014 its recorded cwd no longer exists: ${r.cwd}`,next:s})}r.host_kind!=="broker"&&(await N(e,{host_kind:"broker"}),r.host_kind="broker"),r.review_binding!=null&&!await Xe(e)&&(r.pi_session_id!=null||r.pi_session_file!=null)&&(await U(e),r.pi_session_id=null,r.pi_session_file=null);const w=r.fork_from!=null&&r.pi_session_id==null,c=r.fork_source_file;if(w&&(typeof c!="string"||!ae(c)))throw new A({error:"fork_source_invalid",message:`${e} cannot be revived \u2014 its resolved fork source file is missing or invalid.`,next:`Restore the node's fork source metadata, then retry \`crtr node lifecycle revive ${e}\`.`});const o=w&&typeof c=="string";if(o&&!await q(c))throw new A({error:"fork_from_missing",message:`${e} cannot be revived \u2014 its fork source no longer exists: ${c}`,next:`Restore ${c}, or update the node's fork source, then retry \`crtr node lifecycle revive ${e}\`.`});const{automaticReviveCap:b}=P();if(t!==null){const s=await Ae(t);if(s.state==="pending")throw new Fe(t,s.error)}const I=t===null?Ee:Se("blaxel");let f;try{f=await se(e,{daemonEpoch:V().epoch(),cap:b,...t===null?{}:{runner:"blaxel",release:Ne()}})}catch(s){if(s instanceof Pe)throw X(s.cap,s.live);if(s instanceof le)return{window:null,session:r.tmux_session??null,resumed:!1,outcome:"already-live"};throw s}try{r.cycles=(r.cycles??0)+1,await N(e,{cycles:r.cycles});const R=r.intent==="refresh"||r.cycle_pending===!0?!1:i.resume,h=o?{}:await sr(e,r,R,t===null),y=h.resumeSessionPath!==void 0,B=y&&h.newCycle===!0,m=y&&!B,O=!y&&(i.wakeReason===void 0||i.wakeReason==="runtime-restart-abort")&&await lr(e),x=m&&(i.wakeReason===void 0||i.wakeReason==="runtime-restart-abort")&&!await He(e)&&!await ar(h.resumeSessionPath)?(await g(e))?.trim():void 0,D=x!==void 0&&x!=="",ee=o||O||D,T=r.cycle_pending===!0||B;await N(e,{cycle_pending:T}),r.cycle_pending=T,!o&&!y&&(r.pi_session_id!=null||r.pi_session_file!=null)&&(await U(e),r.pi_session_id=null,r.pi_session_file=null);let u,d=null;const E=l(()=>({type:"runtime",kind:"kickoff",...r.spawned_by!=null&&r.spawned_by!==""?{spawnedBy:r.spawned_by}:{}}),"birthOrigin");if(o){const n=await g(e),S=v(c);if(S===null)throw new Error(`invalid fork source ${c}`);const ie=(await p().header(await p().fork(S,e))).path;u=_(r,{resumeSessionPath:ie,...n!=null&&n!==""?{prompt:n}:{}}),n!=null&&n!==""&&(d=E()),await Ue(e,(await Ke(c))?.node_id??null)}else if(D)u=_(r,{...h,prompt:x}),d=E();else if(m)u=_(r,{...h,...i.wakeReason==="runtime-restart-abort"?{prompt:ke}:{}}),i.wakeReason==="runtime-restart-abort"&&(d={type:"runtime",kind:"restart-continuation"});else if(O){const n=(await g(e))?.trim();u=_(r,n!==void 0&&n!==""?{prompt:n}:{}),n!==void 0&&n!==""&&(d=E()),await Y(e)}else{const n=await ve(r,f);u=_(r,{...h,prompt:await me(r,n,i.wakeReason==="runtime-restart-abort"?void 0:i.wakeReason)}),r.run_id&&n.unreadMessageIds?.length&&(u.env.CRTR_KICKOFF_MESSAGE_IDS=JSON.stringify(n.unreadMessageIds)),d=i.wakeReason!==void 0&&i.wakeReason!=="runtime-restart-abort"?{type:"runtime",kind:"wake",wake:i.wakeReason}:{type:"runtime",kind:"revive",cycle:r.cycles??0},await Y(e)}u.env={...u.env,CRTR_SUBTREE:await We(e)},d!==null&&(u.env[be]=ge(d)),r.status==="done"&&r.last_settled_at!=null&&await Ge(e,r.last_settled_at),await F(e,r.intent==="refresh"?"refresh-launch":"revive"),await Me(e,{preserveEpisode:!0});const L=await ze(e);i.recovery!==!0&&i.viewerAttach!==!0&&await he(e),await er(e,r.grantee);const re=ir(r.cwd,r.profile_id).plans.get("node:start")??[];await tr(re,{node:{id:e,name:r.name,kind:r.kind,mode:r.mode,lifecycle:r.lifecycle,cwd:r.cwd,nodeDir:await rr(e),contextDir:await Ie(e),jobDir:Ze(e)},runtime:{isBirth:ee,canvasHome:Qe(),profile:r.profile_id??null}}),u.env={...u.env,CRTR_EXECUTION_ID:f};const z=await xe(e,u,r.cwd);await Oe(f,z);let k;try{const n=await Be(e);if(k=await I.start({executionId:f,nodeId:e,attempt:n?.attempt??1,sandboxName:n?.sandboxName??null,release:n?.release??"",launchJson:z,cwd:r.cwd,resuming:m}),t===null&&k.pid===null)throw new Error(`broker host returned no pid for ${e}`)}catch(n){try{await F(e,"crash",{reason:"launch_failed",outcome:{detail:{schema:"crtr.node-outcome-detail/v1",message:n instanceof Error?n.message:String(n)}}}),await pe(e,"notice.crash",`Child crashed \u2014 ${de(r)} (${e}) failed to relaunch and is now dead: ${n.message}
|
|
2
2
|
|
|
3
|
-
It stays dead until you revive it \u2014 \`crtr node lifecycle revive ${e}\`.`,{reason:"child-crashed",child:e})}catch{}throw await
|
|
3
|
+
It stays dead until you revive it \u2014 \`crtr node lifecycle revive ${e}\`.`,{reason:"child-crashed",child:e})}catch{}throw await C(f,{reason:"launch_failed"}),new Error(`[broker] refusing to revive ${e}: ${n.message}`)}if(await fe(e,new Date().toISOString()),t!==null)return await G(e),{window:null,session:r.tmux_session??null,resumed:m,faultExplanation:L.explanation,outcome:"launched"};if(await ce(f,e,k.pid)==="shutdown")throw await C(f,{reason:"superseded"}),Re.teardown(e),new Error(`[broker] refusing to revive ${e}: execution was superseded during launch`);return await G(e),{window:null,session:r.tmux_session??null,resumed:m,launch:k,faultExplanation:L.explanation,outcome:"launched"}}catch(s){throw await C(f,{reason:"launch_failed"}),await $e(f,s).catch(R=>{K({level:"warn",event:"broker.launch_failure.unrecorded",node_id:e,error:R})}),s}}l(cr,"launchRevive");export{qr as decideAttachRevive,Xr as hasFreshGroundState,nr as resumeArgs,Yr as reviveNode};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var I=Object.defineProperty;var o=(e,t)=>I(e,"name",{value:t,configurable:!0});import{canonicalSessionFile as q,findNodeBySessionFile as M,getNode as h,isWarmSpare as $,recordRespawnAttempt as j,recordSettledTurn as D,setPresence as k,subscriptionsOf as L,updateNode as v,updateNodeTelemetry as U}from"../../../core/canvas/canvas.js";import{liveExecutionForNode as x,recordExecutionIdle as W,recordExecutionPid as H}from"../../../core/canvas/executions.js";import{bindSession as G,readLiveSession as V,transferSession as J}from"../../../core/canvas/sessions.js";import{isSafeNodeId as Y}from"../../../core/canvas/paths.js";import{appForNode as z}from"../../../core/canvas/node-agent-paths.js";import{isPidAlive as K}from"../../../core/canvas/pid.js";import{editorLabel as S}from"../../../core/canvas/labels.js";import{assembleNodeSubject as Q}from"../../../core/substrate/subject.js";import{openDb as X,withCanvasWrite as p}from"../../../core/canvas/db.js";import{runningJobs as Z}from"../../../core/graph/jobs.js";import{notFound as g,usage as u}from"../../../core/errors.js";import{hasUnseenWakeMail as P}from"../../../core/canvas/deliveries.js";import{clearYieldMessage as ee}from"../../../core/runtime/kickoff.js";import{readRoadmap as te}from"../../../core/runtime/roadmap.js";import{forkSourceNode as ne}from"../../../core/runtime/nodes.js";import{transition as _}from"../../../core/runtime/lifecycle.js";import{confirmViewer as R,probeViewer as O,tearDownNode as F}from"../../../core/runtime/placement.js";import{hasAttachedBrokerViewers as ie}from"../viewer-presence.js";import{evaluateStop as re}from"../../../core/runtime/stop-guard.js";import{readOutputRequest as oe}from"../../../core/runtime/output-result.js";import{clearFault as w,readFault as ae,recordFault as se}from"../../../core/canvas/recovery.js";import{updateModelRecipe as de}from"../../../core/runtime/model-swap.js";import{completeCompanionRequestedSubmit as ce}from"../../review/finish.js";import{emitEvent as A}from"../../../core/events/emit.js";import{consumePendingPark as ue,recordPendingParkActivity as le}from"../../park-pending.js";import{shouldParkAfterSummary as pe}from"../../park-activity.js";import{ownerOnly as fe}from"../router.js";import{situationalContextEnvelope as me}from"../../../core/runtime/situational-context.js";import{requireCurrentExecution as f}from"./broker-recovery.js";import{ensureRunObserver as we}from"../../runs/observer.js";import{parseNodeTelemetryRecord as ye,writeNodeTelemetryRecord as he}from"./telemetry-record.js";import{mapAsync as E}from"../../../core/async-array.js";function l(e,t){if(typeof e!="object"||e===null||Array.isArray(e))throw u(`${t} requires a JSON body`);return e}o(l,"objectBody");function _e(e){const t=l(e,"broker session-bound");if(typeof t.executionId!="string"||t.executionId==="")throw u("executionId must be a non-empty string");if(typeof t.piSessionId!="string"||t.piSessionId==="")throw u("piSessionId must be a non-empty string");if(t.sessionFile!==null&&typeof t.sessionFile!="string")throw u("sessionFile must be a string or null");if(!Number.isSafeInteger(t.pid)||t.pid<=0)throw u("pid must be a positive safe integer");if(t.reason!==null&&typeof t.reason!="string")throw u("reason must be a string or null");if(!Array.isArray(t.reviewBoundaryIds)||!t.reviewBoundaryIds.every(n=>typeof n=="string"))throw u("reviewBoundaryIds must be an array of strings");return t}o(_e,"parseSessionBoundBody");function be(e){const t=l(e,"broker settle");if(typeof t.stopReason!="string")throw u("stopReason must be a string");for(const n of["pushedFinal"])if(typeof t[n]!="boolean")throw u(`${n} must be a boolean`);return t}o(be,"parseSettleBody");function ke(e){const t=l(e,"broker park-complete");if(t.outcome!=="completed"&&t.outcome!=="failed")throw u("outcome must be completed or failed");return t}o(ke,"parseParkCompleteBody");function ve(e){const t=l(e,"broker telemetry");if(typeof t.expected_execution_id!="string"||t.expected_execution_id==="")throw u("expected_execution_id must be a non-empty string");const n=ye(t);return{...n,expected_execution_id:t.expected_execution_id,updated_at:new Date(n.updated_at).toISOString()}}o(ve,"parseTelemetryBody");function ge(e){const t=l(e,"broker model");if(typeof t.spec!="string"||t.spec.trim()==="")throw u("spec must be a non-empty string");const n=t.intent;if(n!==void 0){const i=n!==null&&typeof n=="object"?n:void 0;if(i===void 0||typeof i.family!="string"||i.family===""||!["ultra","strong","medium","light"].includes(i.strength))throw u("intent must be { family, strength } with strength ultra|strong|medium|light when present")}if(typeof t.userSelected!="boolean")throw u("userSelected must be a boolean");return t}o(ge,"parseModelCommitBody");async function m(e){const t=await h(e);if(t===null)throw g(`unknown node: ${e}`,{received:e});return t}o(m,"requireNode");async function b(e){return{node_id:e.node_id,grantee:await z(e.node_id),name:e.name,...e.description===void 0?{}:{description:e.description},...e.title===void 0?{}:{title:e.title},...e.icon===void 0?{}:{icon:e.icon},kind:e.kind,mode:e.mode,lifecycle:e.lifecycle,status:e.status,cwd:e.cwd,parent:e.parent??null,fork_from:e.fork_from??null,profile_id:e.profile_id??null,...e.managed_worktree===void 0?{}:{managed_worktree:e.managed_worktree===null?null:{state:e.managed_worktree.state,...e.managed_worktree.cleanup===void 0?{}:{cleanup:e.managed_worktree.cleanup},path:e.managed_worktree.path,branch:e.managed_worktree.branch,base_ref:e.managed_worktree.base_ref,base_sha:e.managed_worktree.base_sha}},...e.review_binding===void 0?{}:{review_binding:e.review_binding??null},intent:e.intent??null,...e.persona_ack===void 0?{}:{persona_ack:e.persona_ack},created:e.created}}o(b,"extensionNode");async function xe(e){const t=await m(e),n=[],i=new Set([e]);let r=t.parent??null;for(;r!==null&&r!==""&&!i.has(r);){i.add(r);const s=await h(r);if(s===null)break;n.unshift(await b(s)),r=s.parent??null}const a=await E((await E(await L(e),async s=>await h(s.node_id))).filter(s=>s!==null&&s.kind!=="human").sort((s,y)=>s.status===y.status?0:s.status==="active"?-1:y.status==="active"?1:0),b),d=typeof t.fork_source_file=="string"?await ne(t.fork_source_file):null,c=await Q(e);if(c===null)throw g(`unknown node: ${e}`,{received:e});return{node:await b(t),warm_spare:await $(e),situational_card:await me(e),ancestors:n,children:a,fork_source:d===null?null:await b(d),subject:c,roadmap:await te(e)}}o(xe,"extensionState");function T(e,t){return e?.kind===t.kind&&e?.mode===t.mode&&e?.lifecycle===t.lifecycle}o(T,"samePersona");function Se(e){const t=l(e,"broker generated-name");if(t.kind!=="initial"&&t.kind!=="recap")throw u("kind must be initial or recap");if(typeof t.description!="string"||typeof t.title!="string"||typeof t.icon!="string")throw u("description, title, and icon must be strings");if(t.kind==="initial")return t;const n=t.expected;if(typeof n!="object"||n===null||Array.isArray(n)||["name","description","title","icon","kind"].some(i=>typeof n[i]!="string"))throw u("recap expected must contain name, description, title, icon, and kind strings");return t}o(Se,"parseGeneratedNameBody");function Pe(e){const t=l(e,"broker persona-ack"),n=o(i=>{const r=t[i];if(typeof r!="object"||r===null||Array.isArray(r)||typeof r.kind!="string"||r.mode!=="base"&&r.mode!=="orchestrator"||r.lifecycle!=="terminal"&&r.lifecycle!=="resident")throw u(`${i} must be a persona state`);return r},"parse");return{expected_execution_id:t.expected_execution_id,from:n("from"),to:n("to")}}o(Pe,"parsePersonaAckBody");async function Re(e){const t=e.params.id,n=_e(e.body),i=n.sessionFile===null?null:q(n.sessionFile);return{status:200,body:await p(async a=>{await a.prepareUncached("SELECT 1 FROM nodes WHERE node_id = ? FOR UPDATE").get(t);const d=await m(t);if(await H(n.executionId,t,n.pid)==="shutdown")return{action:"shutdown"};const c=d.review_binding?.review_id;if(c!==void 0&&!n.reviewBoundaryIds.includes(c))return{action:"shutdown"};if(n.reason==="new"&&d.parent==null)return{action:"relaunch_root"};if(n.reason!=="new"&&d.fork_from!=null&&d.pi_session_id==null&&i===null)return{action:"shutdown"};const s=i===null?null:await M(i);if(s!==null&&s.node_id!==t){if(K(s.pi_pid))return await se(t,{link:"daemon\u2192node",op:"session-file-ownership",kind:"protocol",retry:{disposition:"fatal"},message:`refusing to bind ${i}: it is owned by live node ${s.node_id}`}),{action:"shutdown"};const y=await V(s.node_id);if(y===null||await J({fromNodeId:s.node_id,fromBindingId:y.bindingId,toNodeId:t,executionId:n.executionId,sessionId:n.piSessionId,transcriptPath:i})!=="transferred")return{action:"shutdown"}}else if(await G(t,{executionId:n.executionId,sessionId:n.piSessionId,transcriptPath:i})==="shutdown")return{action:"shutdown"};return n.reason!=="new"&&(await ee(t),d.intent==="refresh"&&await _(t,"revive")),{action:"none"}})}}o(Re,"handleSessionBound");async function B(e,t){return t.live!==null||await ie(e)||await P(e)}o(B,"isHeldAwake");async function N(e,t){return(await x(e))?.runner==="blaxel"&&!await B(e,t)&&(await Z(await X(),e)).length===0}o(N,"residentBlaxelCanIdle");async function Oe(e,t,n){const i=await h(e);if(i===null){if(t.pushedFinal)return{directive:{action:"shutdown"},closePane:!1};throw g(`unknown node: ${e}`,{received:e})}if(await D(e,new Date().toISOString()),(t.stopReason==="stop"||t.stopReason==="length")&&await j(e,{failures:0,notBefore:null}),t.stopReason==="quit"){let c=!1;return(i.status==="active"||i.status==="idle")&&i.intent===null&&(await _(e,"finish"),await w(e),await k(e,{pane:null,tmux_session:null,window:null}),c=!0),{directive:{action:"shutdown"},closePane:c}}if(t.stopReason!=="stop"&&t.stopReason!=="length")return await w(e,{link:"daemon\u2192node"}),i.intent==="refresh"?{directive:{action:"shutdown"},closePane:!1}:t.stopReason==="error"&&t.faultSettled===!0&&(await ae(e))?.retry.disposition==="fatal"&&await oe(e)===null&&await N(e,n)?{directive:{action:"stay_resident"},closePane:!1}:{directive:{action:"stay_dormant"},closePane:!1};const r={pushedFinal:t.pushedFinal};if(r.pushedFinal||i.status==="done")return await w(e),await k(e,{pane:null,tmux_session:null,window:null}),{directive:{action:"shutdown"},closePane:!0};if(i.intent==="refresh")return await w(e),{directive:{action:"shutdown"},closePane:!1};const a=await re(e,r);if(await w(e),a.action==="reprompt")return{directive:{action:"reprompt",prompt:a.message},closePane:!1};if(a.reason==="finished")return{directive:await P(e)?{action:"stay_dormant"}:{action:"shutdown"},closePane:!1};const d=await B(e,n);return(await x(e))?.runner==="blaxel"?{directive:await N(e,n)?{action:"stay_resident"}:{action:"stay_dormant"},closePane:!1}:a.reason!=="awaiting"&&a.reason!=="scheduled"?{directive:{action:"stay_dormant"},closePane:!1}:d?{directive:{action:"stay_dormant"},closePane:!1}:(await _(e,"release"),{directive:{action:"shutdown"},closePane:!1})}o(Oe,"settleBroker");async function Fe(e){const t=e.params.id,n=l(e.body,"broker idle");return await f(t,n.expected_execution_id),await W(n.expected_execution_id),{status:204}}o(Fe,"handleIdle");async function Ae(e){const t=e.params.id,n=be(e.body);await f(t,n.expected_execution_id);const i=await O(t),{directive:r,closePane:a}=await p(async()=>await Oe(t,n,await R(i)));return a&&await F(t),r.action!=="reprompt"&&ce(t).catch(d=>A({level:"error",event:"api.broker_ops.companion_submit_failed",node_id:t,error:d})),{status:200,body:r}}o(Ae,"handleSettle");async function Ee(e){const t=e.params.id,n=ke(e.body);await f(t,n.expected_execution_id);const i=await O(t),r=await p(async()=>{const a=await ue(t);if(a===void 0)return{action:"stay_dormant"};const d=await m(t);return await pe(t,d,a,await R(i))?(await w(t),await _(t,"park"),await k(t,{pane:null,tmux_session:null,window:null}),A({level:n.outcome==="completed"?"info":"warn",event:"broker.park.complete",...Y(t)?{node_id:t}:{},outcome:n.outcome==="completed"?"succeeded":"failed"}),{action:"shutdown"}):{action:"stay_dormant"}});return r.action==="shutdown"&&await F(t),{status:200,body:r}}o(Ee,"handleParkComplete");async function Te(e){const t=e.params.id;return await f(t,l(e.body,"broker park-activity").expected_execution_id),{status:200,body:await p(async()=>({activity:await le(t)?"recorded":"none"}))}}o(Te,"handleParkActivity");async function Be(e){const t=e.params.id,n=ve(e.body);return await f(t,n.expected_execution_id),await p(async()=>{await U(t,{tokensIn:n.tokens_in,contextTokens:n.context_tokens,lastActivity:n.last_activity,updatedAt:n.updated_at}),he(t,n)}),{status:204}}o(Be,"handleTelemetry");async function Ne(e){const t=e.params.id,n=ge(e.body);return await f(t,n.expected_execution_id),{status:200,body:{modelOverride:(await p(async()=>await de(await m(t),n.spec,n.intent,n.userSelected))).model_override}}}o(Ne,"handleModelCommit");let C=!0;function yt(e){C=e}o(yt,"setRequestsStartRunObservers");async function Ce(e){const t=e.params.id,n=await m(t);return n.run_id&&C&&await we(t,n.run_id),{status:200,body:await xe(t)}}o(Ce,"handleExtensionState");async function Ie(e){const t=e.params.id,n=Se(e.body);return await f(t,n.expected_execution_id),{status:200,body:await p(async r=>{await r.prepareUncached("SELECT 1 FROM nodes WHERE node_id = ? FOR UPDATE").get(t);const a=await m(t);if(n.kind==="initial"){if((a.description??"").trim()!=="")return{applied:!1};const s=await v(t,{description:n.description,...n.title.trim()===""?{}:{title:n.title},...n.icon.trim()===""?{}:{icon:n.icon}});return{applied:!0,editorLabel:S(s),description:s.description??"",title:s.title??"",icon:s.icon??""}}const d=n.expected;if(a.name!==d.name||(a.description??"")!==d.description||(a.title??"")!==d.title||(a.icon??"")!==d.icon||a.kind!==d.kind)return{applied:!1};const c=await v(t,{description:n.description,title:n.title.trim()===""?void 0:n.title,icon:n.icon.trim()===""?void 0:n.icon});return{applied:!0,editorLabel:S(c),description:c.description??"",title:c.title??"",icon:c.icon??""}})}}o(Ie,"handleGeneratedName");async function qe(e){const t=e.params.id,n=Pe(e.body);return await f(t,n.expected_execution_id),{status:200,body:await p(async r=>{await r.prepareUncached("SELECT 1 FROM nodes WHERE node_id = ? FOR UPDATE").get(t);const a=await m(t),d={kind:a.kind,mode:a.mode,lifecycle:a.lifecycle},c=a.persona_ack,s=c===void 0?d:{kind:c.kind??a.kind,mode:c.mode,lifecycle:c.lifecycle};return!T(d,n.to)||!T(s,n.from)?{applied:!1}:(await v(t,{persona_ack:n.to}),{applied:!0})})}}o(qe,"handlePersonaAck");const ht=fe([{method:"POST",pattern:"/v1/nodes/:id/broker/session-bound",handler:Re},{method:"POST",pattern:"/v1/nodes/:id/broker/settle",handler:Ae},{method:"POST",pattern:"/v1/nodes/:id/broker/idle",handler:Fe},{method:"POST",pattern:"/v1/nodes/:id/broker/park-complete",handler:Ee},{method:"POST",pattern:"/v1/nodes/:id/broker/park-activity",handler:Te},{method:"POST",pattern:"/v1/nodes/:id/broker/telemetry",handler:Be},{method:"POST",pattern:"/v1/nodes/:id/broker/model",handler:Ne},{method:"GET",pattern:"/v1/nodes/:id/broker/extension-state",handler:Ce},{method:"POST",pattern:"/v1/nodes/:id/broker/generated-name",handler:Ie},{method:"POST",pattern:"/v1/nodes/:id/broker/persona-ack",handler:qe}]);export{ht as brokerOperationRoutes,b as extensionNode,yt as setRequestsStartRunObservers};
|
|
1
|
+
var C=Object.defineProperty;var o=(e,t)=>C(e,"name",{value:t,configurable:!0});import{canonicalSessionFile as I,findNodeBySessionFile as q,getNode as b,getNodes as M,isWarmSpare as $,recordRespawnAttempt as j,recordSettledTurn as D,setPresence as k,subscriptionsOf as L,updateNode as g,updateNodeTelemetry as U}from"../../../core/canvas/canvas.js";import{liveExecutionForNode as x,recordExecutionIdle as W,recordExecutionPid as H}from"../../../core/canvas/executions.js";import{bindSession as G,readLiveSession as V,transferSession as J}from"../../../core/canvas/sessions.js";import{isSafeNodeId as Y}from"../../../core/canvas/paths.js";import{isPidAlive as z}from"../../../core/canvas/pid.js";import{editorLabel as S}from"../../../core/canvas/labels.js";import{assembleNodeSubject as K}from"../../../core/substrate/subject.js";import{openDb as Q,withCanvasWrite as p}from"../../../core/canvas/db.js";import{runningJobs as X}from"../../../core/graph/jobs.js";import{notFound as v,usage as u}from"../../../core/errors.js";import{hasUnseenWakeMail as P}from"../../../core/canvas/deliveries.js";import{clearYieldMessage as Z}from"../../../core/runtime/kickoff.js";import{readRoadmap as ee}from"../../../core/runtime/roadmap.js";import{forkSourceNode as te}from"../../../core/runtime/nodes.js";import{transition as h}from"../../../core/runtime/lifecycle.js";import{confirmViewer as R,probeViewer as O,tearDownNode as F}from"../../../core/runtime/placement.js";import{hasAttachedBrokerViewers as ne}from"../viewer-presence.js";import{evaluateStop as ie}from"../../../core/runtime/stop-guard.js";import{readOutputRequest as re}from"../../../core/runtime/output-result.js";import{clearFault as w,readFault as oe,recordFault as ae}from"../../../core/canvas/recovery.js";import{updateModelRecipe as se}from"../../../core/runtime/model-swap.js";import{completeCompanionRequestedSubmit as de}from"../../review/finish.js";import{emitEvent as A}from"../../../core/events/emit.js";import{consumePendingPark as ce,recordPendingParkActivity as ue}from"../../park-pending.js";import{shouldParkAfterSummary as le}from"../../park-activity.js";import{ownerOnly as pe}from"../router.js";import{situationalContextEnvelope as fe}from"../../../core/runtime/situational-context.js";import{requireCurrentExecution as f}from"./broker-recovery.js";import{ensureRunObserver as me}from"../../runs/observer.js";import{parseNodeTelemetryRecord as we,writeNodeTelemetryRecord as ye}from"./telemetry-record.js";import{mapAsync as he}from"../../../core/async-array.js";function l(e,t){if(typeof e!="object"||e===null||Array.isArray(e))throw u(`${t} requires a JSON body`);return e}o(l,"objectBody");function _e(e){const t=l(e,"broker session-bound");if(typeof t.executionId!="string"||t.executionId==="")throw u("executionId must be a non-empty string");if(typeof t.piSessionId!="string"||t.piSessionId==="")throw u("piSessionId must be a non-empty string");if(t.sessionFile!==null&&typeof t.sessionFile!="string")throw u("sessionFile must be a string or null");if(!Number.isSafeInteger(t.pid)||t.pid<=0)throw u("pid must be a positive safe integer");if(t.reason!==null&&typeof t.reason!="string")throw u("reason must be a string or null");if(!Array.isArray(t.reviewBoundaryIds)||!t.reviewBoundaryIds.every(n=>typeof n=="string"))throw u("reviewBoundaryIds must be an array of strings");return t}o(_e,"parseSessionBoundBody");function be(e){const t=l(e,"broker settle");if(typeof t.stopReason!="string")throw u("stopReason must be a string");for(const n of["pushedFinal"])if(typeof t[n]!="boolean")throw u(`${n} must be a boolean`);return t}o(be,"parseSettleBody");function ke(e){const t=l(e,"broker park-complete");if(t.outcome!=="completed"&&t.outcome!=="failed")throw u("outcome must be completed or failed");return t}o(ke,"parseParkCompleteBody");function ge(e){const t=l(e,"broker telemetry");if(typeof t.expected_execution_id!="string"||t.expected_execution_id==="")throw u("expected_execution_id must be a non-empty string");const n=we(t);return{...n,expected_execution_id:t.expected_execution_id,updated_at:new Date(n.updated_at).toISOString()}}o(ge,"parseTelemetryBody");function ve(e){const t=l(e,"broker model");if(typeof t.spec!="string"||t.spec.trim()==="")throw u("spec must be a non-empty string");const n=t.intent;if(n!==void 0){const i=n!==null&&typeof n=="object"?n:void 0;if(i===void 0||typeof i.family!="string"||i.family===""||!["ultra","strong","medium","light"].includes(i.strength))throw u("intent must be { family, strength } with strength ultra|strong|medium|light when present")}if(typeof t.userSelected!="boolean")throw u("userSelected must be a boolean");return t}o(ve,"parseModelCommitBody");async function m(e){const t=await b(e);if(t===null)throw v(`unknown node: ${e}`,{received:e});return t}o(m,"requireNode");async function _(e){return{node_id:e.node_id,grantee:e.grantee,name:e.name,...e.description===void 0?{}:{description:e.description},...e.title===void 0?{}:{title:e.title},...e.icon===void 0?{}:{icon:e.icon},kind:e.kind,mode:e.mode,lifecycle:e.lifecycle,status:e.status,cwd:e.cwd,parent:e.parent??null,fork_from:e.fork_from??null,profile_id:e.profile_id??null,...e.managed_worktree===void 0?{}:{managed_worktree:e.managed_worktree===null?null:{state:e.managed_worktree.state,...e.managed_worktree.cleanup===void 0?{}:{cleanup:e.managed_worktree.cleanup},path:e.managed_worktree.path,branch:e.managed_worktree.branch,base_ref:e.managed_worktree.base_ref,base_sha:e.managed_worktree.base_sha}},...e.review_binding===void 0?{}:{review_binding:e.review_binding??null},intent:e.intent??null,...e.persona_ack===void 0?{}:{persona_ack:e.persona_ack},created:e.created}}o(_,"extensionNode");async function xe(e){const t=await m(e),n=[],i=new Set([e]);let r=t.parent??null;for(;r!==null&&r!==""&&!i.has(r);){i.add(r);const s=await b(r);if(s===null)break;n.unshift(await _(s)),r=s.parent??null}const a=await he((await M((await L(e)).map(s=>s.node_id))).filter(s=>s.kind!=="human").sort((s,y)=>s.status===y.status?0:s.status==="active"?-1:y.status==="active"?1:0),_),d=typeof t.fork_source_file=="string"?await te(t.fork_source_file):null,c=await K(e);if(c===null)throw v(`unknown node: ${e}`,{received:e});return{node:await _(t),warm_spare:await $(e),situational_card:await fe(e),ancestors:n,children:a,fork_source:d===null?null:await _(d),subject:c,roadmap:await ee(e)}}o(xe,"extensionState");function E(e,t){return e?.kind===t.kind&&e?.mode===t.mode&&e?.lifecycle===t.lifecycle}o(E,"samePersona");function Se(e){const t=l(e,"broker generated-name");if(t.kind!=="initial"&&t.kind!=="recap")throw u("kind must be initial or recap");if(typeof t.description!="string"||typeof t.title!="string"||typeof t.icon!="string")throw u("description, title, and icon must be strings");if(t.kind==="initial")return t;const n=t.expected;if(typeof n!="object"||n===null||Array.isArray(n)||["name","description","title","icon","kind"].some(i=>typeof n[i]!="string"))throw u("recap expected must contain name, description, title, icon, and kind strings");return t}o(Se,"parseGeneratedNameBody");function Pe(e){const t=l(e,"broker persona-ack"),n=o(i=>{const r=t[i];if(typeof r!="object"||r===null||Array.isArray(r)||typeof r.kind!="string"||r.mode!=="base"&&r.mode!=="orchestrator"||r.lifecycle!=="terminal"&&r.lifecycle!=="resident")throw u(`${i} must be a persona state`);return r},"parse");return{expected_execution_id:t.expected_execution_id,from:n("from"),to:n("to")}}o(Pe,"parsePersonaAckBody");async function Re(e){const t=e.params.id,n=_e(e.body),i=n.sessionFile===null?null:I(n.sessionFile);return{status:200,body:await p(async a=>{await a.prepareUncached("SELECT 1 FROM nodes WHERE node_id = ? FOR UPDATE").get(t);const d=await m(t);if(await H(n.executionId,t,n.pid)==="shutdown")return{action:"shutdown"};const c=d.review_binding?.review_id;if(c!==void 0&&!n.reviewBoundaryIds.includes(c))return{action:"shutdown"};if(n.reason==="new"&&d.parent==null)return{action:"relaunch_root"};if(n.reason!=="new"&&d.fork_from!=null&&d.pi_session_id==null&&i===null)return{action:"shutdown"};const s=i===null?null:await q(i);if(s!==null&&s.node_id!==t){if(z(s.pi_pid))return await ae(t,{link:"daemon\u2192node",op:"session-file-ownership",kind:"protocol",retry:{disposition:"fatal"},message:`refusing to bind ${i}: it is owned by live node ${s.node_id}`}),{action:"shutdown"};const y=await V(s.node_id);if(y===null||await J({fromNodeId:s.node_id,fromBindingId:y.bindingId,toNodeId:t,executionId:n.executionId,sessionId:n.piSessionId,transcriptPath:i})!=="transferred")return{action:"shutdown"}}else if(await G(t,{executionId:n.executionId,sessionId:n.piSessionId,transcriptPath:i})==="shutdown")return{action:"shutdown"};return n.reason!=="new"&&(await Z(t),d.intent==="refresh"&&await h(t,"revive")),{action:"none"}})}}o(Re,"handleSessionBound");async function T(e,t){return t.live!==null||await ne(e)||await P(e)}o(T,"isHeldAwake");async function B(e,t){return(await x(e))?.runner==="blaxel"&&!await T(e,t)&&(await X(await Q(),e)).length===0}o(B,"residentBlaxelCanIdle");async function Oe(e,t,n){const i=await b(e);if(i===null){if(t.pushedFinal)return{directive:{action:"shutdown"},closePane:!1};throw v(`unknown node: ${e}`,{received:e})}if(await D(e,new Date().toISOString()),(t.stopReason==="stop"||t.stopReason==="length")&&await j(e,{failures:0,notBefore:null}),t.stopReason==="quit"){let c=!1;return(i.status==="active"||i.status==="idle")&&i.intent===null&&(await h(e,"finish"),await w(e),await k(e,{pane:null,tmux_session:null,window:null}),c=!0),{directive:{action:"shutdown"},closePane:c}}if(t.stopReason!=="stop"&&t.stopReason!=="length")return await w(e,{link:"daemon\u2192node"}),i.intent==="refresh"?{directive:{action:"shutdown"},closePane:!1}:t.stopReason==="error"&&t.faultSettled===!0&&(await oe(e))?.retry.disposition==="fatal"&&await re(e)===null&&await B(e,n)?{directive:{action:"stay_resident"},closePane:!1}:{directive:{action:"stay_dormant"},closePane:!1};const r={pushedFinal:t.pushedFinal};if(r.pushedFinal||i.status==="done")return await w(e),await k(e,{pane:null,tmux_session:null,window:null}),{directive:{action:"shutdown"},closePane:!0};if(i.intent==="refresh")return await w(e),{directive:{action:"shutdown"},closePane:!1};const a=await ie(e,r);if(await w(e),a.action==="reprompt")return{directive:{action:"reprompt",prompt:a.message},closePane:!1};if(a.reason==="finished")return{directive:await P(e)?{action:"stay_dormant"}:{action:"shutdown"},closePane:!1};const d=await T(e,n);return(await x(e))?.runner==="blaxel"?{directive:await B(e,n)?{action:"stay_resident"}:{action:"stay_dormant"},closePane:!1}:a.reason!=="awaiting"&&a.reason!=="scheduled"?{directive:{action:"stay_dormant"},closePane:!1}:d?{directive:{action:"stay_dormant"},closePane:!1}:(await h(e,"release"),{directive:{action:"shutdown"},closePane:!1})}o(Oe,"settleBroker");async function Fe(e){const t=e.params.id,n=l(e.body,"broker idle");return await f(t,n.expected_execution_id),await W(n.expected_execution_id),{status:204}}o(Fe,"handleIdle");async function Ae(e){const t=e.params.id,n=be(e.body);await f(t,n.expected_execution_id);const i=await O(t),{directive:r,closePane:a}=await p(async()=>await Oe(t,n,await R(i)));return a&&await F(t),r.action!=="reprompt"&&de(t).catch(d=>A({level:"error",event:"api.broker_ops.companion_submit_failed",node_id:t,error:d})),{status:200,body:r}}o(Ae,"handleSettle");async function Ee(e){const t=e.params.id,n=ke(e.body);await f(t,n.expected_execution_id);const i=await O(t),r=await p(async()=>{const a=await ce(t);if(a===void 0)return{action:"stay_dormant"};const d=await m(t);return await le(t,d,a,await R(i))?(await w(t),await h(t,"park"),await k(t,{pane:null,tmux_session:null,window:null}),A({level:n.outcome==="completed"?"info":"warn",event:"broker.park.complete",...Y(t)?{node_id:t}:{},outcome:n.outcome==="completed"?"succeeded":"failed"}),{action:"shutdown"}):{action:"stay_dormant"}});return r.action==="shutdown"&&await F(t),{status:200,body:r}}o(Ee,"handleParkComplete");async function Te(e){const t=e.params.id;return await f(t,l(e.body,"broker park-activity").expected_execution_id),{status:200,body:await p(async()=>({activity:await ue(t)?"recorded":"none"}))}}o(Te,"handleParkActivity");async function Be(e){const t=e.params.id,n=ge(e.body);return await f(t,n.expected_execution_id),await p(async()=>{await U(t,{tokensIn:n.tokens_in,contextTokens:n.context_tokens,lastActivity:n.last_activity,updatedAt:n.updated_at}),ye(t,n)}),{status:204}}o(Be,"handleTelemetry");async function Ne(e){const t=e.params.id,n=ve(e.body);return await f(t,n.expected_execution_id),{status:200,body:{modelOverride:(await p(async()=>await se(await m(t),n.spec,n.intent,n.userSelected))).model_override}}}o(Ne,"handleModelCommit");let N=!0;function wt(e){N=e}o(wt,"setRequestsStartRunObservers");async function Ce(e){const t=e.params.id,n=await m(t);return n.run_id&&N&&await me(t,n.run_id),{status:200,body:await xe(t)}}o(Ce,"handleExtensionState");async function Ie(e){const t=e.params.id,n=Se(e.body);return await f(t,n.expected_execution_id),{status:200,body:await p(async r=>{await r.prepareUncached("SELECT 1 FROM nodes WHERE node_id = ? FOR UPDATE").get(t);const a=await m(t);if(n.kind==="initial"){if((a.description??"").trim()!=="")return{applied:!1};const s=await g(t,{description:n.description,...n.title.trim()===""?{}:{title:n.title},...n.icon.trim()===""?{}:{icon:n.icon}});return{applied:!0,editorLabel:S(s),description:s.description??"",title:s.title??"",icon:s.icon??""}}const d=n.expected;if(a.name!==d.name||(a.description??"")!==d.description||(a.title??"")!==d.title||(a.icon??"")!==d.icon||a.kind!==d.kind)return{applied:!1};const c=await g(t,{description:n.description,title:n.title.trim()===""?void 0:n.title,icon:n.icon.trim()===""?void 0:n.icon});return{applied:!0,editorLabel:S(c),description:c.description??"",title:c.title??"",icon:c.icon??""}})}}o(Ie,"handleGeneratedName");async function qe(e){const t=e.params.id,n=Pe(e.body);return await f(t,n.expected_execution_id),{status:200,body:await p(async r=>{await r.prepareUncached("SELECT 1 FROM nodes WHERE node_id = ? FOR UPDATE").get(t);const a=await m(t),d={kind:a.kind,mode:a.mode,lifecycle:a.lifecycle},c=a.persona_ack,s=c===void 0?d:{kind:c.kind??a.kind,mode:c.mode,lifecycle:c.lifecycle};return!E(d,n.to)||!E(s,n.from)?{applied:!1}:(await g(t,{persona_ack:n.to}),{applied:!0})})}}o(qe,"handlePersonaAck");const yt=pe([{method:"POST",pattern:"/v1/nodes/:id/broker/session-bound",handler:Re},{method:"POST",pattern:"/v1/nodes/:id/broker/settle",handler:Ae},{method:"POST",pattern:"/v1/nodes/:id/broker/idle",handler:Fe},{method:"POST",pattern:"/v1/nodes/:id/broker/park-complete",handler:Ee},{method:"POST",pattern:"/v1/nodes/:id/broker/park-activity",handler:Te},{method:"POST",pattern:"/v1/nodes/:id/broker/telemetry",handler:Be},{method:"POST",pattern:"/v1/nodes/:id/broker/model",handler:Ne},{method:"GET",pattern:"/v1/nodes/:id/broker/extension-state",handler:Ce},{method:"POST",pattern:"/v1/nodes/:id/broker/generated-name",handler:Ie},{method:"POST",pattern:"/v1/nodes/:id/broker/persona-ack",handler:qe}]);export{yt as brokerOperationRoutes,_ as extensionNode,wt as setRequestsStartRunObservers};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var ie=Object.defineProperty;var u=(n,e)=>ie(n,"name",{value:e,configurable:!0});import{ApiError as k}from"../../../api/errors.js";import{DOC_KINDS as x,DOC_UNSET_FIELDS as U}from"../../../api/dto/docs.js";import{PRIVACY_LEVELS_DTO as V}from"../../../api/dto/objects.js";import{withCanvasWrite as A}from"../../../core/canvas/db.js";import{CrtrError as re}from"../../../core/errors.js";import{emitEvent as ae}from"../../../core/events/emit.js";import{canChange as se,spaceOf as ce}from"../../../core/graph/access.js";import{get as j}from"../../../core/graph/bodies.js";import{deleteDocument as de,documentRecord as L,editDocument as ue,heads as W,history as fe,linksIn as K,moveDocument as pe,readBase as le,setDocumentRecord as me,withCurrentNames as we,writeDocument as he}from"../../../core/graph/documents.js";import{resolveName as G}from"../../../core/graph/names.js";import{getById as M}from"../../../core/graph/objects.js";import{noteRepoDocumentsChanged as ye}from"../../../core/graph/repo-sync/index.js";import{checkoutsForCwd as ge}from"../../../core/graph/repo-sync/repos.js";import{lintRules as ve,rulesOf as _e}from"../../../core/graph/rules.js";import{unifiedDiff as be}from"../../../core/graph/diff.js";import{ownerForGrantee as ke}from"../../../core/graph/objects.js";import{ownerFromFlag as q,readerFor as E,resolveRef as X,warmReaderRepos as O}from"../reader.js";import{appCaller as z,asApiError as Ae,requireOwnNamespace as Ee}from"./schemas.js";import{filterAsync as Oe,flatMapAsync as $e}from"../../../core/async-array.js";function g(n,e,t,o,a={}){return new k(n,e,t,{...a,error:e,message:t,next:o})}u(g,"refuse");const b=u((n,e)=>new k(400,"invalid_request",n,e),"invalid");function C(n){const e=n.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(C,"bodyOf");const N=u(async n=>async e=>await ge(n,e),"reposFnFor");function S(n,e){if(n instanceof re){const t=n.details;if(n.code==="read_first")throw g(409,"read_first",n.message,`Read it first with \`crtr canvas read ${e?.id??"<ref>"}\`, then rerun the edit.`,t??{});if(n.code==="conflict")throw new k(409,"name_taken",n.message,t);if(n.code==="forbidden")throw typeof t?.next=="string"?g(403,"forbidden",n.message,t.next,t):new k(403,"forbidden",n.message,t);if(n.code==="scope_missing")throw g(403,"scope_missing",n.message,`Launch the run with \`${String(t?.scope)}\` in its scopes list.`,t??{});if(t?.rule==="repo-public-only")throw g(422,"repo_documents_are_public",n.message,'Own it as `user` and add a rule with `if: {"repo": "<handle>"}` so it loads only in that repo.')}throw Ae(n)}u(S,"mapGraphError");async function B(n,e,t){const o=await X(n,e,decodeURIComponent(t));if("remote"in o)throw g(404,"not_found",Y(o.remote),"Check the name with `crtr canvas search`.");if("deleted"in o)throw new k(404,"not_found",`${o.deleted.name} is deleted`,{id:o.deleted.id,deleted:!0});if(o.type!=="document")throw b(`${t} is a ${o.type}, not a document`);return o}u(B,"refDocument");function Y(n){return`no object named ${n} on this runtime; it may be on another runtime, or the name may be misspelled`}u(Y,"remoteMessage");async function je(n,e){const t=e.owner===null?null:await M(n,e.owner);return t?t.type==="node"?t.id:t.name:""}u(je,"ownerHandle");async function R(n,e){const t=await je(n,e);return t?`${t}/${e.name}`:e.name}u(R,"canonicalName");async function Re(n,e){const t=e.owner===null?null:await M(n,e.owner),o=t?{id:t.id,type:t.type,handle:t.type==="node"?t.id:t.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,...e.type==="document"?{schema_type:e.schema_type??null}:{}}}u(Re,"objectDTO");async function De(n,e){const t=e.owner===null?null:await M(n,e.owner);return t?.type==="repo"?t:null}u(De,"repoOwner");async function T(n,e,t,o){const a=[...new Map(await $e(t,async f=>{const i=await De(n,f);return i?[[i.id,i]]:[]})).values()],c=e.class==="node"?e.cwd:o,s=e.class==="node"?[...e.checkouts,...e.projectCheckouts].map(f=>f.root):[];return{repos:a,dirs:[...new Set([...c!==void 0?[c]:[],...s])]}}u(T,"repoChange");async function F(n){for(const e of n.repos)try{await ye(e,n.dirs)}catch(t){ae({level:"warn",event:"repo_sync.failed",outcome:"failed",error:t,fields:{repo:e.name,step:"export",reason:t instanceof Error?t.message:String(t)}})}}u(F,"syncChanged");const Z=/^[A-Za-z0-9_-]+(\/[A-Za-z0-9_-]+)*$/;function Ce(n,e){if(n===void 0)return;if(!Array.isArray(n)){e.push("`rules` must be a list");return}const t=n.map(a=>{if(typeof a!="object"||a===null||Array.isArray(a))return a;const{match_frontmatter:c,...s}=a;return"matchFrontmatter"in s?{...s,match_frontmatter:s.matchFrontmatter}:c===void 0?s:{...s,matchFrontmatter:c}}),o=ve(t);if(o){e.push(o.replaceAll("matchFrontmatter","match_frontmatter"));return}return t}u(Ce,"rulesFromDTO");function J(n,e){const t={},o=u(i=>{const d=n[i];if(d!==void 0){if(typeof d!="string"){e.push(`\`${i}\` must be a string`);return}return d}},"str"),a=o("preview");a!==void 0&&(a.trim()===""||/[\r\n]/.test(a)?e.push("`preview` must be one non-empty line"):t.preview=a);const c=o("summary");c!==void 0&&(t.summary=c);const s=o("why_it_exists");if(s!==void 0&&(t.whyItExists=s),n.privacy!==void 0&&(V.includes(n.privacy)?t.privacy=n.privacy:e.push(`\`privacy\` must be one of ${V.join(", ")}`)),n.unlisted!==void 0&&(typeof n.unlisted!="boolean"?e.push("`unlisted` must be a boolean"):t.unlisted=n.unlisted),n.lint_ignore!==void 0){const i=n.lint_ignore;!Array.isArray(i)||i.some(d=>typeof d!="string")?e.push("`lint_ignore` must be a list of strings"):t.lintIgnore=i}if(n.extensions!==void 0){const i=n.extensions;typeof i!="object"||i===null||Array.isArray(i)||Object.values(i).some(d=>typeof d!="object"||d===null||Array.isArray(d))?e.push("`extensions` must map each plugin to an object of fields"):t.extensions=i}const f=Ce(n.rules,e);return f!==void 0&&(t.rules=f),t}u(J,"fieldsFrom");function Q(n){if(n.length>0)throw b(n.join("; "),{errors:n})}u(Q,"failOn");async function ee(n,e,t,o){const a=await Oe(K(t),async c=>"remote"in await G(n,e,c));return{...o.length>0?{unresolved_links:o}:{},...a.length>0?{remote_links:a}:{}}}u(ee,"linkReport");async function Ne(n){const e=C(n),t=[],o=e.name;(typeof o!="string"||!Z.test(o))&&t.push("`name` must be segments of letters, digits, `_` or `-` joined by `/`"),typeof e.body!="string"&&t.push("`body` must be a string"),typeof e.preview!="string"&&t.push("`preview` is required");const a=e.kind??"knowledge";x.includes(a)||t.push(a==="report"?"reports are written only by `crtr push`":`\`kind\` must be one of ${x.join(", ")}`);const c=J(e,t);e.cwd!==void 0&&typeof e.cwd!="string"&&t.push("`cwd` must be a string");const s=e.schema_type;s!==void 0&&typeof s!="string"&&t.push("`schema_type` must be a string");const f=e.relations;f!==void 0&&(!Array.isArray(f)||f.some(r=>typeof r!="object"||r===null||typeof r.relation!="string"||typeof r.subject!="string"))&&t.push("`relations` must be a list of {relation, subject} strings"),Q(t);const i=e;await O(n.principal,i.cwd);const{dto:d,change:h}=await A(async r=>{const p=await E(r,n);i.schema_type!==void 0?await Ee(r,z(n).app,i.schema_type):i.relations!==void 0&&z(n);const l=i.owner==="user"&&p.class==="app"&&p.sub!==void 0?await ke(r,p.sub.startsWith("user:")?p.sub:`user:${p.sub}`):await q(r,p,i.owner,i.cwd);try{const{object:w,unresolved:_}=await he(r,p,{...c,owner:l,name:i.name,kind:a,preview:c.preview,privacy:c.privacy??"public",...i.schema_type!==void 0?{schemaType:i.schema_type}:{},...i.relations!==void 0?{relations:i.relations}:{}},i.body,await N(r));return{dto:{id:w.id,name:await R(r,w),...await ee(r,p,i.body,_)},change:await T(r,p,[w],i.cwd)}}catch(w){S(w)}});return await F(h),d}u(Ne,"write");function Se(n,e){let t=n;e.forEach(({old:o,new:a},c)=>{const s=o===""?-1:t.indexOf(o);if(s<0)throw g(422,"replace_no_match",`replace[${c}]: old text not found in the revision you read`,"Copy the old text exactly from your last read and rerun.",{index:c});if(t.indexOf(o,s+1)>=0)throw g(422,"replace_ambiguous",`replace[${c}]: old text occurs more than once`,"Include more surrounding text so the old text matches once, and rerun.",{index:c});t=t.slice(0,s)+a+t.slice(s+o.length)})}u(Se,"checkReplacements");async function Te(n){const e=C(n),t=[],o=e.body!==void 0,a=e.replace!==void 0;o&&a&&t.push("give `body` or `replace`, not both"),o&&typeof e.body!="string"&&t.push("`body` must be a string");const c=e.replace;a&&(!Array.isArray(c)||c.length===0||c.some(r=>typeof r!="object"||r===null||typeof r.old!="string"||typeof r.new!="string"))&&t.push("`replace` must be a non-empty list of {old, new} strings"),(typeof e.rationale!="string"||e.rationale.trim()==="")&&t.push("`rationale` is required"),e.verbatim!==void 0&&typeof e.verbatim!="boolean"&&t.push("`verbatim` must be a boolean"),e.base!==void 0&&(typeof e.base!="string"||e.base==="")&&t.push("`base` must be a non-empty heads key"),e.base!==void 0&&!o&&!a&&t.push("`base` applies only to a `body` or `replace` edit");const s=J(e,t),f=e.unset??[];if(!Array.isArray(f)||f.some(r=>!U.includes(r)))t.push(`\`unset\` takes only ${U.join(", ")}`);else for(const r of f)r==="summary"&&(s.summary=null),r==="why_it_exists"&&(s.whyItExists=null),r==="unlisted"&&(s.unlisted=!1),r==="lint_ignore"&&(s.lintIgnore=null),r==="extensions"&&(s.extensions=null),r==="rules"&&(s.rules=[]);t.length===0&&!o&&!a&&Object.keys(s).length===0&&t.push("nothing to change: give `body`, `replace`, or a field"),Q(t);const i=e;await O(n.principal);const{dto:d,synced:h}=await A(async r=>{const p=await E(r,n),l=await B(r,p,n.params.ref),w=await R(r,l),_=await T(r,p,[l]);try{if(!o&&!a)return await me(r,p,l,s,i.rationale),{dto:{id:l.id,name:w,revision:(await L(r,l)).revision},synced:_};const v=i.base??await le(r,p,l);if(a&&v!==null){const P=await L(r,l),H=await W(r,l);P.source_path===null&&P.heads_key===v&&H.length===1&&Se(await we(r,l,j(H[0].body_hash)),i.replace)}const D=i.verbatim===!0,m=o?{body:i.body,verbatim:D}:{replace:i.replace,verbatim:D},y=await ue(r,p,l,m,i.rationale,v,s,await N(r));if("stale"in y)throw g(409,"stale_revision",`${w} changed after your read; it is now at revision ${y.stale.revision}`,`Read it again with \`crtr canvas read ${w}\`, then redo your change on the current text.`,{stale:y.stale});const I=j((await W(r,l))[0].body_hash);return{dto:{id:l.id,name:w,revision:y.revision,...await ee(r,p,I,y.unresolved)},synced:_}}catch(v){S(v,l)}});return await F(h),d}u(Te,"edit");async function Fe(n){const e=C(n);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"||!Z.test(e.new_name)))throw b("`new_name` must be segments of letters, digits, `_` or `-` joined by `/`");await O(n.principal,e.cwd);const{dto:t,change:o}=await A(async a=>{const c=await E(a,n),s=await B(a,c,n.params.ref),f=e.owner===void 0?void 0:await q(a,c,e.owner,e.cwd);try{const i=await pe(a,c,s,{...e.new_name!==void 0?{name:e.new_name}:{},...f?{owner:f}:{}},await N(a));return{dto:{id:i.id,name:await R(a,i)},change:await T(a,c,[s,i],e.cwd)}}catch(i){S(i,s)}});return await F(o),t}u(Fe,"move");async function Ie(n){await O(n.principal);const{dto:e,change:t}=await A(async o=>{const a=await E(o,n),c=await B(o,a,n.params.ref),s=await R(o,c),f=await T(o,a,[c]);try{await de(o,a,c,await N(o))}catch(i){S(i,c)}return{dto:{id:c.id,name:s},change:f}});return await F(t),e}u(Ie,"remove");async function Le(n){const e=n.query.get("diff"),t=e===null?void 0:Number(e);if(t!==void 0&&!(Number.isInteger(t)&&t>0))throw b("`diff` must be a revision number");return await O(n.principal),await A(async o=>{const a=await E(o,n),c=await X(o,a,decodeURIComponent(n.params.ref));if("remote"in c)throw g(404,"not_found",Y(c.remote),"Check the name with `crtr canvas search`.");const s="deleted"in c?c.deleted:c;if(s.type!=="document")throw b(`${s.name} is a ${s.type}, not a document`);const f=await fe(o,a,s),i={object:await Re(o,s),revisions:f.map(d=>({rev_id:d.rev_id,number:d.number,author_id:d.author,rationale:d.rationale,verbatim:d.verbatim,created_at:d.created_at,parents:d.parents,acting_app:d.acting_app,acting_for:d.acting_for}))};if(t!==void 0){const d=f.find(r=>r.number===t);if(!d)throw new k(404,"not_found",`${s.name} has no revision ${t}`);const h=d.parents[0]===void 0?void 0:f.find(r=>r.rev_id===d.parents[0]);i.diff=be(h?j(h.body_hash):"",j(d.body_hash))}return i})}u(Le,"revisionHistory");const te=1e3,ne=1e3,oe=3e3,We=/^When\b.+\bbecause\b.+/,Me=u(n=>{const e=n.trim();return e===""?0:e.split(/\s+/).length},"words");function qe(n,e){if(n.some(o=>o.on==="boot"&&o.deliver==="content")&&e>te)return`body is ${e} words, over the ${te}-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 t=[...new Set(n.filter(o=>o.on!=="boot"&&o.deliver==="content").map(o=>o.on))];return t.length>0&&e>ne?`body is ${e} words, over the ${ne}-word cap for a content rule on ${t.join("/")}. Keep the core here and move separate subjects into [[linked]] documents.`:n.some(o=>o.on==="boot"&&o.deliver==="preview")&&e>oe?`body is ${e} words, over the ${oe}-word cap for a boot rule at preview. Keep the core here and move separate subjects into [[linked]] documents.`:null}u(qe,"lengthFinding");async function Be(n){const e=C(n);return await O(n.principal,e.cwd),await A(async t=>{const o=await E(t,n),a=e.owner===void 0?null:await q(t,o,e.owner,e.cwd),c=await t.prepare("SELECT * FROM objects WHERE type = 'document' AND deleted_at IS NULL AND home_machine IS NULL AND kind != 'report' ORDER BY name").all(),s=[],f=new Map;for(const i of c){if(a&&i.owner!==a.id||!await se(t,o,i))continue;const d=await L(t,i),h=new Set(d.lint_ignore??[]),r=await R(t,i),p=u((m,y,I)=>{h.has(m)||s.push({name:r,severity:y,rule:m,message:I})},"add"),l=await _e(t,i),w=(await W(t,i))[0],_=w?j(w.body_hash):"",v=qe(l,Me(_));v&&p("length","error",v),l.some(m=>m.deliver==="preview")&&!We.test(i.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 D=new Set((await t.prepare("SELECT written_as FROM edges WHERE type = 'links-to' AND src = ?").all(i.id)).map(m=>m.written_as));for(const m of K(_)){if(D.has(m))continue;const y=await G(t,o,m);"remote"in y||"object"in y||"deleted"in y||p("links","warning",`[[${m}]] names no object in your view`)}if(l.some(m=>m.on==="workspace-open"&&m.deliver==="content")){const m=await ce(t,i);m.type==="repo"&&!h.has("workspace-open")&&f.set(m.name,[...f.get(m.name)??[],r])}}for(const[i,d]of f)if(!(d.length<2))for(const h of d)s.push({name:h,severity:"warning",rule:"workspace-open",message:`repo ${i} has ${d.length} documents delivered at content on workspace-open (${d.join(", ")}); keep one and link the rest from it`});return{findings:s}})}u(Be,"lint");const $=u((n,e=200)=>async t=>({status:e,body:await n(t)}),"ok"),st=[{method:"POST",pattern:"/v1/docs",handler:$(Ne,201)},{method:"PATCH",pattern:"/v1/docs/:ref",handler:$(Te)},{method:"POST",pattern:"/v1/docs/:ref/move",handler:$(Fe)},{method:"DELETE",pattern:"/v1/docs/:ref",handler:$(Ie)},{method:"GET",pattern:"/v1/docs/:ref/history",handler:$(Le)},{method:"POST",pattern:"/v1/docs/lint",handler:$(Be)}];export{R as canonicalName,st as docRoutes,T as repoChange,F as syncChanged};
|
|
1
|
+
var re=Object.defineProperty;var u=(n,e)=>re(n,"name",{value:e,configurable:!0});import{ApiError as k}from"../../../api/errors.js";import{DOC_KINDS as U,DOC_UNSET_FIELDS as V}from"../../../api/dto/docs.js";import{PRIVACY_LEVELS_DTO as K}from"../../../api/dto/objects.js";import{openDb as ae,withCanvasWrite as A}from"../../../core/canvas/db.js";import{CrtrError as se}from"../../../core/errors.js";import{emitEvent as ce}from"../../../core/events/emit.js";import{canChange as de,spaceOf as ue}from"../../../core/graph/access.js";import{get as j}from"../../../core/graph/bodies.js";import{deleteDocument as fe,documentRecord as L,editDocument as me,heads as W,history as pe,linksIn as G,moveDocument as le,readBase as we,setDocumentRecord as he,withCurrentNames as ye,writeDocument as ge}from"../../../core/graph/documents.js";import{resolveName as X}from"../../../core/graph/names.js";import{getById as M}from"../../../core/graph/objects.js";import{noteRepoDocumentsChanged as ve}from"../../../core/graph/repo-sync/index.js";import{checkoutsForCwd as _e}from"../../../core/graph/repo-sync/repos.js";import{lintRules as be,rulesOf as ke}from"../../../core/graph/rules.js";import{unifiedDiff as Ae}from"../../../core/graph/diff.js";import{ownerForGrantee as Ee}from"../../../core/graph/objects.js";import{stubOf as $e}from"../../../core/peer/stubs.js";import{forwarding as Oe}from"../../peer/forward.js";import{resolvedLocally as je}from"./objects.js";import{ownerFromFlag as q,readerFor as E,resolveRef as x,warmReaderRepos as $}from"../reader.js";import{appCaller as z,asApiError as Re,requireOwnNamespace as De}from"./schemas.js";import{filterAsync as Ce,flatMapAsync as Ne}from"../../../core/async-array.js";function g(n,e,t,o,a={}){return new k(n,e,t,{...a,error:e,message:t,next:o})}u(g,"refuse");const b=u((n,e)=>new k(400,"invalid_request",n,e),"invalid");function C(n){const e=n.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(C,"bodyOf");const N=u(async n=>async e=>await _e(n,e),"reposFnFor");function S(n,e){if(n instanceof se){const t=n.details;if(n.code==="read_first")throw g(409,"read_first",n.message,`Read it first with \`crtr canvas read ${e?.id??"<ref>"}\`, then rerun the edit.`,t??{});if(n.code==="conflict")throw new k(409,"name_taken",n.message,t);if(n.code==="forbidden")throw typeof t?.next=="string"?g(403,"forbidden",n.message,t.next,t):new k(403,"forbidden",n.message,t);if(n.code==="scope_missing")throw g(403,"scope_missing",n.message,`Launch the run with \`${String(t?.scope)}\` in its scopes list.`,t??{});if(t?.rule==="repo-public-only")throw g(422,"repo_documents_are_public",n.message,'Own it as `user` and add a rule with `if: {"repo": "<handle>"}` so it loads only in that repo.')}throw Re(n)}u(S,"mapGraphError");async function B(n,e,t){const o=await x(n,e,decodeURIComponent(t));if("remote"in o)throw g(404,"not_found",Z(o.remote),"Check the name with `crtr canvas search`.");if("deleted"in o)throw new k(404,"not_found",`${o.deleted.name} is deleted`,{id:o.deleted.id,deleted:!0});if(o.type!=="document")throw b(`${t} is a ${o.type}, not a document`);return o}u(B,"refDocument");async function Y(n){const{stub:e}=await je(decodeURIComponent(n.params.ref),n);if(e===null)return;const t=await $e(await ae(),e);if(t.object.type!=="document")return;const o=await Oe.current.label(t.home_machine);throw g(404,"not_here",`this document lives on runtime ${o.name}; edit it (or read its history) from a node there`,`Run the command from a node on ${o.name}.`,{id:t.object.id,home_machine:o.id})}u(Y,"refuseRemoteDocument");function Z(n){return`no object named ${n} on this runtime; it may be on another runtime, or the name may be misspelled`}u(Z,"remoteMessage");async function Se(n,e){const t=e.owner===null?null:await M(n,e.owner);return t?t.type==="node"?t.id:t.name:""}u(Se,"ownerHandle");async function R(n,e){const t=await Se(n,e);return t?`${t}/${e.name}`:e.name}u(R,"canonicalName");async function Te(n,e){const t=e.owner===null?null:await M(n,e.owner),o=t?{id:t.id,type:t.type,handle:t.type==="node"?t.id:t.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,...e.type==="document"?{schema_type:e.schema_type??null}:{}}}u(Te,"objectDTO");async function Ie(n,e){const t=e.owner===null?null:await M(n,e.owner);return t?.type==="repo"?t:null}u(Ie,"repoOwner");async function T(n,e,t,o){const a=[...new Map(await Ne(t,async f=>{const i=await Ie(n,f);return i?[[i.id,i]]:[]})).values()],c=e.class==="node"?e.cwd:o,s=e.class==="node"?[...e.checkouts,...e.projectCheckouts].map(f=>f.root):[];return{repos:a,dirs:[...new Set([...c!==void 0?[c]:[],...s])]}}u(T,"repoChange");async function I(n){for(const e of n.repos)try{await ve(e,n.dirs)}catch(t){ce({level:"warn",event:"repo_sync.failed",outcome:"failed",error:t,fields:{repo:e.name,step:"export",reason:t instanceof Error?t.message:String(t)}})}}u(I,"syncChanged");const J=/^[A-Za-z0-9_-]+(\/[A-Za-z0-9_-]+)*$/;function Fe(n,e){if(n===void 0)return;if(!Array.isArray(n)){e.push("`rules` must be a list");return}const t=n.map(a=>{if(typeof a!="object"||a===null||Array.isArray(a))return a;const{match_frontmatter:c,...s}=a;return"matchFrontmatter"in s?{...s,match_frontmatter:s.matchFrontmatter}:c===void 0?s:{...s,matchFrontmatter:c}}),o=be(t);if(o){e.push(o.replaceAll("matchFrontmatter","match_frontmatter"));return}return t}u(Fe,"rulesFromDTO");function Q(n,e){const t={},o=u(i=>{const d=n[i];if(d!==void 0){if(typeof d!="string"){e.push(`\`${i}\` must be a string`);return}return d}},"str"),a=o("preview");a!==void 0&&(a.trim()===""||/[\r\n]/.test(a)?e.push("`preview` must be one non-empty line"):t.preview=a);const c=o("summary");c!==void 0&&(t.summary=c);const s=o("why_it_exists");if(s!==void 0&&(t.whyItExists=s),n.privacy!==void 0&&(K.includes(n.privacy)?t.privacy=n.privacy:e.push(`\`privacy\` must be one of ${K.join(", ")}`)),n.unlisted!==void 0&&(typeof n.unlisted!="boolean"?e.push("`unlisted` must be a boolean"):t.unlisted=n.unlisted),n.lint_ignore!==void 0){const i=n.lint_ignore;!Array.isArray(i)||i.some(d=>typeof d!="string")?e.push("`lint_ignore` must be a list of strings"):t.lintIgnore=i}if(n.extensions!==void 0){const i=n.extensions;typeof i!="object"||i===null||Array.isArray(i)||Object.values(i).some(d=>typeof d!="object"||d===null||Array.isArray(d))?e.push("`extensions` must map each plugin to an object of fields"):t.extensions=i}const f=Fe(n.rules,e);return f!==void 0&&(t.rules=f),t}u(Q,"fieldsFrom");function ee(n){if(n.length>0)throw b(n.join("; "),{errors:n})}u(ee,"failOn");async function te(n,e,t,o){const a=await Ce(G(t),async c=>"remote"in await X(n,e,c));return{...o.length>0?{unresolved_links:o}:{},...a.length>0?{remote_links:a}:{}}}u(te,"linkReport");async function Le(n){const e=C(n),t=[],o=e.name;(typeof o!="string"||!J.test(o))&&t.push("`name` must be segments of letters, digits, `_` or `-` joined by `/`"),typeof e.body!="string"&&t.push("`body` must be a string"),typeof e.preview!="string"&&t.push("`preview` is required");const a=e.kind??"knowledge";U.includes(a)||t.push(a==="report"?"reports are written only by `crtr push`":`\`kind\` must be one of ${U.join(", ")}`);const c=Q(e,t);e.cwd!==void 0&&typeof e.cwd!="string"&&t.push("`cwd` must be a string");const s=e.schema_type;s!==void 0&&typeof s!="string"&&t.push("`schema_type` must be a string");const f=e.relations;f!==void 0&&(!Array.isArray(f)||f.some(r=>typeof r!="object"||r===null||typeof r.relation!="string"||typeof r.subject!="string"))&&t.push("`relations` must be a list of {relation, subject} strings"),ee(t);const i=e;await $(n.principal,i.cwd);const{dto:d,change:h}=await A(async r=>{const m=await E(r,n);i.schema_type!==void 0?await De(r,z(n).app,i.schema_type):i.relations!==void 0&&z(n);const p=i.owner==="user"&&m.class==="app"&&m.sub!==void 0?await Ee(r,m.sub.startsWith("user:")?m.sub:`user:${m.sub}`):await q(r,m,i.owner,i.cwd);try{const{object:w,unresolved:_}=await ge(r,m,{...c,owner:p,name:i.name,kind:a,preview:c.preview,privacy:c.privacy??"public",...i.schema_type!==void 0?{schemaType:i.schema_type}:{},...i.relations!==void 0?{relations:i.relations}:{}},i.body,await N(r));return{dto:{id:w.id,name:await R(r,w),...await te(r,m,i.body,_)},change:await T(r,m,[w],i.cwd)}}catch(w){S(w)}});return await I(h),d}u(Le,"write");function We(n,e){let t=n;e.forEach(({old:o,new:a},c)=>{const s=o===""?-1:t.indexOf(o);if(s<0)throw g(422,"replace_no_match",`replace[${c}]: old text not found in the revision you read`,"Copy the old text exactly from your last read and rerun.",{index:c});if(t.indexOf(o,s+1)>=0)throw g(422,"replace_ambiguous",`replace[${c}]: old text occurs more than once`,"Include more surrounding text so the old text matches once, and rerun.",{index:c});t=t.slice(0,s)+a+t.slice(s+o.length)})}u(We,"checkReplacements");async function Me(n){const e=C(n),t=[],o=e.body!==void 0,a=e.replace!==void 0;o&&a&&t.push("give `body` or `replace`, not both"),o&&typeof e.body!="string"&&t.push("`body` must be a string");const c=e.replace;a&&(!Array.isArray(c)||c.length===0||c.some(r=>typeof r!="object"||r===null||typeof r.old!="string"||typeof r.new!="string"))&&t.push("`replace` must be a non-empty list of {old, new} strings"),(typeof e.rationale!="string"||e.rationale.trim()==="")&&t.push("`rationale` is required"),e.verbatim!==void 0&&typeof e.verbatim!="boolean"&&t.push("`verbatim` must be a boolean"),e.base!==void 0&&(typeof e.base!="string"||e.base==="")&&t.push("`base` must be a non-empty heads key"),e.base!==void 0&&!o&&!a&&t.push("`base` applies only to a `body` or `replace` edit");const s=Q(e,t),f=e.unset??[];if(!Array.isArray(f)||f.some(r=>!V.includes(r)))t.push(`\`unset\` takes only ${V.join(", ")}`);else for(const r of f)r==="summary"&&(s.summary=null),r==="why_it_exists"&&(s.whyItExists=null),r==="unlisted"&&(s.unlisted=!1),r==="lint_ignore"&&(s.lintIgnore=null),r==="extensions"&&(s.extensions=null),r==="rules"&&(s.rules=[]);t.length===0&&!o&&!a&&Object.keys(s).length===0&&t.push("nothing to change: give `body`, `replace`, or a field"),ee(t);const i=e;await Y(n),await $(n.principal);const{dto:d,synced:h}=await A(async r=>{const m=await E(r,n),p=await B(r,m,n.params.ref),w=await R(r,p),_=await T(r,m,[p]);try{if(!o&&!a)return await he(r,m,p,s,i.rationale),{dto:{id:p.id,name:w,revision:(await L(r,p)).revision},synced:_};const v=i.base??await we(r,m,p);if(a&&v!==null){const P=await L(r,p),H=await W(r,p);P.source_path===null&&P.heads_key===v&&H.length===1&&We(await ye(r,p,j(H[0].body_hash)),i.replace)}const D=i.verbatim===!0,l=o?{body:i.body,verbatim:D}:{replace:i.replace,verbatim:D},y=await me(r,m,p,l,i.rationale,v,s,await N(r));if("stale"in y)throw g(409,"stale_revision",`${w} changed after your read; it is now at revision ${y.stale.revision}`,`Read it again with \`crtr canvas read ${w}\`, then redo your change on the current text.`,{stale:y.stale});const F=j((await W(r,p))[0].body_hash);return{dto:{id:p.id,name:w,revision:y.revision,...await te(r,m,F,y.unresolved)},synced:_}}catch(v){S(v,p)}});return await I(h),d}u(Me,"edit");async function qe(n){const e=C(n);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"||!J.test(e.new_name)))throw b("`new_name` must be segments of letters, digits, `_` or `-` joined by `/`");await $(n.principal,e.cwd);const{dto:t,change:o}=await A(async a=>{const c=await E(a,n),s=await B(a,c,n.params.ref),f=e.owner===void 0?void 0:await q(a,c,e.owner,e.cwd);try{const i=await le(a,c,s,{...e.new_name!==void 0?{name:e.new_name}:{},...f?{owner:f}:{}},await N(a));return{dto:{id:i.id,name:await R(a,i)},change:await T(a,c,[s,i],e.cwd)}}catch(i){S(i,s)}});return await I(o),t}u(qe,"move");async function Be(n){await $(n.principal);const{dto:e,change:t}=await A(async o=>{const a=await E(o,n),c=await B(o,a,n.params.ref),s=await R(o,c),f=await T(o,a,[c]);try{await fe(o,a,c,await N(o))}catch(i){S(i,c)}return{dto:{id:c.id,name:s},change:f}});return await I(t),e}u(Be,"remove");async function Pe(n){const e=n.query.get("diff"),t=e===null?void 0:Number(e);if(t!==void 0&&!(Number.isInteger(t)&&t>0))throw b("`diff` must be a revision number");return await Y(n),await $(n.principal),await A(async o=>{const a=await E(o,n),c=await x(o,a,decodeURIComponent(n.params.ref));if("remote"in c)throw g(404,"not_found",Z(c.remote),"Check the name with `crtr canvas search`.");const s="deleted"in c?c.deleted:c;if(s.type!=="document")throw b(`${s.name} is a ${s.type}, not a document`);const f=await pe(o,a,s),i={object:await Te(o,s),revisions:f.map(d=>({rev_id:d.rev_id,number:d.number,author_id:d.author,rationale:d.rationale,verbatim:d.verbatim,created_at:d.created_at,parents:d.parents,acting_app:d.acting_app,acting_for:d.acting_for}))};if(t!==void 0){const d=f.find(r=>r.number===t);if(!d)throw new k(404,"not_found",`${s.name} has no revision ${t}`);const h=d.parents[0]===void 0?void 0:f.find(r=>r.rev_id===d.parents[0]);i.diff=Ae(h?j(h.body_hash):"",j(d.body_hash))}return i})}u(Pe,"revisionHistory");const ne=1e3,oe=1e3,ie=3e3,He=/^When\b.+\bbecause\b.+/,Ue=u(n=>{const e=n.trim();return e===""?0:e.split(/\s+/).length},"words");function Ve(n,e){if(n.some(o=>o.on==="boot"&&o.deliver==="content")&&e>ne)return`body is ${e} words, over the ${ne}-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 t=[...new Set(n.filter(o=>o.on!=="boot"&&o.deliver==="content").map(o=>o.on))];return t.length>0&&e>oe?`body is ${e} words, over the ${oe}-word cap for a content rule on ${t.join("/")}. Keep the core here and move separate subjects into [[linked]] documents.`:n.some(o=>o.on==="boot"&&o.deliver==="preview")&&e>ie?`body is ${e} words, over the ${ie}-word cap for a boot rule at preview. Keep the core here and move separate subjects into [[linked]] documents.`:null}u(Ve,"lengthFinding");async function Ke(n){const e=C(n);return await $(n.principal,e.cwd),await A(async t=>{const o=await E(t,n),a=e.owner===void 0?null:await q(t,o,e.owner,e.cwd),c=await t.prepare("SELECT * FROM objects WHERE type = 'document' AND deleted_at IS NULL AND home_machine IS NULL AND kind != 'report' ORDER BY name").all(),s=[],f=new Map;for(const i of c){if(a&&i.owner!==a.id||!await de(t,o,i))continue;const d=await L(t,i),h=new Set(d.lint_ignore??[]),r=await R(t,i),m=u((l,y,F)=>{h.has(l)||s.push({name:r,severity:y,rule:l,message:F})},"add"),p=await ke(t,i),w=(await W(t,i))[0],_=w?j(w.body_hash):"",v=Ve(p,Ue(_));v&&m("length","error",v),p.some(l=>l.deliver==="preview")&&!He.test(i.preview??"")&&m("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 D=new Set((await t.prepare("SELECT written_as FROM edges WHERE type = 'links-to' AND src = ?").all(i.id)).map(l=>l.written_as));for(const l of G(_)){if(D.has(l))continue;const y=await X(t,o,l);"remote"in y||"object"in y||"deleted"in y||m("links","warning",`[[${l}]] names no object in your view`)}if(p.some(l=>l.on==="workspace-open"&&l.deliver==="content")){const l=await ue(t,i);l.type==="repo"&&!h.has("workspace-open")&&f.set(l.name,[...f.get(l.name)??[],r])}}for(const[i,d]of f)if(!(d.length<2))for(const h of d)s.push({name:h,severity:"warning",rule:"workspace-open",message:`repo ${i} has ${d.length} documents delivered at content on workspace-open (${d.join(", ")}); keep one and link the rest from it`});return{findings:s}})}u(Ke,"lint");const O=u((n,e=200)=>async t=>({status:e,body:await n(t)}),"ok"),wt=[{method:"POST",pattern:"/v1/docs",handler:O(Le,201)},{method:"PATCH",pattern:"/v1/docs/:ref",handler:O(Me)},{method:"POST",pattern:"/v1/docs/:ref/move",handler:O(qe)},{method:"DELETE",pattern:"/v1/docs/:ref",handler:O(Be)},{method:"GET",pattern:"/v1/docs/:ref/history",handler:O(Pe)},{method:"POST",pattern:"/v1/docs/lint",handler:O(Ke)}];export{R as canonicalName,wt as docRoutes,T as repoChange,I as syncChanged};
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import type { RouteTable } from '../router.js';
|
|
1
|
+
import type { RequestContext, RouteTable } from '../router.js';
|
|
2
|
+
/** What a local resolution of `raw` finds: the id of a stub of another machine's object (a stub is never served as the object, however
|
|
3
|
+
* it is named), and whether a live or deleted object is here (an exact answer, with no peer call). */
|
|
4
|
+
export declare function resolvedLocally(raw: string, ctx: RequestContext): Promise<{
|
|
5
|
+
stub: string | null;
|
|
6
|
+
hit: boolean;
|
|
7
|
+
}>;
|
|
2
8
|
/** How long a merged list waits for any one other machine before it counts as unreachable. */
|
|
3
9
|
export declare const listBudget: {
|
|
4
10
|
ms: number;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
var Fe=Object.defineProperty;var l=(e,t)=>Fe(e,"name",{value:t,configurable:!0});import{ApiError as y}from"../../../api/errors.js";import{PRIVACY_LEVELS_DTO as Ae}from"../../../api/dto/objects.js";import{openDb as N,withCanvasWrite as v}from"../../../core/canvas/db.js";import{actorOf as ae}from"../../../core/graph/documents.js";import{readerForObject as C,readerFor as We}from"../../../core/graph/reader.js";import{resolveName as Le,stubsNamed as Pe,unwrapRef as ie}from"../../../core/graph/names.js";import{canRead as D,holdsObjectsScope as Ce,spaceOf as De}from"../../../core/graph/access.js";import{customReachable as Me,mayActAs as re}from"../../../core/graph/custom.js";import{customObjectRef as oe,authorizeCustom as se,fenceArgv as J}from"./custom-objects.js";import{edgesOf as Ge}from"../../../core/graph/edges.js";import{publish as B}from"../../../core/graph/events.js";import{objectDTO as Ue}from"../../../core/graph/kinds/dto.js";import{isKind as He,kindNames as ze,kindOf as K}from"../../../core/graph/kinds/registry.js";import{listObjects as Ve,searchObjects as ue}from"../../../core/graph/objects.js";import{checkoutsForCwd as Je}from"../../../core/graph/repo-sync/repos.js";import{recordWatch as M,unwatch as Be,watchersOf as Ke,watchesOf as Ze}from"../../../core/graph/watches.js";import{armObjectWaitForWatch as G,settleObjectWaitForUnwatch as Qe}from"../../../core/graph/object-waits.js";import{readerFor as T,resolveRef as Z,warmReaderRepos as R}from"../reader.js";import{readDelegationFor as ce,runReadLeaf as Ye}from"../../plugin-objects/read-leaf.js";import{invalidRequest as U,isRecord as q}from"./validate.js";import{callerNode as le,callerStub as Q,forwardNamed as Xe,forwardVerb as fe,originates as de,queryWithoutMachine as H,relayError as z,remoteStub as xe,unknownError as we,forwarding as P,withMachine as Y}from"../../peer/forward.js";import{getById as I}from"../../../core/graph/objects.js";import{ensureNodeStub as et,isStub as X,stubOf as tt,withKindDecl as $}from"../../../core/peer/stubs.js";import{isUnreachable as nt}from"../../../core/peer/client.js";import{normalizeMachineId as F}from"../../../core/peer/directory.js";import{mapAsync as at}from"../../../core/async-array.js";const A=l(async e=>async t=>await Je(e,t),"reposFnFor");async function g(e,t){return{...await Ue(e,t),...t.type==="document"?{schema_type:t.schema_type??null}:{}}}l(g,"objectDTO");async function it(e,t){const n=t.filter(r=>r.type==="document").map(r=>r.id),a=new Map;if(n.length===0)return a;const i=await e.prepareUncached(`SELECT object, extensions_json FROM documents WHERE object IN (${n.map(()=>"?").join(", ")})`).all(...n);for(const r of i)r.extensions_json!==null&&a.set(r.object,JSON.parse(r.extensions_json));return a}l(it,"extensionsOf");async function me(e,t){const n=await it(e,t);return await at(t,async a=>({...await g(e,a),...await(await K(e,a.type)).listItem?.(e,a),...a.type==="document"?{extensions:n.get(a.id)??{}}:{}}))}l(me,"listItems");function rt(e){return`no object named ${e} on this runtime; it may be on another runtime, or the name may be misspelled`}l(rt,"remoteMessage");async function pe(e,t,n){try{return await S(e,t,n)}catch(a){if(a instanceof y&&a.code==="not_found"&&!a.details?.deleted)return null;throw a}}l(pe,"ownerFilter");async function S(e,t,n){const a=await Z(e,t,n);if("remote"in a)throw new y(404,"not_found",rt(a.remote),{next:"Check the name with `crtr canvas search`."});if("deleted"in a)throw new y(404,"not_found",`${a.deleted.name} is deleted`,{id:a.deleted.id,deleted:!0});return a}l(S,"liveRef");const O=l(e=>decodeURIComponent(e.params.ref),"refParam"),he=l(e=>{const t=ie(e),n=t.indexOf("/");return n>0?t.slice(0,n):t},"idOf");async function ye(e){const t=await I(await N(),he(e));return t!==null&&await X(await N(),t)?t.id:null}l(ye,"stubIdOf");async function ot(e,t){const n=await ye(e);return n!==null?{stub:n,hit:!0}:(await R(t.principal),await v(async a=>{try{const i=await T(a,t),r=l(async()=>{const s=await Pe(a,i,e);if(s.length>1)throw new y(409,"ambiguous_name",`'${e}' names more than one remote object`,{candidates:s.map(c=>c.id),next:"Read one by its object id."});return{stub:s[0]?.id??null,hit:!1}},"named");let o;try{o=await Z(a,i,e)}catch(s){if(s instanceof y&&s.code==="not_found")return await r();throw s}if("remote"in o)return await r();if("deleted"in o){const s=await r();return s.stub===null?{stub:null,hit:!0}:s}return{stub:await X(a,o)?o.id:null,hit:!0}}catch(i){if(i instanceof y&&i.code==="ambiguous_name")throw i;return{stub:null,hit:!1}}}))}l(ot,"resolvedLocally");async function x(e,t,n){const a=await ot(t,e);if(a.stub!==null)return fe(e,a.stub,n);if(a.hit||!de(e.principal))return{kind:"local"};const i=await fe(e,he(t),n);return i.kind==="local"&&ie(t).includes("/")?Xe(e,n,{method:"GET",path:V(t),query:H(e)}):i}l(x,"forwardRef");const V=l(e=>`/v1/objects/${encodeURIComponent(e)}`,"objectPath");async function be(e,t,n,a,i){const r=t?.object;!r?.id||!r.type||await v(async o=>{const s=await le(o,e);if(s===null)return;const c=await xe(o,r.id,r.type,n,{kind:r.kind??null,name:r.name??r.id,...r.preview===void 0?{}:{preview:r.preview},owner:r.owner??null,...r.kind_decl===void 0?{}:{kind_decl:r.kind_decl},...r.privacy===void 0?{}:{privacy:r.privacy}});await M(o,s,c,a,i===void 0?{}:{patterns:i}),a==="ask"&&await G(o,s,c)})}l(be,"watchRemote");async function st(e){const t=O(e),n=["1","true"].includes(e.query.get("fields")??""),a=await x(e,t,{method:"GET",path:V(t),query:H(e)});if(a.kind==="unknown")return{state:"unknown",ref:t,unreachable:a.unreachable};if(a.kind==="remote"){if(a.status>=400)throw z(a.status,a.body);return await be(e,a.body,a.machine.id,"read"),Y(a.body,a.machine)}const i=l(async s=>{const c=await Q(s,e);return c===null?await T(s,e):await C(s,c,await A(s))},"readerOf");await R(e.principal);const r=await v(async s=>{const c=await i(s),u=await Z(s,c,t);if("remote"in u)return{state:"remote",remote:u.remote};if("deleted"in u)return{state:"deleted",deleted:await g(s,u.deleted)};const f=await ce(s,u);if(f!==null)return{delegate:f,hitId:u.id};const{data:w,text:b}=await(await K(s,u.type)).read(s,c,u,{fields:n,reposFn:await A(s)});return{state:"object",type:u.type,object:await $(s,u,await g(s,u)),text:b,data:w}});if(!("delegate"in r))return r;const o=await Ye(r.delegate,e.principal);return await R(e.principal),await v(async s=>{const c=await i(s),u=await I(s,r.hitId);if(u===null)throw new y(404,"not_found","object not found");if(u.deleted_at!==null)return{state:"deleted",deleted:await g(s,u)};if(!await D(s,c,u))throw new y(404,"not_found","object not found");const{data:f,text:w}=await(await K(s,u.type)).read(s,c,u,{fields:n,reposFn:await A(s)});return await ce(s,u)===null?{state:"object",type:u.type,object:await $(s,u,await g(s,u)),text:w,data:f}:{state:"object",type:u.type,object:await $(s,u,await g(s,u)),text:"markdown"in o?o.markdown:`${w}
|
|
2
2
|
content unavailable: ${o.unavailable}`,data:{...f,content:"markdown"in o?"live":"unavailable"}}})}l(st,"read");function ee(e,t,n,a){if(e!=null){if(!n.includes(e)){a.push({field:t,problem:`must be one of ${n.join(", ")}`,received:e});return}return e}}l(ee,"oneOf");async function ge(e,t,n){if(t!=null){if(typeof t!="string"||!await He(e,t)){n.push({field:"type",problem:`must be a kind: one of ${(await ze(e)).join(", ")}`,received:t});return}return t}}l(ge,"kindName");function je(e,t,n,a){if(e==null)return a;const i=Number(e);return!Number.isInteger(i)||i<1||i>100?(n.push({field:t,problem:"must be an integer from 1 to 100",received:e}),a):i}l(je,"limitOf");function _e(e,t){if(e==null)return;let n=e;if(typeof e=="string")try{n=JSON.parse(e)}catch{n=null}if(!q(n)||Object.values(n).some(a=>!q(a))){t.push({field:"extensions",problem:'must be an object of objects, e.g. {"firstlight":{"state":"active"}}',received:e});return}return n}l(_e,"extensionsParam");function ke(e,t){if(e!=null){if(typeof e!="string"||e===""){t.push({field:"schema_type",problem:"must be a non-empty string",received:e});return}return e}}l(ke,"schemaTypeParam");async function ve(e){const t=e.query,n=[],a=await ge(await N(),t.get("type"),n),i=ee(t.get("privacy"),"privacy",Ae,n),r=je(t.get("limit"),"limit",n,50),o=t.get("cursor");o!==null&&!/^\d+$/.test(o)&&n.push({field:"cursor",problem:"is not a cursor from a previous page",received:o});const s=t.get("deleted");s!==null&&!["0","1","true","false"].includes(s)&&n.push({field:"deleted",problem:"must be true or false",received:s});const c=t.get("shared");c!==null&&!["0","1","true","false"].includes(c)&&n.push({field:"shared",problem:"must be true or false",received:c});const u=_e(t.get("extensions"),n),f=ke(t.get("schema_type"),n);return n.length>0&&U("object list request",n),await R(e.principal),await v(async w=>{const b=await T(w,e),j={...a?{type:a}:{},...i?{privacy:i}:{},...t.get("kind")!==null?{kind:t.get("kind")}:{},...s==="1"||s==="true"?{deleted:!0}:{},...c==="1"||c==="true"?{shared:!0}:{},...u?{extensions:u}:{},...f?{schemaType:f}:{},...t.get("name")!==null?{namePrefix:t.get("name")}:{}},k=t.get("owner");if(k!==null){const m=await pe(w,b,k);if(m===null)return{items:[],next_cursor:null};j.owner=m}const p=await Ve(w,b,j,{limit:r,after_seq:o===null?0:Number(o)}),d=p.at(-1);return{items:await me(w,p),next_cursor:p.length===r&&d?String(d.seq):null}})}l(ve,"listLocal");const ut={ms:3e4},ct="self",te=l((e,t)=>e.map(n=>({...n,machine:t})),"labelItems");async function Oe(e,t,n,a){const i=P.current;try{const r=await i.call(t.id,{method:"GET",path:"/v1/objects",query:n},await i.envelope(e.principal),a);if(nt(r))return{state:"unreachable",items:[],next:null};if(r.status===426)return{state:"too_old",items:[],next:null};const o=r.body;return r.status!==200||!Array.isArray(o?.items)?{state:"unreachable",items:[],next:null}:{state:"ok",items:te(o.items,t),next:o.next_cursor??null}}catch{return{state:"unreachable",items:[],next:null}}}l(Oe,"remotePage");async function lt(e){const t=new Promise(n=>e.addEventListener("abort",()=>n(null),{once:!0}));return Promise.race([P.current.machines().catch(()=>null),t])}l(lt,"machinesWithin");async function ft(e){const t=e.query.get("machine");if(!de(e.principal)||!P.current.joined()||t===ct)return await ve(Ee(e));const a=P.current.self(),i=t!==null&&F(t)!==a,r=i?null:await ve(Ee(e)),o=new AbortController,s=setTimeout(()=>o.abort(),ut.ms);s.unref?.();try{const c=await lt(o.signal);if(c===null){if(i)throw new y(503,"runtime_unreachable",`The directory did not answer, so ${F(t)} cannot be listed.`,{machine:F(t)});return r}const u=l(d=>({id:d,name:c.find(m=>m.machine_id===d)?.name??d}),"labelOf"),f=u(a),w=c.filter(d=>d.machine_id!==a&&d.kind!=="device"),b=H(e);if(t!==null){if(!i)return{items:te(r.items,f),next_cursor:r.next_cursor,machines:[{machine_id:a,name:f.name,state:"ok",more:r.next_cursor!==null}]};const d=F(t);if(!w.some(L=>L.machine_id===d))throw new y(404,"not_found",`no machine ${d} on your account`,{machine:d});const m=await Oe(e,u(d),b,o.signal);return{items:m.items,next_cursor:m.next,machines:[{machine_id:d,name:u(d).name,state:m.state,more:m.next!==null}]}}const{cursor:j,...k}=b,p=await Promise.all(w.map(d=>Oe(e,u(d.machine_id),k,o.signal)));return{items:[...te(r.items,f),...p.flatMap(d=>d.items)],next_cursor:r.next_cursor,machines:[{machine_id:a,name:f.name,state:"ok",more:r.next_cursor!==null},...w.map((d,m)=>({machine_id:d.machine_id,name:d.name,state:p[m].state,more:p[m].next!==null}))]}}finally{clearTimeout(s)}}l(ft,"list");function Ee(e){const t=new URLSearchParams(e.query);return t.delete("machine"),{...e,query:t}}l(Ee,"withoutMachine");async function dt(e){const t=[],n=q(e.body)?e.body:{};q(e.body)||t.push({field:"body",problem:"must be an object",received:e.body});const a=n.text;(typeof a!="string"||a.trim()==="")&&t.push({field:"text",problem:"is required",received:a});const i=n.grep;if(i!==void 0)if(typeof i!="string")t.push({field:"grep",problem:"must be a regular expression string",received:i});else try{new RegExp(i)}catch(h){t.push({field:"grep",problem:`is not a valid regular expression: ${h.message}`,received:i})}n.body!==void 0&&typeof n.body!="boolean"&&t.push({field:"body",problem:"must be a boolean",received:n.body});const r=await ge(await N(),n.type,t);n.kind!==void 0&&typeof n.kind!="string"&&t.push({field:"kind",problem:"must be a string",received:n.kind}),n.owner!==void 0&&typeof n.owner!="string"&&t.push({field:"owner",problem:"must be a string",received:n.owner});const o=je(n.limit,"limit",t,50),s=_e(n.extensions,t),c=ke(n.schema_type,t);t.length>0&&U("object search request",t),await R(e.principal);const u=await v(async h=>{const _=await T(h,e),$e=typeof n.owner=="string"?await pe(h,_,n.owner):null;return{reader:_,owner:$e}}),{reader:f,owner:w}=u;if(typeof n.owner=="string"&&w===null)return{items:[]};const b={...s?{extensions:s}:{},...c?{schemaType:c}:{},...r?{type:r}:{},...typeof n.kind=="string"?{kind:n.kind}:{},...w?{owner:w}:{}},j=await N(),k=await ue(j,f,{text:a,body:n.body===!0||typeof i=="string",...b}),p=new Set(k.map(h=>h.object.id)),m=(typeof i=="string"?(await ue(j,f,{text:i,grep:!0,...b})).filter(h=>p.has(h.object.id)):k).slice(0,o),L=await me(j,m.map(h=>h.object));return{items:m.map((h,_)=>({object:L[_],...h.line!==void 0?{matches:[{line:h.line,text:h.text??""}]}:{}}))}}l(dt,"search");const Te=["interrupt","steer","after-turn","next-turn"],wt=/^(\*|>|[A-Za-z0-9_-]+)(\.(\*|>|[A-Za-z0-9_-]+))*$/;function mt(e,t){if(e!==void 0){if(!Array.isArray(e)||e.length===0||e.some(n=>typeof n!="string"||!wt.test(n)||n.includes(">")&&!n.endsWith(">"))){t.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}}l(mt,"patternsOf");function pt(e,t){if(e===void 0)return;if(!q(e)||Object.keys(e).length===0){t.push({field:"config",problem:"must map levels 1-10 to a delivery",received:e});return}const n=[];for(const[a,i]of Object.entries(e)){const r=Number(a);!Number.isInteger(r)||r<1||r>10?t.push({field:`config.${a}`,problem:"level must be an integer from 1 to 10"}):Te.includes(i)?n.push({threshold:r,delivery:i}):t.push({field:`config.${a}`,problem:`delivery must be one of ${Te.join(", ")}`,received:i})}return n.sort((a,i)=>i.threshold-a.threshold)}l(pt,"configOf");async function Re(e){const t=await ye(e);if(t!==null)throw new y(400,"invalid_request",`${t} lives on another machine; an explicit watcher cannot watch it from here`,{id:t})}l(Re,"refuseStubWatch");async function ne(e,t){const n=await I(e,t)??await(async()=>{const a=await Le(e,await We(e,{class:"person"},async()=>[]),t);return"object"in a?a.object:null})();return n===null||n.deleted_at!==null||!(n.type.includes(".")||n.type==="node")?null:n}l(ne,"findWatcher");const E=l(()=>{throw new y(404,"not_found","watcher not found")},"watcherNotFound");async function qe(e,t,n){if(typeof t!="string"||n===void 0||n===null)return null;if(typeof n!="string")throw new y(400,"invalid_request","invalid watcher_machine");if(await ne(e,t)!==null)return null;const a=P.current;let i;try{i=await a.machines()}catch{throw new y(503,"runtime_unreachable","The directory did not answer, so the watcher machine cannot be checked.")}const r=F(n);return(r===a.self()||!i.some(o=>F(o.machine_id)===r))&&E(),r}l(qe,"remoteWatcherMachine");async function Ne(e,t,n,a){if(t.publishToken||t.principal.class==="anonymous")return E();const i=await T(e,t);if(i.class==="person")return E();let r;try{r=await S(e,i,a)}catch{return E()}const o=r.owner===null?null:await I(e,r.owner);return o===null||!await re(e,i,o)||!await Ce(e,i,"link",n)||(await De(e,n)).id===i.app.id&&!(await D(e,i,n)&&await D(e,await C(e,n),r))?E():(await J(e,t,n),{actor:i.app,object:r})}l(Ne,"linkWatcher");async function Ie(e,t,n){if(t.publishToken)return!0;if(t.principal.class==="anonymous"||!n.type.includes("."))return!1;const a=await T(e,t),i=n.owner===null?null:await I(e,n.owner);return i!==null&&await re(e,a,i)&&await Me(e,a,n)}l(Ie,"ownsWatcher");async function ht(e){const t=O(e),n=q(e.body)?e.body:{};if(typeof n.watcher=="string"&&await Re(t),typeof n.watcher!="string"){const i=await x(e,t,{method:"POST",path:`${V(t)}/watch`,body:e.body});if(i.kind==="unknown")throw we(t,i.unreachable);if(i.kind==="remote"){if(i.status>=400)throw z(i.status,i.body);const r=i.body.patterns;return await be(e,i.body,i.machine.id,"ask",r),Y(i.body,i.machine)}}const a=await qe(await N(),n.watcher,n.watcher_machine);return await yt(e,a)}l(ht,"watch");async function yt(e,t=null){const n=[],a=e.body===void 0?{}:q(e.body)?e.body:(n.push({field:"body",problem:"must be an object"}),{}),i=mt(a.patterns,n),r=pt(a.config,n);return a.filter!==void 0&&!q(a.filter)&&n.push({field:"filter",problem:"must be an object",received:a.filter}),a.watcher!==void 0&&typeof a.watcher!="string"&&n.push({field:"watcher",problem:"must be a custom-object ref",received:a.watcher}),a.watcher_machine!==void 0&&typeof a.watcher_machine!="string"&&n.push({field:"watcher_machine",problem:"must be a machine id",received:a.watcher_machine}),n.length>0&&U("watch request",n),await R(e.principal),await v(async o=>{const s=typeof a.watcher=="string";if((e.publishToken||e.principal.class==="anonymous")&&!s)throw new y(404,"not_found","watcher not found");const c=i??[">"],u={patterns:c,...r?{config:r}:{},...a.filter!==void 0?{filter:a.filter}:{}};if(s){const j=a.watcher,k=t===null?null:await bt(o,e,j,t),p=k??(e.publishToken?await oe(o,j):await ne(o,j));if(p===null)return E();if(k===null&&await Ie(o,e,p)){const L=await se(o,e,p);await J(o,e,p);const h=await C(o,p),_=await S(o,h,O(e));if(!await D(o,h,_))throw new y(404,"not_found","object not found");return await M(o,p,_,"act",u),await G(o,p,_),await B(o,{event:"watched",object:_,actor:L,attrs:{}},await A(o)),{object:await $(o,_,await g(o,_)),patterns:c}}const{actor:d,object:m}=await Ne(o,e,p,O(e));return await M(o,p,m,"act",{...u,linkApp:d}),await G(o,p,m),await B(o,{event:"watched",object:m,actor:d,attrs:{}},await A(o)),{object:await $(o,m,await g(o,m)),patterns:c}}const f=await T(o,e),w=await Q(o,e)??ae(f),b=await S(o,f,O(e));return await M(o,w,b,"ask",u),await G(o,w,b),await B(o,{event:"watched",object:b,actor:w,attrs:{}},await A(o)),{object:await $(o,b,await g(o,b)),patterns:c}})}l(yt,"watchLocal");async function bt(e,t,n,a){return t.publishToken||t.principal.class==="anonymous"?E():await et(e,n,a)}l(bt,"ensureNodeStubFor");async function Se(e,t,n,a){const i=l(async()=>(await e.prepare(`SELECT count(*) AS n FROM watch_subscriptions s JOIN watches w ON w.watch_id = s.watch
|
|
3
|
-
WHERE w.watcher = ? AND w.object = ?`).get(t.id,n.id)).n,"count"),r=await i();await Be(e,t,n,a??void 0);const o=await i();return o===0&&await Qe(e,t,n),{object:await g(e,n),removed:r-o}}l(Se,"dropWatch");async function gt(e){const t=O(e);if(e.query.get("watcher")&&await Re(t),!e.query.get("watcher")){const a=await x(e,t,{method:"DELETE",path:`${V(t)}/watch`,query:H(e)});if(a.kind==="unknown")throw we(t,a.unreachable);if(a.kind==="remote"){const i=a.status===404?a.body.error?.details:void 0,r=i?.deleted===!0?i.id:void 0;if(a.status>=400&&r===void 0)throw z(a.status,a.body);const o=r??a.body.object?.id,s=await v(async c=>{const u=await le(c,e),f=o===void 0?null:await I(c,o);return u===null||f===null||!await X(c,f)?null:await Se(c,u,f,e.query.get("pattern"))});if(r!==void 0){if(s===null)throw z(a.status,a.body);return{...s,machine:a.machine}}return Y(a.body,a.machine)}}const n=await qe(await N(),e.query.get("watcher")??void 0,e.query.get("watcher_machine")??void 0);return await jt(e,n)}l(gt,"unwatchRoute");async function jt(e,t=null){const n=e.query.get("pattern"),a=e.query.get("watcher");return await R(e.principal),await v(async i=>{if((e.publishToken||e.principal.class==="anonymous")&&!a)throw new y(404,"not_found","watcher not found");const r=l(async(c,u)=>await Se(i,c,u,n),"drop");if(a){const c=t===null?null:await(async()=>{const f=await I(i,a);return f!==null&&await tt(i,f)!==null?f:null})();if(t!==null&&c===null)return E();const u=c??(e.publishToken?await oe(i,a):await ne(i,a));return u===null?E():c===null&&await Ie(i,e,u)?(await se(i,e,u),await J(i,e,u),await r(u,await S(i,await C(i,u),O(e)))):await r(u,(await Ne(i,e,u,O(e))).object)}const o=await T(i,e),s=await Q(i,e)??ae(o);return await r(s,await S(i,o,O(e)))})}l(jt,"unwatchLocal");async function _t(e){const t=[],n=ee(e.query.get("type"),"type",["acted-on","links-to","watches"],t),a=ee(e.query.get("direction"),"direction",["out","in"],t);return t.length>0&&U("edges request",t),await R(e.principal),await v(async i=>{const r=await T(i,e),o=await S(i,r,O(e)),s=[];if(n!=="watches")for(const c of await Ge(i,r,o,{...n?{type:n}:{},direction:a??"both"}))s.push({type:c.type,src:await g(i,c.src),dst:await g(i,c.dst),...c.written_as?{written_as:c.written_as}:{}});if(n===void 0||n==="watches"){const c=[...a!=="in"?await Ze(i,r,o):[],...a!=="out"?await Ke(i,r,o):[]];for(const u of c)s.push({type:"watches",src:await g(i,u.watcher),dst:await g(i,u.object)})}return{items:s}})}l(_t,"edges");const W=l(e=>async t=>({status:200,body:await e(t)}),"ok"),Zt=[{method:"POST",pattern:"/v1/objects/search",handler:W(dt)},{method:"GET",pattern:"/v1/objects/:ref/edges",handler:W(_t)},{method:"POST",pattern:"/v1/objects/:ref/watch",handler:W(ht)},{method:"DELETE",pattern:"/v1/objects/:ref/watch",handler:W(gt)},{method:"GET",pattern:"/v1/objects/:ref",handler:W(st)},{method:"GET",pattern:"/v1/objects",handler:W(ft)}];export{ut as listBudget,Zt as objectRoutes};
|
|
3
|
+
WHERE w.watcher = ? AND w.object = ?`).get(t.id,n.id)).n,"count"),r=await i();await Be(e,t,n,a??void 0);const o=await i();return o===0&&await Qe(e,t,n),{object:await g(e,n),removed:r-o}}l(Se,"dropWatch");async function gt(e){const t=O(e);if(e.query.get("watcher")&&await Re(t),!e.query.get("watcher")){const a=await x(e,t,{method:"DELETE",path:`${V(t)}/watch`,query:H(e)});if(a.kind==="unknown")throw we(t,a.unreachable);if(a.kind==="remote"){const i=a.status===404?a.body.error?.details:void 0,r=i?.deleted===!0?i.id:void 0;if(a.status>=400&&r===void 0)throw z(a.status,a.body);const o=r??a.body.object?.id,s=await v(async c=>{const u=await le(c,e),f=o===void 0?null:await I(c,o);return u===null||f===null||!await X(c,f)?null:await Se(c,u,f,e.query.get("pattern"))});if(r!==void 0){if(s===null)throw z(a.status,a.body);return{...s,machine:a.machine}}return Y(a.body,a.machine)}}const n=await qe(await N(),e.query.get("watcher")??void 0,e.query.get("watcher_machine")??void 0);return await jt(e,n)}l(gt,"unwatchRoute");async function jt(e,t=null){const n=e.query.get("pattern"),a=e.query.get("watcher");return await R(e.principal),await v(async i=>{if((e.publishToken||e.principal.class==="anonymous")&&!a)throw new y(404,"not_found","watcher not found");const r=l(async(c,u)=>await Se(i,c,u,n),"drop");if(a){const c=t===null?null:await(async()=>{const f=await I(i,a);return f!==null&&await tt(i,f)!==null?f:null})();if(t!==null&&c===null)return E();const u=c??(e.publishToken?await oe(i,a):await ne(i,a));return u===null?E():c===null&&await Ie(i,e,u)?(await se(i,e,u),await J(i,e,u),await r(u,await S(i,await C(i,u),O(e)))):await r(u,(await Ne(i,e,u,O(e))).object)}const o=await T(i,e),s=await Q(i,e)??ae(o);return await r(s,await S(i,o,O(e)))})}l(jt,"unwatchLocal");async function _t(e){const t=[],n=ee(e.query.get("type"),"type",["acted-on","links-to","watches"],t),a=ee(e.query.get("direction"),"direction",["out","in"],t);return t.length>0&&U("edges request",t),await R(e.principal),await v(async i=>{const r=await T(i,e),o=await S(i,r,O(e)),s=[];if(n!=="watches")for(const c of await Ge(i,r,o,{...n?{type:n}:{},direction:a??"both"}))s.push({type:c.type,src:await g(i,c.src),dst:await g(i,c.dst),...c.written_as?{written_as:c.written_as}:{}});if(n===void 0||n==="watches"){const c=[...a!=="in"?await Ze(i,r,o):[],...a!=="out"?await Ke(i,r,o):[]];for(const u of c)s.push({type:"watches",src:await g(i,u.watcher),dst:await g(i,u.object)})}return{items:s}})}l(_t,"edges");const W=l(e=>async t=>({status:200,body:await e(t)}),"ok"),Zt=[{method:"POST",pattern:"/v1/objects/search",handler:W(dt)},{method:"GET",pattern:"/v1/objects/:ref/edges",handler:W(_t)},{method:"POST",pattern:"/v1/objects/:ref/watch",handler:W(ht)},{method:"DELETE",pattern:"/v1/objects/:ref/watch",handler:W(gt)},{method:"GET",pattern:"/v1/objects/:ref",handler:W(st)},{method:"GET",pattern:"/v1/objects",handler:W(ft)}];export{ut as listBudget,Zt as objectRoutes,ot as resolvedLocally};
|
|
@@ -9,6 +9,6 @@ export interface BootMigration {
|
|
|
9
9
|
* time (idempotent via its own convergence, not a version gate) and must
|
|
10
10
|
* isolate its own per-item failures — a thrown error here is NOT caught by
|
|
11
11
|
* the boot sequence and would abort daemon startup. */
|
|
12
|
-
apply(): BootMigrationResult
|
|
12
|
+
apply(): BootMigrationResult | Promise<BootMigrationResult>;
|
|
13
13
|
}
|
|
14
14
|
export declare const BOOT_MIGRATIONS: readonly BootMigration[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var o=Object.defineProperty;var r=(e,t)=>o(e,"name",{value:t,configurable:!0});import{migrateLegacyInboxIdentities as i}from"../core/feed/inbox-migrate.js";import{backfillComputedRev as a}from"../core/grants/mirror.js";import{isCloudRole as s}from"../core/canvas/person-state.js";import{emitEvent as n}from"../core/events/emit.js";const u=[{id:"legacy-inbox-identities",description:"normalize pre-cutover inbox entry/operation ids (UUID-spelled or missing) and cursors (ISO-timestamp boundaries) into canonical 32-lowercase-hex identities the strict inbox reader requires.",apply:r(()=>{const e=i();return{changed:e.nodes>0||e.failures>0,summary:{...e}}},"apply")},{id:"grant-computed-rev",description:"mark grant rows a pre-C-D2 build wrote (scopes computed, computed_rev NULL) as computed for their revision, so the terminal grant reads as active before the first directory sync after an upgrade or rollback (NL-550). A cloud role skips it: the directory owns its shared rows.",apply:r(async()=>{if(s())return{changed:!1,summary:{}};try{const e=await a();return{changed:e>0,summary:{rows:e}}}catch(e){return n({level:"warn",event:"daemon.boot_migration.failed",error:e,fields:{migration:"grant-computed-rev"}}),{changed:!1,summary:{}}}},"apply")}];export{u as BOOT_MIGRATIONS};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var S=Object.defineProperty;var i=(e,t)=>S(e,"name",{value:t,configurable:!0});import{randomUUID as w}from"node:crypto";import{setTimeout as L}from"node:timers/promises";import{CRON_DEATH_POLL_MS as R,CRON_KILL_GRACE_MS as C,EMPTY_STDOUT_SHA256 as h}from"./capture.js";import{cronDaemonInstanceId as A,cronOwnerAlive as v,ensureCronOwnerLease as O}from"./live-runs.js";import{crashedOneShotSummary as x,escalateFailure as E}from"./escalation.js";import{settleRun as p}from"./settle.js";import{adoptCronRunId as g,getCron as M,runningCrons as D,stopLeasedCronRun as I,setCronState as H,verifyLeasedCronRun as l}from"../../core/canvas/crons.js";import{claimReconcilerLease as T,releaseReconcilerLease as $,renewReconcilerLease as b}from"../../core/canvas/reconciler-leases.js";import{emitEvent as c}from"../../core/events/emit.js";const _="cron-recovery",f=3e4;async function k(e){const t=w();if(await T(_,e,t,f)===void 0)return;let r=!1;const a=i(async()=>{if(r)return!1;try{r=!await b(_,e,t,f)}catch{r=!0}return!r},"holds"),n=setInterval(()=>{a()},f/3);return n.unref(),{holds:a,release:i(async()=>{clearInterval(n),await $(_,e,t)},"release")}}i(k,"claimRecovery");async function G(e){const t=await M(e.cron_id);if(t===null||t.run_state!=="running"||t.run_execution_id!==e.run_execution_id||t.run_started_at!==e.run_started_at||t.run_lease_owner!==e.run_lease_owner||t.run_lease_owner!==null&&await v(t.run_lease_owner))return null;if(t.run_execution_id!==null)return t;const r=w();return await g(t,r)?{...t,run_execution_id:r}:null}i(G,"reverifyAbandoned");async function W(e,t={}){await O();for(const r of await D()){if(r.run_lease_owner===A||r.run_lease_owner!==null&&await v(r.run_lease_owner))continue;const a=r.run_pid===null||!l(r);if(!a&&e-(r.run_started_at!=null?new Date(r.run_started_at).getTime():e)<r.run_timeout_s*1e3)continue;const n=await k(r.cron_id);if(n===void 0)continue;let o;try{o=await G(r)}catch(s){throw await n.release(),s}if(o===null){await n.release();continue}if(a){U(o,e,t,n);continue}K(o,e,t,n)}}i(W,"recoverStaleCronLeases");function K(e,t,r,a){const n=e.run_started_at!=null?new Date(e.run_started_at).getTime():t,o={runId:e.run_execution_id,startedAtIso:e.run_started_at??new Date(t).toISOString(),exitCode:-1,timedOut:!0,runTimeoutS:e.run_timeout_s,processErrorMessage:null,stdoutHead:"",stdoutSha256:h,stderrHead:`run timed out after ${e.run_timeout_s}s (recovered stale lease from a prior daemon instance)`},s=(async()=>{await a.holds()&&(await I(e),await N(e),await a.holds()&&await p(e,{outOfBand:!1,outcome:{kind:"disposed",ctx:o},record:{runId:o.runId,startedAtIso:o.startedAtIso,finishedAtMs:t,durationMs:t-n,exitCode:-1,stdoutHead:null,stderrHead:o.stderrHead},lease:{kind:"clear"}}))})().finally(()=>a.release());r.register?.(s),s.catch(u=>{c({level:"error",event:"cron.stale_lease.settle_failed",error:u,fields:{cron_id:e.cron_id}})})}i(K,"recoverTimedOutRun");async function N(e){if(!await y(e)&&(await I(e,"SIGKILL"),!await y(e)))throw new Error(`cron ${e.cron_id} run ${e.run_pid} survived SIGKILL`)}i(N,"awaitLeasedRunDeath");async function y(e){const t=Date.now()+C;for(;Date.now()<t;){if(!l(e))return!0;await L(R)}return!l(e)}i(y,"pollLeasedRunGone");function U(e,t,r,a){const n=e.recur==null,o=e.run_started_at!=null?new Date(e.run_started_at).getTime():t,s=e.run_pid===null?"the daemon life that claimed this run ended before its launch pid was recorded \u2014 the command may have started and its outcome is unknown":"the daemon life that owned this run ended before it settled \u2014 the process is gone and its outcome was never observed",u={runId:e.run_execution_id,startedAtIso:e.run_started_at??new Date(t).toISOString(),exitCode:null,timedOut:!1,runTimeoutS:e.run_timeout_s,processErrorMessage:s,stdoutHead:"",stdoutSha256:h,stderrHead:`run outcome unobserved: ${s}`},m=(async()=>{let d=`crashed: ${s}${n?"":" \u2014 the next occurrence is unaffected"}`;if(n){if(!await a.holds())return;if(await H(e.cron_id,"paused"),e.on_output==="silent")d=`crashed: ${s} \u2014 one-shot paused, not re-fired (silent: not escalated)`;else{if(!await a.holds())return;d=`crashed one-shot: ${await E(e,u,x(s))}`}}await a.holds()&&(await p(e,{outOfBand:!1,outcome:{kind:"stated",delivered:d,paused:n},record:{runId:u.runId,startedAtIso:u.startedAtIso,finishedAtMs:t,durationMs:Math.max(0,t-o),exitCode:null,stdoutHead:null,stderrHead:u.stderrHead},lease:"release"}),c({level:"warn",event:"cron.run.unobserved",fields:{cron_id:e.cron_id,name:e.name,one_shot:n}}))})().finally(()=>a.release());r.register?.(m),m.catch(d=>{c({level:"error",event:"cron.crashed_run.settle_failed",error:d,fields:{cron_id:e.cron_id}})})}i(U,"settleCrashedRun");export{W as recoverStaleCronLeases};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var p=Object.defineProperty;var c=(e,u)=>p(e,"name",{value:u,configurable:!0});import{consumeCron as w,recordCronRunLocked as _,releaseCronRunLease as y,setCronState as k}from"../../core/canvas/crons.js";import{withCanvasWrite as I}from"../../core/canvas/db.js";import{enqueueDaemonAction as b}from"../../core/canvas/daemon-actions.js";import{enqueueNodeMail as v}from"../../core/feed/messages.js";import{emitEvent as g}from"../../core/events/emit.js";import{narrowedNotice as C}from"./narrowed.js";import{disposeSettledRun as h}from"./disposition.js";function x(e){return typeof e=="object"&&(e.kind==="park"||e.kind==="redue")}c(x,"occurrenceStaysOwed");async function $(e,u){const{outOfBand:t,outcome:d,record:
|
|
1
|
+
var p=Object.defineProperty;var c=(e,u)=>p(e,"name",{value:u,configurable:!0});import{consumeCron as w,recordCronRunLocked as _,releaseCronRunLease as y,setCronState as k}from"../../core/canvas/crons.js";import{withCanvasWrite as I}from"../../core/canvas/db.js";import{enqueueDaemonAction as b}from"../../core/canvas/daemon-actions.js";import{enqueueNodeMail as v}from"../../core/feed/messages.js";import{emitEvent as g}from"../../core/events/emit.js";import{narrowedNotice as C}from"./narrowed.js";import{disposeSettledRun as h}from"./disposition.js";function x(e){return typeof e=="object"&&(e.kind==="park"||e.kind==="redue")}c(x,"occurrenceStaysOwed");async function $(e,u){const{outOfBand:t,outcome:d,record:r,lease:s}=u;let i,a,n;if(d.kind==="disposed"){const o=await h(e,d.ctx,t,d.selfCanceled??!1);i=o.delivered,a=o.paused,n=o.obligation}else if(d.kind==="refused"){i=`refused: ${d.reason}`;const o=!t&&d.reason==="scope_narrowed";a=!t&&(e.recur==null||o),a&&await k(e.cron_id,"paused"),o&&(n=await C(e,d.message)),g({level:"warn",event:"cron.fire.refused",fields:{cron_id:e.cron_id,execution_id:r.runId,grant_id:e.grant_id,reason:d.reason,out_of_band:t}})}else i=d.delivered,a=d.paused??!1;const m=await I(async o=>{if(n!==void 0){if(n.kind==="node"){const f=await v(n.destinationNodeId,{kind:"message",label:n.label,senderNodeId:n.senderNodeId,bodyJson:{body:n.stdout},urgency:n.urgency,wake:1,idempotencyKey:r.runId});d.kind!=="refused"&&(i=`delivered: ${f.deliveryId}`)}else if(n.kind==="action"){const f=await b({adapter:n.adapter,bodyJson:n.bodyJson,idempotencyKey:r.runId});d.kind!=="refused"&&(i=`delivered: ${f}`)}}const l={run_id:r.runId,cron_id:e.cron_id,started:r.startedAtIso,finished:new Date(r.finishedAtMs).toISOString(),duration_ms:r.durationMs,exit_code:r.exitCode,stdout_head:r.stdoutHead,stderr_head:r.stderrHead,delivered:i};return await _(o,l),l});return s!=="none"&&await y(e.cron_id,r.runId,s==="release"?void 0:s),!t&&e.recur==null&&!a&&!x(s)&&await w(e.cron_id),m}c($,"settleRun");export{$ as settleRun};
|
package/dist/daemon/cron-run.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var N=Object.defineProperty;var i=(e,t)=>N(e,"name",{value:t,configurable:!0});import{randomUUID as Y}from"node:crypto";import{CRON_OUTPUT_HEAD_BYTES as E,EMPTY_STDOUT_SHA256 as q,formatCronOutputHead as A}from"./cron/capture.js";import{clearLiveRun as g,cronDaemonInstanceId as L,ensureCronOwnerLease as J,registerLiveRun as V}from"./cron/live-runs.js";import{closeCronExecution as X,openCronExecution as z}from"./cron/run-socket.js";import{appProcessSandboxed as G}from"../core/spaces/process.js";import{nodeAgentDir as K}from"../core/canvas/paths.js";import{uidForApp as Q}from"../core/spaces/users.js";import{buildArmedRunContext as W}from"./cron/armed-context.js";import{ensureCronFolder as Z}from"./cron/folders.js";import{checkCronFire as j,cronPrincipalOf as ee}from"./cron/authority.js";import{refusalError as te}from"../core/ledger/index.js";import{startRefusal as re}from"../core/runtime/start-check.js";import{decideHeldSettle as ne,EXIT_HELD as oe,HELD_DELIVERED as ae}from"./cron/held.js";import{settleRun as O}from"./cron/settle.js";import{applyOverlapPolicies as se,expireDueCrons as de}from"./cron/passes.js";import{dueClockCrons as ie,acquireCronRunLease as le,releaseCronRunLease as ue,attachCronRunPid as ce,advanceCron as fe,setCronState as me}from"../core/canvas/crons.js";import{emitEvent as $}from"../core/events/emit.js";import{runAppCommand as pe}from"../core/runtime/run-command.js";import{nextSlotAfter as he}from"../core/wake.js";import{CRON_OUTPUT_HEAD_BYTES as Ye}from"./cron/capture.js";import{cronDaemonInstanceId as Je,markSelfCanceledCronRun as Ve}from"./cron/live-runs.js";import{recoverStaleCronLeases as ze}from"./cron/lease-recovery.js";async function we(e,t){const{runId:
|
|
2
|
-
${F}`.trim().slice(0,E)},lease:"release"}).then(d,
|
|
1
|
+
var N=Object.defineProperty;var i=(e,t)=>N(e,"name",{value:t,configurable:!0});import{randomUUID as Y}from"node:crypto";import{CRON_OUTPUT_HEAD_BYTES as E,EMPTY_STDOUT_SHA256 as q,formatCronOutputHead as A}from"./cron/capture.js";import{clearLiveRun as g,cronDaemonInstanceId as L,ensureCronOwnerLease as J,registerLiveRun as V}from"./cron/live-runs.js";import{closeCronExecution as X,openCronExecution as z}from"./cron/run-socket.js";import{appProcessSandboxed as G}from"../core/spaces/process.js";import{nodeAgentDir as K}from"../core/canvas/paths.js";import{uidForApp as Q}from"../core/spaces/users.js";import{buildArmedRunContext as W}from"./cron/armed-context.js";import{ensureCronFolder as Z}from"./cron/folders.js";import{checkCronFire as j,cronPrincipalOf as ee}from"./cron/authority.js";import{refusalError as te}from"../core/ledger/index.js";import{startRefusal as re}from"../core/runtime/start-check.js";import{decideHeldSettle as ne,EXIT_HELD as oe,HELD_DELIVERED as ae}from"./cron/held.js";import{settleRun as O}from"./cron/settle.js";import{applyOverlapPolicies as se,expireDueCrons as de}from"./cron/passes.js";import{dueClockCrons as ie,acquireCronRunLease as le,releaseCronRunLease as ue,attachCronRunPid as ce,advanceCron as fe,setCronState as me}from"../core/canvas/crons.js";import{emitEvent as $}from"../core/events/emit.js";import{runAppCommand as pe}from"../core/runtime/run-command.js";import{nextSlotAfter as he}from"../core/wake.js";import{CRON_OUTPUT_HEAD_BYTES as Ye}from"./cron/capture.js";import{cronDaemonInstanceId as Je,markSelfCanceledCronRun as Ve}from"./cron/live-runs.js";import{recoverStaleCronLeases as ze}from"./cron/lease-recovery.js";async function we(e,t){const{runId:o,outOfBand:s,startedAtIso:u,finishedAtMs:c,code:d,timedOut:r,processError:m}=t,a=!s&&!r&&m==null&&d===oe&&!t.wasReplaced&&!t.wasSelfCanceled;let p,w;return t.wasReplaced?(p={kind:"stated",delivered:"replaced (overlap=replace)"},w="release"):a?(p={kind:"stated",delivered:ae},w=await ne(e,u,c)??"release"):(p={kind:"disposed",ctx:{runId:o,startedAtIso:u,exitCode:r?-1:d,timedOut:r,runTimeoutS:e.run_timeout_s,processErrorMessage:m!=null?m.message:null,stdoutHead:t.stdoutHead,stdoutSha256:t.stdoutSha256,stderrHead:t.stderrHead},selfCanceled:t.wasSelfCanceled},w=s?"release":{kind:"clear"}),O(e,{outOfBand:s,outcome:p,record:{runId:o,startedAtIso:u,finishedAtMs:c,durationMs:c-t.startedAtMs,exitCode:r?-1:d,stdoutHead:t.stdoutHead===""?null:t.stdoutHead,stderrHead:m!=null?`run process error: ${m.message}`.slice(0,E):t.stderrHead===""?null:t.stderrHead},lease:w})}i(we,"settleClosedRun");function R(e,t,o,s){const u=Date.now(),c=`${o}: ${s.message}`.slice(0,E);return O(e,{outOfBand:t.outOfBand,outcome:{kind:"disposed",ctx:{runId:t.runId,startedAtIso:t.startedAtIso,exitCode:null,timedOut:!1,runTimeoutS:e.run_timeout_s,processErrorMessage:s.message,stdoutHead:"",stdoutSha256:q,stderrHead:c}},record:{runId:t.runId,startedAtIso:t.startedAtIso,finishedAtMs:u,durationMs:u-t.startedAtMs,exitCode:null,stdoutHead:null,stderrHead:c},lease:"release"})}i(R,"settleUnspawnedRun");async function P(e,t){let o;try{o=he(e.recur,new Date(t))}catch(s){return $({level:"error",event:"cron.recur.unparseable",error:s,fields:{cron_id:e.cron_id,name:e.name,recur:e.recur}}),await me(e.cron_id,"paused"),new Error(`unparseable recurrence ${JSON.stringify(e.recur)}: ${s.message} \u2014 this cron cannot be rescheduled until its recurrence is fixed (\`crtr cron cancel\` and re-arm it), so it has been paused.`)}return await fe(e.cron_id,o),null}i(P,"advanceRecurrence");function Be(e,t){return B(e,t).settled}i(Be,"executeCron");function B(e,t){const{outOfBand:o}=t;let s=i(()=>{},"admit");const u=new Promise(d=>{s=d}),c=new Promise((d,r)=>{let m=!1;const a=Y();let p=i(()=>{},"undo");const w=i(f=>{if(p(),!m){r(f);return}m=!1,ue(e.cron_id,a).then(()=>r(f),h=>{$({level:"error",event:"cron.lease.release_failed",error:h,fields:{cron_id:e.cron_id}}),r(f)})},"fail");(async()=>{const f=Date.now(),h=new Date(f).toISOString(),S={runId:a,outOfBand:o,startedAtIso:h,startedAtMs:f};if(await J(),!await le(e.cron_id,L,h,o,a)){d(null);return}m=!0;let _=await j(ee(e));if(_.allowed){const n=await re({grantee:e.grantee,sub:e.sub,grant_id:e.grant_id});n!==null&&(_={allowed:!1,reason:"limit_reached",message:te(n).message})}if(!_.allowed){try{if(!o&&e.recur!=null){const C=await P(e,f);if(C!==null)throw C}}catch(C){R(e,S,"run could not be armed",C).then(d,r);return}const n=Date.now();O(e,{outOfBand:o,outcome:{kind:"refused",reason:_.reason,message:_.message},record:{runId:a,startedAtIso:h,finishedAtMs:n,durationMs:n-f,exitCode:null,stdoutHead:null,stderrHead:`${_.reason}: ${_.message}`.slice(0,E)},lease:"release"}).then(d,r);return}let M;try{if(e.isolated&&Z(e.grantee,e.cron_id),{env:M}=await W(e,a),!o&&e.recur!=null){const n=await P(e,f);if(n!==null)throw n}}catch(n){R(e,S,"run could not be armed",n).then(d,r);return}let b=null,T=!1;const D={runId:a,replaced:!1,selfCanceled:!1,kill:i(()=>{b!==null?b():T=!0},"kill")};V(e.cron_id,D),p=i(()=>g(e.cron_id,a),"undo"),s();const x=G()?{executionId:a,kind:"cron",cronId:e.cron_id,fromExec:e.armed_from_exec,grantee:e.grantee,sub:e.sub,grantId:e.grant_id,scopes:e.scopes,originRunId:e.origin_run_id,isolated:e.isolated,anchor:e.anchor_node,uid:await Q(e.grantee),rebuilt:!1,refusal:null}:null,I=i(()=>{x!==null&&X(a)},"closeExecution");p=i(()=>{g(e.cron_id,a),I()},"undo"),i(async()=>(x!==null&&await z(x,e.cwd,e.profile),pe({command:e.command,cwd:e.cwd,env:M,app:e.grantee,isolated:e.isolated,principal:{sub:e.sub,grantId:e.grant_id,scopes:e.scopes},...e.isolated?{folder:e.cwd}:{},...x!==null?{cron:{executionId:a,...e.anchor_node===null||e.isolated?{}:{anchorDir:K(e.anchor_node,e.grantee)}}}:e.anchor_node===null||e.isolated?{}:{nodeId:e.anchor_node},timeoutMs:e.run_timeout_s*1e3,headBytes:E})),"launch")().then(async n=>{if(n.pid===null){g(e.cron_id,a),I(),n.completion.then(l=>{R(e,S,"run failed to spawn",l.processError??new Error("bash did not provide a process id")).then(d,r)},r);return}p=i(()=>{g(e.cron_id,a),I(),n.terminate()},"undo");let C=!1;const v=i(()=>{n.completion.then(l=>{const k=D.replaced,U=D.selfCanceled,H=x?.refusal??null;if(g(e.cron_id,a),I(),C){d(null);return}if(H!==null&&!k){const y=Date.now(),F=A(l.stderr,l.stderrTruncated);O(e,{outOfBand:o,outcome:{kind:"refused",reason:H.reason,message:H.message},record:{runId:a,startedAtIso:h,finishedAtMs:y,durationMs:y-f,exitCode:l.exitCode,stdoutHead:A(l.stdout,l.stdoutTruncated)||null,stderrHead:`${H.reason}: ${H.message}
|
|
2
|
+
${F}`.trim().slice(0,E)},lease:"release"}).then(d,r);return}we(e,{runId:a,outOfBand:o,startedAtIso:h,startedAtMs:f,finishedAtMs:Date.now(),code:l.exitCode,timedOut:l.timedOut,processError:l.processError,stdoutHead:A(l.stdout,l.stdoutTruncated),stderrHead:A(l.stderr,l.stderrTruncated),stdoutSha256:l.stdoutSha256,wasReplaced:k,wasSelfCanceled:U}).then(d,r)},r)},"settleCommand");if(!await ce(e.cron_id,L,h,n.pid)&&!D.selfCanceled){C=!0,n.terminate(),v();return}b=n.terminate,T&&n.terminate(),v()},n=>{g(e.cron_id,a),I(),R(e,S,"run failed to spawn",n).then(d,r)}).catch(w)})().catch(w)});return c.then(s,s),{admitted:u,settled:c}}i(B,"startCron");async function Ue(e,t={}){const o=new Date(e).toISOString();await de(o),await se(e,o);const s=[];for(const u of await ie(o)){const{admitted:c,settled:d}=B(u,{outOfBand:!1}),r=d.then(()=>{});r.catch(()=>{}),await c,s.push(r),t.register?.(r)}for(const u of s)u.catch(()=>{});return s}i(Ue,"runDueCrons");export{Ye as CRON_OUTPUT_HEAD_BYTES,Je as cronDaemonInstanceId,Be as executeCron,Ve as markSelfCanceledCronRun,ze as recoverStaleCronLeases,Ue as runDueCrons,B as startCron};
|
package/dist/daemon/crtrd.js
CHANGED
|
@@ -15,4 +15,4 @@ ${o}
|
|
|
15
15
|
`),process.exit(1)}try{process.platform==="linux"&&b(x)&&(await L({operation:"daemon.handover"}),process.exit(0)),process.pid===1&&await It();const r=await xt({waitForJoinLock:!0});_.fresh(()=>{u({level:"info",event:"daemon.handover.completed",fields:{predecessor_pid:process.pid,successor_pid:r.pid??r.existing_pid??null,spawned:r.started}})})}catch(r){_.fresh(()=>{u({level:"error",event:"daemon.handover.successor_failed",error:r})});const o=r instanceof Error?r.message:String(r);process.stderr.write(`[crtrd] handover successor failed to start: ${o}
|
|
16
16
|
`),process.exit(1)}process.exit(0)}i(Ke,"performHandover");function I(){if(P!==void 0)return P;const r=We();return P=r,r.then(()=>{P===r&&(P=void 0)},()=>{P===r&&(P=void 0)}),r}i(I,"requestCleanup");async function Ve(){S={phase:"initializing",message:Cn,blockerPaths:[]},D!==void 0&&!H&&(H=!0,await D.close({graceMs:Tn}))}i(Ve,"drainApi");async function we(r){try{r==="SIGTERM"&&e.role==="api"&&await Ve(),await I(),await Bt({claimed:i(async()=>{try{return m&&await At()}finally{await le()}},"claimed")}),process.exit(0)}catch(o){process.exitCode=1;const h=o instanceof Error?o.stack??`${o.name}: ${o.message}`:String(o);process.stderr.write(`[crtrd] ${r} cleanup failed:
|
|
17
17
|
${h}
|
|
18
|
-
`),process.exit(1)}}i(we,"handleSignal");function he(){we("SIGINT")}i(he,"onSigint");function ve(){we("SIGTERM")}i(ve,"onSigterm");function ge(){I().catch(()=>{})}i(ge,"onExit");async function ie(r){k&&(B=B.then(r).then(()=>{},o=>{_.fresh(()=>{u({level:"error",event:"daemon.lane_job.failed",error:o})})}))}i(ie,"enqueue");async function W(){!k||Q||(He.check()&&E&&(u({level:"info",event:"daemon.resume.detected"}),R(E().catch(()=>{}))),Q=!0,await ie(async()=>{if(Q=!1,!!k)try{f||await Ft({log:l}),await xn(Date.now(),fe)}catch(r){_.fresh(()=>{u({level:"error",event:"daemon.tick.failed",error:r})})}}))}i(W,"enqueueTick");let G=null;async function Ye(){if(G!==null)throw{status:500,code:"admission_failed",message:`daemon admission previously failed: ${G instanceof Error?G.message:String(G)}`};if(S.phase==="ready")return{admitted:!1,already_admitted:!0,startup_phase:"ready"};if(S.phase!=="prepared"&&S.phase!=="recovering")throw{status:409,code:"not_prepared",message:S.message};const r=S.phase==="prepared";try{return await ae(),S={phase:"ready",message:"",blockerPaths:[]},r?{admitted:!0,already_admitted:!1,startup_phase:"ready"}:{admitted:!1,already_admitted:!0,startup_phase:"ready"}}catch(o){throw G=o,{status:500,code:"admission_failed",message:`daemon admission failed: ${o instanceof Error?o.message:String(o)}`}}}i(Ye,"admitStartup");async function Qe(r){if(C!==null)throw{status:409,code:"migration_in_progress",message:`the canvas import is already running (${C})`};C="repair";try{const o=await en({dryRun:r.dryRun});if(r.dryRun||o.pending||S.phase!=="blocked")return{result:o,resumed:!1};if(e.prepare)return S={phase:"prepared",message:"daemon storage is prepared and normal services are unavailable until admission",blockerPaths:[]},{result:o,resumed:!1};try{return await ae(),S={phase:"ready",message:"",blockerPaths:[]},{result:o,resumed:!0}}catch(h){const s=h instanceof Error?h.message:String(h);return setTimeout(()=>{I().catch(()=>{})},1e3),{result:o,resumed:!1,resumeError:s}}}finally{C=null}}i(Qe,"repairMigrations");async function Xe(){Y=e.intervalMs??Vr;const r=g.token;T=new Kt({epoch:r,enqueue:ie}),kt(T),S={phase:"recovering",message:"daemon startup recovery is running and normal services are unavailable",blockerPaths:[]},_.fresh(()=>{u({level:"info",event:"daemon.started",fields:{pid:process.pid,interval_ms:Y}})});const o=y;_.fresh(()=>{u({level:"info",event:"daemon.install_id.resolved",fields:{install_id:o}})});const h=await Tr(o);if(_.fresh(()=>{u({level:"info",event:"daemon.environment.registered",fields:{environment_id:h.environmentId,created:h.created}})}),_.fresh(()=>{let s;try{s=Kr()}catch{return}s!==null&&u({level:"warn",event:"daemon.startup.warning",fields:{stage:"termrender",warning:s.slice(0,2048)}})}),pt(),e.role!==void 0&&!process.env.CRTR_DIRECTORY_URL)throw new Error("CRTR_DIRECTORY_URL must be set on a cloud role (--role api|reconcile): it names the directory this deployment mints tokens against");if(e.role!==void 0&&Dr(),!V(e.role)){S={phase:"ready",message:"",blockerPaths:[]};return}if(await _.fresh(async()=>{await Jr(),await Ur(),await qr(Date.now()),await Wr(Date.now())}),await _.fresh(async()=>{const{reconcile:s,migrated:t}=await Tt(at);s.changed&&u({level:"info",event:"daemon.boot_change.reconciled",fields:{cleared_count:s.cleared.length,same_boot_proven:s.sameBootProven}}),t.length>0&&u({level:"info",event:"daemon.pid_identity.migrated",fields:{migrated_count:t.length}})}),await _.fresh(async()=>{for(const s of await Ie())s.status!=="active"||s.pi_pid!=null||s.frozen_at!=null||s.respawn_not_before!=null||(await xe(s.node_id,new Date().toISOString()),u({level:"warn",event:"daemon.startup.launch_debt_recorded",node_id:s.node_id}))}),await _.fresh(async()=>{await yt();for(const s of Yt){const t=s.apply();t.changed&&u({level:"info",event:"daemon.boot_migration.applied",fields:{migration:s.id,...t.summary}})}}),R(zr()),E){const s=i(()=>{R(E().catch(()=>{})),R(nr().then(t=>M?.observe(t)).then(()=>{},t=>{u({level:"warn",event:"daemon.peer.status_failed",error:t})}))},"refresh");R(jr().then(({completion:t})=>t).catch(t=>{u({level:"error",event:"daemon.grants.sweep_failed",error:t})})),s(),N=setInterval(s,Br*1e3),N.unref(),oe=tr({joined:!0,register:R})}await ie(async()=>{await Jt(),await Wt()}),j=setInterval(()=>{W().catch(s=>u({level:"error",event:"daemon.tick.failed",error:s}))},Y),X=await St(()=>{W().catch(s=>u({level:"error",event:"daemon.tick.failed",error:s}))}),Z=await F.subscribe(()=>{W().catch(s=>u({level:"error",event:"daemon.tick.failed",error:s}))},{kinds:["spend_limits"]}),await W()}i(Xe,"completeStartup");function ae(){return Ue??=Xe().catch(r=>{throw S={phase:"initializing",message:"daemon startup recovery failed and normal services are unavailable",blockerPaths:[]},r})}i(ae,"resumeStartup");try{process.on("SIGINT",he),process.on("SIGTERM",ve),process.on("exit",ge),Qt(),p!==null&&u({level:"info",event:"daemon.person.resolved",fields:{person_id:p.id,source:p.source}}),n!==null&&u({level:"info",event:"daemon.permissions.boot",fields:{...n}}),c!==null&&u({level:"info",event:"daemon.person.retired",fields:{person_id:c.person,joined_from:c.joinedFrom,retired:c.retired,columns:c.columns}}),$(e.role)&&(U=await dr());const r=g.token;Pt({epoch:r,requestHandover:Je,registerDetached:R,startupBlock:qe,admitStartup:Ye,repairMigrations:Qe}),Be(),D=$(e.role)?kr({tcp:e.tcp}):Dn(e),await D.ready;const o=lr()??se("user").document_port;if($(e.role)){const s=Er(o,Ir());try{await s.ready,re=s}catch(t){u({level:"warn",event:"daemon.document_listener.bind_failed",fields:{port:o,error:t instanceof Error?t.message:String(t)}})}}const h=se("user").runtime;if(h?.issuer&&(E=Fr(h.issuer,R),h.unsandboxed===!0&&(M=or({syncGrants:E}))),$(e.role)&&(te=await Gr()),ne=await Or({serves:$(e.role),runsLanes:V(e.role)}),h?.unsandboxed===!0&&h.listener!==void 0&&u({level:"warn",event:"daemon.app_listener.refused_unsandboxed",fields:{reason:"runtime.unsandboxed is set; runtime.listener is ignored"}}),$(e.role)&&h!==void 0&&h.listener!==void 0&&h.unsandboxed!==!0&&(A=await xr(h,async()=>await Hr(h.issuer.replace(/\/$/,"")),E),await A.ready),e.role===void 0)try{await Xt()}catch(s){if(C=null,s instanceof Zt)return S={phase:"blocked",message:s.message,blockerPaths:s.blockerPaths},I;throw s}process.platform==="linux"&&b(x)&&(wr(),await ur("app:terminal"));try{e.prepare?S={phase:"prepared",message:"daemon storage is prepared and normal services are unavailable until admission",blockerPaths:[]}:(await ae(),S={phase:"ready",message:"",blockerPaths:[]})}finally{C=null}return I}catch(r){try{await I()}catch(o){throw new AggregateError([r,o],"daemon startup failed and cleanup also failed")}throw r}}i($n,"runDaemon");var Pi=$n;export{Tn as API_DRAIN_GRACE_MS,de as brokerCommandDeclaresCanvasHome,pe as brokerCommandEpoch,Pi as default,V as roleRunsLanes,$ as roleServesRequests,$n as runDaemon,xn as superviseTick,dn as teardownFleet};
|
|
18
|
+
`),process.exit(1)}}i(we,"handleSignal");function he(){we("SIGINT")}i(he,"onSigint");function ve(){we("SIGTERM")}i(ve,"onSigterm");function ge(){I().catch(()=>{})}i(ge,"onExit");async function ie(r){k&&(B=B.then(r).then(()=>{},o=>{_.fresh(()=>{u({level:"error",event:"daemon.lane_job.failed",error:o})})}))}i(ie,"enqueue");async function W(){!k||Q||(He.check()&&E&&(u({level:"info",event:"daemon.resume.detected"}),R(E().catch(()=>{}))),Q=!0,await ie(async()=>{if(Q=!1,!!k)try{f||await Ft({log:l}),await xn(Date.now(),fe)}catch(r){_.fresh(()=>{u({level:"error",event:"daemon.tick.failed",error:r})})}}))}i(W,"enqueueTick");let G=null;async function Ye(){if(G!==null)throw{status:500,code:"admission_failed",message:`daemon admission previously failed: ${G instanceof Error?G.message:String(G)}`};if(S.phase==="ready")return{admitted:!1,already_admitted:!0,startup_phase:"ready"};if(S.phase!=="prepared"&&S.phase!=="recovering")throw{status:409,code:"not_prepared",message:S.message};const r=S.phase==="prepared";try{return await ae(),S={phase:"ready",message:"",blockerPaths:[]},r?{admitted:!0,already_admitted:!1,startup_phase:"ready"}:{admitted:!1,already_admitted:!0,startup_phase:"ready"}}catch(o){throw G=o,{status:500,code:"admission_failed",message:`daemon admission failed: ${o instanceof Error?o.message:String(o)}`}}}i(Ye,"admitStartup");async function Qe(r){if(C!==null)throw{status:409,code:"migration_in_progress",message:`the canvas import is already running (${C})`};C="repair";try{const o=await en({dryRun:r.dryRun});if(r.dryRun||o.pending||S.phase!=="blocked")return{result:o,resumed:!1};if(e.prepare)return S={phase:"prepared",message:"daemon storage is prepared and normal services are unavailable until admission",blockerPaths:[]},{result:o,resumed:!1};try{return await ae(),S={phase:"ready",message:"",blockerPaths:[]},{result:o,resumed:!0}}catch(h){const s=h instanceof Error?h.message:String(h);return setTimeout(()=>{I().catch(()=>{})},1e3),{result:o,resumed:!1,resumeError:s}}}finally{C=null}}i(Qe,"repairMigrations");async function Xe(){Y=e.intervalMs??Vr;const r=g.token;T=new Kt({epoch:r,enqueue:ie}),kt(T),S={phase:"recovering",message:"daemon startup recovery is running and normal services are unavailable",blockerPaths:[]},_.fresh(()=>{u({level:"info",event:"daemon.started",fields:{pid:process.pid,interval_ms:Y}})});const o=y;_.fresh(()=>{u({level:"info",event:"daemon.install_id.resolved",fields:{install_id:o}})});const h=await Tr(o);if(_.fresh(()=>{u({level:"info",event:"daemon.environment.registered",fields:{environment_id:h.environmentId,created:h.created}})}),_.fresh(()=>{let s;try{s=Kr()}catch{return}s!==null&&u({level:"warn",event:"daemon.startup.warning",fields:{stage:"termrender",warning:s.slice(0,2048)}})}),pt(),e.role!==void 0&&!process.env.CRTR_DIRECTORY_URL)throw new Error("CRTR_DIRECTORY_URL must be set on a cloud role (--role api|reconcile): it names the directory this deployment mints tokens against");if(e.role!==void 0&&Dr(),!V(e.role)){S={phase:"ready",message:"",blockerPaths:[]};return}if(await _.fresh(async()=>{await Jr(),await Ur(),await qr(Date.now()),await Wr(Date.now())}),await _.fresh(async()=>{const{reconcile:s,migrated:t}=await Tt(at);s.changed&&u({level:"info",event:"daemon.boot_change.reconciled",fields:{cleared_count:s.cleared.length,same_boot_proven:s.sameBootProven}}),t.length>0&&u({level:"info",event:"daemon.pid_identity.migrated",fields:{migrated_count:t.length}})}),await _.fresh(async()=>{for(const s of await Ie())s.status!=="active"||s.pi_pid!=null||s.frozen_at!=null||s.respawn_not_before!=null||(await xe(s.node_id,new Date().toISOString()),u({level:"warn",event:"daemon.startup.launch_debt_recorded",node_id:s.node_id}))}),await _.fresh(async()=>{await yt();for(const s of Yt){const t=await s.apply();t.changed&&u({level:"info",event:"daemon.boot_migration.applied",fields:{migration:s.id,...t.summary}})}}),R(zr()),E){const s=i(()=>{R(E().catch(()=>{})),R(nr().then(t=>M?.observe(t)).then(()=>{},t=>{u({level:"warn",event:"daemon.peer.status_failed",error:t})}))},"refresh");R(jr().then(({completion:t})=>t).catch(t=>{u({level:"error",event:"daemon.grants.sweep_failed",error:t})})),s(),N=setInterval(s,Br*1e3),N.unref(),oe=tr({joined:!0,register:R})}await ie(async()=>{await Jt(),await Wt()}),j=setInterval(()=>{W().catch(s=>u({level:"error",event:"daemon.tick.failed",error:s}))},Y),X=await St(()=>{W().catch(s=>u({level:"error",event:"daemon.tick.failed",error:s}))}),Z=await F.subscribe(()=>{W().catch(s=>u({level:"error",event:"daemon.tick.failed",error:s}))},{kinds:["spend_limits"]}),await W()}i(Xe,"completeStartup");function ae(){return Ue??=Xe().catch(r=>{throw S={phase:"initializing",message:"daemon startup recovery failed and normal services are unavailable",blockerPaths:[]},r})}i(ae,"resumeStartup");try{process.on("SIGINT",he),process.on("SIGTERM",ve),process.on("exit",ge),Qt(),p!==null&&u({level:"info",event:"daemon.person.resolved",fields:{person_id:p.id,source:p.source}}),n!==null&&u({level:"info",event:"daemon.permissions.boot",fields:{...n}}),c!==null&&u({level:"info",event:"daemon.person.retired",fields:{person_id:c.person,joined_from:c.joinedFrom,retired:c.retired,columns:c.columns}}),$(e.role)&&(U=await dr());const r=g.token;Pt({epoch:r,requestHandover:Je,registerDetached:R,startupBlock:qe,admitStartup:Ye,repairMigrations:Qe}),Be(),D=$(e.role)?kr({tcp:e.tcp}):Dn(e),await D.ready;const o=lr()??se("user").document_port;if($(e.role)){const s=Er(o,Ir());try{await s.ready,re=s}catch(t){u({level:"warn",event:"daemon.document_listener.bind_failed",fields:{port:o,error:t instanceof Error?t.message:String(t)}})}}const h=se("user").runtime;if(h?.issuer&&(E=Fr(h.issuer,R),h.unsandboxed===!0&&(M=or({syncGrants:E}))),$(e.role)&&(te=await Gr()),ne=await Or({serves:$(e.role),runsLanes:V(e.role)}),h?.unsandboxed===!0&&h.listener!==void 0&&u({level:"warn",event:"daemon.app_listener.refused_unsandboxed",fields:{reason:"runtime.unsandboxed is set; runtime.listener is ignored"}}),$(e.role)&&h!==void 0&&h.listener!==void 0&&h.unsandboxed!==!0&&(A=await xr(h,async()=>await Hr(h.issuer.replace(/\/$/,"")),E),await A.ready),e.role===void 0)try{await Xt()}catch(s){if(C=null,s instanceof Zt)return S={phase:"blocked",message:s.message,blockerPaths:s.blockerPaths},I;throw s}process.platform==="linux"&&b(x)&&(wr(),await ur("app:terminal"));try{e.prepare?S={phase:"prepared",message:"daemon storage is prepared and normal services are unavailable until admission",blockerPaths:[]}:(await ae(),S={phase:"ready",message:"",blockerPaths:[]})}finally{C=null}return I}catch(r){try{await I()}catch(o){throw new AggregateError([r,o],"daemon startup failed and cleanup also failed")}throw r}}i($n,"runDaemon");var Pi=$n;export{Tn as API_DRAIN_GRACE_MS,de as brokerCommandDeclaresCanvasHome,pe as brokerCommandEpoch,Pi as default,V as roleRunsLanes,$ as roleServesRequests,$n as runDaemon,xn as superviseTick,dn as teardownFleet};
|