@north-light/cli 0.3.529 → 0.3.531
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/dto/lifecycle.d.ts +3 -1
- package/dist/api/dto/messages.d.ts +5 -3
- package/dist/builtin-memory/crouter-plugin/bundles-and-memory.md +1 -1
- package/dist/builtin-memory/crouter-plugin/commands.md +1 -1
- package/dist/clients/attach/session/connection.js +1 -1
- package/dist/clients/attach/session/reconnect.js +1 -1
- package/dist/clients/attach/viewer.js +508 -508
- package/dist/commands/node/message.js +1 -1
- package/dist/commands/sys/join.js +1 -1
- package/dist/core/async-array.d.ts +7 -0
- package/dist/core/async-array.js +1 -0
- package/dist/core/audit.d.ts +1 -1
- package/dist/core/audit.js +2 -2
- package/dist/core/canvas/attention.d.ts +4 -4
- package/dist/core/canvas/attention.js +1 -1
- package/dist/core/canvas/boot.d.ts +4 -4
- package/dist/core/canvas/boot.js +1 -1
- package/dist/core/canvas/canvas.d.ts +59 -59
- package/dist/core/canvas/canvas.js +19 -19
- package/dist/core/canvas/context-strip.js +2 -2
- package/dist/core/canvas/crons.d.ts +27 -27
- package/dist/core/canvas/crons.js +11 -11
- package/dist/core/canvas/daemon-actions.d.ts +10 -10
- package/dist/core/canvas/daemon-actions.js +8 -8
- package/dist/core/canvas/daemon-owner.d.ts +3 -3
- package/dist/core/canvas/daemon-owner.js +2 -2
- package/dist/core/canvas/db.d.ts +19 -30
- package/dist/core/canvas/db.js +3 -2
- package/dist/core/canvas/deliveries.d.ts +16 -16
- package/dist/core/canvas/deliveries.js +24 -24
- package/dist/core/canvas/executions.d.ts +8 -8
- package/dist/core/canvas/executions.js +1 -1
- package/dist/core/canvas/focuses.d.ts +8 -8
- package/dist/core/canvas/focuses.js +1 -1
- package/dist/core/canvas/history.d.ts +3 -3
- package/dist/core/canvas/history.js +9 -9
- package/dist/core/canvas/install-id.d.ts +1 -1
- package/dist/core/canvas/install-id.js +1 -1
- package/dist/core/canvas/managed-worktree-sweep-candidates.d.ts +1 -1
- package/dist/core/canvas/managed-worktree-sweep-candidates.js +2 -2
- package/dist/core/canvas/memory-reads.d.ts +6 -6
- package/dist/core/canvas/memory-reads.js +1 -1
- package/dist/core/canvas/nav-model.d.ts +13 -13
- package/dist/core/canvas/nav-model.js +1 -1
- package/dist/core/canvas/node-agent-paths.d.ts +6 -6
- package/dist/core/canvas/node-agent-paths.js +1 -1
- package/dist/core/canvas/node-tokens.d.ts +7 -7
- package/dist/core/canvas/node-tokens.js +3 -3
- package/dist/core/canvas/outcome-actions.d.ts +5 -5
- package/dist/core/canvas/outcome-actions.js +3 -3
- package/dist/core/canvas/recovery.d.ts +26 -26
- package/dist/core/canvas/recovery.js +2 -2
- package/dist/core/canvas/render-source.d.ts +1 -1
- package/dist/core/canvas/render-source.js +1 -1
- package/dist/core/canvas/sessions.d.ts +10 -10
- package/dist/core/canvas/sessions.js +4 -4
- package/dist/core/canvas/source.js +1 -1
- package/dist/core/canvas/structured-requests.d.ts +15 -15
- package/dist/core/canvas/structured-requests.js +5 -5
- package/dist/core/canvas/tree.d.ts +9 -9
- package/dist/core/canvas/tree.js +5 -5
- package/dist/core/canvas/waits.d.ts +13 -13
- package/dist/core/canvas/waits.js +6 -6
- package/dist/core/canvas/worktrees.d.ts +15 -15
- package/dist/core/canvas/worktrees.js +1 -1
- package/dist/core/command-hooks/lifecycle-catalog.d.ts +4 -4
- package/dist/core/command-hooks/lifecycle-catalog.js +1 -1
- package/dist/core/command-hooks/transport/exec-lifecycle.js +1 -1
- package/dist/core/command-plugins/bundle.d.ts +1 -1
- package/dist/core/command-plugins/bundle.js +1 -1
- package/dist/core/conversation-store/file-store.d.ts +7 -7
- package/dist/core/conversation-store/file-store.js +9 -9
- package/dist/core/conversation-store/index.d.ts +16 -14
- package/dist/core/conversation-store/index.js +1 -1
- package/dist/core/conversation-store/listener.js +5 -5
- package/dist/core/conversation-store/patch.d.ts +3 -1
- package/dist/core/conversation-store/patch.js +1 -1
- package/dist/core/directory/join.d.ts +1 -1
- package/dist/core/feed/feed.js +3 -3
- package/dist/core/feed/inbox.d.ts +2 -2
- package/dist/core/feed/inbox.js +1 -1
- package/dist/core/feed/messages.d.ts +11 -12
- package/dist/core/feed/messages.js +5 -5
- package/dist/core/feed/reports.d.ts +4 -4
- package/dist/core/feed/reports.js +2 -2
- package/dist/core/grants/cover.d.ts +1 -1
- package/dist/core/grants/cover.js +1 -1
- package/dist/core/grants/local.d.ts +1 -1
- package/dist/core/grants/local.js +1 -1
- package/dist/core/grants/mirror.d.ts +19 -19
- package/dist/core/grants/mirror.js +2 -2
- package/dist/core/grants/on-sync.d.ts +1 -1
- package/dist/core/grants/on-sync.js +1 -1
- package/dist/core/grants/remove.js +1 -1
- package/dist/core/grants/sync.js +1 -1
- package/dist/core/graph/access.d.ts +17 -17
- package/dist/core/graph/access.js +3 -3
- package/dist/core/graph/custom.d.ts +16 -16
- package/dist/core/graph/custom.js +9 -9
- package/dist/core/graph/deletion.d.ts +3 -7
- package/dist/core/graph/deletion.js +4 -4
- package/dist/core/graph/documents.d.ts +24 -27
- package/dist/core/graph/documents.js +7 -7
- package/dist/core/graph/edges.d.ts +13 -13
- package/dist/core/graph/edges.js +1 -1
- package/dist/core/graph/events.d.ts +7 -9
- package/dist/core/graph/events.js +8 -8
- package/dist/core/graph/exposures.d.ts +6 -6
- package/dist/core/graph/exposures.js +4 -4
- package/dist/core/graph/jobs.d.ts +6 -8
- package/dist/core/graph/jobs.js +2 -2
- package/dist/core/graph/kinds/action.js +1 -1
- package/dist/core/graph/kinds/custom.js +2 -2
- package/dist/core/graph/kinds/document.d.ts +1 -0
- package/dist/core/graph/kinds/document.js +4 -4
- package/dist/core/graph/kinds/dto.d.ts +2 -2
- 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 +6 -8
- package/dist/core/graph/kinds/kind.js +1 -1
- package/dist/core/graph/kinds/node.js +5 -5
- package/dist/core/graph/kinds/owner.js +2 -2
- package/dist/core/graph/kinds/registry.d.ts +6 -9
- package/dist/core/graph/kinds/registry.js +1 -1
- package/dist/core/graph/names.d.ts +6 -6
- package/dist/core/graph/names.js +3 -3
- package/dist/core/graph/object-waits.d.ts +4 -7
- package/dist/core/graph/object-waits.js +1 -1
- package/dist/core/graph/objects.d.ts +14 -14
- package/dist/core/graph/objects.js +9 -9
- package/dist/core/graph/package-docs.d.ts +2 -7
- package/dist/core/graph/package-docs.js +5 -5
- package/dist/core/graph/package-kinds.d.ts +2 -5
- package/dist/core/graph/package-kinds.js +1 -1
- package/dist/core/graph/package-reconcile.d.ts +2 -5
- package/dist/core/graph/package-reconcile.js +1 -1
- package/dist/core/graph/reader.d.ts +18 -18
- package/dist/core/graph/reader.js +3 -3
- package/dist/core/graph/receivers.d.ts +4 -4
- package/dist/core/graph/receivers.js +5 -5
- package/dist/core/graph/repo-sync/exchange.d.ts +3 -7
- package/dist/core/graph/repo-sync/exchange.js +2 -2
- package/dist/core/graph/repo-sync/repos.d.ts +7 -5
- package/dist/core/graph/repo-sync/repos.js +3 -3
- package/dist/core/graph/repo-sync/sync.d.ts +3 -6
- package/dist/core/graph/repo-sync/sync.js +2 -2
- package/dist/core/graph/rules.d.ts +5 -5
- 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 +4 -5
- package/dist/core/graph/spaces/index.js +1 -1
- package/dist/core/graph/spaces/own-memory.d.ts +4 -4
- 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/watches.d.ts +15 -15
- package/dist/core/graph/watches.js +10 -10
- package/dist/core/human/feedback-companion.d.ts +2 -2
- package/dist/core/human/feedback-companion.js +1 -1
- package/dist/core/human/feedback.d.ts +3 -3
- package/dist/core/human/feedback.js +1 -1
- package/dist/core/human/requests.d.ts +34 -33
- package/dist/core/human/requests.js +20 -20
- package/dist/core/human/scan.d.ts +2 -2
- package/dist/core/human/scan.js +1 -1
- package/dist/core/human/tickets.d.ts +9 -9
- package/dist/core/human/tickets.js +1 -1
- package/dist/core/llm/app-rungs.d.ts +1 -1
- package/dist/core/llm/app-rungs.js +1 -1
- package/dist/core/llm/run.js +1 -1
- package/dist/core/peer/directory.d.ts +1 -1
- package/dist/core/peer/directory.js +1 -1
- package/dist/core/peer/envelope.d.ts +3 -3
- package/dist/core/peer/envelope.js +1 -1
- package/dist/core/peer/home.d.ts +7 -7
- package/dist/core/peer/home.js +2 -2
- package/dist/core/peer/ingest.d.ts +6 -6
- package/dist/core/peer/ingest.js +1 -1
- package/dist/core/peer/outbox-store.d.ts +14 -14
- package/dist/core/peer/outbox-store.js +5 -5
- package/dist/core/peer/receiver.d.ts +2 -2
- package/dist/core/peer/receiver.js +1 -1
- package/dist/core/peer/stubs.d.ts +10 -10
- package/dist/core/peer/stubs.js +1 -1
- package/dist/core/providers/approval.d.ts +2 -2
- package/dist/core/providers/approval.js +2 -2
- package/dist/core/providers/audit.d.ts +3 -3
- package/dist/core/providers/audit.js +2 -2
- package/dist/core/providers/bundles.js +2 -2
- package/dist/core/providers/call.d.ts +2 -2
- package/dist/core/providers/call.js +1 -1
- package/dist/core/providers/files.d.ts +1 -1
- package/dist/core/providers/files.js +1 -1
- package/dist/core/providers/mint.js +1 -1
- package/dist/core/providers/receipts.d.ts +1 -1
- package/dist/core/providers/receipts.js +2 -2
- package/dist/core/review/birth.js +1 -1
- package/dist/core/review/comments.d.ts +19 -19
- package/dist/core/review/comments.js +5 -5
- package/dist/core/review/companion.d.ts +1 -1
- package/dist/core/review/companion.js +1 -1
- package/dist/core/review/document.d.ts +3 -3
- package/dist/core/review/document.js +2 -2
- package/dist/core/review/fork.js +2 -2
- package/dist/core/review/realize.js +1 -1
- package/dist/core/review/remap.d.ts +2 -2
- package/dist/core/review/remap.js +4 -4
- package/dist/core/review/stage.d.ts +1 -1
- package/dist/core/review/stage.js +1 -1
- package/dist/core/review/store.d.ts +21 -21
- package/dist/core/review/store.js +1 -1
- package/dist/core/runs/activity.d.ts +1 -1
- package/dist/core/runs/activity.js +5 -5
- package/dist/core/runs/confinement.d.ts +7 -7
- package/dist/core/runs/confinement.js +2 -2
- package/dist/core/runs/events.d.ts +12 -12
- package/dist/core/runs/events.js +4 -4
- package/dist/core/runs/operations.d.ts +11 -11
- package/dist/core/runs/operations.js +5 -5
- package/dist/core/runs/questions.d.ts +10 -10
- package/dist/core/runs/questions.js +3 -3
- package/dist/core/runtime/auth-reload.js +1 -1
- package/dist/core/runtime/bearings.d.ts +5 -5
- package/dist/core/runtime/bearings.js +6 -6
- package/dist/core/runtime/broker-inventory.js +1 -1
- package/dist/core/runtime/broker-request.js +1 -1
- package/dist/core/runtime/broker.js +1 -1
- package/dist/core/runtime/close.d.ts +3 -3
- package/dist/core/runtime/close.js +1 -1
- package/dist/core/runtime/deliver-live.js +1 -1
- package/dist/core/runtime/fleet.d.ts +2 -2
- package/dist/core/runtime/host.d.ts +3 -3
- package/dist/core/runtime/host.js +3 -3
- package/dist/core/runtime/kickoff.d.ts +12 -12
- package/dist/core/runtime/kickoff.js +17 -17
- package/dist/core/runtime/launch-target.d.ts +1 -1
- package/dist/core/runtime/launch-target.js +1 -1
- package/dist/core/runtime/ledger.d.ts +3 -3
- package/dist/core/runtime/ledger.js +3 -3
- package/dist/core/runtime/lifecycle.d.ts +1 -1
- package/dist/core/runtime/lifecycle.js +2 -2
- package/dist/core/runtime/memory-admission.js +1 -1
- package/dist/core/runtime/model-swap.d.ts +2 -2
- package/dist/core/runtime/model-swap.js +1 -1
- package/dist/core/runtime/node-read.d.ts +1 -1
- package/dist/core/runtime/node-read.js +2 -2
- package/dist/core/runtime/nodes.d.ts +6 -6
- package/dist/core/runtime/nodes.js +1 -1
- package/dist/core/runtime/outcome-document.d.ts +1 -1
- package/dist/core/runtime/outcome-document.js +1 -1
- package/dist/core/runtime/persona.d.ts +3 -3
- package/dist/core/runtime/persona.js +2 -2
- package/dist/core/runtime/placement.d.ts +11 -11
- package/dist/core/runtime/placement.js +1 -1
- package/dist/core/runtime/promote.d.ts +3 -3
- package/dist/core/runtime/promote.js +1 -1
- package/dist/core/runtime/recycle.js +1 -1
- package/dist/core/runtime/reopen.d.ts +21 -10
- package/dist/core/runtime/reopen.js +1 -1
- package/dist/core/runtime/reset.d.ts +4 -4
- package/dist/core/runtime/reset.js +1 -1
- package/dist/core/runtime/revive-all.d.ts +2 -2
- package/dist/core/runtime/revive-all.js +1 -1
- package/dist/core/runtime/revive.d.ts +4 -4
- package/dist/core/runtime/revive.js +2 -2
- package/dist/core/runtime/roadmap.d.ts +6 -6
- package/dist/core/runtime/roadmap.js +5 -5
- package/dist/core/runtime/session-branch.d.ts +1 -1
- package/dist/core/runtime/session-branch.js +1 -1
- package/dist/core/runtime/session-list-cache.js +1 -1
- package/dist/core/runtime/situational-live.js +1 -1
- package/dist/core/runtime/spawn.d.ts +2 -2
- package/dist/core/runtime/spawn.js +2 -2
- package/dist/core/runtime/stop-guard.d.ts +2 -2
- package/dist/core/runtime/stop-guard.js +3 -3
- package/dist/core/runtime/warm-pool.d.ts +2 -2
- package/dist/core/runtime/warm-pool.js +1 -1
- package/dist/core/spaces/mounts.d.ts +2 -2
- package/dist/core/spaces/mounts.js +1 -1
- package/dist/core/spaces/permissions.d.ts +1 -1
- package/dist/core/spaces/permissions.js +1 -1
- package/dist/core/spaces/process.d.ts +1 -1
- package/dist/core/spaces/process.js +1 -1
- package/dist/core/spaces/space.js +1 -1
- package/dist/core/spaces/stop.d.ts +3 -3
- package/dist/core/spaces/stop.js +2 -2
- package/dist/core/spaces/users.d.ts +6 -6
- package/dist/core/spaces/users.js +1 -1
- package/dist/core/storage/attachments.d.ts +2 -2
- package/dist/core/storage/attachments.js +1 -1
- package/dist/core/storage/shares.d.ts +2 -2
- package/dist/core/storage/shares.js +1 -1
- package/dist/core/storage/tables.d.ts +21 -21
- package/dist/core/storage/tables.js +3 -3
- package/dist/core/substrate/delivery/corpus.d.ts +5 -8
- package/dist/core/substrate/delivery/corpus.js +3 -3
- package/dist/core/substrate/delivery/deliver.d.ts +10 -15
- package/dist/core/substrate/delivery/deliver.js +3 -3
- package/dist/core/substrate/delivery/plan.d.ts +2 -12
- package/dist/core/substrate/delivery/plan.js +3 -3
- package/dist/core/substrate/delivery/render-boot.d.ts +4 -4
- package/dist/core/substrate/delivery/render-boot.js +18 -18
- package/dist/core/substrate/delivery/render-event.d.ts +7 -14
- package/dist/core/substrate/delivery/render-event.js +4 -4
- package/dist/core/substrate/subject.d.ts +2 -2
- package/dist/core/substrate/subject.js +1 -1
- package/dist/core/usage/ledger.d.ts +6 -6
- package/dist/core/usage/ledger.js +4 -4
- package/dist/core/worktree-close.js +4 -4
- package/dist/core/worktree-mutation-async.js +7 -7
- package/dist/core/worktree-quarantine.js +1 -1
- package/dist/core/worktree-sweep.d.ts +1 -1
- package/dist/core/worktree-sweep.js +6 -6
- package/dist/core/worktree.d.ts +5 -5
- package/dist/core/worktree.js +13 -13
- package/dist/daemon/analytics/compute.d.ts +2 -2
- package/dist/daemon/analytics/compute.js +1 -1
- package/dist/daemon/api/app-listener.d.ts +4 -4
- package/dist/daemon/api/app-listener.js +13 -13
- package/dist/daemon/api/bridge.js +5 -5
- package/dist/daemon/api/document-listener.js +6 -6
- package/dist/daemon/api/handlers/analytics.js +1 -1
- package/dist/daemon/api/handlers/attach.js +1 -1
- package/dist/daemon/api/handlers/bash-jobs.js +1 -1
- package/dist/daemon/api/handlers/bash.js +1 -1
- package/dist/daemon/api/handlers/broker-ops.d.ts +1 -1
- package/dist/daemon/api/handlers/broker-ops.js +1 -1
- package/dist/daemon/api/handlers/broker-recovery.d.ts +1 -1
- package/dist/daemon/api/handlers/broker-recovery.js +1 -1
- package/dist/daemon/api/handlers/broker-signals.d.ts +2 -2
- package/dist/daemon/api/handlers/broker-signals.js +2 -2
- package/dist/daemon/api/handlers/canvas.d.ts +1 -1
- package/dist/daemon/api/handlers/canvas.js +4 -4
- package/dist/daemon/api/handlers/chat-inventory.js +1 -1
- package/dist/daemon/api/handlers/crons.js +1 -1
- package/dist/daemon/api/handlers/custom-objects.d.ts +4 -4
- package/dist/daemon/api/handlers/custom-objects.js +3 -3
- package/dist/daemon/api/handlers/delivery-retry.js +1 -1
- package/dist/daemon/api/handlers/delivery.js +1 -1
- package/dist/daemon/api/handlers/docs.d.ts +4 -4
- package/dist/daemon/api/handlers/docs.js +1 -1
- package/dist/daemon/api/handlers/feedback-comments.js +3 -3
- package/dist/daemon/api/handlers/files.js +1 -1
- package/dist/daemon/api/handlers/focus.js +1 -1
- package/dist/daemon/api/handlers/health.js +3 -3
- package/dist/daemon/api/handlers/hook-exec.js +1 -1
- package/dist/daemon/api/handlers/human-requests.js +1 -1
- package/dist/daemon/api/handlers/inbox-page.d.ts +1 -1
- package/dist/daemon/api/handlers/inbox-page.js +1 -1
- package/dist/daemon/api/handlers/inbox.d.ts +1 -1
- package/dist/daemon/api/handlers/inbox.js +1 -1
- package/dist/daemon/api/handlers/llm.d.ts +1 -1
- package/dist/daemon/api/handlers/llm.js +3 -3
- package/dist/daemon/api/handlers/memory-reads.js +1 -1
- package/dist/daemon/api/handlers/memory.d.ts +5 -5
- package/dist/daemon/api/handlers/memory.js +5 -5
- package/dist/daemon/api/handlers/messages.js +2 -2
- package/dist/daemon/api/handlers/node-events.d.ts +2 -2
- package/dist/daemon/api/handlers/node-events.js +3 -3
- package/dist/daemon/api/handlers/node-outcomes.js +1 -1
- package/dist/daemon/api/handlers/node-records.js +2 -2
- package/dist/daemon/api/handlers/nodes.d.ts +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/package-docs.js +1 -1
- package/dist/daemon/api/handlers/plugin-app-token.d.ts +1 -1
- package/dist/daemon/api/handlers/plugin-app-token.js +1 -1
- package/dist/daemon/api/handlers/profiles.d.ts +3 -3
- package/dist/daemon/api/handlers/profiles.js +1 -1
- package/dist/daemon/api/handlers/providers.d.ts +1 -1
- package/dist/daemon/api/handlers/providers.js +1 -1
- package/dist/daemon/api/handlers/questions.js +1 -1
- package/dist/daemon/api/handlers/reports.d.ts +1 -1
- package/dist/daemon/api/handlers/reports.js +5 -5
- package/dist/daemon/api/handlers/review-comments.js +1 -1
- package/dist/daemon/api/handlers/reviews.js +1 -1
- package/dist/daemon/api/handlers/runs.js +1 -1
- package/dist/daemon/api/handlers/structured-requests.js +1 -1
- package/dist/daemon/api/handlers/subscriptions.js +1 -1
- package/dist/daemon/api/handlers/transfer.js +1 -1
- package/dist/daemon/api/map.d.ts +3 -3
- package/dist/daemon/api/map.js +1 -1
- package/dist/daemon/api/principal.d.ts +1 -1
- package/dist/daemon/api/principal.js +1 -1
- package/dist/daemon/api/reader.d.ts +5 -5
- package/dist/daemon/api/reader.js +1 -1
- package/dist/daemon/api/router.d.ts +5 -5
- package/dist/daemon/api/router.js +1 -1
- package/dist/daemon/api/server.js +1 -1
- package/dist/daemon/broker-signals/bus.d.ts +1 -1
- package/dist/daemon/broker-signals/bus.js +1 -1
- package/dist/daemon/companion-retire.js +1 -1
- package/dist/daemon/cron/armed-context.d.ts +2 -2
- package/dist/daemon/cron/armed-context.js +1 -1
- package/dist/daemon/cron/authority.d.ts +2 -2
- package/dist/daemon/cron/authority.js +1 -1
- package/dist/daemon/cron/disposition.js +1 -1
- package/dist/daemon/cron/ended.d.ts +1 -1
- package/dist/daemon/cron/ended.js +2 -2
- package/dist/daemon/cron/escalation.js +3 -3
- package/dist/daemon/cron/folders.d.ts +1 -1
- package/dist/daemon/cron/folders.js +1 -1
- package/dist/daemon/cron/held.d.ts +1 -1
- package/dist/daemon/cron/held.js +1 -1
- package/dist/daemon/cron/lease-recovery.d.ts +1 -1
- package/dist/daemon/cron/lease-recovery.js +1 -1
- package/dist/daemon/cron/passes.d.ts +2 -2
- package/dist/daemon/cron/passes.js +1 -1
- package/dist/daemon/cron/run-socket.d.ts +1 -1
- package/dist/daemon/cron/run-socket.js +1 -1
- package/dist/daemon/cron/settle.js +1 -1
- package/dist/daemon/cron/sinks.d.ts +1 -1
- package/dist/daemon/cron/sinks.js +2 -2
- package/dist/daemon/cron-run.d.ts +12 -3
- package/dist/daemon/cron-run.js +2 -2
- package/dist/daemon/crtrd.js +6 -6
- package/dist/daemon/delivery/run-delivery.js +1 -1
- package/dist/daemon/due-sources.d.ts +3 -3
- package/dist/daemon/due-sources.js +1 -1
- package/dist/daemon/due.d.ts +3 -3
- package/dist/daemon/due.js +7 -7
- package/dist/daemon/fleet.d.ts +2 -2
- package/dist/daemon/fleet.js +11 -11
- package/dist/daemon/human/finish.js +3 -3
- package/dist/daemon/human/settle.d.ts +1 -1
- package/dist/daemon/human/settle.js +1 -1
- package/dist/daemon/human/sweep.js +1 -1
- package/dist/daemon/joined-owner.d.ts +3 -3
- package/dist/daemon/joined-owner.js +1 -1
- package/dist/daemon/messaging/node-message.js +1 -1
- package/dist/daemon/park-activity.d.ts +2 -2
- package/dist/daemon/park-activity.js +1 -1
- package/dist/daemon/peer/authority.js +1 -1
- package/dist/daemon/peer/forward.d.ts +6 -6
- package/dist/daemon/peer/forward.js +1 -1
- package/dist/daemon/peer/handlers.js +1 -1
- package/dist/daemon/peer/ingress.d.ts +4 -4
- package/dist/daemon/peer/ingress.js +1 -1
- package/dist/daemon/peer/outbox.d.ts +2 -2
- package/dist/daemon/peer/outbox.js +1 -1
- package/dist/daemon/peer/relay-service.js +1 -1
- package/dist/daemon/plugin-objects/read-leaf.d.ts +2 -2
- package/dist/daemon/plugin-objects/read-leaf.js +2 -2
- package/dist/daemon/profile-delete.js +1 -1
- package/dist/daemon/readiness.d.ts +2 -2
- package/dist/daemon/readiness.js +1 -1
- package/dist/daemon/reconcilers/action-lane.d.ts +1 -1
- package/dist/daemon/reconcilers/action-lane.js +1 -1
- package/dist/daemon/reconcilers/bash-deadline.js +2 -2
- package/dist/daemon/reconcilers/broker-supervision.d.ts +1 -1
- package/dist/daemon/reconcilers/broker-supervision.js +4 -4
- package/dist/daemon/reconcilers/controller-death.d.ts +1 -1
- package/dist/daemon/reconcilers/controller-death.js +1 -1
- package/dist/daemon/reconcilers/cron-lane.d.ts +1 -1
- package/dist/daemon/reconcilers/cron-lane.js +1 -1
- package/dist/daemon/reconcilers/delivery-lane.d.ts +1 -1
- package/dist/daemon/reconcilers/delivery-lane.js +2 -2
- package/dist/daemon/reconcilers/fault-retry-backstop.d.ts +3 -3
- package/dist/daemon/reconcilers/fault-retry-backstop.js +1 -1
- package/dist/daemon/reconcilers/grove-instance-sweep.d.ts +2 -2
- package/dist/daemon/reconcilers/grove-instance-sweep.js +1 -1
- package/dist/daemon/reconcilers/live-obligation.d.ts +6 -6
- package/dist/daemon/reconcilers/live-obligation.js +1 -1
- package/dist/daemon/reconcilers/managed-worktree-sweep.js +1 -1
- package/dist/daemon/reconcilers/node-deadline.d.ts +1 -1
- package/dist/daemon/reconcilers/node-deadline.js +1 -1
- package/dist/daemon/reconcilers/node-lifecycle/freeze-lane.js +1 -1
- package/dist/daemon/reconcilers/node-lifecycle/respawn-policy.d.ts +3 -3
- package/dist/daemon/reconcilers/node-lifecycle/respawn-policy.js +1 -1
- package/dist/daemon/reconcilers/node-lifecycle/terminating.js +1 -1
- package/dist/daemon/reconcilers/node-lifecycle/tick.js +1 -1
- package/dist/daemon/reconcilers/node-lifecycle/wants-execution.d.ts +1 -1
- package/dist/daemon/reconcilers/node-lifecycle/wants-execution.js +1 -1
- package/dist/daemon/reconcilers/pending-review-submit.d.ts +1 -1
- package/dist/daemon/reconcilers/pending-review-submit.js +1 -1
- package/dist/daemon/reconcilers/storage-due-work.js +1 -1
- package/dist/daemon/reconcilers/storage-maintenance.d.ts +1 -1
- package/dist/daemon/reconcilers/storage-maintenance.js +2 -2
- package/dist/daemon/reconcilers/structured-request-lane.d.ts +1 -1
- package/dist/daemon/reconcilers/structured-request-lane.js +1 -1
- package/dist/daemon/review/comment-notify.js +2 -2
- package/dist/daemon/review/companion.d.ts +3 -3
- package/dist/daemon/review/companion.js +1 -1
- package/dist/daemon/review/finish.js +1 -1
- package/dist/daemon/review/sweep.js +1 -1
- package/dist/daemon/run-notices.d.ts +4 -4
- package/dist/daemon/run-notices.js +1 -1
- package/dist/daemon/runs/append-section.d.ts +2 -2
- package/dist/daemon/runs/append-section.js +2 -2
- package/dist/daemon/runs/observer.d.ts +2 -2
- package/dist/daemon/runs/observer.js +2 -2
- package/dist/daemon/structured-requests/boot.d.ts +1 -1
- package/dist/daemon/structured-requests/boot.js +1 -1
- package/dist/daemon/structured-requests/effects.js +1 -1
- package/dist/daemon/structured-requests/sidecar.d.ts +1 -1
- package/dist/daemon/structured-requests/sidecar.js +1 -1
- package/dist/launcher/run.js +1 -1
- package/dist/migrations/004-canvas-documents/apply.d.ts +3 -3
- package/dist/migrations/004-canvas-documents/apply.js +1 -1
- package/dist/migrations/004-canvas-documents/index.d.ts +2 -2
- package/dist/migrations/004-canvas-documents/index.js +2 -2
- package/dist/migrations/activation.js +2 -2
- package/docs/plugin/bundles-and-memory.md +1 -1
- package/docs/plugin/commands.md +1 -1
- package/docs/public-api.md +11 -0
- package/package.json +4 -3
- package/packages/crouter-identity/package.json +1 -1
- package/runtime.lock.json +12 -12
|
@@ -1 +1 @@
|
|
|
1
|
-
var W=Object.defineProperty;var a=(e,t)=>W(e,"name",{value:t,configurable:!0});import{toErrorBody as j}from"./map.js";import{emitEvent as p}from"../../core/events/emit.js";import{scopeAllowed as f,ScopeDeniedError as N}from"../../core/scopes.js";import{coveredByAny as J}from"../../shared/env.js";import{ApiError as c}from"../../api/errors.js";import{activeGrant as B,grantFor as x}from"../../core/grants/mirror.js";import{getNode as _}from"../../core/canvas/canvas.js";import{ownedRun as z,RunError as g}from"../../core/runs/operations.js";import{nodeMayReach as H,placeMayReach as S}from"../../core/runs/confinement.js";import{checkCronFire as M}from"../cron/authority.js";import{readConfig as P}from"../../core/config.js";import{SCOPE_VOCABULARY as I}from"../../core/scopes.js";import{operationFor as L}from"./operations.js";import{CONTROL_BODY_MAX_BYTES as F}from"../../core/llm/body-limits.js";import{getRequest as Y,getRequestByInboxTicket as V}from"../../core/human/requests.js";import{requireVisibleReview as R}from"../../core/review/store.js";import{getComment as O}from"../../core/review/comments.js";function D(e,t,o,s,n){const r=e.path,u=n&&typeof n=="object"&&!Array.isArray(n)?n:{};if(r==="/v1/human/requests"||r==="/v1/human/reviews"){const d=r.endsWith("/reviews")?u.origin_node_id:u.requester_node_id,m=r==="/v1/human/requests"&&d==null;if(d!==t.node&&!m)throw new c(403,"other_app_run","a broker may create a human request only for its own node");const h=u.source;if(h&&typeof h=="object"&&"nodeId"in h&&h.nodeId!==t.node)throw new c(403,"other_app_run","request source must name the calling node")}if(r==="/v1/human/reviews/self/comments"&&e.method==="GET"&&s.get("actor_node_id")!==t.node)throw new c(403,"other_app_run","self review requires the calling node");if(r.includes("/comments")&&e.method!=="GET"&&u.actor_node_id!==t.node)throw new c(403,"other_app_run","comment author must be the calling node");if(o.comment_id&&!O(o.comment_id))throw new c(404,"not_found","comment not found")}a(D,"authorizeHumanBody");function y(e){return e.class==="broker"||e.class==="cron"}a(y,"boundedByStoredScopes");function b(e){return e.class==="person"||e.class==="anonymous"||e.class==="machine"?null:e.class==="forwarded"?e.actor.kind==="app"?e.actor.app:null:e.app}a(b,"appOf");function q(e){return e.class==="person"||e.class==="forwarded"&&e.actor.kind==="person"}a(q,"actsAsPerson");function $(e){const t=x(e.actor.app,e.sub);if(!t)throw new c(403,"app_not_granted",`${e.actor.app} holds no active grant for ${e.sub} on this machine`);return t}a($,"forwardedGrant");function v(e){if(e.class==="person"||e.class==="anonymous"||e.class==="machine")return[];if(e.class==="forwarded"){if(e.actor.kind==="person")return[];const{resolved:o}=$(e),s=e.actor.node_scopes;return s===null?o:s.filter(n=>J(o,n))}if(e.class==="app")return e.scopes;if(e.class==="cron"){const o=M({grantee:e.app,sub:e.sub,grant_id:e.grant,scopes:e.scopes});if(o.allowed)return o.effectiveScopes;throw o.reason==="grant_missing"||o.reason==="grant_revoked"?new c(401,"grant_revoked",o.message):new c(403,"scope_missing",o.message)}const t=e.grant?B(e.grant):x(e.app,e.sub);if(t&&t.grantee===e.app&&t.sub===e.sub)return t.resolved;if(e.app==="app:terminal"&&!P("user").runtime?.issuer)return I;throw new c(401,"grant_revoked","the node grant is not active")}a(v,"resolvedScopes");function k(e){return"class"in e?b(e):e.grantee}a(k,"runCallerApp");function l(e,t,o){return t===void 0||!("class"in e)?!0:e.class==="cron"?S({run:e.origin_run??"",isolated:e.isolated},e.app,t,o):e.class==="forwarded"?e.actor.kind!=="app"||S(e.actor.place,e.actor.app,t,o):e.class!=="broker"?!0:H(e.node,e.app,t,o)}a(l,"brokerMayReach");function X(e,t,o){const s=k(e);if(s===t)return l(e,o,t);if(s===null)return!0;const n="class"in e?null:B(e.grant),r="class"in e?v(e):n?.sub===e.sub&&n.grantee===e.grantee?n.resolved:[];return f(r,`crtr:conversations:read:${t}`)&&(!("class"in e)||!y(e)||f(e.scopes,`crtr:conversations:read:${t}`))}a(X,"canReadRun");function Be(e,t,o=!1,s=!1){const n=_(t);if(!n||n.parent!==null||n.run_id!==t||!n.grantee||n.deleting_at&&!s)throw new g(404,"not_found","run not found");if(!X(e,n.grantee,t))throw new g(404,"not_found","run not found");if(o&&k(e)!==null&&k(e)!==n.grantee)throw new g(403,"other_app_run","cannot change another app's run");return z(t,n.grantee,s)}a(Be,"requireRun");function C(e,t,o){return q(e)?!0:e.class==="anonymous"||e.class==="machine"?!1:b(e)===t?l(e,o,t):f(v(e),`crtr:objects:read:${t}`)&&(!y(e)||f(e.scopes,`crtr:objects:read:${t}`))}a(C,"canReadNode");const K=new Set(["messages.post.58","messages.post.59"]);function Q(e,t,o){if(!e.classes.includes(t.class)&&!(t.class!=="anonymous"&&t.class!=="machine"&&t.class!=="forwarded"&&e.classes.includes("anonymous")))throw new c(403,"permission_error","this operation is not available to the caller");if(t.class==="forwarded"&&t.actor.kind==="app"&&$(t),t.class==="person"||t.class==="anonymous"||t.class==="machine"||q(t))return;const s=v(t);if(e.scope&&(!f(s,e.scope)||y(t)&&!f(t.scopes,e.scope)))throw new c(403,"scope_missing",`missing scope ${e.scope}`);if(t.class==="app")return;const n=b(t);t.class==="broker"&&Z(e,t,o,s);const r=o.id;if((e.resource==="node-read"||e.resource==="node-write")&&r!==void 0){const u=_(r);if(!u)return;if(e.resource==="node-write"&&u.grantee!==n&&!(K.has(e.name)&&f(s,`crtr:objects:message:${u.grantee??"app:terminal"}`)))throw new c(403,"other_app_run","cannot change another app's node");if(e.resource==="node-write"&&!l(t,r,u.grantee??"app:terminal"))throw new c(404,"not_found","node not found");if(e.resource==="node-read"&&!C(t,u.grantee??"app:terminal",r))throw new c(404,"not_found","node not found")}}a(Q,"authorizeOperation");function Z(e,t,o,s){if(e.resource==="daemon-bash"&&(!f(s,"crtr:files:rw:user:.")||!f(t.scopes,"crtr:files:rw:user:.")))throw new c(403,"scope_missing","missing scope crtr:files:rw:user:.");if(e.resource==="human"){const r=e.path,u=e.method==="GET";if(!u&&(r.endsWith("/respond")||r.endsWith("/submit")||r.endsWith("/dismiss")||r.endsWith("/progress")||r.endsWith("/comment-ranges")||r.includes("/feedback-comments")))throw new c(403,"permission_error","only the person may answer or edit the human inbox");const d=o.request_id?Y(o.request_id):o.ticket_id?V(o.ticket_id):null,m=o.comment_id?O(o.comment_id):null,h=o.review_id?R(o.review_id):m?R(m.review_id):null,w=d?.requester_node_id??h?.origin_node_id;if(w!=null){const i=_(w);if(i&&(u?!C(t,i.grantee??"app:terminal",w):i.grantee!==t.app))throw new c(u?404:403,u?"not_found":"other_app_run","human request belongs to another app");if(i&&!u&&!l(t,w,i.grantee??"app:terminal"))throw new c(404,"not_found","human request not found")}else if(d||h)throw new c(403,"permission_error","only the person may access a request without a node")}const n=o.id;if(e.resource==="node-own"&&n!==void 0&&n!==t.node)throw new c(403,"other_app_run","the operation requires the calling node")}a(Z,"authorizeBrokerOnly");function ee(e,t){if(!f(e,t))throw new N("the bearer token",t)}a(ee,"assertCeiling");function te(){return new c(403,"owner_only","this operation is owner-only; a scoped token does not reach it")}a(te,"ownerOnlyError");function xe(e){return e.map(t=>({...t,ownerOnly:!0}))}a(xe,"ownerOnly");class Se{static{a(this,"Router")}routes=[];register(t){const o=L(t.method,t.pattern);if(!o)throw new Error(`route has no operation row: ${t.method} ${t.pattern}`);if(this.routes.some(s=>s.method===t.method.toUpperCase()&&s.operation.path===t.pattern))throw new Error(`duplicate route: ${t.method} ${t.pattern}`);return this.routes.push({operation:o,method:t.method.toUpperCase(),segments:A(t.pattern),handler:t.handler,maxBodyBytes:t.maxBodyBytes??F}),this}registerAll(t){for(const o of t)this.register(o);return this}match(t,o){const s=t.toUpperCase(),n=A(o);for(const r of this.routes){if(r.method!==s)continue;const u=oe(r.segments,n);if(u!==null)return{handler:r.handler,params:u,operation:r.operation,maxBodyBytes:r.maxBodyBytes}}return null}async handle(t,o,s,n={class:"person"}){try{const r=new URL(t.url??"/","http://127.0.0.1"),u=(t.method??"GET").toUpperCase(),d=this.match(u,r.pathname);if(d===null){U(o,404,"not_found",`no route for ${u} ${r.pathname}`);return}if(Q(d.operation,n,d.params),s!==null){if(d.operation.classes.length===1&&d.operation.classes[0]==="person")throw te();d.operation.scope&&ee(s,d.operation.scope)}let m;try{m=await ne(t,d.maxBodyBytes)}catch(i){const E=i instanceof T?"payload_too_large":"invalid_request";U(o,E==="payload_too_large"?413:400,E,i.message);return}n.class==="broker"&&d.operation.resource==="human"&&D(d.operation,n,d.params,r.searchParams,m);const h={method:u,path:r.pathname,params:d.params,query:r.searchParams,body:m,ceiling:s,principal:n,...n.class==="anonymous"&&typeof t.headers.authorization=="string"?{publishToken:t.headers.authorization.slice(7)}:{},req:t,res:o},w=await d.handler(h);o.writableEnded||re(o,w)}catch(r){const{status:u,body:d}=j(r);u>=500&&p({event:"api.request.failed",level:"error",error:r instanceof Error?r:new Error(String(r)),...n.class==="broker"?{node_id:n.node}:{},fields:{method:(t.method??"GET").toUpperCase(),path:t.url??""}}),G(o,u,d)}}}function A(e){return e.split("/").filter(t=>t.length>0)}a(A,"splitPath");function oe(e,t){if(e.length!==t.length)return null;const o={};for(let s=0;s<e.length;s++){const n=e[s],r=t[s];if(n.startsWith(":"))o[n.slice(1)]=decodeURIComponent(r);else if(n!==r)return null}return o}a(oe,"matchSegments");class T extends Error{static{a(this,"BodyTooLargeError")}}async function ne(e,t){const o=[];let s=0;for await(const r of e){const u=r;if(s+=u.length,s>t)throw new T(`request body exceeds ${t} bytes`);o.push(u)}if(s===0)return;const n=Buffer.concat(o).toString("utf8").trim();if(n!=="")try{return JSON.parse(n)}catch{throw new Error("request body is not valid JSON")}}a(ne,"readJsonBody");function re(e,t){if(e.headersSent)return;const o={...t.headers??{}};if(t.rawBody!==void 0){e.writeHead(t.status,o),e.end(t.rawBody);return}if(t.status===204||t.body===void 0){e.writeHead(t.status,o),e.end();return}o["content-type"]===void 0&&(o["content-type"]="application/json; charset=utf-8"),e.writeHead(t.status,o),e.end(JSON.stringify(t.body))}a(re,"writeResult");function G(e,t,o){if(e.headersSent){e.end();return}e.writeHead(t,{"content-type":"application/json; charset=utf-8"}),e.end(JSON.stringify(o))}a(G,"writeJson");function U(e,t,o,s){G(e,t,{error:{code:o,message:s,origin:"runtime"}})}a(U,"writeError");export{Se as Router,q as actsAsPerson,b as appOf,ee as assertCeiling,l as brokerMayReach,C as canReadNode,X as canReadRun,xe as ownerOnly,te as ownerOnlyError,Be as requireRun,v as resolvedScopes,k as runCallerApp};
|
|
1
|
+
var W=Object.defineProperty;var u=(e,t)=>W(e,"name",{value:t,configurable:!0});import{toErrorBody as j}from"./map.js";import{emitEvent as p}from"../../core/events/emit.js";import{scopeAllowed as f,ScopeDeniedError as N}from"../../core/scopes.js";import{coveredByAny as J}from"../../shared/env.js";import{ApiError as c}from"../../api/errors.js";import{activeGrant as B,grantFor as x}from"../../core/grants/mirror.js";import{getNode as y}from"../../core/canvas/canvas.js";import{ownedRun as z,RunError as _}from"../../core/runs/operations.js";import{nodeMayReach as H,placeMayReach as S}from"../../core/runs/confinement.js";import{checkCronFire as M}from"../cron/authority.js";import{readConfig as P}from"../../core/config.js";import{SCOPE_VOCABULARY as I}from"../../core/scopes.js";import{operationFor as L}from"./operations.js";import{CONTROL_BODY_MAX_BYTES as F}from"../../core/llm/body-limits.js";import{getRequest as Y,getRequestByInboxTicket as V}from"../../core/human/requests.js";import{requireVisibleReview as R}from"../../core/review/store.js";import{getComment as O}from"../../core/review/comments.js";async function D(e,t,o,s,n){const r=e.path,a=n&&typeof n=="object"&&!Array.isArray(n)?n:{};if(r==="/v1/human/requests"||r==="/v1/human/reviews"){const d=r.endsWith("/reviews")?a.origin_node_id:a.requester_node_id,h=r==="/v1/human/requests"&&d==null;if(d!==t.node&&!h)throw new c(403,"other_app_run","a broker may create a human request only for its own node");const i=a.source;if(i&&typeof i=="object"&&"nodeId"in i&&i.nodeId!==t.node)throw new c(403,"other_app_run","request source must name the calling node")}if(r==="/v1/human/reviews/self/comments"&&e.method==="GET"&&s.get("actor_node_id")!==t.node)throw new c(403,"other_app_run","self review requires the calling node");if(r.includes("/comments")&&e.method!=="GET"&&a.actor_node_id!==t.node)throw new c(403,"other_app_run","comment author must be the calling node");if(o.comment_id&&!await O(o.comment_id))throw new c(404,"not_found","comment not found")}u(D,"authorizeHumanBody");function g(e){return e.class==="broker"||e.class==="cron"}u(g,"boundedByStoredScopes");function b(e){return e.class==="person"||e.class==="anonymous"||e.class==="machine"?null:e.class==="forwarded"?e.actor.kind==="app"?e.actor.app:null:e.app}u(b,"appOf");function q(e){return e.class==="person"||e.class==="forwarded"&&e.actor.kind==="person"}u(q,"actsAsPerson");async function $(e){const t=await x(e.actor.app,e.sub);if(!t)throw new c(403,"app_not_granted",`${e.actor.app} holds no active grant for ${e.sub} on this machine`);return t}u($,"forwardedGrant");async function v(e){if(e.class==="person"||e.class==="anonymous"||e.class==="machine")return[];if(e.class==="forwarded"){if(e.actor.kind==="person")return[];const{resolved:o}=await $(e),s=e.actor.node_scopes;return s===null?o:s.filter(n=>J(o,n))}if(e.class==="app")return e.scopes;if(e.class==="cron"){const o=await M({grantee:e.app,sub:e.sub,grant_id:e.grant,scopes:e.scopes});if(o.allowed)return o.effectiveScopes;throw o.reason==="grant_missing"||o.reason==="grant_revoked"?new c(401,"grant_revoked",o.message):new c(403,"scope_missing",o.message)}const t=e.grant?await B(e.grant):await x(e.app,e.sub);if(t&&t.grantee===e.app&&t.sub===e.sub)return t.resolved;if(e.app==="app:terminal"&&!P("user").runtime?.issuer)return I;throw new c(401,"grant_revoked","the node grant is not active")}u(v,"resolvedScopes");function k(e){return"class"in e?b(e):e.grantee}u(k,"runCallerApp");async function l(e,t,o){return t===void 0||!("class"in e)?!0:e.class==="cron"?await S({run:e.origin_run??"",isolated:e.isolated},e.app,t,o):e.class==="forwarded"?e.actor.kind!=="app"||await S(e.actor.place,e.actor.app,t,o):e.class!=="broker"?!0:await H(e.node,e.app,t,o)}u(l,"brokerMayReach");async function X(e,t,o){const s=k(e);if(s===t)return await l(e,o,t);if(s===null)return!0;const n="class"in e?null:await B(e.grant),r="class"in e?await v(e):n?.sub===e.sub&&n.grantee===e.grantee?n.resolved:[];return f(r,`crtr:conversations:read:${t}`)&&(!("class"in e)||!g(e)||f(e.scopes,`crtr:conversations:read:${t}`))}u(X,"canReadRun");async function Be(e,t,o=!1,s=!1){const n=await y(t);if(!n||n.parent!==null||n.run_id!==t||!n.grantee||n.deleting_at&&!s)throw new _(404,"not_found","run not found");if(!await X(e,n.grantee,t))throw new _(404,"not_found","run not found");if(o&&k(e)!==null&&k(e)!==n.grantee)throw new _(403,"other_app_run","cannot change another app's run");return await z(t,n.grantee,s)}u(Be,"requireRun");async function C(e,t,o){return q(e)?!0:e.class==="anonymous"||e.class==="machine"?!1:b(e)===t?await l(e,o,t):f(await v(e),`crtr:objects:read:${t}`)&&(!g(e)||f(e.scopes,`crtr:objects:read:${t}`))}u(C,"canReadNode");const K=new Set(["messages.post.58","messages.post.59"]);async function Q(e,t,o){if(!e.classes.includes(t.class)&&!(t.class!=="anonymous"&&t.class!=="machine"&&t.class!=="forwarded"&&e.classes.includes("anonymous")))throw new c(403,"permission_error","this operation is not available to the caller");if(t.class==="forwarded"&&t.actor.kind==="app"&&await $(t),t.class==="person"||t.class==="anonymous"||t.class==="machine"||q(t))return;const s=await v(t);if(e.scope&&(!f(s,e.scope)||g(t)&&!f(t.scopes,e.scope)))throw new c(403,"scope_missing",`missing scope ${e.scope}`);if(t.class==="app")return;const n=b(t);t.class==="broker"&&await Z(e,t,o,s);const r=o.id;if((e.resource==="node-read"||e.resource==="node-write")&&r!==void 0){const a=await y(r);if(!a)return;if(e.resource==="node-write"&&a.grantee!==n&&!(K.has(e.name)&&f(s,`crtr:objects:message:${a.grantee??"app:terminal"}`)))throw new c(403,"other_app_run","cannot change another app's node");if(e.resource==="node-write"&&!await l(t,r,a.grantee??"app:terminal"))throw new c(404,"not_found","node not found");if(e.resource==="node-read"&&!await C(t,a.grantee??"app:terminal",r))throw new c(404,"not_found","node not found")}}u(Q,"authorizeOperation");async function Z(e,t,o,s){if(e.resource==="daemon-bash"&&(!f(s,"crtr:files:rw:user:.")||!f(t.scopes,"crtr:files:rw:user:.")))throw new c(403,"scope_missing","missing scope crtr:files:rw:user:.");if(e.resource==="human"){const r=e.path,a=e.method==="GET";if(!a&&(r.endsWith("/respond")||r.endsWith("/submit")||r.endsWith("/dismiss")||r.endsWith("/progress")||r.endsWith("/comment-ranges")||r.includes("/feedback-comments")))throw new c(403,"permission_error","only the person may answer or edit the human inbox");const d=o.request_id?await Y(o.request_id):o.ticket_id?await V(o.ticket_id):null,h=o.comment_id?await O(o.comment_id):null,i=o.review_id?await R(o.review_id):h?await R(h.review_id):null,w=d?.requester_node_id??i?.origin_node_id;if(w!=null){const m=await y(w);if(m&&(a?!await C(t,m.grantee??"app:terminal",w):m.grantee!==t.app))throw new c(a?404:403,a?"not_found":"other_app_run","human request belongs to another app");if(m&&!a&&!await l(t,w,m.grantee??"app:terminal"))throw new c(404,"not_found","human request not found")}else if(d||i)throw new c(403,"permission_error","only the person may access a request without a node")}const n=o.id;if(e.resource==="node-own"&&n!==void 0&&n!==t.node)throw new c(403,"other_app_run","the operation requires the calling node")}u(Z,"authorizeBrokerOnly");function ee(e,t){if(!f(e,t))throw new N("the bearer token",t)}u(ee,"assertCeiling");function te(){return new c(403,"owner_only","this operation is owner-only; a scoped token does not reach it")}u(te,"ownerOnlyError");function xe(e){return e.map(t=>({...t,ownerOnly:!0}))}u(xe,"ownerOnly");class Se{static{u(this,"Router")}routes=[];register(t){const o=L(t.method,t.pattern);if(!o)throw new Error(`route has no operation row: ${t.method} ${t.pattern}`);if(this.routes.some(s=>s.method===t.method.toUpperCase()&&s.operation.path===t.pattern))throw new Error(`duplicate route: ${t.method} ${t.pattern}`);return this.routes.push({operation:o,method:t.method.toUpperCase(),segments:A(t.pattern),handler:t.handler,maxBodyBytes:t.maxBodyBytes??F}),this}registerAll(t){for(const o of t)this.register(o);return this}match(t,o){const s=t.toUpperCase(),n=A(o);for(const r of this.routes){if(r.method!==s)continue;const a=oe(r.segments,n);if(a!==null)return{handler:r.handler,params:a,operation:r.operation,maxBodyBytes:r.maxBodyBytes}}return null}async handle(t,o,s,n={class:"person"}){try{const r=new URL(t.url??"/","http://127.0.0.1"),a=(t.method??"GET").toUpperCase(),d=this.match(a,r.pathname);if(d===null){U(o,404,"not_found",`no route for ${a} ${r.pathname}`);return}if(await Q(d.operation,n,d.params),s!==null){if(d.operation.classes.length===1&&d.operation.classes[0]==="person")throw te();d.operation.scope&&ee(s,d.operation.scope)}let h;try{h=await ne(t,d.maxBodyBytes)}catch(m){const E=m instanceof T?"payload_too_large":"invalid_request";U(o,E==="payload_too_large"?413:400,E,m.message);return}n.class==="broker"&&d.operation.resource==="human"&&await D(d.operation,n,d.params,r.searchParams,h);const i={method:a,path:r.pathname,params:d.params,query:r.searchParams,body:h,ceiling:s,principal:n,...n.class==="anonymous"&&typeof t.headers.authorization=="string"?{publishToken:t.headers.authorization.slice(7)}:{},req:t,res:o},w=await d.handler(i);o.writableEnded||re(o,w)}catch(r){const{status:a,body:d}=j(r);a>=500&&p({event:"api.request.failed",level:"error",error:r instanceof Error?r:new Error(String(r)),...n.class==="broker"?{node_id:n.node}:{},fields:{method:(t.method??"GET").toUpperCase(),path:t.url??""}}),G(o,a,d)}}}function A(e){return e.split("/").filter(t=>t.length>0)}u(A,"splitPath");function oe(e,t){if(e.length!==t.length)return null;const o={};for(let s=0;s<e.length;s++){const n=e[s],r=t[s];if(n.startsWith(":"))o[n.slice(1)]=decodeURIComponent(r);else if(n!==r)return null}return o}u(oe,"matchSegments");class T extends Error{static{u(this,"BodyTooLargeError")}}async function ne(e,t){const o=[];let s=0;for await(const r of e){const a=r;if(s+=a.length,s>t)throw new T(`request body exceeds ${t} bytes`);o.push(a)}if(s===0)return;const n=Buffer.concat(o).toString("utf8").trim();if(n!=="")try{return JSON.parse(n)}catch{throw new Error("request body is not valid JSON")}}u(ne,"readJsonBody");function re(e,t){if(e.headersSent)return;const o={...t.headers??{}};if(t.rawBody!==void 0){e.writeHead(t.status,o),e.end(t.rawBody);return}if(t.status===204||t.body===void 0){e.writeHead(t.status,o),e.end();return}o["content-type"]===void 0&&(o["content-type"]="application/json; charset=utf-8"),e.writeHead(t.status,o),e.end(JSON.stringify(t.body))}u(re,"writeResult");function G(e,t,o){if(e.headersSent){e.end();return}e.writeHead(t,{"content-type":"application/json; charset=utf-8"}),e.end(JSON.stringify(o))}u(G,"writeJson");function U(e,t,o,s){G(e,t,{error:{code:o,message:s,origin:"runtime"}})}u(U,"writeError");export{Se as Router,q as actsAsPerson,b as appOf,ee as assertCeiling,l as brokerMayReach,C as canReadNode,X as canReadRun,xe as ownerOnly,te as ownerOnlyError,Be as requireRun,v as resolvedScopes,k as runCallerApp};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var le=Object.defineProperty;var a=(r,o)=>le(r,"name",{value:o,configurable:!0});import{createServer as D}from"node:http";import{chmodSync as ae,existsSync as N,unlinkSync as F}from"node:fs";import{MINIMUM_RUNTIME_VERSION_HEADER as G,RUNTIME_VERSION_HEADER as z,minimumRuntimeRefusal as ue}from"../../api/runtime-version.js";import{CONTRACT_HEADER as P,CONTRACT_LEVEL as J,REQUIRED_CONTRACT_HEADER as V,contractRefusal as ce}from"../../api/contract.js";import{crtrVersion as I}from"../../shared/crtr-version.js";import{apiSocketPath as pe}from"../../core/canvas/paths.js";import{resolveNodeToken as de}from"../../core/canvas/node-tokens.js";import{grantFor as me,hasSyncedGrants as fe}from"../../core/grants/mirror.js";import{readConfig as x}from"../../core/config.js";import{peerUid as ge}from"../../native/linux.js";import{findScopedApiToken as he,getApiToken as Ae,listScopedApiTokens as Re}from"../../core/secrets.js";import{emitEvent as g}from"../../core/events/emit.js";import{envCrtrdTcp as ye,envCrtrdToken as ve}from"../../shared/env.js";import{Router as K}from"./router.js";import{handleAttachUpgrade as be,refuseUpgrade as h}from"./bridge.js";import{boundDaemonControl as Ee}from"../control.js";import{attachRoutes as we}from"./handlers/attach.js";import{peerRoutes as Te}from"../peer/handlers.js";import{bashJobRoutes as _e}from"./handlers/bash-jobs.js";import{bashRoutes as Se}from"./handlers/bash.js";import{hookExecRoutes as Ce}from"./handlers/hook-exec.js";import{brokerOperationRoutes as Q}from"./handlers/broker-ops.js";import{brokerSignalRoutes as ke,brokerSignalStreams as Oe}from"./handlers/broker-signals.js";import{brokerRecoveryRoutes as X,nodeFaultRoutes as Ue}from"./handlers/broker-recovery.js";import{canvasRoutes as He}from"./handlers/canvas.js";import{chatInventoryRoutes as Ne}from"./handlers/chat-inventory.js";import{daemonRoutes as ze}from"./handlers/daemon.js";import{fileRoutes as Pe}from"./handlers/files.js";import{focusRoutes as Ie}from"./handlers/focus.js";import{analyticsRoutes as xe}from"./handlers/analytics.js";import{memoryReadsRoutes as Be}from"./handlers/memory-reads.js";import{memoryRoutes as We}from"./handlers/memory.js";import{healthRoutes as $e}from"./handlers/health.js";import{humanRequestRoutes as Le}from"./handlers/human-requests.js";import{inboxRoutes as Me}from"./handlers/inbox.js";import{feedbackCommentRoutes as je}from"./handlers/feedback-comments.js";import{objectRoutes as De}from"./handlers/objects.js";import{customObjectRoutes as Fe}from"./handlers/custom-objects.js";import{docRoutes as Ge}from"./handlers/docs.js";import{deliveryRoutes as Y}from"./handlers/delivery.js";import{deliveryRetryRoutes as Je}from"./handlers/delivery-retry.js";import{packageDocRoutes as Ve}from"./handlers/package-docs.js";import{documentAccessRoutes as Ke}from"./handlers/document-access.js";import{pluginAppRoutes as Qe}from"./handlers/plugin-app-token.js";import{brokerMailRoutes as Z,messageRoutes as Xe}from"./handlers/messages.js";import{modelAuthRoutes as Ye}from"./handlers/modelauth.js";import{llmRoutes as Ze}from"./handlers/llm.js";import{providerRoutes as qe}from"./handlers/providers.js";import{modelConfigRoutes as er}from"./handlers/model-config.js";import{nodeRoutes as rr}from"./handlers/nodes.js";import{nodeRecordRoutes as tr}from"./handlers/node-records.js";import{nodeOutcomeRoutes as or}from"./handlers/node-outcomes.js";import{nodeEventRoutes as nr}from"./handlers/node-events.js";import{profileRoutes as ir}from"./handlers/profiles.js";import{prospectiveChatInventoryRoutes as sr}from"./handlers/prospective-chat-inventory.js";import{reportRoutes as lr}from"./handlers/reports.js";import{runRoutes as ar}from"./handlers/run-routes.js";import{reviewCommentRoutes as ur}from"./handlers/review-comments.js";import{reviewRoutes as cr}from"./handlers/reviews.js";import{subscriptionRoutes as pr}from"./handlers/subscriptions.js";import{structuredRequestRoutes as dr}from"./handlers/structured-requests.js";import{cronRoutes as mr}from"./handlers/crons.js";import{setCronRequestHandler as q}from"../cron/run-socket.js";import{worktreeRoutes as fr}from"./handlers/worktree.js";import{limitsRoutes as gr}from"./handlers/limits.js";function hr(r){return new K().registerAll($e(r)).registerAll(ze).registerAll(rr).registerAll(tr).registerAll(or).registerAll(Je).registerAll(nr).registerAll(_e).registerAll(Se).registerAll(Ce).registerAll(Q).registerAll(ke).registerAll(Y).registerAll(X).registerAll(Ue).registerAll(fr).registerAll(gr).registerAll(Z).registerAll(Xe).registerAll(lr).registerAll(ar).registerAll(dr).registerAll(we).registerAll(He).registerAll(xe).registerAll(Be).registerAll(We).registerAll(Pe).registerAll(De).registerAll(Fe).registerAll(Ge).registerAll(Ve).registerAll(Ke).registerAll(Qe).registerAll(Ie).registerAll(pr).registerAll(mr).registerAll(ir).registerAll(Ye).registerAll(Ze).registerAll(qe).registerAll(er).registerAll(cr).registerAll(ur).registerAll(Me).registerAll(Le).registerAll(Ne).registerAll(sr).registerAll(je).registerAll(Te)}a(hr,"buildRouter");function Ar(r,o){if(r.toUpperCase()!=="GET")return null;const l=o.split("/").filter(f=>f.length>0);if(l.length!==4||l[0]!=="v1"||l[1]!=="nodes"||l[3]!=="attach")return null;const p=l[2];return p===void 0||p===""?null:decodeURIComponent(p)}a(Ar,"attachNodeId");function Rr(r){const o=r.trim();if(o==="")return null;const l=o.lastIndexOf(":");if(l<0)return null;const p=o.slice(0,l),f=o.slice(l+1),m=Number(f);return!Number.isInteger(m)||m<0||m>65535?null:{host:p===""?"0.0.0.0":p,port:m}}a(Rr,"parseTcp");function yr(r,o){return`${r.includes(":")?`[${r}]`:r}:${o}`}a(yr,"formatTcpAddress");const R={code:"unauthorized",message:"missing or invalid bearer token"},v={code:"owner_only",message:"attach is owner-only; a scoped token does not reach it"},B={class:"anonymous",app:"",node:"",run:null,uid:-1,sub:"",grant:null,client_id:null,scopes:[]},b=new WeakMap;function ee(r){return b.get(r)}a(ee,"socketPrincipal");function re(r,o){const l=process.platform==="linux"?ge(r.socket):null,p=r.headers.authorization;if(p===void 0)return l===null||o.has(l)?{class:"person"}:"unauthorized";if(typeof p!="string"||!p.startsWith("Bearer "))return"unauthorized";if(p.slice(7).startsWith("crtr_pub_"))return B;if(p.slice(7).startsWith(W)){const A=O(p.slice(7));return A!==void 0&&(l===null||o.has(l))?A.principal:"unauthorized"}const f=de(p.slice(7));if(!f||l!==null&&l!==f.uid)return"unauthorized";const m=x("user").runtime?.issuer;if(m&&!fe(m.replace(/\/$/,"")))return"runtime_starting";const C=f.grant??me("app:terminal",f.sub)?.id??null;return{class:"broker",...f,grant:C}}a(re,"resolveSocketPrincipal");const W="crtr_app_";function O(r){const o=r.startsWith(W)?he(r):void 0;return o===void 0?void 0:{principal:{class:"app",app:o.grantee,scopes:o.scopes},ceiling:o.scopes}}a(O,"appBearer");function vr(r){const o=new Map;for(const l of Re("user"))o.set(l.token,{principal:{class:"app",app:l.grantee,scopes:l.scopes},ceiling:l.scopes});return o.set(r,{principal:{class:"person"},ceiling:null}),o}a(vr,"resolveBearers");function te(r,o){const l=r.headers.authorization;if(typeof l!="string"||!l.startsWith("Bearer "))return;const p=l.slice(7);return p.startsWith(W)?O(p):o.get(p)}a(te,"authorize");function U(r){r.setHeader(z,I()),r.setHeader(P,J)}a(U,"advertiseRuntime");function _(r){r.setHeader("Access-Control-Allow-Origin","*"),r.setHeader("Access-Control-Expose-Headers",`${z}, ${P}`)}a(_,"exposeRuntimeHeaders");function oe(r,o){return(r.method??"GET").toUpperCase()!=="OPTIONS"?!1:(U(o),o.writeHead(204,{"Access-Control-Allow-Origin":"*","Access-Control-Expose-Headers":`${z}, ${P}`,"Access-Control-Allow-Headers":`authorization, content-type, ${G.toLowerCase()}, ${V.toLowerCase()}`,"Access-Control-Allow-Methods":"GET, POST, PATCH, PUT, DELETE, OPTIONS","Access-Control-Max-Age":"600"}),o.end(),!0)}a(oe,"answerPreflight");function S(r,o=!1){U(r),o&&_(r),r.writeHead(401,{"content-type":"application/json; charset=utf-8"}),r.end(JSON.stringify({error:{...R,origin:"runtime"}}))}a(S,"writeUnauthorized");function br(r,o){r.writeHead(503,{"content-type":"application/json; charset=utf-8"}),r.end(JSON.stringify({error:{code:"startup_blocked",message:o,origin:"runtime"}}))}a(br,"writeStartupBlocked");function ne(r){return new Promise(o=>{try{r.closeAllConnections()}catch{}r.close(()=>o())})}a(ne,"closeServer");function It(r={}){let o=null;const l=hr(()=>o),p=new K().registerAll(Q).registerAll(Y).registerAll(X).registerAll(Z),f=a((e,t)=>{const i=Ee()?.startupBlock()??null;return i===null||e==="GET"&&(t==="/healthz"||t==="/v1/status"||t==="/v1/ready")||e==="POST"&&(t==="/v1/daemon/migrate"||t==="/v1/daemon/admit")||i.phase==="recovering"&&p.match(e,t)!==null?null:i},"startupBlockFor"),m=pe(),C=new Set([process.getuid?.()??0,...x("user").runtime?.person_uids??[]]),A=a((e,t,i)=>{U(t);const c=a(u=>Array.isArray(u)?u[0]:u,"first"),E=c(e.headers[G.toLowerCase()]),n=ue(E,I())??ce(c(e.headers[V.toLowerCase()]),J,{legacyMinimum:E,runtimeVersion:I()});if(n!==null){t.writeHead(n.status,{"content-type":"application/json; charset=utf-8"}),t.end(JSON.stringify({error:{code:n.code,message:n.message,type:"invalid_request_error",origin:"runtime",retryable:!1,..."param"in n?{param:n.param}:{details:n.details}}}));return}const s=a(u=>{const w=ee(e);g({event:"api.request.failed",level:"error",...w?.class==="broker"?{node_id:w.node}:{},error:u instanceof Error?u:new Error(String(u))});try{t.headersSent||t.writeHead(500,{"content-type":"application/json; charset=utf-8"}),t.end(JSON.stringify({error:{code:"internal",message:"internal error",origin:"runtime"}}))}catch{}},"internalFailure");let d;try{d=new URL(e.url??"/","http://127.0.0.1")}catch{try{t.writeHead(400,{"content-type":"application/json; charset=utf-8"}),t.end(JSON.stringify({error:{code:"invalid_request",message:"request URL is invalid",origin:"runtime"}}))}catch{}return}try{const u=f((e.method??"GET").toUpperCase(),d.pathname);if(u!==null){br(t,u.message);return}l.handle(e,t,i,ee(e)??{class:"person"}).catch(s)}catch(u){s(u)}},"onRequest"),H=a((e,t,i)=>{t.on("error",()=>{});try{const c=new URL(e.url??"/","http://127.0.0.1"),E=f((e.method??"GET").toUpperCase(),c.pathname);if(E!==null){h(t,503,"Service Unavailable","startup_blocked",E.message);return}const n=Ar(e.method??"GET",c.pathname);if(n===null){t.destroy();return}be(e,t,i,n).catch(()=>{try{t.destroy()}catch{}})}catch{try{t.destroy()}catch{}}},"onUpgrade"),ie=a(e=>{e.on("error",t=>{g({event:"api.server.failed",level:"error",error:t})})},"bindErrorHandler"),T=D((e,t)=>{try{const i=re(e,C);if(i==="unauthorized"){g({event:"api.principal.denied",level:"warn",fields:{method:e.method}}),S(t);return}if(i==="runtime_starting"){U(t),t.writeHead(503,{"content-type":"application/json; charset=utf-8"}),t.end(JSON.stringify({error:{code:"runtime_starting",message:"grant sync is not ready",type:"server_error",origin:"runtime",retryable:!0}}));return}b.set(e,i),i.class==="broker"&&g({event:"api.request.principal",level:i.app==="app:terminal"?"debug":"info",node_id:i.node,fields:{principal:`${i.app} node:${i.node}`,method:e.method,path:e.url}}),A(e,t,i.class==="app"?i.scopes:null)}catch(i){g({event:"api.principal.failed",level:"error",error:i instanceof Error?i:new Error(String(i))}),S(t)}});T.on("upgrade",(e,t,i)=>{try{const c=re(e,C);if(c==="unauthorized"||c==="runtime_starting"){c==="unauthorized"&&g({event:"api.principal.denied",level:"warn",fields:{method:e.method}}),h(t,c==="unauthorized"?401:503,"Unauthorized",c,"socket principal unavailable");return}if(c.class!=="person"&&c.class!=="broker"){h(t,403,"Forbidden",v.code,v.message);return}b.set(e,c),H(e,t,i)}catch(c){g({event:"api.principal.failed",level:"error",error:c instanceof Error?c:new Error(String(c))}),h(t,401,"Unauthorized",R.code,R.message)}}),q((e,t,i)=>{b.set(e,i),A(e,t,null)});let $=!1,L,M;const se=new Promise((e,t)=>{L=e,M=t});T.once("listening",()=>{$=!0,L()}),T.on("error",e=>{g({event:"api.server.failed",level:"error",error:e}),$||M(e)});try{N(m)&&F(m)}catch{}T.listen(m,()=>{try{ae(m,process.platform==="linux"&&N("/run/crtr/launcher.sock")?438:384)}catch(e){g({event:"api.socket.chmod_failed",level:"error",error:e instanceof Error?e:new Error(String(e))})}});let y;const k=r.tcp??ye()??x("user").api.tcp;if(k!==void 0&&k!==""){const e=Rr(k);if(e===null)g({event:"api.tcp.invalid",level:"error",error:new Error(`invalid CRTRD_TCP/--tcp spec: ${k}`)});else{const t=r.token??ve()??Ae("user"),i=t===void 0?void 0:vr(t),c=i===void 0?(n,s)=>{if(oe(n,s))return;const d=n.headers.authorization;if(typeof d=="string"&&d.startsWith("Bearer crtr_pub_"))b.set(n,B),_(s);else if(n.headers.origin!==void 0){S(s,!0);return}else if(d!==void 0){const w=typeof d=="string"&&d.startsWith("Bearer ")?O(d.slice(7)):void 0;if(w===void 0){S(s,!0);return}b.set(n,w.principal),_(s),A(n,s,w.ceiling);return}A(n,s,null)}:(n,s)=>{if(oe(n,s))return;const d=te(n,i);if(d===void 0&&n.headers.authorization?.startsWith("Bearer crtr_pub_")){b.set(n,B),_(s),A(n,s,null);return}if(d===void 0){S(s,!0);return}b.set(n,d.principal),_(s),A(n,s,d.ceiling)},E=i===void 0?(n,s,d)=>{if(n.headers.origin!==void 0){h(s,401,"Unauthorized",R.code,R.message);return}const u=n.headers.authorization;if(u!==void 0){if(typeof u=="string"&&u.startsWith("Bearer crtr_pub_")){h(s,403,"Forbidden",v.code,v.message);return}(typeof u=="string"&&u.startsWith("Bearer ")?O(u.slice(7)):void 0)===void 0?h(s,401,"Unauthorized",R.code,R.message):h(s,403,"Forbidden",v.code,v.message);return}H(n,s,d)}:(n,s,d)=>{const u=te(n,i);if(u===void 0){h(s,401,"Unauthorized",R.code,R.message);return}if(u.ceiling!==null){h(s,403,"Forbidden",v.code,v.message);return}H(n,s,d)};y=D(c),y.on("upgrade",E),ie(y),y.once("listening",()=>{const n=y?.address();if(n!==null&&typeof n=="object"){const{address:s,port:d}=n;o=yr(s,d)}}),y.listen(e.port,e.host)}}let j=!1;return{ready:se,tcpAddress:a(()=>o,"tcpAddress"),close:a(async()=>{if(!j){j=!0,q(null),Oe.close(),await Promise.all([ne(T),y!==void 0?ne(y):Promise.resolve()]);try{N(m)&&F(m)}catch{}}},"close")}}a(It,"createApiServer");export{hr as buildRouter,It as createApiServer,ee as socketPrincipal};
|
|
1
|
+
var ce=Object.defineProperty;var a=(t,o)=>ce(t,"name",{value:o,configurable:!0});import{createServer as D}from"node:http";import{chmodSync as ue,existsSync as N,unlinkSync as F}from"node:fs";import{MINIMUM_RUNTIME_VERSION_HEADER as G,RUNTIME_VERSION_HEADER as z,minimumRuntimeRefusal as pe}from"../../api/runtime-version.js";import{CONTRACT_HEADER as P,CONTRACT_LEVEL as J,REQUIRED_CONTRACT_HEADER as V,contractRefusal as de}from"../../api/contract.js";import{crtrVersion as I}from"../../shared/crtr-version.js";import{apiSocketPath as me}from"../../core/canvas/paths.js";import{resolveNodeToken as fe}from"../../core/canvas/node-tokens.js";import{grantFor as ge,hasSyncedGrants as he}from"../../core/grants/mirror.js";import{readConfig as x}from"../../core/config.js";import{peerUid as Ae}from"../../native/linux.js";import{findScopedApiToken as Re,getApiToken as ye,listScopedApiTokens as ve}from"../../core/secrets.js";import{emitEvent as g}from"../../core/events/emit.js";import{envCrtrdTcp as be,envCrtrdToken as Ee}from"../../shared/env.js";import{Router as K}from"./router.js";import{handleAttachUpgrade as we,refuseUpgrade as h}from"./bridge.js";import{boundDaemonControl as Se}from"../control.js";import{attachRoutes as Te}from"./handlers/attach.js";import{peerRoutes as _e}from"../peer/handlers.js";import{bashJobRoutes as Ce}from"./handlers/bash-jobs.js";import{bashRoutes as ke}from"./handlers/bash.js";import{hookExecRoutes as Oe}from"./handlers/hook-exec.js";import{brokerOperationRoutes as Q}from"./handlers/broker-ops.js";import{brokerSignalRoutes as Ue,brokerSignalStreams as He}from"./handlers/broker-signals.js";import{brokerRecoveryRoutes as X,nodeFaultRoutes as Ne}from"./handlers/broker-recovery.js";import{canvasRoutes as ze}from"./handlers/canvas.js";import{chatInventoryRoutes as Pe}from"./handlers/chat-inventory.js";import{daemonRoutes as Ie}from"./handlers/daemon.js";import{fileRoutes as xe}from"./handlers/files.js";import{focusRoutes as Be}from"./handlers/focus.js";import{analyticsRoutes as We}from"./handlers/analytics.js";import{memoryReadsRoutes as $e}from"./handlers/memory-reads.js";import{memoryRoutes as Le}from"./handlers/memory.js";import{healthRoutes as Me}from"./handlers/health.js";import{humanRequestRoutes as je}from"./handlers/human-requests.js";import{inboxRoutes as De}from"./handlers/inbox.js";import{feedbackCommentRoutes as Fe}from"./handlers/feedback-comments.js";import{objectRoutes as Ge}from"./handlers/objects.js";import{customObjectRoutes as Je}from"./handlers/custom-objects.js";import{docRoutes as Ve}from"./handlers/docs.js";import{deliveryRoutes as Y}from"./handlers/delivery.js";import{deliveryRetryRoutes as Ke}from"./handlers/delivery-retry.js";import{packageDocRoutes as Qe}from"./handlers/package-docs.js";import{documentAccessRoutes as Xe}from"./handlers/document-access.js";import{pluginAppRoutes as Ye}from"./handlers/plugin-app-token.js";import{brokerMailRoutes as Z,messageRoutes as Ze}from"./handlers/messages.js";import{modelAuthRoutes as qe}from"./handlers/modelauth.js";import{llmRoutes as er}from"./handlers/llm.js";import{providerRoutes as rr}from"./handlers/providers.js";import{modelConfigRoutes as tr}from"./handlers/model-config.js";import{nodeRoutes as or}from"./handlers/nodes.js";import{nodeRecordRoutes as nr}from"./handlers/node-records.js";import{nodeOutcomeRoutes as ir}from"./handlers/node-outcomes.js";import{nodeEventRoutes as sr}from"./handlers/node-events.js";import{profileRoutes as lr}from"./handlers/profiles.js";import{prospectiveChatInventoryRoutes as ar}from"./handlers/prospective-chat-inventory.js";import{reportRoutes as cr}from"./handlers/reports.js";import{runRoutes as ur}from"./handlers/run-routes.js";import{reviewCommentRoutes as pr}from"./handlers/review-comments.js";import{reviewRoutes as dr}from"./handlers/reviews.js";import{subscriptionRoutes as mr}from"./handlers/subscriptions.js";import{structuredRequestRoutes as fr}from"./handlers/structured-requests.js";import{cronRoutes as gr}from"./handlers/crons.js";import{setCronRequestHandler as q}from"../cron/run-socket.js";import{worktreeRoutes as hr}from"./handlers/worktree.js";import{limitsRoutes as Ar}from"./handlers/limits.js";function Rr(t){return new K().registerAll(Me(t)).registerAll(Ie).registerAll(or).registerAll(nr).registerAll(ir).registerAll(Ke).registerAll(sr).registerAll(Ce).registerAll(ke).registerAll(Oe).registerAll(Q).registerAll(Ue).registerAll(Y).registerAll(X).registerAll(Ne).registerAll(hr).registerAll(Ar).registerAll(Z).registerAll(Ze).registerAll(cr).registerAll(ur).registerAll(fr).registerAll(Te).registerAll(ze).registerAll(We).registerAll($e).registerAll(Le).registerAll(xe).registerAll(Ge).registerAll(Je).registerAll(Ve).registerAll(Qe).registerAll(Xe).registerAll(Ye).registerAll(Be).registerAll(mr).registerAll(gr).registerAll(lr).registerAll(qe).registerAll(er).registerAll(rr).registerAll(tr).registerAll(dr).registerAll(pr).registerAll(De).registerAll(je).registerAll(Pe).registerAll(ar).registerAll(Fe).registerAll(_e)}a(Rr,"buildRouter");function yr(t,o){if(t.toUpperCase()!=="GET")return null;const l=o.split("/").filter(f=>f.length>0);if(l.length!==4||l[0]!=="v1"||l[1]!=="nodes"||l[3]!=="attach")return null;const p=l[2];return p===void 0||p===""?null:decodeURIComponent(p)}a(yr,"attachNodeId");function vr(t){const o=t.trim();if(o==="")return null;const l=o.lastIndexOf(":");if(l<0)return null;const p=o.slice(0,l),f=o.slice(l+1),m=Number(f);return!Number.isInteger(m)||m<0||m>65535?null:{host:p===""?"0.0.0.0":p,port:m}}a(vr,"parseTcp");function br(t,o){return`${t.includes(":")?`[${t}]`:t}:${o}`}a(br,"formatTcpAddress");const R={code:"unauthorized",message:"missing or invalid bearer token"},v={code:"owner_only",message:"attach is owner-only; a scoped token does not reach it"},B={class:"anonymous",app:"",node:"",run:null,uid:-1,sub:"",grant:null,client_id:null,scopes:[]},b=new WeakMap;function ee(t){return b.get(t)}a(ee,"socketPrincipal");async function re(t,o){const l=process.platform==="linux"?Ae(t.socket):null,p=t.headers.authorization;if(p===void 0)return l===null||o.has(l)?{class:"person"}:"unauthorized";if(typeof p!="string"||!p.startsWith("Bearer "))return"unauthorized";if(p.slice(7).startsWith("crtr_pub_"))return B;if(p.slice(7).startsWith(W)){const A=O(p.slice(7));return A!==void 0&&(l===null||o.has(l))?A.principal:"unauthorized"}const f=await fe(p.slice(7));if(!f||l!==null&&l!==f.uid)return"unauthorized";const m=x("user").runtime?.issuer;if(m&&!await he(m.replace(/\/$/,"")))return"runtime_starting";const C=f.grant??(await ge("app:terminal",f.sub))?.id??null;return{class:"broker",...f,grant:C}}a(re,"resolveSocketPrincipal");const W="crtr_app_";function O(t){const o=t.startsWith(W)?Re(t):void 0;return o===void 0?void 0:{principal:{class:"app",app:o.grantee,scopes:o.scopes},ceiling:o.scopes}}a(O,"appBearer");function Er(t){const o=new Map;for(const l of ve("user"))o.set(l.token,{principal:{class:"app",app:l.grantee,scopes:l.scopes},ceiling:l.scopes});return o.set(t,{principal:{class:"person"},ceiling:null}),o}a(Er,"resolveBearers");function te(t,o){const l=t.headers.authorization;if(typeof l!="string"||!l.startsWith("Bearer "))return;const p=l.slice(7);return p.startsWith(W)?O(p):o.get(p)}a(te,"authorize");function U(t){t.setHeader(z,I()),t.setHeader(P,J)}a(U,"advertiseRuntime");function T(t){t.setHeader("Access-Control-Allow-Origin","*"),t.setHeader("Access-Control-Expose-Headers",`${z}, ${P}`)}a(T,"exposeRuntimeHeaders");function oe(t,o){return(t.method??"GET").toUpperCase()!=="OPTIONS"?!1:(U(o),o.writeHead(204,{"Access-Control-Allow-Origin":"*","Access-Control-Expose-Headers":`${z}, ${P}`,"Access-Control-Allow-Headers":`authorization, content-type, ${G.toLowerCase()}, ${V.toLowerCase()}`,"Access-Control-Allow-Methods":"GET, POST, PATCH, PUT, DELETE, OPTIONS","Access-Control-Max-Age":"600"}),o.end(),!0)}a(oe,"answerPreflight");function _(t,o=!1){U(t),o&&T(t),t.writeHead(401,{"content-type":"application/json; charset=utf-8"}),t.end(JSON.stringify({error:{...R,origin:"runtime"}}))}a(_,"writeUnauthorized");function wr(t,o){t.writeHead(503,{"content-type":"application/json; charset=utf-8"}),t.end(JSON.stringify({error:{code:"startup_blocked",message:o,origin:"runtime"}}))}a(wr,"writeStartupBlocked");function ne(t){return new Promise(o=>{try{t.closeAllConnections()}catch{}t.close(()=>o())})}a(ne,"closeServer");function Bt(t={}){let o=null;const l=Rr(()=>o),p=new K().registerAll(Q).registerAll(Y).registerAll(X).registerAll(Z),f=a((e,r)=>{const n=Se()?.startupBlock()??null;return n===null||e==="GET"&&(r==="/healthz"||r==="/v1/status"||r==="/v1/ready")||e==="POST"&&(r==="/v1/daemon/migrate"||r==="/v1/daemon/admit")||n.phase==="recovering"&&p.match(e,r)!==null?null:n},"startupBlockFor"),m=me(),C=new Set([process.getuid?.()??0,...x("user").runtime?.person_uids??[]]),A=a((e,r,n)=>{U(r);const c=a(u=>Array.isArray(u)?u[0]:u,"first"),E=c(e.headers[G.toLowerCase()]),i=pe(E,I())??de(c(e.headers[V.toLowerCase()]),J,{legacyMinimum:E,runtimeVersion:I()});if(i!==null){r.writeHead(i.status,{"content-type":"application/json; charset=utf-8"}),r.end(JSON.stringify({error:{code:i.code,message:i.message,type:"invalid_request_error",origin:"runtime",retryable:!1,..."param"in i?{param:i.param}:{details:i.details}}}));return}const s=a(u=>{const w=ee(e);g({event:"api.request.failed",level:"error",...w?.class==="broker"?{node_id:w.node}:{},error:u instanceof Error?u:new Error(String(u))});try{r.headersSent||r.writeHead(500,{"content-type":"application/json; charset=utf-8"}),r.end(JSON.stringify({error:{code:"internal",message:"internal error",origin:"runtime"}}))}catch{}},"internalFailure");let d;try{d=new URL(e.url??"/","http://127.0.0.1")}catch{try{r.writeHead(400,{"content-type":"application/json; charset=utf-8"}),r.end(JSON.stringify({error:{code:"invalid_request",message:"request URL is invalid",origin:"runtime"}}))}catch{}return}try{const u=f((e.method??"GET").toUpperCase(),d.pathname);if(u!==null){wr(r,u.message);return}l.handle(e,r,n,ee(e)??{class:"person"}).catch(s)}catch(u){s(u)}},"onRequest"),H=a((e,r,n)=>{r.on("error",()=>{});try{const c=new URL(e.url??"/","http://127.0.0.1"),E=f((e.method??"GET").toUpperCase(),c.pathname);if(E!==null){h(r,503,"Service Unavailable","startup_blocked",E.message);return}const i=yr(e.method??"GET",c.pathname);if(i===null){r.destroy();return}we(e,r,n,i).catch(()=>{try{r.destroy()}catch{}})}catch{try{r.destroy()}catch{}}},"onUpgrade"),ie=a(e=>{e.on("error",r=>{g({event:"api.server.failed",level:"error",error:r})})},"bindErrorHandler"),se=a(async(e,r)=>{try{const n=await re(e,C);if(n==="unauthorized"){g({event:"api.principal.denied",level:"warn",fields:{method:e.method}}),_(r);return}if(n==="runtime_starting"){U(r),r.writeHead(503,{"content-type":"application/json; charset=utf-8"}),r.end(JSON.stringify({error:{code:"runtime_starting",message:"grant sync is not ready",type:"server_error",origin:"runtime",retryable:!0}}));return}b.set(e,n),n.class==="broker"&&g({event:"api.request.principal",level:n.app==="app:terminal"?"debug":"info",node_id:n.node,fields:{principal:`${n.app} node:${n.node}`,method:e.method,path:e.url}}),A(e,r,n.class==="app"?n.scopes:null)}catch(n){g({event:"api.principal.failed",level:"error",error:n instanceof Error?n:new Error(String(n))}),_(r)}},"onSocketRequest"),S=D((e,r)=>{se(e,r).catch(n=>g({event:"api.principal.failed",level:"error",error:n instanceof Error?n:new Error(String(n))}))}),le=a(async(e,r,n)=>{try{const c=await re(e,C);if(c==="unauthorized"||c==="runtime_starting"){c==="unauthorized"&&g({event:"api.principal.denied",level:"warn",fields:{method:e.method}}),h(r,c==="unauthorized"?401:503,"Unauthorized",c,"socket principal unavailable");return}if(c.class!=="person"&&c.class!=="broker"){h(r,403,"Forbidden",v.code,v.message);return}b.set(e,c),H(e,r,n)}catch(c){g({event:"api.principal.failed",level:"error",error:c instanceof Error?c:new Error(String(c))}),h(r,401,"Unauthorized",R.code,R.message)}},"onSocketUpgrade");S.on("upgrade",(e,r,n)=>{le(e,r,n).catch(c=>g({event:"api.principal.failed",level:"error",error:c instanceof Error?c:new Error(String(c))}))}),q((e,r,n)=>{b.set(e,n),A(e,r,null)});let $=!1,L,M;const ae=new Promise((e,r)=>{L=e,M=r});S.once("listening",()=>{$=!0,L()}),S.on("error",e=>{g({event:"api.server.failed",level:"error",error:e}),$||M(e)});try{N(m)&&F(m)}catch{}S.listen(m,()=>{try{ue(m,process.platform==="linux"&&N("/run/crtr/launcher.sock")?438:384)}catch(e){g({event:"api.socket.chmod_failed",level:"error",error:e instanceof Error?e:new Error(String(e))})}});let y;const k=t.tcp??be()??x("user").api.tcp;if(k!==void 0&&k!==""){const e=vr(k);if(e===null)g({event:"api.tcp.invalid",level:"error",error:new Error(`invalid CRTRD_TCP/--tcp spec: ${k}`)});else{const r=t.token??Ee()??ye("user"),n=r===void 0?void 0:Er(r),c=n===void 0?(i,s)=>{if(oe(i,s))return;const d=i.headers.authorization;if(typeof d=="string"&&d.startsWith("Bearer crtr_pub_"))b.set(i,B),T(s);else if(i.headers.origin!==void 0){_(s,!0);return}else if(d!==void 0){const w=typeof d=="string"&&d.startsWith("Bearer ")?O(d.slice(7)):void 0;if(w===void 0){_(s,!0);return}b.set(i,w.principal),T(s),A(i,s,w.ceiling);return}A(i,s,null)}:(i,s)=>{if(oe(i,s))return;const d=te(i,n);if(d===void 0&&i.headers.authorization?.startsWith("Bearer crtr_pub_")){b.set(i,B),T(s),A(i,s,null);return}if(d===void 0){_(s,!0);return}b.set(i,d.principal),T(s),A(i,s,d.ceiling)},E=n===void 0?(i,s,d)=>{if(i.headers.origin!==void 0){h(s,401,"Unauthorized",R.code,R.message);return}const u=i.headers.authorization;if(u!==void 0){if(typeof u=="string"&&u.startsWith("Bearer crtr_pub_")){h(s,403,"Forbidden",v.code,v.message);return}(typeof u=="string"&&u.startsWith("Bearer ")?O(u.slice(7)):void 0)===void 0?h(s,401,"Unauthorized",R.code,R.message):h(s,403,"Forbidden",v.code,v.message);return}H(i,s,d)}:(i,s,d)=>{const u=te(i,n);if(u===void 0){h(s,401,"Unauthorized",R.code,R.message);return}if(u.ceiling!==null){h(s,403,"Forbidden",v.code,v.message);return}H(i,s,d)};y=D(c),y.on("upgrade",E),ie(y),y.once("listening",()=>{const i=y?.address();if(i!==null&&typeof i=="object"){const{address:s,port:d}=i;o=br(s,d)}}),y.listen(e.port,e.host)}}let j=!1;return{ready:ae,tcpAddress:a(()=>o,"tcpAddress"),close:a(async()=>{if(!j){j=!0,q(null),He.close(),await Promise.all([ne(S),y!==void 0?ne(y):Promise.resolve()]);try{N(m)&&F(m)}catch{}}},"close")}}a(Bt,"createApiServer");export{Rr as buildRouter,Bt as createApiServer,ee as socketPrincipal};
|
|
@@ -16,7 +16,7 @@ export declare class BrokerSignalBus {
|
|
|
16
16
|
private readonly dirty;
|
|
17
17
|
private readonly subscribers;
|
|
18
18
|
private scheduled;
|
|
19
|
-
subscribe(listener: BrokerSignalSubscriber): () => void
|
|
19
|
+
subscribe(listener: BrokerSignalSubscriber): Promise<() => void>;
|
|
20
20
|
markMail(nodeId: string): void;
|
|
21
21
|
markNode(nodeId: string): void;
|
|
22
22
|
private mark;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
var a=Object.defineProperty;var r=(t,e)=>a(t,"name",{value:e,configurable:!0});const d=["description","title","icon","mode","lifecycle","status","cwd","parent","fork_from","profile_id","review_binding_json","persona_ack_json","intent"],c=r(t=>t==="review_binding_json"?"review_binding":t==="persona_ack_json"?"persona_ack":t,"nodeField");function l(t){const e={};for(const i of d){const s=c(i);e[s]=t[s]}return e}r(l,"cachedBrokerNodeFields");class o{static{r(this,"BrokerSignalBus")}dirty=new Map;subscribers=new Set;scheduled;subscribe(e){return this.subscribers.add(e),()=>{this.subscribers.delete(e)}}markMail(e){this.mark(e,1)}markNode(e){this.mark(e,2)}mark(e,i){this.dirty.set(e,(this.dirty.get(e)??0)|i),this.scheduled??=setImmediate(()=>this.flush())}flush(){this.scheduled=void 0;const e=[...this.dirty];this.dirty.clear();for(const[i,s]of e)for(const n of this.subscribers)try{s&1&&n(i,"mail"),s&2&&n(i,"node")}catch{}}install(e){e.function("crtr_signal",{deterministic:!1},(i,s)=>{try{typeof s=="string"&&(i==="mail"&&this.markMail(s),i==="node"&&this.markNode(s))}catch{}return null}),e.exec(`
|
|
1
|
+
var a=Object.defineProperty;var r=(t,e)=>a(t,"name",{value:e,configurable:!0});const d=["description","title","icon","mode","lifecycle","status","cwd","parent","fork_from","profile_id","review_binding_json","persona_ack_json","intent"],c=r(t=>t==="review_binding_json"?"review_binding":t==="persona_ack_json"?"persona_ack":t,"nodeField");function l(t){const e={};for(const i of d){const s=c(i);e[s]=t[s]}return e}r(l,"cachedBrokerNodeFields");class o{static{r(this,"BrokerSignalBus")}dirty=new Map;subscribers=new Set;scheduled;async subscribe(e){return this.subscribers.add(e),()=>{this.subscribers.delete(e)}}markMail(e){this.mark(e,1)}markNode(e){this.mark(e,2)}mark(e,i){this.dirty.set(e,(this.dirty.get(e)??0)|i),this.scheduled??=setImmediate(()=>this.flush())}flush(){this.scheduled=void 0;const e=[...this.dirty];this.dirty.clear();for(const[i,s]of e)for(const n of this.subscribers)try{s&1&&n(i,"mail"),s&2&&n(i,"node")}catch{}}install(e){e.function("crtr_signal",{deterministic:!1},(i,s)=>{try{typeof s=="string"&&(i==="mail"&&this.markMail(s),i==="node"&&this.markNode(s))}catch{}return null}),e.exec(`
|
|
2
2
|
CREATE TEMP TRIGGER crtr_sig_deliv_ins AFTER INSERT ON main.deliveries
|
|
3
3
|
WHEN NEW.wake = 1 BEGIN SELECT crtr_signal('mail', NEW.destination_id); END;
|
|
4
4
|
CREATE TEMP TRIGGER crtr_sig_deliv_upd AFTER UPDATE OF state, canceled_at, claim_owner ON main.deliveries
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var d=Object.defineProperty;var o=(
|
|
1
|
+
var d=Object.defineProperty;var o=(e,r)=>d(e,"name",{value:r,configurable:!0});import{childrenOf as f,getNode as s}from"../core/canvas/canvas.js";import{FinalizationError as l,pushFinal as u}from"../core/feed/feed.js";import{transition as w}from"../core/runtime/lifecycle.js";import{requestBrokerTeardown as c}from"../core/runtime/host.js";async function p(e,r){const i=await s(e);if(i===null)return"missing";const n=i.review_binding?.review_id;if(n!==void 0)for(const t of await f(e))(await s(t))?.review_binding?.review_id===n&&await p(t,r);if(i.status==="canceled"||r==="canceled"&&i.status==="done")return"already";if(r==="approved"&&(i.status==="active"||i.status==="idle"||i.status==="done")){let t="retired";try{await u(e,"The companion conversation is complete.")}catch(a){if(!(a instanceof l)||a.code!=="already_finalized")throw a;t="already"}return c(e),t}return await w(e,"cancel",{reason:"retired"}),(i.status==="active"||i.status==="idle")&&c(e),"retired"}o(p,"retireCompanion");export{p as retireCompanion};
|
|
@@ -27,7 +27,7 @@ export declare function cronBirthPrincipalOf(c: Cron): CronBirthPrincipal;
|
|
|
27
27
|
* existing parentless terminal root). It never takes a parent from another app, run or grant,
|
|
28
28
|
* never takes the terminal's identity for an app cron, and never throws for a missing creator. */
|
|
29
29
|
export type CronBirthPlacement = Pick<SpawnChildOpts, 'parent' | 'root' | 'rootLifecycle' | 'scopes' | 'run' | 'withinCreate'>;
|
|
30
|
-
export declare function cronBirthPlacement(p: CronBirthPrincipal, nodeId: string): CronBirthPlacement
|
|
30
|
+
export declare function cronBirthPlacement(p: CronBirthPrincipal, nodeId: string): Promise<CronBirthPlacement>;
|
|
31
31
|
export declare function resolveLiveProfileOrRoot(c: Cron): string | null;
|
|
32
32
|
export declare function resolveLiveProfileName(c: Cron): string | undefined;
|
|
33
33
|
/** A stored context cannot be rebuilt; the run fails rather than running under a context nobody armed. */
|
|
@@ -39,4 +39,4 @@ export interface ArmedRunContext {
|
|
|
39
39
|
env: NodeJS.ProcessEnv;
|
|
40
40
|
}
|
|
41
41
|
/** Rebuild the armed context. Corrupt snapshots and unreadable profiles fail rather than silently changing its identity or environment. */
|
|
42
|
-
export declare function buildArmedRunContext(c: Cron, runId: string): ArmedRunContext
|
|
42
|
+
export declare function buildArmedRunContext(c: Cron, runId: string): Promise<ArmedRunContext>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var p=Object.defineProperty;var o=(r,e)=>p(r,"name",{value:e,configurable:!0});import{envHomeOverride as m}from"../../shared/env.js";import{loadProfileManifest as h,lookupProfile as v}from"../../core/profiles/manifest.js";import{readProfileEnvVars as g}from"../../core/profiles/env-store.js";import{readAppEnvVars as R}from"../../core/profiles/app-env-store.js";import{ADMITTED_HOST_PATH_ENV as f,buildOperationalEnvBase as w}from"../../core/runtime/spawn-env.js";import{getNode as c}from"../../core/canvas/canvas.js";import{contextDir as y}from"../../core/canvas/paths.js";import{appendRunEvent as O}from"../../core/runs/events.js";import{payerOfGrant as b}from"../../core/grants/mirror.js";import{scopeAllowed as E}from"../../core/scopes.js";import{cronPrincipalOf as C}from"./authority.js";function _(r){if(r.profile==null)return null;let e;try{e=v(r.profile)}catch{return null}if(e.kind==="resolved")return e.entry.profileId;if(e.kind==="absent")return null;throw new l(`the armed profile "${r.profile}" is still on this host but its manifest could not be read (${e.manifestPath}) \u2014 running as root would silently give this cron a different identity, env store, and purview. Repair the manifest, or re-arm the cron under a profile that resolves.`)}o(_,"resolveLiveProfile");function M(r){return{...C(r),cron_id:r.cron_id,origin_run_id:r.origin_run_id,isolated:r.isolated,creator:r.created_by}}o(M,"cronBirthPrincipalOf");function $(r,e){const n=r.creator===null?null:c(r.creator);return n!==null&&r.origin_run_id!==null&&n.run_id===r.origin_run_id&&c(r.origin_run_id)?.deleting_at==null&&n.grantee===r.grantee&&(n.sub??"user:local")===r.sub&&(n.grant_id??null)===r.grant_id&&(r.scopes===null?n.scopes==null:r.scopes.every(t=>E(n.scopes,t)))?{parent:n.node_id,...r.scopes===null?{}:{scopes:[...r.scopes]}}:{root:!0,rootLifecycle:"terminal",...r.scopes===null?{}:{scopes:[...r.scopes]},run:{grantee:r.grantee,sub:r.sub,grant_id:r.grant_id,client_id:null,metadata_json:JSON.stringify({cron_id:r.cron_id}),run_id:e,event_cursor:1,usage_json:JSON.stringify({input_tokens:0,output_tokens:0,cache_read_tokens:0,cache_write_tokens:0,cost_usd:0})},withinCreate:o((t,
|
|
1
|
+
var p=Object.defineProperty;var o=(r,e)=>p(r,"name",{value:e,configurable:!0});import{envHomeOverride as m}from"../../shared/env.js";import{loadProfileManifest as h,lookupProfile as v}from"../../core/profiles/manifest.js";import{readProfileEnvVars as g}from"../../core/profiles/env-store.js";import{readAppEnvVars as R}from"../../core/profiles/app-env-store.js";import{ADMITTED_HOST_PATH_ENV as f,buildOperationalEnvBase as w}from"../../core/runtime/spawn-env.js";import{getNode as c}from"../../core/canvas/canvas.js";import{contextDir as y}from"../../core/canvas/paths.js";import{appendRunEvent as O}from"../../core/runs/events.js";import{payerOfGrant as b}from"../../core/grants/mirror.js";import{scopeAllowed as E}from"../../core/scopes.js";import{cronPrincipalOf as C}from"./authority.js";function _(r){if(r.profile==null)return null;let e;try{e=v(r.profile)}catch{return null}if(e.kind==="resolved")return e.entry.profileId;if(e.kind==="absent")return null;throw new l(`the armed profile "${r.profile}" is still on this host but its manifest could not be read (${e.manifestPath}) \u2014 running as root would silently give this cron a different identity, env store, and purview. Repair the manifest, or re-arm the cron under a profile that resolves.`)}o(_,"resolveLiveProfile");function M(r){return{...C(r),cron_id:r.cron_id,origin_run_id:r.origin_run_id,isolated:r.isolated,creator:r.created_by}}o(M,"cronBirthPrincipalOf");async function $(r,e){const n=r.creator===null?null:await c(r.creator);return n!==null&&r.origin_run_id!==null&&n.run_id===r.origin_run_id&&(await c(r.origin_run_id))?.deleting_at==null&&n.grantee===r.grantee&&(n.sub??"user:local")===r.sub&&(n.grant_id??null)===r.grant_id&&(r.scopes===null?n.scopes==null:r.scopes.every(t=>E(n.scopes,t)))?{parent:n.node_id,...r.scopes===null?{}:{scopes:[...r.scopes]}}:{root:!0,rootLifecycle:"terminal",...r.scopes===null?{}:{scopes:[...r.scopes]},run:{grantee:r.grantee,sub:r.sub,grant_id:r.grant_id,client_id:null,metadata_json:JSON.stringify({cron_id:r.cron_id}),run_id:e,event_cursor:1,usage_json:JSON.stringify({input_tokens:0,output_tokens:0,cache_read_tokens:0,cache_write_tokens:0,cost_usd:0})},withinCreate:o(async(t,a)=>{await O(t,e,e,"run.started",{scopes:a.scopes??null,payer:await b(r.grant_id),usage:JSON.parse(a.usage_json)})},"withinCreate")}}o($,"cronBirthPlacement");function B(r){try{return _(r)}catch{return null}}o(B,"resolveLiveProfileOrRoot");function V(r){if(r.profile!=null)try{return h(r.profile).manifest.name}catch{return}}o(V,"resolveLiveProfileName");class l extends Error{static{o(this,"ArmedContextError")}constructor(e){super(e),this.name="ArmedContextError"}}function N(r){if(r==null)return{};let e;try{e=JSON.parse(r)}catch(i){throw new l(`the armed env snapshot is not valid JSON (${i.message}) \u2014 this cron's stored env_json is corrupt, so the run would silently drop every armed variable. Re-arm the cron with a valid --env.`)}if(typeof e!="object"||e===null||Array.isArray(e))throw new l("the armed env snapshot is not a JSON object \u2014 this cron's stored env_json is corrupt. Re-arm the cron with a valid --env.");const n={};for(const[i,t]of Object.entries(e)){if(typeof t!="string")throw new l(`the armed env snapshot's value for "${i}" is not a string \u2014 this cron's stored env_json is corrupt, so the run would silently drop that variable. Re-arm the cron with a valid --env.`);n[i]=t}return n}o(N,"parseArmedEnv");async function F(r,e){const n=N(r.env_json),i=r.grantee==="app:terminal",t=i?_(r):null,a=w({targetCwd:r.cwd,targetProfileId:t,skipSpawnAllow:!i}),s={...a,...R(r.grantee),...i?g(t):{},...n,...t!==null?{CRTR_PROFILE_ID:t}:{},CRTR_CRON_ID:r.cron_id,CRTR_CRON_NAME:r.name,CRTR_RUN_ID:e},u=m();if(u!==void 0&&u!==""&&(s.CRTR_HOME=u),r.anchor_node!=null){s.CRTR_ANCHOR=r.anchor_node;const d=await c(r.anchor_node);d!==null&&(s.CRTR_CONTEXT_DIR=y(d.node_id,d.grantee))}return s[f]=a[f],{profileId:t,env:s}}o(F,"buildArmedRunContext");export{l as ArmedContextError,F as buildArmedRunContext,$ as cronBirthPlacement,M as cronBirthPrincipalOf,_ as resolveLiveProfile,V as resolveLiveProfileName,B as resolveLiveProfileOrRoot};
|
|
@@ -21,7 +21,7 @@ export type CronAuthority =
|
|
|
21
21
|
* grantee and sub; every stored scope must still be covered by it; `crtr:schedule` must be
|
|
22
22
|
* in the effective set. A null `grant_id` passes only for `app:terminal` on a runtime with
|
|
23
23
|
* no issuer. */
|
|
24
|
-
export declare function checkCronFire(p: CronPrincipal): CronAuthority
|
|
24
|
+
export declare function checkCronFire(p: CronPrincipal): Promise<CronAuthority>;
|
|
25
25
|
/** May this principal start a node? The fire check plus `crtr:act`. */
|
|
26
|
-
export declare function checkCronBirth(p: CronPrincipal): CronAuthority
|
|
26
|
+
export declare function checkCronBirth(p: CronPrincipal): Promise<CronAuthority>;
|
|
27
27
|
export declare function cronPrincipalOf(c: Cron): CronPrincipal;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var c=Object.defineProperty;var
|
|
1
|
+
var c=Object.defineProperty;var a=(r,e)=>c(r,"name",{value:e,configurable:!0});import{covers as u}from"@north-light/identity";import{activeRecord as g,grantRecord as d}from"../../core/grants/mirror.js";import{readConfig as l}from"../../core/config.js";import{isUnsandboxedMachine as f}from"../../core/runtime/unsandboxed.js";import{SCOPE_VOCABULARY as m,isOwnMemoryScope as _,scopeAllowed as i}from"../../core/scopes.js";function t(r,e){return{allowed:!1,reason:r,message:e}}a(t,"refuse");async function h(r){if(r.grantee!=="app:terminal"&&f())return t("unsandboxed_machine",`This computer runs only your own terminal agents; ${r.grantee} runs on your hosted machine.`);let e;if(r.grant_id===null){if(r.grantee!=="app:terminal"||l("user").runtime?.issuer)return t("grant_missing",`cron has no grant for ${r.grantee}; re-arm it from a node of that app`);e=m}else{const n=await d(r.grant_id);if(n===null)return t("grant_missing",`grant ${r.grant_id} is not in this runtime's grant mirror`);if(n.status!=="active")return t("grant_revoked",`grant ${r.grant_id} is ${n.status}`);if(n.expires_at!==null&&Date.parse(n.expires_at)<=Date.now())return t("grant_revoked",`grant ${r.grant_id} expired at ${n.expires_at}`);if(n.grantee!==r.grantee||n.sub!==r.sub)return t("grant_revoked",`grant ${r.grant_id} no longer belongs to ${r.grantee} for ${r.sub}`);const o=g(n);if(o===null)return t("grant_revoked",`grant ${r.grant_id} cannot be read`);e=o.resolved}if(r.scopes!==null){const n=r.scopes.find(o=>!_(o,r.grantee)&&!e.some(s=>u(s,o)));if(n!==void 0)return t("scope_narrowed",`scope ${n} is no longer covered by the grant`)}return!i(e,"crtr:schedule")||!i(r.scopes,"crtr:schedule")?t("scope_missing","the cron no longer holds crtr:schedule"):{allowed:!0,effectiveScopes:e}}a(h,"checkCronFire");async function y(r){const e=await h(r);return e.allowed&&(!i(e.effectiveScopes,"crtr:act")||!i(r.scopes,"crtr:act"))?t("scope_missing","the cron no longer holds crtr:act"):e}a(y,"checkCronBirth");function k(r){return{grantee:r.grantee,sub:r.sub,grant_id:r.grant_id,scopes:r.scopes}}a(k,"cronPrincipalOf");export{y as checkCronBirth,h as checkCronFire,k as cronPrincipalOf};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var c=Object.defineProperty;var
|
|
1
|
+
var c=Object.defineProperty;var i=(n,e)=>c(n,"name",{value:e,configurable:!0});import{getCron as o,setCronLastOutputHash as v}from"../../core/canvas/crons.js";import{escalateFailure as l,failureSummary as h}from"./escalation.js";import{resolveCronSink as g}from"./sinks.js";async function S(n,e,t,d=!1){const r=await m(n,e,t,d);if(!r.refused&&!t&&n.on_output==="on-change"){const a=await o(n.cron_id);a!==null&&a.on_output==="on-change"&&await v(n.cron_id,e.stdoutSha256)}return r}i(S,"disposeSettledRun");async function m(n,e,t,d=!1){const r=t?"out-of-band: ":"",a=await o(n.cron_id);if(a===null&&!d)return{delivered:`${r}cron canceled mid-run \u2014 nothing delivered`,paused:!1};const s=a??n,p=e.timedOut||e.processErrorMessage!==null||e.exitCode!==0;let u=!0;if(s.on_output==="on-change"&&(u=s.last_output_hash!==e.stdoutSha256),p)return s.on_output==="silent"?{delivered:`${r}silent`,paused:!1}:t?{delivered:`out-of-band: ${h(e,null)} \u2014 not escalated`,paused:!1}:{delivered:await l(s,e,null),paused:!0};switch(s.on_output){case"silent":return{delivered:`${r}silent`,paused:!1};case"on-failure":return{delivered:`${r}ok \u2014 nothing to deliver (on-failure)`,paused:!1};case"on-change":return u?f(s,e,t,r):{delivered:`${r}unchanged \u2014 not delivered (on-change)`,paused:!1};case"always":return f(s,e,t,r)}}i(m,"disposeRun");async function f(n,e,t,d){if(e.stdoutHead.trim()==="")return{delivered:`${d}empty stdout \u2014 nothing delivered`,paused:!1};try{const r=await g(n,e.runId,e.stdoutHead);return r.kind==="none"?{delivered:`${d}${r.delivered}`,paused:!1,...r.refused===!0?{refused:!0}:{}}:{delivered:"",paused:!1,obligation:r}}catch(r){const a=`delivery failed: ${r.message}`;return t?{delivered:`out-of-band: ${a} \u2014 not escalated`,paused:!1}:{delivered:await l(n,e,a),paused:!0}}}i(f,"resolveOrEscalate");export{S as disposeSettledRun};
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var p=Object.defineProperty;var r=(e,n)=>p(e,"name",{value:n,configurable:!0});import{getNode as c}from"../../core/canvas/canvas.js";import{withCanvasWrite as f}from"../../core/canvas/db.js";import{CRON_RUN_RING as h,cancelCron as m,listCronRuns as y,parseCronSink as g}from"../../core/canvas/crons.js";import{hasNoNaturalCycle as $}from"../../core/runtime/revive-all.js";import{isParked as
|
|
2
|
-
`)}}r(N,"endedMessage");function C(e){return e.deleting_at!=null||e.run_id!=null&&c(e.run_id)?.deleting_at!=null}r(C,"runIsDeleting");function K(e,n,
|
|
1
|
+
var p=Object.defineProperty;var r=(e,n)=>p(e,"name",{value:n,configurable:!0});import{getNode as c}from"../../core/canvas/canvas.js";import{withCanvasWrite as f}from"../../core/canvas/db.js";import{CRON_RUN_RING as h,cancelCron as m,listCronRuns as y,parseCronSink as g}from"../../core/canvas/crons.js";import{hasNoNaturalCycle as $}from"../../core/runtime/revive-all.js";import{isParked as w}from"../../core/runtime/lifecycle.js";import{enqueueNodeMail as _}from"../../core/feed/messages.js";import{cadenceDisplay as x}from"../../core/wake.js";const v=/^delivered: /,k=r(e=>e.exit_code===0&&(e.stdout_head??"")==="","EMPTY_OK");function b(e){return e.filter(n=>n.exit_code!==null||!(n.delivered??"").startsWith("skipped"))}r(b,"realRuns");function N(e,n,l){const t=b(l),i=l.length>=h,d=t.find(u=>v.test(u.delivered??"")),a=n.kind==="expired"?`expired at ${e.expires_at} and was deleted${e.held?" while held by exit 75; the pending occurrence never fired":""}`:`was canceled by ${n.by} and deleted`,s=[`Cron "${e.name}" (${e.cron_id}, ${e.recur!=null?x(e.recur):"one-shot"}) ${a}. It was delivering to you, so nothing will wake you from it any more.`,"",`- runs made: ${i?`at least ${t.length} (the run log keeps the last ${h} entries)`:t.length}`,d!==void 0?`- last delivery to you: ${d.finished}`:`- last delivery to you: ${i?`none in its last ${t.length} runs`:"never delivered"}`],o=t[0];if(o!==void 0){const u=o.exit_code===null?"no exit observed":o.exit_code===-1?"timed out":`exit ${o.exit_code}`;s.push(`- last run: ${o.finished} \u2014 ${u} \u2014 ${o.delivered??""}`)}return t.length>0&&t.every(k)&&s.push("","Every recorded run exited 0 with empty stdout, so the check may have been failing without saying so. A pipeline exits with its last stage, so `probe 2>&1 | grep \u2026 | jq \u2026` hides a failed probe unless the command starts with `set -o pipefail`."),{label:`\u23F0 cron ${e.name} ${n.kind==="expired"?"expired":"canceled"}`,body:s.join(`
|
|
2
|
+
`)}}r(N,"endedMessage");async function C(e){return e.deleting_at!=null||e.run_id!=null&&(await c(e.run_id))?.deleting_at!=null}r(C,"runIsDeleting");async function K(e,n,l){const t=g(e.sink),i=t?.kind==="node"?await c(t.node):null,d=n!==null&&i!==null&&!await C(i)&&(!$(i)||w(i));return await f(async()=>{const a=d?await y(e.cron_id):[];if(!await m(e.cron_id,l))return!1;if(d){const{label:s,body:o}=N(e,n,a);await _(i.node_id,{kind:"message",label:s,senderNodeId:null,bodyJson:{body:o},urgency:"normal",wake:1,idempotencyKey:`cron-ended:${e.cron_id}`})}return!0})}r(K,"endCron");export{K as endCron};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
|
-
var m=Object.defineProperty;var
|
|
2
|
-
`)[0]?.slice(0,120)??"";return`- ${
|
|
3
|
-
`)}
|
|
1
|
+
var m=Object.defineProperty;var i=(e,r)=>m(e,"name",{value:r,configurable:!0});import{getNode as f}from"../../core/canvas/canvas.js";import{nodeAgentDir as h}from"../../core/canvas/node-agent-paths.js";import{newNodeId as p}from"../../core/runtime/nodes.js";import{fullName as w}from"../../core/canvas/labels.js";import{listCronRuns as $,setCronState as _}from"../../core/canvas/crons.js";import{emitEvent as l}from"../../core/events/emit.js";import{spawnChild as y}from"../../core/runtime/spawn.js";import{cronWakeOrigin as g}from"../../core/runtime/bearings.js";import{cadenceDisplay as b}from"../../core/wake.js";import{cronBirthPlacement as v,cronBirthPrincipalOf as O,resolveLiveProfileOrRoot as k}from"./armed-context.js";import{checkCronBirth as S}from"./authority.js";function T(e,r){return r!==null?r:e.timedOut?`run timed out after ${e.runTimeoutS}s (killed; recorded exit -1)`:e.processErrorMessage!==null?`run process error: ${e.processErrorMessage}`:`command exited ${e.exitCode??"(no exit observed)"}`}i(T,"failureSummary");async function x(e,r,s){const n=e.created_by!=null?await f(e.created_by):null,o=e.created_by==null?"created by: (no creating node recorded)":n!==null?`created by: node ${e.created_by} ("${w(n)}") \u2014 still on the canvas; consider telling it what happened`:`created by: node ${e.created_by} (now gone)`,a=e.recur!=null?`every ${b(e.recur)}`:`one-shot at ${e.fire_at}`,d=(await $(e.cron_id)).slice(0,10).map(t=>{const c=t.exit_code===null?"no exit":`exit ${t.exit_code}`,u=(t.stderr_head??t.stdout_head??"").split(`
|
|
2
|
+
`)[0]?.slice(0,120)??"";return`- ${t.started} \u2014 ${c}, ${t.duration_ms}ms \u2014 ${t.delivered??""}${u!==""?` \u2014 ${u}`:""}`});return["A scheduled cron FAILED and has paused itself. You were spawned to deal with it.","",`- cron: "${e.name}" (${e.cron_id})`,`- schedule: ${a}${e.tz!=null?` (tz ${e.tz})`:""}`,`- context: cwd ${e.cwd}${e.profile!=null?`, profile ${e.profile}`:""}`,`- ${o}`,`- this failure: ${T(r,s)}`,"","## The command","","```bash",e.command,"```","","## This run","",`- exit: ${r.timedOut?"-1 (timeout)":String(r.exitCode)}`,`- stdout (head): ${r.stdoutHead===""?"(empty)":""}`,...r.stdoutHead!==""?["```",r.stdoutHead,"```"]:[],`- stderr (head): ${r.stderrHead===""?"(empty)":""}`,...r.stderrHead!==""?["```",r.stderrHead,"```"]:[],"","## Recent runs (most recent first, this failure not yet recorded)","",...d.length>0?d:["(no prior runs recorded)"],"","## Your mandate","","Diagnose why it failed and decide what to do:",`- Transient or fixable: fix the environment/command context, verify with \`crtr cron run ${e.cron_id}\` (fires now, out of band, shows you the result), then \`crtr cron resume ${e.cron_id}\` to re-arm it.`,`- Obsolete: \`crtr cron cancel ${e.cron_id}\`.`,"- The user's call (or the fix needs a change you cannot make): `crtr human send`.","","The cron stays paused until someone resumes it \u2014 nothing refires while you work."].join(`
|
|
3
|
+
`)}i(x,"buildEscalationKickoff");async function j(e,r,s){await _(e.cron_id,"paused");try{const n=O(e),o=await S(n);if(!o.allowed)return l({level:"warn",event:"cron.birth.refused",fields:{cron_id:e.cron_id,grant_id:e.grant_id,reason:o.reason,stage:"escalation"}}),`failure: cron paused; no escalation node (refused: ${o.reason})`;const a=await p(),d=await v(n,a),t=await y({nodeId:a,kind:"general",isolated:e.isolated,cwd:e.isolated?await h(a,e.grantee):e.cwd,prompt:await x(e,r,s),...d,readiness:"launch",profile:k(e),wakeOrigin:await g(e,"node_birth")});return l({level:"info",event:"cron.failure.escalated",fields:{cron_id:e.cron_id,name:e.name,escalation_node:t.node.node_id}}),`failure: cron paused, escalation node ${t.node.node_id} spawned`}catch(n){return l({level:"error",event:"cron.escalation.spawn_failed",error:n,fields:{cron_id:e.cron_id,name:e.name}}),`failure: cron paused; escalation spawn failed: ${n.message}`}}i(j,"escalateFailure");function M(e){return[`${e}.`,"This is a ONE-SHOT, so it has been PAUSED rather than released: its side effects may have completed in full,","and re-firing would enact them a second time. Determine whether the work actually landed, then either","`crtr cron run` it to redo it deliberately, or `crtr cron cancel` it."].join(" ")}i(M,"crashedOneShotSummary");export{M as crashedOneShotSummary,j as escalateFailure,T as failureSummary};
|
|
@@ -2,4 +2,4 @@
|
|
|
2
2
|
* crtr-data group (Linux sandbox), the folder takes the group of its parent and stays group-writable. */
|
|
3
3
|
export declare function ensureCronFolder(app: string, cronId: string): string;
|
|
4
4
|
/** Delete every `<app space>/crons/<id>` whose cron row no longer exists. */
|
|
5
|
-
export declare function sweepOrphanCronFolders(): number
|
|
5
|
+
export declare function sweepOrphanCronFolders(): Promise<number>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var l=Object.defineProperty;var c=(r,e)=>l(r,"name",{value:e,configurable:!0});import{chmodSync as m,chownSync as u,existsSync as f,mkdirSync as a,readdirSync as s,rmSync as y,statSync as v}from"node:fs";import{dirname as S,join as i}from"node:path";import{getCron as h}from"../../core/canvas/crons.js";import{emitEvent as d}from"../../core/events/emit.js";import{appsRoot as w,cronFolder as x}from"../../core/layout.js";function E(r,e){const n=x(r,e);for(const o of[n,i(n,"home")])if(a(o,{recursive:!0}),process.platform==="linux"){const t=v(S(o));try{u(o,process.getuid(),t.gid),m(o,1528)}catch{}}return n}c(E,"ensureCronFolder");function O(){let r=0;const e=w();if(!f(e))return 0;for(const n of s(e)){const o=i(e,n,"crons");if(f(o)){for(const t of s(o))if(h(t)===null)try{y(i(o,t),{recursive:!0,force:!0}),r++}catch(p){d({level:"warn",event:"cron.folder.sweep_failed",error:p,fields:{cron_id:t,app:n}})}}}return r>0&&d({level:"info",event:"cron.folder.swept",fields:{removed:r}}),r}c(O,"sweepOrphanCronFolders");export{E as ensureCronFolder,O as sweepOrphanCronFolders};
|
|
1
|
+
var l=Object.defineProperty;var c=(r,e)=>l(r,"name",{value:e,configurable:!0});import{chmodSync as m,chownSync as u,existsSync as f,mkdirSync as a,readdirSync as s,rmSync as y,statSync as v}from"node:fs";import{dirname as S,join as i}from"node:path";import{getCron as h}from"../../core/canvas/crons.js";import{emitEvent as d}from"../../core/events/emit.js";import{appsRoot as w,cronFolder as x}from"../../core/layout.js";function E(r,e){const n=x(r,e);for(const o of[n,i(n,"home")])if(a(o,{recursive:!0}),process.platform==="linux"){const t=v(S(o));try{u(o,process.getuid(),t.gid),m(o,1528)}catch{}}return n}c(E,"ensureCronFolder");async function O(){let r=0;const e=w();if(!f(e))return 0;for(const n of s(e)){const o=i(e,n,"crons");if(f(o)){for(const t of s(o))if(await h(t)===null)try{y(i(o,t),{recursive:!0,force:!0}),r++}catch(p){d({level:"warn",event:"cron.folder.sweep_failed",error:p,fields:{cron_id:t,app:n}})}}}return r>0&&d({level:"info",event:"cron.folder.swept",fields:{removed:r}}),r}c(O,"sweepOrphanCronFolders");export{E as ensureCronFolder,O as sweepOrphanCronFolders};
|
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
import { type Cron, type HeldSettle } from '../../core/canvas/crons.js';
|
|
2
2
|
export declare const EXIT_HELD = 75;
|
|
3
3
|
export declare const HELD_DELIVERED = "deferred (exit 75) \u2014 held for poke";
|
|
4
|
-
export declare function decideHeldSettle(c: Cron, startedAtIso: string, finishedAtMs: number): HeldSettle | undefined
|
|
4
|
+
export declare function decideHeldSettle(c: Cron, startedAtIso: string, finishedAtMs: number): Promise<HeldSettle | undefined>;
|
package/dist/daemon/cron/held.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var i=Object.defineProperty;var n=(t,r)=>i(t,"name",{value:r,configurable:!0});import{getCron as
|
|
1
|
+
var i=Object.defineProperty;var n=(t,r)=>i(t,"name",{value:r,configurable:!0});import{getCron as a}from"../../core/canvas/crons.js";const s=75,u="deferred (exit 75) \u2014 held for poke",d="9999-12-31T23:59:59.999Z";async function f(t,r,o){const e=await a(t.cron_id);if(e!==null)return e.state==="active"&&e.last_poke_at!==null&&r<e.last_poke_at?{kind:"redue",nowIso:new Date(o).toISOString()}:t.recur!=null?{kind:"park"}:{kind:"park",fireAt:e.expires_at??d}}n(f,"decideHeldSettle");export{s as EXIT_HELD,u as HELD_DELIVERED,f as decideHeldSettle};
|
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
import type { RunDueCronOptions } from './passes.js';
|
|
2
2
|
/** Recover leases from prior daemon instances. Verify launch identity, not pid liveness: a reboot can recycle the pid, and killing its new owner would signal a stranger. */
|
|
3
|
-
export declare function recoverStaleCronLeases(now: number, options?: RunDueCronOptions): void
|
|
3
|
+
export declare function recoverStaleCronLeases(now: number, options?: RunDueCronOptions): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var v=Object.defineProperty;var d=(e,r)=>v(e,"name",{value:r,configurable:!0});import{randomUUID as m}from"node:crypto";import{setTimeout as
|
|
1
|
+
var v=Object.defineProperty;var d=(e,r)=>v(e,"name",{value:r,configurable:!0});import{randomUUID as m}from"node:crypto";import{setTimeout as w}from"node:timers/promises";import{CRON_DEATH_POLL_MS as S,CRON_KILL_GRACE_MS as A,EMPTY_STDOUT_SHA256 as f}from"./capture.js";import{cronDaemonInstanceId as C}from"./live-runs.js";import{crashedOneShotSummary as L,escalateFailure as y}from"./escalation.js";import{settleRun as h}from"./settle.js";import{runningCrons as H,stopLeasedCronRun as p,setCronState as M,verifyLeasedCronRun as l}from"../../core/canvas/crons.js";import{emitEvent as c}from"../../core/events/emit.js";const i=new Set;async function K(e,r={}){for(const t of await H()){if(t.run_lease_owner===C||i.has(t.cron_id))continue;if(t.run_pid===null||!l(t)){i.add(t.cron_id),x(t,e,r);continue}const a=t.run_started_at!=null?new Date(t.run_started_at).getTime():e;if(e-a<t.run_timeout_s*1e3)continue;const o={runId:t.run_execution_id??m(),startedAtIso:t.run_started_at??new Date(e).toISOString(),exitCode:-1,timedOut:!0,runTimeoutS:t.run_timeout_s,processErrorMessage:null,stdoutHead:"",stdoutSha256:f,stderrHead:`run timed out after ${t.run_timeout_s}s (recovered stale lease from a prior daemon instance)`};i.add(t.cron_id);const n=(async()=>{await p(t),await g(t),await h(t,{outOfBand:!1,outcome:{kind:"disposed",ctx:o},record:{runId:o.runId,startedAtIso:o.startedAtIso,finishedAtMs:e,durationMs:e-a,exitCode:-1,stdoutHead:null,stderrHead:o.stderrHead},lease:{kind:"clear"}})})().finally(()=>i.delete(t.cron_id));r.register?.(n),n.catch(s=>{c({level:"error",event:"cron.stale_lease.settle_failed",error:s,fields:{cron_id:t.cron_id}})})}}d(K,"recoverStaleCronLeases");async function g(e){if(!await I(e)&&(await p(e,"SIGKILL"),!await I(e)))throw new Error(`cron ${e.cron_id} run ${e.run_pid} survived SIGKILL`)}d(g,"awaitLeasedRunDeath");async function I(e){const r=Date.now()+A;for(;Date.now()<r;){if(!l(e))return!0;await w(S)}return!l(e)}d(I,"pollLeasedRunGone");function x(e,r,t){const a=e.recur==null,o=e.run_started_at!=null?new Date(e.run_started_at).getTime():r,n=e.run_pid===null?"the daemon life that claimed this run ended before its launch pid was recorded \u2014 the command may have started and its outcome is unknown":"the daemon life that owned this run ended before it settled \u2014 the process is gone and its outcome was never observed",s={runId:e.run_execution_id??m(),startedAtIso:e.run_started_at??new Date(r).toISOString(),exitCode:null,timedOut:!1,runTimeoutS:e.run_timeout_s,processErrorMessage:n,stdoutHead:"",stdoutSha256:f,stderrHead:`run outcome unobserved: ${n}`},_=(async()=>{let u=`crashed: ${n}${a?"":" \u2014 the next occurrence is unaffected"}`;a&&(await M(e.cron_id,"paused"),u=e.on_output==="silent"?`crashed: ${n} \u2014 one-shot paused, not re-fired (silent: not escalated)`:`crashed one-shot: ${await y(e,s,L(n))}`),await h(e,{outOfBand:!1,outcome:{kind:"stated",delivered:u,paused:a},record:{runId:s.runId,startedAtIso:s.startedAtIso,finishedAtMs:r,durationMs:Math.max(0,r-o),exitCode:null,stdoutHead:null,stderrHead:s.stderrHead},lease:"release"}),c({level:"warn",event:"cron.run.unobserved",fields:{cron_id:e.cron_id,name:e.name,one_shot:a}})})().finally(()=>i.delete(e.cron_id));t.register?.(_),_.catch(u=>{c({level:"error",event:"cron.crashed_run.settle_failed",error:u,fields:{cron_id:e.cron_id}})})}d(x,"settleCrashedRun");export{K as recoverStaleCronLeases};
|
|
@@ -2,5 +2,5 @@ export interface RunDueCronOptions {
|
|
|
2
2
|
/** Registers settlement work for graceful-teardown draining. */
|
|
3
3
|
register?: (work: Promise<void>) => void;
|
|
4
4
|
}
|
|
5
|
-
export declare function expireDueCrons(nowIso: string): void
|
|
6
|
-
export declare function applyOverlapPolicies(now: number, nowIso: string): void
|
|
5
|
+
export declare function expireDueCrons(nowIso: string): Promise<void>;
|
|
6
|
+
export declare function applyOverlapPolicies(now: number, nowIso: string): Promise<void>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var
|
|
1
|
+
var d=Object.defineProperty;var t=(n,e)=>d(n,"name",{value:e,configurable:!0});import{randomUUID as c}from"node:crypto";import{cronDaemonInstanceId as l,liveRunFor as s}from"./live-runs.js";import{advanceCron as u,dueOverlapCrons as p,expiredIdleCrons as f,listCronRuns as m,recordCronRun as _}from"../../core/canvas/crons.js";import{emitEvent as v}from"../../core/events/emit.js";import{nextSlotAfter as x}from"../../core/wake.js";import{endCron as w}from"./ended.js";const a="skipped (overlap=skip)";async function A(n){for(const e of await f(n))await w(e,{kind:"expired"})&&v({level:"info",event:"cron.expired",fields:{cron_id:e.cron_id,name:e.name,expires_at:e.expires_at}})}t(A,"expireDueCrons");async function h(n){return(await m(n))[0]?.delivered?.startsWith(a)===!0}t(h,"latestRunIsSkip");async function E(n,e){for(const r of await p(e)){if(r.overlap==="queue")continue;if(r.overlap==="skip"){let o;try{o=x(r.recur,new Date(n))}catch{continue}await u(r.cron_id,o),await h(r.cron_id)||await _({run_id:c(),cron_id:r.cron_id,started:e,finished:e,duration_ms:0,exit_code:null,stdout_head:null,stderr_head:null,delivered:`${a}: fire landed while the previous run was in flight (consecutive skips are not re-recorded until a run settles)`});continue}const i=s(r.cron_id);r.run_lease_owner===l&&i!==void 0&&!i.replaced&&(i.replaced=!0,i.kill())}}t(E,"applyOverlapPolicies");export{E as applyOverlapPolicies,A as expireDueCrons};
|
|
@@ -26,5 +26,5 @@ export declare function rebuildCronExecutions(list?: () => Promise<Array<{
|
|
|
26
26
|
nodeId: string;
|
|
27
27
|
}>>): Promise<void>;
|
|
28
28
|
/** Close rebuilt executions whose row no longer records them (their lease settled elsewhere). Own executions close in the executor. */
|
|
29
|
-
export declare function reapRebuiltCronExecutions(): void
|
|
29
|
+
export declare function reapRebuiltCronExecutions(): Promise<void>;
|
|
30
30
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var k=Object.defineProperty;var i=(r,n)=>k(r,"name",{value:n,configurable:!0});import{createServer as F}from"node:http";import{chmodSync as g,existsSync as x,mkdirSync as A,readdirSync as O,rmSync as v,unlinkSync as z}from"node:fs";import{dirname as H,join as f}from"node:path";import{peerUid as M}from"../../native/linux.js";import{nodeRunDir as
|
|
1
|
+
var k=Object.defineProperty;var i=(r,n)=>k(r,"name",{value:n,configurable:!0});import{createServer as F}from"node:http";import{chmodSync as g,existsSync as x,mkdirSync as A,readdirSync as O,rmSync as v,unlinkSync as z}from"node:fs";import{dirname as H,join as f}from"node:path";import{peerUid as M}from"../../native/linux.js";import{nodeRunDir as s}from"../../core/canvas/paths.js";import{readConfig as U,readMergedLaunchConfig as j}from"../../core/config.js";import{readRotationConfig as q}from"../../core/subscription-state.js";import{runningCrons as _}from"../../core/canvas/crons.js";import{emitEvent as u}from"../../core/events/emit.js";import{cronLaunchId as a}from"../../core/spaces/process.js";import{ensureAppSpace as B}from"../../core/spaces/space.js";import{launcherPresent as y,listSandboxes as b}from"../../core/grants/sandboxes.js";import{uidForApp as J}from"../../core/spaces/users.js";import{setModeBeneath as L,writeFileBeneath as N}from"../../core/spaces/open-beneath.js";import{cronExecutionFor as w,cronExecutions as D,dropCronExecution as S,registerCronExecution as C}from"./live-runs.js";let p=null;function sr(r){p=r}i(sr,"setCronRequestHandler");const E=i(r=>process.platform==="linux"?M(r.socket):null,"linuxPeerUid");let I=E;function dr(r){I=r??E}i(dr,"__setCronPeerUidForTest");const m=new Map;function T(r){return f(s(a(r)),"cli.sock")}i(T,"cronSocketPath");function W(r){return{class:"cron",app:r.grantee,sub:r.sub,grant:r.grantId,scopes:r.scopes,cron:r.cronId,execution:r.executionId,origin_run:r.originRunId,isolated:r.isolated,anchor:r.anchor,uid:r.uid}}i(W,"cronPrincipalClassOf");function d(r,n,t,o){r.writeHead(n,{"content-type":"application/json; charset=utf-8"}),r.end(JSON.stringify({error:{code:t,message:o,type:"invalid_request_error",origin:"runtime",retryable:!1}}))}i(d,"refuse");function G(r){return(n,t)=>{try{const o=w(r);if(o===void 0){d(t,401,"unauthorized","this cron execution has ended");return}const e=I(n);if(e!==null&&e!==o.uid){u({event:"api.principal.denied",level:"warn",fields:{method:n.method,execution:r}}),d(t,401,"unauthorized","missing or invalid bearer token");return}if(p===null){d(t,503,"daemon_unavailable","the API server is not running");return}p(n,t,W(o))}catch(o){u({event:"api.principal.failed",level:"error",error:o instanceof Error?o:new Error(String(o))}),t.headersSent||d(t,401,"unauthorized","missing or invalid bearer token")}}}i(G,"onCronRequest");async function P(r){const n=T(r);x(n)&&z(n);const t=F(G(r));await new Promise((o,e)=>{t.once("error",e),t.listen(n,()=>{t.off("error",e),o()})}),g(n,438),m.set(r,t)}i(P,"listen");async function lr(r,n,t){const o=s(a(r.executionId));C(r);try{A(o,{recursive:!0,mode:504}),g(o,504);const e={user:U("user"),launch:j(n,t),rotation:q()},c=f(o,"cron-launch.json");if(N(o,c,JSON.stringify({configSnapshot:e}),{atomic:!0,mode:416}),y()){const l=await B(r.grantee);L(o,c,416,{uid:process.getuid(),gid:l.gid})}await P(r.executionId)}catch(e){throw R(r.executionId),e}}i(lr,"openCronExecution");function R(r){S(r);const n=m.get(r);m.delete(r),n!==void 0&&(n.closeAllConnections(),n.close());try{v(s(a(r)),{recursive:!0,force:!0})}catch{}}i(R,"closeCronExecution");let h=Promise.resolve();function fr(){return h}i(fr,"cronExecutionsReady");function pr(r=b){return h=(async()=>{if(r===b&&!y())return;const t=new Set((await r()).map(e=>e.nodeId));for(const e of await _()){const c=e.run_execution_id;if(!(c==null||!t.has(a(c))||w(c)!==void 0))try{C({executionId:c,cronId:e.cron_id,grantee:e.grantee,sub:e.sub,grantId:e.grant_id,scopes:e.scopes,originRunId:e.origin_run_id,isolated:e.isolated,anchor:e.anchor_node,uid:await J(e.grantee),rebuilt:!0,refusal:null}),await P(c),u({level:"info",event:"cron.execution.rebuilt",fields:{cron_id:e.cron_id,execution_id:c}})}catch(l){S(c),u({level:"error",event:"cron.execution.rebuild_failed",error:l,fields:{cron_id:e.cron_id,execution_id:c}})}}if(process.platform!=="linux")return;const o=H(s(a("x")));if(x(o)){for(const e of O(o))if(!(!e.startsWith("cron-")||t.has(e)))try{v(f(o,e),{recursive:!0,force:!0})}catch{}}})().catch(t=>{u({level:"error",event:"cron.execution.rebuild_failed",error:t})}),h}i(pr,"rebuildCronExecutions");async function mr(){const r=new Set((await _()).map(n=>n.run_execution_id));for(const n of D())n.rebuilt&&!r.has(n.executionId)&&R(n.executionId)}i(mr,"reapRebuiltCronExecutions");export{dr as __setCronPeerUidForTest,R as closeCronExecution,fr as cronExecutionsReady,W as cronPrincipalClassOf,T as cronSocketPath,lr as openCronExecution,mr as reapRebuiltCronExecutions,pr as rebuildCronExecutions,sr as setCronRequestHandler};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
var p=Object.defineProperty;var
|
|
1
|
+
var p=Object.defineProperty;var c=(e,u)=>p(e,"name",{value:u,configurable:!0});import{consumeCron as _,recordCronRunLocked as y,releaseCronRunLease as w,setCronState as I}from"../../core/canvas/crons.js";import{withCanvasWrite as b}from"../../core/canvas/db.js";import{enqueueDaemonAction as k}from"../../core/canvas/daemon-actions.js";import{enqueueNodeMail as v}from"../../core/feed/messages.js";import{emitEvent as g}from"../../core/events/emit.js";import{disposeSettledRun as C}from"./disposition.js";function h(e){return typeof e=="object"&&(e.kind==="park"||e.kind==="redue")}c(h,"occurrenceStaysOwed");async function M(e,u){const{outOfBand:a,outcome:t,record:n,lease:s}=u;let o,i,d;if(t.kind==="disposed"){const r=await C(e,t.ctx,a,t.selfCanceled??!1);o=r.delivered,i=r.paused,d=r.obligation}else t.kind==="refused"?(o=`refused: ${t.reason}`,i=!a&&e.recur==null,i&&await I(e.cron_id,"paused"),g({level:"warn",event:"cron.fire.refused",fields:{cron_id:e.cron_id,execution_id:n.runId,grant_id:e.grant_id,reason:t.reason,out_of_band:a}})):(o=t.delivered,i=t.paused??!1);const f=await b(async r=>{d!==void 0&&(d.kind==="node"?o=`delivered: ${(await v(d.destinationNodeId,{kind:"message",label:d.label,senderNodeId:d.senderNodeId,bodyJson:{body:d.stdout},urgency:d.urgency,wake:1,idempotencyKey:n.runId})).deliveryId}`:d.kind==="action"&&(o=`delivered: ${await k({adapter:d.adapter,bodyJson:d.bodyJson,idempotencyKey:n.runId})}`));const l={run_id:n.runId,cron_id:e.cron_id,started:n.startedAtIso,finished:new Date(n.finishedAtMs).toISOString(),duration_ms:n.durationMs,exit_code:n.exitCode,stdout_head:n.stdoutHead,stderr_head:n.stderrHead,delivered:o};return await y(r,l),l});return s!=="none"&&await w(e.cron_id,s==="release"?void 0:s),!a&&e.recur==null&&!i&&!h(s)&&await _(e.cron_id),f}c(M,"settleRun");export{M as settleRun};
|
|
@@ -17,4 +17,4 @@ export type CronSinkResolution = {
|
|
|
17
17
|
bodyJson: unknown;
|
|
18
18
|
};
|
|
19
19
|
/** Resolve a completed run into a durable obligation. No sink effect happens here. */
|
|
20
|
-
export declare function resolveCronSink(c: Cron, runId: string, stdout: string): CronSinkResolution
|
|
20
|
+
export declare function resolveCronSink(c: Cron, runId: string, stdout: string): Promise<CronSinkResolution>;
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var u=Object.defineProperty;var
|
|
2
|
-
`);return{kind:"action",adapter:{adapter:"cron_spawn",cronId:e.cron_id,nodeId:
|
|
1
|
+
var u=Object.defineProperty;var t=(e,o)=>u(e,"name",{value:o,configurable:!0});import{newNodeId as l}from"../../core/runtime/nodes.js";import{nodeAgentDir as f}from"../../core/canvas/node-agent-paths.js";import{getNode as s}from"../../core/canvas/canvas.js";import{parseCronSink as p}from"../../core/canvas/crons.js";import{hasNoNaturalCycle as c}from"../../core/runtime/revive-all.js";import{isParked as k}from"../../core/runtime/lifecycle.js";import{cronWakeOrigin as w}from"../../core/runtime/bearings.js";import{emitEvent as h}from"../../core/events/emit.js";import{cronBirthPrincipalOf as y,resolveLiveProfile as _,resolveLiveProfileName as v}from"./armed-context.js";import{checkCronBirth as g}from"./authority.js";async function J(e,o,i){const n=p(e.sink);if(n===null)return{kind:"none",delivered:"no sink armed \u2014 nothing delivered"};if(n.kind==="node"){const r=await s(n.node);if(r===null)throw new Error(`node sink ${n.node} is gone`);if(c(r)&&!k(r))throw new Error(`node sink ${n.node} has no natural cycle ahead (done or finalized)`);return{kind:"node",destinationNodeId:n.node,senderNodeId:e.created_by!==null&&await s(e.created_by)!==null?e.created_by:null,label:`\u23F0 cron ${e.name}`,stdout:i,urgency:e.tier}}if(n.kind==="spawn"){const r=y(e),a=await g(r);if(!a.allowed)return h({level:"warn",event:"cron.birth.refused",fields:{cron_id:e.cron_id,grant_id:e.grant_id,reason:a.reason,stage:"enqueue"}}),{kind:"none",delivered:`refused: ${a.reason}`,refused:!0};const d=await l(),m=[`Scheduled cron "${e.name}" (${e.cron_id}) fired and delivered its output to you as your kickoff.`,"","## Command output","",i].join(`
|
|
2
|
+
`);return{kind:"action",adapter:{adapter:"cron_spawn",cronId:e.cron_id,nodeId:d,kind:n.spawn,cwd:e.isolated?await f(d,e.grantee):e.cwd,isolated:e.isolated,principal:r,profile:_(e),wakeOrigin:await w(e,"node_birth"),prompt:m},bodyJson:{runId:o,stdout:i}}}return{kind:"action",adapter:{adapter:"cron_human",cronId:e.cron_id,requestId:await l(),title:`\u23F0 cron ${e.name}`,summary:`Scheduled cron "${e.name}" delivered output for your attention.`,sessionName:`cron ${e.name} (${e.cron_id})`,profileName:v(e)??null},bodyJson:{runId:o,stdout:i}}}t(J,"resolveCronSink");export{J as resolveCronSink};
|
|
@@ -19,13 +19,22 @@ export { recoverStaleCronLeases } from './cron/lease-recovery.js';
|
|
|
19
19
|
export declare function executeCron(c: Cron, opts: {
|
|
20
20
|
outOfBand: boolean;
|
|
21
21
|
}): Promise<CronRunRecord | null>;
|
|
22
|
+
/** `executeCron` with its admission exposed: `admitted` resolves once the lease is held, the
|
|
23
|
+
* recurrence is advanced and the live run is registered (or the run ended earlier without
|
|
24
|
+
* launching), so a caller can wait for the claim before it looks at the cron row again. */
|
|
25
|
+
export declare function startCron(c: Cron, opts: {
|
|
26
|
+
outOfBand: boolean;
|
|
27
|
+
}): {
|
|
28
|
+
admitted: Promise<void>;
|
|
29
|
+
settled: Promise<CronRunRecord | null>;
|
|
30
|
+
};
|
|
22
31
|
/** The daemon's cron pass: expire clock-bounded rows, apply overlap policies,
|
|
23
|
-
* then kick off every due active idle cron. Each lease
|
|
24
|
-
* but
|
|
32
|
+
* then kick off every due active idle cron. Each lease and recurrence advance is
|
|
33
|
+
* awaited here, but the launch is NEVER awaited in the tick; returns one settlement promise per
|
|
25
34
|
* admitted run.
|
|
26
35
|
*
|
|
27
36
|
* A run that launches or revives a node is admitted unconditionally: the
|
|
28
37
|
* broker slot ledger is the one admission gate, so such a run's node is born
|
|
29
38
|
* or revived frozen at the cap and the node-lifecycle tick starts it when a
|
|
30
39
|
* slot frees. The cron itself always fires and settles. */
|
|
31
|
-
export declare function runDueCrons(now: number, options?: RunDueCronOptions): Promise<void>[]
|
|
40
|
+
export declare function runDueCrons(now: number, options?: RunDueCronOptions): Promise<Promise<void>[]>;
|
package/dist/daemon/cron-run.js
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
var
|
|
2
|
-
${
|
|
1
|
+
var N=Object.defineProperty;var i=(e,t)=>N(e,"name",{value:t,configurable:!0});import{randomUUID as Y}from"node:crypto";import{CRON_OUTPUT_HEAD_BYTES as E,EMPTY_STDOUT_SHA256 as q,formatCronOutputHead as A}from"./cron/capture.js";import{clearLiveRun as C,cronDaemonInstanceId as $,registerLiveRun as J}from"./cron/live-runs.js";import{closeCronExecution as V,openCronExecution as X}from"./cron/run-socket.js";import{appProcessSandboxed as z}from"../core/spaces/process.js";import{nodeAgentDir as G}from"../core/canvas/paths.js";import{uidForApp as K}from"../core/spaces/users.js";import{buildArmedRunContext as Q}from"./cron/armed-context.js";import{ensureCronFolder as W}from"./cron/folders.js";import{checkCronFire as Z,cronPrincipalOf as j}from"./cron/authority.js";import{decideHeldSettle as ee,EXIT_HELD as te,HELD_DELIVERED as re}from"./cron/held.js";import{settleRun as O}from"./cron/settle.js";import{applyOverlapPolicies as ne,expireDueCrons as oe}from"./cron/passes.js";import{dueClockCrons as se,acquireCronRunLease as ae,releaseCronRunLease as de,attachCronRunPid as ie,advanceCron as le,setCronState as ue}from"../core/canvas/crons.js";import{emitEvent as L}from"../core/events/emit.js";import{runAppCommand as ce}from"../core/runtime/run-command.js";import{nextSlotAfter as fe}from"../core/wake.js";import{CRON_OUTPUT_HEAD_BYTES as Pe}from"./cron/capture.js";import{cronDaemonInstanceId as Ue,markSelfCanceledCronRun as Fe}from"./cron/live-runs.js";import{recoverStaleCronLeases as Ye}from"./cron/lease-recovery.js";async function me(e,t){const{runId:o,outOfBand:s,startedAtIso:u,finishedAtMs:c,code:d,timedOut:n,processError:f}=t,w=!s&&!n&&f==null&&d===te&&!t.wasReplaced&&!t.wasSelfCanceled;let p,r;return t.wasReplaced?(p={kind:"stated",delivered:"replaced (overlap=replace)"},r="release"):w?(p={kind:"stated",delivered:re},r=await ee(e,u,c)??"release"):(p={kind:"disposed",ctx:{runId:o,startedAtIso:u,exitCode:n?-1:d,timedOut:n,runTimeoutS:e.run_timeout_s,processErrorMessage:f!=null?f.message:null,stdoutHead:t.stdoutHead,stdoutSha256:t.stdoutSha256,stderrHead:t.stderrHead},selfCanceled:t.wasSelfCanceled},r=s?"release":{kind:"clear"}),O(e,{outOfBand:s,outcome:p,record:{runId:o,startedAtIso:u,finishedAtMs:c,durationMs:c-t.startedAtMs,exitCode:n?-1:d,stdoutHead:t.stdoutHead===""?null:t.stdoutHead,stderrHead:f!=null?`run process error: ${f.message}`.slice(0,E):t.stderrHead===""?null:t.stderrHead},lease:r})}i(me,"settleClosedRun");function R(e,t,o,s){const u=Date.now(),c=`${o}: ${s.message}`.slice(0,E);return O(e,{outOfBand:t.outOfBand,outcome:{kind:"disposed",ctx:{runId:t.runId,startedAtIso:t.startedAtIso,exitCode:null,timedOut:!1,runTimeoutS:e.run_timeout_s,processErrorMessage:s.message,stdoutHead:"",stdoutSha256:q,stderrHead:c}},record:{runId:t.runId,startedAtIso:t.startedAtIso,finishedAtMs:u,durationMs:u-t.startedAtMs,exitCode:null,stdoutHead:null,stderrHead:c},lease:"release"})}i(R,"settleUnspawnedRun");async function P(e,t){let o;try{o=fe(e.recur,new Date(t))}catch(s){return L({level:"error",event:"cron.recur.unparseable",error:s,fields:{cron_id:e.cron_id,name:e.name,recur:e.recur}}),await ue(e.cron_id,"paused"),new Error(`unparseable recurrence ${JSON.stringify(e.recur)}: ${s.message} \u2014 this cron cannot be rescheduled until its recurrence is fixed (\`crtr cron cancel\` and re-arm it), so it has been paused.`)}return await le(e.cron_id,o),null}i(P,"advanceRecurrence");function ye(e,t){return B(e,t).settled}i(ye,"executeCron");function B(e,t){const{outOfBand:o}=t;let s=i(()=>{},"admit");const u=new Promise(d=>{s=d}),c=new Promise((d,n)=>{let f=!1,w=i(()=>{},"undo");const p=i(r=>{if(w(),!f){n(r);return}f=!1,de(e.cron_id).then(()=>n(r),m=>{L({level:"error",event:"cron.lease.release_failed",error:m,fields:{cron_id:e.cron_id}}),n(r)})},"fail");(async()=>{const r=Y(),m=Date.now(),_=new Date(m).toISOString(),S={runId:r,outOfBand:o,startedAtIso:_,startedAtMs:m};if(!await ae(e.cron_id,$,_,o,r)){d(null);return}f=!0;const g=await Z(j(e));if(!g.allowed){try{if(!o&&e.recur!=null){const h=await P(e,m);if(h!==null)throw h}}catch(h){R(e,S,"run could not be armed",h).then(d,n);return}const a=Date.now();O(e,{outOfBand:o,outcome:{kind:"refused",reason:g.reason,message:g.message},record:{runId:r,startedAtIso:_,finishedAtMs:a,durationMs:a-m,exitCode:null,stdoutHead:null,stderrHead:`${g.reason}: ${g.message}`.slice(0,E)},lease:"release"}).then(d,n);return}let T;try{if(e.isolated&&W(e.grantee,e.cron_id),{env:T}=await Q(e,r),!o&&e.recur!=null){const a=await P(e,m);if(a!==null)throw a}}catch(a){R(e,S,"run could not be armed",a).then(d,n);return}let M=null,b=!1;const D={runId:r,replaced:!1,selfCanceled:!1,kill:i(()=>{M!==null?M():b=!0},"kill")};J(e.cron_id,D),w=i(()=>C(e.cron_id,r),"undo"),s();const x=z()?{executionId:r,cronId:e.cron_id,grantee:e.grantee,sub:e.sub,grantId:e.grant_id,scopes:e.scopes,originRunId:e.origin_run_id,isolated:e.isolated,anchor:e.anchor_node,uid:await K(e.grantee),rebuilt:!1,refusal:null}:null,I=i(()=>{x!==null&&V(r)},"closeExecution");w=i(()=>{C(e.cron_id,r),I()},"undo"),i(async()=>(x!==null&&await X(x,e.cwd,e.profile),ce({command:e.command,cwd:e.cwd,env:T,app:e.grantee,isolated:e.isolated,principal:{sub:e.sub,grantId:e.grant_id,scopes:e.scopes},...e.isolated?{folder:e.cwd}:{},...x!==null?{cron:{executionId:r,...e.anchor_node===null||e.isolated?{}:{anchorDir:G(e.anchor_node,e.grantee)}}}:e.anchor_node===null||e.isolated?{}:{nodeId:e.anchor_node},timeoutMs:e.run_timeout_s*1e3,headBytes:E})),"launch")().then(async a=>{if(a.pid===null){C(e.cron_id,r),I(),a.completion.then(l=>{R(e,S,"run failed to spawn",l.processError??new Error("bash did not provide a process id")).then(d,n)},n);return}w=i(()=>{C(e.cron_id,r),I(),a.terminate()},"undo");let h=!1;const v=i(()=>{a.completion.then(l=>{const y=D.replaced,U=D.selfCanceled,H=x?.refusal??null;if(C(e.cron_id,r),I(),h){d(null);return}if(H!==null&&!y){const k=Date.now(),F=A(l.stderr,l.stderrTruncated);O(e,{outOfBand:o,outcome:{kind:"refused",reason:H.reason,message:H.message},record:{runId:r,startedAtIso:_,finishedAtMs:k,durationMs:k-m,exitCode:l.exitCode,stdoutHead:A(l.stdout,l.stdoutTruncated)||null,stderrHead:`${H.reason}: ${H.message}
|
|
2
|
+
${F}`.trim().slice(0,E)},lease:"release"}).then(d,n);return}me(e,{runId:r,outOfBand:o,startedAtIso:_,startedAtMs:m,finishedAtMs:Date.now(),code:l.exitCode,timedOut:l.timedOut,processError:l.processError,stdoutHead:A(l.stdout,l.stdoutTruncated),stderrHead:A(l.stderr,l.stderrTruncated),stdoutSha256:l.stdoutSha256,wasReplaced:y,wasSelfCanceled:U}).then(d,n)},n)},"settleCommand");if(!await ie(e.cron_id,$,_,a.pid)&&!D.selfCanceled){h=!0,a.terminate(),v();return}M=a.terminate,b&&a.terminate(),v()},a=>{C(e.cron_id,r),I(),R(e,S,"run failed to spawn",a).then(d,n)}).catch(p)})().catch(p)});return c.then(s,s),{admitted:u,settled:c}}i(B,"startCron");async function ke(e,t={}){const o=new Date(e).toISOString();await oe(o),await ne(e,o);const s=[];for(const u of await se(o)){const{admitted:c,settled:d}=B(u,{outOfBand:!1}),n=d.then(()=>{});n.catch(()=>{}),await c,s.push(n),t.register?.(n)}for(const u of s)u.catch(()=>{});return s}i(ke,"runDueCrons");export{Pe as CRON_OUTPUT_HEAD_BYTES,Ue as cronDaemonInstanceId,ye as executeCron,Fe as markSelfCanceledCronRun,Ye as recoverStaleCronLeases,ke as runDueCrons,B as startCron};
|