@north-light/cli 0.3.522 → 0.3.523

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.
@@ -1 +1 @@
1
- var H=Object.defineProperty;var n=(e,t)=>H(e,"name",{value:t,configurable:!0});import{defineBranch as I,defineRoot as y,GLOBAL_TOKENS as R}from"./core/command.js";import{createCoreHookCatalog as x}from"./core/command-hooks/catalog.js";import{composeCoreHooks as O}from"./core/command-hooks/compose.js";import{mark as p}from"./core/timing.js";import{envScopes as D,isSandboxedNode as E,scopeAllowed as G}from"./shared/env.js";const S="crtr: agentic runtime.",b=[{name:"--json",desc:"stdout as the leaf's declared outputs in raw JSON instead of prose \u2014 for scripts (a cron's bash, external tooling) that must branch on canvas state; prose stays the contract for what you read yourself."}],k=Object.assign(Object.create(null),{doc:n(async()=>(await import("./commands/doc.js")).registerDoc(),"doc"),"custom-object":n(async()=>(await import("./commands/custom-object.js")).registerCustomObject(),"custom-object"),profile:n(async()=>(await import("./commands/profile.js")).registerProfile(),"profile"),pkg:n(async()=>(await import("./commands/pkg.js")).registerPkg(),"pkg"),human:n(async()=>(await import("./commands/human.js")).registerHuman(),"human"),sys:n(async()=>(await import("./commands/sys.js")).registerSys(),"sys"),node:n(async()=>(await import("./commands/node.js")).registerNode(),"node"),push:n(async()=>(await import("./commands/push.js")).registerPush(),"push"),cron:n(async()=>(await import("./commands/cron.js")).registerCron(),"cron"),canvas:n(async()=>(await import("./commands/canvas.js")).registerCanvas(),"canvas"),surface:n(async()=>(await import("./commands/surface.js")).registerSurface(),"surface")}),d=Object.freeze(Object.keys(k)),U={human:["crtr:act"],cron:["crtr:schedule"],doc:["crtr:memory:read:user","crtr:memory:rw:user"]};function B(e){const t=D();return t===null?e:e.filter(r=>{const o=U[r.name];return o===void 0||o.some(s=>G(t,s))||r.name==="doc"&&process.env.CRTR_GRANTEE?.startsWith("app:")===!0})}n(B,"allowedSubtrees");const j=new Map;function N(e){let t=j.get(e);return t===void 0&&(t=k[e](),j.set(e,t)),t}n(N,"loadSubtree");function v(e){return Promise.all(d.filter(t=>e.has(t)).map(N))}n(v,"loadCoreSubtreesNamed");function C(){return v(new Set(d))}n(C,"loadCoreSubtrees");function P(e){const t=new Set;for(const r of e){const o=r.split(" ")[0];d.includes(o)&&t.add(o)}return t}n(P,"subtreesNamedBy");let T;function te(){return p("cli.hooks.catalog"),T??=C().then(x),T}n(te,"coreHookCatalog");function L(){let e;return()=>(e??=(async()=>{const{compileHookRegistry:t,declaredCommandHookTargets:r,effectiveHookPlugins:o}=await import("./core/command-hooks/discovery.js"),s=o(),a=E()?await(await import("./core/command-hooks/transport/plan.js")).remoteHookPlan(process.cwd()):[];if(p("cli.hooks.effective_plugins",{count:s.length+a.length}),s.length===0&&a.length===0)return p("cli.hooks.empty_registry"),t(x([]),[]);const c=E()?s.filter(l=>l.scope==="project"):s,i=P([...r(c),...a.map(l=>l.target)]);return p("cli.hooks.catalog",{subtrees:[...i].join(",")}),t(x(await v(i)),c,a)})(),e)}n(L,"hookRegistryLoader");function g(e){const t=new Set,r=n((o,s)=>{if(!(o.kind==="branch"&&o.passthrough!==void 0)&&(t.add(s),o.kind==="branch"))for(const a of o.children)r(a,`${s} ${a.name}`)},"visit");for(const o of e)r(o,o.name);return t}n(g,"commandPathsFor");async function ne(){return g(await C())}n(ne,"coreCommandPaths");async function oe(e){return g(await v(P(e)))}n(oe,"coreCommandPathsCovering");function q(e){const t=[],r=n((o,s)=>{o.extensible===!0&&t.push(s);for(const a of o.children)a.kind==="branch"&&r(a,[...s,a.name])},"visit");for(const o of e)r(o,[o.name]);return t}n(q,"extensibleBranchPaths");const z=Object.freeze(["human","sys tutorial"]);async function M(){return new Set(z)}n(M,"extensibleCoreBranches");async function re(){return new Set(q(await C()).map(e=>e.join(" ")))}n(re,"declaredExtensibleCoreBranches");function $(e,t){const{listing:r,...o}=e.help;return I({name:e.name,description:e.description,whenToUse:e.whenToUse,tier:e.tier,help:o,rootEntry:e.rootEntry,extensible:e.extensible,plugin:e.plugin,slash:e.slash,passthrough:e.passthrough,children:t})}n($,"rebuildBranch");async function _(e,t,r){if(t.size===0)return e;const[{buildExternalCommandSnapshot:o},{composeCoreBranchMounts:s}]=await Promise.all([import("./core/command-plugins/discovery.js"),import("./core/command-plugins/compose.js")]),a=o(new Set(d),void 0,void 0,r,t),c=n((i,l)=>{let h=!1;const w=i.children.map(m=>{if(m.kind!=="branch")return m;const u=c(m,[...l,m.name]);return u!==m&&(h=!0),u}),f=i.extensible===!0?s(a.coreMounts,l):[];return h||f.length>0?$(i,[...w,...f]):i},"composeBranch");return e.map(i=>c(i,[i.name]))}n(_,"composeCorePluginMounts");async function F(e,t){const{validateEffectiveCommandPlugins:r}=await import("./core/command-plugins/discovery.js"),s=r(new Set(d),void 0,void 0,void 0,t).flatMap(c=>c.manifest===void 0?[]:[c.manifest]).filter(c=>c.coreMounts.some(i=>i.parent[0]===e));if(s.length===0)return null;const a=P(s.flatMap(c=>[...c.coreMounts.map(i=>i.parent.join(" ")),...Object.keys(c.helpAddenda??{})]));return a.add(e),g(await v(a))}n(F,"dispatchCommandPaths");function A(e,t){const r=e.slice(2).filter(o=>!R.has(o));return r[0]==="sys"&&r[1]===t}n(A,"isSysInvocation");const J=[["surface"],["sys"],["pkg"],["profile","default"],["canvas","chord"],["canvas","config"],["canvas","use"],["canvas","browse"],["canvas","issue"]];function se(e){const t=e.slice(2).filter(o=>!R.has(o)),r=J.find(o=>o.every((s,a)=>t[a]===s));return r===void 0?null:r.join(" ")}n(se,"personOnlyInvocation");function ae(e){return A(e,"daemon")}n(ae,"isDaemonControlInvocation");function ie(e){return A(e,"migrate")}n(ie,"isLayoutMigrationInvocation");async function ce(){const{registerDaemonControlSys:e}=await import("./commands/sys/daemon.js");return y({tagline:S,globals:b,subtrees:[e()]})}n(ce,"resolveDaemonControlRoot");async function ue(){const[{defineSysBranch:e},{sysMigrateLeaf:t}]=await Promise.all([import("./commands/sys/branch.js"),import("./commands/sys/migrate.js")]);return y({tagline:S,globals:b,subtrees:[e([t])]})}n(ue,"resolveLayoutMigrationRoot");async function le(e){return(e!==void 0?await K(e):null)??W()}n(le,"resolveRoot");async function K(e){if(k[e]===void 0)return null;const t=await N(e),r=await M(),o=[...r].some(a=>a.split(" ")[0]===e)?await F(e,r):null,s=B(o===null?[t]:await _([t],r,o));return s.length>0?y({tagline:S,globals:b,subtrees:O(s,L())}):null}n(K,"resolveCoreRoot");async function W(){const e=await C(),[{buildExternalCommandSnapshot:t},{composeExternalSubtrees:r,composeSandboxProviderSubtrees:o},{qualifiedTopLevelCommandName:s}]=await Promise.all([import("./core/command-plugins/discovery.js"),import("./core/command-plugins/compose.js"),import("./core/command-manifests/registry.js")]),a=await M(),c=await _(e,a,g(e)),i=t(new Set(d),void 0,void 0,g(e),a);let l=r(i);if(E()){const{cliClient:h}=await import("./commands/api-client.js");p("cli.providers.request");const{providers:w}=await h().request("GET","/v1/providers/tools");p("cli.providers.fetched",{providers:w.length});const f=o(w,new Set(d)),m=new Set(f.map(u=>u.name));l=[...f,...r({...i,contributions:i.contributions.map(u=>m.has(u.node.name)?{...u,node:{...u.node,name:s(u.contributor,u.node.name)}}:u)})]}return y({tagline:S,globals:b,subtrees:[...O(B(c),L()),...l]})}n(W,"buildRoot");export{z as EXTENSIBLE_CORE_BRANCHES,d as SUBTREE_NAMES,W as buildRoot,ne as coreCommandPaths,oe as coreCommandPathsCovering,te as coreHookCatalog,re as declaredExtensibleCoreBranches,M as extensibleCoreBranches,ae as isDaemonControlInvocation,ie as isLayoutMigrationInvocation,se as personOnlyInvocation,K as resolveCoreRoot,ce as resolveDaemonControlRoot,ue as resolveLayoutMigrationRoot,le as resolveRoot};
1
+ var D=Object.defineProperty;var o=(e,t)=>D(e,"name",{value:t,configurable:!0});import{defineBranch as I,defineRoot as y,GLOBAL_TOKENS as O}from"./core/command.js";import{createCoreHookCatalog as x}from"./core/command-hooks/catalog.js";import{composeCoreHooks as R}from"./core/command-hooks/compose.js";import{mark as p}from"./core/timing.js";import{envScopes as G,isSandboxedNode as E,scopeAllowed as U}from"./shared/env.js";const S="crtr: agentic runtime.",b=[{name:"--json",desc:"stdout as the leaf's declared outputs in raw JSON instead of prose \u2014 for scripts (a cron's bash, external tooling) that must branch on canvas state; prose stays the contract for what you read yourself."}],k=Object.assign(Object.create(null),{doc:o(async()=>(await import("./commands/doc.js")).registerDoc(),"doc"),"custom-object":o(async()=>(await import("./commands/custom-object.js")).registerCustomObject(),"custom-object"),profile:o(async()=>(await import("./commands/profile.js")).registerProfile(),"profile"),pkg:o(async()=>(await import("./commands/pkg.js")).registerPkg(),"pkg"),human:o(async()=>(await import("./commands/human.js")).registerHuman(),"human"),sys:o(async()=>(await import("./commands/sys.js")).registerSys(),"sys"),node:o(async()=>(await import("./commands/node.js")).registerNode(),"node"),push:o(async()=>(await import("./commands/push.js")).registerPush(),"push"),cron:o(async()=>(await import("./commands/cron.js")).registerCron(),"cron"),canvas:o(async()=>(await import("./commands/canvas.js")).registerCanvas(),"canvas"),surface:o(async()=>(await import("./commands/surface.js")).registerSurface(),"surface")}),d=Object.freeze(Object.keys(k)),q={human:["crtr:act"],cron:["crtr:schedule"],doc:["crtr:memory:read:user","crtr:memory:rw:user"]};function B(e){const t=G();return t===null?e:e.filter(r=>{const n=q[r.name];return n===void 0||n.some(s=>U(t,s))||r.name==="doc"&&process.env.CRTR_GRANTEE?.startsWith("app:")===!0})}o(B,"allowedSubtrees");const L=new Map;function N(e){let t=L.get(e);return t===void 0&&(t=k[e](),L.set(e,t)),t}o(N,"loadSubtree");function v(e){return Promise.all(d.filter(t=>e.has(t)).map(N))}o(v,"loadCoreSubtreesNamed");function C(){return v(new Set(d))}o(C,"loadCoreSubtrees");function P(e){const t=new Set;for(const r of e){const n=r.split(" ")[0];d.includes(n)&&t.add(n)}return t}o(P,"subtreesNamedBy");let j;function oe(){return p("cli.hooks.catalog"),j??=C().then(x),j}o(oe,"coreHookCatalog");function T(){let e;return()=>(e??=(async()=>{const{compileHookRegistry:t,declaredCommandHookTargets:r,effectiveHookPlugins:n}=await import("./core/command-hooks/discovery.js"),s=n(),a=E()?await(await import("./core/command-hooks/transport/plan.js")).remoteHookPlan(process.cwd()):[];if(p("cli.hooks.effective_plugins",{count:s.length+a.length}),s.length===0&&a.length===0)return p("cli.hooks.empty_registry"),t(x([]),[]);const c=E()?s.filter(l=>l.scope==="project"):s,i=P([...r(c),...a.map(l=>l.target)]);return p("cli.hooks.catalog",{subtrees:[...i].join(",")}),t(x(await v(i)),c,a)})(),e)}o(T,"hookRegistryLoader");function g(e){const t=new Set,r=o((n,s)=>{if(!(n.kind==="branch"&&n.passthrough!==void 0)&&(t.add(s),n.kind==="branch"))for(const a of n.children)r(a,`${s} ${a.name}`)},"visit");for(const n of e)r(n,n.name);return t}o(g,"commandPathsFor");async function re(){return g(await C())}o(re,"coreCommandPaths");async function se(e){return g(await v(P(e)))}o(se,"coreCommandPathsCovering");function z(e){const t=[],r=o((n,s)=>{n.extensible===!0&&t.push(s);for(const a of n.children)a.kind==="branch"&&r(a,[...s,a.name])},"visit");for(const n of e)r(n,[n.name]);return t}o(z,"extensibleBranchPaths");const W=Object.freeze(["human","sys tutorial"]);async function _(){return new Set(W)}o(_,"extensibleCoreBranches");async function ae(){return new Set(z(await C()).map(e=>e.join(" ")))}o(ae,"declaredExtensibleCoreBranches");function $(e,t){const{listing:r,...n}=e.help;return I({name:e.name,description:e.description,whenToUse:e.whenToUse,tier:e.tier,help:n,rootEntry:e.rootEntry,extensible:e.extensible,plugin:e.plugin,slash:e.slash,passthrough:e.passthrough,children:t})}o($,"rebuildBranch");async function A(e,t,r){if(t.size===0)return e;const[{buildExternalCommandSnapshot:n},{composeCoreBranchMounts:s}]=await Promise.all([import("./core/command-plugins/discovery.js"),import("./core/command-plugins/compose.js")]),a=n(new Set(d),void 0,void 0,r,t),c=o((i,l)=>{let h=!1;const w=i.children.map(m=>{if(m.kind!=="branch")return m;const u=c(m,[...l,m.name]);return u!==m&&(h=!0),u}),f=i.extensible===!0?s(a.coreMounts,l):[];return h||f.length>0?$(i,[...w,...f]):i},"composeBranch");return e.map(i=>c(i,[i.name]))}o(A,"composeCorePluginMounts");async function F(e,t){const{validateEffectiveCommandPlugins:r}=await import("./core/command-plugins/discovery.js"),s=r(new Set(d),void 0,void 0,void 0,t).flatMap(c=>c.manifest===void 0?[]:[c.manifest]).filter(c=>c.coreMounts.some(i=>i.parent[0]===e));if(s.length===0)return null;const a=P(s.flatMap(c=>[...c.coreMounts.map(i=>i.parent.join(" ")),...Object.keys(c.helpAddenda??{})]));return a.add(e),g(await v(a))}o(F,"dispatchCommandPaths");function M(e,t){const r=e.slice(2).filter(n=>!O.has(n));return r[0]==="sys"&&r[1]===t}o(M,"isSysInvocation");const J=[["surface"],["sys"],["pkg"],["profile","default"],["canvas","chord"],["canvas","config"],["canvas","use"],["canvas","browse"],["canvas","issue"]],K=[["sys","feedback"]];function H(e,t){return t.every((r,n)=>e[n]===r)}o(H,"startsWithPath");function ie(e){const t=e.slice(2).filter(n=>!O.has(n));if(K.some(n=>H(t,n)))return null;const r=J.find(n=>H(t,n));return r===void 0?null:r.join(" ")}o(ie,"personOnlyInvocation");function ce(e){return M(e,"daemon")}o(ce,"isDaemonControlInvocation");function ue(e){return M(e,"migrate")}o(ue,"isLayoutMigrationInvocation");async function le(){const{registerDaemonControlSys:e}=await import("./commands/sys/daemon.js");return y({tagline:S,globals:b,subtrees:[e()]})}o(le,"resolveDaemonControlRoot");async function me(){const[{defineSysBranch:e},{sysMigrateLeaf:t}]=await Promise.all([import("./commands/sys/branch.js"),import("./commands/sys/migrate.js")]);return y({tagline:S,globals:b,subtrees:[e([t])]})}o(me,"resolveLayoutMigrationRoot");async function de(e){return(e!==void 0?await X(e):null)??Y()}o(de,"resolveRoot");async function X(e){if(k[e]===void 0)return null;const t=await N(e),r=await _(),n=[...r].some(a=>a.split(" ")[0]===e)?await F(e,r):null,s=B(n===null?[t]:await A([t],r,n));return s.length>0?y({tagline:S,globals:b,subtrees:R(s,T())}):null}o(X,"resolveCoreRoot");async function Y(){const e=await C(),[{buildExternalCommandSnapshot:t},{composeExternalSubtrees:r,composeSandboxProviderSubtrees:n},{qualifiedTopLevelCommandName:s}]=await Promise.all([import("./core/command-plugins/discovery.js"),import("./core/command-plugins/compose.js"),import("./core/command-manifests/registry.js")]),a=await _(),c=await A(e,a,g(e)),i=t(new Set(d),void 0,void 0,g(e),a);let l=r(i);if(E()){const{cliClient:h}=await import("./commands/api-client.js");p("cli.providers.request");const{providers:w}=await h().request("GET","/v1/providers/tools");p("cli.providers.fetched",{providers:w.length});const f=n(w,new Set(d)),m=new Set(f.map(u=>u.name));l=[...f,...r({...i,contributions:i.contributions.map(u=>m.has(u.node.name)?{...u,node:{...u.node,name:s(u.contributor,u.node.name)}}:u)})]}return y({tagline:S,globals:b,subtrees:[...R(B(c),T()),...l]})}o(Y,"buildRoot");export{W as EXTENSIBLE_CORE_BRANCHES,d as SUBTREE_NAMES,Y as buildRoot,re as coreCommandPaths,se as coreCommandPathsCovering,oe as coreHookCatalog,ae as declaredExtensibleCoreBranches,_ as extensibleCoreBranches,ce as isDaemonControlInvocation,ue as isLayoutMigrationInvocation,ie as personOnlyInvocation,X as resolveCoreRoot,le as resolveDaemonControlRoot,me as resolveLayoutMigrationRoot,de as resolveRoot};
@@ -1 +1 @@
1
- var v=Object.defineProperty;var a=(e,n)=>v(e,"name",{value:n,configurable:!0});import{defineBranch as u,defineLeaf as r}from"../../core/command.js";import{InputError as i}from"../../core/io.js";import{validateEnvVarName as p}from"../../core/env-name.js";import{stripSingleTrailingLineEnding as l}from"../profile/env.js";import{cliClient as t}from"../api-client.js";function s(e){const n=e.name;if(!p(n).isValid)throw new i({error:"invalid_name",message:"invalid env var name",field:"name",next:"Use an env-var-shaped name."});return n}a(s,"name");const y=u({name:"env",description:"manage env vars for every profile of the calling app",whenToUse:"a plugin or the feedback pipeline needs a credential available to every node in this app",help:{name:"sys env",summary:"write-only app env store; list returns names, never values",model:"A stored value reaches new launches immediately, and a running node on its next revive. Profile env overrides app env."},children:[r({name:"set",description:"store one app env value from stdin",whenToUse:"a plugin declares a required env name, or the feedback endpoint and token are being configured",help:{name:"sys env set",summary:"set one app-wide env variable without printing its value",params:[{kind:"flag",name:"name",type:"string",required:!0,constraint:"Env var name. CRTR_* and HOME are reserved, except CRTR_FEEDBACK_ENDPOINT and CRTR_FEEDBACK_TOKEN."},{kind:"stdin",name:"value",required:!0,constraint:"Pipe value on stdin, never argv. One trailing line ending is removed."}],output:[{name:"created",constraint:"Never includes a stored value.",type:"boolean",required:!0},{name:"follow_up",constraint:"Never includes a stored value.",type:"string",required:!0}],outputKind:"object",effects:["Writes the 0600 app env store; a running node picks up changes on next revive."]},run:a(async e=>{const n=l(e.value);if(!n)throw new i({error:"empty_value",message:"env var value is empty",field:"value",next:"Pipe a non-empty value on stdin."});const{changed:o}=await t().setAppEnv(s(e),n);return{created:o,follow_up:"A running node picks up the change on its next revive."}},"run")}),r({name:"list",description:"list app env names, not values",whenToUse:"checking which plugin credentials are set",help:{name:"sys env list",summary:"list stored app env names only",params:[],output:[{name:"names",constraint:"Never includes a stored value.",type:"string[]",required:!0},{name:"count",constraint:"Never includes a stored value.",type:"int",required:!0}],outputKind:"object",effects:["Read-only; never returns values."]},run:a(async()=>{const{names:e}=await t().listAppEnv();return{names:e,count:e.length}},"run")}),r({name:"remove",description:"remove one app env value",whenToUse:"the app no longer needs a plugin credential",help:{name:"sys env remove",summary:"delete a stored app env variable",params:[{kind:"flag",name:"name",type:"string",required:!0,constraint:"Env var name."}],output:[{name:"removed",constraint:"Never includes a stored value.",type:"boolean",required:!0}],outputKind:"object",effects:["A running node picks up the removal on its next revive."]},run:a(async e=>({removed:(await t().removeAppEnv(s(e))).changed}),"run")})]});export{y as sysEnvBranch};
1
+ var v=Object.defineProperty;var r=(e,n)=>v(e,"name",{value:n,configurable:!0});import{defineBranch as p,defineLeaf as a}from"../../core/command.js";import{InputError as i}from"../../core/io.js";import{validateEnvVarName as d}from"../../core/env-name.js";import{stripSingleTrailingLineEnding as u}from"../profile/env.js";import{cliClient as t}from"../api-client.js";function s(e){const n=e.name;if(!d(n).isValid)throw new i({error:"invalid_name",message:"invalid env var name",field:"name",next:"Use an env-var-shaped name."});return n}r(s,"name");const y=p({name:"env",description:"manage env vars for every profile of the calling app",whenToUse:"a plugin needs a credential available to every node in this app, or a person is configuring where feedback is sent",help:{name:"sys env",summary:"write-only app env store; list returns names, never values",model:"A stored value reaches new launches immediately, and a running node on its next revive. Profile env overrides app env. CRTR_FEEDBACK_ENDPOINT and CRTR_FEEDBACK_TOKEN are deployment-wide: every app reads them, and only a person sets or removes them."},children:[a({name:"set",description:"store one app env value from stdin",whenToUse:"a plugin declares a required env name, or the feedback endpoint and token are being configured",help:{name:"sys env set",summary:"set one app-wide env variable without printing its value",params:[{kind:"flag",name:"name",type:"string",required:!0,constraint:"Env var name. CRTR_* and HOME are reserved, except CRTR_FEEDBACK_ENDPOINT and CRTR_FEEDBACK_TOKEN, which are stored once for every app."},{kind:"stdin",name:"value",required:!0,constraint:"Pipe value on stdin, never argv. One trailing line ending is removed."}],output:[{name:"created",constraint:"Never includes a stored value.",type:"boolean",required:!0},{name:"follow_up",constraint:"Never includes a stored value.",type:"string",required:!0}],outputKind:"object",effects:["Writes the 0600 env store of this app, or the deployment-wide store for CRTR_FEEDBACK_ENDPOINT and CRTR_FEEDBACK_TOKEN; a running node picks up changes on next revive."]},run:r(async e=>{const n=u(e.value);if(!n)throw new i({error:"empty_value",message:"env var value is empty",field:"value",next:"Pipe a non-empty value on stdin."});const{changed:o}=await t().setAppEnv(s(e),n);return{created:o,follow_up:"A running node picks up the change on its next revive."}},"run")}),a({name:"list",description:"list app env names, not values",whenToUse:"checking which plugin credentials are set",help:{name:"sys env list",summary:"list stored app env names only",params:[],output:[{name:"names",constraint:"Never includes a stored value.",type:"string[]",required:!0},{name:"count",constraint:"Never includes a stored value.",type:"int",required:!0}],outputKind:"object",effects:["Read-only; never returns values."]},run:r(async()=>{const{names:e}=await t().listAppEnv();return{names:e,count:e.length}},"run")}),a({name:"remove",description:"remove one app env value",whenToUse:"the app no longer needs a plugin credential",help:{name:"sys env remove",summary:"delete a stored app env variable",params:[{kind:"flag",name:"name",type:"string",required:!0,constraint:"Env var name."}],output:[{name:"removed",constraint:"Never includes a stored value.",type:"boolean",required:!0}],outputKind:"object",effects:["A running node picks up the removal on its next revive."]},run:r(async e=>({removed:(await t().removeAppEnv(s(e))).changed}),"run")})]});export{y as sysEnvBranch};
@@ -1,3 +1,5 @@
1
+ export declare const isDeploymentName: (name: string) => boolean;
2
+ /** Every var an app's processes receive: its own store plus the deployment-wide one. */
1
3
  export declare function readAppEnvVars(app: string): Record<string, string>;
