@north-light/crouter 0.3.354 → 0.3.356

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (104) hide show
  1. package/dist/api/dto/delivery.d.ts +13 -3
  2. package/dist/api/dto/docs.d.ts +2 -0
  3. package/dist/api/dto/objects.d.ts +25 -22
  4. package/dist/api/dto/objects.js +1 -1
  5. package/dist/api/dto/reviews.d.ts +6 -4
  6. package/dist/builtin-memory/02-turn-lifecycle/02-resident.md +1 -0
  7. package/dist/builtin-memory/04-orchestration-kernel.md +10 -31
  8. package/dist/builtin-memory/internal/memory-loading.md +1 -1
  9. package/dist/clients/attach/overlays/file-review.d.ts +1 -0
  10. package/dist/clients/attach/overlays/file-review.js +2 -2
  11. package/dist/clients/attach/render/chat-view.d.ts +6 -0
  12. package/dist/clients/attach/render/chat-view.js +2 -2
  13. package/dist/clients/attach/render/doc-links.d.ts +34 -0
  14. package/dist/clients/attach/render/doc-links.js +1 -0
  15. package/dist/clients/attach/render/markdown-source.js +5 -5
  16. package/dist/clients/attach/session/doc-materialize.d.ts +53 -0
  17. package/dist/clients/attach/session/doc-materialize.js +3 -0
  18. package/dist/clients/attach/session/document-links.d.ts +21 -0
  19. package/dist/clients/attach/session/document-links.js +1 -0
  20. package/dist/clients/attach/session/file-links.d.ts +2 -0
  21. package/dist/clients/attach/session/file-links.js +1 -1
  22. package/dist/clients/attach/viewer.js +837 -761
  23. package/dist/clients/inbox/review/review-client.d.ts +5 -1
  24. package/dist/clients/inbox/review/review-client.js +1 -1
  25. package/dist/commands/canvas/list.js +3 -3
  26. package/dist/commands/canvas/read.d.ts +2 -4
  27. package/dist/commands/canvas/read.js +3 -5
  28. package/dist/commands/canvas/search.js +1 -1
  29. package/dist/commands/doc/write.js +1 -1
  30. package/dist/commands/node/lifecycle.js +2 -2
  31. package/dist/commands/sys/context/admin/actions.js +1 -1
  32. package/dist/commands/sys/sync-deps.js +1 -1
  33. package/dist/commands/sys/sync-shared.js +1 -1
  34. package/dist/core/canvas/daemon-actions.d.ts +43 -0
  35. package/dist/core/canvas/daemon-actions.js +26 -0
  36. package/dist/core/canvas/deliveries.d.ts +1 -0
  37. package/dist/core/canvas/deliveries.js +1 -1
  38. package/dist/core/canvas/migrations.js +106 -46
  39. package/dist/core/feed/messages.d.ts +2 -20
  40. package/dist/core/feed/messages.js +6 -10
  41. package/dist/core/graph/deletion.d.ts +5 -4
  42. package/dist/core/graph/deletion.js +3 -3
  43. package/dist/core/graph/documents.d.ts +8 -1
  44. package/dist/core/graph/documents.js +9 -6
  45. package/dist/core/graph/edges.d.ts +3 -2
  46. package/dist/core/graph/edges.js +1 -1
  47. package/dist/core/graph/events.d.ts +11 -6
  48. package/dist/core/graph/events.js +5 -4
  49. package/dist/core/graph/jobs.js +2 -2
  50. package/dist/core/graph/kinds/document.d.ts +19 -0
  51. package/dist/core/graph/kinds/document.js +5 -0
  52. package/dist/core/graph/kinds/dto.d.ts +5 -0
  53. package/dist/core/graph/kinds/dto.js +1 -0
  54. package/dist/core/graph/kinds/job.d.ts +2 -0
  55. package/dist/core/graph/kinds/job.js +2 -0
  56. package/dist/core/graph/kinds/kind.d.ts +39 -0
  57. package/dist/core/graph/kinds/kind.js +1 -0
  58. package/dist/core/graph/kinds/node.d.ts +2 -0
  59. package/dist/core/graph/kinds/node.js +4 -0
  60. package/dist/core/graph/kinds/owner.d.ts +2 -0
  61. package/dist/core/graph/kinds/owner.js +2 -0
  62. package/dist/core/graph/kinds/registry.d.ts +8 -0
  63. package/dist/core/graph/kinds/registry.js +1 -0
  64. package/dist/core/graph/kinds/render.d.ts +9 -0
  65. package/dist/core/graph/kinds/render.js +1 -0
  66. package/dist/core/graph/names.d.ts +3 -1
  67. package/dist/core/graph/names.js +3 -3
  68. package/dist/core/graph/objects.d.ts +5 -4
  69. package/dist/core/graph/objects.js +5 -5
  70. package/dist/core/graph/repo-sync/exchange.js +2 -2
  71. package/dist/core/graph/types.d.ts +6 -5
  72. package/dist/core/runs/operations.js +5 -5
  73. package/dist/core/runtime/broker-persona-guidance.js +2 -2
  74. package/dist/core/runtime/broker-protocol.d.ts +2 -7
  75. package/dist/core/runtime/persona.js +2 -2
  76. package/dist/core/runtime/roadmap.d.ts +3 -0
  77. package/dist/core/runtime/roadmap.js +8 -4
  78. package/dist/core/substrate/delivery/deliver.js +1 -1
  79. package/dist/core/substrate/delivery/listings.d.ts +3 -0
  80. package/dist/core/substrate/delivery/listings.js +5 -2
  81. package/dist/core/substrate/delivery/render-boot.js +26 -26
  82. package/dist/core/substrate/delivery/render-event.d.ts +13 -6
  83. package/dist/core/substrate/delivery/render-event.js +6 -4
  84. package/dist/daemon/api/handlers/docs.js +1 -1
  85. package/dist/daemon/api/handlers/human-requests.js +1 -1
  86. package/dist/daemon/api/handlers/objects.js +2 -5
  87. package/dist/daemon/api/handlers/reviews.d.ts +4 -1
  88. package/dist/daemon/api/handlers/reviews.js +1 -1
  89. package/dist/daemon/cron/settle.js +1 -1
  90. package/dist/daemon/cron/sinks.d.ts +3 -3
  91. package/dist/daemon/cron/sinks.js +2 -2
  92. package/dist/daemon/crtrd.js +6 -6
  93. package/dist/daemon/human/finish.js +6 -6
  94. package/dist/daemon/human/settle.d.ts +2 -3
  95. package/dist/daemon/human/settle.js +1 -1
  96. package/dist/daemon/reconcilers/action-lane.d.ts +8 -0
  97. package/dist/daemon/reconcilers/action-lane.js +1 -0
  98. package/dist/daemon/reconcilers/delivery-lane.d.ts +1 -1
  99. package/dist/daemon/reconcilers/delivery-lane.js +1 -1
  100. package/dist/shared/inbox-entry-body.js +7 -7
  101. package/package.json +2 -2
  102. package/packages/crouter-identity/package.json +1 -1
  103. package/runtime.lock.json +11 -11
  104. package/scripts/lib/isolation-env.mjs +8 -2
