@north-light/cli 0.3.549 → 0.3.551
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/custom-objects.d.ts +1 -1
- package/dist/api/dto/docs.d.ts +12 -0
- package/dist/api/dto/objects.d.ts +17 -1
- package/dist/api/dto/objects.js +1 -1
- package/dist/api/dto/permissions.d.ts +76 -0
- package/dist/api/dto/permissions.js +1 -0
- package/dist/api/index.d.ts +3 -2
- package/dist/api/index.js +1 -1
- package/dist/api/routes.d.ts +4 -0
- package/dist/api/routes.js +1 -1
- package/dist/builtin-memory/crouter-concepts/documents.md +1 -1
- package/dist/builtin-memory/crouter-concepts/scopes-and-trust.md +2 -2
- package/dist/builtin-memory/crouter-sdk/release-notes.md +11 -0
- package/dist/builtin-memory/internal/INDEX.md +2 -1
- package/dist/builtin-memory/internal/agent-shaping.md +1 -1
- package/dist/builtin-memory/internal/storage-tiers.md +1 -1
- package/dist/builtin-memory/northlight-apps/guides/files-and-documents.md +3 -3
- package/dist/builtin-memory/northlight-apps/guides/many-users.md +1 -1
- package/dist/builtin-memory/northlight-apps/guides/test-your-app.md +1 -1
- package/dist/clients/attach/viewer.js +9 -9
- package/dist/commands/canvas/list.js +2 -2
- package/dist/commands/canvas/share.d.ts +2 -0
- package/dist/commands/canvas/share.js +2 -0
- package/dist/commands/canvas.js +1 -1
- package/dist/commands/doc/edit.js +1 -1
- package/dist/commands/doc/shared.js +1 -1
- package/dist/commands/doc/write.js +1 -1
- package/dist/commands/sys/sync-skills.js +2 -2
- package/dist/core/canvas/canvas.js +20 -20
- package/dist/core/canvas/db.js +4 -4
- package/dist/core/canvas/export-sqlite.js +2 -2
- package/dist/core/canvas/import-sqlite.js +5 -5
- package/dist/core/canvas/outcome-actions.js +3 -3
- package/dist/core/canvas/person.js +11 -9
- package/dist/core/canvas/schema-pg.sql +49 -5
- package/dist/core/environments.js +1 -1
- package/dist/core/feed/feed.js +1 -1
- package/dist/core/grants/mirror.d.ts +9 -1
- package/dist/core/grants/mirror.js +2 -2
- package/dist/core/grants/sync.js +1 -1
- package/dist/core/graph/access.d.ts +8 -49
- package/dist/core/graph/access.js +4 -7
- package/dist/core/graph/custom.d.ts +5 -2
- package/dist/core/graph/custom.js +9 -9
- package/dist/core/graph/deletion.js +5 -4
- package/dist/core/graph/documents.d.ts +12 -3
- package/dist/core/graph/documents.js +13 -7
- package/dist/core/graph/edges.js +3 -3
- package/dist/core/graph/events.js +12 -8
- package/dist/core/graph/kinds/document.js +4 -4
- package/dist/core/graph/kinds/kind.js +1 -1
- package/dist/core/graph/kinds/node.js +5 -5
- package/dist/core/graph/names.d.ts +16 -1
- package/dist/core/graph/names.js +11 -3
- package/dist/core/graph/objects.d.ts +19 -2
- package/dist/core/graph/objects.js +16 -10
- package/dist/core/graph/package-docs.js +5 -5
- package/dist/core/graph/package-files.js +2 -2
- package/dist/core/graph/reader.js +3 -3
- package/dist/core/graph/repo-sync/exchange.js +2 -2
- package/dist/core/graph/rules.d.ts +7 -5
- package/dist/core/graph/rules.js +3 -3
- package/dist/core/graph/types.d.ts +12 -1
- package/dist/core/graph/types.js +1 -1
- package/dist/core/graph/watches.d.ts +1 -1
- package/dist/core/graph/watches.js +9 -8
- package/dist/core/peer/envelope.d.ts +1 -1
- package/dist/core/peer/envelope.js +1 -1
- package/dist/core/peer/stubs.d.ts +1 -1
- package/dist/core/peer/stubs.js +1 -1
- package/dist/core/permissions/boot.d.ts +17 -0
- package/dist/core/permissions/boot.js +18 -0
- package/dist/core/permissions/builtin.d.ts +8 -0
- package/dist/core/permissions/builtin.js +20 -0
- package/dist/core/permissions/ceiling.d.ts +57 -0
- package/dist/core/permissions/ceiling.js +22 -0
- package/dist/core/permissions/compile.d.ts +14 -0
- package/dist/core/permissions/compile.js +1 -0
- package/dist/core/permissions/errors.d.ts +7 -0
- package/dist/core/permissions/errors.js +1 -0
- package/dist/core/permissions/evaluator.d.ts +28 -0
- package/dist/core/permissions/evaluator.js +6 -0
- package/dist/core/permissions/facts.d.ts +56 -0
- package/dist/core/permissions/facts.js +2 -0
- package/dist/core/permissions/schema-parser.d.ts +29 -0
- package/dist/core/permissions/schema-parser.js +2 -0
- package/dist/core/permissions/schemas.d.ts +21 -0
- package/dist/core/permissions/schemas.js +2 -0
- package/dist/core/permissions/sql.d.ts +16 -0
- package/dist/core/permissions/sql.js +1 -0
- package/dist/core/runtime/broker/frame-client.d.ts +1 -1
- package/dist/core/runtime/broker/frame-client.js +1 -1
- package/dist/core/runtime/broker/frame-dispatch.d.ts +1 -1
- package/dist/core/runtime/broker/frame-dispatch.js +1 -1
- package/dist/core/runtime/broker/frame-read.d.ts +4 -3
- package/dist/core/runtime/broker/frame-read.js +1 -1
- package/dist/core/runtime/broker-protocol.d.ts +1 -1
- package/dist/core/runtime/host.js +3 -3
- package/dist/core/runtime/placement.js +1 -1
- package/dist/core/runtime/roadmap.js +1 -1
- package/dist/core/substrate/delivery/corpus.d.ts +2 -2
- package/dist/core/substrate/delivery/corpus.js +3 -3
- package/dist/core/substrate/delivery/deliver.js +2 -2
- package/dist/core/substrate/delivery/render-event.js +6 -6
- package/dist/core/substrate/subject-fields.d.ts +2 -0
- package/dist/core/substrate/subject.js +1 -1
- package/dist/daemon/api/app-listener.js +12 -12
- package/dist/daemon/api/bridge.d.ts +1 -1
- package/dist/daemon/api/bridge.js +4 -4
- package/dist/daemon/api/handlers/attach.d.ts +4 -1
- package/dist/daemon/api/handlers/attach.js +1 -1
- package/dist/daemon/api/handlers/canvas.js +5 -5
- package/dist/daemon/api/handlers/check.d.ts +2 -0
- package/dist/daemon/api/handlers/check.js +1 -0
- package/dist/daemon/api/handlers/custom-objects.js +2 -2
- package/dist/daemon/api/handlers/docs.js +1 -1
- package/dist/daemon/api/handlers/files.js +1 -1
- package/dist/daemon/api/handlers/memory.js +7 -6
- package/dist/daemon/api/handlers/nodes.js +1 -1
- package/dist/daemon/api/handlers/objects.js +3 -3
- package/dist/daemon/api/handlers/relations.d.ts +2 -0
- package/dist/daemon/api/handlers/relations.js +1 -0
- package/dist/daemon/api/handlers/schemas.d.ts +12 -0
- package/dist/daemon/api/handlers/schemas.js +1 -0
- package/dist/daemon/api/handlers/shares.d.ts +2 -0
- package/dist/daemon/api/handlers/shares.js +1 -0
- package/dist/daemon/api/operations.js +1 -1
- package/dist/daemon/api/router.d.ts +10 -6
- package/dist/daemon/api/router.js +1 -1
- package/dist/daemon/api/server.js +1 -1
- package/dist/daemon/crtrd.js +12 -12
- package/dist/daemon/reconcilers/delivery-lane.js +2 -2
- package/dist/doc-editor/editor.css +1 -1
- package/dist/doc-editor/editor.js +16 -16
- package/dist/migrations/004-canvas-documents/fields.d.ts +1 -1
- package/dist/migrations/004-canvas-documents/fields.js +2 -2
- package/docs/apps/guides/files-and-documents.md +3 -3
- package/docs/apps/guides/many-users.md +1 -1
- package/docs/apps/guides/test-your-app.md +1 -1
- package/docs/cli/documents-and-preferences.md +1 -1
- package/docs/concepts/documents.md +1 -1
- package/docs/concepts/scopes-and-trust.md +2 -2
- package/docs/sdk/release-notes.md +11 -0
- package/package.json +2 -2
- package/packages/crouter-identity/dist/index.js +14 -1
- package/packages/crouter-identity/package.json +1 -1
- package/runtime.lock.json +13 -13
- package/dist/core/graph/spaces/app.d.ts +0 -3
- package/dist/core/graph/spaces/app.js +0 -1
- package/dist/core/graph/spaces/index.d.ts +0 -18
- package/dist/core/graph/spaces/index.js +0 -1
- package/dist/core/graph/spaces/own-memory.d.ts +0 -18
- package/dist/core/graph/spaces/own-memory.js +0 -1
- package/dist/core/graph/spaces/person.d.ts +0 -5
- package/dist/core/graph/spaces/person.js +0 -3
- package/dist/core/graph/spaces/repo.d.ts +0 -14
- package/dist/core/graph/spaces/repo.js +0 -1
- package/dist/core/runs/confinement.d.ts +0 -25
- package/dist/core/runs/confinement.js +0 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
var ce=Object.defineProperty;var a=(t,o)=>ce(t,"name",{value:o,configurable:!0});import{createServer as D}from"node:http";import{chmodSync as ue,existsSync as N,unlinkSync as F}from"node:fs";import{MINIMUM_RUNTIME_VERSION_HEADER as G,RUNTIME_VERSION_HEADER as z,minimumRuntimeRefusal as pe}from"../../api/runtime-version.js";import{CONTRACT_HEADER as P,CONTRACT_LEVEL as J,REQUIRED_CONTRACT_HEADER as V,contractRefusal as de}from"../../api/contract.js";import{crtrVersion as I}from"../../shared/crtr-version.js";import{apiSocketPath as me}from"../../core/canvas/paths.js";import{resolveNodeToken as fe}from"../../core/canvas/node-tokens.js";import{grantFor as ge,hasSyncedGrants as he}from"../../core/grants/mirror.js";import{readConfig as x}from"../../core/config.js";import{peerUid as Ae}from"../../native/linux.js";import{findScopedApiToken as Re,getApiToken as ye,listScopedApiTokens as ve}from"../../core/secrets.js";import{emitEvent as g}from"../../core/events/emit.js";import{envCrtrdTcp as be,envCrtrdToken as Ee}from"../../shared/env.js";import{Router as K}from"./router.js";import{handleAttachUpgrade as we,refuseUpgrade as h}from"./bridge.js";import{boundDaemonControl as Se}from"../control.js";import{attachRoutes as Te}from"./handlers/attach.js";import{peerRoutes as _e}from"../peer/handlers.js";import{bashJobRoutes as Ce}from"./handlers/bash-jobs.js";import{bashRoutes as ke}from"./handlers/bash.js";import{hookExecRoutes as Oe}from"./handlers/hook-exec.js";import{brokerOperationRoutes as Q}from"./handlers/broker-ops.js";import{brokerSignalRoutes as Ue,brokerSignalStreams as He}from"./handlers/broker-signals.js";import{brokerRecoveryRoutes as X,nodeFaultRoutes as Ne}from"./handlers/broker-recovery.js";import{canvasRoutes as ze}from"./handlers/canvas.js";import{chatInventoryRoutes as Pe}from"./handlers/chat-inventory.js";import{daemonRoutes as Ie}from"./handlers/daemon.js";import{fileRoutes as xe}from"./handlers/files.js";import{focusRoutes as Be}from"./handlers/focus.js";import{analyticsRoutes as We}from"./handlers/analytics.js";import{memoryReadsRoutes as $e}from"./handlers/memory-reads.js";import{memoryRoutes as Le}from"./handlers/memory.js";import{healthRoutes as Me}from"./handlers/health.js";import{humanRequestRoutes as je}from"./handlers/human-requests.js";import{inboxRoutes as De}from"./handlers/inbox.js";import{feedbackCommentRoutes as Fe}from"./handlers/feedback-comments.js";import{objectRoutes as Ge}from"./handlers/objects.js";import{customObjectRoutes as Je}from"./handlers/custom-objects.js";import{docRoutes as Ve}from"./handlers/docs.js";import{deliveryRoutes as Y}from"./handlers/delivery.js";import{deliveryRetryRoutes as Ke}from"./handlers/delivery-retry.js";import{packageDocRoutes as Qe}from"./handlers/package-docs.js";import{documentAccessRoutes as Xe}from"./handlers/document-access.js";import{pluginAppRoutes as Ye}from"./handlers/plugin-app-token.js";import{brokerMailRoutes as Z,messageRoutes as Ze}from"./handlers/messages.js";import{modelAuthRoutes as qe}from"./handlers/modelauth.js";import{llmRoutes as er}from"./handlers/llm.js";import{providerRoutes as rr}from"./handlers/providers.js";import{modelConfigRoutes as tr}from"./handlers/model-config.js";import{nodeRoutes as or}from"./handlers/nodes.js";import{nodeRecordRoutes as nr}from"./handlers/node-records.js";import{nodeOutcomeRoutes as ir}from"./handlers/node-outcomes.js";import{nodeEventRoutes as sr}from"./handlers/node-events.js";import{profileRoutes as lr}from"./handlers/profiles.js";import{prospectiveChatInventoryRoutes as ar}from"./handlers/prospective-chat-inventory.js";import{reportRoutes as cr}from"./handlers/reports.js";import{runRoutes as ur}from"./handlers/run-routes.js";import{reviewCommentRoutes as pr}from"./handlers/review-comments.js";import{reviewRoutes as dr}from"./handlers/reviews.js";import{subscriptionRoutes as mr}from"./handlers/subscriptions.js";import{structuredRequestRoutes as fr}from"./handlers/structured-requests.js";import{cronRoutes as gr}from"./handlers/crons.js";import{setCronRequestHandler as q}from"../cron/run-socket.js";import{worktreeRoutes as hr}from"./handlers/worktree.js";import{limitsRoutes as Ar}from"./handlers/limits.js";function Rr(t){return new K().registerAll(Me(t)).registerAll(Ie).registerAll(or).registerAll(nr).registerAll(ir).registerAll(Ke).registerAll(sr).registerAll(Ce).registerAll(ke).registerAll(Oe).registerAll(Q).registerAll(Ue).registerAll(Y).registerAll(X).registerAll(Ne).registerAll(hr).registerAll(Ar).registerAll(Z).registerAll(Ze).registerAll(cr).registerAll(ur).registerAll(fr).registerAll(Te).registerAll(ze).registerAll(We).registerAll($e).registerAll(Le).registerAll(xe).registerAll(Ge).registerAll(Je).registerAll(Ve).registerAll(Qe).registerAll(Xe).registerAll(Ye).registerAll(Be).registerAll(mr).registerAll(gr).registerAll(lr).registerAll(qe).registerAll(er).registerAll(rr).registerAll(tr).registerAll(dr).registerAll(pr).registerAll(De).registerAll(je).registerAll(Pe).registerAll(ar).registerAll(Fe).registerAll(_e)}a(Rr,"buildRouter");function yr(t,o){if(t.toUpperCase()!=="GET")return null;const l=o.split("/").filter(f=>f.length>0);if(l.length!==4||l[0]!=="v1"||l[1]!=="nodes"||l[3]!=="attach")return null;const p=l[2];return p===void 0||p===""?null:decodeURIComponent(p)}a(yr,"attachNodeId");function vr(t){const o=t.trim();if(o==="")return null;const l=o.lastIndexOf(":");if(l<0)return null;const p=o.slice(0,l),f=o.slice(l+1),m=Number(f);return!Number.isInteger(m)||m<0||m>65535?null:{host:p===""?"0.0.0.0":p,port:m}}a(vr,"parseTcp");function br(t,o){return`${t.includes(":")?`[${t}]`:t}:${o}`}a(br,"formatTcpAddress");const R={code:"unauthorized",message:"missing or invalid bearer token"},v={code:"owner_only",message:"attach is owner-only; a scoped token does not reach it"},B={class:"anonymous",app:"",node:"",run:null,uid:-1,sub:"",grant:null,client_id:null,scopes:[]},b=new WeakMap;function ee(t){return b.get(t)}a(ee,"socketPrincipal");async function re(t,o){const l=process.platform==="linux"?Ae(t.socket):null,p=t.headers.authorization;if(p===void 0)return l===null||o.has(l)?{class:"person"}:"unauthorized";if(typeof p!="string"||!p.startsWith("Bearer "))return"unauthorized";if(p.slice(7).startsWith("crtr_pub_"))return B;if(p.slice(7).startsWith(W)){const A=O(p.slice(7));return A!==void 0&&(l===null||o.has(l))?A.principal:"unauthorized"}const f=await fe(p.slice(7));if(!f||l!==null&&l!==f.uid)return"unauthorized";const m=x("user").runtime?.issuer;if(m&&!await he(m.replace(/\/$/,"")))return"runtime_starting";const C=f.grant??(await ge("app:terminal",f.sub))?.id??null;return{class:"broker",...f,grant:C}}a(re,"resolveSocketPrincipal");const W="crtr_app_";function O(t){const o=t.startsWith(W)?Re(t):void 0;return o===void 0?void 0:{principal:{class:"app",app:o.grantee,scopes:o.scopes},ceiling:o.scopes}}a(O,"appBearer");function Er(t){const o=new Map;for(const l of ve("user"))o.set(l.token,{principal:{class:"app",app:l.grantee,scopes:l.scopes},ceiling:l.scopes});return o.set(t,{principal:{class:"person"},ceiling:null}),o}a(Er,"resolveBearers");function te(t,o){const l=t.headers.authorization;if(typeof l!="string"||!l.startsWith("Bearer "))return;const p=l.slice(7);return p.startsWith(W)?O(p):o.get(p)}a(te,"authorize");function U(t){t.setHeader(z,I()),t.setHeader(P,J)}a(U,"advertiseRuntime");function T(t){t.setHeader("Access-Control-Allow-Origin","*"),t.setHeader("Access-Control-Expose-Headers",`${z}, ${P}`)}a(T,"exposeRuntimeHeaders");function oe(t,o){return(t.method??"GET").toUpperCase()!=="OPTIONS"?!1:(U(o),o.writeHead(204,{"Access-Control-Allow-Origin":"*","Access-Control-Expose-Headers":`${z}, ${P}`,"Access-Control-Allow-Headers":`authorization, content-type, ${G.toLowerCase()}, ${V.toLowerCase()}`,"Access-Control-Allow-Methods":"GET, POST, PATCH, PUT, DELETE, OPTIONS","Access-Control-Max-Age":"600"}),o.end(),!0)}a(oe,"answerPreflight");function _(t,o=!1){U(t),o&&T(t),t.writeHead(401,{"content-type":"application/json; charset=utf-8"}),t.end(JSON.stringify({error:{...R,origin:"runtime"}}))}a(_,"writeUnauthorized");function wr(t,o){t.writeHead(503,{"content-type":"application/json; charset=utf-8"}),t.end(JSON.stringify({error:{code:"startup_blocked",message:o,origin:"runtime"}}))}a(wr,"writeStartupBlocked");function ne(t){return new Promise(o=>{try{t.closeAllConnections()}catch{}t.close(()=>o())})}a(ne,"closeServer");function Bt(t={}){let o=null;const l=Rr(()=>o),p=new K().registerAll(Q).registerAll(Y).registerAll(X).registerAll(Z),f=a((e,r)=>{const n=Se()?.startupBlock()??null;return n===null||e==="GET"&&(r==="/healthz"||r==="/v1/status"||r==="/v1/ready")||e==="POST"&&(r==="/v1/daemon/migrate"||r==="/v1/daemon/admit")||n.phase==="recovering"&&p.match(e,r)!==null?null:n},"startupBlockFor"),m=me(),C=new Set([process.getuid?.()??0,...x("user").runtime?.person_uids??[]]),A=a((e,r,n)=>{U(r);const c=a(u=>Array.isArray(u)?u[0]:u,"first"),E=c(e.headers[G.toLowerCase()]),i=pe(E,I())??de(c(e.headers[V.toLowerCase()]),J,{legacyMinimum:E,runtimeVersion:I()});if(i!==null){r.writeHead(i.status,{"content-type":"application/json; charset=utf-8"}),r.end(JSON.stringify({error:{code:i.code,message:i.message,type:"invalid_request_error",origin:"runtime",retryable:!1,..."param"in i?{param:i.param}:{details:i.details}}}));return}const s=a(u=>{const w=ee(e);g({event:"api.request.failed",level:"error",...w?.class==="broker"?{node_id:w.node}:{},error:u instanceof Error?u:new Error(String(u))});try{r.headersSent||r.writeHead(500,{"content-type":"application/json; charset=utf-8"}),r.end(JSON.stringify({error:{code:"internal",message:"internal error",origin:"runtime"}}))}catch{}},"internalFailure");let d;try{d=new URL(e.url??"/","http://127.0.0.1")}catch{try{r.writeHead(400,{"content-type":"application/json; charset=utf-8"}),r.end(JSON.stringify({error:{code:"invalid_request",message:"request URL is invalid",origin:"runtime"}}))}catch{}return}try{const u=f((e.method??"GET").toUpperCase(),d.pathname);if(u!==null){wr(r,u.message);return}l.handle(e,r,n,ee(e)??{class:"person"}).catch(s)}catch(u){s(u)}},"onRequest"),H=a((e,r,n)=>{r.on("error",()=>{});try{const c=new URL(e.url??"/","http://127.0.0.1"),E=f((e.method??"GET").toUpperCase(),c.pathname);if(E!==null){h(r,503,"Service Unavailable","startup_blocked",E.message);return}const i=yr(e.method??"GET",c.pathname);if(i===null){r.destroy();return}we(e,r,n,i).catch(()=>{try{r.destroy()}catch{}})}catch{try{r.destroy()}catch{}}},"onUpgrade"),ie=a(e=>{e.on("error",r=>{g({event:"api.server.failed",level:"error",error:r})})},"bindErrorHandler"),se=a(async(e,r)=>{try{const n=await re(e,C);if(n==="unauthorized"){g({event:"api.principal.denied",level:"warn",fields:{method:e.method}}),_(r);return}if(n==="runtime_starting"){U(r),r.writeHead(503,{"content-type":"application/json; charset=utf-8"}),r.end(JSON.stringify({error:{code:"runtime_starting",message:"grant sync is not ready",type:"server_error",origin:"runtime",retryable:!0}}));return}b.set(e,n),n.class==="broker"&&g({event:"api.request.principal",level:n.app==="app:terminal"?"debug":"info",node_id:n.node,fields:{principal:`${n.app} node:${n.node}`,method:e.method,path:e.url}}),A(e,r,n.class==="app"?n.scopes:null)}catch(n){g({event:"api.principal.failed",level:"error",error:n instanceof Error?n:new Error(String(n))}),_(r)}},"onSocketRequest"),S=D((e,r)=>{se(e,r).catch(n=>g({event:"api.principal.failed",level:"error",error:n instanceof Error?n:new Error(String(n))}))}),le=a(async(e,r,n)=>{try{const c=await re(e,C);if(c==="unauthorized"||c==="runtime_starting"){c==="unauthorized"&&g({event:"api.principal.denied",level:"warn",fields:{method:e.method}}),h(r,c==="unauthorized"?401:503,"Unauthorized",c,"socket principal unavailable");return}if(c.class!=="person"&&c.class!=="broker"){h(r,403,"Forbidden",v.code,v.message);return}b.set(e,c),H(e,r,n)}catch(c){g({event:"api.principal.failed",level:"error",error:c instanceof Error?c:new Error(String(c))}),h(r,401,"Unauthorized",R.code,R.message)}},"onSocketUpgrade");S.on("upgrade",(e,r,n)=>{le(e,r,n).catch(c=>g({event:"api.principal.failed",level:"error",error:c instanceof Error?c:new Error(String(c))}))}),q((e,r,n)=>{b.set(e,n),A(e,r,null)});let $=!1,L,M;const ae=new Promise((e,r)=>{L=e,M=r});S.once("listening",()=>{$=!0,L()}),S.on("error",e=>{g({event:"api.server.failed",level:"error",error:e}),$||M(e)});try{N(m)&&F(m)}catch{}S.listen(m,()=>{try{ue(m,process.platform==="linux"&&N("/run/crtr/launcher.sock")?438:384)}catch(e){g({event:"api.socket.chmod_failed",level:"error",error:e instanceof Error?e:new Error(String(e))})}});let y;const k=t.tcp??be()??x("user").api.tcp;if(k!==void 0&&k!==""){const e=vr(k);if(e===null)g({event:"api.tcp.invalid",level:"error",error:new Error(`invalid CRTRD_TCP/--tcp spec: ${k}`)});else{const r=t.token??Ee()??ye("user"),n=r===void 0?void 0:Er(r),c=n===void 0?(i,s)=>{if(oe(i,s))return;const d=i.headers.authorization;if(typeof d=="string"&&d.startsWith("Bearer crtr_pub_"))b.set(i,B),T(s);else if(i.headers.origin!==void 0){_(s,!0);return}else if(d!==void 0){const w=typeof d=="string"&&d.startsWith("Bearer ")?O(d.slice(7)):void 0;if(w===void 0){_(s,!0);return}b.set(i,w.principal),T(s),A(i,s,w.ceiling);return}A(i,s,null)}:(i,s)=>{if(oe(i,s))return;const d=te(i,n);if(d===void 0&&i.headers.authorization?.startsWith("Bearer crtr_pub_")){b.set(i,B),T(s),A(i,s,null);return}if(d===void 0){_(s,!0);return}b.set(i,d.principal),T(s),A(i,s,d.ceiling)},E=n===void 0?(i,s,d)=>{if(i.headers.origin!==void 0){h(s,401,"Unauthorized",R.code,R.message);return}const u=i.headers.authorization;if(u!==void 0){if(typeof u=="string"&&u.startsWith("Bearer crtr_pub_")){h(s,403,"Forbidden",v.code,v.message);return}(typeof u=="string"&&u.startsWith("Bearer ")?O(u.slice(7)):void 0)===void 0?h(s,401,"Unauthorized",R.code,R.message):h(s,403,"Forbidden",v.code,v.message);return}H(i,s,d)}:(i,s,d)=>{const u=te(i,n);if(u===void 0){h(s,401,"Unauthorized",R.code,R.message);return}if(u.ceiling!==null){h(s,403,"Forbidden",v.code,v.message);return}H(i,s,d)};y=D(c),y.on("upgrade",E),ie(y),y.once("listening",()=>{const i=y?.address();if(i!==null&&typeof i=="object"){const{address:s,port:d}=i;o=br(s,d)}}),y.listen(e.port,e.host)}}let j=!1;return{ready:ae,tcpAddress:a(()=>o,"tcpAddress"),close:a(async()=>{if(!j){j=!0,q(null),He.close(),await Promise.all([ne(S),y!==void 0?ne(y):Promise.resolve()]);try{N(m)&&F(m)}catch{}}},"close")}}a(Bt,"createApiServer");export{Rr as buildRouter,Bt as createApiServer,ee as socketPrincipal};
|
|
1
|
+
var pe=Object.defineProperty;var a=(t,i)=>pe(t,"name",{value:i,configurable:!0});import{createServer as F}from"node:http";import{chmodSync as de,existsSync as H,unlinkSync as G}from"node:fs";import{MINIMUM_RUNTIME_VERSION_HEADER as J,RUNTIME_VERSION_HEADER as P,minimumRuntimeRefusal as me}from"../../api/runtime-version.js";import{CONTRACT_HEADER as I,CONTRACT_LEVEL as V,REQUIRED_CONTRACT_HEADER as K,contractRefusal as fe}from"../../api/contract.js";import{crtrVersion as x}from"../../shared/crtr-version.js";import{apiSocketPath as ge}from"../../core/canvas/paths.js";import{resolveNodeToken as he}from"../../core/canvas/node-tokens.js";import{grantFor as Ae,hasSyncedGrants as Re}from"../../core/grants/mirror.js";import{readConfig as B}from"../../core/config.js";import{peerUid as ye}from"../../native/linux.js";import{findScopedApiToken as ve,getApiToken as be,listScopedApiTokens as we}from"../../core/secrets.js";import{emitEvent as g}from"../../core/events/emit.js";import{envCrtrdTcp as Ee,envCrtrdToken as _e}from"../../shared/env.js";import{Router as Q}from"./router.js";import{handleAttachUpgrade as Se,refuseUpgrade as h}from"./bridge.js";import{boundDaemonControl as Te}from"../control.js";import{attachRoutes as Ce,mayAttachNode as X}from"./handlers/attach.js";import{peerRoutes as ke}from"../peer/handlers.js";import{bashJobRoutes as Oe}from"./handlers/bash-jobs.js";import{bashRoutes as Ue}from"./handlers/bash.js";import{hookExecRoutes as Ne}from"./handlers/hook-exec.js";import{brokerOperationRoutes as Y}from"./handlers/broker-ops.js";import{brokerSignalRoutes as ze,brokerSignalStreams as He}from"./handlers/broker-signals.js";import{brokerRecoveryRoutes as Z,nodeFaultRoutes as Pe}from"./handlers/broker-recovery.js";import{canvasRoutes as Ie}from"./handlers/canvas.js";import{chatInventoryRoutes as xe}from"./handlers/chat-inventory.js";import{daemonRoutes as Be}from"./handlers/daemon.js";import{fileRoutes as $e}from"./handlers/files.js";import{focusRoutes as We}from"./handlers/focus.js";import{analyticsRoutes as Le}from"./handlers/analytics.js";import{memoryReadsRoutes as Me}from"./handlers/memory-reads.js";import{memoryRoutes as je}from"./handlers/memory.js";import{healthRoutes as De}from"./handlers/health.js";import{humanRequestRoutes as Fe}from"./handlers/human-requests.js";import{inboxRoutes as Ge}from"./handlers/inbox.js";import{feedbackCommentRoutes as Je}from"./handlers/feedback-comments.js";import{objectRoutes as Ve}from"./handlers/objects.js";import{shareRoutes as Ke}from"./handlers/shares.js";import{customObjectRoutes as Qe}from"./handlers/custom-objects.js";import{docRoutes as Xe}from"./handlers/docs.js";import{deliveryRoutes as q}from"./handlers/delivery.js";import{deliveryRetryRoutes as Ye}from"./handlers/delivery-retry.js";import{packageDocRoutes as Ze}from"./handlers/package-docs.js";import{documentAccessRoutes as qe}from"./handlers/document-access.js";import{pluginAppRoutes as er}from"./handlers/plugin-app-token.js";import{brokerMailRoutes as ee,messageRoutes as rr}from"./handlers/messages.js";import{modelAuthRoutes as tr}from"./handlers/modelauth.js";import{llmRoutes as or}from"./handlers/llm.js";import{providerRoutes as nr}from"./handlers/providers.js";import{modelConfigRoutes as ir}from"./handlers/model-config.js";import{nodeRoutes as sr}from"./handlers/nodes.js";import{nodeRecordRoutes as lr}from"./handlers/node-records.js";import{nodeOutcomeRoutes as ar}from"./handlers/node-outcomes.js";import{nodeEventRoutes as cr}from"./handlers/node-events.js";import{profileRoutes as ur}from"./handlers/profiles.js";import{prospectiveChatInventoryRoutes as pr}from"./handlers/prospective-chat-inventory.js";import{reportRoutes as dr}from"./handlers/reports.js";import{runRoutes as mr}from"./handlers/run-routes.js";import{reviewCommentRoutes as fr}from"./handlers/review-comments.js";import{reviewRoutes as gr}from"./handlers/reviews.js";import{subscriptionRoutes as hr}from"./handlers/subscriptions.js";import{structuredRequestRoutes as Ar}from"./handlers/structured-requests.js";import{cronRoutes as Rr}from"./handlers/crons.js";import{setCronRequestHandler as re}from"../cron/run-socket.js";import{worktreeRoutes as yr}from"./handlers/worktree.js";import{limitsRoutes as vr}from"./handlers/limits.js";function br(t){return new Q().registerAll(De(t)).registerAll(Be).registerAll(Ke).registerAll(sr).registerAll(lr).registerAll(ar).registerAll(Ye).registerAll(cr).registerAll(Oe).registerAll(Ue).registerAll(Ne).registerAll(Y).registerAll(ze).registerAll(q).registerAll(Z).registerAll(Pe).registerAll(yr).registerAll(vr).registerAll(ee).registerAll(rr).registerAll(dr).registerAll(mr).registerAll(Ar).registerAll(Ce).registerAll(Ie).registerAll(Le).registerAll(Me).registerAll(je).registerAll($e).registerAll(Ve).registerAll(Qe).registerAll(Xe).registerAll(Ze).registerAll(qe).registerAll(er).registerAll(We).registerAll(hr).registerAll(Rr).registerAll(ur).registerAll(tr).registerAll(or).registerAll(nr).registerAll(ir).registerAll(gr).registerAll(fr).registerAll(Ge).registerAll(Fe).registerAll(xe).registerAll(pr).registerAll(Je).registerAll(ke)}a(br,"buildRouter");function wr(t,i){if(t.toUpperCase()!=="GET")return null;const c=i.split("/").filter(f=>f.length>0);if(c.length!==4||c[0]!=="v1"||c[1]!=="nodes"||c[3]!=="attach")return null;const d=c[2];return d===void 0||d===""?null:decodeURIComponent(d)}a(wr,"attachNodeId");function Er(t){const i=t.trim();if(i==="")return null;const c=i.lastIndexOf(":");if(c<0)return null;const d=i.slice(0,c),f=i.slice(c+1),m=Number(f);return!Number.isInteger(m)||m<0||m>65535?null:{host:d===""?"0.0.0.0":d,port:m}}a(Er,"parseTcp");function _r(t,i){return`${t.includes(":")?`[${t}]`:t}:${i}`}a(_r,"formatTcpAddress");const R={code:"unauthorized",message:"missing or invalid bearer token"},v={code:"owner_only",message:"attach is owner-only; a scoped token does not reach it"},$={class:"anonymous",app:"",node:"",run:null,uid:-1,sub:"",grant:null,client_id:null,scopes:[]},b=new WeakMap;function O(t){return b.get(t)}a(O,"socketPrincipal");async function te(t,i){const c=process.platform==="linux"?ye(t.socket):null,d=t.headers.authorization;if(d===void 0)return c===null||i.has(c)?{class:"person"}:"unauthorized";if(typeof d!="string"||!d.startsWith("Bearer "))return"unauthorized";if(d.slice(7).startsWith("crtr_pub_"))return $;if(d.slice(7).startsWith(W)){const A=U(d.slice(7));return A!==void 0&&(c===null||i.has(c))?A.principal:"unauthorized"}const f=await he(d.slice(7));if(!f||c!==null&&c!==f.uid)return"unauthorized";const m=B("user").runtime?.issuer;if(m&&!await Re(m.replace(/\/$/,"")))return"runtime_starting";const C=f.grant??(await Ae("app:terminal",f.sub))?.id??null;return{class:"broker",...f,grant:C}}a(te,"resolveSocketPrincipal");const W="crtr_app_";function U(t){const i=t.startsWith(W)?ve(t):void 0;return i===void 0?void 0:{principal:{class:"app",app:i.grantee,scopes:i.scopes},ceiling:i.scopes}}a(U,"appBearer");function Sr(t){const i=new Map;for(const c of we("user"))i.set(c.token,{principal:{class:"app",app:c.grantee,scopes:c.scopes},ceiling:c.scopes});return i.set(t,{principal:{class:"person"},ceiling:null}),i}a(Sr,"resolveBearers");function oe(t,i){const c=t.headers.authorization;if(typeof c!="string"||!c.startsWith("Bearer "))return;const d=c.slice(7);return d.startsWith(W)?U(d):i.get(d)}a(oe,"authorize");function N(t){t.setHeader(P,x()),t.setHeader(I,V)}a(N,"advertiseRuntime");function S(t){t.setHeader("Access-Control-Allow-Origin","*"),t.setHeader("Access-Control-Expose-Headers",`${P}, ${I}`)}a(S,"exposeRuntimeHeaders");function ne(t,i){return(t.method??"GET").toUpperCase()!=="OPTIONS"?!1:(N(i),i.writeHead(204,{"Access-Control-Allow-Origin":"*","Access-Control-Expose-Headers":`${P}, ${I}`,"Access-Control-Allow-Headers":`authorization, content-type, ${J.toLowerCase()}, ${K.toLowerCase()}`,"Access-Control-Allow-Methods":"GET, POST, PATCH, PUT, DELETE, OPTIONS","Access-Control-Max-Age":"600"}),i.end(),!0)}a(ne,"answerPreflight");function T(t,i=!1){N(t),i&&S(t),t.writeHead(401,{"content-type":"application/json; charset=utf-8"}),t.end(JSON.stringify({error:{...R,origin:"runtime"}}))}a(T,"writeUnauthorized");function Tr(t,i){t.writeHead(503,{"content-type":"application/json; charset=utf-8"}),t.end(JSON.stringify({error:{code:"startup_blocked",message:i,origin:"runtime"}}))}a(Tr,"writeStartupBlocked");function ie(t){return new Promise(i=>{try{t.closeAllConnections()}catch{}t.close(()=>i())})}a(ie,"closeServer");function Mt(t={}){let i=null;const c=br(()=>i),d=new Q().registerAll(Y).registerAll(q).registerAll(Z).registerAll(ee),f=a((e,r)=>{const o=Te()?.startupBlock()??null;return o===null||e==="GET"&&(r==="/healthz"||r==="/v1/status"||r==="/v1/ready")||e==="POST"&&(r==="/v1/daemon/migrate"||r==="/v1/daemon/admit")||o.phase==="recovering"&&d.match(e,r)!==null?null:o},"startupBlockFor"),m=ge(),C=new Set([process.getuid?.()??0,...B("user").runtime?.person_uids??[]]),A=a((e,r,o)=>{N(r);const l=a(u=>Array.isArray(u)?u[0]:u,"first"),w=l(e.headers[J.toLowerCase()]),n=me(w,x())??fe(l(e.headers[K.toLowerCase()]),V,{legacyMinimum:w,runtimeVersion:x()});if(n!==null){r.writeHead(n.status,{"content-type":"application/json; charset=utf-8"}),r.end(JSON.stringify({error:{code:n.code,message:n.message,type:"invalid_request_error",origin:"runtime",retryable:!1,..."param"in n?{param:n.param}:{details:n.details}}}));return}const s=a(u=>{const E=O(e);g({event:"api.request.failed",level:"error",...E?.class==="broker"?{node_id:E.node}:{},error:u instanceof Error?u:new Error(String(u))});try{r.headersSent||r.writeHead(500,{"content-type":"application/json; charset=utf-8"}),r.end(JSON.stringify({error:{code:"internal",message:"internal error",origin:"runtime"}}))}catch{}},"internalFailure");let p;try{p=new URL(e.url??"/","http://127.0.0.1")}catch{try{r.writeHead(400,{"content-type":"application/json; charset=utf-8"}),r.end(JSON.stringify({error:{code:"invalid_request",message:"request URL is invalid",origin:"runtime"}}))}catch{}return}try{const u=f((e.method??"GET").toUpperCase(),p.pathname);if(u!==null){Tr(r,u.message);return}c.handle(e,r,o,O(e)??{class:"person"}).catch(s)}catch(u){s(u)}},"onRequest"),se=a(async(e,r,o)=>{const l=O(e);return l===void 0||l.class==="person"||await X(l,"either",o)?!0:(h(r,404,"Not Found","node_not_found",`no node ${o}`),!1)},"authorizeAttachUpgrade"),z=a((e,r,o)=>{r.on("error",()=>{});try{const l=new URL(e.url??"/","http://127.0.0.1"),w=f((e.method??"GET").toUpperCase(),l.pathname);if(w!==null){h(r,503,"Service Unavailable","startup_blocked",w.message);return}const n=wr(e.method??"GET",l.pathname);if(n===null){r.destroy();return}se(e,r,n).then(s=>s?Se(e,r,o,n,async p=>{const u=O(e);return u===void 0||u.class==="person"||await X(u,p,n)}):void 0).catch(()=>{try{r.destroy()}catch{}})}catch{try{r.destroy()}catch{}}},"onUpgrade"),le=a(e=>{e.on("error",r=>{g({event:"api.server.failed",level:"error",error:r})})},"bindErrorHandler"),ae=a(async(e,r)=>{try{const o=await te(e,C);if(o==="unauthorized"){g({event:"api.principal.denied",level:"warn",fields:{method:e.method}}),T(r);return}if(o==="runtime_starting"){N(r),r.writeHead(503,{"content-type":"application/json; charset=utf-8"}),r.end(JSON.stringify({error:{code:"runtime_starting",message:"grant sync is not ready",type:"server_error",origin:"runtime",retryable:!0}}));return}b.set(e,o),o.class==="broker"&&g({event:"api.request.principal",level:o.app==="app:terminal"?"debug":"info",node_id:o.node,fields:{principal:`${o.app} node:${o.node}`,method:e.method,path:e.url}}),A(e,r,o.class==="app"?o.scopes:null)}catch(o){g({event:"api.principal.failed",level:"error",error:o instanceof Error?o:new Error(String(o))}),T(r)}},"onSocketRequest"),_=F((e,r)=>{ae(e,r).catch(o=>g({event:"api.principal.failed",level:"error",error:o instanceof Error?o:new Error(String(o))}))}),ce=a(async(e,r,o)=>{try{const l=await te(e,C);if(l==="unauthorized"||l==="runtime_starting"){l==="unauthorized"&&g({event:"api.principal.denied",level:"warn",fields:{method:e.method}}),h(r,l==="unauthorized"?401:503,"Unauthorized",l,"socket principal unavailable");return}if(l.class!=="person"&&l.class!=="broker"){h(r,403,"Forbidden",v.code,v.message);return}b.set(e,l),z(e,r,o)}catch(l){g({event:"api.principal.failed",level:"error",error:l instanceof Error?l:new Error(String(l))}),h(r,401,"Unauthorized",R.code,R.message)}},"onSocketUpgrade");_.on("upgrade",(e,r,o)=>{ce(e,r,o).catch(l=>g({event:"api.principal.failed",level:"error",error:l instanceof Error?l:new Error(String(l))}))}),re((e,r,o)=>{b.set(e,o),A(e,r,null)});let L=!1,M,j;const ue=new Promise((e,r)=>{M=e,j=r});_.once("listening",()=>{L=!0,M()}),_.on("error",e=>{g({event:"api.server.failed",level:"error",error:e}),L||j(e)});try{H(m)&&G(m)}catch{}_.listen(m,()=>{try{de(m,process.platform==="linux"&&H("/run/crtr/launcher.sock")?438:384)}catch(e){g({event:"api.socket.chmod_failed",level:"error",error:e instanceof Error?e:new Error(String(e))})}});let y;const k=t.tcp??Ee()??B("user").api.tcp;if(k!==void 0&&k!==""){const e=Er(k);if(e===null)g({event:"api.tcp.invalid",level:"error",error:new Error(`invalid CRTRD_TCP/--tcp spec: ${k}`)});else{const r=t.token??_e()??be("user"),o=r===void 0?void 0:Sr(r),l=o===void 0?(n,s)=>{if(ne(n,s))return;const p=n.headers.authorization;if(typeof p=="string"&&p.startsWith("Bearer crtr_pub_"))b.set(n,$),S(s);else if(n.headers.origin!==void 0){T(s,!0);return}else if(p!==void 0){const E=typeof p=="string"&&p.startsWith("Bearer ")?U(p.slice(7)):void 0;if(E===void 0){T(s,!0);return}b.set(n,E.principal),S(s),A(n,s,E.ceiling);return}A(n,s,null)}:(n,s)=>{if(ne(n,s))return;const p=oe(n,o);if(p===void 0&&n.headers.authorization?.startsWith("Bearer crtr_pub_")){b.set(n,$),S(s),A(n,s,null);return}if(p===void 0){T(s,!0);return}b.set(n,p.principal),S(s),A(n,s,p.ceiling)},w=o===void 0?(n,s,p)=>{if(n.headers.origin!==void 0){h(s,401,"Unauthorized",R.code,R.message);return}const u=n.headers.authorization;if(u!==void 0){if(typeof u=="string"&&u.startsWith("Bearer crtr_pub_")){h(s,403,"Forbidden",v.code,v.message);return}(typeof u=="string"&&u.startsWith("Bearer ")?U(u.slice(7)):void 0)===void 0?h(s,401,"Unauthorized",R.code,R.message):h(s,403,"Forbidden",v.code,v.message);return}z(n,s,p)}:(n,s,p)=>{const u=oe(n,o);if(u===void 0){h(s,401,"Unauthorized",R.code,R.message);return}if(u.ceiling!==null){h(s,403,"Forbidden",v.code,v.message);return}z(n,s,p)};y=F(l),y.on("upgrade",w),le(y),y.once("listening",()=>{const n=y?.address();if(n!==null&&typeof n=="object"){const{address:s,port:p}=n;i=_r(s,p)}}),y.listen(e.port,e.host)}}let D=!1;return{ready:ue,tcpAddress:a(()=>i,"tcpAddress"),close:a(async()=>{if(!D){D=!0,re(null),He.close(),await Promise.all([ie(_),y!==void 0?ie(y):Promise.resolve()]);try{H(m)&&G(m)}catch{}}},"close")}}a(Mt,"createApiServer");export{br as buildRouter,Mt as createApiServer,O as socketPrincipal};
|
package/dist/daemon/crtrd.js
CHANGED
|
@@ -1,17 +1,17 @@
|
|
|
1
|
-
var $e=Object.defineProperty;var a=(n,s)=>$e(n,"name",{value:s,configurable:!0});import{startPeerOutbox as Ae}from"./peer/outbox.js";import{reportMachineStatus as Me}from"../core/peer/directory.js";import{createPeerRelay as Ne}from"./peer/relay-service.js";import{writeFileSync as Fe,readFileSync as Ge,rmSync as Oe,mkdirSync as ae,existsSync as P,chmodSync as Be}from"node:fs";import{createServer as se}from"node:http";import{dirname as He}from"node:path";import{envCrtrdTcp as je,envDocumentPort as qe}from"../shared/env.js";import{serveCanvasConversationStore as ze}from"../core/canvas/sessions.js";import{pollRunObservers as We}from"./runs/observer.js";import{randomBytes as ce}from"node:crypto";import{apiSocketPath as Ue,crtrHome as Ke}from"../core/canvas/paths.js";import{activeAppUsers as Je}from"../core/spaces/users.js";import{ensureAppSpace as Ve,ensureUserFiles as Qe}from"../core/spaces/space.js";import{LAUNCHER_SOCKET as x}from"../launcher/spec.js";import{launcherRequest as C}from"../launcher/client.js";import{installLauncherEventSink as Ye}from"./launcher-events.js";import{initializeEmptyLayout as Xe,layoutNeedsMigration as Ze,socketDir as de}from"../core/layout.js";import{migrateLooseKeys as er}from"../core/layout-migrate/loose-keys.js";import{relocateProfileFolders as rr}from"../core/profiles/relocate.js";import{getNode as tr,listNodesForSupervision as le,listParkedResidentsWithWakeMail as nr,setFrozen as pe}from"../core/canvas/index.js";import{createApiServer as or}from"./api/server.js";import{createDocumentListener as ir}from"./api/document-listener.js";import{documentSecret as ar}from"./api/document-secret.js";import{createAppListener as sr}from"./api/app-listener.js";import{registerMachineEnvironment as cr}from"../core/environments.js";import{resolvePerson as dr,retireLocalPerson as lr,setPersonId as pr}from"../core/canvas/person.js";import{onRunEventAppended as mr}from"../core/runs/events.js";import{runNotices as fr}from"./run-notices.js";import{createGrantSync as ur,GRANT_SYNC_INTERVAL_S as wr}from"../core/grants/sync.js";import{runRemovalCascades as hr}from"../core/grants/remove.js";import{sweepSandboxes as vr}from"../core/grants/on-sync.js";import{rebuildCronExecutions as gr}from"./cron/run-socket.js";import{hasSyncedGrants as yr}from"../core/grants/mirror.js";import{readConfig as me}from"../core/config.js";import{reconcileUndeliveredTickets as Sr}from"./human/sweep.js";import{resetHandedOffDeliveries as _r}from"../core/canvas/deliveries.js";import{resetHandedOffDaemonActions as br}from"../core/canvas/daemon-actions.js";import{sweepReviews as kr}from"./review/sweep.js";import{pidfilePath as U}from"./pidfile.js";import{rendererWarning as Pr}from"../core/runtime/package-health.js";import{DEFAULT_INTERVAL_MS as Er}from"./supervise-cadence.js";import{createResumeDetector as Rr}from"./resume-detector.js";import{setFatalFaultAnnouncer as Ir}from"../core/canvas/recovery.js";import{BrokerSupervisionReconciler as xr}from"./reconcilers/broker-supervision.js";import{ControllerDeathReconciler as Dr}from"./reconcilers/controller-death.js";import{NodeLifecycleReconciler as Tr}from"./reconcilers/node-lifecycle/tick.js";import{NodeDeadlineReconciler as Cr}from"./reconcilers/node-deadline.js";import{CronLaneReconciler as Lr}from"./reconcilers/cron-lane.js";import{DeliveryLaneReconciler as $r}from"./reconcilers/delivery-lane.js";import{ActionLaneReconciler as Ar}from"./reconcilers/action-lane.js";import{endLiveExecution as Mr,migrateLegacyExecutionIdentities as Nr}from"../core/canvas/executions.js";import{revokePriorEpochNodeTokens as Fr}from"../core/canvas/node-tokens.js";import{PendingReviewSubmitReconciler as Gr}from"./reconcilers/pending-review-submit.js";import{StorageMaintenanceReconciler as Or}from"./reconcilers/storage-maintenance.js";import{StorageDueWorkReconciler as Br}from"./reconcilers/storage-due-work.js";import{BashDeadlineReconciler as Hr}from"./reconcilers/bash-deadline.js";import{FaultRetryBackstopReconciler as jr}from"./reconcilers/fault-retry-backstop.js";import{StructuredRequestReconciler as qr}from"./reconcilers/structured-request-lane.js";import{reconcileStructuredRequestSidecars as zr}from"./structured-requests/boot.js";import{captureLivenessSnapshot as fe,capturePidCommand as Wr,captureTeardownSnapshot as ue,isPidAlive as Ur,isAnyPidAlive as we,killProcessTreePids as he}from"../core/canvas/pid.js";import{bindFleet as Kr,boundFleet as Jr}from"../core/runtime/fleet.js";import{bindDaemonControl as Vr,clearDaemonControl as Qr}from"./control.js";import{execDaemon as Yr,spawnDaemon as Xr}from"./manage.js";import{reconcileAndMigrateBoot as Zr}from"../core/canvas/boot.js";import{resolveInstallId as et}from"../core/canvas/install-id.js";import{setInstallId as rt}from"../core/runtime/nodes.js";import{claimDaemonOwnership as ve,daemonOwnershipClaimed as tt,releaseDaemonOwnership as ge}from"../core/canvas/daemon-owner.js";import{canvasDatabaseUrl as nt,closeAllDbs as K,openDb as ye,withCanvasWrite as ot}from"../core/canvas/db.js";import{importSqliteCanvasIfPresent as it}from"../core/canvas/import-sqlite.js";import{ensurePostgres as at,ensurePostgresHealthy as st,stopPostgres as ct,withPostgresStartLock as dt}from"./postgres/index.js";import{brokerSignalBus as J}from"./broker-signals/bus.js";import{brokerSignalStreams as lt}from"./api/handlers/broker-signals.js";import{reconcilePackages as pt}from"../core/graph/package-reconcile.js";import{startRepoSync as mt}from"../core/graph/repo-sync/index.js";import{prewarmRecentRecipes as ft,reapStaleSpares as ut}from"../core/runtime/warm-pool.js";import{DaemonFleet as wt}from"./fleet.js";import{BOOT_MIGRATIONS as ht}from"./boot-migrations.js";import{emitEvent as m}from"../core/events/emit.js";import{operationIdContext as _}from"../core/events/operation-id.js";import{bindDaemonEventSource as vt}from"../core/events/source.js";import{activateCanvasImport as gt,MigrationBlockedError as yt,runForcedCanvasImport as St}from"../migrations/activation.js";import{convertLegacyProviderStore as _t,convertLegacyScopedStore as bt}from"../core/scoped-state/migrate.js";import{userScopeRoot as kt}from"../core/scope.js";import{secretsDir as Pt}from"../core/layout.js";function V(n,s){return n.includes(` --canvas-home ${s} `)}a(V,"brokerCommandDeclaresCanvasHome");function Q(n){return/ --epoch (\S+) /.exec(n)?.[1]??null}a(Q,"brokerCommandEpoch");const Et=5e3,Se=150;async function Rt(n){const s=fe();if(s===null)throw m({level:"error",event:"daemon.census.snapshot_failed",fields:{invariant:"prior-epoch brokers are reaped before readiness"}}),new Error("prior-epoch broker census could not capture the process table");const l=Ke(),w=[];for(const[c,f]of s.processes){const S=f.command;if(f.zombie||!S.includes("broker-cli.js")||!V(S,l)||Q(S)===n)continue;const k=S.trim().split(/\s+/).at(-1)??"";k===""||k.endsWith("broker-cli.js")||w.push({pid:c,nodeId:k})}let d=0;const t=[];for(const c of w){const f=Wr(c.pid);if(f===null||!f.includes("broker-cli.js")||!V(f,l)||Q(f)===n||f.trim().split(/\s+/).at(-1)!==c.nodeId)continue;const S=ue(c.pid,null);if(!S.reused){try{process.platform==="linux"&&P(x)?await C({operation:"stop",pid:c.pid}):process.kill(c.pid,"SIGTERM")}catch{continue}d++,t.push({pid:c.pid,snap:S})}}const g=Date.now()+Et;for(;Date.now()<g&&t.some(c=>we(c.snap.tree.length>0?c.snap.tree:[c.pid]));)await new Promise(c=>setTimeout(c,Se));let h=0;for(const c of t){const f=c.snap.tree.length>0?c.snap.tree:[c.pid];we(f)&&(process.platform==="linux"&&P(x)?await C({operation:"stop",pid:c.pid}):he(f,"SIGKILL",c.snap.identities),h++)}h>0&&await new Promise(c=>setTimeout(c,Se));const u=fe();if(u===null)throw m({level:"error",event:"daemon.census.snapshot_failed",fields:{invariant:"prior-epoch brokers are reaped before readiness",stage:"final"}}),new Error("prior-epoch broker census could not capture the final process table");const i=[];for(const[c,f]of u.processes){const S=f.command;f.zombie||!S.includes("broker-cli.js")||V(S,l)&&Q(S)!==n&&i.push(c)}if(i.length>0)throw new Error(`prior-epoch broker census could not prove termination of pid(s): ${i.join(", ")}`);m({level:"info",event:"daemon.census.completed",fields:{prior_epoch_brokers:w.length,sigtermed:d,sigkilled:h}})}a(Rt,"reapPriorEpochBrokers");const It=5e3;async function xt(n){const s=Array.from(n.entries());if(s.length===0)return;for(const[t]of s){const g=(await tr(t))?.status;(g==="active"||g==="idle")&&await pe(t,new Date().toISOString())}const l=s.map(([,t])=>({pid:t.pid,snap:ue(t.pid,null),exited:t.handle.exited}));for(const t of l)if(!t.snap.reused)try{process.platform==="linux"&&P(x)?await C({operation:"stop",pid:t.pid}):process.kill(t.pid,"SIGTERM")}catch{}const w=new Promise(t=>{setTimeout(t,It).unref()});await Promise.allSettled(l.map(t=>Promise.race([t.exited.then(()=>{}),w])));const d=[];for(const t of l)Ur(t.pid)&&(process.platform==="linux"&&P(x)?await C({operation:"stop",pid:t.pid}):he(t.snap.tree.length>0?t.snap.tree:[t.pid],"SIGKILL",t.snap.identities),d.push(t));await Promise.all(d.map(t=>t.exited));for(const[t]of s)await Mr(t,{reason:"daemon-teardown"});m({level:"info",event:"daemon.fleet_teardown.completed",fields:{brokers:l.length,sigkilled:d.length}})}a(xt,"teardownFleet");function _e(){ae(He(U()),{recursive:!0}),Fe(U(),String(process.pid),"utf8")}a(_e,"writePidfile");function be(n){return typeof n=="object"&&n!==null&&n.code==="ENOENT"}a(be,"isMissingPathError");function ke(n){const s=U();let l;try{l=Ge(s,"utf8")}catch(w){if(be(w))return;throw w}if(l.trim()!==String(n))throw new Error(`daemon readiness mirror does not name this invocation (expected pid ${n})`);try{Oe(s)}catch(w){if(be(w))return;throw w}}a(ke,"removeOwnedPidfileMirror");const Dt={acceptsDetachedWork:a(()=>!0,"acceptsDetachedWork"),registerDetached:a(n=>{n.catch(()=>{})},"registerDetached")},B=new xr;Ir(n=>B.handleFatalFault(n,!1));const Tt=new Dr,Ct=new Tr,Lt=new Cr,$t=new Lr,At=new $r,Mt=new Ar,Nt=new Gr,Ft=new Or,Gt=new Br,Ot=new Hr,Bt=new jr,Ht=new qr;async function jt(n=Date.now(),s=Dt){const l=Jr(),w=await B.runFleetPreamble(l);let d,t;try{const h=await le();d=h.filter(i=>i.status==="active"||i.status==="idle"),t=h.filter(i=>i.status==="done"||i.status==="canceled"||i.status==="dead");const u=new Set(t.map(i=>i.node_id));t.push(...(await nr()).filter(i=>!u.has(i.node_id)))}catch(h){m({level:"error",event:"canvas.node_list.failed",error:h});return}await B.run(n,{rows:d,fleet:l,lifecycle:s}),await Tt.run(n,{rows:d});const g=await Ct.run(n,{rows:[...d,...t],fleet:l});await Lt.run(n),await Ht.run(n),await $t.run(n,{lifecycle:s}),await At.run(n,{lifecycle:s}),await Mt.run(n,{lifecycle:s}),await Nt.run(n,{lifecycle:s}),await Ft.run(n,{lifecycle:s,fleet:l}),Gt.run(n,{lifecycle:s}),await We(),Bt.run(n,{fleet:l,lifecycle:s}),await Ot.run(n,{rows:d}),B.warnIfSaturated({fleet:l,lifecycle:s,thresholds:w,frozen:g})}a(jt,"superviseTick");async function qt(n){ae(de(),{recursive:!0,mode:493}),process.platform==="linux"&&Be(de(),493);const s=Ue();if(P(s))throw new Error(`layout refusal cannot bind occupied socket: ${s}`);const l=se((u,i)=>{if(u.method==="GET"&&u.url==="/healthz"){i.writeHead(200,{"content-type":"application/json; charset=utf-8"}),i.end(JSON.stringify({ok:!1,daemon_up:!0,store_accessible:!1,brokers_reconciled:!1,startup_phase:"blocked",startup_blocked:"layout_migration_required"}));return}i.writeHead(503,{"content-type":"application/json; charset=utf-8"}),i.end(JSON.stringify({error:{code:"layout_migration_required",message:"run crtr sys migrate while the runtime is offline",type:"server_error",origin:"runtime",retryable:!1}}))});await new Promise((u,i)=>{l.once("error",i),l.listen(s,()=>{l.off("error",i),u()})});let w;const d=n.tcp??je();if(d){const u=/^(.*):(\d+)$/.exec(d);if(!u||Number(u[2])>65535)throw new Error(`invalid refusal TCP address: ${d}`);const i=se(l.listeners("request")[0]);await new Promise((c,f)=>{i.once("error",f),i.listen(Number(u[2]),u[1],()=>{i.off("error",f),c()})}),w=i}_e();let t;const g=a(()=>(t??=(async()=>{l.closeAllConnections(),w?.closeAllConnections(),await Promise.all([l,w].filter(u=>u!==void 0).map(u=>new Promise((i,c)=>u.close(f=>f?c(f):i())))),ke(process.pid),process.off("SIGINT",h),process.off("SIGTERM",h)})(),t),"cleanup"),h=a(()=>{g().then(()=>process.exit(0),u=>{process.stderr.write(`[crtrd] layout refusal cleanup failed: ${String(u)}
|
|
2
|
-
`),process.exit(1)})},"onSignal");return process.on("SIGINT",h),process.on("SIGTERM",h),g}
|
|
3
|
-
`)},"logPostgres"),l=!!process.env.CRTR_TEST_PG_URL,{database:w,ownership:d}=l?{database:{url:await
|
|
4
|
-
`);else{const r=[d.incumbentPid!==void 0?`pid ${d.incumbentPid}`:void 0,d.verdict!==void 0?`verdict ${d.verdict}`:void 0].filter(
|
|
5
|
-
`),d.reason==="own_identity_indeterminate"&&process.stderr.write("[crtrd] cannot read its own process identity. crouter needs /proc on Linux, or the `ps` command elsewhere (Debian/Ubuntu: apt-get install procps).\n"),(d.reason==="own_identity_indeterminate"||d.reason==="incumbent_malformed")&&(process.exitCode=1)}return async()=>{}}const t=d.claim;let g=null,h=null,
|
|
6
|
-
`);if(process.platform==="darwin"){const{readConfig:e,updateConfig:
|
|
7
|
-
`);await
|
|
1
|
+
var Ae=Object.defineProperty;var i=(n,s)=>Ae(n,"name",{value:s,configurable:!0});import{startPeerOutbox as Me}from"./peer/outbox.js";import{reportMachineStatus as Ne}from"../core/peer/directory.js";import{createPeerRelay as Fe}from"./peer/relay-service.js";import{writeFileSync as Ge,readFileSync as Oe,rmSync as Be,mkdirSync as se,existsSync as k,chmodSync as He}from"node:fs";import{createServer as ce}from"node:http";import{dirname as je}from"node:path";import{envCrtrdTcp as qe,envDocumentPort as ze}from"../shared/env.js";import{serveCanvasConversationStore as We}from"../core/canvas/sessions.js";import{pollRunObservers as Ue}from"./runs/observer.js";import{randomBytes as de}from"node:crypto";import{apiSocketPath as Ke,crtrHome as Je}from"../core/canvas/paths.js";import{activeAppUsers as Ve}from"../core/spaces/users.js";import{ensureAppSpace as Qe,ensureUserFiles as Ye}from"../core/spaces/space.js";import{LAUNCHER_SOCKET as x}from"../launcher/spec.js";import{launcherRequest as C}from"../launcher/client.js";import{installLauncherEventSink as Xe}from"./launcher-events.js";import{initializeEmptyLayout as Ze,layoutNeedsMigration as er,socketDir as le}from"../core/layout.js";import{migrateLooseKeys as rr}from"../core/layout-migrate/loose-keys.js";import{relocateProfileFolders as tr}from"../core/profiles/relocate.js";import{getNode as nr,listNodesForSupervision as pe,listParkedResidentsWithWakeMail as or,setFrozen as me}from"../core/canvas/index.js";import{createApiServer as ir}from"./api/server.js";import{createDocumentListener as ar}from"./api/document-listener.js";import{documentSecret as sr}from"./api/document-secret.js";import{createAppListener as cr}from"./api/app-listener.js";import{registerMachineEnvironment as dr}from"../core/environments.js";import{resolvePerson as lr,retireLocalPerson as pr,setPersonId as mr}from"../core/canvas/person.js";import{backfillNodeApps as fr,runPermissionsBoot as ur}from"../core/permissions/boot.js";import{onRunEventAppended as wr}from"../core/runs/events.js";import{runNotices as hr}from"./run-notices.js";import{createGrantSync as vr,GRANT_SYNC_INTERVAL_S as gr}from"../core/grants/sync.js";import{runRemovalCascades as yr}from"../core/grants/remove.js";import{sweepSandboxes as Sr}from"../core/grants/on-sync.js";import{rebuildCronExecutions as _r}from"./cron/run-socket.js";import{hasSyncedGrants as br}from"../core/grants/mirror.js";import{readConfig as fe}from"../core/config.js";import{reconcileUndeliveredTickets as kr}from"./human/sweep.js";import{resetHandedOffDeliveries as Pr}from"../core/canvas/deliveries.js";import{resetHandedOffDaemonActions as Er}from"../core/canvas/daemon-actions.js";import{sweepReviews as Rr}from"./review/sweep.js";import{pidfilePath as K}from"./pidfile.js";import{rendererWarning as Ir}from"../core/runtime/package-health.js";import{DEFAULT_INTERVAL_MS as xr}from"./supervise-cadence.js";import{createResumeDetector as Dr}from"./resume-detector.js";import{setFatalFaultAnnouncer as Tr}from"../core/canvas/recovery.js";import{BrokerSupervisionReconciler as Cr}from"./reconcilers/broker-supervision.js";import{ControllerDeathReconciler as Lr}from"./reconcilers/controller-death.js";import{NodeLifecycleReconciler as $r}from"./reconcilers/node-lifecycle/tick.js";import{NodeDeadlineReconciler as Ar}from"./reconcilers/node-deadline.js";import{CronLaneReconciler as Mr}from"./reconcilers/cron-lane.js";import{DeliveryLaneReconciler as Nr}from"./reconcilers/delivery-lane.js";import{ActionLaneReconciler as Fr}from"./reconcilers/action-lane.js";import{endLiveExecution as Gr,migrateLegacyExecutionIdentities as Or}from"../core/canvas/executions.js";import{revokePriorEpochNodeTokens as Br}from"../core/canvas/node-tokens.js";import{PendingReviewSubmitReconciler as Hr}from"./reconcilers/pending-review-submit.js";import{StorageMaintenanceReconciler as jr}from"./reconcilers/storage-maintenance.js";import{StorageDueWorkReconciler as qr}from"./reconcilers/storage-due-work.js";import{BashDeadlineReconciler as zr}from"./reconcilers/bash-deadline.js";import{FaultRetryBackstopReconciler as Wr}from"./reconcilers/fault-retry-backstop.js";import{StructuredRequestReconciler as Ur}from"./reconcilers/structured-request-lane.js";import{reconcileStructuredRequestSidecars as Kr}from"./structured-requests/boot.js";import{captureLivenessSnapshot as ue,capturePidCommand as Jr,captureTeardownSnapshot as we,isPidAlive as Vr,isAnyPidAlive as he,killProcessTreePids as ve}from"../core/canvas/pid.js";import{bindFleet as Qr,boundFleet as Yr}from"../core/runtime/fleet.js";import{bindDaemonControl as Xr,clearDaemonControl as Zr}from"./control.js";import{execDaemon as et,spawnDaemon as rt}from"./manage.js";import{reconcileAndMigrateBoot as tt}from"../core/canvas/boot.js";import{resolveInstallId as nt}from"../core/canvas/install-id.js";import{setInstallId as ot}from"../core/runtime/nodes.js";import{claimDaemonOwnership as ge,daemonOwnershipClaimed as it,releaseDaemonOwnership as ye}from"../core/canvas/daemon-owner.js";import{canvasDatabaseUrl as at,closeAllDbs as J,openDb as Se,withCanvasWrite as st}from"../core/canvas/db.js";import{importSqliteCanvasIfPresent as ct}from"../core/canvas/import-sqlite.js";import{ensurePostgres as dt,ensurePostgresHealthy as lt,stopPostgres as pt,withPostgresStartLock as mt}from"./postgres/index.js";import{brokerSignalBus as V}from"./broker-signals/bus.js";import{brokerSignalStreams as ft}from"./api/handlers/broker-signals.js";import{reconcilePackages as ut}from"../core/graph/package-reconcile.js";import{startRepoSync as wt}from"../core/graph/repo-sync/index.js";import{prewarmRecentRecipes as ht,reapStaleSpares as vt}from"../core/runtime/warm-pool.js";import{DaemonFleet as gt}from"./fleet.js";import{BOOT_MIGRATIONS as yt}from"./boot-migrations.js";import{emitEvent as m}from"../core/events/emit.js";import{operationIdContext as _}from"../core/events/operation-id.js";import{bindDaemonEventSource as St}from"../core/events/source.js";import{activateCanvasImport as _t,MigrationBlockedError as bt,runForcedCanvasImport as kt}from"../migrations/activation.js";import{convertLegacyProviderStore as Pt,convertLegacyScopedStore as Et}from"../core/scoped-state/migrate.js";import{userScopeRoot as Rt}from"../core/scope.js";import{secretsDir as It}from"../core/layout.js";function Q(n,s){return n.includes(` --canvas-home ${s} `)}i(Q,"brokerCommandDeclaresCanvasHome");function Y(n){return/ --epoch (\S+) /.exec(n)?.[1]??null}i(Y,"brokerCommandEpoch");const xt=5e3,_e=150;async function Dt(n){const s=ue();if(s===null)throw m({level:"error",event:"daemon.census.snapshot_failed",fields:{invariant:"prior-epoch brokers are reaped before readiness"}}),new Error("prior-epoch broker census could not capture the process table");const l=Je(),w=[];for(const[a,u]of s.processes){const y=u.command;if(u.zombie||!y.includes("broker-cli.js")||!Q(y,l)||Y(y)===n)continue;const P=y.trim().split(/\s+/).at(-1)??"";P===""||P.endsWith("broker-cli.js")||w.push({pid:a,nodeId:P})}let d=0;const t=[];for(const a of w){const u=Jr(a.pid);if(u===null||!u.includes("broker-cli.js")||!Q(u,l)||Y(u)===n||u.trim().split(/\s+/).at(-1)!==a.nodeId)continue;const y=we(a.pid,null);if(!y.reused){try{process.platform==="linux"&&k(x)?await C({operation:"stop",pid:a.pid}):process.kill(a.pid,"SIGTERM")}catch{continue}d++,t.push({pid:a.pid,snap:y})}}const g=Date.now()+xt;for(;Date.now()<g&&t.some(a=>he(a.snap.tree.length>0?a.snap.tree:[a.pid]));)await new Promise(a=>setTimeout(a,_e));let h=0;for(const a of t){const u=a.snap.tree.length>0?a.snap.tree:[a.pid];he(u)&&(process.platform==="linux"&&k(x)?await C({operation:"stop",pid:a.pid}):ve(u,"SIGKILL",a.snap.identities),h++)}h>0&&await new Promise(a=>setTimeout(a,_e));const f=ue();if(f===null)throw m({level:"error",event:"daemon.census.snapshot_failed",fields:{invariant:"prior-epoch brokers are reaped before readiness",stage:"final"}}),new Error("prior-epoch broker census could not capture the final process table");const c=[];for(const[a,u]of f.processes){const y=u.command;u.zombie||!y.includes("broker-cli.js")||Q(y,l)&&Y(y)!==n&&c.push(a)}if(c.length>0)throw new Error(`prior-epoch broker census could not prove termination of pid(s): ${c.join(", ")}`);m({level:"info",event:"daemon.census.completed",fields:{prior_epoch_brokers:w.length,sigtermed:d,sigkilled:h}})}i(Dt,"reapPriorEpochBrokers");const Tt=5e3;async function Ct(n){const s=Array.from(n.entries());if(s.length===0)return;for(const[t]of s){const g=(await nr(t))?.status;(g==="active"||g==="idle")&&await me(t,new Date().toISOString())}const l=s.map(([,t])=>({pid:t.pid,snap:we(t.pid,null),exited:t.handle.exited}));for(const t of l)if(!t.snap.reused)try{process.platform==="linux"&&k(x)?await C({operation:"stop",pid:t.pid}):process.kill(t.pid,"SIGTERM")}catch{}const w=new Promise(t=>{setTimeout(t,Tt).unref()});await Promise.allSettled(l.map(t=>Promise.race([t.exited.then(()=>{}),w])));const d=[];for(const t of l)Vr(t.pid)&&(process.platform==="linux"&&k(x)?await C({operation:"stop",pid:t.pid}):ve(t.snap.tree.length>0?t.snap.tree:[t.pid],"SIGKILL",t.snap.identities),d.push(t));await Promise.all(d.map(t=>t.exited));for(const[t]of s)await Gr(t,{reason:"daemon-teardown"});m({level:"info",event:"daemon.fleet_teardown.completed",fields:{brokers:l.length,sigkilled:d.length}})}i(Ct,"teardownFleet");function be(){se(je(K()),{recursive:!0}),Ge(K(),String(process.pid),"utf8")}i(be,"writePidfile");function ke(n){return typeof n=="object"&&n!==null&&n.code==="ENOENT"}i(ke,"isMissingPathError");function Pe(n){const s=K();let l;try{l=Oe(s,"utf8")}catch(w){if(ke(w))return;throw w}if(l.trim()!==String(n))throw new Error(`daemon readiness mirror does not name this invocation (expected pid ${n})`);try{Be(s)}catch(w){if(ke(w))return;throw w}}i(Pe,"removeOwnedPidfileMirror");const Lt={acceptsDetachedWork:i(()=>!0,"acceptsDetachedWork"),registerDetached:i(n=>{n.catch(()=>{})},"registerDetached")},H=new Cr;Tr(n=>H.handleFatalFault(n,!1));const $t=new Lr,At=new $r,Mt=new Ar,Nt=new Mr,Ft=new Nr,Gt=new Fr,Ot=new Hr,Bt=new jr,Ht=new qr,jt=new zr,qt=new Wr,zt=new Ur;async function Wt(n=Date.now(),s=Lt){const l=Yr(),w=await H.runFleetPreamble(l);let d,t;try{const h=await pe();d=h.filter(c=>c.status==="active"||c.status==="idle"),t=h.filter(c=>c.status==="done"||c.status==="canceled"||c.status==="dead");const f=new Set(t.map(c=>c.node_id));t.push(...(await or()).filter(c=>!f.has(c.node_id)))}catch(h){m({level:"error",event:"canvas.node_list.failed",error:h});return}await H.run(n,{rows:d,fleet:l,lifecycle:s}),await $t.run(n,{rows:d});const g=await At.run(n,{rows:[...d,...t],fleet:l});await Mt.run(n),await zt.run(n),await Nt.run(n,{lifecycle:s}),await Ft.run(n,{lifecycle:s}),await Gt.run(n,{lifecycle:s}),await Ot.run(n,{lifecycle:s}),await Bt.run(n,{lifecycle:s,fleet:l}),Ht.run(n,{lifecycle:s}),await Ue(),qt.run(n,{fleet:l,lifecycle:s}),await jt.run(n,{rows:d}),H.warnIfSaturated({fleet:l,lifecycle:s,thresholds:w,frozen:g})}i(Wt,"superviseTick");async function Ut(n){se(le(),{recursive:!0,mode:493}),process.platform==="linux"&&He(le(),493);const s=Ke();if(k(s))throw new Error(`layout refusal cannot bind occupied socket: ${s}`);const l=ce((f,c)=>{if(f.method==="GET"&&f.url==="/healthz"){c.writeHead(200,{"content-type":"application/json; charset=utf-8"}),c.end(JSON.stringify({ok:!1,daemon_up:!0,store_accessible:!1,brokers_reconciled:!1,startup_phase:"blocked",startup_blocked:"layout_migration_required"}));return}c.writeHead(503,{"content-type":"application/json; charset=utf-8"}),c.end(JSON.stringify({error:{code:"layout_migration_required",message:"run crtr sys migrate while the runtime is offline",type:"server_error",origin:"runtime",retryable:!1}}))});await new Promise((f,c)=>{l.once("error",c),l.listen(s,()=>{l.off("error",c),f()})});let w;const d=n.tcp??qe();if(d){const f=/^(.*):(\d+)$/.exec(d);if(!f||Number(f[2])>65535)throw new Error(`invalid refusal TCP address: ${d}`);const c=ce(l.listeners("request")[0]);await new Promise((a,u)=>{c.once("error",u),c.listen(Number(f[2]),f[1],()=>{c.off("error",u),a()})}),w=c}be();let t;const g=i(()=>(t??=(async()=>{l.closeAllConnections(),w?.closeAllConnections(),await Promise.all([l,w].filter(f=>f!==void 0).map(f=>new Promise((c,a)=>f.close(u=>u?a(u):c())))),Pe(process.pid),process.off("SIGINT",h),process.off("SIGTERM",h)})(),t),"cleanup"),h=i(()=>{g().then(()=>process.exit(0),f=>{process.stderr.write(`[crtrd] layout refusal cleanup failed: ${String(f)}
|
|
2
|
+
`),process.exit(1)})},"onSignal");return process.on("SIGINT",h),process.on("SIGTERM",h),g}i(Ut,"serveLayoutRefusal");async function Kt(n={}){if(er())return Ut(n);Ze();const s=i(r=>{process.stderr.write(`[crtrd] ${r}
|
|
3
|
+
`)},"logPostgres"),l=!!process.env.CRTR_TEST_PG_URL,{database:w,ownership:d}=l?{database:{url:await at()},ownership:await ge(de(16).toString("hex"))}:await mt(async()=>({database:await dt({log:s,startLockHeld:!0}),ownership:await ge(de(16).toString("hex"))}));if(!d.claimed){if(d.reason==="incumbent_alive")process.stderr.write(`[crtrd] already running (pid ${d.incumbentPid??"?"})
|
|
4
|
+
`);else{const r=[d.incumbentPid!==void 0?`pid ${d.incumbentPid}`:void 0,d.verdict!==void 0?`verdict ${d.verdict}`:void 0].filter(S=>S!==void 0),e=r.length>0?` (${r.join(", ")})`:"";process.stderr.write(`[crtrd] claim lost: ${d.reason}${e}
|
|
5
|
+
`),d.reason==="own_identity_indeterminate"&&process.stderr.write("[crtrd] cannot read its own process identity. crouter needs /proc on Linux, or the `ps` command elsewhere (Debian/Ubuntu: apt-get install procps).\n"),(d.reason==="own_identity_indeterminate"||d.reason==="incumbent_malformed")&&(process.exitCode=1)}return async()=>{}}const t=d.claim;let g=null,h=null,f=null,c="";try{await Dt(t.token),Et({kind:"user",root:Rt()});for(const e of tr())process.stderr.write(`[crtrd] ${e}
|
|
6
|
+
`);if(process.platform==="darwin"){const{readConfig:e,updateConfig:S}=await import("../core/config.js");if(e("user").paths?.user_files===void 0){const{homedir:o}=await import("node:os");S("user",p=>{p.paths??={},p.paths.user_files??=o()})}}await Pt(It());for(const e of rr())process.stderr.write(`[crtrd] ${e}
|
|
7
|
+
`);await Se(),await ct(w.url,s),await V.listen(w.url);const r=await st(async e=>(await fr(e),await ut(e)));for(const e of r.conflicts)process.stderr.write(`[crtrd] plugin documents not reconciled: ${e.message}
|
|
8
8
|
`);for(const e of r.invalid)process.stderr.write(`[crtrd] package file is not a document: ${e.path}: ${e.error}
|
|
9
9
|
`);for(const e of r.quarantined)process.stderr.write(`[crtrd] plugin "${e.name}" has a damaged ${e.file} (${e.reason}); ${e.movedTo!==void 0?`moved to ${e.movedTo}`:"left in place and skipped"}
|
|
10
10
|
`);for(const e of r.kinds.refused)process.stderr.write(`[crtrd] plugin "${e.plugin}" kind ${e.kind} not registered: ${e.message}
|
|
11
11
|
`);for(const e of r.kinds.invalid)process.stderr.write(`[crtrd] plugin "${e.plugin}" declares invalid object kinds or scopes; no kinds registered and no app token: ${e.error}
|
|
12
|
-
`);
|
|
12
|
+
`);c=await nt(),ot(c),g=await lr(),g!==null&&(mr(g.id),h=await pr(),f=await ur()),process.platform==="linux"&&k(x)&&(Xe(),await C({operation:"users.sync",users:await Ve()})),await Br(t.token)}catch(r){await V.close();try{const{released:e}=await ye(t);if(!e)throw new Error("daemon ownership claim was not released");await J()}catch(e){throw new AggregateError([r,e],"daemon startup failed and cleanup also failed")}throw r}let a=!0,u,y=Promise.resolve(),P=!1,N,D;const F=new Set;let j=!1,X=!1,E,G,q,Z=!1,O,L,$,A,z;const Ee=Dr();let R,v={phase:"initializing",message:"daemon startup is running the canvas import and normal services are unavailable",blockerPaths:[]},T="initial startup activation",Re=null;function Ie(){return v.phase==="ready"?null:{phase:v.phase,message:v.message,blockerPaths:v.blockerPaths}}i(Ie,"startupBlock");function b(r){F.add(r),r.finally(()=>{F.delete(r)}).catch(()=>{})}i(b,"registerDetached");const ee={acceptsDetachedWork:i(()=>a,"acceptsDetachedWork"),registerDetached:b};await wt(ee,Se);async function xe(){try{a=!1,ft.close(),await V.close(),N!==void 0&&(clearInterval(N),N=void 0),$!==void 0&&(clearInterval($),$=void 0),z?.(),z=void 0;let r;do r=y,await r;while(r!==y);for(;F.size>0;)await Promise.allSettled([...F]);if(D!==void 0&&(await Ct(D),await D.exitsSettled(),D.dispose()),q!==void 0&&await q.close(),G!==void 0&&!Z&&(Z=!0,await G.close()),A!==void 0){const e=A;A=void 0,await e.stop()}if(L!==void 0){const e=L;L=void 0,await e.close()}if(O!==void 0){const e=O;O=void 0,await e.close()}if(j||(Pe(process.pid),j=!0),j&&!X){const{released:e}=await ye(t);if(!e)throw new Error("daemon ownership claim was not released");X=!0,await J()}}finally{Zr(),process.off("SIGINT",ne),process.off("SIGTERM",oe),process.off("exit",ie)}}i(xe,"cleanupAttempt");const B=1e3;let re=!1;function De(){return re?{graceMs:B}:(re=!0,_.fresh(()=>{m({level:"info",event:"daemon.handover.armed",fields:{pid:process.pid,grace_ms:B}})}),setTimeout(()=>{Te()},B),{graceMs:B})}i(De,"requestHandover");async function Te(){try{await I()}catch(r){const e=r instanceof Error?r.stack??r.message:String(r);process.stderr.write(`[crtrd] handover cleanup failed:
|
|
13
13
|
${e}
|
|
14
|
-
`),process.exit(1)}try{process.platform==="linux"&&
|
|
15
|
-
`),process.exit(1)}process.exit(0)}
|
|
16
|
-
${
|
|
17
|
-
`),process.exit(1)}}
|
|
14
|
+
`),process.exit(1)}try{process.platform==="linux"&&k(x)&&(await C({operation:"daemon.handover"}),process.exit(0)),process.pid===1&&await et();const r=await rt({waitForJoinLock:!0});_.fresh(()=>{m({level:"info",event:"daemon.handover.completed",fields:{predecessor_pid:process.pid,successor_pid:r.pid??r.existing_pid??null,spawned:r.started}})})}catch(r){_.fresh(()=>{m({level:"error",event:"daemon.handover.successor_failed",error:r})});const e=r instanceof Error?r.message:String(r);process.stderr.write(`[crtrd] handover successor failed to start: ${e}
|
|
15
|
+
`),process.exit(1)}process.exit(0)}i(Te,"performHandover");function I(){if(E!==void 0)return E;const r=xe();return E=r,r.then(()=>{E===r&&(E=void 0)},()=>{E===r&&(E=void 0)}),r}i(I,"requestCleanup");async function te(r){try{await I(),await pt({claimed:i(async()=>{try{return await it()}finally{await J()}},"claimed")}),process.exit(0)}catch(e){process.exitCode=1;const S=e instanceof Error?e.stack??`${e.name}: ${e.message}`:String(e);process.stderr.write(`[crtrd] ${r} cleanup failed:
|
|
16
|
+
${S}
|
|
17
|
+
`),process.exit(1)}}i(te,"handleSignal");function ne(){te("SIGINT")}i(ne,"onSigint");function oe(){te("SIGTERM")}i(oe,"onSigterm");function ie(){I().catch(()=>{})}i(ie,"onExit");async function W(r){a&&(y=y.then(r).then(()=>{},e=>{_.fresh(()=>{m({level:"error",event:"daemon.lane_job.failed",error:e})})}))}i(W,"enqueue");async function ae(){!a||P||(Ee.check()&&R&&(m({level:"info",event:"daemon.resume.detected"}),b(R().catch(()=>{}))),P=!0,await W(async()=>{if(P=!1,!!a)try{l||await lt({log:s}),await Wt(Date.now(),ee)}catch(r){_.fresh(()=>{m({level:"error",event:"daemon.tick.failed",error:r})})}}))}i(ae,"enqueueTick");let M=null;async function Ce(){if(M!==null)throw{status:500,code:"admission_failed",message:`daemon admission previously failed: ${M instanceof Error?M.message:String(M)}`};if(v.phase==="ready")return{admitted:!1,already_admitted:!0,startup_phase:"ready"};if(v.phase!=="prepared"&&v.phase!=="recovering")throw{status:409,code:"not_prepared",message:v.message};const r=v.phase==="prepared";try{return await U(),v={phase:"ready",message:"",blockerPaths:[]},r?{admitted:!0,already_admitted:!1,startup_phase:"ready"}:{admitted:!1,already_admitted:!0,startup_phase:"ready"}}catch(e){throw M=e,{status:500,code:"admission_failed",message:`daemon admission failed: ${e instanceof Error?e.message:String(e)}`}}}i(Ce,"admitStartup");async function Le(r){if(T!==null)throw{status:409,code:"migration_in_progress",message:`the canvas import is already running (${T})`};T="repair";try{const e=await kt({dryRun:r.dryRun});if(r.dryRun||e.pending||v.phase!=="blocked")return{result:e,resumed:!1};if(n.prepare)return v={phase:"prepared",message:"daemon storage is prepared and normal services are unavailable until admission",blockerPaths:[]},{result:e,resumed:!1};try{return await U(),v={phase:"ready",message:"",blockerPaths:[]},{result:e,resumed:!0}}catch(S){const o=S instanceof Error?S.message:String(S);return setTimeout(()=>{I().catch(()=>{})},1e3),{result:e,resumed:!1,resumeError:o}}}finally{T=null}}i(Le,"repairMigrations");async function $e(){u=n.intervalMs??xr;const r=t.token;D=new gt({epoch:r,enqueue:W}),Qr(D),v={phase:"recovering",message:"daemon startup recovery is running and normal services are unavailable",blockerPaths:[]},_.fresh(()=>{m({level:"info",event:"daemon.started",fields:{pid:process.pid,interval_ms:u}})});const e=c;_.fresh(()=>{m({level:"info",event:"daemon.install_id.resolved",fields:{install_id:e}})});const S=await dr(e);if(_.fresh(()=>{m({level:"info",event:"daemon.environment.registered",fields:{environment_id:S.environmentId,created:S.created}})}),_.fresh(()=>{let o;try{o=Ir()}catch{return}o!==null&&m({level:"warn",event:"daemon.startup.warning",fields:{stage:"termrender",warning:o.slice(0,2048)}})}),await _.fresh(async()=>{await Rr(),await kr(),await Pr(Date.now()),await Er(Date.now())}),await _.fresh(async()=>{const{reconcile:o,migrated:p}=await tt(Or);o.changed&&m({level:"info",event:"daemon.boot_change.reconciled",fields:{cleared_count:o.cleared.length,same_boot_proven:o.sameBootProven}}),p.length>0&&m({level:"info",event:"daemon.pid_identity.migrated",fields:{migrated_count:p.length}})}),await _.fresh(async()=>{for(const o of await pe())o.status!=="active"||o.pi_pid!=null||o.frozen_at!=null||o.respawn_not_before!=null||(await me(o.node_id,new Date().toISOString()),m({level:"warn",event:"daemon.startup.launch_debt_recorded",node_id:o.node_id}))}),await _.fresh(async()=>{await Kr();for(const o of yt){const p=o.apply();p.changed&&m({level:"info",event:"daemon.boot_migration.applied",fields:{migration:o.id,...p.summary}})}}),b(_r()),R){const o=i(()=>{b(R().catch(()=>{})),b(Ne().then(p=>A?.observe(p)).then(()=>{},p=>{m({level:"warn",event:"daemon.peer.status_failed",error:p})}))},"refresh");b(yr().catch(()=>{})),b(Sr().then(({completion:p})=>p).catch(p=>{m({level:"error",event:"daemon.grants.sweep_failed",error:p})})),o(),$=setInterval(o,gr*1e3),$.unref(),z=Me({joined:!0,register:b})}await W(async()=>{await vt(),await ht()}),N=setInterval(()=>{ae().catch(o=>m({level:"error",event:"daemon.tick.failed",error:o}))},u),await ae()}i($e,"completeStartup");function U(){return Re??=$e().catch(r=>{throw v={phase:"initializing",message:"daemon startup recovery failed and normal services are unavailable",blockerPaths:[]},r})}i(U,"resumeStartup");try{process.on("SIGINT",ne),process.on("SIGTERM",oe),process.on("exit",ie),St(),g!==null&&m({level:"info",event:"daemon.person.resolved",fields:{person_id:g.id,source:g.source}}),f!==null&&m({level:"info",event:"daemon.permissions.boot",fields:{...f}}),h!==null&&m({level:"info",event:"daemon.person.retired",fields:{person_id:h.person,joined_from:h.joinedFrom,retired:h.retired,columns:h.columns}}),O=await We();const r=t.token;Xr({epoch:r,requestHandover:De,registerDetached:b,startupBlock:Ie,admitStartup:Ce,repairMigrations:Le}),be(),G=ir({tcp:n.tcp}),await G.ready;const e=ze()??fe("user").document_port,S=ar(e,sr());try{await S.ready,q=S}catch(p){m({level:"warn",event:"daemon.document_listener.bind_failed",fields:{port:e,error:p instanceof Error?p.message:String(p)}})}const o=fe("user").runtime;o?.issuer&&(R=vr(o.issuer,b),o.unsandboxed===!0&&(A=Fe({syncGrants:R})),wr(p=>hr().appended(p))),o?.unsandboxed===!0&&o.listener!==void 0&&m({level:"warn",event:"daemon.app_listener.refused_unsandboxed",fields:{reason:"runtime.unsandboxed is set; runtime.listener is ignored"}}),o!==void 0&&o.listener!==void 0&&o.unsandboxed!==!0&&(L=await cr(o,async()=>await br(o.issuer.replace(/\/$/,"")),R),await L.ready);try{await _t()}catch(p){if(T=null,p instanceof bt)return v={phase:"blocked",message:p.message,blockerPaths:p.blockerPaths},I;throw p}process.platform==="linux"&&k(x)&&(Ye(),await Qe("app:terminal"));try{n.prepare?v={phase:"prepared",message:"daemon storage is prepared and normal services are unavailable until admission",blockerPaths:[]}:(await U(),v={phase:"ready",message:"",blockerPaths:[]})}finally{T=null}return I}catch(r){try{await I()}catch(e){throw new AggregateError([r,e],"daemon startup failed and cleanup also failed")}throw r}}i(Kt,"runDaemon");var xo=Kt;export{Q as brokerCommandDeclaresCanvasHome,Y as brokerCommandEpoch,xo as default,Kt as runDaemon,Wt as superviseTick,Ct as teardownFleet};
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
var g=Object.defineProperty;var
|
|
1
|
+
var g=Object.defineProperty;var p=(e,t)=>g(e,"name",{value:t,configurable:!0});import{randomUUID as D}from"node:crypto";import{claimPushDelivery as h,duePushDeliveries as j,messageBodyForDelivery as N,pushDeliveryClaimIsCurrent as O,settleDelivery as d}from"../../core/canvas/deliveries.js";import{deliveryBackoffMs as f}from"../../core/canvas/delivery-contract.js";import{openDb as c}from"../../core/canvas/db.js";import{pushLineFor as u}from"../../core/graph/custom.js";import{postReceiverUrl as b}from"../../core/graph/receiver-url.js";import{emitEvent as l}from"../../core/events/emit.js";import{operationIdContext as m}from"../../core/events/operation-id.js";import{runDelivery as w,DELIVERY_TIMEOUT_MS as E}from"../delivery/run-delivery.js";const v=D();async function o(e,t,a){await d(e.deliveryId,e.attempts,t,{state:"permanent_failed",failure:{kind:"spawn_error",message:a}},Date.now())}p(o,"failed");async function T(e,t){const a=await(await c()).prepare(`SELECT o.type, o.name, c.receiver_json, c.payload_json, m.object_id, i.external_id AS app,
|
|
2
2
|
d.message_id, owner.type AS owner_type, parent.external_id AS parent_app
|
|
3
3
|
FROM deliveries d JOIN objects o ON o.id = d.destination_id
|
|
4
4
|
JOIN custom_objects c ON c.object = o.id JOIN messages m ON m.message_id = d.message_id
|
|
5
5
|
LEFT JOIN objects owner ON owner.id = o.owner
|
|
6
6
|
LEFT JOIN identities i ON i.object = o.owner AND i.scheme = 'app'
|
|
7
7
|
LEFT JOIN identities parent ON parent.object = owner.owner AND parent.scheme = 'app'
|
|
8
|
-
WHERE d.delivery_id = ?`).get(e.deliveryId);if(!a||!a.receiver_json){await o(e,t,`delivery ${e.deliveryId} has no supported receiver`);return}const i=JSON.parse(a.receiver_json);if(!await O(e,t)){await d(e.deliveryId,e.attempts,t,{state:"acknowledged"},Date.now());return}if(typeof i=="object"&&typeof i.url=="string"&&a.type!=="action"){const n=await u(await
|
|
8
|
+
WHERE d.delivery_id = ?`).get(e.deliveryId);if(!a||!a.receiver_json){await o(e,t,`delivery ${e.deliveryId} has no supported receiver`);return}const i=JSON.parse(a.receiver_json);if(!await O(e,t)){await d(e.deliveryId,e.attempts,t,{state:"acknowledged"},Date.now());return}if(typeof i=="object"&&typeof i.url=="string"&&a.type!=="action"){const n=await u(await c(),e.deliveryId);if(!n){await o(e,t,`delivery ${e.deliveryId} has no event document`);return}try{const r=await b(i.url,JSON.stringify(n),{"Content-Type":"application/json","X-Crtr-Delivery":e.deliveryId,"X-Crtr-Event":a.message_id},E);r>=200&&r<300?await d(e.deliveryId,e.attempts,t,{state:"acknowledged"},Date.now()):r>=300&&r<400?await o(e,t,`url receiver returned HTTP ${r}; redirects are not followed \u2014 register the final URL`):r>=400&&r<500&&r!==408&&r!==429?await o(e,t,`url receiver returned HTTP ${r}`):await d(e.deliveryId,e.attempts,t,{state:"pending",nextAttemptAt:Date.now()+f(e.attempts),failure:{kind:"spawn_error",message:`url receiver returned HTTP ${r}`}},Date.now())}catch(r){await d(e.deliveryId,e.attempts,t,{state:"pending",nextAttemptAt:Date.now()+f(e.attempts),failure:{kind:"spawn_error",message:String(r)}},Date.now())}return}if(typeof i!="object"||!Array.isArray(i.argv)||typeof i.cwd!="string"){await o(e,t,`delivery ${e.deliveryId} has an invalid argv receiver`);return}if(a.type==="action"){if(typeof i.name!="string"||!a.object_id){await o(e,t,`delivery ${e.deliveryId} has an invalid argv receiver`);return}const n=await N(e.deliveryId);if(n===null){await o(e,t,`delivery ${e.deliveryId} has no message body`);return}const{push:r,...y}=n,I={...y,action:{name:i.name,payload:a.payload_json===null?null:JSON.parse(a.payload_json)}};await w({argv:i.argv,cwd:i.cwd,document:I,attempt:e.attempts,nodeId:a.object_id,...a.app??a.parent_app?{app:a.app??a.parent_app}:{}},async _=>{await d(e.deliveryId,e.attempts,t,_,Date.now())});return}const s=await u(await c(),e.deliveryId);if(!s){await o(e,t,`delivery ${e.deliveryId} has no event document`);return}await w({argv:i.argv,cwd:i.cwd,document:s,attempt:e.attempts,app:a.app??a.parent_app??"app:terminal",custom:{deliveryId:e.deliveryId,messageId:a.message_id}},async n=>{await d(e.deliveryId,e.attempts,t,n,Date.now())})}p(T,"deliverExternal");class P{static{p(this,"DeliveryLaneReconciler")}async run(t,a){if(!a.lifecycle.acceptsDetachedWork())return;let i;try{i=await j(t)}catch(s){m.fresh(()=>l({level:"error",event:"delivery.scan_failed",error:s}));return}for(const s of i)try{const n=await h(s.deliveryId,t,v);if(n===null)continue;a.lifecycle.registerDetached(T(n,v).catch(r=>{m.fresh(()=>l({level:"error",event:"delivery.failed",error:r,fields:{delivery_id:n.deliveryId}}))}))}catch(n){m.fresh(()=>l({level:"error",event:"delivery.claim_failed",error:n,fields:{delivery_id:s.deliveryId}}))}}}export{P as DeliveryLaneReconciler,v as deliveryDaemonInstanceId};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
:root{color-scheme:light dark;--fg: #1f2328;--muted: #656d76;--bg: #fff;--panel: #f6f8fa;--border: #d0d7de;--accent: #0969da;--error: #b42318}@media(prefers-color-scheme:dark){:root{--fg: #e6edf3;--muted: #8d96a0;--bg: #0d1117;--panel: #161b22;--border: #30363d;--accent: #4493f8;--error: #ff8e85}}*{box-sizing:border-box}body{margin:0;background:var(--bg);color:var(--fg);font:16px/1.6 -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif}header{position:sticky;top:0;z-index:5;display:flex;align-items:center;gap:24px;padding:12px 24px;background:var(--panel);border-bottom:1px solid var(--border)}.identity{min-width:0;flex:1}.name{font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.meta{color:var(--muted);font-size:12px;overflow-wrap:anywhere}.toolbar,.actions{display:flex;gap:8px}button,input,textarea{font:inherit;color:inherit}button{background:var(--bg);border:1px solid var(--border);border-radius:6px;padding:5px 13px;font-size:13px;cursor:pointer;white-space:nowrap}button:hover:not(:disabled){border-color:var(--accent)}button.primary{background:var(--accent);color:#fff;border-color:var(--accent)}button:disabled{opacity:.45;cursor:default}:focus-visible{outline:2px solid var(--accent);outline-offset:3px}main{max-width:860px;margin:0 auto;padding:24px 24px 100px}.status{color:var(--muted);font-size:14px;margin-bottom:12px}.status:empty{display:none}.status.error{color:var(--error)}.rationale{display:block;width:100%;background:transparent;border:0;border-bottom:1px solid var(--border);padding:8px 0;margin:0 0 28px;font-size:13px}.rationale:disabled{display:none}.ProseMirror{outline:none;white-space:pre-wrap;overflow-wrap:break-word}.ProseMirror>:first-child{margin-top:0}.ProseMirror h1,.ProseMirror h2{border-bottom:1px solid var(--border);padding-bottom:.3em;line-height:1.3}.ProseMirror h1{font-size:2em}.ProseMirror h2{margin-top:1.6em}.ProseMirror p{margin:1em 0}.ProseMirror a{color:var(--accent);cursor:pointer}.ProseMirror code,textarea{font:85%/1.6 ui-monospace,SFMono-Regular,Menlo,monospace}.ProseMirror code{background:var(--panel);padding:.2em .4em;border-radius:4px}.ProseMirror pre{background:var(--panel);padding:14px 16px;border-radius:6px;overflow:auto;white-space:pre-wrap}.ProseMirror pre code{background:none;padding:0}.ProseMirror pre[data-language]:before{content:attr(data-language);display:block;color:var(--muted);font:11px/1.5 ui-monospace,monospace;margin-bottom:8px}.ProseMirror blockquote{margin:0;padding:0 1em;color:var(--muted);border-left:.25em solid var(--border)}.ProseMirror table{border-collapse:collapse;width:100%;table-layout:fixed}.ProseMirror th,.ProseMirror td{position:relative;border:1px solid var(--border);padding:6px 13px;min-width:60px}.ProseMirror th{background:var(--panel)}.ProseMirror td p,.ProseMirror th p{margin:.25em 0}.ProseMirror tr:nth-child(2n){background:var(--panel)}.ProseMirror .selectedCell:after{position:absolute;inset:0;content:"";background:var(--accent);opacity:.15;pointer-events:none}.ProseMirror img{max-width:100%}.ProseMirror li>p{margin:.35em 0}.ProseMirror .doc-ref{font-size:.92em;text-decoration:none;border-bottom:1px dotted var(--accent)}.source-block{border:1px dashed var(--border)}.source-block:before{content:"Read-only source";display:block;color:var(--muted);font:11px/1.5 -apple-system,sans-serif;margin-bottom:8px}.diagram{text-align:center;margin:24px 0 0;overflow:auto}.diagram svg{max-width:100%;height:auto}.ProseMirror-selectednode{outline:2px solid var(--accent)}.ProseMirror-gapcursor{display:none;pointer-events:none;position:absolute}.ProseMirror-gapcursor:after{content:"";display:block;position:absolute;top:-2px;width:20px;border-top:1px solid var(--fg);animation:blink 1.1s steps(2,start) infinite}.ProseMirror-focused .ProseMirror-gapcursor{display:block}@keyframes blink{to{visibility:hidden}}dialog{background:var(--bg);color:var(--fg);border:1px solid var(--border);border-radius:10px;padding:24px;width:min(1120px,95vw);max-height:90vh}dialog::backdrop{background:#0008}dialog h2{margin:0;font-size:21px}dialog p{color:var(--muted);font-size:14px}.versions{display:grid;grid-template-columns:1fr 1fr;gap:20px}.versions label{font-size:13px;font-weight:600}.versions textarea{display:block;width:100%;height:45vh;margin-top:8px;padding:12px;background:var(--panel);border:1px solid var(--border);border-radius:6px;resize:vertical;white-space:pre}.actions{justify-content:flex-end;margin-top:20px}@media(max-width:600px){header{padding:10px 16px;gap:12px}main{padding:20px 16px 60px}.toolbar{gap:4px}button{padding:5px 9px}.versions{grid-template-columns:1fr}.versions textarea{height:25vh}}
|
|
1
|
+
:root{color-scheme:light dark;--fg: #1f2328;--muted: #656d76;--bg: #fff;--panel: #f6f8fa;--border: #d0d7de;--accent: #0969da;--error: #b42318}@media(prefers-color-scheme:dark){:root{--fg: #e6edf3;--muted: #8d96a0;--bg: #0d1117;--panel: #161b22;--border: #30363d;--accent: #4493f8;--error: #ff8e85}}*{box-sizing:border-box}body{margin:0;background:var(--bg);color:var(--fg);font:16px/1.6 -apple-system,BlinkMacSystemFont,Segoe UI,Helvetica,Arial,sans-serif}header{position:sticky;top:0;z-index:5;display:flex;align-items:center;gap:24px;padding:12px 24px;background:var(--panel);border-bottom:1px solid var(--border)}.identity{min-width:0;flex:1}.name{font-weight:600;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.meta{color:var(--muted);font-size:12px;overflow-wrap:anywhere}.toolbar,.actions{display:flex;gap:8px}button,input,textarea{font:inherit;color:inherit}button{background:var(--bg);border:1px solid var(--border);border-radius:6px;padding:5px 13px;font-size:13px;cursor:pointer;white-space:nowrap}button:hover:not(:disabled){border-color:var(--accent)}button.primary{background:var(--accent);color:#fff;border-color:var(--accent)}button:disabled{opacity:.45;cursor:default}:focus-visible{outline:2px solid var(--accent);outline-offset:3px}main{max-width:860px;margin:0 auto;padding:24px 24px 100px}.status{color:var(--muted);font-size:14px;margin-bottom:12px}.status:empty{display:none}.status.error{color:var(--error)}.rationale{display:block;width:100%;background:transparent;border:0;border-bottom:1px solid var(--border);padding:8px 0;margin:0 0 28px;font-size:13px}.rationale:disabled{display:none}.ProseMirror{outline:none;white-space:pre-wrap;overflow-wrap:break-word}.ProseMirror>:first-child{margin-top:0}.ProseMirror h1,.ProseMirror h2{border-bottom:1px solid var(--border);padding-bottom:.3em;line-height:1.3}.ProseMirror h1{font-size:2em}.ProseMirror h2{margin-top:1.6em}.ProseMirror p{margin:1em 0}.ProseMirror a{color:var(--accent);cursor:pointer}.ProseMirror code,textarea{font:85%/1.6 ui-monospace,SFMono-Regular,Menlo,monospace}.ProseMirror code{background:var(--panel);padding:.2em .4em;border-radius:4px}.ProseMirror pre{background:var(--panel);padding:14px 16px;border-radius:6px;overflow:auto;white-space:pre-wrap}.ProseMirror pre code{background:none;padding:0}.ProseMirror pre[data-language]:before{content:attr(data-language);display:block;color:var(--muted);font:11px/1.5 ui-monospace,monospace;margin-bottom:8px}.ProseMirror blockquote{margin:0;padding:0 1em;color:var(--muted);border-left:.25em solid var(--border)}.ProseMirror table{border-collapse:collapse;width:100%;table-layout:fixed}.ProseMirror th,.ProseMirror td{position:relative;border:1px solid var(--border);padding:6px 13px;min-width:60px}.ProseMirror th{background:var(--panel)}.ProseMirror td p,.ProseMirror th p{margin:.25em 0}.ProseMirror tr:nth-child(2n){background:var(--panel)}.ProseMirror .selectedCell:after{position:absolute;inset:0;content:"";background:var(--accent);opacity:.15;pointer-events:none}.ProseMirror img{max-width:100%}.ProseMirror li>p{margin:.35em 0}.ProseMirror .doc-ref{font-size:.92em;text-decoration:none;border-bottom:1px dotted var(--accent)}.source-block{border:1px dashed var(--border)}.source-block:before{content:"Read-only source";display:block;color:var(--muted);font:11px/1.5 -apple-system,sans-serif;margin-bottom:8px}.diagram{text-align:center;margin:24px 0 0;overflow:auto}.diagram svg{max-width:100%;height:auto}.source-toggle{display:block;margin:4px auto 12px;padding:0;background:none;border:0;color:var(--muted);font:11px/1.5 ui-monospace,monospace}.source-toggle:hover{color:var(--accent);text-decoration:underline}.source-toggle[hidden],.mermaid-block.source-collapsed pre{display:none}.ProseMirror-selectednode{outline:2px solid var(--accent)}.ProseMirror-gapcursor{display:none;pointer-events:none;position:absolute}.ProseMirror-gapcursor:after{content:"";display:block;position:absolute;top:-2px;width:20px;border-top:1px solid var(--fg);animation:blink 1.1s steps(2,start) infinite}.ProseMirror-focused .ProseMirror-gapcursor{display:block}@keyframes blink{to{visibility:hidden}}dialog{background:var(--bg);color:var(--fg);border:1px solid var(--border);border-radius:10px;padding:24px;width:min(1120px,95vw);max-height:90vh}dialog::backdrop{background:#0008}dialog h2{margin:0;font-size:21px}dialog p{color:var(--muted);font-size:14px}.versions{display:grid;grid-template-columns:1fr 1fr;gap:20px}.versions label{font-size:13px;font-weight:600}.versions textarea{display:block;width:100%;height:45vh;margin-top:8px;padding:12px;background:var(--panel);border:1px solid var(--border);border-radius:6px;resize:vertical;white-space:pre}.actions{justify-content:flex-end;margin-top:20px}@media(max-width:600px){header{padding:10px 16px;gap:12px}main{padding:20px 16px 60px}.toolbar{gap:4px}button{padding:5px 9px}.versions{grid-template-columns:1fr}.versions textarea{height:25vh}}
|