@north-light/cli 0.3.446 → 0.3.448
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/api/contract.d.ts +1 -1
- package/dist/api/contract.js +1 -1
- package/dist/api/dto/nodes.d.ts +5 -0
- package/dist/api/dto/objects.d.ts +33 -2
- package/dist/api/error-codes.d.ts +15 -0
- package/dist/api/error-codes.js +1 -1
- package/dist/clients/attach/viewer.js +578 -577
- package/dist/commands/canvas/list.js +3 -3
- package/dist/commands/canvas/read.js +4 -4
- package/dist/commands/node/inspect.js +8 -8
- package/dist/commands/sys/sync-shared.js +1 -1
- package/dist/commands/sys/update.js +1 -1
- package/dist/core/canvas/migrations.js +65 -31
- package/dist/core/feed/inbox.js +1 -1
- package/dist/core/graph/events.js +8 -8
- package/dist/core/graph/kinds/node.js +5 -5
- package/dist/core/graph/objects.js +8 -8
- package/dist/core/graph/reader.js +3 -3
- package/dist/core/graph/receivers.d.ts +2 -1
- package/dist/core/graph/receivers.js +5 -5
- package/dist/core/graph/spaces/app.js +1 -1
- package/dist/core/graph/types.d.ts +9 -1
- package/dist/core/peer/client.d.ts +2 -0
- package/dist/core/peer/client.js +1 -1
- package/dist/core/peer/directory.js +1 -1
- package/dist/core/peer/home.d.ts +40 -0
- package/dist/core/peer/home.js +2 -0
- package/dist/core/peer/ingest.d.ts +26 -0
- package/dist/core/peer/ingest.js +1 -0
- package/dist/core/peer/names.d.ts +3 -0
- package/dist/core/peer/names.js +1 -0
- package/dist/core/peer/outbox-store.d.ts +70 -0
- package/dist/core/peer/outbox-store.js +4 -0
- package/dist/core/peer/receiver.d.ts +8 -0
- package/dist/core/peer/receiver.js +1 -0
- package/dist/core/peer/stubs.d.ts +53 -0
- package/dist/core/peer/stubs.js +1 -0
- package/dist/core/peer/version.d.ts +2 -2
- package/dist/core/peer/version.js +1 -1
- package/dist/core/runtime/broker/inbox.js +1 -1
- package/dist/core/scoped-state/settings.js +1 -1
- package/dist/daemon/api/app-listener.js +9 -9
- package/dist/daemon/api/handlers/messages.js +2 -2
- package/dist/daemon/api/handlers/nodes.js +1 -1
- package/dist/daemon/api/handlers/objects.d.ts +4 -0
- package/dist/daemon/api/handlers/objects.js +2 -2
- package/dist/daemon/api/principal.d.ts +4 -4
- package/dist/daemon/api/principal.js +1 -1
- package/dist/daemon/api/sync-notice.d.ts +17 -0
- package/dist/daemon/api/sync-notice.js +1 -0
- package/dist/daemon/crtrd.js +8 -8
- package/dist/daemon/peer/forward.d.ts +69 -0
- package/dist/daemon/peer/forward.js +1 -0
- package/dist/daemon/peer/handlers.d.ts +6 -1
- package/dist/daemon/peer/handlers.js +1 -1
- package/dist/daemon/peer/local-ingress.d.ts +8 -0
- package/dist/daemon/peer/local-ingress.js +1 -0
- package/dist/daemon/peer/outbox.d.ts +38 -0
- package/dist/daemon/peer/outbox.js +1 -0
- package/dist/daemon/peer/relay-client.d.ts +35 -0
- package/dist/daemon/peer/relay-client.js +1 -0
- package/dist/daemon/peer/relay-protocol.d.ts +52 -0
- package/dist/daemon/peer/relay-protocol.js +1 -0
- package/dist/daemon/peer/relay-service.d.ts +26 -0
- package/dist/daemon/peer/relay-service.js +1 -0
- package/dist/shared/generated-context.d.ts +8 -0
- package/dist/shared/generated-context.js +4 -4
- package/dist/shared/inbox-entry-body.js +5 -5
- package/package.json +2 -2
- package/packages/crouter-identity/package.json +1 -1
- package/runtime.lock.json +12 -12
|
@@ -1,24 +1,24 @@
|
|
|
1
|
-
var X=Object.defineProperty;var s=(e,n)=>X(e,"name",{value:n,configurable:!0});import{randomUUID as $}from"node:crypto";import{createServer as
|
|
1
|
+
var X=Object.defineProperty;var s=(e,n)=>X(e,"name",{value:n,configurable:!0});import{randomUUID as $}from"node:crypto";import{createServer as F}from"node:http";import{Router as q}from"./router.js";import{OPERATIONS as G}from"./operations.js";import{errorCodes as L}from"../../api/error-codes.js";import{MINIMUM_RUNTIME_VERSION_HEADER as Y,RUNTIME_VERSION_HEADER as z,minimumRuntimeRefusal as Q}from"../../api/runtime-version.js";import{CONTRACT_HEADER as W,CONTRACT_LEVEL as U,REQUIRED_CONTRACT_HEADER as K,contractRefusal as Z}from"../../api/contract.js";import{crtrVersion as M}from"../../shared/crtr-version.js";import{decodeJwt as ee}from"jose";import{AppPrincipalResolver as te}from"./principal.js";import{runtimeOwner as ne,servePeer as re}from"../peer/ingress.js";import{applySyncNotice as ae}from"./sync-notice.js";import{ownMachineId as oe}from"../../core/peer/directory.js";import{handleRunOperation as se,integer as ie}from"./handlers/runs.js";import{parseLlmRequest as ue,runLlm as ce}from"../../core/llm/run.js";import{parseUsageMonth as de,usageFor as le}from"../../core/usage/ledger.js";import{capFields as fe}from"./handlers/llm.js";import{CONTROL_BODY_MAX_BYTES as me,MODEL_CONTEXT_BODY_MAX_BYTES as pe}from"../../core/llm/body-limits.js";import{RunError as d,runIsRunning as he}from"../../core/runs/operations.js";import{requireRun as H}from"./router.js";import{deferHead as _e}from"./deferred-head.js";import{readRunEvents as B,registerGrantStream as we,subscribeRunEvents as ye}from"../../core/runs/events.js";import{activeGrant as ve}from"../../core/grants/mirror.js";import{releaseGrantWaiters as ge}from"../../core/grants/watch.js";import{runNotices as Oe}from"../run-notices.js";import{handleVendorSignIn as Re,isVendorSignInPath as Ee}from"./vendor-signin.js";import{listAppProfiles as Se}from"./handlers/app-profiles.js";import{handleTransferDownload as Te,handleTransferOperation as Ae,TRANSFER_OPERATIONS as Ne}from"./handlers/transfer.js";import{handleQuestionOperation as be,QUESTION_OPERATIONS as Ce}from"./handlers/questions.js";import{vendorStatus as Ie}from"./handlers/vendor-status.js";import{handleMemoryOperation as Pe,MEMORY_OPERATIONS as Me}from"./handlers/memory.js";import{abortOnClose as He,callerFromApp as De,handleProviderOperation as ke,PROVIDER_OPERATIONS as xe,providerFailure as Je}from"./handlers/providers.js";function Le(e){return Object.prototype.hasOwnProperty.call(L,e)?L[e]:void 0}s(Le,"fixedRow");function Ue(e){const n=Le(e);return n?n.type:e==="stream_gap"||e==="provider_error"||e==="runtime_version_unsupported"?"invalid_request_error":"server_error"}s(Ue,"errorType");function Be(e){if(!e||typeof e!="object"||Array.isArray(e)||!("rate_limit"in e))return e;const{rate_limit:n,...a}=e;return a}s(Be,"appDetails");function I(e,n,a){const u=Be(e.details);return{error:{code:e.code,message:e.message,...u===void 0?{}:{details:u},type:Ue(e.code),...e.param?{param:e.param}:{},origin:"runtime",retryable:e.retryable||e.code==="stream_dropped",request_id:n,...a?{run_id:a}:{},...e.scope?{scope:e.scope}:{},...e.code==="unauthorized"?{user_action:"reconnect"}:{},...fe(e),...e.code==="all_routes_exhausted"?{retry_after_s:e.details.retry_after_s}:{}}}}s(I,"envelope");function je(e,n,a,u){const i=n instanceof d?n:new d(500,"server_failure","runtime request failed");if(n instanceof d||console.error("[app-listener]",n),e.headersSent&&!String(e.getHeader("Content-Type")??"").startsWith("text/event-stream")){e.destroy();return}if(e.headersSent){e.end(`event: error
|
|
2
2
|
data: ${JSON.stringify(I(i,a,u))}
|
|
3
3
|
|
|
4
|
-
`);return}e.writeHead(i.status,{"Content-Type":"application/json; charset=utf-8","Request-Id":a,"X-Content-Type-Options":"nosniff",...i.code==="all_routes_exhausted"?{"Retry-After":String(i.details.retry_after_s)}:{}}),e.end(JSON.stringify(I(i,a,u)))}s(je,"fail");function j(e){return Array.isArray(e)?e[0]:e}s(j,"headerValue");function Ve(e){if(!e?.startsWith("Bearer ")||e.length<=7)return!1;try{return typeof ee(e.slice(7)).machine_id=="string"}catch{return!1}}s(Ve,"isMachineBearer");function v(e,n,a){e.writeHead(n,{"Content-Type":"application/json; charset=utf-8"}),e.end(JSON.stringify(a))}s(v,"json");async function C(e,n=
|
|
4
|
+
`);return}e.writeHead(i.status,{"Content-Type":"application/json; charset=utf-8","Request-Id":a,"X-Content-Type-Options":"nosniff",...i.code==="all_routes_exhausted"?{"Retry-After":String(i.details.retry_after_s)}:{}}),e.end(JSON.stringify(I(i,a,u)))}s(je,"fail");function j(e){return Array.isArray(e)?e[0]:e}s(j,"headerValue");function Ve(e){if(!e?.startsWith("Bearer ")||e.length<=7)return!1;try{return typeof ee(e.slice(7)).machine_id=="string"}catch{return!1}}s(Ve,"isMachineBearer");function v(e,n,a){e.writeHead(n,{"Content-Type":"application/json; charset=utf-8"}),e.end(JSON.stringify(a))}s(v,"json");async function C(e,n=me){const a=[];let u=0;for await(const i of e){if(u+=i.length,u>n)throw new d(400,"invalid_request","request body too large");a.push(i)}if(u)try{return JSON.parse(Buffer.concat(a).toString("utf8"))}catch{throw new d(400,"invalid_request","invalid JSON body")}}s(C,"bodyOf");function Xe(e,n){const a=e.headers["last-event-id"]??n.get("after");if(Array.isArray(a))throw new d(400,"invalid_request","invalid cursor","after");return ie(a??null,"after",0,Number.MAX_SAFE_INTEGER,0)}s(Xe,"cursor");function $e(e){return`id: ${e.sequence_number}
|
|
5
5
|
event: ${e.type}
|
|
6
6
|
data: ${JSON.stringify(e)}
|
|
7
7
|
|
|
8
|
-
`}s($e,"frame");const
|
|
8
|
+
`}s($e,"frame");const Fe=6e4;function qe(e,n,a,u,i,w,g,A={}){H(u,a);let l=B(a,i);if(i>l.latest_sequence)throw new d(400,"invalid_request","cursor is beyond the run","after");if(i<l.latest_sequence&&(l.earliest_sequence===null||i<l.earliest_sequence-1))throw new d(409,"stream_gap","events have expired",void 0,{earliest_sequence:l.earliest_sequence,latest_sequence:l.latest_sequence});if(n.destroyed||e.destroyed)return n.destroy(),Promise.resolve();n.writeHead(200,{"Content-Type":g==="sse"?"text/event-stream":"application/x-ndjson","Cache-Control":"no-cache","X-Accel-Buffering":"no"}),g==="sse"?n.write(`: connected
|
|
9
9
|
|
|
10
|
-
`):n.flushHeaders();let E=i;const r=Oe().streamOpened(a);let t=!1,p=!1,_=!1,S;const y=new Promise(h=>{S=h}),f=s(()=>{t||(t=!0,r(E),clearInterval(T),clearInterval(x),
|
|
10
|
+
`):n.flushHeaders();let E=i;const r=Oe().streamOpened(a);let t=!1,p=!1,_=!1,S;const y=new Promise(h=>{S=h}),f=s(()=>{t||(t=!0,r(E),clearInterval(T),clearInterval(x),N(),R(),n.off("close",f),n.off("drain",O),n.end(),S())},"end"),O=s(()=>{_=!1,c()},"onDrain"),o=s(h=>{t||n.write(g==="sse"?`event: error
|
|
11
11
|
data: ${JSON.stringify(I(h,w,a))}
|
|
12
12
|
|
|
13
13
|
`:`${JSON.stringify({type:"error",...I(h,w,a)})}
|
|
14
|
-
`),f()},"error"),c=s(()=>{if(!(t||p)){p=!0;try{if(!m()){
|
|
15
|
-
`),E=h.sequence_number}}catch(h){o(h instanceof d?h:new d(500,"server_failure","stream failed"))}finally{p=!1}}},"flush"),
|
|
14
|
+
`),f()},"error"),c=s(()=>{if(!(t||p)){p=!0;try{if(!m()){b();return}if(H(u,a),l=B(a,E),l.backlog_count>1e3||l.backlog_bytes>32*1024*1024){o(new d(503,"stream_dropped","stream reader fell behind",void 0,{last_sequence:E}));return}for(const h of l.events){if(_)break;_=!n.write(g==="sse"?$e(h):`${JSON.stringify(h)}
|
|
15
|
+
`),E=h.sequence_number}}catch(h){o(h instanceof d?h:new d(500,"server_failure","stream failed"))}finally{p=!1}}},"flush"),b=s(()=>o(new d(401,"grant_revoked","grant is not active")),"revoked"),m=s(()=>"class"in u||ve(u.grant)!==null,"grantActive"),N=ye(a,c),R="class"in u?()=>{}:we(u.grant,b),T=setInterval(()=>{!t&&!_&&g==="sse"&&n.write(`: keepalive
|
|
16
16
|
|
|
17
|
-
`)},15e3),P=A.idleMs??
|
|
17
|
+
`)},15e3),P=A.idleMs??Fe,V=A.isRunning??he;let D=Date.now(),k=E;const x=setInterval(()=>{if(t||g!=="sse")return;const h=Date.now();let J=!0;try{J=V(a)}catch{}if(J||E!==k){D=h,k=E;return}h-D<P||_||(n.write(`event: idle
|
|
18
18
|
data: {}
|
|
19
19
|
|
|
20
|
-
`),f())},A.idleCheckMs??1e3);return x.unref(),n.on("drain",O),n.on("close",f),c(),y}s(
|
|
20
|
+
`),f())},A.idleCheckMs??1e3);return x.unref(),n.on("drain",O),n.on("close",f),c(),y}s(qe,"streamRunEvents");function At(e,n,a,u={}){const i=e.listener;if(!e.issuer||!e.audience||!i?.address||!Number.isInteger(i.port)||i.port<1||i.port>65535)throw new Error("runtime issuer, audience and listener address/port are required");if(["0.0.0.0","::","[::]"].includes(i.address))throw new Error("runtime listener must bind a specific address");const w=new te(e.issuer,e.audience,a,e.jwksUrl),g=new q,A=new Map;for(const r of G.filter(t=>t.stage!==void 0)){const t=s(()=>({status:500}),"handler");g.register({method:r.method,pattern:r.path,handler:t}),A.set(t,r)}const l=F((r,t)=>{(async()=>{_e(r,t,u.deferHead);const p=$();t.setHeader("Request-Id",p),t.setHeader(z,M()),t.setHeader(W,U);let _;try{const S=j(r.headers[Y.toLowerCase()]),y=Q(S,M())??Z(j(r.headers[K.toLowerCase()]),U,{legacyMinimum:S,runtimeVersion:M()});if(y!==null)throw y.status===400?new d(400,y.code,y.message,y.param):new d(426,y.code,y.message,void 0,y.details);const f=new URL(r.url??"/","http://runtime.local");if(Ee(f.pathname)){await Re(r,t,f,w);return}if(Ve(r.headers.authorization)){await re(r,t,{issuer:e.issuer,jwks:w.jwks,audience:s(()=>e.audience,"audience"),owner:ne,self:oe,ready:s(()=>w.isReady()&&n(),"ready")});return}if((r.method!=="GET"||f.pathname!=="/v1/health")&&(!w.isReady()||!n()))throw new d(503,"runtime_starting","runtime_starting");const O=g.match(r.method??"GET",f.pathname);if(!O)throw new d(404,"not_found","unknown operation");const o=A.get(O.handler);if(!o)throw new d(404,"not_found","unknown operation");if(_=O.params.run_id,o.name==="health"){v(t,200,{status:"ok",api_version:"2026-09-23"});return}if(o.name==="runtime.sync-notice"){await ae(await w.verifySyncNotice(r.headers.authorization),a,p),t.writeHead(204),t.end();return}if(o.name==="runtime.vendor-status"){await w.verifyDirectoryRead(r.headers.authorization,"vendor_status"),v(t,200,Ie());return}const c=await w.resolve(r.headers.authorization,o.scope);if(t.setHeader("Request-Id",p),_&&H(c,_,["run.message","run.interrupt","run.cancel","run.rename","run.delete"].includes(o.name),o.name==="run.delete"),o.stream==="bytes"){await Te(r,t,c,f.searchParams);return}if(o.stream){qe(r,t,_,c,Xe(r,f.searchParams),p,"sse",u.stream);return}if(o.name==="llm"){const m=ue(await C(r,pe)),N=new AbortController,R=s(()=>N.abort(),"abort");t.on("close",R);try{const T=await ce(m,N.signal,m.stream?P=>{t.headersSent||t.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache","X-Accel-Buffering":"no"}),t.write(`data: ${JSON.stringify(P)}
|
|
21
21
|
|
|
22
22
|
`)}:void 0,void 0,{grantee:c.grantee,spend_cap:c.spend_cap});m.stream?(t.headersSent||t.writeHead(200,{"Content-Type":"text/event-stream","Cache-Control":"no-cache","X-Accel-Buffering":"no"}),t.end(`data: [DONE]
|
|
23
23
|
|
|
24
|
-
`)):v(t,200,T.completion)}finally{t.off("close",R)}return}if(o.name==="usage.get"){v(t,200,
|
|
24
|
+
`)):v(t,200,T.completion)}finally{t.off("close",R)}return}if(o.name==="usage.get"){v(t,200,le(c.grantee,c.spend_cap,de(f.searchParams.get("month"))));return}if(o.name==="profile.list"){v(t,200,Se(c));return}if(Ce.has(o.name)){const m=await be(o.name,c,O.params.question_id,o.method==="POST"?await C(r):void 0);v(t,m.status,m.body);return}if(xe.has(o.name)){const{signal:m,release:N}=He(t);try{const R=await ke(o.name,De(c),{params:O.params,body:o.method==="POST"?await C(r):void 0,query:f.searchParams},{requestId:p,signal:m});v(t,R.status,R.body)}catch(R){const T=Je(R,p,!0);t.writeHead(T.status,{"Content-Type":"application/json; charset=utf-8","X-Content-Type-Options":"nosniff",...T.headers}),t.end(JSON.stringify(T.body))}finally{N()}return}if(Me.has(o.name)){const m=Pe(o.name,{class:"app",app:c.grantee,scopes:c.resolved},f.searchParams);v(t,m.status,m.body);return}if(Ne.has(o.name)){const m=await Ae(o,c,O.params,f.searchParams,await C(r));v(t,m.status,m.body);return}const b=await se(o,c,_,f.searchParams,await C(r),r.headers["idempotency-key"]);v(t,b.status,b.body)}catch(S){je(t,S,p,_)}})()});return{ready:new Promise((r,t)=>{l.once("error",t),l.listen(i.port,i.address,()=>{l.off("error",t),r()})}),close:s(async()=>{w.close(),ge(),l.closeAllConnections(),await new Promise((r,t)=>l.close(p=>p?t(p):r()))},"close")}}s(At,"createAppListener");export{Fe as RUN_STREAM_IDLE_MS,At as createAppListener,Xe as cursor,qe as streamRunEvents};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var
|
|
2
|
-
`)[0].slice(0,120)}
|
|
1
|
+
var de=Object.defineProperty;var u=(t,e)=>de(t,"name",{value:e,configurable:!0});import{randomBytes as ce}from"node:crypto";import{claimNodeMail as ue,acknowledgeNodeMail as le}from"../../../core/canvas/deliveries.js";import{nodeMailEntry as fe}from"../../../core/feed/inbox.js";import{enqueueNodeMail as J,cancelPendingNodeMail as me}from"../../../core/feed/messages.js";import{reviveNode as L}from"../../../core/runtime/revive.js";import{BrokerUnreachableError as U}from"../../../core/runtime/broker-request.js";import{isBrokerLive as R}from"../../../core/runtime/model-swap.js";import{deliverLive as pe,interruptLive as ye}from"../../../core/runtime/interactive-deliver.js";import{isProfilePaused as he}from"../../../core/profiles/manifest.js";import{getNode as A,withFreshTerminalGuard as be}from"../../../core/canvas/canvas.js";import{getById as D,nodeObject as F,ownerForGrantee as we}from"../../../core/graph/objects.js";import{recordActedOn as ge}from"../../../core/graph/edges.js";import{recordWatch as G}from"../../../core/graph/watches.js";import{publish as H}from"../../../core/graph/events.js";import{readerFor as V}from"../reader.js";import{canRead as ve}from"../../../core/graph/access.js";import{withCanvasWrite as _}from"../../../core/canvas/db.js";import{getPendingStructuredRequestForNode as K}from"../../../core/canvas/structured-requests.js";import{cancelCronsOnWake as Q}from"../../../core/canvas/crons.js";import{assertNotFinalized as M,assertFinalizedForReopen as _e,commitReopenResident as P}from"../../../core/runtime/reopen.js";import{admitLegacyStructuredOutput as ke}from"../../structured-requests/sidecar.js";import{appendSituationalContext as E,formatSituationalProse as Se}from"../../../core/runtime/situational-context.js";import{formatDataCard as X}from"../../../shared/generated-context.js";import{hasNoNaturalCycle as $e}from"../../../core/runtime/revive-all.js";import{recordPendingParkActivity as Ne}from"../../park-pending.js";import{wantsExecution as je}from"../../reconcilers/node-lifecycle/wants-execution.js";import{hasFreshGroundState as qe}from"../../../core/runtime/revive.js";import{CrtrError as xe,notFound as C,usage as c}from"../../../core/errors.js";import{emitEvent as Ae}from"../../../core/events/emit.js";import{assertScope as Ce}from"../../../core/scopes.js";import{InputError as I}from"../../../core/io.js";import{ApiError as Oe}from"../../../api/index.js";import{describeObject as Re,stubOf as Fe}from"../../../core/peer/stubs.js";import{machineNameOf as Y}from"../../../core/peer/names.js";import{callerNode as Me,callerStub as Pe,forwardVerb as Z,relayError as ee,remoteStub as Ee,unknownError as te,withMachine as re}from"../../peer/forward.js";import{ownerOnly as Ie}from"../router.js";const Te=["critical","urgent","normal","deferred"];function ne(t,e){if(typeof t!="object"||t===null||Array.isArray(t))throw c(`${e} must be an object { kind, facts?, body? }`);const i=t,n=i.kind;if(typeof n!="string"||n.trim()==="")throw c(`${e}.kind is required`);if(!n.includes(":"))throw c(`${e}.kind must be namespaced (contain ':'): ${n}`);const r={kind:n},o=i.facts;if(o!==void 0){if(typeof o!="object"||o===null||Array.isArray(o))throw c(`${e}.facts must be an object of string or number values`);const d={};for(const[f,m]of Object.entries(o)){if(typeof m!="string"&&typeof m!="number")throw c(`${e}.facts.${f} must be a string or number`);d[f]=m}r.facts=d}const s=i.body;if(s!==void 0){if(typeof s!="string")throw c(`${e}.body must be a string`);r.body=s}return r}u(ne,"parseCardRequest");function oe(t,e){try{return X(t.kind,t.facts??{},t.body??"")}catch(i){throw c(`${e}: ${i instanceof Error?i.message:String(i)}`)}}u(oe,"renderCard");function Be(t){if(typeof t!="object"||t===null)throw c("a message requires a JSON body { body, tier?, fresh? }");const e=t,i=e.body,n=e.fresh===!0,r=e.tier,o=e.situational_context,s=e.output_schema,d=typeof i=="string"&&i.trim()!=="",f=typeof o=="string"&&o.trim()!=="",m=typeof s=="string"&&s.trim()!=="",S=e.situational_card,g=e.context_cards,h=S===void 0?void 0:ne(S,"situational_card");if(g!==void 0&&!Array.isArray(g))throw c("context_cards must be an array of { kind, facts?, body? }");const p=g?.map((k,N)=>ne(k,`context_cards[${N}]`));if(h!==void 0&&typeof o=="string"&&o!=="")throw c("situational_card and situational_context are mutually exclusive");const $=h!==void 0||p!==void 0&&p.length>0;if(!n&&!d&&!f&&!m&&!$)throw c("a message requires a non-empty body (or fresh: true, situational_context, a runtime card, or output_schema)");if(n&&p!==void 0&&p.length>0)throw c("context_cards cannot ride a fresh revive (no inbox entry carries them)");if(r!==void 0&&!Te.includes(r))throw c(`invalid tier: ${String(r)} (expected critical|urgent|normal|deferred)`);const l={body:typeof i=="string"?i:""};r!==void 0&&(l.tier=r),n&&(l.fresh=!0),e.reopen===!0&&(l.reopen=!0),typeof o=="string"&&(l.situational_context=o),h!==void 0&&(l.situational_card=h),p!==void 0&&(l.context_cards=p),typeof s=="string"&&(l.output_schema=s),typeof e.from=="string"&&(l.from=e.from);const b=e.delivery;if(b!==void 0&&b!=="interactive")throw c(`invalid delivery: ${String(b)} (expected interactive)`);if(b==="interactive"){if(n||l.situational_context!==void 0||l.output_schema!==void 0)throw c("interactive delivery supports a body, runtime cards, and reopen only (no fresh, situational_context, or output_schema)");if(!d)throw c("interactive delivery requires a non-empty body");if(l.tier==="deferred")throw c("interactive delivery cannot be deferred");l.delivery="interactive"}return l}u(Be,"parseSendBody");function ze(t){try{return JSON.parse(t)}catch{throw c("output_schema must be a JSON schema string")}}u(ze,"parseSchema");function We(t){return t.split(`
|
|
2
|
+
`)[0].slice(0,120)}u(We,"label");function ie(t,e){return e===null?"":X("reopen-final-report",{report:`${t}/${e}`},"This node previously completed work. Read this final report before acting on the new instruction.")}u(ie,"previousFinalReportCard");function Je(t,e,i){if(i!==null&&i!=="human"&&D(t,i)?.type==="node"){const o=F(t,i);return{actor:o,senderNode:o}}if(i==="human")return{actor:we(t,"user:local"),senderNode:null};const n=V(t,e);return{actor:n.class==="person"?n.person:n.class==="app"?n.app:n.node,senderNode:n.class==="node"?n.node:null}}u(Je,"messageActor");function ae(t,e,i,n,r,o){const s=F(t,i),{actor:d,senderNode:f}=Je(t,e,n),m=r===null?{}:{pointer:r};ge(t,d,s),f!==null&&f.rowid!==s.rowid&&G(t,f,s,"message",{endsOn:o&&r!==null?`result:${r}`:"final"}),H(t,{event:"messaged",object:s,actor:d,attrs:{},...m}),f!==null&&H(t,{event:"sent",object:f,actor:f,attrs:{to:s.id},...m})}u(ae,"recordMessage");function Le(t,e){return new I({error:"deferred_no_natural_cycle",message:`${t} is ${e} with no natural next cycle ahead of it \u2014 a deferred message would never be delivered.`,next:"Use --tier normal, urgent, or critical to wake it now, or --reopen (with a body or --fresh) to re-task it first."})}u(Le,"deferredNoNaturalCycle");function Ue(t){if(!qe(t))throw new Oe(422,"unprocessable",`node ${t} has no goal/roadmap on disk \u2014 a fresh revive would resume amnesiac.`)}u(Ue,"assertRecoverableForFresh");function De(t,e){return t instanceof I?{error:t.payload.error,message:t.payload.message,next:t.payload.next,message_id:e}:t instanceof xe?{error:t.code,message:t.message,message_id:e}:{error:"wake_failed",message:"the target could not be woken; see the daemon log",message_id:e}}u(De,"wakeFailure");async function Ge(t,e){const i=typeof t.body=="object"&&t.body!==null&&!Array.isArray(t.body)?{...t.body}:t.body;typeof i=="object"&&i!==null&&delete i.from;const n=await Z(t,e,{method:"POST",path:`/v1/nodes/${encodeURIComponent(e)}/messages`,body:i});if(n.kind==="local")return null;if(n.kind==="unknown")throw te(e,n.unreachable);if(n.status>=400)throw ee(n.status,n.body);return _(r=>{const o=Me(r,t);if(o===null)return;const s=n.body?.object,d=Ee(r,e,"node",n.machine.id,s);G(r,o,d,"message",{endsOn:"final"})}),{status:n.status,body:re(n.body,n.machine)}}u(Ge,"forwardMessage");async function He(t){const e=await Ve(t);if(t.principal.class!=="forwarded"||typeof e.body!="object"||e.body===null)return e;const i=_(n=>{const r=F(n,t.params.id);return ve(n,V(n,t),r)?Re(n,r):{id:r.id,type:r.type,kind:null,name:r.id,owner:null}});return{...e,body:{...e.body,object:i}}}u(He,"handleMessage");async function Ve(t){const e=t.params.id,i=await Ge(t,e);if(i!==null)return i;const n=A(e);if(n===null)throw C(`unknown node: ${e}`,{received:e});const r=Be(t.body),o=r.tier??"normal",s=he(n.profile_id),d=t.principal.class==="forwarded"?_(a=>Pe(a,t)?.id??null):r.from??null;if(d!==null){const a=A(d);a!==null&&Ce(a,"crtr:act")}const f=d===null?null:_(a=>{const y=D(a,d);return y===null?null:Fe(a,y)?.home_machine??null}),m=f===null?void 0:`${d} on ${Y(f)}`,S=f===null?{}:{from_machine:Y(f)},g=r.body.trim()!=="",h=r.situational_card!==void 0?oe(r.situational_card,"situational_card"):r.situational_context!==void 0?Se(r.situational_context.trim()):"",p=h!=="",$=(r.context_cards??[]).map((a,y)=>oe(a,`context_cards[${y}]`)),l=r.output_schema!==void 0&&r.output_schema.trim()!==""?ze(r.output_schema):null;let b=!1;const k=u(a=>{if(!(l===null||b)){if(K(e)!==null)throw new I({error:"structured_request_conflict",message:`node ${e} already has a pending structured request`,next:"Wait for the current request to settle before requesting another structured result."});ke(e,"oneoff",l,a),b=!0}},"ensureSchema");if(r.fresh){const a=r.reopen?_e(e):null;r.reopen||M(e),Ue(e),k(),p&&E(e,h),r.reopen&&P(e,a);const y=await L(e,{resume:!1,capacity:"refuse"});return{status:201,body:{node_id:e,delivered:!1,revived:y.launch!==void 0}}}r.delivery==="interactive"&&!r.reopen&&M(e);let N=!1,v="";if(r.delivery==="interactive"&&r.reopen&&(v=ie(e,P(e)),N=!0),r.delivery==="interactive"&&k(),r.delivery==="interactive"&&!s&&!n.run_id&&R(n))try{return p&&E(e,h),await pe(e,r.body,{cards:[...v===""?[]:[v],...p?[h]:[],...$],origin:d==="human"?{type:"human"}:{type:"runtime",kind:"inbox",entries:[{...d===null?{}:{from:d},...m===void 0?{}:{fromName:m},kind:"message",tier:o}]}}),_(y=>ae(y,t,e,d,null,!1)),Q(e),{status:201,body:{node_id:e,delivered:!0,revived:!1,delivered_via:"engine"}}}catch(a){if(!(a instanceof U))throw a}const T=u(()=>{r.reopen||M(e);const a=ce(16).toString("hex"),y=u(x=>ae(x,t,e,d,a,l!==null),"withinEnqueue");k(a),p&&E(e,h),r.reopen&&!N&&(v=ie(e,P(e)));const O=[...v===""?[]:[v],...$],W=O.length>0?{cards:O}:{};if(g||l!==null){const x=g?r.body:`A one-off structured-output request has been granted. Submit a result matching the requested schema with the \`submit_result\` tool (\`request_id: "${K(e)?.request_id??"<request-id>"}"\`) before you stop; after it is accepted, continue normally.`;return J(e,{senderNodeId:d,...m===void 0?{}:{senderName:m},urgency:o,wake:1,kind:"message",messageId:a,withinEnqueue:y,label:We(x),bodyJson:{body:x,...S,...p?{situational:!0}:{},...W}})}return J(e,{senderNodeId:d,...m===void 0?{}:{senderName:m},urgency:o,wake:1,kind:"message",messageId:a,withinEnqueue:y,label:p?"(ambient context updated)":"(context delivered)",bodyJson:{...p?{situational:!0}:{},situationalOnly:!0,...W}})},"deliverImmediate"),w=u(()=>{if(o==="deferred"){const a=be(e,$e,T);if(a.kind==="missing")throw C(`unknown node: ${e}`,{received:e});if(a.kind==="terminal")throw Le(e,a.status);return a.result}return T()},"deliver")();w.urgency!=="deferred"&&_(()=>Ne(e));const j=A(e);if(j===null)throw C(`unknown node: ${e}`,{received:e});n.frozen_at!==null&&Q(e);let B=!1,z=!1,q;if((r.reopen||j.lifecycle==="terminal"||!je(j))&&w.urgency!=="deferred"&&!s&&!R(j))try{const a=await L(e,{resume:!0,capacity:"freeze"});B=a.launch!==void 0,z=a.outcome==="frozen"}catch(a){q=De(a,w.messageId),Ae({level:"error",event:"message.wake_failed",node_id:e,error:a,fields:{message_id:w.messageId,error_code:q.error}})}return{status:201,body:{node_id:e,delivered:!0,revived:B,...z?{not_revived_reason:"capacity_frozen"}:{},...q===void 0?{}:{wake_failed:q},delivered_at:w.createdAt,...w.urgency===o?{}:{delivered_tier:w.urgency},...r.delivery==="interactive"?{delivered_via:"inbox"}:{}}}}u(Ve,"handleMessageHere");async function Ke(t){const e=t.params.id,i=await Z(t,e,{method:"POST",path:`/v1/nodes/${encodeURIComponent(e)}/interrupt`,body:t.body});if(i.kind==="unknown")throw te(e,i.unreachable);if(i.kind==="remote"){if(i.status>=400)throw ee(i.status,i.body);return{status:i.status,body:re(i.body,i.machine)}}const n=A(e);if(n===null)throw C(`unknown node: ${e}`,{received:e});const r=me(e,{senderNodeId:"human",kind:"message"});let o=!1;if(R(n))try{o=await ye(e)!=="idle"}catch(d){if(!(d instanceof U))throw d}return{status:200,body:{node_id:e,outcome:o?"aborted_turn":r.length>0?"canceled_pending":"idle",aborted_turn:o,canceled_pending:r.length}}}u(Ke,"handleInterrupt");function se(t){if(typeof t.body!="object"||t.body===null||Array.isArray(t.body))throw c("mail requires an object body");const e=t.body;if(typeof e.execution_id!="string"||e.execution_id.trim()==="")throw c("execution_id is required");return e}u(se,"mailBody");function Qe(t){const e=se(t),i=e.channel;if(i!=="wake"&&i!=="passive"&&i!=="deferred_run")throw c("channel must be wake, passive, or deferred_run");const n=ue(t.params.id,e.execution_id,i);return{status:200,body:{action:n.action,deliveries:n.deliveries.map(o=>({delivery_id:o.deliveryId,attempts:o.attempts,handoff:o.handoff,entry:{...fe(o),seq:o.message.seq}}))}}}u(Qe,"handleMailClaim");function Xe(t){const e=se(t);if(!Array.isArray(e.deliveries))throw c("deliveries must be an array");const i=e.deliveries.map(o=>{if(typeof o!="object"||o===null||Array.isArray(o))throw c("each delivery must be an object");const s=o;if(typeof s.delivery_id!="string"||s.delivery_id==="")throw c("delivery_id is required");if(!Number.isSafeInteger(s.attempts)||s.attempts<1)throw c("attempts must be a positive integer");if(s.disposition!=="acknowledged"&&s.disposition!=="released")throw c("disposition must be acknowledged or released");return{delivery_id:s.delivery_id,attempts:s.attempts,disposition:s.disposition}}),n=le(t.params.id,e.execution_id,i.map(o=>({deliveryId:o.delivery_id,attempts:o.attempts,disposition:o.disposition})));return{status:200,body:{action:n.action,results:n.results.map(o=>({delivery_id:o.deliveryId,outcome:o.outcome}))}}}u(Xe,"handleMailAcknowledge");const Tt=Ie([{method:"POST",pattern:"/v1/nodes/:id/mail/claim",handler:Qe},{method:"POST",pattern:"/v1/nodes/:id/mail/acknowledge",handler:Xe}]),Bt=[{method:"POST",pattern:"/v1/nodes/:id/messages",scope:"crtr:act",handler:He},{method:"POST",pattern:"/v1/nodes/:id/interrupt",scope:"crtr:act",handler:Ke}];export{Tt as brokerMailRoutes,He as handleMessage,Bt as messageRoutes};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var Se=Object.defineProperty;var a=(e,t)=>Se(e,"name",{value:t,configurable:!0});import{prepared as X}from"../../../core/sqlite-statements.js";import{envProfileId as Re}from"../../../shared/env.js";import{pausedCanvasProfiles as Oe}from"../../../core/profiles/manifest.js";import{existsSync as A,realpathSync as Z,statSync as q}from"node:fs";import{isAbsolute as F,resolve as T}from"node:path";import{appendSituationalContext as Ie,formatSituationalProse as $e}from"../../../core/runtime/situational-context.js";import{closeNode as Ce}from"../../../core/runtime/close.js";import{reviveNode as Ne}from"../../../core/runtime/revive.js";import{nowIso as G}from"../../../core/fs-utils.js";import{assertLaunchModelRegistered as B,forkNode as Ae,resolveForkSource as Te,spawnChildPrepared as Pe}from"../../../core/runtime/spawn.js";import{forkSourceNode as Ee,newNodeId as ee}from"../../../core/runtime/nodes.js";import{abandonCreateRequest as ne,childrenOf as De,completeCreateRequest as te,findCreateRequest as Le,getNode as k,recordCreateRequestNode as je,reserveCreateRequest as oe,reserveCreateRequestNode as Me,listNodes as re,recordRespawnAttempt as Fe,subscribersOf as Ge,subscriptionsOf as ie,setMessageWait as Be,updateNode as N}from"../../../core/canvas/canvas.js";import{subtreeIds as xe}from"../../../core/canvas/nav-model.js";import{withCanvasWrite as x}from"../../../core/canvas/db.js";import{nodeObject as Ke}from"../../../core/graph/objects.js";import{recordActedOn as We}from"../../../core/graph/edges.js";import{publish as Ve}from"../../../core/graph/events.js";import{readerFor as ze}from"../reader.js";import{relocateSessionCwd as Je,unbindSession as Ue}from"../../../core/canvas/sessions.js";import{ticketCountsForNodes as He}from"../../../core/canvas/attention.js";import{isSafeNodeId as Ye}from"../../../core/canvas/paths.js";import{contextDir as de,nodeAgentDir as K}from"../../../core/canvas/node-agent-paths.js";import{checkCronBirth as Qe}from"../../cron/authority.js";import{cronBirthPlacement as Xe}from"../../cron/armed-context.js";import{existsBeneath as Ze,isAbsentOrRefused as qe,isBeneathRefusal as en,readdirBeneath as nn}from"../../../core/spaces/open-beneath.js";import{readNodeMessagesPage as tn,readNodeSession as on,readNodeSnapshot as rn,transcriptMarkdown as dn}from"../../../core/runtime/node-read.js";import{assembleNodeSubject as sn}from"../../../core/substrate/subject.js";import{reviveAll as an}from"../../../core/runtime/revive-all.js";import{promoteAsync as ln,requestYieldAsync as cn,reshapeNodeAsync as W}from"../../../core/runtime/promote.js";import{recycleNode as fn}from"../../../core/runtime/recycle.js";import{relaunchRoot as un}from"../../../core/runtime/reset.js";import{assertReopenGate as pn}from"../../../core/runtime/reopen.js";import{writeYieldMessage as mn,readGoal as hn}from"../../../core/runtime/kickoff.js";import{ensureRoadmap as wn,hasRoadmap as yn}from"../../../core/runtime/roadmap.js";import{renameWindow as _n}from"../../../core/runtime/placement.js";import{buildLaunchSpecAsync as gn,explicitModelIntent as bn,normalizeModel as vn,readMergedLaunchConfigAsync as se}from"../../../core/runtime/launch.js";import{modelRequestFromConfig as kn}from"../../../core/model-routes.js";import{persistDormantModel as Sn,setModelLive as Rn}from"../../../core/runtime/model-swap.js";import{waitForBrokerViewSocket as On}from"../../../core/runtime/view-socket.js";import{BrokerUnreachableError as In}from"../../../core/runtime/broker-request.js";import{boundFleet as V}from"../../../core/runtime/fleet.js";import{admitLegacyStructuredOutput as $n}from"../../structured-requests/sidecar.js";import{OUTCOME_PAYLOAD_MAX_BYTES as ae}from"../../../core/canvas/types.js";import{HUMAN_ACTION_NAME_PATTERN as Cn}from"../../../core/human/action-binding.js";import{resolveHumanAction as Nn}from"../../../core/human-actions.js";import{parseDurationMs as An}from"../../../core/wake.js";import{claimWarmNode as Tn,refillWarmPool as le,resumeWarmClaim as Pn,warmPoolEnabled as En}from"../../../core/runtime/warm-pool.js";import{assertLaunchKind as z,isLaunchKind as Dn,resolveLaunchTarget as Ln}from"../../../core/runtime/launch-target.js";import{fullName as jn}from"../../../core/canvas/labels.js";import{reportsForNode as ce}from"./reports.js";import{requireUsableProfile as Mn}from"./profiles.js";import{assertProfileActive as Fn,loadExactProfileManifest as Gn}from"../../../core/profiles/manifest.js";import{getCron as fe}from"../../../core/canvas/crons.js";import{cronWakeOrigin as Bn}from"../../../core/runtime/bearings.js";import{boundDaemonControl as xn}from"../../control.js";import{notFound as P,usage as h}from"../../../core/errors.js";import{assertScope as Kn,validateScopes as ue}from"../../../core/scopes.js";import{scopeAllowed as O}from"../../../shared/env.js";import{toCloseResultDTO as Wn,toNodeDetailDTO as J,toNodeSummaryDTO as Vn,toReviveResultDTO as zn}from"../map.js";import{ApiError as m}from"../../../api/index.js";import{InputError as w}from"../../../core/io.js";import{brokerMayReach as U,canReadNode as pe,resolvedScopes as Jn}from"../router.js";import{fileRoot as Un}from"../../../core/spaces/file-root.js";import{activeGrant as Hn,terminalGrant as Yn}from"../../../core/grants/mirror.js";import{readConfig as Qn}from"../../../core/config.js";import{hasConfiguredProviderCredential as Xn,NO_PROVIDER_CREDENTIAL_MESSAGE as me}from"../../../core/runtime/provider-credential-gate.js";function y(e){const t=k(e);if(t===null)throw P(`unknown node: ${e}`,{received:e});return t}a(y,"requireMeta");function H(e){return{subscribesTo:ie(e),subscribers:Ge(e),children:De(e)}}a(H,"edgesFor");function g(e){const t=y(e);return J(t,H(e))}a(g,"detailOf");function Zn(e){let t=ce(e).length;try{t+=nn(K(e),de(e)).length}catch(n){if(!qe(n))throw n}return t}a(Zn,"countFiles");function qn(e){if(typeof e!="object"||e===null)throw h("a node create requires a JSON body");const t=e;if(t.kind!==void 0&&(typeof t.kind!="string"||t.kind.trim()===""))throw h("kind must be a non-empty string when provided");if(t.description!==void 0&&(typeof t.description!="string"||t.description.trim()===""))throw h("description must be a non-empty string when provided");if(t.creator!==void 0&&(typeof t.creator!="string"||t.creator.trim()===""))throw h("creator must be a non-empty node id when provided");if(t.scopes!==void 0&&ue(t.scopes),t.isolated!==void 0&&typeof t.isolated!="boolean")throw new m(400,"invalid_request","isolated must be a boolean",{param:"isolated"});const n=t.root_lifecycle;if(n!==void 0&&n!=="resident"&&n!=="terminal")throw h("root_lifecycle must be 'resident' or 'terminal'");if(t.request_key!==void 0&&(typeof t.request_key!="string"||t.request_key.trim()===""||t.request_key.length>128))throw h("request_key must be a non-empty string of at most 128 characters when provided");return t}a(qn,"parseCreateBody");function et(e){if(e===void 0)return;const t=An(e),n=t===null?null:new Date(Date.now()+t);if(t===null||!Number.isFinite(t)||t<=0||n===null||!Number.isFinite(n.getTime()))throw new m(422,"invalid_deadline","`deadline` must be a positive representable duration");return n.toISOString()}a(et,"parseDeadline");function nt(e){if(e!==void 0){if(typeof e!="object"||e===null||Array.isArray(e))throw new m(400,"invalid_request","`outcome_delivery` must be an object");if(typeof e.action!="string"||!Cn.test(e.action))throw new m(400,"invalid_request","`outcome_delivery.action` must be a declared action name");if(e.payload!==void 0){let t;try{t=JSON.stringify(e.payload)}catch{throw new m(400,"invalid_request","`outcome_delivery.payload` must be JSON-serializable")}if(t===void 0)throw new m(400,"invalid_request","`outcome_delivery.payload` must be JSON-serializable");if(Buffer.byteLength(t,"utf8")>ae)throw new m(413,"payload_too_large",`serialized payload exceeds ${ae} bytes`)}return e}}a(nt,"parseOutcomeDelivery");function tt(e,t){const n=Nn(e.action,t);if(!("kind"in n))return{actionName:e.action,argv:n.argv,cwd:n.cwd,configOrigin:n.configOrigin,...e.payload===void 0?{}:{payload:e.payload}};throw n.kind==="unknown_action"?new m(422,"unknown_action",`no action named ${e.action} is declared from ${t}`):new m(422,"invalid_action",`${e.action} is declared in ${n.configOrigin} but unusable: ${n.reason}`,{reason:n.reason,configOrigin:n.configOrigin})}a(tt,"resolveOutcomeDelivery");function ot(e,t,n){const r={kind:e.kind,cwd:n,prompt:e.prompt??""};return e.mode!==void 0&&(r.mode=e.mode),e.name!==void 0&&(r.name=e.name),e.description!==void 0&&(r.description=e.description),t!==void 0&&(r.parent=t),e.creator!==void 0&&(r.creator=e.creator),e.scopes!==void 0&&(r.scopes=e.scopes),e.isolated!==void 0&&(r.isolated=e.isolated),e.root===!0&&(r.root=!0),e.root_lifecycle!==void 0&&(r.rootLifecycle=e.root_lifecycle),(e.worktree===!0||typeof e.worktree=="string")&&(r.worktree=!0),typeof e.worktree=="string"&&(r.worktreeBase=e.worktree),e.worktree!==void 0&&(r.worktreeCwd=T(e.pin_cwd??e.cwd??n)),e.fork_from!==void 0&&(r.forkFrom=e.fork_from),e.model!==void 0&&(r.model=e.model),e.profile!==void 0&&(r.profile=e.profile),e.situational_context!==void 0&&(r.situationalContext=e.situational_context),e.node_id!==void 0&&(r.nodeId=e.node_id),r}a(ot,"buildRecipe");function rt(e,t,n){return!En()||e.prefer_warm!==!0||e.root!==!0||e.parent!=null||e.root_lifecycle==="terminal"||(e.prompt??"")!==""||e.model!==void 0||e.fork_from!==void 0||e.worktree!==void 0||e.node_id!==void 0||e.scopes!==void 0||e.isolated!==void 0?null:{kind:e.kind,mode:e.mode??"base",cwd:t,profileId:n,model:e.model??null,situationalContext:e.situational_context??null,name:e.name??null,creator:e.creator??null}}a(rt,"warmRequestFor");import{resolveCreateKind as Qo}from"../../../core/runtime/launch-target.js";function he(e){const t=e.modelIntent===void 0?void 0:`${e.modelIntent.family}/${e.modelIntent.strength}`;return kn(e.model,t,e.modelExact===!0)}a(he,"requestFromLaunch");function it(e,t){if(t===null)return e;if(e.scopes===void 0)return{...e,scopes:[...t]};const n=e.scopes.filter(r=>!O(t,r));if(n.length===0)return e;throw new m(403,"scope_denied",`scopes exceed the bearer token's ceiling: ${n.join(", ")}`,{scopes:n,ceiling:t})}a(it,"withinCeiling");async function we(e,t,n){const r=(await gn(t.kind,t.mode,{lifecycle:t.lifecycle,hasManager:e.parent!==null,model:t.model,modelOverride:!0,cwd:e.cwd,profileId:e.profile_id??null})).launch;await B(he(r),{cwd:e.cwd,profileId:e.profile_id??null},n)}a(we,"assertNodeModelChangeRegistered");function ye(e,t){const n=e.principal;if(n.class!=="broker"&&n.class!=="cron")return;const r=Un({app:n.app,resolved:Jn(n),launched:n.scopes},t,"read");if("root"in r)return;const o="missing"in r?r.missing:null;throw new m(403,"scope_missing",o?`the child's directory ${t} needs missing scope ${o}`:`no permission of this run names the child's directory ${t}`,void 0,void 0,o?{scope:o}:void 0)}a(ye,"assertCallerReaches");const Y=new Map;async function dt(e,t={},n={}){const r=it(qn(e.body),e.ceiling);if(e.principal.class==="broker"){const l=e.principal;if(r.prefer_warm===!0&&l.app!=="app:terminal"&&(r.prefer_warm=!1),r.parent!=null){const i=y(r.parent);if(i.grantee!==l.app)throw new m(403,"other_app_run","cannot create a child under another app's node");if(!U(l,r.parent,i.grantee??"app:terminal"))throw P(`unknown node: ${r.parent}`,{received:r.parent})}if(r.creator!==void 0&&r.creator!==l.node)throw new m(403,"other_app_run","cannot create for another node");if(r.fork_from!==void 0){let i=null;try{i=Ee(Te(r.fork_from))}catch{}if(i?.grantee!==l.app||!U(l,i.node_id,i.grantee))throw new m(403,"other_app_run","cannot fork another app's conversation")}r.creator=l.node}if(e.principal.class==="cron"){const l=e.principal;for(const c of["parent","creator","fork_from","node_id"])if(r[c]!=null)throw new m(403,"permission_error",`a cron cannot set ${c} on a node it starts`);r.prefer_warm=!1;const i=Qe({grantee:l.app,sub:l.sub,grant_id:l.grant,scopes:l.scopes});if(!i.allowed)throw new m(i.reason==="scope_missing"?403:401,i.reason==="scope_missing"?"scope_missing":"grant_revoked",i.message);if(r.scopes!==void 0){const c=r.scopes.find(p=>!O(i.effectiveScopes,p)||!O(l.scopes,p));if(c!==void 0)throw new m(403,"scope_missing",`scope ${c} is not held by this cron`,void 0,void 0,{scope:c})}else l.scopes!==null&&(r.scopes=[...l.scopes]);r.node_id=ee(),l.isolated&&(r.isolated=!0,r.cwd=K(r.node_id,l.app))}r.creator!==void 0&&Kn(y(r.creator),"crtr:act");const o=r.request_key?.trim();if(o===void 0||r.node_id!==void 0&&Ye(r.node_id)&&k(r.node_id)!==null&&Le(o)?.nodeId!==r.node_id)return E(e,r,t,n);const d=Y.get(o);if(d!==void 0)return d;const s=st(e,r,o,t,n);Y.set(o,s);try{return await s}finally{Y.delete(o)}}a(dt,"handleCreate");async function st(e,t,n,r,o){const d=oe(n);if(d.nodeId!==null&&k(d.nodeId)!==null){if(d.state!=="warm_claimed"){const s=k(d.nodeId);if(e.principal.class!=="person"&&!pe(e.principal,s.grantee??"app:terminal",d.nodeId))throw new m(409,"create_request_conflict","request_key belongs to another caller");return{status:201,body:g(d.nodeId)}}return E(e,t,r,o,d)}try{return await E(e,t,r,o,d)}catch(s){const l=oe(n);throw(l.nodeId===null||k(l.nodeId)===null)&&ne(n,l.nodeId),s}}a(st,"handleKeyedCreateRequest");async function E(e,t,n,r,o=void 0){const d=r.deadlineAt??et(t.deadline),s=nt(t.outcome_delivery),l=e.principal.class==="cron"?Xe({grantee:e.principal.app,sub:e.principal.sub,grant_id:e.principal.grant,scopes:e.principal.scopes,cron_id:e.principal.cron,origin_run_id:e.principal.origin_run,isolated:e.principal.isolated,creator:fe(e.principal.cron)?.created_by??null},t.node_id):null;l!==null&&(t.root=l.root===!0);const i=l?.parent??t.parent??void 0;if(i==null&&t.root!==!0)throw h("a node create requires a parent (or root: true for an independent root)");let c=null;if(t.output_schema!==void 0)try{c=JSON.parse(t.output_schema)}catch{throw h("output_schema must be a JSON schema string")}const{profileId:p,kind:u,cwd:f,launch:_}=await Ln(t,{validateKind:ke});ye(e,f),t.worktree!==void 0&&ye(e,T(t.pin_cwd??t.cwd??f));const S={...t,kind:u},I=s===void 0?void 0:tt(s,f);if(await B(he(_),{cwd:f,profileId:p},n.modelRegistry),!await Xn(p))throw new m(412,"no_provider_credential",me,{error:"no_provider_credential",message:me,next:"The person running this runtime logs a provider in with `crtr sys setup`, or stores a provider key on the profile."});let L=null;{const $=o===void 0||o.nodeId===null||o.state==="warm_claimed"?rt(S,f,p):null,j=c===null&&r.beforeBrokerLaunch===void 0?void 0:v=>{c!==null&&$n(v,"terminal",c),r.beforeBrokerLaunch?.(v)};if(o?.state==="warm_claimed"&&o.nodeId!==null){const v=$===null?null:await Pn($,o.nodeId,j);if(v===null)throw ne(o.requestKey,o.nodeId),new m(503,"create_resume_failed",`could not resume warm claim ${o.nodeId}; retry the create`);return te(o.requestKey,v),{status:201,body:g(v)}}if($!==null){const v=await Tn($,{...d===void 0?{}:{deadlineAt:d},...I===void 0?{}:{outcomeDelivery:I},...o===void 0?{}:{requestKey:o.requestKey}},j);if(v!==null)return o!==void 0&&te(o.requestKey,v),le($),{status:201,body:g(v)};L=$}const M=o?.nodeId??t.node_id??(o===void 0?void 0:ee());o!==void 0&&o.nodeId===null&&Me(o.requestKey,M);const R=ot(M===void 0?S:{...S,node_id:M},i,f);l!==null&&(l.rootLifecycle!==void 0&&(R.rootLifecycle=l.rootLifecycle),l.scopes!==void 0&&S.scopes===void 0&&(R.scopes=l.scopes),l.run!==void 0&&(R.run=l.run),l.withinCreate!==void 0&&(R.withinCreate=l.withinCreate)),d!==void 0&&(R.deadlineAt=d),I!==void 0&&(R.outcomeDelivery=I),R.readiness=t.root===!0?"await":"launch";const Q=await Pe(R,j,()=>{L!==null&&le(L)});return o!==void 0&&je(o.requestKey,Q.node.node_id),{status:201,body:g(Q.node.node_id)}}}a(E,"handleCreateRequest");function b(e,t){const n=e.query.getAll(t);if(n.length>1)throw h(`${t} must appear at most once`);return n[0]}a(b,"singleQueryValue");function _e(e,t){if(e!==void 0){if(e==="1"||e==="true")return!0;if(e==="0"||e==="false")return!1;throw h(`${t} must be true or false`)}}a(_e,"optionalBoolean");function D(e,t,n){if(e!==void 0){if(n.includes(e))return e;throw h(`${t} must be one of: ${n.join(", ")}`)}}a(D,"oneOf");function at(e){const t=new Set(["status","lifecycle","kind","mode","profile_id","profile_prefix","parent","top_level","under","hanging","include"]);for(const[_]of e.query)if(!t.has(_))throw h(`unknown nodes query parameter: ${_}`);const n=D(b(e,"status"),"status",["active","idle","done","dead","canceled"]),r=D(b(e,"lifecycle"),"lifecycle",["terminal","resident"]),o=b(e,"kind"),d=D(b(e,"mode"),"mode",["base","orchestrator"]),s=b(e,"profile_id"),l=b(e,"profile_prefix"),i=b(e,"parent"),c=_e(b(e,"top_level"),"top_level"),p=b(e,"under"),u=_e(b(e,"hanging"),"hanging"),f=D(b(e,"include"),"include",["activity"]);if(i!==void 0&&c===!0)throw h("parent and top_level=true cannot be combined");return{...n!==void 0?{status:n}:{},...r!==void 0?{lifecycle:r}:{},...o!==void 0?{kind:o}:{},...d!==void 0?{mode:d}:{},...s!==void 0?{profile_id:s}:{},...l!==void 0?{profile_prefix:l}:{},...i!==void 0?{parent:i}:{},...c!==void 0?{top_level:c}:{},...p!==void 0?{under:p}:{},...u!==void 0?{hanging:u}:{},...f!==void 0?{include:f}:{}}}a(at,"parseListQuery");function lt(e){const t=at(e);let n=t.status!==void 0?re({status:t.status}):re();if(e.principal.class!=="person"&&(n=n.filter(s=>pe(e.principal,s.grantee??"app:terminal",s.node_id))),t.lifecycle!==void 0&&(n=n.filter(s=>s.lifecycle===t.lifecycle)),t.kind!==void 0&&(n=n.filter(s=>s.kind===t.kind)),t.mode!==void 0&&(n=n.filter(s=>s.mode===t.mode)),t.profile_id!==void 0&&(n=n.filter(s=>s.profile_id===t.profile_id)),t.profile_prefix!==void 0&&(n=n.filter(s=>s.profile_id?.startsWith(t.profile_prefix))),t.parent!==void 0&&(n=n.filter(s=>s.parent===t.parent)),t.top_level===!0&&(n=n.filter(s=>s.parent===null)),t.under!==void 0){const s=new Set(xe(t.under));n=n.filter(l=>s.has(l.node_id))}t.hanging===!0&&(n=n.filter(s=>s.parent!==null&&k(s.parent)===null));const r=t.include==="activity"?He(n.map(s=>s.node_id)):null,o=n.length>0?Oe():new Set;return{status:200,body:n.map(s=>{const l=Vn(s,s.profile_id!==null&&o.has(s.profile_id));if(r!==null){const i=ce(s.node_id);l.activity={latest_report:i[0]??null,final_report:s.final_report===null?null:i.find(c=>c.name===s.final_report)??null,pending_human_count:r[s.node_id]??0}}return l})}}a(lt,"handleList");function ct(e){const t=e.params.id;return y(t),{status:200,body:g(t)}}a(ct,"handleDetail");async function ft(e){const t=e.params.id;y(t);const n=await rn(t);return{status:200,body:{node_id:t,snapshot:{messages:n.snapshot.messages,...n.snapshot.messageIds===void 0?{}:{messageIds:n.snapshot.messageIds},messageVisibility:n.snapshot.messageVisibility,turnVisibility:n.snapshot.turnVisibility,stats:n.snapshot.stats,state:n.snapshot.state,display:n.snapshot.display,...n.snapshot.queued===void 0?{}:{queued:n.snapshot.queued},...n.snapshot.toolGroupSummaries===void 0?{}:{toolGroupSummaries:n.snapshot.toolGroupSummaries},...n.snapshot.turnReplies===void 0?{}:{turnReplies:n.snapshot.turnReplies},...n.snapshot.workingActivity===void 0?{}:{workingActivity:n.snapshot.workingActivity}},commands:n.commands.map(o=>({name:o.name,description:o.description,source:o.source})),captured_at:G()}}}a(ft,"handleSnapshot");async function ut(e){const t=e.params.id,n=sn(t);if(n===null)throw P(`unknown node: ${t}`,{received:t});return{status:200,body:n}}a(ut,"handleSubject");function pt(e){for(const[d]of e.query)if(d!=="cursor"&&d!=="limit")throw h(`unknown messages query parameter: ${d}`);const t=e.query.getAll("cursor"),n=e.query.getAll("limit");if(t.length>1)throw h("cursor must appear at most once");if(n.length>1)throw h("limit must appear at most once");if(n.length===0)return t.length===0?{}:{cursor:t[0]};const r=n[0],o=Number(r);if(!Number.isSafeInteger(o)||r==="")throw h("limit must be an integer from 1 through 500");return t.length===0?{limit:o}:{cursor:t[0],limit:o}}a(pt,"parseMessagesQuery");async function mt(e){const t=e.params.id,n=await tn(t,pt(e));return{status:200,body:{node_id:t,messages:n.messages,...n.messageIds===void 0?{}:{message_ids:n.messageIds},message_visibility:n.messageVisibility,next_cursor:n.nextCursor,captured_at:G()}}}a(mt,"handleMessages");function ht(e){const t=e.params.id;y(t);const n=on(t);return{status:200,body:{node_id:t,session_file:n.sessionFile,session_jsonl:n.sessionJsonl,system_prompt:n.systemPrompt,captured_at:G()}}}a(ht,"handleSession");async function wt(e){const t=e.params.id;return y(t),{status:200,body:{node_id:t,markdown:await dn(t)}}}a(wt,"handleTranscript");function yt(e){const t=e.params.id;y(t);const n=a((o,d)=>({node_id:o,label:k(o)?.name??o,dir:de(o),self:d,files:Zn(o)}),"root"),r=[n(t,!0),...ie(t).map(o=>n(o.node_id,!1))].filter(o=>_t(o.node_id,o.dir)||o.files>0);return{status:200,body:{node_id:t,roots:r}}}a(yt,"handleContext");function _t(e,t){try{return Ze(K(e),t)}catch(n){if(en(n))return!1;throw n}}a(_t,"hasDir");async function gt(e){const t=y(e.params.id),n=e.principal.class==="broker"?e.principal.scopes:e.ceiling,r=n===null?void 0:t.scopes==null?[...n]:[...new Set([...t.scopes.filter(d=>O(n,d)),...n.filter(d=>O(t.scopes,d))])],o=await Ae(t.node_id,r,e.principal.class==="broker"?e.principal.node:void 0);return{status:201,body:g(o.node.node_id)}}a(gt,"handleFork");async function bt(e){const t=e.params.id;y(t);const n=e.body,r=n?.resume??!0,o=n?.reopen??!1;pn(t,o);const d=!r&&n?.cron_id!==void 0?fe(n.cron_id):null,s=await Ne(t,{resume:r,capacity:"refuse",...d!==null?{wakeReason:Bn(d,"schedule_revive")}:{}});s.outcome!=="already-live"&&Fe(t,{failures:0,notBefore:null});const l=k(t)?.status??"active";return{status:200,body:zn(t,s,l)}}a(bt,"handleRevive");async function vt(e){const t=e.params.id;return{status:200,body:{newNodeId:(await un(t))?.newNodeId??null}}}a(vt,"handleRelaunchRoot");function kt(e){const t=e.params.id;y(t);const n=e.body;if(n?.caller_pid!==void 0&&(!Number.isInteger(n.caller_pid)||n.caller_pid<=0))throw h("caller_pid must be a positive integer when provided");const r=xn(),o=Ce(t,{rootEvent:n?.finish===!0?"finish":"cancel",callerPid:n?.caller_pid,...e.principal.class==="broker"?{closer:e.principal.node}:{},...r===null?{}:{registerDetached:r.registerDetached}});return{status:200,body:Wn(o)}}a(kt,"handleClose");async function St(e){const t=e.params.id;y(t);const n=await fn(t);return{status:200,body:{recycled:n.recycled,finalized:n.finalized,new_root:n.newRoot,delivered:n.delivered}}}a(St,"handleRecycle");async function Rt(e){const t=e.params.id;return y(t),await W(t,{lifecycle:"terminal"}),C(e,t,["lifecycle"]),{status:200,body:g(t)}}a(Rt,"handleDemote");async function Ot(e,t={}){const n=e.params.id,r=y(n),o=e.body??{};o.kind!==void 0&&await z(o.kind,r.cwd,r.profile_id??null),o.model!==void 0&&await we(r,{kind:o.kind??r.kind,mode:"orchestrator",lifecycle:o.resident===!0?"resident":r.lifecycle,model:o.model},t.modelRegistry);const d=await ln(n,{...o.kind!==void 0?{kind:o.kind}:{},...o.resident===!0?{resident:!0}:{},...o.model!==void 0?{model:o.model}:{}});C(e,n,["mode",...o.kind!==void 0?["kind"]:[],...o.resident===!0?["lifecycle"]:[],...o.model!==void 0?["model"]:[]]);const s=J(d.meta,H(n));return s.roadmap_written=d.roadmapWritten,s.roadmap_ref=d.roadmapRef,s.goal_path=d.goalPath,{status:200,body:s}}a(Ot,"handlePromote");async function It(e,t={}){const n=e.params.id,r=y(n),o=e.body??{};o.kind!==void 0&&await z(o.kind,r.cwd,r.profile_id??null),o.model!==void 0&&await we(r,{kind:o.kind??r.kind,mode:o.promote===!0?"orchestrator":r.mode,lifecycle:r.lifecycle,model:o.model},t.modelRegistry);const d=o.note??"Refresh: continue against your roadmap or goal.";mn(n,d);const s=await cn(n,{...o.promote===!0?{promote:!0}:{},...o.kind!==void 0?{kind:o.kind}:{},...o.model!==void 0?{model:o.model}:{}});return{status:200,body:J(s.meta,H(n))}}a(It,"handleYield");function $t(e){const t=e.params.id;y(t);const n=e.body;if(n===void 0||typeof n.controller!="string"||n.controller.trim()==="")throw h("a wait requires a controller node id");const r=k(n.controller);if(r===null)throw P(`unknown controller: ${n.controller}`,{received:n.controller});if(r.status!=="active"&&r.status!=="idle")throw new m(422,"unprocessable",`controller ${n.controller} is ${r.status}`);return Be(t,n.controller),{status:200,body:g(t)}}a($t,"handleWait");async function Ct(e){const t=e.principal,n=await an(t.class==="broker"?o=>o.grantee===t.app&&U(t,o.node_id,o.grantee):void 0);return{status:200,body:{revived:[...n.revived],failed:[...n.failed],frozen:[...n.frozen]}}}a(Ct,"handleReviveAll");const Nt=new Set(["interrupt","steer","after-turn","next-turn"]);function At(e){if(e===null)return null;const t=a(r=>{throw new w({error:"invalid_listen",message:r,received:e,field:"listen",next:'Send an object mapping levels "1".."10" to interrupt|steer|after-turn|next-turn (e.g. {"3":"next-turn"}), or null to reset to the global default.'})},"bad");if(typeof e!="object"||Array.isArray(e))return t("listen must be an object or null");const n=Object.entries(e);if(n.length===0)return t("listen must name at least one level");for(const[r,o]of n)/^(?:[1-9]|10)$/.test(r)||t(`listen level must be 1..10: ${r}`),(typeof o!="string"||!Nt.has(o))&&t(`listen delivery must be interrupt|steer|after-turn|next-turn: ${String(o)}`);return JSON.stringify(Object.fromEntries(n))}a(At,"listenJson");function C(e,t,n,r){n.length===0&&r===void 0||x(o=>{if(r?.(o),n.length===0)return;const d=Ke(o,t),s=ze(o,e),l=s.class==="person"?s.person:s.class==="app"?s.app:s.node;We(o,l,d),Ve(o,{event:"configured",object:d,actor:l,attrs:{changed:n.join(",")}})})}a(C,"recordConfigured");function ge(e){const t=V().get(e);if(t===void 0)return!1;try{return process.kill(t.pid,"SIGTERM"),!0}catch{return!1}}a(ge,"restartLiveBroker");function be(e,t){try{return Z(e)===Z(t)}catch{return!1}}a(be,"sameDirectory");async function Tt(e,t={}){const n=e.params.id,r=e.body;let o;if(r===void 0)o={};else if(typeof r=="object"&&r!==null&&!Array.isArray(r))o=r;else throw new w({error:"cwd_invalid",message:"cwd repair requires a non-null object with a non-empty cwd string",received:r,field:"cwd",next:"Send a config patch with a non-empty absolute cwd string."});if(o.profile!==void 0){if(typeof o.profile!="string"||o.profile==="")throw new w({error:"profile_invalid",message:"profile must be a non-empty profile id or name",received:o.profile,field:"profile",next:"Send a profile id or exact name."});if(Object.keys(o).some(u=>u!=="profile"&&u!=="restart"&&o[u]!==void 0))throw new w({error:"profile_not_exclusive",message:"profile can only be combined with restart",field:"profile",next:"Send profile (and optionally restart) alone."});const i=y(n),c=Mn(e,o.profile);Fn(c.profileId);const p=Gn(c.profileId).manifest.grantee??"app:terminal";if(p!==(i.grantee??"app:terminal"))throw new w({error:"profile_grantee_mismatch",message:`profile ${c.profileId} belongs to ${p}, node ${n} to ${i.grantee}`,received:o.profile,field:"profile",next:"Pick a profile owned by the same app as the node."});return(i.profile_id??null)!==c.profileId&&(Dn(i.kind)?(await z(i.kind,i.cwd,c.profileId),await W(n,{profileId:c.profileId})):N(n,{profile_id:c.profileId}),C(e,n,["profile"])),o.restart===!0&&ge(n),{status:200,body:g(n)}}if(Object.prototype.hasOwnProperty.call(o,"cwd")){const i=o.cwd;if(typeof i!="string"||i==="")throw new w({error:"cwd_invalid",message:"cwd must be a non-empty string",received:i,field:"cwd",next:"Send a non-empty absolute cwd string."});if(Object.keys(o).some(f=>f!=="cwd"&&f!=="keep_session"&&f!=="restart"&&o[f]!==void 0))throw new w({error:"cwd_not_exclusive",message:"cwd repair cannot be combined with another config field",received:o,field:"cwd",next:"Send cwd as the only config field."});const c=y(n),p=A(c.cwd);if(o.keep_session===!0||p&&F(i)&&A(i)&&be(c.cwd,i)){if(!F(i))throw new w({error:"cwd_not_absolute",message:`cwd must be an absolute path: ${i}`,received:i,field:"cwd",next:"Send an absolute path."});const f=T(i);let _=!1;try{_=q(f).isDirectory()}catch{}if(!_)throw new w({error:"cwd_missing",message:`cwd is not an existing directory: ${f}`,received:i,field:"cwd",next:"Send an existing absolute directory."});if(p&&!be(c.cwd,f))throw new w({error:"cwd_not_same_directory",message:`${f} is not the same directory as the recorded ${c.cwd}; --keep-session only relocates an alias`,received:i,field:"cwd",next:"Drop --keep-session to repair a gone cwd, or pass the real path of the recorded directory."});if(c.managed_worktree?.state==="open")throw new w({error:"cwd_node_managed_worktree_open",message:`${n} owns an open managed worktree and cannot relocate its cwd`,received:i,field:"cwd",next:"Reconcile the managed worktree first."});const S=c.cwd;return S!==f&&(x(I=>{N(n,{cwd:f}),X(I,"UPDATE crons SET cwd = ? WHERE anchor_node = ? AND cwd = ?").run(f,n,S),Je(n,S,f)}),C(e,n,["cwd"])),o.restart===!0&&ge(n),{status:200,body:g(n)}}if(V().has(n)){const f=`${n} cannot repair its cwd while its broker is live`;throw new m(409,"cwd_node_live",f,{error:"cwd_node_live",message:f,received:i,field:"cwd",next:"Let the node become dormant, then retry the cwd repair."})}if(c.fork_from!=null)throw new w({error:"cwd_node_forked",message:`${n} is a fork and cannot repair its cwd; recorded cwd: ${c.cwd}`,received:i,field:"cwd",next:`Restore ${c.cwd}, then revive the fork normally.`});if(c.managed_worktree?.state==="open")throw new w({error:"cwd_node_managed_worktree_open",message:`${n} owns an open managed worktree and cannot repair its cwd`,received:i,field:"cwd",next:"Restore or reconcile the recorded checkout, then use the managed-worktree close or abandon flow."});if(A(c.cwd))throw new w({error:"cwd_still_present",message:`${n} recorded cwd still exists: ${c.cwd}; cwd repair is not a relocation command`,received:i,field:"cwd",next:"This command only repairs a node whose recorded cwd is gone."});if(!F(i))throw new w({error:"cwd_not_absolute",message:`cwd must be an absolute path: ${i}`,received:i,field:"cwd",next:"Send an absolute path."});const u=T(i);if(!A(u))throw new w({error:"cwd_missing",message:`cwd does not exist: ${u}`,received:i,field:"cwd",next:"Create the replacement directory or send an existing absolute directory."});try{if(!q(u).isDirectory())throw new w({error:"cwd_not_a_directory",message:`cwd is not a directory: ${u}`,received:i,field:"cwd",next:"Send an existing absolute directory."})}catch(f){throw f instanceof w?f:new w({error:"cwd_missing",message:`cwd does not exist: ${u}`,received:i,field:"cwd",next:"Create the replacement directory or send an existing absolute directory."})}return x(()=>{N(n,{cwd:u}),Ue(n)}),C(e,n,["cwd"]),{status:200,body:g(n)}}let d=y(n);const s=o.listen===void 0?void 0:At(o.listen);if(o.scopes!==void 0){const i=ue(o.scopes),c=d.grantee==="app:terminal"?Yn():d.grant_id?Hn(d.grant_id):null,p=d.grantee==="app:terminal"&&!Qn("user").runtime?.issuer;if(!i.every(u=>O(d.scopes,u)&&(c?O(c.resolved,u):p)))throw new w({error:"unknown_scope",message:"scopes may only narrow the node's current effective set",received:i,field:"scopes",next:"Send only scopes the node currently holds."});if(i.includes("crtr:act")&&!O(i,"crtr:llm"))throw new m(400,"invalid_scope","crtr:act requires crtr:llm");d=N(n,{scopes:i})}if(o.situational_context!==void 0&&Ie(n,$e(o.situational_context)),o.model!==void 0){const i=(await se(d.cwd,d.profile_id??null)).modelLadders,c=bn(o.model,i),p=vn(o.model,i);await B({kind:"concrete",spec:p},{cwd:d.cwd,profileId:d.profile_id??null},t.modelRegistry);const u=V();let f=!1;if(u.isClaimed(n)&&await On(n,u.get(n)?.handle.exited)&&(f=await Rn(n,p,c).then(()=>!0,_=>{if(_ instanceof In)return!1;throw _})),!f){if(u.isClaimed(n)){const _=`${n}'s broker did not accept the model switch; the model was not changed`;throw new m(409,"broker_not_ready",_,{error:"broker_not_ready",message:_,received:o.model,field:"model",next:"Check the node with `crtr node show`, then retry the model change."})}if(!p.includes("/"))throw h(`model must resolve to a provider/id spec: ${o.model}`);Sn(n,p,c)}d=y(n)}if(o.kind!==void 0||o.mode!==void 0||o.lifecycle!==void 0){o.kind!==void 0&&await ke(o.kind);const i=o.kind??d.kind,c=o.mode??d.mode,p=o.lifecycle??d.lifecycle;let u;c==="orchestrator"&&!yn(n)&&(u=a(()=>{const f=hn(n);wn(n,f!==null&&f.trim()!==""?{goal:f.trim()}:{})},"beforePersist")),d=await W(n,{...o.kind!==void 0?{kind:i}:{},...o.mode!==void 0?{mode:c}:{},...o.lifecycle!==void 0?{lifecycle:p}:{}},u)}o.name!==void 0&&(d=N(n,{name:o.name}),d.window&&_n(d.window,jn(d)));const l=["scopes","situational_context","model","kind","mode","lifecycle","name","listen"].filter(i=>o[i]!==void 0);return C(e,n,l,s===void 0?void 0:i=>{X(i,"UPDATE objects SET listen_json = ? WHERE id = ? AND type = 'node'").run(s,n)}),{status:200,body:g(n)}}a(Tt,"handleConfig");async function ve(){return(await se(process.cwd(),Re()||null)).kinds}a(ve,"daemonKinds");async function ke(e){const t=Object.keys(await ve());if(!t.includes(e))throw h(`unknown kind: ${e}`,{received:e,next:`Valid kinds: ${t.sort().join(", ")}.`})}a(ke,"assertKindServer");async function Pt(){const e=await ve();return{status:200,body:{kinds:Object.keys(e).sort().map(n=>({kind:n,when_to_use:e[n]?.whenToUse??null,available_to:e[n]?.availableTo??null}))}}}a(Pt,"handleListKinds");const Uo=[{method:"POST",pattern:"/v1/nodes",scope:"crtr:act",handler:dt},{method:"GET",pattern:"/v1/nodes",handler:lt},{method:"GET",pattern:"/v1/kinds",handler:a(()=>Pt(),"handler")},{method:"POST",pattern:"/v1/nodes/revive-all",scope:"crtr:act",handler:Ct},{method:"GET",pattern:"/v1/nodes/:id",handler:ct},{method:"GET",pattern:"/v1/nodes/:id/snapshot",handler:ft},{method:"GET",pattern:"/v1/nodes/:id/subject",handler:ut},{method:"GET",pattern:"/v1/nodes/:id/messages",handler:mt},{method:"GET",pattern:"/v1/nodes/:id/session",handler:ht},{method:"GET",pattern:"/v1/nodes/:id/transcript",handler:wt},{method:"GET",pattern:"/v1/nodes/:id/context",handler:yt},{method:"POST",pattern:"/v1/nodes/:id/fork",scope:"crtr:act",handler:gt},{method:"POST",pattern:"/v1/nodes/:id/revive",scope:"crtr:act",handler:bt},{method:"POST",pattern:"/v1/nodes/:id/relaunch-root",scope:"crtr:act",handler:vt},{method:"POST",pattern:"/v1/nodes/:id/close",handler:kt},{method:"POST",pattern:"/v1/nodes/:id/recycle",scope:"crtr:act",handler:St},{method:"POST",pattern:"/v1/nodes/:id/demote",scope:"crtr:act",handler:Rt},{method:"POST",pattern:"/v1/nodes/:id/promote",scope:"crtr:act",handler:Ot},{method:"POST",pattern:"/v1/nodes/:id/yield",scope:"crtr:act",handler:It},{method:"POST",pattern:"/v1/nodes/:id/wait",handler:$t},{method:"PATCH",pattern:"/v1/nodes/:id/config",handler:Tt}];export{Tt as handleConfig,dt as handleCreate,gt as handleFork,lt as handleList,Ot as handlePromote,It as handleYield,Uo as nodeRoutes,Qo as resolveCreateKind};
|
|
1
|
+
var Se=Object.defineProperty;var a=(e,t)=>Se(e,"name",{value:t,configurable:!0});import{prepared as X}from"../../../core/sqlite-statements.js";import{envProfileId as Re}from"../../../shared/env.js";import{pausedCanvasProfiles as Oe}from"../../../core/profiles/manifest.js";import{existsSync as A,realpathSync as Z,statSync as q}from"node:fs";import{isAbsolute as F,resolve as T}from"node:path";import{appendSituationalContext as Ie,formatSituationalProse as $e}from"../../../core/runtime/situational-context.js";import{closeNode as Ce}from"../../../core/runtime/close.js";import{reviveNode as Ne}from"../../../core/runtime/revive.js";import{nowIso as G}from"../../../core/fs-utils.js";import{assertLaunchModelRegistered as B,forkNode as Ae,resolveForkSource as Te,spawnChildPrepared as Ee}from"../../../core/runtime/spawn.js";import{forkSourceNode as Pe,newNodeId as ee}from"../../../core/runtime/nodes.js";import{abandonCreateRequest as ne,childrenOf as De,completeCreateRequest as te,findCreateRequest as Le,getNode as k,recordCreateRequestNode as Me,reserveCreateRequest as oe,reserveCreateRequestNode as je,listNodes as re,recordRespawnAttempt as Fe,subscribersOf as Ge,subscriptionsOf as ie,setMessageWait as Be,updateNode as N}from"../../../core/canvas/canvas.js";import{subtreeIds as Ke}from"../../../core/canvas/nav-model.js";import{withCanvasWrite as K}from"../../../core/canvas/db.js";import{nodeObject as xe}from"../../../core/graph/objects.js";import{recordActedOn as We}from"../../../core/graph/edges.js";import{publish as Ve}from"../../../core/graph/events.js";import{readerFor as ze}from"../reader.js";import{relocateSessionCwd as Je,unbindSession as Ue}from"../../../core/canvas/sessions.js";import{ticketCountsForNodes as He}from"../../../core/canvas/attention.js";import{isSafeNodeId as Ye}from"../../../core/canvas/paths.js";import{contextDir as de,nodeAgentDir as x}from"../../../core/canvas/node-agent-paths.js";import{checkCronBirth as Qe}from"../../cron/authority.js";import{cronBirthPlacement as Xe}from"../../cron/armed-context.js";import{existsBeneath as Ze,isAbsentOrRefused as qe,isBeneathRefusal as en,readdirBeneath as nn}from"../../../core/spaces/open-beneath.js";import{readNodeMessagesPage as tn,readNodeSession as on,readNodeSnapshot as rn,transcriptMarkdown as dn}from"../../../core/runtime/node-read.js";import{assembleNodeSubject as sn}from"../../../core/substrate/subject.js";import{reviveAll as an}from"../../../core/runtime/revive-all.js";import{promoteAsync as ln,requestYieldAsync as cn,reshapeNodeAsync as W}from"../../../core/runtime/promote.js";import{recycleNode as fn}from"../../../core/runtime/recycle.js";import{relaunchRoot as un}from"../../../core/runtime/reset.js";import{assertReopenGate as pn}from"../../../core/runtime/reopen.js";import{writeYieldMessage as mn,readGoal as hn}from"../../../core/runtime/kickoff.js";import{ensureRoadmap as wn,hasRoadmap as yn}from"../../../core/runtime/roadmap.js";import{renameWindow as _n}from"../../../core/runtime/placement.js";import{buildLaunchSpecAsync as gn,explicitModelIntent as bn,normalizeModel as vn,readMergedLaunchConfigAsync as se}from"../../../core/runtime/launch.js";import{modelRequestFromConfig as kn}from"../../../core/model-routes.js";import{persistDormantModel as Sn,setModelLive as Rn}from"../../../core/runtime/model-swap.js";import{waitForBrokerViewSocket as On}from"../../../core/runtime/view-socket.js";import{BrokerUnreachableError as In}from"../../../core/runtime/broker-request.js";import{boundFleet as V}from"../../../core/runtime/fleet.js";import{admitLegacyStructuredOutput as $n}from"../../structured-requests/sidecar.js";import{OUTCOME_PAYLOAD_MAX_BYTES as ae}from"../../../core/canvas/types.js";import{HUMAN_ACTION_NAME_PATTERN as Cn}from"../../../core/human/action-binding.js";import{resolveHumanAction as Nn}from"../../../core/human-actions.js";import{parseDurationMs as An}from"../../../core/wake.js";import{claimWarmNode as Tn,refillWarmPool as le,resumeWarmClaim as En,warmPoolEnabled as Pn}from"../../../core/runtime/warm-pool.js";import{assertLaunchKind as z,isLaunchKind as Dn,resolveLaunchTarget as Ln}from"../../../core/runtime/launch-target.js";import{fullName as Mn}from"../../../core/canvas/labels.js";import{reportsForNode as ce}from"./reports.js";import{requireUsableProfile as jn}from"./profiles.js";import{assertProfileActive as Fn,loadExactProfileManifest as Gn}from"../../../core/profiles/manifest.js";import{getCron as fe}from"../../../core/canvas/crons.js";import{cronWakeOrigin as Bn}from"../../../core/runtime/bearings.js";import{boundDaemonControl as Kn}from"../../control.js";import{notFound as E,usage as h}from"../../../core/errors.js";import{assertScope as xn,validateScopes as ue}from"../../../core/scopes.js";import{scopeAllowed as O}from"../../../shared/env.js";import{toCloseResultDTO as Wn,toNodeDetailDTO as J,toNodeSummaryDTO as Vn,toReviveResultDTO as zn}from"../map.js";import{ApiError as m}from"../../../api/index.js";import{InputError as w}from"../../../core/io.js";import{brokerMayReach as U,canReadNode as pe,resolvedScopes as Jn}from"../router.js";import{forwardVerb as Un,queryWithoutMachine as Hn,relayError as Yn,unknownError as Qn,withMachine as Xn}from"../../peer/forward.js";import{fileRoot as Zn}from"../../../core/spaces/file-root.js";import{activeGrant as qn,terminalGrant as et}from"../../../core/grants/mirror.js";import{readConfig as nt}from"../../../core/config.js";import{hasConfiguredProviderCredential as tt,NO_PROVIDER_CREDENTIAL_MESSAGE as me}from"../../../core/runtime/provider-credential-gate.js";function y(e){const t=k(e);if(t===null)throw E(`unknown node: ${e}`,{received:e});return t}a(y,"requireMeta");function H(e){return{subscribesTo:ie(e),subscribers:Ge(e),children:De(e)}}a(H,"edgesFor");function g(e){const t=y(e);return J(t,H(e))}a(g,"detailOf");function ot(e){let t=ce(e).length;try{t+=nn(x(e),de(e)).length}catch(n){if(!qe(n))throw n}return t}a(ot,"countFiles");function rt(e){if(typeof e!="object"||e===null)throw h("a node create requires a JSON body");const t=e;if(t.kind!==void 0&&(typeof t.kind!="string"||t.kind.trim()===""))throw h("kind must be a non-empty string when provided");if(t.description!==void 0&&(typeof t.description!="string"||t.description.trim()===""))throw h("description must be a non-empty string when provided");if(t.creator!==void 0&&(typeof t.creator!="string"||t.creator.trim()===""))throw h("creator must be a non-empty node id when provided");if(t.scopes!==void 0&&ue(t.scopes),t.isolated!==void 0&&typeof t.isolated!="boolean")throw new m(400,"invalid_request","isolated must be a boolean",{param:"isolated"});const n=t.root_lifecycle;if(n!==void 0&&n!=="resident"&&n!=="terminal")throw h("root_lifecycle must be 'resident' or 'terminal'");if(t.request_key!==void 0&&(typeof t.request_key!="string"||t.request_key.trim()===""||t.request_key.length>128))throw h("request_key must be a non-empty string of at most 128 characters when provided");return t}a(rt,"parseCreateBody");function it(e){if(e===void 0)return;const t=An(e),n=t===null?null:new Date(Date.now()+t);if(t===null||!Number.isFinite(t)||t<=0||n===null||!Number.isFinite(n.getTime()))throw new m(422,"invalid_deadline","`deadline` must be a positive representable duration");return n.toISOString()}a(it,"parseDeadline");function dt(e){if(e!==void 0){if(typeof e!="object"||e===null||Array.isArray(e))throw new m(400,"invalid_request","`outcome_delivery` must be an object");if(typeof e.action!="string"||!Cn.test(e.action))throw new m(400,"invalid_request","`outcome_delivery.action` must be a declared action name");if(e.payload!==void 0){let t;try{t=JSON.stringify(e.payload)}catch{throw new m(400,"invalid_request","`outcome_delivery.payload` must be JSON-serializable")}if(t===void 0)throw new m(400,"invalid_request","`outcome_delivery.payload` must be JSON-serializable");if(Buffer.byteLength(t,"utf8")>ae)throw new m(413,"payload_too_large",`serialized payload exceeds ${ae} bytes`)}return e}}a(dt,"parseOutcomeDelivery");function st(e,t){const n=Nn(e.action,t);if(!("kind"in n))return{actionName:e.action,argv:n.argv,cwd:n.cwd,configOrigin:n.configOrigin,...e.payload===void 0?{}:{payload:e.payload}};throw n.kind==="unknown_action"?new m(422,"unknown_action",`no action named ${e.action} is declared from ${t}`):new m(422,"invalid_action",`${e.action} is declared in ${n.configOrigin} but unusable: ${n.reason}`,{reason:n.reason,configOrigin:n.configOrigin})}a(st,"resolveOutcomeDelivery");function at(e,t,n){const r={kind:e.kind,cwd:n,prompt:e.prompt??""};return e.mode!==void 0&&(r.mode=e.mode),e.name!==void 0&&(r.name=e.name),e.description!==void 0&&(r.description=e.description),t!==void 0&&(r.parent=t),e.creator!==void 0&&(r.creator=e.creator),e.scopes!==void 0&&(r.scopes=e.scopes),e.isolated!==void 0&&(r.isolated=e.isolated),e.root===!0&&(r.root=!0),e.root_lifecycle!==void 0&&(r.rootLifecycle=e.root_lifecycle),(e.worktree===!0||typeof e.worktree=="string")&&(r.worktree=!0),typeof e.worktree=="string"&&(r.worktreeBase=e.worktree),e.worktree!==void 0&&(r.worktreeCwd=T(e.pin_cwd??e.cwd??n)),e.fork_from!==void 0&&(r.forkFrom=e.fork_from),e.model!==void 0&&(r.model=e.model),e.profile!==void 0&&(r.profile=e.profile),e.situational_context!==void 0&&(r.situationalContext=e.situational_context),e.node_id!==void 0&&(r.nodeId=e.node_id),r}a(at,"buildRecipe");function lt(e,t,n){return!Pn()||e.prefer_warm!==!0||e.root!==!0||e.parent!=null||e.root_lifecycle==="terminal"||(e.prompt??"")!==""||e.model!==void 0||e.fork_from!==void 0||e.worktree!==void 0||e.node_id!==void 0||e.scopes!==void 0||e.isolated!==void 0?null:{kind:e.kind,mode:e.mode??"base",cwd:t,profileId:n,model:e.model??null,situationalContext:e.situational_context??null,name:e.name??null,creator:e.creator??null}}a(lt,"warmRequestFor");import{resolveCreateKind as tr}from"../../../core/runtime/launch-target.js";function he(e){const t=e.modelIntent===void 0?void 0:`${e.modelIntent.family}/${e.modelIntent.strength}`;return kn(e.model,t,e.modelExact===!0)}a(he,"requestFromLaunch");function ct(e,t){if(t===null)return e;if(e.scopes===void 0)return{...e,scopes:[...t]};const n=e.scopes.filter(r=>!O(t,r));if(n.length===0)return e;throw new m(403,"scope_denied",`scopes exceed the bearer token's ceiling: ${n.join(", ")}`,{scopes:n,ceiling:t})}a(ct,"withinCeiling");async function we(e,t,n){const r=(await gn(t.kind,t.mode,{lifecycle:t.lifecycle,hasManager:e.parent!==null,model:t.model,modelOverride:!0,cwd:e.cwd,profileId:e.profile_id??null})).launch;await B(he(r),{cwd:e.cwd,profileId:e.profile_id??null},n)}a(we,"assertNodeModelChangeRegistered");function ye(e,t){const n=e.principal;if(n.class!=="broker"&&n.class!=="cron")return;const r=Zn({app:n.app,resolved:Jn(n),launched:n.scopes},t,"read");if("root"in r)return;const o="missing"in r?r.missing:null;throw new m(403,"scope_missing",o?`the child's directory ${t} needs missing scope ${o}`:`no permission of this run names the child's directory ${t}`,void 0,void 0,o?{scope:o}:void 0)}a(ye,"assertCallerReaches");const Y=new Map;async function ft(e,t={},n={}){const r=ct(rt(e.body),e.ceiling);if(e.principal.class==="broker"){const l=e.principal;if(r.prefer_warm===!0&&l.app!=="app:terminal"&&(r.prefer_warm=!1),r.parent!=null){const i=y(r.parent);if(i.grantee!==l.app)throw new m(403,"other_app_run","cannot create a child under another app's node");if(!U(l,r.parent,i.grantee??"app:terminal"))throw E(`unknown node: ${r.parent}`,{received:r.parent})}if(r.creator!==void 0&&r.creator!==l.node)throw new m(403,"other_app_run","cannot create for another node");if(r.fork_from!==void 0){let i=null;try{i=Pe(Te(r.fork_from))}catch{}if(i?.grantee!==l.app||!U(l,i.node_id,i.grantee))throw new m(403,"other_app_run","cannot fork another app's conversation")}r.creator=l.node}if(e.principal.class==="cron"){const l=e.principal;for(const c of["parent","creator","fork_from","node_id"])if(r[c]!=null)throw new m(403,"permission_error",`a cron cannot set ${c} on a node it starts`);r.prefer_warm=!1;const i=Qe({grantee:l.app,sub:l.sub,grant_id:l.grant,scopes:l.scopes});if(!i.allowed)throw new m(i.reason==="scope_missing"?403:401,i.reason==="scope_missing"?"scope_missing":"grant_revoked",i.message);if(r.scopes!==void 0){const c=r.scopes.find(p=>!O(i.effectiveScopes,p)||!O(l.scopes,p));if(c!==void 0)throw new m(403,"scope_missing",`scope ${c} is not held by this cron`,void 0,void 0,{scope:c})}else l.scopes!==null&&(r.scopes=[...l.scopes]);r.node_id=ee(),l.isolated&&(r.isolated=!0,r.cwd=x(r.node_id,l.app))}r.creator!==void 0&&xn(y(r.creator),"crtr:act");const o=r.request_key?.trim();if(o===void 0||r.node_id!==void 0&&Ye(r.node_id)&&k(r.node_id)!==null&&Le(o)?.nodeId!==r.node_id)return P(e,r,t,n);const d=Y.get(o);if(d!==void 0)return d;const s=ut(e,r,o,t,n);Y.set(o,s);try{return await s}finally{Y.delete(o)}}a(ft,"handleCreate");async function ut(e,t,n,r,o){const d=oe(n);if(d.nodeId!==null&&k(d.nodeId)!==null){if(d.state!=="warm_claimed"){const s=k(d.nodeId);if(e.principal.class!=="person"&&!pe(e.principal,s.grantee??"app:terminal",d.nodeId))throw new m(409,"create_request_conflict","request_key belongs to another caller");return{status:201,body:g(d.nodeId)}}return P(e,t,r,o,d)}try{return await P(e,t,r,o,d)}catch(s){const l=oe(n);throw(l.nodeId===null||k(l.nodeId)===null)&&ne(n,l.nodeId),s}}a(ut,"handleKeyedCreateRequest");async function P(e,t,n,r,o=void 0){const d=r.deadlineAt??it(t.deadline),s=dt(t.outcome_delivery),l=e.principal.class==="cron"?Xe({grantee:e.principal.app,sub:e.principal.sub,grant_id:e.principal.grant,scopes:e.principal.scopes,cron_id:e.principal.cron,origin_run_id:e.principal.origin_run,isolated:e.principal.isolated,creator:fe(e.principal.cron)?.created_by??null},t.node_id):null;l!==null&&(t.root=l.root===!0);const i=l?.parent??t.parent??void 0;if(i==null&&t.root!==!0)throw h("a node create requires a parent (or root: true for an independent root)");let c=null;if(t.output_schema!==void 0)try{c=JSON.parse(t.output_schema)}catch{throw h("output_schema must be a JSON schema string")}const{profileId:p,kind:u,cwd:f,launch:_}=await Ln(t,{validateKind:ke});ye(e,f),t.worktree!==void 0&&ye(e,T(t.pin_cwd??t.cwd??f));const S={...t,kind:u},I=s===void 0?void 0:st(s,f);if(await B(he(_),{cwd:f,profileId:p},n.modelRegistry),!await tt(p))throw new m(412,"no_provider_credential",me,{error:"no_provider_credential",message:me,next:"The person running this runtime logs a provider in with `crtr sys setup`, or stores a provider key on the profile."});let L=null;{const $=o===void 0||o.nodeId===null||o.state==="warm_claimed"?lt(S,f,p):null,M=c===null&&r.beforeBrokerLaunch===void 0?void 0:v=>{c!==null&&$n(v,"terminal",c),r.beforeBrokerLaunch?.(v)};if(o?.state==="warm_claimed"&&o.nodeId!==null){const v=$===null?null:await En($,o.nodeId,M);if(v===null)throw ne(o.requestKey,o.nodeId),new m(503,"create_resume_failed",`could not resume warm claim ${o.nodeId}; retry the create`);return te(o.requestKey,v),{status:201,body:g(v)}}if($!==null){const v=await Tn($,{...d===void 0?{}:{deadlineAt:d},...I===void 0?{}:{outcomeDelivery:I},...o===void 0?{}:{requestKey:o.requestKey}},M);if(v!==null)return o!==void 0&&te(o.requestKey,v),le($),{status:201,body:g(v)};L=$}const j=o?.nodeId??t.node_id??(o===void 0?void 0:ee());o!==void 0&&o.nodeId===null&&je(o.requestKey,j);const R=at(j===void 0?S:{...S,node_id:j},i,f);l!==null&&(l.rootLifecycle!==void 0&&(R.rootLifecycle=l.rootLifecycle),l.scopes!==void 0&&S.scopes===void 0&&(R.scopes=l.scopes),l.run!==void 0&&(R.run=l.run),l.withinCreate!==void 0&&(R.withinCreate=l.withinCreate)),d!==void 0&&(R.deadlineAt=d),I!==void 0&&(R.outcomeDelivery=I),R.readiness=t.root===!0?"await":"launch";const Q=await Ee(R,M,()=>{L!==null&&le(L)});return o!==void 0&&Me(o.requestKey,Q.node.node_id),{status:201,body:g(Q.node.node_id)}}}a(P,"handleCreateRequest");function b(e,t){const n=e.query.getAll(t);if(n.length>1)throw h(`${t} must appear at most once`);return n[0]}a(b,"singleQueryValue");function _e(e,t){if(e!==void 0){if(e==="1"||e==="true")return!0;if(e==="0"||e==="false")return!1;throw h(`${t} must be true or false`)}}a(_e,"optionalBoolean");function D(e,t,n){if(e!==void 0){if(n.includes(e))return e;throw h(`${t} must be one of: ${n.join(", ")}`)}}a(D,"oneOf");function pt(e){const t=new Set(["status","lifecycle","kind","mode","profile_id","profile_prefix","parent","top_level","under","hanging","include"]);for(const[_]of e.query)if(!t.has(_))throw h(`unknown nodes query parameter: ${_}`);const n=D(b(e,"status"),"status",["active","idle","done","dead","canceled"]),r=D(b(e,"lifecycle"),"lifecycle",["terminal","resident"]),o=b(e,"kind"),d=D(b(e,"mode"),"mode",["base","orchestrator"]),s=b(e,"profile_id"),l=b(e,"profile_prefix"),i=b(e,"parent"),c=_e(b(e,"top_level"),"top_level"),p=b(e,"under"),u=_e(b(e,"hanging"),"hanging"),f=D(b(e,"include"),"include",["activity"]);if(i!==void 0&&c===!0)throw h("parent and top_level=true cannot be combined");return{...n!==void 0?{status:n}:{},...r!==void 0?{lifecycle:r}:{},...o!==void 0?{kind:o}:{},...d!==void 0?{mode:d}:{},...s!==void 0?{profile_id:s}:{},...l!==void 0?{profile_prefix:l}:{},...i!==void 0?{parent:i}:{},...c!==void 0?{top_level:c}:{},...p!==void 0?{under:p}:{},...u!==void 0?{hanging:u}:{},...f!==void 0?{include:f}:{}}}a(pt,"parseListQuery");function mt(e){const t=pt(e);let n=t.status!==void 0?re({status:t.status}):re();if(e.principal.class!=="person"&&(n=n.filter(s=>pe(e.principal,s.grantee??"app:terminal",s.node_id))),t.lifecycle!==void 0&&(n=n.filter(s=>s.lifecycle===t.lifecycle)),t.kind!==void 0&&(n=n.filter(s=>s.kind===t.kind)),t.mode!==void 0&&(n=n.filter(s=>s.mode===t.mode)),t.profile_id!==void 0&&(n=n.filter(s=>s.profile_id===t.profile_id)),t.profile_prefix!==void 0&&(n=n.filter(s=>s.profile_id?.startsWith(t.profile_prefix))),t.parent!==void 0&&(n=n.filter(s=>s.parent===t.parent)),t.top_level===!0&&(n=n.filter(s=>s.parent===null)),t.under!==void 0){const s=new Set(Ke(t.under));n=n.filter(l=>s.has(l.node_id))}t.hanging===!0&&(n=n.filter(s=>s.parent!==null&&k(s.parent)===null));const r=t.include==="activity"?He(n.map(s=>s.node_id)):null,o=n.length>0?Oe():new Set;return{status:200,body:n.map(s=>{const l=Vn(s,s.profile_id!==null&&o.has(s.profile_id));if(r!==null){const i=ce(s.node_id);l.activity={latest_report:i[0]??null,final_report:s.final_report===null?null:i.find(c=>c.name===s.final_report)??null,pending_human_count:r[s.node_id]??0}}return l})}}a(mt,"handleList");async function ht(e){const t=e.params.id,n=await Un(e,t,{method:"GET",path:`/v1/nodes/${encodeURIComponent(t)}`,query:Hn(e)});if(n.kind==="unknown")throw Qn(t,n.unreachable);if(n.kind==="remote"){if(n.status>=400)throw Yn(n.status,n.body);return{status:n.status,body:Xn(n.body,n.machine)}}return y(t),{status:200,body:g(t)}}a(ht,"handleDetail");async function wt(e){const t=e.params.id;y(t);const n=await rn(t);return{status:200,body:{node_id:t,snapshot:{messages:n.snapshot.messages,...n.snapshot.messageIds===void 0?{}:{messageIds:n.snapshot.messageIds},messageVisibility:n.snapshot.messageVisibility,turnVisibility:n.snapshot.turnVisibility,stats:n.snapshot.stats,state:n.snapshot.state,display:n.snapshot.display,...n.snapshot.queued===void 0?{}:{queued:n.snapshot.queued},...n.snapshot.toolGroupSummaries===void 0?{}:{toolGroupSummaries:n.snapshot.toolGroupSummaries},...n.snapshot.turnReplies===void 0?{}:{turnReplies:n.snapshot.turnReplies},...n.snapshot.workingActivity===void 0?{}:{workingActivity:n.snapshot.workingActivity}},commands:n.commands.map(o=>({name:o.name,description:o.description,source:o.source})),captured_at:G()}}}a(wt,"handleSnapshot");async function yt(e){const t=e.params.id,n=sn(t);if(n===null)throw E(`unknown node: ${t}`,{received:t});return{status:200,body:n}}a(yt,"handleSubject");function _t(e){for(const[d]of e.query)if(d!=="cursor"&&d!=="limit")throw h(`unknown messages query parameter: ${d}`);const t=e.query.getAll("cursor"),n=e.query.getAll("limit");if(t.length>1)throw h("cursor must appear at most once");if(n.length>1)throw h("limit must appear at most once");if(n.length===0)return t.length===0?{}:{cursor:t[0]};const r=n[0],o=Number(r);if(!Number.isSafeInteger(o)||r==="")throw h("limit must be an integer from 1 through 500");return t.length===0?{limit:o}:{cursor:t[0],limit:o}}a(_t,"parseMessagesQuery");async function gt(e){const t=e.params.id,n=await tn(t,_t(e));return{status:200,body:{node_id:t,messages:n.messages,...n.messageIds===void 0?{}:{message_ids:n.messageIds},message_visibility:n.messageVisibility,next_cursor:n.nextCursor,captured_at:G()}}}a(gt,"handleMessages");function bt(e){const t=e.params.id;y(t);const n=on(t);return{status:200,body:{node_id:t,session_file:n.sessionFile,session_jsonl:n.sessionJsonl,system_prompt:n.systemPrompt,captured_at:G()}}}a(bt,"handleSession");async function vt(e){const t=e.params.id;return y(t),{status:200,body:{node_id:t,markdown:await dn(t)}}}a(vt,"handleTranscript");function kt(e){const t=e.params.id;y(t);const n=a((o,d)=>({node_id:o,label:k(o)?.name??o,dir:de(o),self:d,files:ot(o)}),"root"),r=[n(t,!0),...ie(t).map(o=>n(o.node_id,!1))].filter(o=>St(o.node_id,o.dir)||o.files>0);return{status:200,body:{node_id:t,roots:r}}}a(kt,"handleContext");function St(e,t){try{return Ze(x(e),t)}catch(n){if(en(n))return!1;throw n}}a(St,"hasDir");async function Rt(e){const t=y(e.params.id),n=e.principal.class==="broker"?e.principal.scopes:e.ceiling,r=n===null?void 0:t.scopes==null?[...n]:[...new Set([...t.scopes.filter(d=>O(n,d)),...n.filter(d=>O(t.scopes,d))])],o=await Ae(t.node_id,r,e.principal.class==="broker"?e.principal.node:void 0);return{status:201,body:g(o.node.node_id)}}a(Rt,"handleFork");async function Ot(e){const t=e.params.id;y(t);const n=e.body,r=n?.resume??!0,o=n?.reopen??!1;pn(t,o);const d=!r&&n?.cron_id!==void 0?fe(n.cron_id):null,s=await Ne(t,{resume:r,capacity:"refuse",...d!==null?{wakeReason:Bn(d,"schedule_revive")}:{}});s.outcome!=="already-live"&&Fe(t,{failures:0,notBefore:null});const l=k(t)?.status??"active";return{status:200,body:zn(t,s,l)}}a(Ot,"handleRevive");async function It(e){const t=e.params.id;return{status:200,body:{newNodeId:(await un(t))?.newNodeId??null}}}a(It,"handleRelaunchRoot");function $t(e){const t=e.params.id;y(t);const n=e.body;if(n?.caller_pid!==void 0&&(!Number.isInteger(n.caller_pid)||n.caller_pid<=0))throw h("caller_pid must be a positive integer when provided");const r=Kn(),o=Ce(t,{rootEvent:n?.finish===!0?"finish":"cancel",callerPid:n?.caller_pid,...e.principal.class==="broker"?{closer:e.principal.node}:{},...r===null?{}:{registerDetached:r.registerDetached}});return{status:200,body:Wn(o)}}a($t,"handleClose");async function Ct(e){const t=e.params.id;y(t);const n=await fn(t);return{status:200,body:{recycled:n.recycled,finalized:n.finalized,new_root:n.newRoot,delivered:n.delivered}}}a(Ct,"handleRecycle");async function Nt(e){const t=e.params.id;return y(t),await W(t,{lifecycle:"terminal"}),C(e,t,["lifecycle"]),{status:200,body:g(t)}}a(Nt,"handleDemote");async function At(e,t={}){const n=e.params.id,r=y(n),o=e.body??{};o.kind!==void 0&&await z(o.kind,r.cwd,r.profile_id??null),o.model!==void 0&&await we(r,{kind:o.kind??r.kind,mode:"orchestrator",lifecycle:o.resident===!0?"resident":r.lifecycle,model:o.model},t.modelRegistry);const d=await ln(n,{...o.kind!==void 0?{kind:o.kind}:{},...o.resident===!0?{resident:!0}:{},...o.model!==void 0?{model:o.model}:{}});C(e,n,["mode",...o.kind!==void 0?["kind"]:[],...o.resident===!0?["lifecycle"]:[],...o.model!==void 0?["model"]:[]]);const s=J(d.meta,H(n));return s.roadmap_written=d.roadmapWritten,s.roadmap_ref=d.roadmapRef,s.goal_path=d.goalPath,{status:200,body:s}}a(At,"handlePromote");async function Tt(e,t={}){const n=e.params.id,r=y(n),o=e.body??{};o.kind!==void 0&&await z(o.kind,r.cwd,r.profile_id??null),o.model!==void 0&&await we(r,{kind:o.kind??r.kind,mode:o.promote===!0?"orchestrator":r.mode,lifecycle:r.lifecycle,model:o.model},t.modelRegistry);const d=o.note??"Refresh: continue against your roadmap or goal.";mn(n,d);const s=await cn(n,{...o.promote===!0?{promote:!0}:{},...o.kind!==void 0?{kind:o.kind}:{},...o.model!==void 0?{model:o.model}:{}});return{status:200,body:J(s.meta,H(n))}}a(Tt,"handleYield");function Et(e){const t=e.params.id;y(t);const n=e.body;if(n===void 0||typeof n.controller!="string"||n.controller.trim()==="")throw h("a wait requires a controller node id");const r=k(n.controller);if(r===null)throw E(`unknown controller: ${n.controller}`,{received:n.controller});if(r.status!=="active"&&r.status!=="idle")throw new m(422,"unprocessable",`controller ${n.controller} is ${r.status}`);return Be(t,n.controller),{status:200,body:g(t)}}a(Et,"handleWait");async function Pt(e){const t=e.principal,n=await an(t.class==="broker"?o=>o.grantee===t.app&&U(t,o.node_id,o.grantee):void 0);return{status:200,body:{revived:[...n.revived],failed:[...n.failed],frozen:[...n.frozen]}}}a(Pt,"handleReviveAll");const Dt=new Set(["interrupt","steer","after-turn","next-turn"]);function Lt(e){if(e===null)return null;const t=a(r=>{throw new w({error:"invalid_listen",message:r,received:e,field:"listen",next:'Send an object mapping levels "1".."10" to interrupt|steer|after-turn|next-turn (e.g. {"3":"next-turn"}), or null to reset to the global default.'})},"bad");if(typeof e!="object"||Array.isArray(e))return t("listen must be an object or null");const n=Object.entries(e);if(n.length===0)return t("listen must name at least one level");for(const[r,o]of n)/^(?:[1-9]|10)$/.test(r)||t(`listen level must be 1..10: ${r}`),(typeof o!="string"||!Dt.has(o))&&t(`listen delivery must be interrupt|steer|after-turn|next-turn: ${String(o)}`);return JSON.stringify(Object.fromEntries(n))}a(Lt,"listenJson");function C(e,t,n,r){n.length===0&&r===void 0||K(o=>{if(r?.(o),n.length===0)return;const d=xe(o,t),s=ze(o,e),l=s.class==="person"?s.person:s.class==="app"?s.app:s.node;We(o,l,d),Ve(o,{event:"configured",object:d,actor:l,attrs:{changed:n.join(",")}})})}a(C,"recordConfigured");function ge(e){const t=V().get(e);if(t===void 0)return!1;try{return process.kill(t.pid,"SIGTERM"),!0}catch{return!1}}a(ge,"restartLiveBroker");function be(e,t){try{return Z(e)===Z(t)}catch{return!1}}a(be,"sameDirectory");async function Mt(e,t={}){const n=e.params.id,r=e.body;let o;if(r===void 0)o={};else if(typeof r=="object"&&r!==null&&!Array.isArray(r))o=r;else throw new w({error:"cwd_invalid",message:"cwd repair requires a non-null object with a non-empty cwd string",received:r,field:"cwd",next:"Send a config patch with a non-empty absolute cwd string."});if(o.profile!==void 0){if(typeof o.profile!="string"||o.profile==="")throw new w({error:"profile_invalid",message:"profile must be a non-empty profile id or name",received:o.profile,field:"profile",next:"Send a profile id or exact name."});if(Object.keys(o).some(u=>u!=="profile"&&u!=="restart"&&o[u]!==void 0))throw new w({error:"profile_not_exclusive",message:"profile can only be combined with restart",field:"profile",next:"Send profile (and optionally restart) alone."});const i=y(n),c=jn(e,o.profile);Fn(c.profileId);const p=Gn(c.profileId).manifest.grantee??"app:terminal";if(p!==(i.grantee??"app:terminal"))throw new w({error:"profile_grantee_mismatch",message:`profile ${c.profileId} belongs to ${p}, node ${n} to ${i.grantee}`,received:o.profile,field:"profile",next:"Pick a profile owned by the same app as the node."});return(i.profile_id??null)!==c.profileId&&(Dn(i.kind)?(await z(i.kind,i.cwd,c.profileId),await W(n,{profileId:c.profileId})):N(n,{profile_id:c.profileId}),C(e,n,["profile"])),o.restart===!0&&ge(n),{status:200,body:g(n)}}if(Object.prototype.hasOwnProperty.call(o,"cwd")){const i=o.cwd;if(typeof i!="string"||i==="")throw new w({error:"cwd_invalid",message:"cwd must be a non-empty string",received:i,field:"cwd",next:"Send a non-empty absolute cwd string."});if(Object.keys(o).some(f=>f!=="cwd"&&f!=="keep_session"&&f!=="restart"&&o[f]!==void 0))throw new w({error:"cwd_not_exclusive",message:"cwd repair cannot be combined with another config field",received:o,field:"cwd",next:"Send cwd as the only config field."});const c=y(n),p=A(c.cwd);if(o.keep_session===!0||p&&F(i)&&A(i)&&be(c.cwd,i)){if(!F(i))throw new w({error:"cwd_not_absolute",message:`cwd must be an absolute path: ${i}`,received:i,field:"cwd",next:"Send an absolute path."});const f=T(i);let _=!1;try{_=q(f).isDirectory()}catch{}if(!_)throw new w({error:"cwd_missing",message:`cwd is not an existing directory: ${f}`,received:i,field:"cwd",next:"Send an existing absolute directory."});if(p&&!be(c.cwd,f))throw new w({error:"cwd_not_same_directory",message:`${f} is not the same directory as the recorded ${c.cwd}; --keep-session only relocates an alias`,received:i,field:"cwd",next:"Drop --keep-session to repair a gone cwd, or pass the real path of the recorded directory."});if(c.managed_worktree?.state==="open")throw new w({error:"cwd_node_managed_worktree_open",message:`${n} owns an open managed worktree and cannot relocate its cwd`,received:i,field:"cwd",next:"Reconcile the managed worktree first."});const S=c.cwd;return S!==f&&(K(I=>{N(n,{cwd:f}),X(I,"UPDATE crons SET cwd = ? WHERE anchor_node = ? AND cwd = ?").run(f,n,S),Je(n,S,f)}),C(e,n,["cwd"])),o.restart===!0&&ge(n),{status:200,body:g(n)}}if(V().has(n)){const f=`${n} cannot repair its cwd while its broker is live`;throw new m(409,"cwd_node_live",f,{error:"cwd_node_live",message:f,received:i,field:"cwd",next:"Let the node become dormant, then retry the cwd repair."})}if(c.fork_from!=null)throw new w({error:"cwd_node_forked",message:`${n} is a fork and cannot repair its cwd; recorded cwd: ${c.cwd}`,received:i,field:"cwd",next:`Restore ${c.cwd}, then revive the fork normally.`});if(c.managed_worktree?.state==="open")throw new w({error:"cwd_node_managed_worktree_open",message:`${n} owns an open managed worktree and cannot repair its cwd`,received:i,field:"cwd",next:"Restore or reconcile the recorded checkout, then use the managed-worktree close or abandon flow."});if(A(c.cwd))throw new w({error:"cwd_still_present",message:`${n} recorded cwd still exists: ${c.cwd}; cwd repair is not a relocation command`,received:i,field:"cwd",next:"This command only repairs a node whose recorded cwd is gone."});if(!F(i))throw new w({error:"cwd_not_absolute",message:`cwd must be an absolute path: ${i}`,received:i,field:"cwd",next:"Send an absolute path."});const u=T(i);if(!A(u))throw new w({error:"cwd_missing",message:`cwd does not exist: ${u}`,received:i,field:"cwd",next:"Create the replacement directory or send an existing absolute directory."});try{if(!q(u).isDirectory())throw new w({error:"cwd_not_a_directory",message:`cwd is not a directory: ${u}`,received:i,field:"cwd",next:"Send an existing absolute directory."})}catch(f){throw f instanceof w?f:new w({error:"cwd_missing",message:`cwd does not exist: ${u}`,received:i,field:"cwd",next:"Create the replacement directory or send an existing absolute directory."})}return K(()=>{N(n,{cwd:u}),Ue(n)}),C(e,n,["cwd"]),{status:200,body:g(n)}}let d=y(n);const s=o.listen===void 0?void 0:Lt(o.listen);if(o.scopes!==void 0){const i=ue(o.scopes),c=d.grantee==="app:terminal"?et():d.grant_id?qn(d.grant_id):null,p=d.grantee==="app:terminal"&&!nt("user").runtime?.issuer;if(!i.every(u=>O(d.scopes,u)&&(c?O(c.resolved,u):p)))throw new w({error:"unknown_scope",message:"scopes may only narrow the node's current effective set",received:i,field:"scopes",next:"Send only scopes the node currently holds."});if(i.includes("crtr:act")&&!O(i,"crtr:llm"))throw new m(400,"invalid_scope","crtr:act requires crtr:llm");d=N(n,{scopes:i})}if(o.situational_context!==void 0&&Ie(n,$e(o.situational_context)),o.model!==void 0){const i=(await se(d.cwd,d.profile_id??null)).modelLadders,c=bn(o.model,i),p=vn(o.model,i);await B({kind:"concrete",spec:p},{cwd:d.cwd,profileId:d.profile_id??null},t.modelRegistry);const u=V();let f=!1;if(u.isClaimed(n)&&await On(n,u.get(n)?.handle.exited)&&(f=await Rn(n,p,c).then(()=>!0,_=>{if(_ instanceof In)return!1;throw _})),!f){if(u.isClaimed(n)){const _=`${n}'s broker did not accept the model switch; the model was not changed`;throw new m(409,"broker_not_ready",_,{error:"broker_not_ready",message:_,received:o.model,field:"model",next:"Check the node with `crtr node show`, then retry the model change."})}if(!p.includes("/"))throw h(`model must resolve to a provider/id spec: ${o.model}`);Sn(n,p,c)}d=y(n)}if(o.kind!==void 0||o.mode!==void 0||o.lifecycle!==void 0){o.kind!==void 0&&await ke(o.kind);const i=o.kind??d.kind,c=o.mode??d.mode,p=o.lifecycle??d.lifecycle;let u;c==="orchestrator"&&!yn(n)&&(u=a(()=>{const f=hn(n);wn(n,f!==null&&f.trim()!==""?{goal:f.trim()}:{})},"beforePersist")),d=await W(n,{...o.kind!==void 0?{kind:i}:{},...o.mode!==void 0?{mode:c}:{},...o.lifecycle!==void 0?{lifecycle:p}:{}},u)}o.name!==void 0&&(d=N(n,{name:o.name}),d.window&&_n(d.window,Mn(d)));const l=["scopes","situational_context","model","kind","mode","lifecycle","name","listen"].filter(i=>o[i]!==void 0);return C(e,n,l,s===void 0?void 0:i=>{X(i,"UPDATE objects SET listen_json = ? WHERE id = ? AND type = 'node'").run(s,n)}),{status:200,body:g(n)}}a(Mt,"handleConfig");async function ve(){return(await se(process.cwd(),Re()||null)).kinds}a(ve,"daemonKinds");async function ke(e){const t=Object.keys(await ve());if(!t.includes(e))throw h(`unknown kind: ${e}`,{received:e,next:`Valid kinds: ${t.sort().join(", ")}.`})}a(ke,"assertKindServer");async function jt(){const e=await ve();return{status:200,body:{kinds:Object.keys(e).sort().map(n=>({kind:n,when_to_use:e[n]?.whenToUse??null,available_to:e[n]?.availableTo??null}))}}}a(jt,"handleListKinds");const qo=[{method:"POST",pattern:"/v1/nodes",scope:"crtr:act",handler:ft},{method:"GET",pattern:"/v1/nodes",handler:mt},{method:"GET",pattern:"/v1/kinds",handler:a(()=>jt(),"handler")},{method:"POST",pattern:"/v1/nodes/revive-all",scope:"crtr:act",handler:Pt},{method:"GET",pattern:"/v1/nodes/:id",handler:ht},{method:"GET",pattern:"/v1/nodes/:id/snapshot",handler:wt},{method:"GET",pattern:"/v1/nodes/:id/subject",handler:yt},{method:"GET",pattern:"/v1/nodes/:id/messages",handler:gt},{method:"GET",pattern:"/v1/nodes/:id/session",handler:bt},{method:"GET",pattern:"/v1/nodes/:id/transcript",handler:vt},{method:"GET",pattern:"/v1/nodes/:id/context",handler:kt},{method:"POST",pattern:"/v1/nodes/:id/fork",scope:"crtr:act",handler:Rt},{method:"POST",pattern:"/v1/nodes/:id/revive",scope:"crtr:act",handler:Ot},{method:"POST",pattern:"/v1/nodes/:id/relaunch-root",scope:"crtr:act",handler:It},{method:"POST",pattern:"/v1/nodes/:id/close",handler:$t},{method:"POST",pattern:"/v1/nodes/:id/recycle",scope:"crtr:act",handler:Ct},{method:"POST",pattern:"/v1/nodes/:id/demote",scope:"crtr:act",handler:Nt},{method:"POST",pattern:"/v1/nodes/:id/promote",scope:"crtr:act",handler:At},{method:"POST",pattern:"/v1/nodes/:id/yield",scope:"crtr:act",handler:Tt},{method:"POST",pattern:"/v1/nodes/:id/wait",handler:Et},{method:"PATCH",pattern:"/v1/nodes/:id/config",handler:Mt}];export{Mt as handleConfig,ft as handleCreate,Rt as handleFork,mt as handleList,At as handlePromote,Tt as handleYield,qo as nodeRoutes,tr as resolveCreateKind};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var Z=Object.defineProperty;var f=(e,r)=>Z(e,"name",{value:r,configurable:!0});import{prepared as J}from"../../../core/sqlite-statements.js";import{ApiError as g}from"../../../api/errors.js";import{PRIVACY_LEVELS_DTO as K}from"../../../api/dto/objects.js";import{openDb as A,withCanvasWrite as b}from"../../../core/canvas/db.js";import{actorOf as $}from"../../../core/graph/documents.js";import{readerForObject as F}from"../../../core/graph/reader.js";import{canRead as U}from"../../../core/graph/access.js";import{customObjectRef as I,authorizeCustom as S,fenceArgv as C}from"./custom-objects.js";import{edgesOf as Y}from"../../../core/graph/edges.js";import{publish as B}from"../../../core/graph/events.js";import{objectDTO as a}from"../../../core/graph/kinds/dto.js";import{isKind as Q,kindNames as X,kindOf as D}from"../../../core/graph/kinds/registry.js";import{listObjects as x,searchObjects as L}from"../../../core/graph/objects.js";import{checkoutsForCwd as ee}from"../../../core/graph/repo-sync/repos.js";import{recordWatch as te,unwatch as re,watchersOf as ne,watchesOf as oe}from"../../../core/graph/watches.js";import{readerFor as m,resolveRef as P}from"../reader.js";import{invalidRequest as E,isRecord as v}from"./validate.js";const W=f(e=>r=>ee(e,r),"reposFnFor");function z(e,r){return{...a(e,r),...D(e,r.type).listItem?.(e,r)}}f(z,"listItem");function ie(e){return`no object named ${e} on this runtime; it may be on another runtime, or the name may be misspelled`}f(ie,"remoteMessage");function G(e,r,t){try{return k(e,r,t)}catch(o){if(o instanceof g&&o.code==="not_found"&&!o.details?.deleted)return null;throw o}}f(G,"ownerFilter");function k(e,r,t){const o=P(e,r,t);if("remote"in o)throw new g(404,"not_found",ie(o.remote),{next:"Check the name with `crtr canvas search`."});if("deleted"in o)throw new g(404,"not_found",`${o.deleted.name} is deleted`,{id:o.deleted.id,deleted:!0});return o}f(k,"liveRef");const O=f(e=>decodeURIComponent(e.params.ref),"refParam");function se(e){const r=["1","true"].includes(e.query.get("fields")??"");return b(t=>{const o=m(t,e),n=P(t,o,O(e));if("remote"in n)return{state:"remote",remote:n.remote};if("deleted"in n)return{state:"deleted",deleted:a(t,n.deleted)};const{data:i,text:s}=D(t,n.type).read(t,o,n,{fields:r,reposFn:W(t)});return{state:"object",type:n.type,object:a(t,n),text:s,data:i}})}f(se,"read");function q(e,r,t,o){if(e!=null){if(!t.includes(e)){o.push({field:r,problem:`must be one of ${t.join(", ")}`,received:e});return}return e}}f(q,"oneOf");function V(e,r,t){if(r!=null){if(typeof r!="string"||!Q(e,r)){t.push({field:"type",problem:`must be a kind: one of ${X(e).join(", ")}`,received:r});return}return r}}f(V,"kindName");function H(e,r,t,o){if(e==null)return o;const n=Number(e);return!Number.isInteger(n)||n<1||n>100?(t.push({field:r,problem:"must be an integer from 1 to 100",received:e}),o):n}f(H,"limitOf");function ce(e){const r=e.query,t=[],o=V(A(),r.get("type"),t),n=q(r.get("privacy"),"privacy",K,t),i=H(r.get("limit"),"limit",t,50),s=r.get("cursor");s!==null&&!/^\d+$/.test(s)&&t.push({field:"cursor",problem:"is not a cursor from a previous page",received:s});const c=r.get("deleted");return c!==null&&!["0","1","true","false"].includes(c)&&t.push({field:"deleted",problem:"must be true or false",received:c}),t.length>0&&E("object list request",t),b(u=>{const d=m(u,e),p={...o?{type:o}:{},...n?{privacy:n}:{},...r.get("kind")!==null?{kind:r.get("kind")}:{},...c==="1"||c==="true"?{deleted:!0}:{}},h=r.get("owner");if(h!==null){const y=G(u,d,h);if(y===null)return{items:[],next_cursor:null};p.owner=y}const _=r.get("name"),w=[];let l=s===null?0:Number(s),T=!0;for(;w.length<i&&T;){const y=x(u,d,p,{limit:100,after_rowid:l});T=y.length===100;for(const R of y)if(l=R.rowid,(_===null||R.name.startsWith(_))&&w.push(R),w.length===i)break}const N=w.at(-1);return{items:w.map(y=>z(u,y)),next_cursor:w.length===i&&N?String(N.rowid):null}})}f(ce,"list");function ue(e){const r=[],t=v(e.body)?e.body:{};v(e.body)||r.push({field:"body",problem:"must be an object",received:e.body});const o=t.text;(typeof o!="string"||o.trim()==="")&&r.push({field:"text",problem:"is required",received:o});const n=t.grep;if(n!==void 0)if(typeof n!="string")r.push({field:"grep",problem:"must be a regular expression string",received:n});else try{new RegExp(n)}catch(c){r.push({field:"grep",problem:`is not a valid regular expression: ${c.message}`,received:n})}t.body!==void 0&&typeof t.body!="boolean"&&r.push({field:"body",problem:"must be a boolean",received:t.body});const i=V(A(),t.type,r);t.kind!==void 0&&typeof t.kind!="string"&&r.push({field:"kind",problem:"must be a string",received:t.kind}),t.owner!==void 0&&typeof t.owner!="string"&&r.push({field:"owner",problem:"must be a string",received:t.owner});const s=H(t.limit,"limit",r,50);return r.length>0&&E("object search request",r),b(c=>{const u=m(c,e),d=typeof t.owner=="string"?G(c,u,t.owner):null;if(typeof t.owner=="string"&&d===null)return{items:[]};const p=L(c,u,{text:o,body:t.body===!0||typeof n=="string"}),h=new Set(p.map(l=>l.object.rowid));return{items:(typeof n=="string"?L(c,u,{text:n,grep:!0}).filter(l=>h.has(l.object.rowid)):p).filter(l=>(!i||l.object.type===i)&&(t.kind===void 0||l.object.kind===t.kind)&&(!d||l.object.owner===d.rowid)).slice(0,s).map(l=>({object:z(c,l.object),...l.line!==void 0?{matches:[{line:l.line,text:l.text??""}]}:{}}))}})}f(ue,"search");const M=["interrupt","steer","after-turn","next-turn"],fe=/^(\*|>|[A-Za-z0-9_-]+)(\.(\*|>|[A-Za-z0-9_-]+))*$/;function de(e,r){if(e!==void 0){if(!Array.isArray(e)||e.length===0||e.some(t=>typeof t!="string"||!fe.test(t)||t.includes(">")&&!t.endsWith(">"))){r.push({field:"patterns",problem:"must be a non-empty list of event patterns (dot-separated words, `*` for one word, a final `>` for the rest)",received:e});return}return e}}f(de,"patternsOf");function le(e,r){if(e===void 0)return;if(!v(e)||Object.keys(e).length===0){r.push({field:"config",problem:"must map levels 1-10 to a delivery",received:e});return}const t=[];for(const[o,n]of Object.entries(e)){const i=Number(o);!Number.isInteger(i)||i<1||i>10?r.push({field:`config.${o}`,problem:"level must be an integer from 1 to 10"}):M.includes(n)?t.push({threshold:i,delivery:n}):r.push({field:`config.${o}`,problem:`delivery must be one of ${M.join(", ")}`,received:n})}return t.sort((o,n)=>n.threshold-o.threshold)}f(le,"configOf");function ae(e){const r=[],t=e.body===void 0?{}:v(e.body)?e.body:(r.push({field:"body",problem:"must be an object"}),{}),o=de(t.patterns,r),n=le(t.config,r);return t.filter!==void 0&&!v(t.filter)&&r.push({field:"filter",problem:"must be an object",received:t.filter}),t.watcher!==void 0&&typeof t.watcher!="string"&&r.push({field:"watcher",problem:"must be a custom-object ref",received:t.watcher}),r.length>0&&E("watch request",r),b(i=>{const s=typeof t.watcher=="string"?I(i,t.watcher):null;if(e.publishToken&&!s)throw new g(404,"not_found","watcher not found");if(e.principal.class==="anonymous"&&!s)throw new g(404,"not_found","watcher not found");const c=s?S(i,e,s):$(m(i,e));s&&C(i,e,s);const u=s?F(i,s):m(i,e),d=s?(()=>{const h=k(i,u,O(e));if(!U(i,u,h))throw new g(404,"not_found","object not found");return h})():k(i,u,O(e)),p=o??[">"];return te(i,s??c,d,s?"act":"ask",{patterns:p,...n?{config:n}:{},...t.filter!==void 0?{filter:t.filter}:{}}),B(i,{event:"watched",object:d,actor:c,attrs:{}},W(i)),{object:a(i,d),patterns:p}})}f(ae,"watch");function pe(e){const r=e.query.get("pattern"),t=e.query.get("watcher");return b(o=>{const n=t?I(o,t):null;if((e.publishToken||e.principal.class==="anonymous")&&!n)throw new g(404,"not_found","watcher not found");const i=n?S(o,e,n):$(m(o,e));n&&C(o,e,n);const s=n?F(o,n):m(o,e),c=k(o,s,O(e)),u=f(()=>J(o,`SELECT count(*) AS n FROM watch_subscriptions s JOIN watches w ON w.rowid = s.watch
|
|
2
|
-
WHERE w.watcher = ? AND w.object = ?`).get((
|
|
1
|
+
var we=Object.defineProperty;var u=(e,t)=>we(e,"name",{value:t,configurable:!0});import{prepared as ye}from"../../../core/sqlite-statements.js";import{ApiError as w}from"../../../api/errors.js";import{PRIVACY_LEVELS_DTO as be}from"../../../api/dto/objects.js";import{openDb as T,withCanvasWrite as y}from"../../../core/canvas/db.js";import{actorOf as V}from"../../../core/graph/documents.js";import{readerForObject as A}from"../../../core/graph/reader.js";import{canRead as ge}from"../../../core/graph/access.js";import{customObjectRef as H,authorizeCustom as B,fenceArgv as Z}from"./custom-objects.js";import{edgesOf as je}from"../../../core/graph/edges.js";import{publish as ke}from"../../../core/graph/events.js";import{objectDTO as b}from"../../../core/graph/kinds/dto.js";import{isKind as _e,kindNames as ve,kindOf as J}from"../../../core/graph/kinds/registry.js";import{listObjects as Ee,searchObjects as K}from"../../../core/graph/objects.js";import{checkoutsForCwd as Oe}from"../../../core/graph/repo-sync/repos.js";import{recordWatch as Q,unwatch as Y,watchersOf as qe,watchesOf as Re}from"../../../core/graph/watches.js";import{readerFor as g,resolveRef as L}from"../reader.js";import{invalidRequest as $,isRecord as k}from"./validate.js";import{callerNode as X,callerStub as N,forwardVerb as x,originates as ee,queryWithoutMachine as P,relayError as C,remoteStub as Te,unknownError as te,forwarding as S,withMachine as F}from"../../peer/forward.js";import{getById as ne}from"../../../core/graph/objects.js";import{isStub as re}from"../../../core/peer/stubs.js";import{isUnreachable as $e}from"../../../core/peer/client.js";import{normalizeMachineId as I}from"../../../core/peer/directory.js";const M=u(e=>t=>Oe(e,t),"reposFnFor");function oe(e,t){return{...b(e,t),...J(e,t.type).listItem?.(e,t)}}u(oe,"listItem");function Se(e){return`no object named ${e} on this runtime; it may be on another runtime, or the name may be misspelled`}u(Se,"remoteMessage");function ie(e,t,n){try{return R(e,t,n)}catch(r){if(r instanceof w&&r.code==="not_found"&&!r.details?.deleted)return null;throw r}}u(ie,"ownerFilter");function R(e,t,n){const r=L(e,t,n);if("remote"in r)throw new w(404,"not_found",Se(r.remote),{next:"Check the name with `crtr canvas search`."});if("deleted"in r)throw new w(404,"not_found",`${r.deleted.name} is deleted`,{id:r.deleted.id,deleted:!0});return r}u(R,"liveRef");const _=u(e=>decodeURIComponent(e.params.ref),"refParam"),se=u(e=>{const t=e.trim().replace(/^\[\[(.*)\]\]$/,"$1").trim(),n=t.indexOf("/");return n>0?t.slice(0,n):t},"idOf");function ae(e){const t=ne(T(),se(e));return t!==null&&re(T(),t)?t.id:null}u(ae,"stubIdOf");async function W(e,t,n,r){const o=ae(t);return o!==null?x(e,o,n):r()?{kind:"local"}:ee(e.principal)?x(e,se(t),n):{kind:"local"}}u(W,"forwardRef");function D(e,t){return y(n=>{try{return!("remote"in L(n,g(n,t),e))}catch{return!1}})}u(D,"resolvesLocally");const G=u(e=>`/v1/objects/${encodeURIComponent(e)}`,"objectPath");function ue(e,t,n,r,o){const i=t?.object;!i?.id||!i.type||y(s=>{const a=X(s,e);if(a===null)return;const c=Te(s,i.id,i.type,n,{kind:i.kind??null,name:i.name??i.id,...i.preview===void 0?{}:{preview:i.preview},owner:i.owner??null});Q(s,a,c,r,o===void 0?{}:{patterns:o})})}u(ue,"watchRemote");async function Ie(e){const t=_(e),n=["1","true"].includes(e.query.get("fields")??""),r=await W(e,t,{method:"GET",path:G(t),query:P(e)},()=>D(t,e));if(r.kind==="unknown")return{state:"unknown",ref:t,unreachable:r.unreachable};if(r.kind==="remote"){if(r.status>=400)throw C(r.status,r.body);return ue(e,r.body,r.machine.id,"read"),F(r.body,r.machine)}return y(o=>{const i=N(o,e),s=i===null?g(o,e):A(o,i,M(o)),a=L(o,s,t);if("remote"in a)return{state:"remote",remote:a.remote};if("deleted"in a)return{state:"deleted",deleted:b(o,a.deleted)};const{data:c,text:l}=J(o,a.type).read(o,s,a,{fields:n,reposFn:M(o)});return{state:"object",type:a.type,object:b(o,a),text:l,data:c}})}u(Ie,"read");function z(e,t,n,r){if(e!=null){if(!n.includes(e)){r.push({field:t,problem:`must be one of ${n.join(", ")}`,received:e});return}return e}}u(z,"oneOf");function ce(e,t,n){if(t!=null){if(typeof t!="string"||!_e(e,t)){n.push({field:"type",problem:`must be a kind: one of ${ve(e).join(", ")}`,received:t});return}return t}}u(ce,"kindName");function le(e,t,n,r){if(e==null)return r;const o=Number(e);return!Number.isInteger(o)||o<1||o>100?(n.push({field:t,problem:"must be an integer from 1 to 100",received:e}),r):o}u(le,"limitOf");function fe(e){const t=e.query,n=[],r=ce(T(),t.get("type"),n),o=z(t.get("privacy"),"privacy",be,n),i=le(t.get("limit"),"limit",n,50),s=t.get("cursor");s!==null&&!/^\d+$/.test(s)&&n.push({field:"cursor",problem:"is not a cursor from a previous page",received:s});const a=t.get("deleted");return a!==null&&!["0","1","true","false"].includes(a)&&n.push({field:"deleted",problem:"must be true or false",received:a}),n.length>0&&$("object list request",n),y(c=>{const l=g(c,e),h={...r?{type:r}:{},...o?{privacy:o}:{},...t.get("kind")!==null?{kind:t.get("kind")}:{},...a==="1"||a==="true"?{deleted:!0}:{}},p=t.get("owner");if(p!==null){const m=ie(c,l,p);if(m===null)return{items:[],next_cursor:null};h.owner=m}const v=t.get("name"),j=[];let d=s===null?0:Number(s),E=!0;for(;j.length<i&&E;){const m=Ee(c,l,h,{limit:100,after_rowid:d});E=m.length===100;for(const q of m)if(d=q.rowid,(v===null||q.name.startsWith(v))&&j.push(q),j.length===i)break}const f=j.at(-1);return{items:j.map(m=>oe(c,m)),next_cursor:j.length===i&&f?String(f.rowid):null}})}u(fe,"listLocal");const Ae={ms:3e4},Le="self",U=u((e,t)=>e.map(n=>({...n,machine:t})),"labelItems");async function de(e,t,n,r){const o=S.current;try{const i=await o.call(t.id,{method:"GET",path:"/v1/objects",query:n},o.envelope(e.principal),r);if($e(i))return{state:"unreachable",items:[],next:null};if(i.status===426)return{state:"too_old",items:[],next:null};const s=i.body;return i.status!==200||!Array.isArray(s?.items)?{state:"unreachable",items:[],next:null}:{state:"ok",items:U(s.items,t),next:s.next_cursor??null}}catch{return{state:"unreachable",items:[],next:null}}}u(de,"remotePage");async function Ne(e){const t=new Promise(n=>e.addEventListener("abort",()=>n(null),{once:!0}));return Promise.race([S.current.machines().catch(()=>null),t])}u(Ne,"machinesWithin");async function Pe(e){const t=e.query.get("machine");if(!ee(e.principal)||!S.current.joined()||t===Le)return fe(me(e));const r=S.current.self(),o=t!==null&&I(t)!==r,i=o?null:fe(me(e)),s=new AbortController,a=setTimeout(()=>s.abort(),Ae.ms);a.unref?.();try{const c=await Ne(s.signal);if(c===null){if(o)throw new w(503,"runtime_unreachable",`The directory did not answer, so ${I(t)} cannot be listed.`,{machine:I(t)});return i}const l=u(f=>({id:f,name:c.find(m=>m.machine_id===f)?.name??f}),"labelOf"),h=l(r),p=c.filter(f=>f.machine_id!==r),v=P(e);if(t!==null){if(!o)return{items:U(i.items,h),next_cursor:i.next_cursor,machines:[{machine_id:r,name:h.name,state:"ok",more:i.next_cursor!==null}]};const f=I(t);if(!p.some(q=>q.machine_id===f))throw new w(404,"not_found",`no machine ${f} on your account`,{machine:f});const m=await de(e,l(f),v,s.signal);return{items:m.items,next_cursor:m.next,machines:[{machine_id:f,name:l(f).name,state:m.state,more:m.next!==null}]}}const{cursor:j,...d}=v,E=await Promise.all(p.map(f=>de(e,l(f.machine_id),d,s.signal)));return{items:[...U(i.items,h),...E.flatMap(f=>f.items)],next_cursor:i.next_cursor,machines:[{machine_id:r,name:h.name,state:"ok",more:i.next_cursor!==null},...p.map((f,m)=>({machine_id:f.machine_id,name:f.name,state:E[m].state,more:E[m].next!==null}))]}}finally{clearTimeout(a)}}u(Pe,"list");function me(e){const t=new URLSearchParams(e.query);return t.delete("machine"),{...e,query:t}}u(me,"withoutMachine");function Ce(e){const t=[],n=k(e.body)?e.body:{};k(e.body)||t.push({field:"body",problem:"must be an object",received:e.body});const r=n.text;(typeof r!="string"||r.trim()==="")&&t.push({field:"text",problem:"is required",received:r});const o=n.grep;if(o!==void 0)if(typeof o!="string")t.push({field:"grep",problem:"must be a regular expression string",received:o});else try{new RegExp(o)}catch(a){t.push({field:"grep",problem:`is not a valid regular expression: ${a.message}`,received:o})}n.body!==void 0&&typeof n.body!="boolean"&&t.push({field:"body",problem:"must be a boolean",received:n.body});const i=ce(T(),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 s=le(n.limit,"limit",t,50);return t.length>0&&$("object search request",t),y(a=>{const c=g(a,e),l=typeof n.owner=="string"?ie(a,c,n.owner):null;if(typeof n.owner=="string"&&l===null)return{items:[]};const h=K(a,c,{text:r,body:n.body===!0||typeof o=="string"}),p=new Set(h.map(d=>d.object.rowid));return{items:(typeof o=="string"?K(a,c,{text:o,grep:!0}).filter(d=>p.has(d.object.rowid)):h).filter(d=>(!i||d.object.type===i)&&(n.kind===void 0||d.object.kind===n.kind)&&(!l||d.object.owner===l.rowid)).slice(0,s).map(d=>({object:oe(a,d.object),...d.line!==void 0?{matches:[{line:d.line,text:d.text??""}]}:{}}))}})}u(Ce,"search");const he=["interrupt","steer","after-turn","next-turn"],Fe=/^(\*|>|[A-Za-z0-9_-]+)(\.(\*|>|[A-Za-z0-9_-]+))*$/;function Me(e,t){if(e!==void 0){if(!Array.isArray(e)||e.length===0||e.some(n=>typeof n!="string"||!Fe.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}}u(Me,"patternsOf");function We(e,t){if(e===void 0)return;if(!k(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[r,o]of Object.entries(e)){const i=Number(r);!Number.isInteger(i)||i<1||i>10?t.push({field:`config.${r}`,problem:"level must be an integer from 1 to 10"}):he.includes(o)?n.push({threshold:i,delivery:o}):t.push({field:`config.${r}`,problem:`delivery must be one of ${he.join(", ")}`,received:o})}return n.sort((r,o)=>o.threshold-r.threshold)}u(We,"configOf");function pe(e){const t=ae(e);if(t!==null)throw new w(400,"invalid_request",`${t} lives on another machine; an explicit watcher cannot watch it from here`,{id:t})}u(pe,"refuseStubWatch");async function De(e){const t=_(e);if(typeof(k(e.body)?e.body:{}).watcher=="string"&&pe(t),typeof(k(e.body)?e.body:{}).watcher!="string"){const n=await W(e,t,{method:"POST",path:`${G(t)}/watch`,body:e.body},()=>D(t,e));if(n.kind==="unknown")throw te(t,n.unreachable);if(n.kind==="remote"){if(n.status>=400)throw C(n.status,n.body);const r=n.body.patterns;return ue(e,n.body,n.machine.id,"ask",r),F(n.body,n.machine)}}return Ge(e)}u(De,"watch");function Ge(e){const t=[],n=e.body===void 0?{}:k(e.body)?e.body:(t.push({field:"body",problem:"must be an object"}),{}),r=Me(n.patterns,t),o=We(n.config,t);return n.filter!==void 0&&!k(n.filter)&&t.push({field:"filter",problem:"must be an object",received:n.filter}),n.watcher!==void 0&&typeof n.watcher!="string"&&t.push({field:"watcher",problem:"must be a custom-object ref",received:n.watcher}),t.length>0&&$("watch request",t),y(i=>{const s=typeof n.watcher=="string"?H(i,n.watcher):null;if(e.publishToken&&!s)throw new w(404,"not_found","watcher not found");if(e.principal.class==="anonymous"&&!s)throw new w(404,"not_found","watcher not found");const a=s?B(i,e,s):N(i,e)??V(g(i,e));s&&Z(i,e,s);const c=s?A(i,s):g(i,e),l=s?(()=>{const p=R(i,c,_(e));if(!ge(i,c,p))throw new w(404,"not_found","object not found");return p})():R(i,c,_(e)),h=r??[">"];return Q(i,s??a,l,s?"act":"ask",{patterns:h,...o?{config:o}:{},...n.filter!==void 0?{filter:n.filter}:{}}),ke(i,{event:"watched",object:l,actor:a,attrs:{}},M(i)),{object:b(i,l),patterns:h}})}u(Ge,"watchLocal");async function ze(e){const t=_(e);if(e.query.get("watcher")&&pe(t),!e.query.get("watcher")){const n=await W(e,t,{method:"DELETE",path:`${G(t)}/watch`,query:P(e)},()=>D(t,e));if(n.kind==="unknown")throw te(t,n.unreachable);if(n.kind==="remote"){if(n.status>=400)throw C(n.status,n.body);const r=n.body.object?.id;return y(o=>{const i=X(o,e),s=r===void 0?null:ne(o,r);i!==null&&s!==null&&re(o,s)&&Y(o,i,s,e.query.get("pattern")??void 0)}),F(n.body,n.machine)}}return Ue(e)}u(ze,"unwatchRoute");function Ue(e){const t=e.query.get("pattern"),n=e.query.get("watcher");return y(r=>{const o=n?H(r,n):null;if((e.publishToken||e.principal.class==="anonymous")&&!o)throw new w(404,"not_found","watcher not found");const i=o?B(r,e,o):N(r,e)??V(g(r,e));o&&Z(r,e,o);const s=o?A(r,o):g(r,e),a=R(r,s,_(e)),c=u(()=>ye(r,`SELECT count(*) AS n FROM watch_subscriptions s JOIN watches w ON w.rowid = s.watch
|
|
2
|
+
WHERE w.watcher = ? AND w.object = ?`).get((o??i).rowid,a.rowid).n,"count"),l=c();return Y(r,o??i,a,t??void 0),{object:b(r,a),removed:l-c()}})}u(Ue,"unwatchLocal");function Ve(e){const t=[],n=z(e.query.get("type"),"type",["acted-on","links-to","watches"],t),r=z(e.query.get("direction"),"direction",["out","in"],t);return t.length>0&&$("edges request",t),y(o=>{const i=g(o,e),s=R(o,i,_(e)),a=[];if(n!=="watches")for(const c of je(o,i,s,{...n?{type:n}:{},direction:r??"both"}))a.push({type:c.type,src:b(o,c.src),dst:b(o,c.dst),...c.written_as?{written_as:c.written_as}:{}});if(n===void 0||n==="watches"){const c=[...r!=="in"?Re(o,i,s):[],...r!=="out"?qe(o,i,s):[]];for(const l of c)a.push({type:"watches",src:b(o,l.watcher),dst:b(o,l.object)})}return{items:a}})}u(Ve,"edges");const O=u(e=>async t=>({status:200,body:await e(t)}),"ok"),ht=[{method:"POST",pattern:"/v1/objects/search",handler:O(Ce)},{method:"GET",pattern:"/v1/objects/:ref/edges",handler:O(Ve)},{method:"POST",pattern:"/v1/objects/:ref/watch",handler:O(De)},{method:"DELETE",pattern:"/v1/objects/:ref/watch",handler:O(ze)},{method:"GET",pattern:"/v1/objects/:ref",handler:O(Ie)},{method:"GET",pattern:"/v1/objects",handler:O(Pe)}];export{Ae as listBudget,ht as objectRoutes};
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { JwksCache, type Scope } from '@north-light/identity';
|
|
2
2
|
import { type ActiveGrant, type GrantDependencies, type GrantScope } from '../../core/grants/mirror.js';
|
|
3
|
+
import { type NoticeTicket } from './sync-notice.js';
|
|
3
4
|
export interface AppPrincipal {
|
|
4
5
|
sub: string;
|
|
5
6
|
grantee: string;
|
|
@@ -33,11 +34,10 @@ export declare class AppPrincipalResolver {
|
|
|
33
34
|
/** The directory key set, for the peer ingress's machine-token check. */
|
|
34
35
|
get jwks(): JwksCache;
|
|
35
36
|
close(): void;
|
|
36
|
-
|
|
37
|
-
private readonly notices;
|
|
37
|
+
private readonly ledger;
|
|
38
38
|
/** A directory sync notice authorizes one grant sync and nothing else.
|
|
39
|
-
* Returns
|
|
40
|
-
verifySyncNotice(authorization: string | undefined): Promise<
|
|
39
|
+
* Returns null for a replay of a notice already accepted. */
|
|
40
|
+
verifySyncNotice(authorization: string | undefined): Promise<NoticeTicket | null>;
|
|
41
41
|
/** Verify a directory `vendor_sign_in` handoff: ES256 signature against the
|
|
42
42
|
* JWKS mirror, `iss`, `aud`, `exp`, `purpose`, and that `jti` and `sub` are
|
|
43
43
|
* present (runtime spec §7 "Vendor sign-in page", RT-LLM-52). The owner and
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var p=Object.defineProperty;var o=(a,e)=>p(a,"name",{value:e,configurable:!0});import{covers as m,JwksCache as _,MissingRevClaimError as b,verifyAccessToken as k
|
|
1
|
+
var p=Object.defineProperty;var o=(a,e)=>p(a,"name",{value:e,configurable:!0});import{covers as m,JwksCache as _,MissingRevClaimError as b,verifyAccessToken as k}from"@north-light/identity";import{createLocalJWKSet as g,decodeProtectedHeader as f,jwtVerify as w}from"jose";import{emitEvent as x}from"../../core/events/emit.js";import{activeGrant as G,grantSyncState as c,grantsGeneration as R}from"../../core/grants/mirror.js";import{RunError as n}from"../../core/runs/operations.js";import{NoticeLedger as S}from"./sync-notice.js";class A{static{o(this,"AppPrincipalResolver")}issuer;audience;syncGrants;cache;ready=!1;timer;constructor(e,r,t,i){this.issuer=e,this.audience=r,this.syncGrants=t,this.cache=new _(e,fetch,i),this.load(),this.timer=setInterval(()=>{this.ready||this.load()},5e3),this.timer.unref()}async load(){try{await this.cache.load(),this.ready=!0}catch{}}isReady(){return this.ready}get jwks(){return this.cache}close(){this.timer&&clearInterval(this.timer)}ledger=new S;async verifySyncNotice(e){if(!this.ready)throw new n(503,"runtime_starting","runtime_starting");return this.ledger.accept(e,this.cache,this.issuer,this.audience)}async verifyHandoff(e){if(!this.ready)throw new n(503,"runtime_starting","runtime_starting");const r=o(()=>new n(401,"unauthorized","invalid vendor sign-in handoff"),"refuse");if(!e)throw r();let t;try{const u=f(e);if(u.alg!=="ES256")throw r();const l=await this.cache.forKid(u.kid);({payload:t}=await w(e,g(l),{issuer:this.issuer,audience:this.audience,algorithms:["ES256"],requiredClaims:["exp","jti","sub"]}))}catch{throw r()}const{sub:i,jti:s,exp:h,purpose:d,aud:y}=t;if(d!=="vendor_sign_in"||y!==this.audience||typeof i!="string"||typeof s!="string"||s===""||typeof h!="number")throw r();return{sub:i,jti:s,exp:h}}async verifyDirectoryRead(e,r){if(!this.ready)throw new n(503,"runtime_starting","runtime_starting");const t=o(()=>new n(401,"unauthorized","invalid directory token"),"refuse");if(!e?.startsWith("Bearer ")||e.length<=7)throw t();const i=e.slice(7);let s;try{const h=f(i);if(h.alg!=="ES256")throw t();const d=await this.cache.forKid(h.kid);({payload:s}=await w(i,g(d),{issuer:this.issuer,audience:this.audience,algorithms:["ES256"],requiredClaims:["exp"]}))}catch{throw t()}if(s.purpose!==r||s.aud!==this.audience)throw t()}behind=new Map;behindGeneration=-1;behindRev(e){const r=R();return r!==this.behindGeneration&&(this.behind=new Map,this.behindGeneration=r),this.behind.get(e)}async ensureCovers(e){if(v(c(e.grant),e.rev))return;const r=this.behindRev(e.grant);if(r===void 0||e.rev>r){try{await this.syncGrants({fresh:!0})}catch{throw new n(503,"service_unavailable","grant sync failed")}const t=c(e.grant);if(v(t,e.rev))return;this.behindRev(e.grant),this.behind.set(e.grant,Math.max(e.rev,this.behind.get(e.grant)??0)),x({level:"error",event:"daemon.grants.behind_token",fields:{grant:e.grant,token_rev:e.rev,mirror_rev:t?.rev??0}})}throw c(e.grant)?new n(503,"service_unavailable","the directory answered grant sync below the access token's grant revision"):new n(401,"grant_revoked","grant is not active")}async resolve(e,r){if(!this.ready)throw new n(503,"runtime_starting","runtime_starting");if(!e?.startsWith("Bearer ")||e.length<=7)throw new n(401,"unauthorized","a directory access token is required");let t;try{t=await k({token:e.slice(7),jwks:this.cache,issuer:this.issuer,audience:this.audience})}catch(s){throw s instanceof b?new n(401,"unauthorized",s.message):new n(401,"unauthorized","invalid directory access token")}await this.ensureCovers(t);const i=E(t);if(r&&!i.resolved.some(s=>m(s,r)))throw new n(403,"scope_missing",`missing scope ${r}`,void 0,void 0,r);return{sub:t.sub,grantee:t.grantee,client_id:t.client_id,grant:t.grant,rev:i.rev,resolved:i.resolved,resolved_scopes:i.resolved_scopes,spend_cap:i.spend_cap,dependencies:i.dependencies??{},exp:t.exp}}}function E(a){const e=G(a.grant);if(!e||e.sub!==a.sub||e.grantee!==a.grantee||e.expires_at!==null&&!(Date.parse(e.expires_at)>Date.now()))throw new n(401,"grant_revoked","grant is not active");return e}o(E,"callerGrant");function v(a,e){return a!==null&&a.rev>=e}o(v,"covered");export{A as AppPrincipalResolver,E as callerGrant};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { type JwksCache } from '@north-light/identity';
|
|
2
|
+
/** An accepted notice whose sync has not yet finished. `done(true)` records it as applied; `done(false)` releases it so the directory's retry syncs. */
|
|
3
|
+
export interface NoticeTicket {
|
|
4
|
+
jti: string;
|
|
5
|
+
done(applied: boolean): void;
|
|
6
|
+
}
|
|
7
|
+
/** jti → exp of every notice applied (or being applied) within its lifetime. */
|
|
8
|
+
export declare class NoticeLedger {
|
|
9
|
+
private readonly seen;
|
|
10
|
+
/** Verify the bearer as a sync notice for `audience`. Null for a replay of a notice already applied or being applied. Throws `RunError` 401 when invalid. */
|
|
11
|
+
accept(authorization: string | undefined, jwks: JwksCache, issuer: string, audience: string): Promise<NoticeTicket | null>;
|
|
12
|
+
}
|
|
13
|
+
/** Apply an accepted notice: pull grants fresh and answer only after the sync commits (a 2xx tells the directory the change is applied).
|
|
14
|
+
* A replay (`ticket` null) triggers no second sync. Throws `RunError` 503 when the sync fails, so the directory retries. */
|
|
15
|
+
export declare function applySyncNotice(ticket: NoticeTicket | null, syncGrants: (options?: {
|
|
16
|
+
fresh?: boolean;
|
|
17
|
+
}) => Promise<void>, requestId: string): Promise<void>;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var d=Object.defineProperty;var r=(t,e)=>d(t,"name",{value:e,configurable:!0});import{verifySyncNotice as h}from"@north-light/identity";import{emitEvent as u}from"../../core/events/emit.js";import{RunError as s}from"../../core/runs/operations.js";class v{static{r(this,"NoticeLedger")}seen=new Map;async accept(e,i,c,a){if(!e?.startsWith("Bearer ")||e.length<=7)throw new s(401,"unauthorized","a directory sync notice token is required");let n;try{n=await h({token:e.slice(7),jwks:i,issuer:c,audience:a})}catch{throw new s(401,"unauthorized","invalid directory sync notice token")}const l=Math.floor(Date.now()/1e3);for(const[o,f]of this.seen)f+30<l&&this.seen.delete(o);return this.seen.has(n.jti)?null:(this.seen.set(n.jti,n.exp),{jti:n.jti,done:r(o=>{o||this.seen.delete(n.jti)},"done")})}}async function j(t,e,i){if(t!==null){u({level:"info",event:"daemon.grants.sync_notice",fields:{request_id:i}});try{await e({fresh:!0})}catch{throw t.done(!1),new s(503,"service_unavailable","grant sync failed")}t.done(!0)}}r(j,"applySyncNotice");export{v as NoticeLedger,j as applySyncNotice};
|