@north-light/cli 0.3.458 → 0.3.460
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/profiles.d.ts +3 -1
- package/dist/builtin-memory/crouter-sdk/guides/apps-on-northlight.md +1 -1
- package/dist/builtin-memory/crouter-sdk/release-notes.md +12 -0
- package/dist/clients/attach/session/profile-files.js +1 -1
- package/dist/clients/attach/viewer.js +178 -178
- package/dist/commands/profile/new.js +1 -1
- package/dist/commands/profile/show.js +1 -1
- package/dist/commands/sys/join.js +1 -1
- package/dist/commands/sys/panels/models-panel.js +1 -1
- package/dist/core/command-plugins/compose.js +1 -1
- package/dist/core/config.js +1 -1
- package/dist/core/directory/join.d.ts +4 -2
- package/dist/core/directory/join.js +1 -1
- package/dist/core/io.d.ts +12 -2
- package/dist/core/io.js +7 -7
- package/dist/core/layout-migrate/stored-paths.js +3 -3
- package/dist/core/layout-migrate/stores.js +1 -1
- package/dist/core/layout.d.ts +2 -2
- package/dist/core/layout.js +2 -2
- package/dist/core/profiles/manifest.d.ts +1 -1
- package/dist/core/profiles/manifest.js +1 -1
- package/dist/core/profiles/relocate.d.ts +8 -0
- package/dist/core/profiles/relocate.js +1 -0
- package/dist/core/providers/device.js +1 -1
- package/dist/core/render.d.ts +1 -1
- package/dist/core/render.js +6 -6
- package/dist/core/scoped-state/migrate.js +1 -1
- package/dist/core/scoped-state/profiles.js +1 -1
- package/dist/core/scoped-state/settings.js +1 -1
- package/dist/core/spaces/space.js +2 -2
- package/dist/core/storage/download.js +1 -1
- package/dist/daemon/api/map.js +2 -2
- package/dist/daemon/api/router.js +1 -1
- package/dist/daemon/crtrd.js +8 -7
- package/dist/migrations/004-canvas-documents/index.js +2 -2
- package/dist/migrations/004-canvas-documents/legacy/types.d.ts +1 -1
- package/docs/sdk/guides/apps-on-northlight.md +1 -1
- package/docs/sdk/release-notes.md +12 -0
- package/package.json +2 -2
- package/packages/crouter-identity/package.json +1 -1
- package/runtime.lock.json +12 -12
|
@@ -1 +1 @@
|
|
|
1
|
-
var W=Object.defineProperty;var a=(e,t)=>W(e,"name",{value:t,configurable:!0});import{toErrorBody as j}from"./map.js";import{emitEvent as N}from"../../core/events/emit.js";import{scopeAllowed as h,ScopeDeniedError as p}from"../../core/scopes.js";import{coveredByAny as J}from"../../shared/env.js";import{ApiError as d}from"../../api/errors.js";import{activeGrant as B,grantFor as x}from"../../core/grants/mirror.js";import{getNode as _}from"../../core/canvas/canvas.js";import{ownedRun as z,RunError as g}from"../../core/runs/operations.js";import{nodeMayReach as H,placeMayReach as S}from"../../core/runs/confinement.js";import{checkCronFire as M}from"../cron/authority.js";import{readConfig as P}from"../../core/config.js";import{SCOPE_VOCABULARY as I}from"../../core/scopes.js";import{operationFor as L}from"./operations.js";import{CONTROL_BODY_MAX_BYTES as F}from"../../core/llm/body-limits.js";import{getRequest as Y,getRequestByInboxTicket as V}from"../../core/human/requests.js";import{requireVisibleReview as R}from"../../core/review/store.js";import{getComment as O}from"../../core/review/comments.js";function D(e,t,o,s,r){const n=e.path,u=r&&typeof r=="object"&&!Array.isArray(r)?r:{};if(n==="/v1/human/requests"||n==="/v1/human/reviews"){if((n.endsWith("/reviews")?u.origin_node_id:u.requester_node_id)!==t.node)throw new d(403,"other_app_run","a broker may create a human request only for its own node");const f=u.source;if(f&&typeof f=="object"&&"nodeId"in f&&f.nodeId!==t.node)throw new d(403,"other_app_run","request source must name the calling node")}if(n==="/v1/human/reviews/self/comments"&&e.method==="GET"&&s.get("actor_node_id")!==t.node)throw new d(403,"other_app_run","self review requires the calling node");if(n.includes("/comments")&&e.method!=="GET"&&u.actor_node_id!==t.node)throw new d(403,"other_app_run","comment author must be the calling node");if(o.comment_id&&!O(o.comment_id))throw new d(404,"not_found","comment not found")}a(D,"authorizeHumanBody");function y(e){return e.class==="broker"||e.class==="cron"}a(y,"boundedByStoredScopes");function b(e){return e.class==="person"||e.class==="anonymous"||e.class==="machine"?null:e.class==="forwarded"?e.actor.kind==="app"?e.actor.app:null:e.app}a(b,"appOf");function q(e){return e.class==="person"||e.class==="forwarded"&&e.actor.kind==="person"}a(q,"actsAsPerson");function $(e){const t=x(e.actor.app,e.sub);if(!t)throw new d(403,"app_not_granted",`${e.actor.app} holds no active grant for ${e.sub} on this machine`);return t}a($,"forwardedGrant");function v(e){if(e.class==="person"||e.class==="anonymous"||e.class==="machine")return[];if(e.class==="forwarded"){if(e.actor.kind==="person")return[];const{resolved:o}=$(e),s=e.actor.node_scopes;return s===null?o:s.filter(r=>J(o,r))}if(e.class==="app")return e.scopes;if(e.class==="cron"){const o=M({grantee:e.app,sub:e.sub,grant_id:e.grant,scopes:e.scopes});if(o.allowed)return o.effectiveScopes;throw o.reason==="grant_missing"||o.reason==="grant_revoked"?new d(401,"grant_revoked",o.message):new d(403,"scope_missing",o.message)}const t=e.grant?B(e.grant):x(e.app,e.sub);if(t&&t.grantee===e.app&&t.sub===e.sub)return t.resolved;if(e.app==="app:terminal"&&!P("user").runtime?.issuer)return I;throw new d(401,"grant_revoked","the node grant is not active")}a(v,"resolvedScopes");function k(e){return"class"in e?b(e):e.grantee}a(k,"runCallerApp");function l(e,t,o){return t===void 0||!("class"in e)?!0:e.class==="cron"?S({run:e.origin_run??"",isolated:e.isolated},e.app,t,o):e.class==="forwarded"?e.actor.kind!=="app"||S(e.actor.place,e.actor.app,t,o):e.class!=="broker"?!0:H(e.node,e.app,t,o)}a(l,"brokerMayReach");function X(e,t,o){const s=k(e);if(s===t)return l(e,o,t);if(s===null)return!0;const r="class"in e?null:B(e.grant),n="class"in e?v(e):r?.sub===e.sub&&r.grantee===e.grantee?r.resolved:[];return h(n,`crtr:conversations:read:${t}`)&&(!("class"in e)||!y(e)||h(e.scopes,`crtr:conversations:read:${t}`))}a(X,"canReadRun");function Be(e,t,o=!1,s=!1){const r=_(t);if(!r||r.parent!==null||r.run_id!==t||!r.grantee||r.deleting_at&&!s)throw new g(404,"not_found","run not found");if(!X(e,r.grantee,t))throw new g(404,"not_found","run not found");if(o&&k(e)!==null&&k(e)!==r.grantee)throw new g(403,"other_app_run","cannot change another app's run");return z(t,r.grantee,s)}a(Be,"requireRun");function C(e,t,o){return q(e)?!0:e.class==="anonymous"||e.class==="machine"?!1:b(e)===t?l(e,o,t):h(v(e),`crtr:objects:read:${t}`)&&(!y(e)||h(e.scopes,`crtr:objects:read:${t}`))}a(C,"canReadNode");const K=new Set(["messages.post.58","messages.post.59"]);function Q(e,t,o){if(!e.classes.includes(t.class)&&!(t.class!=="anonymous"&&t.class!=="machine"&&t.class!=="forwarded"&&e.classes.includes("anonymous")))throw new d(403,"permission_error","this operation is not available to the caller");if(t.class==="forwarded"&&t.actor.kind==="app"&&$(t),t.class==="person"||t.class==="anonymous"||t.class==="machine"||q(t))return;const s=v(t);if(e.scope&&(!h(s,e.scope)||y(t)&&!h(t.scopes,e.scope)))throw new d(403,"scope_missing",`missing scope ${e.scope}`);if(t.class==="app")return;const r=b(t);t.class==="broker"&&Z(e,t,o,s);const n=o.id;if((e.resource==="node-read"||e.resource==="node-write")&&n!==void 0){const u=_(n);if(!u)return;if(e.resource==="node-write"&&u.grantee!==r&&!(K.has(e.name)&&h(s,`crtr:objects:message:${u.grantee??"app:terminal"}`)))throw new d(403,"other_app_run","cannot change another app's node");if(e.resource==="node-write"&&!l(t,n,u.grantee??"app:terminal"))throw new d(404,"not_found","node not found");if(e.resource==="node-read"&&!C(t,u.grantee??"app:terminal",n))throw new d(404,"not_found","node not found")}}a(Q,"authorizeOperation");function Z(e,t,o,s){if(e.resource==="daemon-bash"&&(!h(s,"crtr:files:rw:user:.")||!h(t.scopes,"crtr:files:rw:user:.")))throw new d(403,"scope_missing","missing scope crtr:files:rw:user:.");if(e.resource==="human"){const n=e.path,u=e.method==="GET";if(!u&&(n.endsWith("/respond")||n.endsWith("/submit")||n.endsWith("/dismiss")||n.endsWith("/progress")||n.endsWith("/comment-ranges")||n.includes("/feedback-comments")))throw new d(403,"permission_error","only the person may answer or edit the human inbox");const c=o.request_id?Y(o.request_id):o.ticket_id?V(o.ticket_id):null,f=o.comment_id?O(o.comment_id):null,w=o.review_id?R(o.review_id):f?R(f.review_id):null,i=c?.requester_node_id??w?.origin_node_id;if(i!=null){const m=_(i);if(m&&(u?!C(t,m.grantee??"app:terminal",i):m.grantee!==t.app))throw new d(u?404:403,u?"not_found":"other_app_run","human request belongs to another app");if(m&&!u&&!l(t,i,m.grantee??"app:terminal"))throw new d(404,"not_found","human request not found")}else if(c||w)throw new d(403,"permission_error","only the person may access a request without a node")}const r=o.id;if(e.resource==="node-own"&&r!==void 0&&r!==t.node)throw new d(403,"other_app_run","the operation requires the calling node")}a(Z,"authorizeBrokerOnly");function ee(e,t){if(!h(e,t))throw new p("the bearer token",t)}a(ee,"assertCeiling");function te(){return new d(403,"owner_only","this operation is owner-only; a scoped token does not reach it")}a(te,"ownerOnlyError");function xe(e){return e.map(t=>({...t,ownerOnly:!0}))}a(xe,"ownerOnly");class Se{static{a(this,"Router")}routes=[];register(t){const o=L(t.method,t.pattern);if(!o)throw new Error(`route has no operation row: ${t.method} ${t.pattern}`);if(this.routes.some(s=>s.method===t.method.toUpperCase()&&s.operation.path===t.pattern))throw new Error(`duplicate route: ${t.method} ${t.pattern}`);return this.routes.push({operation:o,method:t.method.toUpperCase(),segments:A(t.pattern),handler:t.handler,maxBodyBytes:t.maxBodyBytes??F}),this}registerAll(t){for(const o of t)this.register(o);return this}match(t,o){const s=t.toUpperCase(),r=A(o);for(const n of this.routes){if(n.method!==s)continue;const u=oe(n.segments,r);if(u!==null)return{handler:n.handler,params:u,operation:n.operation,maxBodyBytes:n.maxBodyBytes}}return null}async handle(t,o,s,r={class:"person"}){try{const n=new URL(t.url??"/","http://127.0.0.1"),u=(t.method??"GET").toUpperCase(),c=this.match(u,n.pathname);if(c===null){U(o,404,"not_found",`no route for ${u} ${n.pathname}`);return}if(Q(c.operation,r,c.params),s!==null){if(c.operation.classes.length===1&&c.operation.classes[0]==="person")throw te();c.operation.scope&&ee(s,c.operation.scope)}let f;try{f=await re(t,c.maxBodyBytes)}catch(m){const E=m instanceof T?"payload_too_large":"invalid_request";U(o,E==="payload_too_large"?413:400,E,m.message);return}r.class==="broker"&&c.operation.resource==="human"&&D(c.operation,r,c.params,n.searchParams,f);const w={method:u,path:n.pathname,params:c.params,query:n.searchParams,body:f,ceiling:s,principal:r,...r.class==="anonymous"&&typeof t.headers.authorization=="string"?{publishToken:t.headers.authorization.slice(7)}:{},req:t,res:o},i=await c.handler(w);o.writableEnded||ne(o,i)}catch(n){const{status:u,body:c}=j(n);u>=500&&N({event:"api.request.failed",level:"error",error:n instanceof Error?n:new Error(String(n)),...r.class==="broker"?{node_id:r.node}:{},fields:{method:(t.method??"GET").toUpperCase(),path:t.url??""}}),G(o,u,c)}}}function A(e){return e.split("/").filter(t=>t.length>0)}a(A,"splitPath");function oe(e,t){if(e.length!==t.length)return null;const o={};for(let s=0;s<e.length;s++){const r=e[s],n=t[s];if(r.startsWith(":"))o[r.slice(1)]=decodeURIComponent(n);else if(r!==n)return null}return o}a(oe,"matchSegments");class T extends Error{static{a(this,"BodyTooLargeError")}}async function re(e,t){const o=[];let s=0;for await(const n of e){const u=n;if(s+=u.length,s>t)throw new T(`request body exceeds ${t} bytes`);o.push(u)}if(s===0)return;const r=Buffer.concat(o).toString("utf8").trim();if(r!=="")try{return JSON.parse(r)}catch{throw new Error("request body is not valid JSON")}}a(re,"readJsonBody");function ne(e,t){if(e.headersSent)return;const o={...t.headers??{}};if(t.rawBody!==void 0){e.writeHead(t.status,o),e.end(t.rawBody);return}if(t.status===204||t.body===void 0){e.writeHead(t.status,o),e.end();return}o["content-type"]===void 0&&(o["content-type"]="application/json; charset=utf-8"),e.writeHead(t.status,o),e.end(JSON.stringify(t.body))}a(ne,"writeResult");function G(e,t,o){if(e.headersSent){e.end();return}e.writeHead(t,{"content-type":"application/json; charset=utf-8"}),e.end(JSON.stringify(o))}a(G,"writeJson");function U(e,t,o,s){G(e,t,{error:{code:o,message:s}})}a(U,"writeError");export{Se as Router,q as actsAsPerson,b as appOf,ee as assertCeiling,l as brokerMayReach,C as canReadNode,X as canReadRun,xe as ownerOnly,te as ownerOnlyError,Be as requireRun,v as resolvedScopes,k as runCallerApp};
|
|
1
|
+
var W=Object.defineProperty;var a=(e,t)=>W(e,"name",{value:t,configurable:!0});import{toErrorBody as j}from"./map.js";import{emitEvent as p}from"../../core/events/emit.js";import{scopeAllowed as f,ScopeDeniedError as N}from"../../core/scopes.js";import{coveredByAny as J}from"../../shared/env.js";import{ApiError as c}from"../../api/errors.js";import{activeGrant as B,grantFor as x}from"../../core/grants/mirror.js";import{getNode as _}from"../../core/canvas/canvas.js";import{ownedRun as z,RunError as g}from"../../core/runs/operations.js";import{nodeMayReach as H,placeMayReach as S}from"../../core/runs/confinement.js";import{checkCronFire as M}from"../cron/authority.js";import{readConfig as P}from"../../core/config.js";import{SCOPE_VOCABULARY as I}from"../../core/scopes.js";import{operationFor as L}from"./operations.js";import{CONTROL_BODY_MAX_BYTES as F}from"../../core/llm/body-limits.js";import{getRequest as Y,getRequestByInboxTicket as V}from"../../core/human/requests.js";import{requireVisibleReview as R}from"../../core/review/store.js";import{getComment as O}from"../../core/review/comments.js";function D(e,t,o,s,n){const r=e.path,u=n&&typeof n=="object"&&!Array.isArray(n)?n:{};if(r==="/v1/human/requests"||r==="/v1/human/reviews"){const d=r.endsWith("/reviews")?u.origin_node_id:u.requester_node_id,m=r==="/v1/human/requests"&&d==null;if(d!==t.node&&!m)throw new c(403,"other_app_run","a broker may create a human request only for its own node");const h=u.source;if(h&&typeof h=="object"&&"nodeId"in h&&h.nodeId!==t.node)throw new c(403,"other_app_run","request source must name the calling node")}if(r==="/v1/human/reviews/self/comments"&&e.method==="GET"&&s.get("actor_node_id")!==t.node)throw new c(403,"other_app_run","self review requires the calling node");if(r.includes("/comments")&&e.method!=="GET"&&u.actor_node_id!==t.node)throw new c(403,"other_app_run","comment author must be the calling node");if(o.comment_id&&!O(o.comment_id))throw new c(404,"not_found","comment not found")}a(D,"authorizeHumanBody");function y(e){return e.class==="broker"||e.class==="cron"}a(y,"boundedByStoredScopes");function b(e){return e.class==="person"||e.class==="anonymous"||e.class==="machine"?null:e.class==="forwarded"?e.actor.kind==="app"?e.actor.app:null:e.app}a(b,"appOf");function q(e){return e.class==="person"||e.class==="forwarded"&&e.actor.kind==="person"}a(q,"actsAsPerson");function $(e){const t=x(e.actor.app,e.sub);if(!t)throw new c(403,"app_not_granted",`${e.actor.app} holds no active grant for ${e.sub} on this machine`);return t}a($,"forwardedGrant");function v(e){if(e.class==="person"||e.class==="anonymous"||e.class==="machine")return[];if(e.class==="forwarded"){if(e.actor.kind==="person")return[];const{resolved:o}=$(e),s=e.actor.node_scopes;return s===null?o:s.filter(n=>J(o,n))}if(e.class==="app")return e.scopes;if(e.class==="cron"){const o=M({grantee:e.app,sub:e.sub,grant_id:e.grant,scopes:e.scopes});if(o.allowed)return o.effectiveScopes;throw o.reason==="grant_missing"||o.reason==="grant_revoked"?new c(401,"grant_revoked",o.message):new c(403,"scope_missing",o.message)}const t=e.grant?B(e.grant):x(e.app,e.sub);if(t&&t.grantee===e.app&&t.sub===e.sub)return t.resolved;if(e.app==="app:terminal"&&!P("user").runtime?.issuer)return I;throw new c(401,"grant_revoked","the node grant is not active")}a(v,"resolvedScopes");function k(e){return"class"in e?b(e):e.grantee}a(k,"runCallerApp");function l(e,t,o){return t===void 0||!("class"in e)?!0:e.class==="cron"?S({run:e.origin_run??"",isolated:e.isolated},e.app,t,o):e.class==="forwarded"?e.actor.kind!=="app"||S(e.actor.place,e.actor.app,t,o):e.class!=="broker"?!0:H(e.node,e.app,t,o)}a(l,"brokerMayReach");function X(e,t,o){const s=k(e);if(s===t)return l(e,o,t);if(s===null)return!0;const n="class"in e?null:B(e.grant),r="class"in e?v(e):n?.sub===e.sub&&n.grantee===e.grantee?n.resolved:[];return f(r,`crtr:conversations:read:${t}`)&&(!("class"in e)||!y(e)||f(e.scopes,`crtr:conversations:read:${t}`))}a(X,"canReadRun");function Be(e,t,o=!1,s=!1){const n=_(t);if(!n||n.parent!==null||n.run_id!==t||!n.grantee||n.deleting_at&&!s)throw new g(404,"not_found","run not found");if(!X(e,n.grantee,t))throw new g(404,"not_found","run not found");if(o&&k(e)!==null&&k(e)!==n.grantee)throw new g(403,"other_app_run","cannot change another app's run");return z(t,n.grantee,s)}a(Be,"requireRun");function C(e,t,o){return q(e)?!0:e.class==="anonymous"||e.class==="machine"?!1:b(e)===t?l(e,o,t):f(v(e),`crtr:objects:read:${t}`)&&(!y(e)||f(e.scopes,`crtr:objects:read:${t}`))}a(C,"canReadNode");const K=new Set(["messages.post.58","messages.post.59"]);function Q(e,t,o){if(!e.classes.includes(t.class)&&!(t.class!=="anonymous"&&t.class!=="machine"&&t.class!=="forwarded"&&e.classes.includes("anonymous")))throw new c(403,"permission_error","this operation is not available to the caller");if(t.class==="forwarded"&&t.actor.kind==="app"&&$(t),t.class==="person"||t.class==="anonymous"||t.class==="machine"||q(t))return;const s=v(t);if(e.scope&&(!f(s,e.scope)||y(t)&&!f(t.scopes,e.scope)))throw new c(403,"scope_missing",`missing scope ${e.scope}`);if(t.class==="app")return;const n=b(t);t.class==="broker"&&Z(e,t,o,s);const r=o.id;if((e.resource==="node-read"||e.resource==="node-write")&&r!==void 0){const u=_(r);if(!u)return;if(e.resource==="node-write"&&u.grantee!==n&&!(K.has(e.name)&&f(s,`crtr:objects:message:${u.grantee??"app:terminal"}`)))throw new c(403,"other_app_run","cannot change another app's node");if(e.resource==="node-write"&&!l(t,r,u.grantee??"app:terminal"))throw new c(404,"not_found","node not found");if(e.resource==="node-read"&&!C(t,u.grantee??"app:terminal",r))throw new c(404,"not_found","node not found")}}a(Q,"authorizeOperation");function Z(e,t,o,s){if(e.resource==="daemon-bash"&&(!f(s,"crtr:files:rw:user:.")||!f(t.scopes,"crtr:files:rw:user:.")))throw new c(403,"scope_missing","missing scope crtr:files:rw:user:.");if(e.resource==="human"){const r=e.path,u=e.method==="GET";if(!u&&(r.endsWith("/respond")||r.endsWith("/submit")||r.endsWith("/dismiss")||r.endsWith("/progress")||r.endsWith("/comment-ranges")||r.includes("/feedback-comments")))throw new c(403,"permission_error","only the person may answer or edit the human inbox");const d=o.request_id?Y(o.request_id):o.ticket_id?V(o.ticket_id):null,m=o.comment_id?O(o.comment_id):null,h=o.review_id?R(o.review_id):m?R(m.review_id):null,w=d?.requester_node_id??h?.origin_node_id;if(w!=null){const i=_(w);if(i&&(u?!C(t,i.grantee??"app:terminal",w):i.grantee!==t.app))throw new c(u?404:403,u?"not_found":"other_app_run","human request belongs to another app");if(i&&!u&&!l(t,w,i.grantee??"app:terminal"))throw new c(404,"not_found","human request not found")}else if(d||h)throw new c(403,"permission_error","only the person may access a request without a node")}const n=o.id;if(e.resource==="node-own"&&n!==void 0&&n!==t.node)throw new c(403,"other_app_run","the operation requires the calling node")}a(Z,"authorizeBrokerOnly");function ee(e,t){if(!f(e,t))throw new N("the bearer token",t)}a(ee,"assertCeiling");function te(){return new c(403,"owner_only","this operation is owner-only; a scoped token does not reach it")}a(te,"ownerOnlyError");function xe(e){return e.map(t=>({...t,ownerOnly:!0}))}a(xe,"ownerOnly");class Se{static{a(this,"Router")}routes=[];register(t){const o=L(t.method,t.pattern);if(!o)throw new Error(`route has no operation row: ${t.method} ${t.pattern}`);if(this.routes.some(s=>s.method===t.method.toUpperCase()&&s.operation.path===t.pattern))throw new Error(`duplicate route: ${t.method} ${t.pattern}`);return this.routes.push({operation:o,method:t.method.toUpperCase(),segments:A(t.pattern),handler:t.handler,maxBodyBytes:t.maxBodyBytes??F}),this}registerAll(t){for(const o of t)this.register(o);return this}match(t,o){const s=t.toUpperCase(),n=A(o);for(const r of this.routes){if(r.method!==s)continue;const u=oe(r.segments,n);if(u!==null)return{handler:r.handler,params:u,operation:r.operation,maxBodyBytes:r.maxBodyBytes}}return null}async handle(t,o,s,n={class:"person"}){try{const r=new URL(t.url??"/","http://127.0.0.1"),u=(t.method??"GET").toUpperCase(),d=this.match(u,r.pathname);if(d===null){U(o,404,"not_found",`no route for ${u} ${r.pathname}`);return}if(Q(d.operation,n,d.params),s!==null){if(d.operation.classes.length===1&&d.operation.classes[0]==="person")throw te();d.operation.scope&&ee(s,d.operation.scope)}let m;try{m=await ne(t,d.maxBodyBytes)}catch(i){const E=i instanceof T?"payload_too_large":"invalid_request";U(o,E==="payload_too_large"?413:400,E,i.message);return}n.class==="broker"&&d.operation.resource==="human"&&D(d.operation,n,d.params,r.searchParams,m);const h={method:u,path:r.pathname,params:d.params,query:r.searchParams,body:m,ceiling:s,principal:n,...n.class==="anonymous"&&typeof t.headers.authorization=="string"?{publishToken:t.headers.authorization.slice(7)}:{},req:t,res:o},w=await d.handler(h);o.writableEnded||re(o,w)}catch(r){const{status:u,body:d}=j(r);u>=500&&p({event:"api.request.failed",level:"error",error:r instanceof Error?r:new Error(String(r)),...n.class==="broker"?{node_id:n.node}:{},fields:{method:(t.method??"GET").toUpperCase(),path:t.url??""}}),G(o,u,d)}}}function A(e){return e.split("/").filter(t=>t.length>0)}a(A,"splitPath");function oe(e,t){if(e.length!==t.length)return null;const o={};for(let s=0;s<e.length;s++){const n=e[s],r=t[s];if(n.startsWith(":"))o[n.slice(1)]=decodeURIComponent(r);else if(n!==r)return null}return o}a(oe,"matchSegments");class T extends Error{static{a(this,"BodyTooLargeError")}}async function ne(e,t){const o=[];let s=0;for await(const r of e){const u=r;if(s+=u.length,s>t)throw new T(`request body exceeds ${t} bytes`);o.push(u)}if(s===0)return;const n=Buffer.concat(o).toString("utf8").trim();if(n!=="")try{return JSON.parse(n)}catch{throw new Error("request body is not valid JSON")}}a(ne,"readJsonBody");function re(e,t){if(e.headersSent)return;const o={...t.headers??{}};if(t.rawBody!==void 0){e.writeHead(t.status,o),e.end(t.rawBody);return}if(t.status===204||t.body===void 0){e.writeHead(t.status,o),e.end();return}o["content-type"]===void 0&&(o["content-type"]="application/json; charset=utf-8"),e.writeHead(t.status,o),e.end(JSON.stringify(t.body))}a(re,"writeResult");function G(e,t,o){if(e.headersSent){e.end();return}e.writeHead(t,{"content-type":"application/json; charset=utf-8"}),e.end(JSON.stringify(o))}a(G,"writeJson");function U(e,t,o,s){G(e,t,{error:{code:o,message:s}})}a(U,"writeError");export{Se as Router,q as actsAsPerson,b as appOf,ee as assertCeiling,l as brokerMayReach,C as canReadNode,X as canReadRun,xe as ownerOnly,te as ownerOnlyError,Be as requireRun,v as resolvedScopes,k as runCallerApp};
|
package/dist/daemon/crtrd.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
|
-
var _e=Object.defineProperty;var s=(t,n)=>_e(t,"name",{value:n,configurable:!0});import{startPeerOutbox as ke}from"./peer/outbox.js";import{reportMachineStatus as Ee}from"../core/peer/directory.js";import{createPeerRelay as Re}from"./peer/relay-service.js";import{writeFileSync as xe,readFileSync as Pe,rmSync as Ie,mkdirSync as Z,existsSync as k,chmodSync as Te}from"node:fs";import{createServer as ee}from"node:http";import{dirname as De}from"node:path";import{envCrtrdTcp as Ce}from"../shared/env.js";import{serveCanvasConversationStore as Le}from"../core/canvas/sessions.js";import{pollRunObservers as $e}from"./runs/observer.js";import{randomBytes as Ae}from"node:crypto";import{apiSocketPath as Ne,crtrHome as Me}from"../core/canvas/paths.js";import{activeAppUsers as Oe}from"../core/spaces/users.js";import{ensureAppSpace as Ge,ensureUserFiles as Fe}from"../core/spaces/space.js";import{LAUNCHER_SOCKET as x}from"../launcher/spec.js";import{launcherRequest as I}from"../launcher/client.js";import{installLauncherEventSink as He}from"./launcher-events.js";import{initializeEmptyLayout as Be,layoutNeedsMigration as je,socketDir as re}from"../core/layout.js";import{migrateLooseKeys as qe}from"../core/layout-migrate/loose-keys.js";import{getNode as ze,listNodesForSupervision as We,setFrozen as Ue}from"../core/canvas/index.js";import{createApiServer as Ke}from"./api/server.js";import{createAppListener as Je}from"./api/app-listener.js";import{installLocalTerminalGrant as Ve}from"../core/grants/local.js";import{onRunEventAppended as Qe}from"../core/runs/events.js";import{runNotices as Ye}from"./run-notices.js";import{createGrantSync as Xe,GRANT_SYNC_INTERVAL_S as Ze}from"../core/grants/sync.js";import{runRemovalCascades as er}from"../core/grants/remove.js";import{sweepSandboxes as rr}from"../core/grants/on-sync.js";import{rebuildCronExecutions as tr}from"./cron/run-socket.js";import{hasSyncedGrants as nr}from"../core/grants/mirror.js";import{readConfig as or}from"../core/config.js";import{reconcileUndeliveredTickets as ir}from"./human/sweep.js";import{resetHandedOffDeliveries as sr}from"../core/canvas/deliveries.js";import{resetHandedOffDaemonActions as ar}from"../core/canvas/daemon-actions.js";import{sweepReviews as cr}from"./review/sweep.js";import{pidfilePath as F}from"./pidfile.js";import{rendererWarning as dr}from"../core/runtime/package-health.js";import{DEFAULT_INTERVAL_MS as lr}from"./supervise-cadence.js";import{createResumeDetector as pr}from"./resume-detector.js";import{BrokerSupervisionReconciler as mr}from"./reconcilers/broker-supervision.js";import{ControllerDeathReconciler as fr}from"./reconcilers/controller-death.js";import{NodeLifecycleReconciler as ur}from"./reconcilers/node-lifecycle/tick.js";import{NodeDeadlineReconciler as hr}from"./reconcilers/node-deadline.js";import{CronLaneReconciler as vr}from"./reconcilers/cron-lane.js";import{DeliveryLaneReconciler as wr}from"./reconcilers/delivery-lane.js";import{ActionLaneReconciler as gr}from"./reconcilers/action-lane.js";import{endLiveExecution as yr,migrateLegacyExecutionIdentities as Sr}from"../core/canvas/executions.js";import{revokePriorEpochNodeTokens as br}from"../core/canvas/node-tokens.js";import{PendingReviewSubmitReconciler as _r}from"./reconcilers/pending-review-submit.js";import{StorageMaintenanceReconciler as kr}from"./reconcilers/storage-maintenance.js";import{StorageDueWorkReconciler as Er}from"./reconcilers/storage-due-work.js";import{BashDeadlineReconciler as Rr}from"./reconcilers/bash-deadline.js";import{FaultRetryBackstopReconciler as xr}from"./reconcilers/fault-retry-backstop.js";import{StructuredRequestReconciler as Pr}from"./reconcilers/structured-request-lane.js";import{reconcileStructuredRequestSidecars as Ir}from"./structured-requests/boot.js";import{captureLivenessSnapshot as te,capturePidCommand as Tr,captureTeardownSnapshot as ne,isPidAlive as Dr,isAnyPidAlive as oe,killProcessTreePids as ie}from"../core/canvas/pid.js";import{bindFleet as Cr,boundFleet as Lr}from"../core/runtime/fleet.js";import{bindDaemonControl as $r,clearDaemonControl as Ar}from"./control.js";import{execDaemon as Nr,spawnDaemon as Mr}from"./manage.js";import{reconcileAndMigrateBoot as Or}from"../core/canvas/boot.js";import{resolveInstallId as Gr}from"../core/canvas/install-id.js";import{setInstallId as Fr}from"../core/runtime/nodes.js";import{claimDaemonOwnership as Hr,releaseDaemonOwnership as se}from"../core/canvas/daemon-owner.js";import{migrate as Br,openDb as ae,withCanvasWrite as jr,bindDaemonCanvasOpenHook as qr,clearDaemonCanvasOpenHook as ce}from"../core/canvas/db.js";import{brokerSignalBus as H}from"./broker-signals/bus.js";import{brokerSignalStreams as zr}from"./api/handlers/broker-signals.js";import{reconcilePackageDocuments as Wr}from"../core/graph/package-docs.js";import{startRepoSync as Ur}from"../core/graph/repo-sync/index.js";import{prewarmRecentRecipes as Kr,reapStaleSpares as Jr}from"../core/runtime/warm-pool.js";import{DaemonFleet as Vr}from"./fleet.js";import{BOOT_MIGRATIONS as Qr}from"./boot-migrations.js";import{applyJoinedOwner as Yr}from"./joined-owner.js";import{emitEvent as u}from"../core/events/emit.js";import{operationIdContext as b}from"../core/events/operation-id.js";import{bindDaemonEventSource as Xr}from"../core/events/source.js";import{activateCanvasImport as Zr,MigrationBlockedError as et,runForcedCanvasImport as rt}from"../migrations/activation.js";import{convertLegacyProviderStore as tt,convertLegacyScopedStore as nt}from"../core/scoped-state/migrate.js";import{userScopeRoot as ot}from"../core/scope.js";import{secretsDir as it}from"../core/layout.js";function B(t,n){return t.includes(` --canvas-home ${n} `)}s(B,"brokerCommandDeclaresCanvasHome");function j(t){return/ --epoch (\S+) /.exec(t)?.[1]??null}s(j,"brokerCommandEpoch");const st=5e3,de=150;async function at(t){const n=te();if(n===null)throw u({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 a=Me(),m=[];for(const[i,p]of n.processes){const y=p.command;if(p.zombie||!y.includes("broker-cli.js")||!B(y,a)||j(y)===t)continue;const S=y.trim().split(/\s+/).at(-1)??"";S===""||S.endsWith("broker-cli.js")||m.push({pid:i,nodeId:S})}let f=0;const o=[];for(const i of m){const p=Tr(i.pid);if(p===null||!p.includes("broker-cli.js")||!B(p,a)||j(p)===t||p.trim().split(/\s+/).at(-1)!==i.nodeId)continue;const y=ne(i.pid,null);if(!y.reused){try{process.platform==="linux"&&k(x)?await I({operation:"stop",pid:i.pid}):process.kill(i.pid,"SIGTERM")}catch{continue}f++,o.push({pid:i.pid,snap:y})}}const g=Date.now()+st;for(;Date.now()<g&&o.some(i=>oe(i.snap.tree.length>0?i.snap.tree:[i.pid]));)await new Promise(i=>setTimeout(i,de));let v=0;for(const i of o){const p=i.snap.tree.length>0?i.snap.tree:[i.pid];oe(p)&&(process.platform==="linux"&&k(x)?await I({operation:"stop",pid:i.pid}):ie(p,"SIGKILL",i.snap.identities),v++)}v>0&&await new Promise(i=>setTimeout(i,de));const d=te();if(d===null)throw u({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 l=[];for(const[i,p]of d.processes){const y=p.command;p.zombie||!y.includes("broker-cli.js")||B(y,a)&&j(y)!==t&&l.push(i)}if(l.length>0)throw new Error(`prior-epoch broker census could not prove termination of pid(s): ${l.join(", ")}`);u({level:"info",event:"daemon.census.completed",fields:{prior_epoch_brokers:m.length,sigtermed:f,sigkilled:v}})}s(at,"reapPriorEpochBrokers");const ct=5e3;async function dt(t){const n=Array.from(t.entries());if(n.length===0)return;for(const[o]of n){const g=ze(o)?.status;(g==="active"||g==="idle")&&Ue(o,new Date().toISOString())}const a=n.map(([,o])=>({pid:o.pid,snap:ne(o.pid,null),exited:o.handle.exited}));for(const o of a)if(!o.snap.reused)try{process.platform==="linux"&&k(x)?await I({operation:"stop",pid:o.pid}):process.kill(o.pid,"SIGTERM")}catch{}const m=new Promise(o=>{setTimeout(o,ct).unref()});await Promise.allSettled(a.map(o=>Promise.race([o.exited.then(()=>{}),m])));const f=[];for(const o of a)Dr(o.pid)&&(process.platform==="linux"&&k(x)?await I({operation:"stop",pid:o.pid}):ie(o.snap.tree.length>0?o.snap.tree:[o.pid],"SIGKILL",o.snap.identities),f.push(o));await Promise.all(f.map(o=>o.exited));for(const[o]of n)yr(o,{reason:"daemon-teardown"});u({level:"info",event:"daemon.fleet_teardown.completed",fields:{brokers:a.length,sigkilled:f.length}})}s(dt,"teardownFleet");function le(){Z(De(F()),{recursive:!0}),xe(F(),String(process.pid),"utf8")}s(le,"writePidfile");function pe(t){return typeof t=="object"&&t!==null&&t.code==="ENOENT"}s(pe,"isMissingPathError");function me(t){const n=F();let a;try{a=Pe(n,"utf8")}catch(m){if(pe(m))return;throw m}if(a.trim()!==String(t))throw new Error(`daemon readiness mirror does not name this invocation (expected pid ${t})`);try{Ie(n)}catch(m){if(pe(m))return;throw m}}s(me,"removeOwnedPidfileMirror");const lt={acceptsDetachedWork:s(()=>!0,"acceptsDetachedWork"),registerDetached:s(t=>{t.catch(()=>{})},"registerDetached")},q=new mr,pt=new fr,mt=new ur,ft=new hr,ut=new vr,ht=new wr,vt=new gr,wt=new _r,gt=new kr,yt=new Er,St=new Rr,bt=new xr,_t=new Pr;async function kt(t=Date.now(),n=lt){const a=Lr(),m=await q.runFleetPreamble(a);let f,o;try{const v=We();f=v.filter(d=>d.status==="active"||d.status==="idle"),o=v.filter(d=>d.status==="done"||d.status==="canceled"||d.status==="dead")}catch(v){u({level:"error",event:"canvas.node_list.failed",error:v});return}await q.run(t,{rows:f,fleet:a,lifecycle:n}),pt.run(t,{rows:f});const g=await mt.run(t,{rows:[...f,...o],fleet:a});ft.run(t),_t.run(t),ut.run(t,{lifecycle:n}),ht.run(t,{lifecycle:n}),vt.run(t,{lifecycle:n}),wt.run(t,{lifecycle:n}),gt.run(t,{lifecycle:n,fleet:a}),yt.run(t,{lifecycle:n}),$e(),bt.run(t,{fleet:a,lifecycle:n}),await St.run(t,{rows:f}),q.warnIfSaturated({fleet:a,lifecycle:n,thresholds:m,frozen:g})}s(kt,"superviseTick");async function Et(t){Z(re(),{recursive:!0,mode:493}),process.platform==="linux"&&Te(re(),493);const n=Ne();if(k(n))throw new Error(`layout refusal cannot bind occupied socket: ${n}`);const a=ee((d,l)=>{if(d.method==="GET"&&d.url==="/healthz"){l.writeHead(200,{"content-type":"application/json; charset=utf-8"}),l.end(JSON.stringify({ok:!1,daemon_up:!0,store_accessible:!1,brokers_reconciled:!1,startup_phase:"blocked",startup_blocked:"layout_migration_required"}));return}l.writeHead(503,{"content-type":"application/json; charset=utf-8"}),l.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((d,l)=>{a.once("error",l),a.listen(n,()=>{a.off("error",l),d()})});let m;const f=t.tcp??Ce();if(f){const d=/^(.*):(\d+)$/.exec(f);if(!d||Number(d[2])>65535)throw new Error(`invalid refusal TCP address: ${f}`);const l=ee(a.listeners("request")[0]);await new Promise((i,p)=>{l.once("error",p),l.listen(Number(d[2]),d[1],()=>{l.off("error",p),i()})}),m=l}le();let o;const g=s(()=>(o??=(async()=>{a.closeAllConnections(),m?.closeAllConnections(),await Promise.all([a,m].filter(d=>d!==void 0).map(d=>new Promise((l,i)=>d.close(p=>p?i(p):l())))),me(process.pid),process.off("SIGINT",v),process.off("SIGTERM",v)})(),o),"cleanup"),v=s(()=>{g().then(()=>process.exit(0),d=>{process.stderr.write(`[crtrd] layout refusal cleanup failed: ${String(d)}
|
|
2
|
-
`),process.exit(1)})},"onSignal");return process.on("SIGINT",v),process.on("SIGTERM",v),g}s(
|
|
1
|
+
var _e=Object.defineProperty;var s=(t,n)=>_e(t,"name",{value:n,configurable:!0});import{startPeerOutbox as ke}from"./peer/outbox.js";import{reportMachineStatus as Ee}from"../core/peer/directory.js";import{createPeerRelay as Re}from"./peer/relay-service.js";import{writeFileSync as xe,readFileSync as Pe,rmSync as Ie,mkdirSync as Z,existsSync as k,chmodSync as Te}from"node:fs";import{createServer as ee}from"node:http";import{dirname as De}from"node:path";import{envCrtrdTcp as Ce}from"../shared/env.js";import{serveCanvasConversationStore as Le}from"../core/canvas/sessions.js";import{pollRunObservers as $e}from"./runs/observer.js";import{randomBytes as Ae}from"node:crypto";import{apiSocketPath as Ne,crtrHome as Me}from"../core/canvas/paths.js";import{activeAppUsers as Oe}from"../core/spaces/users.js";import{ensureAppSpace as Ge,ensureUserFiles as Fe}from"../core/spaces/space.js";import{LAUNCHER_SOCKET as x}from"../launcher/spec.js";import{launcherRequest as I}from"../launcher/client.js";import{installLauncherEventSink as He}from"./launcher-events.js";import{initializeEmptyLayout as Be,layoutNeedsMigration as je,socketDir as re}from"../core/layout.js";import{migrateLooseKeys as qe}from"../core/layout-migrate/loose-keys.js";import{relocateProfileFolders as ze}from"../core/profiles/relocate.js";import{getNode as We,listNodesForSupervision as Ue,setFrozen as Ke}from"../core/canvas/index.js";import{createApiServer as Je}from"./api/server.js";import{createAppListener as Ve}from"./api/app-listener.js";import{installLocalTerminalGrant as Qe}from"../core/grants/local.js";import{onRunEventAppended as Ye}from"../core/runs/events.js";import{runNotices as Xe}from"./run-notices.js";import{createGrantSync as Ze,GRANT_SYNC_INTERVAL_S as er}from"../core/grants/sync.js";import{runRemovalCascades as rr}from"../core/grants/remove.js";import{sweepSandboxes as tr}from"../core/grants/on-sync.js";import{rebuildCronExecutions as nr}from"./cron/run-socket.js";import{hasSyncedGrants as or}from"../core/grants/mirror.js";import{readConfig as ir}from"../core/config.js";import{reconcileUndeliveredTickets as sr}from"./human/sweep.js";import{resetHandedOffDeliveries as ar}from"../core/canvas/deliveries.js";import{resetHandedOffDaemonActions as cr}from"../core/canvas/daemon-actions.js";import{sweepReviews as dr}from"./review/sweep.js";import{pidfilePath as F}from"./pidfile.js";import{rendererWarning as lr}from"../core/runtime/package-health.js";import{DEFAULT_INTERVAL_MS as pr}from"./supervise-cadence.js";import{createResumeDetector as mr}from"./resume-detector.js";import{BrokerSupervisionReconciler as fr}from"./reconcilers/broker-supervision.js";import{ControllerDeathReconciler as ur}from"./reconcilers/controller-death.js";import{NodeLifecycleReconciler as hr}from"./reconcilers/node-lifecycle/tick.js";import{NodeDeadlineReconciler as vr}from"./reconcilers/node-deadline.js";import{CronLaneReconciler as wr}from"./reconcilers/cron-lane.js";import{DeliveryLaneReconciler as gr}from"./reconcilers/delivery-lane.js";import{ActionLaneReconciler as yr}from"./reconcilers/action-lane.js";import{endLiveExecution as Sr,migrateLegacyExecutionIdentities as br}from"../core/canvas/executions.js";import{revokePriorEpochNodeTokens as _r}from"../core/canvas/node-tokens.js";import{PendingReviewSubmitReconciler as kr}from"./reconcilers/pending-review-submit.js";import{StorageMaintenanceReconciler as Er}from"./reconcilers/storage-maintenance.js";import{StorageDueWorkReconciler as Rr}from"./reconcilers/storage-due-work.js";import{BashDeadlineReconciler as xr}from"./reconcilers/bash-deadline.js";import{FaultRetryBackstopReconciler as Pr}from"./reconcilers/fault-retry-backstop.js";import{StructuredRequestReconciler as Ir}from"./reconcilers/structured-request-lane.js";import{reconcileStructuredRequestSidecars as Tr}from"./structured-requests/boot.js";import{captureLivenessSnapshot as te,capturePidCommand as Dr,captureTeardownSnapshot as ne,isPidAlive as Cr,isAnyPidAlive as oe,killProcessTreePids as ie}from"../core/canvas/pid.js";import{bindFleet as Lr,boundFleet as $r}from"../core/runtime/fleet.js";import{bindDaemonControl as Ar,clearDaemonControl as Nr}from"./control.js";import{execDaemon as Mr,spawnDaemon as Or}from"./manage.js";import{reconcileAndMigrateBoot as Gr}from"../core/canvas/boot.js";import{resolveInstallId as Fr}from"../core/canvas/install-id.js";import{setInstallId as Hr}from"../core/runtime/nodes.js";import{claimDaemonOwnership as Br,releaseDaemonOwnership as se}from"../core/canvas/daemon-owner.js";import{migrate as jr,openDb as ae,withCanvasWrite as qr,bindDaemonCanvasOpenHook as zr,clearDaemonCanvasOpenHook as ce}from"../core/canvas/db.js";import{brokerSignalBus as H}from"./broker-signals/bus.js";import{brokerSignalStreams as Wr}from"./api/handlers/broker-signals.js";import{reconcilePackageDocuments as Ur}from"../core/graph/package-docs.js";import{startRepoSync as Kr}from"../core/graph/repo-sync/index.js";import{prewarmRecentRecipes as Jr,reapStaleSpares as Vr}from"../core/runtime/warm-pool.js";import{DaemonFleet as Qr}from"./fleet.js";import{BOOT_MIGRATIONS as Yr}from"./boot-migrations.js";import{applyJoinedOwner as Xr}from"./joined-owner.js";import{emitEvent as u}from"../core/events/emit.js";import{operationIdContext as b}from"../core/events/operation-id.js";import{bindDaemonEventSource as Zr}from"../core/events/source.js";import{activateCanvasImport as et,MigrationBlockedError as rt,runForcedCanvasImport as tt}from"../migrations/activation.js";import{convertLegacyProviderStore as nt,convertLegacyScopedStore as ot}from"../core/scoped-state/migrate.js";import{userScopeRoot as it}from"../core/scope.js";import{secretsDir as st}from"../core/layout.js";function B(t,n){return t.includes(` --canvas-home ${n} `)}s(B,"brokerCommandDeclaresCanvasHome");function j(t){return/ --epoch (\S+) /.exec(t)?.[1]??null}s(j,"brokerCommandEpoch");const at=5e3,de=150;async function ct(t){const n=te();if(n===null)throw u({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 a=Me(),m=[];for(const[i,p]of n.processes){const y=p.command;if(p.zombie||!y.includes("broker-cli.js")||!B(y,a)||j(y)===t)continue;const S=y.trim().split(/\s+/).at(-1)??"";S===""||S.endsWith("broker-cli.js")||m.push({pid:i,nodeId:S})}let f=0;const o=[];for(const i of m){const p=Dr(i.pid);if(p===null||!p.includes("broker-cli.js")||!B(p,a)||j(p)===t||p.trim().split(/\s+/).at(-1)!==i.nodeId)continue;const y=ne(i.pid,null);if(!y.reused){try{process.platform==="linux"&&k(x)?await I({operation:"stop",pid:i.pid}):process.kill(i.pid,"SIGTERM")}catch{continue}f++,o.push({pid:i.pid,snap:y})}}const g=Date.now()+at;for(;Date.now()<g&&o.some(i=>oe(i.snap.tree.length>0?i.snap.tree:[i.pid]));)await new Promise(i=>setTimeout(i,de));let v=0;for(const i of o){const p=i.snap.tree.length>0?i.snap.tree:[i.pid];oe(p)&&(process.platform==="linux"&&k(x)?await I({operation:"stop",pid:i.pid}):ie(p,"SIGKILL",i.snap.identities),v++)}v>0&&await new Promise(i=>setTimeout(i,de));const d=te();if(d===null)throw u({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 l=[];for(const[i,p]of d.processes){const y=p.command;p.zombie||!y.includes("broker-cli.js")||B(y,a)&&j(y)!==t&&l.push(i)}if(l.length>0)throw new Error(`prior-epoch broker census could not prove termination of pid(s): ${l.join(", ")}`);u({level:"info",event:"daemon.census.completed",fields:{prior_epoch_brokers:m.length,sigtermed:f,sigkilled:v}})}s(ct,"reapPriorEpochBrokers");const dt=5e3;async function lt(t){const n=Array.from(t.entries());if(n.length===0)return;for(const[o]of n){const g=We(o)?.status;(g==="active"||g==="idle")&&Ke(o,new Date().toISOString())}const a=n.map(([,o])=>({pid:o.pid,snap:ne(o.pid,null),exited:o.handle.exited}));for(const o of a)if(!o.snap.reused)try{process.platform==="linux"&&k(x)?await I({operation:"stop",pid:o.pid}):process.kill(o.pid,"SIGTERM")}catch{}const m=new Promise(o=>{setTimeout(o,dt).unref()});await Promise.allSettled(a.map(o=>Promise.race([o.exited.then(()=>{}),m])));const f=[];for(const o of a)Cr(o.pid)&&(process.platform==="linux"&&k(x)?await I({operation:"stop",pid:o.pid}):ie(o.snap.tree.length>0?o.snap.tree:[o.pid],"SIGKILL",o.snap.identities),f.push(o));await Promise.all(f.map(o=>o.exited));for(const[o]of n)Sr(o,{reason:"daemon-teardown"});u({level:"info",event:"daemon.fleet_teardown.completed",fields:{brokers:a.length,sigkilled:f.length}})}s(lt,"teardownFleet");function le(){Z(De(F()),{recursive:!0}),xe(F(),String(process.pid),"utf8")}s(le,"writePidfile");function pe(t){return typeof t=="object"&&t!==null&&t.code==="ENOENT"}s(pe,"isMissingPathError");function me(t){const n=F();let a;try{a=Pe(n,"utf8")}catch(m){if(pe(m))return;throw m}if(a.trim()!==String(t))throw new Error(`daemon readiness mirror does not name this invocation (expected pid ${t})`);try{Ie(n)}catch(m){if(pe(m))return;throw m}}s(me,"removeOwnedPidfileMirror");const pt={acceptsDetachedWork:s(()=>!0,"acceptsDetachedWork"),registerDetached:s(t=>{t.catch(()=>{})},"registerDetached")},q=new fr,mt=new ur,ft=new hr,ut=new vr,ht=new wr,vt=new gr,wt=new yr,gt=new kr,yt=new Er,St=new Rr,bt=new xr,_t=new Pr,kt=new Ir;async function Et(t=Date.now(),n=pt){const a=$r(),m=await q.runFleetPreamble(a);let f,o;try{const v=Ue();f=v.filter(d=>d.status==="active"||d.status==="idle"),o=v.filter(d=>d.status==="done"||d.status==="canceled"||d.status==="dead")}catch(v){u({level:"error",event:"canvas.node_list.failed",error:v});return}await q.run(t,{rows:f,fleet:a,lifecycle:n}),mt.run(t,{rows:f});const g=await ft.run(t,{rows:[...f,...o],fleet:a});ut.run(t),kt.run(t),ht.run(t,{lifecycle:n}),vt.run(t,{lifecycle:n}),wt.run(t,{lifecycle:n}),gt.run(t,{lifecycle:n}),yt.run(t,{lifecycle:n,fleet:a}),St.run(t,{lifecycle:n}),$e(),_t.run(t,{fleet:a,lifecycle:n}),await bt.run(t,{rows:f}),q.warnIfSaturated({fleet:a,lifecycle:n,thresholds:m,frozen:g})}s(Et,"superviseTick");async function Rt(t){Z(re(),{recursive:!0,mode:493}),process.platform==="linux"&&Te(re(),493);const n=Ne();if(k(n))throw new Error(`layout refusal cannot bind occupied socket: ${n}`);const a=ee((d,l)=>{if(d.method==="GET"&&d.url==="/healthz"){l.writeHead(200,{"content-type":"application/json; charset=utf-8"}),l.end(JSON.stringify({ok:!1,daemon_up:!0,store_accessible:!1,brokers_reconciled:!1,startup_phase:"blocked",startup_blocked:"layout_migration_required"}));return}l.writeHead(503,{"content-type":"application/json; charset=utf-8"}),l.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((d,l)=>{a.once("error",l),a.listen(n,()=>{a.off("error",l),d()})});let m;const f=t.tcp??Ce();if(f){const d=/^(.*):(\d+)$/.exec(f);if(!d||Number(d[2])>65535)throw new Error(`invalid refusal TCP address: ${f}`);const l=ee(a.listeners("request")[0]);await new Promise((i,p)=>{l.once("error",p),l.listen(Number(d[2]),d[1],()=>{l.off("error",p),i()})}),m=l}le();let o;const g=s(()=>(o??=(async()=>{a.closeAllConnections(),m?.closeAllConnections(),await Promise.all([a,m].filter(d=>d!==void 0).map(d=>new Promise((l,i)=>d.close(p=>p?i(p):l())))),me(process.pid),process.off("SIGINT",v),process.off("SIGTERM",v)})(),o),"cleanup"),v=s(()=>{g().then(()=>process.exit(0),d=>{process.stderr.write(`[crtrd] layout refusal cleanup failed: ${String(d)}
|
|
2
|
+
`),process.exit(1)})},"onSignal");return process.on("SIGINT",v),process.on("SIGTERM",v),g}s(Rt,"serveLayoutRefusal");async function xt(t={}){if(je())return Rt(t);Be();const n=Br(Ae(16).toString("hex"));if(!n.claimed){if(n.reason==="incumbent_alive")process.stderr.write(`[crtrd] already running (pid ${n.incumbentPid??"?"})
|
|
3
3
|
`);else{const r=[n.incumbentPid!==void 0?`pid ${n.incumbentPid}`:void 0,n.verdict!==void 0?`verdict ${n.verdict}`:void 0].filter(c=>c!==void 0),e=r.length>0?` (${r.join(", ")})`:"";process.stderr.write(`[crtrd] claim lost: ${n.reason}${e}
|
|
4
|
-
`),n.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"),(n.reason==="own_identity_indeterminate"||n.reason==="incumbent_malformed")&&(process.exitCode=1)}return async()=>{}}const a=n.claim;let m=null;try{
|
|
5
|
-
`);
|
|
4
|
+
`),n.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"),(n.reason==="own_identity_indeterminate"||n.reason==="incumbent_malformed")&&(process.exitCode=1)}return async()=>{}}const a=n.claim;let m=null;try{await ct(a.token),ot({kind:"user",root:it()});for(const e of ze())process.stderr.write(`[crtrd] ${e}
|
|
5
|
+
`);if(process.platform==="darwin"){const{readConfig:e,updateConfig:c}=await import("../core/config.js");if(e("user").paths?.user_files===void 0){const{homedir:w}=await import("node:os");c("user",X=>{X.paths??={},X.paths.user_files??=w()})}}await nt(st());for(const e of qe())process.stderr.write(`[crtrd] ${e}
|
|
6
|
+
`);jr(ae()),zr(e=>H.install(e));const r=qr(e=>Ur(e));for(const e of r.conflicts)process.stderr.write(`[crtrd] plugin documents not reconciled: ${e.message}
|
|
6
7
|
`);for(const e of r.invalid)process.stderr.write(`[crtrd] package file is not a document: ${e.path}: ${e.error}
|
|
7
8
|
`);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"}
|
|
8
|
-
`);m=
|
|
9
|
+
`);m=Xr(),process.platform==="linux"&&k(x)&&(He(),await I({operation:"users.sync",users:Oe()})),_r(a.token)}catch(r){ce(),H.close();try{const{released:e}=se(a);if(!e)throw new Error("daemon ownership claim was not released")}catch(e){throw new AggregateError([r,e],"daemon startup failed and cleanup also failed")}throw r}let f=!0,o,g=Promise.resolve(),v=!1,d,l;const i=new Set;let p=!1,y=!1,S,$,z=!1,A,T,D,C,M;const fe=mr();let E,h={phase:"initializing",message:"daemon startup is running the canvas import and normal services are unavailable",blockerPaths:[]},P="initial startup activation",ue=null;function he(){return h.phase==="ready"?null:{phase:h.phase,message:h.message,blockerPaths:h.blockerPaths}}s(he,"startupBlock");function _(r){i.add(r),r.finally(()=>{i.delete(r)}).catch(()=>{})}s(_,"registerDetached");const W={acceptsDetachedWork:s(()=>f,"acceptsDetachedWork"),registerDetached:_};Kr(W,ae);async function ve(){try{f=!1,Wr.close(),ce(),H.close(),d!==void 0&&(clearInterval(d),d=void 0),D!==void 0&&(clearInterval(D),D=void 0),M?.(),M=void 0;let r;do r=g,await r;while(r!==g);for(;i.size>0;)await Promise.allSettled([...i]);if(l!==void 0&&(await lt(l),l.dispose()),$!==void 0&&!z&&(z=!0,await $.close()),C!==void 0){const e=C;C=void 0,await e.stop()}if(T!==void 0){const e=T;T=void 0,await e.close()}if(A!==void 0){const e=A;A=void 0,await e.close()}if(p||(me(process.pid),p=!0),p&&!y){const{released:e}=se(a);if(!e)throw new Error("daemon ownership claim was not released");y=!0}}finally{Nr(),process.off("SIGINT",J),process.off("SIGTERM",V),process.off("exit",Q)}}s(ve,"cleanupAttempt");const N=1e3;let U=!1;function we(){return U?{graceMs:N}:(U=!0,b.fresh(()=>{u({level:"info",event:"daemon.handover.armed",fields:{pid:process.pid,grace_ms:N}})}),setTimeout(()=>{ge()},N),{graceMs:N})}s(we,"requestHandover");async function ge(){try{await R()}catch(r){const e=r instanceof Error?r.stack??r.message:String(r);process.stderr.write(`[crtrd] handover cleanup failed:
|
|
9
10
|
${e}
|
|
10
|
-
`),process.exit(1)}try{process.platform==="linux"&&k(x)&&(await I({operation:"daemon.handover"}),process.exit(0)),process.pid===1&&await
|
|
11
|
+
`),process.exit(1)}try{process.platform==="linux"&&k(x)&&(await I({operation:"daemon.handover"}),process.exit(0)),process.pid===1&&await Mr();const r=await Or({waitForJoinLock:!0});b.fresh(()=>{u({level:"info",event:"daemon.handover.completed",fields:{predecessor_pid:process.pid,successor_pid:r.pid??r.existing_pid??null,spawned:r.started}})})}catch(r){b.fresh(()=>{u({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}
|
|
11
12
|
`),process.exit(1)}process.exit(0)}s(ge,"performHandover");function R(){if(S!==void 0)return S;const r=ve();return S=r,r.then(()=>{S===r&&(S=void 0)},()=>{S===r&&(S=void 0)}),r}s(R,"requestCleanup");async function K(r){try{await R(),process.exit(0)}catch(e){process.exitCode=1;const c=e instanceof Error?e.stack??`${e.name}: ${e.message}`:String(e);process.stderr.write(`[crtrd] ${r} cleanup failed:
|
|
12
13
|
${c}
|
|
13
|
-
`),process.exit(1)}}s(K,"handleSignal");function J(){K("SIGINT")}s(J,"onSigint");function V(){K("SIGTERM")}s(V,"onSigterm");function Q(){R().catch(()=>{})}s(Q,"onExit");function O(r){f&&(g=g.then(r).then(()=>{},e=>{b.fresh(()=>{u({level:"error",event:"daemon.lane_job.failed",error:e})})}))}s(O,"enqueue");function Y(){!f||v||(fe.check()&&E&&(u({level:"info",event:"daemon.resume.detected"}),_(E().catch(()=>{}))),v=!0,O(async()=>{if(v=!1,!!f)try{await
|
|
14
|
+
`),process.exit(1)}}s(K,"handleSignal");function J(){K("SIGINT")}s(J,"onSigint");function V(){K("SIGTERM")}s(V,"onSigterm");function Q(){R().catch(()=>{})}s(Q,"onExit");function O(r){f&&(g=g.then(r).then(()=>{},e=>{b.fresh(()=>{u({level:"error",event:"daemon.lane_job.failed",error:e})})}))}s(O,"enqueue");function Y(){!f||v||(fe.check()&&E&&(u({level:"info",event:"daemon.resume.detected"}),_(E().catch(()=>{}))),v=!0,O(async()=>{if(v=!1,!!f)try{await Et(Date.now(),W)}catch(r){b.fresh(()=>{u({level:"error",event:"daemon.tick.failed",error:r})})}}))}s(Y,"enqueueTick");let L=null;async function ye(){if(L!==null)throw{status:500,code:"admission_failed",message:`daemon admission previously failed: ${L instanceof Error?L.message:String(L)}`};if(h.phase==="ready")return{admitted:!1,already_admitted:!0,startup_phase:"ready"};if(h.phase!=="prepared"&&h.phase!=="recovering")throw{status:409,code:"not_prepared",message:h.message};const r=h.phase==="prepared";try{return await G(),h={phase:"ready",message:"",blockerPaths:[]},r?{admitted:!0,already_admitted:!1,startup_phase:"ready"}:{admitted:!1,already_admitted:!0,startup_phase:"ready"}}catch(e){throw L=e,{status:500,code:"admission_failed",message:`daemon admission failed: ${e instanceof Error?e.message:String(e)}`}}}s(ye,"admitStartup");async function Se(r){if(P!==null)throw{status:409,code:"migration_in_progress",message:`the canvas import is already running (${P})`};P="repair";try{const e=await tt({dryRun:r.dryRun});if(r.dryRun||e.pending||h.phase!=="blocked")return{result:e,resumed:!1};if(t.prepare)return h={phase:"prepared",message:"daemon storage is prepared and normal services are unavailable until admission",blockerPaths:[]},{result:e,resumed:!1};try{return await G(),h={phase:"ready",message:"",blockerPaths:[]},{result:e,resumed:!0}}catch(c){const w=c instanceof Error?c.message:String(c);return setTimeout(()=>{R().catch(()=>{})},1e3),{result:e,resumed:!1,resumeError:w}}}finally{P=null}}s(Se,"repairMigrations");async function be(){o=t.intervalMs??pr;const r=a.token;l=new Qr({epoch:r,enqueue:O}),Lr(l),h={phase:"recovering",message:"daemon startup recovery is running and normal services are unavailable",blockerPaths:[]},b.fresh(()=>{u({level:"info",event:"daemon.started",fields:{pid:process.pid,interval_ms:o}})});const e=Fr();if(Hr(e),b.fresh(()=>{u({level:"info",event:"daemon.install_id.resolved",fields:{install_id:e}})}),b.fresh(()=>{let c;try{c=lr()}catch{return}c!==null&&u({level:"warn",event:"daemon.startup.warning",fields:{stage:"termrender",warning:c.slice(0,2048)}})}),await b.fresh(async()=>{await dr(),await sr(),ar(Date.now()),cr(Date.now())}),b.fresh(()=>{const{reconcile:c,migrated:w}=Gr(br);c.changed&&u({level:"info",event:"daemon.boot_change.reconciled",fields:{cleared_count:c.cleared.length,same_boot_proven:c.sameBootProven}}),w.length>0&&u({level:"info",event:"daemon.pid_identity.migrated",fields:{migrated_count:w.length}})}),b.fresh(()=>{Tr();for(const c of Yr){const w=c.apply();w.changed&&u({level:"info",event:"daemon.boot_migration.applied",fields:{migration:c.id,...w.summary}})}}),_(nr()),E){const c=s(()=>{_(E().catch(()=>{})),_(Ee().then(w=>C?.observe(w)).then(()=>{},w=>{u({level:"warn",event:"daemon.peer.status_failed",error:w})}))},"refresh");_(rr().catch(()=>{})),_(tr().then(({completion:w})=>w).catch(w=>{u({level:"error",event:"daemon.grants.sweep_failed",error:w})})),c(),D=setInterval(c,er*1e3),D.unref(),M=ke({joined:!0,register:_})}O(()=>{Vr(),Jr()}),d=setInterval(Y,o),Y()}s(be,"completeStartup");function G(){return ue??=be().catch(r=>{throw h={phase:"initializing",message:"daemon startup recovery failed and normal services are unavailable",blockerPaths:[]},r})}s(G,"resumeStartup");try{process.on("SIGINT",J),process.on("SIGTERM",V),process.on("exit",Q),Zr(),m!==null&&u({level:"info",event:"daemon.joined_owner.applied",fields:{owner:m.owner,rows:m.rows}}),A=await Le();const r=a.token;Ar({epoch:r,requestHandover:we,registerDetached:_,startupBlock:he,admitStartup:ye,repairMigrations:Se}),le(),$=Je({tcp:t.tcp}),await $.ready;const e=ir("user").runtime;e?.issuer?(E=Ze(e.issuer,_),e.unsandboxed===!0&&(C=Re({syncGrants:E})),Ye(c=>Xe().appended(c))):Qe(),e?.unsandboxed===!0&&e.listener!==void 0&&u({level:"warn",event:"daemon.app_listener.refused_unsandboxed",fields:{reason:"runtime.unsandboxed is set; runtime.listener is ignored"}}),e!==void 0&&e.listener!==void 0&&e.unsandboxed!==!0&&(T=Ve(e,()=>or(e.issuer.replace(/\/$/,"")),E),await T.ready);try{await et()}catch(c){if(P=null,c instanceof rt)return h={phase:"blocked",message:c.message,blockerPaths:c.blockerPaths},R;throw c}process.platform==="linux"&&k(x)&&(Fe(),await Ge("app:terminal"));try{t.prepare?h={phase:"prepared",message:"daemon storage is prepared and normal services are unavailable until admission",blockerPaths:[]}:(await G(),h={phase:"ready",message:"",blockerPaths:[]})}finally{P=null}return R}catch(r){try{await R()}catch(e){throw new AggregateError([r,e],"daemon startup failed and cleanup also failed")}throw r}}s(xt,"runDaemon");var eo=xt;export{B as brokerCommandDeclaresCanvasHome,j as brokerCommandEpoch,eo as default,xt as runDaemon,Et as superviseTick,lt as teardownFleet};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var g=Object.defineProperty;var a=(
|
|
2
|
-
LEFT JOIN identities i ON i.object = o.rowid WHERE o.type IN ('person','app','repo','profile')`).all();return O(o,{roots:
|
|
1
|
+
var g=Object.defineProperty;var a=(r,n)=>g(r,"name",{value:n,configurable:!0});import{existsSync as f}from"node:fs";import{join as l}from"node:path";import{openDb as c,withCanvasWrite as w}from"../../core/canvas/db.js";import{nodeAgentDir as k,nodeRecordDir as S,onDiskMigrationMarkerPath as C}from"../../core/canvas/paths.js";import{identifyCheckout as j}from"../../core/graph/repo-sync/identity.js";import{profileSpace as I,userRoot as b}from"../../core/layout.js";import{commitConvertedProjectCaps as E,listLegacyProjectCaps as P,listStoredProfiles as x}from"../../core/scoped-state/profiles.js";import{userStore as L}from"../../core/scoped-state/paths.js";import{userScopeRoot as y}from"../../core/scope.js";import{applyPlan as M,readImportRecord as h,storePlanBodies as _}from"./apply.js";import{readLegacyCorpus as v,readMarkerIds as D}from"./legacy/discover.js";import{planImport as O}from"./plan.js";const F=a(()=>({stores:[],counts:{},rewrites:[],droppedFields:[],skipped:[],resolutions:[]}),"emptyReport");function A(){const r=y(),n=x(r),o=P(r),d=L(r).path,i=n.map(({profileId:e,manifest:s})=>{const p=s.grantee??"app:terminal",m=new Map(o.filter(t=>t.profileId===e).map(t=>[t.path,t.memory]));return{id:e,name:s.name,app:p,memory:I(p,e).dir,projects:s.projects.map(t=>t.path),raw:{projects:s.projects.map(t=>m.has(t.path)?{path:t.path,memory:m.get(t.path)}:{path:t.path})},manifestPath:`${d}#${e}`}}),u=c().prepare("SELECT node_id, cwd, grantee FROM node_rows ORDER BY created").all(),R=u.map(e=>{const s=e.grantee==="user:local"?"app:terminal":e.grantee,p=s?.startsWith("app:")?k(e.node_id,s):null,m=p!==null&&(f(l(p,"context"))||f(l(p,"reports")))?p:S(e.node_id);return{id:e.node_id,dir:m}});return{roots:{userMemory:l(b(),"memory"),profiles:i,nodeCwds:[...new Set(u.map(e=>e.cwd))],nodes:R},stored:n}}a(A,"legacyRoots");function N(){const{roots:r,stored:n}=A(),o=v(r),d=c().prepare(`SELECT o.type, o.name AS handle, i.external_id AS externalId FROM objects o
|
|
2
|
+
LEFT JOIN identities i ON i.object = o.rowid WHERE o.type IN ('person','app','repo','profile')`).all();return O(o,{roots:r,markerIds:D(C()),repoIdentity:j,existingOwners:d,storedProfiles:n.map(i=>({id:i.profileId,deliveryLimits:{...i.manifest.delivery_limits??{}}}))})}a(N,"plan");function V(){return h(c())!==null}a(V,"canvasImportDone");function X(r){const n=h(c());if(n!==null)return{report:r.dryRun?n:F(),blockers:[],dryRun:r.dryRun,pending:!1};const o=N();if(r.dryRun||o.blockers.length>0)return{report:o.report,blockers:o.blockers,dryRun:r.dryRun,pending:!0};const d=_(o);return E(y(),o.profileLimits),w(i=>M(i,o,d)),{report:o.report,blockers:[],dryRun:!1,pending:!1}}a(X,"runCanvasImport");export{V as canvasImportDone,X as runCanvasImport};
|
|
@@ -15,7 +15,7 @@ export interface LegacyProfile {
|
|
|
15
15
|
name: string;
|
|
16
16
|
/** The owning app (`grantee`), `app:terminal` for older manifests without one. */
|
|
17
17
|
app: string;
|
|
18
|
-
/** The profile's store (`<app
|
|
18
|
+
/** The profile's store (`<app space>/profiles/<id>`), resolved by the caller. */
|
|
19
19
|
memory: string;
|
|
20
20
|
/** Every `projects[].path` in the manifest. */
|
|
21
21
|
projects: string[];
|
|
@@ -32,7 +32,7 @@ Then join your laptop to the account:
|
|
|
32
32
|
crtr sys join --directory https://account.northlight.ai --token <token> --name my-laptop
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
-
It answers with `registered: true`, the machine id (`runtime:<id>`), your user id and `daemon: restarted` (`daemon:
|
|
35
|
+
It answers with `registered: true`, the machine id (`runtime:<id>`), your user id and `daemon: restarted` (`daemon: started` when crtr was not running: join starts the daemon, and its first grant sync installs `crtr cloud …` and your other provider plugins). Your open viewers and nodes reconnect on their own.
|
|
36
36
|
3. Check it: `crtr cloud apps mine` lists the apps you manage. Before you have joined, it answers `not_joined` and prints these same steps.
|
|
37
37
|
|
|
38
38
|
Things to know before you join:
|
|
@@ -7,6 +7,18 @@ description: Behavior changes in @north-light/sdk that an app must act on, newes
|
|
|
7
7
|
|
|
8
8
|
Changes to `@north-light/sdk` that can change what an existing app sees. Newest first.
|
|
9
9
|
|
|
10
|
+
## 0.3.460
|
|
11
|
+
|
|
12
|
+
### `crouter-sdk keygen` releases its key file when the add fails (no app change)
|
|
13
|
+
|
|
14
|
+
When `keygen` cannot add the public key to the app (the machine is not joined, or the directory refuses), it deletes the `local/app-key.json` it had reserved, so a rerun after fixing the cause starts clean. It keeps the file when the add timed out or returned no key, because the add may have landed.
|
|
15
|
+
|
|
16
|
+
## 0.3.459
|
|
17
|
+
|
|
18
|
+
### `ProfileDTO.profile_path` replaces `memory_path` (additive, no app change)
|
|
19
|
+
|
|
20
|
+
A profile's folder holds no documents (those live in the canvas), so it is now `<app space>/profiles/<id>` rather than `<app space>/memory/profiles/<id>`, and the profile objects carry `profile_path` with that path. `memory_path` is still sent with the same value and is deprecated; it goes in the next breaking release, so read `profile_path` and fall back to `memory_path` against an older runtime. Nothing else changes: the runtime moves existing folders itself on startup.
|
|
21
|
+
|
|
10
22
|
## 0.3.455
|
|
11
23
|
|
|
12
24
|
### `provider.call` can target a device (additive, no app change)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@north-light/cli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.460",
|
|
4
4
|
"description": "crtr — agent runtime with memory, plugins, and marketplaces",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -137,7 +137,7 @@
|
|
|
137
137
|
},
|
|
138
138
|
"license": "UNLICENSED",
|
|
139
139
|
"dependencies": {
|
|
140
|
-
"@north-light/identity": "0.3.
|
|
140
|
+
"@north-light/identity": "0.3.460",
|
|
141
141
|
"@earendil-works/pi-agent-core": "1.1.0",
|
|
142
142
|
"@earendil-works/pi-ai": "1.1.0",
|
|
143
143
|
"@earendil-works/pi-coding-agent": "1.1.0",
|
package/runtime.lock.json
CHANGED
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@north-light/cli",
|
|
3
|
-
"version": "0.3.
|
|
3
|
+
"version": "0.3.460",
|
|
4
4
|
"lockfileVersion": 3,
|
|
5
5
|
"requires": true,
|
|
6
6
|
"packages": {
|
|
7
7
|
"": {
|
|
8
8
|
"name": "@north-light/cli",
|
|
9
|
-
"version": "0.3.
|
|
9
|
+
"version": "0.3.460",
|
|
10
10
|
"hasInstallScript": true,
|
|
11
11
|
"license": "UNLICENSED",
|
|
12
12
|
"workspaces": [
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
"@earendil-works/pi-ai": "1.1.0",
|
|
19
19
|
"@earendil-works/pi-coding-agent": "1.1.0",
|
|
20
20
|
"@earendil-works/pi-tui": "1.1.0",
|
|
21
|
-
"@north-light/identity": "0.3.
|
|
21
|
+
"@north-light/identity": "0.3.460",
|
|
22
22
|
"cron-parser": "^5.6.0",
|
|
23
23
|
"esbuild": "^0.27.7",
|
|
24
24
|
"jose": "^6.2.12",
|
|
@@ -12095,17 +12095,17 @@
|
|
|
12095
12095
|
},
|
|
12096
12096
|
"packages/crouter-api": {
|
|
12097
12097
|
"name": "@north-light/api",
|
|
12098
|
-
"version": "0.3.
|
|
12098
|
+
"version": "0.3.460",
|
|
12099
12099
|
"license": "UNLICENSED"
|
|
12100
12100
|
},
|
|
12101
12101
|
"packages/crouter-env-docker": {
|
|
12102
12102
|
"name": "@north-light/env-docker",
|
|
12103
|
-
"version": "0.3.
|
|
12103
|
+
"version": "0.3.460",
|
|
12104
12104
|
"license": "UNLICENSED"
|
|
12105
12105
|
},
|
|
12106
12106
|
"packages/crouter-identity": {
|
|
12107
12107
|
"name": "@north-light/identity",
|
|
12108
|
-
"version": "0.3.
|
|
12108
|
+
"version": "0.3.460",
|
|
12109
12109
|
"license": "UNLICENSED",
|
|
12110
12110
|
"dependencies": {
|
|
12111
12111
|
"jose": "^6.2.1"
|
|
@@ -12113,20 +12113,20 @@
|
|
|
12113
12113
|
},
|
|
12114
12114
|
"packages/crouter-plugin": {
|
|
12115
12115
|
"name": "@north-light/plugin",
|
|
12116
|
-
"version": "0.3.
|
|
12116
|
+
"version": "0.3.460",
|
|
12117
12117
|
"license": "UNLICENSED",
|
|
12118
12118
|
"dependencies": {
|
|
12119
|
-
"@north-light/api": "0.3.
|
|
12120
|
-
"@north-light/identity": "0.3.
|
|
12119
|
+
"@north-light/api": "0.3.460",
|
|
12120
|
+
"@north-light/identity": "0.3.460"
|
|
12121
12121
|
}
|
|
12122
12122
|
},
|
|
12123
12123
|
"packages/crouter-sdk": {
|
|
12124
12124
|
"name": "@north-light/sdk",
|
|
12125
|
-
"version": "0.3.
|
|
12125
|
+
"version": "0.3.460",
|
|
12126
12126
|
"license": "UNLICENSED",
|
|
12127
12127
|
"dependencies": {
|
|
12128
|
-
"@north-light/api": "0.3.
|
|
12129
|
-
"@north-light/identity": "0.3.
|
|
12128
|
+
"@north-light/api": "0.3.460",
|
|
12129
|
+
"@north-light/identity": "0.3.460",
|
|
12130
12130
|
"jose": "^6.2.1"
|
|
12131
12131
|
},
|
|
12132
12132
|
"bin": {
|