@@ -1 +1 @@
1
- var p=Object.defineProperty;var s=(e,r)=>p(e,"name",{value:r,configurable:!0});import{randomUUID as h}from"node:crypto";import{rmSync as g}from"node:fs";import{claimExternalActionDelivery as y,dueExternalActionDeliveries as I,messageBodyForDelivery as v,settleDelivery as a}from"../../core/canvas/deliveries.js";import{getNode as w}from"../../core/canvas/canvas.js";import{emitEvent as c}from"../../core/events/emit.js";import{operationIdContext as u}from"../../core/events/operation-id.js";import{createPageRequest as _,getRequest as f}from"../../core/human/requests.js";import{synthesizedPageDocument as D,writeSynthesizedPage as k}from"../../core/human/page-synth.js";import{preparePage as $}from"../../core/human/page-authoring.js";import{resolvePageComponents as q}from"../../core/config.js";import{spawnChild as E}from"../../core/runtime/spawn.js";import{runDelivery as x}from"../delivery/run-delivery.js";const m=h();function N(e){if(e.adapter===null||typeof e.adapter.adapter!="string")throw new Error(`delivery ${e.deliveryId} has no adapter`);return e.adapter}s(N,"adapterFor");function d(e,r,t){a(e.deliveryId,e.attempts,r,{state:"permanent_failed",failure:{kind:"spawn_error",message:t}},Date.now())}s(d,"failed");async function P(e,r,t){const n=w(t.nodeId);if(n!==null){if(n.frozen_at!==null||n.pi_session_id!==null||n.status==="idle"||n.status==="done"||n.status==="canceled"){a(e.deliveryId,e.attempts,r,{state:"acknowledged"},Date.now());return}d(e,r,n.status==="dead"?`cron spawn ${t.nodeId} recorded a failed birth`:`cron spawn ${t.nodeId} found an incomplete birth`);return}try{await E({nodeId:t.nodeId,kind:t.kind,cwd:t.cwd,prompt:t.prompt,...t.root?{root:!0,rootLifecycle:t.rootLifecycle}:{parent:t.parent},readiness:"launch",profile:t.profile,wakeOrigin:t.wakeOrigin}),a(e.deliveryId,e.attempts,r,{state:"acknowledged"},Date.now())}catch(o){d(e,r,`cron spawn ${t.nodeId} failed: ${o instanceof Error?o.message:String(o)}`),u.fresh(()=>c({level:"error",event:"delivery.cron_spawn_failed",node_id:t.nodeId,error:o,fields:{delivery_id:e.deliveryId}}))}}s(P,"deliverSpawn");function b(e,r){const t=k(D(e.title,e.summary,r,!1));try{return $({sourceFile:t.path,source:{sessionName:e.sessionName,...e.profileName===null?{}:{profileName:e.profileName}},productKinds:q(),delivery:{placement:"inline",inbox:!0,reply:!1}})}finally{g(t.dir,{recursive:!0,force:!0})}}s(b,"preparedCronPage");function z(e,r,t,n){if(f(t.requestId)!==null){a(e.deliveryId,e.attempts,r,{state:"acknowledged"},Date.now());return}const o=typeof n?.stdout=="string"?n.stdout:null;if(o===null){d(e,r,`cron human ${t.requestId} has no frozen stdout`);return}try{_({request_id:t.requestId,prepared:b(t,o)}),a(e.deliveryId,e.attempts,r,{state:"acknowledged"},Date.now())}catch(i){d(e,r,`cron human ${t.requestId} failed: ${i instanceof Error?i.message:String(i)}`)}}s(z,"deliverHuman");async function S(e,r){const t=N(e),n=v(e.deliveryId);if(n===null){d(e,r,`delivery ${e.deliveryId} has no message body`);return}if(t.adapter==="subprocess"){let o=t.node_id;if(o===void 0){const i=e.idempotencyKey;if(i?.startsWith("node-outcome:"))o=i.slice(13);else if(i?.startsWith("human-action:")){const l=f(i.slice(13));if(!l)throw new Error(`delivery ${e.deliveryId} has no originating human request`);o=l.requester_node_id}else throw new Error(`delivery ${e.deliveryId} has no originating app`)}await x({argv:t.argv,cwd:t.cwd,document:n,attempt:e.attempts,nodeId:o,...t.app?{app:t.app}:{}},i=>{a(e.deliveryId,e.attempts,r,i,Date.now())});return}if(t.adapter==="cron_spawn"){await P(e,r,t);return}z(e,r,t,n)}s(S,"deliverExternal");class J{static{s(this,"DeliveryLaneReconciler")}run(r,t){if(!t.lifecycle.acceptsDetachedWork())return;let n;try{n=I(r)}catch(o){u.fresh(()=>c({level:"error",event:"delivery.scan_failed",error:o}));return}for(const o of n)try{const i=y(o.deliveryId,r,m);if(i===null)continue;t.lifecycle.registerDetached(S(i,m).catch(l=>{u.fresh(()=>c({level:"error",event:"delivery.failed",error:l,fields:{delivery_id:i.deliveryId}}))}))}catch(i){u.fresh(()=>c({level:"error",event:"delivery.claim_failed",error:i,fields:{delivery_id:o.deliveryId}}))}}}export{J as DeliveryLaneReconciler,m as deliveryDaemonInstanceId};
1
+ var m=Object.defineProperty;var o=(e,t)=>m(e,"name",{value:t,configurable:!0});import{randomUUID as v}from"node:crypto";import{claimExternalActionDelivery as y,dueExternalActionDeliveries as u,messageBodyForDelivery as h,settleDelivery as c}from"../../core/canvas/deliveries.js";import{emitEvent as d}from"../../core/events/emit.js";import{operationIdContext as l}from"../../core/events/operation-id.js";import{runDelivery as I}from"../delivery/run-delivery.js";const s=v();function p(e,t,r){c(e.deliveryId,e.attempts,t,{state:"permanent_failed",failure:{kind:"spawn_error",message:r}},Date.now())}o(p,"failed");async function D(e,t){const r=e.adapter;if(r===null||r.adapter!=="subprocess"){p(e,t,`delivery ${e.deliveryId} has no subprocess adapter`);return}const n=h(e.deliveryId);if(n===null){p(e,t,`delivery ${e.deliveryId} has no message body`);return}let a=r.node_id;if(a===void 0){const i=e.idempotencyKey;if(!i?.startsWith("node-outcome:"))throw new Error(`delivery ${e.deliveryId} has no originating app`);a=i.slice(13)}await I({argv:r.argv,cwd:r.cwd,document:n,attempt:e.attempts,nodeId:a,...r.app?{app:r.app}:{}},i=>{c(e.deliveryId,e.attempts,t,i,Date.now())})}o(D,"deliverExternal");class k{static{o(this,"DeliveryLaneReconciler")}run(t,r){if(!r.lifecycle.acceptsDetachedWork())return;let n;try{n=u(t)}catch(a){l.fresh(()=>d({level:"error",event:"delivery.scan_failed",error:a}));return}for(const a of n)try{const i=y(a.deliveryId,t,s);if(i===null)continue;r.lifecycle.registerDetached(D(i,s).catch(f=>{l.fresh(()=>d({level:"error",event:"delivery.failed",error:f,fields:{delivery_id:i.deliveryId}}))}))}catch(i){l.fresh(()=>d({level:"error",event:"delivery.claim_failed",error:i,fields:{delivery_id:a.deliveryId}}))}}}export{k as DeliveryLaneReconciler,s as deliveryDaemonInstanceId};
@@ -1,10 +1,10 @@
1
- var p=Object.defineProperty;var i=(e,t)=>p(e,"name",{value:t,configurable:!0});import{formatInboxRefInstruction as $}from"./generated-context.js";const l=12,f=1e3,j=1e3;function k(e){return(e===void 0?null:/^([a-z0-9-]+)\/reports\/[^/]+$/.exec(e))?.[1]}i(k,"reportRefNodeId");function h(e){let t=e,r=!1;const o=t.split(`
2
- `);return o.length>l&&(t=o.slice(0,l).join(`
3
- `),r=!0),t.length>f&&(t=t.slice(0,f),r=!0),{text:t.trimEnd(),clipped:r}}i(h,"clipBody");function y(e){const t=typeof e.data?.body=="string"?String(e.data.body).trim():"";return t===""||t===e.label?"":t}i(y,"inlineBody");function x(e){const t=e.data?.push;return typeof t=="object"&&t!==null&&typeof t.event=="string"?t:null}i(x,"pushOf");function v(e){return e.type==="document"?`[[${e.owner===null?e.name:`${e.owner}/${e.name}`}]]`:e.type==="job"?`job ${e.id} (\`${e.name}\`)`:e.type==="node"?`node ${e.name} (${e.id})`:`${e.type} ${e.name}`}i(v,"objectText");function _(e,t){return t.actor===null?"the runtime":e.from_name===void 0||e.from_name===t.actor?t.actor:`${e.from_name} (${t.actor})`}i(_,"actorText");function u(e){return Array.isArray(e)?e.filter(t=>typeof t=="string"):[]}i(u,"list");function R(e,t){const r=v(t.object),o=_(e,t),n=t.attrs,a=t.object.type==="document"?` Read it with \`crtr canvas read ${t.object.owner===null?t.object.name:`${t.object.owner}/${t.object.name}`}\`.`:"";switch(t.event){case"created":return t.object.type==="node"?`${o} created ${r}${typeof n.kind=="string"?`, kind ${n.kind}`:""}.`:`${o} created ${r}.${a}`;case"read":return`${o} read ${r}.`;case"watched":return`${o} started watching ${r}.`;case"deleted":return`${o} deleted ${r}.`;case"edited":{const c=u(n.authors),d=u(n.rationales),s=typeof n.from_revision=="number"&&typeof n.revision=="number"&&n.revision-n.from_revision>1?`revisions ${n.from_revision+1}\u2013${n.revision}`:typeof n.revision=="number"?`revision ${n.revision}`:"a new revision",m=c.length===0?o:c.join(", "),b=d.length===0?"":` Rationale: ${d.join("; ")}.`,g=n.needs_merge===!0?" Two edits were made from the same revision; read it and edit it to merge them.":"",w=` You get this because you read or wrote it; if it no longer concerns your work, stop with \`crtr canvas unwatch ${t.object.owner===null?t.object.name:`${t.object.owner}/${t.object.name}`}\`.`;return`${m} edited ${r} (${s}).${b}${g}${a}${w}`}case"messaged":return`${o} messaged ${r}.`;case"sent":return`${o} sent a message as ${r}.`;case"configured":return`${o} changed the settings of ${r}${typeof n.changed=="string"?`: ${n.changed}`:""}.`;case"exited":return`${r[0].toUpperCase()}${r.slice(1)} exited with code ${String(n["exit-code"])}. Log: ${String(n["log-path"])}`;case"killed":{const c=t.actor===null?"":` by ${o}`,d=typeof n.reason=="string"?` (${n.reason})`:"",s=n.reason==="deadline"?` It was canceled at its deadline; claim it with \`crtr node bash extend ${t.object.id} --for <duration>\` next time.`:"";return`${r[0].toUpperCase()}${r.slice(1)} was killed${c}${d}.${s} Log: ${String(n["log-path"])}`}default:return e.label}}i(R,"renderPush");function E(e,t){if(t!==null&&t.length<j&&e.ref!==void 0)return`${t.trimEnd()}
1
+ var w=Object.defineProperty;var i=(e,t)=>w(e,"name",{value:t,configurable:!0});import{formatInboxRefInstruction as u}from"./generated-context.js";const f=12,l=1e3,y=1e3;function k(e){return(e===void 0?null:/^([a-z0-9-]+)\/reports\/[^/]+$/.exec(e))?.[1]}i(k,"reportRefNodeId");function x(e){let t=e,r=!1;const o=t.split(`
2
+ `);return o.length>f&&(t=o.slice(0,f).join(`
3
+ `),r=!0),t.length>l&&(t=t.slice(0,l),r=!0),{text:t.trimEnd(),clipped:r}}i(x,"clipBody");function j(e){const t=typeof e.data?.body=="string"?String(e.data.body).trim():"";return t===""||t===e.label?"":t}i(j,"inlineBody");function v(e){const t=e.data?.push;return typeof t=="object"&&t!==null&&typeof t.event=="string"?t:null}i(v,"pushOf");function $(e){const t=e.owner_handle??e.owner;return t==null?e.name:`${t}/${e.name}`}i($,"objectRef");function _(e){return e.type==="document"?`[[${$(e)}]]`:e.type==="job"?`job ${e.id} (\`${e.name}\`)`:e.type==="node"?`node ${e.name} (${e.id})`:`${e.type} ${e.name}`}i(_,"objectText");function R(e,t){return t.actor===null?"the runtime":e.from_name===void 0||e.from_name===t.actor?t.actor:`${e.from_name} (${t.actor})`}i(R,"actorText");function m(e){return Array.isArray(e)?e.filter(t=>typeof t=="string"):[]}i(m,"list");function A(e,t){const r=_(t.object),o=R(e,t),n=t.attrs,a=t.object.type==="document"?` Read it with \`crtr canvas read ${$(t.object)}\`.`:"";switch(t.event){case"created":return t.object.type==="node"?`${o} created ${r}${typeof n.kind=="string"?`, kind ${n.kind}`:""}.`:`${o} created ${r}.${a}`;case"read":return`${o} read ${r}.`;case"watched":return`${o} started watching ${r}.`;case"deleted":return`${o} deleted ${r}.`;case"edited":{const c=m(n.authors),s=m(n.rationales),d=typeof n.from_revision=="number"&&typeof n.revision=="number"&&n.revision-n.from_revision>1?`revisions ${n.from_revision+1}\u2013${n.revision}`:typeof n.revision=="number"?`revision ${n.revision}`:"a new revision",g=c.length===0?o:c.join(", "),b=s.length===0?"":` Rationale: ${s.join("; ")}.`,p=n.needs_merge===!0?" Two edits were made from the same revision; read it and edit it to merge them.":"",h=` You get this because you read or wrote it; if it no longer concerns your work, stop with \`crtr canvas unwatch ${$(t.object)}\`.`;return`${g} edited ${r} (${d}).${b}${p}${a}${h}`}case"messaged":return`${o} messaged ${r}.`;case"sent":return`${o} sent a message as ${r}.`;case"configured":return`${o} changed the settings of ${r}${typeof n.changed=="string"?`: ${n.changed}`:""}.`;case"exited":return`${r[0].toUpperCase()}${r.slice(1)} exited with code ${String(n["exit-code"])}. Log: ${String(n["log-path"])}`;case"killed":{const c=t.actor===null?"":` by ${o}`,s=typeof n.reason=="string"?` (${n.reason})`:"",d=n.reason==="deadline"?` It was canceled at its deadline; claim it with \`crtr node bash extend ${t.object.id} --for <duration>\` next time.`:"";return`${r[0].toUpperCase()}${r.slice(1)} was killed${c}${s}.${d} Log: ${String(n["log-path"])}`}default:return e.label}}i(A,"renderPush");function E(e,t){if(t!==null&&t.length<y&&e.ref!==void 0)return`${t.trimEnd()}
4
4
 
5
- ${$(e.ref)}`;const r=y(e);if(r===""){const a=x(e);return a!==null&&e.ref===void 0?R(e,a):e.ref===void 0?e.label:`${e.label}
5
+ ${u(e.ref)}`;const r=j(e);if(r===""){const a=v(e);return a!==null&&e.ref===void 0?A(e,a):e.ref===void 0?e.label:`${e.label}
6
6
 
7
- ${$(e.ref)}`}const{text:o,clipped:n}=h(r);return e.ref!==void 0?`${o}
7
+ ${u(e.ref)}`}const{text:o,clipped:n}=x(r);return e.ref!==void 0?`${o}
8
8
 
9
- ${$(e.ref)}`:n?`${o}
10
- \u2026 (body clipped)`:o}i(E,"renderEntryBody");export{j as INLINE_REPORT_MAX_CHARS,h as clipBody,y as inlineBody,E as renderEntryBody,k as reportRefNodeId};
9
+ ${u(e.ref)}`:n?`${o}
10
+ \u2026 (body clipped)`:o}i(E,"renderEntryBody");export{y as INLINE_REPORT_MAX_CHARS,x as clipBody,j as inlineBody,E as renderEntryBody,k as reportRefNodeId};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@north-light/crouter",
3
- "version": "0.3.354",
3
+ "version": "0.3.356",
4
4
  "description": "crtr — agent runtime with memory, plugins, and marketplaces",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -131,7 +131,7 @@
131
131
  "@earendil-works/pi-ai": "0.87.1",
132
132
  "@earendil-works/pi-coding-agent": "0.87.1",
133
133
  "@earendil-works/pi-tui": "0.87.1",
134
- "@north-light/crouter-identity": "^0.3.354",
134
+ "@north-light/crouter-identity": "^0.3.356",
135
135
  "cron-parser": "^5.6.0",
136
136
  "esbuild": "^0.27.7",
137
137
  "jose": "^6.2.12",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@north-light/crouter-identity",
3
- "version": "0.3.354",
3
+ "version": "0.3.356",
4
4
  "description": "Northlight access-token verification and scope rules",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
package/runtime.lock.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@north-light/crouter",
3
- "version": "0.3.354",
3
+ "version": "0.3.356",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@north-light/crouter",
9
- "version": "0.3.354",
9
+ "version": "0.3.356",
10
10
  "hasInstallScript": true,
11
11
  "license": "GPL-3.0-only",
12
12
  "workspaces": [
@@ -18,7 +18,7 @@
18
18
  "@earendil-works/pi-ai": "0.87.1",
19
19
  "@earendil-works/pi-coding-agent": "0.87.1",
20
20
  "@earendil-works/pi-tui": "0.87.1",
21
- "@north-light/crouter-identity": "^0.3.354",
21
+ "@north-light/crouter-identity": "^0.3.356",
22
22
  "cron-parser": "^5.6.0",
23
23
  "esbuild": "^0.27.7",
24
24
  "jose": "^6.2.12",
@@ -10885,17 +10885,17 @@
10885
10885
  },
10886
10886
  "packages/crouter-api": {
10887
10887
  "name": "@north-light/crouter-api",
10888
- "version": "0.3.354",
10888
+ "version": "0.3.356",
10889
10889
  "license": "GPL-3.0-only"
10890
10890
  },
10891
10891
  "packages/crouter-env-docker": {
10892
10892
  "name": "@north-light/crouter-env-docker",
10893
- "version": "0.3.354",
10893
+ "version": "0.3.356",
10894
10894
  "license": "GPL-3.0-only"
10895
10895
  },
10896
10896
  "packages/crouter-identity": {
10897
10897
  "name": "@north-light/crouter-identity",
10898
- "version": "0.3.354",
10898
+ "version": "0.3.356",
10899
10899
  "license": "GPL-3.0-only",
10900
10900
  "dependencies": {
10901
10901
  "jose": "^6.2.1"
@@ -10903,19 +10903,19 @@
10903
10903
  },
10904
10904
  "packages/crouter-plugin": {
10905
10905
  "name": "@north-light/crouter-plugin",
10906
- "version": "0.3.354",
10906
+ "version": "0.3.356",
10907
10907
  "license": "GPL-3.0-only",
10908
10908
  "dependencies": {
10909
- "@north-light/crouter-api": "^0.3.354"
10909
+ "@north-light/crouter-api": "^0.3.356"
10910
10910
  }
10911
10911
  },
10912
10912
  "packages/crouter-sdk": {
10913
10913
  "name": "@north-light/crouter-sdk",
10914
- "version": "0.3.354",
10914
+ "version": "0.3.356",
10915
10915
  "license": "GPL-3.0-only",
10916
10916
  "dependencies": {
10917
- "@north-light/crouter-api": "^0.3.354",
10918
- "@north-light/crouter-identity": "^0.3.354",
10917
+ "@north-light/crouter-api": "^0.3.356",
10918
+ "@north-light/crouter-identity": "^0.3.356",
10919
10919
  "jose": "^6.2.1"
10920
10920
  }
10921
10921
  }
@@ -1,6 +1,6 @@
1
1
  import { realpathSync } from 'node:fs';
2
2
  import { tmpdir, userInfo } from 'node:os';
3
- import { isAbsolute, relative, sep } from 'node:path';
3
+ import { basename, dirname, isAbsolute, join, relative, sep } from 'node:path';
4
4
 
5
5
  // A node's shell inherits broker identity and pi paths. Neither an installer
6
6
  // nor a test lane is that broker; nested processes must resolve their own roots.
@@ -15,6 +15,12 @@ export function scrubInheritedBrokerEnv(env = process.env) {
15
15
 
16
16
  // A normal host install uses the account HOME. When HOME is overridden, no
17
17
  // working directory or configured write root may still point into that account.
18
+ // A node's shell runs with HOME at its app-space home (`~/.crouter/apps/<app>/home`);
19
+ // that is the account acting through a node, not an isolated home.
20
+ function isAccountAppSpaceHome(home, accountHome) {
21
+ return basename(home) === 'home' && dirname(dirname(home)) === join(accountHome, '.crouter', 'apps');
22
+ }
23
+
18
24
  export function unsafeIsolationReason({ requireTemporaryHome = false, requireCrtrHome = false } = {}) {
19
25
  const inside = (home, target) => {
20
26
  const rel = relative(home, target);
@@ -23,7 +29,7 @@ export function unsafeIsolationReason({ requireTemporaryHome = false, requireCrt
23
29
  try {
24
30
  const home = realpathSync(process.env.HOME);
25
31
  const accountHome = realpathSync(userInfo().homedir);
26
- if (home === accountHome) return requireTemporaryHome ? 'HOME is the account home' : null;
32
+ if (home === accountHome || isAccountAppSpaceHome(home, accountHome)) return requireTemporaryHome ? 'HOME is the account home' : null;
27
33
  if (requireCrtrHome && !process.env.CRTR_HOME) return 'CRTR_HOME is missing';
28
34
  for (const [name, path] of [
29
35
  ['cwd', process.cwd()], ['TMPDIR', tmpdir()],