2
4
  export declare function listAppEnvNames(app: string): string[];
3
5
  export declare function setAppEnvVar(app: string, name: string, value: string): boolean;
@@ -1,2 +1,2 @@
1
- var h=Object.defineProperty;var o=(r,e)=>h(r,"name",{value:e,configurable:!0});import{existsSync as b,readFileSync as w,writeFileSync as O,chmodSync as S,renameSync as j}from"node:fs";import{basename as A,dirname as a,join as E}from"node:path";import{appSpace as x,secretsDir as N}from"../layout.js";import{ensureDir as f}from"../fs-utils.js";import{withExclusiveDirectoryLock as u}from"../exclusive-lock.js";import{isReservedAppEnvName as p}from"./env-store.js";import{validateEnvVarName as m}from"../env-name.js";import{usage as v}from"../errors.js";function s(r){return E(N(),"env",A(x(r).root),"_app")}o(s,"storePath");function c(r){const e=Object.create(null);try{if(!b(s(r)))return e;const t=JSON.parse(w(s(r),"utf8"));if(!t||typeof t!="object"||!("vars"in t)||!t.vars||typeof t.vars!="object"||Array.isArray(t.vars))return e;for(const[n,i]of Object.entries(t.vars))m(n).isValid&&!p(n)&&typeof i=="string"&&!i.includes("\0")&&(e[n]=i)}catch{}return e}o(c,"read");function d(r,e){const t=s(r);f(a(t));const n=`${t}.tmp.${process.pid}.${Math.random().toString(36).slice(2)}`;O(n,JSON.stringify({vars:e})+`
2
- `,{mode:384}),S(n,384),j(n,t)}o(d,"write");function l(r){if(!m(r).isValid||p(r))throw v(`invalid or reserved env var name: ${r}`,{field:"name"})}o(l,"validate");function M(r){return{...c(r)}}o(M,"readAppEnvVars");function P(r){return Object.keys(c(r)).sort()}o(P,"listAppEnvNames");function R(r,e,t){if(l(e),!t||t.includes("\0"))throw v("a non-empty env value without NUL bytes is required",{field:"value"});const n=s(r);return f(a(n)),u(`${n}.lock`,()=>{const i=c(r),y=!Object.hasOwn(i,e);return i[e]=t,d(r,i),y})}o(R,"setAppEnvVar");function U(r,e){l(e);const t=s(r);return f(a(t)),u(`${t}.lock`,()=>{const n=c(r);return Object.hasOwn(n,e)?(delete n[e],d(r,n),!0):!1})}o(U,"removeAppEnvVar");export{P as listAppEnvNames,M as readAppEnvVars,U as removeAppEnvVar,R as setAppEnvVar};
1
+ var N=Object.defineProperty;var o=(t,r)=>N(t,"name",{value:r,configurable:!0});import{existsSync as O,readFileSync as S,writeFileSync as w,chmodSync as A,renameSync as b}from"node:fs";import{basename as D,dirname as p,join as u}from"node:path";import{appSpace as _,secretsDir as f}from"../layout.js";import{ensureDir as m}from"../fs-utils.js";import{withExclusiveDirectoryLock as j}from"../exclusive-lock.js";import{isReservedEnvName as x}from"./env-store.js";import{validateEnvVarName as d}from"../env-name.js";import{usage as l}from"../errors.js";const T=new Set(["CRTR_FEEDBACK_ENDPOINT","CRTR_FEEDBACK_TOKEN"]),s=o(t=>T.has(t),"isDeploymentName"),v=o(t=>!x(t),"isAppName"),E={path:o(()=>u(f(),"env","_deployment"),"path"),admits:s},h=o(t=>({path:o(()=>u(f(),"env",D(_(t).root),"_app"),"path"),admits:v}),"appStore"),V=o((t,r)=>s(r)?E:h(t),"storeFor");function a(t){const r=Object.create(null);try{if(!O(t.path()))return r;const e=JSON.parse(S(t.path(),"utf8"));if(!e||typeof e!="object"||!("vars"in e)||!e.vars||typeof e.vars!="object"||Array.isArray(e.vars))return r;for(const[n,i]of Object.entries(e.vars))d(n).isValid&&t.admits(n)&&typeof i=="string"&&!i.includes("\0")&&(r[n]=i)}catch{}return r}o(a,"read");function R(t,r){const e=t.path();m(p(e));const n=`${e}.tmp.${process.pid}.${Math.random().toString(36).slice(2)}`;w(n,JSON.stringify({vars:r})+`
2
+ `,{mode:384}),A(n,384),b(n,e)}o(R,"write");function F(t){if(!d(t).isValid||!(v(t)||s(t)))throw l(`invalid or reserved env var name: ${t}`,{field:"name"})}o(F,"validate");function y(t,r,e){F(r);const n=V(t,r);return m(p(n.path())),j(`${n.path()}.lock`,()=>{const i=a(n),c=e(i);return c!==null&&R(n,i),c})}o(y,"update");function $(t){return{...a(h(t)),...a(E)}}o($,"readAppEnvVars");function Y(t){return Object.keys($(t)).sort()}o(Y,"listAppEnvNames");function q(t,r,e){if(!e||e.includes("\0"))throw l("a non-empty env value without NUL bytes is required",{field:"value"});return y(t,r,n=>{const i=!Object.hasOwn(n,r);return n[r]=e,i})}o(q,"setAppEnvVar");function I(t,r){return y(t,r,e=>Object.hasOwn(e,r)?(delete e[r],!0):null)??!1}o(I,"removeAppEnvVar");export{s as isDeploymentName,Y as listAppEnvNames,$ as readAppEnvVars,I as removeAppEnvVar,q as setAppEnvVar};
@@ -1,7 +1,4 @@
1
1
  export declare function isReservedEnvName(name: string): boolean;
