@north-light/cli 0.3.589 → 0.3.590
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/client.d.ts +4 -1
- package/dist/api/client.js +1 -1
- package/dist/api/contract.d.ts +1 -1
- package/dist/api/contract.js +1 -1
- package/dist/api/dto/docs.d.ts +5 -0
- package/dist/api/dto/settings.d.ts +21 -0
- package/dist/build-root.d.ts +2 -0
- package/dist/build-root.js +1 -1
- package/dist/cli.js +8 -8
- package/dist/clients/attach/viewer.js +468 -468
- package/dist/commands/pkg/app-installs.d.ts +53 -0
- package/dist/commands/pkg/app-installs.js +2 -0
- package/dist/commands/pkg/market-inspect.js +1 -1
- package/dist/commands/pkg/market-manage.js +1 -1
- package/dist/commands/pkg/plugin-inspect.js +1 -1
- package/dist/commands/pkg/plugin-manage.js +13 -13
- package/dist/core/canvas/schema-pg/011-package-revision.sql +12 -0
- package/dist/core/canvas/schema-version.d.ts +1 -1
- package/dist/core/canvas/schema-version.js +1 -1
- package/dist/core/config.d.ts +1 -0
- package/dist/core/config.js +1 -1
- package/dist/core/graph/names.js +8 -8
- package/dist/core/graph/package-docs.d.ts +6 -15
- package/dist/core/graph/package-docs.js +8 -6
- package/dist/core/graph/package-publish.d.ts +35 -5
- package/dist/core/graph/package-publish.js +3 -3
- package/dist/core/graph/package-reconcile.d.ts +20 -1
- package/dist/core/graph/package-reconcile.js +3 -1
- package/dist/core/import/export/dump.js +4 -3
- package/dist/core/import/load/stores.js +2 -2
- package/dist/core/installed-plugins.js +1 -1
- package/dist/core/packages/directory-sync.d.ts +41 -0
- package/dist/core/packages/directory-sync.js +6 -0
- package/dist/core/packages/eligibility.d.ts +16 -0
- package/dist/core/packages/eligibility.js +4 -0
- package/dist/core/packages/launch-kinds.d.ts +6 -0
- package/dist/core/packages/launch-kinds.js +2 -0
- package/dist/core/packages/source-url.d.ts +3 -0
- package/dist/core/packages/source-url.js +1 -0
- package/dist/core/permissions/ceiling.d.ts +9 -2
- package/dist/core/permissions/ceiling.js +11 -12
- package/dist/core/permissions/evaluator.js +2 -2
- package/dist/core/runtime/launch-config-worker.js +1 -1
- package/dist/core/runtime/launch-target.d.ts +6 -2
- package/dist/core/runtime/launch-target.js +1 -1
- package/dist/core/runtime/launch.d.ts +8 -1
- package/dist/core/runtime/launch.js +2 -2
- package/dist/core/runtime/promote.js +1 -1
- package/dist/core/runtime/recycle.js +1 -1
- package/dist/core/runtime/reset.js +1 -1
- package/dist/core/runtime/spawn.js +2 -2
- package/dist/core/runtime/warm-pool.js +1 -1
- package/dist/core/scoped-state/legacy-profiles.js +1 -1
- package/dist/core/scoped-state/migrate-app-installs.d.ts +13 -0
- package/dist/core/scoped-state/migrate-app-installs.js +1 -0
- package/dist/core/scoped-state/person-rows.js +4 -6
- package/dist/core/scoped-state/person-store.d.ts +23 -0
- package/dist/core/scoped-state/person-store.js +1 -1
- package/dist/daemon/api/handlers/execution-start.d.ts +2 -0
- package/dist/daemon/api/handlers/execution-start.js +2 -2
- package/dist/daemon/api/handlers/nodes.js +1 -1
- package/dist/daemon/api/handlers/package-docs.d.ts +1 -1
- package/dist/daemon/api/handlers/package-docs.js +1 -1
- package/dist/daemon/api/handlers/settings.d.ts +4 -1
- package/dist/daemon/api/handlers/settings.js +1 -1
- package/dist/daemon/crtrd.js +19 -19
- package/package.json +2 -2
- package/packages/crouter-identity/package.json +1 -1
- package/runtime.lock.json +13 -13
- package/dist/core/graph/package-kinds.d.ts +0 -22
- package/dist/core/graph/package-kinds.js +0 -1
- package/dist/core/scoped-state/materialized-plugins.d.ts +0 -20
- package/dist/core/scoped-state/materialized-plugins.js +0 -1
|
@@ -0,0 +1,41 @@
|
|
|
1
|
+
import { type PublishReport } from '../graph/package-publish.js';
|
|
2
|
+
export interface DirectoryPackage {
|
|
3
|
+
name: string;
|
|
4
|
+
origin: 'plugin' | 'provider';
|
|
5
|
+
source: string | null;
|
|
6
|
+
revision: number;
|
|
7
|
+
digest: string;
|
|
8
|
+
version: string;
|
|
9
|
+
kinds: Record<string, never> | null;
|
|
10
|
+
object_kinds: Record<string, never> | null;
|
|
11
|
+
files: Array<{
|
|
12
|
+
path: string;
|
|
13
|
+
text: string;
|
|
14
|
+
}>;
|
|
15
|
+
}
|
|
16
|
+
/** Why a name has no documents. `name_taken` carries the holder's source. */
|
|
17
|
+
export type FetchOutcome = {
|
|
18
|
+
ok: true;
|
|
19
|
+
pkg: DirectoryPackage;
|
|
20
|
+
} | {
|
|
21
|
+
ok: true;
|
|
22
|
+
notModified: true;
|
|
23
|
+
} | {
|
|
24
|
+
ok: false;
|
|
25
|
+
reason: 'name_taken';
|
|
26
|
+
holder?: string;
|
|
27
|
+
} | {
|
|
28
|
+
ok: false;
|
|
29
|
+
reason: 'not_public' | 'not_found' | 'unavailable';
|
|
30
|
+
};
|
|
31
|
+
export declare const getPackage: (name: string, etag?: string) => Promise<FetchOutcome>;
|
|
32
|
+
export declare const resolvePackage: (sourceUrl: string, name: string) => Promise<FetchOutcome>;
|
|
33
|
+
/** Publish a directory package body. The files are written to a temporary directory only to be read by the one package reader. */
|
|
34
|
+
export declare function publishDirectoryPackage(pkg: DirectoryPackage): Promise<PublishReport>;
|
|
35
|
+
/** Resolve one install now (the install route). Publishes on success. */
|
|
36
|
+
export declare function syncInstall(name: string, url: string): Promise<{
|
|
37
|
+
out: FetchOutcome;
|
|
38
|
+
published?: PublishReport;
|
|
39
|
+
}>;
|
|
40
|
+
/** One package-sync pass. Called after each grant sync on the api role. */
|
|
41
|
+
export declare function syncPackages(): Promise<void>;
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
var S=Object.defineProperty;var i=(e,n)=>S(e,"name",{value:n,configurable:!0});import{mkdtempSync as A,mkdirSync as I,rmSync as N,writeFileSync as $}from"node:fs";import{tmpdir as O}from"node:os";import{dirname as T,join as m}from"node:path";import{withCanvasWrite as w,openDb as x}from"../canvas/db.js";import{emitEvent as d}from"../events/emit.js";import{outboundFetch as j}from"../events/outbound.js";import{directoryIssuer as g}from"../directory/issuer.js";import{allGrants as D,providerIdsFromGrants as M}from"../grants/mirror.js";import{mintDirectoryToken as P}from"../grants/sync.js";import{publish as R,readPackageSnapshot as F,withdraw as W}from"../graph/package-publish.js";import{normalizeSourceUrl as k}from"./source-url.js";const L=25e3,C=15e3;async function h(e,n){const o=g();if(o===null)return{ok:!1,reason:"unavailable"};try{const t=await P(o),r=await j("package_sync",`${o}${e}`,{method:n.method,headers:{Authorization:`Bearer ${t.access_token}`,...n.body===void 0?{}:{"content-type":"application/json"},...n.etag===void 0?{}:{"If-None-Match":`"${n.etag}"`}},...n.body===void 0?{}:{body:JSON.stringify(n.body)},signal:AbortSignal.timeout(n.wait)});if(r.status===304)return{ok:!0,notModified:!0};if(r.status===404)return{ok:!1,reason:"not_found"};if(r.status===409){const l=await r.json().catch(()=>({}));return(l.error?.code??l.code)==="name_taken"?{ok:!1,reason:"name_taken",holder:l.error?.details?.holder_source??l.error?.holder_source??l.holder_source}:{ok:!1,reason:"not_public"}}return r.ok?{ok:!0,pkg:await r.json()}:{ok:!1,reason:"unavailable"}}catch(t){return d({level:"warn",event:"daemon.packages.fetch_failed",fields:{path:e},error:t}),{ok:!1,reason:"unavailable"}}}i(h,"call");const y=i((e,n)=>h(`/v1/packages/${encodeURIComponent(e)}`,{method:"GET",etag:n,wait:C}),"getPackage"),v=i((e,n)=>h("/v1/packages/resolve",{method:"POST",body:{source_url:e,name:n},wait:L}),"resolvePackage");async function _(e){const n=A(m(O(),"crtr-pkg-"));try{for(const t of e.files){const r=m(n,t.path);if(!r.startsWith(`${n}/`))throw new Error(`package file escapes its folder: ${t.path}`);I(T(r),{recursive:!0}),$(r,t.text)}const o={...F(n,{app:e.name,origin:e.origin,version:e.version,revision:e.revision,source:e.source===null?null:k(e.source),launchKinds:e.kinds,objectKinds:e.object_kinds}),digest:e.digest};return await w(async t=>await R(t,o,"package-sync"))}finally{N(n,{recursive:!0,force:!0})}}i(_,"publishDirectoryPackage");async function G(e){return await e.prepare(`SELECT p.name, m.url FROM scope_plugins p LEFT JOIN scope_marketplaces m
|
|
2
|
+
ON m.person = p.person AND m.owner_key = p.owner_key AND m.name = p.source_marketplace
|
|
3
|
+
WHERE p.owner_key LIKE 'app:%' AND p.enabled = 1`).all()}i(G,"wantedPlugins");async function J(e){return(await e.prepare(`SELECT i.external_id, p.origin, p.source, p.digest, p.withdrawn_at FROM package_publications p
|
|
4
|
+
JOIN identities i ON i.object = p.app AND i.scheme = 'app' WHERE p.origin <> 'builtin'`).all()).map(o=>({name:o.external_id.replace(/^app:/,""),origin:o.origin,source:o.source,digest:o.digest,withdrawn:o.withdrawn_at!==null}))}i(J,"publications");async function ne(e,n){const o=await v(n,e);return"pkg"in o?{out:o,published:await _(o.pkg)}:{out:o}}i(ne,"syncInstall");async function p(e){const n=await _(e);for(const o of n.invalid)d({level:"error",event:"daemon.packages.invalid_file",fields:{app:e.name,path:o.path,error:o.error}});for(const o of n.kinds.refused)d({level:"warn",event:"daemon.packages.kind_refused",fields:{app:e.name,kind:o.kind,message:o.message}})}i(p,"publishAndReport");const b=new Set;function E(e,n,o){if(o.ok)return;const t=`${e}
|
|
5
|
+
${n}
|
|
6
|
+
${o.reason}`;b.has(t)||(b.add(t),o.reason!=="unavailable"&&d({level:"warn",event:"daemon.packages.resolve_refused",fields:{name:e,source:n??"",reason:o.reason}}))}i(E,"refused");async function oe(){if(g()===null)return;const e=await x(),n=await D(),o=M(n),t=await G(e),r=new Map((await J(e)).map(a=>[a.name,a])),l=new Set([...o,...t.map(a=>a.name)]);for(const a of t){const s=r.get(a.name),c=a.url===null?null:k(a.url);if(c!==null&&(s===void 0||s.withdrawn||s.source!==c)){const u=await v(c,a.name);"pkg"in u?await p(u.pkg):E(a.name,c,u)}}for(const a of l){const s=r.get(a);if(s===void 0||s.withdrawn){if(o.includes(a)){const u=await y(a);"pkg"in u?await p(u.pkg):E(a,null,u)}continue}const c=await y(a,s.digest);"pkg"in c&&await p(c.pkg)}const f=n.some(a=>a.status==="active");for(const[a,s]of r)s.withdrawn||l.has(a)||s.origin==="provider"&&!f||await w(async c=>{await W(c,a)})}i(oe,"syncPackages");export{y as getPackage,_ as publishDirectoryPackage,v as resolvePackage,ne as syncInstall,oe as syncPackages};
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/** The read rule for shipped package documents: which published package apps a reader may read the documents of.
|
|
2
|
+
* `crtr` (builtin) always; a provider when the reader's scopes hold a scope of it; a plugin on a Mac always (the local install set is the Mac's
|
|
3
|
+
* own), on a cloud role when the reader's app has it enabled from the marketplace the publication was read from. The ceiling applies the set to
|
|
4
|
+
* every shipped document whichever root admitted it. */
|
|
5
|
+
import type { CanvasDb } from '../canvas/db.js';
|
|
6
|
+
export interface EligibilityInput {
|
|
7
|
+
/** whether the reader's scopes hold a scope of the provider app with this external id (`app:<id>`) */
|
|
8
|
+
holdsProvider: (appExt: string) => boolean;
|
|
9
|
+
cloud: boolean;
|
|
10
|
+
/** the reader's app external id (`app:<id>`), null when the app has none */
|
|
11
|
+
ownExt: string | null;
|
|
12
|
+
/** the bare user id the reader acts for; null for a reader that acts for no person */
|
|
13
|
+
user: string | null;
|
|
14
|
+
}
|
|
15
|
+
/** Object ids of the live published package apps the reader may read the shipped documents of. */
|
|
16
|
+
export declare function eligiblePackageApps(db: CanvasDb, input: EligibilityInput): Promise<string[]>;
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
var t=Object.defineProperty;var n=(l,r)=>t(l,"name",{value:r,configurable:!0});import{normalizeSourceUrl as c}from"./source-url.js";async function f(l,r){const s=await l.prepare(`SELECT p.app, p.origin, p.source, i.external_id FROM package_publications p
|
|
2
|
+
JOIN identities i ON i.object = p.app AND i.scheme = 'app' WHERE p.withdrawn_at IS NULL`).all();let p=null;const i=n(async()=>{if(p!==null||(p=new Map,r.user===null||r.ownExt===null))return p;const e=await l.prepare(`SELECT p.name, m.url FROM scope_plugins p JOIN scope_marketplaces m
|
|
3
|
+
ON m.person = p.person AND m.owner_key = p.owner_key AND m.name = p.source_marketplace
|
|
4
|
+
WHERE p.person = ? AND p.owner_key = ? AND p.enabled = 1 AND m.url IS NOT NULL`).all(`user:${r.user}`,r.ownExt);for(const o of e)p.set(o.name,c(o.url));return p},"installs"),a=[];for(const e of s)e.origin==="builtin"?a.push(e.app):e.origin==="provider"?r.holdsProvider(e.external_id)&&a.push(e.app):r.cloud?e.source!==null&&(await i()).get(e.external_id.replace(/^app:/,""))===e.source&&a.push(e.app):a.push(e.app);return a}n(f,"eligiblePackageApps");export{f as eligiblePackageApps};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
/** The launch `kinds` a cloud role layers into a node's launch config: those of the plugins enabled in the node's app whose published package was
|
|
2
|
+
* read from the marketplace the app installed it from. A cloud role holds no plugin directories, so the publication rows are the only source. */
|
|
3
|
+
import type { CanvasDb } from '../canvas/db.js';
|
|
4
|
+
import type { PersonSnapshot } from '../scoped-state/person-store.js';
|
|
5
|
+
/** Launch kinds by plugin name for the plugins enabled in `app`, from live publication rows whose `source` is the install's marketplace. */
|
|
6
|
+
export declare function appLaunchKinds(db: CanvasDb, snapshot: PersonSnapshot, app: string): Promise<Record<string, unknown>>;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var u=Object.defineProperty;var c=(e,n)=>u(e,"name",{value:n,configurable:!0});import{normalizeSourceUrl as l}from"./source-url.js";async function _(e,n,s){const i=n.apps[s];if(i===void 0)return{};const r={};for(const[o,a]of Object.entries(i.plugins)){if(a.enabled===!1||a.source_marketplace===void 0)continue;const t=i.marketplaces[a.source_marketplace]?.url;if(t===void 0)continue;const p=await e.prepare(`SELECT p.source, p.launch_kinds_json FROM package_publications p JOIN identities i ON i.object = p.app AND i.scheme = 'app'
|
|
2
|
+
WHERE i.external_id = ? AND p.origin = 'plugin' AND p.withdrawn_at IS NULL AND p.launch_kinds_json IS NOT NULL`).get(`app:${o}`);p!==void 0&&p.source===l(t)&&(r[o]=JSON.parse(p.launch_kinds_json))}return r}c(_,"appLaunchKinds");export{_ as appLaunchKinds};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
/** A marketplace git URL as the directory normalizes it: lowercased host, no `.git` suffix, no trailing slash. A plugin package is published
|
|
2
|
+
* with this URL as its `source`, and the read rule matches an install's marketplace URL against it. */
|
|
3
|
+
export declare function normalizeSourceUrl(url: string): string;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var c=Object.defineProperty;var n=(o,t)=>c(o,"name",{value:t,configurable:!0});function s(o){const t=o.trim();let r;try{const e=new URL(t);e.hostname=e.hostname.toLowerCase(),r=e.toString()}catch{const e=/^([^@\s]+@)?([^:/\s]+):(.+)$/.exec(t);r=e===null?t:`${e[1]??""}${e[2].toLowerCase()}:${e[3]}`}return r.replace(/\/+$/,"").replace(/\.git$/,"").replace(/\/+$/,"")}n(s,"normalizeSourceUrl");export{s as normalizeSourceUrl};
|
|
@@ -28,6 +28,9 @@ export interface Ceiling {
|
|
|
28
28
|
/** App object ids for the `authored:` match (first-revision author rule): the caller's app and every first-party app, one whose grant holds
|
|
29
29
|
* `crtr:memory:manage:user` always. A revoked first-party grant still counts: revocation stops its calls, not who wrote the document. */
|
|
30
30
|
authorApps: string[];
|
|
31
|
+
/** The read rule for shipped package documents: the published package apps (object ids) whose shipped documents the reader may read. A shipped document
|
|
32
|
+
* (`documents.source_path` set) passes only when its owner is in this set, whichever root admitted it. Null: no read is asked, nothing is narrowed. */
|
|
33
|
+
packageApps: string[] | null;
|
|
31
34
|
}
|
|
32
35
|
export type Access = 'read' | 'write' | 'message';
|
|
33
36
|
export interface CeilingOptions {
|
|
@@ -38,8 +41,12 @@ export interface CeilingOptions {
|
|
|
38
41
|
export declare function personObjectIds(db: CanvasDb): Promise<string[]>;
|
|
39
42
|
/** Whether `scopes` hold a provider-group scope `<provider>:<group>` of the app whose external id is `appExt`: what lets a run read that app's private objects. */
|
|
40
43
|
export declare function holdsProviderGroup(scopes: readonly string[], appExt: string): boolean;
|
|
41
|
-
/** The
|
|
42
|
-
|
|
44
|
+
/** The published package apps whose shipped documents `reader` may read (the read rule); null for a person reader, who reads every package. `user` is the
|
|
45
|
+
* bare user id the reader acts for, null for a reader that acts for no person. A revoked grant (null scopes) holds no provider scope. */
|
|
46
|
+
export declare function readablePackageApps(db: CanvasDb, reader: Reader, user: string | null): Promise<string[] | null>;
|
|
47
|
+
/** The ceiling of `reader` for `access`; null for a person reader (no ceiling). `user` is the bare user id the reader acts for (`readerUser`), null for a
|
|
48
|
+
* reader that acts for no person: it reads the package apps every reader reads and the providers its scopes hold, never a plugin. */
|
|
49
|
+
export declare function resolveCeiling(db: CanvasDb, reader: Reader, user: string | null, access: Access, options?: CeilingOptions): Promise<Ceiling | null>;
|
|
43
50
|
export interface RunPlace {
|
|
44
51
|
run: string;
|
|
45
52
|
isolated: boolean;
|
|
@@ -1,22 +1,21 @@
|
|
|
1
|
-
var
|
|
2
|
-
WHERE g.resolved_scopes_json::jsonb @> '[{"scope":"crtr:memory:manage:user","mode":"always"}]'::jsonb`).all()).map(
|
|
3
|
-
SELECT 1 FROM objects o JOIN documents d ON d.object = o.id WHERE o.owner = a.id AND o.type = 'document' AND o.deleted_at IS NULL AND d.source_path IS NOT NULL)`).all();for(const r of a)r.id!==e.app.id&&p.roots.push({id:r.id,private:!1,match:"shipped"});for(const r of await t.prepare("SELECT o.id, i.external_id FROM objects o JOIN identities i ON i.object = o.id AND i.scheme = 'app' WHERE o.type = 'app' AND o.deleted_at IS NULL").all())r.id!==e.app.id&&p.roots.push({id:r.id,private:D(c,r.external_id),match:"custom"})}if(n!=="message")for(const a of await k(t,e,n==="write"?"rw":"read"))p.roots.push({id:a,private:n==="read",match:"any"});return p}s(G,"resolveCeiling");async function X(t,e){return(await t.prepare("SELECT namespace FROM schemas WHERE app = ?").all(e)).map(n=>n.namespace)}s(X,"ownNamespaces");async function L(t,e){const n=await t.prepare("SELECT run_id, isolated FROM nodes WHERE node_id = ?").get(e);if(n!==void 0)return{run:n.run_id??e,isolated:n.isolated===1};const d=await t.prepare("SELECT run_id FROM deleted_isolated_nodes WHERE node_id = ?").get(e);return d?{run:d.run_id,isolated:!0}:null}s(L,"nodePlace");async function K(t,e){const n=await L(e,t);n?.isolated&&await e.prepare("INSERT INTO deleted_isolated_nodes (node_id, run_id) VALUES (?, ?) ON CONFLICT (node_id) DO UPDATE SET run_id = excluded.run_id").run(t,n.run)}s(K,"rememberDeletedIsolated");function q(t){return t.class==="person"?t:{...t,launched:null}}s(q,"asRuntimeWriter");async function Q(t,e,n,d,p=!1){if(e.class==="person"||e.launched===void 0||e.launched===null)return null;const c=await t.prepare(`WITH RECURSIVE c(id, owner, type, kind, depth) AS (
|
|
1
|
+
var b=Object.defineProperty;var c=(t,e)=>b(t,"name",{value:e,configurable:!0});import{covers as O}from"@north-light/identity";import{isCloudRole as j}from"../canvas/person-state.js";import{eligiblePackageApps as x}from"../packages/eligibility.js";import{fileRoot as F}from"../spaces/file-root.js";import{FALSE as M,TRUE as I,and as U,f as h,or as D,raw as d}from"./sql.js";const k=c(t=>({ownApp:t,roots:[],namespaces:[],place:null,predicates:{allNodes:!1,spaces:!1},authorApps:[],packageApps:null}),"empty");async function S(t,e){return(await t.prepare("SELECT external_id FROM identities WHERE object = ? ORDER BY scheme LIMIT 1").get(e))?.external_id??null}c(S,"externalId");async function L(t,e,i){return(await t.prepare("SELECT o.id FROM identities i JOIN objects o ON o.id = i.object WHERE i.scheme = ? AND i.external_id = ? AND o.deleted_at IS NULL").get(e,i))?.id??null}c(L,"objectOf");async function J(t){return(await t.prepare("SELECT id FROM objects WHERE type = 'person' AND home_machine IS NULL AND deleted_at IS NULL ORDER BY created_at").all()).map(i=>i.id)}c(J,"personObjectIds");async function P(t){return(await t.prepare(`SELECT DISTINCT i.object AS id FROM grants g JOIN identities i ON i.external_id = g.grantee AND i.scheme = 'app'
|
|
2
|
+
WHERE g.resolved_scopes_json::jsonb @> '[{"scope":"crtr:memory:manage:user","mode":"always"}]'::jsonb`).all()).map(i=>i.id)}c(P,"firstPartyApps");function y(t,e){return X(t).has(e.replace(/^app:/,""))}c(y,"holdsProviderGroup");const g=new WeakMap;function X(t){let e=g.get(t);if(e===void 0){e=new Set;for(const i of t){const n=i.indexOf(":");n>=0&&!i.includes(":",n+1)&&e.add(i.slice(0,n))}g.set(t,e)}return e}c(X,"providerGroupHolders");async function z(t,e,i){if(e.class==="object")return e.repos.map(o=>o.id);if(e.class!=="node")return[];const n=await S(t,e.app.id);if(n===null)return[];const N={app:n,resolved:e.scopes??[],launched:null},r=new Set;for(const o of[...e.checkouts,...e.projectCheckouts])"root"in F(N,o.root,i)&&r.add(o.repo.id);return[...r]}c(z,"repoRoots");async function Y(t,e,i){if(e.class==="person")return null;const n=e.scopes;return await x(t,{holdsProvider:c(N=>n!==null&&y(n,N),"holdsProvider"),cloud:j(),ownExt:await S(t,e.app.id),user:i})}c(Y,"readablePackageApps");async function ne(t,e,i,n,N={}){if(e.class==="person")return null;const r=k(e.app.id),o=e.scopes,E=c(a=>o!==null&&o.some(p=>O(p,a)),"has"),l=await S(t,e.app.id),w=e.class==="node"?await R(t,e.node.id):e.place??null;r.place=w,r.authorApps=[e.app.id];const s=n==="write"?"rw":"read",f=e.launched,$=c((a,p,u=!0)=>{r.roots.push({id:a,private:u,match:p})},"own");if(n==="message"||f===void 0||f===null||l===null||f.some(a=>O(a,`crtr:memory:${s}:${l}`)))$(e.app.id,"any"),l!==null&&(r.namespaces=await Z(t,l));else{$(e.app.id,"non-document"),n==="read"&&w!==null&&$(e.app.id,"run-report");for(const a of await t.prepare("SELECT o.id, i.external_id FROM objects o JOIN identities i ON i.object = o.id AND i.scheme = 'profile' WHERE o.owner = ? AND o.type = 'profile' AND o.deleted_at IS NULL").all(e.app.id))f.some(p=>O(p,`crtr:memory:${s}:${l}:profile:${a.external_id}`))&&$(a.id,"no-node")}if(n==="read"&&(r.packageApps=await Y(t,e,i)??[]),o===null)return r;r.predicates.spaces=!0;const H=await J(t),_=E("crtr:memory:manage:user"),T=_||E("crtr:memory:read_private:user"),m=c((a,p)=>{for(const u of H)u!==e.app.id&&r.roots.push({id:u,private:p,match:a})},"addPerson");if(n==="write")if(_)m("any",!0);else{E("crtr:memory:rw:user")&&(m("self",!0),m("authored:*",!0));for(const a of o){const p=/^crtr:memory:rw:user:(.+)$/.exec(a);p!==null&&m(`authored:${p[1]}`,!0)}E("crtr:objects:write:user")&&m("any",!0),r.roots.some(a=>a.match.startsWith("authored:"))&&r.authorApps.push(...await P(t))}else n==="read"&&(_?m("any",!0):m("direct-doc",T),E(`crtr:objects:${N.verb??"read"}:user`)&&m("any",T));const W=n==="write"?"write":N.verb??"read",v=e.class==="object"&&e.object.type.includes("."),A=c(async(a,p)=>{const u=await L(t,"app",a);u===null||u===e.app.id||r.roots.push({id:u,private:y(o,a),match:p})},"appRoot");for(const a of o){if(!a.startsWith("crtr:"))continue;let p=/^crtr:memory:(read|rw):app:([A-Za-z0-9_-]{1,64})(?::profile:([A-Za-z0-9_-]{1,64}))?$/.exec(a);if(p!==null&&(n==="read"||n==="write"&&p[1]==="rw")){if(p[3]===void 0)await A(`app:${p[2]}`,"no-node");else{const u=await L(t,"profile",p[3]);u!==null&&r.roots.push({id:u,private:!1,match:"no-node"})}continue}if(p=/^crtr:objects:(read|watch|link|write):(user|node|profile:[A-Za-z0-9_-]+|app:[A-Za-z0-9_-]+)$/.exec(a),p!==null&&n!=="message"&&(p[1]===W||n==="read"&&v&&p[1]==="watch")){const u=p[2];if(u==="node")r.predicates.allNodes=!0;else if(u.startsWith("profile:")){const C=await L(t,"profile",u.slice(8));C!==null&&r.roots.push({id:C,private:!1,match:"below"})}else u.startsWith("app:")&&await A(u,"objects-app");continue}if(p=/^crtr:conversations:read:(app:[A-Za-z0-9_-]+)$/.exec(a),p!==null&&n==="read"){await A(p[1],"node-report"),await A(p[1],"run-node");continue}p=/^crtr:objects:message:(app:[A-Za-z0-9_-]+)$/.exec(a),p!==null&&n==="message"&&await A(p[1],"node-tree")}if(n==="read"){for(const a of r.packageApps??[])a!==e.app.id&&r.roots.push({id:a,private:!1,match:"shipped"});for(const a of await t.prepare("SELECT o.id, i.external_id FROM objects o JOIN identities i ON i.object = o.id AND i.scheme = 'app' WHERE o.type = 'app' AND o.deleted_at IS NULL").all())a.id!==e.app.id&&r.roots.push({id:a.id,private:y(o,a.external_id),match:"custom"})}if(n!=="message")for(const a of await z(t,e,n==="write"?"rw":"read"))r.roots.push({id:a,private:n==="read",match:"any"});return r}c(ne,"resolveCeiling");async function Z(t,e){return(await t.prepare("SELECT namespace FROM schemas WHERE app = ?").all(e)).map(i=>i.namespace)}c(Z,"ownNamespaces");async function R(t,e){const i=await t.prepare("SELECT run_id, isolated FROM nodes WHERE node_id = ?").get(e);if(i!==void 0)return{run:i.run_id??e,isolated:i.isolated===1};const n=await t.prepare("SELECT run_id FROM deleted_isolated_nodes WHERE node_id = ?").get(e);return n?{run:n.run_id,isolated:!0}:null}c(R,"nodePlace");async function oe(t,e){const i=await R(e,t);i?.isolated&&await e.prepare("INSERT INTO deleted_isolated_nodes (node_id, run_id) VALUES (?, ?) ON CONFLICT (node_id) DO UPDATE SET run_id = excluded.run_id").run(t,i.run)}c(oe,"rememberDeletedIsolated");function ie(t){return t.class==="person"?t:{...t,launched:null}}c(ie,"asRuntimeWriter");async function re(t,e,i,n,N=!1){if(e.class==="person"||e.launched===void 0||e.launched===null)return null;const r=await t.prepare(`WITH RECURSIVE c(id, owner, type, kind, depth) AS (
|
|
4
3
|
SELECT id, owner, type, kind, 0 FROM objects WHERE id = ? UNION ALL
|
|
5
4
|
SELECT p.id, p.owner, p.type, p.kind, c.depth + 1 FROM c JOIN objects p ON p.id = c.owner WHERE c.depth < 12)
|
|
6
|
-
SELECT c.id, c.type, c.kind FROM c ORDER BY c.depth`).all(
|
|
7
|
-
SELECT ${
|
|
5
|
+
SELECT c.id, c.type, c.kind FROM c ORDER BY c.depth`).all(i);if(r[r.length-1]?.id!==e.app.id)return null;const o=await S(t,e.app.id);if(o===null)return null;if(r.length===1)return N?e.launched.some(s=>O(s,`crtr:memory:${n}:${o}`))?null:`crtr:memory:${n}:${o}`:null;if(!N&&r[0].type!=="document")return null;const E=r.slice(0,-1).reverse();if(n==="read"&&!N&&r[0].kind==="report"&&E[0].type==="node"&&e.class!=="object"){const s=e.class==="node"?await R(t,e.node.id):e.place??null,f=await R(t,E[0].id);if(s!==null&&f!==null&&s.run===f.run)return null}const l=E[0],w=l.type==="profile"?`crtr:memory:${n}:${o}:profile:${await S(t,l.id)}`:`crtr:memory:${n}:${o}`;return e.launched.some(s=>O(s,w))?null:w}c(re,"missingMemoryScope");function ae(t,e){const i=[];t.roots.length>0&&i.push(B(t,e)),t.namespaces.length>0&&i.push(h`split_part(${d(e)}.schema_type, '/', 1) = ANY(${t.namespaces}::text[])`),t.predicates.allNodes&&i.push(d(`(${e}.type = 'node' AND ${e}.privacy = 'public')`)),t.predicates.spaces&&i.push(d(`(${e}.owner IS NULL AND ${e}.type IN ('app','person','repo'))`));const n=t.packageApps===null?I:h`(NOT EXISTS (SELECT 1 FROM documents sd WHERE sd.object = ${d(e)}.id AND sd.source_path IS NOT NULL) OR ${d(e)}.owner = ANY(${t.packageApps}::text[]))`;return U([D(i),V(t,e),n])}c(ae,"ceilingFrag");function V(t,e){if(t.place===null)return I;const i=t.place.isolated?1:0;return h`NOT EXISTS (WITH RECURSIVE ca(id, owner, depth, near_node) AS (
|
|
6
|
+
SELECT ${d(e)}.id, ${d(e)}.owner, 0, CASE WHEN ${d(e)}.type = 'node' THEN ${d(e)}.id END
|
|
8
7
|
UNION ALL
|
|
9
8
|
SELECT p.id, p.owner, ca.depth + 1, COALESCE(ca.near_node, CASE WHEN p.type = 'node' THEN p.id END)
|
|
10
9
|
FROM ca JOIN objects p ON p.id = ca.owner WHERE ca.depth < 12)
|
|
11
10
|
SELECT 1 FROM ca LEFT JOIN nodes cn ON cn.node_id = ca.near_node LEFT JOIN deleted_isolated_nodes cd ON cd.node_id = ca.near_node
|
|
12
11
|
WHERE ca.id = ${t.ownApp} AND ca.depth > 0 AND ca.near_node IS NOT NULL
|
|
13
|
-
AND NOT (CASE WHEN cn.node_id IS NOT NULL THEN COALESCE(cn.run_id, cn.node_id) = ${t.place.run} OR (cn.isolated = 0 AND ${
|
|
14
|
-
WHEN cd.node_id IS NOT NULL THEN cd.run_id = ${t.place.run} ELSE ${
|
|
15
|
-
WHERE rv.document = ${
|
|
16
|
-
AND (au.type = 'person' OR COALESCE((SELECT app FROM nodes WHERE node_id = au.id), au.owner) = ANY(${t.authorApps}::text[]))))`)}const
|
|
17
|
-
SELECT ${
|
|
12
|
+
AND NOT (CASE WHEN cn.node_id IS NOT NULL THEN COALESCE(cn.run_id, cn.node_id) = ${t.place.run} OR (cn.isolated = 0 AND ${i} = 0)
|
|
13
|
+
WHEN cd.node_id IS NOT NULL THEN cd.run_id = ${t.place.run} ELSE ${i} = 0 END))`}c(V,"placeFrag");function B(t,e){const i=t.roots.map(s=>s.id),n=t.roots.map(s=>s.private?1:0),N=t.roots.map(s=>s.match),r=new Set(t.roots.map(s=>s.match)),o=c(s=>`${e}.${s}`,"O"),E=[],l=c((s,f)=>{r.has(s)&&E.push(h`(r.match = ${s} AND ${typeof f=="string"?d(f):f})`)},"t");l("any","TRUE"),l("below","ca.depth > 0"),l("direct-doc",`(ca.depth = 0 OR (ca.depth = 1 AND ${o("type")} = 'document'))`),l("no-node","NOT ca.node_below"),l("node-tree","ca.node_below"),l("objects-app",`(ca.node_below OR ${o("type")} LIKE '%.%')`),l("node-report",`(ca.node_below AND ${o("type")} = 'document' AND ${o("kind")} = 'report')`),l("run-node",`(${o("type")} = 'node' AND EXISTS (SELECT 1 FROM nodes rn WHERE rn.node_id = ${o("id")} AND rn.run_id IS NOT NULL))`),l("custom",`${o("type")} LIKE '%.%'`),l("shipped",`(ca.depth > 0 AND EXISTS (SELECT 1 FROM documents sd WHERE sd.object = ${o("id")} AND sd.source_path IS NOT NULL))`),l("non-document",`(${o("type")} <> 'document')`),l("self","ca.depth = 0"),r.has("run-report")&&E.push(t.place===null?M:h`(r.match = 'run-report' AND ${d(o("type"))} = 'document' AND ${d(o("kind"))} = 'report' AND EXISTS (SELECT 1 FROM nodes rn WHERE rn.node_id = ca.near_node AND COALESCE(rn.run_id, rn.node_id) = ${t.place.run}))`);for(const s of r)if(s.startsWith("authored:")){const f=s.slice(9);E.push(h`(r.match = ${s} AND ca.depth = 1 AND ${d(o("type"))} = 'document' AND ${f==="*"?d("TRUE"):h`${d(o("name"))} = ${f}`} AND EXISTS (SELECT 1 FROM revisions rv JOIN objects au ON au.id = rv.author
|
|
14
|
+
WHERE rv.document = ${d(o("id"))} AND rv.number = (SELECT min(number) FROM revisions WHERE document = ${d(o("id"))})
|
|
15
|
+
AND (au.type = 'person' OR COALESCE((SELECT app FROM nodes WHERE node_id = au.id), au.owner) = ANY(${t.authorApps}::text[]))))`)}const w=D(E);return h`EXISTS (WITH RECURSIVE ca(id, owner, type, depth, node_below, near_node) AS (
|
|
16
|
+
SELECT ${d(o("id"))}, ${d(o("owner"))}, ${d(o("type"))}, 0, FALSE, CASE WHEN ${d(o("type"))} = 'node' THEN ${d(o("id"))} END
|
|
18
17
|
UNION ALL
|
|
19
18
|
SELECT p.id, p.owner, p.type, ca.depth + 1, ca.node_below OR ca.type = 'node', COALESCE(ca.near_node, CASE WHEN p.type = 'node' THEN p.id END)
|
|
20
19
|
FROM ca JOIN objects p ON p.id = ca.owner WHERE ca.depth < 12)
|
|
21
|
-
SELECT 1 FROM ca JOIN unnest(${
|
|
22
|
-
WHERE (${
|
|
20
|
+
SELECT 1 FROM ca JOIN unnest(${i}::text[], ${n}::int[], ${N}::text[]) AS r(id, priv, match) ON r.id = ca.id
|
|
21
|
+
WHERE (${d(o("privacy"))} = 'public' OR r.priv = 1) AND ${w})`}c(B,"rootsFrag");export{ie as asRuntimeWriter,ae as ceilingFrag,y as holdsProviderGroup,re as missingMemoryScope,R as nodePlace,J as personObjectIds,Y as readablePackageApps,oe as rememberDeletedIsolated,ne as resolveCeiling};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
var
|
|
1
|
+
var b=Object.defineProperty;var o=(e,t)=>b(e,"name",{value:t,configurable:!0});import{isCloudRole as j,personIdAsync as m}from"../canvas/person.js";import{OBJECT_TYPE as C,GROUP_TYPE as w}from"./builtin.js";import{ceilingFrag as L,resolveCeiling as O}from"./ceiling.js";import{compilePermission as f}from"./compile.js";import{PermissionError as $}from"./errors.js";import{loadDefinitions as A}from"./schemas.js";import{TRUE as x,and as H,f as E,or as U,raw as p}from"./sql.js";const D=["read","edit","message","use","share"],W={read:"read",use:"read",edit:"write",share:"write",message:"message"},l=o(e=>e.replace(/^user:/,""),"bareUser");async function F(e,t){if(t.class==="person"){const c=await e.prepare("SELECT external_id FROM identities WHERE object = ? AND scheme = 'user'").get(t.person.id);return l(c?.external_id??await m())}if(t.class==="app")return l(t.sub??await m());const s=t.class==="node"?t.node.id:t.object.id,r=await e.prepare("SELECT sub FROM nodes WHERE node_id = ?").get(s);return l(r?.sub??await m())}o(F,"userOf");async function M(e,t){return t.class==="app"&&t.sub===void 0&&j()?null:await F(e,t)}o(M,"readerUser");async function _(e,t){const s=[t,"*"],r=await e.prepareUncached(`WITH RECURSIVE g(id) AS (
|
|
2
2
|
SELECT resource_id FROM relations WHERE resource_type = ? AND relation = 'member' AND subject_type = 'user' AND subject_id = ANY(?::text[])
|
|
3
3
|
UNION
|
|
4
4
|
SELECT r.resource_id FROM relations r JOIN g ON r.subject_type = ? AND r.subject_id = g.id AND r.subject_relation = 'member'
|
|
5
5
|
WHERE r.resource_type = ? AND r.relation = 'member')
|
|
6
|
-
SELECT id FROM g`).all(w,s,w,w);return{userIds:s,groupIds:r.map(c=>c.id)}}o(_,"subjectSet");async function k(e,t){const s=await M(e,t);return{reader:t,userId:s,subjects:s===null?{userIds:["*"],groupIds:[]}:await _(e,s)}}o(k,"resolveReader");const P=o(e=>"subjects"in e,"isEval");async function v(e,t,s,r="o",c={}){if(!D.includes(s))throw new $(400,"unknown_permission",`unknown permission ${s}`);const n=P(t)?t:await k(e,t),i=await A(e),d=p(`${r}.id`),N=f(i,n.subjects,
|
|
6
|
+
SELECT id FROM g`).all(w,s,w,w);return{userIds:s,groupIds:r.map(c=>c.id)}}o(_,"subjectSet");async function k(e,t){const s=await M(e,t);return{reader:t,userId:s,subjects:s===null?{userIds:["*"],groupIds:[]}:await _(e,s)}}o(k,"resolveReader");const P=o(e=>"subjects"in e,"isEval");async function v(e,t,s,r="o",c={}){if(!D.includes(s))throw new $(400,"unknown_permission",`unknown permission ${s}`);const n=P(t)?t:await k(e,t),i=await A(e),d=p(`${r}.id`),N=f(i,n.subjects,C,s,d),S=s==="read"?U([N,p(`${r}.type = 'app'`)]):N,R=n.reader.class==="person"?null:n.reader.app.id,I=n.reader.class==="app"&&n.reader.place===void 0&&R!==null?await q(e,R):new Set,u=[];for(const[a,y]of i){if(a.startsWith("crtr/")||a==="user"||a==="app"||!(s in y.permissions)&&!(s in y.relations))continue;const T=a.split("/")[0];u.push(E`WHEN ${p(r)}.schema_type = ${a} THEN ${I.has(T)?x:f(i,n.subjects,a,s,d)}`)}const g=u.length===0?E`(CASE WHEN ${p(r)}.schema_type IS NULL THEN ${S} ELSE FALSE END)`:E`(CASE WHEN ${p(r)}.schema_type IS NULL THEN ${S} ${{sql:u.map(a=>a.sql).join(" "),params:u.flatMap(a=>a.params)}} ELSE FALSE END)`,h=await O(e,n.reader,n.userId,W[s],c);return h===null?g:H([L(h,r),g])}o(v,"permits");async function q(e,t){const s=await e.prepare("SELECT s.namespace FROM schemas s JOIN identities i ON i.external_id = s.app AND i.scheme = 'app' WHERE i.object = ?").all(t);return new Set(s.map(r=>r.namespace))}o(q,"ownNamespaceTypes");async function Z(e,t,s,r,c={}){const n=await v(e,t,s,"o",c);return(await e.prepareUncached(`SELECT ${n.sql} AS ok FROM objects o WHERE o.id = ?`).get(...n.params,r))?.ok===!0}o(Z,"check");async function ee(e,t,s,r){const c=await _(e,l(t)),n=await A(e),i=f(n,c,r.type,s,E`${r.id}::text`);return(await e.prepareUncached(`SELECT ${i.sql} AS ok`).get(...i.params))?.ok===!0}o(ee,"checkUser");export{D as PERMISSIONS,Z as check,ee as checkUser,v as permits,M as readerUser,k as resolveReader,_ as subjectSet,F as userOf};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
import{readMergedLaunchConfig as
|
|
1
|
+
import{readMergedLaunchConfig as o,setAppPluginKinds as p}from"../config.js";import{setPersonId as i}from"../canvas/person-state.js";import{installPersonSnapshot as e}from"../scoped-state/person-store.js";process.once("message",r=>{try{r.person!==void 0&&r.snapshot!==void 0&&(i(r.person),e(r.person,r.snapshot)),p(r.appPluginKinds),process.send?.({config:o(r.cwd,r.profileId)})}catch(n){process.send?.({error:n instanceof Error?n.message:String(n)})}});
|
|
@@ -32,12 +32,16 @@ export declare function isLaunchKind(kind: string): boolean;
|
|
|
32
32
|
/** Validate a kind against the same cwd/profile configuration used to build its launch.
|
|
33
33
|
* Resolution is subprocess-isolated: crtrd is single-threaded and a config read can
|
|
34
34
|
* block indefinitely on a network filesystem. */
|
|
35
|
-
export declare function assertLaunchKind(kind: string, cwd?: string, profileId?: string | null
|
|
35
|
+
export declare function assertLaunchKind(kind: string, cwd?: string, profileId?: string | null,
|
|
36
|
+
/** The app the kind is launched in. */
|
|
37
|
+
app?: string): Promise<void>;
|
|
36
38
|
/** Resolve the exact profile, kind, cwd, mode and launch recipe a create will use. */
|
|
37
39
|
export declare function resolveLaunchTarget(req: CreateNodeRequest, options?: {
|
|
38
40
|
readOnlyProfileSelection?: boolean;
|
|
39
41
|
/** Preserve an existing caller's validation boundary before target resolution. */
|
|
40
|
-
validateKind?: (kind: string) => void | Promise<void>;
|
|
42
|
+
validateKind?: (kind: string, app: string) => void | Promise<void>;
|
|
43
|
+
/** The app the node runs in, when its caller is an app's broker or cron; else its parent's, else `app:terminal`. */
|
|
44
|
+
app?: string;
|
|
41
45
|
}): Promise<ResolvedLaunchTarget>;
|
|
42
46
|
/** The directory a new node is pinned to. */
|
|
43
47
|
export declare function resolveNodeCwd(req: CreateNodeRequest, parent: string | undefined, _profileId: string | null, contextCwd: string): Promise<string>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var m=Object.defineProperty;var i=(e,n)=>m(e,"name",{value:n,configurable:!0});import{appSpace as w}from"../layout.js";import{envProfileId as _}from"../../shared/env.js";import{resolve as s}from"node:path";import{getNode as f}from"../canvas/canvas.js";import{usage as v}from"../errors.js";import{assertProfileActive as x}from"../profiles/manifest.js";import{buildLaunchSpecAsync as h,readMergedLaunchConfigAsync as y}from"./launch.js";import{resolveProfileId as g}from"./spawn.js";function k(e,n){return e??n?.manifest.default_kind??"general"}i(k,"resolveCreateKind");const L="general",N="medium";function E(e){return e.manifest.default_kind??L}i(E,"resolveRunKind");function T(e,n){return n??(e.manifest.default_kind===void 0?N:void 0)}i(T,"resolveRunModel");const K=new Set(["human"]);function j(e){return!K.has(e)}i(j,"isLaunchKind");async function A(e,n=process.cwd(),o=_()||null,r="app:terminal"){const t=Object.keys((await y(n,o,r)).kinds);if(!t.includes(e))throw v(`unknown kind: ${e}`,{received:e,next:`Valid kinds: ${t.sort().join(", ")}.`})}i(A,"assertLaunchKind");async function F(e,n={}){const o=e.parent??void 0,r=e.cwd??process.cwd(),t=await g(e.profile,o??null,r,{readOnlySelection:n.readOnlyProfileSelection}),l=x(t),d=k(e.kind,l),a=n.app??(o===void 0?void 0:(await f(o))?.grantee)??"app:terminal";await n.validateKind?.(d,a);const c=await I({...e,kind:d},o,t,r);n.validateKind===void 0&&await A(d,c,t,a);const u=e.mode??"base",p=(await h(d,u,{lifecycle:e.root_lifecycle??(e.root===!0?"resident":"terminal"),hasManager:e.root!==!0,...e.model!==void 0?{model:e.model,modelOverride:!0}:{},cwd:c,profileId:t,app:a})).launch;return{profileId:t,profile:l,kind:d,mode:u,cwd:c,launch:p}}i(F,"resolveLaunchTarget");async function I(e,n,o,r){if(e.pin_cwd!==void 0&&e.pin_cwd!=="")return s(e.pin_cwd);if(n!=null){const t=await f(n);if(t!==null)return t.cwd}return e.cwd!==void 0&&e.cwd!==""?s(e.cwd):process.platform==="linux"?w("terminal").files:r}i(I,"resolveNodeCwd");export{L as RUN_DEFAULT_KIND,N as RUN_DEFAULT_MODEL,A as assertLaunchKind,j as isLaunchKind,k as resolveCreateKind,F as resolveLaunchTarget,I as resolveNodeCwd,E as resolveRunKind,T as resolveRunModel};
|
|
@@ -94,6 +94,9 @@ export interface LaunchBuildOptions {
|
|
|
94
94
|
* exactly the path that creates the user's sessions — so callers that
|
|
95
95
|
* know the node's profile must pass it explicitly (null = no profile). */
|
|
96
96
|
profileId?: string | null;
|
|
97
|
+
/** The app the launched node runs in: a cloud role layers in the launch kinds of the plugins enabled in THIS app. Required by the async
|
|
98
|
+
* builder (the only one a cloud role reaches); a launch for an existing or soon-to-exist node passes that node's own app. */
|
|
99
|
+
app?: string;
|
|
97
100
|
/** Preserved intent from an existing launch recipe when rebuilding it. */
|
|
98
101
|
modelIntent?: ModelIntent;
|
|
99
102
|
/** Exact-consult launch: pass the captured `provider/id:thinking` spec
|
|
@@ -115,7 +118,9 @@ export declare function buildLaunchSpec(kind: string, mode: Mode, opts: LaunchBu
|
|
|
115
118
|
* filesystem, so even an ordinary synchronous config read must never run on
|
|
116
119
|
* its event loop.
|
|
117
120
|
*/
|
|
118
|
-
export declare function buildLaunchSpecAsync(kind: string, mode: Mode, opts: LaunchBuildOptions
|
|
121
|
+
export declare function buildLaunchSpecAsync(kind: string, mode: Mode, opts: LaunchBuildOptions & {
|
|
122
|
+
app: string;
|
|
123
|
+
}): Promise<{
|
|
119
124
|
launch: LaunchSpec;
|
|
120
125
|
lifecycle: 'terminal' | 'resident';
|
|
121
126
|
}>;
|
|
@@ -124,6 +129,8 @@ export declare function buildLaunchSpecAsync(kind: string, mode: Mode, opts: Lau
|
|
|
124
129
|
* failure, an uncaught exception). Exported for tests. */
|
|
125
130
|
export declare function describeLaunchConfigExit(code: number | null, signal: NodeJS.Signals | null, stderr: string): string;
|
|
126
131
|
export declare function readMergedLaunchConfigAsync(cwd: string, profileId: string | null,
|
|
132
|
+
/** The app the launch runs in. */
|
|
133
|
+
app: string,
|
|
127
134
|
/** Test seam: the interpreter and worker script to fork with. */
|
|
128
135
|
seam?: {
|
|
129
136
|
execPath?: string;
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var
|
|
1
|
+
var U=Object.defineProperty;var s=(e,r)=>U(e,"name",{value:r,configurable:!0});import{envProfileId as P}from"../../shared/env.js";import{readMergedLaunchConfig as D}from"../config.js";import{fork as $}from"node:child_process";import{fileURLToPath as F}from"node:url";import{isCloudRole as G,personId as K,PersonUnresolvedError as W,PersonOutsideRequestError as X}from"../canvas/person-state.js";import{openDb as B}from"../canvas/db.js";import{appLaunchKinds as j}from"../packages/launch-kinds.js";import{currentSnapshot as z,PersonSettingsNotLoadedError as Y}from"../scoped-state/person-store.js";import{freshChildNodeExecPath as Q,recheckChildNode as J}from"./branded-host.js";import{LAUNCH_SYSTEM_PROMPT as Z}from"./launch-prompt.js";import{nodeEnv as q}from"./nodes.js";import{editorLabel as ee}from"../canvas/index.js";import{CANVAS_EXTENSIONS as be,CANVAS_STOPHOOK_PATH as He,CANVAS_INBOX_WATCHER_PATH as Ve,CANVAS_RECAP_PATH as Me,CANVAS_GOAL_CAPTURE_PATH as Ue,CANVAS_PASSIVE_CONTEXT_PATH as De,CANVAS_CONTEXT_INTRO_PATH as $e,CANVAS_TOOL_GUIDE_PATH as Fe,CANVAS_DOC_SUBSTRATE_PATH as Ge,CANVAS_STRUCTURED_OUTPUT_PATH as Ke,CANVAS_BASH_VALVE_PATH as We}from"./canvas-extensions.js";import{CANVAS_EXTENSIONS as ne,mergeCanvasExtensions as k,assertMandatoryCanvasExtensions as re}from"./canvas-extensions.js";import{modelLadders as h,defaultProvider as C,STRENGTH_ALIASES as m,MODEL_PROVIDER_KEYS as E,MODEL_STRENGTHS as A,THINKING_SUFFIXES as te,stripThinkingSuffix as g}from"./model-selection.js";import{OPENAI_PROVIDER_ENV as Be,configuredLadderProviders as je,inferPortableModelSelection as ze}from"./model-selection.js";function w(e,r=h()){return r[e]}s(w,"ladderFor");const S={light:0,medium:1,strong:2,ultra:3};function oe(e,r,n){const t=g(e);for(const o of[!0,!1]){const i=o?A:[...A].sort((f,u)=>S[f]-S[u]);for(const f of n)for(const u of i){const c=r[f][u];if(!(o?c!==e:g(c)!==t))return{provider:f,strength:u}}}return null}s(oe,"findLadderCell");function N(e){const r=e.lastIndexOf("/"),n=r===-1?void 0:e.slice(0,r),t=r===-1?e:e.slice(r+1),o=m[t];return o!==void 0?o:n!==void 0&&n!=="anthropic"?null:t==="opus"?"strong":t==="sonnet"?"medium":t==="haiku"?"light":null}s(N,"modelTokenStrength");function I(e,r=h()){const n=N(e);return n!==null?n:oe(_(e,r),r,E)?.strength??null}s(I,"resolvedModelStrength");function ie(e){return e==="review"||e.startsWith("review/")||e.includes("/reviewers/")}s(ie,"isReviewQualityKind");function se(e,r,n,t=h()){if(r===void 0)return n;if(!ie(e)||n===void 0)return r;const o=I(r,t),i=I(n,t);return o===null||i===null?r:S[o]<S[i]?n:r}s(se,"floorReviewModel");function O(e){if(e.includes("/")){const r=e.lastIndexOf("/"),n=e.slice(0,r),t=e.slice(r+1);return n!==""&&(m[t]!==void 0||n==="anthropic"&&(t==="opus"||t==="sonnet"||t==="haiku"))}return m[e]!==void 0||e==="opus"||e==="sonnet"||e==="haiku"}s(O,"isPortableModelToken");function v(e,r=h()){const n=N(e);if(n!==null)return e.includes("/")?{family:e.slice(0,e.lastIndexOf("/")),strength:n}:e==="opus"||e==="sonnet"||e==="haiku"?{family:"anthropic",strength:n}:{family:C(r),strength:n}}s(v,"logicalModelIntent");function we(e,r=h()){return O(e)?v(e,r):void 0}s(we,"explicitModelIntent");function _(e,r=h()){if(e.includes("/")){const t=e.indexOf("/"),o=e.slice(0,t),i=e.slice(t+1),f=m[i];if(f!==void 0&&(o==="anthropic"||o==="openai"))return w(o,r)[f];if(o==="anthropic"){if(i==="opus")return r.anthropic.strong;if(i==="sonnet")return r.anthropic.medium;if(i==="haiku")return r.anthropic.light}return e}const n=m[e];return n!==void 0?w(C(r),r)[n]:e==="opus"?r.anthropic.strong:e==="sonnet"?r.anthropic.medium:e==="haiku"?r.anthropic.light:e}s(_,"normalizeModel");function L(e){const r=e.lastIndexOf(":");if(r<=0)return;const n=e.slice(r+1);return te.has(n)?n:void 0}s(L,"thinkingSuffixOf");function ce(e=E){const r=e.length>0?e:E,n=h(),t=[];for(const o of A)for(const i of r)t.push(n[i][o]);return t}s(ce,"interleavedLadderCycle");function Ne(e,r=1,n){const t=ce(n),o=_(e),i=g(o),f=L(o);let u=t.findIndex(c=>g(c)===i&&L(c)===f);return u===-1&&(u=t.findIndex(c=>g(c)===i)),u===-1?t[0]:t[(u+r+t.length)%t.length]}s(Ne,"nextLadderModel");function y(e,r,n,t){const o=t.kinds[e],i=t.modelLadders,f=r==="orchestrator"?o?.orchestratorModel??o?.model:o?.model,u=n.modelExact===!0?n.model:se(e,n.model,f,i),c=n.modelExact===!0||n.modelOverride===!0&&n.model!==void 0&&!O(n.model),a=n.modelExact===!0?u:u!==void 0?_(u,i):void 0,l=c?void 0:n.modelIntent??(u!==void 0?v(u,i):void 0);return{launch:{model:a,modelIntent:l,modelExact:c?!0:void 0,tools:o?.tools??[],extensions:k([...ne,...o?.extensions??[]]),systemPrompt:Z,env:{...n.extraEnv??{},...l?{CRTR_MODEL_INTENT:`${l.family}/${l.strength}`}:{}}},lifecycle:n.lifecycle}}s(y,"buildLaunchSpecFromMerged");function Ie(e,r,n){return y(e,r,n,D(n.cwd??process.cwd(),n.profileId!==void 0?n.profileId:P()||null))}s(Ie,"buildLaunchSpec");async function Oe(e,r,n){const t=n.cwd??process.cwd(),o=n.profileId!==void 0?n.profileId:P()||null,i=await fe(t,o,n.app);return y(e,r,n,i)}s(Oe,"buildLaunchSpecAsync");const R=15e3;function ue(e,r,n){const t=r!==null?`was killed by ${r}`:`exited with code ${e}`,o=n.trim().split(`
|
|
2
2
|
`).slice(-8).join(`
|
|
3
|
-
`).slice(-1500);return`launch config subprocess ${t}${o!==""?`: ${o}`:" (no stderr output)"}`}s(
|
|
3
|
+
`).slice(-1500);return`launch config subprocess ${t}${o!==""?`: ${o}`:" (no stderr output)"}`}s(ue,"describeLaunchConfigExit");class b extends Error{static{s(this,"LaunchConfigWorkerCrash")}}async function fe(e,r,n,t={}){const o=t.execPath??await Q(),i=t.workerPath??F(new URL("./launch-config-worker.js",import.meta.url)),f=de(),u=G()?"snapshot"in f?await j(await B(),f.snapshot,n):{}:void 0;try{return await H(e,r,o,i,f,u)}catch(c){if(!(c instanceof b))throw c;const a=await J(o);if(a===o)throw c;return H(e,r,a,i,f,u)}}s(fe,"readMergedLaunchConfigAsync");function de(){try{return{person:K(),snapshot:z()}}catch(e){if(e instanceof W||e instanceof X||e instanceof Y)return{};throw e}}s(de,"heldPersonSettings");function H(e,r,n,t,o,i){return new Promise((f,u)=>{const c=$(t,[],{execPath:n,stdio:["ignore","ignore","pipe","ipc"],serialization:"advanced"});let a="";c.stderr?.setEncoding("utf8").on("data",d=>{a=(a+d).slice(-8192)}),c.send({cwd:e,profileId:r,...o,appPluginKinds:i});let l=!1;const p=s(d=>{l||(l=!0,clearTimeout(V),c.connected&&c.disconnect(),c.killed||c.kill("SIGKILL"),d())},"finish"),V=setTimeout(()=>p(()=>u(new Error(`timed out after ${R}ms reading launch config for ${e}`))),R);c.once("message",d=>{d.error!==void 0?p(()=>u(new Error(d.error))):d.config!==void 0?p(()=>f(d.config)):p(()=>u(new Error("launch config subprocess returned no result")))});let x=null;c.on("error",d=>{x??=d}),c.once("close",(d,M)=>{if(l)return;const T=ue(d,M,a);p(()=>u(new b(x===null?T:`${T} (${x.message})`)))})})}s(H,"runLaunchConfigWorker");function ve(e,r={}){const n=e.launch,t=k(n?.extensions);re(t);const o=[];for(const i of t)o.push("-e",i);if(o.push("-n",ee(e)),r.forkFrom!==void 0&&r.forkFrom!=="")o.push("--fork",r.forkFrom);else{const i=r.resumeSessionPath??r.resumeSessionId;i!==void 0&&o.push("--session",i),r.newCycle===!0&&o.push("--crtr-new-cycle")}return n?.model!==void 0&&o.push("--model",n.model),n?.modelExact===!0&&o.push("--crtr-model-exact"),n?.tools!==void 0&&n.tools.length>0&&o.push("--tools",n.tools.join(",")),n?.systemPrompt!==void 0&&n.systemPrompt!==""&&o.push("--append-system-prompt",n.systemPrompt),r.prompt!==void 0&&r.prompt!==""&&o.push(r.prompt),{argv:o,env:q(e),...n?.worktree===void 0?{}:{worktree:n.worktree}}}s(ve,"buildPiArgv");function Le(e){for(const[t,o]of Object.entries(e.env))process.env[t]=o;const r={cwd:e.env.CRTR_NODE_CWD??process.cwd(),extensionPaths:[]},n=e.argv;for(let t=0;t<n.length;t++){const o=n[t];switch(o){case"-e":r.extensionPaths.push(n[++t]);break;case"-n":r.editorName=n[++t];break;case"--fork":r.forkFrom=n[++t];break;case"--session":{const i=n[++t];i.includes("/")||i.endsWith(".jsonl")?r.resumeSessionPath=i:r.resumeSessionId=i;break}case"--model":r.model=n[++t];break;case"--crtr-model-exact":r.modelExact=!0;break;case"--tools":r.tools=n[++t].split(",").filter(i=>i!=="");break;case"--append-system-prompt":r.appendSystemPromptPath=n[++t];break;case"--crtr-new-cycle":r.newCycle=!0;break;default:r.firstPrompt=o;break}}return r}s(Le,"piInvocationToSdkConfig");export{We as CANVAS_BASH_VALVE_PATH,$e as CANVAS_CONTEXT_INTRO_PATH,Ge as CANVAS_DOC_SUBSTRATE_PATH,be as CANVAS_EXTENSIONS,Ue as CANVAS_GOAL_CAPTURE_PATH,Ve as CANVAS_INBOX_WATCHER_PATH,De as CANVAS_PASSIVE_CONTEXT_PATH,Me as CANVAS_RECAP_PATH,He as CANVAS_STOPHOOK_PATH,Ke as CANVAS_STRUCTURED_OUTPUT_PATH,Fe as CANVAS_TOOL_GUIDE_PATH,Be as OPENAI_PROVIDER_ENV,Ie as buildLaunchSpec,Oe as buildLaunchSpecAsync,ve as buildPiArgv,je as configuredLadderProviders,ue as describeLaunchConfigExit,we as explicitModelIntent,ze as inferPortableModelSelection,ce as interleavedLadderCycle,O as isPortableModelToken,v as logicalModelIntent,N as modelTokenStrength,Ne as nextLadderModel,_ as normalizeModel,Le as piInvocationToSdkConfig,fe as readMergedLaunchConfigAsync};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var g=Object.defineProperty;var r=(n,e)=>g(n,"name",{value:e,configurable:!0});import{getNode as o,updateNode as x}from"../canvas/index.js";import{transition as E}from"./lifecycle.js";import{ensureDaemon as R}from"../../daemon/manage.js";import{buildLaunchSpec as $,buildLaunchSpecAsync as
|
|
1
|
+
var g=Object.defineProperty;var r=(n,e)=>g(n,"name",{value:e,configurable:!0});import{getNode as o,updateNode as x}from"../canvas/index.js";import{transition as E}from"./lifecycle.js";import{ensureDaemon as R}from"../../daemon/manage.js";import{buildLaunchSpec as $,buildLaunchSpecAsync as p}from"./launch.js";import{ensureRoadmap as m,hasRoadmap as c,roadmapRef as u}from"./roadmap.js";import{readGoal as f,goalPath as w}from"./kickoff.js";async function k(n,e){const i=await o(n);if(i===null)throw new Error(`unknown node: ${n}`);const a=e.kind??i.kind,l=e.mode??i.mode,d=e.lifecycle??i.lifecycle,t=e.profileId===void 0?i.profile_id??null:e.profileId;return{node:i,kind:a,mode:l,lifecycle:d,profileId:t,launchOpts:{lifecycle:d,hasManager:i.parent!==null,model:e.model??i.model_override??void 0,modelOverride:e.model!==void 0,modelIntent:e.model===void 0?i.launch?.modelIntent:void 0,modelExact:e.model===void 0?i.launch?.modelExact:void 0,cwd:i.cwd,profileId:t,app:i.grantee??"app:terminal"}}}r(k,"reshapeInputs");async function s(n,e,i,a,l){await l?.();const d=i.node.name===i.node.kind&&i.kind!==i.node.kind;return await x(n,{kind:i.kind,mode:i.mode,lifecycle:i.lifecycle,profile_id:i.profileId,launch:a,...d?{name:i.kind}:{},...e.model!==void 0?{model_override:a?.model??e.model}:{}})}r(s,"persistReshape");async function h(n,e={},i){const a=await k(n,e);return await s(n,e,a,$(a.kind,a.mode,a.launchOpts).launch,i)}r(h,"reshapeNode");async function y(n,e={},i){const a=await k(n,e),{launch:l}=await p(a.kind,a.mode,a.launchOpts);return await s(n,e,a,l,i)}r(y,"reshapeNodeAsync");async function A(n,e={}){const i=await o(n);if(i===null)throw new Error(`unknown node: ${n}`);let a=!1;return{meta:await h(n,{...e.kind!==void 0?{kind:e.kind}:{},...e.model!==void 0?{model:e.model}:{},mode:"orchestrator",lifecycle:e.resident===!0?"resident":i.lifecycle},async()=>{if(!await c(n)){const d=await f(n);a=await m(n,d!==null&&d.trim()!==""?{goal:d.trim()}:{})}}),roadmapWritten:a,roadmapRef:u(n),goalPath:await w(n)}}r(A,"promote");async function N(n,e={}){const i=await o(n);if(i===null)throw new Error(`unknown node: ${n}`);let a=!1;return{meta:await y(n,{...e.kind!==void 0?{kind:e.kind}:{},...e.model!==void 0?{model:e.model}:{},mode:"orchestrator",lifecycle:e.resident===!0?"resident":i.lifecycle},async()=>{if(!await c(n)){const d=await f(n);a=await m(n,d!==null&&d.trim()!==""?{goal:d.trim()}:{})}}),roadmapWritten:a,roadmapRef:u(n),goalPath:await w(n)}}r(N,"promoteAsync");async function W(n,e={},i={}){if(await o(n)===null)throw new Error(`unknown node: ${n}`);return e.promote===!0?await N(n,{...e.kind!==void 0?{kind:e.kind}:{},...e.model!==void 0?{model:e.model}:{}}):(e.kind!==void 0||e.model!==void 0)&&await y(n,{...e.kind!==void 0?{kind:e.kind}:{},...e.model!==void 0?{model:e.model}:{}}),{...await O(n,{},i),promoted:e.promote===!0}}r(W,"requestYieldAsync");async function O(n,e={},i={}){const a=i.ensure??R;if(await o(n)===null)throw new Error(`unknown node: ${n}`);const d=e.kind!==void 0||e.model!==void 0;let t=!1;return e.promote===!0?(await A(n,{...e.kind!==void 0?{kind:e.kind}:{},...e.model!==void 0?{model:e.model}:{}}),t=!0):d&&await h(n,{...e.kind!==void 0?{kind:e.kind}:{},...e.model!==void 0?{model:e.model}:{}}),a(),await E(n,"yield"),{meta:await o(n),promoted:t,willRefresh:!0}}r(O,"requestYield");export{A as promote,N as promoteAsync,O as requestYield,W as requestYieldAsync,h as reshapeNode,y as reshapeNodeAsync};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var m=Object.defineProperty;var r=(e,t)=>m(e,"name",{value:t,configurable:!0});import{abortExecution as y,beginExecution as _,getNode as s,setPresence as h,setFocusOccupant as v,fullName as R,recordExecutionPid as b,recordLaunch as k}from"../canvas/index.js";import{pushFinal as E}from"../feed/feed.js";import{newestReportBody as g}from"../feed/reports.js";import{spawnNode as S,rootOfSpine as x}from"./nodes.js";import{buildLaunchSpecAsync as T,buildPiArgv as B}from"./launch.js";import{focusOf as C,respawnPaneSync as N,setPaneOption as O}from"./placement.js";import{waitForBrokerViewSocket as P,viewerSplitEnv as D}from"./placement-tmux.js";import{headlessBrokerHost as u}from"./host.js";import{boundFleet as F,brokerThresholdsForDaemon as z}from"./fleet.js";import{transition as A}from"./lifecycle.js";import{ensureDaemon as L}from"../../daemon/manage.js";import{invokeBirthLifecycleHooks as U}from"./spawn.js";import{checkStart as H}from"./start-check.js";async function ne(e,t){const a=await s(e);if(a===null)return{recycled:!1,finalized:!1,newRoot:null,delivered:[]};const o=t??process.env.TMUX_PANE;if(o===void 0||o==="")return{recycled:!1,finalized:!1,newRoot:null,delivered:[]};await H(a);const w=await C(e);try{L()}catch{}const{launch:f}=await T("general","base",{lifecycle:"resident",hasManager:!1,cwd:a.cwd,profileId:a.profile_id,app:a.grantee??"app:terminal"}),p=await g(e)||`Closed via recycle \u2014 no final summary was authored by ${a.name}.`;let c=[],d=!1;const n=await S({kind:"general",mode:"base",lifecycle:"resident",cwd:a.cwd,name:"general",parent:null,replaces:e,profile_id:a.profile_id,launch:f,beforeCreate:r(async()=>{try{c=(await E(e,p)).deliveredTo,d=!0}catch{}},"beforeCreate")}),i=await s(n.node_id);await U(i);const l=B(i);if(l.env={...l.env,CRTR_SUBTREE:await x(n.node_id)},!await M(i,l))return{recycled:!1,finalized:d,newRoot:n.node_id,delivered:c};try{u.teardown(e)}catch{}try{await h(e,{pane:null,window:null,tmux_session:null})}catch{}if(w!==null)try{await v(w.focus_id,n.node_id)}catch{}return{recycled:X(i,o),finalized:d,newRoot:n.node_id,delivered:c}}r(ne,"recycleNode");async function M(e,t){const a=await _(e.node_id,{daemonEpoch:F().epoch(),cap:z().automaticReviveCap});t.env={...t.env,CRTR_EXECUTION_ID:a};let o;try{if(o=await u.launch(e.node_id,t,{cwd:e.cwd,name:R(e),resuming:!1}),o.pid===null)throw new Error("broker host returned no pid");if(await k(e.node_id,new Date().toISOString()),await b(a,e.node_id,o.pid)==="shutdown")throw new Error("broker execution was superseded");if(await P(e.node_id,o.exited))return!0}catch{await y(a,{reason:"launch_failed"})}try{await V(e.node_id)}catch{}try{u.teardown(e.node_id)}catch{}return!1}r(M,"launchRecycledBroker");async function V(e){const t=await s(e);(t?.status==="active"||t?.status==="idle")&&await A(e,"crash")}r(V,"transitionReplacementToDead");function X(e,t){try{O(t,"@crtr_node","")}catch{}return N({pane:t,cwd:e.cwd,env:D(),command:`crtr surface attach to ${e.node_id}`})}r(X,"respawnRecycledViewer");export{ne as recycleNode};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var S=Object.defineProperty;var s=(e,a)=>S(e,"name",{value:a,configurable:!0});import{getNode as f,beginExecution as b,recordExecutionPid as
|
|
1
|
+
var S=Object.defineProperty;var s=(e,a)=>S(e,"name",{value:a,configurable:!0});import{getNode as f,beginExecution as b,recordExecutionPid as g,abortExecution as v,bindSession as B,recordLaunch as F,fullName as x,liveExecutionForNode as N,closeFocusRow as R,view as C}from"../canvas/index.js";import{transition as r}from"./lifecycle.js";import{headlessBrokerHost as y,requestBrokerTeardown as D}from"./host.js";import{boundFleet as O,brokerThresholdsForDaemon as T}from"./fleet.js";import{tearDownNode as V,focusOf as P,registerViewerFocus as I,respawnPaneSync as L,windowOfPane as q,renameWindow as A}from"./placement.js";import{viewerSplitEnv as H,waitForBrokerViewSocket as M}from"./placement-tmux.js";import{buildLaunchSpecAsync as U,buildPiArgv as j}from"./launch.js";import{newNodeId as W,spawnNode as X,rootOfSpine as $}from"./nodes.js";import{appSpace as z}from"../layout.js";import{join as G}from"node:path";import{invokeBirthLifecycleHooks as J}from"./spawn.js";import{checkStart as K}from"./start-check.js";async function Q(e){const a=[];for(const i of await C(e))try{await r(i,"cancel",{reason:"closed"}),D(i),await V(i),a.push(i)}catch{}return a}s(Q,"reapDescendants");async function we(e,a={}){const i=a.launchBroker??y.launch,l=a.waitForViewSocket??M,p=a.respawnViewer??L,c=a.teardownBroker??y.teardown,n=await f(e);if(n===null||n.parent!=null||n.status==="done")return null;await K(n);const d=await P(e),h=n.isolated?await W():void 0,_=h?G(z(n.grantee??"app:terminal").nodes,h):n.cwd,{launch:E}=await U(n.kind,"base",{lifecycle:"resident",hasManager:!1,model:n.model_override??void 0,modelIntent:n.launch?.modelIntent,modelExact:n.launch?.modelExact,cwd:_,profileId:n.profile_id,app:n.grantee??"app:terminal"}),t=await X({nodeId:h,kind:n.kind,mode:"base",lifecycle:"resident",cwd:_,name:n.kind,parent:null,replaces:e,profile_id:n.profile_id,launch:E,modelOverride:n.model_override??void 0});await J(t);const u=j(t,{});u.env={...u.env,CRTR_SUBTREE:await $(t.node_id)};const w=await b(t.node_id,{daemonEpoch:O().epoch(),cap:T().automaticReviveCap});u.env={...u.env,CRTR_EXECUTION_ID:w};let m;try{m=await i(t.node_id,u,{cwd:_,name:x(t),resuming:!1})}catch(o){throw await v(w,{reason:"launch_failed"}),await r(t.node_id,"crash"),o}if(m.pid==null)return await v(w,{reason:"launch_failed"}),await r(t.node_id,"crash"),null;if(await F(t.node_id,new Date().toISOString()),await g(w,t.node_id,m.pid)==="shutdown"){await v(w,{reason:"superseded"});try{c(t.node_id)}catch{}return await r(t.node_id,"crash"),null}let k=!1;try{k=await l(t.node_id,m.exited)}catch{}if(!k){const o=await f(t.node_id);(o?.status==="active"||o?.status==="idle")&&await r(t.node_id,"crash");try{c(t.node_id)}catch{}return null}if(await Q(e),await r(e,"finish"),d?.pane!=null){await R(d.focus_id),p({pane:d.pane,cwd:n.cwd,env:H(),command:`crtr surface attach to ${t.node_id}`});const o=q(d.pane);o!==null&&A(o,x(t)),await I(t.node_id,d.pane,d.session,o)}return c(e),{newNodeId:t.node_id}}s(we,"relaunchRoot");async function Y(e,a,i){const l=await f(e),p={reaped:[],detached:[],reset:!1};if(l===null||l.parent==null)return p;if(a!==void 0){const c=await N(e);c!==null&&await B(e,{executionId:c.executionId,sessionId:a,transcriptPath:i??null})}return p}s(Y,"resetRoot");async function fe(e,a,i){return await f(e)===null?{path:"noop"}:(await Y(e,a,i),{path:"reset-child"})}s(fe,"handleNewSession");async function pe(e,a){if(a!=="quit")return!1;const i=await f(e);return i===null||i.status!=="active"&&i.status!=="idle"||i.intent!=null?!1:(await r(e,"finish"),!0)}s(pe,"markCleanExitDone");export{fe as handleNewSession,pe as markCleanExitDone,Q as reapDescendants,we as relaunchRoot,Y as resetRoot};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var me=Object.defineProperty;var d=(e,o)=>me(e,"name",{value:o,configurable:!0});import{accessSync as he,constants as pe}from"node:fs";import{isAbsolute as _e,resolve as ke,join as ve}from"node:path";import{appSpace as ge}from"../layout.js";import{ApiError as ne}from"../../api/errors.js";import{spawnNode as ye,forkSourceNode as be,currentNodeContext as xe,rootOfSpine as $e,newNodeId as Se,preflightNodeId as Ce}from"./nodes.js";import{resolveProfileOperand as Ee}from"../profiles/manifest.js";import{selectProfileForCwd as Re,selectProfileForCwdReadOnly as Oe}from"../profiles/select.js";import{buildLaunchSpecAsync as oe,buildPiArgv as Fe}from"./launch.js";import{runsOnBlaxel as Ie,sandboxWorktreeRequest as Pe}from"../../daemon/api/environment-of.js";import{createManagedWorktreeAsync as Be,rollbackManagedWorktreeAsync as De}from"../worktree-mutation-async.js";import{usage as w,brokerLaunchFailed as B}from"../errors.js";import{writeGoal as Ne}from"./kickoff.js";import{appendSituationalContext as Le,formatSituationalProse as Me}from"./situational-context.js";import{ensureRoadmap as Te}from"./roadmap.js";import{buildWakeBearings as Ae}from"./bearings.js";import{encodeKickoffOrigin as We,KICKOFF_ORIGIN_ENV as je}from"./stamp/protocol.js";import{ExecutionCapReached as ze,beginExecution as He,crtrHome as Ke,getNode as u,fullName as re,jobDir as Ge,recordExecutionPid as Ue,abortExecution as j,setFrozen as z}from"../canvas/index.js";import{contextDir as H,nodeAgentDir as K}from"../canvas/node-agent-paths.js";import{copyTreeBeneath as Ve}from"../spaces/open-beneath.js";import{conversationIdFromPath as D,conversationStore as S}from"../conversation-store/index.js";import{appMemoryTooSmall as Xe,boundFleet as qe,brokerThresholdsForDaemon as te}from"./fleet.js";import{admitBrokerMemory as Ye}from"./memory-admission.js";import{emitEvent as N}from"../events/emit.js";import{blaxelEnvironmentOf as Je}from"./blaxel-environment.js";import{openViewerWindow as Qe,focusOf as Ze,windowOfPane as en}from"./placement.js";import{awaitBrokerViewSocket as nn}from"./view-socket.js";import{readLogSnapshot as on}from"../events/read.js";import{transition as k}from"./lifecycle.js";import{beginBootFaultAttempt as rn}from"../canvas/recovery.js";import{headlessBrokerHost as G}from"./host.js";import{ensureDaemon as tn}from"../../daemon/manage.js";import{readConfig as an}from"../config.js";import{modelRequestFromConfig as dn,unregisteredConcreteModel as sn,unroutableConcreteModel as ln}from"../model-routes.js";import{openModelRegistry as cn}from"./model-registry.js";import{MODEL_SPEC_NEXT as un}from"./model-selection.js";import{forkNodeLedger as fn}from"./ledger.js";import{appRungForGrant as wn}from"../llm/app-rungs.js";import{APP_FAMILY as U}from"../model-routes.js";import{discoverLifecycleHookRegistry as mn}from"../command-hooks/discovery.js";import{invokeLifecycleHooks as hn}from"../command-hooks/transport/exec-lifecycle.js";import{someAsync as pn}from"../async-array.js";import{checkStart as _n}from"./start-check.js";function v(e){return{detail:{schema:"crtr.node-outcome-detail/v1",message:e instanceof Error?e.message:String(e)}}}d(v,"launchFailureOutcome");async function kn(e,o,a){try{return await G.launch(e,o,a)}catch(r){try{await k(e,"crash",{reason:"launch_failed",outcome:v(r)})}catch{}const t=r.message;throw B(t.startsWith("[broker]")?t:`[broker] refusing to launch ${e}: ${t}`,"Inspect the cause above, fix the launch recipe or environment, then retry.")}}d(kn,"launchBrokerOrCrash");function vn(e){return on({nodeId:e,component:"broker",pattern:"broker.startup."},!1).items.flatMap(a=>a.kind==="event"&&a.envelope.event.startsWith("broker.startup.")&&a.envelope.event!=="broker.startup.warning"?[a.envelope.event.slice(15)]:[]).at(-1)??null}d(vn,"lastStartupStep");function gn(e,o){const a=vn(e),r=a===null?"it had logged no startup step":`the last startup step it logged was \`${a}\``;if(o.reason==="exited"){const{code:t,signal:s}=o.status;return{text:`exited (code ${t??"null"}, signal ${s??"null"}) before binding its view socket; ${r}`,fields:{reason:"exited",code:t,signal:s,last_startup_step:a}}}return{text:`was still starting after ${Math.round(o.waitedMs/1e3)} s without binding its view socket, so the launcher stopped it; ${r}`,fields:{reason:"timeout",waited_ms:o.waitedMs,last_startup_step:a}}}d(gn,"notReadyDescription");async function yn(e,o){try{await k(e,"crash",{reason:"launch_failed",outcome:v(o)})}catch{}try{G.teardown(e)}catch{}}d(yn,"crashAndTearDown");async function bn(e){const o=(await S().list()).map(({conversation_id:t,path:s})=>({id:t,path:s})),a=o.filter(t=>t.id===e),r=a.length>0?a:o.filter(t=>t.id.startsWith(e));if(r.length===0)throw w(`--fork-from '${e}': no pi session with that id found.`,{next:"Pass a live node id, a real session uuid/prefix, or an absolute .jsonl session path."});if(r.length>1)throw w(`--fork-from '${e}': ambiguous \u2014 ${r.length} sessions match that id prefix; pass the full id or the .jsonl path.`,{next:"Pass the full session uuid or an absolute .jsonl path to disambiguate."});return r[0].path}d(bn,"resolveSessionUuid");async function ie(e){const o=e.trim();if(o==="")throw w("--fork-from requires a node id, session file, or session uuid.",{next:"Pass a live node id, an absolute .jsonl session path, or a session uuid/prefix."});if(o.includes("/")||o.endsWith(".jsonl")){const r=D(_e(o)?o:ke(process.cwd(),o));if(r===null)throw w(`--fork-from '${o}': invalid conversation path.`,{next:"Pass a conversation file path or id."});return(await S().header(r)).path}const a=await u(o);if(a!==null){const r=a.pi_session_file;if(r==null||r==="")throw w(`node ${o} has no pi session yet \u2014 it has not captured a session FILE to fork from (the broker forks a .jsonl path, not a bare id).`,{next:"Pick a node that has captured a session, or drop --fork-from."});const t=D(r);if(t===null)throw w(`node ${o} has no valid conversation id.`,{next:"Pick a node with a captured conversation."});return(await S().header(t)).path}return await bn(o)}d(ie,"resolveForkSource");async function xn(e,o,a,r={}){return e===null?null:e!==void 0&&e!==""?Ee(e).profileId:o!==null?(await u(o))?.profile_id??null:r.readOnlySelection===!0?Oe(a):Re(a)}d(xn,"resolveProfileId");function ae(e){const o=e.modelIntent===void 0?void 0:`${e.modelIntent.family}/${e.modelIntent.strength}`;return dn(e.model,o,e.modelExact===!0)}d(ae,"requestFromLaunch");async function de(e,o,a){const r=a??(e.modelIntent?`${e.modelIntent.family}/${e.modelIntent.strength}`:e.model),t=await wn(o,r,e.modelExact===!0);if(t===null)return e;const{CRTR_MODEL_INTENT:s,...l}=e.env??{};return{...e,model:t.model,modelIntent:{family:U,strength:t.strength},modelExact:void 0,env:{...l,CRTR_MODEL_INTENT:`${U}/${t.strength}`}}}d(de,"appPaidLaunch");async function se(e,o,a){if(e===void 0||e.kind==="logical"&&e.family!==U)return;const r=await sn(e.kind==="logical"?{kind:"concrete",spec:e.spec}:e,a??await cn(),o);if(r!==void 0)throw w(`model '${r.request.spec}' is not registered in this daemon.`,{received:r.request.spec,next:un});const t=await ln(e,o);if(t!==void 0)throw w(`model '${t.spec}' is registered but no configured model route offers it, so no turn could be served.`,{received:t.spec,next:"Pick a model from your configured routes (`crtr sys config get modelLadders`), or add this one to a ladder or route."})}d(se,"assertLaunchModelRegistered");function $n(e,o,a){const r=e??o??null;if(!a&&r===null)throw new Error("spawnChild requires a calling node (CRTR_NODE_ID) or an explicit parent");return r}d($n,"resolveSpawner");async function le(e,o,a){try{tn()}catch{}const r=xe(),t=e.root===!0,s=$n(e.parent,r.nodeId??null,t),l=e.mode??"base",g=e.rootLifecycle??(t?"resident":"terminal"),ce=t&&g==="resident",E=s===null?null:await u(s),V=e.creator===void 0||e.creator===null?null:await u(e.creator);e.nodeId!==void 0&&await Ce(e.nodeId);const y=e.forkFrom!==void 0?await ie(e.forkFrom):void 0,L=y===void 0?null:await be(y),M=await pn([E,V,L],async f=>f?.isolated===!0||f?.run_id!=null&&(await u(f.run_id))?.isolated===!0);if(M&&e.isolated===!1)throw new ne(403,"isolated_run","isolation cannot be turned off under an isolated run",{param:"isolated"});const R=M||e.isolated===!0;if(R&&e.worktree===!0)throw new ne(400,"invalid_request","isolated nodes cannot use a worktree",{param:"worktree"});const C=e.worktree===!0,m=R||C?e.nodeId??await Se():e.nodeId,O=R?e.run!==void 0&&t&&!M?e.cwd:ve(ge(e.run?.grantee??E?.grantee??"app:terminal").nodes,m):e.cwd,h=await xn(e.profile,s,O),X=e.run?.grant_id??E?.grant_id??null,q=await de((await oe(e.kind,l,{lifecycle:g,hasManager:!t,model:e.model,modelOverride:e.model!==void 0,cwd:O,profileId:h})).launch,X,e.model);await se(ae(q),{cwd:O,profileId:h});const T=e.run??V??E??L;await _n({grantee:T?.grantee??"app:terminal",sub:T?.sub,grant_id:T?.grant_id});const Y=L?.node_id??null;let b,F=O;const A=C&&await Ie(h)?await Pe(h,e.worktreeCwd??e.cwd,m,e.worktreeBase):void 0;try{C&&A===void 0&&(b=await Be(e.worktreeCwd??e.cwd,m,e.worktreeBase),F=b.path);const f=C?await de((await oe(e.kind,l,{lifecycle:g,hasManager:!t,model:e.model,modelOverride:e.model!==void 0,cwd:F,profileId:h})).launch,X,e.model):q;A!==void 0&&(f.worktree=A),C&&await se(ae(f),{cwd:F,profileId:h});const n=await ye({kind:e.kind,mode:l,lifecycle:g,cwd:F,name:e.name??e.kind,description:e.description,parent:t?null:s,creator:e.creator,...e.actor===void 0?{}:{actor:e.actor},forkSourceNode:Y,spawnedBy:t?s??void 0:void 0,profile_id:h,...e.scopes===void 0?{}:{scopes:e.scopes},isolated:R,...e.run===void 0?{}:{run:e.run},...e.causedBy===void 0?{}:{causedBy:e.causedBy},...e.withinCreate===void 0?{}:{withinCreate:e.withinCreate},forkFrom:e.forkFrom,forkSourceFile:y,modelOverride:e.model===void 0?void 0:f.model,...b!==void 0?{managedWorktree:b}:{},...m!==void 0?{nodeId:m}:{},...e.reviewBinding===void 0?{}:{reviewBinding:e.reviewBinding},...e.deadlineAt===void 0?{}:{deadlineAt:e.deadlineAt},...e.outcomeDelivery===void 0?{}:{outcomeDelivery:e.outcomeDelivery},launch:f});if(a?.(n.node_id),e.forkFrom!==void 0)try{await fn(n.node_id,Y??null)}catch(i){throw await k(n.node_id,"crash",{reason:"launch_failed",outcome:v(i)}),i}if(await Ne(n.node_id,e.prompt),e.situationalContext!==void 0&&await Le(n.node_id,Me(e.situationalContext)),o!==void 0)try{o(n.node_id)}catch(i){throw await k(n.node_id,"crash",{reason:"launch_failed",outcome:v(i)}),i}const W=e.prompt!=="",ue=`${W&&e.wakeOrigin!==void 0?`${Ae(e.wakeOrigin)}
|
|
1
|
+
var me=Object.defineProperty;var d=(e,o)=>me(e,"name",{value:o,configurable:!0});import{accessSync as he,constants as pe}from"node:fs";import{isAbsolute as _e,resolve as ke,join as ve}from"node:path";import{appSpace as ge}from"../layout.js";import{ApiError as ne}from"../../api/errors.js";import{spawnNode as ye,forkSourceNode as be,currentNodeContext as xe,rootOfSpine as $e,newNodeId as Se,preflightNodeId as Ce}from"./nodes.js";import{resolveProfileOperand as Ee}from"../profiles/manifest.js";import{selectProfileForCwd as Re,selectProfileForCwdReadOnly as Oe}from"../profiles/select.js";import{buildLaunchSpecAsync as oe,buildPiArgv as Fe}from"./launch.js";import{runsOnBlaxel as Ie,sandboxWorktreeRequest as Pe}from"../../daemon/api/environment-of.js";import{createManagedWorktreeAsync as Be,rollbackManagedWorktreeAsync as De}from"../worktree-mutation-async.js";import{usage as w,brokerLaunchFailed as D}from"../errors.js";import{writeGoal as Ne}from"./kickoff.js";import{appendSituationalContext as Le,formatSituationalProse as Me}from"./situational-context.js";import{ensureRoadmap as Te}from"./roadmap.js";import{buildWakeBearings as Ae}from"./bearings.js";import{encodeKickoffOrigin as We,KICKOFF_ORIGIN_ENV as je}from"./stamp/protocol.js";import{ExecutionCapReached as ze,beginExecution as He,crtrHome as Ke,getNode as u,fullName as re,jobDir as Ge,recordExecutionPid as Ue,abortExecution as j,setFrozen as z}from"../canvas/index.js";import{contextDir as H,nodeAgentDir as K}from"../canvas/node-agent-paths.js";import{copyTreeBeneath as Ve}from"../spaces/open-beneath.js";import{conversationIdFromPath as N,conversationStore as S}from"../conversation-store/index.js";import{appMemoryTooSmall as Xe,boundFleet as qe,brokerThresholdsForDaemon as te}from"./fleet.js";import{admitBrokerMemory as Ye}from"./memory-admission.js";import{emitEvent as L}from"../events/emit.js";import{blaxelEnvironmentOf as Je}from"./blaxel-environment.js";import{openViewerWindow as Qe,focusOf as Ze,windowOfPane as en}from"./placement.js";import{awaitBrokerViewSocket as nn}from"./view-socket.js";import{readLogSnapshot as on}from"../events/read.js";import{transition as k}from"./lifecycle.js";import{beginBootFaultAttempt as rn}from"../canvas/recovery.js";import{headlessBrokerHost as G}from"./host.js";import{ensureDaemon as tn}from"../../daemon/manage.js";import{readConfig as an}from"../config.js";import{modelRequestFromConfig as dn,unregisteredConcreteModel as sn,unroutableConcreteModel as ln}from"../model-routes.js";import{openModelRegistry as cn}from"./model-registry.js";import{MODEL_SPEC_NEXT as un}from"./model-selection.js";import{forkNodeLedger as fn}from"./ledger.js";import{appRungForGrant as wn}from"../llm/app-rungs.js";import{APP_FAMILY as U}from"../model-routes.js";import{discoverLifecycleHookRegistry as mn}from"../command-hooks/discovery.js";import{invokeLifecycleHooks as hn}from"../command-hooks/transport/exec-lifecycle.js";import{someAsync as pn}from"../async-array.js";import{checkStart as _n}from"./start-check.js";function v(e){return{detail:{schema:"crtr.node-outcome-detail/v1",message:e instanceof Error?e.message:String(e)}}}d(v,"launchFailureOutcome");async function kn(e,o,a){try{return await G.launch(e,o,a)}catch(r){try{await k(e,"crash",{reason:"launch_failed",outcome:v(r)})}catch{}const t=r.message;throw D(t.startsWith("[broker]")?t:`[broker] refusing to launch ${e}: ${t}`,"Inspect the cause above, fix the launch recipe or environment, then retry.")}}d(kn,"launchBrokerOrCrash");function vn(e){return on({nodeId:e,component:"broker",pattern:"broker.startup."},!1).items.flatMap(a=>a.kind==="event"&&a.envelope.event.startsWith("broker.startup.")&&a.envelope.event!=="broker.startup.warning"?[a.envelope.event.slice(15)]:[]).at(-1)??null}d(vn,"lastStartupStep");function gn(e,o){const a=vn(e),r=a===null?"it had logged no startup step":`the last startup step it logged was \`${a}\``;if(o.reason==="exited"){const{code:t,signal:s}=o.status;return{text:`exited (code ${t??"null"}, signal ${s??"null"}) before binding its view socket; ${r}`,fields:{reason:"exited",code:t,signal:s,last_startup_step:a}}}return{text:`was still starting after ${Math.round(o.waitedMs/1e3)} s without binding its view socket, so the launcher stopped it; ${r}`,fields:{reason:"timeout",waited_ms:o.waitedMs,last_startup_step:a}}}d(gn,"notReadyDescription");async function yn(e,o){try{await k(e,"crash",{reason:"launch_failed",outcome:v(o)})}catch{}try{G.teardown(e)}catch{}}d(yn,"crashAndTearDown");async function bn(e){const o=(await S().list()).map(({conversation_id:t,path:s})=>({id:t,path:s})),a=o.filter(t=>t.id===e),r=a.length>0?a:o.filter(t=>t.id.startsWith(e));if(r.length===0)throw w(`--fork-from '${e}': no pi session with that id found.`,{next:"Pass a live node id, a real session uuid/prefix, or an absolute .jsonl session path."});if(r.length>1)throw w(`--fork-from '${e}': ambiguous \u2014 ${r.length} sessions match that id prefix; pass the full id or the .jsonl path.`,{next:"Pass the full session uuid or an absolute .jsonl path to disambiguate."});return r[0].path}d(bn,"resolveSessionUuid");async function ie(e){const o=e.trim();if(o==="")throw w("--fork-from requires a node id, session file, or session uuid.",{next:"Pass a live node id, an absolute .jsonl session path, or a session uuid/prefix."});if(o.includes("/")||o.endsWith(".jsonl")){const r=N(_e(o)?o:ke(process.cwd(),o));if(r===null)throw w(`--fork-from '${o}': invalid conversation path.`,{next:"Pass a conversation file path or id."});return(await S().header(r)).path}const a=await u(o);if(a!==null){const r=a.pi_session_file;if(r==null||r==="")throw w(`node ${o} has no pi session yet \u2014 it has not captured a session FILE to fork from (the broker forks a .jsonl path, not a bare id).`,{next:"Pick a node that has captured a session, or drop --fork-from."});const t=N(r);if(t===null)throw w(`node ${o} has no valid conversation id.`,{next:"Pick a node with a captured conversation."});return(await S().header(t)).path}return await bn(o)}d(ie,"resolveForkSource");async function xn(e,o,a,r={}){return e===null?null:e!==void 0&&e!==""?Ee(e).profileId:o!==null?(await u(o))?.profile_id??null:r.readOnlySelection===!0?Oe(a):Re(a)}d(xn,"resolveProfileId");function ae(e){const o=e.modelIntent===void 0?void 0:`${e.modelIntent.family}/${e.modelIntent.strength}`;return dn(e.model,o,e.modelExact===!0)}d(ae,"requestFromLaunch");async function de(e,o,a){const r=a??(e.modelIntent?`${e.modelIntent.family}/${e.modelIntent.strength}`:e.model),t=await wn(o,r,e.modelExact===!0);if(t===null)return e;const{CRTR_MODEL_INTENT:s,...l}=e.env??{};return{...e,model:t.model,modelIntent:{family:U,strength:t.strength},modelExact:void 0,env:{...l,CRTR_MODEL_INTENT:`${U}/${t.strength}`}}}d(de,"appPaidLaunch");async function se(e,o,a){if(e===void 0||e.kind==="logical"&&e.family!==U)return;const r=await sn(e.kind==="logical"?{kind:"concrete",spec:e.spec}:e,a??await cn(),o);if(r!==void 0)throw w(`model '${r.request.spec}' is not registered in this daemon.`,{received:r.request.spec,next:un});const t=await ln(e,o);if(t!==void 0)throw w(`model '${t.spec}' is registered but no configured model route offers it, so no turn could be served.`,{received:t.spec,next:"Pick a model from your configured routes (`crtr sys config get modelLadders`), or add this one to a ladder or route."})}d(se,"assertLaunchModelRegistered");function $n(e,o,a){const r=e??o??null;if(!a&&r===null)throw new Error("spawnChild requires a calling node (CRTR_NODE_ID) or an explicit parent");return r}d($n,"resolveSpawner");async function le(e,o,a){try{tn()}catch{}const r=xe(),t=e.root===!0,s=$n(e.parent,r.nodeId??null,t),l=e.mode??"base",g=e.rootLifecycle??(t?"resident":"terminal"),ce=t&&g==="resident",R=s===null?null:await u(s),V=e.creator===void 0||e.creator===null?null:await u(e.creator);e.nodeId!==void 0&&await Ce(e.nodeId);const y=e.forkFrom!==void 0?await ie(e.forkFrom):void 0,M=y===void 0?null:await be(y),T=await pn([R,V,M],async f=>f?.isolated===!0||f?.run_id!=null&&(await u(f.run_id))?.isolated===!0);if(T&&e.isolated===!1)throw new ne(403,"isolated_run","isolation cannot be turned off under an isolated run",{param:"isolated"});const O=T||e.isolated===!0;if(O&&e.worktree===!0)throw new ne(400,"invalid_request","isolated nodes cannot use a worktree",{param:"worktree"});const C=e.worktree===!0,m=O||C?e.nodeId??await Se():e.nodeId,F=O?e.run!==void 0&&t&&!T?e.cwd:ve(ge(e.run?.grantee??R?.grantee??"app:terminal").nodes,m):e.cwd,h=await xn(e.profile,s,F),X=e.run?.grant_id??R?.grant_id??null,E=e.run??V??R??M,q=await de((await oe(e.kind,l,{lifecycle:g,hasManager:!t,model:e.model,modelOverride:e.model!==void 0,cwd:F,profileId:h,app:E?.grantee??"app:terminal"})).launch,X,e.model);await se(ae(q),{cwd:F,profileId:h}),await _n({grantee:E?.grantee??"app:terminal",sub:E?.sub,grant_id:E?.grant_id});const Y=M?.node_id??null;let b,I=F;const A=C&&await Ie(h)?await Pe(h,e.worktreeCwd??e.cwd,m,e.worktreeBase):void 0;try{C&&A===void 0&&(b=await Be(e.worktreeCwd??e.cwd,m,e.worktreeBase),I=b.path);const f=C?await de((await oe(e.kind,l,{lifecycle:g,hasManager:!t,model:e.model,modelOverride:e.model!==void 0,cwd:I,profileId:h,app:E?.grantee??"app:terminal"})).launch,X,e.model):q;A!==void 0&&(f.worktree=A),C&&await se(ae(f),{cwd:I,profileId:h});const n=await ye({kind:e.kind,mode:l,lifecycle:g,cwd:I,name:e.name??e.kind,description:e.description,parent:t?null:s,creator:e.creator,...e.actor===void 0?{}:{actor:e.actor},forkSourceNode:Y,spawnedBy:t?s??void 0:void 0,profile_id:h,...e.scopes===void 0?{}:{scopes:e.scopes},isolated:O,...e.run===void 0?{}:{run:e.run},...e.causedBy===void 0?{}:{causedBy:e.causedBy},...e.withinCreate===void 0?{}:{withinCreate:e.withinCreate},forkFrom:e.forkFrom,forkSourceFile:y,modelOverride:e.model===void 0?void 0:f.model,...b!==void 0?{managedWorktree:b}:{},...m!==void 0?{nodeId:m}:{},...e.reviewBinding===void 0?{}:{reviewBinding:e.reviewBinding},...e.deadlineAt===void 0?{}:{deadlineAt:e.deadlineAt},...e.outcomeDelivery===void 0?{}:{outcomeDelivery:e.outcomeDelivery},launch:f});if(a?.(n.node_id),e.forkFrom!==void 0)try{await fn(n.node_id,Y??null)}catch(i){throw await k(n.node_id,"crash",{reason:"launch_failed",outcome:v(i)}),i}if(await Ne(n.node_id,e.prompt),e.situationalContext!==void 0&&await Le(n.node_id,Me(e.situationalContext)),o!==void 0)try{o(n.node_id)}catch(i){throw await k(n.node_id,"crash",{reason:"launch_failed",outcome:v(i)}),i}const W=e.prompt!=="",ue=`${W&&e.wakeOrigin!==void 0?`${Ae(e.wakeOrigin)}
|
|
2
2
|
|
|
3
|
-
`:""}${e.prompt}`;l==="orchestrator"&&await Te(n.node_id,{goal:e.prompt.trim()}),await Sn(n);let J;if(y!==void 0)try{const i=
|
|
3
|
+
`:""}${e.prompt}`;l==="orchestrator"&&await Te(n.node_id,{goal:e.prompt.trim()}),await Sn(n);let J;if(y!==void 0)try{const i=N(y);if(i===null)throw new Error(`invalid fork source ${y}`);const c=await S().fork(i,n.node_id);J=(await S().header(c)).path}catch(i){throw await k(n.node_id,"crash",{reason:"launch_failed",outcome:v(i)}),i}const x=Fe(n,{prompt:ue,resumeSessionPath:J});if(x.env={...x.env,CRTR_SUBTREE:await $e(n.node_id)},W){const i=e.wakeOrigin!==void 0?{type:"runtime",kind:"wake",wake:e.wakeOrigin}:{type:"runtime",kind:"kickoff",...n.spawned_by!=null&&n.spawned_by!==""?{spawnedBy:n.spawned_by}:{}};x.env[je]=We(i)}const p=qe();if(await Je(n.profile_id??null)!==null)return await z(n.node_id,new Date().toISOString()),L({level:"info",event:"broker.frozen",node_id:n.node_id,fields:{reason:"remote_environment"}}),{node:await u(n.node_id),frozen:!0,window:null,session:null};const Q=await p.reserveSlot(n.node_id),_=Q?await Ye(n.node_id):null;if(_?.verdict==="too_small"){p.releaseReservation(n.node_id);const i=Xe(_);throw await k(n.node_id,"crash",{reason:"launch_failed",outcome:v(i)}),i}if(!Q||_?.verdict==="denied")return _?.verdict==="denied"&&p.releaseReservation(n.node_id),await z(n.node_id,new Date().toISOString()),L({level:"info",event:"broker.frozen",node_id:n.node_id,fields:_?.verdict==="denied"?{reason:"app_memory",free_bytes:_.free_bytes,needed_bytes:_.needed_bytes}:{reason:"broker_cap",live_count:await p.occupancy(),hard_cap:te().automaticReviveCap}}),{node:await u(n.node_id),frozen:!0,window:null,session:null};const fe=await rn(n.node_id),{automaticReviveCap:we}=te();let $;try{$=await He(n.node_id,{daemonEpoch:p.epoch(),cap:we})}catch(i){if(!(i instanceof ze))throw i;return p.releaseReservation(n.node_id),await z(n.node_id,new Date().toISOString()),L({level:"info",event:"broker.frozen",node_id:n.node_id,fields:{reason:"broker_cap",live_count:i.live,hard_cap:i.cap}}),{node:await u(n.node_id),frozen:!0,window:null,session:null}}x.env={...x.env,CRTR_EXECUTION_ID:$};let P;try{P=await kn(n.node_id,x,{cwd:n.cwd,name:re(n),resuming:!1})}catch(i){throw await j($,{reason:"launch_failed"}),i}finally{p.releaseReservation(n.node_id)}if(P.pid===null){const i=new Error(`broker host returned no pid for ${n.node_id}`);throw await j($,{reason:"launch_failed"}),await k(n.node_id,"crash",{reason:"launch_failed",outcome:v(i)}),D(`failed to launch the broker engine for ${n.node_id} (${n.name}) \u2014 the node was not started.`,`Inspect canonical event diagnostics with \`crtr sys logs --node ${n.node_id}\`, then verify the pi engine can start in this environment.`)}if(await Ue($,n.node_id,P.pid)==="shutdown")throw await j($,{reason:"superseded"}),G.teardown(n.node_id),D(`broker execution was superseded for ${n.node_id}`,"Retry spawning the node.");if(ce&&e.readiness==="await"){const i=await nn(n.node_id,P.exited);if(!i.ready){const c=gn(n.node_id,i);L({level:"error",event:"broker.launch.not_ready",node_id:n.node_id,fields:c.fields});const B=await fe.explanation();throw await yn(n.node_id,new Error(B??c.text)),D(B!==null?`the root broker ${n.node_id} could not start \u2014 ${B}`:`the root broker ${n.node_id} ${c.text} \u2014 it was not started.`,B!==null?"Resolve the cause named above, then retry.":`Inspect canonical event diagnostics with \`crtr sys logs --node ${n.node_id}\`, then retry.`)}}let Z=null,ee=null;if(!t&&s!==null&&an("user").auto_open_child_viewers)try{const i=await Ze(s);if(i!==null&&i.pane!==null&&i.pane!==""){const c=await Qe(n.node_id,i.session??"",{name:re(n),cwd:e.cwd,besidePane:i.pane,waitForBroker:!0,initialWhip:W});c!==null&&c.pane!==null&&c.pane!==""&&(ee=c.session,Z=en(c.pane))}}catch{}return{node:await u(n.node_id),frozen:!1,window:Z,session:ee}}catch(f){throw b!==void 0&&m!==void 0&&await u(m)===null&&await De(b),f}}d(le,"spawnChildPrepared");async function vo(e){return le(e)}d(vo,"spawnChild");async function Sn(e){const o=mn(e.cwd,e.profile_id).plans.get("node:start")??[];await hn(o,{node:{id:e.node_id,name:e.name,kind:e.kind,mode:e.mode,lifecycle:e.lifecycle,cwd:e.cwd,nodeDir:await K(e.node_id),contextDir:await H(e.node_id),jobDir:Ge(e.node_id)},runtime:{isBirth:!0,canvasHome:Ke(),profile:e.profile_id??null}})}d(Sn,"invokeBirthLifecycleHooks");const Cn=new Set(["initial-prompt.md","yield-message.md","result.json","jobs"]);async function go(e,o,a){const r=await u(e);if(r===null)throw w(`unknown node: ${e}`,{received:e,next:"List nodes and pass the id of a node with a captured pi session."});const t=await ie(e),s=await H(e);try{await S().header(N(t)),he(s,pe.R_OK)}catch(l){throw new Error(`cannot fork ${e}: its conversation or context is unreadable \u2014 ${l.message}`)}return le({kind:r.kind,mode:"base",cwd:r.cwd,prompt:"",root:!0,readiness:"await",forkFrom:e,...a===void 0?{}:{actor:a},profile:r.profile_id,model:r.model_override??void 0,...o===void 0?{}:{scopes:o}},async l=>{const g=await H(l);Ve(await K(e),s,await K(l),g,Cn)})}d(go,"forkNode");export{de as appPaidLaunch,se as assertLaunchModelRegistered,go as forkNode,Sn as invokeBirthLifecycleHooks,ie as resolveForkSource,xn as resolveProfileId,$n as resolveSpawner,vo as spawnChild,le as spawnChildPrepared};
|