@north-light/cli 0.3.532 → 0.3.533
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 -3
- package/dist/api/client.js +1 -1
- package/dist/api/contract.d.ts +1 -1
- package/dist/api/contract.js +1 -1
- package/dist/api/dto/canvas.d.ts +2 -0
- package/dist/api/dto/crons.d.ts +2 -0
- package/dist/builtin-memory/crouter-sdk/release-notes.md +8 -0
- package/dist/builtin-memory/northlight-apps/providers/README.md +2 -0
- package/dist/builtin-memory/northlight-apps/providers/sms.md +2 -0
- package/dist/clients/attach/chrome/inbox-strip.d.ts +6 -1
- package/dist/clients/attach/chrome/inbox-strip.js +1 -1
- package/dist/clients/attach/chrome/roster.js +1 -1
- package/dist/clients/attach/session/chrome-refresh.d.ts +12 -3
- package/dist/clients/attach/session/chrome-refresh.js +1 -1
- package/dist/clients/attach/session/document-links.js +1 -1
- package/dist/clients/attach/viewer.js +586 -587
- package/dist/commands/api-client.js +3 -3
- package/dist/commands/node/inspect.js +6 -6
- package/dist/commands/sys/context/expose.js +2 -2
- package/dist/commands/sys/db.d.ts +1 -0
- package/dist/commands/sys/db.js +1 -0
- package/dist/commands/sys.js +1 -1
- package/dist/core/bash-guard.js +9 -3
- package/dist/core/canvas/canvas.d.ts +12 -2
- package/dist/core/canvas/canvas.js +23 -20
- package/dist/core/canvas/daemon-actions.d.ts +0 -3
- package/dist/core/canvas/daemon-actions.js +7 -24
- package/dist/core/canvas/daemon-owner.d.ts +3 -0
- package/dist/core/canvas/daemon-owner.js +1 -6
- package/dist/core/canvas/db.d.ts +28 -20
- package/dist/core/canvas/db.js +4 -3
- package/dist/core/canvas/deliveries.d.ts +5 -0
- package/dist/core/canvas/deliveries.js +25 -30
- package/dist/core/canvas/export-sqlite.d.ts +14 -0
- package/dist/core/canvas/export-sqlite.js +3 -0
- package/dist/core/canvas/import-sqlite.d.ts +44 -0
- package/dist/core/canvas/import-sqlite.js +7 -0
- package/dist/core/canvas/node-tokens.js +3 -3
- package/dist/core/canvas/outcome-actions.js +4 -4
- package/dist/core/canvas/recovery.js +1 -1
- package/dist/core/canvas/schema-pg.sql +1022 -0
- package/dist/core/canvas/schema-version.d.ts +4 -0
- package/dist/core/canvas/schema-version.js +1 -0
- package/dist/core/canvas/sessions.js +3 -3
- package/dist/core/canvas/structured-requests.js +2 -2
- package/dist/core/canvas/tree.js +6 -6
- package/dist/core/canvas/waits.js +1 -1
- package/dist/core/feed/inbox.js +1 -1
- package/dist/core/feed/messages.js +5 -5
- package/dist/core/feed/reports.js +2 -2
- package/dist/core/grants/mirror.js +2 -2
- package/dist/core/graph/access.js +7 -7
- package/dist/core/graph/custom.js +10 -10
- package/dist/core/graph/deletion.js +6 -6
- package/dist/core/graph/documents.d.ts +1 -1
- package/dist/core/graph/documents.js +9 -9
- package/dist/core/graph/edges.d.ts +3 -3
- package/dist/core/graph/edges.js +3 -1
- package/dist/core/graph/events.js +7 -7
- package/dist/core/graph/exposures.d.ts +8 -8
- package/dist/core/graph/jobs.d.ts +1 -1
- package/dist/core/graph/jobs.js +2 -2
- package/dist/core/graph/kinds/custom.js +1 -1
- package/dist/core/graph/kinds/document.js +4 -4
- package/dist/core/graph/kinds/dto.js +1 -1
- package/dist/core/graph/kinds/job.js +2 -2
- package/dist/core/graph/kinds/kind.d.ts +2 -2
- package/dist/core/graph/kinds/kind.js +1 -1
- package/dist/core/graph/kinds/live-read.d.ts +5 -0
- package/dist/core/graph/kinds/live-read.js +1 -0
- package/dist/core/graph/kinds/node.js +5 -5
- package/dist/core/graph/kinds/owner.js +2 -2
- package/dist/core/graph/names.js +3 -3
- package/dist/core/graph/objects.d.ts +5 -5
- package/dist/core/graph/objects.js +10 -10
- package/dist/core/graph/package-docs.js +6 -5
- package/dist/core/graph/reader.d.ts +1 -1
- package/dist/core/graph/reader.js +2 -2
- package/dist/core/graph/receivers.js +4 -5
- package/dist/core/graph/repo-sync/exchange.js +2 -2
- package/dist/core/graph/repo-sync/repos.js +3 -3
- package/dist/core/graph/repo-sync/sync.js +1 -1
- package/dist/core/graph/rules.d.ts +3 -4
- package/dist/core/graph/rules.js +3 -3
- package/dist/core/graph/spaces/app.js +1 -1
- package/dist/core/graph/spaces/index.d.ts +1 -1
- package/dist/core/graph/spaces/index.js +1 -1
- package/dist/core/graph/spaces/own-memory.js +1 -1
- package/dist/core/graph/spaces/person.js +3 -3
- package/dist/core/graph/spaces/repo.d.ts +1 -1
- package/dist/core/graph/spaces/repo.js +1 -1
- package/dist/core/graph/types.d.ts +4 -3
- package/dist/core/graph/watches.d.ts +2 -2
- package/dist/core/graph/watches.js +17 -17
- package/dist/core/human/page-schema.js +5 -4
- package/dist/core/human/requests.d.ts +1 -1
- package/dist/core/human/requests.js +20 -23
- package/dist/core/peer/ingest.js +1 -1
- package/dist/core/peer/receiver.js +1 -1
- package/dist/core/peer/stubs.js +1 -1
- package/dist/core/providers/receipts.js +3 -2
- package/dist/core/review/comments.js +5 -4
- package/dist/core/runs/activity.js +4 -5
- package/dist/core/runs/confinement.d.ts +1 -1
- package/dist/core/runs/confinement.js +2 -2
- package/dist/core/runs/events.d.ts +1 -1
- package/dist/core/runs/events.js +5 -5
- package/dist/core/runs/operations.js +6 -4
- package/dist/core/runtime/close.d.ts +3 -0
- package/dist/core/runtime/close.js +1 -1
- package/dist/core/runtime/host.d.ts +5 -1
- package/dist/core/runtime/host.js +3 -3
- package/dist/core/runtime/launch.js +2 -2
- package/dist/core/runtime/ledger.js +3 -3
- package/dist/core/runtime/lifecycle.d.ts +9 -0
- package/dist/core/runtime/lifecycle.js +2 -2
- package/dist/core/runtime/nodes.d.ts +1 -1
- package/dist/core/runtime/nodes.js +1 -1
- package/dist/core/runtime/roadmap.js +1 -1
- package/dist/core/spaces/stop.d.ts +1 -0
- package/dist/core/spaces/stop.js +2 -2
- package/dist/core/statements.d.ts +17 -0
- package/dist/core/statements.js +2 -0
- package/dist/core/substrate/delivery/corpus.js +3 -3
- package/dist/core/substrate/delivery/deliver.js +5 -5
- package/dist/core/substrate/delivery/listings.js +1 -1
- package/dist/core/substrate/delivery/match.d.ts +2 -2
- package/dist/core/substrate/delivery/match.js +1 -1
- package/dist/core/substrate/delivery/plan.js +3 -3
- package/dist/core/substrate/delivery/render-boot.js +5 -5
- package/dist/core/substrate/delivery/render-event.js +6 -6
- package/dist/core/usage/ledger.js +8 -8
- package/dist/daemon/api/bridge.js +4 -4
- package/dist/daemon/api/document-listener.js +1 -1
- package/dist/daemon/api/handlers/broker-ops.js +1 -1
- package/dist/daemon/api/handlers/canvas.js +1 -1
- package/dist/daemon/api/handlers/crons.js +1 -1
- package/dist/daemon/api/handlers/custom-objects.js +3 -3
- package/dist/daemon/api/handlers/docs.js +1 -1
- package/dist/daemon/api/handlers/inbox.js +1 -1
- package/dist/daemon/api/handlers/memory.js +7 -7
- package/dist/daemon/api/handlers/messages.js +1 -1
- package/dist/daemon/api/handlers/nodes.js +1 -1
- package/dist/daemon/api/handlers/objects.js +3 -3
- package/dist/daemon/api/handlers/reviews.js +1 -1
- package/dist/daemon/api/handlers/structured-requests.js +1 -1
- package/dist/daemon/api/reader.js +1 -1
- package/dist/daemon/broker-signals/bus.d.ts +14 -6
- package/dist/daemon/broker-signals/bus.js +1 -10
- package/dist/daemon/crtrd-cli.js +1 -1
- package/dist/daemon/crtrd.js +12 -11
- package/dist/daemon/due.js +1 -1
- package/dist/daemon/export-sqlite-run.d.ts +1 -0
- package/dist/daemon/export-sqlite-run.js +4 -0
- package/dist/daemon/fleet.d.ts +1 -0
- package/dist/daemon/fleet.js +3 -3
- package/dist/daemon/human/settle.js +1 -1
- package/dist/daemon/manage.d.ts +10 -0
- package/dist/daemon/manage.js +3 -2
- package/dist/daemon/postgres/binary.d.ts +17 -0
- package/dist/daemon/postgres/binary.js +2 -0
- package/dist/daemon/postgres/cluster.d.ts +37 -0
- package/dist/daemon/postgres/cluster.js +6 -0
- package/dist/daemon/postgres/index.d.ts +2 -0
- package/dist/daemon/postgres/index.js +1 -0
- package/dist/daemon/postgres/pins.d.ts +7 -0
- package/dist/daemon/postgres/pins.js +1 -0
- package/dist/daemon/postgres/supervisor.d.ts +95 -0
- package/dist/daemon/postgres/supervisor.js +2 -0
- package/dist/daemon/reconcilers/bash-deadline.js +2 -2
- package/dist/daemon/reconcilers/delivery-lane.js +2 -2
- package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.d.ts +7 -3
- package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.js +1 -1
- package/dist/daemon/reconcilers/node-lifecycle/tick.js +1 -1
- package/dist/daemon/reconcilers/storage-maintenance.d.ts +0 -6
- package/dist/daemon/reconcilers/storage-maintenance.js +1 -8
- package/dist/daemon/runs/observer.js +5 -4
- package/dist/migrations/004-canvas-documents/index.js +1 -1
- package/dist/pi-extensions/canvas-doc-substrate.d.ts +2 -0
- package/dist/pi-extensions/canvas-doc-substrate.js +6 -6
- package/dist/pi-extensions/envelope-merge.d.ts +3 -2
- package/dist/pi-extensions/envelope-merge.js +9 -8
- package/dist/shared/env.d.ts +3 -0
- package/dist/shared/env.js +2 -2
- package/docs/apps/providers/README.md +2 -0
- package/docs/apps/providers/sms.md +2 -0
- package/docs/public-api.md +11 -2
- package/docs/sdk/release-notes.md +8 -0
- package/package.json +6 -6
- package/packages/crouter-identity/package.json +1 -1
- package/runtime.lock.json +13 -26
- package/scripts/install-runtime.mjs +53 -3
- package/scripts/lib/isolation-env.mjs +3 -1
|
@@ -1,12 +1,14 @@
|
|
|
1
|
-
var Oe=Object.defineProperty;var c=(e,t)=>Oe(e,"name",{value:t,configurable:!0});import{coveredByAny as be}from"../../shared/env.js";import{createHash as
|
|
1
|
+
var Oe=Object.defineProperty;var c=(e,t)=>Oe(e,"name",{value:t,configurable:!0});import{coveredByAny as be}from"../../shared/env.js";import{createHash as X}from"node:crypto";import{ApiError as De}from"../../api/errors.js";import{CrtrError as Ie}from"../errors.js";import{isAbsolute as z,relative as Me,resolve as Ae,sep as Te,join as Le}from"node:path";import{SessionManager as Ce}from"@earendil-works/pi-coding-agent";import{covers as U}from"@north-light/identity";import{openDb as P,withCanvasWrite as W}from"../canvas/db.js";import{deleteNodeWithOwned as ke}from"../graph/deletion.js";import{getById as xe}from"../graph/objects.js";import{repairRunConversations as Q}from"../canvas/sessions.js";import{getNode as N,nodeFiles as We,removeNodeFiles as Fe,updateNode as He}from"../canvas/canvas.js";import{fullName as qe}from"../canvas/labels.js";import{renameWindow as Ue}from"../runtime/placement.js";import{liveExecutionForNode as V}from"../canvas/executions.js";import{conversationStore as Z,isConversationNotFound as Pe}from"../conversation-store/index.js";import{PARKED_RESIDENT_SQL as $e}from"../canvas/canvas.js";import{WAKE_MAIL_SQL as Be}from"../canvas/deliveries.js";import{enqueueNodeMail as je}from"../feed/messages.js";import{newestReportBody as Je}from"../feed/reports.js";import{ensureAppProfile as Ye,loadExactProfileManifest as Ge}from"../profiles/manifest.js";import{stopNodeSandboxes as K}from"../spaces/stop.js";import{BrokerUnreachableError as Xe}from"../runtime/broker-request.js";import{interruptLive as ze}from"../runtime/interactive-deliver.js";import{isBrokerLive as ee}from"../runtime/model-swap.js";import{newNodeId as Qe}from"../runtime/nodes.js";import{reviveNode as $}from"../runtime/revive.js";import{spawnChildPrepared as Ve}from"../runtime/spawn.js";import{isPortableModelToken as Ze}from"../runtime/launch.js";import{parseDurationMs as Ke}from"../wake.js";import{expandModelCandidates as et,parseModelSpec as tt}from"../model-routes.js";import{payerOfGrant as B}from"../grants/mirror.js";import{isolatedBrokerLauncherAvailable as nt}from"../runtime/host.js";import{resolveRunKind as at}from"../runtime/launch-target.js";import{cycleAwareMessages as st}from"../runtime/session-cycles.js";import{originFor as te}from"../runtime/stamp/protocol.js";import{readOutputRequest as rt,readOutputResult as ne}from"../runtime/structured-output.js";import{admitLegacyStructuredOutput as ae}from"../../daemon/structured-requests/sidecar.js";import{runSchemaRepromptPending as it}from"../runtime/stop-guard.js";import{toRunOutcomeDTO as ot}from"../../daemon/api/map.js";import{openAssistantMessageStartSequence as dt}from"../../daemon/runs/observer.js";import{closeNode as se}from"../runtime/close.js";import{parseScope as ct}from"@north-light/identity";import{appendRunEvent as re,subscribeRunEvents as ut}from"./events.js";import{runActivity as mt}from"./activity.js";import{cancelOpenQuestions as ie,openNoticeIds as lt,openQuestionIds as oe}from"./questions.js";import{appSpace as j}from"../layout.js";import{ensureAppSpace as pt}from"../spaces/space.js";import{assertUploadsUsable as de,resolveStorageUrls as _t}from"../storage/attachments.js";import{storageClient as ft,storageConfig as wt}from"../storage/client.js";import{deleteUploadRow as gt,insertUploadUses as ce,releaseRunUploads as Et}from"../storage/tables.js";import{abortProviderCalls as ue}from"../providers/inflight.js";import{filterAsync as me,mapAsync as T}from"../async-array.js";const le=c((e,t,s)=>_t(t,e,s),"defaultResolver"),yt=3e3;async function vn(e){return Number((await e.prepare("UPDATE idempotency_keys SET grantee = 'app:terminal' WHERE grantee = 'user:local'").run()).changes)}c(vn,"rewriteLocalIdempotencyGrantee");class S extends Error{static{c(this,"RunError")}status;code;param;details;scope;retryable;constructor(t,s,a,o,m,i,r=t===503){super(a),this.status=t,this.code=s,this.param=o,this.details=m,this.scope=i,this.retryable=r}}const R=c((e,t)=>new S(400,"invalid_request",e,t),"invalid"),J=c(()=>new S(404,"not_found","run not found"),"missing"),Y=c(()=>({input_tokens:0,output_tokens:0,cache_read_tokens:0,cache_write_tokens:0,cost_usd:0}),"usage"),D=c(async()=>await P(),"db");async function F(e,t,s=!1){const a=await N(e);if(!a||a.parent!==null||a.run_id!==e||a.grantee!==t||!s&&a.deleting_at)throw J();return a}c(F,"ownedRun");const pe=["waiting_on_user","idle","settled"];async function A(e){if(e.status==="canceled"||e.status==="dead"||e.status==="done"&&e.intent!=="parked")return"settled";const t=await(await D()).prepare(`SELECT 1 FROM node_rows n WHERE n.run_id = ? AND n.status = 'active' AND
|
|
2
2
|
(n.last_settled_at IS NULL OR EXISTS (
|
|
3
3
|
SELECT 1 FROM run_events e WHERE e.run_id = ? AND e.node_id = n.node_id AND e.type = 'node.turn.started'
|
|
4
4
|
AND e.sequence_number > COALESCE((SELECT MAX(c.sequence_number) FROM run_events c
|
|
5
5
|
WHERE c.run_id = e.run_id AND c.node_id = e.node_id AND c.type = 'node.turn.completed'), 0)
|
|
6
|
-
)) LIMIT 1`).get(e.node_id,e.node_id),s
|
|
6
|
+
)) LIMIT 1`).get(e.node_id,e.node_id),s=!e.last_settled_at&&e.status!=="done";return t||s||await it(e)?"running":(await oe(e.node_id)).length?"waiting_on_user":await(await D()).prepare(`SELECT 1 FROM deliveries d JOIN nodes n ON n.node_id = d.destination_id
|
|
7
|
+
WHERE n.run_id = ? AND ${Be("d","'armed', 'pending'")}
|
|
8
|
+
AND (n.status IN ('active', 'idle') OR ${$e("n")}) LIMIT 1`).get(e.node_id)?"running":"idle"}c(A,"runStatus");async function On(e){const t=await N(e);return t!==null&&await A(t)==="running"}c(On,"runIsRunning");async function L(e){await Q(e.node_id),e=await N(e.node_id)??e;const t=await A(e),s=t==="settled"?[]:await oe(e.node_id),a=await Je(e.node_id)||void 0,o=t==="settled"?ot(e):null,m=o?.kind==="result"?ne(e.node_id,e.grantee):void 0;return{run_id:e.node_id,name:e.name,status:t,...o?{outcome:o}:{},...m===void 0?{}:{result:m},...a!==void 0?{last_report:a}:{},pending_question_ids:s,open_notice_ids:t==="settled"?[]:await lt(e.node_id),...e.last_turn_error_json?{last_turn_error:JSON.parse(e.last_turn_error_json)}:{},usage:JSON.parse(e.usage_json??JSON.stringify(Y())),payer:await B(e.grant_id),scopes:e.scopes,metadata:e.metadata_json?JSON.parse(e.metadata_json):{},created_at:e.created,...t==="settled"&&e.outcome_at?{settled_at:e.outcome_at}:{},latest_sequence:(e.event_cursor??1)-1,last_activity_at:e.last_activity_at,activity:await mt(e.node_id,t)}}c(L,"runObject");const G=864e5,_e=255;function bn(e){if(e!==void 0){if(typeof e!="string"||!e.length||e.length>_e)throw R(`Idempotency-Key must be 1-${_e} characters`);return e}}c(bn,"idempotencyKeyOf");async function H(e,t,s,a){a??=await P();const o=await a.prepare("SELECT body_hash, run_id, response_json, created_at FROM idempotency_keys WHERE grantee = ? AND key = ?").get(e,t);if(!(!o||Date.now()-Date.parse(o.created_at)>=G)){if(o.body_hash!==s)throw new S(409,"idempotency_conflict","key used with a different request");return{run_id:o.run_id,response:JSON.parse(o.response_json)}}}c(H,"findIdempotent");async function fe(e,t,s,a,o,m,i){await e.prepare("DELETE FROM idempotency_keys WHERE grantee = ? AND key = ? AND created_at <= ?").run(t,s,new Date(Date.now()-G).toISOString()),await e.prepare("INSERT INTO idempotency_keys (grantee, key, body_hash, run_id, response_json, created_at) VALUES (?, ?, ?, ?, ?, ?)").run(t,s,a,o,JSON.stringify(m),i)}c(fe,"recordIdempotent");async function Dn(e=Date.now()){return Number((await(await P()).prepare("DELETE FROM idempotency_keys WHERE created_at <= ?").run(new Date(e-G).toISOString())).changes)}c(Dn,"pruneExpiredIdempotencyKeys");async function we(e,t,s,a,o){const m=a.text;let i=0;return{messageId:(await je(t,{kind:"message",label:m.slice(0,120),senderNodeId:"human",senderName:s,bodyJson:o?{body:m}:{body:m,start_turn:!1},urgency:o?"normal":"deferred",wake:o?1:0,withinEnqueue:c(async(u,f)=>{a.uses.length&&(await de(s,a.uses,u),await ce(a.uses.map(({upload_id:y,path:g})=>({upload_id:y,path:g,run_id:t})),u)),i=(await re(u,t,t,"node.message.accepted",{message_id:f,start_turn:o})).sequence_number},"withinEnqueue")})).messageId,sequence:i}}c(we,"acceptRunMessage");class ge extends Error{static{c(this,"IdempotentReplay")}winner;constructor(t){super("idempotent replay"),this.winner=t}}const ht=1440*60*1e3;function Ee(e){const t=typeof e=="string"?Ke(e):null;if(t===null||!Number.isSafeInteger(t))throw R(`deadline '${String(e)}' is not a duration; use one or more <int>[smhd] parts such as 10m or 1h30m`,"deadline");if(t<=0)throw R("deadline must be greater than zero","deadline");if(t>ht)throw R("deadline must be at most 24h","deadline");return t}c(Ee,"parseRunDeadlineMs");async function In(e,t,s,a=le){if(t.isolated&&!nt())throw new S(503,"isolated_unavailable","isolated runs require the Linux root launcher","isolated");t.deadline!==void 0&&Ee(t.deadline);const o=X("sha256").update(JSON.stringify(t)).digest("hex");if(s){const n=await H(e.grantee,s,o);if(n){const l=await F(n.run_id,e.grantee);return!l.pi_pid&&await A(l)==="running"&&(t.output_schema!==void 0&&!l.outcome_at&&rt(l.node_id).state==="absent"&&ne(l.node_id,l.grantee)===void 0&&await ae(l.node_id,"terminal",t.output_schema),await $(l.node_id,{resume:!0,capacity:"freeze"})),n.response}}await pt(e.grantee);const m=t.profile===void 0?Ye(e.grantee):Ge(t.profile),i=m.manifest.grantee??"app:terminal";if(i!==e.grantee){const n=`crtr:memory:rw:${i}:profile:${m.profileId}`;if(!e.resolved.some(l=>U(l,n))||t.scopes!==null&&!t.scopes.some(l=>U(l,n)))throw new S(403,"scope_missing",`missing scope ${n}`,"profile",void 0,n)}if(t.model!==void 0){const n=t.model;if(Ze(n)){if(n.includes("/")&&await B(e.grant)!=="app"){const l=n.lastIndexOf("/"),E=n.slice(0,l),h=n.slice(l+1);if(["ultra","strong","medium","light"].includes(h)&&et({kind:"logical",family:E,strength:h,spec:n},j(e.grantee).files,m.profileId).every(b=>b.family!==E))throw R(`model '${n}' names a model family that is not configured in this daemon`,"model")}}else if(tt(n)===void 0)throw R(`model '${n}' is not a strength (ultra, strong, medium, light), a family/strength, or a provider/model id`,"model")}const r=await Qe(),u=Le(j(e.grantee).nodes,r);if(t.isolated&&t.cwd!==void 0){const n=Me(u,Ae(t.cwd));if(!z(t.cwd)||n===".."||n.startsWith(`..${Te}`)||z(n))throw R("cwd must be inside the isolated root node folder","cwd")}const f=await a(r,e.grantee,t.prompt),y=f.text;let g;try{g=t.message===void 0?void 0:await a(r,e.grantee,t.message)}catch(n){throw f.cleanup(),n}const w=await B(e.grant);let d;try{await Ve({kind:at(m),mode:"base",root:!0,rootLifecycle:"resident",readiness:"launch",cwd:t.isolated?t.cwd??u:j(e.grantee).files,profile:m.profileId,prompt:y,nodeId:r,isolated:t.isolated??!1,...t.model===void 0?{}:{model:t.model},...t.deadline===void 0?{}:{deadlineAt:new Date(Date.now()+Ee(t.deadline)).toISOString()},...t.scopes===null?{}:{scopes:t.scopes},run:{grantee:e.grantee,sub:e.sub,grant_id:e.grant,client_id:e.client_id,metadata_json:JSON.stringify(t.metadata),run_id:r,event_cursor:1,usage_json:JSON.stringify(Y())},withinCreate:c(async(n,l)=>{if(s){const h=await H(e.grantee,s,o,n);if(h)throw new ge(h)}const E=f.uses;if(E.length&&(await de(e.grantee,E,n),await ce(E.map(({upload_id:h,path:b})=>({upload_id:h,path:b,run_id:r})),n)),d={run_id:r,node_id:r,grantee:e.grantee,grant:e.grant,rev:e.rev,scopes:t.scopes,payer:w,status:"running",created_at:l.created,metadata:t.metadata,sequence_number:0},await re(n,r,r,"run.started",{scopes:t.scopes,payer:w,usage:Y()}),g){const h=await we(n,r,e.grantee,g,!1);d.message={run_id:r,message_id:h.messageId,sequence_number:h.sequence}}s&&await fe(n,e.grantee,s,o,r,d,l.created)},"withinCreate")},t.output_schema===void 0?void 0:async n=>{await ae(n,"terminal",t.output_schema)})}catch(n){if(await N(r)||(f.cleanup(),g?.cleanup()),n instanceof ge)return n.winner.response;if(t.model!==void 0&&n instanceof Ie&&n.code==="usage")throw R(n.message,"model");if(n instanceof De&&(n.code==="isolated_run"||n.code==="invalid_request")){const l=n.details&&typeof n.details=="object"&&"param"in n.details&&typeof n.details.param=="string"?n.details.param:void 0;throw new S(n.status,n.code,n.message,l)}throw n}if(!d)throw new Error("run creation did not commit");return d}c(In,"startRun");async function Mn(e,t){let s;if(t.after)try{const r=JSON.parse(Buffer.from(t.after,"base64url").toString());if(!r||typeof r!="object"||!("activity"in r)||typeof r.activity!="string"||!("id"in r)||typeof r.id!="string")throw new Error("invalid cursor");s={activity:r.activity,id:r.id}}catch{throw R("invalid list cursor","after")}const a=await(await D()).prepareUncached(`SELECT node_id, COALESCE(last_activity_at, created) AS activity FROM node_rows
|
|
7
9
|
WHERE run_id = node_id AND deleting_at IS NULL ${e===null?"":"AND grantee = ?"}
|
|
8
|
-
ORDER BY activity DESC, node_id DESC`).all(...e===null?[]:[e]),o=await me(await
|
|
10
|
+
ORDER BY activity DESC, node_id DESC`).all(...e===null?[]:[e]),o=await me(await T((await me(a,async({node_id:r})=>!t.visible||await t.visible(r))).filter(({activity:r,node_id:u})=>!s||r<s.activity||r===s.activity&&u<s.id),async r=>({root:await N(r.node_id),activity:r.activity})),async({root:r})=>!t.status||await A(r)===t.status),m=o.slice(0,t.limit),i=m.at(-1);return{runs:await T(m,async({root:r})=>await L(r)),next:o.length>t.limit&&i?Buffer.from(JSON.stringify({activity:i.activity,id:i.root.node_id})).toString("base64url"):null}}c(Mn,"listRuns");async function An(e,t,s){const a=await F(e,t),o=c(async()=>await L(await F(e,t)),"read");return!s||pe.includes(await A(a))?await o():new Promise((m,i)=>{let r=c(()=>{},"unsubscribe");const u=c(()=>{clearTimeout(d),clearInterval(w),r()},"settle"),f=c(async()=>{u();try{m(await o())}catch(n){i(n)}},"finish"),y=c(async()=>{pe.includes(String((await o()).status))&&await f()},"check"),g=c(()=>{y().catch(n=>{u(),i(n)})},"run"),w=setInterval(g,250),d=setTimeout(()=>{f()},s*1e3);ut(e,g).then(n=>{r=n},n=>{u(),i(n)})})}c(An,"waitRun");async function Tn(e,t,s=le,a=!0,o){const m=e.status==="canceled"||e.outcome_reason==="closed",i=e.grantee??"app:terminal",r=X("sha256").update(JSON.stringify(["run.message",e.node_id,t,a])).digest("hex"),u=c(async w=>{const d=await N(e.node_id),n=await(await D()).prepare("SELECT 1 FROM deliveries WHERE message_id = ? AND state = 'pending' AND canceled_at IS NULL").get(String(w.message_id));return d&&!m&&a&&!d.pi_pid&&n&&await $(e.node_id,{resume:!0,capacity:"freeze"}),w},"replay");if(o){const w=await H(i,o,r);if(w)return u(w.response)}if(m)throw new S(409,"run_settled","canceled run cannot receive a message");const f=await s(e.node_id,i,t),y=a&&e.final_report&&!e.pi_pid?(await import("../runtime/reopen.js")).commitReopenResident:void 0;let g;try{g=await W(async w=>{if(o){const l=await H(i,o,r,w);if(l)return{replayed:l.response}}await y?.(e.node_id);const d=await we(w,e.node_id,i,f,a),n={run_id:e.node_id,message_id:d.messageId,sequence_number:d.sequence};return o&&await fe(w,i,o,r,e.node_id,n,new Date().toISOString()),{result:n}})}catch(w){throw f.cleanup(),w}return"replayed"in g?(f.cleanup(),u(g.replayed)):(a&&!e.pi_pid&&await $(e.node_id,{resume:!0,capacity:"freeze"}),g.result)}c(Tn,"messageRun");async function Rt(e){const t=c(()=>new S(503,"service_unavailable",`node ${e} broker was unavailable before the interrupt reached it`),"unavailable");for(let s=0;s<2;s++){const a=await N(e);if(!a)throw J();if(!ee(a)){if(a.streaming)throw t();return}const o=(await V(e))?.executionId;try{await ze(e)==="turn"&&ue({nodes:[e]});return}catch(m){if(!(m instanceof Xe))throw m;const i=await N(e);if(!i)throw J();if(!i.streaming)return;if(s===0&&ee(i)&&(await V(e))?.executionId!==o)continue;throw t()}}throw t()}c(Rt,"interruptNode");async function Ln(e,t="stop"){const s=t==="stop"?(await(await D()).prepare("SELECT node_id FROM nodes WHERE run_id = ?").all(e.node_id)).map(({node_id:a})=>a):[e.node_id];return await Promise.all(s.map(a=>Rt(a))),await L(await N(e.node_id)??e)}c(Ln,"interruptRun");async function Cn(e,t={}){const s=(await(await D()).prepare("SELECT node_id FROM nodes WHERE run_id = ? ORDER BY created DESC").all(e.node_id)).map(i=>i.node_id);ue({run:e.node_id});const a=[];if(await A(e)!=="settled")a.push(...(await se(e.node_id,{preserveEmpty:!0,stopReason:"run_canceled"})).closed);else for(const i of s){if(i===e.node_id)continue;const r=await N(i);r&&r.status!=="done"&&r.status!=="canceled"&&r.status!=="dead"&&a.push(...(await se(i,{preserveEmpty:!0,stopReason:"run_canceled"})).closed)}if(await ie({run_id:e.node_id},"the run was canceled"),(await Promise.all([...new Set([e.node_id,...a])].map(i=>K(i,"run_canceled")))).some(i=>!i.confirmed))throw new S(500,"server_error","run process teardown could not be confirmed",void 0,void 0,void 0,!0);const m=await N(e.node_id);return await L(m??e)}c(Cn,"cancelRun");const ye=200;async function kn(e,t){if(typeof t!="string"||!t.trim())throw R("name is required","name");const s=t.trim();if(s.length>ye)throw R(`name exceeds ${ye} characters`,"name");const a=await He(e.node_id,{name:s});return a.window&&Ue(a.window,qe(a)),await L(a)}c(kn,"renameRun");async function xn(e,t={config:wt,client:ft}){await ie({run_id:e.node_id},"the run was deleted");const s=await W(async u=>(await u.prepare("UPDATE nodes SET deleting_at = COALESCE(deleting_at, ?) WHERE node_id = ?").run(new Date().toISOString(),e.node_id),(await u.prepare("SELECT node_id FROM nodes WHERE run_id = ? ORDER BY created DESC").all(e.node_id)).map(f=>f.node_id)));if((await Promise.all(s.map(u=>K(u,"run_deleted",{deleting:!0})))).some(u=>!u.confirmed))throw new S(500,"server_error","run process teardown could not be confirmed",void 0,void 0,void 0,!0);const o=await T(s,async u=>{const f=await We(u);if(f.app===null)throw new Error(`run node missing during deletion: ${u}`);return f}),m=await(await D()).prepare("SELECT DISTINCT session_id FROM sessions WHERE session_id IS NOT NULL AND node_id IN (SELECT node_id FROM nodes WHERE run_id = ?)").all(e.node_id);for(const{session_id:u}of m)try{await Z().delete(u)}catch(f){if(!Pe(f))throw f}const i=await W(async u=>{for(const w of s){const d=await xe(u,w);d!==null&&d.deleted_at===null&&await ke(u,d)}const f=await Et([e.node_id],u);await u.prepare("DELETE FROM run_events WHERE run_id = ?").run(e.node_id),await u.prepare("DELETE FROM idempotency_keys WHERE run_id = ?").run(e.node_id);const y=s.map(()=>"?").join(","),g=await u.prepareUncached(`SELECT message_id FROM messages WHERE sender_node_id IN (${y}) UNION SELECT message_id FROM deliveries WHERE destination_id IN (${y})`).all(...s,...s);await u.prepareUncached(`DELETE FROM deliveries WHERE destination_id IN (${y})`).run(...s);for(const{message_id:w}of g)await u.prepare("DELETE FROM messages WHERE message_id = ? AND NOT EXISTS (SELECT 1 FROM deliveries WHERE message_id = ?)").run(w,w);return f});for(const u of o)await Fe(u);const{notifyRunDeleted:r}=await import("./events.js");return r(e.node_id),{uploads_pending:await St(i,t)}}c(xn,"deleteRun");async function St(e,t){if(!e.length||!t.config())return e.length;let s;try{s=t.client()}catch{return e.length}const a=new Set,o=e.map(i=>s.deleteUpload(i).then(async()=>{await gt(i),a.add(i)},()=>{}));let m;return await Promise.race([Promise.all(o),new Promise(i=>{m=setTimeout(i,t.budgetMs??yt),m.unref?.()})]),clearTimeout(m),e.length-a.size}c(St,"deleteReleasedUploads");async function Wn(e,t,s){await F(e,t),await Q(e);const a=await W(async d=>{const n=await d.prepare("SELECT node_id, parent FROM nodes WHERE run_id = ? ORDER BY CASE WHEN node_id = ? THEN 0 ELSE 1 END, created, node_id").all(e,e),l=new Map;for(const k of n)l.set(k.node_id,(await d.prepare("SELECT session_id FROM sessions WHERE node_id = ? GROUP BY session_id ORDER BY min(created_at)").all(k.node_id)).map(x=>x.session_id));const h=(await d.prepare("SELECT event_cursor FROM nodes WHERE node_id = ?").get(e)).event_cursor-1,b=await d.prepare(`SELECT node_id, sequence_number FROM run_events
|
|
9
11
|
WHERE run_id = ? AND sequence_number <= ? AND type IN ('node.thinking.done', 'node.output_text.done', 'usage')
|
|
10
12
|
ORDER BY sequence_number`).all(e,h),C=await d.prepare(`SELECT node_id, sequence_number, type, body_json FROM run_events
|
|
11
13
|
WHERE run_id = ? AND sequence_number <= ? AND type IN ('node.thinking.delta', 'node.output_text.delta')
|
|
12
|
-
ORDER BY sequence_number`).all(e,h);return{nodes:n,sessionIds:l,latestSequence:h,completed:b,deltas:C}}),{nodes:o,sessionIds:m,latestSequence:i,completed:r,deltas:u}=a,f=await
|
|
14
|
+
ORDER BY sequence_number`).all(e,h);return{nodes:n,sessionIds:l,latestSequence:h,completed:b,deltas:C}}),{nodes:o,sessionIds:m,latestSequence:i,completed:r,deltas:u}=a,f=await T(o,async d=>({node_id:d.node_id,parent_node_id:d.parent,conversations:await T(m.get(d.node_id)??[],async n=>{const{header:l,entries:E}=await Z().read(n);if(s==="entries")return{conversation_id:n,header:l,entries:E};const h=Ce.inMemory(l.cwd,void 0,[l,...E]),b=st(h)??[],C=new Map(E.map((_,v)=>[_.id,v])),k=E.filter(_=>_.type==="custom"&&_.customType==="crtr-system-prompt").map(_=>({id:_.id,message:{role:"custom",customType:"crtr-system-prompt",data:"data"in _?_.data:void 0,timestamp:_.timestamp}})),x=E.filter(_=>_.type==="custom_message"&&_.customType==="app_message").map(_=>({id:_.id,message:{role:"custom",customType:"app_message",content:"content"in _?_.content:"",timestamp:_.timestamp}})),he=d.node_id===e?E.find(_=>{if(_.type!=="message"||_.message.role!=="user")return!1;const v=te(E,_.message.timestamp);return v?.type==="runtime"&&v.kind==="kickoff"})?.id:void 0,Re=[...b.filter(({id:_})=>!x.some(v=>v.id===_)),...k,...x].sort((_,v)=>(C.get(_.id)??Number.MAX_SAFE_INTEGER)-(C.get(v.id)??Number.MAX_SAFE_INTEGER)).map(({id:_,message:v})=>{const p=v,I=p.usage,q=p.role==="user"?te(E,Number(p.timestamp)):null,Se=q?.type==="human"||_===he,M=p.role==="toolResult"?"tool_result":p.role==="bashExecution"?"bash_execution":p.role==="compactionSummary"?"compaction_summary":p.role==="branchSummary"?"branch_summary":p.role==="custom"&&p.customType==="crtr-system-prompt"?"system":p.role==="user"?Se?"user":"custom":p.role,Ne=M==="custom"?p.role==="custom"?p.customType:q?.type==="runtime"?q.kind:"unknown":void 0,ve=M==="system"&&p.customType==="crtr-system-prompt"?[{type:"text",text:p.data?.text??""}]:typeof p.content=="string"?[{type:"text",text:p.content}]:Array.isArray(p.content)?p.content.map(O=>O.type==="toolCall"?{type:"tool_call",tool_call_id:O.id,name:O.name,arguments:O.arguments}:O.type==="image"?{type:"image",mime_type:O.mimeType}:O.type==="thinking"?{type:"thinking",text:O.thinking}:O):[];return{entry_id:_,role:M,...M==="custom"?{custom_type:Ne}:{},time:typeof p.timestamp=="string"?p.timestamp:new Date(Number(p.timestamp??Date.now())).toISOString(),content:ve,...M==="assistant"?{model:p.model,provider:p.provider,stop_reason:p.stopReason,...p.errorMessage?{error_message:p.errorMessage}:{},...I?{usage:{input_tokens:I.input??0,output_tokens:I.output??0,cache_read_tokens:I.cacheRead??0,cache_write_tokens:I.cacheWrite??0,cost_usd:I.cost?.total??0}}:{}}:{},...M==="tool_result"?{tool_call_id:p.toolCallId,tool_name:p.toolName,is_error:p.isError}:{}}})??[];return{conversation_id:n,messages:Re}})})),y=new Map(f.map(d=>[d.node_id,dt(d.node_id)]));for(const d of r){const n=y.get(d.node_id);n!=null&&d.sequence_number>=n&&y.set(d.node_id,null)}const g=new Map;for(const d of u){const n=y.get(d.node_id);if(n==null||d.sequence_number<n)continue;const l=JSON.parse(d.body_json),E=g.get(d.node_id)??{thinking:"",text:""};d.type==="node.thinking.delta"?E.thinking+=l.delta:E.text+=l.delta,g.set(d.node_id,E)}const w=f.map(d=>({...d,in_progress_message:y.get(d.node_id)==null?null:g.get(d.node_id)??{thinking:"",text:""}}));return{run_id:e,latest_sequence:i,nodes:w}}c(Wn,"traceRun");function Fn(e,t,s){if(t===void 0){if(!e.some(a=>U(a,"crtr:llm")))throw new S(403,"scope_missing","missing scope crtr:llm",void 0,void 0,"crtr:llm");return null}if(!Array.isArray(t)||t.some(a=>typeof a!="string"))throw R("scopes must be a list of scope strings","scopes");for(const a of t){try{ct(a)}catch{throw R(`invalid scope ${a}`,"scopes")}if(/^crtr:files:(?:read|rw):app:/.test(a)&&a.split(":")[4]===s.slice(4))throw R(`own-app files cannot narrow a run: ${a}`,"scopes");if(!(/^crtr:memory:(?:read|rw):app:/.test(a)&&a.split(":")[4]===s.slice(4))&&!be(e,a))throw new S(403,"scope_missing",`missing scope ${a}`,void 0,void 0,a)}if(!t.includes("crtr:llm"))throw new S(403,"scope_missing","missing scope crtr:llm",void 0,void 0,"crtr:llm");return t}c(Fn,"requestedScopes");export{G as IDEMPOTENCY_WINDOW_MS,ht as RUN_DEADLINE_MAX_MS,yt as RUN_DELETE_STORAGE_BUDGET_MS,ye as RUN_NAME_MAX,S as RunError,Cn as cancelRun,xn as deleteRun,bn as idempotencyKeyOf,Ln as interruptRun,Mn as listRuns,Tn as messageRun,F as ownedRun,Ee as parseRunDeadlineMs,Dn as pruneExpiredIdempotencyKeys,kn as renameRun,Fn as requestedScopes,vn as rewriteLocalIdempotencyGrantee,On as runIsRunning,L as runObject,In as startRun,Wn as traceRun,An as waitRun};
|
|
@@ -37,6 +37,9 @@ export declare function closeNode(rootId: string, opts?: {
|
|
|
37
37
|
callerPid?: number;
|
|
38
38
|
/** App runs retain their root and child rows even when no assistant output exists. */
|
|
39
39
|
preserveEmpty?: boolean;
|
|
40
|
+
/** Broker teardowns wait for this to settle: the close handler's response, so
|
|
41
|
+
* a close run from the node's own shell gets its answer before its relay dies. */
|
|
42
|
+
teardownAfter?: Promise<unknown>;
|
|
40
43
|
/** Daemon-owned close work that must drain before this daemon exits. */
|
|
41
44
|
registerDetached?: (work: Promise<void>) => void;
|
|
42
45
|
/** Reason recorded when an active turn or background job is stopped. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var k=Object.defineProperty;var d=(
|
|
1
|
+
var k=Object.defineProperty;var d=(t,o)=>k(t,"name",{value:o,configurable:!0});import{getNode as w,subscriptionsOf as u,subscribersOf as E}from"../canvas/index.js";import{transition as _}from"./lifecycle.js";import{stopNodeSandboxes as $}from"../spaces/stop.js";import{tearDownNode as D,reapIfEmpty as N}from"./placement.js";import{crtrHome as L,jobDir as O}from"../canvas/paths.js";import{contextDir as x,nodeAgentDir as A}from"../canvas/node-agent-paths.js";import{readLiveSession as S}from"../canvas/sessions.js";import{discoverLifecycleHookRegistry as j}from"../command-hooks/discovery.js";import{invokeLifecycleHooks as H}from"../command-hooks/transport/exec-lifecycle.js";import{emitEvent as h}from"../events/emit.js";import{enqueueNodeMail as B}from"../feed/messages.js";import{withCanvasWrite as g}from"../canvas/db.js";import{recordActedOn as C}from"../graph/edges.js";import{publish as R}from"../graph/events.js";import{getById as v,nodeObject as T,ownerForGrantee as Y}from"../graph/objects.js";import{mapAsync as q}from"../async-array.js";const P={deferred:3,normal:5,urgent:7,critical:7};async function z(t,o,c,a,l="normal",r=null,s){await g(async e=>{const n=await v(e,t);n===null||n.type!=="node"||await R(e,{event:o,object:n,actor:r,level:P[l],attrs:{},messageBody:{...a,body:c},...s===void 0?{}:{onlyWatchers:s}})})}d(z,"publishNotice");async function F(t){const o=new Set([t]);let c=!0;for(;c;){c=!1;for(const a of[...o])for(const l of await u(a)){const r=l.node_id;o.has(r)||(await E(r)).every(s=>o.has(s.node_id))&&(o.add(r),c=!0)}}return o}d(F,"closingSet");async function G(t,o){const c=[],a=new Set([t]),l=[t];for(;l.length>0;){const r=l.shift();c.push(r);for(const s of await u(r))o.has(s.node_id)&&!a.has(s.node_id)&&(a.add(s.node_id),l.push(s.node_id))}for(const r of o)a.has(r)||c.push(r);return c.reverse()}d(G,"killOrder");async function J(t,o){const c=t?"You were CLOSED by the user from the canvas":"You were CANCELED \u2014 an ancestor of yours was closed from the canvas";if(o.length===0)return`${c}. Your pi session is preserved; this resume reopened it.`;const a=await q(o.slice(0,4),async r=>{const s=await w(r);return s!==null?`${s.name} (${r})`:r}),l=o.length>a.length?` +${o.length-a.length} more`:"";return`${c}. ${o.length} child node(s) you subscribe to were canceled with you and are no longer running: ${a.join(", ")}${l}. Resuming will NOT restore them \u2014 re-spawn if you still need that work.`}d(J,"cancellationLabel");async function ce(t,o={}){if(await w(t)===null)throw new Error(`closeNode: unknown node ${t}`);const c=o.rootEvent??"cancel",a=await F(t),l=await G(t,a),r=[];for(const e of a)for(const n of await u(e))!a.has(n.node_id)&&!r.includes(n.node_id)&&r.push(n.node_id);const s=[];for(const e of l)try{const n=await w(e);if(n===null)continue;const p=(await u(e)).map(i=>i.node_id).filter(i=>a.has(i));let m;try{const i=j(n.cwd,n.profile_id).plans.get("node:close")??[];if(i.length>0){const f={node:{id:e,name:n.name,kind:n.kind,mode:n.mode,lifecycle:n.lifecycle,cwd:n.cwd,nodeDir:await A(e),contextDir:await x(e),jobDir:O(e)},runtime:{isBirth:!1,canvasHome:L(),profile:n.profile_id??null}};m=d(()=>H(i,f),"afterTeardown")}}catch(i){h({level:"error",event:"node.close_hook.discovery_failed",node_id:e,error:i})}const b=$(e,o.stopReason??"node_closed",{...e===t?{excludePid:o.callerPid}:{},...o.teardownAfter?{startAfter:o.teardownAfter}:{},...m?{after:m}:{}});try{o.registerDetached?.(b.then(()=>{}))}catch(i){h({level:"error",event:"node.close_hook.detached_registration_failed",node_id:e,error:i})}if(await g(async i=>{const f=await v(i,e);if(f===null||f.type!=="node")return;const y=o.closer!==void 0?await T(i,o.closer):await Y(i,"user:local");await C(i,y,f),await z(e,"notice.close",`Child closed \u2014 ${n.name} (${e}) was closed from the canvas and is no longer running.`,{reason:"child-closed",child:e},"normal",y)}),o.preserveEmpty||n.run_id!==null&&n.pi_pid!==null&&(await S(e))?.sessionId!=null||!await N(e,void 0,!1)){const i=n.final_report!==null&&n.final_report!==void 0;e===t&&c==="finish"||i?(n.status==="active"||n.status==="idle")&&await _(e,"finish"):await _(e,"cancel",{reason:"closed"}),await D(e),await B(e,{kind:"message",label:await J(e===t,p),bodyJson:{reason:"user-close",cascade_root:t,canceled_children:p},urgency:"normal",wake:1})}s.push(e)}catch(n){h({level:"error",event:"node.close.failed",node_id:e,error:n})}return{root:t,closed:s,spared:r}}d(ce,"closeNode");export{ce as closeNode,F as closingSet,z as publishNotice};
|
|
@@ -24,6 +24,10 @@ export interface HostHandle {
|
|
|
24
24
|
}
|
|
25
25
|
export interface TeardownOptions {
|
|
26
26
|
excludePid?: number;
|
|
27
|
+
/** Requested teardowns start when this settles instead of on the next turn. A
|
|
28
|
+
* close handler passes its response's `close` so the caller's own broker relay
|
|
29
|
+
* outlives the response even when the handler awaits I/O after queuing. */
|
|
30
|
+
startAfter?: Promise<unknown>;
|
|
27
31
|
}
|
|
28
32
|
/** The only completion signal a caller may use for post-teardown work. A false
|
|
29
33
|
* result means the original engine tree could not be confirmed dead, so no
|
|
@@ -51,7 +55,7 @@ export interface Host {
|
|
|
51
55
|
* the fast-fail seam for known module/path errors: a bad engine resolve or a
|
|
52
56
|
* missing plain session path throws here, before spawn(). */
|
|
53
57
|
export declare function preflightBrokerLaunch(nodeId: string, inv: PiInvocation, cwd: string): Promise<void>;
|
|
54
|
-
/** Queue broker teardown
|
|
58
|
+
/** Queue broker teardown for the next turn, or until `opts.startAfter` settles. Completion includes
|
|
55
59
|
* any post-teardown work, which lets the daemon drain it during shutdown. */
|
|
56
60
|
export declare function requestBrokerTeardown(nodeId: string, opts?: TeardownOptions, after?: () => Promise<void>): Promise<TeardownResult>;
|
|
57
61
|
/** Isolated brokers require the Linux launcher; direct host spawn cannot enforce their filesystem or network policy. */
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var be=Object.defineProperty;var
|
|
2
|
-
`;if(n===r&&o!==
|
|
3
|
-
`,{atomic:!0,mode:432}),P(b,oe,432);const ie=
|
|
1
|
+
var be=Object.defineProperty;var l=(e,t)=>be(e,"name",{value:t,configurable:!0});import{assertGranteeRunsHere as Pe}from"./unsandboxed.js";import{spawn as Re}from"node:child_process";import{mkdirSync as ue,existsSync as j,unlinkSync as fe,openSync as F,closeSync as N,writeSync as xe,chmodSync as Oe,lstatSync as Te}from"node:fs";import{ensureAppSpace as De}from"../spaces/space.js";import{sandboxCacheEnv as Ne}from"../spaces/cache-env.js";import{compileLaunch as Ae,launchStillGranted as Ce}from"../spaces/mounts.js";import{grantsGeneration as de}from"../grants/mirror.js";import{LAUNCHER_SOCKET as z}from"../../launcher/spec.js";import{launcherRequest as M}from"../../launcher/client.js";import{piAgentDir as Le}from"./package-health.js";import{existsBeneath as V,readFileBeneath as Be,readTextBeneathIfExists as $e,setModeBeneath as P,withDirBeneath as X,writeFileBeneath as G}from"../spaces/open-beneath.js";import{dirname as Q,join as w,resolve as je,isAbsolute as Fe}from"node:path";import{fileURLToPath as me}from"node:url";import{connectViewSocket as Me}from"./view-socket.js";import{appSpace as K}from"../layout.js";import{readConfig as Ge,readMergedLaunchConfig as Ke}from"../config.js";import{readRotationConfig as He}from"../subscription-state.js";import{getNode as _}from"../canvas/index.js";import{scopesFilePath as Y,crtrHome as pe,nodeRunDir as Z,nodeRunJobDir as Je,jobDir as qe,viewSocketPath as Ue,nodeAgentDir as We,contextDir as ze,nodeHome as Ve}from"../canvas/paths.js";import{encodeFrame as Xe}from"./broker-protocol.js";import{buildBrokerEnv as Qe}from"./spawn-env.js";import{hostExecPathFresh as Ye}from"./branded-host.js";import{isPidAlive as I,killProcessTreePids as he,isAnyPidAlive as Ze,captureTeardownSnapshot as Ie}from"../canvas/pid.js";import{assertMandatoryCanvasExtensions as er}from"./canvas-extensions.js";import{appMemoryFull as rr,appMemoryTooSmall as tr,boundFleet as nr,brokerCapReached as or,brokerThresholdsForDaemon as ir}from"./fleet.js";import{admitBrokerMemory as sr}from"./memory-admission.js";import{emitEvent as E}from"../events/emit.js";import{bindBrokerEventSource as ar,eventSource as cr}from"../events/source.js";import{envBrokerEngine as lr}from"../../shared/env.js";import{conversationIdFromPath as ur,conversationStore as fr,ConversationNotFoundError as we,storeAddress as dr}from"../conversation-store/index.js";import{takeNodeToken as mr}from"../canvas/node-tokens.js";function H(){const e=Q(me(import.meta.url));return w(e,"broker-cli.js")}l(H,"resolveBrokerEntry");const pr="@earendil-works/pi-coding-agent";function hr(e,t){const n=w(Le(),"models.json"),r=w(t,"models.json"),o=$e(Q(n),n);if(o===null)return;const d=JSON.parse(o),s=l(f=>Array.isArray(f)?f.map(s):f===null||typeof f!="object"?f:Object.fromEntries(Object.entries(f).filter(([i])=>!/^(apiKey|authorization|headers|token|secret)$/i.test(i)).map(([i,m])=>[i,s(m)])),"scrub"),u=`${JSON.stringify(s(d),null,2)}
|
|
2
|
+
`;if(n===r&&o!==u){if(JSON.stringify(d)!==JSON.stringify(s(d)))throw new Error("terminal models.json contains credentials; move them into daemon secrets");P(e,r,432);return}G(e,r,u,{atomic:!0,mode:432}),P(e,r,432)}l(hr,"writeBrokerModels");function ge(e){return e.env.CRTR_BROKER_ENGINE??lr()}l(ge,"resolveEngineSpec");function Ee(e){return e.includes("/")||e.endsWith(".jsonl")}l(Ee,"isPlainLaunchSessionPath");function wr(e,t){return Fe(e)?e:je(t,e)}l(wr,"resolvePlainLaunchPath");async function gr(e,t,n,r){if(n==="--session"&&!Ee(r))throw new Error(`[broker] refusing to launch ${e}: launch recipe passes bare --session id '${r}' \u2014 the broker fatally rejects bare ids; pass the .jsonl path instead.`);if(!Ee(r))return;const o=wr(r,t),d=ur(o);try{if(d===null)throw new we(o);await fr().header(d)}catch(s){if(!(s instanceof we))throw s;const u=n==="--session"?"session file":"fork source";throw new Error(`[broker] refusing to launch ${e}: launch recipe references missing ${u} '${r}' (${o})`)}}l(gr,"preflightLaunchSessionArg");async function Er(e,t,n){const r=Z(e);ue(r,{recursive:!0}),process.platform==="linux"&&j(z)&&Te(r).uid===process.getuid()&&Oe(r,504);const o=w(r,"broker-launch.json"),d={user:Ge("user"),launch:Ke(n,t.env.CRTR_PROFILE_ID||null),rotation:He()};G(r,o,JSON.stringify({...t,configSnapshot:d}),{atomic:!0}),t.env.CRTR_SCOPES_FILE!==void 0&&G(r,Y(e),JSON.stringify((await _(e))?.scopes??[]),{atomic:!0});const s=Be(r,o).toString("utf8"),u=JSON.parse(s);if(!Array.isArray(u.argv))throw new Error(`[broker] refusing to launch ${e}: broker-launch.json is missing the argv array`);const f=ge(t);try{const c=import.meta.resolve(f);if(c.startsWith("file:")&&!j(me(c)))throw new Error(`resolved to missing file ${c}`)}catch(c){throw new Error(`[broker] refusing to launch ${e}: cannot resolve broker engine '${f}' from ${H()} \u2014 ${c.message}`)}const i=u.argv,m=[];for(let c=0;c<i.length;c++){const R=i[c];if(R==="-e"){const A=i[++c];A!==void 0&&m.push(A);continue}if(R!=="--session"&&R!=="--fork")continue;const O=i[++c];O!==void 0&&await gr(e,n,R,O)}try{er(m)}catch(c){throw new Error(`[broker] refusing to launch ${e}: ${c.message}`)}}l(Er,"preflightBrokerLaunch");const kr=2e3,vr=2e3,_r=150;async function J(e,t){const n=Date.now()+t;for(;Ze(e);){const r=n-Date.now();if(r<=0)return!1;await new Promise(o=>setTimeout(o,Math.min(_r,r)))}return!0}l(J,"waitForTreeExit");async function yr(e,t,n){return e.length===0?{confirmed:!0}:n&&await J(e,kr)?{confirmed:!0}:(he(e,"SIGTERM",t),await J(e,vr)?{confirmed:!0}:(he(e,"SIGKILL",t),await J(e,5e3)?{confirmed:!0}:{confirmed:!1,error:new Error(`broker process tree for ${e.join(", ")} remained alive after SIGKILL`)}))}l(yr,"terminateBrokerTree");async function ke(e,t){const n=await _(e),r=n?.pi_pid,o=r!=null?Ie(r,n?.pi_pid_identity??null,t.excludePid):null;return o?.reused===!0&&E({level:"warn",event:"broker.teardown.pid_reuse_refused",node_id:e,fields:{recorded_pid:r,expected_identity:n?.pi_pid_identity??null}}),{tree:o?.tree??[],identities:o?.identities??null,nodeId:e,launcherPid:j(z)&&o?.tree.includes(r)?r:null}}l(ke,"prepareBrokerTeardown");async function ve(e){if(e.launcherPid!==null){try{await M({operation:"stop",pid:e.launcherPid})}catch(t){return I(e.launcherPid)?{confirmed:!1,error:t instanceof Error?t:new Error(String(t))}:{confirmed:!0}}return await J([e.launcherPid],5e3)?{confirmed:!0}:{confirmed:!1,error:new Error(`launcher pid ${e.launcherPid} remained alive`)}}return new Promise(t=>{let n=!1,r=!1;const o=l(f=>{r||(r=!0,t(f))},"settle"),d=l(()=>{try{fe(Ue(e.nodeId))}catch{}},"cleanupSocket"),s=l(f=>{yr(e.tree,e.identities,f).then(o,i=>o({confirmed:!1,error:i instanceof Error?i:new Error(String(i))}))},"finish"),u=Me(e.nodeId);u.once("error",()=>{n||(d(),s(!1))}),u.once("connect",()=>{n=!0;try{u.write(Xe({type:"shutdown"}))}catch{}u.end(),d(),s(!0)})})}l(ve,"runPreparedBrokerTeardown");const q=new Map;async function rt(e,t={},n){const r=q.get(e);if(r!==void 0)return n!==void 0&&r.after.push(n),r.completion;let o;const d=new Promise(i=>{o=i}),s={completion:d,resolve:o,after:n===void 0?[]:[n]};q.set(e,s);let u;try{u=await ke(e,t)}catch(i){const m={confirmed:!1,error:i instanceof Error?i:new Error(String(i))};return q.delete(e),E({level:"error",event:"broker.teardown.unconfirmed",node_id:e,error:m.error}),s.resolve(m),d}const f=l(()=>{q.delete(e),ve(u).then(async i=>{if(i.confirmed)for(const m of s.after)try{await m()}catch(c){E({level:"error",event:"broker.teardown.after_failed",node_id:e,error:c})}else E({level:"error",event:"broker.teardown.unconfirmed",node_id:e,error:i.error});s.resolve(i)},i=>{const m={confirmed:!1,error:i instanceof Error?i:new Error(String(i))};E({level:"error",event:"broker.teardown.unconfirmed",node_id:e,error:m.error}),s.resolve(m)})},"run");return t.startAfter===void 0?setImmediate(f):t.startAfter.then(f,f),d}l(rt,"requestBrokerTeardown");function _e(){return process.platform==="linux"&&j(z)}l(_e,"isolatedBrokerLauncherAvailable");const tt={async launch(e,t,n){if(Pe((await _(e))?.grantee),(await _(e))?.isolated===!0&&!_e())throw new Error("isolated broker requires the Linux root launcher");await Er(e,t,n.cwd);const r=nr();if(!r.reserveSlot(e))throw or(ir().automaticReviveCap,r.size());let o=null,d,s=!1;try{const u=qe(e);ue(u,{recursive:!0}),o=F(w(u,"broker.log"),"a");const f=ge(t),i={...Qe(t),CRTR_BROKER_ENGINE:f,CRTR_STORE_ADDRESS:dr()};if(f!==pr){const a=t.env.NODE_OPTIONS??process.env.NODE_OPTIONS;a!==void 0&&(i.NODE_OPTIONS=a)}cr()===void 0&&ar(e);const m=(await _(e))?.run_id;if(m){const a=await _(m);if(!a||a.deleting_at)throw new Error("run is deleting")}const c=t.env.CRTR_EXECUTION_ID;if(!c)throw new Error("broker launch has no execution id");const R=mr(c),O=_e();if((await _(e))?.isolated===!0&&!O)throw new Error("isolated broker requires the Linux root launcher");if(process.platform==="linux"&&process.env.CRTR_LAUNCHER_SOCKET&&!O)throw new Error("root launcher socket is unavailable; refusing an unsandboxed broker");if(O){const a=await _(e);if(!a)throw new Error(`missing node ${e}`);const h=a.grantee??"app:terminal",x=await sr(e,{useMemo:!1});if(x.verdict==="denied")throw rr(x);if(x.verdict==="too_small")throw tr(x);const y=await De(h);Object.assign(i,Ne(h));const S={uid:process.getuid(),gid:y.gid},g=Z(e);for(const[p,k]of[[K(h).nodes,We(e,h)],[K(h).nodes,ze(e,h)],[g,Je(e)]])X(p,k,()=>{},!0),P(p,k,1528,S);P(g,w(g,"broker-launch.json"),416,S),V(g,Y(e))&&P(g,Y(e),416,S);const te=w(g,"system-prompt.md");V(g,te)&&P(g,te,432,S);for(const p of["output-schema.json","situational-context.md"]){const k=w(g,p);V(g,k)&&P(g,k,432,S)}const ne=a.isolated===!0,b=Ve(e,h,ne);ne&&(X(K(h).nodes,b,()=>{},!0),P(K(h).nodes,b,1528,S),i.HOME=b,i.PI_CODING_AGENT_DIR=w(b,".pi","agent"));const W=w(b,".pi","agent");X(b,W,()=>{},!0),hr(b,W);const oe=w(W,"settings.json"),ye=w(Q(H()),"../../builtin-pi-packages/pi-crtr-extensions");G(b,oe,`${JSON.stringify({packages:[ye]})}
|
|
3
|
+
`,{atomic:!0,mode:432}),P(b,oe,432);const ie=w(Z(e),`token-${c}`),L=F(ie,"wx+",384);fe(ie),xe(L,R);const se=[F(`/proc/self/fd/${L}`,"r"),F(`/proc/self/fd/${L}`,"r")];N(L);const ae={nodeId:e,app:h,sub:a.sub??"user:local",grantId:a.grant_id??null,scopes:a.scopes??null,isolated:a.isolated===!0,...a.isolated===!0?{cwd:a.cwd}:{},command:[process.execPath,H(),"--canvas-home",pe(),"--epoch",r.epoch(),e],env:Object.fromEntries(Object.entries({...i,...a.isolated===!0?{PWD:a.cwd}:{}}).filter(p=>p[1]!==void 0)),auditMissing:l(p=>E({level:"warn",event:"broker.mount.missing",node_id:e,fields:{source:p}}),"auditMissing")};try{let p;for(const D of se){const B=await de(),v=await Ae(ae);v.broker=!0;const $=await M({operation:"launch",spec:v},[D]);if(!("pid"in $))throw new Error("launcher did not return a pid");if(await de()===B||await Ce(ae,v)){p=$.pid;break}E({level:"info",event:"broker.launch.regranted",node_id:e,fields:{pid:$.pid}}),await M({operation:"stop",pid:$.pid,signal:"SIGKILL"}).catch(()=>{})}if(p===void 0)throw new Error("grant changed during every launch attempt");const k=p,Se=Date.now(),ce=new Promise(D=>{const B=setInterval(()=>{I(k)||(clearInterval(B),M({operation:"exit.status",pid:k}).then(v=>"oomKilled"in v&&v.oomKilled,()=>!1).then(v=>{E({level:v?"warn":"info",event:"broker.exited",node_id:e,fields:{pid:k,uptime_ms:Date.now()-Se,oom_killed:v}}),D({code:null,signal:null,...v?{oomKilled:!0}:{}})}))},250);B.unref()});N(o),o=null;const le={pid:k,exited:ce};return r.register(e,le),s=!0,ce.then(async D=>await r.onChildExit(e,D,c)),le}finally{for(const p of se)N(p)}}const A=await Ye(),T=Re(A,[H(),"--canvas-home",pe(),"--epoch",r.epoch(),e],{cwd:n.cwd,detached:!0,stdio:["ignore",o,o,"pipe"],env:i});d=T;const C=T.stdio[3];if(!C||!("end"in C))throw new Error("broker token pipe did not open");C.on("error",a=>E({event:"broker.token_pipe.failed",level:"error",node_id:e,error:a})),C.end(R),N(o),o=null;const ee=Date.now(),re=new Promise(a=>{let h=!1;const x=l(y=>{h||(h=!0,a(y))},"finish");T.once("exit",(y,S)=>{E({level:y===0?"info":"warn",event:"broker.exited",node_id:e,fields:{code:y,signal:S,uptime_ms:Date.now()-ee}}),x({code:y,signal:S})}),T.once("error",y=>{E({level:"error",event:"broker.launch.failed",node_id:e,error:y,fields:{uptime_ms:Date.now()-ee}}),x({code:null,signal:null})})});T.unref();const U={pid:T.pid??null,exited:re};return U.pid!==null&&(r.register(e,U),s=!0,re.then(async a=>await r.onChildExit(e,a,c))),U}catch(u){if(!s&&d?.pid!=null)try{d.kill("SIGTERM")}catch{}throw u}finally{s||r.releaseReservation(e),o!==null&&N(o)}},async isAlive(e){return I((typeof e=="string"?await _(e):e)?.pi_pid)},async teardown(e,t={}){try{return ve(await ke(e,t))}catch(n){return Promise.resolve({confirmed:!1,error:n instanceof Error?n:new Error(String(n))})}},async signal(e,t){const n=(await _(e))?.pi_pid;if(n!=null)try{process.kill(n,t)}catch{}}};export{tt as headlessBrokerHost,_e as isolatedBrokerLauncherAvailable,Er as preflightBrokerLaunch,rt as requestBrokerTeardown};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var b=Object.defineProperty;var s=(e,r)=>b(e,"name",{value:r,configurable:!0});import{envProfileId as
|
|
1
|
+
var b=Object.defineProperty;var s=(e,r)=>b(e,"name",{value:r,configurable:!0});import{envProfileId as T}from"../../shared/env.js";import{mkdirSync as H}from"node:fs";import{join as V}from"node:path";import{readMergedLaunchConfig as M}from"../config.js";import{fork as U}from"node:child_process";import{fileURLToPath as D}from"node:url";import{freshChildNodeExecPath as F,recheckChildNode as $}from"./branded-host.js";import{LAUNCH_SYSTEM_PROMPT as G}from"./launch-prompt.js";import{nodeEnv as K}from"./nodes.js";import{editorLabel as W}from"../canvas/index.js";import{CANVAS_EXTENSIONS as Ie,CANVAS_STOPHOOK_PATH as Oe,CANVAS_INBOX_WATCHER_PATH as ye,CANVAS_RECAP_PATH as ve,CANVAS_GOAL_CAPTURE_PATH as Le,CANVAS_PASSIVE_CONTEXT_PATH as Re,CANVAS_CONTEXT_INTRO_PATH as be,CANVAS_TOOL_GUIDE_PATH as He,CANVAS_DOC_SUBSTRATE_PATH as Ve,CANVAS_STRUCTURED_OUTPUT_PATH as Me,CANVAS_BASH_VALVE_PATH as Ue}from"./canvas-extensions.js";import{nodeRunDir as X}from"../canvas/paths.js";import{writeFileBeneath as B}from"../spaces/open-beneath.js";import{projectOutputSchema as j}from"./structured-output.js";import{CANVAS_EXTENSIONS as z,mergeCanvasExtensions as E,assertMandatoryCanvasExtensions as Y}from"./canvas-extensions.js";import{modelLadders as a,defaultProvider as P,STRENGTH_ALIASES as p,MODEL_PROVIDER_KEYS as S,MODEL_STRENGTHS as x,THINKING_SUFFIXES as Q,stripThinkingSuffix as m}from"./model-selection.js";import{OPENAI_PROVIDER_ENV as Fe,configuredLadderProviders as $e,inferPortableModelSelection as Ge}from"./model-selection.js";function C(e,r=a()){return r[e]}s(C,"ladderFor");const g={light:0,medium:1,strong:2,ultra:3};function J(e,r,n){const t=m(e);for(const o of[!0,!1]){const i=o?x:[...x].sort((c,u)=>g[c]-g[u]);for(const c of n)for(const u of i){const f=r[c][u];if(!(o?f!==e:m(f)!==t))return{provider:c,strength:u}}}return null}s(J,"findLadderCell");function k(e){const r=e.lastIndexOf("/"),n=r===-1?void 0:e.slice(0,r),t=r===-1?e:e.slice(r+1),o=p[t];return o!==void 0?o:n!==void 0&&n!=="anthropic"?null:t==="opus"?"strong":t==="sonnet"?"medium":t==="haiku"?"light":null}s(k,"modelTokenStrength");function w(e,r=a()){const n=k(e);return n!==null?n:J(A(e,r),r,S)?.strength??null}s(w,"resolvedModelStrength");function Z(e){return e==="review"||e.startsWith("review/")||e.includes("/reviewers/")}s(Z,"isReviewQualityKind");function q(e,r,n,t=a()){if(r===void 0)return n;if(!Z(e)||n===void 0)return r;const o=w(r,t),i=w(n,t);return o===null||i===null?r:g[o]<g[i]?n:r}s(q,"floorReviewModel");function N(e){if(e.includes("/")){const r=e.lastIndexOf("/"),n=e.slice(0,r),t=e.slice(r+1);return n!==""&&(p[t]!==void 0||n==="anthropic"&&(t==="opus"||t==="sonnet"||t==="haiku"))}return p[e]!==void 0||e==="opus"||e==="sonnet"||e==="haiku"}s(N,"isPortableModelToken");function I(e,r=a()){const n=k(e);if(n!==null)return e.includes("/")?{family:e.slice(0,e.lastIndexOf("/")),strength:n}:e==="opus"||e==="sonnet"||e==="haiku"?{family:"anthropic",strength:n}:{family:P(r),strength:n}}s(I,"logicalModelIntent");function _e(e,r=a()){return N(e)?I(e,r):void 0}s(_e,"explicitModelIntent");function A(e,r=a()){if(e.includes("/")){const t=e.indexOf("/"),o=e.slice(0,t),i=e.slice(t+1),c=p[i];if(c!==void 0&&(o==="anthropic"||o==="openai"))return C(o,r)[c];if(o==="anthropic"){if(i==="opus")return r.anthropic.strong;if(i==="sonnet")return r.anthropic.medium;if(i==="haiku")return r.anthropic.light}return e}const n=p[e];return n!==void 0?C(P(r),r)[n]:e==="opus"?r.anthropic.strong:e==="sonnet"?r.anthropic.medium:e==="haiku"?r.anthropic.light:e}s(A,"normalizeModel");function O(e){const r=e.lastIndexOf(":");if(r<=0)return;const n=e.slice(r+1);return Q.has(n)?n:void 0}s(O,"thinkingSuffixOf");function ee(e=S){const r=e.length>0?e:S,n=a(),t=[];for(const o of x)for(const i of r)t.push(n[i][o]);return t}s(ee,"interleavedLadderCycle");function Te(e,r=1,n){const t=ee(n),o=A(e),i=m(o),c=O(o);let u=t.findIndex(f=>m(f)===i&&O(f)===c);return u===-1&&(u=t.findIndex(f=>m(f)===i)),u===-1?t[0]:t[(u+r+t.length)%t.length]}s(Te,"nextLadderModel");function y(e,r,n,t){const o=t.kinds[e],i=t.modelLadders,c=r==="orchestrator"?o?.orchestratorModel??o?.model:o?.model,u=n.modelExact===!0?n.model:q(e,n.model,c,i),f=n.modelExact===!0||n.modelOverride===!0&&n.model!==void 0&&!N(n.model),l=n.modelExact===!0?u:u!==void 0?A(u,i):void 0,h=f?void 0:n.modelIntent??(u!==void 0?I(u,i):void 0);return{launch:{model:l,modelIntent:h,modelExact:f?!0:void 0,tools:o?.tools??[],extensions:E([...z,...o?.extensions??[]]),systemPrompt:G,env:{...n.extraEnv??{},...h?{CRTR_MODEL_INTENT:`${h.family}/${h.strength}`}:{}}},lifecycle:n.lifecycle}}s(y,"buildLaunchSpecFromMerged");function Ee(e,r,n){return y(e,r,n,M(n.cwd??process.cwd(),n.profileId!==void 0?n.profileId:T()||null))}s(Ee,"buildLaunchSpec");async function Pe(e,r,n){const t=n.cwd??process.cwd(),o=n.profileId!==void 0?n.profileId:T()||null,i=await re(t,o);return y(e,r,n,i)}s(Pe,"buildLaunchSpecAsync");const v=15e3;function ne(e,r,n){const t=r!==null?`was killed by ${r}`:`exited with code ${e}`,o=n.trim().split(`
|
|
2
2
|
`).slice(-8).join(`
|
|
3
|
-
`).slice(-1500);return`launch config subprocess ${t}${o!==""?`: ${o}`:" (no stderr output)"}`}s(ne,"describeLaunchConfigExit");class
|
|
3
|
+
`).slice(-1500);return`launch config subprocess ${t}${o!==""?`: ${o}`:" (no stderr output)"}`}s(ne,"describeLaunchConfigExit");class _ extends Error{static{s(this,"LaunchConfigWorkerCrash")}}async function re(e,r,n={}){const t=n.execPath??await F(),o=n.workerPath??D(new URL("./launch-config-worker.js",import.meta.url));try{return await L(e,r,t,o)}catch(i){if(!(i instanceof _))throw i;const c=await $(t);if(c===t)throw i;return L(e,r,c,o)}}s(re,"readMergedLaunchConfigAsync");function L(e,r,n,t){return new Promise((o,i)=>{const c=U(t,[],{execPath:n,stdio:["ignore","ignore","pipe","ipc"],serialization:"advanced"});let u="";c.stderr?.setEncoding("utf8").on("data",d=>{u=(u+d).slice(-8192)}),c.send({cwd:e,profileId:r});let f=!1;const l=s(d=>{f||(f=!0,clearTimeout(h),c.connected&&c.disconnect(),c.killed||c.kill("SIGKILL"),d())},"finish"),h=setTimeout(()=>l(()=>i(new Error(`timed out after ${v}ms reading launch config for ${e}`))),v);c.once("message",d=>{d.error!==void 0?l(()=>i(new Error(d.error))):d.config!==void 0?l(()=>o(d.config)):l(()=>i(new Error("launch config subprocess returned no result")))}),c.once("error",d=>l(()=>i(new _(`launch config subprocess failed: ${d.message}`)))),c.once("close",(d,R)=>{d!==0&&!f&&l(()=>i(new _(ne(d,R,u))))})})}s(L,"runLaunchConfigWorker");function te(e,r){try{const n=X(e);H(n,{recursive:!0});const t=V(n,"system-prompt.md");return B(n,t,r,{atomic:!0}),t}catch{return null}}s(te,"writeSystemPromptFile");function Ce(e,r={}){const n=e.launch,t=E(n?.extensions);Y(t);const o=[];for(const i of t)o.push("-e",i);if(o.push("-n",W(e)),r.forkFrom!==void 0&&r.forkFrom!=="")o.push("--fork",r.forkFrom);else{const i=r.resumeSessionPath??r.resumeSessionId;i!==void 0&&o.push("--session",i),r.newCycle===!0&&o.push("--crtr-new-cycle")}if(n?.model!==void 0&&o.push("--model",n.model),n?.modelExact===!0&&o.push("--crtr-model-exact"),n?.tools!==void 0&&n.tools.length>0&&o.push("--tools",n.tools.join(",")),n?.systemPrompt!==void 0&&n.systemPrompt!==""){const i=te(e.node_id,n.systemPrompt)??n.systemPrompt;o.push("--append-system-prompt",i)}return r.prompt!==void 0&&r.prompt!==""&&o.push(r.prompt),j(e.node_id),{argv:o,env:K(e)}}s(Ce,"buildPiArgv");function ke(e){for(const[t,o]of Object.entries(e.env))process.env[t]=o;const r={cwd:e.env.CRTR_NODE_CWD??process.cwd(),extensionPaths:[]},n=e.argv;for(let t=0;t<n.length;t++){const o=n[t];switch(o){case"-e":r.extensionPaths.push(n[++t]);break;case"-n":r.editorName=n[++t];break;case"--fork":r.forkFrom=n[++t];break;case"--session":{const i=n[++t];i.includes("/")||i.endsWith(".jsonl")?r.resumeSessionPath=i:r.resumeSessionId=i;break}case"--model":r.model=n[++t];break;case"--crtr-model-exact":r.modelExact=!0;break;case"--tools":r.tools=n[++t].split(",").filter(i=>i!=="");break;case"--append-system-prompt":r.appendSystemPromptPath=n[++t];break;case"--crtr-new-cycle":r.newCycle=!0;break;default:r.firstPrompt=o;break}}return r}s(ke,"piInvocationToSdkConfig");export{Ue as CANVAS_BASH_VALVE_PATH,be as CANVAS_CONTEXT_INTRO_PATH,Ve as CANVAS_DOC_SUBSTRATE_PATH,Ie as CANVAS_EXTENSIONS,Le as CANVAS_GOAL_CAPTURE_PATH,ye as CANVAS_INBOX_WATCHER_PATH,Re as CANVAS_PASSIVE_CONTEXT_PATH,ve as CANVAS_RECAP_PATH,Oe as CANVAS_STOPHOOK_PATH,Me as CANVAS_STRUCTURED_OUTPUT_PATH,He as CANVAS_TOOL_GUIDE_PATH,Fe as OPENAI_PROVIDER_ENV,Ee as buildLaunchSpec,Pe as buildLaunchSpecAsync,Ce as buildPiArgv,$e as configuredLadderProviders,ne as describeLaunchConfigExit,_e as explicitModelIntent,Ge as inferPortableModelSelection,ee as interleavedLadderCycle,N as isPortableModelToken,I as logicalModelIntent,k as modelTokenStrength,Te as nextLadderModel,A as normalizeModel,ke as piInvocationToSdkConfig,re as readMergedLaunchConfigAsync};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var $=Object.defineProperty;var
|
|
2
|
-
${
|
|
3
|
-
`)}`,label:"documents changed while you were done",tier:"normal",wake:0}),!0})}
|
|
1
|
+
var $=Object.defineProperty;var o=(e,a)=>$(e,"name",{value:a,configurable:!0});import{withCanvasWrite as c}from"../canvas/db.js";import{changedWhileDone as L}from"../substrate/delivery/deliver.js";import{queueNodeNotice as k}from"../feed/messages.js";import{clearLedger as s,forkLedger as N,hasLedger as j}from"../graph/exposures.js";import{getById as l,nodeObject as w}from"../graph/objects.js";import{mapAsync as f}from"../async-array.js";async function B(e){await c(async a=>await s(a,(await w(a,e)).id))}o(B,"clearNodeLedger");async function H(e,a){await c(async n=>{const t=await w(n,e);if(await j(n,t.id))return;const i=a===null?null:await l(n,a);i===null||i.type!=="node"?await s(n,t.id):await N(n,i.id,t.id)})}o(H,"forkNodeLedger");function m(e){return e===null?"?":e.type==="node"?e.id:e.name}o(m,"ownerHandle");async function O(e,a){return await c(async n=>{const t=await L(n,await w(n,e),a);if(t.length===0)return!1;const i=await f(t,async({doc:r,from:y,to:d,authors:u})=>{const g=r.owner===null?null:await l(n,r.owner),h=u.length===0?"":`, by ${(await f(u,async p=>m(await l(n,p)))).join(", ")}`;return`- ${m(g)}/${r.name} \u2014 revision ${y??"none"} \u2192 ${d}${h}`});return await k(n,e,{body:`Documents you watch changed while you were done:
|
|
2
|
+
${i.join(`
|
|
3
|
+
`)}`,label:"documents changed while you were done",tier:"normal",wake:0}),!0})}o(O,"noticeChangedWhileDone");export{B as clearNodeLedger,H as forkNodeLedger,O as noticeChangedWhileDone};
|
|
@@ -26,6 +26,15 @@ export declare function isParked(node: {
|
|
|
26
26
|
status: NodeStatus;
|
|
27
27
|
intent?: ExitIntent;
|
|
28
28
|
}): boolean;
|
|
29
|
+
/** A parked node the runtime reopens for wake mail: resident, no final latch, not being deleted.
|
|
30
|
+
* `PARKED_RESIDENT_SQL` (canvas/canvas.ts) is its SQL form and must change with it. */
|
|
31
|
+
export declare function isParkedResident(node: {
|
|
32
|
+
status: NodeStatus;
|
|
33
|
+
intent?: ExitIntent;
|
|
34
|
+
lifecycle?: string;
|
|
35
|
+
final_report?: unknown;
|
|
36
|
+
deleting_at?: unknown;
|
|
37
|
+
}): boolean;
|
|
29
38
|
/** Whether the lifecycle table committed a deliberate idle release. `release`
|
|
30
39
|
* writes this intent with `status='idle'` atomically before its broker may exit,
|
|
31
40
|
* so an old busy marker cannot override the durable release decision. */
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var x=Object.defineProperty;var a=(t
|
|
2
|
-
`)[0]??"";let n=0,c="";for(const d of r){const s=Buffer.byteLength(d,"utf8");if(n+s>
|
|
1
|
+
var x=Object.defineProperty;var a=(e,t)=>x(e,"name",{value:t,configurable:!0});import{getNode as O,cancelCronsOnWake as J,transitionStatusIntent as b}from"../canvas/index.js";import{composeNodeOutcomeDocument as A}from"./outcome-document.js";import{withCanvasWrite as E}from"../canvas/db.js";import{nodeObject as D}from"../graph/objects.js";import{endMessageSubscriptions as L}from"../graph/watches.js";import{settleNodeObjectWaits as P}from"../canvas/waits.js";import{runStructuredRequestEffects as j,settlePendingStructuredRequestForNodeIn as $}from"../canvas/structured-requests.js";const m="*",q={finish:"finished",park:"parked",cancel:"stranded",crash:"crashed","refresh-launch":null,revive:null},l=["active","idle"],M={finish:{status:"done",intent:"done",from:l},park:{status:"done",intent:"parked",from:l},cancel:{status:"canceled",intent:null,from:m},crash:{status:"dead",from:l},yield:{intent:"refresh",from:l},release:{status:"idle",intent:"idle-release",from:[...l,"done"]},"refresh-launch":{status:"active",intent:"refresh",from:m},revive:{status:"active",intent:null,from:m}};function T(e,t){const r=e.split(`
|
|
2
|
+
`)[0]??"";let n=0,c="";for(const d of r){const s=Buffer.byteLength(d,"utf8");if(n+s>t)break;n+=s,c+=d}return c}a(T,"firstLineAtMost");function W(e){if(e===void 0)return null;const t=e.message===void 0?void 0:T(e.message,500),r={...e,...t===void 0?{}:{message:t}},n=JSON.stringify(r);return Buffer.byteLength(n,"utf8")<=4*1024?n:JSON.stringify({schema:"crtr.node-outcome-detail/v1",truncated:!0,...t===void 0?{}:{message:t}})}a(W,"detailJson");function B(e,t){let r,n;return t==="finished"||t==="declined"?(r="done",n="done"):t==="parked"?(r="done",n="parked"):t==="closed"||t==="retired"||t==="stranded"||t==="deadline_exceeded"?(r="canceled",n=null):(r="dead",n=null),{...e,status:r,intent:n,terminal_reason:t}}a(B,"nodeAtOutcome");async function K(e,t,r){const n=M[t],c=Object.prototype.hasOwnProperty.call(n,"status"),d=Object.prototype.hasOwnProperty.call(n,"intent"),s=r?.reason??q[t],f={};c&&(f.status=n.status),d&&(f.intent=n.intent??null),s!==void 0&&(f.terminal_reason=s);const u=t==="finish"||t==="park"||t==="cancel"||t==="crash",_=u?new Date().toISOString():null,p=s,y=W(r?.outcome?.detail),S=u?s==="deadline_exceeded"?{intended:"expired",failureReason:"node_deadline_exceeded",failureDetail:r?.outcome?.detail??null}:{intended:"failed",failureReason:s,failureDetail:r?.outcome?.detail??null}:null,h=await E(async i=>{const o=u?await O(e):null,w=u&&o?.kind!=="human",N=w&&o?.run_id!=null&&s!=="parked"&&o.outcome_at!==null&&(l.includes(o.status)||o.outcome_reason==="parked");let k;w&&o!==null&&(o.outcome_at===null||N)&&(k=JSON.stringify(await A({node:B(o,p),outcome:{kind:"failure",reason:p,at:_,revision:(o.outcome_revision??0)+1,detailJson:y}})));const g=await b(e,f,{fromStatuses:n.from===m?void 0:n.from,requireNoFinalReport:t==="cancel",...w?{outcome:{kind:"failure",reason:p,detailJson:y,at:_,...N?{supersede:!0}:{},...k===void 0?{}:{documentJson:k}}}:{}});u&&g>0&&(await L(i,await D(i,e),"done"),await P(i,e));const R=g===1&&S!==null?await $(i,e,S):null;return{changes:g,settlement:R}});if(h.changes===0){const i=await O(e);if(i===null)throw new Error(`transition: unknown node ${e}`);if(t==="cancel"&&i.final_report!==null&&i.final_report!==void 0)return i;throw new Error(`illegal lifecycle transition: '${t}' from status='${i.status}' (node ${e})`)}return h.settlement?.changed&&j(h.settlement.row),(t==="finish"||t==="park"||t==="cancel")&&await J(e),await O(e)}a(K,"transition");function C(e){return e.status==="done"&&e.intent==="parked"}a(C,"isParked");function Q(e){return C(e)&&e.lifecycle==="resident"&&e.final_report==null&&e.deleting_at==null}a(Q,"isParkedResident");function U(e){return e?.intent==="idle-release"}a(U,"hasIdleReleaseIntent");export{U as hasIdleReleaseIntent,C as isParked,Q as isParkedResident,K as transition};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { type NodeMeta, type Mode, type Lifecycle, type LaunchSpec, type ManagedWorktree, type OutcomeDeliveryBinding, type ReviewBinding } from '../canvas/index.js';
|
|
2
|
-
import type
|
|
2
|
+
import { type CanvasDb } from '../canvas/db.js';
|
|
3
3
|
/** Explicitly set the resolved install id. crtrd calls this once at boot,
|
|
4
4
|
* immediately after `resolveInstallId()` — see crtrd.ts — so a provisioning
|
|
5
5
|
* mismatch fails the daemon loudly at STARTUP rather than lazily on first
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var K=Object.defineProperty;var l=(e,t)=>K(e,"name",{value:t,configurable:!0});import{envHomeOverride as X,envRuntimeHomeOverride as z,INBOX_BETWEEN_TURNS_ENV as V,SCOPES_FILE_ENV as Y,scopeAllowed as C}from"../../shared/env.js";import{isOwnMemoryScope as Q,validateScopes as Z}from"../scopes.js";import{activeGrant as B,terminalGrant as k}from"../grants/mirror.js";import{grantSnapshotMissing as ee}from"../../daemon/readiness.js";import{appendRunEvent as ne}from"../runs/events.js";import{readConfig as S}from"../config.js";import{InputError as T}from"../io.js";import{ApiError as g}from"../../api/errors.js";import{assertGranteeRunsHere as re}from"./unsandboxed.js";import{randomBytes as te}from"node:crypto";import{existsSync as P}from"node:fs";import{resolve as ie,relative as ae,isAbsolute as H,join as oe,sep as le}from"node:path";import{appSpace as se}from"../layout.js";import{scopesFilePath as de}from"../canvas/paths.js";import{createNode as ce,assertRunNotDeleting as ue,conversationOwner as fe,getNode as u,getRow as pe}from"../canvas/index.js";import{ensureAppSpace as me}from"../spaces/space.js";import{LAUNCHER_SOCKET as L}from"../../launcher/spec.js";import{resolveInstallId as _e}from"../canvas/install-id.js";import{isAppRun as we}from"../canvas/app-run.js";import{canvasDbPath as ge,contextDir as he}from"../canvas/paths.js";import{conversationIdFromPath as ve}from"../conversation-store/index.js";import{usage as U}from"../errors.js";import{assertProfileAvailableForBirth as Re}from"../profiles/deletion-reservation.js";import{loadExactProfileManifest as ye}from"../profiles/manifest.js";import{admitNodeCreate as Ee}from"../command-hooks/lifecycle-create.js";import{getById as Ce,nodeObject as I,ownerForGrantee as Ie}from"../graph/objects.js";import{recordActedOn as Ne}from"../graph/edges.js";import{recordWatch as ke,copyWatchesForFork as Se}from"../graph/watches.js";import{publish as Te}from"../graph/events.js";import{someAsync as Oe}from"../async-array.js";let O;const j=new Map;function _n(e){O=e}l(_n,"setInstallId");async function xe(){if(O!==void 0)return O;const e=ge(),t=j.get(e);if(t!==void 0)return t;const a=await _e();return j.set(e,a),a}l(xe,"installId");function De(){return`${Date.now().toString(36)}-${te(4).toString("hex")}`}l(De,"newJobId");async function be(){return`${await xe()}-${De()}`}l(be,"newNodeId");const x=128,Ae=/^[a-z0-9-]+$/;class q extends Error{static{l(this,"NodeIdConflictError")}nodeId;constructor(t){super(`node already exists: ${t}`),this.nodeId=t,this.name="NodeIdConflictError"}}function D(e){if(e.length===0||e.length>x)throw U(`invalid --node-id '${e}': must be 1-${x} characters`,{next:`Pass an id-safe string (lowercase letters, digits, hyphens) of at most ${x} characters.`});if(!Ae.test(e))throw U(`invalid --node-id '${e}': must contain only lowercase letters, digits, and hyphens (e.g. 'remote42', 'my-node-1')`,{next:"Use only lowercase letters, digits, and hyphens."})}l(D,"validateNodeIdFormat");async function wn(e){if(D(e),await u(e)!==null)throw new q(e)}l(wn,"preflightNodeId");async function Me(e){if(D(e),await u(e)!==null)throw new q(e);return e}l(Me,"validatedExplicitNodeId");async function gn(e){let t=e;const a=new Set;for(;;){if(a.has(t))return t;a.add(t);const s=await pe(t);if(s===null||s.parent==null)return t;t=s.parent}}l(gn,"rootOfSpine");function hn(){const e=process.env;return{nodeId:e.CRTR_NODE_ID??null,kind:e.CRTR_KIND??null,mode:e.CRTR_MODE??null}}l(hn,"currentNodeContext");function $e(e){return we(e)}l($e,"inboxBetweenTurns");function vn(e){const t={CRTR_NODE_ID:e.node_id,CRTR_KIND:e.kind,CRTR_MODE:e.mode,CRTR_LIFECYCLE:e.lifecycle,CRTR_NODE_CWD:e.cwd,CRTR_CONTEXT_DIR:he(e.node_id,e.grantee),CRTR_CYCLES:(e.cycles??0).toString(),CRTR_PROFILE_ID:e.profile_id??"",PI_CLAUDE_OAUTH_REINJECT_SCOPE:"never"};e.parent&&(t.CRTR_PARENT_NODE_ID=e.parent),e.run_id&&(t.CRTR_RUN_ID=e.run_id),$e(e)&&(t[V]="1"),e.scopes!==null&&e.scopes!==void 0&&(t[Y]=de(e.node_id)),t.CRTR_GRANTEE=e.grantee??"app:terminal";const a=X();a!==void 0&&a!==""&&(t.CRTR_HOME=a);const s=z();s!==void 0&&s!==""&&(t.CRTR_RUNTIME_HOME=s);const f=process.env.CRTR_SUBTREE;return f!==void 0&&f!==""&&(t.CRTR_SUBTREE=f),{...t,...e.launch?.env??{}}}l(vn,"nodeEnv");async function Fe(e){const t=ve(e),a=t===null?null:await fe(t);return a===null?null:await u(a)}l(Fe,"forkSourceNode");async function Rn(e){const t=e.nodeId!==void 0?(D(e.nodeId),e.nodeId):await be(),a=e.parent??null,s=a===null,f=e.spawnedBy??a,m=e.creator??null,b=e.mode??"base",N=e.lifecycle??(s?"resident":"terminal"),h=e.run===void 0?await k():null,n={node_id:t,name:e.name??e.kind,description:e.description,cycles:0,created:new Date().toISOString(),cwd:e.cwd,host_kind:"broker",profile_id:e.profile_id??null,kind:e.kind,mode:b,lifecycle:N,persona_ack:{kind:e.kind,mode:b,lifecycle:N},status:"active",parent:a,spawned_by:f,creator:m,fork_from:e.forkFrom,fork_source_file:e.forkSourceFile,review_binding:e.reviewBinding,model_override:e.modelOverride??null,scopes:e.scopes??null,isolated:e.isolated===!0,grantee:e.run?.grantee??"app:terminal",sub:e.run?.sub??h?.sub??null,grant_id:e.run?.grant_id??h?.id??null,client_id:e.run?.client_id??null,metadata_json:s?e.run?.metadata_json??null:null,run_id:s?t:e.run?.run_id??null,event_cursor:s?e.run?.event_cursor??1:null,usage_json:s?e.run?.usage_json??JSON.stringify({input_tokens:0,output_tokens:0,cache_read_tokens:0,cache_write_tokens:0,cost_usd:0}):null,passive_default:e.passiveDefault??!1,...e.managedWorktree!==void 0?{managed_worktree:e.managedWorktree}:{},intent:null,deadline_at:e.deadlineAt??null,pi_session_id:null,pi_session_file:null,launch:e.launch},y=e.scopes===void 0?void 0:Z(e.scopes),v=a===null?null:await u(a);if(a!==null&&v===null)throw new Error(`cannot spawn under unknown parent node: ${a}`);if(v?.run_id&&(await u(v.run_id))?.deleting_at)throw new Error("run is deleting");const c=m===null?null:await u(m);if(m!==null&&c===null)throw new Error(`cannot spawn from unknown creator node: ${m}`);if(c?.run_id&&(await u(c.run_id))?.deleting_at)throw new Error("run is deleting");const A=e.forkSourceFile==null?null:await Fe(e.forkSourceFile),M=e.replaces==null?null:await u(e.replaces),_=v??A??M??c??(f===null?null:await u(f)),W=[v,c,A,M,f===null?null:await u(f)],$=await Oe(W,async r=>r?.isolated===!0||r?.run_id!=null&&(await u(r.run_id))?.isolated===!0);if($&&e.isolated===!1)throw new g(403,"isolated_run","isolation cannot be turned off under an isolated run",{param:"isolated"});if(n.isolated=$||e.isolated===!0,_!==null){const r=c??_;if(c&&_.grantee&&c.grantee&&c.grantee!==_.grantee)throw new g(403,"other_app_run","cannot create under another app's node");const i=c&&c!==_?[_,c]:[_],d=[],w=new Set;for(const o of i){o.scopes!==null&&o.scopes!==void 0&&d.push(o.scopes);const p=o.grantee==="app:terminal"?await k():o.grant_id?await B(o.grant_id):null;if(p){const R=[...p.resolved];w.add(R),d.push(R)}else if(!(o.grantee==="app:terminal"&&!S("user").runtime?.issuer)){const R=[];w.add(R),d.push(R)}}const E=l(o=>Q(o,r.grantee==="user:local"?"app:terminal":r.grantee??"app:terminal"),"ownMemory"),F=l((o,p)=>E(p)&&w.has(o)||C(o,p),"allowed");if(y!==void 0&&!y.every(o=>d.every(p=>F(p,o))))throw new T({error:"unknown_scope",message:"child scopes must be covered by the creating node, its source and their current grants",received:y,field:"scopes",next:"Request only scopes the creating node currently holds."});if(n.scopes=y??(i.every(o=>o.scopes==null)&&i.every(o=>o.grant_id===r.grant_id&&o.sub===r.sub)?null:i.length===1?_.scopes??null:[...new Set(d.flat().filter(o=>d.every(p=>F(p,o))))]),n.scopes?.includes("crtr:act")&&!C(n.scopes,"crtr:llm"))throw new T({error:"invalid_scope",message:"crtr:act requires crtr:llm",received:n.scopes,field:"scopes",next:"Include crtr:llm or omit crtr:act."});n.grantee=r.grantee==="user:local"?"app:terminal":r.grantee,n.sub=r.sub??(n.grantee==="app:terminal"?h?.sub:null)??null,n.grant_id=r.grant_id??(n.grantee==="app:terminal"?h?.id:null)??null,n.client_id=r.client_id,n.run_id=s?t:r.run_id??null}if(re(n.grantee),e.run===void 0&&n.grantee==="app:terminal"&&S("user").runtime?.issuer&&h===null)throw await ee()?new g(503,"runtime_starting","the first grant snapshot from the directory has not committed"):new g(403,"scope_missing","terminal grant is not active");if(n.isolated){if(process.platform!=="linux"||!P(L))throw new g(400,"isolated_unavailable","isolated nodes require the Linux root launcher");if(e.managedWorktree!==void 0)throw new g(400,"invalid_request","isolated nodes cannot use a worktree",{param:"worktree"});const r=oe(se(n.grantee??"app:terminal").nodes,t),i=ae(r,ie(n.cwd));if(!H(n.cwd)||i===".."||i.startsWith(`..${le}`)||H(i))throw new g(400,"invalid_request","isolated node cwd must be inside its own folder",{param:"cwd"})}if(n.profile_id){const r=ye(n.profile_id).manifest.grantee??"app:terminal";if(r!==n.grantee){const i=`crtr:memory:rw:${r}:profile:${n.profile_id}`,d=n.grantee==="app:terminal"?await k():n.grant_id?await B(n.grant_id):null;if(!(n.grantee==="app:terminal"&&!S("user").runtime?.issuer)&&(!d||d.grantee!==n.grantee||!C(d.resolved,i))||!C(n.scopes,i))throw new T({error:"scope_missing",message:`missing scope ${i}`,received:n.profile_id,field:"profile",next:"Select a profile covered by this run and its current grant."})}}if(Re(n.profile_id??null),!n.grantee)throw new Error("node creation requires an app");const G=await Ee({kind:n.kind,mode:n.mode,cwd:n.cwd,profile:n.profile_id??null,root:s,parentId:a,requestingNodeId:m,lifecycle:N,replaces:e.replaces??null},n.grantee),J=l(async(r,i)=>{const d=await I(r,i.node_id),w=m??a??e.actor??f??null,E=w!==null&&(await Ce(r,w))?.type==="node"?await I(r,w):await Ie(r,e.run===void 0?"user:local":i.grantee);await Ne(r,E,d),a!==null&&e.subscribe!==!1&&await ke(r,await I(r,a),d,"spawn"),e.forkSourceNode&&await Se(r,await I(r,e.forkSourceNode),d),await Te(r,{event:"created",object:d,actor:E,attrs:{name:i.name,kind:i.kind,creator:m??null}})},"recordBirth");try{e.nodeId!==void 0&&await Me(e.nodeId),await e.beforeCreate?.(),(process.platform!=="linux"||P(L))&&await me(n.grantee??"app:terminal"),await ce(n,{outcomeDelivery:e.outcomeDelivery,withinCreate:l(async(r,i)=>{i.run_id&&i.run_id!==i.node_id&&await ue(r,i.run_id),s&&e.run===void 0&&await ne(r,t,t,"run.started",{scopes:i.scopes??null,payer:"user",usage:JSON.parse(i.usage_json)}),await e.withinCreate?.(r,i),await J(r,i)},"withinCreate")})}finally{G()}return n}l(Rn,"spawnNode");export{q as NodeIdConflictError,hn as currentNodeContext,Fe as forkSourceNode,$e as inboxBetweenTurns,De as newJobId,be as newNodeId,vn as nodeEnv,wn as preflightNodeId,gn as rootOfSpine,_n as setInstallId,Rn as spawnNode};
|
|
1
|
+
var K=Object.defineProperty;var l=(e,t)=>K(e,"name",{value:t,configurable:!0});import{envHomeOverride as X,envRuntimeHomeOverride as z,INBOX_BETWEEN_TURNS_ENV as V,SCOPES_FILE_ENV as Y,scopeAllowed as C}from"../../shared/env.js";import{isOwnMemoryScope as Q,validateScopes as Z}from"../scopes.js";import{activeGrant as B,terminalGrant as k}from"../grants/mirror.js";import{grantSnapshotMissing as ee}from"../../daemon/readiness.js";import{appendRunEvent as ne}from"../runs/events.js";import{readConfig as S}from"../config.js";import{InputError as T}from"../io.js";import{ApiError as g}from"../../api/errors.js";import{assertGranteeRunsHere as re}from"./unsandboxed.js";import{randomBytes as te}from"node:crypto";import{existsSync as P}from"node:fs";import{resolve as ie,relative as ae,isAbsolute as U,join as oe,sep as le}from"node:path";import{appSpace as se}from"../layout.js";import{scopesFilePath as de}from"../canvas/paths.js";import{createNode as ce,assertRunNotDeleting as ue,conversationOwner as fe,getNode as u,getRow as pe}from"../canvas/index.js";import{ensureAppSpace as me}from"../spaces/space.js";import{LAUNCHER_SOCKET as H}from"../../launcher/spec.js";import{resolveInstallId as _e}from"../canvas/install-id.js";import{isAppRun as we}from"../canvas/app-run.js";import{contextDir as ge}from"../canvas/paths.js";import{conversationIdFromPath as he}from"../conversation-store/index.js";import{usage as L}from"../errors.js";import{assertProfileAvailableForBirth as ve}from"../profiles/deletion-reservation.js";import{loadExactProfileManifest as Re}from"../profiles/manifest.js";import{admitNodeCreate as ye}from"../command-hooks/lifecycle-create.js";import{getById as Ee,nodeObject as I,ownerForGrantee as Ce}from"../graph/objects.js";import{recordActedOn as Ie}from"../graph/edges.js";import{recordWatch as Ne,copyWatchesForFork as ke}from"../graph/watches.js";import{publish as Se}from"../graph/events.js";import{canvasDatabaseUrl as Te}from"../canvas/db.js";import{someAsync as Oe}from"../async-array.js";let O;const j=new Map;function wn(e){O=e}l(wn,"setInstallId");async function xe(){if(O!==void 0)return O;const e=await Te(),t=j.get(e);if(t!==void 0)return t;const a=await _e();return j.set(e,a),a}l(xe,"installId");function De(){return`${Date.now().toString(36)}-${te(4).toString("hex")}`}l(De,"newJobId");async function be(){return`${await xe()}-${De()}`}l(be,"newNodeId");const x=128,Ae=/^[a-z0-9-]+$/;class q extends Error{static{l(this,"NodeIdConflictError")}nodeId;constructor(t){super(`node already exists: ${t}`),this.nodeId=t,this.name="NodeIdConflictError"}}function D(e){if(e.length===0||e.length>x)throw L(`invalid --node-id '${e}': must be 1-${x} characters`,{next:`Pass an id-safe string (lowercase letters, digits, hyphens) of at most ${x} characters.`});if(!Ae.test(e))throw L(`invalid --node-id '${e}': must contain only lowercase letters, digits, and hyphens (e.g. 'remote42', 'my-node-1')`,{next:"Use only lowercase letters, digits, and hyphens."})}l(D,"validateNodeIdFormat");async function gn(e){if(D(e),await u(e)!==null)throw new q(e)}l(gn,"preflightNodeId");async function Me(e){if(D(e),await u(e)!==null)throw new q(e);return e}l(Me,"validatedExplicitNodeId");async function hn(e){let t=e;const a=new Set;for(;;){if(a.has(t))return t;a.add(t);const s=await pe(t);if(s===null||s.parent==null)return t;t=s.parent}}l(hn,"rootOfSpine");function vn(){const e=process.env;return{nodeId:e.CRTR_NODE_ID??null,kind:e.CRTR_KIND??null,mode:e.CRTR_MODE??null}}l(vn,"currentNodeContext");function $e(e){return we(e)}l($e,"inboxBetweenTurns");function Rn(e){const t={CRTR_NODE_ID:e.node_id,CRTR_KIND:e.kind,CRTR_MODE:e.mode,CRTR_LIFECYCLE:e.lifecycle,CRTR_NODE_CWD:e.cwd,CRTR_CONTEXT_DIR:ge(e.node_id,e.grantee),CRTR_CYCLES:(e.cycles??0).toString(),CRTR_PROFILE_ID:e.profile_id??"",PI_CLAUDE_OAUTH_REINJECT_SCOPE:"never"};e.parent&&(t.CRTR_PARENT_NODE_ID=e.parent),e.run_id&&(t.CRTR_RUN_ID=e.run_id),$e(e)&&(t[V]="1"),e.scopes!==null&&e.scopes!==void 0&&(t[Y]=de(e.node_id)),t.CRTR_GRANTEE=e.grantee??"app:terminal";const a=X();a!==void 0&&a!==""&&(t.CRTR_HOME=a);const s=z();s!==void 0&&s!==""&&(t.CRTR_RUNTIME_HOME=s);const f=process.env.CRTR_SUBTREE;return f!==void 0&&f!==""&&(t.CRTR_SUBTREE=f),{...t,...e.launch?.env??{}}}l(Rn,"nodeEnv");async function Fe(e){const t=he(e),a=t===null?null:await fe(t);return a===null?null:await u(a)}l(Fe,"forkSourceNode");async function yn(e){const t=e.nodeId!==void 0?(D(e.nodeId),e.nodeId):await be(),a=e.parent??null,s=a===null,f=e.spawnedBy??a,m=e.creator??null,b=e.mode??"base",N=e.lifecycle??(s?"resident":"terminal"),h=e.run===void 0?await k():null,n={node_id:t,name:e.name??e.kind,description:e.description,cycles:0,created:new Date().toISOString(),cwd:e.cwd,host_kind:"broker",profile_id:e.profile_id??null,kind:e.kind,mode:b,lifecycle:N,persona_ack:{kind:e.kind,mode:b,lifecycle:N},status:"active",parent:a,spawned_by:f,creator:m,fork_from:e.forkFrom,fork_source_file:e.forkSourceFile,review_binding:e.reviewBinding,model_override:e.modelOverride??null,scopes:e.scopes??null,isolated:e.isolated===!0,grantee:e.run?.grantee??"app:terminal",sub:e.run?.sub??h?.sub??null,grant_id:e.run?.grant_id??h?.id??null,client_id:e.run?.client_id??null,metadata_json:s?e.run?.metadata_json??null:null,run_id:s?t:e.run?.run_id??null,event_cursor:s?e.run?.event_cursor??1:null,usage_json:s?e.run?.usage_json??JSON.stringify({input_tokens:0,output_tokens:0,cache_read_tokens:0,cache_write_tokens:0,cost_usd:0}):null,passive_default:e.passiveDefault??!1,...e.managedWorktree!==void 0?{managed_worktree:e.managedWorktree}:{},intent:null,deadline_at:e.deadlineAt??null,pi_session_id:null,pi_session_file:null,launch:e.launch},y=e.scopes===void 0?void 0:Z(e.scopes),v=a===null?null:await u(a);if(a!==null&&v===null)throw new Error(`cannot spawn under unknown parent node: ${a}`);if(v?.run_id&&(await u(v.run_id))?.deleting_at)throw new Error("run is deleting");const c=m===null?null:await u(m);if(m!==null&&c===null)throw new Error(`cannot spawn from unknown creator node: ${m}`);if(c?.run_id&&(await u(c.run_id))?.deleting_at)throw new Error("run is deleting");const A=e.forkSourceFile==null?null:await Fe(e.forkSourceFile),M=e.replaces==null?null:await u(e.replaces),_=v??A??M??c??(f===null?null:await u(f)),W=[v,c,A,M,f===null?null:await u(f)],$=await Oe(W,async r=>r?.isolated===!0||r?.run_id!=null&&(await u(r.run_id))?.isolated===!0);if($&&e.isolated===!1)throw new g(403,"isolated_run","isolation cannot be turned off under an isolated run",{param:"isolated"});if(n.isolated=$||e.isolated===!0,_!==null){const r=c??_;if(c&&_.grantee&&c.grantee&&c.grantee!==_.grantee)throw new g(403,"other_app_run","cannot create under another app's node");const i=c&&c!==_?[_,c]:[_],d=[],w=new Set;for(const o of i){o.scopes!==null&&o.scopes!==void 0&&d.push(o.scopes);const p=o.grantee==="app:terminal"?await k():o.grant_id?await B(o.grant_id):null;if(p){const R=[...p.resolved];w.add(R),d.push(R)}else if(!(o.grantee==="app:terminal"&&!S("user").runtime?.issuer)){const R=[];w.add(R),d.push(R)}}const E=l(o=>Q(o,r.grantee==="user:local"?"app:terminal":r.grantee??"app:terminal"),"ownMemory"),F=l((o,p)=>E(p)&&w.has(o)||C(o,p),"allowed");if(y!==void 0&&!y.every(o=>d.every(p=>F(p,o))))throw new T({error:"unknown_scope",message:"child scopes must be covered by the creating node, its source and their current grants",received:y,field:"scopes",next:"Request only scopes the creating node currently holds."});if(n.scopes=y??(i.every(o=>o.scopes==null)&&i.every(o=>o.grant_id===r.grant_id&&o.sub===r.sub)?null:i.length===1?_.scopes??null:[...new Set(d.flat().filter(o=>d.every(p=>F(p,o))))]),n.scopes?.includes("crtr:act")&&!C(n.scopes,"crtr:llm"))throw new T({error:"invalid_scope",message:"crtr:act requires crtr:llm",received:n.scopes,field:"scopes",next:"Include crtr:llm or omit crtr:act."});n.grantee=r.grantee==="user:local"?"app:terminal":r.grantee,n.sub=r.sub??(n.grantee==="app:terminal"?h?.sub:null)??null,n.grant_id=r.grant_id??(n.grantee==="app:terminal"?h?.id:null)??null,n.client_id=r.client_id,n.run_id=s?t:r.run_id??null}if(re(n.grantee),e.run===void 0&&n.grantee==="app:terminal"&&S("user").runtime?.issuer&&h===null)throw await ee()?new g(503,"runtime_starting","the first grant snapshot from the directory has not committed"):new g(403,"scope_missing","terminal grant is not active");if(n.isolated){if(process.platform!=="linux"||!P(H))throw new g(400,"isolated_unavailable","isolated nodes require the Linux root launcher");if(e.managedWorktree!==void 0)throw new g(400,"invalid_request","isolated nodes cannot use a worktree",{param:"worktree"});const r=oe(se(n.grantee??"app:terminal").nodes,t),i=ae(r,ie(n.cwd));if(!U(n.cwd)||i===".."||i.startsWith(`..${le}`)||U(i))throw new g(400,"invalid_request","isolated node cwd must be inside its own folder",{param:"cwd"})}if(n.profile_id){const r=Re(n.profile_id).manifest.grantee??"app:terminal";if(r!==n.grantee){const i=`crtr:memory:rw:${r}:profile:${n.profile_id}`,d=n.grantee==="app:terminal"?await k():n.grant_id?await B(n.grant_id):null;if(!(n.grantee==="app:terminal"&&!S("user").runtime?.issuer)&&(!d||d.grantee!==n.grantee||!C(d.resolved,i))||!C(n.scopes,i))throw new T({error:"scope_missing",message:`missing scope ${i}`,received:n.profile_id,field:"profile",next:"Select a profile covered by this run and its current grant."})}}if(ve(n.profile_id??null),!n.grantee)throw new Error("node creation requires an app");const G=await ye({kind:n.kind,mode:n.mode,cwd:n.cwd,profile:n.profile_id??null,root:s,parentId:a,requestingNodeId:m,lifecycle:N,replaces:e.replaces??null},n.grantee),J=l(async(r,i)=>{const d=await I(r,i.node_id),w=m??a??e.actor??f??null,E=w!==null&&(await Ee(r,w))?.type==="node"?await I(r,w):await Ce(r,e.run===void 0?"user:local":i.grantee);await Ie(r,E,d),a!==null&&e.subscribe!==!1&&await Ne(r,await I(r,a),d,"spawn"),e.forkSourceNode&&await ke(r,await I(r,e.forkSourceNode),d),await Se(r,{event:"created",object:d,actor:E,attrs:{name:i.name,kind:i.kind,creator:m??null}})},"recordBirth");try{e.nodeId!==void 0&&await Me(e.nodeId),await e.beforeCreate?.(),(process.platform!=="linux"||P(H))&&await me(n.grantee??"app:terminal"),await ce(n,{outcomeDelivery:e.outcomeDelivery,withinCreate:l(async(r,i)=>{i.run_id&&i.run_id!==i.node_id&&await ue(r,i.run_id),s&&e.run===void 0&&await ne(r,t,t,"run.started",{scopes:i.scopes??null,payer:"user",usage:JSON.parse(i.usage_json)}),await e.withinCreate?.(r,i),await J(r,i)},"withinCreate")})}finally{G()}return n}l(yn,"spawnNode");export{q as NodeIdConflictError,vn as currentNodeContext,Fe as forkSourceNode,$e as inboxBetweenTurns,De as newJobId,be as newNodeId,Rn as nodeEnv,gn as preflightNodeId,hn as rootOfSpine,wn as setInstallId,yn as spawnNode};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
var l=Object.defineProperty;var r=(t,e)=>l(t,"name",{value:e,configurable:!0});import{openDb as u,withCanvasWrite as s}from"../canvas/db.js";import{get as c}from"../graph/bodies.js";import{heads as d,writeDocument as m}from"../graph/documents.js";import{asRuntimeWriter as p}from"../graph/spaces/own-memory.js";import{getById as f,liveDocumentNamed as w,nodeObject as h}from"../graph/objects.js";import{readerForNode as y}from"../graph/reader.js";const o="roadmap",g="To understand this node's long-term task and current plan, read this.";function x(t){return t?.split(`
|
|
2
|
-
`).map(n=>n.trim()).find(n=>n!=="")??g}r(x,"roadmapPreview");function P(t){return`${t}/${o}`}r(P,"roadmapRef");async function i(t,e){const n=await f(t,e);return n===null||n.type!=="node"?null:await w(t,n.
|
|
2
|
+
`).map(n=>n.trim()).find(n=>n!=="")??g}r(x,"roadmapPreview");function P(t){return`${t}/${o}`}r(P,"roadmapRef");async function i(t,e){const n=await f(t,e);return n===null||n.type!=="node"?null:await w(t,n.id,o)}r(i,"roadmapObject");async function $(t){return await i(await u(),t)!==null}r($,"hasRoadmap");async function M(t){const e=await u(),n=await i(e,t);if(n===null)return null;const a=(await d(e,n))[0];if(a===void 0)return null;try{return c(a.body_hash)}catch{return null}}r(M,"readRoadmap");function R(t){return`# Roadmap
|
|
3
3
|
|
|
4
4
|
## Goal
|
|
5
5
|
${t.goal?.trim()||"(the goal you now own)"}
|
|
@@ -15,6 +15,7 @@ export declare function recordBashJobObject(nodeId: string, jobId: string, spec:
|
|
|
15
15
|
/** Stop the broker first so it cannot start another job during the job scan. */
|
|
16
16
|
export declare function stopNodeSandboxes(nodeId: string, reason: string, options?: {
|
|
17
17
|
excludePid?: number;
|
|
18
|
+
startAfter?: Promise<unknown>;
|
|
18
19
|
after?: () => Promise<void>;
|
|
19
20
|
deleting?: boolean;
|
|
20
21
|
holdRecovery?: boolean;
|
package/dist/core/spaces/stop.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var _=Object.defineProperty;var s=(t,e)=>_(t,"name",{value:e,configurable:!0});import{randomUUID as g}from"node:crypto";import{activeBackgroundBashJobs as x,stopBackgroundBashJob as R}from"../bash-jobs.js";import{getNode as T}from"../canvas/index.js";import{withCanvasWrite as b,openDb as D}from"../canvas/db.js";import{finishJob as S,startJob as J}from"../graph/jobs.js";import{getById as h,nodeObject as O}from"../graph/objects.js";import{readLiveSession as
|
|
2
|
-
AND type IN ('node.turn.started', 'node.turn.completed') ORDER BY sequence_number DESC LIMIT 1`).get(t),"latestTurn"),v=
|
|
1
|
+
var _=Object.defineProperty;var s=(t,e)=>_(t,"name",{value:e,configurable:!0});import{randomUUID as g}from"node:crypto";import{activeBackgroundBashJobs as x,stopBackgroundBashJob as R}from"../bash-jobs.js";import{getNode as T}from"../canvas/index.js";import{withCanvasWrite as b,openDb as D}from"../canvas/db.js";import{finishJob as S,startJob as J}from"../graph/jobs.js";import{getById as h,nodeObject as O}from"../graph/objects.js";import{readLiveSession as A}from"../canvas/sessions.js";import{contextDir as M}from"../canvas/node-agent-paths.js";import{conversationStore as N}from"../conversation-store/index.js";import{requestBrokerTeardown as W}from"../runtime/host.js";import{holdRecovery as $}from"../runtime/recovery-hold.js";async function C(t,e,r){return await b(async n=>{const o=await h(n,t);return o===null||o.type!=="job"?!1:(await S(n,o,{killedBy:await e(n),...r===void 0?{}:{reason:r}}),!0)})}s(C,"killBashJobObject");async function X(t,e,r){return await b(async n=>{const o=await h(n,e);if(o!==null){if(o.type!=="job")throw new Error(`${e} names a ${o.type}`);return o}return await J(n,await O(n,t),{id:e,...r})})}s(X,"recordBashJobObject");const d=new Map;async function Z(t,e,r={}){const n=d.get(t);if(n)return n;const o=await T(t);if(!o)return Promise.resolve({confirmed:!1,error:new Error(`missing node ${t}`)});const l=(await A(t))?.sessionId,m=s(async()=>await(await D()).prepare(`SELECT type, body_json FROM run_events WHERE node_id = ?
|
|
2
|
+
AND type IN ('node.turn.started', 'node.turn.completed') ORDER BY sequence_number DESC LIMIT 1`).get(t),"latestTurn"),v=o.run_id!==null&&o.pi_pid!==null&&(await m())?.type==="node.turn.started",E=r.holdRecovery?$(t):()=>{},j=W(t,{excludePid:r.excludePid,...r.startAfter?{startAfter:r.startAfter}:{}}),c=(async()=>{const u=await j;if(!u.confirmed)return u;try{const a=await M(t);for(const p of x(a,!0)){const i=await R(a,p.jobId,!0,t,e);if(i.kind==="not-stoppable")throw new Error(`background bash job ${p.jobId} could not be stopped`);i.kind!=="stopped"||r.deleting||await C(p.jobId,async()=>null,e)}if(v&&l&&!r.deleting){if((await m())?.type!=="node.turn.started")return await r.after?.(),u;const i=N(),{entries:k}=await i.read(l),B=k.at(-1),f=new Date().toISOString(),w=e==="permission_revoked",y={type:"message",id:g(),parentId:B?.id??null,timestamp:f,message:{role:"assistant",content:[],api:"openai-completions",provider:"crouter",model:"",usage:{input:0,output:0,cacheRead:0,cacheWrite:0,totalTokens:0,cost:{input:0,output:0,cacheRead:0,cacheWrite:0,total:0}},stopReason:w?"error":"aborted",errorMessage:e,timestamp:Date.now()}};await i.append(l,[y,{type:"custom",id:g(),parentId:y.id,timestamp:f,customType:"crtr-turn-end",data:w?{stop_reason:"error",error:{code:"model_error",message:e}}:{stop_reason:"aborted"}}])}return await r.after?.(),u}catch(a){return{confirmed:!1,error:a instanceof Error?a:new Error(String(a))}}})();return d.set(t,c),c.finally(()=>{E(),d.get(t)===c&&d.delete(t)}),c}s(Z,"stopNodeSandboxes");export{C as killBashJobObject,X as recordBashJobObject,Z as stopNodeSandboxes};
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Placeholder translation for the Postgres engine. Call sites keep SQLite's `?` / `?N` spelling; this turns it into
|
|
3
|
+
* `$n`. Slot semantics follow SQLite: `?N` is always slot N (so one value can be bound to several `?1`), and a bare
|
|
4
|
+
* `?` takes the slot after the highest one used so far. `?` inside single-quoted literals, double-quoted identifiers,
|
|
5
|
+
* dollar-quoted bodies and comments is left alone. Identifiers are never rewritten.
|
|
6
|
+
*/
|
|
7
|
+
export interface TranslatedStatement {
|
|
8
|
+
/** SQL with `$n` placeholders. */
|
|
9
|
+
text: string;
|
|
10
|
+
/** Number of parameter slots (the highest slot used). */
|
|
11
|
+
slots: number;
|
|
12
|
+
/** Prepared-statement name on the connection: a hash of the original SQL. */
|
|
13
|
+
name: string;
|
|
14
|
+
}
|
|
15
|
+
export declare function translatePlaceholders(sql: string): TranslatedStatement;
|
|
16
|
+
/** Translation without caching, for generated SQL that is run once. */
|
|
17
|
+
export declare function translateOnce(sql: string): Omit<TranslatedStatement, 'name'>;
|
|
@@ -0,0 +1,2 @@
|
|
|
1
|
+
var s=Object.defineProperty;var f=(t,i)=>s(t,"name",{value:i,configurable:!0});import{createHash as u}from"node:crypto";const h=new Map;function $(t){const i=h.get(t);if(i!==void 0)return i;const r=l(t);return h.set(t,r),r}f($,"translatePlaceholders");function g(t){const{text:i,slots:r}=l(t);return{text:i,slots:r}}f(g,"translateOnce");function l(t){let i="",r=0,n=0;const a=t.length;for(;n<a;){const o=t[n];if(o==="'"||o==='"'){let e=n+1;for(;e<a;e++)if(t[e]===o){if(t[e+1]===o){e++;continue}break}i+=t.slice(n,e+1),n=e+1}else if(o==="-"&&t[n+1]==="-"){let e=t.indexOf(`
|
|
2
|
+
`,n);e===-1&&(e=a),i+=t.slice(n,e),n=e}else if(o==="/"&&t[n+1]==="*"){let e=t.indexOf("*/",n+2);e=e===-1?a:e+2,i+=t.slice(n,e),n=e}else if(o==="$"&&/[A-Za-z_$]/.test(t[n+1]??"")){const e=/^\$[A-Za-z_]*\$/.exec(t.slice(n))?.[0];if(e===void 0){i+=o,n++;continue}let c=t.indexOf(e,n+e.length);c=c===-1?a:c+e.length,i+=t.slice(n,c),n=c}else if(o==="?"){let e=n+1;for(;e<a&&t[e]>="0"&&t[e]<="9";)e++;const c=e>n+1?Number(t.slice(n+1,e)):r+1;if(c<1)throw new Error(`invalid placeholder ?${c} in: ${t}`);c>r&&(r=c),i+=`$${c}`,n=e}else i+=o,n++}return{text:i,slots:r,name:`s${u("sha1").update(t).digest("hex")}`}}f(l,"translate");export{g as translateOnce,$ as translatePlaceholders};
|