2
- /** The app env store's reservation: `isReservedEnvName` minus the admitted
3
- * deployment names. Both its write and read paths use this one rule. */
4
- export declare function isReservedAppEnvName(name: string): boolean;
5
2
  /** Every stored variable NAME for a profile, sorted. Never returns values. */
6
3
  export declare function listProfileEnvNames(profileId: string): string[];
7
4
  /** Set one variable, replacing any prior value under the same name. Holds the
@@ -1,2 +1,2 @@
1
- var h=Object.defineProperty;var n=(e,t)=>h(e,"name",{value:t,configurable:!0});import{existsSync as p,readFileSync as R,renameSync as S,writeFileSync as y,chmodSync as N}from"node:fs";import{dirname as _}from"node:path";import{profileSpace as O}from"../layout.js";import{loadExactProfileManifest as u,withProfileManifestLock as f}from"./manifest.js";import{ensureDir as w}from"../fs-utils.js";import{notFound as P,usage as v}from"../errors.js";const b="CRTR_",x=new Set(["HOME"]),T=new Set(["CRTR_FEEDBACK_ENDPOINT","CRTR_FEEDBACK_TOKEN"]);function c(e){return e.startsWith(b)||x.has(e)}n(c,"isReservedEnvName");function j(e){return c(e)&&!T.has(e)}n(j,"isReservedAppEnvName");function E(e){return e.includes("\0")}n(E,"hasNulByte");function m(e){const t=u(e);return O(t.manifest.grantee??"app:terminal",e).env}n(m,"envPath");function s(e){const t=m(e),r=Object.create(null);if(!p(t))return{vars:r};try{const o=JSON.parse(R(t,"utf8"));for(const[i,a]of Object.entries(o.vars??{}))typeof a=="string"&&(E(a)||c(i)||(r[i]=a))}catch{}return{vars:r}}n(s,"readStoreUnlocked");function l(e,t){const r=m(e);w(_(r));const o=`${r}.tmp.${process.pid}.${Math.random().toString(36).slice(2)}`;y(o,JSON.stringify(t,null,2)+`
2
- `,{mode:384}),N(o,384),S(o,r)}n(l,"writeStoreAtomic");function d(e){try{u(e)}catch(t){throw t instanceof Error&&t.message.startsWith("profile not found:")?P(`profile not found: ${e}`,{received:e}):t}}n(d,"requireProfileExists");function $(e){return Object.keys(s(e).vars).sort()}n($,"listProfileEnvNames");function k(e,t,r){if(c(t))throw v(`env var name is reserved by crtr: ${t}`,{received:t,field:"name",next:"crtr identity/routing names (CRTR_* and HOME) cannot be stored in a profile env store \u2014 a stored value under one of these names could redirect a broker to a different canvas home. Choose a different name."});if(E(r))throw v("env var value contains a NUL byte, which no OS accepts in an environment variable",{field:"value",next:"Remove NUL bytes from the piped value and retry."});return f(e,()=>{d(e);const o=s(e),i=!Object.hasOwn(o.vars,t);return o.vars[t]=r,l(e,o),i})}n(k,"setProfileEnvVar");function B(e,t){return f(e,()=>{d(e);const r=s(e);return Object.hasOwn(r.vars,t)?(delete r.vars[t],l(e,r),!0):!1})}n(B,"removeProfileEnvVar");function K(e){if(e===null||e==="")return{};try{return{...s(e).vars}}catch{return{}}}n(K,"readProfileEnvVars");export{j as isReservedAppEnvName,c as isReservedEnvName,$ as listProfileEnvNames,K as readProfileEnvVars,B as removeProfileEnvVar,k as setProfileEnvVar};
1
+ var E=Object.defineProperty;var n=(e,t)=>E(e,"name",{value:t,configurable:!0});import{existsSync as p,readFileSync as y,renameSync as S,writeFileSync as O,chmodSync as b}from"node:fs";import{dirname as w}from"node:path";import{profileSpace as R}from"../layout.js";import{loadExactProfileManifest as c,withProfileManifestLock as u}from"./manifest.js";import{ensureDir as x}from"../fs-utils.js";import{notFound as N,usage as f}from"../errors.js";const P="CRTR_",g=new Set(["HOME"]);function v(e){return e.startsWith(P)||g.has(e)}n(v,"isReservedEnvName");function m(e){return e.includes("\0")}n(m,"hasNulByte");function l(e){const t=c(e);return R(t.manifest.grantee??"app:terminal",e).env}n(l,"envPath");function s(e){const t=l(e),r=Object.create(null);if(!p(t))return{vars:r};try{const o=JSON.parse(y(t,"utf8"));for(const[i,a]of Object.entries(o.vars??{}))typeof a=="string"&&(m(a)||v(i)||(r[i]=a))}catch{}return{vars:r}}n(s,"readStoreUnlocked");function d(e,t){const r=l(e);x(w(r));const o=`${r}.tmp.${process.pid}.${Math.random().toString(36).slice(2)}`;O(o,JSON.stringify(t,null,2)+`
2
+ `,{mode:384}),b(o,384),S(o,r)}n(d,"writeStoreAtomic");function h(e){try{c(e)}catch(t){throw t instanceof Error&&t.message.startsWith("profile not found:")?N(`profile not found: ${e}`,{received:e}):t}}n(h,"requireProfileExists");function F(e){return Object.keys(s(e).vars).sort()}n(F,"listProfileEnvNames");function A(e,t,r){if(v(t))throw f(`env var name is reserved by crtr: ${t}`,{received:t,field:"name",next:"crtr identity/routing names (CRTR_* and HOME) cannot be stored in a profile env store \u2014 a stored value under one of these names could redirect a broker to a different canvas home. Choose a different name."});if(m(r))throw f("env var value contains a NUL byte, which no OS accepts in an environment variable",{field:"value",next:"Remove NUL bytes from the piped value and retry."});return u(e,()=>{h(e);const o=s(e),i=!Object.hasOwn(o.vars,t);return o.vars[t]=r,d(e,o),i})}n(A,"setProfileEnvVar");function D(e,t){return u(e,()=>{h(e);const r=s(e);return Object.hasOwn(r.vars,t)?(delete r.vars[t],d(e,r),!0):!1})}n(D,"removeProfileEnvVar");function L(e){if(e===null||e==="")return{};try{return{...s(e).vars}}catch{return{}}}n(L,"readProfileEnvVars");export{v as isReservedEnvName,F as listProfileEnvNames,L as readProfileEnvVars,D as removeProfileEnvVar,A as setProfileEnvVar};
@@ -1 +1 @@
1
- var D=Object.defineProperty;var a=(t,e)=>D(t,"name",{value:e,configurable:!0});import{assertLaunchKind as v}from"../../../core/runtime/launch-target.js";import{listNodesByProfile as h,shiftProfileNodeDeadlines as q}from"../../../core/canvas/canvas.js";import{liveExecutionForNode as N}from"../../../core/canvas/executions.js";import{shiftAutoBackgroundBashDeadlines as O}from"../../../core/bash-jobs.js";import{contextDir as L}from"../../../core/canvas/node-agent-paths.js";import{boundFleet as $}from"../../../core/runtime/fleet.js";import{recordedPidLiveness as F}from"../../../core/canvas/pid.js";import{withCanvasWrite as P}from"../../../core/canvas/db.js";import{reposForCwd as M}from"../../../core/graph/repo-sync/repos.js";import{renameProfileObject as S}from"../../../core/graph/objects.js";import{usage as l}from"../../../core/errors.js";import{ApiError as p}from"../../../api/errors.js";import{scopeAllowed as w}from"../../../core/scopes.js";import{validateEnvVarName as V}from"../../../core/env-name.js";import{listProfileEnvNames as R,removeProfileEnvVar as C,setProfileEnvVar as G}from"../../../core/profiles/env-store.js";import{listAppEnvNames as U,removeAppEnvVar as B,setAppEnvVar as K}from"../../../core/profiles/app-env-store.js";import{addProfileProject as H,assertDeliveryLimits as W,setProfileDeliveryLimit as E,assertProfileProjects as y,createProfile as g,ensureRootProfile as z,listProfiles as u,loadProfileManifest as _,pauseProfile as J,removeProfileProject as Q,renameProfile as X,resumeProfile as Y,setProfileDefaultKind as Z,updateProfileMetadata as x}from"../../../core/profiles/manifest.js";import{requestProfileDeletion as ee}from"../../profile-delete.js";import{brokerSignalBus as te}from"../../broker-signals/bus.js";import{toProfileDTO as d}from"../map.js";import{appOf as b,resolvedScopes as re}from"../router.js";const j="root";function m(t){return b(t.principal)??"app:terminal"}a(m,"callerApp");function A(t,e,n=null){if(u().some(r=>r.manifest.name===e&&r.profileId!==n&&(r.manifest.grantee??"app:terminal")===t))throw new p(400,"invalid_request",`${t} already has a profile named ${e}`)}a(A,"assertNameFree");function f(t,e){const n=I(t,e),r=n.manifest.grantee??"app:terminal";if(t.principal.class!=="person"&&r!==b(t.principal))throw new p(403,"permission_error",`profile ${n.profileId} belongs to ${r}; only that app changes it`);return n}a(f,"requireOwnProfile");async function ne(t){const e=t.body??{};if(typeof e.name!="string"||e.name.trim()==="")throw l("a profile name is required",{field:"name"});e.projects!==void 0&&y(e.projects);const n=m(t),r=e.name.trim();A(n,r),e.default_kind!==void 0&&await v(e.default_kind,process.cwd(),null);const o=g(r,e.projects??[],{defaultKind:e.default_kind,metadata:e.metadata,grantee:n});return{status:201,body:d(o)}}a(ne,"handleCreate");function oe(t,e){const n=e.trim();if(n==="")throw l("profile name must not be empty");return P(r=>(S(r,t,n),X(t,n)))}a(oe,"renameProfileAndHandle");function ie(t,e,n){const r=P(o=>M(o,n).map(i=>i.name));H(t,n);for(const o of r)e[o]===void 0&&e[`repo:${o}`]===void 0&&E(t,o,"preview")}a(ie,"addProjectWithDefaultLimit");async function ae(t){const{profileId:e,manifest:n}=f(t,t.params.name),r=t.body??{};return r.name!==void 0&&A(n.grantee??"app:terminal",r.name.trim(),e),r.default_kind!==void 0&&await v(r.default_kind,process.cwd(),e),r.add_project!==void 0&&y([r.add_project]),r.set_delivery_limit!==void 0&&W({[r.set_delivery_limit.owner]:r.set_delivery_limit.level}),r.name!==void 0&&oe(e,r.name),r.default_kind!==void 0&&Z(e,r.default_kind),r.add_project!==void 0&&ie(e,n.delivery_limits??{},r.add_project.path),r.set_delivery_limit!==void 0&&E(e,r.set_delivery_limit.owner,r.set_delivery_limit.level),r.remove_project!==void 0&&Q(e,r.remove_project),{status:200,body:d(_(e))}}a(ae,"handleUpdate");function se(t){const{profileId:e}=f(t,t.params.name);return{status:200,body:{profile_id:e,names:R(e)}}}a(se,"handleEnvList");function c(t){const e=t.params.var,n=V(e);if(!n.isValid)throw l(`invalid env var name: ${n.errors.join("; ")}`,{field:"name",received:e});return e}a(c,"requireEnvVarName");function de(t){const{profileId:e}=f(t,t.params.name),n=c(t),{value:r}=t.body??{};if(typeof r!="string"||r==="")throw l("a non-empty env value is required",{field:"value"});return{status:200,body:{profile_id:e,changed:G(e,n,r)}}}a(de,"handleEnvSet");function le(t){const{profileId:e}=f(t,t.params.name),n=c(t);return{status:200,body:{profile_id:e,changed:C(e,n)}}}a(le,"handleEnvRemove");async function fe(t){const e=t.params.name,n=t.body??{};n.projects!==void 0&&y(n.projects);const r=m(t);if(e===j&&r==="app:terminal")return{status:200,body:d(z())};if(e===j)throw new p(403,"permission_error","root belongs to the terminal app");const o=u().find(s=>s.manifest.name===e&&(s.manifest.grantee??"app:terminal")===r);if(o!==void 0)return{status:200,body:d(o)};n.default_kind!==void 0&&await v(n.default_kind,process.cwd(),null);const i=g(e,n.projects??[],{defaultKind:n.default_kind,metadata:n.metadata,grantee:r});return{status:200,body:d(i)}}a(fe,"handleEnsure");function pe(t){const e=f(t,t.params.name),n=t.body??{};if(typeof n!="object"||n===null||Array.isArray(n))throw l("profile metadata body must be an object",{field:"body"});const r=n,o=r.unset===void 0?[]:r.unset;if(!Array.isArray(o)||o.some(k=>typeof k!="string"))throw l("profile metadata `unset` must be an array of strings",{field:"unset"});const i=r.set===void 0?{}:r.set,s=x(e.profileId,i,o);return{status:200,body:d(s)}}a(pe,"handleSetMetadata");function me(t){const e=_(t.params.name),n=J(e.profileId),r=h(e.profileId).filter(i=>i.status==="active"||i.status==="idle");if(r.length===0)return{status:200,body:{profile_id:e.profileId,paused_at:n.manifest.paused_at}};const o=$();for(const i of r){const s=o.get(i.node_id);if(s!==void 0){o.interruptForProfilePause(i.node_id,s.pid);continue}i.pi_pid!=null&&F(i.pi_pid,i.pi_pid_identity)==="alive"&&o.interruptForProfilePause(i.node_id,i.pi_pid)}return{status:200,body:{profile_id:e.profileId,paused_at:n.manifest.paused_at}}}a(me,"handlePause");function ue(t){const e=_(t.params.name),n=Y(e.profileId);for(const r of h(e.profileId))(r.status==="active"||r.status==="idle"||N(r.node_id)!==null)&&te.markMail(r.node_id);if(n.pausedAt!==null){const r=Date.parse(n.pausedAt);if(!Number.isNaN(r)){const o=Math.max(0,Date.now()-r);q(e.profileId,o);for(const i of h(e.profileId))i.status!=="dead"&&O(L(i.node_id),o)}}return{status:200,body:{profile_id:e.profileId,paused_at:n.manifest.paused_at}}}a(ue,"handleResume");function T(t){const e=t.principal;if(e.class==="person")return u();const n=re(e);return u().filter(({profileId:r,manifest:o})=>{const i=o.grantee??"app:terminal";if(i===b(e))return!0;const s=`crtr:memory:rw:${i}:profile:${r}`;return w(n,s)&&(e.class!=="broker"||w(e.scopes,s))})}a(T,"visibleProfiles");function I(t,e){const n=T(t),r=n.find(({profileId:i})=>i===e),o=r?[r]:n.filter(({manifest:i})=>i.name===e);if(o.length===0)throw new p(404,"not_found","profile not found");if(o.length>1)throw new p(400,"ambiguous","profile name matches multiple visible profiles; use an exact id");return o[0]}a(I,"requireUsableProfile");function ce(t){return{status:200,body:T(t).map(d)}}a(ce,"handleList");function ve(t){return{status:200,body:d(I(t,t.params.name))}}a(ve,"handleGet");async function he(t){return ee(f(t,t.params.name).profileId,t.body)}a(he,"handleDelete");const Re=[{method:"GET",pattern:"/v1/apps/self/env",handler:a(t=>({status:200,body:{names:U(m(t))}}),"handler")},{method:"PUT",pattern:"/v1/apps/self/env/:var",handler:a(t=>{const e=c(t),{value:n}=t.body??{};if(typeof n!="string"||!n)throw l("a non-empty env value is required",{field:"value"});return{status:200,body:{changed:K(m(t),e,n)}}},"handler")},{method:"DELETE",pattern:"/v1/apps/self/env/:var",handler:a(t=>({status:200,body:{changed:B(m(t),c(t))}}),"handler")},{method:"PUT",pattern:"/v1/profiles/:name",handler:fe},{method:"POST",pattern:"/v1/profiles/:name/pause",ownerOnly:!0,handler:me},{method:"POST",pattern:"/v1/profiles/:name/resume",ownerOnly:!0,handler:ue},{method:"PATCH",pattern:"/v1/profiles/:name/metadata",handler:pe},{method:"POST",pattern:"/v1/profiles",handler:ne},{method:"PATCH",pattern:"/v1/profiles/:name",handler:ae},{method:"GET",pattern:"/v1/profiles/:name/env",handler:se},{method:"PUT",pattern:"/v1/profiles/:name/env/:var",handler:de},{method:"DELETE",pattern:"/v1/profiles/:name/env/:var",handler:le},{method:"DELETE",pattern:"/v1/profiles/:name",handler:he},{method:"GET",pattern:"/v1/profiles",handler:ce},{method:"GET",pattern:"/v1/profiles/:name",handler:ve}];export{ie as addProjectWithDefaultLimit,Re as profileRoutes,oe as renameProfileAndHandle,I as requireUsableProfile};
1
+ var N=Object.defineProperty;var a=(r,e)=>N(r,"name",{value:e,configurable:!0});import{assertLaunchKind as c}from"../../../core/runtime/launch-target.js";import{listNodesByProfile as v,shiftProfileNodeDeadlines as q}from"../../../core/canvas/canvas.js";import{liveExecutionForNode as O}from"../../../core/canvas/executions.js";import{shiftAutoBackgroundBashDeadlines as L}from"../../../core/bash-jobs.js";import{contextDir as $}from"../../../core/canvas/node-agent-paths.js";import{boundFleet as S}from"../../../core/runtime/fleet.js";import{recordedPidLiveness as V}from"../../../core/canvas/pid.js";import{withCanvasWrite as P}from"../../../core/canvas/db.js";import{reposForCwd as F}from"../../../core/graph/repo-sync/repos.js";import{renameProfileObject as M}from"../../../core/graph/objects.js";import{usage as l}from"../../../core/errors.js";import{ApiError as f}from"../../../api/errors.js";import{scopeAllowed as w}from"../../../core/scopes.js";import{validateEnvVarName as R}from"../../../core/env-name.js";import{listProfileEnvNames as C,removeProfileEnvVar as G,setProfileEnvVar as U}from"../../../core/profiles/env-store.js";import{isDeploymentName as B,listAppEnvNames as K,removeAppEnvVar as H,setAppEnvVar as W}from"../../../core/profiles/app-env-store.js";import{addProfileProject as z,assertDeliveryLimits as J,setProfileDeliveryLimit as E,assertProfileProjects as h,createProfile as g,ensureRootProfile as Q,listProfiles as u,loadProfileManifest as y,pauseProfile as X,removeProfileProject as Y,renameProfile as Z,resumeProfile as x,setProfileDefaultKind as ee,updateProfileMetadata as re}from"../../../core/profiles/manifest.js";import{requestProfileDeletion as te}from"../../profile-delete.js";import{brokerSignalBus as ne}from"../../broker-signals/bus.js";import{toProfileDTO as d}from"../map.js";import{actsAsPerson as ie,appOf as _,resolvedScopes as oe}from"../router.js";const j="root";function m(r){return _(r.principal)??"app:terminal"}a(m,"callerApp");function A(r,e,n=null){if(u().some(t=>t.manifest.name===e&&t.profileId!==n&&(t.manifest.grantee??"app:terminal")===r))throw new f(400,"invalid_request",`${r} already has a profile named ${e}`)}a(A,"assertNameFree");function p(r,e){const n=I(r,e),t=n.manifest.grantee??"app:terminal";if(r.principal.class!=="person"&&t!==_(r.principal))throw new f(403,"permission_error",`profile ${n.profileId} belongs to ${t}; only that app changes it`);return n}a(p,"requireOwnProfile");async function ae(r){const e=r.body??{};if(typeof e.name!="string"||e.name.trim()==="")throw l("a profile name is required",{field:"name"});e.projects!==void 0&&h(e.projects);const n=m(r),t=e.name.trim();A(n,t),e.default_kind!==void 0&&await c(e.default_kind,process.cwd(),null);const i=g(t,e.projects??[],{defaultKind:e.default_kind,metadata:e.metadata,grantee:n});return{status:201,body:d(i)}}a(ae,"handleCreate");function se(r,e){const n=e.trim();if(n==="")throw l("profile name must not be empty");return P(t=>(M(t,r,n),Z(r,n)))}a(se,"renameProfileAndHandle");function de(r,e,n){const t=P(i=>F(i,n).map(o=>o.name));z(r,n);for(const i of t)e[i]===void 0&&e[`repo:${i}`]===void 0&&E(r,i,"preview")}a(de,"addProjectWithDefaultLimit");async function le(r){const{profileId:e,manifest:n}=p(r,r.params.name),t=r.body??{};return t.name!==void 0&&A(n.grantee??"app:terminal",t.name.trim(),e),t.default_kind!==void 0&&await c(t.default_kind,process.cwd(),e),t.add_project!==void 0&&h([t.add_project]),t.set_delivery_limit!==void 0&&J({[t.set_delivery_limit.owner]:t.set_delivery_limit.level}),t.name!==void 0&&se(e,t.name),t.default_kind!==void 0&&ee(e,t.default_kind),t.add_project!==void 0&&de(e,n.delivery_limits??{},t.add_project.path),t.set_delivery_limit!==void 0&&E(e,t.set_delivery_limit.owner,t.set_delivery_limit.level),t.remove_project!==void 0&&Y(e,t.remove_project),{status:200,body:d(y(e))}}a(le,"handleUpdate");function fe(r){const{profileId:e}=p(r,r.params.name);return{status:200,body:{profile_id:e,names:C(e)}}}a(fe,"handleEnvList");function b(r){const e=r.params.var,n=R(e);if(!n.isValid)throw l(`invalid env var name: ${n.errors.join("; ")}`,{field:"name",received:e});return e}a(b,"requireEnvVarName");function T(r){const e=b(r);if(B(e)&&!ie(r.principal))throw new f(403,"permission_error",`${e} is deployment-wide; only a person changes it`);return e}a(T,"requireSelfEnvVarName");function pe(r){const{profileId:e}=p(r,r.params.name),n=b(r),{value:t}=r.body??{};if(typeof t!="string"||t==="")throw l("a non-empty env value is required",{field:"value"});return{status:200,body:{profile_id:e,changed:U(e,n,t)}}}a(pe,"handleEnvSet");function me(r){const{profileId:e}=p(r,r.params.name),n=b(r);return{status:200,body:{profile_id:e,changed:G(e,n)}}}a(me,"handleEnvRemove");async function ue(r){const e=r.params.name,n=r.body??{};n.projects!==void 0&&h(n.projects);const t=m(r);if(e===j&&t==="app:terminal")return{status:200,body:d(Q())};if(e===j)throw new f(403,"permission_error","root belongs to the terminal app");const i=u().find(s=>s.manifest.name===e&&(s.manifest.grantee??"app:terminal")===t);if(i!==void 0)return{status:200,body:d(i)};n.default_kind!==void 0&&await c(n.default_kind,process.cwd(),null);const o=g(e,n.projects??[],{defaultKind:n.default_kind,metadata:n.metadata,grantee:t});return{status:200,body:d(o)}}a(ue,"handleEnsure");function ce(r){const e=p(r,r.params.name),n=r.body??{};if(typeof n!="object"||n===null||Array.isArray(n))throw l("profile metadata body must be an object",{field:"body"});const t=n,i=t.unset===void 0?[]:t.unset;if(!Array.isArray(i)||i.some(k=>typeof k!="string"))throw l("profile metadata `unset` must be an array of strings",{field:"unset"});const o=t.set===void 0?{}:t.set,s=re(e.profileId,o,i);return{status:200,body:d(s)}}a(ce,"handleSetMetadata");function ve(r){const e=y(r.params.name),n=X(e.profileId),t=v(e.profileId).filter(o=>o.status==="active"||o.status==="idle");if(t.length===0)return{status:200,body:{profile_id:e.profileId,paused_at:n.manifest.paused_at}};const i=S();for(const o of t){const s=i.get(o.node_id);if(s!==void 0){i.interruptForProfilePause(o.node_id,s.pid);continue}o.pi_pid!=null&&V(o.pi_pid,o.pi_pid_identity)==="alive"&&i.interruptForProfilePause(o.node_id,o.pi_pid)}return{status:200,body:{profile_id:e.profileId,paused_at:n.manifest.paused_at}}}a(ve,"handlePause");function he(r){const e=y(r.params.name),n=x(e.profileId);for(const t of v(e.profileId))(t.status==="active"||t.status==="idle"||O(t.node_id)!==null)&&ne.markMail(t.node_id);if(n.pausedAt!==null){const t=Date.parse(n.pausedAt);if(!Number.isNaN(t)){const i=Math.max(0,Date.now()-t);q(e.profileId,i);for(const o of v(e.profileId))o.status!=="dead"&&L($(o.node_id),i)}}return{status:200,body:{profile_id:e.profileId,paused_at:n.manifest.paused_at}}}a(he,"handleResume");function D(r){const e=r.principal;if(e.class==="person")return u();const n=oe(e);return u().filter(({profileId:t,manifest:i})=>{const o=i.grantee??"app:terminal";if(o===_(e))return!0;const s=`crtr:memory:rw:${o}:profile:${t}`;return w(n,s)&&(e.class!=="broker"||w(e.scopes,s))})}a(D,"visibleProfiles");function I(r,e){const n=D(r),t=n.find(({profileId:o})=>o===e),i=t?[t]:n.filter(({manifest:o})=>o.name===e);if(i.length===0)throw new f(404,"not_found","profile not found");if(i.length>1)throw new f(400,"ambiguous","profile name matches multiple visible profiles; use an exact id");return i[0]}a(I,"requireUsableProfile");function ye(r){return{status:200,body:D(r).map(d)}}a(ye,"handleList");function _e(r){return{status:200,body:d(I(r,r.params.name))}}a(_e,"handleGet");async function be(r){return te(p(r,r.params.name).profileId,r.body)}a(be,"handleDelete");const Ue=[{method:"GET",pattern:"/v1/apps/self/env",handler:a(r=>({status:200,body:{names:K(m(r))}}),"handler")},{method:"PUT",pattern:"/v1/apps/self/env/:var",handler:a(r=>{const e=T(r),{value:n}=r.body??{};if(typeof n!="string"||!n)throw l("a non-empty env value is required",{field:"value"});return{status:200,body:{changed:W(m(r),e,n)}}},"handler")},{method:"DELETE",pattern:"/v1/apps/self/env/:var",handler:a(r=>({status:200,body:{changed:H(m(r),T(r))}}),"handler")},{method:"PUT",pattern:"/v1/profiles/:name",handler:ue},{method:"POST",pattern:"/v1/profiles/:name/pause",ownerOnly:!0,handler:ve},{method:"POST",pattern:"/v1/profiles/:name/resume",ownerOnly:!0,handler:he},{method:"PATCH",pattern:"/v1/profiles/:name/metadata",handler:ce},{method:"POST",pattern:"/v1/profiles",handler:ae},{method:"PATCH",pattern:"/v1/profiles/:name",handler:le},{method:"GET",pattern:"/v1/profiles/:name/env",handler:fe},{method:"PUT",pattern:"/v1/profiles/:name/env/:var",handler:pe},{method:"DELETE",pattern:"/v1/profiles/:name/env/:var",handler:me},{method:"DELETE",pattern:"/v1/profiles/:name",handler:be},{method:"GET",pattern:"/v1/profiles",handler:ye},{method:"GET",pattern:"/v1/profiles/:name",handler:_e}];export{de as addProjectWithDefaultLimit,Ue as profileRoutes,se as renameProfileAndHandle,I as requireUsableProfile};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@north-light/cli",
3
- "version": "0.3.522",
3
+ "version": "0.3.523",
4
4
  "description": "crtr — agent runtime with memory, plugins, and marketplaces",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
@@ -139,7 +139,7 @@
139
139
  },
140
140
  "license": "UNLICENSED",
141
141
  "dependencies": {
142
- "@north-light/identity": "0.3.522",
142
+ "@north-light/identity": "0.3.523",
143
143
  "@earendil-works/pi-agent-core": "1.1.0",
144
144
  "@earendil-works/pi-ai": "1.1.0",
145
145
  "@earendil-works/pi-coding-agent": "1.1.0",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@north-light/identity",
3
- "version": "0.3.522",
3
+ "version": "0.3.523",
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/cli",
3
- "version": "0.3.522",
3
+ "version": "0.3.523",
4
4
  "lockfileVersion": 3,
5
5
  "requires": true,
6
6
  "packages": {
7
7
  "": {
8
8
  "name": "@north-light/cli",
9
- "version": "0.3.522",
9
+ "version": "0.3.523",
10
10
  "hasInstallScript": true,
11
11
  "license": "UNLICENSED",
12
12
  "workspaces": [
@@ -24,7 +24,7 @@
24
24
  "@milkdown/preset-gfm": "^7.22.3",
25
25
  "@milkdown/prose": "^7.22.3",
26
26
  "@milkdown/utils": "^7.22.3",
27
- "@north-light/identity": "0.3.522",
27
+ "@north-light/identity": "0.3.523",
28
28
  "cron-parser": "^5.6.0",
29
29
  "esbuild": "^0.27.7",
30
30
  "jose": "^6.2.12",
@@ -12468,17 +12468,17 @@
12468
12468
  },
12469
12469
  "packages/crouter-api": {
12470
12470
  "name": "@north-light/api",
12471
- "version": "0.3.522",
12471
+ "version": "0.3.523",
12472
12472
  "license": "UNLICENSED"
12473
12473
  },
12474
12474
  "packages/crouter-env-docker": {
12475
12475
  "name": "@north-light/env-docker",
12476
- "version": "0.3.522",
12476
+ "version": "0.3.523",
12477
12477
  "license": "UNLICENSED"
12478
12478
  },
12479
12479
  "packages/crouter-identity": {
12480
12480
  "name": "@north-light/identity",
12481
- "version": "0.3.522",
12481
+ "version": "0.3.523",
12482
12482
  "license": "UNLICENSED",
12483
12483
  "dependencies": {
12484
12484
  "jose": "^6.2.1"
@@ -12486,20 +12486,20 @@
12486
12486
  },
12487
12487
  "packages/crouter-plugin": {
12488
12488
  "name": "@north-light/plugin",
12489
- "version": "0.3.522",
12489
+ "version": "0.3.523",
12490
12490
  "license": "UNLICENSED",
12491
12491
  "dependencies": {
12492
- "@north-light/api": "0.3.522",
12493
- "@north-light/identity": "0.3.522"
12492
+ "@north-light/api": "0.3.523",
12493
+ "@north-light/identity": "0.3.523"
12494
12494
  }
12495
12495
  },
12496
12496
  "packages/crouter-sdk": {
12497
12497
  "name": "@north-light/sdk",
12498
- "version": "0.3.522",
12498
+ "version": "0.3.523",
12499
12499
  "license": "UNLICENSED",
12500
12500
  "dependencies": {
12501
- "@north-light/api": "0.3.522",
12502
- "@north-light/identity": "0.3.522",
12501
+ "@north-light/api": "0.3.523",
12502
+ "@north-light/identity": "0.3.523",
12503
12503
  "jose": "^6.2.1"
12504
12504
  },
12505
12505
  "bin": {