@north-light/cli 0.3.579 → 0.3.581
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 +6 -1
- package/dist/api/client.js +3 -3
- package/dist/api/contract.d.ts +1 -1
- package/dist/api/contract.js +1 -1
- package/dist/api/dto/execution-start.d.ts +14 -0
- package/dist/api/dto/health.d.ts +20 -0
- package/dist/api/dto/imports.d.ts +142 -0
- package/dist/api/dto/imports.js +0 -0
- package/dist/api/index.d.ts +1 -0
- package/dist/api/index.js +1 -1
- package/dist/api/routes.d.ts +2 -0
- package/dist/api/routes.js +1 -1
- package/dist/builtin-memory/internal/storage-tiers.md +2 -2
- package/dist/clients/attach/session/connection.d.ts +3 -1
- package/dist/clients/attach/session/connection.js +1 -1
- package/dist/clients/attach/viewer.js +510 -510
- package/dist/commands/api-client.d.ts +7 -4
- package/dist/commands/api-client.js +3 -3
- package/dist/commands/sys/daemon.js +1 -1
- package/dist/commands/sys/import/resume.d.ts +1 -0
- package/dist/commands/sys/import/resume.js +1 -0
- package/dist/commands/sys/import/start.d.ts +5 -0
- package/dist/commands/sys/import/start.js +4 -0
- package/dist/commands/sys/join.d.ts +2 -0
- package/dist/commands/sys/join.js +1 -1
- package/dist/commands/sys/machine/rotate.d.ts +1 -0
- package/dist/commands/sys/machine/rotate.js +1 -0
- package/dist/commands/sys/signin.d.ts +7 -0
- package/dist/commands/sys/signin.js +2 -0
- package/dist/commands/sys.js +1 -1
- package/dist/core/blobs/r2.d.ts +4 -0
- package/dist/core/blobs/r2.js +7 -4
- package/dist/core/canvas/daemon-owner.d.ts +1 -1
- package/dist/core/canvas/executions.d.ts +1 -1
- package/dist/core/canvas/export-sqlite.js +1 -1
- package/dist/core/canvas/node-tokens.d.ts +2 -0
- package/dist/core/canvas/node-tokens.js +3 -3
- package/dist/core/canvas/schema-pg/009-bodies.sql +10 -0
- package/dist/core/canvas/schema-version.d.ts +1 -1
- package/dist/core/canvas/schema-version.js +1 -1
- package/dist/core/directory/person-credential.d.ts +36 -0
- package/dist/core/directory/person-credential.js +1 -0
- package/dist/core/feed/feed.js +3 -3
- package/dist/core/feed/inbox.js +1 -1
- package/dist/core/feed/reports.js +2 -2
- package/dist/core/graph/access.d.ts +1 -1
- package/dist/core/graph/bodies-boot-copy.d.ts +14 -0
- package/dist/core/graph/bodies-boot-copy.js +1 -0
- package/dist/core/graph/bodies.d.ts +13 -6
- package/dist/core/graph/bodies.js +1 -1
- package/dist/core/graph/deletion.d.ts +4 -1
- package/dist/core/graph/deletion.js +3 -3
- package/dist/core/graph/documents.d.ts +4 -0
- package/dist/core/graph/documents.js +10 -10
- package/dist/core/graph/objects.js +11 -11
- package/dist/core/graph/package-docs.js +5 -5
- package/dist/core/graph/reader.js +2 -2
- package/dist/core/graph/repo-sync/exchange.js +2 -2
- package/dist/core/graph/repo-sync/ref-format.d.ts +0 -1
- package/dist/core/graph/repo-sync/ref-format.js +2 -2
- package/dist/core/import/bundle/blob-keys.d.ts +10 -0
- package/dist/core/import/bundle/blob-keys.js +1 -0
- package/dist/core/import/bundle/layout.d.ts +89 -0
- package/dist/core/import/bundle/layout.js +5 -0
- package/dist/core/import/export/archive.d.ts +11 -0
- package/dist/core/import/export/archive.js +1 -0
- package/dist/core/import/export/cloud.d.ts +21 -0
- package/dist/core/import/export/cloud.js +1 -0
- package/dist/core/import/export/dump.d.ts +34 -0
- package/dist/core/import/export/dump.js +3 -0
- package/dist/core/import/export/files.d.ts +22 -0
- package/dist/core/import/export/files.js +1 -0
- package/dist/core/import/export/inline.d.ts +3 -0
- package/dist/core/import/export/inline.js +1 -0
- package/dist/core/import/export/source.d.ts +2 -0
- package/dist/core/import/export/source.js +1 -0
- package/dist/core/import/export/stores.d.ts +9 -0
- package/dist/core/import/export/stores.js +1 -0
- package/dist/core/import/load/bind.d.ts +19 -0
- package/dist/core/import/load/bind.js +15 -0
- package/dist/core/import/load/blobs.d.ts +10 -0
- package/dist/core/import/load/blobs.js +1 -0
- package/dist/core/import/load/catalog.d.ts +32 -0
- package/dist/core/import/load/catalog.js +9 -0
- package/dist/core/import/load/copy.d.ts +26 -0
- package/dist/core/import/load/copy.js +6 -0
- package/dist/core/import/load/path-map.d.ts +7 -0
- package/dist/core/import/load/path-map.js +1 -0
- package/dist/core/import/load/prepare.d.ts +37 -0
- package/dist/core/import/load/prepare.js +10 -0
- package/dist/core/import/load/rewrite.d.ts +39 -0
- package/dist/core/import/load/rewrite.js +9 -0
- package/dist/core/import/load/rollback.d.ts +3 -0
- package/dist/core/import/load/rollback.js +6 -0
- package/dist/core/import/load/run.d.ts +22 -0
- package/dist/core/import/load/run.js +3 -0
- package/dist/core/import/load/stage.d.ts +15 -0
- package/dist/core/import/load/stage.js +1 -0
- package/dist/core/import/load/stores.d.ts +24 -0
- package/dist/core/import/load/stores.js +2 -0
- package/dist/core/import/load/verify.d.ts +4 -0
- package/dist/core/import/load/verify.js +11 -0
- package/dist/core/peer/receiver.js +1 -1
- package/dist/core/runtime/broker.js +1 -1
- package/dist/core/runtime/revive.d.ts +5 -2
- package/dist/core/runtime/revive.js +2 -2
- package/dist/core/runtime/roadmap.js +3 -3
- package/dist/core/runtime/runner/blaxel/runner.js +3 -3
- package/dist/core/runtime/runner/index.d.ts +1 -0
- package/dist/core/runtime/runner/index.js +1 -1
- package/dist/core/runtime/runner/machine/call.d.ts +8 -0
- package/dist/core/runtime/runner/machine/call.js +3 -0
- package/dist/core/runtime/runner/machine/environment.d.ts +1 -0
- package/dist/core/runtime/runner/machine/environment.js +1 -0
- package/dist/core/runtime/runner/machine/executor.d.ts +23 -0
- package/dist/core/runtime/runner/machine/executor.js +1 -0
- package/dist/core/runtime/runner/machine/machine-executor.test.d.ts +1 -0
- package/dist/core/runtime/runner/machine/machine-executor.test.js +4 -0
- package/dist/core/runtime/runner/machine/ops.d.ts +127 -0
- package/dist/core/runtime/runner/machine/ops.js +1 -0
- package/dist/core/runtime/runner/machine/runner.d.ts +12 -0
- package/dist/core/runtime/runner/machine/runner.js +1 -0
- package/dist/core/runtime/runner/types.d.ts +7 -1
- package/dist/core/runtime/warm-pool.d.ts +2 -0
- package/dist/core/runtime/warm-pool.js +1 -1
- package/dist/core/secrets/env-rows.d.ts +1 -0
- package/dist/core/secrets/env-rows.js +1 -1
- package/dist/core/storage/purge.d.ts +6 -0
- package/dist/core/storage/purge.js +4 -0
- package/dist/core/subscription-state.d.ts +1 -0
- package/dist/core/subscription-state.js +1 -1
- package/dist/core/substrate/delivery/corpus.d.ts +2 -0
- package/dist/core/substrate/delivery/corpus.js +3 -3
- package/dist/core/substrate/delivery/deliver.js +3 -3
- package/dist/core/substrate/delivery/render-boot.js +25 -25
- package/dist/core/substrate/delivery/render-event.d.ts +1 -1
- package/dist/core/substrate/delivery/render-event.js +4 -4
- package/dist/core/substrate/delivery/types.d.ts +2 -2
- package/dist/daemon/api/bridge.js +3 -3
- package/dist/daemon/api/document-listener.js +4 -4
- package/dist/daemon/api/handlers/attach.js +1 -1
- package/dist/daemon/api/handlers/crons.js +1 -1
- package/dist/daemon/api/handlers/daemon.js +1 -1
- package/dist/daemon/api/handlers/docs.js +1 -1
- package/dist/daemon/api/handlers/execution-start.js +2 -2
- package/dist/daemon/api/handlers/files.js +1 -1
- package/dist/daemon/api/handlers/imports.d.ts +2 -0
- package/dist/daemon/api/handlers/imports.js +1 -0
- package/dist/daemon/api/handlers/machine-credential.d.ts +2 -0
- package/dist/daemon/api/handlers/machine-credential.js +1 -0
- package/dist/daemon/api/handlers/memory.js +4 -4
- package/dist/daemon/api/handlers/profiles.js +1 -1
- package/dist/daemon/api/handlers/providers.js +1 -1
- package/dist/daemon/api/handlers/reports.js +4 -4
- package/dist/daemon/api/handlers/runs.js +1 -1
- package/dist/daemon/api/import-auth.d.ts +6 -0
- package/dist/daemon/api/import-auth.js +1 -0
- package/dist/daemon/api/operations.d.ts +2 -2
- package/dist/daemon/api/operations.js +1 -1
- package/dist/daemon/api/router.d.ts +7 -1
- package/dist/daemon/api/router.js +1 -1
- package/dist/daemon/api/server.js +1 -1
- package/dist/daemon/boot-migrations.js +1 -1
- package/dist/daemon/broker-signals/bus.d.ts +3 -2
- package/dist/daemon/broker-signals/bus.js +1 -1
- package/dist/daemon/cron/armed-context.d.ts +1 -0
- package/dist/daemon/cron/armed-context.js +1 -1
- package/dist/daemon/cron/closed.d.ts +31 -0
- package/dist/daemon/cron/closed.js +1 -0
- package/dist/daemon/cron/ended.js +2 -2
- package/dist/daemon/cron/lease-recovery.js +1 -1
- package/dist/daemon/cron/machine-exec.d.ts +5 -0
- package/dist/daemon/cron/machine-exec.js +1 -0
- package/dist/daemon/cron/machine-fire.d.ts +26 -0
- package/dist/daemon/cron/machine-fire.js +1 -0
- package/dist/daemon/cron/recurrence.d.ts +14 -0
- package/dist/daemon/cron/recurrence.js +1 -0
- package/dist/daemon/cron/run-token.d.ts +7 -0
- package/dist/daemon/cron/run-token.js +1 -0
- package/dist/daemon/cron-run.js +2 -2
- package/dist/daemon/crtrd-cli.js +1 -1
- package/dist/daemon/crtrd.d.ts +2 -2
- package/dist/daemon/crtrd.js +10 -10
- package/dist/daemon/drain.d.ts +25 -0
- package/dist/daemon/drain.js +9 -0
- package/dist/daemon/due-sources.d.ts +1 -1
- package/dist/daemon/due-sources.js +1 -1
- package/dist/daemon/due.js +8 -8
- package/dist/daemon/fleet.js +5 -5
- package/dist/daemon/import-dump-run.d.ts +1 -0
- package/dist/daemon/import-dump-run.js +5 -0
- package/dist/daemon/machine-daemon.d.ts +7 -0
- package/dist/daemon/machine-daemon.js +1 -0
- package/dist/daemon/machine-link/client.d.ts +29 -0
- package/dist/daemon/machine-link/client.js +1 -0
- package/dist/daemon/machine-link/config.d.ts +14 -0
- package/dist/daemon/machine-link/config.js +3 -0
- package/dist/daemon/machine-link/credential.d.ts +7 -0
- package/dist/daemon/machine-link/credential.js +2 -0
- package/dist/daemon/machine-link/forward.d.ts +16 -0
- package/dist/daemon/machine-link/forward.js +1 -0
- package/dist/daemon/machine-link/frames.d.ts +49 -0
- package/dist/daemon/machine-link/frames.js +1 -0
- package/dist/daemon/machine-link/holder.d.ts +73 -0
- package/dist/daemon/machine-link/holder.js +9 -0
- package/dist/daemon/manage.d.ts +19 -3
- package/dist/daemon/manage.js +3 -3
- package/dist/daemon/reconcilers/cron-lane.js +1 -1
- package/dist/daemon/reconcilers/delivery-lane.js +2 -2
- package/dist/daemon/reconcilers/import-lane.d.ts +9 -0
- package/dist/daemon/reconcilers/import-lane.js +1 -0
- package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.js +1 -1
- package/dist/daemon/reconcilers/node-lifecycle/remote-wake.d.ts +3 -0
- package/dist/daemon/reconcilers/node-lifecycle/remote-wake.js +1 -1
- package/dist/daemon/reconcilers/node-lifecycle/tick.js +1 -1
- package/dist/daemon/reconcilers/purge-due-work.d.ts +13 -0
- package/dist/daemon/reconcilers/purge-due-work.js +1 -0
- package/dist/daemon/reconcilers/row-claim.d.ts +1 -0
- package/dist/daemon/reconcilers/row-claim.js +2 -2
- package/dist/daemon/review/finish.js +1 -1
- package/dist/daemon/runs/observer.js +3 -3
- package/dist/migrations/004-canvas-documents/apply.d.ts +2 -4
- package/dist/migrations/004-canvas-documents/apply.js +1 -1
- package/dist/migrations/004-canvas-documents/index.js +2 -2
- package/package.json +2 -2
- package/packages/crouter-identity/package.json +1 -1
- package/runtime.lock.json +13 -13
- package/scripts/sandbox-start.mjs +185 -2
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var
|
|
2
|
-
WHERE person = ? AND enabled = 1 AND owner_key IN (${
|
|
1
|
+
var f=Object.defineProperty;var c=(i,e)=>f(i,"name",{value:e,configurable:!0});import{ApiError as a}from"../../../api/errors.js";import{getNode as w}from"../../../core/canvas/canvas.js";import{openDb as d}from"../../../core/canvas/db.js";import{blobStore as h}from"../../../core/blobs/index.js";import{presignGet as E,releaseSignerFromEnv as b}from"../../../core/secrets/blaxel-launch.js";import{grantedProviderIds as g,isProviderBundleRow as k}from"../../../core/grants/mirror.js";import{profileMetadataEnv as x}from"../../../core/runtime/spawn-env.js";import{localEnvironmentSecrets as y}from"../../../core/secrets/environment-owner.js";import{environmentOfNode as v,recipeOf as R}from"../environment-of.js";import{mintInstallationToken as S}from"./git-credential.js";async function $(i,e){const n=await d(),s=e===null?["user"]:["user",`profile:${e}`],t=await n.prepare(`SELECT owner_key, name, version, source_marketplace, source_path FROM scope_plugins
|
|
2
|
+
WHERE person = ? AND enabled = 1 AND owner_key IN (${s.map(()=>"?").join(", ")}) ORDER BY name`).all(i,...s),r=new Map;for(const o of t)(!r.has(o.name)||o.owner_key!=="user")&&r.set(o.name,o);const u=[],p=await g(i);for(const o of r.values()){if(k(o,p))continue;if(o.source_path!==null){u.push({name:o.name,source:{path:o.source_path},version:o.version});continue}if(o.source_marketplace===null)throw new a(500,"plugin_source_missing",`plugin ${o.name} names neither a marketplace nor a path`);const l=await n.prepare("SELECT url, ref FROM scope_marketplaces WHERE person = ? AND owner_key = ? AND name = ?").get(i,o.owner_key,o.source_marketplace);u.push({name:o.name,source:{marketplace:{url:l?.url??null,ref:l?.ref??null}},version:o.version})}return u}c($,"plugins");const O=900;async function T(i){const e=await d(),n=await e.prepare("SELECT blob_key, unpacked_at FROM import_node_files WHERE node = ?").get(i);if(n===void 0)return null;if(!(await(await h()).list(n.blob_key)).includes(n.blob_key)){if(n.unpacked_at!==null)return null;throw new a(500,"import_files_missing",`the imported archive ${n.blob_key} of ${i} is gone and no sandbox unpacked it`)}const s=/^imports\/([^/]+)\/node-files\//.exec(n.blob_key)?.[1];if(s===void 0)throw new a(500,"import_files_invalid",`import_node_files names ${n.blob_key} for ${i}, which is no imports/<run>/node-files key`);const t=await e.prepare("SELECT source_value, target_value FROM import_id_map WHERE run_id = ? AND kind = 'path' ORDER BY source_value").all(s);return{url:E(b(),n.blob_key,O),path_map:t.map(r=>({from:r.source_value,to:r.target_value}))}}c(T,"importFiles");async function N(i){const{principal:e}=i;if(e.class!=="broker")throw new a(403,"broker_only","this route is called with a node token");const n=i.params.execution_id??"",t=await(await d()).prepare("SELECT node_id, state FROM executions WHERE execution_id = ?").get(n);if(t===void 0||t.node_id!==e.node)throw new a(403,"not_your_execution",`execution ${n} is not an execution of this node`);if(t.state!=="launching"&&t.state!=="running")throw new a(403,"execution_ended",`execution ${n} is ${t.state}`);return e.node}c(N,"ownedExecution");async function D(i){const e=await N(i);return await(await d()).prepare("UPDATE import_node_files SET unpacked_at = ? WHERE node = ? AND unpacked_at IS NULL").run(new Date().toISOString(),e),{status:200,body:{}}}c(D,"handleImportUnpacked");async function L(i){const{principal:e}=i;if(e.class!=="broker")throw new a(403,"broker_only","the start bundle is read with a node token");const n=i.params.execution_id??"",s=await d(),t=await s.prepare("SELECT node_id, state, launch_json, runner FROM executions WHERE execution_id = ?").get(n);if(t===void 0||t.node_id!==e.node)throw new a(403,"not_your_execution",`execution ${n} is not an execution of this node`);if(t.state!=="launching"&&t.state!=="running")throw new a(403,"execution_ended",`execution ${n} is ${t.state}`);if(t.launch_json===null)throw new a(409,"launch_missing",`execution ${n} carries no launch recipe`);const r=await w(e.node);if(r===null)throw new a(404,"node_not_found",`no node ${e.node}`);const u=await s.prepare("SELECT plugins_revision FROM person_settings WHERE person = ?").get(e.sub),p=await v(r.profile_id??null),o=await R(p),l=o?.repositories.map(m=>m.github_full_name)??[],_=l.length===0?null:(await S(e.sub,l)).author;return{status:200,body:{launch:JSON.parse(t.launch_json),node:{id:r.node_id,app:e.app,cwd:r.cwd,profile:r.profile_id??null,isolated:r.isolated===!0,environment_id:p},recipe:o,git_identity:_,plugins_revision:u===void 0?0:Number(u.plugins_revision),plugins:await $(e.sub,r.profile_id??null),import_node_files:await T(r.node_id),...t.runner==="machine"?{machine_env:{...x(r.profile_id??null),...await y(r.profile_id??null,e.app)}}:{}}}}c(L,"handleStart");const Y=[{method:"GET",pattern:"/v1/executions/:execution_id/start",handler:L},{method:"POST",pattern:"/v1/executions/:execution_id/import-unpacked",handler:D}];export{Y as executionStartRoutes};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var R=Object.defineProperty;var s=(e,t)=>R(e,"name",{value:t,configurable:!0});import{closeSync as T,constants as q,fstatSync as B,readSync as v}from"node:fs";import{isAbsolute as L,relative as F,resolve as b,sep as I}from"node:path";import{filterAsync as M}from"../../../core/async-array.js";import{appSpace as g}from"../../../core/layout.js";import{ApiError as f}from"../../../api/index.js";import{notFound as E,usage as c}from"../../../core/errors.js";import{InputError as k}from"../../../core/io.js";import{RunError as m}from"../../../core/runs/operations.js";import{isBeneathRefusal as z,listBeneath as N,openBeneath as O,writeFileBeneath as D}from"../../../core/spaces/open-beneath.js";import{fileRoot as P}from"../../../core/spaces/permissions.js";import{openDb as C}from"../../../core/canvas/db.js";import{canReadNode as $,resolvedScopes as S}from"../router.js";const h=512*1024,_=1024*1024,W=1e3;function y(e,t){if(e===null||e==="")throw c(`a file ${t} requires a \`path\` ${t==="write"?"body field":"query param"}`);if(!L(e))throw c(`file ${t} path must be absolute`,{received:e});return e}s(y,"requireAbsolutePath");function A(e){if(e==null)return"utf8";if(e==="utf8"||e==="base64")return e;throw c("encoding must be `utf8` or `base64`",{received:e})}s(A,"parseEncoding");function
|
|
1
|
+
var R=Object.defineProperty;var s=(e,t)=>R(e,"name",{value:t,configurable:!0});import{closeSync as T,constants as q,fstatSync as B,readSync as v}from"node:fs";import{isAbsolute as L,relative as F,resolve as b,sep as I}from"node:path";import{filterAsync as M}from"../../../core/async-array.js";import{appSpace as g}from"../../../core/layout.js";import{ApiError as f}from"../../../api/index.js";import{notFound as E,usage as c}from"../../../core/errors.js";import{InputError as k}from"../../../core/io.js";import{RunError as m}from"../../../core/runs/operations.js";import{isBeneathRefusal as z,listBeneath as N,openBeneath as O,writeFileBeneath as D}from"../../../core/spaces/open-beneath.js";import{fileRoot as P}from"../../../core/spaces/permissions.js";import{openDb as C}from"../../../core/canvas/db.js";import{canReadNode as $,resolvedScopes as S}from"../router.js";const h=512*1024,_=1024*1024,W=1e3;function y(e,t){if(e===null||e==="")throw c(`a file ${t} requires a \`path\` ${t==="write"?"body field":"query param"}`);if(!L(e))throw c(`file ${t} path must be absolute`,{received:e});return e}s(y,"requireAbsolutePath");function A(e){if(e==null)return"utf8";if(e==="utf8"||e==="base64")return e;throw c("encoding must be `utf8` or `base64`",{received:e})}s(A,"parseEncoding");function u(e,t,r){if(e instanceof f||e instanceof k||e instanceof m)throw e;if(z(e))throw new m(400,"invalid_request",`${t} meets a symlink, leaves its permitted root, or is not a regular file`,"path");const n=e.code;throw n==="ENOENT"?E(`no such file: ${t}`,{received:t}):n==="EACCES"||n==="EPERM"?new f(403,"forbidden",`permission denied ${r} ${t}`):new f(500,"internal",`cannot ${r} ${t}: ${e instanceof Error?e.message:String(e)}`)}s(u,"mapFilesystemError");async function Y(e,t,r,n){const i=await(await C()).prepare("SELECT isolated FROM nodes WHERE node_id = ?").get(t),[l,d]=F(g(r).root,b(n)).split(I),a=l==="nodes"&&d?await $(e.principal,r,d):!1;return{isolated:i?.isolated===1,reaches:s(()=>a,"reaches")}}s(Y,"runConfinementFor");async function w(e,t,r){const n=e.principal;if(n.class==="forwarded"||n.class==="machine"||n.class==="import")throw new f(403,"permission_error","this operation is not available to the caller");if(n.class==="person"&&n.sub!==void 0)throw new f(403,"permission_error","files are read by the install's person or a node");const o=n.class==="person"?null:n.class==="app"?{app:n.app,resolved:n.scopes,launched:null}:n.class==="cron"?{app:n.app,resolved:await S(n),launched:n.scopes}:{app:n.app,resolved:await S(n),launched:n.scopes,run:await Y(e,n.node,n.app,t)},i=P(o,t,r);if("root"in i)return i.root;throw"hidden"in i?E(`no such file: ${t}`,{received:t}):new m(403,"scope_missing",i.missing?`missing scope ${i.missing}`:`no permission names ${t}`,void 0,void 0,i.missing??void 0)}s(w,"rootFor");function Z(e,t,r){let n;try{n=O(e,t,q.O_RDONLY)}catch(o){return u(o,t,"reading")}try{const o=B(n);if(o.isDirectory())throw c(`file peek path is a directory: ${t}`,{received:t});const i=Buffer.allocUnsafe(Math.min(o.size,h)+1),l=v(n,i,0,i.length,0),d=l>h,a=i.subarray(0,Math.min(l,h)).toString(r);return{path:t,content:a,truncated:d}}catch(o){return u(o,t,"reading")}finally{T(n)}}s(Z,"readHead");async function j(e){const t=y(e.query.get("path"),"peek");return{status:200,body:Z(await w(e,t,"read"),t,A(e.query.get("encoding")))}}s(j,"handlePeek");function G(e){return e.length%4===0&&/^(?:[A-Za-z0-9+/]{4})*(?:[A-Za-z0-9+/]{2}==|[A-Za-z0-9+/]{3}=)?$/.test(e)}s(G,"isBase64");function H(e){if(typeof e!="object"||e===null||Array.isArray(e))throw c("file write requires an object body");const t=e,r=y(typeof t.path=="string"?t.path:null,"write");if(typeof t.content!="string")throw c("file write requires a string `content` body field");const n=A(t.encoding);if(n==="base64"&&!G(t.content))throw c("base64 file content must be valid base64");return{path:r,content:t.content,encoding:n}}s(H,"parseWriteBody");function U(e,t,r){if(r.byteLength>_)throw new f(413,"file_too_large",`file content exceeds the ${_} byte limit`);try{return D(e,t,r,{mode:process.platform==="linux"?432:384,atomic:!0}),{path:t,bytes_written:r.byteLength}}catch(n){return u(n,t,"writing")}}s(U,"writeAtomically");async function X(e){const{path:t,content:r,encoding:n}=H(e.body);return{status:200,body:U(await w(e,t,"rw"),t,Buffer.from(r,n))}}s(X,"handleWrite");function K(e){if(e===null)return W;const t=Number(e);if(!Number.isInteger(t)||t<1)throw c("file list limit must be a positive integer",{received:e});return t}s(K,"parseLimit");async function J(e){const t=y(e.query.get("path"),"list"),r=K(e.query.get("limit")),n=await w(e,t,"read");let o;try{o=N(n,t,r+1)}catch(a){return u(a,t,"listing")}const i=e.principal;i.class==="broker"&&b(t)===g(i.app).nodes&&(o=await M(o,async({name:a})=>await $(i,i.app,a)));const l=o.slice(0,r).map(({name:a,stat:p})=>({name:a,type:p.isFile()?"file":p.isDirectory()?"dir":"other",size:p.size,modified:p.mtime.toISOString()}));return{status:200,body:{path:t,entries:l,truncated:o.length>r}}}s(J,"handleList");const fe=[{method:"GET",pattern:"/v1/files/peek",scope:"crtr:act",handler:j},{method:"POST",pattern:"/v1/files/write",scope:"crtr:act",handler:X},{method:"GET",pattern:"/v1/files/list",scope:"crtr:act",handler:J}];export{fe as fileRoutes};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var k=Object.defineProperty;var a=(t,n)=>k(t,"name",{value:n,configurable:!0});import{randomBytes as E}from"node:crypto";import{ApiError as o}from"../../../api/errors.js";import{blobStore as w}from"../../../core/blobs/index.js";import{presignPutUrl as $,r2ConfigFromEnv as v}from"../../../core/blobs/r2.js";import{openDb as c}from"../../../core/canvas/db.js";import{bundleKeys as m}from"../../../core/import/bundle/layout.js";import{putStore as O,StoreBodyError as T,STORE_NAMES as R}from"../../../core/import/load/stores.js";import{rollbackRun as D}from"../../../core/import/load/rollback.js";import{crtrVersion as f}from"../../../shared/crtr-version.js";import{importTokenFor as N}from"../import-auth.js";const h=3600;function y(t){if(t.principal.class!=="person"||t.principal.sub===void 0)throw new o(403,"person_only","an import is made by a signed-in person");return t.principal.sub}a(y,"personOf");async function _(t,n=!1){const e=t.params.run_id??"",r=await(await c()).prepare("SELECT * FROM import_runs WHERE run_id = ?").get(e),s=t.principal;if(s.class==="import"){if(s.run===null&&!n)throw new o(403,"permission_error","the service credential starts and reads runs; the import token uploads and loads");if(r===void 0||(s.run===null?r.source_kind!=="hosted":s.run!==r.run_id))throw new o(404,"import_not_found",`no import run ${e}`);if(s.run!==null&&!n&&r.state!=="uploading"&&r.state!=="loading")throw new o(403,"import_token_expired",`import run ${r.run_id} is ${r.state}: its import token no longer works`);return r}if(r===void 0||r.person!==y(t))throw new o(404,"import_not_found",`no import run ${e}`);return r}a(_,"ownRun");function A(t,n,e){const r=t.principal;if(r.class!=="import")return y(t);if(r.run!==null)throw new o(403,"permission_error","an import token reaches only its own run");const s=n.person;if(typeof s!="string"||!/^user:.+/.test(s))throw new o(400,"invalid_body","person (user:<id>) is required");if(e!=="hosted")throw new o(400,"invalid_body","the service credential starts hosted runs only: source_kind must be hosted");return s}a(A,"startPerson");const g=a(t=>{if(t===null||typeof t!="object"||Array.isArray(t))throw new o(400,"invalid_body","the body must be a JSON object");return t},"objectBody");async function j(t){const n=g(t.body),e=A(t,n,n.source_kind),r=n.source_install_id,s=n.source_kind,u=n.release;if(typeof r!="string"||r===""||s!=="machine"&&s!=="hosted"||typeof u!="string")throw new o(400,"invalid_body","source_install_id, source_kind (machine | hosted) and release are required");if(u!==f())throw new o(409,"release_mismatch",`the source runs ${u}, the control plane accepts ${f()}`);const p=await c();let i=await p.prepare("SELECT run_id, state FROM import_runs WHERE source_install_id = ? AND state IN ('uploading', 'loading', 'committed', 'done')").get(r);if(i?.state==="uploading"){const S={step:"uploading",code:"superseded",message:`a new import run was started for install ${r} before this one asked for the load`};await p.prepare("UPDATE import_runs SET state = 'failed', failure_json = ?, finished_at = ? WHERE run_id = ? AND state = 'uploading'").run(JSON.stringify(S),new Date().toISOString(),i.run_id),i=await p.prepare("SELECT run_id, state FROM import_runs WHERE source_install_id = ? AND state IN ('uploading', 'loading', 'committed', 'done')").get(r)}if(i?.state==="done")throw new o(409,"already_imported",`install ${r} was imported by run ${i.run_id}`);if(i!==void 0)throw new o(409,"import_running",`install ${r} has an open run ${i.run_id} (${i.state})`);const d=`imp_${E(8).toString("hex")}`;await p.prepare("INSERT INTO import_runs (run_id, source_install_id, source_kind, person, release, state, created_at) VALUES (?, ?, ?, ?, ?, 'uploading', ?)").run(d,r,s,e,u,new Date().toISOString());const l=t.principal.class==="import"?N(d):null;return{status:201,body:{run_id:d,upload:{rows_prefix:m.prefix(d),url_template:`POST /v1/imports/${d}/upload-urls {"keys":[...]}`},...l===null?{}:{import_token:l}}}}a(j,"handleStart");async function P(t){const n=await _(t);if(n.state!=="uploading")throw new o(409,"import_not_uploading",`import run ${n.run_id} is ${n.state}`);const e=g(t.body).keys;if(!Array.isArray(e)||e.some(i=>typeof i!="string"))throw new o(400,"invalid_body","keys must be a list of blob keys");const r=m.prefix(n.run_id);for(const i of e)if(!(i.startsWith(r)&&!i.startsWith(`${r}stores/`)&&i!==m.manifest(n.run_id))||i.split("/").some(l=>l===""||l==="."||l===".."))throw new o(400,"invalid_key",`${i} is not a key this run may upload`);const s=v();if(s===null)throw new o(501,"upload_not_supported","this control plane keeps blobs in a directory: there is no URL to upload to");const u={};for(const i of e)u[i]=$(s,i,h);return{status:200,body:{urls:u,expires_at:new Date(Date.now()+h*1e3).toISOString()}}}a(P,"handleUploadUrls");async function I(t){const n=await _(t);if(n.state!=="uploading")throw new o(409,"import_not_uploading",`import run ${n.run_id} is ${n.state}`);const e=t.params.name;if(!R.includes(e))throw new o(404,"unknown_store",`no file store ${e}`);try{await O(await w(),n.run_id,e,t.body)}catch(r){throw r instanceof T?new o(400,"invalid_body",r.message):r}return{status:204}}a(I,"handleStore");async function U(t){const n=await _(t),e=await c();if(n.state==="uploading"){if(await(await w()).get(m.source(n.run_id))===null)throw new o(409,"bundle_invalid","source.json is not uploaded");await e.prepare("UPDATE import_runs SET state = 'loading', step = 'queued', loaded_at = ? WHERE run_id = ? AND state = 'uploading'").run(new Date().toISOString(),n.run_id)}else if(n.state!=="loading"&&n.state!=="committed"&&n.state!=="done")throw new o(409,"import_not_uploading",`import run ${n.run_id} is ${n.state}`);return{status:202,body:await b(n.run_id)}}a(U,"handleLoad");async function b(t){const n=await(await c()).prepare("SELECT * FROM import_runs WHERE run_id = ?").get(t),e=n.counts_json===null?{}:JSON.parse(n.counts_json),{unresolved_plugins:r,...s}=e;return{run_id:n.run_id,source_install_id:n.source_install_id,source_kind:n.source_kind,person:n.person,release:n.release,state:n.state,step:n.step,counts:s,verify:n.verify_json===null?null:JSON.parse(n.verify_json),failure:n.failure_json===null?null:JSON.parse(n.failure_json),unresolved_plugins:r??[],created:n.created_at,loaded:n.loaded_at,finished:n.finished_at}}a(b,"runDto");async function L(t){const n=await _(t,!0);return{status:200,body:await b(n.run_id)}}a(L,"handleGet");async function W(t){const n=await _(t),e=await D(n.run_id,await w());if(!e.rolled_back)throw new o(409,"rollback_has_dependents",`later rows depend on import run ${n.run_id}`,e.dependents);return{status:200,body:e}}a(W,"handleRollback");const X=[{method:"POST",pattern:"/v1/imports",handler:j},{method:"POST",pattern:"/v1/imports/:run_id/upload-urls",handler:P},{method:"PUT",pattern:"/v1/imports/:run_id/stores/:name",handler:I},{method:"POST",pattern:"/v1/imports/:run_id/load",handler:U},{method:"GET",pattern:"/v1/imports/:run_id",handler:L},{method:"POST",pattern:"/v1/imports/:run_id/rollback",handler:W}];export{X as importRoutes};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var s=Object.defineProperty;var a=(e,t)=>s(e,"name",{value:t,configurable:!0});import{ApiError as i}from"../../../api/errors.js";import{openDb as d}from"../../../core/canvas/db.js";import{hasMachineCredential as c,mintMachineCredential as m}from"../../machine-link/credential.js";async function p(e){if(e.principal.class!=="person")throw new i(403,"person_only","the machine credential is issued to a person");const t=e.params.run_id??"",o=await d(),n=await o.prepare("SELECT source_install_id, source_kind, person, state FROM import_runs WHERE run_id = ?").get(t);if(n===void 0||e.principal.sub!==void 0&&n.person!==e.principal.sub)throw new i(404,"import_not_found",`no import run ${t}`);if(n.source_kind!=="machine")throw new i(409,"not_a_machine_import","only a machine source gets a machine credential");if(n.state!=="done")throw new i(409,"import_not_done",`import run ${t} is ${n.state}`);const r=await o.prepare("SELECT object FROM environments WHERE machine_id = ? AND kind = 'machine'").get(n.source_install_id);if(r===void 0)throw new i(409,"environment_missing",`no machine environment for install ${n.source_install_id}`);if(!(e.query.get("rotate")==="1")&&await c(r.object))throw new i(409,"credential_exists","the machine credential was already issued; rotate it");return{status:200,body:{environment_id:r.object,credential:await m(r.object)}}}a(p,"handleMint");const f=[{method:"POST",pattern:"/v1/imports/:run_id/machine-credential",handler:p}];export{f as machineCredentialRoutes};
|
|
@@ -1,9 +1,9 @@
|
|
|
1
|
-
var
|
|
1
|
+
var x=Object.defineProperty;var r=(e,t)=>x(e,"name",{value:t,configurable:!0});import{createHash as T}from"node:crypto";import{withCanvasWrite as g}from"../../../core/canvas/db.js";import{canRead as k}from"../../../core/graph/access.js";import{permits as M}from"../../../core/permissions/evaluator.js";import{get as b}from"../../../core/graph/bodies.js";import{ownerForGrantee as C}from"../../../core/graph/objects.js";import{readerFor as F}from"../../../core/graph/reader.js";import{checkoutsForCwd as H}from"../../../core/graph/repo-sync/repos.js";import{RunError as h}from"../../../core/runs/operations.js";import{mapAsync as j}from"../../../core/async-array.js";import{personId as B}from"../../../core/canvas/person.js";const ut=new Set(["memory.list","memory.get"]),W=1024*1024,w=/^[A-Za-z0-9_-]+(\/[A-Za-z0-9_-]+)*$/,N=["knowledge","preference"],i=r((e,t)=>new h(400,"invalid_request",e,t),"invalid"),O=r(()=>new h(404,"not_found","no memory document by that name"),"notFound");function _(e){const t=e.get("store");if(t===null)throw i("store is required","store");if(t!=="user")throw i('store must be "user"',"store")}r(_,"store");function J(e){const t=e.get("kind");if(t===null)return null;if(!N.includes(t))throw i("kind must be knowledge or preference","kind");return t}r(J,"kindOf");function Y(e){const t=e.get("limit");if(t===null)return 50;if(!/^(0|[1-9]\d*)$/.test(t)||Number(t)<1||Number(t)>100)throw i("limit must be an integer from 1 to 100","limit");return Number(t)}r(Y,"limitOf");function U(e,t){return T("sha256").update(JSON.stringify(["user",e,t])).digest("base64url").slice(0,16)}r(U,"filterHash");function $(e,t){return Buffer.from(JSON.stringify({n:e,f:t}),"utf8").toString("base64url")}r($,"encodeCursor");function z(e,t){if(e===null)return null;try{if(!/^[A-Za-z0-9_-]+$/.test(e))throw new Error("not base64url");const n=JSON.parse(Buffer.from(e,"base64url").toString("utf8"));if(typeof n.n=="string"&&w.test(n.n)&&n.f===t)return n.n}catch{}throw i("cursor is not the next_cursor of a previous page with the same store, path and kind","cursor")}r(z,"decodeCursor");async function R(e){return await C(e,B())}r(R,"personObject");async function v(e,t){return await F(e,t,async n=>await H(e,n))}r(v,"graphReader");async function S(e,t){const n=await e.prepare(`SELECT r.body_hash, r.created_at FROM revisions r WHERE r.document = ?
|
|
2
2
|
AND NOT EXISTS (SELECT 1 FROM revision_parents p WHERE p.parent = r.rev_id) ORDER BY r.number DESC, r.rev_id LIMIT 1`).get(t.id),o=await e.prepare("SELECT created_at, author FROM revisions WHERE document = ? ORDER BY number, created_at LIMIT 1").get(t.id);if(!n||!o)throw O();return{head:n,first:o}}r(S,"revisions");async function A(e,t){const{head:n,first:o}=await S(e,t),a=t.name.lastIndexOf("/");return{name:t.name,folder:a<0?"":t.name.slice(0,a),kind:t.kind,preview:t.preview,summary:t.summary,privacy:t.privacy,revision:t.revision,created_at:o.created_at,updated_at:n.created_at}}r(A,"item");async function G(e,t){return t===null?null:(await e.prepare(`SELECT i.external_id FROM objects a LEFT JOIN nodes n ON n.node_id = a.id
|
|
3
3
|
JOIN identities i ON i.object = CASE WHEN a.type = 'node' THEN n.app ELSE a.id END AND i.scheme = 'app'
|
|
4
|
-
WHERE a.id = ?`).get(t))?.external_id??null}r(G,"granteeOf");function Z(e,t){if(e.length<=t)return e;let n=t;for(;n>0&&(e[n]&192)===128;)n--;return e.subarray(0,n)}r(Z,"utf8Prefix");async function P(e,t){_(t);const n=t.get("path");if(n!==null&&!w.test(n))throw
|
|
4
|
+
WHERE a.id = ?`).get(t))?.external_id??null}r(G,"granteeOf");function Z(e,t){if(e.length<=t)return e;let n=t;for(;n>0&&(e[n]&192)===128;)n--;return e.subarray(0,n)}r(Z,"utf8Prefix");async function P(e,t){_(t);const n=t.get("path");if(n!==null&&!w.test(n))throw i("path must be name segments of letters, digits, `_` or `-` joined by `/`","path");const o=J(t),a=Y(t),d=U(n,o),s=z(t.get("cursor"),d);return await g(async u=>{const l=await v(u,e),c=await R(u),m=n===null?null:`${n}/`,f=o===null?N:[o],y=await M(u,l,"read"),E=await u.prepareUncached(`SELECT o.*, d.summary, d.revision, d.source_path FROM objects o JOIN documents d ON d.object = o.id
|
|
5
5
|
WHERE o.owner = ? AND o.type = 'document' AND o.deleted_at IS NULL AND d.unlisted = 0
|
|
6
6
|
AND o.kind IN (?, ?) AND (?::text IS NULL OR starts_with(o.name, ?::text)) AND (?::text IS NULL OR o.name > ?::text)
|
|
7
7
|
AND ${y.sql}
|
|
8
|
-
ORDER BY o.name LIMIT ?`).all(c.id,f[0],f[f.length-1],m,m,
|
|
9
|
-
WHERE o.owner = ? AND o.type = 'document' AND o.name = ? AND o.deleted_at IS NULL AND o.kind IN ('knowledge', 'preference')`).get(d.id,n);if(!
|
|
8
|
+
ORDER BY o.name LIMIT ?`).all(c.id,f[0],f[f.length-1],m,m,s,s,...y.params,a+1),p=E.slice(0,a),D=E.length>a;return{items:await j(p,async L=>await A(u,L)),next_cursor:D?$(p[p.length-1].name,d):null}})}r(P,"memoryList");async function X(e,t){_(t);const n=t.get("name");if(n===null)throw i("name is required","name");if(!w.test(n))throw i("name must be segments of letters, digits, `_` or `-` joined by `/`","name");return await g(async o=>{const a=await v(o,e),d=await R(o),s=await o.prepare(`SELECT o.*, d.summary, d.revision, d.source_path FROM objects o JOIN documents d ON d.object = o.id
|
|
9
|
+
WHERE o.owner = ? AND o.type = 'document' AND o.name = ? AND o.deleted_at IS NULL AND o.kind IN ('knowledge', 'preference')`).get(d.id,n);if(!s||!await k(o,a,s))throw O();const{head:u,first:l}=await S(o,s),c=Buffer.from(await b(o,u.body_hash),"utf8"),m=Z(c,W);return{...await A(o,s),body:m.toString("utf8"),size:c.length,truncated:m.length<c.length,grantee:await G(o,l.author)}})}r(X,"memoryGet");async function I(e,t,n){if(e==="memory.list")return{status:200,body:await P(t,n)};if(e==="memory.get")return{status:200,body:await X(t,n)};throw new h(404,"not_found","unknown operation")}r(I,"handleMemoryOperation");const ct=[{method:"GET",pattern:"/v1/memory",handler:r(async e=>await I("memory.list",e.principal,e.query),"handler")},{method:"GET",pattern:"/v1/memory/document",handler:r(async e=>await I("memory.get",e.principal,e.query),"handler")}];export{W as MEMORY_BODY_MAX_BYTES,ut as MEMORY_OPERATIONS,I as handleMemoryOperation,X as memoryGet,P as memoryList,ct as memoryRoutes,Z as utf8Prefix};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var N=Object.defineProperty;var o=(t,e)=>N(t,"name",{value:e,configurable:!0});import{openDb as q}from"../../../core/canvas/db.js";import{assertLaunchKind as c}from"../../../core/runtime/launch-target.js";import{listNodesByProfile as v,shiftProfileNodeDeadlines as L}from"../../../core/canvas/canvas.js";import{liveExecutionForNode as S}from"../../../core/canvas/executions.js";import{shiftJobDeadlines as $}from"../../../core/graph/jobs.js";import{boundFleet as F}from"../../../core/runtime/fleet.js";import{recordedPidLiveness as M}from"../../../core/canvas/pid.js";import{withCanvasWrite as w}from"../../../core/canvas/db.js";import{reposForCwd as R,warmCheckoutIdentities as V}from"../../../core/graph/repo-sync/repos.js";import{renameProfileObject as C}from"../../../core/graph/objects.js";import{usage as l}from"../../../core/errors.js";import{ApiError as f}from"../../../api/errors.js";import{scopeAllowed as E}from"../../../core/scopes.js";import{validateEnvVarName as G}from"../../../core/env-name.js";import{listProfileEnvNames as U,removeProfileEnvVar as H,setProfileEnvVar as K}from"../../../core/profiles/env-store.js";import{isDeploymentName as W,listAppEnvNames as B,removeAppEnvVar as J,setAppEnvVar as z}from"../../../core/profiles/app-env-store.js";import{addProfileProject as Q,assertDeliveryLimits as X,setProfileDeliveryLimit as g,assertProfileProjects as h,createProfile as j,ensureRootProfile as Y,listProfiles as m,loadProfileManifest as y,pauseProfile as Z,removeProfileProject as x,renameProfile as ee,resumeProfile as te,setProfileDefaultKind as ae,updateProfileMetadata as ne}from"../../../core/profiles/manifest.js";import{requestProfileDeletion as re}from"../../profile-delete.js";import{brokerSignalBus as ie}from"../../broker-signals/bus.js";import{toProfileDTO as oe}from"../map.js";import{machineEnvironmentId as se}from"../../../core/environments.js";import{actsAsPerson as _,appOf as b,resolvedScopes as de}from"../router.js";const T="root";function d(t){return{...oe(t),environment_id:t.manifest.environment_id??se()}}o(d,"toProfileDTO");function u(t){return b(t.principal)??"app:terminal"}o(u,"callerApp");function A(t,e,n=null){if(m().some(a=>a.manifest.name===e&&a.profileId!==n&&(a.manifest.grantee??"app:terminal")===t))throw new f(400,"invalid_request",`${t} already has a profile named ${e}`)}o(A,"assertNameFree");async function p(t,e){const n=await k(t,e),a=n.manifest.grantee??"app:terminal";if(!_(t.principal)&&a!==b(t.principal))throw new f(403,"permission_error",`profile ${n.profileId} belongs to ${a}; only that app changes it`);return n}o(p,"requireOwnProfile");async function le(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&&h(e.projects);const n=u(t),a=e.name.trim();A(n,a),e.default_kind!==void 0&&await c(e.default_kind,process.cwd(),null);const i=await j(a,e.projects??[],{defaultKind:e.default_kind,metadata:e.metadata,grantee:n});return{status:201,body:d(i)}}o(le,"handleCreate");async function fe(t,e){const n=e.trim();if(n==="")throw l("profile name must not be empty");return await w(async a=>(await C(a,t,n),await ee(t,n)))}o(fe,"renameProfileAndHandle");async function pe(t,e,n){await V(n);const a=await w(async i=>(await R(i,n)).map(r=>r.name));await Q(t,n);for(const i of a)e[i]===void 0&&e[`repo:${i}`]===void 0&&await g(t,i,"preview")}o(pe,"addProjectWithDefaultLimit");async function me(t){const{profileId:e,manifest:n}=await p(t,t.params.name),a=t.body??{};return a.name!==void 0&&A(n.grantee??"app:terminal",a.name.trim(),e),a.default_kind!==void 0&&await c(a.default_kind,process.cwd(),e),a.add_project!==void 0&&h([a.add_project]),a.set_delivery_limit!==void 0&&X({[a.set_delivery_limit.owner]:a.set_delivery_limit.level}),a.name!==void 0&&await fe(e,a.name),a.default_kind!==void 0&&await ae(e,a.default_kind),a.add_project!==void 0&&await pe(e,n.delivery_limits??{},a.add_project.path),a.set_delivery_limit!==void 0&&await g(e,a.set_delivery_limit.owner,a.set_delivery_limit.level),a.remove_project!==void 0&&await x(e,a.remove_project),{status:200,body:d(y(e))}}o(me,"handleUpdate");async function ue(t){const{profileId:e}=await p(t,t.params.name);return{status:200,body:{profile_id:e,names:await U(e)}}}o(ue,"handleEnvList");function P(t){const e=t.params.var,n=G(e);if(!n.isValid)throw l(`invalid env var name: ${n.errors.join("; ")}`,{field:"name",received:e});return e}o(P,"requireEnvVarName");function D(t){const e=P(t);if(W(e)&&!_(t.principal))throw new f(403,"permission_error",`${e} is deployment-wide; only a person changes it`);return e}o(D,"requireSelfEnvVarName");async function ce(t){const{profileId:e}=await p(t,t.params.name),n=P(t),{value:a}=t.body??{};if(typeof a!="string"||a==="")throw l("a non-empty env value is required",{field:"value"});return{status:200,body:{profile_id:e,changed:await K(e,n,a)}}}o(ce,"handleEnvSet");async function ve(t){const{profileId:e}=await p(t,t.params.name),n=P(t);return{status:200,body:{profile_id:e,changed:await H(e,n)}}}o(ve,"handleEnvRemove");async function we(t){const e=t.params.name,n=t.body??{};n.projects!==void 0&&h(n.projects);const a=u(t);if(e===T&&a==="app:terminal")return{status:200,body:d(await Y())};if(e===T)throw new f(403,"permission_error","root belongs to the terminal app");const i=m().find(s=>s.manifest.name===e&&(s.manifest.grantee??"app:terminal")===a);if(i!==void 0)return{status:200,body:d(i)};n.default_kind!==void 0&&await c(n.default_kind,process.cwd(),null);const r=await j(e,n.projects??[],{defaultKind:n.default_kind,metadata:n.metadata,grantee:a});return{status:200,body:d(r)}}o(we,"handleEnsure");async function he(t){const e=await p(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 a=n,i=a.unset===void 0?[]:a.unset;if(!Array.isArray(i)||i.some(O=>typeof O!="string"))throw l("profile metadata `unset` must be an array of strings",{field:"unset"});const r=a.set===void 0?{}:a.set,s=await ne(e.profileId,r,i);return{status:200,body:d(s)}}o(he,"handleSetMetadata");async function ye(t){const e=y(t.params.name),n=await Z(e.profileId),a=(await v(e.profileId)).filter(r=>r.status==="active"||r.status==="idle");if(a.length===0)return{status:200,body:{profile_id:e.profileId,paused_at:n.manifest.paused_at}};const i=F();for(const r of a){const s=i.get(r.node_id);if(s!==void 0){await i.interruptForProfilePause(r.node_id,s.pid);continue}r.pi_pid!=null&&M(r.pi_pid,r.pi_pid_identity)==="alive"&&await i.interruptForProfilePause(r.node_id,r.pi_pid)}return{status:200,body:{profile_id:e.profileId,paused_at:n.manifest.paused_at}}}o(ye,"handlePause");async function _e(t){const e=y(t.params.name),n=await te(e.profileId);for(const a of await v(e.profileId))(a.status==="active"||a.status==="idle"||await S(a.node_id)!==null)&&ie.markMail(a.node_id);if(n.pausedAt!==null){const a=Date.parse(n.pausedAt);if(!Number.isNaN(a)){const i=Math.max(0,Date.now()-a);await L(e.profileId,i);for(const r of await v(e.profileId))r.status!=="dead"&&await w(s=>$(s,r.node_id,i))}}return{status:200,body:{profile_id:e.profileId,paused_at:n.manifest.paused_at}}}o(_e,"handleResume");async function I(t){const e=t.principal;if(_(e))return m();if(e.class==="person"&&e.sub!==void 0){const a=await q(),i=new Set((await a.prepare("SELECT id FROM profiles WHERE person = ?").all(e.sub)).map(r=>r.id));return m().filter(({profileId:r})=>i.has(r))}const n=await de(e);return m().filter(({profileId:a,manifest:i})=>{const r=i.grantee??"app:terminal";if(r===b(e))return!0;const s=`crtr:memory:rw:${r}:profile:${a}`;return E(n,s)&&(e.class!=="broker"||E(e.scopes,s))})}o(I,"visibleProfiles");async function k(t,e){const n=await I(t),a=n.find(({profileId:r})=>r===e),i=a?[a]:n.filter(({manifest:r})=>r.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]}o(k,"requireUsableProfile");async function be(t){return{status:200,body:(await I(t)).map(d)}}o(be,"handleList");async function Pe(t){return{status:200,body:d(await k(t,t.params.name))}}o(Pe,"handleGet");async function Ee(t){return re((await p(t,t.params.name)).profileId,t.body)}o(Ee,"handleDelete");const Be=[{method:"GET",pattern:"/v1/apps/self/env",handler:o(async t=>({status:200,body:{names:await B(u(t))}}),"handler")},{method:"PUT",pattern:"/v1/apps/self/env/:var",handler:o(async t=>{const e=D(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:await z(u(t),e,n)}}},"handler")},{method:"DELETE",pattern:"/v1/apps/self/env/:var",handler:o(async t=>({status:200,body:{changed:await J(u(t),D(t))}}),"handler")},{method:"PUT",pattern:"/v1/profiles/:name",handler:we},{method:"POST",pattern:"/v1/profiles/:name/pause",ownerOnly:!0,handler:ye},{method:"POST",pattern:"/v1/profiles/:name/resume",ownerOnly:!0,handler:_e},{method:"PATCH",pattern:"/v1/profiles/:name/metadata",handler:he},{method:"POST",pattern:"/v1/profiles",handler:le},{method:"PATCH",pattern:"/v1/profiles/:name",handler:me},{method:"GET",pattern:"/v1/profiles/:name/env",handler:ue},{method:"PUT",pattern:"/v1/profiles/:name/env/:var",handler:ce},{method:"DELETE",pattern:"/v1/profiles/:name/env/:var",handler:ve},{method:"DELETE",pattern:"/v1/profiles/:name",handler:Ee},{method:"GET",pattern:"/v1/profiles",handler:be},{method:"GET",pattern:"/v1/profiles/:name",handler:Pe}];export{pe as addProjectWithDefaultLimit,Be as profileRoutes,fe as renameProfileAndHandle,k as requireUsableProfile};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var q=Object.defineProperty;var s=(e,r)=>q(e,"name",{value:r,configurable:!0});import{randomUUID as G}from"node:crypto";import{cloudPersonScope as N}from"../../../core/runs/operations.js";import{directoryIssuer as T}from"../../../core/directory/issuer.js";import{activeGrantForApp as F,allGrants as x,grantFor as C,localGrants as j,providerIdsFromGrants as y}from"../../../core/grants/mirror.js";import{getNode as k}from"../../../core/canvas/canvas.js";import{scopeAllowed as B}from"../../../core/scopes.js";import{ProviderError as f,providerErrorBody as D,scopeMissing as M}from"../../../core/providers/errors.js";import{callProvider as U,providerTools as z}from"../../../core/providers/call.js";import{providerInstallState as L}from"../../../core/providers/bundles.js";import{installedProviderPlugins as V,providerRootClaims as Z,resolveProviderRef as W}from"../../../core/providers/roots.js";import{isCloudRole as h}from"../../../core/canvas/person-state.js";import{listAudit as J,writeProviderAudit as X}from"../../../core/providers/audit.js";import{emitEvent as S}from"../../../core/events/emit.js";import{resolvedScopes as P}from"../router.js";const Ae=new Set(["provider.tools","provider.call","audit.list"]);async function H(e){if(e.class==="forwarded"){if(e.actor.kind==="person")return{class:"person",sub:null,grantee:null,client_id:null,resolved:null,nodeScopes:null,run_id:null,node_id:null,origin:{node:null,run:null,machine:e.via}};const r=await C(e.actor.app,e.sub);if(!r)throw new f("grant_revoked",`app ${e.actor.app} has no active grant`);return{class:"app",sub:e.sub,grantee:e.actor.app,client_id:null,resolved:r.resolved,nodeScopes:e.actor.node_scopes,run_id:null,node_id:null,origin:{node:e.actor.node,run:e.actor.place?.run??null,machine:e.via}}}if(e.class==="machine")throw new f("permission_error","this operation is not available to the caller");if(e.class==="person"&&e.sub!==void 0)throw new f("permission_error","provider calls are made by the install's person, a node or an app");if(e.class==="person")return{class:"person",sub:null,grantee:null,client_id:null,resolved:null,nodeScopes:null,run_id:null,node_id:null};if(e.class==="app"){const r=await F(e.app);if(!r)throw new f("grant_revoked",`app ${e.app} has no active grant`);return{class:"app",sub:r.sub,grantee:e.app,client_id:null,resolved:r.resolved,nodeScopes:e.scopes,run_id:null,node_id:null}}return e.class==="cron"?{class:"app",sub:e.sub,grantee:e.app,client_id:null,resolved:await P(e),nodeScopes:e.scopes,run_id:e.origin_run,node_id:null}:{class:"broker",sub:e.sub,grantee:e.app,client_id:e.client_id,resolved:await P(e),nodeScopes:e.scopes,run_id:e.run??(await k(e.node))?.run_id??null,node_id:e.node}}s(H,"callerFromRequest");function Ee(e){return{class:"app",sub:e.sub,grantee:e.grantee,client_id:e.client_id,resolved:e.resolved,nodeScopes:null,run_id:null,node_id:null}}s(Ee,"callerFromApp");const K=/^([A-Za-z0-9_-]{1,64}):([A-Za-z0-9_-]{1,64})$/;function Q(e){const r=K.exec(e);return r!==null&&r[1]!=="crtr"}s(Q,"isProviderScope");const A=new WeakMap;function Y(e){let r=A.get(e);return r===void 0&&(r=new Set(e),A.set(e,r)),r}s(Y,"heldSet");function E(e,r){return e===null?!0:Q(r)?Y(e).has(r):B(e,r)}s(E,"holds");function R(e,r){return e.class==="person"?!0:E(e.resolved??[],r)&&E(e.nodeScopes,r)}s(R,"callerAllows");function Re(e,r,n){const o=`${r}:${n}`;if(!R(e,o))throw M(o)}s(Re,"requireGroup");function ee(){return!!T()}s(ee,"providerOperationsEnabled");const re=/^[A-Za-z0-9_-]{1,64}$/;function m(e,r){return new f("invalid_request",e,{param:r})}s(m,"invalid");function I(e){if(typeof e!="string"||!re.test(e)||e==="crtr")throw m("provider must be a provider id","provider");return e}s(I,"parseProvider");function oe(e){if(!e||typeof e!="object"||Array.isArray(e))throw new f("invalid_request","a JSON object is required");const r=e,n=I(r.provider),o=r.tool;if(typeof o!="string"||!o.trim())throw m("tool must be a non-empty string","tool");const i=r.arguments??{};if(!i||typeof i!="object"||Array.isArray(i))throw m("arguments must be an object","arguments");const a=r.version;if(a!==void 0&&(typeof a!="number"||!Number.isInteger(a)||a<1))throw m("version must be an integer >= 1","version");const d=r.approval;if(d!==void 0&&(typeof d!="string"||!d))throw m("approval must be a question id","approval");const u=r.machine;if(u!==void 0&&(typeof u!="string"||!u.trim()))throw m("machine must be a machine id","machine");return{provider:n,tool:o.trim(),arguments:i,...a===void 0?{}:{version:a},...d===void 0?{}:{approval:d},...u===void 0?{}:{machine:u.trim()}}}s(oe,"parseCallInput");async function te(e,r=new URLSearchParams){const n=s((l,v,w)=>{const p=r.get(l);if(p===null)return v;if(!/^\d+$/.test(p)||Number(p)>w||Number(p)<1)throw m(`invalid ${l}`,l);return Number(p)},"numeric"),o=r.has("after")?n("after",0,Number.MAX_SAFE_INTEGER):void 0,i=n("limit",100,1e3),a=Object.fromEntries(["operation","outcome","run_id","since","until"].filter(l=>r.has(l)).map(l=>[l,r.get(l)])),d=N(e.sub),u=d===void 0?{}:{sub:d};return{status:200,body:await J(e.class==="person"?null:e.grantee,{after:o,limit:i,...u,...a})}}s(te,"auditList");async function ne(e,r,n){let o=r;const i=performance.now(),a=V(),{skipped:d}=Z(a),u=h()?await x():await j(),l=h()?new Set(y(u.filter(t=>t.sub===e.sub))):null,v=s(t=>!d.has(t)&&(l===null||l.has(t)),"shown"),w=new Set(a.filter(t=>t.enabled&&t.manifest.provider?.id===t.name&&v(t.name)).map(t=>t.name)),p=y(u).filter(v),_=[...new Set([...w,...p])].sort();if(o!==void 0){const t=W(o);if(t===null)throw new f("not_found",`provider "${o}" is not available`);o=t}if(o!==void 0&&!_.includes(o))throw new f("not_found",`provider "${o}" is not available`);const $=o===void 0?_:[o],O=e.class==="person"?u.flatMap(t=>t.status==="active"&&(!h()||t.sub===e.sub)?t.resolved_scopes.map(({scope:c})=>c):[]):e.resolved??[],b=await Promise.all($.map(async t=>{if(w.has(t))return z(e,t);if(!O.some(g=>g.startsWith(`${t}:`)&&R(e,g)))return null;const c=L(t);return c===void 0?null:{provider:t,display_name:t,status:c.status,...c.error?{error:c.error}:{},groups:[],commands:[]}})).then(t=>t.filter(c=>c!==null));if(S({level:"debug",event:"api.provider.tools",duration_ms:performance.now()-i,fields:{caller:e.class,provider:o??null,providers:b.length}}),o!==void 0){if(b.length===0)throw new f("not_found",`provider "${o}" is not available`);return{status:200,body:b[0]}}return{status:200,body:{providers:b}}}s(ne,"providerTools");async function se(e,r,n){return U(e,r,n)}s(se,"providerCall");async function ie(e,r,n,o){if(!ee())throw new f("not_found","provider operations need a directory-connected runtime");if(e==="audit.list")return await te(r,n.query);if(e==="provider.tools")return ne(r,n.params.provider===void 0?void 0:I(n.params.provider),o);if(e==="provider.call"){let i;try{i=oe(n.body)}catch(a){const d=n.body&&typeof n.body=="object"&&!Array.isArray(n.body)?n.body:{};throw await X({request_id:o.requestId,caller:r,provider:typeof d.provider=="string"?d.provider:"",tool:typeof d.tool=="string"?d.tool:"",outcome:`refused:${a instanceof f?a.code:"invalid_request"}`}),a}return se(r,i,o)}throw new f("not_found","unknown operation")}s(ie,"handleProviderOperation");function ae(e){const r=new AbortController,n=s(()=>{e.writableFinished||r.abort()},"abort");return e.on("close",n),{signal:r.signal,release:s(()=>e.off("close",n),"release")}}s(ae,"abortOnClose");function de(e,r,n,o){const i=D(e,r,n,o??void 0);return i.status>=500&&!(e instanceof f)&&S({event:"api.provider.failed",level:"error",error:e instanceof Error?e:new Error(String(e)),fields:{request_id:r}}),i}s(de,"providerFailure");const Ie=[{method:"GET",pattern:"/v1/audit",name:"audit.list"},{method:"GET",pattern:"/v1/providers/tools",name:"provider.tools"},{method:"GET",pattern:"/v1/providers/:provider/tools",name:"provider.tools"},{method:"POST",pattern:"/v1/provider/call",name:"provider.call"}].map(({method:e,pattern:r,name:n})=>({method:e,pattern:r,handler:s(async o=>{const i=G(),{signal:a,release:d}=ae(o.res);let u=null;try{return u=await H(o.principal),{...await ie(n,u,{params:o.params,body:o.body,query:new URL(o.req.url??"/","http://runtime.local").searchParams},{requestId:i,signal:a,...o.causedBy===void 0?{}:{causedBy:o.causedBy}}),headers:{"Request-Id":i}}}catch(l){return de(l,i,!1,u?.run_id)}finally{d()}},"handler")}));export{Ae as PROVIDER_OPERATIONS,ae as abortOnClose,R as callerAllows,Ee as callerFromApp,H as callerFromRequest,ie as handleProviderOperation,oe as parseCallInput,I as parseProvider,de as providerFailure,ee as providerOperationsEnabled,Ie as providerRoutes,Re as requireGroup};
|
|
1
|
+
var q=Object.defineProperty;var s=(e,r)=>q(e,"name",{value:r,configurable:!0});import{randomUUID as G}from"node:crypto";import{cloudPersonScope as N}from"../../../core/runs/operations.js";import{directoryIssuer as T}from"../../../core/directory/issuer.js";import{activeGrantForApp as F,allGrants as x,grantFor as C,localGrants as j,providerIdsFromGrants as y}from"../../../core/grants/mirror.js";import{getNode as k}from"../../../core/canvas/canvas.js";import{scopeAllowed as B}from"../../../core/scopes.js";import{ProviderError as f,providerErrorBody as D,scopeMissing as M}from"../../../core/providers/errors.js";import{callProvider as U,providerTools as z}from"../../../core/providers/call.js";import{providerInstallState as L}from"../../../core/providers/bundles.js";import{installedProviderPlugins as V,providerRootClaims as Z,resolveProviderRef as W}from"../../../core/providers/roots.js";import{isCloudRole as h}from"../../../core/canvas/person-state.js";import{listAudit as J,writeProviderAudit as X}from"../../../core/providers/audit.js";import{emitEvent as S}from"../../../core/events/emit.js";import{resolvedScopes as P}from"../router.js";const Ae=new Set(["provider.tools","provider.call","audit.list"]);async function H(e){if(e.class==="forwarded"){if(e.actor.kind==="person")return{class:"person",sub:null,grantee:null,client_id:null,resolved:null,nodeScopes:null,run_id:null,node_id:null,origin:{node:null,run:null,machine:e.via}};const r=await C(e.actor.app,e.sub);if(!r)throw new f("grant_revoked",`app ${e.actor.app} has no active grant`);return{class:"app",sub:e.sub,grantee:e.actor.app,client_id:null,resolved:r.resolved,nodeScopes:e.actor.node_scopes,run_id:null,node_id:null,origin:{node:e.actor.node,run:e.actor.place?.run??null,machine:e.via}}}if(e.class==="machine"||e.class==="import")throw new f("permission_error","this operation is not available to the caller");if(e.class==="person"&&e.sub!==void 0)throw new f("permission_error","provider calls are made by the install's person, a node or an app");if(e.class==="person")return{class:"person",sub:null,grantee:null,client_id:null,resolved:null,nodeScopes:null,run_id:null,node_id:null};if(e.class==="app"){const r=await F(e.app);if(!r)throw new f("grant_revoked",`app ${e.app} has no active grant`);return{class:"app",sub:r.sub,grantee:e.app,client_id:null,resolved:r.resolved,nodeScopes:e.scopes,run_id:null,node_id:null}}return e.class==="cron"?{class:"app",sub:e.sub,grantee:e.app,client_id:null,resolved:await P(e),nodeScopes:e.scopes,run_id:e.origin_run,node_id:null}:{class:"broker",sub:e.sub,grantee:e.app,client_id:e.client_id,resolved:await P(e),nodeScopes:e.scopes,run_id:e.run??(await k(e.node))?.run_id??null,node_id:e.node}}s(H,"callerFromRequest");function Ee(e){return{class:"app",sub:e.sub,grantee:e.grantee,client_id:e.client_id,resolved:e.resolved,nodeScopes:null,run_id:null,node_id:null}}s(Ee,"callerFromApp");const K=/^([A-Za-z0-9_-]{1,64}):([A-Za-z0-9_-]{1,64})$/;function Q(e){const r=K.exec(e);return r!==null&&r[1]!=="crtr"}s(Q,"isProviderScope");const A=new WeakMap;function Y(e){let r=A.get(e);return r===void 0&&(r=new Set(e),A.set(e,r)),r}s(Y,"heldSet");function E(e,r){return e===null?!0:Q(r)?Y(e).has(r):B(e,r)}s(E,"holds");function R(e,r){return e.class==="person"?!0:E(e.resolved??[],r)&&E(e.nodeScopes,r)}s(R,"callerAllows");function Re(e,r,n){const o=`${r}:${n}`;if(!R(e,o))throw M(o)}s(Re,"requireGroup");function ee(){return!!T()}s(ee,"providerOperationsEnabled");const re=/^[A-Za-z0-9_-]{1,64}$/;function m(e,r){return new f("invalid_request",e,{param:r})}s(m,"invalid");function I(e){if(typeof e!="string"||!re.test(e)||e==="crtr")throw m("provider must be a provider id","provider");return e}s(I,"parseProvider");function oe(e){if(!e||typeof e!="object"||Array.isArray(e))throw new f("invalid_request","a JSON object is required");const r=e,n=I(r.provider),o=r.tool;if(typeof o!="string"||!o.trim())throw m("tool must be a non-empty string","tool");const i=r.arguments??{};if(!i||typeof i!="object"||Array.isArray(i))throw m("arguments must be an object","arguments");const a=r.version;if(a!==void 0&&(typeof a!="number"||!Number.isInteger(a)||a<1))throw m("version must be an integer >= 1","version");const d=r.approval;if(d!==void 0&&(typeof d!="string"||!d))throw m("approval must be a question id","approval");const u=r.machine;if(u!==void 0&&(typeof u!="string"||!u.trim()))throw m("machine must be a machine id","machine");return{provider:n,tool:o.trim(),arguments:i,...a===void 0?{}:{version:a},...d===void 0?{}:{approval:d},...u===void 0?{}:{machine:u.trim()}}}s(oe,"parseCallInput");async function te(e,r=new URLSearchParams){const n=s((l,v,w)=>{const p=r.get(l);if(p===null)return v;if(!/^\d+$/.test(p)||Number(p)>w||Number(p)<1)throw m(`invalid ${l}`,l);return Number(p)},"numeric"),o=r.has("after")?n("after",0,Number.MAX_SAFE_INTEGER):void 0,i=n("limit",100,1e3),a=Object.fromEntries(["operation","outcome","run_id","since","until"].filter(l=>r.has(l)).map(l=>[l,r.get(l)])),d=N(e.sub),u=d===void 0?{}:{sub:d};return{status:200,body:await J(e.class==="person"?null:e.grantee,{after:o,limit:i,...u,...a})}}s(te,"auditList");async function ne(e,r,n){let o=r;const i=performance.now(),a=V(),{skipped:d}=Z(a),u=h()?await x():await j(),l=h()?new Set(y(u.filter(t=>t.sub===e.sub))):null,v=s(t=>!d.has(t)&&(l===null||l.has(t)),"shown"),w=new Set(a.filter(t=>t.enabled&&t.manifest.provider?.id===t.name&&v(t.name)).map(t=>t.name)),p=y(u).filter(v),_=[...new Set([...w,...p])].sort();if(o!==void 0){const t=W(o);if(t===null)throw new f("not_found",`provider "${o}" is not available`);o=t}if(o!==void 0&&!_.includes(o))throw new f("not_found",`provider "${o}" is not available`);const $=o===void 0?_:[o],O=e.class==="person"?u.flatMap(t=>t.status==="active"&&(!h()||t.sub===e.sub)?t.resolved_scopes.map(({scope:c})=>c):[]):e.resolved??[],b=await Promise.all($.map(async t=>{if(w.has(t))return z(e,t);if(!O.some(g=>g.startsWith(`${t}:`)&&R(e,g)))return null;const c=L(t);return c===void 0?null:{provider:t,display_name:t,status:c.status,...c.error?{error:c.error}:{},groups:[],commands:[]}})).then(t=>t.filter(c=>c!==null));if(S({level:"debug",event:"api.provider.tools",duration_ms:performance.now()-i,fields:{caller:e.class,provider:o??null,providers:b.length}}),o!==void 0){if(b.length===0)throw new f("not_found",`provider "${o}" is not available`);return{status:200,body:b[0]}}return{status:200,body:{providers:b}}}s(ne,"providerTools");async function se(e,r,n){return U(e,r,n)}s(se,"providerCall");async function ie(e,r,n,o){if(!ee())throw new f("not_found","provider operations need a directory-connected runtime");if(e==="audit.list")return await te(r,n.query);if(e==="provider.tools")return ne(r,n.params.provider===void 0?void 0:I(n.params.provider),o);if(e==="provider.call"){let i;try{i=oe(n.body)}catch(a){const d=n.body&&typeof n.body=="object"&&!Array.isArray(n.body)?n.body:{};throw await X({request_id:o.requestId,caller:r,provider:typeof d.provider=="string"?d.provider:"",tool:typeof d.tool=="string"?d.tool:"",outcome:`refused:${a instanceof f?a.code:"invalid_request"}`}),a}return se(r,i,o)}throw new f("not_found","unknown operation")}s(ie,"handleProviderOperation");function ae(e){const r=new AbortController,n=s(()=>{e.writableFinished||r.abort()},"abort");return e.on("close",n),{signal:r.signal,release:s(()=>e.off("close",n),"release")}}s(ae,"abortOnClose");function de(e,r,n,o){const i=D(e,r,n,o??void 0);return i.status>=500&&!(e instanceof f)&&S({event:"api.provider.failed",level:"error",error:e instanceof Error?e:new Error(String(e)),fields:{request_id:r}}),i}s(de,"providerFailure");const Ie=[{method:"GET",pattern:"/v1/audit",name:"audit.list"},{method:"GET",pattern:"/v1/providers/tools",name:"provider.tools"},{method:"GET",pattern:"/v1/providers/:provider/tools",name:"provider.tools"},{method:"POST",pattern:"/v1/provider/call",name:"provider.call"}].map(({method:e,pattern:r,name:n})=>({method:e,pattern:r,handler:s(async o=>{const i=G(),{signal:a,release:d}=ae(o.res);let u=null;try{return u=await H(o.principal),{...await ie(n,u,{params:o.params,body:o.body,query:new URL(o.req.url??"/","http://runtime.local").searchParams},{requestId:i,signal:a,...o.causedBy===void 0?{}:{causedBy:o.causedBy}}),headers:{"Request-Id":i}}}catch(l){return de(l,i,!1,u?.run_id)}finally{d()}},"handler")}));export{Ae as PROVIDER_OPERATIONS,ae as abortOnClose,R as callerAllows,Ee as callerFromApp,H as callerFromRequest,ie as handleProviderOperation,oe as parseCallInput,I as parseProvider,de as providerFailure,ee as providerOperationsEnabled,Ie as providerRoutes,Re as requireGroup};
|
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
var
|
|
1
|
+
var M=Object.defineProperty;var s=(t,e)=>M(t,"name",{value:e,configurable:!0});import{existsSync as P}from"node:fs";import{getNode as d}from"../../../core/canvas/canvas.js";import{liveExecutionForNode as D}from"../../../core/canvas/executions.js";import{markStopSignal as B}from"../../../core/runtime/stop-signals.js";import{emitEvent as j}from"../../../core/events/emit.js";import{push as J,FinalizationError as k,StructuredRequestFinalizationError as z}from"../../../core/feed/feed.js";import{branchIsPushedAtCurrentTip as L,hasOpenManagedWorktree as W,missingWorktreeRecoveryHint as H}from"../../../core/worktree.js";import{autoDropCleanManagedWorktreeAsync as X}from"../../../core/worktree-mutation-async.js";import{withCanvasWrite as G,openDb as K}from"../../../core/canvas/db.js";import{getMany as U}from"../../../core/graph/bodies.js";import{heads as V}from"../../../core/graph/documents.js";import{listObjects as Y,nodeObject as Q}from"../../../core/graph/objects.js";import{readerFor as Z}from"../../../core/graph/reader.js";import{notFound as ee,usage as f}from"../../../core/errors.js";import{InputError as u}from"../../../core/io.js";import{toReportResultDTO as te}from"../map.js";import{validateStructuredResult as re}from"../../../core/runtime/structured-output.js";import{clearSchemaReprompts as ne}from"../../../core/runtime/output-result.js";import{getPendingStructuredRequestForNode as _,getStructuredRequest as S,settleStructuredRequestIn as ie}from"../../../core/canvas/structured-requests.js";import{ApiError as h}from"../../../api/errors.js";import{applySettlementEffects as R}from"../../structured-requests/effects.js";import{nodeEventStreams as x}from"./node-events.js";import{emitRunEvent as E}from"../../../core/runs/events.js";import{mapAsync as oe}from"../../../core/async-array.js";async function g(t){const e=await d(t);if(e===null)throw ee(`unknown node: ${t}`,{received:t});return e}s(g,"requireNode");function ae(t){if(typeof t!="object"||t===null)throw f("a push report requires a JSON body { tier, body }");const e=t.tier,r=t.delivery_tier,i=t.body;if(e!=="update"&&e!=="urgent"&&e!=="final")throw f(`invalid report tier: ${String(e)} (expected update|urgent|final)`);if(r!==void 0&&r!=="deferred"&&r!=="normal"&&r!=="urgent")throw f(`invalid delivery_tier: ${String(r)} (expected deferred|normal|urgent)`);if(e!=="update"&&r!==void 0)throw f("delivery_tier is only valid for update reports");if(typeof i!="string"||i.trim()==="")throw f("a push report requires a non-empty body");return{tier:e,...r===void 0?{}:{delivery_tier:r},body:i}}s(ae,"parsePushBody");async function se(t){const e=t.params.id;await g(e);const r=ae(t.body);if(r.tier==="final"&&await _(e)!==null)throw new u({error:"structured_result_pending",message:"This node owes a structured result \u2014 a plain `push final` would finish it without recording one.",next:'Submit the result with the `submit_result` tool instead (or `crtr push result`); it validates against the pending schema, records it, and pushes the final report for you. If the schema cannot be honestly satisfied, call `submit_result` with `decline` (or `crtr push result --decline "<reason>" --code <token>`) to record the decline and finish the node.'});const i=r.tier==="final"?(await d(e))?.status:void 0,n=r.tier==="final"?await O(e):void 0,o=await b(e,r);r.tier==="final"&&await A(e);const a=r.tier==="final"&&i!==void 0?{from:i,to:(await d(e))?.status??"done"}:void 0,c=te(o,a,n),m=(await q(e)).find(p=>p.id===o.reportId);if(m!==void 0){x.report(e,m);const p=(await d(e))?.run_id;p&&await E(p,e,"node.report.pushed",{body:m.body,kind:m.tier==="final"?"final":"update"})}return{status:200,body:c}}s(se,"handlePush");async function O(t){if(!W(await d(t)))return;const e=await X(t);if(e!==null)return e.worktree_path;if(!await L((await d(t)).managed_worktree))throw new u({error:"open_managed_worktree",message:"This node still owns an open managed worktree that is neither clean and locally landed nor clean with its exact tip on origin \u2014 `push final` cannot finish.",next:await(async()=>{const r=(await d(t))?.managed_worktree;return r!=null&&r.state==="open"&&!P(r.path)?H(r):"Make the recorded worktree clean, including untracked files: commit work to retain and remove or ignore only disposable generated files. With its recorded branch checked out and no rebase in progress, push its current tip to a branch on origin, then rerun `crtr push final`; or run `crtr node worktree close` to land the clean worktree into its recorded local base."})()})}s(O,"guardFinalWorktree");const $=2e3;function de(t){const e=JSON.stringify(t,null,2);return`Structured output submitted.
|
|
2
2
|
|
|
3
3
|
\`\`\`json
|
|
4
4
|
${e.length>$?`${e.slice(0,$)}
|
|
5
5
|
\u2026 (truncated \u2014 the full result is on the structured request)`:e}
|
|
6
6
|
\`\`\`
|
|
7
|
-
`}
|
|
7
|
+
`}s(de,"submitReportBody");function ue(t){return`Structured result declined.
|
|
8
8
|
|
|
9
9
|
Reason: ${t.reason}
|
|
10
10
|
Code: ${t.code}
|
|
11
11
|
Retryable: ${t.retryable?"yes":"no"}
|
|
12
|
-
`}
|
|
12
|
+
`}s(ue,"declineReportBody");const I=1024,N=64;async function ce(t,e){if(typeof t!="object"||t===null)throw f("a result submission requires a JSON body { value } or { decline, code, retryable }");const r=t.request_id;if(typeof r!="string"||r.trim()===""){const o=await _(e);throw new u({error:"request_id_required",message:`a structured result requires request_id${o===null?"":` (pending request: ${o.request_id})`}`,next:"Pass `--request <request-id>` exactly as named in the structured-output instruction."})}const i=Object.hasOwn(t,"value"),n=Object.hasOwn(t,"decline");if(i&&n)throw f("a result submission carries either { value } or { decline, code, retryable }, not both");if(n){const{decline:o,code:a,retryable:c}=t;if(typeof o!="string"||o.trim()==="")throw new u({error:"missing_decline_reason",message:"A decline needs a reason.",next:'Rerun with `--decline "<one sentence on why the schema cannot be honestly satisfied>" --code <token>`.'});if(o.length>I)throw new u({error:"decline_reason_too_long",message:`A decline reason is at most ${I} characters (got ${o.length}).`,next:"Keep the reason to one plain sentence; put any detail in an artifact and name its path."});if(typeof a!="string"||a.trim()===""||/\s/.test(a.trim())||a.trim().length>N)throw new u({error:"invalid_decline_code",message:`A decline needs a code: one whitespace-free token of at most ${N} characters naming the decline class.`,next:"Rerun with `--code <token>` \u2014 the token your requester documented for this case."});if(typeof c!="boolean")throw f("a decline carries `retryable` as a boolean");return{requestId:r.trim(),declined:{reason:o.trim(),code:a.trim(),retryable:c}}}if(!i)throw f("a result submission requires a JSON body { value } or { decline, code, retryable }");return{requestId:r.trim(),value:t.value}}s(ce,"parseSubmitBody");const le=1024*1024;async function fe(t){const e=t.params.id,r=await g(e);await _(e)!==null&&await ne(e);const i=await ce(t.body,e),n=await S(i.requestId);if(n===null||n.node_id!==e)throw new h(404,"structured_request_not_found","the named structured request does not belong to this node");if(n.state!=="pending")throw new h(409,n.state==="expired"?"structured_request_expired":"structured_request_settled",`structured request ${n.request_id} is already ${n.state}`);let o;if("value"in i){if(Buffer.byteLength(JSON.stringify(i.value)??"")>le)throw new u({error:"result_too_large",message:"the submitted result is over 1 MiB serialized; nothing was recorded.",next:"Submit a smaller result \u2014 write bulky content to a file and put its path in the result."});try{o=await re(n.schema,i.value)}catch(l){throw new u({error:"result_schema_mismatch",message:`the submitted result does not match the requested schema: ${l.message}`,next:'Fix the listed fields and submit again; if the schema cannot be honestly satisfied, decline it (`submit_result` with `decline`, or `crtr push result --decline "<reason>" --code <token>`).'})}}const a="declined"in i?ue(i.declined):de(o);if(n.submission==="oneoff"){const l=await G(async C=>await ie(C,n.request_id,"declined"in i?{intended:"declined",declined:i.declined}:{intended:"completed",result:o}));if(!l.changed||l.row===null||l.row.state!=="completed"&&l.row.state!=="declined")throw new h(409,l.row?.state==="expired"?"structured_request_expired":"structured_request_settled",`structured request ${n.request_id} is already ${l.row?.state??"settled"}`);await R(l.row);const y=await b(e,{tier:"update",body:a},void 0,{requestMessageId:n.request_message_id});return await T(e,y.reportId),{status:200,body:{mode:n.submission,report:y.report,notified:[...y.deliveredTo],..."declined"in i?{declined:i.declined}:{}}}}const c=(await d(e))?.status,m=await O(e),p="declined"in i?{kind:"failure",reason:"declined",detailJson:JSON.stringify({schema:"crtr.node-outcome-detail/v1",message:i.declined.reason,declined:i.declined}),structured:{requestId:n.request_id,declined:i.declined,skipEffects:!0}}:{structured:{requestId:n.request_id,value:o,skipEffects:!0}},w=await b(e,{tier:"final",body:a},p);await A(e);const F=await S(n.request_id);await R(F),await T(e,w.reportId);const v=c===void 0?void 0:{from:c,to:(await d(e))?.status??"done"};return{status:200,body:{mode:n.submission,report:w.report,notified:[...w.deliveredTo],..."declined"in i?{declined:i.declined}:{},...v===void 0?{}:{transitioned:v},...m===void 0?{}:{worktree_auto_dropped:!0,worktree_auto_dropped_path:m}}}}s(fe,"handleSubmitResult");async function T(t,e){const r=(await q(t)).find(n=>n.id===e);if(r===void 0)return;x.report(t,r);const i=(await d(t))?.run_id;i&&await E(i,t,"node.report.pushed",{body:r.body,kind:r.tier==="final"?"final":"update"})}s(T,"emitReportEvents");async function A(t){try{const e=await D(t);e!==null&&B(t,"pushedFinal",e.executionId)}catch(e){try{j({event:"daemon.node.final-marker.failed",level:"error",node_id:t,error:e})||process.stderr.write(`final marker failed for ${t}: ${String(e)}
|
|
13
13
|
`)}catch{process.stderr.write(`final marker failed for ${t}: ${String(e)}
|
|
14
|
-
`)}}}
|
|
14
|
+
`)}}}s(A,"markCommittedFinal");async function b(t,e,r,i){try{return await J(t,{kind:e.tier,body:e.body,...e.delivery_tier===void 0?{}:{deliveryTier:e.delivery_tier},...r===void 0?{}:{outcome:r},...i===void 0?{}:{result:i}})}catch(n){throw n instanceof z?new h(409,n.message,n.message==="structured_request_expired"?"the named structured request expired before this submission committed":"the named structured request is already settled"):n instanceof k&&n.code==="already_finalized"?new u({error:"already_finalized",message:"This node already submitted its canonical final result.",next:"Push an update with the new information, then stop."}):n instanceof k&&n.code==="finalization_forbidden"?new u({error:"finalization_forbidden",message:"A canceled or dead node cannot submit a canonical final result.",next:"Do not push final from this node."}):n}}s(b,"pushOrRethrow");async function q(t){const e=await K(),r=await Y(e,await Z(e,{class:"person"},async()=>[]),{type:"document",kind:"report",owner:await Q(e,t)}),i=await oe(r,async o=>({doc:o,head:(await V(e,o))[0]})),n=await U(e,i.flatMap(o=>o.head===void 0?[]:[o.head.body_hash]));return i.map(({doc:o,head:a})=>{const c=o.name.match(/-(update|urgent|final)$/)?.[1]??"update";return{name:o.name,id:o.id,tier:c,body:a===void 0?"":n.get(a.body_hash).trim(),created:o.created_at}}).sort((o,a)=>o.created<a.created?1:o.created>a.created?-1:a.name.localeCompare(o.name))}s(q,"reportsForNode");async function me(t){const e=t.params.id;await g(e);const r=t.query.get("tier"),i=t.query.get("limit"),n=i!==null?Number(i):void 0;let o=await q(e);return r!==null&&(o=o.filter(a=>a.tier===r)),n!==void 0&&Number.isFinite(n)&&n>=0&&(o=o.slice(0,n)),{status:200,body:o}}s(me,"handleList");const Be=[{method:"POST",pattern:"/v1/nodes/:id/reports",ownerOnly:!0,handler:se},{method:"GET",pattern:"/v1/nodes/:id/reports",handler:me},{method:"POST",pattern:"/v1/nodes/:id/result",handler:fe}];export{Be as reportRoutes,q as reportsForNode};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var S=Object.defineProperty;var c=(a,t)=>S(a,"name",{value:t,configurable:!0});import{callerGrant as g}from"../principal.js";import{grantVersion as b,payerOfGrant as O}from"../../../core/grants/mirror.js";import{holdGrant as $}from"../../../core/grants/watch.js";import{RunError as n,idempotencyKeyOf as v,cancelRun as N,cloudPersonScope as A,deleteRun as j,interruptRun as x,listRuns as B,messageRun as J,renameRun as z,requestedScopes as D,startRun as E,traceRun as G,waitRun as K}from"../../../core/runs/operations.js";import{canReadRun as y,requireRun as w,runCallerApp as M}from"../router.js";import{waitSeconds as q}from"../long-poll-wait.js";import{outputSchemaProblem as P}from"../../../core/runtime/structured-output.js";function m(a){if(!a||typeof a!="object"||Array.isArray(a))throw new n(400,"invalid_request","a JSON object is required");return a}c(m,"object");function k(a,t,i,u,l){if(a===null)return l;if(!/^(0|[1-9]\d*)$/.test(a)||!Number.isSafeInteger(Number(a))||Number(a)<i||Number(a)>u)throw new n(400,"invalid_request",`invalid ${t}`,t);return Number(a)}c(k,"integer");const T=256*1024;async function Y(a,t,i,u,l,_,h){switch(a.name){case"grant.get":{if("class"in t)throw new n(403,"permission_error","an app token is required");const e=q("grant.get",u),s=u.get("since");if(s!==null&&!/^[A-Za-z0-9_-]{1,64}$/.test(s))throw new n(400,"invalid_request","invalid since","since");const d=e&&s!==null?$(t.grant):void 0;let o;try{if(o=await g(t),d){const f=Date.now()+e*1e3;for(;b(o)===s&&Date.now()<f;)await d.changed(Math.max(0,(f-Date.now())/1e3)),o=await g(t)}}finally{d?.release()}return{status:200,body:{sub:t.sub,grantee:t.grantee,client_id:t.client_id,grant:t.grant,rev:o.rev,resolved_scopes:o.resolved_scopes,spend_cap:o.spend_cap,exp:t.exp,payer:await O(t.grant),dependencies:o.dependencies??{},version:b(o)}}}case"run.start":{if("class"in t)throw new n(403,"permission_error","an app token is required");const e=m(l),s=["mode","parent","fork_from","node_id","env","tools","system_prompt"];for(const r of s)if(e[r]!==void 0)throw new n(403,"owner_only",`${r} is owner-only`,r);const d=["payer","model_policy","kind"];for(const r of d)if(e[r]!==void 0)throw new n(400,"invalid_request",`${r} is not available`,r);for(const r of Object.keys(e))if(!["prompt","scopes","metadata","profile","isolated","cwd","worktree","output_schema","message","model","deadline"].includes(r))throw new n(400,"invalid_request",`unknown field ${r}`,r);if(e.model!==void 0&&(typeof e.model!="string"||!e.model.trim()))throw new n(400,"invalid_request","model must be a non-empty string","model");if(e.deadline!==void 0&&(typeof e.deadline!="string"||!e.deadline.trim()))throw new n(400,"invalid_request","deadline must be a duration string such as 10m","deadline");if(e.profile!==void 0&&(typeof e.profile!="string"||!e.profile))throw new n(400,"invalid_request","profile must be a profile id","profile");if(e.isolated!==void 0&&typeof e.isolated!="boolean")throw new n(400,"invalid_request","isolated must be a boolean","isolated");if(e.cwd!==void 0&&(e.isolated!==!0||typeof e.cwd!="string"||!e.cwd))throw new n(400,"invalid_request","cwd is available only for an isolated run and must be an absolute path inside its root folder","cwd");if(e.worktree!==void 0&&e.isolated!==!0)throw new n(400,"invalid_request","worktree is not available","worktree");if(e.isolated===!0&&e.worktree!==void 0)throw new n(400,"invalid_request","worktree is unavailable for an isolated run","worktree");if(typeof e.prompt!="string"||!e.prompt.trim())throw new n(400,"invalid_request","prompt is required","prompt");if(e.message!==void 0&&(typeof e.message!="string"||!e.message.trim()))throw new n(400,"invalid_request","message must be a non-empty string","message");const o=e.metadata===void 0?{}:m(e.metadata);if(Buffer.byteLength(JSON.stringify(o))>4096)throw new n(400,"invalid_request","metadata exceeds 4 KB","metadata");let f;if(e.output_schema!==void 0){const r=e.output_schema;if(!r||typeof r!="object"||Array.isArray(r))throw new n(400,"invalid_request","output_schema must be a JSON Schema object","output_schema");if(Buffer.byteLength(JSON.stringify(r))>T)throw new n(400,"invalid_request","output_schema exceeds 256 KB","output_schema");const p=await P(r);if(p!==null)throw new n(400,"invalid_request",`output_schema is not usable: ${p}`,"output_schema");f=r}const R=D(t.resolved,e.scopes,t.grantee);return{status:201,body:await E(t,{prompt:e.prompt,scopes:R,metadata:o,profile:e.profile,isolated:e.isolated,cwd:e.cwd,...e.model===void 0?{}:{model:e.model},...e.deadline===void 0?{}:{deadline:e.deadline},...f===void 0?{}:{output_schema:f},...e.message===void 0?{}:{message:e.message},...h===void 0?{}:{causedBy:h}},v(_))}}case"run.list":{const e=u.get("status")??void 0;if(e&&!["running","waiting_on_user","idle","settled"].includes(e))throw new n(400,"invalid_request","invalid status","status");const s=u.get("app");if(s!==null&&!/^(?:app:)?[a-z0-9][a-z0-9-]*$/.test(s))throw new n(400,"invalid_request","invalid app","app");const d=s===null?M(t):s.startsWith("app:")?s:`app:${s}`;if(d!==null&&!await y(t,d))throw new n(404,"not_found","run not found");const o=A(t.sub);return{status:200,body:await B(d,{status:e,...o===void 0?{}:{sub:o},after:u.get("after")??void 0,limit:k(u.get("limit"),"limit",1,100,50),..."class"in t&&(t.class==="broker"||t.class==="cron")&&d!==null?{visible:c(async f=>await y(t,d,f),"visible")}:{}})}}case"run.get":{const e=q("run.get",u),s=await w(t,i),d=await K(i,s.grantee,e);return await w(t,i),{status:200,body:d}}case"run.message":{const e=m(l);if(typeof e.message!="string"||!e.message.trim())throw new n(400,"invalid_request","message is required","message");if(e.start_turn!==void 0&&typeof e.start_turn!="boolean")throw new n(400,"invalid_request","start_turn must be a boolean","start_turn");if(e.steer!==void 0&&typeof e.steer!="boolean")throw new n(400,"invalid_request","steer must be a boolean","steer");if(e.start_turn===!1&&e.steer===!0)throw new n(400,"invalid_request","steer requires start_turn","steer");return{status:202,body:await J(await w(t,i,!0),e.message,void 0,e.start_turn,v(_),e.steer)}}case"run.interrupt":{const e=m(l===void 0?{}:l);if(e.children!==void 0&&e.children!=="stop"&&e.children!=="continue")throw new n(400,"invalid_request","invalid children","children");return{status:200,body:await x(await w(t,i,!0),e.children)}}case"run.cancel":{const e=m(l===void 0?{}:l);if(e.keep_schedules!==void 0&&typeof e.keep_schedules!="boolean")throw new n(400,"invalid_request","invalid keep_schedules","keep_schedules");return{status:200,body:await N(await w(t,i,!0),{keepSchedules:e.keep_schedules})}}case"run.rename":{const e=m(l);for(const s of Object.keys(e))if(s!=="name")throw new n(400,"invalid_request",`unknown field ${s}`,s);return{status:200,body:await z(await w(t,i,!0),e.name)}}case"run.delete":{const{uploads_pending:e}=await j(await w(t,i,!0,!0));return{status:200,body:{run_id:i,uploads_pending:e}}}case"trace.get":{const e=u.get("format")??void 0;if(e&&e!=="entries")throw new n(400,"invalid_request","unknown trace format","format");const s=await w(t,i);return{status:200,body:await G(i,s.grantee,e)}}default:throw new n(404,"not_found","unknown operation")}}c(Y,"handleRunOperation");export{Y as handleRunOperation,k as integer};
|
|
1
|
+
var S=Object.defineProperty;var c=(a,t)=>S(a,"name",{value:t,configurable:!0});import{callerGrant as g}from"../principal.js";import{grantVersion as b,payerOfGrant as O}from"../../../core/grants/mirror.js";import{holdGrant as $}from"../../../core/grants/watch.js";import{RunError as n,idempotencyKeyOf as v,cancelRun as N,cloudPersonScope as A,deleteRun as j,interruptRun as x,listRuns as B,messageRun as J,renameRun as z,requestedScopes as D,startRun as E,traceRun as G,waitRun as K}from"../../../core/runs/operations.js";import{canReadRun as y,requireRun as w,runCallerApp as M}from"../router.js";import{waitSeconds as q}from"../long-poll-wait.js";import{outputSchemaProblem as P}from"../../../core/runtime/structured-output.js";function m(a){if(!a||typeof a!="object"||Array.isArray(a))throw new n(400,"invalid_request","a JSON object is required");return a}c(m,"object");function k(a,t,i,u,l){if(a===null)return l;if(!/^(0|[1-9]\d*)$/.test(a)||!Number.isSafeInteger(Number(a))||Number(a)<i||Number(a)>u)throw new n(400,"invalid_request",`invalid ${t}`,t);return Number(a)}c(k,"integer");const T=256*1024;async function Y(a,t,i,u,l,_,h){switch(a.name){case"grant.get":{if("class"in t)throw new n(403,"permission_error","an app token is required");const e=q("grant.get",u),s=u.get("since");if(s!==null&&!/^[A-Za-z0-9_-]{1,64}$/.test(s))throw new n(400,"invalid_request","invalid since","since");const d=e&&s!==null?$(t.grant):void 0;let o;try{if(o=await g(t),d){const f=Date.now()+e*1e3;for(;b(o)===s&&Date.now()<f;)await d.changed(Math.max(0,(f-Date.now())/1e3)),o=await g(t)}}finally{d?.release()}return{status:200,body:{sub:t.sub,grantee:t.grantee,client_id:t.client_id,grant:t.grant,rev:o.rev,resolved_scopes:o.resolved_scopes,spend_cap:o.spend_cap,exp:t.exp,payer:await O(t.grant),dependencies:o.dependencies??{},version:b(o)}}}case"run.start":{if("class"in t)throw new n(403,"permission_error","an app token is required");const e=m(l),s=["mode","parent","fork_from","node_id","env","tools","system_prompt"];for(const r of s)if(e[r]!==void 0)throw new n(403,"owner_only",`${r} is owner-only`,r);const d=["payer","model_policy","kind"];for(const r of d)if(e[r]!==void 0)throw new n(400,"invalid_request",`${r} is not available`,r);for(const r of Object.keys(e))if(!["prompt","scopes","metadata","profile","isolated","cwd","worktree","output_schema","message","model","deadline"].includes(r))throw new n(400,"invalid_request",`unknown field ${r}`,r);if(e.model!==void 0&&(typeof e.model!="string"||!e.model.trim()))throw new n(400,"invalid_request","model must be a non-empty string","model");if(e.deadline!==void 0&&(typeof e.deadline!="string"||!e.deadline.trim()))throw new n(400,"invalid_request","deadline must be a duration string such as 10m","deadline");if(e.profile!==void 0&&(typeof e.profile!="string"||!e.profile))throw new n(400,"invalid_request","profile must be a profile id","profile");if(e.isolated!==void 0&&typeof e.isolated!="boolean")throw new n(400,"invalid_request","isolated must be a boolean","isolated");if(e.cwd!==void 0&&(e.isolated!==!0||typeof e.cwd!="string"||!e.cwd))throw new n(400,"invalid_request","cwd is available only for an isolated run and must be an absolute path inside its root folder","cwd");if(e.worktree!==void 0&&e.isolated!==!0)throw new n(400,"invalid_request","worktree is not available","worktree");if(e.isolated===!0&&e.worktree!==void 0)throw new n(400,"invalid_request","worktree is unavailable for an isolated run","worktree");if(typeof e.prompt!="string"||!e.prompt.trim())throw new n(400,"invalid_request","prompt is required","prompt");if(e.message!==void 0&&(typeof e.message!="string"||!e.message.trim()))throw new n(400,"invalid_request","message must be a non-empty string","message");const o=e.metadata===void 0?{}:m(e.metadata);if(Buffer.byteLength(JSON.stringify(o))>4096)throw new n(400,"invalid_request","metadata exceeds 4 KB","metadata");let f;if(e.output_schema!==void 0){const r=e.output_schema;if(!r||typeof r!="object"||Array.isArray(r))throw new n(400,"invalid_request","output_schema must be a JSON Schema object","output_schema");if(Buffer.byteLength(JSON.stringify(r))>T)throw new n(400,"invalid_request","output_schema exceeds 256 KB","output_schema");const p=await P(r);if(p!==null)throw new n(400,"invalid_request",`output_schema is not usable: ${p}`,"output_schema");f=r}const R=D(t.resolved,e.scopes,t.grantee);return{status:201,body:await E(t,{prompt:e.prompt,scopes:R,metadata:o,profile:e.profile,isolated:e.isolated,cwd:e.cwd,...e.model===void 0?{}:{model:e.model},...e.deadline===void 0?{}:{deadline:e.deadline},...f===void 0?{}:{output_schema:f},...e.message===void 0?{}:{message:e.message},...h===void 0?{}:{causedBy:h}},v(_))}}case"run.list":{const e=u.get("status")??void 0;if(e&&!["running","waiting_on_user","idle","settled"].includes(e))throw new n(400,"invalid_request","invalid status","status");const s=u.get("app");if(s!==null&&!/^(?:app:)?[a-z0-9][a-z0-9-]*$/.test(s))throw new n(400,"invalid_request","invalid app","app");const d=s===null?M(t):s.startsWith("app:")?s:`app:${s}`;if(d!==null&&!await y(t,d))throw new n(404,"not_found","run not found");const o=A("sub"in t?t.sub:void 0);return{status:200,body:await B(d,{status:e,...o===void 0?{}:{sub:o},after:u.get("after")??void 0,limit:k(u.get("limit"),"limit",1,100,50),..."class"in t&&(t.class==="broker"||t.class==="cron")&&d!==null?{visible:c(async f=>await y(t,d,f),"visible")}:{}})}}case"run.get":{const e=q("run.get",u),s=await w(t,i),d=await K(i,s.grantee,e);return await w(t,i),{status:200,body:d}}case"run.message":{const e=m(l);if(typeof e.message!="string"||!e.message.trim())throw new n(400,"invalid_request","message is required","message");if(e.start_turn!==void 0&&typeof e.start_turn!="boolean")throw new n(400,"invalid_request","start_turn must be a boolean","start_turn");if(e.steer!==void 0&&typeof e.steer!="boolean")throw new n(400,"invalid_request","steer must be a boolean","steer");if(e.start_turn===!1&&e.steer===!0)throw new n(400,"invalid_request","steer requires start_turn","steer");return{status:202,body:await J(await w(t,i,!0),e.message,void 0,e.start_turn,v(_),e.steer)}}case"run.interrupt":{const e=m(l===void 0?{}:l);if(e.children!==void 0&&e.children!=="stop"&&e.children!=="continue")throw new n(400,"invalid_request","invalid children","children");return{status:200,body:await x(await w(t,i,!0),e.children)}}case"run.cancel":{const e=m(l===void 0?{}:l);if(e.keep_schedules!==void 0&&typeof e.keep_schedules!="boolean")throw new n(400,"invalid_request","invalid keep_schedules","keep_schedules");return{status:200,body:await N(await w(t,i,!0),{keepSchedules:e.keep_schedules})}}case"run.rename":{const e=m(l);for(const s of Object.keys(e))if(s!=="name")throw new n(400,"invalid_request",`unknown field ${s}`,s);return{status:200,body:await z(await w(t,i,!0),e.name)}}case"run.delete":{const{uploads_pending:e}=await j(await w(t,i,!0,!0));return{status:200,body:{run_id:i,uploads_pending:e}}}case"trace.get":{const e=u.get("format")??void 0;if(e&&e!=="entries")throw new n(400,"invalid_request","unknown trace format","format");const s=await w(t,i);return{status:200,body:await G(i,s.grantee,e)}}default:throw new n(404,"not_found","unknown operation")}}c(Y,"handleRunOperation");export{Y as handleRunOperation,k as integer};
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { ImportPrincipal } from './router.js';
|
|
2
|
+
export declare const IMPORT_TOKEN_PREFIX = "crtr_imp_";
|
|
3
|
+
/** The import token for `run`: `crtr_imp_<run>.<hex hmac-sha256(run) under the service token>`; null when the service token is unset. */
|
|
4
|
+
export declare function importTokenFor(run: string): string | null;
|
|
5
|
+
/** The principal a bearer is, when it is the service credential or a valid import token; null otherwise (including when the service token is unset). */
|
|
6
|
+
export declare function importPrincipalFor(token: string): ImportPrincipal | null;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
var u=Object.defineProperty;var e=(t,n)=>u(t,"name",{value:n,configurable:!0});import{createHash as a,createHmac as p,timingSafeEqual as m}from"node:crypto";const s="crtr_imp_",i=e(()=>{const t=process.env.CRTR_IMPORT_SERVICE_TOKEN;return t===void 0||t===""?null:t},"serviceToken"),c=e(t=>a("sha256").update(t).digest(),"digest"),o=e((t,n)=>m(c(t),c(n)),"sameString");function d(t){const n=i();return n===null?null:`${s}${t}.${p("sha256",n).update(t).digest("hex")}`}e(d,"importTokenFor");function _(t){const n=i();if(n===null)return null;if(t.startsWith(s)){const r=t.slice(s.length).split(".")[0]??"",l=d(r);return r!==""&&l!==null&&o(t,l)?{class:"import",run:r}:null}return o(t,n)?{class:"import",run:null}:null}e(_,"importPrincipalFor");export{s as IMPORT_TOKEN_PREFIX,_ as importPrincipalFor,d as importTokenFor};
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { Scope } from '@north-light/identity';
|
|
2
|
-
export type CallerClass = 'anonymous' | 'person' | 'app' | 'broker' | 'cron' | 'directory' | 'forwarded' | 'machine';
|
|
3
|
-
export type ResourceRule = 'none' | 'node-read' | 'node-write' | 'node-own' | 'nodes-list' | 'canvas-read' | 'cron' | 'profile' | 'human' | 'run' | 'daemon-bash' | 'objects';
|
|
2
|
+
export type CallerClass = 'anonymous' | 'person' | 'app' | 'broker' | 'cron' | 'directory' | 'forwarded' | 'machine' | 'import';
|
|
3
|
+
export type ResourceRule = 'none' | 'node-read' | 'node-write' | 'node-own' | 'nodes-list' | 'canvas-read' | 'cron' | 'profile' | 'human' | 'run' | 'daemon-bash' | 'daemon-control' | 'objects';
|
|
4
4
|
export interface Operation {
|
|
5
5
|
name: string;
|
|
6
6
|
method: string;
|